diff --git a/src/Pages/TagDistribution.tsx b/src/Pages/TagDistribution.tsx new file mode 100644 index 0000000..afb4869 --- /dev/null +++ b/src/Pages/TagDistribution.tsx @@ -0,0 +1,220 @@ +import { useEffect, useState } from "react"; +import { useApiRequest } from "../utils/useApiRequest"; +import { Grid } from "../components/Grid/Grid"; +import Table from "../components/Table/Table"; +import Button from "../components/Button/Button"; +import { useModalStore } from "../context/zustand-store/appStore"; +import { SubmitTagDistribution } from "../partials/tagging/SubmitTagDistribution"; +import Typography from "../components/Typography/Typography"; +import ShowMoreInfo from "../components/ShowMoreInfo/ShowMoreInfo"; +import { formatJustDate } from "../utils/formatTime"; +import { Bars3Icon, CubeIcon, SparklesIcon } from "@heroicons/react/24/outline"; +import { DeleteButtonForPopOver } from "../components/PopOverButtons/PopOverButtons"; +import { Tooltip } from "../components/Tooltip/Tooltip"; +import { Popover } from "../components/PopOver/PopOver"; + +export default function TagDistribtution() { + const { openModal } = useModalStore(); + const [tableInfo, setTableInfo] = useState({ page: 1, page_size: 10 }); + const [tagsTableData, setTagsTableData] = useState([]); + + const { data: tagsData, refetch } = useApiRequest({ + api: "/tag/web/api/v1/tag_distribution_batch", + method: "get", + queryKey: ["tagsList", tableInfo], + params: { + ...tableInfo, + }, + }); + + const { data: tagDashboardData, refetch: updateDashboard } = useApiRequest({ + api: "/tag/web/api/v1/tag/tag_dashboard/", + method: "get", + queryKey: ["tagDashboard"], + }); + + const handleUpdate = () => { + refetch(); + updateDashboard(); + }; + const speciesMap: Record = { + 1: "گاو", + 2: "گاومیش", + 3: "شتر", + 4: "گوسفند", + 5: "بز", + }; + + useEffect(() => { + if (tagsData?.results) { + const formattedData = tagsData.results.map((item: any, index: number) => { + const dist = item?.distributions; + + return [ + tableInfo.page === 1 + ? index + 1 + : index + tableInfo.page_size * (tableInfo.page - 1) + 1, + item?.dist_batch_identity, + formatJustDate(item?.create_date), + item?.assigner_org?.name, + item?.assigned_org?.name, + item?.total_tag_count, + item?.distribution_type === "batch" ? "توزیع گروهی" : "توزیع تصادفی", + + + {dist?.map((opt: any, index: number) => ( + + {item?.distribution_type === "batch" && opt?.serial_from && ( + + + + بازه سریال: + + + از {opt?.serial_from ?? "-"} تا {opt?.serial_to ?? "-"} + + + )} + + + + + تعداد پلاک: + + + {opt?.distributed_number?.toLocaleString()} + + + + + + + گونه: + + + {speciesMap[opt?.species_code] ?? "-"} + + + + ))} + + , + + + + + + + + + +
+ + ); +} diff --git a/src/components/AutoComplete/AutoComplete.tsx b/src/components/AutoComplete/AutoComplete.tsx index 13dd0fc..7f599f4 100644 --- a/src/components/AutoComplete/AutoComplete.tsx +++ b/src/components/AutoComplete/AutoComplete.tsx @@ -27,7 +27,7 @@ interface AutoCompleteProps { multiselect?: boolean; inPage?: boolean; disabled?: boolean; - selectedKeys: (number | string)[]; + selectedKeys: (number | string)[] | any; onChange: (keys: (number | string)[]) => void | []; width?: string; buttonHeight?: number | string; diff --git a/src/components/FormItems/FormApiBasedAutoComplete.tsx b/src/components/FormItems/FormApiBasedAutoComplete.tsx index f85ddea..7e9b8a4 100644 --- a/src/components/FormItems/FormApiBasedAutoComplete.tsx +++ b/src/components/FormItems/FormApiBasedAutoComplete.tsx @@ -226,17 +226,25 @@ export const FormApiBasedAutoComplete = ({ setSelectedKeys(defaultItems.map((item: any) => item.key)); if (onChange) { if (secondaryKey) { - onChange({ - key1: defaultItems.map((item: any) => item.key), - key2: defaultItems.map((item: any) => item.secondaryKey), - ...(tertiaryKey - ? { - key3: defaultItems.map( - (item: any) => item.tertiaryKey - ), - } - : {}), - }); + console.log("dksk0", defaultItems); + onChange( + defaultItems.map((item: any) => { + return { + key: item?.key, + key2: item?.secondaryKey, + ...(tertiaryKey + ? { + key3: item?.tertiaryKey, + } + : {}), + }; + }) + ); + if (onChangeValue) { + onChangeValue( + defaultItems.map((item: any) => item.value.trim()) + ); + } } else { onChange(defaultItems.map((item: any) => item.key)); } diff --git a/src/partials/tagging/SubmitTagDistribution.tsx b/src/partials/tagging/SubmitTagDistribution.tsx new file mode 100644 index 0000000..a014558 --- /dev/null +++ b/src/partials/tagging/SubmitTagDistribution.tsx @@ -0,0 +1,256 @@ +import { z } from "zod"; +import { useEffect, useState } from "react"; +import { Controller, useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { Grid } from "../../components/Grid/Grid"; +import Button from "../../components/Button/Button"; +import Textfield from "../../components/Textfeild/Textfeild"; +import { RadioGroup } from "../../components/RadioButton/RadioGroup"; +import { FormApiBasedAutoComplete } from "../../components/FormItems/FormApiBasedAutoComplete"; +import AutoComplete from "../../components/AutoComplete/AutoComplete"; +import { zValidateAutoComplete } from "../../data/getFormTypeErrors"; +import { useApiMutation } from "../../utils/useApiRequest"; +import { useToast } from "../../hooks/useToast"; +import { useModalStore } from "../../context/zustand-store/appStore"; + +const speciesOptions = [ + { key: 1, value: "گاو" }, + { key: 2, value: "گاومیش" }, + { key: 3, value: "شتر" }, + { key: 4, value: "گوسفند" }, + { key: 5, value: "بز" }, +]; + +const distributionTypeOptions = [ + { label: "توزیع گروهی", value: "group" }, + { label: "توزیع تصادفی", value: "random" }, +]; + +const schema = z.object({ + organization: zValidateAutoComplete("سازمان"), +}); + +type FormValues = z.infer; + +type BatchItem = { + batch_identity?: string | number; + species_code?: number; + count: number | ""; + label?: string; +}; + +export const SubmitTagDistribution = ({ item, getData }: any) => { + const showToast = useToast(); + const { closeModal } = useModalStore(); + + const isEdit = Boolean(item?.id); + + const [distributionType, setDistributionType] = useState<"group" | "random">( + isEdit + ? item?.distribution_type === "random" + ? "random" + : "group" + : "group" + ); + const [batches, setBatches] = useState([]); + + const { + control, + handleSubmit, + setValue, + trigger, + formState: { errors }, + } = useForm({ + resolver: zodResolver(schema), + defaultValues: { + organization: [], + }, + }); + + const mutation = useApiMutation({ + api: isEdit + ? `/tag/web/api/v1/tag_distribution/${item?.id}` + : "/tag/web/api/v1/tag_distribution/", + method: isEdit ? "put" : "post", + }); + + useEffect(() => { + if (!item) return; + + setValue("organization", [item.assigned_org?.id]); + trigger("organization"); + + const mappedBatches = item.distributions.map((d: any) => ({ + ...(item.distribution_type === "batch" && { + batch_identity: item.dist_batch_identity, + }), + species_code: d.species_code, + count: d.distributed_number, + label: + item.distribution_type === "batch" + ? `از ${d.serial_from ?? "-"} تا ${d.serial_to ?? "-"}` + : undefined, + })); + + setBatches(mappedBatches); + }, [item]); + + const onSubmit = async (data: FormValues) => { + const dists = + distributionType === "random" + ? batches.map((b) => ({ + species_code: b.species_code, + count: b.count, + })) + : batches.map((b) => ({ + batch_identity: b.batch_identity, + species_code: b.species_code, + count: b.count, + })); + + try { + await mutation.mutateAsync({ + assigner_org: item?.organization?.id, + assigned_org: data.organization[0], + dists, + }); + + showToast( + isEdit ? "ویرایش با موفقیت انجام شد" : "ثبت با موفقیت انجام شد", + "success" + ); + getData(); + closeModal(); + } catch (error: any) { + showToast( + error?.response?.data?.message || "خطا در ثبت اطلاعات!", + "error" + ); + } + }; + + return ( +
+ + ( + { + setValue("organization", [r]); + trigger("organization"); + }} + /> + )} + /> + + { + const val = e.target.value as "group" | "random"; + setDistributionType(val); + setBatches([]); + }} + /> + + {distributionType === "group" && ( + d.batch_identity) || [] + } + groupFunction={(item) => + speciesOptions.find((s) => s.key === item)?.value || "نامشخص" + } + valueTemplateProps={[{ v1: "string" }, { v2: "string" }]} + multiple + onChange={(items) => { + setBatches( + items?.map((r: any) => { + const existing = batches.find( + (b) => + b.batch_identity === r.key1 && b.species_code === r.key2 + ); + return { + batch_identity: r.key1, + species_code: r.key2, + count: existing?.count ?? "", + }; + }) || [] + ); + }} + onChangeValue={(labels) => { + setBatches((prev) => + prev.map((item, index) => ({ + ...item, + label: labels[index], + })) + ); + }} + /> + )} + + {distributionType === "random" && ( + b.species_code)} + onChange={(keys: (string | number)[]) => { + setBatches( + keys.map((k) => { + const prev = batches.find((b) => b.species_code === k); + return { + species_code: k as number, + count: prev?.count ?? "", + }; + }) + ); + }} + title="گونه" + /> + )} + + {batches.map((batch, index) => ( + s.key === batch.species_code) + ?.value + }` + } + value={batch.count} + onChange={(e) => { + const next = [...batches]; + next[index].count = Number(e.target.value); + setBatches(next); + }} + /> + ))} + + + + + ); +}; diff --git a/src/routes/paths.ts b/src/routes/paths.ts index 61b9c57..04b78f0 100644 --- a/src/routes/paths.ts +++ b/src/routes/paths.ts @@ -53,4 +53,5 @@ export const UNITS_SETTINGS = "/unit-settings"; //TAGGING export const TAGGING = "/tagging"; export const TAGS = "/tags"; +export const TAG_DISTRIBUTION = "/tag-distribution"; export const TAGS_BATCH = "/tags/$id/$from/$to"; diff --git a/src/utils/getCategoryParameters.ts b/src/utils/getCategoryParameters.ts index fddb8f1..935566e 100644 --- a/src/utils/getCategoryParameters.ts +++ b/src/utils/getCategoryParameters.ts @@ -24,6 +24,7 @@ import CooperativeRanchers from "../Pages/CooperativeRanchers"; import SettingsOfUnits from "../Pages/SettingsOfUnits"; import Tagging from "../Pages/Tagging"; import Tags from "../Pages/Tags"; +import TagDistribtution from "../Pages/TagDistribution"; export const managementCategoryItems = [ { @@ -182,6 +183,11 @@ export const taggingCategoryItems = [ path: R.TAGS_BATCH, component: Tags, }, + { + name: "tag_distribution", + path: R.TAG_DISTRIBUTION, + component: TagDistribtution, + }, ]; export const posCategoryItems = [ diff --git a/src/utils/getFaPermissions.ts b/src/utils/getFaPermissions.ts index bdb9972..3377149 100644 --- a/src/utils/getFaPermissions.ts +++ b/src/utils/getFaPermissions.ts @@ -100,6 +100,9 @@ export function getFaPermissions(permission: string) { case "tags": faPermission = "پلاک ها"; break; + case "tag_distribution": + faPermission = "توزیع پلاک"; + break; default: break; }