2026-01-19 13:08:58 +03:30
|
|
|
|
import { motion } from "framer-motion";
|
2026-02-23 12:30:27 +03:30
|
|
|
|
import { useApiRequest } from "../../utils/useApiRequest";
|
|
|
|
|
|
import sabos from "../../assets/images/products/saboos.png";
|
|
|
|
|
|
import jo from "../../assets/images/products/jo.png";
|
|
|
|
|
|
import soya from "../../assets/images/products/soya.png";
|
|
|
|
|
|
import zorat from "../../assets/images/products/zorat.png";
|
|
|
|
|
|
import goosfandi from "../../assets/images/products/constantre-goosfandi.png";
|
|
|
|
|
|
import parvari from "../../assets/images/products/constantre-parvari.png";
|
|
|
|
|
|
import porTolid from "../../assets/images/products/constantre-gave-shiri-por-tolid.png";
|
|
|
|
|
|
import shiriMotevaset from "../../assets/images/products/constantre-gave-shiri-motevaset.png";
|
|
|
|
|
|
import defaultImage from "../../assets/images/products/default.png";
|
|
|
|
|
|
import Button from "../../components/Button/Button";
|
2026-01-19 13:08:58 +03:30
|
|
|
|
import { PencilIcon, TrashIcon } from "@heroicons/react/24/outline";
|
2026-02-23 12:30:27 +03:30
|
|
|
|
import { Grid } from "../../components/Grid/Grid";
|
|
|
|
|
|
import { useModalStore } from "../../context/zustand-store/appStore";
|
2026-02-23 14:38:30 +03:30
|
|
|
|
import { AddProduct } from "../../partials/LiveStock/feed-input/AddProduct";
|
2026-02-23 12:30:27 +03:30
|
|
|
|
import { getAbleToSee } from "../../utils/getAbleToSee";
|
2026-02-23 14:38:30 +03:30
|
|
|
|
import { DeleteProduct } from "../../partials/LiveStock/feed-input/DeleteProduct";
|
2026-01-19 13:08:58 +03:30
|
|
|
|
|
|
|
|
|
|
interface Category {
|
|
|
|
|
|
id: number;
|
|
|
|
|
|
name: string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
interface Product {
|
|
|
|
|
|
id: number;
|
|
|
|
|
|
create_date: string;
|
|
|
|
|
|
modify_date: string;
|
|
|
|
|
|
creator_info: string;
|
|
|
|
|
|
modifier_info: string;
|
|
|
|
|
|
trash: boolean;
|
|
|
|
|
|
name: string;
|
|
|
|
|
|
product_id: number;
|
|
|
|
|
|
type: string;
|
|
|
|
|
|
img: string;
|
|
|
|
|
|
created_by: number;
|
|
|
|
|
|
modified_by: number;
|
|
|
|
|
|
category: Category;
|
|
|
|
|
|
image: string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export default function Products() {
|
|
|
|
|
|
const { openModal } = useModalStore();
|
|
|
|
|
|
|
|
|
|
|
|
const { data: productsData, refetch } = useApiRequest({
|
|
|
|
|
|
api: "/product/web/api/v1/product/",
|
|
|
|
|
|
method: "get",
|
|
|
|
|
|
params: { page: 1, page_size: 100 },
|
|
|
|
|
|
queryKey: ["products"],
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const getProductImage = (name: string) => {
|
|
|
|
|
|
switch (name) {
|
|
|
|
|
|
case "سبوس":
|
|
|
|
|
|
return sabos;
|
|
|
|
|
|
case "جو":
|
|
|
|
|
|
return jo;
|
|
|
|
|
|
case "سویا":
|
|
|
|
|
|
return soya;
|
|
|
|
|
|
case "ذرت":
|
|
|
|
|
|
return zorat;
|
|
|
|
|
|
case "کنسانتره گوسفندی":
|
|
|
|
|
|
return goosfandi;
|
|
|
|
|
|
case "کنسانتره گاو شیری پر تولید":
|
|
|
|
|
|
return porTolid;
|
|
|
|
|
|
case "کنسانتره پرواری":
|
|
|
|
|
|
return parvari;
|
|
|
|
|
|
case "کنسانتره گاو شیری متوسط":
|
|
|
|
|
|
return shiriMotevaset;
|
|
|
|
|
|
default:
|
|
|
|
|
|
return defaultImage;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const container = {
|
|
|
|
|
|
hidden: { opacity: 0 },
|
|
|
|
|
|
show: {
|
|
|
|
|
|
opacity: 1,
|
|
|
|
|
|
transition: {
|
|
|
|
|
|
staggerChildren: 0.1,
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const item = {
|
|
|
|
|
|
hidden: { y: 20, opacity: 0 },
|
|
|
|
|
|
show: {
|
|
|
|
|
|
y: 0,
|
|
|
|
|
|
opacity: 1,
|
|
|
|
|
|
transition: {
|
|
|
|
|
|
duration: 0.3,
|
|
|
|
|
|
ease: "easeOut",
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<motion.div
|
|
|
|
|
|
className="p-1 md:p-4 w-full"
|
|
|
|
|
|
initial="hidden"
|
|
|
|
|
|
animate="show"
|
|
|
|
|
|
variants={container}
|
|
|
|
|
|
>
|
|
|
|
|
|
<Grid>
|
|
|
|
|
|
<Button
|
|
|
|
|
|
className="mb-2"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
page="feed_input_products"
|
|
|
|
|
|
access="Post-Product"
|
|
|
|
|
|
variant="submit"
|
|
|
|
|
|
onClick={() => {
|
|
|
|
|
|
openModal({
|
|
|
|
|
|
title: "ایجاد محصول",
|
|
|
|
|
|
content: <AddProduct getData={refetch} />,
|
|
|
|
|
|
});
|
|
|
|
|
|
}}
|
|
|
|
|
|
>
|
|
|
|
|
|
ایجاد محصول
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
</Grid>
|
|
|
|
|
|
<motion.div className=" hidden md:grid grid-cols-2 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-3 2xl:grid-cols-4 lg:mx-30 xl:mx-40 2xl:mx-70 gap-4 justify-items-center">
|
|
|
|
|
|
{productsData?.results?.map((product: Product) => (
|
|
|
|
|
|
<motion.div
|
|
|
|
|
|
key={product.id}
|
|
|
|
|
|
className="bg-white dark:bg-dark-600 rounded-lg shadow-md overflow-hidden flex flex-col max-w-60 w-full"
|
|
|
|
|
|
variants={item}
|
|
|
|
|
|
initial="hidden"
|
|
|
|
|
|
animate="show"
|
|
|
|
|
|
>
|
|
|
|
|
|
<div className="h-50 bg-gray-100 dark:bg-dark-700">
|
|
|
|
|
|
<img
|
|
|
|
|
|
src={
|
|
|
|
|
|
product?.img && product.img !== "empty"
|
|
|
|
|
|
? `${product.img}?t=${product.modify_date || Date.now()}`
|
|
|
|
|
|
: getProductImage(product.name)
|
|
|
|
|
|
}
|
|
|
|
|
|
alt={product.name}
|
|
|
|
|
|
className="w-full h-full object-cover dark:opacity-60"
|
|
|
|
|
|
key={`${product.id}-${product.modify_date}`}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div className="p-3 flex flex-col gap-1 text-sm text-gray-500 dark:text-dark-200">
|
|
|
|
|
|
<p className="font-extrabold">{product.name}</p>
|
|
|
|
|
|
<p>کد محصول: {product.product_id}</p>
|
|
|
|
|
|
<p
|
|
|
|
|
|
className={`text-xs p-1 px-2 rounded-lg w-12 text-center ${
|
|
|
|
|
|
product.type === "gov"
|
|
|
|
|
|
? "text-gray-600 bg-gray1-100"
|
|
|
|
|
|
: "text-gray-100 bg-gray-400"
|
|
|
|
|
|
}`}
|
|
|
|
|
|
>
|
|
|
|
|
|
{product.type === "gov" ? "دولتی" : "آزاد"}
|
|
|
|
|
|
</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div className="flex justify-between items-center gap-2 px-2 pb-3 mt-auto">
|
|
|
|
|
|
<Button
|
|
|
|
|
|
page="feed_input_products"
|
|
|
|
|
|
access="Edit-Product"
|
|
|
|
|
|
onClick={() => {
|
|
|
|
|
|
openModal({
|
|
|
|
|
|
title: "ویرایش محصول",
|
|
|
|
|
|
content: <AddProduct getData={refetch} item={product} />,
|
|
|
|
|
|
});
|
|
|
|
|
|
}}
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
fullWidth
|
|
|
|
|
|
className="bg-primary-500 dark:bg-dark-500 hover:bg-primary-400 dark:hover:bg-dark-400 text-white px-3 w-full rounded-lg text-sm"
|
|
|
|
|
|
>
|
|
|
|
|
|
ویرایش
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
<Button
|
|
|
|
|
|
onClick={() => {
|
|
|
|
|
|
openModal({
|
|
|
|
|
|
title: "آیا از حذف محصول اطمینان دارید؟",
|
|
|
|
|
|
content: <DeleteProduct getData={refetch} item={product} />,
|
|
|
|
|
|
});
|
|
|
|
|
|
}}
|
|
|
|
|
|
page="feed_input_products"
|
|
|
|
|
|
access="Delete-Product"
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
fullWidth
|
|
|
|
|
|
className="bg-white dark:bg-dark-600 text-primary-600 border w-full px-3 rounded-lg hover:bg-red-100 dark:hover:bg-dark-500 text-sm"
|
|
|
|
|
|
>
|
|
|
|
|
|
حذف
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</motion.div>
|
|
|
|
|
|
))}
|
|
|
|
|
|
</motion.div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* mobile */}
|
|
|
|
|
|
<motion.div className="grid md:hidden grid-cols-1 gap-2 justify-items-center">
|
|
|
|
|
|
{productsData?.results?.map((product: Product) => (
|
|
|
|
|
|
<motion.div
|
|
|
|
|
|
key={product.id}
|
|
|
|
|
|
className="bg-white dark:bg-dark-600 rounded-lg shadow-sm border border-gray-300 overflow-hidden flex justify-between items-center p-2 w-full"
|
|
|
|
|
|
variants={item}
|
|
|
|
|
|
initial="hidden"
|
|
|
|
|
|
animate="show"
|
|
|
|
|
|
>
|
|
|
|
|
|
<div className="h-15 bg-transparent w-1/6 dark:bg-dark-700">
|
|
|
|
|
|
<img
|
|
|
|
|
|
src={
|
|
|
|
|
|
product?.img && product.img !== "empty"
|
|
|
|
|
|
? `${product.img}?t=${product.modify_date || Date.now()}`
|
|
|
|
|
|
: getProductImage(product.name)
|
|
|
|
|
|
}
|
|
|
|
|
|
alt={product.name}
|
|
|
|
|
|
className="w-15 h-full object-cover rounded-xl dark:opacity-80"
|
|
|
|
|
|
key={`${product.id}-${product.modify_date}`}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div className="p-3 flex flex-col text-xs text-gray-500 dark:text-dark-200 w-3/6">
|
|
|
|
|
|
<p className="font-extrabold">{product.name}</p>
|
|
|
|
|
|
<p>کد محصول: {product.product_id}</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<p
|
|
|
|
|
|
className={`text-xs p-1 px-2 rounded-lg max-w-12 text-center w-1/6 ${
|
|
|
|
|
|
product.type === "gov"
|
|
|
|
|
|
? "text-gray-600 bg-gray1-100"
|
|
|
|
|
|
: "text-gray-100 bg-gray-400"
|
|
|
|
|
|
}`}
|
|
|
|
|
|
>
|
|
|
|
|
|
{product.type === "gov" ? "دولتی" : "آزاد"}
|
|
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
|
|
<div className="flex justify-between items-end flex-col gap-4 w-1/6">
|
|
|
|
|
|
<button
|
|
|
|
|
|
className={`${getAbleToSee(
|
|
|
|
|
|
"feed_input_products",
|
2026-02-23 12:30:27 +03:30
|
|
|
|
"Edit-Product",
|
2026-01-19 13:08:58 +03:30
|
|
|
|
)} rounded-full text-primary-600 text-sm`}
|
|
|
|
|
|
onClick={() => {
|
|
|
|
|
|
openModal({
|
|
|
|
|
|
title: "ویرایش محصول",
|
|
|
|
|
|
content: <AddProduct getData={refetch} item={product} />,
|
|
|
|
|
|
});
|
|
|
|
|
|
}}
|
|
|
|
|
|
>
|
|
|
|
|
|
<PencilIcon className="w-5" />
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<button
|
|
|
|
|
|
onClick={() => {
|
|
|
|
|
|
openModal({
|
|
|
|
|
|
title: "آیا از حذف محصول اطمینان دارید؟",
|
|
|
|
|
|
content: <DeleteProduct getData={refetch} item={product} />,
|
|
|
|
|
|
});
|
|
|
|
|
|
}}
|
|
|
|
|
|
className={`${getAbleToSee(
|
|
|
|
|
|
"feed_input_products",
|
2026-02-23 12:30:27 +03:30
|
|
|
|
"Delete-Product",
|
2026-01-19 13:08:58 +03:30
|
|
|
|
)} text-red-400 rounded-lg text-sm`}
|
|
|
|
|
|
>
|
|
|
|
|
|
<TrashIcon className="w-5" />
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</motion.div>
|
|
|
|
|
|
))}
|
|
|
|
|
|
</motion.div>
|
|
|
|
|
|
</motion.div>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|