|
@@ -17,6 +17,7 @@ import { fetchPoListClient, testing } from "@/app/api/po/actions"; |
|
|
import dayjs from "dayjs"; |
|
|
import dayjs from "dayjs"; |
|
|
import { arrayToDateString, OUTPUT_DATE_FORMAT } from "@/app/utils/formatUtil"; |
|
|
import { arrayToDateString, OUTPUT_DATE_FORMAT } from "@/app/utils/formatUtil"; |
|
|
import arraySupport from "dayjs/plugin/arraySupport"; |
|
|
import arraySupport from "dayjs/plugin/arraySupport"; |
|
|
|
|
|
import { Checkbox, Box } from "@mui/material"; |
|
|
dayjs.extend(arraySupport); |
|
|
dayjs.extend(arraySupport); |
|
|
|
|
|
|
|
|
type Props = { |
|
|
type Props = { |
|
@@ -34,6 +35,8 @@ const PoSearch: React.FC<Props> = ({ |
|
|
warehouse, |
|
|
warehouse, |
|
|
totalCount: initTotalCount, |
|
|
totalCount: initTotalCount, |
|
|
}) => { |
|
|
}) => { |
|
|
|
|
|
const [selectedPoIds, setSelectedPoIds] = useState<number[]>([]); |
|
|
|
|
|
const [selectAll, setSelectAll] = useState(false); |
|
|
const [filteredPo, setFilteredPo] = useState<PoResult[]>(po); |
|
|
const [filteredPo, setFilteredPo] = useState<PoResult[]>(po); |
|
|
const [filterArgs, setFilterArgs] = useState<Record<string, any>>({}); |
|
|
const [filterArgs, setFilterArgs] = useState<Record<string, any>>({}); |
|
|
const { t } = useTranslation("purchaseOrder"); |
|
|
const { t } = useTranslation("purchaseOrder"); |
|
@@ -44,7 +47,8 @@ const PoSearch: React.FC<Props> = ({ |
|
|
const [totalCount, setTotalCount] = useState(initTotalCount); |
|
|
const [totalCount, setTotalCount] = useState(initTotalCount); |
|
|
const searchCriteria: Criterion<SearchParamNames>[] = useMemo(() => { |
|
|
const searchCriteria: Criterion<SearchParamNames>[] = useMemo(() => { |
|
|
const searchCriteria: Criterion<SearchParamNames>[] = [ |
|
|
const searchCriteria: Criterion<SearchParamNames>[] = [ |
|
|
{ label: t("Po No."), paramName: "code", type: "text" }, |
|
|
|
|
|
|
|
|
{ label: t("Po No."), paramName: "code", type: "text" }, |
|
|
|
|
|
{ label: t("Supplier"), paramName: "supplier", type: "text" }, |
|
|
{ label: t("Order Date"), label2: t("Order Date To"), paramName: "orderDate", type: "dateRange" }, |
|
|
{ label: t("Order Date"), label2: t("Order Date To"), paramName: "orderDate", type: "dateRange" }, |
|
|
{ |
|
|
{ |
|
|
label: t("Escalated"), |
|
|
label: t("Escalated"), |
|
@@ -69,15 +73,57 @@ const PoSearch: React.FC<Props> = ({ |
|
|
|
|
|
|
|
|
const onDetailClick = useCallback( |
|
|
const onDetailClick = useCallback( |
|
|
(po: PoResult) => { |
|
|
(po: PoResult) => { |
|
|
router.push(`/po/edit?id=${po.id}&start=true`); |
|
|
|
|
|
|
|
|
setSelectedPoIds([]); |
|
|
|
|
|
setSelectAll(false); |
|
|
|
|
|
router.push(`/po/edit?id=${po.id}&start=true&selectedIds=${po.id}`); |
|
|
}, |
|
|
}, |
|
|
[router], |
|
|
[router], |
|
|
); |
|
|
); |
|
|
|
|
|
|
|
|
const onDeleteClick = useCallback((po: PoResult) => {}, []); |
|
|
const onDeleteClick = useCallback((po: PoResult) => {}, []); |
|
|
|
|
|
// handle single checkbox selection |
|
|
|
|
|
const handleSelectPo = useCallback((poId: number, checked: boolean) => { |
|
|
|
|
|
if (checked) { |
|
|
|
|
|
setSelectedPoIds(prev => [...prev, poId]); |
|
|
|
|
|
} else { |
|
|
|
|
|
setSelectedPoIds(prev => prev.filter(id => id !== poId)); |
|
|
|
|
|
} |
|
|
|
|
|
}, []); |
|
|
|
|
|
|
|
|
|
|
|
// 处理全选 |
|
|
|
|
|
const handleSelectAll = useCallback((checked: boolean) => { |
|
|
|
|
|
if (checked) { |
|
|
|
|
|
setSelectedPoIds(filteredPo.map(po => po.id)); |
|
|
|
|
|
setSelectAll(true); |
|
|
|
|
|
} else { |
|
|
|
|
|
setSelectedPoIds([]); |
|
|
|
|
|
setSelectAll(false); |
|
|
|
|
|
} |
|
|
|
|
|
}, [filteredPo]); |
|
|
|
|
|
|
|
|
|
|
|
// navigate to PoDetail page |
|
|
|
|
|
const handleGoToPoDetail = useCallback(() => { |
|
|
|
|
|
if (selectedPoIds.length > 0) { |
|
|
|
|
|
const selectedIdsParam = selectedPoIds.join(','); |
|
|
|
|
|
const firstPoId = selectedPoIds[0]; |
|
|
|
|
|
router.push(`/po/edit?id=${firstPoId}&start=true&selectedIds=${selectedIdsParam}`); |
|
|
|
|
|
} |
|
|
|
|
|
}, [selectedPoIds, router]); |
|
|
|
|
|
|
|
|
const columns = useMemo<Column<PoResult>[]>( |
|
|
const columns = useMemo<Column<PoResult>[]>( |
|
|
() => [ |
|
|
() => [ |
|
|
|
|
|
{ |
|
|
|
|
|
name: "id" as keyof PoResult, |
|
|
|
|
|
label: "Select", |
|
|
|
|
|
renderCell: (params) => ( |
|
|
|
|
|
<Checkbox |
|
|
|
|
|
checked={selectedPoIds.includes(params.id)} |
|
|
|
|
|
onChange={(e) => handleSelectPo(params.id, e.target.checked)} |
|
|
|
|
|
onClick={(e) => e.stopPropagation()} |
|
|
|
|
|
/> |
|
|
|
|
|
), |
|
|
|
|
|
width: 60, |
|
|
|
|
|
}, |
|
|
{ |
|
|
{ |
|
|
name: "id", |
|
|
name: "id", |
|
|
label: t("Details"), |
|
|
label: t("Details"), |
|
@@ -132,7 +178,7 @@ const PoSearch: React.FC<Props> = ({ |
|
|
}, |
|
|
}, |
|
|
}, |
|
|
}, |
|
|
], |
|
|
], |
|
|
[filteredPo], |
|
|
|
|
|
|
|
|
[selectedPoIds, handleSelectPo, onDetailClick, t], // only keep necessary dependencies |
|
|
); |
|
|
); |
|
|
|
|
|
|
|
|
const onReset = useCallback(() => { |
|
|
const onReset = useCallback(() => { |
|
@@ -177,6 +223,14 @@ const PoSearch: React.FC<Props> = ({ |
|
|
useEffect(() => { |
|
|
useEffect(() => { |
|
|
newPageFetch(pagingController, filterArgs); |
|
|
newPageFetch(pagingController, filterArgs); |
|
|
}, [newPageFetch, pagingController, filterArgs]); |
|
|
}, [newPageFetch, pagingController, filterArgs]); |
|
|
|
|
|
// when filteredPo changes, update select all state |
|
|
|
|
|
useEffect(() => { |
|
|
|
|
|
if (filteredPo.length > 0 && selectedPoIds.length === filteredPo.length) { |
|
|
|
|
|
setSelectAll(true); |
|
|
|
|
|
} else { |
|
|
|
|
|
setSelectAll(false); |
|
|
|
|
|
} |
|
|
|
|
|
}, [filteredPo, selectedPoIds]); |
|
|
return ( |
|
|
return ( |
|
|
<> |
|
|
<> |
|
|
<Grid container> |
|
|
<Grid container> |
|
@@ -201,6 +255,7 @@ const PoSearch: React.FC<Props> = ({ |
|
|
console.log(query); |
|
|
console.log(query); |
|
|
setFilterArgs({ |
|
|
setFilterArgs({ |
|
|
code: query.code, |
|
|
code: query.code, |
|
|
|
|
|
supplier: query.supplier, |
|
|
status: query.status === "All" ? "" : query.status, |
|
|
status: query.status === "All" ? "" : query.status, |
|
|
escalated: |
|
|
escalated: |
|
|
query.escalated === "All" |
|
|
query.escalated === "All" |
|
@@ -211,15 +266,8 @@ const PoSearch: React.FC<Props> = ({ |
|
|
orderDate: query.orderDate === "Invalid Date" ? "" : query.orderDate, |
|
|
orderDate: query.orderDate === "Invalid Date" ? "" : query.orderDate, |
|
|
orderDateTo: query.orderDateTo === "Invalid Date" ? "" : query.orderDateTo, |
|
|
orderDateTo: query.orderDateTo === "Invalid Date" ? "" : query.orderDateTo, |
|
|
}); |
|
|
}); |
|
|
// setFilteredPo((prev) => |
|
|
|
|
|
// po.filter((p) => { |
|
|
|
|
|
// return ( |
|
|
|
|
|
// p.code.toLowerCase().includes(query.code.toLowerCase()) && |
|
|
|
|
|
// (query.status === "All" || t(`${p.status.toLowerCase()}`) === query.status) && |
|
|
|
|
|
// (query.escalated === "All" || (p.escalated === Boolean((query.escalated) === t("Escalated")))) |
|
|
|
|
|
// ) |
|
|
|
|
|
// }) |
|
|
|
|
|
// ); |
|
|
|
|
|
|
|
|
setSelectedPoIds([]); // reset selected po ids |
|
|
|
|
|
setSelectAll(false); // reset select all |
|
|
}} |
|
|
}} |
|
|
onReset={onReset} |
|
|
onReset={onReset} |
|
|
/> |
|
|
/> |
|
@@ -231,6 +279,24 @@ const PoSearch: React.FC<Props> = ({ |
|
|
totalCount={totalCount} |
|
|
totalCount={totalCount} |
|
|
isAutoPaging={false} |
|
|
isAutoPaging={false} |
|
|
/> |
|
|
/> |
|
|
|
|
|
{/* add select all and view selected button */} |
|
|
|
|
|
<Box sx={{ mb: 2, display: 'flex', alignItems: 'center', gap: 2 }}> |
|
|
|
|
|
<Button |
|
|
|
|
|
variant="outlined" |
|
|
|
|
|
onClick={() => handleSelectAll(!selectAll)} |
|
|
|
|
|
startIcon={<Checkbox checked={selectAll} />} |
|
|
|
|
|
> |
|
|
|
|
|
{t("Select All")} ({selectedPoIds.length} / {filteredPo.length}) |
|
|
|
|
|
</Button> |
|
|
|
|
|
<Button |
|
|
|
|
|
variant="contained" |
|
|
|
|
|
onClick={handleGoToPoDetail} |
|
|
|
|
|
disabled={selectedPoIds.length === 0} |
|
|
|
|
|
color="primary" |
|
|
|
|
|
> |
|
|
|
|
|
{t("View Selected")} ({selectedPoIds.length}) |
|
|
|
|
|
</Button> |
|
|
|
|
|
</Box> |
|
|
</> |
|
|
</> |
|
|
</> |
|
|
</> |
|
|
); |
|
|
); |
|
|