summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/helpers/convertToOption.js11
-rw-r--r--src/helpers/formValidation.js1
-rw-r--r--src/pages/my/address/[id]/edit.js239
-rw-r--r--src/pages/my/address/create.js248
-rw-r--r--src/pages/my/address/index.js33
5 files changed, 397 insertions, 135 deletions
diff --git a/src/helpers/convertToOption.js b/src/helpers/convertToOption.js
new file mode 100644
index 00000000..08fec08f
--- /dev/null
+++ b/src/helpers/convertToOption.js
@@ -0,0 +1,11 @@
+const convertToOption = (data) => {
+ if (data) {
+ return {
+ value: data.id,
+ label: data.name,
+ }
+ }
+ return null;
+};
+
+export default convertToOption; \ No newline at end of file
diff --git a/src/helpers/formValidation.js b/src/helpers/formValidation.js
index 10c36e01..0e83f4cc 100644
--- a/src/helpers/formValidation.js
+++ b/src/helpers/formValidation.js
@@ -98,6 +98,7 @@ const useFormValidation = ({ initialFormValue = {}, validationScheme = {} }) =>
handleFormSubmit,
handleInputChange,
handleSelectChange,
+ hasChangedInputs,
formInputs,
formErrors
};
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>