diff --git a/src/app/(main)/do/edit/page.tsx b/src/app/(main)/do/edit/page.tsx
new file mode 100644
index 0000000..e69de29
diff --git a/src/app/(main)/do/page.tsx b/src/app/(main)/do/page.tsx
new file mode 100644
index 0000000..3ec9163
--- /dev/null
+++ b/src/app/(main)/do/page.tsx
@@ -0,0 +1,33 @@
+import DoSearch from "@/components/DoSearch";
+import { getServerI18n } from "@/i18n"
+import { Stack, Typography } from "@mui/material";
+import { Metadata } from "next";
+import { Suspense } from "react";
+
+export const metadata: Metadata = {
+ title: "Delivery Order"
+}
+
+const DeliveryOrder: React.FC = async () => {
+ const { t } = await getServerI18n("do");
+
+ return (
+ <>
+
+
+ {t("Delivery Order")}
+
+
+ }>
+
+
+ >
+ )
+}
+
+export default DeliveryOrder;
\ No newline at end of file
diff --git a/src/app/api/do/actions.tsx b/src/app/api/do/actions.tsx
new file mode 100644
index 0000000..e69de29
diff --git a/src/app/api/do/index.tsx b/src/app/api/do/index.tsx
new file mode 100644
index 0000000..31494a8
--- /dev/null
+++ b/src/app/api/do/index.tsx
@@ -0,0 +1,21 @@
+import { serverFetchJson } from "@/app/utils/fetchUtil";
+import { BASE_API_URL } from "@/config/api";
+import { cache } from "react";
+
+export interface DoResult {
+ id: number,
+ code: string,
+ orderDate: string,
+ status: string,
+ shopName: string,
+}
+
+export const preloadDo = () => {
+ fetchDoList();
+}
+
+export const fetchDoList = cache(async () => {
+ return serverFetchJson(`${BASE_API_URL}/do/list`, {
+ next: { tags: ["doList"] }
+ })
+})
\ No newline at end of file
diff --git a/src/components/Breadcrumb/Breadcrumb.tsx b/src/components/Breadcrumb/Breadcrumb.tsx
index 863c5e2..3539937 100644
--- a/src/components/Breadcrumb/Breadcrumb.tsx
+++ b/src/components/Breadcrumb/Breadcrumb.tsx
@@ -20,6 +20,7 @@ const pathToLabelMap: { [path: string]: string } = {
"/scheduling/detail/edit": "FG Production Schedule",
"/inventory": "Inventory",
"/settings/importTesting": "Import Testing",
+ "/do": "Delivery Order",
};
const Breadcrumb = () => {
diff --git a/src/components/DoSave/DoSaveWrapper.tsx b/src/components/DoSave/DoSaveWrapper.tsx
new file mode 100644
index 0000000..e69de29
diff --git a/src/components/DoSave/index.ts b/src/components/DoSave/index.ts
new file mode 100644
index 0000000..2800028
--- /dev/null
+++ b/src/components/DoSave/index.ts
@@ -0,0 +1 @@
+export default from "./DoSaveWrapper"
\ No newline at end of file
diff --git a/src/components/DoSearch/DoSearch.tsx b/src/components/DoSearch/DoSearch.tsx
new file mode 100644
index 0000000..8230620
--- /dev/null
+++ b/src/components/DoSearch/DoSearch.tsx
@@ -0,0 +1,115 @@
+"use client";
+
+import { DoResult } from "@/app/api/do"
+import { useRouter } from "next/navigation";
+import { useCallback, useMemo, useState } from "react";
+import { useTranslation } from "react-i18next";
+import { Criterion } from "../SearchBox";
+import { isEmpty, sortBy, uniqBy, upperFirst } from "lodash";
+import { Column } from "../SearchResults";
+import { arrayToDateString, arrayToDayjs } from "@/app/utils/formatUtil";
+import SearchBox from "../SearchBox/SearchBox";
+import SearchResults from "../SearchResults/SearchResults";
+import { EditNote } from "@mui/icons-material";
+
+type Props = {
+ dos: DoResult[]
+}
+
+type SearchQuery = Partial>;
+type SearchParamNames = keyof SearchQuery;
+
+const DoSearch: React.FC = ({
+ dos
+}) => {
+
+ const [filteredDos, setFilteredDos] = useState(dos);
+ const { t } = useTranslation("do");
+ const router = useRouter();
+
+ const searchCriteria: Criterion[] = useMemo(() => [
+ { label: t("Code"), paramName: "code", type: "text" },
+
+ { label: t("Order Date From"), label2: t("Order Date To"), paramName: "orderDate", type: "dateRange" },
+ { label: t("Shop Name"), paramName: "shopName", type: "text" },
+ {
+ label: t("Status"), paramName: "status", type: "autocomplete", options: sortBy(
+ uniqBy(dos.map((_do) => ({ value: _do.status, label: t(upperFirst(_do.status)) })), "value"),
+ "label")
+ },
+ ], [t, dos])
+
+ const onReset = useCallback(() => {
+ setFilteredDos(dos)
+ }, [dos])
+
+ const onDetailClick = useCallback(
+ (doResult: DoResult) => {
+ router.push(`/do/edit?id=${doResult.id}`);
+ },
+ [router]
+ );
+
+
+ const columns = useMemo[]>(() => [
+ {
+ name: "id",
+ label: t("Details"),
+ onClick: onDetailClick,
+ buttonIcon: ,
+ },
+ {
+ name: "code",
+ label: t("Code")
+ },
+ {
+ name: "shopName",
+ label: t("Shop Name")
+ },
+ {
+ name: "orderDate",
+ label: t("Order Date"),
+ renderCell: (params) => {
+ return params.orderDate ? arrayToDateString(params.orderDate) : "N/A"
+ },
+ },
+ {
+ name: "status",
+ label: t("Status"),
+ renderCell: (params) => {
+ return t(upperFirst(params.status))
+ },
+ },
+ ], [t])
+
+ return (
+ <>
+ {
+ setFilteredDos(
+ dos.filter(
+ (_do) => {
+ const doOrderDateStr = arrayToDayjs(_do.orderDate)
+
+ return _do.code.toLowerCase().includes(query.code.toLowerCase())
+ && _do.shopName.toLowerCase().includes(query.shopName.toLowerCase())
+ && (query.status == "All" || _do.status.toLowerCase().includes(query.status.toLowerCase()))
+ && (isEmpty(query.orderDate) || doOrderDateStr.isSame(query.orderDate) || doOrderDateStr.isAfter(query.orderDate))
+ && (isEmpty(query.orderDateTo) || doOrderDateStr.isSame(query.orderDateTo) || doOrderDateStr.isBefore(query.orderDateTo))
+ }
+ )
+ )
+ }}
+ onReset={onReset}
+ />
+ items={filteredDos} columns={columns} pagingController={{
+ pageNum: 0,
+ pageSize: 0,
+ totalCount: 0,
+ }} />
+ >
+ )
+}
+
+export default DoSearch;
\ No newline at end of file
diff --git a/src/components/DoSearch/DoSearchWrapper.tsx b/src/components/DoSearch/DoSearchWrapper.tsx
new file mode 100644
index 0000000..4cf3631
--- /dev/null
+++ b/src/components/DoSearch/DoSearchWrapper.tsx
@@ -0,0 +1,22 @@
+import React from "react";
+import GeneralLoading from "../General/GeneralLoading"
+import { fetchDoList } from "@/app/api/do";
+import DoSearch from "./DoSearch";
+
+interface SubComponents {
+ Loading: typeof GeneralLoading;
+}
+
+const DoSearchWrapper: React.FC & SubComponents = async () => {
+
+ const [
+ dos
+ ] = await Promise.all([
+ fetchDoList()
+ ]);
+ return
+}
+
+DoSearchWrapper.Loading = GeneralLoading;
+
+export default DoSearchWrapper;
\ No newline at end of file
diff --git a/src/components/DoSearch/index.ts b/src/components/DoSearch/index.ts
new file mode 100644
index 0000000..4cb8a1d
--- /dev/null
+++ b/src/components/DoSearch/index.ts
@@ -0,0 +1 @@
+export { default } from "./DoSearchWrapper"
\ No newline at end of file
diff --git a/src/components/NavigationContent/NavigationContent.tsx b/src/components/NavigationContent/NavigationContent.tsx
index 29fdf4e..4817500 100644
--- a/src/components/NavigationContent/NavigationContent.tsx
+++ b/src/components/NavigationContent/NavigationContent.tsx
@@ -128,7 +128,7 @@ const NavigationContent: React.FC = () => {
{
icon: ,
label: "Delivery Order",
- path: "",
+ path: "/do",
},
],
},
diff --git a/src/components/SearchBox/SearchBox.tsx b/src/components/SearchBox/SearchBox.tsx
index a0f0e54..7cb767c 100644
--- a/src/components/SearchBox/SearchBox.tsx
+++ b/src/components/SearchBox/SearchBox.tsx
@@ -210,7 +210,7 @@ function SearchBox({
{c.type === "autocomplete" && (
option.group)
+ c.options.filter((option) => option.group !== "All").length > 0 && c.options.every((option) => option.group)
? (option) => (option.group && option.group.trim() !== '' ? option.group : 'Ungrouped')
: undefined
}