summaryrefslogtreecommitdiff
path: root/src/lib/auth
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/auth')
-rw-r--r--src/lib/auth/api/editPersonalProfileApi.js10
-rw-r--r--src/lib/auth/api/loginApi.js8
-rw-r--r--src/lib/auth/api/registerApi.js8
-rw-r--r--src/lib/auth/components/Activate.jsx166
-rw-r--r--src/lib/auth/components/CompanyProfile.jsx158
-rw-r--r--src/lib/auth/components/IsAuth.jsx20
-rw-r--r--src/lib/auth/components/Login.jsx125
-rw-r--r--src/lib/auth/components/PersonalProfile.jsx118
-rw-r--r--src/lib/auth/components/Register.jsx151
9 files changed, 764 insertions, 0 deletions
diff --git a/src/lib/auth/api/editPersonalProfileApi.js b/src/lib/auth/api/editPersonalProfileApi.js
new file mode 100644
index 00000000..39cd44c1
--- /dev/null
+++ b/src/lib/auth/api/editPersonalProfileApi.js
@@ -0,0 +1,10 @@
+import odooApi from '@/core/api/odooApi'
+import { getAuth } from '@/core/utils/auth'
+
+const editPersonalProfileApi = async ({ data }) => {
+ const auth = getAuth()
+ const dataProfile = await odooApi('PUT', `/api/v1/user/${auth.id}`, data)
+ return dataProfile
+}
+
+export default editPersonalProfileApi
diff --git a/src/lib/auth/api/loginApi.js b/src/lib/auth/api/loginApi.js
new file mode 100644
index 00000000..e393309c
--- /dev/null
+++ b/src/lib/auth/api/loginApi.js
@@ -0,0 +1,8 @@
+import odooApi from '@/core/api/odooApi'
+
+const loginApi = async ({ email, password }) => {
+ let result = await odooApi('POST', '/api/v1/user/login', { email, password })
+ return result
+}
+
+export default loginApi
diff --git a/src/lib/auth/api/registerApi.js b/src/lib/auth/api/registerApi.js
new file mode 100644
index 00000000..f3d75ce8
--- /dev/null
+++ b/src/lib/auth/api/registerApi.js
@@ -0,0 +1,8 @@
+import odooApi from '@/core/api/odooApi'
+
+const registerApi = async ({ data }) => {
+ const dataRegister = await odooApi('POST', '/api/v1/user/register', data)
+ return dataRegister
+}
+
+export default registerApi
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