add: multiple addresses

This commit is contained in:
2026-02-08 16:52:55 +03:30
parent 95780cfbc9
commit a818683247
2 changed files with 97 additions and 28 deletions

View File

@@ -8,7 +8,6 @@ import {
zValidateNumber, zValidateNumber,
zValidateNumberOptional, zValidateNumberOptional,
zValidateString, zValidateString,
zValidateStringOptional,
} from "../../data/getFormTypeErrors"; } from "../../data/getFormTypeErrors";
import { z } from "zod"; import { z } from "zod";
import { useApiMutation } from "../../utils/useApiRequest"; import { useApiMutation } from "../../utils/useApiRequest";
@@ -21,11 +20,11 @@ import { getToastResponse } from "../../data/getToastResponse";
import { useUserProfileStore } from "../../context/zustand-store/userStore"; import { useUserProfileStore } from "../../context/zustand-store/userStore";
import { useState } from "react"; import { useState } from "react";
import Checkbox from "../../components/CheckBox/CheckBox"; import Checkbox from "../../components/CheckBox/CheckBox";
import { PlusIcon, TrashIcon } from "@heroicons/react/24/outline";
const schema = z.object({ const schema = z.object({
name: zValidateString("نام سازمان"), name: zValidateString("نام سازمان"),
national_unique_id: zValidateString("شناسه کشوری"), national_unique_id: zValidateString("شناسه کشوری"),
address: zValidateStringOptional("آدرس"),
field_of_activity: zValidateAutoComplete("حوزه فعالیت"), field_of_activity: zValidateAutoComplete("حوزه فعالیت"),
province: zValidateNumber("استان"), province: zValidateNumber("استان"),
city: zValidateNumber("شهر"), city: zValidateNumber("شهر"),
@@ -75,7 +74,6 @@ export const AddOrganization = ({ getData, item }: AddPageProps) => {
resolver: zodResolver(schema), resolver: zodResolver(schema),
defaultValues: { defaultValues: {
name: item?.name || "", name: item?.name || "",
address: item?.address || "",
national_unique_id: item?.national_unique_id || "", national_unique_id: item?.national_unique_id || "",
free_visibility_by_scope: item?.free_visibility_by_scope || false, free_visibility_by_scope: item?.free_visibility_by_scope || false,
field_of_activity: field_of_activity:
@@ -95,16 +93,48 @@ export const AddOrganization = ({ getData, item }: AddPageProps) => {
city: string | any; city: string | any;
}>({ province: "", city: "" }); }>({ province: "", city: "" });
const [addresses, setAddresses] = useState<
{ postal_code: string; address: string }[]
>(
item?.addresses?.length
? item.addresses.map((a: any) => ({
postal_code: a.postal_code || "",
address: a.address || "",
}))
: [{ postal_code: "", address: "" }],
);
const handleAddAddress = () => {
setAddresses((prev) => [...prev, { postal_code: "", address: "" }]);
};
const handleRemoveAddress = (index: number) => {
setAddresses((prev) => prev.filter((_, i) => i !== index));
};
const handleAddressChange = (
index: number,
field: "postal_code" | "address",
value: string,
) => {
setAddresses((prev) =>
prev.map((item, i) => (i === index ? { ...item, [field]: value } : item)),
);
};
const onSubmit = async (data: FormValues) => { const onSubmit = async (data: FormValues) => {
try { try {
await mutation.mutateAsync({ await mutation.mutateAsync({
addresses: addresses.filter(
(a) => a.postal_code.trim() || a.address.trim(),
),
organization: { organization: {
name: `${data?.name} ${ name: `${data?.name} ${
data?.is_repeatable data?.is_repeatable
? "" ? ""
: data.field_of_activity[0] === "CI" : data.field_of_activity[0] === "CI"
? LocationValues.city ? LocationValues.city
: LocationValues.province : LocationValues.province
}`, }`,
...(data.organizationType !== undefined && { ...(data.organizationType !== undefined && {
@@ -118,7 +148,6 @@ export const AddOrganization = ({ getData, item }: AddPageProps) => {
}), }),
field_of_activity: data.field_of_activity[0], field_of_activity: data.field_of_activity[0],
free_visibility_by_scope: data.free_visibility_by_scope, free_visibility_by_scope: data.free_visibility_by_scope,
address: data.address,
}, },
}); });
showToast(getToastResponse(item, "سازمان"), "success"); showToast(getToastResponse(item, "سازمان"), "success");
@@ -128,12 +157,12 @@ export const AddOrganization = ({ getData, item }: AddPageProps) => {
if (error?.status === 403) { if (error?.status === 403) {
showToast( showToast(
error?.response?.data?.message || "این سازمان تکراری است!", error?.response?.data?.message || "این سازمان تکراری است!",
"error" "error",
); );
} else { } else {
showToast( showToast(
error?.response?.data?.message || "خطا در ثبت اطلاعات!", error?.response?.data?.message || "خطا در ثبت اطلاعات!",
"error" "error",
); );
} }
} }
@@ -258,7 +287,7 @@ export const AddOrganization = ({ getData, item }: AddPageProps) => {
defaultKey={item?.parent_organization?.id} defaultKey={item?.parent_organization?.id}
title="سازمان والد (اختیاری)" title="سازمان والد (اختیاری)"
api={`auth/api/v1/organization/organizations_by_province?province=${getValues( api={`auth/api/v1/organization/organizations_by_province?province=${getValues(
"province" "province",
)}`} )}`}
keyField="id" keyField="id"
valueField="name" valueField="name"
@@ -273,20 +302,53 @@ export const AddOrganization = ({ getData, item }: AddPageProps) => {
)} )}
/> />
<Controller <div className="flex flex-col gap-2 w-full">
name="address" <div className="flex items-center justify-between">
control={control} <span className="text-sm font-medium text-gray-700">آدرسها</span>
render={({ field }) => ( <button
<Textfield type="button"
fullWidth onClick={handleAddAddress}
placeholder="آدرس (اختیاری)" className="flex items-center gap-1 text-sm text-blue-600 hover:text-blue-800 transition-colors"
value={field.value} >
onChange={field.onChange} <PlusIcon className="w-4 h-4" />
error={!!errors.address} افزودن آدرس
helperText={errors.address?.message} </button>
/> </div>
)} {addresses.map((addr, index) => (
/> <div
key={index}
className="flex items-start gap-2 p-3 border border-gray-200 rounded-lg"
>
<div className="flex flex-col gap-2 flex-1">
<Textfield
fullWidth
placeholder="کد پستی"
value={addr.postal_code}
onChange={(e) =>
handleAddressChange(index, "postal_code", e.target.value)
}
/>
<Textfield
fullWidth
placeholder="آدرس"
value={addr.address}
onChange={(e) =>
handleAddressChange(index, "address", e.target.value)
}
/>
</div>
{addresses.length > 1 && (
<button
type="button"
onClick={() => handleRemoveAddress(index)}
className="mt-2 text-red-500 hover:text-red-700 transition-colors shrink-0"
>
<TrashIcon className="w-5 h-5" />
</button>
)}
</div>
))}
</div>
<Controller <Controller
name="free_visibility_by_scope" name="free_visibility_by_scope"

View File

@@ -53,13 +53,20 @@ export const OrganizationsList = () => {
item?.field_of_activity === "CO" item?.field_of_activity === "CO"
? "کشور" ? "کشور"
: item?.field_of_activity === "PR" : item?.field_of_activity === "PR"
? "استان" ? "استان"
: item?.field_of_activity === "CI" : item?.field_of_activity === "CI"
? "شهرستان" ? "شهرستان"
: "نامشخص", : "نامشخص",
item?.province?.name, item?.province?.name,
item?.city?.name, item?.city?.name,
item?.address || "-", <ShowMoreInfo
key={`address-${i}`}
title="آدرس‌ها"
disabled={!item?.addresses?.length}
data={item?.addresses}
columns={["کد پستی", "آدرس"]}
accessKeys={[["postal_code"], ["address"]]}
/>,
<ShowMoreInfo <ShowMoreInfo
key={i} key={i}
title="اطلاعات حساب" title="اطلاعات حساب"