diff options
| author | Rafi Zadanly <zadanlyr@gmail.com> | 2023-02-17 17:07:50 +0700 |
|---|---|---|
| committer | Rafi Zadanly <zadanlyr@gmail.com> | 2023-02-17 17:07:50 +0700 |
| commit | f99e0aba70efad0deb907d8e27f09fc9f527c8a4 (patch) | |
| tree | f0ac96e4e736a1d385e32553f0e641ee27e11fd3 /src2/pages/my/address | |
| parent | 90e1edab9b6a8ccc09a49fed3addbec2cbc4e4c3 (diff) | |
Refactor
Diffstat (limited to 'src2/pages/my/address')
| -rw-r--r-- | src2/pages/my/address/[id]/edit.js | 249 | ||||
| -rw-r--r-- | src2/pages/my/address/create.js | 234 | ||||
| -rw-r--r-- | src2/pages/my/address/index.js | 84 |
3 files changed, 567 insertions, 0 deletions
diff --git a/src2/pages/my/address/[id]/edit.js b/src2/pages/my/address/[id]/edit.js new file mode 100644 index 00000000..838d39e7 --- /dev/null +++ b/src2/pages/my/address/[id]/edit.js @@ -0,0 +1,249 @@ +import { Controller, useForm } from "react-hook-form" +import WithAuth from "@/components/auth/WithAuth"; +import Layout from "@/components/layouts/Layout"; +import AppBar from "@/components/layouts/AppBar"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as Yup from "yup"; +import { Select } from "@/components/elements/Fields"; +import { useEffect, useState } from "react"; +import apiOdoo from "@/core/utils/apiOdoo"; +import { toast } from "react-hot-toast"; +import { useRouter } from "next/router"; + +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.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' }, +]; + +export async function getServerSideProps( context ) { + const { id } = context.query; + const address = await apiOdoo('GET', `/api/v1/partner/${id}/address`); + let defaultValues = { + type: address.type, + name: address.name, + email: address.email, + mobile: address.mobile, + street: address.street, + zip: address.zip, + city: address.city?.id || '', + oldDistrict: address.district?.id || '', + district: '', + oldSubDistrict: address.sub_district?.id || '', + subDistrict: '', + }; + return { props: { id, defaultValues } }; +} + +export default function EditAddress({ id, defaultValues }) { + const router = useRouter(); + const { + register, + formState: { errors }, + handleSubmit, + watch, + setValue, + getValues, + 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'); + dataCities = dataCities.map((city) => ({ value: city.id, label: city.name })); + setCities(dataCities); + }; + loadCities(); + }, []); + + const watchCity = watch('city'); + useEffect(() => { + setValue('district', ''); + if (watchCity) { + const loadDistricts = async () => { + let dataDistricts = await apiOdoo('GET', `/api/v1/district?city_id=${watchCity}`); + dataDistricts = dataDistricts.map((district) => ({ value: district.id, label: district.name })); + setDistricts(dataDistricts); + let oldDistrict = getValues('oldDistrict'); + if (oldDistrict) { + setValue('district', oldDistrict); + setValue('oldDistrict', ''); + } + }; + loadDistricts(); + } + }, [ watchCity, setValue, getValues ]); + + const watchDistrict = watch('district'); + useEffect(() => { + setValue('subDistrict', ''); + if (watchDistrict) { + const loadSubDistricts = async () => { + let dataSubDistricts = await apiOdoo('GET', `/api/v1/sub_district?district_id=${watchDistrict}`); + dataSubDistricts = dataSubDistricts.map((district) => ({ value: district.id, label: district.name })); + setSubDistricts(dataSubDistricts); + let oldSubDistrict = getValues('oldSubDistrict'); + if (oldSubDistrict) { + setValue('subDistrict', oldSubDistrict); + setValue('oldSubDistrict', ''); + } + }; + loadSubDistricts(); + } + }, [ watchDistrict, setValue, getValues ]) + + 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 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} isSearchable={false} 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-2 w-full" + > + Simpan + </button> + </form> + </Layout> + </WithAuth> + ) +}
\ No newline at end of file diff --git a/src2/pages/my/address/create.js b/src2/pages/my/address/create.js new file mode 100644 index 00000000..42cd117c --- /dev/null +++ b/src2/pages/my/address/create.js @@ -0,0 +1,234 @@ +import { Controller, useForm } from "react-hook-form" +import WithAuth from "@/components/auth/WithAuth"; +import Layout from "@/components/layouts/Layout"; +import AppBar from "@/components/layouts/AppBar"; +import { yupResolver } from "@hookform/resolvers/yup"; +import * as Yup from "yup"; +import { Select } from "@/components/elements/Fields"; +import { useEffect, useState } from "react"; +import apiOdoo from "@/core/utils/apiOdoo"; +import { useAuth } from "@/core/utils/auth"; +import { toast } from "react-hot-toast"; +import { useRouter } from "next/router"; + +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.string().required('Harus di-pilih'), +}); + +const defaultValues = { + type: '', + name: '', + email: '', + mobile: '', + street: '', + city: '', + district: '', + subDistrict: '', + zip: '', +}; + +const types = [ + { value: 'contact', label: 'Contact Address' }, + { value: 'invoice', label: 'Invoice Address' }, + { value: 'delivery', label: 'Delivery Address' }, + { value: 'other', label: 'Other Address' }, +]; + +export default function CreateAddress() { + const [ auth ] = useAuth(); + const router = useRouter(); + const { + register, + formState: { errors }, + handleSubmit, + 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'); + dataCities = dataCities.map((city) => ({ value: city.id, label: city.name })); + setCities(dataCities); + }; + loadCities(); + }, []); + + const watchCity = watch('city'); + useEffect(() => { + setValue('district', ''); + if (watchCity) { + const loadDistricts = async () => { + let dataDistricts = await apiOdoo('GET', `/api/v1/district?city_id=${watchCity}`); + dataDistricts = dataDistricts.map((district) => ({ value: district.id, label: district.name })); + setDistricts(dataDistricts); + }; + loadDistricts(); + } + }, [ 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=${watchDistrict}`); + dataSubDistricts = dataSubDistricts.map((district) => ({ value: district.id, label: district.name })); + setSubDistricts(dataSubDistricts); + }; + loadSubDistricts(); + } + }, [ 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 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} isSearchable={false} 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-2 w-full" + > + Simpan + </button> + </form> + </Layout> + </WithAuth> + ) +}
\ No newline at end of file diff --git a/src2/pages/my/address/index.js b/src2/pages/my/address/index.js new file mode 100644 index 00000000..5cad4410 --- /dev/null +++ b/src2/pages/my/address/index.js @@ -0,0 +1,84 @@ +import { useEffect, useState } from "react"; +import { useRouter } from "next/router"; + +import AppBar from "@/components/layouts/AppBar"; +import Layout from "@/components/layouts/Layout"; +import Link from "@/components/elements/Link"; +import WithAuth from "@/components/auth/WithAuth"; + +import apiOdoo from "@/core/utils/apiOdoo"; +import { useAuth } from "@/core/utils/auth"; +import { createOrUpdateItemAddress, getItemAddress } from "@/core/utils/address"; +import { toast } from "react-hot-toast"; + +export default function Address() { + const router = useRouter(); + const { select } = router.query; + const [ auth ] = useAuth(); + const [ addresses, setAddresses ] = useState(null); + const [ selectedAdress, setSelectedAdress ] = useState(null); + + useEffect(() => { + const getAddress = async () => { + if (auth) { + const dataAddress = await apiOdoo('GET', `/api/v1/user/${auth.id}/address`); + setAddresses(dataAddress); + } + }; + getAddress(); + }, [auth]); + + useEffect(() => { + if (select) { + setSelectedAdress(getItemAddress(select)); + } + }, [select]); + + const changeSelectedAddress = (id) => { + if (select) { + createOrUpdateItemAddress(select, id); + router.back(); + } + }; + + return ( + <WithAuth> + <Layout> + <AppBar title="Daftar Alamat" /> + + <div className="text-right mt-4 px-4"> + <Link href="/my/address/create">Tambah Alamat</Link> + </div> + + <div className="grid gap-y-4 p-4"> + { auth && addresses && addresses.map((address, index) => { + let type = address.type.charAt(0).toUpperCase() + address.type.slice(1) + ' Address'; + return ( + <div + key={index} + className={"p-4 rounded-md border " + (selectedAdress && selectedAdress == address.id ? "bg-gray_r-4" : "border-gray_r-7") } + > + <div onClick={() => changeSelectedAddress(address.id)}> + <div className="flex gap-x-2" > + <div className="badge-red">{ type }</div> + { auth?.partner_id == 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> + ) } + <p className={`mt-1 leading-6 ${selectedAdress && selectedAdress == address.id ? "text-gray_r-12" : "text-gray_r-11"}`}> + { address.street } + </p> + </div> + <Link href={`/my/address/${address.id}/edit`} className="btn-light bg-white mt-3 w-full text-gray_r-11">Ubah Alamat</Link> + </div> + ); + }) } + </div> + </Layout> + </WithAuth> + ) +}
\ No newline at end of file |
