This commit is contained in:
2026-01-18 16:03:27 +03:30
parent 4fe6e70525
commit ca22cced44
321 changed files with 10738 additions and 17770 deletions

View File

@@ -38,7 +38,7 @@ function AdvancedTablePage({ columns, list, api }) {
setPage(0);
};
const codeList = eval(list);
let codeList = eval(list);
function replacePlaceholders(inputHTML, item) {
const replacedHTML = inputHTML.replace(
@@ -60,7 +60,7 @@ function AdvancedTablePage({ columns, list, api }) {
useEffect(() => {
const d = tableData?.map((item) => {
const result = codeList.map((option) => {
const result = codeList.map((option, i) => {
const properties = option.split(".");
let value = item;
for (const property of properties) {

View File

@@ -19,8 +19,8 @@ export const AdvancedTable = ({ columns, data, name, pagination }) => {
}, [data]);
useEffect(() => {
const d = data?.map((item) => {
return item?.map((row) => {
const d = data?.map((item, i) => {
return item?.map((row, index) => {
if (!row && row !== 0) {
return "";
} else {

View File

@@ -4,8 +4,6 @@ import { Grid } from "../grid/Grid";
import { SPACING } from "../../data/spacing";
import { LabelField } from "../label-field/LabelField";
import CloseIcon from "@mui/icons-material/Close";
import PictureAsPdfIcon from "@mui/icons-material/PictureAsPdf";
import axios from "axios";
export const InspectionDetailsModal = ({ item }) => {
const [statusTab, setStatusTab] = useState(0);
@@ -23,12 +21,6 @@ export const InspectionDetailsModal = ({ item }) => {
setFullscreenMedia(null);
};
const handleDownloadPdf = () => {
const baseUrl = axios.defaults.baseURL || "";
const url = `${baseUrl}poultry_science_report_pdf/?key=${item?.key}`;
window.open(url, "_blank");
};
const formatDate = (dateString) => {
if (!dateString) return "---";
try {
@@ -433,25 +425,9 @@ export const InspectionDetailsModal = ({ item }) => {
p: 2,
}}
>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
mb: 2,
}}
>
<Typography variant="h5" sx={{ fontWeight: "bold" }}>
<Typography variant="h5" sx={{ fontWeight: "bold", mb: 2 }}>
اطلاعات
</Typography>
<IconButton
onClick={handleDownloadPdf}
color="error"
title="دانلود PDF"
>
<PictureAsPdfIcon />
</IconButton>
</Box>
<Divider sx={{ mb: 3 }} />
{renderInformationTab()}

View File

@@ -224,7 +224,7 @@ const ResponsiveTable = ({
justifyContent="space-between"
xs={12}
style={{
width: "100%",
width: "85vw",
}}
>
<Grid gap={2} alignItems="center">
@@ -442,7 +442,7 @@ const ResponsiveTable = ({
id="startoftable"
display={{ xs: "none", sm: "grid" }}
style={{
width: customWidth ? customWidth : "100%",
width: customWidth ? customWidth : "85vw",
}}
>
<TableContainer

View File

@@ -1,26 +0,0 @@
import { useSelector } from "react-redux";
/**
* Hook to get the currently selected sub user from Redux state
* @returns {Object|null} - The selected sub user object with { key, name, unit, mobile, fullname } or null
*/
export const useSelectedSubUser = () => {
const selectedSubUser = useSelector(
(state) => state.userSlice.selectedSubUser
);
return selectedSubUser;
};
/**
* Hook to get only the selected sub user key
* @returns {string|null} - The sub user key or null
*/
export const useSelectedSubUserKey = () => {
const selectedSubUser = useSelector(
(state) => state.userSlice.selectedSubUser
);
return selectedSubUser?.key || null;
};
export default useSelectedSubUser;

View File

@@ -1,23 +0,0 @@
import { createAsyncThunk } from "@reduxjs/toolkit";
import axios from "axios";
import { LOADING_END, LOADING_START } from "../../../lib/redux/slices/appSlice";
export const getUserRoleInfo = createAsyncThunk(
"GET_USER_ROLE_INFO",
async ({ userKey, role }, { dispatch }) => {
try {
dispatch(LOADING_START());
const { data, status } = await axios.get("user-role-info/", {
params: {
user_key: userKey,
role: role,
},
});
dispatch(LOADING_END());
return { data, status };
} catch (error) {
dispatch(LOADING_END());
throw error;
}
}
);

View File

@@ -39,7 +39,7 @@ export const AvicultureActiveRequests = () => {
const filteredData =
Array.isArray(avicultureRequests) &&
avicultureRequests?.filter(
(item) =>
(item, i) =>
(item.stateProcess === "accepted" ||
item.stateProcess === "pending") &&
item.finalState !== "archive"

View File

@@ -365,7 +365,7 @@ export const AvicultureFreeSaleNewRequest = () => {
useEffect(() => {
if (poultryKey) {
dispatch(LOADING_START());
dispatch(avicultureGetHatchingData({ key: poultryKey })).then((r) => {
dispatch(avicultureGetHatchingData(poultryKey)).then((r) => {
if (r.payload.data) {
setHatchingData(r.payload.data);

View File

@@ -170,7 +170,7 @@ export const AvicultureNewRequest = () => {
}
};
const removeInput = () => {
const removeInput = (e) => {
const number = arr.length - 1;
if (number !== 0) {
@@ -381,7 +381,7 @@ export const AvicultureNewRequest = () => {
useEffect(() => {
if (poultryKey) {
dispatch(LOADING_START());
dispatch(avicultureGetHatchingData({ key: poultryKey })).then((r) => {
dispatch(avicultureGetHatchingData(poultryKey)).then((r) => {
if (r.payload.data) {
setHatchingData(r.payload.data);

View File

@@ -487,7 +487,7 @@ export const ProvinceFreeSaleNewRequest = ({ fetchApiData }) => {
useEffect(() => {
if (poultryKey) {
dispatch(LOADING_START());
dispatch(avicultureGetHatchingData({ key: poultryKey })).then((r) => {
dispatch(avicultureGetHatchingData(poultryKey)).then((r) => {
if (r.payload.data) {
setHatchingData(r.payload.data);

View File

@@ -3,12 +3,8 @@ import axios from "axios";
export const avicultureGetHatchingData = createAsyncThunk(
"VET_GET_HATCHING",
async (d) => {
const { data, status } = await axios.get("poultry_hatching/", {
params: {
key: d.key || "",
},
});
async (key) => {
const { data, status } = await axios.get("poultry_hatching/?key=" + key);
return { data, status };
}
);

View File

@@ -864,7 +864,7 @@ export const CityHatchingShowTableDetail = ({ keyItem }) => {
</AccordionDetails>
</Accordion>
</Grid>
<Grid item xs={12}>
<Grid>
<Accordion sx={{ width: "100%" }}>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography>اطلاعات بارهای قرنطینه</Typography>
@@ -895,7 +895,7 @@ export const CityHatchingShowTableDetail = ({ keyItem }) => {
</AccordionDetails>
</Accordion>
</Grid>
<Grid item xs={12}>
<Grid>
<Accordion sx={{ width: "100%" }}>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography>اطلاعات بارهای بازگشتی</Typography>
@@ -942,7 +942,7 @@ export const CityHatchingShowTableDetail = ({ keyItem }) => {
</AccordionDetails>
</Accordion>
</Grid>
<Grid item xs={12}>
<Grid>
<Accordion sx={{ width: "100%" }}>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography>اطلاعات تخصیصات بازگشتی</Typography>
@@ -982,7 +982,7 @@ export const CityHatchingShowTableDetail = ({ keyItem }) => {
</AccordionDetails>
</Accordion>
</Grid>
<Grid item xs={12}>
<Grid>
<Accordion sx={{ width: "100%" }}>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography>اطلاعات بارهای خارج استان</Typography>
@@ -1016,7 +1016,7 @@ export const CityHatchingShowTableDetail = ({ keyItem }) => {
</Accordion>
</Grid>
<Grid item xs={12}>
<Grid>
<Accordion sx={{ width: "100%" }}>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography>مدیریت بار زنجیره</Typography>
@@ -1052,7 +1052,7 @@ export const CityHatchingShowTableDetail = ({ keyItem }) => {
</AccordionDetails>
</Accordion>
</Grid>
<Grid item xs={12}>
<Grid>
<Accordion sx={{ width: "100%" }}>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography>اختلاف کشتار</Typography>
@@ -1086,7 +1086,7 @@ export const CityHatchingShowTableDetail = ({ keyItem }) => {
</AccordionDetails>
</Accordion>
</Grid>
<Grid item xs={12}>
<Grid>
<Accordion sx={{ width: "100%" }}>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography>گزارش تلفات</Typography>

View File

@@ -556,7 +556,7 @@ export const CityHatchingUnassigned = ({ readOnly }) => {
return (
<Grid alignItems="center" justifyContent="center" mt={2} xs={12}>
<Grid alignItems="center" justifyContent="center" isDashboard xs={12}>
<Grid alignItems="center" justifyContent="center" isDashboard>
<ResponsiveTable
noPagination
isDashboard

View File

@@ -354,7 +354,7 @@ export const CityHatchingsArchive = ({ readOnly }) => {
return (
<Grid container xs={12} justifyContent="center" alignItems="center" gap={2}>
<Grid alignItems="center" justifyContent="center" isDashboard xs={12}>
<Grid alignItems="center" justifyContent="center" isDashboard>
<ResponsiveTable
noPagination
isDashboard

View File

@@ -538,7 +538,7 @@ export const CityHatchingsTotal = ({ readOnly }) => {
return (
<Grid alignItems="center" justifyContent="center" mt={2}>
<Grid alignItems="center" justifyContent="center" isDashboard xs={12}>
<Grid alignItems="center" justifyContent="center" isDashboard>
<ResponsiveTable
noPagination
isDashboard

View File

@@ -546,7 +546,7 @@ export const CityHatchings = ({ readOnly }) => {
return (
<Grid alignItems="center" justifyContent="center" mt={2}>
<Grid alignItems="center" justifyContent="center" isDashboard xs={12}>
<Grid alignItems="center" justifyContent="center" isDashboard>
<ResponsiveTable
noPagination
isDashboard

View File

@@ -30,8 +30,9 @@ export const CityIncreaseHatching = ({ state }) => {
const [tableData, setTableData] = useState([]);
const fetchApiData = async (page) => {
let response;
dispatch(LOADING_START());
const response = await axios.get(
response = await axios.get(
`hatching-increase-request/?search=filter&value=${textValue}&role=${getRoleFromUrl()}&page=${page}&page_size=${perPage}`
);
dispatch(LOADING_END());

View File

@@ -668,7 +668,7 @@ export const CityNewKillRequest = ({
);
}
});
dispatch(avicultureGetHatchingData({ key: poultryKey })).then((r) => {
dispatch(avicultureGetHatchingData(poultryKey)).then((r) => {
if (r.payload.data) {
setHatchingData(r.payload.data);
} else {

View File

@@ -1,4 +1,5 @@
import {
Card,
Grid,
IconButton,
List,
@@ -7,7 +8,7 @@ import {
ListItemText,
Popover,
} from "@mui/material";
import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable";
import { AdvancedTable } from "../../../../components/advanced-table/AdvancedTable";
import { SPACING } from "../../../../data/spacing";
import { useDispatch, useSelector } from "react-redux";
@@ -186,12 +187,13 @@ export const CityPoultryFarms = () => {
gap={SPACING.SMALL}
mt={SPACING.MEDIUM}
>
<ResponsiveTable
title="مرغداران زیرمجموعه"
<Card sx={{ width: "100%" }}>
<AdvancedTable
name="مرغداران زیرمجموعه"
columns={tableDataCol}
data={dataTable}
customWidth="100%"
/>
</Card>
</Grid>
);
};

View File

@@ -326,7 +326,7 @@ export const NationalInfoTransports = () => {
</Grid>
</Grid>
<Grid container mt={2} mb={4} isDashboard xs={12}>
<Grid container mt={2} mb={4} isDashboard>
<ResponsiveTable
noPagination
isDashboard

View File

@@ -220,7 +220,7 @@ export const NationalInfoHatchingDetails = () => {
</Grid>
</Grid>
<Grid container mt={2} mb={4} isDashboard xs={12}>
<Grid container mt={2} mb={4} isDashboard>
<ResponsiveTable
noPagination
isDashboard

View File

@@ -101,7 +101,8 @@ export const BarChartSection = ({ boxStats }) => {
return (
<Box
sx={{
width: "100%",
flex: { xs: "1 1 100%", md: "1 1 25%" },
minWidth: { xs: "100%", sm: 300 },
borderRadius: 2,
border: "1px solid",
borderColor: "divider",
@@ -111,13 +112,12 @@ export const BarChartSection = ({ boxStats }) => {
flexDirection: "column",
boxSizing: "border-box",
overflow: "hidden",
maxHeight: "fit-content",
}}
>
<Typography
variant="subtitle1"
color="text.primary"
sx={{ mb: 2, fontWeight: 600, fontSize: "1rem" }}
variant="h6"
color="primary.main"
sx={{ mb: 2 }}
textAlign="left"
>
گزارش انبار کشتارگاه

View File

@@ -1,74 +1,17 @@
import { Box, Typography } from "@mui/material";
import { SPACING } from "../../../../data/spacing";
const reportItems = [
{ label: "حجم درخواست کشتار مرغدار:", key: "quantity" },
{ label: "وزن درخواست کشتار مرغدار:", key: "totalWeight" },
{ label: "حجم خرید های مستقیم :", key: "killRequestQuantity" },
{ label: "وزن خرید های مستقیم :", key: "killRequestWeight" },
{
label: "حجم خرید های خارج از استان (زنده) :",
key: "quantityKillHouseFreeBarLive",
},
{
label: "وزن خرید های خارج از استان (زنده) :",
key: "WeightKillHouseFreeBarLive",
},
{
label: "وزن خرید های خارج از استان (لاشه) :",
key: "WeightKillHouseFreeBarCarcass",
},
{
label: "حجم کل تخصیصات (خرید مستقیم/ مرغدار ):",
key: "provinceKillRequestQuantity",
},
{
label: "وزن کل تخصیصات (خرید مستقیم/ مرغدار ):",
key: "provinceKillRequestWeightCarcass",
},
{ label: "حجم فروش به خارج استان:", key: "poultryOutProvinceQuantity" },
{ label: "وزن فروش به خارج استان:", key: "poultryOutProvinceWeight" },
{ label: "حجم بارها:", key: "KillHouseRequestQuantity" },
{ label: "وزن بارها:", key: "KillHouseRequestWeight" },
{
label: "لاشه تولیدی امروز با احتساب 25درصد افت کشتار :",
key: "totalLossWeight",
},
];
const ReportRow = ({ label, value }) => (
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
minHeight: 40,
px: 2,
py: 0.5,
borderRadius: 1,
backgroundColor: "rgba(147, 112, 219, 0.1)",
}}
>
<Typography
color="text.primary"
sx={{ fontSize: "0.85rem", textAlign: "left" }}
>
{label}
</Typography>
<Typography
color="primary.main"
fontWeight="bold"
sx={{ fontSize: "0.85rem", textAlign: "left" }}
>
{value?.toLocaleString() || 0}
</Typography>
</Box>
);
export const DailykillingReport = ({ boxStats }) => (
<Box
sx={{
width: "100%",
flex: "1 1 30%",
minWidth: {
md: "620px",
},
maxWidth: {
md: "32%",
},
borderRadius: 2,
border: "1px solid",
borderColor: "divider",
@@ -77,16 +20,18 @@ export const DailykillingReport = ({ boxStats }) => (
display: "flex",
flexDirection: "column",
gap: 2,
height: "600px",
}}
>
<Typography
textAlign="start"
variant="subtitle1"
color="text.primary"
sx={{ fontWeight: 600, fontSize: "1rem" }}
variant="h6"
sx={{ fontSize: { xs: "1rem", lg: "1rem" } }}
color="primary.main"
>
گزارش کشتار امروز مرغ گوشتی استان
</Typography>
<Box
sx={{
display: "flex",
@@ -94,16 +39,439 @@ export const DailykillingReport = ({ boxStats }) => (
gap: 1,
overflowY: "auto",
flex: 1,
maxHeight: "500px",
}}
>
{reportItems.map((item) => (
<ReportRow
key={item.key}
label={item.label}
value={boxStats?.killing?.[item.key]}
/>
))}
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
height: { xs: "inherit", md: 48 },
px: 2,
py: 1,
backgroundColor: "rgba(147, 112, 219, 0.1)",
}}
>
<Typography
color="primary.main"
sx={{
fontSize: { xs: "0.875rem", lg: "1rem" },
textAlign: "left",
}}
>
حجم درخواست کشتار مرغدار:
</Typography>
<Typography
color="primary.main"
fontWeight="bold"
sx={{
fontSize: { xs: "0.825rem", sm: "1rem" },
}}
>
{boxStats?.killing?.quantity?.toLocaleString() || 0}
</Typography>
</Box>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
height: { xs: "inherit", md: 48 },
px: 2,
py: 1,
backgroundColor: "rgba(147, 112, 219, 0.1)",
}}
>
<Typography
color="primary.main"
sx={{
fontSize: { xs: "0.875rem", lg: "1rem" },
textAlign: "left",
}}
>
وزن درخواست کشتار مرغدار:
</Typography>
<Typography
color="primary.main"
fontWeight="bold"
sx={{
fontSize: { xs: "0.825rem", sm: "1rem" },
}}
>
{boxStats?.killing?.totalWeight?.toLocaleString() || 0}
</Typography>
</Box>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
height: { xs: "inherit", md: 48 },
px: 2,
py: 1,
backgroundColor: "rgba(147, 112, 219, 0.1)",
}}
>
<Typography
color="primary.main"
sx={{
fontSize: { xs: "0.875rem", lg: "1rem" },
textAlign: "left",
}}
>
حجم خرید های مستقیم :
</Typography>
<Typography
color="primary.main"
fontWeight="bold"
sx={{
fontSize: { xs: "0.825rem", sm: "1rem" },
}}
>
{boxStats?.killing?.killRequestQuantity?.toLocaleString() || 0}
</Typography>
</Box>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
height: { xs: "inherit", md: 48 },
px: 2,
py: 1,
backgroundColor: "rgba(147, 112, 219, 0.1)",
}}
>
<Typography
color="primary.main"
sx={{
fontSize: { xs: "0.875rem", lg: "1rem" },
textAlign: "left",
}}
>
وزن خرید های مستقیم :
</Typography>
<Typography
color="primary.main"
fontWeight="bold"
sx={{
fontSize: { xs: "0.825rem", sm: "1rem" },
}}
>
{boxStats?.killing?.killRequestWeight?.toLocaleString() || 0}
</Typography>
</Box>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
height: { xs: "inherit", md: 48 },
px: 2,
py: 1,
backgroundColor: "rgba(147, 112, 219, 0.1)",
}}
>
<Typography
color="primary.main"
sx={{
fontSize: { xs: "0.875rem", lg: "1rem" },
textAlign: "left",
}}
>
حجم خرید های خارج از استان (زنده) :
</Typography>
<Typography
color="primary.main"
fontWeight="bold"
sx={{
fontSize: { xs: "0.825rem", sm: "1rem" },
}}
>
{boxStats?.killing?.quantityKillHouseFreeBarLive?.toLocaleString() ||
0}
</Typography>
</Box>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
height: { xs: "inherit", md: 48 },
px: 2,
py: 1,
backgroundColor: "rgba(147, 112, 219, 0.1)",
}}
>
<Typography
color="primary.main"
sx={{
fontSize: { xs: "0.875rem", lg: "1rem" },
textAlign: "left",
}}
>
وزن خرید های خارج از استان (زنده) :
</Typography>
<Typography
color="primary.main"
fontWeight="bold"
sx={{
fontSize: { xs: "0.825rem", sm: "1rem" },
}}
>
{boxStats?.killing?.WeightKillHouseFreeBarLive?.toLocaleString() || 0}
</Typography>
</Box>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
height: { xs: "inherit", md: 48 },
px: 2,
py: 1,
backgroundColor: "rgba(147, 112, 219, 0.1)",
}}
>
<Typography
color="primary.main"
sx={{
fontSize: { xs: "0.875rem", lg: "1rem" },
textAlign: "left",
}}
>
وزن خرید های خارج از استان (لاشه) :
</Typography>
<Typography
color="primary.main"
fontWeight="bold"
sx={{
fontSize: { xs: "0.825rem", sm: "1rem" },
}}
>
{boxStats?.killing?.WeightKillHouseFreeBarCarcass?.toLocaleString() ||
0}
</Typography>
</Box>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
height: { xs: "inherit", md: 48 },
px: 2,
py: 1,
backgroundColor: "rgba(147, 112, 219, 0.1)",
}}
>
<Typography
color="primary.main"
sx={{
fontSize: { xs: "0.875rem", lg: "1rem" },
textAlign: "left",
}}
>
حجم کل تخصیصات (خرید مستقیم/ مرغدار ):
</Typography>
<Typography
color="primary.main"
fontWeight="bold"
sx={{
fontSize: { xs: "0.825rem", sm: "1rem" },
}}
>
{boxStats?.killing?.provinceKillRequestQuantity?.toLocaleString() ||
0}
</Typography>
</Box>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
height: { xs: "inherit", md: 48 },
px: 2,
py: 1,
backgroundColor: "rgba(147, 112, 219, 0.1)",
}}
>
<Typography
color="primary.main"
sx={{
fontSize: { xs: "0.875rem", lg: "1rem" },
textAlign: "left",
}}
>
وزن کل تخصیصات (خرید مستقیم/ مرغدار ):
</Typography>
<Typography
color="primary.main"
fontWeight="bold"
sx={{
fontSize: { xs: "0.825rem", sm: "1rem" },
}}
>
{boxStats?.killing?.provinceKillRequestWeightCarcass?.toLocaleString() ||
0}
</Typography>
</Box>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
height: { xs: "inherit", md: 48 },
px: 2,
py: 1,
backgroundColor: "rgba(147, 112, 219, 0.1)",
}}
>
<Typography
color="primary.main"
sx={{
fontSize: { xs: "0.875rem", lg: "1rem" },
textAlign: "left",
}}
>
حجم فروش به خارج استان:
</Typography>
<Typography
color="primary.main"
fontWeight="bold"
sx={{
fontSize: { xs: "0.825rem", sm: "1rem" },
}}
>
{boxStats?.killing?.poultryOutProvinceQuantity?.toLocaleString() || 0}
</Typography>
</Box>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
height: { xs: "inherit", md: 48 },
px: 2,
py: 1,
backgroundColor: "rgba(147, 112, 219, 0.1)",
}}
>
<Typography
color="primary.main"
sx={{
fontSize: { xs: "0.875rem", lg: "1rem" },
textAlign: "left",
}}
>
وزن فروش به خارج استان:
</Typography>
<Typography
color="primary.main"
fontWeight="bold"
sx={{
fontSize: { xs: "0.825rem", sm: "1rem" },
}}
>
{boxStats?.killing?.poultryOutProvinceWeight?.toLocaleString() || 0}
</Typography>
</Box>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
height: { xs: "inherit", md: 48 },
px: 2,
py: 1,
backgroundColor: "rgba(147, 112, 219, 0.1)",
}}
>
<Typography
color="primary.main"
sx={{
fontSize: { xs: "0.875rem", lg: "1rem" },
textAlign: "left",
}}
>
حجم بارها:
</Typography>
<Typography
color="primary.main"
fontWeight="bold"
sx={{
fontSize: { xs: "0.825rem", sm: "1rem" },
}}
>
{boxStats?.killing?.KillHouseRequestQuantity?.toLocaleString() || 0}
</Typography>
</Box>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
height: { xs: "inherit", md: 48 },
px: 2,
py: 1,
backgroundColor: "rgba(147, 112, 219, 0.1)",
}}
>
<Typography
color="primary.main"
sx={{
fontSize: { xs: "0.875rem", lg: "1rem" },
textAlign: "left",
}}
>
وزن بارها:
</Typography>
<Typography
color="primary.main"
fontWeight="bold"
sx={{
fontSize: { xs: "0.825rem", sm: "1rem" },
}}
>
{boxStats?.killing?.KillHouseRequestWeight?.toLocaleString() || 0}
</Typography>
</Box>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
height: { xs: "inherit", md: 48 },
px: 2,
py: 1,
borderRadius: 1,
backgroundColor: "rgba(147, 112, 219, 0.1)",
}}
>
<Typography
color="primary.main"
sx={{
fontSize: { xs: "0.875rem", lg: "1rem" },
textAlign: "left",
// maxWidth: "70%",
}}
>
لاشه تولیدی امروز با احتساب 25درصد افت کشتار :
</Typography>
<Typography
color="primary.main"
fontWeight="bold"
sx={{
fontSize: { xs: "0.825rem", sm: "1rem" },
}}
>
{boxStats?.killing?.totalLossWeight?.toLocaleString() || 0}
</Typography>
</Box>
</Box>
</Box>
);

View File

@@ -1,87 +1,60 @@
import { Box, Typography } from "@mui/material";
import { SPACING } from "../../../../data/spacing";
const inventoryItems = [
{
label: "حجم آماده کشتار بزرگتر از 40 روز (قطعه) :",
key: "leftOverBetweenFortySeventyFive",
},
{
label: "وزن تقریبی کشتار بزرگتر از 40 روز (کیلوگرم) :",
key: "weightBetweenFortySeventyFive",
},
{
label: "میانگین وزن مرغداری‌های آماده کشتار:",
key: "aveWeight",
suffix: " کیلوگرم",
},
{ label: "وزن گوشت قابل تولید:", key: "carcassWeight", suffix: " کیلوگرم" },
];
const InventoryRow = ({ label, value, suffix = "" }) => (
export const InventorySection = ({ boxStats }) => (
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
minHeight: 40,
px: 2,
py: 0.5,
borderRadius: 1,
backgroundColor: "rgba(0, 128, 0, 0.1)",
}}
>
<Typography
color="text.primary"
sx={{ fontSize: "0.85rem", textAlign: "left" }}
>
{label}
</Typography>
<Typography
fontWeight="bold"
color="success.main"
sx={{ fontSize: "0.85rem" }}
>
{value?.toLocaleString() || 0}
{suffix}
</Typography>
</Box>
);
export const InventorySection = ({ boxStats, sx }) => (
<Box
sx={{
width: "100%",
flex: "1 1 30%",
minWidth: { xs: "100%", sm: "340px" },
maxWidth: { xs: "100%", md: "16%" },
borderRadius: 2,
border: "1px solid",
borderColor: "divider",
px: SPACING.MEDIUM,
py: SPACING.SMALL,
p: SPACING.MEDIUM,
pt: 4,
display: "flex",
flexDirection: "column",
boxSizing: "border-box",
backgroundColor: "rgba(0, 128, 0, 0.05)",
textAlign: "left",
...sx,
}}
>
<Typography
variant="subtitle1"
color="text.primary"
sx={{ mb: 2, fontWeight: 600, fontSize: "1rem" }}
variant="h6"
color="primary.main"
sx={{ mb: 2, fontSize: { xs: "1rem", lg: "1rem" } }}
>
موجودی
</Typography>
<Box sx={{ display: "flex", flexDirection: "column", gap: 1 }}>
{inventoryItems.map((item) => (
<InventoryRow
key={item.key}
label={item.label}
value={boxStats?.inventory?.[item.key]}
suffix={item.suffix}
/>
))}
</Box>
<Typography variant="body2" mt={3} bgGreen>
حجم آماده کشتار بزرگتر از 40 روز (قطعه) :
</Typography>
<Typography variant="h6" mt={2} color="success.main">
{boxStats?.inventory?.leftOverBetweenFortySeventyFive?.toLocaleString() ||
0}
</Typography>
<Typography variant="body2" mt={3} bgGreen>
وزن تقریبی کشتار بزرگتر از 40 روز (کیلوگرم) :
</Typography>
<Typography variant="h6" mt={2} color="success.main">
{boxStats?.inventory?.weightBetweenFortySeventyFive?.toLocaleString() ||
0}
</Typography>
<Typography variant="body2" mt={3} bgGreen>
میانگین وزن مرغداریهای آماده کشتار:
</Typography>
<Typography variant="h6" mt={2} color="success.main">
{boxStats?.inventory?.aveWeight?.toLocaleString() || 0} کیلوگرم
</Typography>
<Typography variant="body2" mt={3} bgGreen>
وزن گوشت قابل تولید:
</Typography>
<Typography variant="h6" mt={2} color="success.main">
{boxStats?.inventory?.carcassWeight?.toLocaleString() || 0} کیلوگرم
</Typography>
</Box>
);

View File

@@ -87,7 +87,8 @@ export const PieChartSection = ({ boxStats }) => {
<Box
sx={{
flex: "1 1 20%",
width: "100%",
minWidth: "300px",
maxWidth: "100%",
borderRadius: 2,
border: "1px solid",
borderColor: "divider",
@@ -100,9 +101,9 @@ export const PieChartSection = ({ boxStats }) => {
>
<Typography
textAlign="start"
variant="subtitle1"
color="text.primary"
sx={{ mb: 2, fontWeight: 600, fontSize: "1rem" }}
variant="h6"
color="primary.main"
sx={{ mb: 2 }}
>
آمار روز گذشته کشتار مرغ گوشتی استان
</Typography>

View File

@@ -13,18 +13,12 @@ export const PriceChartSection = ({ boxStats }) => (
border: "1px solid",
borderColor: "divider",
p: 2,
mt: 3,
}}
>
<Typography
variant="subtitle1"
sx={{
width: "100%",
textAlign: "start",
fontWeight: 600,
fontSize: "1rem",
mb: 1,
}}
color="text.primary"
sx={{ width: "100%", textAlign: "start", fontWeight: "400", mb: 1 }}
color="primary.main"
>
نمودار قیمت مرغ در هفته گذشته (میانگین قیمت)
</Typography>

View File

@@ -120,7 +120,12 @@ export const SlaughterDashboard = () => {
];
return (
<Grid container alignItems="center" justifyContent="flex-start">
<Grid
container
direction="column"
alignItems="center"
justifyContent="flex-start"
>
<Grid
container
xs={12}

View File

@@ -15,7 +15,7 @@ export const DashboardTab = () => {
setValue(newValue);
};
return (
<Grid container xs={12}>
<Grid container justifyContent="center" alignItems="center">
<Grid
item
xs={12}
@@ -44,7 +44,13 @@ export const DashboardTab = () => {
<Tab label="پایش کشتار" value={2} />
{/* <Tab label="گزارش عملکرد دوره ای" value={3} /> */}
</Tabs>
<Grid container xs={12} pt={3}>
<Grid
container
xs={12}
justifyContent="center"
alignItems="center"
p={1}
>
{value === 0 && <Dashboard />}
{value === 1 && <SlaughterDashboard />}
{value === 2 && <DashboardPeriodicPerformance />}

View File

@@ -1,65 +1,26 @@
import { Box, Typography } from "@mui/material";
const warehouseItems = [
{ label: "وزن ورودی به انبار:", key: "enterWarehouseWeight" },
{ label: "وزن فروش به خارج استان:", key: "outSellWeight" },
{ label: "وزن توزیع به داخل استان:", key: "allocationWeight" },
{ label: "وزن مانده در انبار کشتارگاه:", key: "leftOverWarehouseWeight" },
];
const WarehouseRow = ({ label, value }) => (
export const WarehouseInfoSection = ({ boxStats }) => (
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
minHeight: 40,
px: 2,
py: 0.5,
borderRadius: 1,
backgroundColor: "rgba(147, 112, 219, 0.1)",
}}
>
<Typography
color="text.primary"
sx={{ fontSize: "0.85rem", textAlign: "left" }}
>
{label}
</Typography>
<Box sx={{ display: "flex", alignItems: "center", gap: 0.5 }}>
<Typography
color="primary.main"
fontWeight="bold"
sx={{ fontSize: "0.85rem" }}
>
{value?.toLocaleString() || 0}
</Typography>
<Typography sx={{ fontSize: "0.75rem" }} color="text.secondary">
کیلوگرم
</Typography>
</Box>
</Box>
);
export const WarehouseInfoSection = ({ boxStats, sx }) => (
<Box
sx={{
width: "100%",
flex: { xs: "1 1 100%", md: "1 1 30%" },
minWidth: { xs: "100%", sm: "340px" },
borderRadius: 2,
border: "1px solid",
borderColor: "divider",
p: "16px",
// backgroundColor: "#EAEFFF",
boxSizing: "border-box",
display: "flex",
flexDirection: "column",
gap: 2,
...sx,
// height: "100%",
}}
>
<Typography
variant="subtitle1"
color="text.primary"
sx={{ fontWeight: 600, fontSize: "1rem" }}
variant="h6"
color="primary.main"
sx={{ fontSize: { xs: "1rem", lg: "1rem" } }}
textAlign="left"
>
اطلاعات انبار و توزیع امروز
@@ -70,16 +31,114 @@ export const WarehouseInfoSection = ({ boxStats, sx }) => (
display: "flex",
flexDirection: "column",
gap: 1,
overflowY: "auto",
flex: 1,
pr: 1,
}}
>
{warehouseItems.map((item) => (
<WarehouseRow
key={item.key}
label={item.label}
value={boxStats?.warehouseInformation?.[item.key]}
/>
))}
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
height: 48,
px: 2,
borderRadius: 1,
backgroundColor: "rgba(147, 112, 219, 0.1)",
}}
>
<Typography
color="primary.main"
sx={{ fontSize: { xs: "0.875rem", lg: "1rem" } }}
>
وزن ورودی به انبار:
</Typography>
<Box sx={{ display: "flex", alignItems: "center", gap: 1 }}>
<Typography color="primary.main" fontWeight="bold">
{boxStats?.warehouseInformation?.enterWarehouseWeight?.toLocaleString() ||
0}
</Typography>
<Typography variant="caption">کیلوگرم</Typography>
</Box>
</Box>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
height: 48,
px: 2,
borderRadius: 1,
backgroundColor: "rgba(147, 112, 219, 0.1)",
}}
>
<Typography
color="primary.main"
sx={{ fontSize: { xs: "0.875rem", lg: "1rem" } }}
>
وزن فروش به خارج استان:
</Typography>
<Box sx={{ display: "flex", alignItems: "center", gap: 1 }}>
<Typography color="primary.main" fontWeight="bold">
{boxStats?.warehouseInformation?.outSellWeight?.toLocaleString() ||
0}
</Typography>
<Typography variant="caption">کیلوگرم</Typography>
</Box>
</Box>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
height: 48,
px: 2,
borderRadius: 1,
backgroundColor: "rgba(147, 112, 219, 0.1)",
}}
>
<Typography
color="primary.main"
sx={{ fontSize: { xs: "0.875rem", lg: "1rem" } }}
>
وزن توزیع به داخل استان:
</Typography>
<Box sx={{ display: "flex", alignItems: "center", gap: 1 }}>
<Typography color="primary.main" fontWeight="bold">
{boxStats?.warehouseInformation?.allocationWeight?.toLocaleString() ||
0}
</Typography>
<Typography variant="caption">کیلوگرم</Typography>
</Box>
</Box>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
height: 48,
px: 2,
borderRadius: 1,
backgroundColor: "rgba(147, 112, 219, 0.1)",
}}
>
<Typography
color="primary.main"
sx={{ fontSize: { xs: "0.875rem", lg: "1rem" } }}
>
وزن مانده در انبار کشتارگاه:
</Typography>
<Box sx={{ display: "flex", alignItems: "center", gap: 1 }}>
<Typography color="primary.main" fontWeight="bold">
{boxStats?.warehouseInformation?.leftOverWarehouseWeight?.toLocaleString() ||
0}
</Typography>
<Typography variant="caption">کیلوگرم</Typography>
</Box>
</Box>
</Box>
</Box>
);

View File

@@ -1,80 +1,17 @@
import { Box, Typography } from "@mui/material";
import { SPACING } from "../../../../data/spacing";
const reportItems = [
{ label: "حجم درخواست کشتار مرغدار:", key: "quantityYesterday" },
{ label: "وزن درخواست کشتار مرغدار:", key: "totalWeightYesterday" },
{ label: "حجم خرید های مستقیم :", key: "killRequestQuantityYesterday" },
{ label: "وزن خرید های مستقیم :", key: "killRequestWeightYesterday" },
{
label: "حجم خرید های خارج از استان (زنده) :",
key: "quantityKillHouseFreeBarLiveYesterday",
},
{
label: "وزن خرید های خارج از استان (زنده) :",
key: "WeightKillHouseFreeBarLiveYesterday",
},
{
label: "وزن خرید های خارج از استان (لاشه) :",
key: "WeightKillHouseFreeBarCarcassYesterday",
},
{
label: "حجم کل تخصیصات (خرید مستقیم/ مرغدار ):",
key: "provinceKillRequestQuantityYesterday",
},
{
label: "وزن کل تخصیصات (خرید مستقیم/ مرغدار ):",
key: "provinceKillRequestWeightCarcassYesterday",
},
{
label: "حجم فروش به خارج استان:",
key: "poultryOutProvinceQuantityYesterday",
},
{
label: "وزن فروش به خارج استان:",
key: "poultryOutProvinceWeightYesterday",
},
{ label: "حجم بارها:", key: "KillHouseRequestQuantityYesterday" },
{ label: "وزن بارها:", key: "KillHouseRequestWeightYesterday" },
{
label: "لاشه تولیدی با احتساب 25درصد افت کشتار :",
key: "totalLossWeightYesterday",
},
];
const ReportRow = ({ label, value }) => (
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
minHeight: 40,
px: 2,
py: 0.5,
borderRadius: 1,
backgroundColor: "rgba(86, 156, 221, 0.1)",
}}
>
<Typography
color="text.primary"
sx={{ fontSize: "0.85rem", textAlign: "left" }}
>
{label}
</Typography>
<Typography
color="primary.main"
fontWeight="bold"
sx={{ fontSize: "0.85rem", textAlign: "left" }}
>
{value?.toLocaleString() || 0}
</Typography>
</Box>
);
export const YesterdayKillingReport = ({ boxStats }) => (
<Box
sx={{
width: "100%",
flex: "1 1 20%",
minWidth: {
md: "500px",
},
maxWidth: {
md: "25%",
},
borderRadius: 2,
border: "1px solid",
borderColor: "divider",
@@ -83,14 +20,10 @@ export const YesterdayKillingReport = ({ boxStats }) => (
display: "flex",
flexDirection: "column",
gap: 2,
height: "700px",
}}
>
<Typography
textAlign="start"
variant="subtitle1"
color="text.primary"
sx={{ fontWeight: 600, fontSize: "1rem" }}
>
<Typography textAlign="start" variant="h6" color="primary.main">
گزارش کشتار دیروز مرغ گوشتی استان
</Typography>
@@ -101,16 +34,262 @@ export const YesterdayKillingReport = ({ boxStats }) => (
gap: 1,
overflowY: "auto",
flex: 1,
maxHeight: "500px",
}}
>
{reportItems.map((item, index) => (
<ReportRow
key={index}
label={item.label}
value={boxStats?.killingYesterday?.[item.key]}
/>
))}
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
height: 48,
px: 2,
borderRadius: 1,
backgroundColor: "rgba(86, 156, 221, 0.1)",
}}
>
<Typography color="primary.main">حجم درخواست کشتار مرغدار:</Typography>
<Typography color="primary.main" fontWeight="bold">
{boxStats?.killingYesterday?.quantityYesterday?.toLocaleString() || 0}
</Typography>
</Box>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
height: 48,
px: 2,
borderRadius: 1,
backgroundColor: "rgba(86, 156, 221, 0.1)",
}}
>
<Typography color="primary.main">وزن درخواست کشتار مرغدار:</Typography>
<Typography color="primary.main" fontWeight="bold">
{boxStats?.killingYesterday?.totalWeightYesterday?.toLocaleString() ||
0}
</Typography>
</Box>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
height: 48,
px: 2,
borderRadius: 1,
backgroundColor: "rgba(86, 156, 221, 0.1)",
}}
>
<Typography color="primary.main">حجم خرید های مستقیم :</Typography>
<Typography color="primary.main" fontWeight="bold">
{boxStats?.killingYesterday?.killRequestQuantityYesterday?.toLocaleString() ||
0}
</Typography>
</Box>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
height: 48,
px: 2,
borderRadius: 1,
backgroundColor: "rgba(86, 156, 221, 0.1)",
}}
>
<Typography color="primary.main">وزن خرید های مستقیم :</Typography>
<Typography color="primary.main" fontWeight="bold">
{boxStats?.killingYesterday?.killRequestWeightYesterday?.toLocaleString() ||
0}
</Typography>
</Box>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
height: 48,
px: 2,
borderRadius: 1,
backgroundColor: "rgba(86, 156, 221, 0.1)",
}}
>
<Typography color="primary.main">
حجم خرید های خارج از استان (زنده) :
</Typography>
<Typography color="primary.main" fontWeight="bold">
{boxStats?.killingYesterday?.quantityKillHouseFreeBarLiveYesterday?.toLocaleString() ||
0}
</Typography>
</Box>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
height: 48,
px: 2,
borderRadius: 1,
backgroundColor: "rgba(86, 156, 221, 0.1)",
}}
>
<Typography color="primary.main">
وزن خرید های خارج از استان (زنده) :
</Typography>
<Typography color="primary.main" fontWeight="bold">
{boxStats?.killingYesterday?.WeightKillHouseFreeBarLiveYesterday?.toLocaleString() ||
0}
</Typography>
</Box>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
height: 48,
px: 2,
borderRadius: 1,
backgroundColor: "rgba(86, 156, 221, 0.1)",
}}
>
<Typography color="primary.main">
وزن خرید های خارج از استان (لاشه) :
</Typography>
<Typography color="primary.main" fontWeight="bold">
{boxStats?.killingYesterday?.WeightKillHouseFreeBarCarcassYesterday?.toLocaleString() ||
0}
</Typography>
</Box>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
height: 48,
px: 2,
borderRadius: 1,
backgroundColor: "rgba(86, 156, 221, 0.1)",
}}
>
<Typography color="primary.main">
حجم کل تخصیصات (خرید مستقیم/ مرغدار ):
</Typography>
<Typography color="primary.main" fontWeight="bold">
{boxStats?.killingYesterday?.provinceKillRequestQuantityYesterday?.toLocaleString() ||
0}
</Typography>
</Box>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
height: 48,
px: 2,
borderRadius: 1,
backgroundColor: "rgba(86, 156, 221, 0.1)",
}}
>
<Typography color="primary.main">
وزن کل تخصیصات (خرید مستقیم/ مرغدار ):
</Typography>
<Typography color="primary.main" fontWeight="bold">
{boxStats?.killingYesterday?.provinceKillRequestWeightCarcassYesterday?.toLocaleString() ||
0}
</Typography>
</Box>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
height: 48,
px: 2,
borderRadius: 1,
backgroundColor: "rgba(86, 156, 221, 0.1)",
}}
>
<Typography color="primary.main">حجم فروش به خارج استان:</Typography>
<Typography color="primary.main" fontWeight="bold">
{boxStats?.killingYesterday?.poultryOutProvinceQuantityYesterday?.toLocaleString() ||
0}
</Typography>
</Box>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
height: 48,
px: 2,
borderRadius: 1,
backgroundColor: "rgba(86, 156, 221, 0.1)",
}}
>
<Typography color="primary.main">وزن فروش به خارج استان:</Typography>
<Typography color="primary.main" fontWeight="bold">
{boxStats?.killingYesterday?.poultryOutProvinceWeightYesterday?.toLocaleString() ||
0}
</Typography>
</Box>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
height: 48,
px: 2,
borderRadius: 1,
backgroundColor: "rgba(86, 156, 221, 0.1)",
}}
>
<Typography color="primary.main">حجم بارها:</Typography>
<Typography color="primary.main" fontWeight="bold">
{boxStats?.killingYesterday?.KillHouseRequestQuantityYesterday?.toLocaleString() ||
0}
</Typography>
</Box>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
height: 48,
px: 2,
borderRadius: 1,
backgroundColor: "rgba(86, 156, 221, 0.1)",
}}
>
<Typography color="primary.main">وزن بارها:</Typography>
<Typography color="primary.main" fontWeight="bold">
{boxStats?.killingYesterday?.KillHouseRequestWeightYesterday?.toLocaleString() ||
0}
</Typography>
</Box>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
height: 48,
px: 2,
borderRadius: 1,
backgroundColor: "rgba(86, 156, 221, 0.1)",
}}
>
<Typography color="primary.main">
لاشه تولیدی با احتساب 25درصد افت کشتار :
</Typography>
<Typography color="primary.main" fontWeight="bold">
{boxStats?.killingYesterday?.totalLossWeightYesterday?.toLocaleString() ||
0}
</Typography>
</Box>
</Box>
</Box>
);

View File

@@ -154,6 +154,7 @@ export const Dashboard = () => {
return (
<Grid
container
direction="column"
alignItems="center"
justifyContent="flex-start"
gap={SPACING.SMALL}
@@ -236,13 +237,7 @@ export const Dashboard = () => {
<Typography variant="body1" textAlign="left">
{notification.title}
</Typography>
<Typography
variant="caption"
textAlign="left"
sx={{
textAlign: "left",
}}
>
<Typography variant="caption" textAlign="left">
{notification.message}
</Typography>
</Box>
@@ -450,16 +445,14 @@ export const Dashboard = () => {
}}
>
<Typography
variant="subtitle1"
sx={{
width: "100%",
textAlign: "start",
fontWeight: "600",
fontWeight: "400",
mb: 2,
px: 1,
fontSize: "1rem",
}}
color="text.primary"
color="primary.main"
>
آمار جوجه ریزی استان
</Typography>
@@ -496,7 +489,7 @@ export const Dashboard = () => {
))}
</Grid>
</Grid>
<Grid item xs={12} my={SPACING.MEDIUM}>
<ResponsiveTable
isDashboard
noPagination
@@ -546,45 +539,44 @@ export const Dashboard = () => {
]}
title="مانده در سالن (قطعه)"
/>
</Grid>
<Grid container item xs={12} spacing={2} sx={{ alignItems: "stretch" }}>
<Grid item xs={12} xl={4} sx={{ display: "flex" }}>
<DailykillingReport boxStats={boxStats} />
</Grid>
<Grid item xs={12} xl={4}>
<Box
sx={{
display: "flex",
flexDirection: "column",
gap: 2,
height: "100%",
}}
>
<WarehouseInfoSection boxStats={boxStats} sx={{ flex: 1 }} />
<InventorySection boxStats={boxStats} sx={{ flex: 1 }} />
</Box>
</Grid>
<Grid item xs={12} xl={4} sx={{ display: "flex" }}>
<YesterdayKillingReport boxStats={boxStats} />
</Grid>
</Grid>
<Grid
container
item
xs={12}
spacing={2}
sx={{ mt: 2, alignItems: "stretch" }}
sx={{
width: "100%",
display: "flex",
flexWrap: "wrap",
gap: SPACING.SMALL,
justifyContent: "center",
alignItems: "stretch",
mt: 2,
}}
>
<DailykillingReport boxStats={boxStats} />
<WarehouseInfoSection boxStats={boxStats} />
<InventorySection boxStats={boxStats} />
</Grid>
<Grid
container
spacing={4}
sx={{
width: "100%",
display: "flex",
flexWrap: "wrap",
gap: "20px",
justifyContent: "center",
alignItems: "stretch",
mt: 2,
}}
>
<Grid item xs={12} lg={4} sx={{ display: "flex" }}>
<BarChartSection boxStats={boxStats} />
</Grid>
<Grid item xs={12} lg={4} sx={{ display: "flex" }}>
<PieChartSection boxStats={boxStats} />
<YesterdayKillingReport boxStats={boxStats} />
</Grid>
<Grid item xs={12} lg={4} sx={{ display: "flex" }}>
<PriceChartSection boxStats={boxStats} />
</Grid>
</Grid>
</Grid>
);
};

View File

@@ -12,7 +12,7 @@ import {
import { checkRequestBySlaughter } from "../../services/checkRequestBySlaughter";
import { useFormik } from "formik";
import { Yup } from "../../../../lib/yup/yup";
import { useDispatch, useSelector } from "react-redux";
import { useDispatch } from "react-redux";
import { PropTypes } from "prop-types";
import { getAllocationInformation } from "../../services/get-allocation-information";
import { Grid } from "../../../../components/grid/Grid";
@@ -22,16 +22,13 @@ import { useContext } from "react";
import { AppContext } from "../../../../contexts/AppContext";
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
import { slaughterGetActiveRequests } from "../../../slaughter-house/services/slaughter-get-active-requests";
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
export default function CheckRequestItem({ reqKey, poultryRequestKey }) {
const [openNotif] = useContext(AppContext);
const [isDenyed, setisDenyed] = useState(false);
const dispatch = useDispatch();
const { id } = useParams();
const selectedSubUser = useSelector(
(state) => state.userSlice.selectedSubUser
);
const [, , selectedDate1, , selectedDate2] = useContext(AppContext);
const formik = useFormik({
@@ -134,30 +131,17 @@ export default function CheckRequestItem({ reqKey, poultryRequestKey }) {
})
);
// getFileFromApi(roles, id, dispatch);
dispatch(
getAcceptedSlaughterRequest({
id,
role_key: checkPathStartsWith("slaughter")
? selectedSubUser?.key || ""
: "",
})
);
dispatch(getAcceptedSlaughterRequest({ id }));
setisDenyed(false);
dispatch(
getAllocationInformation({
key: poultryRequestKey,
role_key: checkPathStartsWith("slaughter")
? selectedSubUser?.key || ""
: "",
})
);
dispatch(
slaughterGetActiveRequests({
selectedDate1,
selectedDate2,
role_key: checkPathStartsWith("slaughter")
? selectedSubUser?.key || ""
: "",
})
);
openNotif({
@@ -215,29 +199,14 @@ export default function CheckRequestItem({ reqKey, poultryRequestKey }) {
content: null,
})
);
dispatch(getAcceptedSlaughterRequest({ id }));
dispatch(
getAcceptedSlaughterRequest({
id,
role_key: checkPathStartsWith("slaughter")
? selectedSubUser?.key || ""
: "",
})
);
dispatch(
getAllocationInformation({
key: poultryRequestKey,
role_key: checkPathStartsWith("slaughter")
? selectedSubUser?.key || ""
: "",
})
getAllocationInformation({ key: poultryRequestKey })
);
dispatch(
slaughterGetActiveRequests({
selectedDate1,
selectedDate2,
role_key: checkPathStartsWith("slaughter")
? selectedSubUser?.key || ""
: "",
})
);
openNotif({

View File

@@ -26,7 +26,6 @@ import { NumberInput } from "../../../../components/number-format-custom/NumberF
import { resizeImage } from "../../../../utils/resizeImage";
import { slaughterGetExlusiveKillers } from "../../services/slaughterGetExlusiveKillers";
import { isValidIndexWeight } from "../../../../utils/isValidIndexWeight";
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
export const SlaughterEnterBarItem = ({
data,
@@ -42,9 +41,7 @@ export const SlaughterEnterBarItem = ({
const [weightWithBarImages, setWeightWithBarImages] = React.useState([]);
const [weightWithBarImg, setWeightWithBarImg] = React.useState(null);
const { weightRange } = useSelector((state) => state.provinceSlice);
const selectedSubUser = useSelector(
(state) => state.userSlice.selectedSubUser
);
const weightWithBarImgHandler = (imageList) => {
setWeightWithBarImages(imageList);
formik.setFieldValue("weightWithBarImg", "");
@@ -147,18 +144,11 @@ export const SlaughterEnterBarItem = ({
const [exclusiveKillers, setExclusiveKillers] = useState();
const [selectedOption, setSelectedOption] = useState();
useEffect(() => {
dispatch(
slaughterGetExlusiveKillers({
role_key: checkPathStartsWith("slaughter")
? selectedSubUser?.key || ""
: "",
})
).then((r) => {
dispatch(slaughterGetExlusiveKillers()).then((r) => {
setExclusiveKillers(r.payload.data);
});
}, [selectedSubUser?.key]);
}, []);
const handleOptionChange = (event) => {
setSelectedOption(event?.target.value);

View File

@@ -13,14 +13,10 @@ import TimelineItem from "@mui/lab/TimelineItem";
import { SlaughterEnterBarItem } from "../slaughter-enter-bar-item/SlaughterEnterBarItem";
import { format } from "date-fns-jalali";
import { provincePolicyGetWeightRange } from "../../../province/services/province-policy-get-weight-range";
import { useDispatch, useSelector } from "react-redux";
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
import { useDispatch } from "react-redux";
export const SlaughterEnterBarWeight = ({ item, updateTable }) => {
const dispatch = useDispatch();
const selectedSubUser = useSelector(
(state) => state.userSlice.selectedSubUser
);
const sum = item?.acceptedRealWeight / item?.acceptedRealQuantity;
const data = [
[
@@ -41,15 +37,8 @@ export const SlaughterEnterBarWeight = ({ item, updateTable }) => {
];
useEffect(() => {
dispatch(
provincePolicyGetWeightRange({
role_key: checkPathStartsWith("slaughter")
? selectedSubUser?.key || ""
: "",
})
);
}, [selectedSubUser?.key]);
dispatch(provincePolicyGetWeightRange());
}, []);
return (
<TimelineItem sx={{ alignSelf: "flex-start", width: "100%" }}>
<TimelineSeparator>

View File

@@ -4,12 +4,11 @@ import { getRoleFromUrl } from "../../../utils/getRoleFromUrl";
export const getAcceptedSlaughterRequest = createAsyncThunk(
"GET_ACCEPTED_SLAUGHTER_REQUEST",
async ({ id, role_key }) => {
async ({ id }) => {
const { data, status } = await axios.get("province_kill_request", {
params: {
id,
role: getRoleFromUrl(),
role_key: role_key || "",
},
});
return { data, status };

View File

@@ -7,10 +7,7 @@ export const slaughterGetExlusiveKillers = createAsyncThunk(
async (d, { dispatch }) => {
dispatch(LOADING_START());
const { data, status } = await axios.get(
"kill_house/?exclusive-killers=true",
{
params: d,
}
"kill_house/?exclusive-killers=true"
);
dispatch(LOADING_END());
return { data, status };

View File

@@ -42,7 +42,7 @@ export const GuildReceiveBarOperation = ({ item }) => {
authCode: Yup.string().required("کداحراز اجباری است"),
});
const onSubmit = () => {
const onSubmit = (values) => {
// Handle form submission here
// console.log("Form submitted with values:", values);
};
@@ -65,6 +65,9 @@ export const GuildReceiveBarOperation = ({ item }) => {
weight: "",
},
validationSchema: Yup.object({
number: Yup.number()
.required("این فیلد اجباری است!")
.typeError("لطفا عدد وارد کنید!"),
weight: Yup.number()
.required("این فیلد اجباری است!")
.typeError("لطفا وزن را وارد کنید!"),
@@ -114,7 +117,6 @@ export const GuildReceiveBarOperation = ({ item }) => {
size="small"
label="وزن"
variant="outlined"
fullWidth
disabled={!isChecked}
onChange={formikRealInfo.handleChange}
onBlur={formikRealInfo.handleBlur}
@@ -130,6 +132,27 @@ export const GuildReceiveBarOperation = ({ item }) => {
}
/>
</Grid>
<Grid item xs={6}>
<TextField
id="number"
size="small"
label="تعداد"
variant="outlined"
disabled={!isChecked}
onChange={formikRealInfo.handleChange}
onBlur={formikRealInfo.handleBlur}
value={formikRealInfo.values.number}
error={
formikRealInfo.touched.number &&
Boolean(formikRealInfo.errors.number)
}
helperText={
formikRealInfo.touched.number
? formikRealInfo.errors.number
: ""
}
/>
</Grid>
</Grid>
</Grid>
<FormControl component="fieldset">
@@ -181,7 +204,9 @@ export const GuildReceiveBarOperation = ({ item }) => {
if (getRoleFromUrl() === "senf") {
reqObj = {
guild_check_allocation: true,
receiver_real_number_of_carcasses: 0,
receiver_real_number_of_carcasses: formikRealInfo.values.number
? formikRealInfo.values.number
: item.numberOfCarcasses,
receiver_real_weight_of_carcasses: formikRealInfo.values.weight
? formikRealInfo.values.weight
: item.weightOfCarcasses,
@@ -193,7 +218,9 @@ export const GuildReceiveBarOperation = ({ item }) => {
reqObj = {
steward_check_allocation: true,
allocation_key: item.key,
receiver_real_number_of_carcasses: 0,
receiver_real_number_of_carcasses: formikRealInfo.values.number
? formikRealInfo.values.number
: item.numberOfCarcasses,
receiver_real_weight_of_carcasses: formikRealInfo.values.weight
? formikRealInfo.values.weight
: item.weightOfCarcasses,
@@ -206,7 +233,9 @@ export const GuildReceiveBarOperation = ({ item }) => {
reqObj = {
guild_check_allocation: true,
allocation_key: item.key,
receiver_real_number_of_carcasses: 0,
receiver_real_number_of_carcasses: formikRealInfo.values.number
? formikRealInfo.values.number
: item.numberOfCarcasses,
receiver_real_weight_of_carcasses: formikRealInfo.values.weight
? formikRealInfo.values.weight
: item.weightOfCarcasses,
@@ -216,7 +245,9 @@ export const GuildReceiveBarOperation = ({ item }) => {
reqObj = {
steward_check_allocation: true,
allocation_key: item.key,
receiver_real_number_of_carcasses: 0,
receiver_real_number_of_carcasses: formikRealInfo.values.number
? formikRealInfo.values.number
: item.numberOfCarcasses,
receiver_real_weight_of_carcasses: formikRealInfo.values.weight
? formikRealInfo.values.weight
: item.weightOfCarcasses,

View File

@@ -4,7 +4,7 @@ import { Button, InputAdornment, TextField } from "@mui/material";
import { Yup } from "../../../lib/yup/yup";
import { useContext, useEffect } from "react";
import { SPACING } from "../../../data/spacing";
import { useDispatch, useSelector } from "react-redux";
import { useDispatch } from "react-redux";
import { guildUpdateAllocatedStockService } from "../services/guild-update-allocated-stock";
import { AppContext } from "../../../contexts/AppContext";
import { guildGetInventoryStockService } from "../services/guild-get-inventory-stock";
@@ -13,7 +13,6 @@ import { CLOSE_MODAL } from "../../../lib/redux/slices/appSlice";
import { getRoleFromUrl } from "../../../utils/getRoleFromUrl";
import { senfGetInventoryStockService } from "../services/senf-get-inventory-stock";
import { senfGetInventoryAllocatedService } from "../services/senf-get-inventory-allocated";
import { checkPathStartsWith } from "../../../utils/checkPathStartsWith";
const schema = Yup.object().shape({
quantity: Yup.number().required("وارد کردن تعداد اجباری است"),
@@ -24,9 +23,6 @@ export const RegisterEditDeliveryNumberAndWeight = ({ item }) => {
const [openNotif] = useContext(AppContext);
const [, , selectedDate1] = useContext(AppContext);
const dispatch = useDispatch();
const selectedSubUser = useSelector(
(state) => state.userSlice.selectedSubUser
);
const formik = useFormik({
initialValues: {
quantity: item?.receiverRealNumberOfCarcasses,
@@ -65,17 +61,11 @@ export const RegisterEditDeliveryNumberAndWeight = ({ item }) => {
dispatch(
guildGetInventoryStockService({
date: selectedDate1,
role_key: checkPathStartsWith("senf")
? selectedSubUser?.key
: "",
})
);
dispatch(
guildGetInventoryAllocatedService({
date: selectedDate1,
role_key: checkPathStartsWith("senf")
? selectedSubUser?.key
: "",
})
);
}

View File

@@ -11,7 +11,7 @@ import {
TextField,
Typography,
} from "@mui/material";
import { useDispatch, useSelector } from "react-redux";
import { useDispatch } from "react-redux";
import { useFormik } from "formik";
import { DatePicker } from "@mui/x-date-pickers";
import moment from "moment";
@@ -36,7 +36,6 @@ import PersianDate from "persian-date";
import axios from "axios";
import { LabelField } from "../../../components/label-field/LabelField";
import { SPACING } from "../../../data/spacing";
import { checkPathStartsWith } from "../../../utils/checkPathStartsWith";
export const StewardAllocationToGuild = ({
item,
@@ -80,9 +79,6 @@ export const StewardAllocationToGuild = ({
const [selectedDate1, setSelectedDate1] = useState(
moment(new Date()).format("YYYY-MM-DD")
);
const selectedSubUser = useSelector(
(state) => state.userSlice.selectedSubUser
);
const handleChange = (event) => {
setValue(event.target.value);
@@ -164,10 +160,13 @@ export const StewardAllocationToGuild = ({
return transformedData;
}, []);
const updateCalendarData = useCallback((dataArray) => {
const updateCalendarData = useCallback(
(dataArray) => {
const transformed = transformCalendarData(dataArray);
setCalendarDayData(transformed);
}, []);
},
[transformCalendarData]
);
const fetchCalendarData = useCallback(
async (dateParam = selectedDate1) => {
@@ -175,9 +174,6 @@ export const StewardAllocationToGuild = ({
const response = await axios.get("/steward-remain-weight/", {
params: {
date: dateParam,
role_key: checkPathStartsWith("steward")
? selectedSubUser?.key
: "",
},
});
if (response.data) {
@@ -195,7 +191,7 @@ export const StewardAllocationToGuild = ({
console.error("Error fetching calendar data:", error);
}
},
[selectedInventory, updateCalendarData, selectedDate1, selectedSubUser]
[selectedInventory, updateCalendarData, selectedDate1]
);
const [buyerData, setBuyerData] = useState({
@@ -213,7 +209,7 @@ export const StewardAllocationToGuild = ({
useEffect(() => {
fetchCalendarData(selectedDate1);
}, [selectedDate1]);
}, [fetchCalendarData, selectedDate1]);
useEffect(() => {
if (
@@ -229,41 +225,30 @@ export const StewardAllocationToGuild = ({
setProductionDate(null);
setSelectedDateAmount(null);
}
}, [selectedInventory, calendarRawData]);
}, [selectedInventory, calendarRawData, updateCalendarData]);
useEffect(() => {
dispatch(
provincePolicyGetUploadImageService({
role_key: checkPathStartsWith("steward") ? selectedSubUser?.key : "",
})
).then((r) => {
dispatch(provincePolicyGetUploadImageService()).then((r) => {
if (r.payload?.data) {
setImageUploadLimit(r.payload.data.killHouseAllocation);
}
});
if (!editData) {
dispatch(
slaughterGetProductsService({
role_key: checkPathStartsWith("steward") ? selectedSubUser?.key : "",
})
).then((r) => {
dispatch(slaughterGetProductsService()).then((r) => {
setProductData(r.payload.data);
});
if (!item) {
dispatch(
slaughterGetGuildsForAllocateService({
free: value === "free" ? true : false,
role_key: checkPathStartsWith("steward")
? selectedSubUser?.key
: "",
})
).then((r) => {
setGuildsData(r.payload.data);
});
}
}
}, [value, selectedSubUser?.key]);
}, [dispatch, value]);
const validationSchema = Yup.object({
mobile: Yup.string().when([], {
@@ -350,11 +335,14 @@ export const StewardAllocationToGuild = ({
}, [formik.values.price, formik.values.weight]);
const successSubmit = () => {
dispatch(
fetchSlaughterBroadcastAndProducts({
role_key: checkPathStartsWith("steward") ? selectedSubUser?.key : "",
})
);
dispatch(CLOSE_MODAL());
openNotif({
vertical: "top",
horizontal: "center",
msg: "عملیات با موفقیت انجام شد.",
severity: "success",
});
dispatch(fetchSlaughterBroadcastAndProducts());
dispatch(
DRAWER({
right: false,
@@ -366,13 +354,6 @@ export const StewardAllocationToGuild = ({
fetchApiData && fetchApiData(1);
updateTable && updateTable();
fetchData && fetchData(1);
dispatch(CLOSE_MODAL());
openNotif({
vertical: "top",
horizontal: "center",
msg: "عملیات با موفقیت انجام شد.",
severity: "success",
});
};
const [dateRangeError, setDateRangeError] = useState(null);
@@ -472,9 +453,13 @@ export const StewardAllocationToGuild = ({
<FormControlLabel
value="own"
control={<Radio />}
label="اختصاصی"
label="صنوف اختصاصی"
/>
<FormControlLabel
value="free"
control={<Radio />}
label="صنوف آزاد"
/>
<FormControlLabel value="free" control={<Radio />} label="آزاد" />
</RadioGroup>
</FormControl>
</LabelField>
@@ -492,7 +477,9 @@ export const StewardAllocationToGuild = ({
? guildsData.map((i) => {
return {
data: i,
label: `${i?.guildsName} ${i?.user?.fullname} (${i?.user?.mobile})`,
label: `${i?.steward ? "مباشر" : "صنف"} ${
i?.guildsName
} ${i?.user?.fullname} (${i?.user?.mobile})`,
};
})
: []
@@ -501,8 +488,10 @@ export const StewardAllocationToGuild = ({
setBuyerData({
item: value?.data,
key: value?.data?.key,
allocationType: "steward_guild",
buyerType: "Guild",
allocationType: value?.data?.steward
? "steward_steward"
: "steward_guild",
buyerType: value?.data?.steward ? "Steward" : "Guild",
});
formik.setFieldValue("mobile", value?.data?.user?.mobile);
formik.setFieldTouched("mobile", true, false);
@@ -513,7 +502,7 @@ export const StewardAllocationToGuild = ({
}
}}
renderInput={(params) => (
<TextField fullWidth {...params} label="انتخاب صنف" />
<TextField fullWidth {...params} label="انتخاب مباشر / صنف" />
)}
/>
</Grid>
@@ -538,7 +527,7 @@ export const StewardAllocationToGuild = ({
checked={changeMobile}
onChange={() => setChangeMobile(!changeMobile)}
/>
از این قسمت میتوانید تلفن صنف را ویرایش کنید.
از این قسمت میتوانید تلفن مباشر/صنف را ویرایش کنید.
</Typography>
{buyerData?.key && changeMobile && (
@@ -786,21 +775,31 @@ export const StewardAllocationToGuild = ({
weight_of_carcasses: formik.values.weight,
amount: formik.values.price,
total_amount: formik.values.wholePrice,
role_key: checkPathStartsWith("steward")
? selectedSubUser?.key || ""
: "",
distribution_type: "web",
...(imageChanged && { image: formik.values.image }),
};
} else if (!editData) {
req = {
seller_type: sellerType,
buyer_type: "Guild",
guild_key: buyerData?.item?.key,
buyer_type: buyerData?.buyerType,
guild_key:
buyerData?.buyerType === "Guild"
? buyerData?.item?.key
: null,
steward_key:
buyerData?.buyerType === "Steward"
? buyerData?.item?.key
: null,
kill_house_key:
buyerData?.buyerType === "KillHouse"
? buyerData?.item?.key
: null,
cold_house_key: coldHouseKey || null,
product_key: coldHouseKey ? null : productKey.key,
type: "manual",
allocation_type: coldHouseKey ? "ColdHouse" : "steward_guild",
allocation_type: coldHouseKey
? "ColdHouse"
: buyerData?.allocationType,
number_of_carcasses: 0,
weight_of_carcasses: formik.values.weight,
sell_type: sellType,
@@ -811,9 +810,6 @@ export const StewardAllocationToGuild = ({
quota: selectedInventory,
date: selectedDate1,
production_date: productionDate,
role_key: checkPathStartsWith("steward")
? selectedSubUser?.key || ""
: "",
distribution_type: "web",
...(buyerData?.item?.user?.mobile !== formik.values.mobile
? { interface_number: formik.values.mobile }
@@ -831,9 +827,6 @@ export const StewardAllocationToGuild = ({
number_of_carcasses: 0,
weight_of_carcasses: formik.values.weight,
amount: formik.values.price,
role_key: checkPathStartsWith("steward")
? selectedSubUser?.key || ""
: "",
total_amount: formik.values.wholePrice,
distribution_type: "web",
...(imageChanged && { image: formik.values.image }),

View File

@@ -1,5 +1,5 @@
import React, { useContext, useEffect, useRef, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { useDispatch } from "react-redux";
import InfoIcon from "@mui/icons-material/Info";
import TextField from "@mui/material/TextField";
import InputAdornment from "@mui/material/InputAdornment";
@@ -35,7 +35,6 @@ import { Grid } from "../../../components/grid/Grid";
import { NumberInput } from "../../../components/number-format-custom/NumberFormatCustom";
import ResponsiveTable from "../../../components/responsive-table/ResponsiveTable";
import { AppContext } from "../../../contexts/AppContext";
import { checkPathStartsWith } from "../../../utils/checkPathStartsWith";
export const StewardDailyList = () => {
const [productsTable, setProductsTable] = useState();
@@ -49,9 +48,7 @@ export const StewardDailyList = () => {
const [filteredData, setFilteredData] = useState([]);
const [openNotif] = useContext(AppContext);
const selectedSubUser = useSelector(
(state) => state.userSlice.selectedSubUser
);
const priceRefs = useRef([]);
const weightRefs = useRef([]);
@@ -138,25 +135,16 @@ export const StewardDailyList = () => {
}
};
const fetchPriceStatus = async () => {
dispatch(
slaughterGetPriceService({
role: getRoleFromUrl(),
role_key: checkPathStartsWith("steward") ? selectedSubUser?.key : "",
})
).then((r) => {
dispatch(slaughterGetPriceService({ role: getRoleFromUrl() })).then((r) => {
setPriceState(r.payload.data);
});
};
const fetchApiData = async () => {
const fetchApiData = async (page) => {
dispatch(LOADING_START());
try {
const response = await axios.get(
`commonly-used/?search=filter&value=&role=${getRoleFromUrl()}${
checkPathStartsWith("steward")
? `&role_key=${selectedSubUser?.key}`
: ""
}&page=1&page_size=10000`
`commonly-used/?search=filter&value=&role=${getRoleFromUrl()}&page=1&page_size=10000`
);
setrendered(true);
setData(response.data.results || []);
@@ -222,10 +210,10 @@ export const StewardDailyList = () => {
dispatch(slaughterGetProductsService()).then((r) => {
setSlaughterProducts(r.payload.data);
});
}, [selectedSubUser?.key]);
}, []);
useEffect(() => {
const d = slaughterProducts?.map((item) => {
const d = slaughterProducts?.map((item, i) => {
return [item?.name, item?.totalRemainWeight?.toLocaleString()];
});

View File

@@ -1,6 +1,6 @@
import { useContext, useEffect, useState } from "react";
import { AppContext } from "../../../contexts/AppContext";
import { useDispatch, useSelector } from "react-redux";
import { useDispatch } from "react-redux";
import ResponsiveTable from "../../../components/responsive-table/ResponsiveTable";
import { Grid } from "../../../components/grid/Grid";
import moment from "moment";
@@ -20,7 +20,6 @@ import { stewardGetOutSellService } from "../services/steward-get-sell-out-servi
import { formatJustDate, formatTime } from "../../../utils/formatTime";
import { StewardSegmentOperation } from "./StewardSegmentOperation";
import { stawardGetSegmentDashboardService } from "../services/steward-get-dashboard-service";
import { checkPathStartsWith } from "../../../utils/checkPathStartsWith";
export const StewardSegmant = () => {
const [data, setData] = useState([]);
@@ -34,9 +33,6 @@ export const StewardSegmant = () => {
const [, , selectedDate1, setSelectedDate1, selectedDate2, setSelectedDate2] =
useContext(AppContext);
const dispatch = useDispatch();
const selectedSubUser = useSelector(
(state) => state.userSlice.selectedSubUser
);
// const userKey = useSelector((state) => state.userSlice.userProfile.key);
@@ -46,7 +42,6 @@ export const StewardSegmant = () => {
value: textValue,
date1: selectedDate1,
date2: selectedDate2,
role_key: checkPathStartsWith("steward") ? selectedSubUser?.key : "",
})
).then((r) => {
setDashboardData(r.payload.data);
@@ -62,11 +57,7 @@ export const StewardSegmant = () => {
const fetchApiData = async (page) => {
dispatch(LOADING_START());
const response = await axios.get(
`app-segmentation/?search=filter&value=${textValue}&date1=${selectedDate1}&date2=${selectedDate2}&page=${page}&page_size=${perPage}&role=${getRoleFromUrl()}${
checkPathStartsWith("steward")
? `&role_key=${selectedSubUser?.key}`
: ""
}`
`app-segmentation/?search=filter&value=${textValue}&date1=${selectedDate1}&date2=${selectedDate2}&page=${page}&page_size=${perPage}&role=${getRoleFromUrl()}`
);
getDashboardData();
@@ -98,14 +89,10 @@ export const StewardSegmant = () => {
useEffect(() => {
fetchApiData(1);
dispatch(
stewardGetOutSellService({
role_key: checkPathStartsWith("steward") ? selectedSubUser?.key : "",
})
).then((r) => {
dispatch(stewardGetOutSellService()).then((r) => {
setProducts(r.payload.data);
});
}, [selectedSubUser?.key]);
}, []);
useEffect(() => {
const d = data?.map((item, i) => {
@@ -157,11 +144,7 @@ export const StewardSegmant = () => {
dispatch(LOADING_START());
try {
const response = await axios.get(
`app-segmentation/?search=filter&value=${textValue}&date1=${selectedDate1}&date2=${selectedDate2}&page=${page}&role=${getRoleFromUrl()}${
checkPathStartsWith("steward")
? `&role_key=${selectedSubUser?.key}`
: ""
}`
`app-segmentation/?search=filter&value=${textValue}&date1=${selectedDate1}&date2=${selectedDate2}&page=${page}&role=${getRoleFromUrl()}`
);
setData(response.data.results);
setTotalRows(response.data.count);
@@ -181,7 +164,7 @@ export const StewardSegmant = () => {
gap={SPACING.SMALL}
justifyContent="flex-start"
>
<Grid container mt={2} mb={4} isDashboard xs={12}>
<Grid container mt={2} mb={4} isDashboard>
<ResponsiveTable
noPagination
isDashboard

View File

@@ -12,23 +12,18 @@ import { SPACING } from "../../../data/spacing";
import { Grid } from "../../../components/grid/Grid";
import { DRAWER } from "../../../lib/redux/slices/appSlice";
import { stewardSegmentSubmitService } from "../services/steward-segment-submit-service";
import { useDispatch, useSelector } from "react-redux";
import { useDispatch } from "react-redux";
import { useContext, useEffect, useState, useCallback } from "react";
import { AppContext } from "../../../contexts/AppContext";
import { useFormik } from "formik";
import { Yup } from "../../../lib/yup/yup";
import { stawardGetSegmantRoleService } from "../services/steward-get-segmant-role";
import { getRoleFromUrl } from "../../../utils/getRoleFromUrl";
import { stewardEditSegmentService } from "../services/steward-segment-edit-operation";
import MonthlyDataCalendar from "../../../components/date-picker/MonthlyDataCalendar";
import PersianDate from "persian-date";
import axios from "axios";
import { LabelField } from "../../../components/label-field/LabelField";
import { checkPathStartsWith } from "../../../utils/checkPathStartsWith";
import {
slaughterGetGuildsForAllocateService,
slaughterGetStewardsForAllocateService,
} from "../../slaughter-house/services/slaughter-get-guilds-for-allocate";
import { Typography } from "@mui/material";
const getValidationSchema = (selectedDateAmount) =>
Yup.object().shape({
@@ -59,22 +54,13 @@ export const StewardSegmentSubmitOperation = ({
}) => {
const dispatch = useDispatch();
const [openNotif] = useContext(AppContext);
const [stewardData, setStewardData] = useState([]);
const [segmentType, setSegmentType] = useState("own");
const [selectedInventory] = useState("free");
const [approvedStatus, setApprovedStatus] = useState("governmental");
const [buyerCategory, setBuyerCategory] = useState(""); // "stewards" or "guilds"
const [guildsData, setGuildsData] = useState([]);
const [stewardsData, setStewardsData] = useState([]);
const [buyerData, setBuyerData] = useState({
key: "",
item: "",
buyerType: "",
allocationType: "",
});
const selectedSubUser = useSelector(
(state) => state.userSlice.selectedSubUser
);
const [selectedBuyer, setSelectedBuyer] = useState(null);
// Calendar states
const [selectedCalendarDate, setSelectedCalendarDate] = useState(null);
const [calendarDayData, setCalendarDayData] = useState({});
const [productionDate, setProductionDate] = useState(null);
@@ -130,7 +116,7 @@ export const StewardSegmentSubmitOperation = ({
distribution_type: "web",
};
} else {
if (!buyerData?.key) {
if (!selectedBuyer) {
openNotif({
vertical: "top",
horizontal: "center",
@@ -141,9 +127,7 @@ export const StewardSegmentSubmitOperation = ({
}
req = {
guild_key: buyerData?.buyerType === "Guild" ? buyerData?.key : null,
steward_key:
buyerData?.buyerType === "Steward" ? buyerData?.key : null,
guild_key: selectedBuyer.key,
weight: values.weight,
product_key: productKey || "",
sale_type: selectedInventory,
@@ -151,9 +135,6 @@ export const StewardSegmentSubmitOperation = ({
production_date: productionDate,
distribution_type: "web",
};
req = Object.fromEntries(
Object.entries(req).filter(([, val]) => val !== null)
);
}
dispatch(stewardSegmentSubmitService(req)).then((r) => {
@@ -195,19 +176,6 @@ export const StewardSegmentSubmitOperation = ({
setApprovedStatus(newType);
};
const handleBuyerCategoryChange = (event) => {
const newCategory = event.target.value;
setBuyerCategory(newCategory);
setBuyerData({
key: "",
item: "",
buyerType: "",
allocationType: "",
});
setGuildsData([]);
setStewardsData([]);
};
// Calendar functions
const handleDateSelect = (dateInfo) => {
if (dateInfo && dateInfo.formattedDate) {
@@ -216,6 +184,7 @@ export const StewardSegmentSubmitOperation = ({
// Get the data for the selected date
const data = calendarDayData[dateInfo.formattedDate];
// Use the original Gregorian date from the API data for production_date
if (data && data.originalDay) {
setProductionDate(data.originalDay);
}
@@ -229,24 +198,30 @@ export const StewardSegmentSubmitOperation = ({
}
};
// Transform calendar data from array format to object format
// Input: [{day: "2025-10-10", amount: 100}]
// Output: {"1404/07/19": {value1: 100, originalDay: "2025-10-10"}}
const transformCalendarData = useCallback((dataArray) => {
if (!Array.isArray(dataArray)) return {};
const transformedData = {};
dataArray.forEach((item) => {
if (item.day && item.amount !== undefined) {
// Convert Gregorian date to Persian date
const persianDate = new PersianDate(new Date(item.day));
const persianDateStr = persianDate.format("YYYY/MM/DD");
// Calendar expects 'value1' property, also store the original day
transformedData[persianDateStr] = {
value1: item.amount,
originalDay: item.day,
active: item.active === true,
originalDay: item.day, // Store the original Gregorian date
active: item.active === true, // Store active status
};
}
});
return transformedData;
}, []);
// Function to update calendar data from API response
const updateCalendarData = useCallback(
(dataArray) => {
const transformed = transformCalendarData(dataArray);
@@ -258,30 +233,17 @@ export const StewardSegmentSubmitOperation = ({
// Fetch calendar data from API
const fetchCalendarData = useCallback(async () => {
try {
const currentRole = getRoleFromUrl();
console.log(getRoleFromUrl());
let remainWeightEndpoint = "kill-house-remain-weight";
if (currentRole === "Steward") {
remainWeightEndpoint = "steward-remain-weight";
} else if (currentRole === "Guilds") {
remainWeightEndpoint = "guild-remain-weight";
}
const response = await axios.get(`${remainWeightEndpoint}/`, {
params: {
role_key:
checkPathStartsWith("slaughter") ||
checkPathStartsWith("steward") ||
checkPathStartsWith("senf")
? selectedSubUser?.key || ""
: "",
},
});
const response = await axios.get(
`/${
getRoleFromUrl() === "Steward" ? "steward" : "kill-house"
}-remain-weight/`
);
if (response.data) {
setCalendarRawData({
governmental: response.data.governmental || [],
free: response.data.free || [],
});
// Update calendar based on current inventory type
const dataToShow =
approvedStatus === "governmental"
? response.data.governmental
@@ -291,42 +253,21 @@ export const StewardSegmentSubmitOperation = ({
} catch (error) {
console.error("Error fetching calendar data:", error);
}
}, [approvedStatus, updateCalendarData, selectedSubUser]);
}, [approvedStatus, updateCalendarData]);
useEffect(() => {
if (!editData) {
dispatch(stawardGetSegmantRoleService({ role: getRoleFromUrl() })).then(
(r) => {
setStewardData(r.payload.data);
}
);
}
// Fetch calendar data on mount
fetchCalendarData();
}, []);
useEffect(() => {
if (!editData && buyerCategory) {
if (buyerCategory === "guilds") {
dispatch(
slaughterGetGuildsForAllocateService({
free: true,
role_key:
checkPathStartsWith("slaughter") || checkPathStartsWith("steward")
? selectedSubUser?.key || ""
: "",
})
).then((r) => {
setGuildsData(r.payload.data || []);
});
} else if (buyerCategory === "stewards") {
dispatch(
slaughterGetStewardsForAllocateService({
free: true,
role_key:
checkPathStartsWith("slaughter") || checkPathStartsWith("steward")
? selectedSubUser?.key || ""
: "",
})
).then((r) => {
setStewardsData(r.payload.data || []);
});
}
}
}, [buyerCategory, selectedSubUser?.key, editData]);
}, [dispatch, editData, fetchCalendarData]);
// Update calendar when inventory type changes
useEffect(() => {
if (
calendarRawData.governmental.length > 0 ||
@@ -337,25 +278,18 @@ export const StewardSegmentSubmitOperation = ({
? calendarRawData.governmental
: calendarRawData.free;
updateCalendarData(dataToShow);
// Reset selected date when inventory type changes
setSelectedCalendarDate(null);
setProductionDate(null);
setSelectedDateAmount(null);
}
}, [approvedStatus, calendarRawData, updateCalendarData]);
// Validate form when selectedDateAmount changes
useEffect(() => {
formik.validateForm();
}, [selectedDateAmount]);
// Set segmentType to "own" for Guilds role
useEffect(() => {
const currentRole = getRoleFromUrl();
if (currentRole === "Guilds" && !editData) {
setSegmentType("own");
formik.setFieldValue("segmentType", "own");
}
}, [editData]);
return (
<Grid container direction="column" justifyContent="center" gap={2}>
<Grid container direction="column" justifyContent="center" gap={2} pt={2}>
@@ -367,7 +301,7 @@ export const StewardSegmentSubmitOperation = ({
gap: SPACING.LARGE + 4,
}}
>
{!editData && getRoleFromUrl() !== "Guilds" && (
{!editData && (
<LabelField label="قطعه بندی (کاربر)">
<FormControl>
<RadioGroup
@@ -396,120 +330,45 @@ export const StewardSegmentSubmitOperation = ({
)}
{!editData && segmentType === "free" && (
<>
<LabelField label="خریداران">
<FormControl fullWidth>
<RadioGroup
row
aria-labelledby="buyer-category-radio-group"
name="buyerCategory"
value={buyerCategory}
onChange={handleBuyerCategoryChange}
sx={{
justifyContent: "space-between",
}}
>
<FormControlLabel
value="stewards"
control={<Radio />}
label="مباشرین"
/>
<FormControlLabel
value="guilds"
control={<Radio />}
label="اصناف"
/>
</RadioGroup>
</FormControl>
</LabelField>
{buyerCategory && (
<Grid xs={12} container>
{(() => {
const currentData =
buyerCategory === "guilds" ? guildsData : stewardsData;
const isEmpty = !currentData || currentData.length === 0;
if (isEmpty) {
return (
<Typography
variant="body2"
color="text.secondary"
sx={{
width: "100%",
textAlign: "center",
padding: 2,
fontStyle: "italic",
}}
>
{buyerCategory === "guilds"
? "هیچ صنفی یافت نشد"
: "هیچ مباشری یافت نشد"}
</Typography>
);
}
return (
<Autocomplete
fullWidth
style={{ minWidth: 210 }}
disablePortal
id="buyer-selection"
id="steward-select"
options={
buyerCategory === "guilds"
? guildsData.map((i) => {
stewardData
? stewardData.map((i) => {
return {
data: i,
label: `${i?.guildsName} ${i?.user?.fullname} (${i?.user?.mobile})`,
};
})
: stewardsData.map((i) => {
return {
data: i,
label: `${i?.name || ""} - ${
i?.user?.fullname || ""
} (${i?.user?.mobile || ""})`,
label: `${i?.steward ? "مباشر" : "صنف"} ${
i?.guildsName
} ${i?.user?.fullname} (${i?.user?.mobile})`,
};
})
: []
}
onChange={(event, value) => {
if (buyerCategory === "guilds") {
setBuyerData({
if (value) {
setSelectedBuyer({
item: value?.data,
key: value?.data?.key,
allocationType: value?.data?.steward
? "steward_steward"
: "steward_guild",
buyerType: value?.data?.steward
? "Steward"
: "Guild",
});
} else if (buyerCategory === "stewards") {
setBuyerData({
item: value?.data,
key: value?.data?.key,
allocationType: "steward_steward",
buyerType: "Steward",
});
} else {
setSelectedBuyer(null);
}
}}
renderInput={(params) => (
<TextField
fullWidth
{...params}
label={
buyerCategory === "guilds"
? "انتخاب صنف"
: "انتخاب مباشر"
}
label="انتخاب مباشر / صنف"
required={segmentType === "free"}
/>
)}
/>
);
})()}
</Grid>
)}
</>
)}
{/* {!editData && (
<LabelField label="نوع فروش">
@@ -625,8 +484,7 @@ export const StewardSegmentSubmitOperation = ({
!editData &&
(!productionDate ||
(selectedDateAmount &&
formik.values.weight > selectedDateAmount) ||
(segmentType === "free" && !buyerData?.key))
formik.values.weight > selectedDateAmount))
}
>
{editData ? "ویرایش" : "ثبت"}

View File

@@ -1,141 +0,0 @@
import { useContext, useState } from "react";
import { useDispatch } from "react-redux";
import {
Button,
FormControl,
Grid,
InputLabel,
MenuItem,
Select,
Typography,
} from "@mui/material";
import axios from "axios";
import { AppContext } from "../../../../contexts/AppContext";
import { CLOSE_MODAL } from "../../../../lib/redux/slices/appSlice";
import { SPACING } from "../../../../data/spacing";
import { getFaUserRole } from "../../../../utils/getFaUserRole";
export const AddAccessLevelModal = ({ device, onSuccess }) => {
const dispatch = useDispatch();
const [openNotif] = useContext(AppContext);
const [selectedAccessLevel, setSelectedAccessLevel] = useState("");
const [submitting, setSubmitting] = useState(false);
const accessLevelOptions = ["Steward", "KillHouse", "Guilds"];
const handleCloseModal = () => {
dispatch(CLOSE_MODAL());
};
const handleSubmit = async () => {
if (!selectedAccessLevel) {
openNotif({
vertical: "top",
horizontal: "center",
severity: "error",
msg: "لطفاً یک سطح دسترسی را انتخاب کنید.",
});
return;
}
if (!device?.key && !device?.id) {
openNotif({
vertical: "top",
horizontal: "center",
severity: "error",
msg: "شناسه دستگاه یافت نشد. لطفاً دوباره تلاش کنید.",
});
return;
}
setSubmitting(true);
try {
const payload = {
pos_key: device?.key || device?.id,
name: selectedAccessLevel,
};
await axios.post("/pos-access-level/", payload);
openNotif({
vertical: "top",
horizontal: "center",
severity: "success",
msg: "سطح دسترسی با موفقیت افزوده شد.",
});
if (onSuccess) {
onSuccess();
}
handleCloseModal();
} catch (error) {
openNotif({
vertical: "top",
horizontal: "center",
severity: "error",
msg:
error?.response?.data?.result ||
error?.response?.data?.detail ||
"افزودن سطح دسترسی با خطا مواجه شد.",
});
} finally {
setSubmitting(false);
}
};
return (
<Grid
container
direction="column"
gap={SPACING.SMALL}
width="100%"
alignItems="stretch"
sx={{ minWidth: 300 }}
>
<Typography variant="body2">
دستگاه انتخاب شده:{" "}
{device?.serial ||
device?.pos_unique_id ||
device?.pos_id ||
device?.posId ||
"-"}
</Typography>
<FormControl fullWidth size="small">
<InputLabel id="access-level-label">سطح دسترسی</InputLabel>
<Select
labelId="access-level-label"
id="access-level-select"
value={selectedAccessLevel}
label="سطح دسترسی"
onChange={(e) => setSelectedAccessLevel(e.target.value)}
>
<MenuItem value="">
<em>انتخاب سطح دسترسی</em>
</MenuItem>
{accessLevelOptions.map((option) => (
<MenuItem key={option} value={option}>
{getFaUserRole(option)}
</MenuItem>
))}
</Select>
</FormControl>
<Grid container justifyContent="flex-end" gap={SPACING.SMALL} mt={2}>
<Button
variant="outlined"
color="primary"
onClick={handleCloseModal}
disabled={submitting}
>
انصراف
</Button>
<Button
variant="contained"
onClick={handleSubmit}
disabled={!selectedAccessLevel || submitting}
>
{submitting ? "در حال ثبت..." : "ثبت"}
</Button>
</Grid>
</Grid>
);
};

View File

@@ -1,354 +0,0 @@
import { useContext, useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import {
Autocomplete,
Button,
CircularProgress,
FormControl,
FormControlLabel,
Grid,
MenuItem,
Radio,
RadioGroup,
Select,
TextField,
Typography,
} from "@mui/material";
import axios from "axios";
import { AppContext } from "../../../../contexts/AppContext";
import { CLOSE_MODAL } from "../../../../lib/redux/slices/appSlice";
import { LabelField } from "../../../../components/label-field/LabelField";
import { SPACING } from "../../../../data/spacing";
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
import { getFaUserRole } from "../../../../utils/getFaUserRole";
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
export const AssignSubUserModal = ({ device, onSuccess }) => {
const dispatch = useDispatch();
const [openNotif] = useContext(AppContext);
const [options, setOptions] = useState([]);
const [selectedUser, setSelectedUser] = useState(null);
const [selectedAccessLevel, setSelectedAccessLevel] = useState("");
const [loading, setLoading] = useState(false);
const [submitting, setSubmitting] = useState(false);
const [fetchError, setFetchError] = useState("");
const [userType, setUserType] = useState("delegate");
const selectedSubUser = useSelector(
(state) => state.userSlice.selectedSubUser
);
useEffect(() => {
let isMounted = true;
const fetchUsers = async () => {
setLoading(true);
setFetchError("");
setSelectedUser(null);
setSelectedAccessLevel("");
try {
let response;
const role = getRoleFromUrl();
if (userType === "delegate") {
response = await axios.get(
`/get_representatives/?role=${role}${
checkPathStartsWith("slaughter") || checkPathStartsWith("steward")
? `&role_key=${selectedSubUser?.key}`
: ""
}`
);
} else {
response = await axios.get(
`/get_dispensers/?role=${role}${
checkPathStartsWith("slaughter") || checkPathStartsWith("steward")
? `&role_key=${selectedSubUser?.key}`
: ""
}`
);
}
if (isMounted) {
const rawOptions = Array.isArray(response?.data?.results)
? response?.data?.results
: Array.isArray(response?.data)
? response?.data
: Array.isArray(response?.data?.data)
? response?.data?.data
: Array.isArray(response)
? response
: [];
// Normalize the data - both delegates and dispensers have the same structure
const normalizedOptions = rawOptions.map((item) => {
const fullname = item?.fullname || "-";
const mobile = item?.mobile || "";
const mobileLabel = mobile ? ` (${mobile})` : "";
const label = `${fullname}${mobileLabel}`;
return {
...item,
label: label || "-",
};
});
setOptions(normalizedOptions);
}
} catch (error) {
if (isMounted) {
setFetchError("دریافت لیست کاربران با خطا مواجه شد.");
console.error("Error fetching users:", error);
}
} finally {
if (isMounted) {
setLoading(false);
}
}
};
fetchUsers();
return () => {
isMounted = false;
};
}, [userType, selectedSubUser?.key]);
const handleCloseModal = () => {
dispatch(CLOSE_MODAL());
};
const getSubAccessLevels = (user) => {
if (!user) return [];
const subAccessLevels = [];
// Common excluded boolean fields that are not access levels
const excludedFields = [
"active",
"trash",
"deleted",
"isActive",
"isDeleted",
];
// Get all boolean fields that represent sub access levels
// These are fields in the object that are boolean and indicate sub access levels
Object.keys(user).forEach((key) => {
if (typeof user[key] === "boolean" && user[key] === true) {
// Exclude common boolean fields that aren't access levels
if (!excludedFields.includes(key.toLowerCase())) {
// Use getFaUserRole to get the Persian translation
const translatedLabel = getFaUserRole(key);
subAccessLevels.push({
key: key,
label: translatedLabel || key,
});
}
}
});
return subAccessLevels;
};
const handleSubmit = async () => {
if (!selectedUser) {
openNotif({
vertical: "top",
horizontal: "center",
severity: "error",
msg: "لطفاً یک کاربر را انتخاب کنید.",
});
return;
}
if (!device?.key && !device?.id) {
openNotif({
vertical: "top",
horizontal: "center",
severity: "error",
msg: "شناسه دستگاه یافت نشد. لطفاً دوباره تلاش کنید.",
});
return;
}
setSubmitting(true);
try {
const payload = {
key: device?.key || device?.id,
recipient_type:
userType === "delegate" ? "representative" : "dispenser",
recipient_key: selectedUser?.key || selectedUser?.id,
};
await axios.put("/user-pos-machine/0/", payload);
openNotif({
vertical: "top",
horizontal: "center",
severity: "success",
msg: "دستگاه با موفقیت به کاربر فرعی اختصاص داده شد.",
});
if (onSuccess) {
onSuccess();
}
handleCloseModal();
} catch (error) {
openNotif({
vertical: "top",
horizontal: "center",
severity: "error",
msg:
error?.response?.data?.result ||
error?.response?.data?.detail ||
"اختصاص دستگاه با خطا مواجه شد.",
});
} finally {
setSubmitting(false);
}
};
const selectedUserSubAccessLevels = selectedUser
? getSubAccessLevels(selectedUser)
: [];
return (
<Grid
container
direction="column"
gap={SPACING.SMALL}
width="100%"
alignItems="stretch"
sx={{ minWidth: 400 }}
>
<Typography variant="body2">
دستگاه انتخاب شده:{" "}
{device?.serial ||
device?.pos_unique_id ||
device?.pos_id ||
device?.posId ||
"-"}
</Typography>
<LabelField label="نوع کاربر">
<FormControl fullWidth>
<RadioGroup
row
sx={{ gap: 2 }}
value={userType}
onChange={(e) => setUserType(e.target.value)}
>
<FormControlLabel
value="delegate"
control={<Radio />}
label="نماینده‌ها"
/>
<FormControlLabel
value="dispenser"
control={<Radio />}
label="پخش‌کنندگان"
/>
</RadioGroup>
</FormControl>
</LabelField>
{loading ? (
<Grid container justifyContent="center">
<CircularProgress size={24} />
</Grid>
) : (
<Autocomplete
disablePortal
fullWidth
size="small"
options={options}
value={selectedUser}
loading={loading}
loadingText="در حال دریافت..."
noOptionsText="موردی یافت نشد."
onChange={(event, value) => {
setSelectedUser(value);
setSelectedAccessLevel("");
}}
isOptionEqualToValue={(option, value) =>
option?.key === value?.key || option?.id === value?.id
}
getOptionLabel={(option) => option?.label || ""}
renderOption={(props, option) => {
if (!option) return null;
return (
<li {...props} key={option?.key || option?.id}>
<Grid container direction="column">
<Typography variant="body2" fontWeight={600}>
{option?.label || "-"}
</Typography>
{option?.city && (
<Typography variant="caption" color="text.secondary">
{option.city}
</Typography>
)}
</Grid>
</li>
);
}}
renderInput={(params) => (
<TextField
{...params}
label="انتخاب کاربر"
placeholder="نام یا شماره تماس"
InputProps={{
...params.InputProps,
endAdornment: (
<>
{loading ? (
<CircularProgress color="inherit" size={16} />
) : null}
{params.InputProps.endAdornment}
</>
),
}}
/>
)}
/>
)}
{fetchError && (
<Typography variant="caption" color="error">
{fetchError}
</Typography>
)}
{selectedUser && selectedUserSubAccessLevels.length > 0 && (
<LabelField label="سطح دسترسی فرعی">
<Select
fullWidth
size="small"
value={selectedAccessLevel}
onChange={(e) => setSelectedAccessLevel(e.target.value)}
displayEmpty
>
<MenuItem value="">
<em>انتخاب سطح دسترسی</em>
</MenuItem>
{selectedUserSubAccessLevels.map((level) => (
<MenuItem key={level.key} value={level.key}>
{level.label}
</MenuItem>
))}
</Select>
</LabelField>
)}
<Grid container justifyContent="flex-end" gap={SPACING.SMALL} mt={2}>
<Button
variant="outlined"
color="primary"
onClick={handleCloseModal}
disabled={submitting}
>
انصراف
</Button>
<Button
variant="contained"
onClick={handleSubmit}
disabled={!selectedUser || submitting || loading}
>
{submitting ? "در حال ثبت..." : "ثبت"}
</Button>
</Grid>
</Grid>
);
};

View File

@@ -1,266 +0,0 @@
import { useContext, useState } from "react";
import { useDispatch } from "react-redux";
import {
Box,
Grid,
IconButton,
List,
ListItemButton,
ListItemIcon,
ListItemText,
Popover,
Typography,
Button,
} from "@mui/material";
import TuneIcon from "@mui/icons-material/Tune";
import PersonAddAlt1RoundedIcon from "@mui/icons-material/PersonAddAlt1Rounded";
import AddIcon from "@mui/icons-material/Add";
import EditIcon from "@mui/icons-material/Edit";
import DeleteIcon from "@mui/icons-material/Delete";
import { AppContext } from "../../../../contexts/AppContext";
import {
LOADING_START,
LOADING_END,
CLOSE_MODAL,
OPEN_MODAL,
} from "../../../../lib/redux/slices/appSlice";
import axios from "axios";
import { getFaUserRole } from "../../../../utils/getFaUserRole";
import { AssignSubUserModal } from "./AssignSubUserModal";
import { AddAccessLevelModal } from "./AddAccessLevelModal";
import { EditSubSectionsModal } from "./EditSubSectionsModal";
export const DeviceOperations = ({
device,
onSubUserAssigned,
fetchApiData,
page,
}) => {
const [anchorEl, setAnchorEl] = useState(null);
const dispatch = useDispatch();
const [openNotif] = useContext(AppContext);
const handleOpen = (event) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const handleAssignSubUser = () => {
handleClose();
dispatch(
OPEN_MODAL({
title: "اختصاص دستگاه به کاربر فرعی",
width: "auto",
content: (
<AssignSubUserModal device={device} onSuccess={onSubUserAssigned} />
),
})
);
};
const handleAddAccessLevel = () => {
handleClose();
dispatch(
OPEN_MODAL({
title: "افزودن سطح دسترسی",
width: "auto",
content: (
<AddAccessLevelModal device={device} onSuccess={onSubUserAssigned} />
),
})
);
};
const handleEditSubSections = (accessLevel) => {
handleClose();
dispatch(
OPEN_MODAL({
title: "ویرایش زیربخش‌های سطح دسترسی",
width: "auto",
content: (
<EditSubSectionsModal
accessLevel={accessLevel}
device={device}
onSuccess={() => fetchApiData(page)}
/>
),
})
);
};
const handleDeleteAccessLevel = (accessLevel) => {
handleClose();
dispatch(
OPEN_MODAL({
title: "حذف سطح دسترسی",
size: 320,
content: (
<Grid container spacing={2}>
<Grid
item
xs={12}
container
justifyContent="center"
alignItems="center"
mb={2}
>
<Typography variant="body2" color="default">
آیا از حذف سطح دسترسی{" "}
{getFaUserRole(accessLevel?.name) || accessLevel?.name} مطمئن
هستید؟
</Typography>
</Grid>
<Grid item xs={6}>
<Button
fullWidth
variant="contained"
color="error"
onClick={async () => {
try {
dispatch(LOADING_START());
await axios.delete(
`/pos-access-level/0/?key=${accessLevel?.key}`
);
dispatch(LOADING_END());
dispatch(CLOSE_MODAL());
openNotif({
vertical: "top",
horizontal: "center",
severity: "success",
msg: "سطح دسترسی با موفقیت حذف شد.",
});
if (fetchApiData) {
fetchApiData(page);
}
} catch (error) {
dispatch(LOADING_END());
openNotif({
vertical: "top",
horizontal: "center",
severity: "error",
msg:
error?.response?.data?.result ||
error?.response?.data?.detail ||
"حذف سطح دسترسی با خطا مواجه شد.",
});
}
}}
>
تایید
</Button>
</Grid>
<Grid item xs={6}>
<Button
fullWidth
variant="outlined"
onClick={() => dispatch(CLOSE_MODAL())}
>
انصراف
</Button>
</Grid>
</Grid>
),
})
);
};
const open = Boolean(anchorEl);
const id = open ? "device-operations-popover" : undefined;
const accessLevels = Array.isArray(device?.accessLevels)
? device.accessLevels.filter((level) => !level?.trash)
: [];
return (
<>
<IconButton
aria-describedby={id}
color="primary"
onClick={handleOpen}
size="small"
>
<TuneIcon fontSize="small" />
</IconButton>
<Popover
id={id}
open={open}
anchorEl={anchorEl}
onClose={handleClose}
anchorOrigin={{
vertical: "bottom",
horizontal: "right",
}}
transformOrigin={{
vertical: "top",
horizontal: "left",
}}
>
<List sx={{ minWidth: 200, p: 0 }}>
<ListItemButton onClick={handleAssignSubUser}>
<ListItemIcon sx={{ minWidth: 36, color: "success.main" }}>
<PersonAddAlt1RoundedIcon fontSize="small" />
</ListItemIcon>
<ListItemText
primary="اختصاص به کاربر"
primaryTypographyProps={{
sx: { color: "success.main", fontSize: "0.875rem" },
}}
/>
</ListItemButton>
<ListItemButton onClick={handleAddAccessLevel}>
<ListItemIcon sx={{ minWidth: 36, color: "info.main" }}>
<AddIcon fontSize="small" />
</ListItemIcon>
<ListItemText
primary="افزودن سطح دسترسی"
primaryTypographyProps={{
sx: { color: "info.main", fontSize: "0.875rem" },
}}
/>
</ListItemButton>
{accessLevels.length > 0 && (
<>
<Box sx={{ pl: 1.5, py: 0.5, bgcolor: "action.hover" }}>
<Typography variant="caption" color="text.secondary">
مدیریت سطح دسترسی:
</Typography>
</Box>
{accessLevels.map((level, idx) => (
<Box key={level?.key || idx} sx={{ pl: 1, pr: 0.5 }}>
<Grid
container
alignItems="center"
justifyContent="space-between"
>
<Typography variant="body2" sx={{ py: 0.5, pl: 0.5 }}>
{getFaUserRole(level?.name) || level?.name || "-"}
</Typography>
<Grid gap={0.5}>
<IconButton
size="small"
color="primary"
onClick={() => handleEditSubSections(level)}
>
<EditIcon fontSize="small" />
</IconButton>
<IconButton
size="small"
color="error"
onClick={() => handleDeleteAccessLevel(level)}
>
<DeleteIcon fontSize="small" />
</IconButton>
</Grid>
</Grid>
</Box>
))}
</>
)}
</List>
</Popover>
</>
);
};

View File

@@ -1,202 +0,0 @@
import { useContext, useState } from "react";
import { useDispatch } from "react-redux";
import {
Button,
Checkbox,
FormControlLabel,
Grid,
Typography,
} from "@mui/material";
import axios from "axios";
import { AppContext } from "../../../../contexts/AppContext";
import { CLOSE_MODAL } from "../../../../lib/redux/slices/appSlice";
import { LabelField } from "../../../../components/label-field/LabelField";
import { SPACING } from "../../../../data/spacing";
import { getFaUserRole } from "../../../../utils/getFaUserRole";
export const EditSubSectionsModal = ({ accessLevel, device, onSuccess }) => {
const dispatch = useDispatch();
const [openNotif] = useContext(AppContext);
const [submitting, setSubmitting] = useState(false);
const [values, setValues] = useState({
in_province_sale: accessLevel?.in_province_sale || false,
out_province_sale: accessLevel?.out_province_sale || false,
cutting: accessLevel?.cutting || false,
freezing: accessLevel?.freezing || false,
warehouse: accessLevel?.warehouse || false,
retail: accessLevel?.retail || false,
});
const handleCloseModal = () => {
dispatch(CLOSE_MODAL());
};
const handleChange = (field) => (event) => {
setValues((prev) => ({
...prev,
[field]: event.target.checked,
}));
};
const handleSubmit = async () => {
if (!accessLevel?.key) {
openNotif({
vertical: "top",
horizontal: "center",
severity: "error",
msg: "شناسه سطح دسترسی یافت نشد. لطفاً دوباره تلاش کنید.",
});
return;
}
setSubmitting(true);
try {
const payload = {
key: accessLevel.key,
in_province_sale: values.in_province_sale,
out_province_sale: values.out_province_sale,
cutting: values.cutting,
freezing: values.freezing,
warehouse: values.warehouse,
retail: values.retail,
};
await axios.put("/pos-access-level/0/", payload);
openNotif({
vertical: "top",
horizontal: "center",
severity: "success",
msg: "زیربخش‌های سطح دسترسی با موفقیت ویرایش شد.",
});
if (onSuccess) {
onSuccess();
}
handleCloseModal();
} catch (error) {
openNotif({
vertical: "top",
horizontal: "center",
severity: "error",
msg:
error?.response?.data?.result ||
error?.response?.data?.detail ||
"ویرایش زیربخش‌ها با خطا مواجه شد.",
});
} finally {
setSubmitting(false);
}
};
return (
<Grid
container
direction="column"
gap={SPACING.SMALL}
width="100%"
alignItems="stretch"
sx={{ minWidth: 400 }}
>
<Typography variant="body2">
سطح دسترسی:{" "}
{getFaUserRole(accessLevel?.name) || accessLevel?.name || "-"}
</Typography>
<Typography variant="body2">
دستگاه:{" "}
{device?.serial ||
device?.pos_unique_id ||
device?.pos_id ||
device?.posId ||
"-"}
</Typography>
<LabelField label="تنظیمات زیربخش‌ها">
<Grid container p={1}>
<Grid item xs={6}>
<FormControlLabel
control={
<Checkbox
checked={values.in_province_sale}
onChange={handleChange("in_province_sale")}
/>
}
label="فروش داخل استان"
/>
</Grid>
<Grid item xs={6}>
<FormControlLabel
control={
<Checkbox
checked={values.out_province_sale}
onChange={handleChange("out_province_sale")}
/>
}
label="فروش خارج استان"
/>
</Grid>
<Grid item xs={6}>
<FormControlLabel
control={
<Checkbox
checked={values.cutting}
onChange={handleChange("cutting")}
/>
}
label="قطعه بندی"
/>
</Grid>
<Grid item xs={6}>
<FormControlLabel
control={
<Checkbox
checked={values.freezing}
onChange={handleChange("freezing")}
/>
}
label="انجماد"
/>
</Grid>
<Grid item xs={6}>
<FormControlLabel
control={
<Checkbox
checked={values.warehouse}
onChange={handleChange("warehouse")}
/>
}
label="انبار"
/>
</Grid>
<Grid item xs={6}>
<FormControlLabel
control={
<Checkbox
checked={values.retail}
onChange={handleChange("retail")}
/>
}
label="خرده‌فروشی"
/>
</Grid>
</Grid>
</LabelField>
<Grid container justifyContent="flex-end" gap={SPACING.SMALL} mt={2}>
<Button
variant="outlined"
color="primary"
onClick={handleCloseModal}
disabled={submitting}
>
انصراف
</Button>
<Button
variant="contained"
onClick={handleSubmit}
disabled={submitting}
>
{submitting ? "در حال ثبت..." : "ثبت"}
</Button>
</Grid>
</Grid>
);
};

View File

@@ -1,284 +0,0 @@
import { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import {
LOADING_END,
LOADING_START,
} from "../../../../lib/redux/slices/appSlice";
import axios from "axios";
import { Grid } from "../../../../components/grid/Grid";
import { SPACING } from "../../../../data/spacing";
import { BackButton } from "../../../../components/back-button/BackButton";
import { Autocomplete, Button, TextField, Box, Chip } from "@mui/material";
import { RiSearchLine } from "react-icons/ri";
import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable";
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
import { formatJustDate } from "../../../../utils/formatTime";
import { getFaUserRole } from "../../../../utils/getFaUserRole";
import { DeviceOperations } from "./DeviceOperations";
import { Lock } from "@mui/icons-material";
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
const GuildPspDevices = () => {
const [data, setData] = useState([]);
const [totalRows, setTotalRows] = useState(0);
const [perPage, setPerPage] = useState(10);
const [textValue, setTextValue] = useState("");
const [page, setPage] = useState(1);
const [tableData, setTableData] = useState([]);
const [brands, setBrands] = useState([]);
const [selectedBrand, setSelectedBrand] = useState("");
const selectedSubUser = useSelector(
(state) => state.userSlice.selectedSubUser
);
const dispatch = useDispatch();
const fetchBrands = async () => {
try {
dispatch(LOADING_START());
const response = await axios.get(
`/get_all_pos_company/?role=${getRoleFromUrl()}${
checkPathStartsWith("slaughter") || checkPathStartsWith("steward")
? `&role_key=${selectedSubUser?.key}`
: ""
}`
);
setBrands(response.data);
dispatch(LOADING_END());
} catch (error) {
console.error("Error fetching brands:", error);
dispatch(LOADING_END());
}
};
const canDoAction = (item) => {
if (item?.owner?.role?.includes("KillHouse")) {
return getRoleFromUrl() === "KillHouse";
}
if (item?.owner?.includes("Steward")) {
return getRoleFromUrl() === "Steward";
}
return false;
};
const fetchApiData = async (page) => {
try {
dispatch(LOADING_START());
let url = `/user-pos-machine/?search=filter&value=${textValue}&role=${getRoleFromUrl()}${
checkPathStartsWith("slaughter") || checkPathStartsWith("steward")
? `&role_key=${selectedSubUser?.key}`
: ""
}&page=${page}&page_size=${perPage}`;
if (selectedBrand) {
url += `&company=${selectedBrand}`;
}
const response = await axios.get(url);
setData(response.data?.results || []);
setTotalRows(response.data?.count || 0);
} catch (error) {
console.error("Error fetching devices:", error);
} finally {
dispatch(LOADING_END());
}
};
const handlePageChange = (page) => {
fetchApiData(page);
setPage(page);
};
const handlePerRowsChange = (perRows) => {
setPerPage(perRows);
setPage(1);
};
const handleTextChange = (event) => {
setTextValue(event.target.value);
};
useEffect(() => {
const d = data?.map((item, i) => {
const owner = item?.owner || {};
const posCompany = item?.posCompany || {};
// Format recipient information
const recipientDisplay = item?.recipient
? `${item?.recipient?.firstName || ""} ${
item?.recipient?.lastName || ""
}`.trim() +
(item?.recipient?.mobile
? ` (${item?.recipient?.mobile} - ${
item?.recipient?.agentType === "dispenser"
? "توزیع کننده"
: "نماینده"
})`
: "")
: "-";
// Format access_levels to display as chips only (filter out trash items)
const activeAccessLevels = Array.isArray(item?.accessLevels)
? item.accessLevels.filter((level) => !level?.trash)
: [];
const accessLevelsDisplay =
activeAccessLevels.length > 0 ? (
<Grid container gap={0.5} flexWrap="wrap">
{activeAccessLevels.map((level, idx) => (
<Chip
key={level?.key || idx}
label={getFaUserRole(level?.name) || level?.name || "-"}
size="small"
/>
))}
</Grid>
) : (
"-"
);
return [
page === 1 ? i + 1 : i + perPage * (page - 1) + 1,
posCompany?.name || "-",
item?.serial ?? "-",
item?.receiverNumber ?? "-",
item?.terminalNumber ?? "-",
item?.password ?? "-",
item?.posUniqueId || item?.posId || "-",
owner?.fullname ? `${owner?.fullname} (${owner?.mobile ?? "-"})` : "-",
owner?.nationalId || owner?.nationalCode || "-",
item?.createDate ? formatJustDate(item?.createDate) : "-",
accessLevelsDisplay,
recipientDisplay,
item?.active ? "فعال" : "غیرفعال",
canDoAction(item) ? (
<DeviceOperations
key={item?.id || item?.key || `device-${i}`}
device={item}
/>
) : (
<Lock sx={{ fontSize: 20, mt: 1, color: "gray" }} />
),
];
});
setTableData(d);
}, [data, page, perPage]);
useEffect(() => {
fetchBrands();
}, [dispatch, selectedSubUser?.key]);
useEffect(() => {
fetchApiData(page);
}, [selectedBrand, perPage, selectedSubUser?.key]);
const handleSubmit = async (event) => {
event.preventDefault();
fetchApiData(1);
};
const tableTitle = (
<Grid
container
alignItems="center"
justifyContent="space-between"
gap={2}
mb={1}
padding={2}
width="100%"
>
<Grid
container
width="100%"
alignItems="center"
justifyContent="space-between"
gap={SPACING.SMALL}
>
<Grid
container
alignItems="center"
gap={SPACING.SMALL}
xs={12}
md="auto"
>
<Autocomplete
size="small"
style={{ minWidth: 210 }}
disablePortal
id="brand"
options={
Array.isArray(brands)
? brands.map((i) => {
return {
data: i,
label: `${i?.name || ""}`,
};
})
: []
}
onChange={(event, value) => {
setSelectedBrand(value?.data?.key);
}}
renderInput={(params) => (
<TextField fullWidth {...params} label="انتخاب برند دستگاه" />
)}
/>
<Grid container alignItems="center" gap={SPACING.SMALL}>
<TextField
size="small"
autoComplete="off"
label="جستجو"
variant="outlined"
style={{ width: 250 }}
value={textValue}
onChange={handleTextChange}
/>
<Button
type="submit"
onClick={handleSubmit}
endIcon={<RiSearchLine />}
>
جستجو
</Button>
</Grid>
</Grid>
</Grid>
</Grid>
);
return (
<Box display="flex" justifyContent="center">
<Grid container xs={12} lg={10}>
<BackButton />
{tableTitle}
<ResponsiveTable
data={tableData}
columns={[
"ردیف",
"برند دستگاه",
"شماره سریال",
"شماره پذیرنده",
"شماره ترمینال",
"کلمه عبور امنیتی",
"کلید پوز",
"مالک",
"کدملی",
"تاریخ ایجاد",
"سطوح دسترسی",
"تحویل گیرنده",
"فعال / غیرفعال",
"عملیات",
]}
handlePageChange={handlePageChange}
totalRows={totalRows}
page={page}
perPage={perPage}
handlePerRowsChange={handlePerRowsChange}
title="مدیریت دستگاه ها"
/>
</Grid>
</Box>
);
};
export default GuildPspDevices;

View File

@@ -7,7 +7,7 @@ export const guildGetInventoryAllocatedService = createAsyncThunk(
async (d, { dispatch }) => {
dispatch(LOADING_START());
const { data, status } = await axios.get("steward-allocation/", {
params: { date: d.date, steward: true, role_key: d.role_key || "" },
params: { date: d.date, steward: true },
});
dispatch(LOADING_END());
return { data, status };

View File

@@ -7,7 +7,7 @@ export const guildGetInventoryStockService = createAsyncThunk(
async (d, { dispatch }) => {
dispatch(LOADING_START());
const { data, status } = await axios.get("steward_warehouse/", {
params: { date: d.date, role_key: d.role_key || "" },
params: { date: d.date },
});
dispatch(LOADING_END());
return { data, status };

View File

@@ -1,24 +0,0 @@
import { createAsyncThunk } from "@reduxjs/toolkit";
import axios from "axios";
import { LOADING_END, LOADING_START } from "../../../lib/redux/slices/appSlice";
import { getRoleFromUrl } from "../../../utils/getRoleFromUrl";
export const guildSalesInfoDashboardService = createAsyncThunk(
"GUILD_SALES_INFO_DASHBOARD_SERVICE",
async (d, { dispatch }) => {
dispatch(LOADING_START());
try {
const { data, status } = await axios.get("guild-sales-info-dashboard/", {
params: {
role: d.role || getRoleFromUrl(),
role_key: d.role_key || "",
},
});
dispatch(LOADING_END());
return { data, status };
} catch (e) {
dispatch(LOADING_END());
return { error: e.response?.data?.result };
}
}
);

View File

@@ -1,15 +0,0 @@
import { createAsyncThunk } from "@reduxjs/toolkit";
import axios from "axios";
import { LOADING_END, LOADING_START } from "../../../lib/redux/slices/appSlice";
export const senfGetAllocationDashboardService = createAsyncThunk(
"SENF_GET_ALLOCATION_DASHBOARD_SERVICE",
async (d, { dispatch }) => {
dispatch(LOADING_START());
const { data, status } = await axios.get("guild-allocation-dashbord/", {
params: d,
});
dispatch(LOADING_END());
return { data, status };
}
);

View File

@@ -1,21 +1,13 @@
import { createAsyncThunk } from "@reduxjs/toolkit";
import axios from "axios";
import { LOADING_END, LOADING_START } from "../../../lib/redux/slices/appSlice";
import { getRoleFromUrl } from "../../../utils/getRoleFromUrl";
export const senfGetInventoryAllocatedService = createAsyncThunk(
"SENF_GET_INVENTORY_ALLOCATED_SERVICE",
async (d, { dispatch }) => {
dispatch(LOADING_START());
const { data, status } = await axios.get("steward-allocation/", {
params: {
date1: d.date1,
date2: d.date2,
type: d.type || "",
role_key: d.role_key || "",
role: getRoleFromUrl(),
search: d.search,
},
params: { date: d.date, guild: true },
});
dispatch(LOADING_END());
return { data, status };

View File

@@ -7,7 +7,7 @@ export const senfGetInventoryStockService = createAsyncThunk(
async (d, { dispatch }) => {
dispatch(LOADING_START());
const { data, status } = await axios.get("guilds_warehouse/", {
params: d,
params: { date: d.date },
});
dispatch(LOADING_END());
return { data, status };

View File

@@ -1,7 +1,6 @@
import { createAsyncThunk } from "@reduxjs/toolkit";
import { LOADING_END, LOADING_START } from "../../../lib/redux/slices/appSlice";
import axios from "axios";
import { getRoleFromUrl } from "../../../utils/getRoleFromUrl";
export const stawardGetOutDashboardService = createAsyncThunk(
"STEWARD-GET-OUT_DASHBOARD_SERVICE",
@@ -10,7 +9,6 @@ export const stawardGetOutDashboardService = createAsyncThunk(
const { data, status } = await axios.get("steward_free_bar_dashboard", {
params: {
...d,
role: getRoleFromUrl(),
},
});
dispatch(LOADING_END());

View File

@@ -7,12 +7,9 @@ export const stewardGetOutSellService = createAsyncThunk(
"STEWRD_GET_OUT_SELL_SERVICE",
async (d, { dispatch }) => {
dispatch(LOADING_START());
const { data, status } = await axios.get("roles-products", {
params: {
role: getRoleFromUrl(),
...d,
},
});
const { data, status } = await axios.get(
"roles-products/?role=" + getRoleFromUrl()
);
dispatch(LOADING_END());
return { data, status };
}

View File

@@ -5,14 +5,10 @@ import { createAsyncThunk } from "@reduxjs/toolkit";
export const stewardSellOutGetBuyers = createAsyncThunk(
"STEWARD_GET_BUYERS_SELL_OUT",
async (d, { dispatch }) => {
async (id, { dispatch }) => {
dispatch(LOADING_START());
const { data, status } = await axios.get("out-province-carcasses-buyer/", {
params: {
role: getRoleFromUrl(),
role_key: d?.role_key || "",
mobile: d?.mobile,
},
params: { role: getRoleFromUrl() },
});
dispatch(LOADING_END());
return { data, status };

View File

@@ -14,7 +14,6 @@ export const stewardSellOutGetDashboard = createAsyncThunk(
date1: d.selectedDate1,
date2: d.selectedDate2,
role: getRoleFromUrl(),
role_key: d.role_key || "",
},
}
);

View File

@@ -57,7 +57,7 @@ export const ProvinceJahadBranDistributionsAllocation = ({ product }) => {
return (
<Grid container xs={12} justifyContent="center" alignItems="center" gap={2}>
<Grid container mt={2} mb={4} isDashboard xs={12}>
<Grid container mt={2} mb={4} isDashboard>
<ResponsiveTable
noPagination
isDashboard

View File

@@ -176,7 +176,7 @@ export const ProvinceJahadBranDistributionsPolicy = ({ product }) => {
return (
<Grid container xs={12} justifyContent="center" alignItems="center" gap={2}>
{getRoleFromUrl() === "LiveStockProvinceJahad" && (
<Grid container mt={2} mb={4} isDashboard xs={12}>
<Grid container mt={2} mb={4} isDashboard>
<ResponsiveTable
noPagination
isDashboard

View File

@@ -211,7 +211,7 @@ export const ProvinceJahadHerds = () => {
</Tooltip>
</Grid>
<Grid container mt={2} mb={4} isDashboard xs={12}>
<Grid container mt={2} mb={4} isDashboard>
<ResponsiveTable
noPagination
isDashboard

View File

@@ -184,7 +184,7 @@ export const ProvinceJahadRanchers = () => {
</a>
</Tooltip>
</Grid>
<Grid container mt={2} mb={4} isDashboard xs={12}>
<Grid container mt={2} mb={4} isDashboard>
<ResponsiveTable
noPagination
isDashboard

View File

@@ -354,7 +354,7 @@ export const ProvinceJahadTransactions = ({ product }) => {
</a>
</Tooltip>
</Grid>
<Grid container mt={2} mb={4} isDashboard xs={12}>
<Grid container mt={2} mb={4} isDashboard>
<ResponsiveTable
noPagination
isDashboard

File diff suppressed because it is too large Load Diff

View File

@@ -1,45 +0,0 @@
import React from "react";
import {
Button,
Typography,
ListItem,
ListItemIcon,
ListItemText,
} from "@mui/material";
import { Grid } from "../../../../../components/grid/Grid";
import { SPACING } from "../../../../../data/spacing";
import { DialogAlert } from "../../../../../components/dialog-alert/DialogAlert";
import { Done } from "@mui/icons-material";
export const ConfirmationDialog = ({ isAccepted, onAccept, onReject }) => {
return (
<Grid item pb={2} mt={2}>
<DialogAlert
title="تعهد نامه"
content={
<>
<ListItem>
<ListItemIcon>
<Done />
</ListItemIcon>
<ListItemText primary="لطفا صحت اطلاعات وارد شده را بررسی نمایید. پس از تکمیل و ثبت درخواست، یک کد احراز هویت از طریق پیامک برای صنف یا مباشر به شماره تلفن اعلامی ارسال میگردد." />
</ListItem>
<Typography></Typography>
</>
}
actions={
<Grid container gap={SPACING.TINY}>
<Button variant="outlined" color="error" onClick={onReject}>
رد
</Button>
<Button variant="contained" color="success" onClick={onAccept}>
موافقم
</Button>
</Grid>
}
btnTitle="تایید صحت اطلاعات"
isAccepted={isAccepted}
/>
</Grid>
);
};

View File

@@ -1,69 +0,0 @@
import React from "react";
import { Button, Typography, Checkbox, FormControlLabel } from "@mui/material";
import { Grid } from "../../../../../components/grid/Grid";
export const FormActions = ({
formik,
onClose,
showCloseButton,
isKillHouse,
onSubmit,
}) => {
if (showCloseButton) {
return (
<Grid item xs={12} mt={4}>
<Button color="primary" fullWidth variant="contained" onClick={onClose}>
متوجه شدم
</Button>
</Grid>
);
}
// For KillHouse: check if area_activity contains "مرغ"
const isAreaActivityValid = isKillHouse
? formik.values.area_activity && formik.values.area_activity.includes("مرغ")
: true;
return (
<>
<Grid item xs={12}>
<FormControlLabel
control={
<Checkbox
checked={formik.values.verify_mobile}
onChange={formik.handleChange}
name="verify_mobile"
color="primary"
/>
}
label="احراز شماره موبایل"
/>
</Grid>
<Grid item xs={12}>
<Button
disabled={
formik.errors.isAccepted ||
Boolean(formik.errors.national_id) ||
!isAreaActivityValid
}
color="primary"
fullWidth
variant="contained"
onClick={onSubmit}
type="button"
>
ثبت
</Button>
{isKillHouse && !isAreaActivityValid && (
<Typography
variant="caption"
color="error"
sx={{ mt: 1, display: "block" }}
>
رسته واحد صنفی باید شامل کلمه &quot;مرغ&quot; باشد
</Typography>
)}
</Grid>
</>
);
};

View File

@@ -1,97 +0,0 @@
import React from "react";
import {
Accordion,
AccordionSummary,
AccordionDetails,
Typography,
IconButton,
} from "@mui/material";
import {
ExpandMore as ExpandMoreIcon,
Delete as DeleteIcon,
} from "@mui/icons-material";
import { GuildInfoSection } from "./GuildInfoSection";
export const GuildInfoAccordionItem = ({
guildIndex,
guildData,
guildActive,
isAdmin,
cities,
typeActivities,
onDelete,
canDelete,
guildFormValues,
onGuildValuesChange,
expanded,
onChange,
}) => {
// Create a formik-like object for this guild's values
const guildFormik = {
values: guildFormValues || {},
setFieldValue: (fieldName, value) => {
onGuildValuesChange(guildIndex, fieldName, value);
},
handleChange: (e) => {
onGuildValuesChange(guildIndex, e.target.name, e.target.value);
},
handleBlur: () => {},
errors: {},
touched: {},
};
const getGuildTitle = () => {
if (guildData?.guildsName) {
return guildData.guildsName;
}
if (guildData?.title) {
return guildData.title;
}
if (guildFormik.values.guild_name) {
return guildFormik.values.guild_name;
}
return `واحد صنفی ${guildIndex + 1}`;
};
return (
<Accordion expanded={expanded} onChange={onChange}>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
sx={{
"& .MuiAccordionSummary-content": {
alignItems: "center",
justifyContent: "space-between",
},
}}
>
<Typography variant="h6" sx={{ flexGrow: 1, fontSize: 18 }}>
{getGuildTitle()}
</Typography>
{canDelete && (
<IconButton
onClick={(e) => {
e.stopPropagation();
onDelete();
}}
color="error"
size="small"
sx={{ mr: 1 }}
>
<DeleteIcon />
</IconButton>
)}
</AccordionSummary>
<AccordionDetails>
<GuildInfoSection
formik={guildFormik}
guild={guildData}
guildActive={guildActive}
isAdmin={isAdmin}
cities={cities}
typeActivities={typeActivities}
hideTitle={true}
noGridWrapper={true}
/>
</AccordionDetails>
</Accordion>
);
};

View File

@@ -1,566 +0,0 @@
import React from "react";
import {
TextField,
Typography,
RadioGroup,
FormControl,
Radio,
FormControlLabel,
Select,
MenuItem,
InputLabel,
Checkbox,
} from "@mui/material";
import { DatePicker } from "@mui/x-date-pickers";
import moment from "moment";
import BusinessIcon from "@mui/icons-material/Business";
import PublicIcon from "@mui/icons-material/Public";
import LocationCityIcon from "@mui/icons-material/LocationCity";
import DateRangeIcon from "@mui/icons-material/DateRange";
import ConfirmationNumberIcon from "@mui/icons-material/ConfirmationNumber";
import AccountBalanceIcon from "@mui/icons-material/AccountBalance";
import LocalPostOfficeIcon from "@mui/icons-material/LocalPostOffice";
import PhoneIcon from "@mui/icons-material/Phone";
import BadgeIcon from "@mui/icons-material/Badge";
import CheckCircleIcon from "@mui/icons-material/CheckCircle";
import HomeIcon from "@mui/icons-material/Home";
import CorporateFareIcon from "@mui/icons-material/CorporateFare";
import { Grid } from "../../../../../components/grid/Grid";
import { SPACING } from "../../../../../data/spacing";
import { LabelField } from "../../../../../components/label-field/LabelField";
import { InfoBox } from "./InfoBox";
import { STATUS_VALUES } from "../constants";
import {
convertPersianToGregorian,
convertGregorianToPersian,
} from "../utils/dateUtils";
export const GuildInfoSection = ({
formik,
guild,
guildActive,
isAdmin,
cities,
typeActivities,
hideTitle = false,
noGridWrapper = false,
}) => {
const getForeignerDisplay = (isForeigner) => {
if (isForeigner === STATUS_VALUES.NO || isForeigner === false)
return STATUS_VALUES.NO;
if (isForeigner === STATUS_VALUES.YES || isForeigner === true)
return STATUS_VALUES.YES;
return "-";
};
const getLicenseExpireDateDisplay = () => {
return formik.values.license_expire_date || "-";
};
const getActiveStatusDisplay = () => {
const activeValue =
formik.values.active !== null
? formik.values.active
: guild?.active === true || guildActive === true;
return activeValue === true ? "فعال" : "غیر فعال";
};
const content = (
<Grid container gap={SPACING.TINY} direction="column">
{!hideTitle && (
<Grid item xs={12}>
<Typography variant="h6" gutterBottom>
اطلاعات صنفی
</Typography>
</Grid>
)}
<Grid container xs={12}>
<Grid
container
direction="column"
xs={12}
md={6}
px={SPACING.TINY}
gap={SPACING.TINY}
>
<Grid item xs={12}>
{isAdmin ? (
<TextField
label="نام واحد"
variant="outlined"
fullWidth
id="guild_name"
name="guild_name"
value={formik.values.guild_name}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
) : (
<InfoBox
icon={BusinessIcon}
label="نام واحد"
value={formik.values.guild_name}
/>
)}
</Grid>
<Grid item xs={12}>
{isAdmin ? (
<FormControl fullWidth>
<InputLabel id="area-activity-select-label">
رسته واحد صنفی
</InputLabel>
<Select
labelId="area-activity-select-label"
id="area_activity"
name="area_activity"
value={formik.values.area_activity || ""}
label="رسته واحد صنفی"
onChange={(e) => {
formik.setFieldValue("area_activity", e.target.value);
}}
onBlur={formik.handleBlur}
>
{typeActivities.map((activity) => (
<MenuItem key={activity.key} value={activity.title}>
{activity.title}
</MenuItem>
))}
{/* Show current value if it doesn't exist in options */}
{formik.values.area_activity &&
!typeActivities.some(
(activity) =>
activity.title === formik.values.area_activity
) && (
<MenuItem
key="current-value"
value={formik.values.area_activity}
>
{formik.values.area_activity}
</MenuItem>
)}
</Select>
</FormControl>
) : (
<InfoBox
icon={BusinessIcon}
label="رسته واحد صنفی"
value={formik.values.area_activity}
/>
)}
</Grid>
<Grid item xs={12}>
{isAdmin ? (
<TextField
label="استان"
variant="outlined"
fullWidth
id="state"
name="state"
value={formik.values.state}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
) : (
<InfoBox
icon={PublicIcon}
label="استان"
value={formik.values.state}
/>
)}
</Grid>
<Grid item xs={12}>
{isAdmin ? (
<FormControl fullWidth>
<InputLabel id="city-select-label">شهرستان</InputLabel>
<Select
labelId="city-select-label"
id="city"
name="city"
value={formik.values.city || ""}
label="شهرستان"
onChange={(e) => {
formik.setFieldValue("city", e.target.value);
}}
onBlur={formik.handleBlur}
>
{cities.map((city) => (
<MenuItem key={city.key} value={city.name}>
{city.name}
</MenuItem>
))}
{/* Show current value if it doesn't exist in options */}
{formik.values.city &&
!cities.some(
(city) => city.name === formik.values.city
) && (
<MenuItem key="current-value" value={formik.values.city}>
{formik.values.city}
</MenuItem>
)}
</Select>
</FormControl>
) : (
<InfoBox
icon={LocationCityIcon}
label="شهرستان"
value={formik.values.city}
/>
)}
</Grid>
<Grid item xs={12}>
{isAdmin ? (
<DatePicker
label="تاریخ انقضا مجوز"
value={
formik.values.license_expire_date
? moment(
convertPersianToGregorian(
formik.values.license_expire_date
)
)
: null
}
onChange={(newValue) => {
if (newValue) {
const gregorianDate = moment(newValue).format("YYYY-MM-DD");
const persianDate =
convertGregorianToPersian(gregorianDate);
formik.setFieldValue("license_expire_date", persianDate);
} else {
formik.setFieldValue("license_expire_date", "");
}
}}
renderInput={(params) => (
<TextField {...params} fullWidth variant="outlined" />
)}
/>
) : (
<InfoBox
icon={DateRangeIcon}
label="تاریخ انقضا مجوز"
value={getLicenseExpireDateDisplay()}
/>
)}
</Grid>
<Grid item xs={12}>
{isAdmin ? (
<TextField
label="شماره مجوز"
variant="outlined"
fullWidth
id="license_number"
name="license_number"
value={formik.values.license_number}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
) : (
<InfoBox
icon={ConfirmationNumberIcon}
label="شماره مجوز"
value={formik.values.license_number}
/>
)}
</Grid>
<Grid item xs={12}>
{isAdmin ? (
<TextField
label="نام اتحادیه"
variant="outlined"
fullWidth
id="union_name"
name="union_name"
value={formik.values.union_name}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
) : (
<InfoBox
icon={AccountBalanceIcon}
label="نام اتحادیه"
value={formik.values.union_name}
/>
)}
</Grid>
<Grid item xs={12}>
{isAdmin ? (
<LabelField label="وضعیت">
<FormControl fullWidth>
<RadioGroup
row
name="active"
value={
formik.values.active === true
? "true"
: formik.values.active === false
? "false"
: ""
}
onChange={(e) => {
formik.setFieldValue(
"active",
e.target.value === "true" ? true : false
);
}}
sx={{ justifyContent: "space-around" }}
>
<FormControlLabel
value="true"
control={<Radio />}
label="فعال"
/>
<FormControlLabel
value="false"
control={<Radio />}
label="غیر فعال"
/>
</RadioGroup>
</FormControl>
</LabelField>
) : (
<InfoBox
icon={CheckCircleIcon}
label="وضعیت"
value={getActiveStatusDisplay()}
/>
)}
</Grid>
</Grid>
<Grid
container
xs={12}
md={6}
px={SPACING.TINY}
direction="column"
gap={SPACING.TINY}
>
<Grid item xs={12}>
{isAdmin ? (
<TextField
label="کد پستی"
variant="outlined"
fullWidth
id="postal_code"
name="postal_code"
value={formik.values.postal_code}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
) : (
<InfoBox
icon={LocalPostOfficeIcon}
label="کد پستی"
value={formik.values.postal_code}
/>
)}
</Grid>
<Grid item xs={12}>
{isAdmin ? (
<TextField
label="شماره تلفن"
variant="outlined"
fullWidth
id="phone_number"
name="phone_number"
value={formik.values.phone_number}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
) : (
<InfoBox
icon={PhoneIcon}
label="شماره تلفن"
value={formik.values.phone_number}
/>
)}
</Grid>
<Grid item xs={12}>
{isAdmin ? (
<LabelField label="آیا اتباع است؟">
<FormControl fullWidth>
<RadioGroup
row
name="is_foreigner"
value={
formik.values.is_foreigner === "بلی" ||
formik.values.is_foreigner === true
? "بلی"
: formik.values.is_foreigner === "خیر" ||
formik.values.is_foreigner === false
? "خیر"
: ""
}
onChange={(e) => {
formik.setFieldValue(
"is_foreigner",
e.target.value === "بلی" ? "بلی" : "خیر"
);
}}
sx={{ justifyContent: "space-around" }}
>
<FormControlLabel
value="بلی"
control={<Radio />}
label="بلی"
/>
<FormControlLabel
value="خیر"
control={<Radio />}
label="خیر"
/>
</RadioGroup>
</FormControl>
</LabelField>
) : (
<InfoBox
icon={PublicIcon}
label="آیا اتباع است؟"
value={getForeignerDisplay(formik.values.is_foreigner)}
/>
)}
</Grid>
<Grid item xs={12}>
{isAdmin ? (
<TextField
label="نام شرکت"
variant="outlined"
fullWidth
id="corporation_name"
name="corporation_name"
value={formik.values.corporation_name}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
) : (
<InfoBox
icon={CorporateFareIcon}
label="نام شرکت"
value={formik.values.corporation_name}
/>
)}
</Grid>
<Grid item xs={12}>
{isAdmin ? (
<TextField
label="شناسه ملی شرکت"
variant="outlined"
fullWidth
id="guild_national_id"
name="guild_national_id"
value={formik.values.guild_national_id}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
) : (
<InfoBox
icon={BadgeIcon}
label="شناسه ملی شرکت"
value={formik.values.guild_national_id}
/>
)}
</Grid>
<Grid item xs={12}>
{isAdmin ? (
<TextField
label="وضعیت مجوز"
variant="outlined"
fullWidth
id="license_status"
name="license_status"
value={formik.values.license_status}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
) : (
<InfoBox
icon={CheckCircleIcon}
label="وضعیت مجوز"
value={formik.values.license_status}
/>
)}
</Grid>
<Grid item xs={12}>
{isAdmin ? (
<TextField
label="آدرس"
variant="outlined"
fullWidth
multiline
rows={3}
id="address"
name="address"
value={formik.values.address}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
) : (
<InfoBox
icon={HomeIcon}
label="آدرس"
value={formik.values.address}
iconSx={{ mt: 0.5 }}
/>
)}
</Grid>
</Grid>
</Grid>
<Grid item xs={12} sx={{ display: "flex", mt: 2, pl: 2, mb: 2 }}>
{isAdmin ? (
<>
<FormControlLabel
control={
<Checkbox
checked={formik.values.steward || false}
onChange={(e) =>
formik.setFieldValue("steward", e.target.checked)
}
name="steward"
color="primary"
/>
}
label="مباشر"
/>
<FormControlLabel
sx={{ ml: 3 }}
control={
<Checkbox
checked={formik.values.guild || false}
onChange={(e) =>
formik.setFieldValue("guild", e.target.checked)
}
name="guild"
color="primary"
/>
}
label="صنف"
/>
</>
) : (
<>
<InfoBox
icon={CheckCircleIcon}
label="مباشر"
value={formik.values.steward ? "بلی" : "خیر"}
/>
<InfoBox
icon={CheckCircleIcon}
label="صنف"
value={formik.values.guild ? "بلی" : "خیر"}
sx={{ ml: 3 }}
/>
</>
)}
</Grid>
</Grid>
);
if (noGridWrapper) {
return <>{content}</>;
}
return (
<Grid item xs={12} lg={6} pr={{ xs: 0, md: 2 }} pl={{ xs: 0, md: 3 }}>
{content}
</Grid>
);
};

View File

@@ -1,23 +0,0 @@
import React from "react";
import { Box, Typography } from "@mui/material";
export const InfoBox = ({ icon: Icon, label, value, iconSx }) => (
<Box
display="flex"
alignItems={iconSx ? "flex-start" : "center"}
gap={1}
px={1.5}
py={0.5}
bgcolor="#f5f5f5"
borderRadius={1}
>
<Icon color="action" sx={iconSx} />
<Box>
<Typography variant="caption" color="text.secondary">
{label}
</Typography>
<Typography variant="body1">{value || "-"}</Typography>
</Box>
</Box>
);

View File

@@ -1,34 +0,0 @@
import React from "react";
import { TextField, Button } from "@mui/material";
export const InquiryForm = ({
inquiryNationalCode,
setInquiryNationalCode,
onInquiry,
isAdmin,
}) => {
return (
<>
<TextField
label="کد ملی برای استعلام"
variant="outlined"
fullWidth
value={inquiryNationalCode}
onChange={(e) => setInquiryNationalCode(e.target.value)}
placeholder={
isAdmin ? "کد ملی را وارد کنید" : "کد ملی 10 رقمی را وارد کنید"
}
inputProps={isAdmin ? {} : { maxLength: 10 }}
/>
<Button
color="primary"
fullWidth
variant="contained"
onClick={onInquiry}
disabled={!isAdmin && inquiryNationalCode.length !== 10}
>
استعلام
</Button>
</>
);
};

View File

@@ -1,369 +0,0 @@
import React from "react";
import {
TextField,
Typography,
RadioGroup,
FormControl,
Radio,
FormControlLabel,
} from "@mui/material";
import { DatePicker } from "@mui/x-date-pickers";
import moment from "moment";
import PersonIcon from "@mui/icons-material/Person";
import PhoneIcon from "@mui/icons-material/Phone";
import BadgeIcon from "@mui/icons-material/Badge";
import CakeIcon from "@mui/icons-material/Cake";
import FaceIcon from "@mui/icons-material/Face";
import LocationCityIcon from "@mui/icons-material/LocationCity";
import FavoriteIcon from "@mui/icons-material/Favorite";
import { Grid } from "../../../../../components/grid/Grid";
import { SPACING } from "../../../../../data/spacing";
import { LabelField } from "../../../../../components/label-field/LabelField";
import { InfoBox } from "./InfoBox";
import { GENDER_VALUES, ALIVE_STATUS } from "../constants";
import {
convertPersianToGregorian,
convertGregorianToPersian,
} from "../utils/dateUtils";
export const PersonalInfoSection = ({
formik,
guild,
hasInquiry,
isAdmin,
isSuperAdmin,
isKillHouse,
}) => {
const getGenderDisplay = (gender) => {
if (gender === "True" || gender === true) return GENDER_VALUES.MALE;
if (gender === "False" || gender === false) return GENDER_VALUES.FEMALE;
return "-";
};
const getAliveStatusDisplay = (isAlive) => {
if (isAlive === ALIVE_STATUS.YES || isAlive === true)
return ALIVE_STATUS.YES;
if (isAlive === ALIVE_STATUS.NO || isAlive === false)
return ALIVE_STATUS.NO;
return "-";
};
const getBirthDateDisplay = () => {
return formik.values.birth_date || "-";
};
return (
<Grid
item
xs={12}
lg={6}
pl={{ xs: 0, md: 2 }}
pr={{ xs: 0, md: 3 }}
mb={2}
>
<Grid container direction="column" gap={SPACING.SMALL}>
<Grid item xs={12}>
<Typography variant="h6" gutterBottom>
اطلاعات شخصی
</Typography>
</Grid>
<Grid container xs={12}>
<Grid container xs={12} md={6} gap={SPACING.TINY} px={SPACING.TINY}>
<Grid item xs={12}>
{guild || isAdmin ? (
<TextField
label="کد ملی"
variant="outlined"
fullWidth
id="national_id"
name="national_id"
value={formik.values.national_id}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
error={Boolean(formik.errors.national_id)}
helperText={formik.errors.national_id}
inputProps={{ maxLength: 10 }}
disabled={!isAdmin || isKillHouse}
/>
) : (
<InfoBox
icon={BadgeIcon}
label="کد ملی"
value={formik.values.national_id}
/>
)}
</Grid>
<Grid item xs={12}>
{isAdmin ? (
<TextField
label="نام"
variant="outlined"
fullWidth
id="first_name"
name="first_name"
value={formik.values.first_name}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
) : (
<InfoBox
icon={PersonIcon}
label="نام"
value={formik.values.first_name}
/>
)}
</Grid>
<Grid item xs={12}>
{isAdmin ? (
<TextField
label="نام خانوادگی"
variant="outlined"
fullWidth
id="last_name"
name="last_name"
value={formik.values.last_name}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
) : (
<InfoBox
icon={PersonIcon}
label="نام خانوادگی"
value={formik.values.last_name}
/>
)}
</Grid>
<Grid item xs={12}>
{isAdmin ? (
<TextField
label="شماره شناسنامه"
variant="outlined"
fullWidth
id="national_code"
name="national_code"
value={formik.values.national_code}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
) : (
<InfoBox
icon={BadgeIcon}
label="شماره شناسنامه"
value={formik.values.national_code}
/>
)}
</Grid>
<Grid item xs={12}>
{isAdmin ? (
<LabelField label="در قید حیات">
<FormControl fullWidth>
<RadioGroup
row
name="is_alive"
value={
formik.values.is_alive === "بلی" ||
formik.values.is_alive === true
? "بلی"
: formik.values.is_alive === "خیر" ||
formik.values.is_alive === false
? "خیر"
: ""
}
onChange={(e) => {
formik.setFieldValue(
"is_alive",
e.target.value === "بلی" ? "بلی" : "خیر"
);
}}
sx={{ justifyContent: "space-around" }}
>
<FormControlLabel
value="بلی"
control={<Radio />}
label="بلی"
/>
<FormControlLabel
value="خیر"
control={<Radio />}
label="خیر"
/>
</RadioGroup>
</FormControl>
</LabelField>
) : (
<InfoBox
icon={FavoriteIcon}
label="در قید حیات"
value={getAliveStatusDisplay(formik.values.is_alive)}
/>
)}
</Grid>
</Grid>
<Grid
container
xs={12}
md={6}
gap={SPACING.TINY}
px={SPACING.TINY}
mt={{ xs: 1, md: 0 }}
>
<Grid item xs={12}>
{isAdmin ? (
<DatePicker
label="تاریخ تولد"
value={
formik.values.birth_date
? moment(
convertPersianToGregorian(formik.values.birth_date)
)
: null
}
onChange={(newValue) => {
if (newValue) {
const gregorianDate =
moment(newValue).format("YYYY-MM-DD");
const persianDate =
convertGregorianToPersian(gregorianDate);
formik.setFieldValue("birth_date", persianDate);
} else {
formik.setFieldValue("birth_date", "");
}
}}
renderInput={(params) => (
<TextField {...params} fullWidth variant="outlined" />
)}
/>
) : (
<InfoBox
icon={CakeIcon}
label="تاریخ تولد"
value={getBirthDateDisplay()}
/>
)}
</Grid>
<Grid item xs={12}>
{isAdmin ? (
<TextField
label="نام پدر"
variant="outlined"
fullWidth
id="father_name"
name="father_name"
value={formik.values.father_name}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
) : (
<InfoBox
icon={PersonIcon}
label="نام پدر"
value={formik.values.father_name}
/>
)}
</Grid>
<Grid item xs={12}>
{isAdmin ? (
<LabelField label="جنسیت">
<FormControl fullWidth>
<RadioGroup
row
name="gender"
value={
formik.values.gender === "True" ||
formik.values.gender === true
? "True"
: formik.values.gender === "False" ||
formik.values.gender === false
? "False"
: ""
}
onChange={(e) => {
formik.setFieldValue("gender", e.target.value);
}}
sx={{ justifyContent: "space-around" }}
>
<FormControlLabel
value="True"
control={<Radio />}
label="مرد"
/>
<FormControlLabel
value="False"
control={<Radio />}
label="زن"
/>
</RadioGroup>
</FormControl>
</LabelField>
) : (
<InfoBox
icon={FaceIcon}
label="جنسیت"
value={getGenderDisplay(formik.values.gender)}
/>
)}
</Grid>
<Grid item xs={12}>
{isAdmin ? (
<TextField
label="شهر"
variant="outlined"
fullWidth
id="person_city"
name="person_city"
value={formik.values.person_city}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
) : (
<InfoBox
icon={LocationCityIcon}
label="شهر"
value={formik.values.person_city}
/>
)}
</Grid>
<Grid item xs={12} mt={{ xs: 1, md: 0 }}>
{!guild &&
hasInquiry &&
!isAdmin &&
!isSuperAdmin &&
!isKillHouse ? (
<InfoBox
icon={PhoneIcon}
label="شماره همراه"
value={formik.values.mobile}
/>
) : isKillHouse &&
formik.values.mobile &&
/^[0-9]{11}$/.test(formik.values.mobile) ? (
<InfoBox
icon={PhoneIcon}
label="شماره همراه"
value={formik.values.mobile}
/>
) : (
<TextField
label="شماره همراه"
variant="outlined"
fullWidth
id="mobile"
name="mobile"
value={formik.values.mobile}
onChange={formik.handleChange}
error={formik.touched.mobile && Boolean(formik.errors.mobile)}
helperText={formik.touched.mobile && formik.errors.mobile}
disabled={
isKillHouse &&
formik.values.mobile &&
/^[0-9]{11}$/.test(formik.values.mobile)
}
/>
)}
</Grid>
</Grid>
</Grid>
</Grid>
</Grid>
);
};

View File

@@ -1,19 +0,0 @@
import React from "react";
import { Button } from "@mui/material";
import { Refresh } from "@mui/icons-material";
import { Grid } from "../../../../../components/grid/Grid";
export const UpdateFromExternalButton = ({ onUpdate, disabled }) => {
return (
<Grid container xs={12} justifyContent="flex-end">
<Button
onClick={onUpdate}
disabled={disabled}
color="primary"
size="small"
>
بروزرسانی از سامانه واحد <Refresh />
</Button>
</Grid>
);
};

View File

@@ -1,17 +0,0 @@
export const STATUS_VALUES = {
YES: "بلی",
NO: "خیر",
TRUE: "True",
FALSE: "False",
};
export const GENDER_VALUES = {
MALE: "مرد",
FEMALE: "زن",
};
export const ALIVE_STATUS = {
YES: "بلی",
NO: "خیر",
};

View File

@@ -1,232 +0,0 @@
import { getRoleFromUrl } from "../../../../../utils/getRoleFromUrl";
import { normalizeExternalApiDate, normalizeDatabaseDate } from "./dateUtils";
import { formatDateForSubmit } from "./dateUtils";
export const prepareSubmitData = (
values,
guild,
originalPhoneNumber,
hasInquiry
) => {
const baseData = {
national_id: values.national_id,
mobile: values.mobile,
mobilenumber: values.mobile,
steward: !!values.steward,
guild: !!values.guild,
active_register_code: !!values.verify_mobile,
firstName: values.first_name || "",
lastName: values.last_name || "",
fatherName: values.father_name || "",
gender: values.gender || "",
identityNo: values.national_code || "",
isLive: values.is_alive === "بلی" || values.is_alive === true,
birthDate: formatDateForSubmit(
values.birth_date || "",
hasInquiry === true
),
city: values.city || "",
address: values.address || "",
postalcode: values.postal_code || "",
licenseNumber: values.license_number || "",
licenseExpireDate: formatDateForSubmit(
values.license_expire_date || "",
hasInquiry === true
),
licenseIssueDate: formatDateForSubmit(
values.license_issue_date || "",
hasInquiry === true
),
licenseType: values.license_type || "",
licenseStatus: values.license_status || "",
isicname: values.area_activity || "",
corporationName: values.corporation_name || "",
nationalId: values.guild_national_id || "",
unionName: values.union_name || "",
phonenumber: values.phone_number || "",
hasPartner: values.has_partner === true || values.has_partner === "بلی",
isForeigner: values.is_foreigner === true || values.is_foreigner === "بلی",
title: values.guild_name || "",
role: getRoleFromUrl(),
has_inquiry: hasInquiry !== null ? hasInquiry : false,
...(values.active !== null && { active: values.active }),
};
if (guild) {
baseData.guilds_key = guild.key;
if (values.mobile !== originalPhoneNumber) {
baseData.mobile = values.mobile;
baseData.mobilenumber = values.mobile;
}
}
return baseData;
};
export const mapResponseDataToFormFields = (
responseData,
inquiryNationalCode,
formik
) => {
const isExternalApi = responseData.dbRegister === false;
// New structure: user is at top level, guilds is an array
const userData = responseData.user || {};
// For personal info, we use the first guild's data if available, or empty
const firstGuild =
Array.isArray(responseData.guilds) && responseData.guilds.length > 0
? responseData.guilds[0]
: {};
const guildData = firstGuild || {};
const layerTwo = guildData.layerTwo || {};
const addressData = firstGuild?.address || guildData.address || {};
const provinceData = addressData.province || {};
const cityData = addressData.city || {};
const nationalIdValue = isExternalApi
? String(
layerTwo.nationalcode || userData.nationalCode || inquiryNationalCode
).trim()
: String(userData.nationalId || inquiryNationalCode).trim();
const birthDatePersian = isExternalApi
? normalizeExternalApiDate(userData.birthDate || "")
: normalizeDatabaseDate(userData.birthday || "");
const licenseExpireDatePersian = isExternalApi
? normalizeExternalApiDate(guildData.licenseExpireDate || "")
: normalizeDatabaseDate(firstGuild.licenseExpireDate || "");
const licenseIssueDatePersian = isExternalApi
? normalizeExternalApiDate(layerTwo.licenseIssueDate || "")
: normalizeDatabaseDate(responseData.licenseIssueDate || "");
const genderValue = isExternalApi
? userData.gender === true
? "True"
: userData.gender === false
? "False"
: ""
: userData.gender || "";
const isAliveValue = isExternalApi
? userData.isLive === true
? "بلی"
: userData.isLive === false
? "خیر"
: ""
: userData.isAlive === false
? "خیر"
: userData.isAlive === true
? "بلی"
: "";
const isForeignerValue = isExternalApi
? layerTwo.isForeigner === "خیر"
? false
: layerTwo.isForeigner === "بلی"
? true
: ""
: responseData.isForeignNational === false
? false
: responseData.isForeignNational === true
? true
: "";
const hasStewardValue = isExternalApi
? layerTwo.hasSteward === "خیر"
? false
: layerTwo.hasSteward === "بلی"
? true
: ""
: responseData.steward === false
? false
: responseData.steward === true
? true
: "";
const hasPartnerValue = isExternalApi
? layerTwo.hasPartner === "خیر"
? false
: layerTwo.hasPartner === "بلی"
? true
: ""
: responseData.hasPartner === false
? false
: responseData.hasPartner === true
? true
: "";
const values = {
first_name: userData.firstName || "",
last_name: userData.lastName || "",
national_id: nationalIdValue,
national_code: isExternalApi
? userData.identityNo || ""
: userData.nationalCode || "",
birth_date: birthDatePersian,
father_name: userData.fatherName || "",
gender: genderValue,
person_city: userData.city || "",
is_alive: isAliveValue,
// Guild fields - will be set per guild in accordion, so we set empty or first guild's data
guild_name: isExternalApi
? guildData.title || ""
: firstGuild.guildsName || "",
area_activity: isExternalApi
? guildData.isicname || ""
: firstGuild.areaActivity || "",
state: isExternalApi ? guildData.state || "" : provinceData.name || "",
city: isExternalApi ? guildData.city || "" : cityData.name || "",
address: isExternalApi
? guildData.address || ""
: addressData.address || "",
license_expire_date: licenseExpireDatePersian,
license_status: isExternalApi
? guildData.licenseStatus || ""
: firstGuild.licenseStatus || "",
license_type: isExternalApi
? guildData.licenseType || ""
: firstGuild.licenseType || "",
license_number: isExternalApi
? guildData.licenseNumber || ""
: firstGuild.licenseNumber || "",
union_name: isExternalApi
? layerTwo.unionName || ""
: firstGuild.unionName || "",
postal_code: isExternalApi
? layerTwo.postalcode || ""
: addressData.postalCode || "",
phone_number: isExternalApi
? layerTwo.phonenumber || ""
: firstGuild.phoneNumber || "",
mobile: isExternalApi ? layerTwo.mobilenumber || "" : userData.mobile || "",
guild_national_id: isExternalApi
? layerTwo.nationalId || ""
: firstGuild.nationalCode || "",
is_foreigner: isForeignerValue,
corporation_name: isExternalApi
? layerTwo.corporationName || ""
: firstGuild.companyName || "",
has_steward: hasStewardValue,
has_partner: hasPartnerValue,
steward: isExternalApi ? false : firstGuild.isSteward || false,
guild: isExternalApi
? typeof guildData.guild === "boolean"
? guildData.guild
: false
: typeof firstGuild.guild === "boolean"
? firstGuild.guild
: false,
license_issue_date: licenseIssueDatePersian,
...(isExternalApi
? {}
: {
company_name: firstGuild.companyName || "",
company_identifier: firstGuild.companyIdentifier || "",
type_activity_name: firstGuild.typeActivity || "",
}),
};
formik.setValues({ ...formik.values, ...values });
};

View File

@@ -1,158 +0,0 @@
import {
convertToIranianTime,
convertPersianToEnglishNumerals,
} from "../../../../../utils/formatTime";
import { fromJalali } from "../../../../../utils/jalali";
export const convertGregorianToPersian = (gregorianDateString) => {
if (!gregorianDateString || typeof gregorianDateString !== "string") {
return "";
}
// Check if the date is already in Persian format (YYYY/MM/DD with year < 1500)
const persianPattern = /^\d{4}\/\d{2}\/\d{2}$/;
if (persianPattern.test(gregorianDateString)) {
const year = parseInt(gregorianDateString.split("/")[0]);
// If year is < 1500, it's likely Persian, return as is
if (year < 1500) {
return gregorianDateString;
}
}
// Try to convert using convertToIranianTime
try {
return convertToIranianTime(gregorianDateString);
} catch (error) {
console.error("Error converting Gregorian date to Persian:", error);
return gregorianDateString; // Return original on error
}
};
export const convertPersianToGregorian = (persianDateString) => {
if (!persianDateString || typeof persianDateString !== "string") {
return "";
}
const normalizedDateString =
convertPersianToEnglishNumerals(persianDateString);
const gregorianPattern = /^\d{4}[-/]\d{2}[-/]\d{2}$/;
if (gregorianPattern.test(normalizedDateString)) {
const year = parseInt(normalizedDateString.split(/[-/]/)[0]);
if (year > 1500) {
return normalizedDateString.replace(/\//g, "-");
}
}
const parts = normalizedDateString.split("/");
if (parts.length !== 3) {
return persianDateString;
}
const py = parseInt(parts[0]);
const pm = parseInt(parts[1]);
const pd = parseInt(parts[2]);
if (isNaN(py) || isNaN(pm) || isNaN(pd)) {
return persianDateString;
}
try {
const gregorianDate = fromJalali(py, pm, pd);
const year = gregorianDate.getFullYear();
const month = String(gregorianDate.getMonth() + 1).padStart(2, "0");
const day = String(gregorianDate.getDate()).padStart(2, "0");
return `${year}-${month}-${day}`;
} catch (error) {
console.error("Error converting Persian date to Gregorian:", error);
return persianDateString;
}
};
export const normalizeExternalApiDate = (dateString) => {
if (!dateString || typeof dateString !== "string") {
return "";
}
return convertPersianToEnglishNumerals(dateString);
};
export const normalizeDatabaseDate = (dateString) => {
if (!dateString || typeof dateString !== "string") {
return "";
}
const first10Chars = dateString.substring(0, 10);
const normalizedDate = first10Chars.replace(/-/g, "/");
return convertToIranianTime(normalizedDate);
};
export const formatDateForSubmitExternal = (dateString) => {
if (!dateString || typeof dateString !== "string") {
return "";
}
return convertPersianToEnglishNumerals(dateString);
};
export const formatDateForSubmitDatabase = (dateString) => {
if (!dateString || typeof dateString !== "string") {
return "";
}
const normalizedDate = convertPersianToEnglishNumerals(dateString);
const persianPattern = /^\d{4}\/\d{2}\/\d{2}$/;
if (persianPattern.test(normalizedDate)) {
const year = parseInt(normalizedDate.split("/")[0]);
if (year < 1500) {
const parts = normalizedDate.split("/");
const py = parseInt(parts[0]);
const pm = parseInt(parts[1]);
const pd = parseInt(parts[2]);
if (!isNaN(py) && !isNaN(pm) && !isNaN(pd)) {
try {
const gregorianDate = fromJalali(py, pm, pd);
const gy = gregorianDate.getFullYear();
const gm = String(gregorianDate.getMonth() + 1).padStart(2, "0");
const gd = String(gregorianDate.getDate()).padStart(2, "0");
return `${gy}/${gm}/${gd}`;
} catch (error) {
console.error("Error converting Persian to Gregorian:", error);
}
}
}
}
const gregorianPattern = /^\d{4}[-/]\d{2}[-/]\d{2}$/;
if (gregorianPattern.test(normalizedDate)) {
const year = parseInt(normalizedDate.split(/[-/]/)[0]);
if (year > 1900) {
return normalizedDate.replace(/-/g, "/");
}
}
try {
const date = new Date(normalizedDate);
if (!isNaN(date.getTime())) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDate()).padStart(2, "0");
return `${year}/${month}/${day}`;
}
} catch (error) {
console.error("Error formatting database date:", error);
}
return normalizedDate.replace(/-/g, "/");
};
export const formatDateForSubmit = (dateString, isExternalApi = false) => {
if (!dateString || typeof dateString !== "string") {
return "";
}
if (isExternalApi) {
return formatDateForSubmitExternal(dateString);
} else {
return formatDateForSubmitDatabase(dateString);
}
};

View File

@@ -1,95 +0,0 @@
import * as yup from "yup";
import { normalizeDatabaseDate } from "./dateUtils";
export const getValidationSchema = (isEditMode) =>
yup.object({
national_id: yup
.string()
.required("کد ملی الزامی است")
.matches(/^[0-9]{10}$/, "کد ملی باید 10 رقم باشد"),
mobile: isEditMode
? yup
.string()
.nullable()
.test(
"mobile-format",
"شماره تلفن باید 11 رقم باشد",
(value) => !value || /^[0-9]{11}$/.test(value)
)
: yup
.string()
.required("شماره تلفن الزامی است")
.matches(/^[0-9]{11}$/, "شماره تلفن باید 11 رقم باشد"),
first_name: yup.string(),
last_name: yup.string(),
guild_name: yup.string(),
guild_category: yup.string(),
state: yup.string(),
city: yup.string(),
address: yup.string(),
license_expire_date: yup.string(),
license_status: yup.string(),
union_name: yup.string(),
postal_code: yup.string(),
guild_national_id: yup.string(),
is_foreigner: yup.string(),
national_code: yup.string(),
has_steward: yup.string(),
has_partner: yup.string(),
license_number: yup.string(),
isAccepted: yup
.boolean()
.test("req", "باید تعهد نامه را بپذیرید!", (val) => {
return val === true;
})
.required("این فیلد اجباری است!"),
});
export const getInitialValues = (guild) => ({
first_name: guild?.user?.firstName || "",
last_name: guild?.user?.lastName || "",
corporation_name: guild?.companyName || "",
national_id: guild?.user?.nationalId || "",
national_code: guild?.user?.nationalCode || "",
birth_date: normalizeDatabaseDate(guild?.user?.birthday || ""),
father_name: guild?.user?.fatherName || "",
gender: guild?.user?.gender || "",
person_city: guild?.user?.city || "",
is_alive: guild?.user?.isAlive || "",
guild_name: guild?.guildsName || "",
area_activity: guild?.areaActivity || "",
state: guild?.address?.province?.name || "",
city: guild?.address?.city?.name || "",
address: guild?.address?.address || "",
license_expire_date: normalizeDatabaseDate(guild?.licenseExpireDate || ""),
license_status: guild?.licenseStatus || "",
license_type: guild?.licenseType || "",
union_name: guild?.unionName || "",
postal_code: guild?.address?.postalCode || "",
phone_number: guild?.phoneNumber || "",
mobile: guild?.user?.mobile || "",
is_foreigner: guild?.is_foreign_national || "",
has_steward: guild?.hasSteward || "",
has_partner: guild?.hasPartner || "",
license_number: guild?.licenseNumber || "",
isAccepted: guild?.provinceAcceptState === "accepted" || false,
steward:
typeof guild?.steward === "boolean"
? guild.steward
: typeof guild?.isSteward === "boolean"
? guild.isSteward
: false,
guild:
typeof guild?.guild === "boolean"
? guild.guild
: typeof guild?.isGuild === "boolean"
? guild.isGuild
: false,
verify_mobile: guild?.verifyMobile || false,
guild_national_id: guild?.nationalId || "",
license_issue_date: normalizeDatabaseDate(guild?.licenseIssueDate || ""),
company_name: guild?.companyName || "",
company_identifier: guild?.companyIdentifier || "",
type_activity_name: guild?.typeActivityName || "",
active: guild?.active ?? null,
});

View File

@@ -1,45 +0,0 @@
import {
CLOSE_MODAL,
OPEN_MODAL,
} from "../../../../../lib/redux/slices/appSlice";
import { ProvinceManageGuildsSubmitRegisterCode } from "../../province-manage-guilds-submit-register-code/ProvinceManageGuildsSubmitRegisterCode";
export const handleSubmitSuccess = (
dispatch,
openNotif,
updateTable,
values,
responseData
) => {
updateTable();
openNotif({
vertical: "top",
horizontal: "center",
msg: "عملیات با موفقیت انجام شد.",
severity: "success",
});
dispatch(CLOSE_MODAL());
if (values.verify_mobile && responseData) {
dispatch(
OPEN_MODAL({
title: "ثبت کد احراز",
content: (
<ProvinceManageGuildsSubmitRegisterCode
item={responseData}
updateTable={updateTable}
/>
),
})
);
}
};
export const handleSubmitError = (openNotif, error) => {
openNotif({
vertical: "top",
horizontal: "center",
msg: error,
severity: "error",
});
};

View File

@@ -19,7 +19,6 @@ import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
import { provinceChangeActiveGuildService } from "../../services/province-change-active-guild";
import { provinceGetBuyersService } from "../../services/province-get-buyers";
import { provinceGetStewardsService } from "../../services/province-get-stewards";
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
const validationSchema = Yup.object().shape({
// agreed: Yup.boolean().oneOf([true], 'You must agree to the terms and conditions'),
@@ -29,9 +28,6 @@ export const GuildLimitaion = ({ guild, updateTable }) => {
const { provinceGetStewardsOptions, provinceGetBuyersOptions } = useSelector(
(state) => state.provinceSlice
);
const selectedSubUser = useSelector(
(state) => state.userSlice.selectedSubUser
);
const [warehouses, setWarehouses] = useState(
guild.centersAllocation ? guild.centersAllocation : []
);
@@ -81,21 +77,9 @@ export const GuildLimitaion = ({ guild, updateTable }) => {
});
useEffect(() => {
dispatch(
provinceGetStewardsService({
role_key: checkPathStartsWith("province")
? selectedSubUser?.key || ""
: "",
})
);
dispatch(
provinceGetBuyersService({
role_key: checkPathStartsWith("province")
? selectedSubUser?.key || ""
: "",
})
);
}, [selectedSubUser?.key]);
dispatch(provinceGetStewardsService());
dispatch(provinceGetBuyersService());
}, []);
return (
<form onSubmit={formik.handleSubmit} style={{ width: "100%" }}>
@@ -161,7 +145,7 @@ export const GuildLimitaion = ({ guild, updateTable }) => {
{!warehouses.length && (
<Typography variant="caption">محدودیتی وجود ندارد</Typography>
)}
{warehouses?.map((item) => {
{warehouses?.map((item, i) => {
return (
<>
{item !== null && (
@@ -220,7 +204,7 @@ export const GuildLimitaion = ({ guild, updateTable }) => {
{!buyers.length && (
<Typography variant="caption">محدودیتی وجود ندارد</Typography>
)}
{buyers?.map((item) => {
{buyers?.map((item, i) => {
return (
<>
{item !== null && (

View File

@@ -4,19 +4,25 @@ import { NavLink } from "../../../../components/nav-link/NavLink";
import { useLocation } from "react-router-dom";
import {
// ROUTE_ADMINX_ROUTE_GUILDS,
ROUTE_ADMINX_ROUTE_IN_PROVINCE_GUILDS_DISTRIBUTIONS,
ROUTE_ADMINX_ROUTE_IN_PROVINCE_GUILDS_REQUESTS,
ROUTE_ADMINX_ROUTE_IN_PROVINCE_GUILDS,
ROUTE_ADMINX_ROUTE_MANAGE_GUILDS,
ROUTE_ADMINX_ROUTE_OUT_PROVINCE_GUILDS,
ROUTE_ADMINX_ROUTE_IN_PROVINCE_STEWARDS,
ROUTE_PROVINCE_ROUTE_GUILDS,
ROUTE_PROVINCE_ROUTE_IN_PROVINCE_GUILDS_REQUESTS,
ROUTE_PROVINCE_ROUTE_IN_PROVINCE_GUILDS,
ROUTE_PROVINCE_ROUTE_MANAGE_GUILDS,
ROUTE_PROVINCE_ROUTE_OUT_PROVINCE_GUILDS,
ROUTE_PROVINCE_ROUTE_IN_PROVINCE_STEWARDS,
// ROUTE_SUPER_ADMIN_ROUTE_GUILDS,
ROUTE_SUPER_ADMIN_ROUTE_IN_PROVINCE_GUILDS_DISTRIBUTIONS,
ROUTE_SUPER_ADMIN_ROUTE_IN_PROVINCE_GUILDS_REQUESTS,
ROUTE_SUPER_ADMIN_ROUTE_IN_PROVINCE_GUILDS,
ROUTE_SUPER_ADMIN_ROUTE_MANAGE_GUILDS,
ROUTE_SUPER_ADMIN_ROUTE_OUT_PROVINCE_GUILDS,
ROUTE_SUPER_ADMIN_ROUTE_IN_PROVINCE_STEWARDS,
ROUTE_SUPER_ADMIN_ROUTE_OUT_PROVINCE_TRUE_GUILDS,
ROUTE_ADMINX_ROUTE_OUT_PROVINCE_TRUE_GUILDS,
ROUTE_PROVINCE_ROUTE_OUT_PROVINCE_TRUE_GUILDS,
@@ -32,7 +38,9 @@ import {
} from "../../../../routes/routes";
import LinkItem from "../../../../components/link-item/LinkItem";
import { MdCorporateFare } from "react-icons/md";
import { IoIosPeople } from "react-icons/io";
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
import { VscLiveShare } from "react-icons/vsc";
import { BackButton } from "../../../../components/back-button/BackButton";
export const GuildsOperations = () => {
@@ -156,7 +164,7 @@ export const GuildsOperations = () => {
title="اصناف حقوقی"
/>
</NavLink>
{/* <NavLink
<NavLink
to={
getRoleFromUrl() === "SuperAdmin"
? ROUTE_SUPER_ADMIN_ROUTE_IN_PROVINCE_STEWARDS
@@ -191,7 +199,7 @@ export const GuildsOperations = () => {
title="مدیریت مباشرین"
/>
</NavLink>
)} */}
)}
</>
)}

View File

@@ -315,7 +315,7 @@ export const ManageGuildDistributions = () => {
return (
<Grid container xs={12} justifyContent="center" alignItems="center" gap={2}>
<Grid container mt={2} mb={4} isDashboard xs={12}>
<Grid container mt={2} mb={4} isDashboard>
<ResponsiveTable
noPagination
isDashboard

View File

@@ -1,5 +1,12 @@
import React, { useEffect, useState } from "react";
import { Button, TextField, Tooltip, MenuItem } from "@mui/material";
import {
Button,
Checkbox,
FormControlLabel,
TextField,
Tooltip,
MenuItem,
} from "@mui/material";
import { useDispatch, useSelector } from "react-redux";
import axios from "axios";
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
@@ -12,24 +19,22 @@ import { RiFileExcel2Fill, RiSearchLine } from "react-icons/ri";
import { SPACING } from "../../../../data/spacing";
import { SimpleTable } from "../../../../components/simple-table/SimpleTable";
import { CreateGuilds } from "../create-guilds/CreateGuilds";
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
export const MaangeGuilds = () => {
const userKey = useSelector((state) => state.userSlice?.userProfile?.key);
const dispatch = useDispatch();
const selectedSubUser = useSelector(
(state) => state.userSlice.selectedSubUser
);
const [data, setData] = useState([]);
const [totalRows, setTotalRows] = useState(0);
const [perPage, setPerPage] = useState(10);
const [textValue, setTextValue] = useState("");
const [page, setPage] = useState(1);
const [tableData, setTableData] = useState([]);
const [isSteward, setIsSteward] = useState(false);
const [activeState, setActiveState] = useState("active");
const handleTextChange = (e) => setTextValue(e.target.value);
// const handleCheckboxChange = () => setIsSteward(!isSteward);
const handleCheckboxChange = () => setIsSteward(!isSteward);
const fetchApiData = async (page) => {
const response = await dispatch(
@@ -38,12 +43,9 @@ export const MaangeGuilds = () => {
value: textValue,
page: page,
page_size: perPage,
steward: false,
steward: isSteward,
active_state: activeState,
is_real_person: true,
role_key: checkPathStartsWith("province")
? selectedSubUser?.key || ""
: "",
})
);
@@ -73,7 +75,7 @@ export const MaangeGuilds = () => {
useEffect(() => {
fetchApiData(1);
}, [perPage, selectedSubUser?.key, activeState]);
}, [dispatch, isSteward, activeState]);
useEffect(() => {
if (!data || !Array.isArray(data)) {
@@ -205,6 +207,10 @@ export const MaangeGuilds = () => {
setTableData(d);
}, [data]);
useEffect(() => {
fetchApiData(1);
}, [perPage]);
const handleSubmit = async (e) => {
e.preventDefault();
const response = await dispatch(
@@ -213,12 +219,9 @@ export const MaangeGuilds = () => {
value: textValue,
page: page,
page_size: perPage,
steward: false,
steward: isSteward,
active_state: activeState,
is_real_person: true,
role_key: checkPathStartsWith("province")
? selectedSubUser?.key || ""
: "",
})
);
@@ -250,7 +253,7 @@ export const MaangeGuilds = () => {
>
<form onSubmit={handleSubmit}>
<Grid container alignItems="center" gap={SPACING.SMALL}>
{["KillHouse", "GuildRoom"].includes(getRoleFromUrl()) && (
{["GuildRoom", "KillHouse"].includes(getRoleFromUrl()) && (
<Button
variant="contained"
onClick={() => {
@@ -278,7 +281,7 @@ export const MaangeGuilds = () => {
onChange={handleTextChange}
/>
{/* <FormControlLabel
<FormControlLabel
style={{ marginRight: 4 }}
control={
<Checkbox
@@ -289,7 +292,7 @@ export const MaangeGuilds = () => {
/>
}
label="نمایش مباشرین"
/> */}
/>
{getRoleFromUrl() !== "KillHouse" && (
<TextField
select
@@ -320,11 +323,7 @@ export const MaangeGuilds = () => {
<a
href={`${
axios.defaults.baseURL
}guilds_excel/?key=${userKey}&search=filter&value=${textValue}&role=${getRoleFromUrl()}${
checkPathStartsWith("province")
? `&role_key=${selectedSubUser?.key}`
: ""
}&active_state=${activeState}`}
}guilds_excel/?key=${userKey}&search=filter&value=${textValue}&role=${getRoleFromUrl()}&active_state=${activeState}`}
rel="noreferrer"
>
<Button color="success">

View File

@@ -583,7 +583,7 @@ export const ManagePoultries = () => {
</Tooltip>
</Grid>
<Grid container mt={2} mb={4} isDashboard xs={12}>
<Grid container mt={2} mb={4} isDashboard>
<ResponsiveTable
noPagination
isDashboard

View File

@@ -427,7 +427,7 @@ export const PoultriesDetails = () => {
</Tabs>
</Grid>
{dashboardData && (
<Grid container mt={2} mb={4} isDashboard xs={12}>
<Grid container mt={2} mb={4} isDashboard>
<ResponsiveTable
noPagination
isDashboard

View File

@@ -56,8 +56,9 @@ export const ProvinceAllocateRequests = () => {
const fetchApiData = async (page) => {
dispatch(getPoultryRequestsTotalQuantityService(selectedDate1)).then(
async () => {
let response;
dispatch(LOADING_START());
const response = await axios.get(
response = await axios.get(
`city_operator_check_request_new/?state=waiting&date=${selectedDate1}&page=${page}&page_size=${perPage}&search=filter&value=${
textValue ? textValue : ""
}`
@@ -298,9 +299,6 @@ export const ProvinceAllocateRequests = () => {
))}
</Grid>
<Box
sx={{
width: "100%",
}}
px={{
xs: 1,
sm: 0,

View File

@@ -24,16 +24,13 @@ import { ProvinceGetDeletedAllocatedRequests } from "../province-get-deleted-all
import { provinceGetDashboardKillRequestService } from "../../services/get-dahsnoard-province-kill-request";
import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable";
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
export const ProvinceAllocatedRequests = () => {
const dispatch = useDispatch();
const [dataTable, setDataTable] = useState();
const [hasDocumentState, setHasDocumentState] = useState(false);
const [selectedTab, setSelectedTab] = useState(0);
const selectedSubUser = useSelector(
(state) => state.userSlice.selectedSubUser
);
const userKey = useSelector((state) => state.userSlice.userProfile.key);
const [textValue, setTextValue] = useState("");
@@ -47,9 +44,6 @@ export const ProvinceAllocatedRequests = () => {
dispatch(
provinceGetAllocatedRequestsService({
role_key: checkPathStartsWith("province")
? selectedSubUser?.key || ""
: "",
selectedDate1,
selectedDate2,
textValue,
@@ -84,9 +78,6 @@ export const ProvinceAllocatedRequests = () => {
selectedDate2,
textValue,
hasDocumentState: checked,
role_key: checkPathStartsWith("province")
? selectedSubUser?.key || ""
: "",
};
dispatch(provinceGetDashboardKillRequestService(params)).then((r) => {
@@ -98,9 +89,6 @@ export const ProvinceAllocatedRequests = () => {
if (selectedTab === 0) {
dispatch(
provinceGetAllocatedRequestsService({
role_key: checkPathStartsWith("province")
? selectedSubUser?.key || ""
: "",
selectedDate1,
selectedDate2,
textValue,
@@ -109,15 +97,12 @@ export const ProvinceAllocatedRequests = () => {
);
fetchDashboard();
}
}, [selectedDate1, selectedDate2, selectedTab, selectedSubUser?.key]);
}, [selectedDate1, selectedDate2, selectedTab]);
const handleSubmit = () => {
if (selectedTab === 0) {
dispatch(
provinceGetAllocatedRequestsService({
role_key: checkPathStartsWith("province")
? selectedSubUser?.key || ""
: "",
selectedDate1,
selectedDate2,
textValue,
@@ -287,11 +272,7 @@ export const ProvinceAllocatedRequests = () => {
<a
href={`${
axios.defaults.baseURL
}allocated_excel/?start=${selectedDate1}&end=${selectedDate2}&role=${getRoleFromUrl()}${
checkPathStartsWith("province")
? `&role_key=${selectedSubUser?.key}`
: ""
}&key=${userKey}&filter=search&value=${textValue}`}
}allocated_excel/?start=${selectedDate1}&end=${selectedDate2}&role=${getRoleFromUrl()}&key=${userKey}&filter=search&value=${textValue}`}
rel="noreferrer"
>
<Button color="success">
@@ -312,7 +293,7 @@ export const ProvinceAllocatedRequests = () => {
/>
</Grid>
<Grid container mt={2} mb={4} isDashboard xs={12}>
<Grid container mt={2} mb={4} isDashboard>
<ResponsiveTable
noPagination
isDashboard

View File

@@ -3,7 +3,7 @@ import { DatePicker } from "@mui/x-date-pickers";
import moment from "moment/moment";
import { useContext, useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable";
import { AdvancedTable } from "../../../../components/advanced-table/AdvancedTable";
import { Grid } from "../../../../components/grid/Grid";
import { AppContext } from "../../../../contexts/AppContext";
import { SPACING } from "../../../../data/spacing";
@@ -62,7 +62,8 @@ export const ProvinceAutoAllocationArchive = () => {
return (
<Grid mt={SPACING.SMALL} xs={12} px={2}>
{!isSingleView && (
<>
<AdvancedTable
name={
<Grid container alignItems="center" gap={SPACING.SMALL} mb={2}>
<Grid>
<Typography>بایگانی تخصیصات خودکار</Typography>
@@ -94,8 +95,7 @@ export const ProvinceAutoAllocationArchive = () => {
/>
</Grid>
</Grid>
<ResponsiveTable
title="بایگانی تخصیصات خودکار"
}
columns={[
"ردیف",
"کد تخصیص خودکار",
@@ -108,7 +108,6 @@ export const ProvinceAutoAllocationArchive = () => {
]}
data={dataTable}
/>
</>
)}
{isSingleView && (

View File

@@ -1,6 +1,6 @@
import React, { useContext, useEffect, useState } from "react";
import { Button, IconButton, TextField } from "@mui/material";
import { useDispatch, useSelector } from "react-redux";
import { useDispatch } from "react-redux";
import axios from "axios";
import { RiSearchLine } from "react-icons/ri";
import { DatePicker } from "@mui/x-date-pickers";
@@ -21,7 +21,6 @@ import { ProvinceBarDifferencesOperations } from "../province-bar-differences-op
// import EmailIcon from "@mui/icons-material/Email";
import { provinceGetDashboardBarDiffrenceRequest } from "../../services/province-dashboard-bar-diffrence-get-request";
import { ProvinceBarDifferencesModal } from "../province-bar-differences-modal/ProvinceBarDifferencesModal";
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
export const ProvinceBarDifferenceRequests = ({ state }) => {
const dispatch = useDispatch();
@@ -34,18 +33,12 @@ export const ProvinceBarDifferenceRequests = ({ state }) => {
const [page, setPage] = useState(1);
const [tableData, setTableData] = useState([]);
const [dashboardData, setDashboardData] = useState([]);
const selectedSubUser = useSelector(
(state) => state.userSlice.selectedSubUser
);
const fetchApiData = async (page) => {
dispatch(LOADING_START());
try {
const response = await axios.get(
`bar-difference-request/?search=filter&value=${textValue}&role=${getRoleFromUrl()}${
checkPathStartsWith("province")
? `&role_key=${selectedSubUser?.key}`
: ""
}&page=${page}&page_size=${perPage}&state=${state}&date1=${selectedDate1}&date2=${selectedDate2}`
`bar-difference-request/?search=filter&value=${textValue}&role=${getRoleFromUrl()}&page=${page}&page_size=${perPage}&state=${state}&date1=${selectedDate1}&date2=${selectedDate2}`
);
setData(response.data.results);
setTotalRows(response.data.count);
@@ -60,9 +53,6 @@ export const ProvinceBarDifferenceRequests = ({ state }) => {
dispatch(
provinceGetDashboardBarDiffrenceRequest({
role: getRoleFromUrl(),
role_key: checkPathStartsWith("slaughter")
? selectedSubUser?.key || ""
: "",
state: state,
filter: "search",
value: textValue,
@@ -156,7 +146,7 @@ export const ProvinceBarDifferenceRequests = ({ state }) => {
useEffect(() => {
fetchApiData(1);
fetchDashboardData();
}, [state, perPage, selectedDate1, selectedDate2, selectedSubUser?.key]);
}, [state, perPage, selectedDate1, selectedDate2]);
const handleTextChange = (event) => {
setTextValue(event.target.value);
@@ -177,7 +167,7 @@ export const ProvinceBarDifferenceRequests = ({ state }) => {
alignItems="center"
gap={2}
>
<Grid container mt={2} mb={4} isDashboard xs={12}>
<Grid container mt={2} mb={4} isDashboard>
<ResponsiveTable
noPagination
isDashboard

View File

@@ -130,7 +130,7 @@ export const ProvinceBuyersAllocations = () => {
</a>
</Tooltip>
</Grid>
<Grid mb={SPACING.SMALL} isDashboard xs={12}>
<Grid mb={SPACING.SMALL} isDashboard>
<ResponsiveTable
noPagination
isDashboard

View File

@@ -196,7 +196,7 @@ export const ProvinceChickenDistributionsAndSales = () => {
return (
<Grid container xs={12} justifyContent="center" alignItems="center" gap={2}>
<Grid container mt={2} mb={4} isDashboard xs={12}>
<Grid container mt={2} mb={4} isDashboard>
<ResponsiveTable
noPagination
isDashboard

View File

@@ -172,7 +172,7 @@ export const ProvinceChickenStewardSales = () => {
return (
<Grid container xs={12} justifyContent="center" alignItems="center" gap={2}>
<Grid container mt={2} mb={4} isDashboard xs={12}>
<Grid container mt={2} mb={4} isDashboard>
<ResponsiveTable
noPagination
isDashboard

View File

@@ -89,9 +89,9 @@ export const ProvinceDispenserAcceptedSaleWithInProvince = ({ priceInfo }) => {
item?.toKillHouse?.killHouseOperator?.user?.fullname || "-"
} (${item?.toKillHouse?.killHouseOperator?.user?.mobile || "-"})`;
case "killhouse_steward":
return `${item?.toStewards?.name || "-"} - ${
item?.toStewards?.user?.fullname || "-"
} (${item?.toStewards?.user?.mobile || "-"})`;
return `${item?.toSteward?.guildsName || "-"} - ${
item?.toSteward?.user?.fullname || "-"
} (${item?.toSteward?.user?.mobile || "-"})`;
case "killhouse_guild":
return `${item?.toGuilds?.guildsName || "-"} - ${
item?.toGuilds?.user?.fullname || "-"

View File

@@ -89,9 +89,9 @@ export const ProvinceDispenserRejectedSaleWithInProvince = ({ priceInfo }) => {
item?.toKillHouse?.killHouseOperator?.user?.fullname || "-"
} (${item?.toKillHouse?.killHouseOperator?.user?.mobile || "-"})`;
case "killhouse_steward":
return `${item?.toStewards?.name || "-"} - ${
item?.toStewards?.user?.fullname || "-"
} (${item?.toStewards?.user?.mobile || "-"})`;
return `${item?.toSteward?.guildsName || "-"} - ${
item?.toSteward?.user?.fullname || "-"
} (${item?.toSteward?.user?.mobile || "-"})`;
case "killhouse_guild":
return `${item?.toGuilds?.guildsName || "-"} - ${
item?.toGuilds?.user?.fullname || "-"

View File

@@ -88,9 +88,9 @@ export const ProvinceDispenserReturnedSaleWithInProvince = ({ priceInfo }) => {
item?.toKillHouse?.killHouseOperator?.user?.fullname || "-"
} (${item?.toKillHouse?.killHouseOperator?.user?.mobile || "-"})`;
case "killhouse_steward":
return `${item?.toStewards?.name || "-"} - ${
item?.toStewards?.user?.fullname || "-"
} (${item?.toStewards?.user?.mobile || "-"})`;
return `${item?.toSteward?.guildsName || "-"} - ${
item?.toSteward?.user?.fullname || "-"
} (${item?.toSteward?.user?.mobile || "-"})`;
case "killhouse_guild":
return `${item?.toGuilds?.guildsName || "-"} - ${
item?.toGuilds?.user?.fullname || "-"

View File

@@ -144,7 +144,7 @@ export const ProvinceDispenserSegmentation = ({
gap={2}
mt={4}
>
<Grid container width="100%" isDashboard xs={12}>
<Grid container width="100%" isDashboard>
<ResponsiveTable
noPagination
isDashboard

View File

@@ -102,7 +102,7 @@ export const ProvinceDispensersSellCarcassSellOut = () => {
</Tooltip> */}
</Grid>
<Grid container xs={12} mt={2} mb={4} isDashboard xs={12}>
<Grid container xs={12} mt={2} mb={4} isDashboard>
<ResponsiveTable
noPagination
isDashboard

View File

@@ -220,7 +220,7 @@ export const ProvinceFreeSalesTransactions = () => {
</Tooltip>
</Grid>
</Grid>
<Grid container mt={2} mb={4} isDashboard xs={12}>
<Grid container mt={2} mb={4} isDashboard>
<ResponsiveTable
noPagination
isDashboard

View File

@@ -14,16 +14,13 @@ import ResponsiveTable from "../../../../components/responsive-table/ResponsiveT
import { provinceGetDashboardDeletedKillRequestService } from "../../services/get-dahsnoard-province-kill-request";
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
import { RiSearchLine } from "react-icons/ri";
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
export const ProvinceGetDeletedAllocatedRequests = () => {
const dispatch = useDispatch();
const [dataTable, setDataTable] = useState();
const [, , selectedDate1, setSelectedDate1, selectedDate2, setSelectedDate2] =
useContext(AppContext);
const selectedSubUser = useSelector(
(state) => state.userSlice.selectedSubUser
);
const userKey = useSelector((state) => state.userSlice.userProfile.key);
useEffect(() => {
@@ -45,22 +42,16 @@ export const ProvinceGetDeletedAllocatedRequests = () => {
useEffect(() => {
dispatch(
provinceGetDeletedAllocatedRequestsService({
role_key: checkPathStartsWith("slaughter")
? selectedSubUser?.key || ""
: "",
selectedDate1,
selectedDate2,
textValue,
})
);
}, [selectedDate1, selectedDate2, selectedSubUser?.key]);
}, [selectedDate1, selectedDate2]);
const handleSubmit = () => {
dispatch(
provinceGetDeletedAllocatedRequestsService({
role_key: checkPathStartsWith("slaughter")
? selectedSubUser?.key || ""
: "",
selectedDate1,
selectedDate2,
textValue,
@@ -72,9 +63,6 @@ export const ProvinceGetDeletedAllocatedRequests = () => {
selectedDate1,
selectedDate2,
textValue,
role_key: checkPathStartsWith("slaughter")
? selectedSubUser?.key || ""
: "",
})
).then((r) => {
setDashboardData(r.payload.data);
@@ -122,14 +110,11 @@ export const ProvinceGetDeletedAllocatedRequests = () => {
selectedDate1,
selectedDate2,
textValue,
role_key: checkPathStartsWith("slaughter")
? selectedSubUser?.key || ""
: "",
})
).then((r) => {
setDashboardData(r.payload.data);
});
}, [selectedDate1, selectedDate2, selectedSubUser?.key]);
}, [selectedDate1, selectedDate2]);
return (
<Grid>
@@ -185,11 +170,7 @@ export const ProvinceGetDeletedAllocatedRequests = () => {
<a
href={`${
axios.defaults.baseURL
}allocated_excel/?start=${selectedDate1}&end=${selectedDate2}&type=deleted&role=${getRoleFromUrl()}${
checkPathStartsWith("province")
? `&role_key=${selectedSubUser?.key}`
: ""
}&key=${userKey}&filter=search&value=${textValue}`}
}allocated_excel/?start=${selectedDate1}&end=${selectedDate2}&type=deleted&role=${getRoleFromUrl()}&key=${userKey}&filter=search&value=${textValue}`}
rel="noreferrer"
>
<Button color="success">
@@ -199,7 +180,7 @@ export const ProvinceGetDeletedAllocatedRequests = () => {
</Tooltip>
</Grid>
<Grid container mt={2} mb={4} isDashboard xs={12}>
<Grid container mt={2} mb={4} isDashboard>
<ResponsiveTable
noPagination
isDashboard

View File

@@ -37,7 +37,6 @@ import EditOutlinedIcon from "@mui/icons-material/EditOutlined";
import DeleteOutlineIcon from "@mui/icons-material/DeleteOutline";
import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable";
import { provinceCarsDashboardService } from "../../services/province-cars-dashboard";
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
export const ProvinceManageCars = () => {
const dispatch = useDispatch();
@@ -46,32 +45,18 @@ export const ProvinceManageCars = () => {
const { provinceCars } = useSelector((state) => state.provinceSlice);
// const userInfo = useSelector((state) => state.userSlice);
const userKey = useSelector((state) => state.userSlice.userProfile.key);
const selectedSubUser = useSelector(
(state) => state.userSlice.selectedSubUser
);
useEffect(() => {
dispatch(
provinceGetCars({
role_key: checkPathStartsWith("province")
? selectedSubUser?.key || ""
: "",
})
);
}, [selectedSubUser?.key]);
dispatch(provinceGetCars());
}, []);
const [dashboardData, setDashboardData] = useState([]);
useEffect(() => {
dispatch(
provinceCarsDashboardService({
role_key: checkPathStartsWith("province")
? selectedSubUser?.key || ""
: "",
})
).then((r) => {
dispatch(provinceCarsDashboardService()).then((r) => {
setDashboardData(r.payload.data);
});
}, [dispatch, provinceCars, selectedSubUser?.key]);
}, [dispatch, provinceCars]);
useEffect(() => {
const d = provinceCars?.map((item, i) => {
@@ -162,11 +147,7 @@ export const ProvinceManageCars = () => {
<a
href={`${
axios.defaults.baseURL
}car_province_excel/?key=${userKey}&role=${getRoleFromUrl()}${
checkPathStartsWith("province")
? `&role_key=${selectedSubUser?.key}`
: ""
}`}
}car_province_excel/?key=${userKey}&role=${getRoleFromUrl()}`}
rel="noreferrer"
>
<Button color="success">
@@ -175,7 +156,7 @@ export const ProvinceManageCars = () => {
</a>
</Tooltip>
<Card sx={{ width: "100%" }}>
<Grid container mt={2} mb={4} isDashboard xs={12}>
<Grid container mt={2} mb={4} isDashboard>
<ResponsiveTable
noPagination
isDashboard

View File

@@ -60,7 +60,7 @@ export const ProvinceManageContradictions = () => {
};
const userInfo = useSelector((state) => state.userSlice);
const setPdfOptions = () => {
const setPdfOptions = (item) => {
dispatch(LOADING_START());
dispatch(
provinceGetContradictionsData({ selectedDate1, selectedDate2 })

View File

@@ -425,7 +425,7 @@ export const ProvinceNationalInfoSlaughterhouse = () => {
</Tooltip>
</Grid>
</Grid>
<Grid container mt={2} mb={4} isDashboard xs={12}>
<Grid container mt={2} mb={4} isDashboard>
<ResponsiveTable
noPagination
isDashboard

View File

@@ -278,7 +278,7 @@ export const ProvinceNationalInfoFarm = () => {
</Grid>
</Grid>
<Grid container mt={2} mb={4} isDashboard xs={12}>
<Grid container mt={2} mb={4} isDashboard>
<ResponsiveTable
noPagination
isDashboard

Some files were not shown because too many files have changed in this diff Show More