diff options
| author | IT Fixcomart <it@fixcomart.co.id> | 2023-03-01 09:18:52 +0000 |
|---|---|---|
| committer | IT Fixcomart <it@fixcomart.co.id> | 2023-03-01 09:18:52 +0000 |
| commit | a7abbf4ddc70068620e9f44b74dc162ce2e16ee2 (patch) | |
| tree | 74f66253717515d364ce74bd8275015c1f829cbc /src/lib/address/components | |
| parent | 90e1edab9b6a8ccc09a49fed3addbec2cbc4e4c3 (diff) | |
| parent | a1b9b647a6c4bda1f5db63879639d44543f9557e (diff) | |
Merged in refactor (pull request #1)
Refactor
Diffstat (limited to 'src/lib/address/components')
| -rw-r--r-- | src/lib/address/components/Addresses.jsx | 70 | ||||
| -rw-r--r-- | src/lib/address/components/CreateAddress.jsx | 250 | ||||
| -rw-r--r-- | src/lib/address/components/EditAddress.jsx | 252 |
3 files changed, 572 insertions, 0 deletions
diff --git a/src/lib/address/components/Addresses.jsx b/src/lib/address/components/Addresses.jsx new file mode 100644 index 00000000..3ac06b6c --- /dev/null +++ b/src/lib/address/components/Addresses.jsx @@ -0,0 +1,70 @@ +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' + +const Addresses = () => { + const router = useRouter() + const { select = null } = router.query + const auth = useAuth() + const { addresses } = useAddresses() + const selectedAdress = getItemAddress(select || '') + const changeSelectedAddress = (id) => { + if (!select) return + updateItemAddress(select, id) + router.back() + } + + 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 ( + <div className='p-4'> + <div className='text-right'> + <Link href='/my/address/create'>Tambah Alamat</Link> + </div> + + <div className='grid gap-y-4 mt-4'> + {addresses.data?.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 + ? 'border-gray_r-7 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?.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>} + <p className='mt-1 leading-6 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> + </div> + ) +} + +export default Addresses diff --git a/src/lib/address/components/CreateAddress.jsx b/src/lib/address/components/CreateAddress.jsx new file mode 100644 index 00000000..849b4c01 --- /dev/null +++ b/src/lib/address/components/CreateAddress.jsx @@ -0,0 +1,250 @@ +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' + +const 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 cityApi() + 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 districtApi({ cityId: 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 subDistrictApi({ districtId: watchDistrict }) + dataSubDistricts = dataSubDistricts.map((district) => ({ + value: district.id, + label: district.name + })) + setSubDistricts(dataSubDistricts) + } + loadSubDistricts() + } + }, [watchDistrict, setValue]) + + const onSubmitHandler = async (values) => { + const data = { + ...values, + city_id: values.city, + district_id: values.district, + sub_district_id: values.subDistrict, + parent_id: auth.partnerId + } + + const address = await createAddressApi({ data }) + if (address?.id) { + toast.success('Berhasil menambahkan alamat') + router.back() + } + } + + return ( + <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) => ( + <HookFormSelect + {...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='contoh@email.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) => ( + <HookFormSelect + {...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) => ( + <HookFormSelect + {...props} + options={districts} + disabled={!watchCity} + /> + )} + /> + </div> + + <div> + <label className='form-label mb-2'>Kelurahan</label> + <Controller + name='subDistrict' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={subDistricts} + disabled={!watchDistrict} + /> + )} + /> + </div> + + <button + type='submit' + className='btn-yellow mt-2 w-full' + > + Simpan + </button> + </form> + ) +} + +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') +}) + +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 CreateAddress diff --git a/src/lib/address/components/EditAddress.jsx b/src/lib/address/components/EditAddress.jsx new file mode 100644 index 00000000..a832edbc --- /dev/null +++ b/src/lib/address/components/EditAddress.jsx @@ -0,0 +1,252 @@ +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' + +const 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 cityApi() + 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 districtApi({ cityId: 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 subDistrictApi({ + districtId: 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 data = { + ...values, + city_id: values.city, + district_id: values.district, + sub_district_id: values.subDistrict + } + + const address = await editAddressApi({ id, data }) + if (address?.id) { + toast.success('Berhasil mengubah alamat') + router.back() + } + } + + return ( + <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) => ( + <HookFormSelect + {...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) => ( + <HookFormSelect + {...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) => ( + <HookFormSelect + {...props} + options={districts} + disabled={!watchCity} + /> + )} + /> + </div> + + <div> + <label className='form-label mb-2'>Kelurahan</label> + <Controller + name='subDistrict' + control={control} + render={(props) => ( + <HookFormSelect + {...props} + options={subDistricts} + disabled={!watchDistrict} + /> + )} + /> + </div> + + <button + type='submit' + className='btn-yellow mt-2 w-full' + > + Simpan + </button> + </form> + ) +} + +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 default EditAddress |
