diff options
| author | Rafi Zadanly <zadanlyr@gmail.com> | 2023-01-13 15:36:28 +0700 |
|---|---|---|
| committer | Rafi Zadanly <zadanlyr@gmail.com> | 2023-01-13 15:36:28 +0700 |
| commit | 1739c6eb03631e08bfe9d5de3a97acbc0a8566ce (patch) | |
| tree | a4e4e9c91059ed5bf68534892b851e22bcba195a /src/pages | |
| parent | cf69435c321eb6866caf75ed2a5391526f499c4e (diff) | |
create "edit" feature and fix "create" feature
Diffstat (limited to 'src/pages')
| -rw-r--r-- | src/pages/my/address/[id]/edit.js | 239 | ||||
| -rw-r--r-- | src/pages/my/address/create.js | 248 | ||||
| -rw-r--r-- | src/pages/my/address/index.js | 33 |
3 files changed, 385 insertions, 135 deletions
diff --git a/src/pages/my/address/[id]/edit.js b/src/pages/my/address/[id]/edit.js new file mode 100644 index 00000000..d2de2815 --- /dev/null +++ b/src/pages/my/address/[id]/edit.js @@ -0,0 +1,239 @@ +import { useRouter } from "next/router"; +import AppBar from "../../../../components/AppBar"; +import Layout from "../../../../components/Layout"; +import WithAuth from "../../../../components/WithAuth"; +import { useAuth } from "../../../../helpers/auth"; +import useFormValidation from "../../../../helpers/formValidation"; +import { useEffect, useState } from "react"; +import apiOdoo from "../../../../helpers/apiOdoo"; +import ReactSelect from "react-select"; +import convertToOption from "../../../../helpers/convertToOption"; +import { toast } from "react-hot-toast"; +import _ from "lodash"; + +const validationScheme = { + type: ['label:Label Alamat', 'required'], + name: ['label:Nama', 'required'], + email: ['label:Email', 'required', 'email'], + mobile: ['label:No. Handphone', 'required', 'maxLength:16'], + street: ['label:Alamat', 'required'], + city: ['label:Kota', 'required'], + zip: ['label:Kode Pos', 'required'] +}; + +const typesSelection = [ + { 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 initialFormValue = { + type: typesSelection.find((x) => x.value == address.type), + name: address.name, + email: address.email, + mobile: address.mobile, + street: address.street, + zip: address.zip, + city: convertToOption(address.city), + district: convertToOption(address.district), + subDistrict: convertToOption(address.sub_district) + }; + return { props: { id, initialFormValue } }; +} + +export default function EditAddress({ id, initialFormValue }) { + const [auth] = useAuth(); + const router = useRouter(); + + // Master Data + const [cities, setCities] = useState([]); + const [districts, setDistricts] = useState([]); + const [subDistricts, setSubDistricts] = useState([]); + + const { + formInputs, + formErrors, + handleInputChange, + handleSelectChange, + handleFormSubmit, + hasChangedInputs + } = useFormValidation({ validationScheme, initialFormValue }); + + useEffect(() => { + if (cities.length == 0) { + const loadCities = async () => { + let dataCities = await apiOdoo('GET', '/api/v1/city'); + dataCities = dataCities.map((city) => ({ value: city.id, label: city.name })); + setCities(dataCities); + }; + loadCities(); + } + }, [cities]); + + useEffect(() => { + if (hasChangedInputs?.city) handleSelectChange('district', null); + if (formInputs.city) { + const loadDistricts = async () => { + let dataDistricts = await apiOdoo('GET', `/api/v1/district?city_id=${formInputs.city.value}`); + dataDistricts = dataDistricts.map((district) => ({ value: district.id, label: district.name })); + setDistricts(dataDistricts); + }; + loadDistricts(); + } + }, [ formInputs.city, hasChangedInputs.city, handleSelectChange ]); + + useEffect(() => { + if (hasChangedInputs?.district) handleSelectChange('subDistrict', null); + if (formInputs.district) { + const loadSubDistricts = async () => { + let dataSubDistricts = await apiOdoo('GET', `/api/v1/sub_district?district_id=${formInputs.district.value}`); + dataSubDistricts = dataSubDistricts.map((subDistrict) => ({ value: subDistrict.id, label: subDistrict.name })); + setSubDistricts(dataSubDistricts); + }; + loadSubDistricts(); + } + }, [ formInputs.district, hasChangedInputs.district, handleSelectChange ]); + + const onSubmit = async () => { + const parameters = { + ...formInputs, + city_id: formInputs.city?.value, + district_id: formInputs.district?.value, + sub_district_id: formInputs.subDistrict?.value, + type: formInputs.type?.value + }; + + 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" /> + + { !_.isEmpty(formInputs) && ( + <form className="px-4 pb-4" onSubmit={(e) => handleFormSubmit(e, onSubmit)}> + <label className="form-label mt-4 mb-2">Label Alamat</label> + <ReactSelect + placeholder="Pilih label alamat..." + classNamePrefix="form-select" + options={typesSelection} + name="type" + onChange={(value) => handleSelectChange('type', value)} + value={formInputs?.type} + /> + <div className="text-caption-2 text-red_r-11 mt-1">{formErrors?.type}</div> + + <label className="form-label mt-4 mb-2">Nama Kontak</label> + <input + type="text" + className='form-input' + placeholder="John Doe" + name="name" + onChange={handleInputChange} + value={formInputs.name} + aria-invalid={formErrors?.name} + /> + <div className="text-caption-2 text-red_r-11 mt-1">{formErrors?.name}</div> + + <label className="form-label mt-4 mb-2">Email</label> + <input + type="text" + className='form-input' + placeholder="johndoe@gmail.com" + name="email" + value={formInputs.email} + onChange={handleInputChange} + aria-invalid={formErrors?.email} + /> + <div className="text-caption-2 text-red_r-11 mt-1">{formErrors?.email}</div> + + <label className="form-label mt-4 mb-2">No. Handphone</label> + <input + type="number" + className='form-input' + placeholder="08xxxxxxxx" + name="mobile" + value={formInputs.mobile} + onChange={handleInputChange} + aria-invalid={formErrors?.mobile} + /> + <div className="text-caption-2 text-red_r-11 mt-1">{formErrors?.mobile}</div> + + <label className="form-label mt-4 mb-2">Alamat</label> + <input + type="text" + className='form-input' + placeholder="Jl. Bandengan Utara" + name="street" + value={formInputs.street} + onChange={handleInputChange} + aria-invalid={formErrors?.street} + /> + <div className="text-caption-2 text-red_r-11 mt-1">{formErrors?.street}</div> + + <label className="form-label mt-4 mb-2">Kode Pos</label> + <input + type="number" + className='form-input' + placeholder="10100" + name="zip" + value={formInputs.zip} + onChange={handleInputChange} + aria-invalid={formErrors?.zip} + /> + <div className="text-caption-2 text-red_r-11 mt-1">{formErrors?.zip}</div> + + <label className="form-label mt-4 mb-2">Kota</label> + <ReactSelect + placeholder="Pilih kota..." + classNamePrefix="form-select" + classNames={{ control: (state) => state.menuIsOpen || state.isFocused ? '!border-yellow_r-9' : '' }} + options={cities} + value={formInputs.city} + onChange={(value) => handleSelectChange('city', value)} + /> + <div className="text-caption-2 text-red_r-11 mt-1">{formErrors?.city}</div> + + <label className="form-label mt-4 mb-2">Kecamatan <span className="text-gray_r-10">(opsional)</span></label> + <ReactSelect + placeholder="Pilih Kecamatan..." + classNamePrefix="form-select" + classNames={{ control: (state) => state.menuIsOpen || state.isFocused ? '!border-yellow_r-9' : '' }} + options={districts} + value={formInputs.district} + onChange={(value) => handleSelectChange('district', value)} + isDisabled={!formInputs.city} + /> + + <label className="form-label mt-4 mb-2">Kelurahan <span className="text-gray_r-10">(opsional)</span></label> + <ReactSelect + placeholder="Pilih Kelurahan..." + classNamePrefix="form-select" + classNames={{ control: (state) => state.menuIsOpen || state.isFocused ? '!border-yellow_r-9' : '' }} + options={subDistricts} + onChange={(value) => handleSelectChange('subDistrict', value)} + value={formInputs.subDistrict} + isDisabled={!formInputs.district} + /> + + <button + type="submit" + className="btn-yellow mt-6 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 d68d1f76..457429e3 100644 --- a/src/pages/my/address/create.js +++ b/src/pages/my/address/create.js @@ -8,6 +8,7 @@ import { useAuth } from "../../../helpers/auth"; import useFormValidation from "../../../helpers/formValidation"; import { toast } from "react-hot-toast"; import { useRouter } from "next/router"; +import _ from "lodash"; const initialFormValue = { type: null, @@ -31,6 +32,13 @@ const validationScheme = { zip: ['label:Kode Pos', 'required'] }; +const typesSelection = [ + { 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(); @@ -85,13 +93,6 @@ export default function CreateAddress() { } }, [ formInputs.district, handleSelectChange ]); - const addressTypes = [ - { value: 'contact', label: 'Contact Address' }, - { value: 'invoice', label: 'Invoice Address' }, - { value: 'delivery', label: 'Delivery Address' }, - { value: 'other', label: 'Other Address' }, - ]; - const onSubmit = async () => { const parameters = { ...formInputs, @@ -99,15 +100,14 @@ export default function CreateAddress() { district_id: formInputs.district?.value, sub_district_id: formInputs.subDistrict?.value, type: formInputs.type?.value, - user_id: auth.id, - partner_id: auth.partner_id, + parent_id: auth.partner_id, }; - const address = await apiOdoo('POST', '/api/v1/partner', parameters); + const address = await apiOdoo('POST', '/api/v1/partner/address', parameters); if (address?.id) { handleFormReset(); toast.success('Berhasil menambahkan alamat'); - router.push('/my/address'); + router.back(); } } @@ -116,118 +116,120 @@ export default function CreateAddress() { <Layout> <AppBar title="Tambah Alamat" /> - <form className="px-4 pb-4" onSubmit={(e) => handleFormSubmit(e, onSubmit)}> - <label className="form-label mt-4 mb-2">Label Alamat</label> - <ReactSelect - placeholder="Pilih label alamat..." - classNamePrefix="form-select" - options={addressTypes} - name="type" - onChange={(value) => handleSelectChange('type', value)} - value={formInputs?.type} - /> - <div className="text-caption-2 text-red_r-11 mt-1">{formErrors?.type}</div> - - <label className="form-label mt-4 mb-2">Nama Kontak</label> - <input - type="text" - className='form-input' - placeholder="John Doe" - name="name" - onChange={handleInputChange} - value={formInputs.name} - aria-invalid={formErrors?.name} - /> - <div className="text-caption-2 text-red_r-11 mt-1">{formErrors?.name}</div> - - <label className="form-label mt-4 mb-2">Email</label> - <input - type="text" - className='form-input' - placeholder="johndoe@gmail.com" - name="email" - value={formInputs.email} - onChange={handleInputChange} - aria-invalid={formErrors?.email} - /> - <div className="text-caption-2 text-red_r-11 mt-1">{formErrors?.email}</div> - - <label className="form-label mt-4 mb-2">No. Handphone</label> - <input - type="tel" - className='form-input' - placeholder="08xxxxxxxx" - name="mobile" - value={formInputs.mobile} - onChange={handleInputChange} - aria-invalid={formErrors?.mobile} - /> - <div className="text-caption-2 text-red_r-11 mt-1">{formErrors?.mobile}</div> - - <label className="form-label mt-4 mb-2">Alamat</label> - <input - type="text" - className='form-input' - placeholder="Jl. Bandengan Utara" - name="street" - value={formInputs.street} - onChange={handleInputChange} - aria-invalid={formErrors?.street} - /> - <div className="text-caption-2 text-red_r-11 mt-1">{formErrors?.street}</div> - - <label className="form-label mt-4 mb-2">Kota</label> - <ReactSelect - placeholder="Pilih kota..." - classNamePrefix="form-select" - classNames={{ control: (state) => state.menuIsOpen || state.isFocused ? '!border-yellow_r-9' : '' }} - options={cities} - value={formInputs.city} - onChange={(value) => handleSelectChange('city', value)} - /> - <div className="text-caption-2 text-red_r-11 mt-1">{formErrors?.city}</div> - - <label className="form-label mt-4 mb-2">Kecamatan <span className="text-gray_r-11">(opsional)</span></label> - <ReactSelect - placeholder="Pilih Kecamatan..." - classNamePrefix="form-select" - classNames={{ control: (state) => state.menuIsOpen || state.isFocused ? '!border-yellow_r-9' : '' }} - options={districts} - value={formInputs.district} - onChange={(value) => handleSelectChange('district', value)} - isDisabled={!formInputs.city} - /> - - <label className="form-label mt-4 mb-2">Kelurahan <span className="text-gray_r-11">(opsional)</span></label> - <ReactSelect - placeholder="Pilih Kelurahan..." - classNamePrefix="form-select" - classNames={{ control: (state) => state.menuIsOpen || state.isFocused ? '!border-yellow_r-9' : '' }} - options={subDistricts} - onChange={(value) => handleSelectChange('subDistrict', value)} - value={formInputs.subDistrict} - isDisabled={!formInputs.district} - /> - - <label className="form-label mt-4 mb-2">Kode Pos</label> - <input - type="number" - className='form-input' - placeholder="10100" - name="zip" - value={formInputs.zip} - onChange={handleInputChange} - aria-invalid={formErrors?.zip} - /> - <div className="text-caption-2 text-red_r-11 mt-1">{formErrors?.zip}</div> - - <button - type="submit" - className="btn-yellow mt-6 w-full" - > - Simpan - </button> - </form> + { !_.isEmpty(formInputs) && ( + <form className="px-4 pb-4" onSubmit={(e) => handleFormSubmit(e, onSubmit)}> + <label className="form-label mt-4 mb-2">Label Alamat</label> + <ReactSelect + placeholder="Pilih label alamat..." + classNamePrefix="form-select" + options={typesSelection} + name="type" + onChange={(value) => handleSelectChange('type', value)} + value={formInputs?.type} + /> + <div className="text-caption-2 text-red_r-11 mt-1">{formErrors?.type}</div> + + <label className="form-label mt-4 mb-2">Nama Kontak</label> + <input + type="text" + className='form-input' + placeholder="John Doe" + name="name" + onChange={handleInputChange} + value={formInputs.name} + aria-invalid={formErrors?.name} + /> + <div className="text-caption-2 text-red_r-11 mt-1">{formErrors?.name}</div> + + <label className="form-label mt-4 mb-2">Email</label> + <input + type="text" + className='form-input' + placeholder="johndoe@gmail.com" + name="email" + value={formInputs.email} + onChange={handleInputChange} + aria-invalid={formErrors?.email} + /> + <div className="text-caption-2 text-red_r-11 mt-1">{formErrors?.email}</div> + + <label className="form-label mt-4 mb-2">No. Handphone</label> + <input + type="number" + className='form-input' + placeholder="08xxxxxxxx" + name="mobile" + value={formInputs.mobile} + onChange={handleInputChange} + aria-invalid={formErrors?.mobile} + /> + <div className="text-caption-2 text-red_r-11 mt-1">{formErrors?.mobile}</div> + + <label className="form-label mt-4 mb-2">Alamat</label> + <input + type="text" + className='form-input' + placeholder="Jl. Bandengan Utara" + name="street" + value={formInputs.street} + onChange={handleInputChange} + aria-invalid={formErrors?.street} + /> + <div className="text-caption-2 text-red_r-11 mt-1">{formErrors?.street}</div> + + <label className="form-label mt-4 mb-2">Kode Pos</label> + <input + type="number" + className='form-input' + placeholder="10100" + name="zip" + value={formInputs.zip} + onChange={handleInputChange} + aria-invalid={formErrors?.zip} + /> + <div className="text-caption-2 text-red_r-11 mt-1">{formErrors?.zip}</div> + + <label className="form-label mt-4 mb-2">Kota</label> + <ReactSelect + placeholder="Pilih kota..." + classNamePrefix="form-select" + classNames={{ control: (state) => state.menuIsOpen || state.isFocused ? '!border-yellow_r-9' : '' }} + options={cities} + value={formInputs.city} + onChange={(value) => handleSelectChange('city', value)} + /> + <div className="text-caption-2 text-red_r-11 mt-1">{formErrors?.city}</div> + + <label className="form-label mt-4 mb-2">Kecamatan <span className="text-gray_r-10">(opsional)</span></label> + <ReactSelect + placeholder="Pilih Kecamatan..." + classNamePrefix="form-select" + classNames={{ control: (state) => state.menuIsOpen || state.isFocused ? '!border-yellow_r-9' : '' }} + options={districts} + value={formInputs.district} + onChange={(value) => handleSelectChange('district', value)} + isDisabled={!formInputs.city} + /> + + <label className="form-label mt-4 mb-2">Kelurahan <span className="text-gray_r-10">(opsional)</span></label> + <ReactSelect + placeholder="Pilih Kelurahan..." + classNamePrefix="form-select" + classNames={{ control: (state) => state.menuIsOpen || state.isFocused ? '!border-yellow_r-9' : '' }} + options={subDistricts} + onChange={(value) => handleSelectChange('subDistrict', value)} + value={formInputs.subDistrict} + isDisabled={!formInputs.district} + /> + + <button + type="submit" + className="btn-yellow mt-6 w-full" + > + Simpan + </button> + </form> + ) } </Layout> </WithAuth> ); diff --git a/src/pages/my/address/index.js b/src/pages/my/address/index.js index b97e21e7..787cfcfa 100644 --- a/src/pages/my/address/index.js +++ b/src/pages/my/address/index.js @@ -48,18 +48,27 @@ export default function Address() { </div> <div className="grid gap-y-4 p-4"> - { addresses && addresses.map((address, index) => ( - <div - key={index} - className={"p-4 rounded-md border " + (selectedAdress && selectedAdress == address.id ? "border-yellow_r-7 bg-yellow_r-2" : "border-gray_r-7") } - onClick={() => changeSelectedAddress(address.id)} - > - <p className="font-medium">{ address.name }</p> - <p className="mt-3 text-gray_r-11">{ address.mobile }</p> - <p className="mt-1 text-gray_r-11 leading-6">{ address.street } { address.street2 }</p> - <button className="btn-light mt-3 w-full">Ubah Alamat</button> - </div> - )) } + { 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 ? "border-yellow_r-7 bg-yellow_r-2" : "border-gray_r-7") } + 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-1">{ address.name }</p> + <p className="mt-2 text-gray_r-11">{ address.mobile }</p> + <p className="mt-1 text-gray_r-11 leading-6">{ address.street } { address.street2 }</p> + <Link href={`/my/address/${address.id}/edit`} className="btn-light mt-3 w-full text-gray_r-11">Ubah Alamat</Link> + </div> + ); + }) } </div> </Layout> </WithAuth> |
