diff options
Diffstat (limited to 'src-migrate')
6 files changed, 481 insertions, 81 deletions
diff --git a/src-migrate/modules/register/components/Form.tsx b/src-migrate/modules/register/components/Form.tsx index b834f97a..7d18f4ee 100644 --- a/src-migrate/modules/register/components/Form.tsx +++ b/src-migrate/modules/register/components/Form.tsx @@ -9,7 +9,12 @@ import { useRouter } from "next/router"; import { UseToastOptions, useToast } from "@chakra-ui/react"; import Link from "next/link"; -const Form = () => { +interface FormProps { + type: string; + required: boolean; +} + +const Form: React.FC<FormProps> = ({ type, required }) => { const { form, isCheckedTNC, @@ -75,25 +80,9 @@ const Form = () => { return ( <form className="mt-6 grid grid-cols-1 gap-y-4" onSubmit={handleSubmit}> - <div> - <label htmlFor="company"> - Nama Perusahaan <span className='text-gray_r-11'>(opsional)</span> - </label> - - <input - type="text" - name="company" - id="company" - className="form-input mt-3" - placeholder="cth: INDOTEKNIK DOTCOM GEMILANG" - autoCapitalize="true" - value={form.company} - onChange={handleInputChange} - /> - </div> <div> - <label htmlFor='name'>Nama Lengkap</label> + <label htmlFor='name' className="text-black font-bold">Nama Lengkap</label> <input type='text' @@ -110,24 +99,7 @@ const Form = () => { </div> <div> - <label htmlFor='phone'>No Handphone</label> - - <input - type='tel' - id='phone' - name='phone' - className='form-input mt-3' - placeholder='08xxxxxxxx' - value={form.phone} - onChange={handleInputChange} - aria-invalid={!!errors.phone} - /> - - {!!errors.phone && <span className="form-msg-danger">{errors.phone}</span>} - </div> - - <div> - <label htmlFor='email'>Alamat Email</label> + <label htmlFor='email' className="text-black font-bold">Alamat Email</label> <input type='text' @@ -143,9 +115,9 @@ const Form = () => { {!!errors.email && <span className="form-msg-danger">{errors.email}</span>} </div> - + <div> - <label htmlFor='password'>Kata Sandi</label> + <label htmlFor='password' className="text-black font-bold">Kata Sandi</label> <input type='password' name='password' @@ -161,17 +133,40 @@ const Form = () => { {!!errors.password && <span className="form-msg-danger">{errors.password}</span>} </div> - <FormCaptcha /> + <div> + <label htmlFor='phone' className="text-black font-bold">No Handphone</label> + + <input + type='tel' + id='phone' + name='phone' + className='form-input mt-3' + placeholder='08xxxxxxxx' + value={form.phone} + onChange={handleInputChange} + aria-invalid={!!errors.phone} + /> + + {!!errors.phone && <span className="form-msg-danger">{errors.phone}</span>} + </div> + + {type==='individu' && ( + <> + <FormCaptcha /> + + <TermCondition /> + <button + type="submit" + className="btn-yellow w-full mt-2" + disabled={!isFormValid || !isCheckedTNC || mutation.isLoading || !isValidCaptcha} + > + {mutation.isLoading ? 'Loading...' : 'Daftar'} + </button> + </> + + )} - <TermCondition /> - <button - type="submit" - className="btn-yellow w-full mt-2" - disabled={!isFormValid || !isCheckedTNC || mutation.isLoading || !isValidCaptcha} - > - {mutation.isLoading ? 'Loading...' : 'Daftar'} - </button> </form> ) } diff --git a/src-migrate/modules/register/components/FormBisnis.tsx b/src-migrate/modules/register/components/FormBisnis.tsx new file mode 100644 index 00000000..85e37875 --- /dev/null +++ b/src-migrate/modules/register/components/FormBisnis.tsx @@ -0,0 +1,230 @@ +import { ChangeEvent, useMemo } from "react"; +import { useMutation } from "react-query"; +import { useRegisterStore } from "../stores/useRegisterStore"; +import { RegisterProps } from "~/types/auth"; +import { registerUser } from "~/services/auth"; +import { useRouter } from "next/router"; +import { UseToastOptions, useToast } from "@chakra-ui/react"; +import Link from "next/link"; +import getFileBase64 from '@/core/utils/getFileBase64' + +interface FormProps { + type: string; + required: boolean; +} + +const Form: React.FC<FormProps> = ({ type, required }) => { + const { + form, + isCheckedTNC, + isValidCaptcha, + errors, + updateForm, + validate, + } = useRegisterStore() + + const isFormValid = useMemo(() => Object.keys(errors).length === 0, [errors]) + + const router = useRouter() + const toast = useToast() + + const handleInputChange = (event: ChangeEvent<HTMLInputElement>) => { + const { name, value } = event.target; + updateForm(name, value) + validate() + } + + const handleFileChange = async (event: ChangeEvent<HTMLInputElement>) => { + let fileBase64 = '' + const file = event.target.files?.[0]; + if (file) { + if (typeof file !== 'undefined') { + if (file.size > 5000000) { + // toast.error('Maksimal ukuran file adalah 5MB') + return + } + fileBase64 = await getFileBase64(file) + } + updateForm("document", fileBase64); // Menyimpan file ke dalam form state + validate(); + } + } + + const mutation = useMutation({ + mutationFn: (data: RegisterProps) => registerUser(data) + }) + + const handleSubmit = async (e: ChangeEvent<HTMLFormElement>) => { + e.preventDefault() + + const response = await mutation.mutateAsync(form) + + if (response?.register === true) { + const urlParams = new URLSearchParams({ + activation: 'otp', + email: form.email, + redirect: (router.query?.next || '/') as string + }) + router.push(`${router.route}?${urlParams}`) + } + + const toastProps: UseToastOptions = { + duration: 5000, + isClosable: true + } + + switch (response?.reason) { + case 'EMAIL_USED': + toast({ + ...toastProps, + title: 'Email sudah digunakan', + status: 'warning' + }) + break; + case 'NOT_ACTIVE': + const activationUrl = `${router.route}?activation=email` + toast({ + ...toastProps, + title: 'Akun belum aktif', + description: <>Akun sudah terdaftar namun belum aktif. <Link href={activationUrl} className="underline">Klik untuk aktivasi akun</Link></>, + status: 'warning' + }) + break + } + } + + + return ( + <form className="mt-6 grid grid-cols-1 gap-y-4" onSubmit={handleSubmit}> + <div> + <label htmlFor='email'>Email Bisnis</label> + + <input + type='text' + id='email' + name='email' + className='form-input mt-3' + placeholder='example@email.com' + value={form.email} + onChange={handleInputChange} + autoComplete="username" + aria-invalid={!!errors.email} + /> + + {!!errors.email && <span className="form-msg-danger">{errors.email}</span>} + </div> + + <div> + <label htmlFor="company"> + Nama Bisnis <span className='text-gray_r-11'>(opsional)</span> + </label> + <div className="flex justify-between items-center gap-2 h-12"> + <select + className="w-3/4 border h-full rounded-sm" + > + <option value=''>Pilih Site</option> + </select> + + <input + type="text" + name="company" + id="company" + className="form-input h-full w-[120%]" + placeholder="Nama Perusahaan" + autoCapitalize="true" + value={form.company} + onChange={handleInputChange} + /> + </div> + </div> + + <div> + <label htmlFor="company"> + Klasifikasi Jenis Usaha <span className='text-gray_r-11'>(opsional)</span> + </label> + <div className="flex justify-between flex-col items-center h-12"> + <select + className="w-full border h-full rounded-sm" + > + <option value=''>After Market Auto Shop</option> + </select> + </div> + <span className='text-gray_r-11 text-xs'>Kategori: Industri Otomotif, Bengkel, Car Wash</span> + </div> + + <div> + <label htmlFor='name'>Nama Wajib Pajak</label> + + <input + type='text' + id='name' + name='name' + className='form-input mt-3' + placeholder='Masukan nama lengkap anda' + value={form.name} + onChange={handleInputChange} + aria-invalid={!!errors.name} + /> + + {!!errors.name && <span className="form-msg-danger">{errors.name}</span>} + </div> + + <div> + <label htmlFor='phone'>Nomor NPWP</label> + + <input + type='tel' + id='phone' + name='phone' + className='form-input mt-3' + placeholder='08xxxxxxxx' + value={form.phone} + onChange={handleInputChange} + aria-invalid={!!errors.phone} + /> + + {!!errors.phone && <span className="form-msg-danger">{errors.phone}</span>} + </div> + + <div> + <label htmlFor="document">Dokumen NPWP (opsional)</label> + + <input + type="file" + id="document" + name="document" + className="form-input mt-3" + onChange={handleFileChange} + accept=".pdf,.doc,.docx,.png,.jpg,.jpeg" // Filter file types + /> + + {/* {!!errors.document && <span className="form-msg-danger">{errors.document}</span>} */} + </div> + + <div> + <label htmlFor="document">Dokumen SPPKP (opsional)</label> + + <input + type="file" + id="document" + name="document" + className="form-input mt-3" + onChange={handleFileChange} + accept=".pdf,.doc,.docx,.png,.jpg,.jpeg" // Filter file types + /> + + {/* {!!errors.document && <span className="form-msg-danger">{errors.document}</span>} */} + </div> + + <button + type="submit" + className="btn-yellow w-full mt-2" + disabled={!isFormValid || !isCheckedTNC || mutation.isLoading || !isValidCaptcha} + > + {mutation.isLoading ? 'Loading...' : 'Daftar'} + </button> + </form> + ) +} + +export default Form
\ No newline at end of file diff --git a/src-migrate/modules/register/components/RegistrasiBisnis.tsx b/src-migrate/modules/register/components/RegistrasiBisnis.tsx new file mode 100644 index 00000000..217b4c79 --- /dev/null +++ b/src-migrate/modules/register/components/RegistrasiBisnis.tsx @@ -0,0 +1,105 @@ +import { useState } from "react"; +import FormBisnis from "./FormBisnis"; +import Form from "./Form"; +import TermCondition from "./TermCondition"; +import FormCaptcha from "./FormCaptcha"; +import { Radio, RadioGroup, Stack, Divider } from '@chakra-ui/react' +import React from "react"; +import { + ChevronDownIcon, + ChevronRightIcon +} from '@heroicons/react/24/outline'; + +const RegistrasiBisnis = () => { + const [isPKP, setIsPKP] = useState(false); + const [isTerdaftar, setIsTerdaftar] = useState(false); + const [isIndividuRequired, setIsIndividuRequired] = useState(true); + const [isBisnisRequired, setIsBisnisRequired] = useState(true); + const [selectedValue, setSelectedValue] = useState('PKP'); + + const handleChange = (value: string) => { + setSelectedValue(value); + if (value === "PKP") { + setIsPKP(true); + setIsIndividuRequired(true); // Show and require Individu form + } else { + setIsPKP(false); + setIsIndividuRequired(false); // Hide and make optional the Individu form + } + }; + + const handleClick = () => { + setIsIndividuRequired(!isIndividuRequired) + }; + + const handleClickBisnis = () => { + setIsBisnisRequired(!isBisnisRequired) + }; + + return ( + <> + <div> + <p className="text-black font-bold">Tipe Bisnis</p> + <RadioGroup onChange={handleChange} value={selectedValue}> + <Stack direction='row'> + <Radio value='PKP'>PKP</Radio> + <Radio value='Non-PKP'>Non-PKP</Radio> + </Stack> + </RadioGroup> + </div> + <div className="mt-4 border"> + <div className="p-4"> + <div onClick={handleClick} className="flex justify-between"> + <p>Data Akun</p> + {isIndividuRequired ? ( + <div className="flex"> + <ChevronDownIcon onClick={handleClick} className='h-6 w-6 text-black' /> + </div> + ) : ( + <ChevronRightIcon onClick={handleClick} className='h-6 w-6 text-black' /> + )} + </div> + {isIndividuRequired && ( + <div> + <Divider my={4} /> + <Form type="bisnis" required={isIndividuRequired} /> + </div> + )} + </div> + </div> + <div className="mt-4 border"> + <div className="p-4"> + <div onClick={handleClickBisnis} className="flex justify-between"> + <p>Data Bisnis</p> + {isBisnisRequired ? ( + <div className="flex"> + <ChevronDownIcon onClick={handleClickBisnis} className='h-6 w-6 text-black' /> + </div> + ) : ( + <ChevronRightIcon onClick={handleClickBisnis} className='h-6 w-6 text-black' /> + )} + </div> + {isBisnisRequired && ( + <div> + <Divider my={4} /> + <div> + <p className="text-black font-bold">Bisnis Terdaftar di Indoteknik?</p> + <RadioGroup onChange={handleChange} value={selectedValue}> + <Stack direction='row'> + <Radio value='true'>Sudah Terdaftar</Radio> + <Radio value='false'>Belum Terdaftar</Radio> + </Stack> + </RadioGroup> + </div> + <FormBisnis type="bisnis" required={isIndividuRequired} /> + </div> + )} + </div> + </div> + <FormCaptcha /> + <TermCondition /> + </> + ); +}; + +export default RegistrasiBisnis; diff --git a/src-migrate/modules/register/components/RegistrasiIndividu.tsx b/src-migrate/modules/register/components/RegistrasiIndividu.tsx new file mode 100644 index 00000000..eff86124 --- /dev/null +++ b/src-migrate/modules/register/components/RegistrasiIndividu.tsx @@ -0,0 +1,11 @@ +import Form from "./Form"; +const RegistrasiIndividu = () => { + + return ( + <> + <Form type='individu' required={false}/> + </> + ); +}; + +export default RegistrasiIndividu; diff --git a/src-migrate/modules/register/index.tsx b/src-migrate/modules/register/index.tsx index 00931284..9b3f5509 100644 --- a/src-migrate/modules/register/index.tsx +++ b/src-migrate/modules/register/index.tsx @@ -1,43 +1,101 @@ -import PageContent from "~/modules/page-content" -import Form from "./components/Form" -import Link from "next/link" -import Image from "next/image" -import IndoteknikLogo from "~/images/logo.png" -import AccountActivation from "../account-activation" +import PageContent from "~/modules/page-content"; +import Form from "./components/Form"; +import RegistrasiIndividu from "./components/RegistrasiIndividu"; +import RegistrasiBisnis from "./components/RegistrasiBisnis"; +import FormBisnis from "./components/FormBisnis"; +import Link from "next/link"; +import Image from "next/image"; +import IndoteknikLogo from "~/images/logo.png"; +import AccountActivation from "../account-activation"; +import { useState } from "react"; const LOGO_WIDTH = 150; const LOGO_HEIGHT = LOGO_WIDTH / 3; const Register = () => { + const [isIndividuClicked, setIsIndividuClicked] = useState(true); + const [isBisnisClicked, setIsBisnisClicked] = useState(false); + + const handleIndividuClick = () => { + setIsIndividuClicked(true); + setIsBisnisClicked(false); + }; + + const handleBisnisClick = () => { + setIsIndividuClicked(false); + setIsBisnisClicked(true); + }; + return ( <div className="container"> - <div className="grid grid-cols-1 md:grid-cols-2 gap-x-10 pt-10 px-2 md:pt-16"> - <section> - <Link href='/' className="block md:hidden"> - <Image src={IndoteknikLogo} alt='Logo Indoteknik' width={LOGO_WIDTH} height={LOGO_HEIGHT} className="mx-auto mb-4 w-auto h-auto" priority /> - </Link> - - <h1 className="text-2xl font-semibold text-center md:text-left"> - Daftar Akun Indoteknik - </h1> - <h2 className="text-gray_r-11 mt-1 mb-10 text-center md:text-left"> - Buat akun sekarang lebih mudah dan terverifikasi - </h2> - - <Form /> - - <div className='text-gray_r-11 mt-4 text-center md:text-left'> - Sudah punya akun Indoteknik?{' '} - <Link href='/login' className='inline font-medium text-danger-500'> - Masuk + <div className="grid grid-cols-1 md:grid-cols-2 gap-x-8 pt-10 px-2 md:pt-16"> + <section className="border"> + <div className="px-8 py-4"> + <Link href="/" className="block md:hidden"> + <Image + src={IndoteknikLogo} + alt="Logo Indoteknik" + width={LOGO_WIDTH} + height={LOGO_HEIGHT} + className="mx-auto mb-4 w-auto h-auto" + priority + /> </Link> - </div> - <div className='text-gray_r-11 mt-4 text-center md:text-left'> - Akun anda belum aktif?{' '} - <Link href='/register?activation=email' className='inline font-medium text-danger-500'> - Aktivasi - </Link> + <h1 className="text-2xl font-semibold text-center md:text-left"> + Daftar Akun Indoteknik + </h1> + <h2 className="text-gray_r-11 mt-1 mb-10 text-center md:text-left"> + Buat akun sekarang lebih mudah dan terverifikasi + </h2> + + <label htmlFor="name" className="text-black font-bold"> + Tipe Akun + </label> + <div className="grid grid-cols-2 gap-x-3 h-10 font-bold text-black hover:cursor-pointer"> + <div + className={` border rounded-md flex justify-center items-center transition-colors duration-300 ease-in-out ${ + isIndividuClicked ? "bg-red-500 text-white" : "" + }`} + onClick={handleIndividuClick} + > + <p>Individu</p> + </div> + <div + className={` border rounded-md flex justify-center items-center transition-colors duration-300 ease-in-out ${ + isBisnisClicked ? "bg-red-500 text-white" : "" + }`} + onClick={handleBisnisClick} + > + <p>Bisnis</p> + </div> + </div> + <div className="transition-opacity duration-300 ease-in-out"> + {isIndividuClicked && ( + <div className="opacity-100"> + <RegistrasiIndividu /> + </div> + )} + {isBisnisClicked && ( + <div className="opacity-100"> + <RegistrasiBisnis /> + </div> + )} + </div> + <section className="flex justify-center items-center flex-col"> + <div className="text-gray_r-11 mt-4 text-center md:text-left"> + Sudah punya akun Indoteknik?{" "} + <Link href="/login" className="inline font-medium text-danger-500"> + Masuk + </Link> + </div> + <div className="text-gray_r-11 mt-4 text-center md:text-left"> + Akun anda belum aktif?{" "} + <Link href="/register?activation=email" className="inline font-medium text-danger-500"> + Aktivasi + </Link> + </div> + </section> </div> </section> @@ -48,7 +106,7 @@ const Register = () => { <AccountActivation /> </div> - ) -} + ); +}; -export default Register
\ No newline at end of file +export default Register; diff --git a/src-migrate/modules/register/stores/useRegisterStore.ts b/src-migrate/modules/register/stores/useRegisterStore.ts index d8abf52b..1438ccc2 100644 --- a/src-migrate/modules/register/stores/useRegisterStore.ts +++ b/src-migrate/modules/register/stores/useRegisterStore.ts @@ -29,6 +29,7 @@ export const useRegisterStore = create<State & Action>((set, get) => ({ email: '', password: '', phone: '', + document: File, }, updateForm: (name, value) => set((state) => ({ form: { ...state.form, [name]: value } })), |
