summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--package.json3
-rw-r--r--src/components/Fields.js19
-rw-r--r--src/pages/my/address/[id]/edit.js307
-rw-r--r--src/pages/my/address/create.js323
4 files changed, 329 insertions, 323 deletions
diff --git a/package.json b/package.json
index b560c22b..645510b2 100644
--- a/package.json
+++ b/package.json
@@ -10,9 +10,9 @@
},
"dependencies": {
"@heroicons/react": "^2.0.13",
+ "@hookform/resolvers": "^2.9.10",
"axios": "^1.1.3",
"cookies-next": "^2.1.1",
- "formik": "^2.2.9",
"framer-motion": "^7.6.7",
"lodash": "^4.17.21",
"next": "13.0.0",
@@ -20,6 +20,7 @@
"nodemailer": "^6.8.0",
"react": "18.2.0",
"react-dom": "18.2.0",
+ "react-hook-form": "^7.42.1",
"react-hot-toast": "^2.4.0",
"react-infinite-scroll-component": "^6.1.0",
"react-lazy-load-image-component": "^1.5.5",
diff --git a/src/components/Fields.js b/src/components/Fields.js
index 3db8bfdd..586a6a22 100644
--- a/src/components/Fields.js
+++ b/src/components/Fields.js
@@ -1,20 +1,19 @@
import ReactSelect from "react-select";
const Select = ({
- options,
- name,
- setFieldValue,
- value,
- disabled
+ field,
+ ...props
}) => (
+ <>
<ReactSelect
classNamePrefix="form-select"
- options={options}
- name={name}
- onChange={(option) => setFieldValue(name, option.value)}
- value={value ? options.find(option => option.value === value) : ''}
- isDisabled={disabled}
+ ref={field.ref}
+ onChange={(option) => field.onChange(option.value)}
+ value={field.value ? props.options.find(option => option.value === field.value) : ''}
+ isDisabled={props.disabled}
+ {...props}
/>
+ </>
);
export {
diff --git a/src/pages/my/address/[id]/edit.js b/src/pages/my/address/[id]/edit.js
index 98bd05e7..78eef635 100644
--- a/src/pages/my/address/[id]/edit.js
+++ b/src/pages/my/address/[id]/edit.js
@@ -1,8 +1,9 @@
-import { useFormik } from "formik";
-import * as Yup from "yup";
+import { Controller, useForm } from "react-hook-form"
import WithAuth from "../../../../components/WithAuth";
import Layout from "../../../../components/Layout";
import AppBar from "../../../../components/AppBar";
+import { yupResolver } from "@hookform/resolvers/yup";
+import * as Yup from "yup";
import { Select } from "../../../../components/Fields";
import { useEffect, useState } from "react";
import apiOdoo from "../../../../helpers/apiOdoo";
@@ -29,7 +30,7 @@ const types = [
export async function getServerSideProps( context ) {
const { id } = context.query;
const address = await apiOdoo('GET', `/api/v1/partner/${id}/address`);
- let initialValues = {
+ let defaultValues = {
type: address.type,
name: address.name,
email: address.email,
@@ -37,197 +38,199 @@ export async function getServerSideProps( context ) {
street: address.street,
zip: address.zip,
city: address.city?.id,
- district: address.district?.id || null,
- subDistrict: address.sub_district?.id || null
+ district: address.district?.id || '',
+ subDistrict: address.sub_district?.id || ''
};
- return { props: { id, initialValues } };
+ return { props: { id, defaultValues } };
}
-export default function EditAddress({ id, initialValues }) {
+export default function CreateAddress({ id, defaultValues }) {
const router = useRouter();
-
- const onSubmit = async (values) => {
- const parameters = {
- ...values,
- city_id: values.city,
- district_id: values.district,
- sub_district_id: values.subDistrict
- }
-
- const address = await apiOdoo('PUT', `/api/v1/partner/${id}/address`, parameters);
- if (address?.id) {
- toast.success('Berhasil mengubah alamat');
- router.back();
- }
- };
-
- const form = useFormik({ initialValues, validationSchema, onSubmit });
-
const {
- values,
- errors,
- touched,
- handleChange,
+ register,
+ formState: { errors },
handleSubmit,
- setFieldValue,
- } = form;
+ watch,
+ setValue,
+ control,
+ } = useForm({
+ resolver: yupResolver(validationSchema),
+ defaultValues
+ });
const [ cities, setCities ] = useState([]);
const [ districts, setDistricts ] = useState([]);
const [ subDistricts, setSubDistricts ] = useState([]);
- useEffect(() => {
- const loadCities = async () => {
- let dataCities = await apiOdoo('GET', '/api/v1/city');
+ useEffect(() => {
+ const loadCities = async () => {
+ let dataCities = await apiOdoo('GET', '/api/v1/city');
dataCities = dataCities.map((city) => ({ value: city.id, label: city.name }));
setCities(dataCities);
};
loadCities();
}, []);
-
+
+ const watchCity = watch('city');
useEffect(() => {
- setFieldValue('district', '');
- if (values.city) {
+ setValue('district', '');
+ if (watchCity) {
const loadDistricts = async () => {
- let dataDistricts = await apiOdoo('GET', `/api/v1/district?city_id=${values.city}`);
+ let dataDistricts = await apiOdoo('GET', `/api/v1/district?city_id=${watchCity}`);
dataDistricts = dataDistricts.map((district) => ({ value: district.id, label: district.name }));
setDistricts(dataDistricts);
};
loadDistricts();
}
- }, [ values.city, setFieldValue ]);
-
- useEffect(() => {
- setFieldValue('subDistrict', '');
- if (values.district) {
+ }, [ watchCity, setValue ]);
+
+ const watchDistrict = watch('district');
+ useEffect(() => {
+ setValue('subDistrict', '');
+ if (watchDistrict) {
const loadSubDistricts = async () => {
- let dataSubDistricts = await apiOdoo('GET', `/api/v1/sub_district?district_id=${values.district}`);
+ let dataSubDistricts = await apiOdoo('GET', `/api/v1/sub_district?district_id=${watchDistrict}`);
dataSubDistricts = dataSubDistricts.map((district) => ({ value: district.id, label: district.name }));
setSubDistricts(dataSubDistricts);
};
loadSubDistricts();
}
- }, [ values.district, setFieldValue ]);
+ }, [ watchDistrict, setValue ])
+
+ const onSubmitHandler = async (values) => {
+ const parameters = {
+ ...values,
+ city_id: values.city,
+ district_id: values.district,
+ sub_district_id: values.subDistrict
+ }
+
+ const address = await apiOdoo('PUT', `/api/v1/partner/${id}/address`, parameters);
+ if (address?.id) {
+ toast.success('Berhasil mengubah alamat');
+ router.back();
+ }
+ };
return (
<WithAuth>
<Layout>
<AppBar title="Ubah Alamat" />
- <form onSubmit={handleSubmit} className="p-4 pt-0">
- <label className="form-label mt-4 mb-2">Label Alamat</label>
- <Select
- name="type"
- options={types}
- setFieldValue={setFieldValue}
- value={values.type}
- />
- { errors.type && touched.type && (
- <div className="text-caption-2 text-red_r-11 mt-1">{ errors.type }</div>
- ) }
-
- <label className="form-label mt-4 mb-2">Nama</label>
- <input
- type="text"
- className="form-input"
- placeholder="John Doe"
- onChange={handleChange}
- value={values.name}
- name="name"
- />
- { errors.name && touched.name && (
- <div className="text-caption-2 text-red_r-11 mt-1">{ errors.name }</div>
- ) }
-
- <label className="form-label mt-4 mb-2">Email</label>
- <input
- type="email"
- className="form-input"
- placeholder="johndoe@example.com"
- onChange={handleChange}
- value={values.email}
- name="email"
- />
- { errors.email && touched.email && (
- <div className="text-caption-2 text-red_r-11 mt-1">{ errors.email }</div>
- ) }
-
- <label className="form-label mt-4 mb-2">No. Handphone</label>
- <input
- type="tel"
- className="form-input"
- placeholder="08xxxxxxxx"
- onChange={handleChange}
- value={values.mobile}
- name="mobile"
- />
- { errors.mobile && touched.mobile && (
- <div className="text-caption-2 text-red_r-11 mt-1">{ errors.mobile }</div>
- ) }
-
- <label className="form-label mt-4 mb-2">Alamat</label>
- <input
- type="text"
- className="form-input"
- placeholder="Jl. Bandengan Utara 85A"
- onChange={handleChange}
- value={values.street}
- name="street"
- />
- { errors.street && touched.street && (
- <div className="text-caption-2 text-red_r-11 mt-1">{ errors.street }</div>
- ) }
-
- <label className="form-label mt-4 mb-2">Kode Pos</label>
- <input
- type="number"
- className="form-input"
- placeholder="10100"
- onChange={handleChange}
- value={values.zip}
- name="zip"
- />
- { errors.zip && touched.zip && (
- <div className="text-caption-2 text-red_r-11 mt-1">{ errors.zip }</div>
- ) }
-
- <label className="form-label mt-4 mb-2">Kota</label>
- <Select
- name="city"
- options={cities}
- setFieldValue={setFieldValue}
- value={values.city}
- />
- { errors.city && touched.city && (
- <div className="text-caption-2 text-red_r-11 mt-1">{ errors.city }</div>
- ) }
-
- <label className="form-label mt-4 mb-2">Kecamatan</label>
- <Select
- name="district"
- options={districts}
- setFieldValue={setFieldValue}
- value={values.district}
- disabled={!values.city}
- />
-
- <label className="form-label mt-4 mb-2">Kelurahan</label>
- <Select
- name="subDistrict"
- options={subDistricts}
- setFieldValue={setFieldValue}
- value={values.subDistrict}
- disabled={!values.district}
- />
+ <form className="p-4 flex flex-col gap-y-4" onSubmit={handleSubmit(onSubmitHandler)}>
+ <div>
+ <label className="form-label mb-2">Label Alamat</label>
+ <Controller
+ name="type"
+ control={control}
+ render={props => <Select {...props} options={types} />}
+ />
+ <div className="text-caption-2 text-red_r-11 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-red_r-11 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-red_r-11 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-red_r-11 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-red_r-11 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-red_r-11 mt-1">{ errors.zip?.message }</div>
+ </div>
+
+ <div>
+ <label className="form-label mb-2">Kota</label>
+ <Controller
+ name="city"
+ control={control}
+ render={props => <Select {...props} options={cities} />}
+ />
+ <div className="text-caption-2 text-red_r-11 mt-1">{ errors.city?.message }</div>
+ </div>
+
+ <div>
+ <label className="form-label mb-2">Kecamatan</label>
+ <Controller
+ name="district"
+ control={control}
+ render={props => (
+ <Select
+ {...props}
+ options={districts}
+ disabled={!watchCity}
+ />
+ )}
+ />
+ </div>
+
+ <div>
+ <label className="form-label mb-2">Kelurahan</label>
+ <Controller
+ name="subDistrict"
+ control={control}
+ render={props => (
+ <Select
+ {...props}
+ options={subDistricts}
+ disabled={!watchDistrict}
+ />
+ )}
+ />
+ </div>
<button
type="submit"
- className="btn-yellow mt-6 w-full"
+ className="btn-yellow mt-2 w-full"
>
Simpan
</button>
</form>
</Layout>
</WithAuth>
- );
+ )
} \ No newline at end of file
diff --git a/src/pages/my/address/create.js b/src/pages/my/address/create.js
index b04e67ec..5e9aaab8 100644
--- a/src/pages/my/address/create.js
+++ b/src/pages/my/address/create.js
@@ -1,8 +1,9 @@
-import { useFormik } from "formik";
-import * as Yup from "yup";
+import { Controller, useForm } from "react-hook-form"
import WithAuth from "../../../components/WithAuth";
import Layout from "../../../components/Layout";
import AppBar from "../../../components/AppBar";
+import { yupResolver } from "@hookform/resolvers/yup";
+import * as Yup from "yup";
import { Select } from "../../../components/Fields";
import { useEffect, useState } from "react";
import apiOdoo from "../../../helpers/apiOdoo";
@@ -10,7 +11,17 @@ import { useAuth } from "../../../helpers/auth";
import { toast } from "react-hot-toast";
import { useRouter } from "next/router";
-const initialValues = {
+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 johndoe@example.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.number().required('Harus di-pilih'),
+});
+
+const defaultValues = {
type: '',
name: '',
email: '',
@@ -22,16 +33,6 @@ const initialValues = {
zip: '',
};
-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 johndoe@example.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.number().required('Harus di-pilih'),
-});
-
const types = [
{ value: 'contact', label: 'Contact Address' },
{ value: 'invoice', label: 'Invoice Address' },
@@ -40,192 +41,194 @@ const types = [
];
export default function CreateAddress() {
- const [auth] = useAuth();
+ const [ auth ] = useAuth();
const router = useRouter();
-
- const onSubmit = async (values) => {
- const parameters = {
- ...values,
- city_id: values.city,
- district_id: values.district,
- sub_district_id: values.subDistrict,
- parent_id: auth.partner_id
- }
-
- const address = await apiOdoo('POST', '/api/v1/partner/address', parameters);
- if (address?.id) {
- toast.success('Berhasil menambahkan alamat');
- router.back();
- }
- };
-
- const form = useFormik({ initialValues, validationSchema, onSubmit });
-
const {
- values,
- errors,
- touched,
- handleChange,
+ register,
+ formState: { errors },
handleSubmit,
- setFieldValue,
- } = form;
+ watch,
+ setValue,
+ control,
+ } = useForm({
+ resolver: yupResolver(validationSchema),
+ defaultValues
+ });
const [ cities, setCities ] = useState([]);
const [ districts, setDistricts ] = useState([]);
const [ subDistricts, setSubDistricts ] = useState([]);
- useEffect(() => {
- const loadCities = async () => {
- let dataCities = await apiOdoo('GET', '/api/v1/city');
+ useEffect(() => {
+ const loadCities = async () => {
+ let dataCities = await apiOdoo('GET', '/api/v1/city');
dataCities = dataCities.map((city) => ({ value: city.id, label: city.name }));
setCities(dataCities);
};
loadCities();
}, []);
-
+
+ const watchCity = watch('city');
useEffect(() => {
- setFieldValue('district', '');
- if (values.city) {
+ setValue('district', '');
+ if (watchCity) {
const loadDistricts = async () => {
- let dataDistricts = await apiOdoo('GET', `/api/v1/district?city_id=${values.city}`);
+ let dataDistricts = await apiOdoo('GET', `/api/v1/district?city_id=${watchCity}`);
dataDistricts = dataDistricts.map((district) => ({ value: district.id, label: district.name }));
setDistricts(dataDistricts);
};
loadDistricts();
}
- }, [ values.city, setFieldValue ]);
-
- useEffect(() => {
- setFieldValue('subDistrict', '');
- if (values.district) {
+ }, [ watchCity, setValue ]);
+
+ const watchDistrict = watch('district');
+ useEffect(() => {
+ setValue('subDistrict', '');
+ if (watchDistrict) {
const loadSubDistricts = async () => {
- let dataSubDistricts = await apiOdoo('GET', `/api/v1/sub_district?district_id=${values.district}`);
+ let dataSubDistricts = await apiOdoo('GET', `/api/v1/sub_district?district_id=${watchDistrict}`);
dataSubDistricts = dataSubDistricts.map((district) => ({ value: district.id, label: district.name }));
setSubDistricts(dataSubDistricts);
};
loadSubDistricts();
}
- }, [ values.district, setFieldValue ]);
+ }, [ watchDistrict, setValue ])
+
+ const onSubmitHandler = async (values) => {
+ const parameters = {
+ ...values,
+ city_id: values.city,
+ district_id: values.district,
+ sub_district_id: values.subDistrict,
+ parent_id: auth.partner_id
+ };
+
+ const address = await apiOdoo('POST', '/api/v1/partner/address', parameters);
+ if (address?.id) {
+ toast.success('Berhasil menambahkan alamat');
+ router.back();
+ }
+ };
return (
<WithAuth>
<Layout>
<AppBar title="Tambah Alamat" />
- <form onSubmit={handleSubmit} className="p-4 pt-0">
- <label className="form-label mt-4 mb-2">Label Alamat</label>
- <Select
- name="type"
- options={types}
- setFieldValue={setFieldValue}
- value={values.type}
- />
- { errors.type && touched.type && (
- <div className="text-caption-2 text-red_r-11 mt-1">{ errors.type }</div>
- ) }
-
- <label className="form-label mt-4 mb-2">Nama</label>
- <input
- type="text"
- className="form-input"
- placeholder="John Doe"
- onChange={handleChange}
- value={values.name}
- name="name"
- />
- { errors.name && touched.name && (
- <div className="text-caption-2 text-red_r-11 mt-1">{ errors.name }</div>
- ) }
-
- <label className="form-label mt-4 mb-2">Email</label>
- <input
- type="email"
- className="form-input"
- placeholder="johndoe@example.com"
- onChange={handleChange}
- value={values.email}
- name="email"
- />
- { errors.email && touched.email && (
- <div className="text-caption-2 text-red_r-11 mt-1">{ errors.email }</div>
- ) }
-
- <label className="form-label mt-4 mb-2">No. Handphone</label>
- <input
- type="tel"
- className="form-input"
- placeholder="08xxxxxxxx"
- onChange={handleChange}
- value={values.mobile}
- name="mobile"
- />
- { errors.mobile && touched.mobile && (
- <div className="text-caption-2 text-red_r-11 mt-1">{ errors.mobile }</div>
- ) }
-
- <label className="form-label mt-4 mb-2">Alamat</label>
- <input
- type="text"
- className="form-input"
- placeholder="Jl. Bandengan Utara 85A"
- onChange={handleChange}
- value={values.street}
- name="street"
- />
- { errors.street && touched.street && (
- <div className="text-caption-2 text-red_r-11 mt-1">{ errors.street }</div>
- ) }
-
- <label className="form-label mt-4 mb-2">Kode Pos</label>
- <input
- type="number"
- className="form-input"
- placeholder="10100"
- onChange={handleChange}
- value={values.zip}
- name="zip"
- />
- { errors.zip && touched.zip && (
- <div className="text-caption-2 text-red_r-11 mt-1">{ errors.zip }</div>
- ) }
-
- <label className="form-label mt-4 mb-2">Kota</label>
- <Select
- name="city"
- options={cities}
- setFieldValue={setFieldValue}
- value={values.city}
- />
- { errors.city && touched.city && (
- <div className="text-caption-2 text-red_r-11 mt-1">{ errors.city }</div>
- ) }
-
- <label className="form-label mt-4 mb-2">Kecamatan</label>
- <Select
- name="district"
- options={districts}
- setFieldValue={setFieldValue}
- value={values.district}
- disabled={!values.city}
- />
-
- <label className="form-label mt-4 mb-2">Kelurahan</label>
- <Select
- name="subDistrict"
- options={subDistricts}
- setFieldValue={setFieldValue}
- value={values.subDistrict}
- disabled={!values.district}
- />
+ <form className="p-4 flex flex-col gap-y-4" onSubmit={handleSubmit(onSubmitHandler)}>
+ <div>
+ <label className="form-label mb-2">Label Alamat</label>
+ <Controller
+ name="type"
+ control={control}
+ render={props => <Select {...props} options={types} />}
+ />
+ <div className="text-caption-2 text-red_r-11 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-red_r-11 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-red_r-11 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-red_r-11 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-red_r-11 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-red_r-11 mt-1">{ errors.zip?.message }</div>
+ </div>
+
+ <div>
+ <label className="form-label mb-2">Kota</label>
+ <Controller
+ name="city"
+ control={control}
+ render={props => <Select {...props} options={cities} />}
+ />
+ <div className="text-caption-2 text-red_r-11 mt-1">{ errors.city?.message }</div>
+ </div>
+
+ <div>
+ <label className="form-label mb-2">Kecamatan</label>
+ <Controller
+ name="district"
+ control={control}
+ render={props => (
+ <Select
+ {...props}
+ options={districts}
+ disabled={!watchCity}
+ />
+ )}
+ />
+ </div>
+
+ <div>
+ <label className="form-label mb-2">Kelurahan</label>
+ <Controller
+ name="subDistrict"
+ control={control}
+ render={props => (
+ <Select
+ {...props}
+ options={subDistricts}
+ disabled={!watchDistrict}
+ />
+ )}
+ />
+ </div>
<button
type="submit"
- className="btn-yellow mt-6 w-full"
+ className="btn-yellow mt-2 w-full"
>
Simpan
</button>
</form>
</Layout>
</WithAuth>
- );
+ )
} \ No newline at end of file