Kaynağa Gözat

DO search, pagination, translation update

master
kelvin.yau 3 ay önce
ebeveyn
işleme
aae7dbdd03
4 değiştirilmiş dosya ile 235 ekleme ve 82 silme
  1. +23
    -1
      src/app/api/do/actions.tsx
  2. +15
    -0
      src/app/api/do/index.tsx
  3. +187
    -79
      src/components/DoSearch/DoSearch.tsx
  4. +10
    -2
      src/i18n/zh/do.json

+ 23
- 1
src/app/api/do/actions.tsx Dosyayı Görüntüle

@@ -34,6 +34,18 @@ export interface DoDetailLine {
itemName?: string;
uomCode?: string;
}

export interface DoSearchAll {
id: number;
code: string;
status: string;
estimatedArrivalDate: string;
orderDate: string;
supplierName: string;
shopName: string;
deliveryOrderLines: DoDetailLine[];
}

export interface ReleaseDoRequest {
id: number;
}
@@ -68,4 +80,14 @@ export const fetchDoDetail = cache(async (id: number) => {
tags: ["doDetail"]
}
});
});
});

export const fetchDoSearch = cache(async (code: string, shopName: string, status: string, orderStartDate: string, orderEndDate: string, estArrStartDate: string, estArrEndDate: string)=>{
console.log(`${BASE_API_URL}/do/search-DO/${code}&${shopName}&${status}&${orderStartDate}&${orderEndDate}&${estArrStartDate}&${estArrEndDate}`);
return serverFetchJson<DoSearchAll[]>(`${BASE_API_URL}/do/search-DO/${code}&${shopName}&${status}&${orderStartDate}&${orderEndDate}&${estArrStartDate}&${estArrEndDate}`,{
method: "GET",
next: { tags: ["doSearch"] }
});
});


+ 15
- 0
src/app/api/do/index.tsx Dosyayı Görüntüle

@@ -13,6 +13,19 @@ export interface DoResult {
shopName: string;
}

export interface DoDetailLine {
id: number;
itemNo: string;
qty: number;
price: number;
status: string;
itemName?: string;
uomCode?: string;
}




export const preloadDo = () => {
fetchDoList();
};
@@ -22,3 +35,5 @@ export const fetchDoList = cache(async () => {
next: { tags: ["doList"] },
});
});



+ 187
- 79
src/components/DoSearch/DoSearch.tsx Dosyayı Görüntüle

@@ -1,15 +1,14 @@
"use client";

import { DoResult } from "@/app/api/do";
import { DoSearchAll, fetchDoSearch } from "@/app/api/do/actions";
import { useRouter } from "next/navigation";
import { useCallback, useMemo, useState } from "react";
import React, { useCallback, useEffect, 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";
import InputDataGrid from "../InputDataGrid";
import { CreateConsoDoInput } from "@/app/api/do/actions";
@@ -26,17 +25,22 @@ import {
SubmitErrorHandler,
SubmitHandler,
useForm,
} from "react-hook-form";
} from "react-hook-form";
import { Box, Button, Grid, Stack, Typography } from "@mui/material";
import StyledDataGrid from "../StyledDataGrid";
import { GridRowSelectionModel } from "@mui/x-data-grid";
import { TablePagination } from "@mui/material";



type Props = {
dos: DoResult[];
filterArgs?: Record<string, any>;
searchQuery?: Record<string, any>;
onDeliveryOrderSearch: () => void;
};
type SearchBoxInputs = Record<"code" | "status" | "estimatedArrivalDate" | "orderDate" | "supplierName" | "shopName" | "deliveryOrderLines" | "codeTo" | "statusTo" | "estimatedArrivalDateTo" | "orderDateTo" | "supplierNameTo" | "shopNameTo" | "deliveryOrderLinesTo" , string>;
type SearchParamNames = keyof SearchBoxInputs;

type SearchQuery = Partial<Omit<DoResult, "id">>;
type SearchParamNames = keyof SearchQuery;
// put all this into a new component
// ConsoDoForm
type EntryError =
@@ -46,7 +50,8 @@ type EntryError =
| undefined;
type DoRow = TableRow<Partial<DoResult>, EntryError>;

