dispatch: fix dispatch after update

This commit is contained in:
2026-02-02 11:17:49 +03:30
parent 176ee774f0
commit 296ac6d198
2 changed files with 313 additions and 129 deletions

View File

@@ -9,7 +9,7 @@ import {
MenuItem, MenuItem,
Select, Select,
TextField, TextField,
Tooltip, Tooltip
} from "@mui/material"; } from "@mui/material";
import { DatePicker } from "@mui/x-date-pickers"; import { DatePicker } from "@mui/x-date-pickers";
import moment from "moment"; import moment from "moment";
@@ -18,7 +18,7 @@ import axios from "axios";
import { import {
LOADING_END, LOADING_END,
LOADING_START, LOADING_START,
OPEN_MODAL, OPEN_MODAL
} from "../../../../lib/redux/slices/appSlice"; } from "../../../../lib/redux/slices/appSlice";
import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl"; import { getRoleFromUrl } from "../../../../utils/getRoleFromUrl";
import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable"; import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable";
@@ -29,7 +29,13 @@ import { formatJustDate } from "../../../../utils/formatTime";
import { RiSearchLine } from "react-icons/ri"; import { RiSearchLine } from "react-icons/ri";
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith"; import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
export const SlaughterInventoryInProvinceBars = ({ type }) => { export const SlaughterInventoryInProvinceBars = ({
type,
useExternalFilters = false,
filterValues = {},
onAfterUpdate,
refreshTrigger
}) => {
const [selectedDate1, setSelectedDate1] = useState( const [selectedDate1, setSelectedDate1] = useState(
moment(new Date()).format("YYYY-MM-DD") moment(new Date()).format("YYYY-MM-DD")
); );
@@ -53,42 +59,60 @@ export const SlaughterInventoryInProvinceBars = ({ type }) => {
const [tableData, setTableData] = useState([]); const [tableData, setTableData] = useState([]);
const [quota, setQuota] = useState("all"); const [quota, setQuota] = useState("all");
const effectiveFilters = useExternalFilters
? {
selectedDate1: filterValues.selectedDate1 ?? selectedDate1,
selectedDate2: filterValues.selectedDate2 ?? selectedDate2,
withDate: filterValues.withDate ?? withDate,
textValue: filterValues.textValue ?? textValue,
quota: filterValues.quota ?? quota
}
: {
selectedDate1,
selectedDate2,
withDate,
textValue,
quota
};
const fetchApiData = useCallback( const fetchApiData = useCallback(
async (page) => { async (pageNum) => {
dispatch(LOADING_START()); dispatch(LOADING_START());
const response = await axios.get( const response = await axios.get(
`bars_for_kill_house/?search=filter&value=${textValue}&role=${getRoleFromUrl()}${ `bars_for_kill_house/?search=filter&value=${
withDate effectiveFilters.textValue
? `&date1=${selectedDate1}${ }&role=${getRoleFromUrl()}${
effectiveFilters.withDate
? `&date1=${effectiveFilters.selectedDate1}${
checkPathStartsWith("slaughter") checkPathStartsWith("slaughter")
? `&role_key=${selectedSubUser?.key}` ? `&role_key=${selectedSubUser?.key}`
: "" : ""
}&date2=${selectedDate2}` }&date2=${effectiveFilters.selectedDate2}`
: `` : ``
}&page=${page}&page_size=${perPage}&type=${type}&quota=${quota}` }&page=${pageNum}&page_size=${perPage}&type=${type}&quota=${
effectiveFilters.quota
}`
); );
dispatch(LOADING_END()); dispatch(LOADING_END());
setData(response.data.results); setData(response.data.results);
setTotalRows(response.data.count); setTotalRows(response.data.count);
}, },
[ [
textValue, effectiveFilters.textValue,
withDate, effectiveFilters.withDate,
selectedDate1, effectiveFilters.selectedDate1,
selectedDate2, effectiveFilters.selectedDate2,
effectiveFilters.quota,
perPage, perPage,
type, type,
quota,
dispatch, dispatch,
setData, selectedSubUser?.key
selectedSubUser?.key,
setTotalRows,
] ]
); );
const handlePageChange = (page) => { const handlePageChange = (pageNum) => {
fetchApiData(page); fetchApiData(pageNum);
setPage(page); setPage(pageNum);
}; };
const handlePerRowsChange = (perRows) => { const handlePerRowsChange = (perRows) => {
@@ -96,10 +120,25 @@ export const SlaughterInventoryInProvinceBars = ({ type }) => {
setPage(1); setPage(1);
}; };
const updateTable = () => { const updateTable = async () => {
fetchApiData(page !== 0 ? page : 1); const currentPage = page !== 0 ? page : 1;
await fetchApiData(currentPage);
onAfterUpdate?.();
}; };
useEffect(() => {
if (!useExternalFilters) {
fetchApiData(1);
}
}, [fetchApiData, useExternalFilters]);
useEffect(() => {
if (useExternalFilters && refreshTrigger !== undefined) {
fetchApiData(1);
setPage(1);
}
}, [refreshTrigger, useExternalFilters]);
useEffect(() => { useEffect(() => {
const d = data?.map((item, i) => { const d = data?.map((item, i) => {
return [ return [
@@ -148,24 +187,20 @@ export const SlaughterInventoryInProvinceBars = ({ type }) => {
updateTable={updateTable} updateTable={updateTable}
item={item} item={item}
/> />
), )
}) })
); );
}} }}
> >
<SettingsIcon fontSize="small" /> <SettingsIcon fontSize="small" />
</IconButton> </IconButton>
</Tooltip>, </Tooltip>
]; ];
}); });
setTableData(d); setTableData(d);
}, [data]); }, [data]);
useEffect(() => {
fetchApiData(1);
}, [fetchApiData]);
const handleSubmit = async (event) => { const handleSubmit = async (event) => {
event.preventDefault(); event.preventDefault();
dispatch(LOADING_START()); dispatch(LOADING_START());
@@ -190,109 +225,111 @@ export const SlaughterInventoryInProvinceBars = ({ type }) => {
return ( return (
<Grid container xs={12} justifyContent="center" alignItems="center" gap={2}> <Grid container xs={12} justifyContent="center" alignItems="center" gap={2}>
<Grid {!useExternalFilters && (
container
xs={12}
justifyContent="start"
alignItems="center"
gap={2}
>
<Grid <Grid
container container
style={{ xs={12}
borderStyle: "solid", justifyContent="start"
borderWidth: "1px", alignItems="center"
padding: "10px", gap={2}
borderRadius: "15px",
borderColor: "gray",
justifyContent: "left",
}}
> >
{type === "notentered" && ( <Grid
container
style={{
borderStyle: "solid",
borderWidth: "1px",
padding: "10px",
borderRadius: "15px",
borderColor: "gray",
justifyContent: "left"
}}
>
{type === "notentered" && (
<Grid>
<FormControlLabel
control={
<Checkbox
checked={withDate}
onChange={() => setWithDate(!withDate)}
color="primary"
/>
}
/>
</Grid>
)}
<Grid> <Grid>
<FormControlLabel <DatePicker
control={ disabled={!withDate}
<Checkbox label="از تاریخ"
checked={withDate} id="date"
onChange={() => setWithDate(!withDate)} renderInput={(params) => (
color="primary" <TextField
size="small"
style={{ width: "160px" }}
{...params}
/> />
} )}
value={selectedDate1}
onChange={(e) => {
setSelectedDate1(moment(e).format("YYYY-MM-DD"));
}}
/>
</Grid>
<Grid>
<DatePicker
disabled={!withDate}
label="تا تاریخ"
id="date"
renderInput={(params) => (
<TextField
size="small"
style={{ width: "160px" }}
{...params}
/>
)}
value={selectedDate2}
onChange={(e) => {
setSelectedDate2(moment(e).format("YYYY-MM-DD"));
}}
/> />
</Grid> </Grid>
)}
<Grid>
<DatePicker
disabled={!withDate}
label="از تاریخ"
id="date"
renderInput={(params) => (
<TextField
size="small"
style={{ width: "160px" }}
{...params}
/>
)}
value={selectedDate1}
onChange={(e) => {
setSelectedDate1(moment(e).format("YYYY-MM-DD"));
}}
/>
</Grid> </Grid>
<Grid> <Grid>
<DatePicker <FormControl size="small" style={{ minWidth: 150 }}>
disabled={!withDate} <InputLabel>نوع فروش</InputLabel>
label="تا تاریخ" <Select
id="date" value={quota}
renderInput={(params) => ( onChange={(e) => setQuota(e.target.value)}
<TextField label="نوع فروش"
size="small" >
style={{ width: "160px" }} <MenuItem value="all">همه</MenuItem>
{...params} <MenuItem value="governmental">دولتی</MenuItem>
/> <MenuItem value="free">آزاد</MenuItem>
)} </Select>
value={selectedDate2} </FormControl>
onChange={(e) => { </Grid>
setSelectedDate2(moment(e).format("YYYY-MM-DD")); <Grid>
}} <form onSubmit={handleSubmit}>
/> <TextField
id="outlined-basic"
size="small"
label="جستجو"
variant="outlined"
style={{ width: 250 }}
onChange={handleTextChange}
/>
<Button
type="submit"
onClick={handleSubmit}
endIcon={<RiSearchLine />}
>
جستجو
</Button>
</form>
</Grid> </Grid>
</Grid> </Grid>
<Grid> )}
<FormControl size="small" style={{ minWidth: 150 }}>
<InputLabel>نوع فروش</InputLabel>
<Select
value={quota}
onChange={(e) => setQuota(e.target.value)}
label="نوع فروش"
>
<MenuItem value="all">همه</MenuItem>
<MenuItem value="governmental">دولتی</MenuItem>
<MenuItem value="free">آزاد</MenuItem>
</Select>
</FormControl>
</Grid>
<Grid>
<form onSubmit={handleSubmit}>
<TextField
id="outlined-basic"
size="small"
label="جستجو"
variant="outlined"
style={{ width: 250 }}
onChange={handleTextChange}
/>
<Button
type="submit"
onClick={handleSubmit}
endIcon={<RiSearchLine />}
>
جستجو
</Button>
</form>
</Grid>
</Grid>
<ResponsiveTable <ResponsiveTable
data={tableData} data={tableData}
@@ -319,7 +356,7 @@ export const SlaughterInventoryInProvinceBars = ({ type }) => {
"درصد افت در لحظه", "درصد افت در لحظه",
"درصد افت ورود به انبار", "درصد افت ورود به انبار",
"تاریخ ورود به انبار", "تاریخ ورود به انبار",
"عملیات", "عملیات"
]} ]}
handlePageChange={handlePageChange} handlePageChange={handlePageChange}
totalRows={totalRows} totalRows={totalRows}

View File

@@ -1,6 +1,17 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { Grid } from "../../../../components/grid/Grid"; import { Grid } from "../../../../components/grid/Grid";
import {
Button,
Checkbox,
FormControl,
FormControlLabel,
InputLabel,
MenuItem,
Select,
TextField
} from "@mui/material";
import { DatePicker } from "@mui/x-date-pickers";
import moment from "moment";
import { Tab, Tabs } from "@mui/material"; import { Tab, Tabs } from "@mui/material";
import { SPACING } from "../../../../data/spacing"; import { SPACING } from "../../../../data/spacing";
import { SlaughterShowProducts } from "../slaughter-show-products/SlaughterShowProducts"; import { SlaughterShowProducts } from "../slaughter-show-products/SlaughterShowProducts";
@@ -11,6 +22,7 @@ import { useDispatch } from "react-redux";
import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable"; import ResponsiveTable from "../../../../components/responsive-table/ResponsiveTable";
import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith"; import { checkPathStartsWith } from "../../../../utils/checkPathStartsWith";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import { RiSearchLine } from "react-icons/ri";
export const SlaughterInventory = () => { export const SlaughterInventory = () => {
const [value, setValue] = useState("0"); const [value, setValue] = useState("0");
@@ -24,12 +36,36 @@ export const SlaughterInventory = () => {
const dispatch = useDispatch(); const dispatch = useDispatch();
// Shared filter state for both province bars tables
const [selectedDate1, setSelectedDate1] = useState(
moment(new Date()).format("YYYY-MM-DD")
);
const [selectedDate2, setSelectedDate2] = useState(
moment(new Date()).format("YYYY-MM-DD")
);
const [withDate, setWithDate] = useState(false);
const [textValue, setTextValue] = useState("");
const [quota, setQuota] = useState("all");
const [refreshTrigger, setRefreshTrigger] = useState(0);
const filterValues = {
selectedDate1,
selectedDate2,
withDate,
textValue,
quota
};
const handleFilterSubmit = () => {
setRefreshTrigger((t) => t + 1);
};
useEffect(() => { useEffect(() => {
dispatch( dispatch(
slaughterGetBarsInfo({ slaughterGetBarsInfo({
role_key: checkPathStartsWith("slaughter") role_key: checkPathStartsWith("slaughter")
? selectedSubUser?.key || "" ? selectedSubUser?.key || ""
: "", : ""
}) })
).then((r) => { ).then((r) => {
setBarsInfo(r.payload.data); setBarsInfo(r.payload.data);
@@ -78,8 +114,8 @@ export const SlaughterInventory = () => {
barsInfo?.totalEnteredBarsCarcassesWeight?.toLocaleString(), barsInfo?.totalEnteredBarsCarcassesWeight?.toLocaleString(),
barsInfo?.totalNotEnteredBars?.toLocaleString(), barsInfo?.totalNotEnteredBars?.toLocaleString(),
barsInfo?.totalNotEnteredBarsQuantity?.toLocaleString(), barsInfo?.totalNotEnteredBarsQuantity?.toLocaleString(),
barsInfo?.totalNotEnteredKillHouseRequestsWeight?.toLocaleString(), barsInfo?.totalNotEnteredKillHouseRequestsWeight?.toLocaleString()
], ]
]} ]}
columns={[ columns={[
"تعداد کل بارها", "تعداد کل بارها",
@@ -91,16 +127,127 @@ export const SlaughterInventory = () => {
"وزن کل لاشه وارد شده (کیلوگرم)", "وزن کل لاشه وارد شده (کیلوگرم)",
"تعداد کل بارهای وارد نشده", "تعداد کل بارهای وارد نشده",
"حجم کل بار وارد نشده (قطعه)", "حجم کل بار وارد نشده (قطعه)",
"وزن کل بار وارد نشده (کیلوگرم)", "وزن کل بار وارد نشده (کیلوگرم)"
]} ]}
allColors={{ color: "#f3bda3", text: "#332a3d" }} allColors={{ color: "#f3bda3", text: "#332a3d" }}
/> />
<Grid container mt={SPACING.MEDIUM} mb={SPACING.MEDIUM}> <Grid
<SlaughterInventoryInProvinceBars type="notentered" /> container
xs={12}
justifyContent="start"
alignItems="center"
gap={2}
pt={SPACING.MEDIUM}
>
<Grid
container
style={{
borderStyle: "solid",
borderWidth: "1px",
padding: "10px",
borderRadius: "15px",
borderColor: "gray",
justifyContent: "left"
}}
>
<Grid>
<FormControlLabel
control={
<Checkbox
checked={withDate}
onChange={() => setWithDate(!withDate)}
color="primary"
/>
}
label="فیلتر تاریخ"
/>
</Grid>
<Grid>
<DatePicker
disabled={!withDate}
label="از تاریخ"
renderInput={(params) => (
<TextField
size="small"
style={{ width: "160px" }}
{...params}
/>
)}
value={selectedDate1}
onChange={(e) => {
setSelectedDate1(moment(e).format("YYYY-MM-DD"));
}}
/>
</Grid>
<Grid>
<DatePicker
disabled={!withDate}
label="تا تاریخ"
renderInput={(params) => (
<TextField
size="small"
style={{ width: "160px" }}
{...params}
/>
)}
value={selectedDate2}
onChange={(e) => {
setSelectedDate2(moment(e).format("YYYY-MM-DD"));
}}
/>
</Grid>
</Grid>
<Grid>
<FormControl size="small" style={{ minWidth: 150 }}>
<InputLabel>نوع فروش</InputLabel>
<Select
value={quota}
onChange={(e) => setQuota(e.target.value)}
label="نوع فروش"
>
<MenuItem value="all">همه</MenuItem>
<MenuItem value="governmental">دولتی</MenuItem>
<MenuItem value="free">آزاد</MenuItem>
</Select>
</FormControl>
</Grid>
<Grid>
<TextField
size="small"
label="جستجو"
variant="outlined"
style={{ width: 250 }}
value={textValue}
onChange={(e) => setTextValue(e.target.value)}
/>
<Button
sx={{ ml: 1 }}
variant="contained"
onClick={handleFilterSubmit}
endIcon={<RiSearchLine />}
>
جستجو
</Button>
</Grid>
</Grid> </Grid>
<Grid container mt={SPACING.MEDIUM} mb={SPACING.MEDIUM}> <Grid container mt={SPACING.MEDIUM} mb={SPACING.MEDIUM}>
<SlaughterInventoryInProvinceBars type="entered" /> <SlaughterInventoryInProvinceBars
type="notentered"
useExternalFilters
filterValues={filterValues}
onAfterUpdate={() => setRefreshTrigger((t) => t + 1)}
refreshTrigger={refreshTrigger}
/>
</Grid>
<Grid container mt={SPACING.MEDIUM} mb={SPACING.MEDIUM}>
<SlaughterInventoryInProvinceBars
type="entered"
useExternalFilters
filterValues={filterValues}
refreshTrigger={refreshTrigger}
/>
</Grid> </Grid>
</Grid> </Grid>
</Grid> </Grid>