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

View File

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

View File

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

View File

@@ -224,7 +224,7 @@ const ResponsiveTable = ({
justifyContent="space-between" justifyContent="space-between"
xs={12} xs={12}
style={{ style={{
width: "100%", width: "85vw",
}} }}
> >
<Grid gap={2} alignItems="center"> <Grid gap={2} alignItems="center">
@@ -442,7 +442,7 @@ const ResponsiveTable = ({
id="startoftable" id="startoftable"
display={{ xs: "none", sm: "grid" }} display={{ xs: "none", sm: "grid" }}
style={{ style={{
width: customWidth ? customWidth : "100%", width: customWidth ? customWidth : "85vw",
}} }}
> >
<TableContainer <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 = const filteredData =
Array.isArray(avicultureRequests) && Array.isArray(avicultureRequests) &&
avicultureRequests?.filter( avicultureRequests?.filter(
(item) => (item, i) =>
(item.stateProcess === "accepted" || (item.stateProcess === "accepted" ||
item.stateProcess === "pending") && item.stateProcess === "pending") &&
item.finalState !== "archive" item.finalState !== "archive"

View File

@@ -365,7 +365,7 @@ export const AvicultureFreeSaleNewRequest = () => {
useEffect(() => { useEffect(() => {
if (poultryKey) { if (poultryKey) {
dispatch(LOADING_START()); dispatch(LOADING_START());
dispatch(avicultureGetHatchingData({ key: poultryKey })).then((r) => { dispatch(avicultureGetHatchingData(poultryKey)).then((r) => {
if (r.payload.data) { if (r.payload.data) {
setHatchingData(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; const number = arr.length - 1;
if (number !== 0) { if (number !== 0) {
@@ -381,7 +381,7 @@ export const AvicultureNewRequest = () => {
useEffect(() => { useEffect(() => {
if (poultryKey) { if (poultryKey) {
dispatch(LOADING_START()); dispatch(LOADING_START());
dispatch(avicultureGetHatchingData({ key: poultryKey })).then((r) => { dispatch(avicultureGetHatchingData(poultryKey)).then((r) => {
if (r.payload.data) { if (r.payload.data) {
setHatchingData(r.payload.data); setHatchingData(r.payload.data);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -30,8 +30,9 @@ export const CityIncreaseHatching = ({ state }) => {
const [tableData, setTableData] = useState([]); const [tableData, setTableData] = useState([]);
const fetchApiData = async (page) => { const fetchApiData = async (page) => {
let response;
dispatch(LOADING_START()); 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}` `hatching-increase-request/?search=filter&value=${textValue}&role=${getRoleFromUrl()}&page=${page}&page_size=${perPage}`
); );
dispatch(LOADING_END()); 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) { if (r.payload.data) {
setHatchingData(r.payload.data); setHatchingData(r.payload.data);
} else { } else {

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,74 +1,17 @@
import { Box, Typography } from "@mui/material"; import { Box, Typography } from "@mui/material";
import { SPACING } from "../../../../data/spacing"; 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 }) => ( export const DailykillingReport = ({ boxStats }) => (
<Box <Box
sx={{ sx={{
width: "100%", flex: "1 1 30%",
minWidth: {
md: "620px",
},
maxWidth: {
md: "32%",
},
borderRadius: 2, borderRadius: 2,
border: "1px solid", border: "1px solid",
borderColor: "divider", borderColor: "divider",
@@ -77,16 +20,18 @@ export const DailykillingReport = ({ boxStats }) => (
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
gap: 2, gap: 2,
height: "600px",
}} }}
> >
<Typography <Typography
textAlign="start" textAlign="start"
variant="subtitle1" variant="h6"
color="text.primary" sx={{ fontSize: { xs: "1rem", lg: "1rem" } }}
sx={{ fontWeight: 600, fontSize: "1rem" }} color="primary.main"
> >
گزارش کشتار امروز مرغ گوشتی استان گزارش کشتار امروز مرغ گوشتی استان
</Typography> </Typography>
<Box <Box
sx={{ sx={{
display: "flex", display: "flex",
@@ -94,16 +39,439 @@ export const DailykillingReport = ({ boxStats }) => (
gap: 1, gap: 1,
overflowY: "auto", overflowY: "auto",
flex: 1, flex: 1,
maxHeight: "500px",
}} }}
> >
{reportItems.map((item) => ( <Box
<ReportRow sx={{
key={item.key} display: "flex",
label={item.label} justifyContent: "space-between",
value={boxStats?.killing?.[item.key]} 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>
</Box> </Box>
); );

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,80 +1,17 @@
import { Box, Typography } from "@mui/material"; import { Box, Typography } from "@mui/material";
import { SPACING } from "../../../../data/spacing"; 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 }) => ( export const YesterdayKillingReport = ({ boxStats }) => (
<Box <Box
sx={{ sx={{
width: "100%", flex: "1 1 20%",
minWidth: {
md: "500px",
},
maxWidth: {
md: "25%",
},
borderRadius: 2, borderRadius: 2,
border: "1px solid", border: "1px solid",
borderColor: "divider", borderColor: "divider",
@@ -83,14 +20,10 @@ export const YesterdayKillingReport = ({ boxStats }) => (
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
gap: 2, gap: 2,
height: "700px",
}} }}
> >
<Typography <Typography textAlign="start" variant="h6" color="primary.main">
textAlign="start"
variant="subtitle1"
color="text.primary"
sx={{ fontWeight: 600, fontSize: "1rem" }}
>
گزارش کشتار دیروز مرغ گوشتی استان گزارش کشتار دیروز مرغ گوشتی استان
</Typography> </Typography>
@@ -101,16 +34,262 @@ export const YesterdayKillingReport = ({ boxStats }) => (
gap: 1, gap: 1,
overflowY: "auto", overflowY: "auto",
flex: 1, flex: 1,
maxHeight: "500px",
}} }}
> >
{reportItems.map((item, index) => ( <Box
<ReportRow sx={{
key={index} display: "flex",
label={item.label} justifyContent: "space-between",
value={boxStats?.killingYesterday?.[item.key]} 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>
</Box> </Box>
); );

View File

@@ -154,6 +154,7 @@ export const Dashboard = () => {
return ( return (
<Grid <Grid
container container
direction="column"
alignItems="center" alignItems="center"
justifyContent="flex-start" justifyContent="flex-start"
gap={SPACING.SMALL} gap={SPACING.SMALL}
@@ -236,13 +237,7 @@ export const Dashboard = () => {
<Typography variant="body1" textAlign="left"> <Typography variant="body1" textAlign="left">
{notification.title} {notification.title}
</Typography> </Typography>
<Typography <Typography variant="caption" textAlign="left">
variant="caption"
textAlign="left"
sx={{
textAlign: "left",
}}
>
{notification.message} {notification.message}
</Typography> </Typography>
</Box> </Box>
@@ -450,16 +445,14 @@ export const Dashboard = () => {
}} }}
> >
<Typography <Typography
variant="subtitle1"
sx={{ sx={{
width: "100%", width: "100%",
textAlign: "start", textAlign: "start",
fontWeight: "600", fontWeight: "400",
mb: 2, mb: 2,
px: 1, px: 1,
fontSize: "1rem",
}} }}
color="text.primary" color="primary.main"
> >
آمار جوجه ریزی استان آمار جوجه ریزی استان
</Typography> </Typography>
@@ -496,95 +489,94 @@ export const Dashboard = () => {
))} ))}
</Grid> </Grid>
</Grid> </Grid>
<Grid item xs={12} my={SPACING.MEDIUM}>
<ResponsiveTable <ResponsiveTable
isDashboard isDashboard
noPagination noPagination
operation={ operation={
<MUITooltip title="خروجی اکسل"> <MUITooltip title="خروجی اکسل">
<a <a
href={`${axios.defaults.baseURL}hatching_for_every_age_range/`} href={`${axios.defaults.baseURL}hatching_for_every_age_range/`}
rel="noreferrer" rel="noreferrer"
> >
<Button color="success"> <Button color="success">
<RiFileExcel2Fill size={24} /> <RiFileExcel2Fill size={24} />
</Button> </Button>
</a> </a>
</MUITooltip> </MUITooltip>
} }
data={[ data={[
[ [
boxStats?.hatching?.totalLeftOverLt35?.toLocaleString() || "0", boxStats?.hatching?.totalLeftOverLt35?.toLocaleString() || "0",
boxStats?.hatching?.totalLeftOverBetween3540?.toLocaleString() || boxStats?.hatching?.totalLeftOverBetween3540?.toLocaleString() ||
"0", "0",
boxStats?.hatching?.totalLeftOverBetween4045?.toLocaleString() || boxStats?.hatching?.totalLeftOverBetween4045?.toLocaleString() ||
"0", "0",
boxStats?.hatching?.totalLeftOverBetween4550?.toLocaleString() || boxStats?.hatching?.totalLeftOverBetween4550?.toLocaleString() ||
"0", "0",
boxStats?.hatching?.totalLeftOverBetween5055?.toLocaleString() || boxStats?.hatching?.totalLeftOverBetween5055?.toLocaleString() ||
"0", "0",
boxStats?.hatching?.totalLeftOverBetween5560?.toLocaleString() || boxStats?.hatching?.totalLeftOverBetween5560?.toLocaleString() ||
"0", "0",
boxStats?.hatching?.totalLeftOverBetween6065?.toLocaleString() || boxStats?.hatching?.totalLeftOverBetween6065?.toLocaleString() ||
"0", "0",
boxStats?.hatching?.totalLeftOverBetween6570?.toLocaleString() || boxStats?.hatching?.totalLeftOverBetween6570?.toLocaleString() ||
"0", "0",
boxStats?.hatching?.totalLeftOverGt70?.toLocaleString() || "0", boxStats?.hatching?.totalLeftOverGt70?.toLocaleString() || "0",
], ],
]} ]}
allColors={{ color: "#244CCC", text: "#fff" }} allColors={{ color: "#244CCC", text: "#fff" }}
columns={[ columns={[
"کمتر از 35 روز", "کمتر از 35 روز",
"بین 35 تا 40 روز", "بین 35 تا 40 روز",
"بین 40 تا 45 روز", "بین 40 تا 45 روز",
"بین 45 تا 50 روز", "بین 45 تا 50 روز",
"بین 50 تا 55 روز", "بین 50 تا 55 روز",
"بین 55 تا 60 روز", "بین 55 تا 60 روز",
"بین 60 تا 65 روز", "بین 60 تا 65 روز",
"بین 65 تا 70 روز", "بین 65 تا 70 روز",
"بیش از 70 روز", "بیش از 70 روز",
]} ]}
title="مانده در سالن (قطعه)" 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 <Grid
container container
item
xs={12}
spacing={2} spacing={2}
sx={{ mt: 2, alignItems: "stretch" }} sx={{
width: "100%",
display: "flex",
flexWrap: "wrap",
gap: SPACING.SMALL,
justifyContent: "center",
alignItems: "stretch",
mt: 2,
}}
> >
<Grid item xs={12} lg={4} sx={{ display: "flex" }}> <DailykillingReport boxStats={boxStats} />
<BarChartSection boxStats={boxStats} /> <WarehouseInfoSection boxStats={boxStats} />
</Grid> <InventorySection boxStats={boxStats} />
<Grid item xs={12} lg={4} sx={{ display: "flex" }}>
<PieChartSection boxStats={boxStats} />
</Grid>
<Grid item xs={12} lg={4} sx={{ display: "flex" }}>
<PriceChartSection boxStats={boxStats} />
</Grid>
</Grid> </Grid>
<Grid
container
spacing={4}
sx={{
width: "100%",
display: "flex",
flexWrap: "wrap",
gap: "20px",
justifyContent: "center",
alignItems: "stretch",
mt: 2,
}}
>
<BarChartSection boxStats={boxStats} />
<PieChartSection boxStats={boxStats} />
<YesterdayKillingReport boxStats={boxStats} />
</Grid>
<PriceChartSection boxStats={boxStats} />
</Grid> </Grid>
); );
}; };

View File

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

View File

@@ -26,7 +26,6 @@ import { NumberInput } from "../../../../components/number-format-custom/NumberF
import { resizeImage } from "../../../../utils/resizeImage"; import { resizeImage } from "../../../../utils/resizeImage";
import { slaughterGetExlusiveKillers } from "../../services/slaughterGetExlusiveKillers"; import { slaughterGetExlusiveKillers } from "../../services/slaughterGetExlusiveKillers";
import { isValidIndexWeight } from "../../../../utils/isValidIndexWeight"; import { isValidIndexWeight } from "../../../../utils/isValidIndexWeight";
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
export const SlaughterEnterBarItem = ({ export const SlaughterEnterBarItem = ({
data, data,
@@ -42,9 +41,7 @@ export const SlaughterEnterBarItem = ({
const [weightWithBarImages, setWeightWithBarImages] = React.useState([]); const [weightWithBarImages, setWeightWithBarImages] = React.useState([]);
const [weightWithBarImg, setWeightWithBarImg] = React.useState(null); const [weightWithBarImg, setWeightWithBarImg] = React.useState(null);
const { weightRange } = useSelector((state) => state.provinceSlice); const { weightRange } = useSelector((state) => state.provinceSlice);
const selectedSubUser = useSelector(
(state) => state.userSlice.selectedSubUser
);
const weightWithBarImgHandler = (imageList) => { const weightWithBarImgHandler = (imageList) => {
setWeightWithBarImages(imageList); setWeightWithBarImages(imageList);
formik.setFieldValue("weightWithBarImg", ""); formik.setFieldValue("weightWithBarImg", "");
@@ -147,18 +144,11 @@ export const SlaughterEnterBarItem = ({
const [exclusiveKillers, setExclusiveKillers] = useState(); const [exclusiveKillers, setExclusiveKillers] = useState();
const [selectedOption, setSelectedOption] = useState(); const [selectedOption, setSelectedOption] = useState();
useEffect(() => { useEffect(() => {
dispatch( dispatch(slaughterGetExlusiveKillers()).then((r) => {
slaughterGetExlusiveKillers({
role_key: checkPathStartsWith("slaughter")
? selectedSubUser?.key || ""
: "",
})
).then((r) => {
setExclusiveKillers(r.payload.data); setExclusiveKillers(r.payload.data);
}); });
}, [selectedSubUser?.key]); }, []);
const handleOptionChange = (event) => { const handleOptionChange = (event) => {
setSelectedOption(event?.target.value); 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 { SlaughterEnterBarItem } from "../slaughter-enter-bar-item/SlaughterEnterBarItem";
import { format } from "date-fns-jalali"; import { format } from "date-fns-jalali";
import { provincePolicyGetWeightRange } from "../../../province/services/province-policy-get-weight-range"; import { provincePolicyGetWeightRange } from "../../../province/services/province-policy-get-weight-range";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch } from "react-redux";
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
export const SlaughterEnterBarWeight = ({ item, updateTable }) => { export const SlaughterEnterBarWeight = ({ item, updateTable }) => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const selectedSubUser = useSelector(
(state) => state.userSlice.selectedSubUser
);
const sum = item?.acceptedRealWeight / item?.acceptedRealQuantity; const sum = item?.acceptedRealWeight / item?.acceptedRealQuantity;
const data = [ const data = [
[ [
@@ -41,15 +37,8 @@ export const SlaughterEnterBarWeight = ({ item, updateTable }) => {
]; ];
useEffect(() => { useEffect(() => {
dispatch( dispatch(provincePolicyGetWeightRange());
provincePolicyGetWeightRange({ }, []);
role_key: checkPathStartsWith("slaughter")
? selectedSubUser?.key || ""
: "",
})
);
}, [selectedSubUser?.key]);
return ( return (
<TimelineItem sx={{ alignSelf: "flex-start", width: "100%" }}> <TimelineItem sx={{ alignSelf: "flex-start", width: "100%" }}>
<TimelineSeparator> <TimelineSeparator>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -56,8 +56,9 @@ export const ProvinceAllocateRequests = () => {
const fetchApiData = async (page) => { const fetchApiData = async (page) => {
dispatch(getPoultryRequestsTotalQuantityService(selectedDate1)).then( dispatch(getPoultryRequestsTotalQuantityService(selectedDate1)).then(
async () => { async () => {
let response;
dispatch(LOADING_START()); 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=${ `city_operator_check_request_new/?state=waiting&date=${selectedDate1}&page=${page}&page_size=${perPage}&search=filter&value=${
textValue ? textValue : "" textValue ? textValue : ""
}` }`
@@ -298,9 +299,6 @@ export const ProvinceAllocateRequests = () => {
))} ))}
</Grid> </Grid>
<Box <Box
sx={{
width: "100%",
}}
px={{ px={{
xs: 1, xs: 1,
sm: 0, 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 { provinceGetDashboardKillRequestService } from "../../services/get-dahsnoard-province-kill-request";
import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable"; import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable";
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl"; import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
export const ProvinceAllocatedRequests = () => { export const ProvinceAllocatedRequests = () => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const [dataTable, setDataTable] = useState(); const [dataTable, setDataTable] = useState();
const [hasDocumentState, setHasDocumentState] = useState(false); const [hasDocumentState, setHasDocumentState] = useState(false);
const [selectedTab, setSelectedTab] = useState(0); const [selectedTab, setSelectedTab] = useState(0);
const selectedSubUser = useSelector(
(state) => state.userSlice.selectedSubUser
);
const userKey = useSelector((state) => state.userSlice.userProfile.key); const userKey = useSelector((state) => state.userSlice.userProfile.key);
const [textValue, setTextValue] = useState(""); const [textValue, setTextValue] = useState("");
@@ -47,9 +44,6 @@ export const ProvinceAllocatedRequests = () => {
dispatch( dispatch(
provinceGetAllocatedRequestsService({ provinceGetAllocatedRequestsService({
role_key: checkPathStartsWith("province")
? selectedSubUser?.key || ""
: "",
selectedDate1, selectedDate1,
selectedDate2, selectedDate2,
textValue, textValue,
@@ -84,9 +78,6 @@ export const ProvinceAllocatedRequests = () => {
selectedDate2, selectedDate2,
textValue, textValue,
hasDocumentState: checked, hasDocumentState: checked,
role_key: checkPathStartsWith("province")
? selectedSubUser?.key || ""
: "",
}; };
dispatch(provinceGetDashboardKillRequestService(params)).then((r) => { dispatch(provinceGetDashboardKillRequestService(params)).then((r) => {
@@ -98,9 +89,6 @@ export const ProvinceAllocatedRequests = () => {
if (selectedTab === 0) { if (selectedTab === 0) {
dispatch( dispatch(
provinceGetAllocatedRequestsService({ provinceGetAllocatedRequestsService({
role_key: checkPathStartsWith("province")
? selectedSubUser?.key || ""
: "",
selectedDate1, selectedDate1,
selectedDate2, selectedDate2,
textValue, textValue,
@@ -109,15 +97,12 @@ export const ProvinceAllocatedRequests = () => {
); );
fetchDashboard(); fetchDashboard();
} }
}, [selectedDate1, selectedDate2, selectedTab, selectedSubUser?.key]); }, [selectedDate1, selectedDate2, selectedTab]);
const handleSubmit = () => { const handleSubmit = () => {
if (selectedTab === 0) { if (selectedTab === 0) {
dispatch( dispatch(
provinceGetAllocatedRequestsService({ provinceGetAllocatedRequestsService({
role_key: checkPathStartsWith("province")
? selectedSubUser?.key || ""
: "",
selectedDate1, selectedDate1,
selectedDate2, selectedDate2,
textValue, textValue,
@@ -287,11 +272,7 @@ export const ProvinceAllocatedRequests = () => {
<a <a
href={`${ href={`${
axios.defaults.baseURL axios.defaults.baseURL
}allocated_excel/?start=${selectedDate1}&end=${selectedDate2}&role=${getRoleFromUrl()}${ }allocated_excel/?start=${selectedDate1}&end=${selectedDate2}&role=${getRoleFromUrl()}&key=${userKey}&filter=search&value=${textValue}`}
checkPathStartsWith("province")
? `&role_key=${selectedSubUser?.key}`
: ""
}&key=${userKey}&filter=search&value=${textValue}`}
rel="noreferrer" rel="noreferrer"
> >
<Button color="success"> <Button color="success">
@@ -312,7 +293,7 @@ export const ProvinceAllocatedRequests = () => {
/> />
</Grid> </Grid>
<Grid container mt={2} mb={4} isDashboard xs={12}> <Grid container mt={2} mb={4} isDashboard>
<ResponsiveTable <ResponsiveTable
noPagination noPagination
isDashboard isDashboard

View File

@@ -3,7 +3,7 @@ import { DatePicker } from "@mui/x-date-pickers";
import moment from "moment/moment"; import moment from "moment/moment";
import { useContext, useEffect, useState } from "react"; import { useContext, useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux"; 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 { Grid } from "../../../../components/grid/Grid";
import { AppContext } from "../../../../contexts/AppContext"; import { AppContext } from "../../../../contexts/AppContext";
import { SPACING } from "../../../../data/spacing"; import { SPACING } from "../../../../data/spacing";
@@ -62,53 +62,52 @@ export const ProvinceAutoAllocationArchive = () => {
return ( return (
<Grid mt={SPACING.SMALL} xs={12} px={2}> <Grid mt={SPACING.SMALL} xs={12} px={2}>
{!isSingleView && ( {!isSingleView && (
<> <AdvancedTable
<Grid container alignItems="center" gap={SPACING.SMALL} mb={2}> name={
<Grid> <Grid container alignItems="center" gap={SPACING.SMALL} mb={2}>
<Typography>بایگانی تخصیصات خودکار</Typography> <Grid>
<Typography>بایگانی تخصیصات خودکار</Typography>
</Grid>
<Grid>
<DatePicker
label="از تاریخ"
id="date"
renderInput={(params) => (
<TextField style={{ width: "160px" }} {...params} />
)}
value={selectedDate1}
onChange={(e) => {
setSelectedDate1(moment(e).format("YYYY-MM-DD"));
}}
/>
</Grid>
<Grid>
<DatePicker
label="تا تاریخ"
id="date"
renderInput={(params) => (
<TextField style={{ width: "160px" }} {...params} />
)}
value={selectedDate2}
onChange={(e) => {
setSelectedDate2(moment(e).format("YYYY-MM-DD"));
}}
/>
</Grid>
</Grid> </Grid>
<Grid> }
<DatePicker columns={[
label="از تاریخ" "ردیف",
id="date" "کد تخصیص خودکار",
renderInput={(params) => ( "تاریخ تخصیص",
<TextField style={{ width: "160px" }} {...params} /> "تعداد درخواست کشتار",
)} "تعداد تخصیصی",
value={selectedDate1} "تعداد مرغدار",
onChange={(e) => { "تعداد کشتارگاه",
setSelectedDate1(moment(e).format("YYYY-MM-DD")); "مشاهده",
}} ]}
/> data={dataTable}
</Grid> />
<Grid>
<DatePicker
label="تا تاریخ"
id="date"
renderInput={(params) => (
<TextField style={{ width: "160px" }} {...params} />
)}
value={selectedDate2}
onChange={(e) => {
setSelectedDate2(moment(e).format("YYYY-MM-DD"));
}}
/>
</Grid>
</Grid>
<ResponsiveTable
title="بایگانی تخصیصات خودکار"
columns={[
"ردیف",
"کد تخصیص خودکار",
"تاریخ تخصیص",
"تعداد درخواست کشتار",
"تعداد تخصیصی",
"تعداد مرغدار",
"تعداد کشتارگاه",
"مشاهده",
]}
data={dataTable}
/>
</>
)} )}
{isSingleView && ( {isSingleView && (

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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