diff options
| author | IT Fixcomart <it@fixcomart.co.id> | 2023-03-01 09:18:52 +0000 |
|---|---|---|
| committer | IT Fixcomart <it@fixcomart.co.id> | 2023-03-01 09:18:52 +0000 |
| commit | a7abbf4ddc70068620e9f44b74dc162ce2e16ee2 (patch) | |
| tree | 74f66253717515d364ce74bd8275015c1f829cbc /src/lib/auth/components | |
| parent | 90e1edab9b6a8ccc09a49fed3addbec2cbc4e4c3 (diff) | |
| parent | a1b9b647a6c4bda1f5db63879639d44543f9557e (diff) | |
Merged in refactor (pull request #1)
Refactor
Diffstat (limited to 'src/lib/auth/components')
| -rw-r--r-- | src/lib/auth/components/Activate.jsx | 166 | ||||
| -rw-r--r-- | src/lib/auth/components/CompanyProfile.jsx | 158 | ||||
| -rw-r--r-- | src/lib/auth/components/IsAuth.jsx | 20 | ||||
| -rw-r--r-- | src/lib/auth/components/Login.jsx | 125 | ||||
| -rw-r--r-- | src/lib/auth/components/PersonalProfile.jsx | 118 | ||||
| -rw-r--r-- | src/lib/auth/components/Register.jsx | 151 |
6 files changed, 738 insertions, 0 deletions
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 new file mode 100644 index 00000000..1b25551e --- /dev/null +++ b/src/lib/auth/components/CompanyProfile.jsx @@ -0,0 +1,158 @@ +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 { Controller, useForm } from 'react-hook-form' +import { toast } from 'react-hot-toast' + +const CompanyProfile = () => { + const auth = useAuth() + const [isOpen, setIsOpen] = useState(false) + const toggle = () => setIsOpen(!isOpen) + const { register, setValue, control, handleSubmit } = useForm({ + defaultValues: { + industry: '', + companyType: '', + name: '', + 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.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) + if (isUpdated?.id) { + setIsOpen(false) + toast.success('Berhasil mengubah profil', { duration: 1500 }) + return + } + toast.error('Terjadi kesalahan internal') + } + + return ( + <> + <button + type='button' + onClick={toggle} + className='p-4 flex items-center text-left' + > + <div> + <div className='font-semibold mb-2'>Informasi Usaha</div> + <div className='text-gray_r-11'> + Dibawah ini adalah data usaha yang anda masukkan, periksa kembali data usaha anda. + </div> + </div> + <div className='p-2 bg-gray_r-3 rounded'> + {!isOpen && <ChevronDownIcon className='w-6' />} + {isOpen && <ChevronUpIcon className='w-6' />} + </div> + </button> + + {isOpen && ( + <form + className='p-4 border-t border-gray_r-6 flex flex-col gap-y-4' + onSubmit={handleSubmit(onSubmitHandler)} + > + <div> + <label className='block mb-3'>Klasifikasi Jenis Usaha</label> + <Controller + name='industry' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={industries} + /> + )} + /> + </div> + <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>Nama Wajib Pajak</label> + <input + {...register('taxName')} + type='text' + className='form-input mt-3' + /> + </div> + <div> + <label>Nomor NPWP</label> + <input + {...register('npwp')} + type='text' + className='form-input mt-3' + /> + </div> + <button + type='submit' + className='btn-yellow w-full mt-2' + > + Simpan + </button> + </form> + )} + </> + ) +} + +export default CompanyProfile diff --git a/src/lib/auth/components/IsAuth.jsx b/src/lib/auth/components/IsAuth.jsx new file mode 100644 index 00000000..1cfd3172 --- /dev/null +++ b/src/lib/auth/components/IsAuth.jsx @@ -0,0 +1,20 @@ +import { useRouter } from 'next/router' +import { useEffect, useState } from 'react' +import { getAuth } from '@/core/utils/auth' + +const IsAuth = ({ children }) => { + const router = useRouter() + const [response, setResponse] = useState(<></>) + + useEffect(() => { + if (!getAuth()) { + router.replace('/login') + } else { + setResponse(children) + } + }, [children, router]) + + return response +} + +export default IsAuth diff --git a/src/lib/auth/components/Login.jsx b/src/lib/auth/components/Login.jsx new file mode 100644 index 00000000..b25cf4fe --- /dev/null +++ b/src/lib/auth/components/Login.jsx @@ -0,0 +1,125 @@ +import Image from 'next/image' +import IndoteknikLogo from '@/images/logo.png' +import Link from '@/core/components/elements/Link/Link' +import { useState } from 'react' +import loginApi from '../api/loginApi' +import { useRouter } from 'next/router' +import Alert from '@/core/components/elements/Alert/Alert' +import { setAuth } from '@/core/utils/auth' + +const Login = () => { + const router = useRouter() + const [email, setEmail] = useState('') + const [password, setPassword] = useState('') + const [isLoading, setIsLoading] = useState(false) + const [alert, setAlert] = useState(null) + + const handleSubmit = async (e) => { + e.preventDefault() + setAlert(null) + setIsLoading(true) + const login = await loginApi({ email, password }) + setIsLoading(false) + + if (login.isAuth) { + setAuth(login.user) + router.push('/') + return + } + switch (login.reason) { + case 'NOT_FOUND': + setAlert({ + children: 'Email atau password tidak cocok', + type: 'info' + }) + break + case 'NOT_ACTIVE': + setAlert({ + children: ( + <> + Email belum diaktivasi, + <Link + className='text-gray-900' + href={`/activate?email=${email}`} + > + aktivasi sekarang + </Link> + </> + ), + type: 'info' + }) + break + } + } + + 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'>Mulai Belanja Sekarang</h1> + <h2 className='text-gray_r-11 font-normal mt-1 mb-4'>Masuk ke akun kamu untuk belanja</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} + > + <div> + <label htmlFor='email'>Alamat Email</label> + <input + type='email' + id='email' + className='form-input w-full mt-3' + value={email} + onChange={(e) => setEmail(e.target.value)} + placeholder='contoh@email.com' + /> + </div> + <div> + <label htmlFor='password'>Kata Sandi</label> + <input + type='password' + id='password' + className='form-input w-full mt-3' + value={password} + onChange={(e) => setPassword(e.target.value)} + placeholder='••••••••••••' + /> + </div> + <button + type='submit' + className='btn-yellow w-full mt-2' + disabled={!email || !password || isLoading} + > + {!isLoading ? 'Masuk' : 'Loading...'} + </button> + </form> + + <div className='text-gray_r-11 mt-4'> + Belum punya akun Indoteknik?{' '} + <Link + href='/register' + className='inline' + > + Daftar + </Link> + </div> + </div> + ) +} + +export default Login diff --git a/src/lib/auth/components/PersonalProfile.jsx b/src/lib/auth/components/PersonalProfile.jsx new file mode 100644 index 00000000..0b387f2e --- /dev/null +++ b/src/lib/auth/components/PersonalProfile.jsx @@ -0,0 +1,118 @@ +import useAuth from '@/core/hooks/useAuth' +import { setAuth } from '@/core/utils/auth' +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 { toast } from 'react-hot-toast' +import editPersonalProfileApi from '../api/editPersonalProfileApi' + +const PersonalProfile = () => { + const auth = useAuth() + const [isOpen, setIsOpen] = useState(false) + const toggle = () => setIsOpen(!isOpen) + const { register, setValue, handleSubmit } = useForm({ + defaultValues: { + email: '', + name: '', + mobile: '', + password: '' + } + }) + + useEffect(() => { + const loadProfile = async () => { + const dataProfile = await addressApi({ id: auth.partnerId }) + setValue('email', dataProfile?.email) + setValue('name', dataProfile?.name) + setValue('mobile', dataProfile?.mobile) + } + if (auth) loadProfile() + }, [auth, setValue]) + + const onSubmitHandler = async (values) => { + let data = values + if (!values.password) delete data.password + const isUpdated = await editPersonalProfileApi({ data }) + console.log(isUpdated) + if (isUpdated?.user) { + setAuth(isUpdated.user) + setValue('password', '') + setIsOpen(false) + toast.success('Berhasil mengubah profil', { duration: 1500 }) + return + } + toast.error('Terjadi kesalahan internal') + } + + return ( + <> + <button + type='button' + onClick={toggle} + className='p-4 flex items-center text-left' + > + <div> + <div className='font-semibold mb-2'>Informasi Akun</div> + <div className='text-gray_r-11'> + Dibawah ini adalah data diri yang anda masukan, periksa kembali data diri anda + </div> + </div> + <div className='p-2 bg-gray_r-3 rounded'> + {!isOpen && <ChevronDownIcon className='w-6' />} + {isOpen && <ChevronUpIcon className='w-6' />} + </div> + </button> + + {isOpen && ( + <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' + /> + </div> + <div> + <label>Nama Lengkap</label> + <input + {...register('name')} + type='text' + className='form-input mt-3' + /> + </div> + <div> + <label>No. Handphone</label> + <input + {...register('mobile')} + type='tel' + className='form-input mt-3' + /> + </div> + <div> + <label>Kata Sandi</label> + <input + {...register('password')} + type='password' + className='form-input mt-3' + placeholder='Isi jika ingin mengubah kata sandi' + /> + </div> + <button + type='submit' + className='btn-yellow w-full mt-2' + > + Simpan + </button> + </form> + )} + </> + ) +} + +export default PersonalProfile diff --git a/src/lib/auth/components/Register.jsx b/src/lib/auth/components/Register.jsx new file mode 100644 index 00000000..d02081ce --- /dev/null +++ b/src/lib/auth/components/Register.jsx @@ -0,0 +1,151 @@ +import Image from 'next/image' +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('') + const [email, setEmail] = useState('') + 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, + email, + password + } + const isRegistered = await registerApi({ data }) + 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 ( + <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'>Daftar Akun Indoteknik</h1> + <h2 className='text-gray_r-11 font-normal mt-1 mb-4 text-center'> + 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} + > + <div> + <label htmlFor='companyName'> + Nama Perusahaan <span className='text-gray_r-11'>(opsional)</span> + </label> + <input + type='text' + id='companyName' + className='form-input w-full mt-3' + value={companyName} + onChange={(e) => setCompanyName(e.target.value.toUpperCase())} + placeholder='cth: INDOTEKNIK DOTCOM GEMILANG' + autoCapitalize='true' + /> + </div> + + <div> + <label htmlFor='fullname'>Nama Lengkap</label> + <input + type='text' + id='fullname' + className='form-input w-full mt-3' + value={fullname} + onChange={(e) => setFullname(e.target.value)} + placeholder='John Doe' + /> + </div> + <div> + <label htmlFor='email'>Alamat Email</label> + <input + type='email' + id='email' + className='form-input w-full mt-3' + value={email} + onChange={(e) => setEmail(e.target.value)} + placeholder='contoh@email.com' + /> + </div> + <div> + <label htmlFor='password'>Kata Sandi</label> + <input + type='password' + id='password' + className='form-input w-full mt-3' + value={password} + onChange={(e) => setPassword(e.target.value)} + placeholder='••••••••••••' + /> + </div> + + <button + type='submit' + className='btn-yellow w-full mt-2' + disabled={!email || !password || !fullname || isLoading} + > + {!isLoading ? 'Daftar' : 'Loading...'} + </button> + </form> + + <div className='text-gray_r-11 mt-4'> + Sudah punya akun Indoteknik?{' '} + <Link + href='/login' + className='inline' + > + Masuk + </Link> + </div> + </div> + ) +} + +export default Register |
