diff options
| author | trisusilo48 <tri.susilo@altama.co.id> | 2024-09-24 09:33:10 +0700 |
|---|---|---|
| committer | trisusilo48 <tri.susilo@altama.co.id> | 2024-09-24 09:33:10 +0700 |
| commit | d4cb977d050a54b9daa1658b6de6e82878ca4c9b (patch) | |
| tree | c58569a165721c6e60aad9c1ed9fcf8f8525b6b0 /src-migrate/modules/register/components | |
| parent | 1475593324319d1faf377f2d00a22a4b3caa3faa (diff) | |
| parent | cf42512eb11b1a96c99ced8d1f867aeb8c2dcbc1 (diff) | |
Merge branch 'release' into CR/product_detail
Diffstat (limited to 'src-migrate/modules/register/components')
5 files changed, 1068 insertions, 132 deletions
diff --git a/src-migrate/modules/register/components/Form.tsx b/src-migrate/modules/register/components/Form.tsx index b834f97a..38e9c810 100644 --- a/src-migrate/modules/register/components/Form.tsx +++ b/src-migrate/modules/register/components/Form.tsx @@ -1,179 +1,169 @@ -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 TermCondition from "./TermCondition"; -import FormCaptcha from "./FormCaptcha"; -import { useRouter } from "next/router"; -import { UseToastOptions, useToast } from "@chakra-ui/react"; -import Link from "next/link"; - -const Form = () => { - const { - form, - isCheckedTNC, - isValidCaptcha, - errors, - updateForm, - validate, - } = useRegisterStore() - - const isFormValid = useMemo(() => Object.keys(errors).length === 0, [errors]) - - const router = useRouter() - const toast = useToast() +import { ChangeEvent, useMemo, useEffect, useRef, useState } from 'react'; +import { useMutation } from 'react-query'; +import { useRegisterStore } from '../stores/useRegisterStore'; +import { RegisterProps } from '~/types/auth'; +import { registerUser } from '~/services/auth'; +import TermCondition from './TermCondition'; +import FormCaptcha from './FormCaptcha'; +import { useRouter } from 'next/router'; +import { UseToastOptions, useToast } from '@chakra-ui/react'; +import Link from 'next/link'; + +interface FormProps { + type: string; + required: boolean; + isBisnisRegist: boolean; + chekValid: boolean; + buttonSubmitClick: boolean; +} + +const Form: React.FC<FormProps> = ({ + type, + required, + isBisnisRegist = false, + chekValid, + buttonSubmitClick, +}) => { + const { form, isCheckedTNC, isValidCaptcha, errors, updateForm, validate } = + useRegisterStore(); + const isFormValid = useMemo(() => Object.keys(errors).length === 0, [errors]); + + const router = useRouter(); + const toast = useToast(); + + const emailRef = useRef<HTMLInputElement>(null); + const nameRef = useRef<HTMLInputElement>(null); + const passwordRef = useRef<HTMLInputElement>(null); + const phoneRef = useRef<HTMLInputElement>(null); const handleInputChange = (event: ChangeEvent<HTMLInputElement>) => { const { name, value } = event.target; - updateForm(name, value) - 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 - } - } + updateForm(name, value); + validate(); + }; + useEffect(() => { + const loadIndustries = async () => { + if (!isFormValid) { + const options: ScrollIntoViewOptions = { + behavior: 'smooth', + block: 'center', + }; + + if (errors.email_partner && emailRef.current) { + emailRef.current.scrollIntoView(options); + return; + } + if (errors.name && nameRef.current) { + nameRef.current.scrollIntoView(options); + return; + } + + if (errors.password && passwordRef.current) { + passwordRef.current.scrollIntoView(options); + return; + } + + if (errors.phone && phoneRef.current) { + phoneRef.current.scrollIntoView(options); + return; + } + } + }; + loadIndustries(); + }, [buttonSubmitClick, chekValid]); return ( - <form className="mt-6 grid grid-cols-1 gap-y-4" onSubmit={handleSubmit}> + <form className='mt-6 grid grid-cols-1 gap-y-4'> <div> - <label htmlFor="company"> - Nama Perusahaan <span className='text-gray_r-11'>(opsional)</span> + <label htmlFor='name' className='text-black font-bold'> + Nama Lengkap </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> - - <input type='text' id='name' name='name' - className='form-input mt-3' + className='form-input mt-3 transition-all duration-700' placeholder='Masukan nama lengkap anda' value={form.name} + ref={nameRef} onChange={handleInputChange} - aria-invalid={!!errors.name} - /> - - {!!errors.name && <span className="form-msg-danger">{errors.name}</span>} - </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} + aria-invalid={chekValid && !!errors.name} /> - {!!errors.phone && <span className="form-msg-danger">{errors.phone}</span>} + {chekValid && !!errors.name && ( + <span className='form-msg-danger'>{errors.name}</span> + )} </div> <div> - <label htmlFor='email'>Alamat Email</label> + <label htmlFor='email' className='text-black font-bold'> + Alamat Email + </label> <input type='text' id='email' name='email' - className='form-input mt-3' + className='form-input mt-3 transition-all duration-500' placeholder='Masukan alamat email anda' value={form.email} + ref={emailRef} onChange={handleInputChange} - autoComplete="username" - aria-invalid={!!errors.email} + autoComplete='username' + aria-invalid={chekValid && !!errors.email} /> - {!!errors.email && <span className="form-msg-danger">{errors.email}</span>} + {chekValid && !!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' id='password' - className='form-input mt-3' + className='form-input mt-3 transition-all duration-500' placeholder='••••••••••••' value={form.password} + ref={passwordRef} onChange={handleInputChange} - autoComplete="current-password" - aria-invalid={!!errors.password} + autoComplete='current-password' + aria-invalid={chekValid && !!errors.password} /> - {!!errors.password && <span className="form-msg-danger">{errors.password}</span>} + {chekValid && !!errors.password && ( + <span className='form-msg-danger'>{errors.password}</span> + )} </div> - <FormCaptcha /> + <div> + <label htmlFor='phone' className='text-black font-bold'> + No Handphone + </label> - <TermCondition /> + <input + type='tel' + id='phone' + name='phone' + className='form-input mt-3 transition-all duration-500' + placeholder='08xxxxxxxx' + value={form.phone} + ref={phoneRef} + onChange={handleInputChange} + aria-invalid={chekValid && !!errors.phone} + /> - <button - type="submit" - className="btn-yellow w-full mt-2" - disabled={!isFormValid || !isCheckedTNC || mutation.isLoading || !isValidCaptcha} - > - {mutation.isLoading ? 'Loading...' : 'Daftar'} - </button> + {chekValid && !!errors.phone && ( + <span className='form-msg-danger'>{errors.phone}</span> + )} + </div> </form> - ) -} + ); +}; -export default Form
\ No newline at end of file +export default 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..5ee19e58 --- /dev/null +++ b/src-migrate/modules/register/components/FormBisnis.tsx @@ -0,0 +1,715 @@ +import { ChangeEvent, useEffect, useMemo, useRef, useState } 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 { + Button, + Checkbox, + UseToastOptions, + color, + useToast, +} from '@chakra-ui/react'; +import Link from 'next/link'; +import getFileBase64 from '@/core/utils/getFileBase64'; +import { Controller, useForm } from 'react-hook-form'; +import HookFormSelect from '@/core/components/elements/Select/HookFormSelect'; +import odooApi from '~/libs/odooApi'; +import { toast } from 'react-hot-toast'; +import { EyeIcon } from '@heroicons/react/24/outline'; +import BottomPopup from '@/core/components/elements/Popup/BottomPopup'; +import Image from 'next/image'; +import useDevice from '@/core/hooks/useDevice'; +interface FormProps { + type: string; + required: boolean; + isPKP: boolean; + chekValid: boolean; + buttonSubmitClick: boolean; +} + +interface industry_id { + label: string; + value: string; + category: string; +} + +interface companyType { + value: string; + label: string; +} + +const form: React.FC<FormProps> = ({ + type, + required, + isPKP, + chekValid, + buttonSubmitClick, +}) => { + const { form, errors, updateForm, validate } = useRegisterStore(); + const { control, watch, setValue } = useForm(); + const [selectedCategory, setSelectedCategory] = useState<string>(''); + const [isChekBox, setIsChekBox] = useState<boolean>(false); + const [isExample, setIsExample] = useState<boolean>(false); + const { isDesktop, isMobile } = useDevice(); + // Inside your component + const [formattedNpwp, setFormattedNpwp] = useState<string>(''); // State for formatted NPWP + const [unformattedNpwp, setUnformattedNpwp] = useState<string>(''); // State for unformatted NPWP + + const [industries, setIndustries] = useState<industry_id[]>([]); + const [companyTypes, setCompanyTypes] = useState<companyType[]>([]); + + const router = useRouter(); + const toast = useToast(); + + const emailRef = useRef<HTMLInputElement>(null); + const businessNameRef = useRef<HTMLInputElement>(null); + const companyTypeRef = useRef<HTMLInputElement>(null); + const industryRef = useRef<HTMLDivElement>(null); + const addressRef = useRef<HTMLInputElement>(null); + const namaWajibPajakRef = useRef<HTMLInputElement>(null); + const alamatWajibPajakRef = useRef<HTMLInputElement>(null); + const npwpRef = useRef<HTMLInputElement>(null); + const sppkpRef = useRef<HTMLInputElement>(null); + const docsSppkpRef = useRef<HTMLInputElement>(null); + const docsNpwpRef = useRef<HTMLInputElement>(null); + + useEffect(() => { + const loadCompanyTypes = async () => { + const dataCompanyTypes = await odooApi( + 'GET', + '/api/v1/partner/company_type' + ); + setCompanyTypes( + dataCompanyTypes?.map((o: { id: any; name: any }) => ({ + value: o.id, + label: o.name, + })) + ); + }; + loadCompanyTypes(); + }, []); + + useEffect(() => { + const selectedCompanyType = companyTypes.find( + (company) => company.value === watch('companyType') + ); + if (selectedCompanyType) { + updateForm('company_type_id', `${selectedCompanyType?.value}`); + validate(); + } + }, [watch('companyType'), companyTypes]); + + useEffect(() => { + const selectedIndustryType = industries.find( + (industry) => industry.value === watch('industry_id') + ); + if (selectedIndustryType) { + updateForm('industry_id', `${selectedIndustryType?.value}`); + setSelectedCategory(selectedIndustryType.category); + validate(); + } + }, [watch('industry_id'), industries]); + + useEffect(() => { + const loadIndustries = async () => { + const dataIndustries = await odooApi('GET', '/api/v1/partner/industry'); + setIndustries( + dataIndustries?.map((o: { id: any; name: any; category: any }) => ({ + value: o.id, + label: o.name, + category: o.category, + })) + ); + }; + loadIndustries(); + }, []); + + const handleInputChange = (event: ChangeEvent<HTMLInputElement>) => { + const { name, value } = event.target; + + updateForm('type_acc', 'business'); + updateForm('is_pkp', `${isPKP}`); + + // Update form dengan nilai terbaru dari input yang berubah + updateForm(name, value); + + // Jika checkbox aktif, sinkronisasi alamat_wajib_pajak dengan alamat_bisnis + if (isChekBox) { + if (name === 'alamat_wajib_pajak') { + updateForm('alamat_bisnis', value); + } else if (name === 'alamat_bisnis') { + updateForm('alamat_wajib_pajak', value); + } + } + + // Validasi setelah perubahan dilakukan + validate(); + }; + + const handleInputChangeNpwp = (event: ChangeEvent<HTMLInputElement>) => { + const { name, value } = event.target; + updateForm('type_acc', `business`); + updateForm('is_pkp', `${isPKP}`); + updateForm('npwp', value); + validate(); + }; + + const handleChange = (event: ChangeEvent<HTMLInputElement>) => { + setIsChekBox(!isChekBox); + }; + + const formatNpwp = (value: string) => { + try { + const cleaned = ('' + value).replace(/\D/g, ''); + let match; + if (cleaned.length <= 15) { + match = cleaned.match( + /(\d{0,2})?(\d{0,3})?(\d{0,3})?(\d{0,1})?(\d{0,3})?(\d{0,3})$/ + ); + } else { + match = cleaned.match( + /(\d{0,3})?(\d{0,3})?(\d{0,3})?(\d{0,1})?(\d{0,3})?(\d{0,3})$/ + ); + } + + if (match) { + return [ + match[1], + match[2] ? '.' : '', + match[2], + match[3] ? '.' : '', + match[3], + match[4] ? '.' : '', + match[4], + match[5] ? '-' : '', + match[5], + match[6] ? '.' : '', + match[6], + ].join(''); + } + + // If match is null, return the original cleaned string or handle as needed + return cleaned; + } catch (error) { + // Handle error or return a default value + console.error('Error formatting NPWP:', error); + return value; + } + }; + + useEffect(() => { + if (isChekBox) { + updateForm('isChekBox', 'true'); + updateForm('alamat_wajib_pajak', `${form.alamat_bisnis}`); + validate(); + } else { + updateForm('isChekBox', 'false'); + validate(); + } + }, [isChekBox]); + + const handleFileChange = async (event: ChangeEvent<HTMLInputElement>) => { + const toastProps: UseToastOptions = { + duration: 5000, + isClosable: true, + position: 'top', + }; + + let fileBase64 = ''; + const { name } = event.target; + const file = event.target.files?.[0]; + + // Allowed file extensions + const allowedExtensions = ['pdf', 'doc', 'docx', 'png', 'jpg', 'jpeg']; + + if (file) { + const fileExtension = file.name.split('.').pop()?.toLowerCase(); // Extract file extension + + // Check if the file extension is allowed + if (!fileExtension || !allowedExtensions.includes(fileExtension)) { + toast({ + ...toastProps, + title: + 'Format file yang diijinkan adalah .pdf, .doc, .docx, .png, .jpg, atau .jpeg', + status: 'error', + }); + event.target.value = ''; + return; + } + + // Check for file size + if (file.size > 5000000) { + toast({ + ...toastProps, + title: 'Maksimal ukuran file adalah 5MB', + status: 'error', + }); + event.target.value = ''; + return; + } + + // Convert file to Base64 + fileBase64 = await getFileBase64(file); + updateForm(name, fileBase64); // Update form with the Base64 string + validate(); // Perform form validation + } + }; + const isFormValid = useMemo(() => Object.keys(errors).length === 0, [errors]); + + useEffect(() => { + const loadIndustries = async () => { + if (!isFormValid) { + const options: ScrollIntoViewOptions = { + behavior: 'smooth', + block: 'center', + }; + if (errors.email_partner && emailRef.current) { + emailRef.current.scrollIntoView(options); + return; + } + if (errors.company_type_id && companyTypeRef.current) { + companyTypeRef.current.scrollIntoView(options); + return; + } + + if (errors.business_name && businessNameRef.current) { + businessNameRef.current.scrollIntoView(options); + return; + } + + if (errors.industry_id && industryRef.current) { + industryRef.current.scrollIntoView(options); + return; + } + + if (errors.alamat_bisnis && addressRef.current) { + addressRef.current.scrollIntoView(options); + return; + } + + if (errors.npwp && npwpRef.current) { + npwpRef.current.scrollIntoView(options); + return; + } + + if (errors.sppkp && sppkpRef.current) { + sppkpRef.current.scrollIntoView(options); + return; + } + if (errors.sppkp_document && docsSppkpRef.current) { + docsSppkpRef.current.scrollIntoView(options); + return; + } + if (errors.npwp_document && docsNpwpRef.current) { + docsNpwpRef.current.scrollIntoView(options); + return; + } + } + }; + loadIndustries(); + }, [buttonSubmitClick, chekValid]); + return ( + <> + <BottomPopup + className='' + title='Contoh SPPKP' + active={isExample} + close={() => setIsExample(false)} + > + <div className='flex p-2'> + <Image + src='/images/NO-SPPKP-FORMAT-TEMPLATE.jpg' + alt='Contoh SPPKP' + className='w-full h-full ' + width={800} + height={800} + quality={100} + /> + </div> + </BottomPopup> + <form + className={` ${ + type === 'bisnis' + ? 'mt-6 grid grid-cols-1 gap-y-4' + : 'mt-6 grid grid-cols-2 gap-x-4 gap-y-2' + }`} + > + <div> + <label htmlFor='email' className='font-bold'> + Email Bisnis{' '} + {!isPKP && !required && ( + <span className='font-normal text-gray_r-11'>(opsional)</span> + )} + </label> + + <input + type='text' + id='email_partner' + name='email_partner' + placeholder='example@email.com' + value={!required ? form.email_partner : ''} + className={`form-input max-h-11 mt-3 transition-all duration-500 ${ + required ? 'cursor-no-drop' : '' + }`} + disabled={required} + contentEditable={required} + readOnly={required} + onChange={handleInputChange} + autoComplete='username' + ref={emailRef} + aria-invalid={ + chekValid && !required && isPKP && !!errors.email_partner + } + /> + + {chekValid && !required && isPKP && !!errors.email_partner && ( + <span className='form-msg-danger'>{errors.email_partner}</span> + )} + </div> + + <div> + <label className='font-bold' htmlFor='company'> + Nama Bisnis + </label> + <div className='flex justify-between items-start gap-2 max-h-12 min-h-12 text-sm mt-3'> + <div + className='w-4/5 pr-1 max-h-11 transition-all duration-500' + ref={companyTypeRef} + > + <Controller + name='companyType' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={companyTypes} + disabled={required} + placeholder='Badan Usaha' + /> + )} + /> + {chekValid && !required && !!errors.company_type_id && ( + <span className='form-msg-danger'> + {errors.company_type_id} + </span> + )} + </div> + <div className='w-[120%] '> + <input + type='text' + name='business_name' + id='business_name' + className='form-input max-h-11 transition-all duration-500' + placeholder='Nama Perusahaan' + autoCapitalize='true' + value={form.business_name} + ref={businessNameRef} + aria-invalid={chekValid && !!errors.business_name} + onChange={handleInputChange} + /> + + {chekValid && !!errors.business_name && ( + <span className='form-msg-danger'>{errors.business_name}</span> + )} + </div> + </div> + </div> + + <div className='mt-8 md:mt-0'> + <label className='font-bold' htmlFor='business_name'> + Klasifikasi Jenis Usaha + </label> + <div + className='max-h-10 transition-all duration-500' + ref={industryRef} + > + <Controller + name='industry_id' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={industries} + disabled={required} + placeholder={'Select industry'} + /> + )} + /> + </div> + {selectedCategory && ( + <span className='text-gray_r-11 text-xs'> + Kategori : {selectedCategory} + </span> + )} + {chekValid && !required && !!errors.industry_id && ( + <span className='form-msg-danger'>{errors.industry_id}</span> + )} + </div> + + <div> + <label htmlFor='alamat_bisnis' className='font-bold'> + Alamat Bisnis + </label> + + <input + type='text' + id='alamat_bisnis' + name='alamat_bisnis' + placeholder='Masukan alamat bisnis anda' + value={!required ? form.alamat_bisnis : ''} + className={`form-input mt-3 max-h-11 transition-all duration-500 ${ + required ? 'cursor-no-drop' : '' + }`} + disabled={required} + contentEditable={required} + readOnly={required} + ref={addressRef} + onChange={handleInputChange} + aria-invalid={chekValid && !required && !!errors.alamat_bisnis} + /> + + {chekValid && !required && !!errors.alamat_bisnis && ( + <span className='form-msg-danger'>{errors.alamat_bisnis}</span> + )} + </div> + + <div> + <label htmlFor='nama_wajib_pajak' className='font-bold'> + Nama Wajib Pajak{' '} + {!isPKP && !required && ( + <span className='font-normal text-gray_r-11'>(opsional)</span> + )} + </label> + + <input + type='text' + id='nama_wajib_pajak' + name='nama_wajib_pajak' + placeholder='Masukan nama lengkap anda' + value={!required ? form.nama_wajib_pajak : ''} + className={`form-input mt-3 max-h-11 transition-all duration-500${ + required ? 'cursor-no-drop' : '' + }`} + disabled={required} + contentEditable={required} + readOnly={required} + onChange={handleInputChange} + ref={namaWajibPajakRef} + aria-invalid={ + chekValid && isPKP && !required && !!errors.nama_wajib_pajak + } + /> + + {chekValid && isPKP && !required && !!errors.nama_wajib_pajak && ( + <span className='form-msg-danger'>{errors.nama_wajib_pajak}</span> + )} + </div> + + <div> + <label + htmlFor='alamat_wajib_pajak' + className='font-bold flex items-center' + > + <p> + Alamat Wajib Pajak{' '} + {!isPKP && !required && ( + <span className='font-normal text-gray_r-11'>(opsional)</span> + )} + </p> + <div className='flex items-center ml-2 mt-1 '> + <Checkbox + borderColor='gray.600' + colorScheme='red' + size='md' + isChecked={isChekBox} + onChange={handleChange} + /> + <span className='text-caption-2 ml-2 font-normal italic'> + sama dengan alamat bisnis? + </span> + </div> + </label> + + <input + type='text' + id='alamat_wajib_pajak' + name='alamat_wajib_pajak' + placeholder='Masukan alamat wajib pajak anda' + value={ + !required + ? isChekBox + ? form.alamat_bisnis + : form.alamat_wajib_pajak + : '' + } + className={`form-input max-h-11 mt-3 transition-all duration-500 ${ + required ? 'cursor-no-drop' : '' + }`} + disabled={isChekBox || required} + contentEditable={required} + readOnly={required} + onChange={handleInputChange} + ref={alamatWajibPajakRef} + aria-invalid={ + chekValid && isPKP && !required && !!errors.alamat_wajib_pajak + } + /> + + {chekValid && isPKP && !required && !!errors.alamat_wajib_pajak && ( + <span className='form-msg-danger'>{errors.alamat_wajib_pajak}</span> + )} + </div> + + <div> + <label htmlFor='npwp' className='font-bold'> + Nomor NPWP{' '} + {!isPKP && !required && ( + <span className='font-normal text-gray_r-11'>(opsional)</span> + )} + </label> + + <input + type='tel' + id='npwp' + name='npwp' + className={`form-input max-h-11 mt-3 transition-all duration-500 ${ + required ? 'cursor-no-drop' : '' + }`} + disabled={required} + contentEditable={required} + readOnly={required} + ref={npwpRef} + placeholder='000.000.000.0-000.000' + value={!required ? formattedNpwp : ''} + maxLength={21} // Set maximum length to 16 characters + onChange={(e) => { + if (!required) { + const unformatted = e.target.value.replace(/\D/g, ''); // Remove all non-digit characters + const formattedValue = formatNpwp(unformatted); // Format the value + setUnformattedNpwp(unformatted); // Store unformatted value + setFormattedNpwp(formattedValue); // Store formatted value + handleInputChangeNpwp({ + ...e, + target: { ...e.target, value: unformatted }, + }); // Update form state with unformatted value + } + }} + aria-invalid={chekValid && !required && !!errors.npwp} + /> + + {chekValid && !required && !!errors.npwp && ( + <span className='form-msg-danger'>{errors.npwp}</span> + )} + </div> + + <div> + <label + htmlFor='sppkp' + className='font-bold flex flex-row items-center justify-between' + > + <div className='flex flex-row items-center'> + Nomor SPPKP{' '} + {!required && ( + <span className='ml-2 font-normal text-gray_r-11'> + (opsional){' '} + </span> + )} + </div> + { + <div + onClick={() => setIsExample(!isExample)} + className='rounded text-white p-2 flex flex-row bg-red-500 hover:cursor-pointer hover:bg-red-400' + > + <EyeIcon className={`w-4 ${isDesktop && 'mr-2'}`} /> + {isDesktop && ( + <p className='font-light text-xs'>Lihat Contoh</p> + )} + </div> + } + </label> + + <input + type='tel' + id='sppkp' + name='sppkp' + className={`form-input max-h-11 mt-3 transition-all duration-500 ${ + required ? 'cursor-no-drop' : '' + }`} + disabled={required} + contentEditable={required} + readOnly={required} + ref={sppkpRef} + placeholder='X-XXXPKP/WJPXXX/XX.XXXX/XXXX' + onChange={handleInputChange} + value={!required ? form.sppkp : ''} + aria-invalid={chekValid && !required && !!errors.sppkp} + /> + + {chekValid && !required && !!errors.sppkp && ( + <span className='form-msg-danger'>{errors.sppkp}</span> + )} + </div> + + <div> + <label htmlFor='npwp_document' className='font-bold'> + Dokumen NPWP{' '} + {!isPKP && !required && ( + <span className='font-normal text-gray_r-11'>(opsional)</span> + )} + </label> + + <input + type='file' + id='npwp_document' + name='npwp_document' + className={`form-input transition-all duration-500 ${ + type === 'bisnis' ? '' : 'border-none' + } mt-3 ${required ? 'cursor-no-drop' : ''}`} + disabled={required} + contentEditable={required} + ref={docsNpwpRef} + readOnly={required} + onChange={handleFileChange} + accept='.pdf,.doc,.docx,.png,.jpg,.jpeg' // Filter file types + /> + + {chekValid && isPKP && !required && !!errors.npwp_document && ( + <span className='form-msg-danger'>{errors.npwp_document}</span> + )} + </div> + + <div> + <label htmlFor='sppkp_document' className='font-bold'> + Dokumen SPPKP{' '} + {!isPKP && !required && ( + <span className='font-normal text-gray_r-11'>(opsional)</span> + )} + </label> + + <input + type='file' + id='sppkp_document' + name='sppkp_document' + className={`form-input transition-all duration-500 ${ + type === 'bisnis' ? '' : 'border-none' + } mt-3 ${required ? 'cursor-no-drop' : ''}`} + disabled={required} + contentEditable={required} + ref={docsSppkpRef} + readOnly={required} + onChange={handleFileChange} + accept='.pdf,.doc,.docx,.png,.jpg,.jpeg' // Filter file types + /> + + {chekValid && isPKP && !required && !!errors.sppkp_document && ( + <span className='form-msg-danger'>{errors.sppkp_document}</span> + )} + </div> + </form> + </> + ); +}; + +export default form; diff --git a/src-migrate/modules/register/components/RegistrasiBisnis.tsx b/src-migrate/modules/register/components/RegistrasiBisnis.tsx new file mode 100644 index 00000000..ce4d3972 --- /dev/null +++ b/src-migrate/modules/register/components/RegistrasiBisnis.tsx @@ -0,0 +1,197 @@ +import { ChangeEvent, useEffect, useMemo, useState } from 'react'; +import FormBisnis from './FormBisnis'; +import Form from './Form'; +import TermCondition from './TermCondition'; +import FormCaptcha from './FormCaptcha'; +import { Radio, RadioGroup, Stack, Divider, Button } from '@chakra-ui/react'; +import React from 'react'; +import { ChevronDownIcon, ChevronRightIcon } from '@heroicons/react/24/outline'; +import { useRegisterStore } from '../stores/useRegisterStore'; +import { useMutation } from 'react-query'; +import { RegisterProps } from '~/types/auth'; +import { registerUser } from '~/services/auth'; +import router from 'next/router'; +import { useRouter } from 'next/router'; +import { UseToastOptions, useToast } from '@chakra-ui/react'; +import Link from 'next/link'; +interface FormProps { + chekValid: boolean; + buttonSubmitClick: boolean; +} +const RegistrasiBisnis: React.FC<FormProps> = ({ + chekValid, + buttonSubmitClick, +}) => { + const [isPKP, setIsPKP] = useState(true); + const [isTerdaftar, setIsTerdaftar] = useState(false); + const [isDropIndividu, setIsDropIndividu] = useState(true); + const [isBisnisClicked, setisBisnisClicked] = useState(true); + const [selectedValue, setSelectedValue] = useState('PKP'); + const [selectedValueBisnis, setSelectedValueBisnis] = useState('false'); + const { form, isCheckedTNC, isValidCaptcha, errors, validate, updateForm } = + useRegisterStore(); + const isFormValid = useMemo(() => Object.keys(errors).length === 0, [errors]); + const toast = useToast(); + const mutation = useMutation({ + mutationFn: (data: RegisterProps) => registerUser(data), + }); + + useEffect(() => { + if (selectedValue === 'PKP') { + updateForm('is_pkp', 'true'); + validate(); + } else { + updateForm('is_pkp', 'false'); + validate(); + } + }, [selectedValue]); + + useEffect(() => { + if (isTerdaftar) { + updateForm('is_terdaftar', 'true'); + validate(); + } else { + updateForm('is_terdaftar', 'false'); + validate(); + } + }, [isTerdaftar]); + + const handleChange = (value: string) => { + setSelectedValue(value); + if (value === 'PKP') { + validate(); + setIsPKP(true); + } else { + validate(); + setIsPKP(false); + setIsPKP(false); + } + }; + + const handleChangeBisnis = (value: string) => { + setSelectedValueBisnis(value); + if (value === 'true') { + validate(); + setIsTerdaftar(true); + } else { + validate(); + setIsTerdaftar(false); + } + }; + + const handleClick = () => { + setIsDropIndividu(!isDropIndividu); + }; + + const handleClickBisnis = () => { + setisBisnisClicked(!isBisnisClicked); + }; + + return ( + <> + <div className='mt-4 border'> + <div className='p-4'> + <div onClick={handleClick} className='flex justify-between'> + <p className='text-2xl font-semibold text-center md:text-left'> + Data Akun + </p> + {isDropIndividu ? ( + <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> + {isDropIndividu && ( + <div> + <Divider my={4} /> + <Form + type='bisnis' + required={true} + isBisnisRegist={true} + chekValid={chekValid} + buttonSubmitClick={buttonSubmitClick} + /> + </div> + )} + </div> + </div> + <div className='mt-4 border'> + <div className='p-4'> + <div onClick={handleClickBisnis} className='flex justify-between'> + <p className='text-2xl font-semibold text-center md:text-left'> + Data Bisnis + </p> + {isBisnisClicked ? ( + <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> + {isBisnisClicked && ( + <div> + <Divider my={4} /> + <div> + <p className='text-black font-bold mb-2'> + Bisnis Terdaftar di Indoteknik? + </p> + <RadioGroup + onChange={handleChangeBisnis} + value={selectedValueBisnis} + > + <Stack direction='row'> + <Radio colorScheme='red' value='true'> + Sudah Terdaftar + </Radio> + <Radio colorScheme='red' value='false' className='ml-2'> + Belum Terdaftar + </Radio> + </Stack> + </RadioGroup> + </div> + <div className='mt-4'> + <p className='text-black font-bold mb-2'>Tipe Bisnis</p> + <RadioGroup onChange={handleChange} value={selectedValue}> + <Stack direction='row' className='font-bold'> + <Radio colorScheme='red' value='PKP'> + PKP + </Radio> + <Radio colorScheme='red' value='Non-PKP' className='ml-4'> + Non-PKP + </Radio> + </Stack> + </RadioGroup> + </div> + <FormBisnis + type='bisnis' + required={isTerdaftar} + isPKP={isPKP} + chekValid={chekValid} + buttonSubmitClick={buttonSubmitClick} + /> + </div> + )} + </div> + </div> + + <h1 className=''></h1> + </> + ); +}; + +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..84049065 --- /dev/null +++ b/src-migrate/modules/register/components/RegistrasiIndividu.tsx @@ -0,0 +1,34 @@ +import Form from './Form'; +import { useRegisterStore } from '../stores/useRegisterStore'; +import { useEffect } from 'react'; +interface FormProps { + chekValid: boolean; + buttonSubmitClick: boolean; +} +const RegistrasiIndividu: React.FC<FormProps> = ({ + chekValid, + buttonSubmitClick, +}) => { + const { form, errors, updateForm, validate } = useRegisterStore(); + + useEffect(() => { + updateForm('is_pkp', 'false'); + updateForm('is_terdaftar', 'false'); + updateForm('type_acc', 'individu'); + validate(); + }, []); + + return ( + <> + <Form + type='individu' + required={false} + isBisnisRegist={false} + chekValid={chekValid} + buttonSubmitClick={buttonSubmitClick} + /> + </> + ); +}; + +export default RegistrasiIndividu; diff --git a/src-migrate/modules/register/components/TermCondition.tsx b/src-migrate/modules/register/components/TermCondition.tsx index b7729deb..d54fe921 100644 --- a/src-migrate/modules/register/components/TermCondition.tsx +++ b/src-migrate/modules/register/components/TermCondition.tsx @@ -10,7 +10,7 @@ const TermCondition = () => { return ( <> <div className="mt-4 flex items-center gap-x-2"> - <Checkbox id='tnc' name='tnc' isChecked={isCheckedTNC} onChange={toggleCheckTNC} /> + <Checkbox id='tnc' name='tnc' colorScheme='red' isChecked={isCheckedTNC} onChange={toggleCheckTNC} /> <div> <label htmlFor="tnc" className="cursor-pointer">Dengan ini saya menyetujui</label> {' '} |
