summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--public/images/NO-SPPKP-FORMAT-TEMPLATE.jpgbin0 -> 131466 bytes
-rw-r--r--src-migrate/modules/register/components/Form.tsx252
-rw-r--r--src-migrate/modules/register/components/FormBisnis.tsx715
-rw-r--r--src-migrate/modules/register/components/RegistrasiBisnis.tsx197
-rw-r--r--src-migrate/modules/register/components/RegistrasiIndividu.tsx34
-rw-r--r--src-migrate/modules/register/components/TermCondition.tsx2
-rw-r--r--src-migrate/modules/register/index.tsx232
-rw-r--r--src-migrate/modules/register/stores/useRegisterStore.ts43
-rw-r--r--src-migrate/types/auth.ts1
-rw-r--r--src-migrate/validations/auth.ts158
-rw-r--r--src/core/components/elements/Navbar/NavbarDesktop.jsx8
-rw-r--r--src/core/components/elements/Navbar/NavbarUserDropdown.jsx31
-rw-r--r--src/core/components/layouts/AppLayout.jsx16
-rw-r--r--src/lib/address/components/Addresses.jsx140
-rw-r--r--src/lib/address/components/CreateAddress.jsx205
-rw-r--r--src/lib/address/components/EditAddress.jsx420
-rw-r--r--src/lib/auth/components/CompanyProfile.jsx260
-rw-r--r--src/lib/checkout/components/Checkout.jsx3
-rw-r--r--src/lib/home/components/PreferredBrand.jsx10
-rw-r--r--src/lib/home/components/PromotionProgram.jsx2
-rw-r--r--src/lib/product/api/productSimilarApi.js2
-rw-r--r--src/pages/api/activation-request.js26
-rw-r--r--src/pages/api/shop/brands.js2
-rw-r--r--src/pages/api/shop/finish-checkout.js84
-rw-r--r--src/pages/index.jsx20
-rw-r--r--src/pages/login.jsx12
-rw-r--r--src/pages/my/address/[id]/edit.jsx29
-rw-r--r--src/styles/globals.css4
-rw-r--r--tsconfig.json18
29 files changed, 2279 insertions, 647 deletions
diff --git a/public/images/NO-SPPKP-FORMAT-TEMPLATE.jpg b/public/images/NO-SPPKP-FORMAT-TEMPLATE.jpg
new file mode 100644
index 00000000..63001bb5
--- /dev/null
+++ b/public/images/NO-SPPKP-FORMAT-TEMPLATE.jpg
Binary files differ
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>
{' '}
diff --git a/src-migrate/modules/register/index.tsx b/src-migrate/modules/register/index.tsx
index 00931284..da41fd8b 100644
--- a/src-migrate/modules/register/index.tsx
+++ b/src-migrate/modules/register/index.tsx
@@ -1,54 +1,212 @@
-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 RegistrasiIndividu from './components/RegistrasiIndividu';
+import RegistrasiBisnis from './components/RegistrasiBisnis';
+import Link from 'next/link';
+import Image from 'next/image';
+import IndoteknikLogo from '~/images/logo.png';
+import AccountActivation from '../account-activation';
+import { useMemo, useState } from 'react';
+import { useRegisterStore } from './stores/useRegisterStore';
+import FormCaptcha from './components/FormCaptcha';
+import TermCondition from './components/TermCondition';
+import { Button } from '@chakra-ui/react';
+import { useMutation } from 'react-query';
+import { UseToastOptions, useToast } from '@chakra-ui/react';
+import { RegisterProps } from '~/types/auth';
+import { registerUser } from '~/services/auth';
+import { useRouter } from 'next/router';
const LOGO_WIDTH = 150;
const LOGO_HEIGHT = LOGO_WIDTH / 3;
const Register = () => {
+ const [isIndividuClicked, setIsIndividuClicked] = useState(true);
+ const [notValid, setNotValid] = useState(false);
+ const [buttonSubmitClick, setButtonSubmitClick] = useState(false);
+ const [isBisnisClicked, setIsBisnisClicked] = useState(false);
+ const { form, isCheckedTNC, isValidCaptcha, resetForm, errors, updateForm } =
+ useRegisterStore();
+
+ const isFormValid = useMemo(() => Object.keys(errors).length === 0, [errors]);
+ const toast = useToast();
+ const router = useRouter();
+ const mutation = useMutation({
+ mutationFn: (data: RegisterProps) => registerUser(data),
+ });
+
+ const handleIndividuClick = () => {
+ resetForm();
+ setIsIndividuClicked(true);
+ setIsBisnisClicked(false);
+ };
+
+ const handleBisnisClick = () => {
+ resetForm();
+ updateForm('is_terdaftar', 'false');
+ updateForm('type_acc', 'business');
+ setIsIndividuClicked(false);
+ setIsBisnisClicked(true);
+ };
+ const handleSubmit = async () => {
+ if (!isFormValid) {
+ setNotValid(true);
+ setButtonSubmitClick(!buttonSubmitClick);
+ return;
+ } else {
+ setButtonSubmitClick(!buttonSubmitClick);
+ setNotValid(false);
+ }
+ 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,
+ position: 'top',
+ };
+
+ 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 (
- <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='container'>
+ <div className='grid grid-cols-1 md:grid-cols-2 gap-x-8 pt-10 px-2 md:pt-16'>
+ <section className=''>
+ <div className='px-8 py-4 border'>
+ <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-4 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 mt-2 h-14 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
+ chekValid={notValid}
+ buttonSubmitClick={buttonSubmitClick}
+ />
+ </div>
+ )}
+ {isBisnisClicked && (
+ <div className='opacity-100'>
+ <RegistrasiBisnis
+ chekValid={notValid}
+ buttonSubmitClick={buttonSubmitClick}
+ />
+ </div>
+ )}
+ </div>
+ <section className='mt-2'>
+ <FormCaptcha />
+ <TermCondition />
+ <Button
+ type='submit'
+ colorScheme='red'
+ className='w-full mt-2'
+ size='lg'
+ onClick={handleSubmit}
+ isDisabled={
+ !isCheckedTNC || mutation.isLoading || !isValidCaptcha
+ }
+ >
+ {mutation.isLoading ? 'Loading...' : 'Daftar'}
+ </Button>
+ </section>
+ <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>
- <section className="my-10 md:my-0">
- <PageContent path="/register" />
+ <section className='my-10 md:my-0'>
+ <PageContent path='/register' />
</section>
</div>
<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..273472be 100644
--- a/src-migrate/modules/register/stores/useRegisterStore.ts
+++ b/src-migrate/modules/register/stores/useRegisterStore.ts
@@ -1,7 +1,7 @@
import { create } from 'zustand';
import { RegisterProps } from '~/types/auth';
import { registerSchema } from '~/validations/auth';
-import { ZodError } from 'zod';
+import { boolean, ZodError } from 'zod';
type State = {
form: RegisterProps;
@@ -20,18 +20,33 @@ type Action = {
openTNC: () => void;
closeTNC: () => void;
validate: () => void;
+ resetForm: () => void;
};
export const useRegisterStore = create<State & Action>((set, get) => ({
form: {
- company: '',
+ company_type_id: '',
+ business_name: '',
name: '',
+ nama_wajib_pajak : '',
email: '',
+ email_partner: '',
password: '',
phone: '',
+ sppkp_document: '',
+ npwp_document: '',
+ industry_id: '',
+ npwp: '',
+ sppkp: '',
+ is_pkp: '',
+ type_acc:'',
+ is_terdaftar:'',
+ alamat_bisnis:'',
+ alamat_wajib_pajak:'',
},
updateForm: (name, value) =>
set((state) => ({ form: { ...state.form, [name]: value } })),
+
errors: {},
validate: () => {
@@ -48,6 +63,7 @@ export const useRegisterStore = create<State & Action>((set, get) => ({
}
}
},
+
isCheckedTNC: false,
toggleCheckTNC: () => set((state) => ({ isCheckedTNC: !state.isCheckedTNC })),
@@ -57,4 +73,27 @@ export const useRegisterStore = create<State & Action>((set, get) => ({
isValidCaptcha: false,
updateValidCaptcha: (value) => set(() => ({ isValidCaptcha: value })),
+
+ resetForm: () => set({
+ form: {
+ company_type_id: '',
+ business_name: '',
+ name: '',
+ nama_wajib_pajak : '',
+ email: '',
+ email_partner: '',
+ password: '',
+ phone: '',
+ sppkp_document: '',
+ npwp_document: '',
+ industry_id: '',
+ npwp: '',
+ sppkp: '',
+ is_pkp: '',
+ type_acc:'',
+ is_terdaftar:'',
+ alamat_bisnis:'',
+ alamat_wajib_pajak:'',
+ },
+ }),
}));
diff --git a/src-migrate/types/auth.ts b/src-migrate/types/auth.ts
index e93a475a..593e120f 100644
--- a/src-migrate/types/auth.ts
+++ b/src-migrate/types/auth.ts
@@ -10,6 +10,7 @@ export type AuthProps = {
name: string;
email: string;
phone: string;
+ npwp: string;
mobile: string;
external: boolean;
company: boolean;
diff --git a/src-migrate/validations/auth.ts b/src-migrate/validations/auth.ts
index 78fc5e71..3abdfb57 100644
--- a/src-migrate/validations/auth.ts
+++ b/src-migrate/validations/auth.ts
@@ -1,17 +1,147 @@
import { z } from 'zod';
-export const registerSchema = z.object({
- name: z.string().min(1, { message: 'Nama harus diisi' }),
- email: z
- .string()
- .min(1, { message: 'Email harus diisi' })
- .email({ message: 'Email harus menggunakan format example@mail.com' }),
- password: z.string().min(6, { message: 'Password minimal 6 karakter' }),
- company: z.string().optional(),
- phone: z
- .string()
- .min(1, { message: 'Nomor telepon harus diisi' })
- .refine((val) => /^\d{10,12}$/.test(val), {
- message: 'Format nomor telepon tidak valid, contoh: 081234567890',
+export const registerSchema = z
+ .object({
+ name: z.string().min(1, { message: 'Nama harus diisi' }),
+ email: z
+ .string()
+ .min(1, { message: 'Email harus diisi' })
+ .email({ message: 'Email harus menggunakan format example@mail.com' }),
+ password: z.string().min(6, { message: 'Password minimal 6 karakter' }),
+ phone: z
+ .string()
+ .min(1, { message: 'Nomor telepon harus diisi' })
+ .refine((val) => /^\d{10,12}$/.test(val), {
+ message: 'Format nomor telepon tidak valid, contoh: 081234567890',
+ }),
+ type_acc: z.string().optional(),
+ nama_wajib_pajak: z.string().optional(),
+ alamat_bisnis: z.string().optional(),
+ alamat_wajib_pajak: z.string().optional(),
+ is_pkp: z.string(),
+ is_terdaftar: z.string(),
+ sppkp_document: z.string().optional(),
+ npwp_document: z.string().optional(),
+ industry_id: z.string().optional(),
+ email_partner: z.string().optional(),
+ business_name: z.string().optional(),
+ company_type_id: z.string().optional(),
+ isChekBox: z.string().optional(),
+ npwp: z.string().optional().refine((val) => !val || /^\d{15,16}$/.test(val), {
+ message: 'Format NPWP tidak valid, NPWP harus terdiri dari 15-16 digit angka.',
}),
-});
+ sppkp: z.string().optional(),
+ })
+ .superRefine((data, ctx) => {
+ if (data.type_acc === 'business') {
+ if (data.is_terdaftar === 'false') {
+ if (data.is_pkp === 'true') {
+ const requiredFields: { field: keyof typeof data; message: string }[] = [
+ { field: 'business_name', message: 'Nama perusahaan harus diisi' },
+ { field: 'alamat_bisnis', message: 'Alamat perusahaan harus diisi' },
+ // { field: 'alamat_wajib_pajak', message: 'Alamat wajib pajak harus diisi' },
+ { field: 'company_type_id', message: 'Badan usaha wajib dipilih' },
+ { field: 'industry_id', message: 'Jenis usaha harus dipilih' },
+ { field: 'sppkp_document', message: 'Document harus diisi' },
+ { field: 'npwp_document', message: 'Document harus diisi' },
+ { field: 'npwp', message: 'Format NPWP tidak valid, NPWP harus terdiri dari 15-16 digit angka.' },
+ { field: 'nama_wajib_pajak', message: 'Nama wajib pajak harus diisi' },
+ ];
+
+ requiredFields.forEach(({ field, message }) => {
+ if (!data[field]) {
+ ctx.addIssue({
+ code: 'custom',
+ path: [field],
+ message,
+ });
+ }
+ });
+
+ if (!data.email_partner || !z.string().email().safeParse(data.email_partner).success) {
+ ctx.addIssue({
+ code: 'custom',
+ path: ['email_partner'],
+ message: 'Email partner harus diisi dengan format example@mail.com',
+ });
+ }
+ if(data.isChekBox === 'false'){
+ if (!data.alamat_wajib_pajak) {
+ ctx.addIssue({
+ code: 'custom',
+ path: ['alamat_wajib_pajak'],
+ message: 'Alamat wajib pajak harus diisi',
+ });
+ }
+ }
+
+ } else {
+ if (!data.business_name) {
+ ctx.addIssue({
+ code: 'custom',
+ path: ['business_name'],
+ message: 'Nama perusahaan harus diisi',
+ });
+ }
+ if (!data.alamat_bisnis) {
+ ctx.addIssue({
+ code: 'custom',
+ path: ['alamat_bisnis'],
+ message: 'Alamat perusahaan harus diisi',
+ });
+ }
+
+ if (!data.company_type_id) {
+ ctx.addIssue({
+ code: 'custom',
+ path: ['company_type_id'],
+ message: 'Badan usaha wajib dipilih',
+ });
+ }
+ if (!data.industry_id) {
+ ctx.addIssue({
+ code: 'custom',
+ path: ['industry_id'],
+ message: 'Jenis usaha harus dipilih',
+ });
+ }
+
+ if (data.npwp && !/^\d{15,16}$/.test(data.npwp)) {
+ ctx.addIssue({
+ code: 'custom',
+ path: ['npwp'],
+ message: 'Format NPWP tidak valid, NPWP harus terdiri dari 15-16 digit angka.',
+ });
+ }
+
+ }
+ }else{
+ if (data.is_pkp === 'true') {
+ if (!data.business_name) {
+ ctx.addIssue({
+ code: 'custom',
+ path: ['business_name'],
+ message: 'Nama perusahaan harus diisi',
+ });
+ }
+ } else {
+ if (!data.business_name) {
+ ctx.addIssue({
+ code: 'custom',
+ path: ['business_name'],
+ message: 'Nama perusahaan harus diisi',
+ });
+ }
+ }
+ }
+
+ // Remove this unconditional issue addition to prevent blocking form submission
+ // ctx.addIssue({
+ // code: 'custom',
+ // path: ['business_name'],
+ // message: 'Nama perusahaan harus diisi',
+ // });
+ }else{
+
+ }
+ });
diff --git a/src/core/components/elements/Navbar/NavbarDesktop.jsx b/src/core/components/elements/Navbar/NavbarDesktop.jsx
index ebbcf857..2a51c41f 100644
--- a/src/core/components/elements/Navbar/NavbarDesktop.jsx
+++ b/src/core/components/elements/Navbar/NavbarDesktop.jsx
@@ -293,7 +293,7 @@ const NavbarDesktop = () => {
/>
</div>
)}
- <p className="absolute inset-0 flex justify-center items-center group-hover:scale-105 group-hover:text-red-500 transition-transform duration-200 z-10">Semua Promo</p>
+ <span className="absolute inset-0 flex justify-center items-center group-hover:scale-105 group-hover:text-red-500 transition-transform duration-200 z-10">Semua Promo</span>
</Link>
{/* {showPopup && router.pathname === '/' && (
<div className={`fixed ${isTop ? 'top-[170px]' : 'top-[90px]'} rounded-3xl left-[700px] w-fit object-center bg-green-50 text-xs font-medium text-green-700 ring-1 ring-inset ring-green-600/20 text-center p-2 z-50 transition-all duration-300`}>
@@ -312,7 +312,7 @@ const NavbarDesktop = () => {
target='_blank'
rel='noreferrer'
>
- <p className="group-hover:scale-105 group-hover:text-red-500 transition-transform duration-200">Semua Brand</p>
+ <span className="group-hover:scale-105 group-hover:text-red-500 transition-transform duration-200">Semua Brand</span>
</Link>
<Link
href='/shop/search?orderBy=stock'
@@ -323,7 +323,7 @@ const NavbarDesktop = () => {
target='_blank'
rel='noreferrer'
>
- <p className="group-hover:scale-105 group-hover:text-red-500 transition-transform duration-200">Ready Stock</p>
+ <span className="group-hover:scale-105 group-hover:text-red-500 transition-transform duration-200">Ready Stock</span>
</Link>
<Link
href='https://blog.indoteknik.com/'
@@ -331,7 +331,7 @@ const NavbarDesktop = () => {
target='_blank'
rel='noreferrer noopener'
>
- <p className="group-hover:scale-105 group-hover:text-red-500 transition-transform duration-200">Blog Indoteknik</p>
+ <span className="group-hover:scale-105 group-hover:text-red-500 transition-transform duration-200">Blog Indoteknik</span>
</Link>
{/* <Link
href='/video'
diff --git a/src/core/components/elements/Navbar/NavbarUserDropdown.jsx b/src/core/components/elements/Navbar/NavbarUserDropdown.jsx
index 42bdc12a..c0698b6e 100644
--- a/src/core/components/elements/Navbar/NavbarUserDropdown.jsx
+++ b/src/core/components/elements/Navbar/NavbarUserDropdown.jsx
@@ -1,37 +1,38 @@
-import { deleteAuth } from '@/core/utils/auth'
-import Link from '../Link/Link'
-import { useRouter } from 'next/router'
-import { signOut, useSession } from 'next-auth/react'
-import useAuth from '@/core/hooks/useAuth'
+import { deleteAuth } from '@/core/utils/auth';
+import Link from '../Link/Link';
+import { useRouter } from 'next/router';
+import { signOut, useSession } from 'next-auth/react';
+import useAuth from '@/core/hooks/useAuth';
const NavbarUserDropdown = () => {
- const router = useRouter()
- const atuh = useAuth()
+ const router = useRouter();
+ const atuh = useAuth();
const logout = async () => {
deleteAuth().then(() => {
- router.push('/login')
- })
- }
+ router.push('/login');
+ });
+ };
return (
<div className='navbar-user-dropdown-wrapper'>
<div className='navbar-user-dropdown'>
+ <Link href='/my/profile'>Profil Saya</Link>
<Link href='/my/quotations'>Daftar Quotation</Link>
<Link href='/my/transactions'>Daftar Transaksi</Link>
<Link href='/my/shipments'>Daftar Pengiriman</Link>
<Link href='/my/invoices'>Invoice & Faktur Pajak</Link>
<Link href='/my/wishlist'>Wishlist</Link>
<Link href='/my/address'>Daftar Alamat</Link>
- {!atuh?.external &&
+ {!atuh?.external && (
<Link href='/my/recomendation'>Dashboard Recomendation</Link>
- }
+ )}
<button type='button' onClick={logout}>
Keluar Akun
</button>
</div>
</div>
- )
-}
+ );
+};
-export default NavbarUserDropdown
+export default NavbarUserDropdown;
diff --git a/src/core/components/layouts/AppLayout.jsx b/src/core/components/layouts/AppLayout.jsx
index ebbc1ad5..ec61ca06 100644
--- a/src/core/components/layouts/AppLayout.jsx
+++ b/src/core/components/layouts/AppLayout.jsx
@@ -10,13 +10,15 @@ const BasicFooter = dynamic(() => import('../elements/Footer/BasicFooter'), {
const AppLayout = ({ children, title, withFooter = true }) => {
return (
- <>
- <AnimationLayout>
- <AppBar title={title} />
- {children}
- </AnimationLayout>
- {withFooter && <BasicFooter />}
- </>
+ <div className='flex flex-col min-h-screen max-h-screen overflow-y-auto'>
+ <AppBar title={title} />
+ <div className='flex-grow p-4'>{children}</div>
+ {withFooter && (
+ <div className='mt-auto'>
+ <BasicFooter />
+ </div>
+ )}
+ </div>
);
};
diff --git a/src/lib/address/components/Addresses.jsx b/src/lib/address/components/Addresses.jsx
index a610d371..9ca617ae 100644
--- a/src/lib/address/components/Addresses.jsx
+++ b/src/lib/address/components/Addresses.jsx
@@ -1,34 +1,72 @@
-import Link from '@/core/components/elements/Link/Link'
-import Spinner from '@/core/components/elements/Spinner/Spinner'
-import useAuth from '@/core/hooks/useAuth'
-import { getItemAddress, updateItemAddress } from '@/core/utils/address'
-import { useRouter } from 'next/router'
-import useAddresses from '../hooks/useAddresses'
-import MobileView from '@/core/components/views/MobileView'
-import DesktopView from '@/core/components/views/DesktopView'
-import Menu from '@/lib/auth/components/Menu'
+import { useState } from 'react';
+import Link from '@/core/components/elements/Link/Link';
+import Spinner from '@/core/components/elements/Spinner/Spinner';
+import useAuth from '@/core/hooks/useAuth';
+import { getItemAddress, updateItemAddress } from '@/core/utils/address';
+import { useRouter } from 'next/router';
+import useAddresses from '../hooks/useAddresses';
+import MobileView from '@/core/components/views/MobileView';
+import DesktopView from '@/core/components/views/DesktopView';
+import Menu from '@/lib/auth/components/Menu';
+import BottomPopup from '@/core/components/elements/Popup/BottomPopup';
const Addresses = () => {
- const router = useRouter()
- const { select = null } = router.query
- const { addresses } = useAddresses()
- const selectedAddress = getItemAddress(select || '')
+ const router = useRouter();
+ const { select = null } = router.query;
+ const { addresses } = useAddresses();
+ const selectedAddress = getItemAddress(select || '');
+ const [changeConfirmation, setChangeConfirmation] = useState(false);
+ const [selectedForChange, setSelectedForChange] = useState(null); // State baru untuk simpan alamat yang akan diubah
+
const changeSelectedAddress = (id) => {
- if (!select) return
- updateItemAddress(select, id)
- router.back()
- }
+ if (!select) return;
+ updateItemAddress(select, id);
+ router.back();
+ };
+
+ const handleConfirmSubmit = () => {
+ setChangeConfirmation(false);
+ if (selectedForChange) {
+ router.push(`/my/address/${selectedForChange}/edit`);
+ }
+ };
if (addresses.isLoading) {
return (
<div className='flex justify-center my-6'>
<Spinner className='w-6 text-gray_r-12/50 fill-gray_r-12' />
</div>
- )
+ );
}
return (
<>
+ <BottomPopup
+ active={changeConfirmation}
+ close={() => setChangeConfirmation(false)} // Menutup popup
+ title='Ubah alamat Bisnis'
+ >
+ <div className='leading-7 text-gray_r-12/80'>
+ Anda akan mengubah alamat utama bisnis?
+ </div>
+ <div className='flex mt-6 gap-x-4 md:justify-end'>
+ <button
+ className='btn-solid-red flex-1 md:flex-none'
+ type='button'
+ onClick={handleConfirmSubmit}
+ >
+ Yakin
+ </button>
+ <button
+ className='btn-light flex-1 md:flex-none'
+ type='button'
+ onClick={() => setChangeConfirmation(false)}
+ >
+ Batal
+ </button>
+ </div>
+ </BottomPopup>
+
<MobileView>
<div className='p-4'>
<div className='text-right'>
@@ -37,7 +75,10 @@ const Addresses = () => {
<div className='grid gap-y-4 mt-4'>
{addresses.data?.map((address, index) => {
- const type = address.type.charAt(0).toUpperCase() + address.type.slice(1) + ' Address'
+ const type =
+ address.type.charAt(0).toUpperCase() +
+ address.type.slice(1) +
+ ' Address';
return (
<AddressCard
key={index}
@@ -45,9 +86,11 @@ const Addresses = () => {
type={type}
changeSelectedAddress={changeSelectedAddress}
selectedAddress={selectedAddress}
+ setChangeConfirmation={setChangeConfirmation} // Memanggil popup
+ setSelectedForChange={setSelectedForChange} // Simpan id address yang akan diubah
select={select}
/>
- )
+ );
})}
</div>
</div>
@@ -72,7 +115,9 @@ const Addresses = () => {
<div className='grid grid-cols-2 gap-4'>
{addresses.data?.map((address, index) => {
const type =
- address.type.charAt(0).toUpperCase() + address.type.slice(1) + ' Address'
+ address.type.charAt(0).toUpperCase() +
+ address.type.slice(1) +
+ ' Address';
return (
<AddressCard
key={index}
@@ -80,20 +125,31 @@ const Addresses = () => {
type={type}
changeSelectedAddress={changeSelectedAddress}
selectedAddress={selectedAddress}
+ setChangeConfirmation={setChangeConfirmation}
+ setSelectedForChange={setSelectedForChange}
select={select}
/>
- )
+ );
})}
</div>
</div>
</div>
</DesktopView>
</>
- )
-}
+ );
+};
-const AddressCard = ({ address, selectedAddress, changeSelectedAddress, type, select }) => {
- const auth = useAuth()
+const AddressCard = ({
+ address,
+ selectedAddress,
+ changeSelectedAddress,
+ type,
+ select,
+ setChangeConfirmation,
+ setSelectedForChange,
+}) => {
+ const auth = useAuth();
+ const router = useRouter();
return (
<div
@@ -106,23 +162,37 @@ const AddressCard = ({ address, selectedAddress, changeSelectedAddress, type, se
(select && 'cursor-pointer hover:bg-gray_r-4 transition')
}`}
>
- <div onClick={() => changeSelectedAddress(address.id)} className={select && 'cursor-pointer'}>
+ <div
+ onClick={() => changeSelectedAddress(address.id)}
+ className={select && 'cursor-pointer'}
+ >
<div className='flex gap-x-2'>
<div className='badge-red'>{type}</div>
- {auth?.partnerId == address.id && <div className='badge-green'>Utama</div>}
+ {auth?.partnerId == address.id && (
+ <div className='badge-green'>Utama</div>
+ )}
</div>
<p className='font-medium mt-2'>{address.name}</p>
- {address.mobile && <p className='mt-2 text-gray_r-11'>{address.mobile}</p>}
+ {address.mobile && (
+ <p className='mt-2 text-gray_r-11'>{address.mobile}</p>
+ )}
<p className='mt-1 leading-6 text-gray_r-11'>{address.street}</p>
</div>
- <Link
- href={`/my/address/${address.id}/edit`}
+ <button
+ onClick={() => {
+ if (type == 'Contact Address' && auth.parentId) {
+ setSelectedForChange(address.id); // Set alamat yang dipilih
+ setChangeConfirmation(true); // Tampilkan popup konfirmasi
+ } else {
+ router.push(`/my/address/${address.id}/edit`);
+ }
+ }}
className='btn-light bg-white mt-3 w-full !text-gray_r-11'
>
Ubah Alamat
- </Link>
+ </button>
</div>
- )
-}
+ );
+};
-export default Addresses
+export default Addresses;
diff --git a/src/lib/address/components/CreateAddress.jsx b/src/lib/address/components/CreateAddress.jsx
index 86519147..e315affe 100644
--- a/src/lib/address/components/CreateAddress.jsx
+++ b/src/lib/address/components/CreateAddress.jsx
@@ -1,76 +1,101 @@
-import HookFormSelect from '@/core/components/elements/Select/HookFormSelect'
-import useAuth from '@/core/hooks/useAuth'
-import { useRouter } from 'next/router'
-import { Controller, useForm } from 'react-hook-form'
-import * as Yup from 'yup'
-import cityApi from '../api/cityApi'
-import districtApi from '../api/districtApi'
-import subDistrictApi from '../api/subDistrictApi'
-import { useEffect, useState } from 'react'
-import createAddressApi from '../api/createAddressApi'
-import { toast } from 'react-hot-toast'
-import { yupResolver } from '@hookform/resolvers/yup'
-import Menu from '@/lib/auth/components/Menu'
+import HookFormSelect from '@/core/components/elements/Select/HookFormSelect';
+import useAuth from '@/core/hooks/useAuth';
+import { useRouter } from 'next/router';
+import { Controller, useForm } from 'react-hook-form';
+import * as Yup from 'yup';
+import cityApi from '../api/cityApi';
+import districtApi from '../api/districtApi';
+import subDistrictApi from '../api/subDistrictApi';
+import { useEffect, useState } from 'react';
+import createAddressApi from '../api/createAddressApi';
+import { toast } from 'react-hot-toast';
+import { yupResolver } from '@hookform/resolvers/yup';
+import Menu from '@/lib/auth/components/Menu';
+import useAddresses from '../hooks/useAddresses';
const CreateAddress = () => {
- const auth = useAuth()
- const router = useRouter()
+ const auth = useAuth();
+ const router = useRouter();
const {
register,
formState: { errors },
handleSubmit,
watch,
setValue,
- control
+ control,
} = useForm({
resolver: yupResolver(validationSchema),
- defaultValues
- })
-
- const [cities, setCities] = useState([])
- const [districts, setDistricts] = useState([])
- const [subDistricts, setSubDistricts] = useState([])
+ defaultValues,
+ });
+ const { addresses = [] } = useAddresses(); // Ensure addresses is an array
+ const [cities, setCities] = useState([]);
+ const [districts, setDistricts] = useState([]);
+ const [subDistricts, setSubDistricts] = useState([]);
+ const [filteredTypes, setFilteredTypes] = useState(types); // State to manage filtered types
useEffect(() => {
const loadCities = async () => {
- let dataCities = await cityApi()
- dataCities = dataCities.map((city) => ({ value: city.id, label: city.name }))
- setCities(dataCities)
+ let dataCities = await cityApi();
+ dataCities = dataCities.map((city) => ({
+ value: city.id,
+ label: city.name,
+ }));
+ setCities(dataCities);
+ };
+ loadCities();
+ }, []);
+
+ useEffect(() => {
+ if (addresses) {
+ let hasContactAddress = false;
+
+ for (let i = 0; i < addresses?.data?.length; i++) {
+ if (addresses.data[i].type === 'contact') {
+ hasContactAddress = true;
+ break;
+ }
+ }
+ if (hasContactAddress) {
+ setFilteredTypes(types.filter((type) => type.value !== 'contact'));
+ } else {
+ setFilteredTypes(types);
+ }
}
- loadCities()
- }, [])
+ }, [auth]);
- const watchCity = watch('city')
+ const watchCity = watch('city');
useEffect(() => {
- setValue('district', '')
+ setValue('district', '');
if (watchCity) {
const loadDistricts = async () => {
- let dataDistricts = await districtApi({ cityId: watchCity })
+ let dataDistricts = await districtApi({ cityId: watchCity });
dataDistricts = dataDistricts.map((district) => ({
value: district.id,
- label: district.name
- }))
- setDistricts(dataDistricts)
- }
- loadDistricts()
+ label: district.name,
+ }));
+ setDistricts(dataDistricts);
+ };
+ loadDistricts();
}
- }, [watchCity, setValue])
+ }, [watchCity, setValue]);
- const watchDistrict = watch('district')
+ const watchDistrict = watch('district');
useEffect(() => {
- setValue('subDistrict', '')
+ setValue('subDistrict', '');
if (watchDistrict) {
const loadSubDistricts = async () => {
- let dataSubDistricts = await subDistrictApi({ districtId: watchDistrict })
+ let dataSubDistricts = await subDistrictApi({
+ districtId: watchDistrict,
+ });
dataSubDistricts = dataSubDistricts.map((district) => ({
value: district.id,
- label: district.name
- }))
- setSubDistricts(dataSubDistricts)
- }
- loadSubDistricts()
+ label: district.name,
+ }));
+ setSubDistricts(dataSubDistricts);
+ };
+ loadSubDistricts();
}
- }, [watchDistrict, setValue])
+ }, [watchDistrict, setValue]);
const onSubmitHandler = async (values) => {
const data = {
@@ -78,15 +103,15 @@ const CreateAddress = () => {
city_id: values.city,
district_id: values.district,
sub_district_id: values.subDistrict,
- parent_id: auth.partnerId
- }
+ parent_id: auth.partnerId,
+ };
- const address = await createAddressApi({ data })
+ const address = await createAddressApi({ data });
if (address?.id) {
- toast.success('Berhasil menambahkan alamat')
- router.back()
+ toast.success('Berhasil menambahkan alamat');
+ router.back();
}
- }
+ };
return (
<div className='max-w-none md:container mx-auto flex p-0 md:py-10'>
@@ -102,10 +127,16 @@ const CreateAddress = () => {
name='type'
control={control}
render={(props) => (
- <HookFormSelect {...props} isSearchable={false} options={types} />
+ <HookFormSelect
+ {...props}
+ isSearchable={false}
+ options={filteredTypes}
+ />
)}
/>
- <div className='text-caption-2 text-danger-500 mt-1'>{errors.type?.message}</div>
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.type?.message}
+ </div>
</div>
<div>
@@ -116,7 +147,9 @@ const CreateAddress = () => {
type='text'
className='form-input'
/>
- <div className='text-caption-2 text-danger-500 mt-1'>{errors.name?.message}</div>
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.name?.message}
+ </div>
</div>
<div>
@@ -127,7 +160,9 @@ const CreateAddress = () => {
type='email'
className='form-input'
/>
- <div className='text-caption-2 text-danger-500 mt-1'>{errors.email?.message}</div>
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.email?.message}
+ </div>
</div>
<div>
@@ -138,7 +173,9 @@ const CreateAddress = () => {
type='tel'
className='form-input'
/>
- <div className='text-caption-2 text-danger-500 mt-1'>{errors.mobile?.message}</div>
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.mobile?.message}
+ </div>
</div>
<div>
@@ -149,7 +186,9 @@ const CreateAddress = () => {
type='text'
className='form-input'
/>
- <div className='text-caption-2 text-danger-500 mt-1'>{errors.street?.message}</div>
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.street?.message}
+ </div>
</div>
<div>
@@ -160,7 +199,9 @@ const CreateAddress = () => {
type='number'
className='form-input'
/>
- <div className='text-caption-2 text-danger-500 mt-1'>{errors.zip?.message}</div>
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.zip?.message}
+ </div>
</div>
<div>
@@ -168,9 +209,13 @@ const CreateAddress = () => {
<Controller
name='city'
control={control}
- render={(props) => <HookFormSelect {...props} options={cities} />}
+ render={(props) => (
+ <HookFormSelect {...props} options={cities} />
+ )}
/>
- <div className='text-caption-2 text-danger-500 mt-1'>{errors.city?.message}</div>
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.city?.message}
+ </div>
</div>
<div>
@@ -179,10 +224,16 @@ const CreateAddress = () => {
name='district'
control={control}
render={(props) => (
- <HookFormSelect {...props} options={districts} disabled={!watchCity} />
+ <HookFormSelect
+ {...props}
+ options={districts}
+ disabled={!watchCity}
+ />
)}
/>
- <div className='text-caption-2 text-danger-500 mt-1'>{errors.district?.message}</div>
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.district?.message}
+ </div>
</div>
<div>
@@ -191,31 +242,37 @@ const CreateAddress = () => {
name='subDistrict'
control={control}
render={(props) => (
- <HookFormSelect {...props} options={subDistricts} disabled={!watchDistrict} />
+ <HookFormSelect
+ {...props}
+ options={subDistricts}
+ disabled={!watchDistrict}
+ />
)}
/>
</div>
</div>
- <button type='submit' className='btn-yellow w-full md:w-fit mt-6 ml-0 md:ml-auto'>
+ <button
+ type='submit'
+ className='btn-yellow w-full md:w-fit mt-6 ml-0 md:ml-auto'
+ >
Simpan
</button>
</form>
</div>
</div>
- )
-}
+ );
+};
const validationSchema = Yup.object().shape({
type: Yup.string().required('Harus di-pilih'),
name: Yup.string().min(3, 'Minimal 3 karakter').required('Harus di-isi'),
- // email: Yup.string().email('Format harus seperti contoh@email.com').required('Harus di-isi'),
mobile: Yup.string().required('Harus di-isi'),
street: Yup.string().required('Harus di-isi'),
zip: Yup.string().required('Harus di-isi'),
city: Yup.string().required('Harus di-pilih'),
- district: Yup.string().required('Harus di-pilih')
-})
+ district: Yup.string().required('Harus di-pilih'),
+});
const defaultValues = {
type: '',
@@ -226,14 +283,14 @@ const defaultValues = {
city: '',
district: '',
subDistrict: '',
- zip: ''
-}
+ zip: '',
+};
const types = [
{ value: 'contact', label: 'Contact Address' },
{ value: 'invoice', label: 'Invoice Address' },
{ value: 'delivery', label: 'Delivery Address' },
- { value: 'other', label: 'Other Address' }
-]
+ { value: 'other', label: 'Other Address' },
+];
-export default CreateAddress
+export default CreateAddress;
diff --git a/src/lib/address/components/EditAddress.jsx b/src/lib/address/components/EditAddress.jsx
index 520bba51..ff6b1f12 100644
--- a/src/lib/address/components/EditAddress.jsx
+++ b/src/lib/address/components/EditAddress.jsx
@@ -1,18 +1,22 @@
-import { yupResolver } from '@hookform/resolvers/yup'
-import { useRouter } from 'next/router'
-import { useEffect, useState } from 'react'
-import * as Yup from 'yup'
-import cityApi from '../api/cityApi'
-import { Controller, useForm } from 'react-hook-form'
-import districtApi from '../api/districtApi'
-import subDistrictApi from '../api/subDistrictApi'
-import editAddressApi from '../api/editAddressApi'
-import HookFormSelect from '@/core/components/elements/Select/HookFormSelect'
-import { toast } from 'react-hot-toast'
-import Menu from '@/lib/auth/components/Menu'
+import { yupResolver } from '@hookform/resolvers/yup';
+import { useRouter } from 'next/router';
+import { useEffect, useState } from 'react';
+import * as Yup from 'yup';
+import cityApi from '../api/cityApi';
+import { Controller, useForm } from 'react-hook-form';
+import districtApi from '../api/districtApi';
+import subDistrictApi from '../api/subDistrictApi';
+import addressApi from '@/lib/address/api/addressApi';
+import editAddressApi from '../api/editAddressApi';
+import HookFormSelect from '@/core/components/elements/Select/HookFormSelect';
+import { toast } from 'react-hot-toast';
+import Menu from '@/lib/auth/components/Menu';
+import useAuth from '@/core/hooks/useAuth';
+import odooApi from '@/core/api/odooApi';
const EditAddress = ({ id, defaultValues }) => {
- const router = useRouter()
+ const auth = useAuth();
+ const router = useRouter();
const {
register,
formState: { errors },
@@ -20,205 +24,283 @@ const EditAddress = ({ id, defaultValues }) => {
watch,
setValue,
getValues,
- control
+ control,
} = useForm({
resolver: yupResolver(validationSchema),
- defaultValues
- })
+ defaultValues,
+ });
+ const [cities, setCities] = useState([]);
+ const [districts, setDistricts] = useState([]);
+ const [subDistricts, setSubDistricts] = useState([]);
- const [cities, setCities] = useState([])
- const [districts, setDistricts] = useState([])
- const [subDistricts, setSubDistricts] = useState([])
+ useEffect(() => {
+ const loadProfile = async () => {
+ const dataProfile = await addressApi({ id: auth.parentId });
+ setValue('industry', dataProfile.industryId);
+ setValue('companyType', dataProfile.companyTypeId);
+ setValue('taxName', dataProfile.taxName);
+ setValue('npwp', dataProfile.npwp);
+ setValue('alamat_wajib_pajak', dataProfile.alamatWajibPajak);
+ setValue('alamat_bisnis', dataProfile.alamatBisnis);
+ setValue('business_name', dataProfile.name);
+ };
+ if (auth) loadProfile();
+ }, [auth, setValue]);
useEffect(() => {
const loadCities = async () => {
- let dataCities = await cityApi()
+ let dataCities = await cityApi();
dataCities = dataCities.map((city) => ({
value: city.id,
- label: city.name
- }))
- setCities(dataCities)
- }
- loadCities()
- }, [])
+ label: city.name,
+ }));
+ setCities(dataCities);
+ };
+ loadCities();
+ }, []);
- const watchCity = watch('city')
+ const watchCity = watch('city');
useEffect(() => {
- setValue('district', '')
+ setValue('district', '');
if (watchCity) {
const loadDistricts = async () => {
- let dataDistricts = await districtApi({ cityId: watchCity })
+ let dataDistricts = await districtApi({ cityId: watchCity });
dataDistricts = dataDistricts.map((district) => ({
value: district.id,
- label: district.name
- }))
- setDistricts(dataDistricts)
- let oldDistrict = getValues('oldDistrict')
+ label: district.name,
+ }));
+ setDistricts(dataDistricts);
+ let oldDistrict = getValues('oldDistrict');
if (oldDistrict) {
- setValue('district', oldDistrict)
- setValue('oldDistrict', '')
+ setValue('district', oldDistrict);
+ setValue('oldDistrict', '');
}
- }
- loadDistricts()
+ };
+ loadDistricts();
}
- }, [watchCity, setValue, getValues])
+ }, [watchCity, setValue, getValues]);
- const watchDistrict = watch('district')
+ const watchDistrict = watch('district');
useEffect(() => {
- setValue('subDistrict', '')
+ setValue('subDistrict', '');
if (watchDistrict) {
const loadSubDistricts = async () => {
let dataSubDistricts = await subDistrictApi({
- districtId: watchDistrict
- })
+ districtId: watchDistrict,
+ });
dataSubDistricts = dataSubDistricts.map((district) => ({
value: district.id,
- label: district.name
- }))
- setSubDistricts(dataSubDistricts)
- let oldSubDistrict = getValues('oldSubDistrict')
+ label: district.name,
+ }));
+ setSubDistricts(dataSubDistricts);
+ let oldSubDistrict = getValues('oldSubDistrict');
if (oldSubDistrict) {
- setValue('subDistrict', oldSubDistrict)
- setValue('oldSubDistrict', '')
+ setValue('subDistrict', oldSubDistrict);
+ setValue('oldSubDistrict', '');
}
- }
- loadSubDistricts()
+ };
+ loadSubDistricts();
}
- }, [watchDistrict, setValue, getValues])
-
+ }, [watchDistrict, setValue, getValues]);
const onSubmitHandler = async (values) => {
const data = {
...values,
+ phone: values.mobile,
city_id: values.city,
district_id: values.district,
- sub_district_id: values.subDistrict
+ sub_district_id: values.subDistrict,
+ };
+ const address = await editAddressApi({ id, data });
+ let dataAlamat;
+ let isUpdated = true;
+ if (auth?.partnerId == id) {
+ dataAlamat = {
+ id_user: auth.partnerId,
+ company_type_id: values.companyType,
+ industry_id: values.industry,
+ tax_name: values.taxName,
+ alamat_lengkap_text: values.alamat_wajib_pajak,
+ street: values.street,
+ business_name: values.business_name,
+ name: values.business_name,
+ npwp: values.npwp,
+ };
+ isUpdated = await odooApi(
+ 'PUT',
+ `/api/v1/partner/${auth.parentId}`,
+ dataAlamat
+ );
}
- const address = await editAddressApi({ id, data })
- if (address?.id) {
- toast.success('Berhasil mengubah alamat')
- router.back()
+ // if (isUpdated?.id) {
+ if (address?.id && isUpdated?.id) {
+ toast.success('Berhasil mengubah alamat');
+ router.back();
+ } else {
+ toast.error('Terjadi kesalahan internal');
+ router.back();
}
- }
+ };
return (
- <div className='max-w-none md:container mx-auto flex p-0 md:py-10'>
- <div className='hidden md:block w-3/12 pr-4'>
- <Menu />
- </div>
- <div className='w-full md:w-9/12 p-4 bg-white border border-gray_r-6 rounded'>
- <h1 className='text-title-sm font-semibold mb-6 hidden md:block'>Ubah Alamat</h1>
- <form onSubmit={handleSubmit(onSubmitHandler)}>
- <div className='grid grid-cols-1 md:grid-cols-2 gap-4'>
- <div>
- <label className='form-label mb-2'>Label Alamat</label>
- <Controller
- name='type'
- control={control}
- render={(props) => (
- <HookFormSelect {...props} isSearchable={false} options={types} />
- )}
- />
- <div className='text-caption-2 text-danger-500 mt-1'>{errors.type?.message}</div>
- </div>
+ <>
+ <div className='max-w-none md:container mx-auto flex p-0 md:py-10'>
+ <div className='hidden md:block w-3/12 pr-4'>
+ <Menu />
+ </div>
+ <div className='w-full md:w-9/12 p-4 bg-white border border-gray_r-6 rounded'>
+ <div className='flex justify-start items-center mb-6'>
+ <h1 className='text-title-sm font-semibold hidden md:block mr-2'>
+ Ubah Alamat
+ </h1>
+ {auth?.partnerId == id && <div className='badge-green'>Utama</div>}
+ </div>
+ <form onSubmit={handleSubmit(onSubmitHandler)}>
+ <div className='grid grid-cols-1 md:grid-cols-2 gap-4'>
+ <div>
+ <label className='form-label mb-2'>Label Alamat</label>
+ <Controller
+ name='type'
+ control={control}
+ render={(props) => (
+ <HookFormSelect
+ {...props}
+ isSearchable={false}
+ options={types}
+ />
+ )}
+ />
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.type?.message}
+ </div>
+ </div>
- <div>
- <label className='form-label mb-2'>Nama</label>
- <input
- {...register('name')}
- placeholder='John Doe'
- type='text'
- className='form-input'
- />
- <div className='text-caption-2 text-danger-500 mt-1'>{errors.name?.message}</div>
- </div>
+ <div>
+ <label className='form-label mb-2'>Nama</label>
+ <input
+ {...register('name')}
+ placeholder='John Doe'
+ type='text'
+ className='form-input'
+ />
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.name?.message}
+ </div>
+ </div>
- <div>
- <label className='form-label mb-2'>Email</label>
- <input
- {...register('email')}
- placeholder='johndoe@example.com'
- type='email'
- className='form-input'
- />
- <div className='text-caption-2 text-danger-500 mt-1'>{errors.email?.message}</div>
- </div>
+ <div>
+ <label className='form-label mb-2'>Email</label>
+ <input
+ {...register('email')}
+ placeholder='johndoe@example.com'
+ type='email'
+ className='form-input'
+ disabled={auth?.partnerId == id && true}
+ />
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.email?.message}
+ </div>
+ </div>
- <div>
- <label className='form-label mb-2'>Mobile</label>
- <input
- {...register('mobile')}
- placeholder='08xxxxxxxx'
- type='tel'
- className='form-input'
- />
- <div className='text-caption-2 text-danger-500 mt-1'>{errors.mobile?.message}</div>
- </div>
+ <div>
+ <label className='form-label mb-2'>Mobile</label>
+ <input
+ {...register('mobile')}
+ placeholder='08xxxxxxxx'
+ type='tel'
+ className='form-input'
+ />
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.mobile?.message}
+ </div>
+ </div>
- <div>
- <label className='form-label mb-2'>Alamat</label>
- <input
- {...register('street')}
- placeholder='Jl. Bandengan Utara 85A'
- type='text'
- className='form-input'
- />
- <div className='text-caption-2 text-danger-500 mt-1'>{errors.street?.message}</div>
- </div>
+ <div>
+ <label className='form-label mb-2'>Alamat</label>
+ <input
+ {...register('street')}
+ placeholder='Jl. Bandengan Utara 85A'
+ type='text'
+ className='form-input'
+ />
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.street?.message}
+ </div>
+ </div>
- <div>
- <label className='form-label mb-2'>Kode Pos</label>
- <input
- {...register('zip')}
- placeholder='10100'
- type='number'
- className='form-input'
- />
- <div className='text-caption-2 text-danger-500 mt-1'>{errors.zip?.message}</div>
- </div>
+ <div>
+ <label className='form-label mb-2'>Kode Pos</label>
+ <input
+ {...register('zip')}
+ placeholder='10100'
+ type='number'
+ className='form-input'
+ />
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.zip?.message}
+ </div>
+ </div>
- <div>
- <label className='form-label mb-2'>Kota</label>
- <Controller
- name='city'
- control={control}
- render={(props) => <HookFormSelect {...props} options={cities} />}
- />
- <div className='text-caption-2 text-danger-500 mt-1'>{errors.city?.message}</div>
- </div>
+ <div>
+ <label className='form-label mb-2'>Kota</label>
+ <Controller
+ name='city'
+ control={control}
+ render={(props) => (
+ <HookFormSelect {...props} options={cities} />
+ )}
+ />
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.city?.message}
+ </div>
+ </div>
- <div>
- <label className='form-label mb-2'>Kecamatan</label>
- <Controller
- name='district'
- control={control}
- render={(props) => (
- <HookFormSelect {...props} options={districts} disabled={!watchCity} />
- )}
- />
- <div className='text-caption-2 text-danger-500 mt-1'>{errors.district?.message}</div>
- </div>
+ <div>
+ <label className='form-label mb-2'>Kecamatan</label>
+ <Controller
+ name='district'
+ control={control}
+ render={(props) => (
+ <HookFormSelect
+ {...props}
+ options={districts}
+ disabled={!watchCity}
+ />
+ )}
+ />
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.district?.message}
+ </div>
+ </div>
- <div>
- <label className='form-label mb-2'>Kelurahan</label>
- <Controller
- name='subDistrict'
- control={control}
- render={(props) => (
- <HookFormSelect {...props} options={subDistricts} disabled={!watchDistrict} />
- )}
- />
+ <div>
+ <label className='form-label mb-2'>Kelurahan</label>
+ <Controller
+ name='subDistrict'
+ control={control}
+ render={(props) => (
+ <HookFormSelect
+ {...props}
+ options={subDistricts}
+ disabled={!watchDistrict}
+ />
+ )}
+ />
+ </div>
</div>
- </div>
- <button type='submit' className='btn-yellow w-full md:w-fit mt-6 ml-0 md:ml-auto'>
- Simpan
- </button>
- </form>
+ <button
+ type='submit'
+ className='btn-yellow w-full md:w-fit mt-6 ml-0 md:ml-auto'
+ >
+ Simpan
+ </button>
+ </form>
+ </div>
</div>
- </div>
- )
-}
+ </>
+ );
+};
const validationSchema = Yup.object().shape({
type: Yup.string().required('Harus di-pilih'),
@@ -228,14 +310,14 @@ const validationSchema = Yup.object().shape({
street: Yup.string().required('Harus di-isi'),
zip: Yup.string().required('Harus di-isi'),
city: Yup.string().required('Harus di-pilih'),
- district: Yup.string().required('Harus di-pilih')
-})
+ district: Yup.string().required('Harus di-pilih'),
+});
const types = [
{ value: 'contact', label: 'Contact Address' },
{ value: 'invoice', label: 'Invoice Address' },
{ value: 'delivery', label: 'Delivery Address' },
- { value: 'other', label: 'Other Address' }
-]
+ { value: 'other', label: 'Other Address' },
+];
-export default EditAddress
+export default EditAddress;
diff --git a/src/lib/auth/components/CompanyProfile.jsx b/src/lib/auth/components/CompanyProfile.jsx
index 2faede9b..7bda992f 100644
--- a/src/lib/auth/components/CompanyProfile.jsx
+++ b/src/lib/auth/components/CompanyProfile.jsx
@@ -1,78 +1,136 @@
-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'
+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';
+import BottomPopup from '@/core/components/elements/Popup/BottomPopup';
+import { yupResolver } from '@hookform/resolvers/yup';
+import * as Yup from 'yup';
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 [changeConfirmation, setChangeConfirmation] = useState(false);
+ const auth = useAuth();
+ const [isOpen, setIsOpen] = useState(false);
+ const toggle = () => setIsOpen(!isOpen);
+ const {
+ register,
+ formState: { errors },
+ setValue,
+ control,
+ handleSubmit,
+ } = useForm({
+ resolver: yupResolver(validationSchema),
+ defaultValues,
+ });
- const [industries, setIndustries] = useState([])
+ 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 dataIndustries = await odooApi('GET', '/api/v1/partner/industry');
+ setIndustries(
+ dataIndustries?.map((o) => ({ value: o.id, label: o.name }))
+ );
+ };
+ loadIndustries();
+ }, []);
- const [companyTypes, setCompanyTypes] = useState([])
+ 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()
- }, [])
+ 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 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);
+ setValue('alamat_wajib_pajak', dataProfile.alamatWajibPajak);
+ setValue('alamat_bisnis', dataProfile.alamatBisnis);
+ };
+ 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
+ if (changeConfirmation) {
+ const data = {
+ ...values,
+ id_user: auth.partnerId,
+ company_type_id: values.companyType,
+ industry_id: values.industry,
+ tax_name: values.taxName,
+ alamat_lengkap_text: values.alamat_wajib_pajak,
+ street: values.alamat_bisnis,
+ };
+ const isUpdated = await odooApi(
+ 'PUT',
+ `/api/v1/partner/${auth.parentId}`,
+ data
+ );
+ if (isUpdated?.id) {
+ toast.success('Berhasil mengubah profil', { duration: 1500 });
+ return;
+ }
+ toast.error('Terjadi kesalahan internal');
}
- const isUpdated = await odooApi('PUT', `/api/v1/partner/${auth.parentId}`, data)
- if (isUpdated?.id) {
- toast.success('Berhasil mengubah profil', { duration: 1500 })
- return
- }
- toast.error('Terjadi kesalahan internal')
- }
+ };
+
+ const handleConfirmSubmit = () => {
+ setChangeConfirmation(false);
+ handleSubmit(onSubmitHandler)();
+ };
return (
<>
- <button type='button' onClick={toggle} className='p-4 flex items-center text-left w-full'>
+ <BottomPopup
+ active={changeConfirmation}
+ close={() => setChangeConfirmation(true)}
+ title='Ubah profil Bisnis'
+ >
+ <div className='leading-7 text-gray_r-12/80'>
+ Apakah anda yakin mengubah data bisnis?
+ </div>
+ <div className='flex mt-6 gap-x-4 md:justify-end'>
+ <button
+ className='btn-solid-red flex-1 md:flex-none'
+ type='button'
+ onClick={handleConfirmSubmit}
+ >
+ Ya, Ubah
+ </button>
+ <button
+ className='btn-light flex-1 md:flex-none'
+ type='button'
+ onClick={() => setChangeConfirmation(false)}
+ >
+ Batal
+ </button>
+ </div>
+ </BottomPopup>
+ <button
+ type='button'
+ onClick={toggle}
+ className='p-4 flex items-center text-left w-full'
+ >
<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.
+ Dibawah ini adalah data usaha yang anda masukkan, periksa kembali
+ data usaha anda.
</div>
</div>
<div className='ml-auto p-2 bg-gray_r-3 rounded'>
@@ -82,15 +140,26 @@ const CompanyProfile = () => {
</button>
{isOpen && (
- <form className='p-4 border-t border-gray_r-6' onSubmit={handleSubmit(onSubmitHandler)}>
+ <form
+ className='p-4 border-t border-gray_r-6'
+ onSubmit={(e) => {
+ e.preventDefault();
+ setChangeConfirmation(true);
+ }}
+ >
<div className='grid grid-cols-1 sm:grid-cols-2 gap-4'>
<div>
<label className='block mb-3'>Klasifikasi Jenis Usaha</label>
<Controller
name='industry'
control={control}
- render={(props) => <HookFormSelect {...props} options={industries} />}
+ render={(props) => (
+ <HookFormSelect {...props} options={industries} />
+ )}
/>
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.industry?.message}
+ </div>
</div>
<div className='flex flex-wrap'>
<div className='w-full mb-3'>Badan Usaha</div>
@@ -98,8 +167,13 @@ const CompanyProfile = () => {
<Controller
name='companyType'
control={control}
- render={(props) => <HookFormSelect {...props} options={companyTypes} />}
+ render={(props) => (
+ <HookFormSelect {...props} options={companyTypes} />
+ )}
/>
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.companyType?.message}
+ </div>
</div>
<div className='w-9/12 pl-1'>
<input
@@ -108,15 +182,55 @@ const CompanyProfile = () => {
className='form-input'
placeholder='Cth: Indoteknik Dotcom Gemilang'
/>
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.name?.message}
+ </div>
</div>
</div>
<div>
<label>Nama Wajib Pajak</label>
- <input {...register('taxName')} type='text' className='form-input mt-3' />
+ <input
+ {...register('taxName')}
+ type='text'
+ className='form-input mt-3'
+ />
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.taxName?.message}
+ </div>
+ </div>
+ <div>
+ <label>Alamat Wajib Pajak</label>
+ <input
+ {...register('alamat_wajib_pajak')}
+ type='text'
+ className='form-input mt-3'
+ />
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.alamat_wajib_pajak?.message}
+ </div>
+ </div>
+ <div>
+ <label>Alamat Bisnis</label>
+ <input
+ {...register('alamat_bisnis')}
+ type='text'
+ className='form-input mt-3'
+ />
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.alamat_bisnis?.message}
+ </div>
</div>
<div>
<label>Nomor NPWP</label>
- <input {...register('npwp')} type='text' className='form-input mt-3' />
+ <input
+ {...register('npwp')}
+ type='text'
+ className='form-input mt-3'
+ maxLength={16}
+ />
+ <div className='text-caption-2 text-danger-500 mt-1'>
+ {errors.npwp?.message}
+ </div>
</div>
</div>
<button type='submit' className='btn-yellow w-full mt-6'>
@@ -125,7 +239,27 @@ const CompanyProfile = () => {
</form>
)}
</>
- )
-}
+ );
+};
+
+export default CompanyProfile;
+
+const validationSchema = Yup.object().shape({
+ alamat_bisnis: Yup.string().required('Harus di-isi'),
+ alamat_wajib_pajak: Yup.string().required('Harus di-isi'),
+ taxName: Yup.string().required('Harus di-isi'),
+ npwp: Yup.string().required('Harus di-isi'),
+ name: Yup.string().required('Harus di-isi'),
+ industry: Yup.string().required('Harus di-pilih'),
+ companyType: Yup.string().required('Harus di-pilih'),
+});
-export default CompanyProfile
+const defaultValues = {
+ industry: '',
+ companyType: '',
+ name: '',
+ taxName: '',
+ npwp: '',
+ alamat_wajib_pajak: '',
+ alamat_bisnis: '',
+};
diff --git a/src/lib/checkout/components/Checkout.jsx b/src/lib/checkout/components/Checkout.jsx
index f63ef457..4c7e852f 100644
--- a/src/lib/checkout/components/Checkout.jsx
+++ b/src/lib/checkout/components/Checkout.jsx
@@ -77,6 +77,9 @@ const Checkout = () => {
if (!addresses) return;
const matchAddress = (key) => {
+ if (key === 'invoicing') {
+ key = 'invoice';
+ }
const addressToMatch = getItemAddress(key);
const foundAddress = addresses.filter(
(address) => address.id == addressToMatch
diff --git a/src/lib/home/components/PreferredBrand.jsx b/src/lib/home/components/PreferredBrand.jsx
index b30fa5c9..eefced60 100644
--- a/src/lib/home/components/PreferredBrand.jsx
+++ b/src/lib/home/components/PreferredBrand.jsx
@@ -9,7 +9,7 @@ import Link from '@/core/components/elements/Link/Link'
import axios from 'axios'
const PreferredBrand = () => {
- let query = 'level_s'
+ let query = ''
let params = 'prioritas'
const [isLoading, setIsLoading] = useState(true)
const [startWith, setStartWith] = useState(null)
@@ -18,7 +18,7 @@ const PreferredBrand = () => {
const loadBrand = useCallback(async () => {
setIsLoading(true)
const name = startWith ? `${startWith}*` : ''
- const result = await axios(`${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/brands?params=${name}`)
+ const result = await axios(`${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/brands?rows=20`)
setIsLoading(false)
setManufactures((manufactures) => [...result.data])
@@ -35,9 +35,9 @@ const PreferredBrand = () => {
useEffect(() => {
loadBrand()
- }, [loadBrand])
+ }, [])
- const { preferredBrands } = usePreferredBrand(query)
+ // const { preferredBrands } = usePreferredBrand(query)
const { isMobile, isDesktop } = useDevice()
const swiperBanner = {
modules:[Navigation, Pagination, Autoplay],
@@ -59,7 +59,7 @@ const PreferredBrand = () => {
return (
<div className='px-4 sm:px-0'>
<div className='flex justify-between items-center mb-4'>
- <div className='font-semibold sm:text-h-lg'>Brand Pilihan</div>
+ <h1 className='font-semibold text-[14px] sm:text-h-lg'><Link href='/shop/brands' className='!text-black font-semibold'>Brand Pilihan</Link></h1>
{isDesktop && (
<Link href='/shop/brands' className='!text-red-500 font-semibold'>
Lihat Semua
diff --git a/src/lib/home/components/PromotionProgram.jsx b/src/lib/home/components/PromotionProgram.jsx
index c2f76069..ae8d5d6f 100644
--- a/src/lib/home/components/PromotionProgram.jsx
+++ b/src/lib/home/components/PromotionProgram.jsx
@@ -16,7 +16,7 @@ const BannerSection = () => {
return (
<div className='px-4 sm:px-0'>
<div className='flex justify-between items-center mb-4 '>
- <div className='font-semibold sm:text-h-lg'>Promo Tersedia</div>
+ <h1 className='font-semibold text-[14px] sm:text-h-lg'> <Link href='/shop/promo' className='!text-black font-semibold' >Promo Tersedia</Link></h1>
{isDesktop && (
<Link href='/shop/promo' className='!text-red-500 font-semibold'>
Lihat Semua
diff --git a/src/lib/product/api/productSimilarApi.js b/src/lib/product/api/productSimilarApi.js
index ecd6724a..51cc17fa 100644
--- a/src/lib/product/api/productSimilarApi.js
+++ b/src/lib/product/api/productSimilarApi.js
@@ -19,7 +19,7 @@ const productSimilarApi = async ({ query, source }) => {
}
}
const dataProductSimilar = await axios(
- `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/search?q=${query}&page=1&orderBy=popular-weekly&operation=OR&priceFrom=1`
+ `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/search?q=${query}&page=1&orderBy=popular-weekly&operation=OR&priceFrom=1&source=similar`
)
if (dataflashSale) {
dataProductSimilar.data.response.products = [
diff --git a/src/pages/api/activation-request.js b/src/pages/api/activation-request.js
index 98d27f78..2b8ccec3 100644
--- a/src/pages/api/activation-request.js
+++ b/src/pages/api/activation-request.js
@@ -1,27 +1,29 @@
-import odooApi from '@/core/api/odooApi'
-import mailer from '@/core/utils/mailer'
+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 })
+ const { email } = req.body;
+ let result = await odooApi('POST', '/api/v1/user/activation-request', {
+ email,
+ });
if (result.activationRequest) {
mailer.sendMail({
- from: 'Indoteknik.com <noreply@indoteknik.com>',
+ from: 'noreply@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.NEXT_PUBLIC_SELF_HOST}/activate?token=${result.token}">Aktivasi Akun</a></p>
- `
- })
+ `,
+ });
}
- delete result.user
- delete result.token
- res.status(200).json(result)
+ delete result.user;
+ delete result.token;
+ res.status(200).json(result);
} catch (error) {
- console.log(error)
- res.status(400).json({ error: error.message })
+ console.log(error);
+ res.status(400).json({ error: error.message });
}
}
diff --git a/src/pages/api/shop/brands.js b/src/pages/api/shop/brands.js
index cc64a7e7..9c2824b3 100644
--- a/src/pages/api/shop/brands.js
+++ b/src/pages/api/shop/brands.js
@@ -24,6 +24,8 @@ export default async function handler(req, res) {
params = `name_s:${req.query.params}`.toLowerCase();
}
}
+ if(req.query.rows) rows = req.query.rows;
+
const url = `${SOLR_HOST}/solr/brands/select?q=${params}&q.op=OR&indent=true&rows=${rows}&${sort}`;
let brands = await axios(url);
let dataBrands = responseMap(brands.data.response.docs);
diff --git a/src/pages/api/shop/finish-checkout.js b/src/pages/api/shop/finish-checkout.js
index 9eaa36db..4dcc915c 100644
--- a/src/pages/api/shop/finish-checkout.js
+++ b/src/pages/api/shop/finish-checkout.js
@@ -1,60 +1,66 @@
-import odooApi from '@/core/api/odooApi'
-import mailer from '@/core/utils/mailer'
-import FinishCheckoutEmail from '@/lib/checkout/email/FinishCheckoutEmail'
-import { render } from '@react-email/render'
-import axios from 'axios'
-import camelcaseObjectDeep from 'camelcase-object-deep'
+import odooApi from '@/core/api/odooApi';
+import mailer from '@/core/utils/mailer';
+import FinishCheckoutEmail from '@/lib/checkout/email/FinishCheckoutEmail';
+import { render } from '@react-email/render';
+import axios from 'axios';
+import camelcaseObjectDeep from 'camelcase-object-deep';
export default async function handler(req, res) {
- const { orderName = null } = req.query
+ const { orderName = null } = req.query;
if (!orderName) {
- return res.status(422).json({ error: 'parameter missing' })
+ return res.status(422).json({ error: 'parameter missing' });
}
- let { auth } = req.cookies
+ let { auth } = req.cookies;
if (!auth) {
- return res.status(401).json({ error: 'Unauthorized' })
+ return res.status(401).json({ error: 'Unauthorized' });
}
- auth = JSON.parse(auth)
+ auth = JSON.parse(auth);
- const midtransAuthKey = btoa(process.env.MIDTRANS_SERVER_KEY + ':')
+ const midtransAuthKey = btoa(process.env.MIDTRANS_SERVER_KEY + ':');
const midtransHeaders = {
Accept: 'application/json',
'Content-Type': 'application/json',
- Authorization: `Basic ${midtransAuthKey}`
- }
- let midtransStatus = {}
+ Authorization: `Basic ${midtransAuthKey}`,
+ };
+ let midtransStatus = {};
try {
- midtransStatus = await axios.get(`${process.env.MIDTRANS_HOST}/v2/${orderName}/status`, {
- headers: midtransHeaders
- })
- midtransStatus = camelcaseObjectDeep(midtransStatus.data)
+ midtransStatus = await axios.get(
+ `${process.env.MIDTRANS_HOST}/v2/${orderName}/status`,
+ {
+ headers: midtransHeaders,
+ }
+ );
+ midtransStatus = camelcaseObjectDeep(midtransStatus.data);
} catch (error) {
- console.log(error)
+ console.log(error);
}
- let statusPayment = 'manual'
+ let statusPayment = 'manual';
if (midtransStatus?.orderId) {
- const transactionStatus = midtransStatus.transactionStatus
- statusPayment = 'failed'
+ const transactionStatus = midtransStatus.transactionStatus;
+ statusPayment = 'failed';
if (['capture', 'settlement'].includes(transactionStatus)) {
- statusPayment = 'success'
+ statusPayment = 'success';
} else if (transactionStatus == 'pending') {
- statusPayment = 'pending'
+ statusPayment = 'pending';
}
}
- const query = `name=${orderName.replaceAll('-', '/')}&limit=1&context=quotation`
+ const query = `name=${orderName.replaceAll(
+ '-',
+ '/'
+ )}&limit=1&context=quotation`;
const searchTransaction = await odooApi(
'GET',
`/api/v1/partner/${auth.partnerId}/sale_order?${query}`,
{},
{ Token: auth.token }
- )
+ );
if (searchTransaction.saleOrderTotal == 0) {
- return res.status(400).json({ error: 'Transaction Not Found' })
+ return res.status(400).json({ error: 'Transaction Not Found' });
}
let transaction = await odooApi(
@@ -62,17 +68,17 @@ export default async function handler(req, res) {
`/api/v1/partner/${auth.partnerId}/sale_order/${searchTransaction.saleOrders[0].id}`,
{},
{ Token: auth.token }
- )
+ );
if (!transaction?.id) {
- return res.status(400).json({ error: 'Transaction Detail Not Found' })
+ return res.status(400).json({ error: 'Transaction Detail Not Found' });
}
- transaction.subtotal = 0
- transaction.discountTotal = 0
+ transaction.subtotal = 0;
+ transaction.discountTotal = 0;
for (const product of transaction.products) {
- transaction.subtotal += product.price.price * product.quantity
+ transaction.subtotal += product.price.price * product.quantity;
transaction.discountTotal -=
- (product.price.price - product.price.priceDiscount) * product.quantity
+ (product.price.price - product.price.priceDiscount) * product.quantity;
}
const emailMessage = render(
@@ -81,14 +87,14 @@ export default async function handler(req, res) {
payment={midtransStatus}
statusPayment={statusPayment}
/>
- )
+ );
mailer.sendMail({
- from: 'sales@indoteknik.com',
+ from: 'noreply@indoteknik.com',
to: transaction.address.customer.email,
subject: 'Pembelian di Indoteknik.com',
- html: emailMessage
- })
+ html: emailMessage,
+ });
- return res.status(200).json({ description: 'success' })
+ return res.status(200).json({ description: 'success' });
}
diff --git a/src/pages/index.jsx b/src/pages/index.jsx
index 0e87205e..6077c192 100644
--- a/src/pages/index.jsx
+++ b/src/pages/index.jsx
@@ -18,7 +18,7 @@ import { getAuth } from '~/libs/auth';
import useProductDetail from '~/modules/product-detail/stores/useProductDetail';
const BasicLayout = dynamic(() =>
- import('@/core/components/layouts/BasicLayout')
+ import('@/core/components/layouts/BasicLayout'),{ssr: false}
);
const HeroBanner = dynamic(() => import('@/components/ui/HeroBanner'), {
loading: () => <HeroBannerSkeleton />,
@@ -55,24 +55,24 @@ const ProgramPromotion = dynamic(() =>
);
const BannerSection = dynamic(() =>
- import('@/lib/home/components/BannerSection')
+ import('@/lib/home/components/BannerSection'), {ssr: false}
);
const CategoryHomeId = dynamic(() =>
- import('@/lib/home/components/CategoryHomeId')
+ import('@/lib/home/components/CategoryHomeId'), {ssr: false}
);
const CategoryDynamic = dynamic(() =>
- import('@/lib/home/components/CategoryDynamic')
+ import('@/lib/home/components/CategoryDynamic'), {ssr: false}
);
const CategoryDynamicMobile = dynamic(() =>
-import('@/lib/home/components/CategoryDynamicMobile')
+import('@/lib/home/components/CategoryDynamicMobile'), {ssr: false}
);
const CustomerReviews = dynamic(() =>
- import('@/lib/review/components/CustomerReviews')
+ import('@/lib/review/components/CustomerReviews'), {ssr: false}
); // need to ssr:false
-const ServiceList = dynamic(() => import('@/lib/home/components/ServiceList')); // need to ssr: false
+const ServiceList = dynamic(() => import('@/lib/home/components/ServiceList'), {ssr: false}); // need to ssr: false
@@ -148,11 +148,11 @@ export default function Home({categoryId}) {
</DelayRender>
</>
)}
- <PromotinProgram />
+ {/* <PromotinProgram /> */}
{dataCategories &&(
<CategoryPilihan categories={dataCategories} />
)}
- <CategoryDynamic />
+ <CategoryDynamic />
<CategoryHomeId />
<BannerSection />
<CustomerReviews />
@@ -183,7 +183,7 @@ export default function Home({categoryId}) {
</>
)}
<DelayRender renderAfter={600}>
- <PromotinProgram />
+ {/* <PromotinProgram /> */}
</DelayRender>
<DelayRender renderAfter={600}>
{dataCategories &&(
diff --git a/src/pages/login.jsx b/src/pages/login.jsx
index 9a1aa85b..07d13784 100644
--- a/src/pages/login.jsx
+++ b/src/pages/login.jsx
@@ -1,3 +1,5 @@
+import { useEffect } from 'react';
+import { useRouter } from 'next/router';
import Seo from '@/core/components/Seo';
import SimpleFooter from '@/core/components/elements/Footer/SimpleFooter';
import BasicLayout from '@/core/components/layouts/BasicLayout';
@@ -5,8 +7,18 @@ import DesktopView from '@/core/components/views/DesktopView';
import MobileView from '@/core/components/views/MobileView';
import LoginComponent from '@/lib/auth/components/Login';
import AccountActivation from '~/modules/account-activation';
+import useAuth from '@/core/hooks/useAuth';
export default function Login() {
+ const router = useRouter();
+ const auth = useAuth();
+
+ useEffect(() => {
+ if (auth) {
+ router.push('/');
+ }
+ }, [auth, router]);
+
return (
<>
<Seo title='Login - Indoteknik.com' />
diff --git a/src/pages/my/address/[id]/edit.jsx b/src/pages/my/address/[id]/edit.jsx
index bd680b90..c552659b 100644
--- a/src/pages/my/address/[id]/edit.jsx
+++ b/src/pages/my/address/[id]/edit.jsx
@@ -1,11 +1,11 @@
-import Seo from '@/core/components/Seo'
-import AppLayout from '@/core/components/layouts/AppLayout'
-import BasicLayout from '@/core/components/layouts/BasicLayout'
-import DesktopView from '@/core/components/views/DesktopView'
-import MobileView from '@/core/components/views/MobileView'
-import addressApi from '@/lib/address/api/addressApi'
-import EditAddressComponent from '@/lib/address/components/EditAddress'
-import IsAuth from '@/lib/auth/components/IsAuth'
+import Seo from '@/core/components/Seo';
+import AppLayout from '@/core/components/layouts/AppLayout';
+import BasicLayout from '@/core/components/layouts/BasicLayout';
+import DesktopView from '@/core/components/views/DesktopView';
+import MobileView from '@/core/components/views/MobileView';
+import addressApi from '@/lib/address/api/addressApi';
+import EditAddressComponent from '@/lib/address/components/EditAddress';
+import IsAuth from '@/lib/auth/components/IsAuth';
export default function EditAddress({ id, defaultValues }) {
return (
@@ -24,12 +24,12 @@ export default function EditAddress({ id, defaultValues }) {
</BasicLayout>
</DesktopView>
</IsAuth>
- )
+ );
}
export async function getServerSideProps(context) {
- const { id } = context.query
- const address = await addressApi({ id })
+ const { id } = context.query;
+ const address = await addressApi({ id });
const defaultValues = {
type: address.type,
name: address.name,
@@ -41,7 +41,8 @@ export async function getServerSideProps(context) {
oldDistrict: address.district?.id || '',
district: '',
oldSubDistrict: address.subDistrict?.id || '',
- subDistrict: ''
- }
- return { props: { id, defaultValues } }
+ subDistrict: '',
+ business_name: '',
+ };
+ return { props: { id, defaultValues } };
}
diff --git a/src/styles/globals.css b/src/styles/globals.css
index b3ca85f4..6447284e 100644
--- a/src/styles/globals.css
+++ b/src/styles/globals.css
@@ -98,7 +98,7 @@ button {
border
text-gray_r-12
border-gray_r-7
- !bg-white
+ bg-white
bg-transparent
w-full
leading-none
@@ -117,7 +117,7 @@ button {
}
.form-msg-danger {
- @apply text-danger-600 mt-2 block;
+ @apply text-danger-600 mt-2 block text-sm;
}
.btn-yellow,
diff --git a/tsconfig.json b/tsconfig.json
index 3afcd9ea..96670169 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,11 +1,7 @@
{
"compilerOptions": {
"target": "ES5",
- "lib": [
- "DOM",
- "DOM.Iterable",
- "ESNext"
- ],
+ "lib": ["DOM", "DOM.Iterable", "ESNext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
@@ -33,10 +29,10 @@
"**/*.ts",
"**/*.tsx",
"**/*.jsx",
- ".next/types/**/*.ts"
-, "src/pages/shop/promo/index.tsx", "src/pages/shop/promo/[slug].jsx", "src/lib/promo/hooks/usePromotionSearch.js" ],
- "exclude": [
- "node_modules",
- "src"
- ]
+ ".next/types/**/*.ts",
+ "src-migrate/**/*",
+ "src/pages/shop/promo/index.tsx",
+ "src/pages/shop/promo/[slug].jsx"
+ ],
+ "exclude": ["node_modules", "src"]
}