Files
absens-api/app/helpers/helpers.js

112 lines
7.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const bcrypt = require('bcrypt');
const crypto = require('crypto');
const moment = require('moment');
const { sendMail } = require('../config/mail.config');
// 🔐 Generate OTP (panjang default 6 digit)
function generateOTP(length = 6) {
const digits = '0123456789';
let otp = '';
for (let i = 0; i < length; i++) {
otp += digits[Math.floor(Math.random() * 10)];
}
return otp;
}
// 📤 Kirim OTP via WhatsApp atau Email
async function sendOTP(type, otp, via, phone, email) {
if (via === 'EMAIL') {
const subject = `${type} Kode Verifikasi`;
const html = `
<p>Kode verifikasi Anda adalah:</p>
<h2>${otp}</h2>
<p>Gunakan kode ini untuk melanjutkan proses.</p>
`;
await sendMail(email, subject, html);
} else if (via === 'WHATSAPP') {
// Simulasi WhatsApp - bisa diintegrasi ke API WhatsApp asli
console.log(`[WhatsApp] Kirim OTP ke ${phone}: ${otp}`);
// TODO: Ganti dengan pengiriman lewat API WhatsApp nyata
} else {
throw new Error('Metode pengiriman OTP tidak valid.');
}
}
// 🔁 Kirim Link Reset Password via Email
const sendForgotPassword = async (email, token) => {
const resetLink = `http://localhost:3000/auth/reset/${token}`;
const subject = 'Reset Password';
const html = `
<div style="max-width:600px;margin:auto;border:1px solid #ddd;padding:20px;border-radius:10px;font-family:sans-serif;">
<div style="text-align:right;">
<svg style="margin-top: 15px;" width="35" height="35" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="20" height="20" rx="4" fill="url(#paint0_linear_563_10546)"/>
<g clip-path="url(#clip0_563_10546)">
<path d="M15.6071 6.33079C15.697 6.27014 15.721 6.14788 15.6578 6.05969C14.8161 4.88431 13.6288 3.99802 12.259 3.52594C10.8272 3.0325 9.27365 3.0184 7.8331 3.48577C6.39256 3.95315 5.14323 4.8766 4.27382 6.11666C3.40441 7.35671 2.96214 8.84601 3.01383 10.3596C3.06552 11.8732 3.60834 13.3288 4.56032 14.5067C5.51229 15.6846 6.82171 16.5206 8.29078 16.8887C9.75985 17.2567 11.3088 17.1366 12.7036 16.5467C14.0381 15.9822 15.1621 15.017 15.9217 13.787C15.9787 13.6947 15.9465 13.5743 15.8526 13.52L13.5124 12.1643C13.4186 12.1099 13.2988 12.1423 13.2398 12.2333C12.8187 12.8821 12.2122 13.3916 11.4971 13.694C10.7215 14.0221 9.86026 14.0888 9.04342 13.8842C8.22659 13.6796 7.49852 13.2147 6.9692 12.5598C6.43988 11.9049 6.13806 11.0955 6.10932 10.2539C6.08058 9.4123 6.32649 8.58422 6.8099 7.89472C7.29331 7.20522 7.98797 6.69176 8.78894 6.43189C9.58992 6.17202 10.4537 6.17986 11.2498 6.45422C11.9839 6.70721 12.6238 7.17414 13.0881 7.79273C13.1532 7.87947 13.2749 7.90356 13.3648 7.84292L15.6071 6.33079Z" fill="white"/>
<path d="M15.6071 6.33079C15.697 6.27014 15.721 6.14788 15.6578 6.05969C14.8264 4.89869 13.6576 4.0194 12.308 3.54304C10.8967 3.04487 9.36252 3.01381 7.93215 3.45445C6.50179 3.89509 5.25106 4.78406 4.36469 5.99007C3.51714 7.14326 3.04572 8.52786 3.01174 9.95545C3.00916 10.0639 3.09776 10.1515 3.20623 10.151L5.9107 10.1392C6.01917 10.1388 6.10619 10.0504 6.11121 9.94204C6.14654 9.17917 6.40644 8.44204 6.86043 7.82434C7.35327 7.15377 8.0487 6.65948 8.84402 6.41447C9.63934 6.16947 10.4924 6.18674 11.2771 6.46373C12 6.71889 12.6296 7.18198 13.0881 7.79273C13.1532 7.87947 13.2749 7.90356 13.3648 7.84292L15.6071 6.33079Z" fill="white"/>
<path d="M15.625 6.35746C15.7152 6.29724 15.7398 6.17509 15.677 6.0866C14.841 4.90741 13.6581 4.01559 12.2908 3.53697C10.8615 3.0367 9.30832 3.01505 7.86569 3.47529C6.42306 3.93553 5.16935 4.85266 4.29388 6.0882C3.41841 7.32373 2.96872 8.81057 3.01271 10.3242C3.05671 11.8378 3.592 13.296 4.53776 14.4786C5.48351 15.6612 6.78838 16.504 8.2553 16.8797C9.72223 17.2553 11.2716 17.1435 12.6693 16.5611C14.0066 16.0038 15.1357 15.0448 15.9018 13.819C15.9593 13.7271 15.9277 13.6065 15.8341 13.5517L13.5013 12.1834C13.4077 12.1285 13.2878 12.1602 13.2283 12.2508C12.8037 12.8973 12.1946 13.4034 11.478 13.702C10.7008 14.0259 9.83934 14.0881 9.0237 13.8792C8.20805 13.6703 7.48252 13.2017 6.95666 12.5442C6.43079 11.8866 6.13316 11.0758 6.1087 10.2342C6.08423 9.3926 6.33427 8.56588 6.82106 7.87889C7.30784 7.19191 8.00493 6.68196 8.80706 6.42606C9.6092 6.17016 10.4728 6.1822 11.2675 6.46036C12.0003 6.71685 12.6378 7.18676 13.0991 7.80745C13.1638 7.8945 13.2854 7.91917 13.3756 7.85895L15.625 6.35746Z" fill="url(#paint1_radial_563_10546)"/>
<path d="M8.9834 10.7974C8.9834 11.1889 9.28385 11.5046 9.65715 11.5046H10.4189C10.7436 11.5046 11.0077 11.2284 11.0077 10.8885C11.0077 10.5182 10.8468 10.3877 10.6071 10.3027L9.38401 9.87785C9.14425 9.79287 8.9834 9.66237 8.9834 9.29211C8.9834 8.9522 9.24743 8.67603 9.57217 8.67603H10.3339C10.7072 8.67603 11.0077 8.99166 11.0077 9.38316" stroke="url(#paint2_radial_563_10546)" stroke-width="0.455235" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M9.99316 8.26929V11.9112" stroke="url(#paint3_radial_563_10546)" stroke-width="0.455235" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<linearGradient id="paint0_linear_563_10546" x1="19.1806" y1="0.757954" x2="-0.0446659" y2="18.6575" gradientUnits="userSpaceOnUse">
<stop stop-color="#87CEF1"/>
<stop offset="0.343102" stop-color="#81ACD6"/>
<stop offset="0.704149" stop-color="#2D46C2"/>
<stop offset="1" stop-color="#283FB1"/>
</linearGradient>
<radialGradient id="paint1_radial_563_10546" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(9.98601 10.1215) rotate(90) scale(6.97625)">
<stop stop-color="#86C6EA"/>
<stop offset="1" stop-color="white"/>
</radialGradient>
<radialGradient id="paint2_radial_563_10546" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(9.99554 10.0903) rotate(90) scale(1.41426 1.01214)">
<stop stop-color="#86C6EA"/>
<stop offset="1" stop-color="white"/>
</radialGradient>
<radialGradient id="paint3_radial_563_10546" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(10.4932 10.0902) rotate(90) scale(1.82094 0.5)">
<stop stop-color="#86C6EA"/>
<stop offset="1" stop-color="white"/>
</radialGradient>
<clipPath id="clip0_563_10546">
<rect width="13.9909" height="13.9909" fill="white" transform="translate(2.97461 3.11011)"/>
</clipPath>
</defs>
</svg>
</div>
<h2 style="color:#000;">Reset Password</h2>
<p>Halo, <b>User</b>!</p>
<p>Heres the link to reset your Cashfio Account:</p>
<p>
<a href="${resetLink}" style="color:#1a73e8;text-decoration:none;">${resetLink}</a>
</p>
<p style="color:#d32f2f;"><strong>For your security, do not share the link with anyone!</strong></p>
<br>
<div style="background:#0d47a1;color:#fff;text-align:center;padding:10px;border-radius:0 0 10px 10px;">
Copyright Cashfio ${new Date().getFullYear()}
</div>
</div>
`;
await sendMail({ to: email, subject, html });
};
const normalizePhone = (phone) => {
return phone ? phone.replace(/[^+\d]/g, '') : null;
};
module.exports = {
generateOTP,
sendOTP,
sendForgotPassword,
normalizePhone
};