const DoSearch: React.FC<Props> = ({ dos }) => {

const DoSearch: React.FC<Props> = ({filterArgs, searchQuery, onDeliveryOrderSearch}) => {
const apiRef = useGridApiRef();

const formProps = useForm<CreateConsoDoInput>({
@@ -54,39 +59,66 @@ const DoSearch: React.FC<Props> = ({ dos }) => {
});
const errors = formProps.formState.errors;

const tttt = [
{
id: 1,
code: "string",
orderDate: "2025-01-01",
estimatedArrivalDate: "2025-01-01",
status: "string",
shopName: "string",
},
{
id: 2,
code: "string1",
orderDate: "2025-01-01",
estimatedArrivalDate: "2025-01-01",
status: "string",
shopName: "string",
},
{
id: 3,
code: "string2",
orderDate: "2025-01-01",
estimatedArrivalDate: "2025-01-01",
status: "string",
shopName: "string",
},
];
// const [filteredDos, setFilteredDos] = useState<DoResult[]>(dos);
const [filteredDos, setFilteredDos] = useState<DoResult[]>(tttt);
const { t } = useTranslation("do");
const router = useRouter();
const [rowSelectionModel, setRowSelectionModel] =
useState<GridRowSelectionModel>([]);

const [searchAllDos, setSearchAllDos] = useState<DoSearchAll[]>([]);

const [pagingController, setPagingController] = useState({
pageNum: 1,
pageSize: 10,
});

const handlePageChange = useCallback((event: unknown, newPage: number) => {
const newPagingController = {
...pagingController,
pageNum: newPage + 1,
};
setPagingController(newPagingController);
},[pagingController]);

const handlePageSizeChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
const newPageSize = parseInt(event.target.value, 10);
const newPagingController = {
pageNum: 1,
pageSize: newPageSize,
};
setPagingController(newPagingController);
}, []);

const pagedRows = useMemo(() => {
const start = (pagingController.pageNum - 1) * pagingController.pageSize;
return searchAllDos.slice(start, start + pagingController.pageSize);
}, [searchAllDos, pagingController]);

useEffect(() =>{
setPagingController(p => ({
...p,
pageNum: 1,
}));
}, [searchAllDos]);


//INITIALIZATION
useEffect(() => {
const loadItems = async () => {
try{
const itemsData = await fetchDoSearch("","","","","","","");
setSearchAllDos(itemsData);
}
catch (error){
console.error("Loading Error: ", error);
setSearchAllDos([]);
};
};
loadItems();
console.log("success");
},[]);


const searchCriteria: Criterion<SearchParamNames>[] = useMemo(
() => [
{ label: t("Code"), paramName: "code", type: "text" },
@@ -98,28 +130,39 @@ const DoSearch: React.FC<Props> = ({ dos }) => {
type: "dateRange",
},
{ label: t("Shop Name"), paramName: "shopName", type: "text" },

{
label: t("Estimated Arrival From"),
label2: t("Estimated Arrival To"),
paramName: "estimatedArrivalDate",
type: "dateRange",
},

{
label: t("Status"),
paramName: "status",
type: "autocomplete",
options: sortBy(
uniqBy(
dos.map((_do) => ({
value: _do.status,
label: t(upperFirst(_do.status)),
})),
"value",
),
"label",
),
},
options:[
{label: t('Pending'), value: 'pending'},
{label: t('Receiving'), value: 'receiving'},
{label: t('Completed'), value: 'completed'}
]
}
],
[t, dos],
[t],
);

const onReset = useCallback(() => {
setFilteredDos(dos);
}, [dos]);
const onReset = useCallback(async () => {
try {
const data = await fetchDoSearch("", "", "", "", "","","");
setSearchAllDos(data);

}
catch (error) {
console.error("Error: ", error);
setSearchAllDos([]);
}
}, []);

