diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/utils/mailer.js | 12 | ||||
| -rw-r--r-- | src/lib/auth/components/Activate.jsx | 166 | ||||
| -rw-r--r-- | src/lib/auth/components/CompanyProfile.jsx | 120 | ||||
| -rw-r--r-- | src/lib/auth/components/Register.jsx | 36 | ||||
| -rw-r--r-- | src/pages/activate.jsx | 5 | ||||
| -rw-r--r-- | src/pages/api/activation-request.js | 27 | ||||
| -rw-r--r-- | src/pages/my/profile.jsx | 4 |
7 files changed, 335 insertions, 35 deletions
diff --git a/src/core/utils/mailer.js b/src/core/utils/mailer.js new file mode 100644 index 00000000..cab66bec --- /dev/null +++ b/src/core/utils/mailer.js @@ -0,0 +1,12 @@ +const nodemailer = require('nodemailer') +const mailer = nodemailer.createTransport({ + port: process.env.MAIL_PORT, + host: process.env.MAIL_HOST, + auth: { + user: process.env.MAIL_USER, + pass: process.env.MAIL_PASS + }, + secure: true +}) + +export default mailer diff --git a/src/lib/auth/components/Activate.jsx b/src/lib/auth/components/Activate.jsx new file mode 100644 index 00000000..7970524c --- /dev/null +++ b/src/lib/auth/components/Activate.jsx @@ -0,0 +1,166 @@ +import Image from 'next/image' +import Link from 'next/link' +import { useRouter } from 'next/router' +import { useEffect, useState } from 'react' +import IndoteknikLogo from '@/images/logo.png' +import axios from 'axios' +import { setAuth } from '@/core/utils/auth' +import Alert from '@/core/components/elements/Alert/Alert' +import odooApi from '@/core/api/odooApi' + +const Activate = () => { + const router = useRouter() + const { token } = router.query + + const [isLoading, setIsLoading] = useState(false) + const [alert, setAlert] = useState() + + const [email, setEmail] = useState(router.query?.email || '') + + useEffect(() => { + const activateIfTokenExist = async () => { + if (token) { + let isActivated = await odooApi('POST', '/api/v1/user/activation', { token }) + if (isActivated.activation) { + setAuth(isActivated.user) + setAlert({ + children: ( + <> + Selamat, akun anda berhasil diaktifkan,{' '} + <Link + className='text-gray_r-12' + href='/' + > + kembali ke beranda + </Link> + . + </> + ), + type: 'success' + }) + } else { + setAlert({ + children: ( + <> + Mohon maaf token sudah tidak aktif, lakukan permintaan aktivasi akun kembali atau{' '} + <Link + className='text-gray_r-12' + href='/login' + > + masuk + </Link>{' '} + jika sudah memiliki akun. + </> + ), + type: 'info' + }) + } + } + } + activateIfTokenExist() + }, [token]) + + useEffect(() => { + if (router.query.email) setEmail(router.query.email) + }, [router]) + + const activationRequest = async (e) => { + e.preventDefault() + setIsLoading(true) + let activationRequest = await axios.post(`${process.env.SELF_HOST}/api/activation-request`, { + email + }) + if (activationRequest.data.activationRequest) { + setAlert({ + children: <>Mohon cek email anda untuk aktivasi akun Indoteknik</>, + type: 'success' + }) + } else { + switch (activationRequest.data.reason) { + case 'NOT_FOUND': + setAlert({ + children: ( + <> + Email tersebut belum terdaftar,{' '} + <Link + className='text-gray_r-12' + href='/register' + > + daftar sekarang + </Link> + . + </> + ), + type: 'info' + }) + break + case 'ACTIVE': + setAlert({ + children: ( + <> + Email tersebut sudah terdaftar dan sudah aktif,{' '} + <Link + className='text-gray_r-12' + href='/login' + > + masuk sekarang + </Link> + . + </> + ), + type: 'info' + }) + break + } + } + setIsLoading(false) + } + + return ( + <div className='p-6 pt-10 flex flex-col items-center'> + <Link href='/'> + <Image + src={IndoteknikLogo} + alt='Logo Indoteknik' + width={150} + height={50} + /> + </Link> + + <h1 className='text-2xl mt-4 font-semibold'>Aktivasi Akun Indoteknik</h1> + + {alert && ( + <Alert + className='text-center mt-4' + type={alert.type} + > + {alert.children} + </Alert> + )} + + <form + onSubmit={activationRequest} + className='mt-6 w-full' + > + <input + type='email' + id='email' + className='form-input w-full text-center' + value={email} + onChange={(e) => setEmail(e.target.value)} + placeholder='Masukan alamat email' + autoFocus + /> + <button + type='submit' + disabled={email != ''} + className='btn-yellow font-semibold mt-4 w-full' + > + {isLoading ? 'Loading...' : 'Aktivasi'} + </button> + </form> + </div> + ) +} + +export default Activate diff --git a/src/lib/auth/components/CompanyProfile.jsx b/src/lib/auth/components/CompanyProfile.jsx index d66a0209..95575c87 100644 --- a/src/lib/auth/components/CompanyProfile.jsx +++ b/src/lib/auth/components/CompanyProfile.jsx @@ -1,32 +1,66 @@ +import odooApi from '@/core/api/odooApi' +import HookFormSelect from '@/core/components/elements/Select/HookFormSelect' import useAuth from '@/core/hooks/useAuth' import addressApi from '@/lib/address/api/addressApi' import { ChevronDownIcon, ChevronUpIcon } from '@heroicons/react/24/outline' import { useEffect, useState } from 'react' -import { useForm } from 'react-hook-form' +import { Controller, useForm } from 'react-hook-form' -const PersonalProfile = () => { +const CompanyProfile = () => { const auth = useAuth() const [isOpen, setIsOpen] = useState(false) const toggle = () => setIsOpen(!isOpen) - const { register, setValue } = useForm({ + const { register, setValue, control, handleSubmit } = useForm({ defaultValues: { - email: '', + industry: '', + companyType: '', name: '', - mobile: '', - password: '' + taxName: '', + npwp: '' } }) + const [industries, setIndustries] = useState([]) + useEffect(() => { + const loadIndustries = async () => { + const dataIndustries = await odooApi('GET', '/api/v1/partner/industry') + setIndustries(dataIndustries?.map((o) => ({ value: o.id, label: o.name }))) + } + loadIndustries() + }, []) + + const [companyTypes, setCompanyTypes] = useState([]) + useEffect(() => { + const loadCompanyTypes = async () => { + const dataCompanyTypes = await odooApi('GET', '/api/v1/partner/company_type') + setCompanyTypes(dataCompanyTypes?.map((o) => ({ value: o.id, label: o.name }))) + } + loadCompanyTypes() + }, []) + useEffect(() => { const loadProfile = async () => { - const dataProfile = await addressApi({ id: auth.partnerId }) - setValue('email', dataProfile?.email) - setValue('name', dataProfile?.name) - setValue('mobile', dataProfile?.mobile) + const dataProfile = await addressApi({ id: auth.parentId }) + setValue('name', dataProfile.name) + setValue('industry', dataProfile.industryId) + setValue('companyType', dataProfile.companyTypeId) + setValue('taxName', dataProfile.taxName) + setValue('npwp', dataProfile.npwp) } if (auth) loadProfile() }, [auth, setValue]) + const onSubmitHandler = async (values) => { + const data = { + ...values, + company_type_id: values.companyType, + industry_id: values.industry, + tax_name: values.taxName + }; + const isUpdated = await odooApi('PUT', `/api/v1/partner/${auth.parentId}`, data) + console.log(isUpdated); + } + return ( <> <button @@ -35,9 +69,9 @@ const PersonalProfile = () => { className='p-4 flex items-center text-left' > <div> - <div className='font-semibold mb-2'>Informasi Akun</div> + <div className='font-semibold mb-2'>Informasi Usaha</div> <div className='text-gray_r-11'> - Dibawah ini adalah data diri yang anda masukkan, periksa kembali data diri anda + Dibawah ini adalah data usaha yang anda masukkan, periksa kembali data usaha anda. </div> </div> <div className='p-2 bg-gray_r-3 rounded'> @@ -47,44 +81,62 @@ const PersonalProfile = () => { </button> {isOpen && ( - <form className='p-4 border-t border-gray_r-6 flex flex-col gap-y-4'> + <form className='p-4 border-t border-gray_r-6 flex flex-col gap-y-4' onSubmit={handleSubmit(onSubmitHandler)}> <div> - <label>Email</label> - <input - {...register('email')} - type='text' - disabled - className='form-input mt-3' + <label className='block mb-3'>Klasifikasi Jenis Usaha</label> + <Controller + name='industry' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={industries} + /> + )} /> </div> - <div> - <label>Nama Lengkap</label> - <input - {...register('name')} - type='text' - className='form-input mt-3' - /> + <div className='flex flex-wrap'> + <div className='w-full mb-3'>Nama Usaha</div> + <div className='w-3/12 pr-1'> + <Controller + name='companyType' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={companyTypes} + /> + )} + /> + </div> + <div className='w-9/12 pl-1'> + <input + {...register('name')} + type='text' + className='form-input' + placeholder='Cth: Indoteknik Dotcom Gemilang' + /> + </div> </div> <div> - <label>No. Handphone</label> + <label>Nama Wajib Pajak</label> <input - {...register('mobile')} + {...register('taxName')} type='text' className='form-input mt-3' /> </div> <div> - <label>Kata Sandi</label> + <label>Nomor NPWP</label> <input - {...register('password')} - type='password' + {...register('npwp')} + type='text' className='form-input mt-3' - placeholder='Isi jika ingin mengubah kata sandi' /> </div> <button type='submit' - className='btn-yellow w-full' + className='btn-yellow w-full mt-2' > Simpan </button> @@ -94,4 +146,4 @@ const PersonalProfile = () => { ) } -export default PersonalProfile +export default CompanyProfile diff --git a/src/lib/auth/components/Register.jsx b/src/lib/auth/components/Register.jsx index 135972d3..d02081ce 100644 --- a/src/lib/auth/components/Register.jsx +++ b/src/lib/auth/components/Register.jsx @@ -3,6 +3,8 @@ import Link from '@/core/components/elements/Link/Link' import IndoteknikLogo from '@/images/logo.png' import { useState } from 'react' import registerApi from '../api/registerApi' +import Alert from '@/core/components/elements/Alert/Alert' +import axios from 'axios' const Register = () => { const [fullname, setFullname] = useState('') @@ -10,9 +12,12 @@ const Register = () => { const [password, setPassword] = useState('') const [companyName, setCompanyName] = useState('') const [isLoading, setIsLoading] = useState('') + const [alert, setAlert] = useState(null) const handleSubmit = async (e) => { e.preventDefault() + setAlert(null) + setIsLoading(true) const data = { name: fullname, company: companyName, @@ -20,7 +25,27 @@ const Register = () => { password } const isRegistered = await registerApi({ data }) - console.log(isRegistered) + setIsLoading(false) + if (isRegistered.register) { + await axios.post(`${process.env.SELF_HOST}/api/activation-request`, { email }) + setAlert({ + children: 'Berhasil mendaftarkan akun anda, cek email untuk melakukan aktivasi akun', + type: 'success' + }) + setCompanyName('') + setFullname('') + setEmail('') + setPassword('') + } else { + switch (isRegistered.reason) { + case 'EMAIL_USED': + setAlert({ + children: 'Email telah digunakan', + type: 'info' + }) + break + } + } } return ( @@ -39,6 +64,15 @@ const Register = () => { Buat akun sekarang lebih mudah dan terverifikasi </h2> + {alert && ( + <Alert + className='text-center' + type={alert.type} + > + {alert.children} + </Alert> + )} + <form className='w-full mt-6 flex flex-col gap-y-4' onSubmit={handleSubmit} diff --git a/src/pages/activate.jsx b/src/pages/activate.jsx new file mode 100644 index 00000000..a8106509 --- /dev/null +++ b/src/pages/activate.jsx @@ -0,0 +1,5 @@ +import ActivateComponent from '@/lib/auth/components/Activate' + +export default function Activate() { + return <ActivateComponent /> +} diff --git a/src/pages/api/activation-request.js b/src/pages/api/activation-request.js new file mode 100644 index 00000000..7fae2fd1 --- /dev/null +++ b/src/pages/api/activation-request.js @@ -0,0 +1,27 @@ +import odooApi from '@/core/api/odooApi' +import mailer from '@/core/utils/mailer' + +export default async function handler(req, res) { + try { + const { email } = req.body + let result = await odooApi('POST', '/api/v1/user/activation-request', { email }) + if (result.activationRequest) { + mailer.sendMail({ + from: 'sales@indoteknik.com', + to: result.user.email, + subject: 'Permintaan Aktivasi Akun Indoteknik', + html: ` + <h1>Permintaan Aktivasi Akun Indoteknik</h1> + <br> + <p>Aktivasi akun anda melalui link berikut: <a href="${process.env.SELF_HOST}/activate?token=${result.token}">Aktivasi Akun</a></p> + ` + }) + } + delete result.user + delete result.token + res.status(200).json(result) + } catch (error) { + console.log(error) + res.status(400).json({ error: error.message }) + } +} diff --git a/src/pages/my/profile.jsx b/src/pages/my/profile.jsx index f69d4303..f8d4c3de 100644 --- a/src/pages/my/profile.jsx +++ b/src/pages/my/profile.jsx @@ -1,10 +1,14 @@ +import Divider from '@/core/components/elements/Divider/Divider' import AppLayout from '@/core/components/layouts/AppLayout' +import CompanyProfile from '@/lib/auth/components/CompanyProfile' import PersonalProfile from '@/lib/auth/components/PersonalProfile' export default function Profile() { return ( <AppLayout title='Akun Saya'> <PersonalProfile /> + <Divider /> + <CompanyProfile /> </AppLayout> ) } |
