@@ -0,0 +1,36 @@ | |||||
import { PreloadPickOrder } from "@/app/api/pickOrder"; | |||||
import PickOrderSearch from "@/components/PickOrderSearch"; | |||||
import { getServerI18n } from "@/i18n"; | |||||
import { Stack, Typography } from "@mui/material"; | |||||
import { Metadata } from "next"; | |||||
import { Suspense } from "react"; | |||||
export const metadata: Metadata = { | |||||
title: "Pick Order" | |||||
} | |||||
const PickOrder: React.FC = async () => { | |||||
const { t } = await getServerI18n("pickOrder") | |||||
PreloadPickOrder() | |||||
return ( | |||||
<> | |||||
<Stack | |||||
direction={"row"} | |||||
justifyContent={"space-between"} | |||||
flexWrap={"wrap"} | |||||
rowGap={2} | |||||
> | |||||
<Typography variant="h4" marginInlineEnd={2}> | |||||
{t("Pick Order")} | |||||
</Typography> | |||||
</Stack> | |||||
<Suspense fallback={<PickOrderSearch.Loading />}> | |||||
<PickOrderSearch /> | |||||
</Suspense> | |||||
</> | |||||
) | |||||
} | |||||
export default PickOrder; |
@@ -0,0 +1,33 @@ | |||||
import "server-only"; | |||||
import { serverFetchJson } from "@/app/utils/fetchUtil"; | |||||
import { BASE_API_URL } from "@/config/api"; | |||||
import { cache } from "react"; | |||||
interface PickOrderItemInfo { | |||||
name: string, | |||||
type: string, | |||||
} | |||||
export interface PickOrderResult{ | |||||
id: number, | |||||
code: string, | |||||
consoCode?: string, | |||||
targetDate: string, | |||||
completeDate?: string, | |||||
type: string, | |||||
status: string, | |||||
releasedBy: string, | |||||
items?: PickOrderItemInfo[] | null, | |||||
} | |||||
export const PreloadPickOrder = () => { | |||||
fetchPickOrders() | |||||
} | |||||
export const fetchPickOrders = cache(async () => { | |||||
return serverFetchJson<PickOrderResult[]>(`${BASE_API_URL}/pickOrder/list`, { | |||||
next: { | |||||
tags: ["pickOrders"] | |||||
} | |||||
}) | |||||
}) |
@@ -113,8 +113,8 @@ const InventorySearch: React.FC<Props> = ({ | |||||
<SearchBox | <SearchBox | ||||
criteria={searchCriteria} | criteria={searchCriteria} | ||||
onSearch={(query) => { | onSearch={(query) => { | ||||
console.log(query) | |||||
console.log(inventories) | |||||
// console.log(query) | |||||
// console.log(inventories) | |||||
setFilteredInventories( | setFilteredInventories( | ||||
inventories.filter( | inventories.filter( | ||||
(i) => | (i) => | ||||
@@ -52,7 +52,7 @@ const NavigationContent: React.FC = () => { | |||||
{ | { | ||||
icon: <RequestQuote />, | icon: <RequestQuote />, | ||||
label: "Pick Order", | label: "Pick Order", | ||||
path: "", | |||||
path: "/pickOrder", | |||||
}, | }, | ||||
{ | { | ||||
icon: <RequestQuote />, | icon: <RequestQuote />, | ||||
@@ -0,0 +1,108 @@ | |||||
"use client" | |||||
import { PickOrderResult } from "@/app/api/pickOrder"; | |||||
import { SearchParams } from "@/app/utils/fetchUtil"; | |||||
import { useCallback, useMemo, useState } from "react"; | |||||
import { useTranslation } from "react-i18next"; | |||||
import SearchBox, { Criterion } from "../SearchBox"; | |||||
import SearchResults, { Column } from "../SearchResults"; | |||||
import { groupBy, map, sortBy, sortedUniq, uniqBy, upperCase, upperFirst } from "lodash"; | |||||
interface Props { | |||||
pickOrders: PickOrderResult[]; | |||||
} | |||||
type SearchQuery = Partial<Omit<PickOrderResult, | |||||
| "id" | |||||
| "consoCode" | |||||
| "completeDate">> | |||||
type SearchParamNames = keyof SearchQuery; | |||||
const PickOrderSearch: React.FC<Props> = ({ | |||||
pickOrders, | |||||
}) => { | |||||
const { t } = useTranslation("pickOrders"); | |||||
const [filteredPickOrders, setFilteredPickOrders] = useState(pickOrders) | |||||
const searchCriteria: Criterion<SearchParamNames>[] = useMemo(() => [ | |||||
{ label: t("Code"), paramName: "code", type: "text" }, | |||||
{ label: t("Target Date From"), label2: t("Target Date To"), paramName: "targetDate", type: "dateRange" }, | |||||
{ | |||||
label: t("Type"), paramName: "type", type: "autocomplete", | |||||
options: sortBy( | |||||
uniqBy(pickOrders.map((po) => ({ value: po.type, label: t(upperCase(po.type)) })), "value"), | |||||
"label").map((po) => (po)) | |||||
}, | |||||
{ | |||||
label: t("Status"), paramName: "status", type: "autocomplete", | |||||
options: sortBy( | |||||
uniqBy(pickOrders.map((po) => ({ value: po.status, label: t(upperFirst(po.status)) })), "value"), | |||||
"label").map((po) => (po)) | |||||
}, | |||||
// { | |||||
// label: t("Items"), paramName: "items", type: "autocomplete", multiple: true, | |||||
// options: sortBy( | |||||
// uniqBy(pickOrders.map((po) => po.items?.map((item) => ({ value: item.name, label: item.name, group: item.type }))), "value"), | |||||
// "label") | |||||
// }, | |||||
], [t]) | |||||
const onReset = useCallback(() => { | |||||
setFilteredPickOrders(pickOrders) | |||||
}, [pickOrders]) | |||||
const columns = useMemo<Column<PickOrderResult>[]>(() => [ | |||||
{ | |||||
name: "code", | |||||
label: t("Code"), | |||||
}, | |||||
{ | |||||
name: "consoCode", | |||||
label: t("Consolidated Code"), | |||||
}, | |||||
{ | |||||
name: "type", | |||||
label: t("type"), | |||||
}, | |||||
{ | |||||
name: "items", | |||||
label: t("Items"), | |||||
renderCell: (params) => { | |||||
return params.items?.map((i) => i.name).join(", ") | |||||
} | |||||
}, | |||||
{ | |||||
name: "releasedBy", | |||||
label: t("Released By"), | |||||
}, | |||||
{ | |||||
name: "status", | |||||
label: t("Status"), | |||||
}, | |||||
], [t]) | |||||
return ( | |||||
<> | |||||
<SearchBox | |||||
criteria={searchCriteria} | |||||
onSearch={(query) => { | |||||
setFilteredPickOrders( | |||||
pickOrders.filter( | |||||
(po) => | |||||
po.code.toLowerCase().includes(query.code.toLowerCase()) | |||||
) | |||||
) | |||||
}} | |||||
onReset={onReset} | |||||
/> | |||||
<SearchResults<PickOrderResult> items={filteredPickOrders} columns={columns} pagingController={{ | |||||
pageNum: 0, | |||||
pageSize: 0, | |||||
totalCount: 0, | |||||
}} /> | |||||
</> | |||||
) | |||||
} | |||||
export default PickOrderSearch; |
@@ -0,0 +1,21 @@ | |||||
import { fetchPickOrders } from "@/app/api/pickOrder"; | |||||
import GeneralLoading from "../General/GeneralLoading"; | |||||
import PickOrderSearch from "./PickOrderSearch"; | |||||
interface SubComponents { | |||||
Loading: typeof GeneralLoading; | |||||
} | |||||
const PickOrderSearchWrapper: React.FC & SubComponents = async () => { | |||||
const [ | |||||
pickOrders | |||||
] = await Promise.all([ | |||||
fetchPickOrders() | |||||
]) | |||||
return <PickOrderSearch pickOrders={pickOrders}/> | |||||
} | |||||
PickOrderSearchWrapper.Loading = GeneralLoading; | |||||
export default PickOrderSearchWrapper; |
@@ -0,0 +1 @@ | |||||
export { default } from './PickOrderSearchWrapper' |