const onDetailClick = useCallback(
(doResult: DoResult) => {
@@ -155,7 +198,6 @@ const DoSearch: React.FC<Props> = ({ dos }) => {
// onClick: onDetailClick,
// buttonIcon: <EditNote />,
// },

{
field: "id",
headerName: t("Details"),
@@ -174,13 +216,18 @@ const DoSearch: React.FC<Props> = ({ dos }) => {
{
field: "code",
headerName: t("code"),
flex: 1,
flex: 1.5,
},
{
field: "shopName",
headerName: t("Shop Name"),
flex: 1,
},
{
field: "supplierName",
headerName: t("Supplier Name"),
flex: 1,
},
{
field: "orderDate",
headerName: t("Order Date"),
@@ -217,7 +264,6 @@ const DoSearch: React.FC<Props> = ({ dos }) => {
async (data, event) => {
const hasErrors = false;
console.log(errors);
console.log(data);
},
[],
);
@@ -225,6 +271,64 @@ const DoSearch: React.FC<Props> = ({ dos }) => {
(errors) => {},
[],
);
//SEARCH FUNCTION
const handleSearch = useCallback(async (query: SearchBoxInputs) => {
try {

let orderStartDate = query.orderDate;
let orderEndDate = query.orderDateTo;
let estArrStartDate = query.estimatedArrivalDate;
let estArrEndDate = query.estimatedArrivalDateTo;
const time = "T00:00:00";

if(orderStartDate != ""){
orderStartDate = query.orderDate + time;
}
if(orderEndDate != ""){
orderEndDate = query.orderDateTo + time;
}
if(estArrStartDate != ""){
estArrStartDate = query.estimatedArrivalDate + time;
}
if(estArrEndDate != ""){
estArrEndDate = query.estimatedArrivalDateTo + time;
}
let status = "";
if(query.status == "All"){
status = "";
}
else{
status = query.status;
}
const data = await fetchDoSearch(
query.code || "",
query.shopName || "",
status,
orderStartDate,
orderEndDate,
estArrStartDate,
estArrEndDate
);

console.log("Search parameters:", {
code: query.code,
shopName: query.shopName,
status: query.status,
orderStartDate,
orderEndDate,
estArrStartDate,
estArrEndDate
});

setSearchAllDos(data);
} catch (error) {
console.error("Error: ", error);
}
}, []);

return (
<>
<FormProvider {...formProps}>
@@ -246,6 +350,7 @@ const DoSearch: React.FC<Props> = ({ dos }) => {
justifyContent="end"
alignItems="end"
>
<Stack spacing={2} direction="row">
<Button
name="submit"
variant="contained"
@@ -254,39 +359,29 @@ const DoSearch: React.FC<Props> = ({ dos }) => {
>
{t("Create")}
</Button>
<Button
name="direct_release"
variant="contained"
type="submit"
>
{t("Direct Release")}
</Button>
</Stack>
</Grid>
</Grid>
<SearchBox
criteria={searchCriteria}
onSearch={(query) => {
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))
);
}),
);
}}

onSearch={handleSearch}

onReset={onReset}
/>
<StyledDataGrid
checkboxSelection={true}
rows={filteredDos}
rows={pagedRows}
columns={columns}
checkboxSelection
rowSelectionModel={rowSelectionModel}
onRowSelectionModelChange={(newRowSelectionModel) => {
setRowSelectionModel(newRowSelectionModel);
@@ -297,7 +392,19 @@ const DoSearch: React.FC<Props> = ({ dos }) => {
noRowsOverlay: NoRowsOverlay,
}}
/>
<TablePagination
component="div"
count={searchAllDos.length}
page={(pagingController.pageNum - 1)}
rowsPerPage={pagingController.pageSize}
onPageChange={handlePageChange}
onRowsPerPageChange={handlePageSizeChange}
rowsPerPageOptions={[10, 25, 50]}
/>

</Stack>

</FormProvider>
</>
);
@@ -319,4 +426,5 @@ const NoRowsOverlay: React.FC = () => {
</Box>
);
};

export default DoSearch;

+ 10
- 2
src/i18n/zh/do.json Dosyayı Görüntüle

@@ -6,10 +6,18 @@
"Delivery Order Status": "交貨單狀態",
"Order Date": "訂單日期",
"Estimated Arrival": "預計到貨日期",
"Estimated Arrival From": "預計到貨日期從",
"Estimated Arrival To": "預計到貨日期到",
"Status": "來貨狀態",
"Order Date From": "訂單日期從",
"Order Date From": "訂單日期",
"Order Date To": "訂單日期到",
"Code": "編號",
"code": "編號",
"Create": "新增"
"Create": "新增",
"Supplier Name": "供應商名稱",
"Details": "詳情",
"Pending": "待處理",
"Receiving": "接收中",
"Completed": "已完成"

}

Yükleniyor…
İptal
Kaydet