summaryrefslogtreecommitdiff
path: root/src/lib/address/components
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/address/components')
-rw-r--r--src/lib/address/components/CreateAddress.jsx107
-rw-r--r--src/lib/address/components/EditAddress.jsx331
2 files changed, 332 insertions, 106 deletions
diff --git a/src/lib/address/components/CreateAddress.jsx b/src/lib/address/components/CreateAddress.jsx
index 963a19aa..2879fb3d 100644
--- a/src/lib/address/components/CreateAddress.jsx
+++ b/src/lib/address/components/CreateAddress.jsx
@@ -48,19 +48,16 @@ const CreateAddress = () => {
pinedMaps,
setPinedMaps
} = useMaps();
- useEffect(() => {
- if (detailAddress) {
- setValue('zip', detailAddress.postalCode);
- const selectedState = states.find(
- (state) =>
- detailAddress?.province.includes(state.label) ||
- state.label.includes(detailAddress?.province)
- );
- setValue('state', selectedState?.value);
- setValue('street', detailAddress?.street);
-
- }
- }, [detailAddress, setValue]);
+
+ const resetPin = useMaps((state) => state.resetPin);
+ const [showValidationPopup, setShowValidationPopup] = useState(false);
+ const [popupMessage, setPopupMessage] = useState("");
+ const [selectedCityName, setSelectedCityName] = useState("");
+ const [normalizedDistrict, setNormalizedDistrict] = useState("");
+
+ useEffect(() => {
+ resetPin();
+ }, [resetPin]);
useEffect(() => {
const loadState = async () => {
@@ -75,6 +72,20 @@ const CreateAddress = () => {
setAddressMaps('');
}, []);
+ useEffect(() => {
+ if (detailAddress) {
+ setValue('zip', detailAddress.postalCode);
+ const selectedState = states.find(
+ (state) =>
+ (detailAddress?.province || "").includes(state.label) ||
+ state.label.includes(detailAddress?.province)
+ );
+ setValue('state', selectedState?.value);
+ setValue('street', detailAddress?.street);
+
+ }
+ }, [detailAddress, setValue]);
+
const watchState = watch('state');
useEffect(() => {
setValue('city', '');
@@ -91,19 +102,6 @@ const CreateAddress = () => {
}
}, [watchState, setValue]);
- useEffect(() => {
- if (detailAddress && Object.keys(detailAddress).length > 0) {
- const selectedCities = cities.find(
- (city) =>
- city.label.toLowerCase() === detailAddress?.district.toLowerCase()
- ) || cities.find(
- (city) =>
- detailAddress?.district.toLowerCase().includes(city.label.toLowerCase()) ||
- city.label.toLowerCase().includes(detailAddress?.district.toLowerCase())
- );
- setValue('city', selectedCities?.value);
- }
- }, [cities, detailAddress, setValue]);
useEffect(() => {
if (addresses) {
@@ -123,6 +121,29 @@ const CreateAddress = () => {
}
}, [auth]);
+ const normalizeName = (name = "") => {
+ return name
+ .toLowerCase()
+ .replace(/\bkabupaten\b/gi, "")
+ .replace(/\bkota\b/gi, "")
+ .trim();
+ };
+
+ useEffect(() => {
+ if (detailAddress?.district) {
+ const normalizedDistrict = normalizeName(detailAddress.district);
+
+ const selectedCity = cities.find((city) => {
+ const normalizedCity = normalizeName(city.label);
+ return normalizedCity === normalizedDistrict;
+ });
+
+ if (selectedCity) {
+ setValue("city", selectedCity.value);
+ }
+ }
+ }, [cities, detailAddress, setValue]);
+
const watchCity = watch('city');
useEffect(() => {
setValue('district', '');
@@ -188,7 +209,23 @@ const CreateAddress = () => {
}
}, [subDistricts, detailAddress, setValue]);
+
+
+ // console.log(selectedCityName, '=', normalizedDistrict);
const onSubmitHandler = async (values) => {
+ if (detailAddress) {
+ const cityName = normalizeName(
+ cities.find((c) => c.value === watch("city"))?.label || ""
+ );
+ const districtName = normalizeName(detailAddress?.district || "");
+ console.log(cityName, '=', districtName);
+
+ if (cityName && cityName !== districtName) {
+ setPopupMessage("Titik Koordinat tidak sesuai dengan Kota yang dipilih");
+ setShowValidationPopup(true);
+ return;
+ }
+ }
const data = {
...values,
state_id: values.state,
@@ -219,6 +256,24 @@ const CreateAddress = () => {
<PinPointMap />
</div>
</BottomPopup>
+ <BottomPopup
+ active={showValidationPopup}
+ close={() => setShowValidationPopup(false)}
+ >
+ <div className="leading-7 text-gray_r-12/80 text-center">
+ {popupMessage}
+ </div>
+
+ <div className="flex justify-center mt-6">
+ <button
+ className="btn-solid-red w-full md:w-auto"
+ type="button"
+ onClick={() => setShowValidationPopup(false)}
+ >
+ OK
+ </button>
+ </div>
+ </BottomPopup>
<div className='max-w-none md:container mx-auto flex p-0 md:py-10'>
<div className='hidden md:block w-3/12 pr-4'>
<Menu />
diff --git a/src/lib/address/components/EditAddress.jsx b/src/lib/address/components/EditAddress.jsx
index deaa8a3e..75f1a89a 100644
--- a/src/lib/address/components/EditAddress.jsx
+++ b/src/lib/address/components/EditAddress.jsx
@@ -1,6 +1,6 @@
import { yupResolver } from '@hookform/resolvers/yup';
import { useRouter } from 'next/router';
-import { useEffect, useState } from 'react';
+import { useEffect, useState, useMemo } from 'react';
import * as Yup from 'yup';
import cityApi from '../api/cityApi';
import { Controller, useForm } from 'react-hook-form';
@@ -44,22 +44,92 @@ const EditAddress = ({ id, defaultValues }) => {
const [districts, setDistricts] = useState([]);
const [subDistricts, setSubDistricts] = useState([]);
const [tempAddress, setTempAddress] = useState(getValues('addressMap'));
- const { addressMaps,
+ const resetPin = useMaps((state) => state.resetPin);
+ const setSelectedPosition = useMaps((state) => state.setSelectedPosition);
+ const setAddressMaps = useMaps((state) => state.setAddressMaps);
+ const setDetailAddress = useMaps((state) => state.setDetailAddress);
+ const [showValidationPopup, setShowValidationPopup] = useState(false);
+ const [popupMessage, setPopupMessage] = useState("");
+ const [selectedCityName, setSelectedCityName] = useState("");
+ const [normalizedDistrict, setNormalizedDistrict] = useState("");
+
+ const {
+ addressMaps,
selectedPosition,
detailAddress,
pinedMaps,
- setPinedMaps } = useMaps();
+ setPinedMaps,
+ getDefaultCenter, // penting untuk deteksi default center
+ } = useMaps();
+
+ const normalizeName = (name = "") => {
+ return name
+ .toLowerCase()
+ .replace(/\bkabupaten\b/gi, "")
+ .replace(/\bkota\b/gi, "")
+ .trim();
+ };
-
+ // Helper: cek apakah benar2 sudah PIN (bukan default center & ada addressMaps)
+ const isPinned = useMemo(() => {
+ if (!selectedPosition) return false;
+
+ // pastikan selalu cast ke number
+ const lat = Number(selectedPosition.lat);
+ const lng = Number(selectedPosition.lng);
+
+ // kalau hasil cast bukan angka valid
+ if (isNaN(lat) || isNaN(lng)) return false;
+
+ const dc =
+ typeof getDefaultCenter === "function"
+ ? getDefaultCenter()
+ : { lat: -6.2, lng: 106.816666 };
+
+ const nearDefault =
+ Math.abs(lat - dc.lat) < 1e-4 &&
+ Math.abs(lng - dc.lng) < 1e-4;
+
+ return Boolean(addressMaps) && !nearDefault;
+ }, [selectedPosition, addressMaps, getDefaultCenter]);
+
+ // Hanya isi addressMap & lat/lng di form kalau SUDAH PIN
useEffect(() => {
- if (addressMaps) {
- setTempAddress(addressMaps);
- setValue('addressMap', addressMaps);
- setValue('longtitude', selectedPosition.lng);
- setValue('latitude', selectedPosition.lat);
+ // cek kalau form punya koordinat lama
+ const lat = getValues("latitude");
+ const lng = getValues("longtitude");
+ const oldAddress = getValues("addressMap");
+
+ if (lat && lng) {
+ setTempAddress(oldAddress);
+ setValue("addressMap", oldAddress);
+
+ // kalau store punya setter untuk koordinat/alamat:
+ if (typeof setSelectedPosition === "function") {
+ setSelectedPosition({ lat: Number(lat), lng: Number(lng) });
+ }
+ if (typeof setAddressMaps === "function") {
+ setAddressMaps(oldAddress);
+ }
}
- }, [addressMaps, selectedPosition, setValue]);
-
+ }, [setSelectedPosition, setAddressMaps, getValues, setValue]);
+
+ useEffect(() => {
+ const addr = getValues("addressMap");
+
+ if (!addr || addr.trim() === "") {
+ resetPin();
+ } else {
+ setAddressMaps(addr);
+
+ const lat = getValues("latitude");
+ const lng = getValues("longtitude");
+ if (lat && lng) {
+ setSelectedPosition({ lat: Number(lat), lng: Number(lng) });
+ }
+ }
+ }, [getValues, resetPin, setAddressMaps, setSelectedPosition]);
+
useEffect(() => {
if (Object.keys(detailAddress).length > 0) {
setValue('zip', detailAddress.postalCode);
@@ -72,7 +142,7 @@ const EditAddress = ({ id, defaultValues }) => {
setValue('street', detailAddress?.street);
}
}, [detailAddress, setValue]);
-
+
useEffect(() => {
const loadProfile = async () => {
const dataProfile = await addressApi({ id: auth.partnerId });
@@ -83,13 +153,40 @@ const EditAddress = ({ id, defaultValues }) => {
setValue('alamat_wajib_pajak', dataProfile.alamatWajibPajak);
setValue('alamat_bisnis', dataProfile.alamatBisnis);
setValue('business_name', dataProfile.name);
- setValue('city', dataProfile.city?.id);
- setValue('district', dataProfile.district?.id);
- setValue('subDistrict', dataProfile.subDistrict?.id);
};
if (auth) loadProfile();
- }, [auth?.parentId]);
-
+ }, [auth?.parentId, setValue]);
+
+ // Isi ZIP/Prov dari detailAddress (JANGAN isi street)
+useEffect(() => {
+ const zip = getValues("zip");
+ const province = getValues("state");
+ const street = getValues("street");
+
+ // set zip dari DB kalau kosong
+ if (!zip && defaultValues?.zip) {
+ setValue("zip", defaultValues.zip);
+ }
+
+ // set state dari DB kalau kosong
+ if (!province && defaultValues?.state) {
+ const selectedState = states.find(
+ (state) =>
+ defaultValues.state.includes(state.label) ||
+ state.label.includes(defaultValues.state)
+ );
+ if (selectedState) {
+ setValue("state", selectedState.value);
+ }
+ }
+
+ // set street dari DB kalau kosong
+ if (!street && defaultValues?.street) {
+ setValue("street", defaultValues.street);
+ }
+ }, [states, setValue, getValues, defaultValues]);
+
+
useEffect(() => {
const loadStates = async () => {
let dataStates = await stateApi({ tempo: false });
@@ -101,7 +198,7 @@ const EditAddress = ({ id, defaultValues }) => {
};
loadStates();
}, []);
-
+
const watchState = watch('state');
useEffect(() => {
setValue('city', '');
@@ -122,35 +219,46 @@ const EditAddress = ({ id, defaultValues }) => {
loadCities();
}
}, [watchState, setValue, getValues]);
-
+
useEffect(() => {
- if (Object.keys(detailAddress).length > 0) {
- const selectedCities = cities.find(
- (city) =>
- city.label.toLowerCase() === detailAddress?.district.toLowerCase()
- ) || cities.find(
+ if (!isPinned) return;
+
+ if (getValues("city")) return;
+
+ if (Object.keys(detailAddress || {}).length > 0) {
+ const selectedCities =
+ cities.find(
+ (city) =>
+ city.label.toLowerCase() === detailAddress?.district?.toLowerCase()
+ ) ||
+ cities.find(
(city) =>
- detailAddress?.district.toLowerCase().includes(city.label.toLowerCase()) ||
- city.label.toLowerCase().includes(detailAddress?.district.toLowerCase())
+ detailAddress?.district
+ ?.toLowerCase()
+ .includes(city.label.toLowerCase()) ||
+ city.label
+ .toLowerCase()
+ .includes(detailAddress?.district?.toLowerCase())
);
- setValue('city', selectedCities?.value);
- }
- }, [cities, detailAddress, setValue]);
-
- const watchCity = watch('city');
- useEffect(() => {
- if (watchCity) {
- // setValue('district', '');
- const loadDistricts = async () => {
- let dataDistricts = await districtApi({ cityId: watchCity });
- dataDistricts = dataDistricts.map((district) => ({
- value: district.id,
- label: district.name,
+
+ if (selectedCities) {
+ setValue("city", selectedCities.value);
+ }
+ }
+ }, [cities, detailAddress, isPinned, getValues, setValue]);
+
+ const watchCity = watch('city');
+ useEffect(() => {
+ 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', '');
}
};
@@ -159,6 +267,9 @@ const EditAddress = ({ id, defaultValues }) => {
}, [watchCity, setValue, getValues]);
useEffect(() => {
+ if (!isPinned) return; // skip kalau belum pin
+ if (getValues("district")) return;
+
if (Object.keys(detailAddress).length > 0) {
const selectedDistrict = districts.find(
(district) =>
@@ -173,12 +284,10 @@ const EditAddress = ({ id, defaultValues }) => {
}
}, [districts, detailAddress, setValue]);
-
-
+
const watchDistrict = watch('district');
useEffect(() => {
if (watchDistrict) {
- // setValue('subDistrict', '');
const loadSubDistricts = async () => {
let dataSubDistricts = await subDistrictApi({
districtId: watchDistrict,
@@ -199,8 +308,10 @@ const EditAddress = ({ id, defaultValues }) => {
}
}, [watchDistrict, setValue, getValues]);
-
useEffect(() => {
+ if (!isPinned) return; // skip kalau belum pin
+ if (getValues("subDistrict")) return;
+
if (Object.keys(detailAddress).length > 0) {
const selectedSubDistrict = subDistricts.find(
(district) =>
@@ -221,8 +332,39 @@ const EditAddress = ({ id, defaultValues }) => {
setValue('id', id);
}
}, [id, setValue]);
-
+
const onSubmitHandler = async (values) => {
+ if (addressMaps) {
+ if (!detailAddress){
+ if (defaultValues?.oldCity !== values.city) {
+ setPopupMessage("Titik Koordinat tidak sesuai dengan Kota yang dipilih");
+ setShowValidationPopup(true);
+ // console.log(detailAddress)
+ return;
+ }
+ }
+ if (detailAddress) {
+ const cityName = normalizeName(
+ cities.find((c) => c.value === watch("city"))?.label || ""
+ );
+ const districtName = normalizeName(detailAddress?.district || "");
+ // console.log(cityName, '=', districtName);
+
+ if (cityName && cityName !== districtName) {
+ setPopupMessage("Titik Koordinat tidak sesuai dengan Kota yang dipilih");
+ setShowValidationPopup(true);
+ return;
+ }
+ }
+ }
+ // if(!addressMaps && detailAddress){
+ // if (selectedCityName && selectedCityName !== detailAddress?.district?.toLowerCase()) {
+ // setPopupMessage("Titik Koordinat tidak sesuai dengan Kota yang dipilih 3");
+ // setShowValidationPopup(true);
+ // return;
+ // }
+ // }
+
const data = {
...values,
phone: values.mobile,
@@ -230,20 +372,32 @@ const EditAddress = ({ id, defaultValues }) => {
city_id: parseInt(values.city, 10),
district_id: parseInt(values.district, 10),
sub_district_id: parseInt(values.subDistrict, 10),
- longtitude: selectedPosition?.lng,
- latitude: selectedPosition?.lat,
- address_map: addressMaps,
};
+
+
+ if (isPinned) {
+ data.longtitude = selectedPosition?.lng;
+ data.latitude = selectedPosition?.lat;
+ data.address_map = addressMaps || values.addressMap;
+ data.use_pin = true;
+ } else {
+ data.use_pin = false;
+ // pastikan tidak ada nilai default center yang ikut terkirim
+ delete data.longtitude;
+ delete data.latitude;
+ delete data.address_map;
+ }
+
if (!auth.company) {
data.alamat_lengkap_text = values.street;
}
+
try {
const address = await editAddressApi({ id, data });
console.log('Response address:', address);
let isUpdated = null;
- // Jika company dan partnerId sama dengan id, maka update data alamat wajib pajak
const isCompanyEditingSelf = auth.company && auth.partnerId == id;
if (isCompanyEditingSelf) {
@@ -260,15 +414,13 @@ const EditAddress = ({ id, defaultValues }) => {
mobile: values.mobile,
};
- const isUpdated = await editPartnerApi({
+ const isUpdatedRes = await editPartnerApi({
id: auth.partnerId,
data: dataAlamat,
});
-
- console.log('Response isUpdated:', isUpdated);
+ console.log('Response isUpdated:', isUpdatedRes);
}
- // Validasi kondisi sukses
const isSuccess = !!address?.id;
if (isSuccess) {
@@ -286,21 +438,10 @@ const EditAddress = ({ id, defaultValues }) => {
toast.error(error?.message || 'Terjadi kesalahan tidak terduga.');
}
-
const dataProfile = await addressApi({ id: auth.partnerId });
- console.log('ini adalah', dataProfile);
-
-
- // if (isUpdated?.id) {
- // if (address?.id && auth.company ? isUpdated?.id : true) {
- // toast.success('Berhasil mengubah alamat');
- // router.back();
- // } else {
- // toast.error('Terjadi kesalahan internal');
- // router.back();
- // }
+ // console.log('ini adalah', dataProfile);
};
-
+ // console.log('ini adalah', detailAddress);
return (
<>
<BottomPopup
@@ -310,12 +451,29 @@ const EditAddress = ({ id, defaultValues }) => {
close={() => setPinedMaps(false)}
>
<div className='flex mt-4'>
- <PinPointMap
- initialLatitude={selectedPosition?.lat}
- initialLongitude={selectedPosition?.lng}
- initialAddress={tempAddress}
- />
+ <PinPointMap
+ initialLatitude={getValues('latitude')}
+ initialLongitude={getValues('longtitude')}
+ initialAddress={getValues('addressMap')}
+ />
+ </div>
+ </BottomPopup>
+ <BottomPopup
+ active={showValidationPopup}
+ close={() => setShowValidationPopup(false)}
+ >
+ <div className="leading-7 text-gray_r-12/80 text-center">
+ {popupMessage}
+ </div>
+ <div className="flex justify-center mt-6">
+ <button
+ className="btn-solid-red w-full md:w-auto"
+ type="button"
+ onClick={() => setShowValidationPopup(false)}
+ >
+ OK
+ </button>
</div>
</BottomPopup>
<div className='max-w-none md:container mx-auto flex p-0 md:py-10'>
@@ -332,17 +490,30 @@ const EditAddress = ({ id, defaultValues }) => {
<form onSubmit={handleSubmit(onSubmitHandler)}>
<div className='mb-4 items-start'>
<label className='form-label mb-2'>Koordinat Alamat</label>
- {tempAddress ? (
+ {addressMaps ? (
<div className='flex gap-x-2 items-center'>
- <button type='button' className="flex items-center justify-center me-3 p-2 badge-solid-red text-white rounded-full hover:bg-red-500 transition">
- <MapPinIcon class='h-6 w-6' onClick={() => setPinedMaps(true)} />{' '}
- </button>
- <span> {tempAddress} </span>
+ <button
+ type='button'
+ className='flex items-center justify-center me-3 p-2 badge-solid-red text-white rounded-full hover:bg-red-500 transition'
+ >
+ <MapPinIcon
+ className='h-6 w-6'
+ onClick={() => setPinedMaps(true)}
+ />
+ </button>
+ <span> {addressMaps} </span>
</div>
) : (
- <Button variant='plain' style={{ padding: 0 }} onClick={() => setPinedMaps(true)}>
- <button type='button' className="flex items-center justify-center me-3 p-2 badge-solid-red text-white rounded-full hover:bg-red-500 transition">
- <MapPinIcon className="h-6 w-6" />
+ <Button
+ variant='plain'
+ style={{ padding: 0 }}
+ onClick={() => setPinedMaps(true)}
+ >
+ <button
+ type='button'
+ className='flex items-center justify-center me-3 p-2 badge-solid-red text-white rounded-full hover:bg-red-500 transition'
+ >
+ <MapPinIcon className='h-6 w-6' />
</button>
Pin Koordinat Alamat
</Button>
@@ -530,4 +701,4 @@ const types = [
{ value: 'other', label: 'Other Address' },
];
-export default EditAddress;
+export default EditAddress; \ No newline at end of file