feat: tag distributions

This commit is contained in:
2026-01-24 16:21:37 +03:30
parent 576fc434dc
commit e0633245cd
4 changed files with 500 additions and 222 deletions

View File

@@ -1,220 +1,38 @@
import { useEffect, useState } from "react";
import { useApiRequest } from "../utils/useApiRequest";
import { useState } from "react";
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";
import Tabs from "../components/Tab/Tab";
import TagActiveDistributions from "../partials/tagging/TagActiveDistributions";
import TagCanceledDistributions from "../partials/tagging/TagCanceledDistributions";
export default function TagDistribtution() {
const { openModal } = useModalStore();
const [tableInfo, setTableInfo] = useState({ page: 1, page_size: 10 });
const [tagsTableData, setTagsTableData] = useState([]);
const [selectedTab, setSelectedTab] = useState<number>(0);
const handleTabChange = (index: number) => {
setSelectedTab(index);
};
const { data: tagsData, refetch } = useApiRequest({
api: "/tag/web/api/v1/tag_distribution_batch",
method: "get",
queryKey: ["tagsList", tableInfo],
params: {
...tableInfo,
const tabItems = [
{
label: "توزیع فعال",
page: "tag_distribution",
access: "Tag-Distribution-Actives",
},
});
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<number, string> = {
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" ? "توزیع گروهی" : "توزیع تصادفی",
<ShowMoreInfo key={item?.id} title="جزئیات توزیع">
<Grid container column className="gap-4 w-full">
{dist?.map((opt: any, index: number) => (
<Grid
key={index}
container
column
className="gap-3 w-full rounded-xl border border-gray-200 dark:border-gray-700 p-4"
>
{item?.distribution_type === "batch" && opt?.serial_from && (
<Grid container className="gap-2 items-center">
<Bars3Icon className="w-5 h-5 text-gray-500 dark:text-gray-300" />
<Typography variant="body2" className="font-medium">
بازه سریال:
</Typography>
<Typography
variant="body2"
className="text-gray-600 dark:text-gray-400"
>
از {opt?.serial_from ?? "-"} تا {opt?.serial_to ?? "-"}
</Typography>
</Grid>
)}
<Grid container className="gap-2 items-center">
<CubeIcon className="w-5 h-5 text-gray-500 dark:text-gray-300" />
<Typography variant="body2" className="font-medium">
تعداد پلاک:
</Typography>
<Typography
variant="body2"
className="text-gray-700 dark:text-gray-300"
>
{opt?.distributed_number?.toLocaleString()}
</Typography>
</Grid>
<Grid container className="gap-2 items-center">
<SparklesIcon className="w-5 h-5 text-gray-500 dark:text-gray-300" />
<Typography variant="body2" className="font-medium">
گونه:
</Typography>
<Typography
variant="body2"
className="text-gray-700 dark:text-gray-300"
>
{speciesMap[opt?.species_code] ?? "-"}
</Typography>
</Grid>
</Grid>
))}
</Grid>
</ShowMoreInfo>,
<Popover key={index}>
<Tooltip title="ویرایش دام" position="right">
<Button
variant="edit"
page="tagging"
access="Create-Tag"
onClick={() => {
openModal({
title: "ایجاد پلاک جدید",
content: (
<SubmitTagDistribution
getData={handleUpdate}
item={item}
/>
),
});
}}
/>
</Tooltip>
<DeleteButtonForPopOver
api={`livestock/web/api/v1/livestock/${item?.id}/`}
getData={refetch}
/>
</Popover>,
];
});
setTagsTableData(formattedData);
} else {
setTagsTableData([]);
}
}, [tagsData, tableInfo]);
{
label: "توزیع های لغو شده",
page: "tag_distribution",
access: "Tag-Distribution-Cancels",
},
];
return (
<Grid container column className="gap-4 mt-2">
<Grid>
<Button
size="small"
variant="submit"
page="tagging"
access="Create-Tag"
onClick={() => {
openModal({
title: "ایجاد پلاک جدید",
content: <SubmitTagDistribution getData={handleUpdate} />,
});
}}
>
توزیع پلاک
</Button>
<Grid container column className="justify-center mt-2">
<Tabs tabs={tabItems} onChange={handleTabChange} size="medium" />
<Grid container column className="mt-2">
{selectedTab === 0 ? (
<TagActiveDistributions />
) : (
<TagCanceledDistributions />
)}
</Grid>
<Grid isDashboard>
<Table
isDashboard
title="خلاصه اطلاعات"
noPagination
noSearch
columns={[
"تعداد کل",
"تعداد پلاک های آزاد",
"تعداد پلاک شده",
"گاو",
"گاومیش",
"شتر",
"گوسفند",
"بز",
]}
rows={[
[
tagDashboardData?.count?.toLocaleString() || 0,
tagDashboardData?.free_count?.toLocaleString() || 0,
tagDashboardData?.assign_count?.toLocaleString() || 0,
tagDashboardData?.cow_count?.toLocaleString() || 0,
tagDashboardData?.buffalo_count?.toLocaleString() || 0,
tagDashboardData?.camel_count?.toLocaleString() || 0,
tagDashboardData?.sheep_count?.toLocaleString() || 0,
tagDashboardData?.goat_count?.toLocaleString() || 0,
],
]}
/>
</Grid>
<Table
className="mt-2"
onChange={setTableInfo}
count={tagsData?.count || 0}
isPaginated
title="توزیع پلاک"
columns={[
"ردیف",
"شناسه توزیع",
"تاریخ ثبت",
"توزیع کننده",
"دریافت کننده",
"تعداد کل پلاک",
"نوع توزیع",
"جزئیات توزیع",
"عملیات",
]}
rows={tagsTableData}
/>
</Grid>
);
}