# Conflicts: # src/components/DetailScheduleDetail/DetailScheudleDetailView.tsxmaster
| @@ -2,7 +2,6 @@ | |||||
| // import DetailSchedule from "@/components/DetailSchedule"; | // import DetailSchedule from "@/components/DetailSchedule"; | ||||
| // import { getServerI18n } from "@/i18n"; | // import { getServerI18n } from "@/i18n"; | ||||
| import { TypeEnum } from "../../../../app/utils/typeEnum"; | |||||
| import DetailSchedule from "../../../../components/DetailSchedule"; | import DetailSchedule from "../../../../components/DetailSchedule"; | ||||
| import { getServerI18n } from "../../../../i18n"; | import { getServerI18n } from "../../../../i18n"; | ||||
| import { I18nProvider } from "@/i18n"; | import { I18nProvider } from "@/i18n"; | ||||
| @@ -16,8 +15,8 @@ export const metadata: Metadata = { | |||||
| }; | }; | ||||
| const DetailScheduling: React.FC = async () => { | const DetailScheduling: React.FC = async () => { | ||||
| const project = TypeEnum.PRODUCT | |||||
| const { t } = await getServerI18n("detailScheduling"); | |||||
| const { t } = await getServerI18n("schedule"); | |||||
| const type = "detailed" | |||||
| // preloadClaims(); | // preloadClaims(); | ||||
| return ( | return ( | ||||
| @@ -32,9 +31,9 @@ const DetailScheduling: React.FC = async () => { | |||||
| {t("Detail Scheduling")} | {t("Detail Scheduling")} | ||||
| </Typography> | </Typography> | ||||
| </Stack> | </Stack> | ||||
| <I18nProvider namespaces={["detailScheduling", "items", "common","schedule"]}> | |||||
| <I18nProvider namespaces={["schedule", "common"]}> | |||||
| <Suspense fallback={<DetailSchedule.Loading />}> | <Suspense fallback={<DetailSchedule.Loading />}> | ||||
| <DetailSchedule /> | |||||
| <DetailSchedule type={type}/> | |||||
| </Suspense> | </Suspense> | ||||
| </I18nProvider> | </I18nProvider> | ||||
| </> | </> | ||||
| @@ -1,6 +1,7 @@ | |||||
| // import { TypeEnum } from "@/app/utils/typeEnum"; | // import { TypeEnum } from "@/app/utils/typeEnum"; | ||||
| // import RoughSchedule from "@/components/RoughSchedule"; | // import RoughSchedule from "@/components/RoughSchedule"; | ||||
| // import { getServerI18n, I18nProvider } from "@/i18n"; | // import { getServerI18n, I18nProvider } from "@/i18n"; | ||||
| import { testRoughSchedule } from "@/app/api/scheduling/actions"; | |||||
| import { TypeEnum } from "../../../../app/utils/typeEnum"; | import { TypeEnum } from "../../../../app/utils/typeEnum"; | ||||
| import RoughSchedule from "../../../../components/RoughSchedule"; | import RoughSchedule from "../../../../components/RoughSchedule"; | ||||
| import { getServerI18n, I18nProvider } from "../../../../i18n"; | import { getServerI18n, I18nProvider } from "../../../../i18n"; | ||||
| @@ -22,6 +23,10 @@ const roughScheduling: React.FC = async () => { | |||||
| const type = "rough" | const type = "rough" | ||||
| // preloadClaims(); | // preloadClaims(); | ||||
| // async function testingRoughSchedule() { | |||||
| // await testRoughSchedule(); | |||||
| // } | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| <Stack | <Stack | ||||
| @@ -33,19 +38,18 @@ const roughScheduling: React.FC = async () => { | |||||
| <Typography variant="h4" marginInlineEnd={2}> | <Typography variant="h4" marginInlineEnd={2}> | ||||
| {t("Demand Forecast")} | {t("Demand Forecast")} | ||||
| </Typography> | </Typography> | ||||
| {/* <Button | {/* <Button | ||||
| variant="contained" | |||||
| startIcon={<Add />} | |||||
| LinkComponent={Link} | |||||
| href="product/create" | |||||
| > | |||||
| {t("Create product")} | |||||
| </Button> */} | |||||
| variant="contained" | |||||
| startIcon={<Add />} | |||||
| onClick={() => testingRoughSchedule} | |||||
| > | |||||
| {t("Test Rough Scheduling")} | |||||
| </Button> */} | |||||
| </Stack> | </Stack> | ||||
| <I18nProvider namespaces={["schedule", "common","items","project"]}> | |||||
| <I18nProvider namespaces={["schedule", "common"]}> | |||||
| <Suspense fallback={<RoughSchedule.Loading />}> | <Suspense fallback={<RoughSchedule.Loading />}> | ||||
| <RoughSchedule type={type}/> | |||||
| <RoughSchedule type={type} /> | |||||
| </Suspense> | </Suspense> | ||||
| </I18nProvider> | </I18nProvider> | ||||
| </> | </> | ||||
| @@ -4,13 +4,14 @@ import { convertObjToURLSearchParams } from "@/app/utils/commonUtil"; | |||||
| import { serverFetchJson } from "@/app/utils/fetchUtil" | import { serverFetchJson } from "@/app/utils/fetchUtil" | ||||
| import { BASE_API_URL } from "@/config/api" | import { BASE_API_URL } from "@/config/api" | ||||
| import { cache } from "react" | import { cache } from "react" | ||||
| import { ScheduleType } from "."; | |||||
| export interface SearchProdSchedule { | export interface SearchProdSchedule { | ||||
| scheduleAt?: string; | scheduleAt?: string; | ||||
| schedulePeriod?: string; | schedulePeriod?: string; | ||||
| schedulePeriodTo?: string; | schedulePeriodTo?: string; | ||||
| totalEstProdCount?: number; | totalEstProdCount?: number; | ||||
| type?: "manual" | "detailed" | "rough"; | |||||
| types?: ScheduleType[]; | |||||
| pageSize?: number; | pageSize?: number; | ||||
| pageNum?: number; | pageNum?: number; | ||||
| } | } | ||||
| @@ -40,4 +41,24 @@ export const fetchProdSchedules = cache(async (data: SearchProdSchedule | null) | |||||
| tags: ["prodSchedules"] | tags: ["prodSchedules"] | ||||
| } | } | ||||
| }) | }) | ||||
| }) | |||||
| export const testRoughSchedule = cache(async () => { | |||||
| return serverFetchJson(`${BASE_API_URL}/productionSchedule/testRoughSchedule`, { | |||||
| method: "GET", | |||||
| headers: { "Content-Type": "application/json" }, | |||||
| next: { | |||||
| tags: ["prodSchedules"] | |||||
| } | |||||
| }) | |||||
| }) | |||||
| export const testDetailSchedule = cache(async () => { | |||||
| return serverFetchJson(`${BASE_API_URL}/productionSchedule/testDetailSchedule`, { | |||||
| method: "GET", | |||||
| headers: { "Content-Type": "application/json" }, | |||||
| next: { | |||||
| tags: ["prodSchedules"] | |||||
| } | |||||
| }) | |||||
| }) | }) | ||||
| @@ -3,9 +3,9 @@ import { BASE_API_URL } from "@/config/api" | |||||
| import { cache } from "react" | import { cache } from "react" | ||||
| import "server-only" | import "server-only" | ||||
| export type ScheduleType = "rough" | "detail"; | |||||
| export type ScheduleType = "all" | "rough" | "detailed" | "manual"; | |||||
| export interface ProdScheduleResult { | |||||
| export interface RoughProdScheduleResult { | |||||
| id: number; | id: number; | ||||
| scheduleAt: number[]; | scheduleAt: number[]; | ||||
| schedulePeriod: number[]; | schedulePeriod: number[]; | ||||
| @@ -13,13 +13,13 @@ export interface ProdScheduleResult { | |||||
| totalEstProdCount: number; | totalEstProdCount: number; | ||||
| totalFGType: number; | totalFGType: number; | ||||
| type: string; | type: string; | ||||
| prodScheduleLinesByFg: ProdScheduleLineResultByFg[]; | |||||
| prodScheduleLinesByFgByDate: { [assignDate: number]: ProdScheduleLineResultByFg[] }; | |||||
| prodScheduleLinesByBom: ProdScheduleLineResultByBom[]; | |||||
| prodScheduleLinesByBomByDate: { [assignDate: number]: ProdScheduleLineResultByBomByDate[] }; | |||||
| prodScheduleLinesByFg: RoughProdScheduleLineResultByFg[]; | |||||
| prodScheduleLinesByFgByDate: { [assignDate: number]: RoughProdScheduleLineResultByFg[] }; | |||||
| prodScheduleLinesByBom: RoughProdScheduleLineResultByBom[]; | |||||
| prodScheduleLinesByBomByDate: { [assignDate: number]: RoughProdScheduleLineResultByBomByDate[] }; | |||||
| } | } | ||||
| export interface ProdScheduleLineResultByFg { | |||||
| export interface RoughProdScheduleLineResultByFg { | |||||
| id: number; | id: number; | ||||
| code: string; | code: string; | ||||
| name: string; | name: string; | ||||
| @@ -30,10 +30,10 @@ export interface ProdScheduleLineResultByFg { | |||||
| estCloseBal: number; | estCloseBal: number; | ||||
| priority: number; | priority: number; | ||||
| assignDate: number; | assignDate: number; | ||||
| bomMaterials: ProdScheduleLineBomMaterialResult[]; | |||||
| bomMaterials: RoughProdScheduleLineBomMaterialResult[]; | |||||
| } | } | ||||
| export interface ProdScheduleLineBomMaterialResult { | |||||
| export interface RoughProdScheduleLineBomMaterialResult { | |||||
| id: number; | id: number; | ||||
| code: string; | code: string; | ||||
| name: string; | name: string; | ||||
| @@ -43,7 +43,7 @@ export interface ProdScheduleLineBomMaterialResult { | |||||
| uomName: string; | uomName: string; | ||||
| } | } | ||||
| export interface ProdScheduleLineResultByBom { | |||||
| export interface RoughProdScheduleLineResultByBom { | |||||
| id: number, | id: number, | ||||
| code: string, | code: string, | ||||
| name: string, | name: string, | ||||
| @@ -60,7 +60,7 @@ export interface ProdScheduleLineResultByBom { | |||||
| uomName: string, | uomName: string, | ||||
| } | } | ||||
| export interface ProdScheduleLineResultByBomByDate { | |||||
| export interface RoughProdScheduleLineResultByBomByDate { | |||||
| id: number, | id: number, | ||||
| code: string, | code: string, | ||||
| name: string, | name: string, | ||||
| @@ -72,7 +72,7 @@ export interface ProdScheduleLineResultByBomByDate { | |||||
| } | } | ||||
| export const fetchProdScheduleDetail = cache(async (id: number) => { | export const fetchProdScheduleDetail = cache(async (id: number) => { | ||||
| return serverFetchJson<ProdScheduleResult>(`${BASE_API_URL}/productionSchedule/detail/${id}`, { | |||||
| return serverFetchJson<RoughProdScheduleResult>(`${BASE_API_URL}/productionSchedule/detail/${id}`, { | |||||
| method: "GET", | method: "GET", | ||||
| headers: { "Content-Type": "application/json" }, | headers: { "Content-Type": "application/json" }, | ||||
| next: { | next: { | ||||
| @@ -1,67 +1,75 @@ | |||||
| "use client"; | "use client"; | ||||
| import React, {useCallback, useEffect, useMemo, useState} from "react"; | |||||
| import React, { useCallback, useEffect, useMemo, useState } from "react"; | |||||
| import SearchBox, { Criterion } from "../SearchBox"; | import SearchBox, { Criterion } from "../SearchBox"; | ||||
| import { ItemsResult} from "@/app/api/settings/item"; | |||||
| import { ItemsResult } from "@/app/api/settings/item"; | |||||
| import SearchResults, { Column } from "../SearchResults"; | import SearchResults, { Column } from "../SearchResults"; | ||||
| import { EditNote } from "@mui/icons-material"; | import { EditNote } from "@mui/icons-material"; | ||||
| import { useRouter, useSearchParams } from "next/navigation"; | import { useRouter, useSearchParams } from "next/navigation"; | ||||
| import { GridDeleteIcon } from "@mui/x-data-grid"; | import { GridDeleteIcon } from "@mui/x-data-grid"; | ||||
| import { TypeEnum } from "@/app/utils/typeEnum"; | import { TypeEnum } from "@/app/utils/typeEnum"; | ||||
| import axios from "axios"; | import axios from "axios"; | ||||
| import {BASE_API_URL, NEXT_PUBLIC_API_URL} from "@/config/api"; | |||||
| import { BASE_API_URL, NEXT_PUBLIC_API_URL } from "@/config/api"; | |||||
| import { useTranslation } from "react-i18next"; | import { useTranslation } from "react-i18next"; | ||||
| import axiosInstance from "@/app/(main)/axios/axiosInstance"; | import axiosInstance from "@/app/(main)/axios/axiosInstance"; | ||||
| import Qs from 'qs'; | import Qs from 'qs'; | ||||
| import EditableSearchResults from "@/components/SearchResults/EditableSearchResults"; // Make sure to import Qs | import EditableSearchResults from "@/components/SearchResults/EditableSearchResults"; // Make sure to import Qs | ||||
| import { ScheduleType } from "@/app/api/scheduling"; | |||||
| import { ProdScheduleResult, SearchProdSchedule, fetchProdSchedules } from "@/app/api/scheduling/actions"; | |||||
| import { defaultPagingController } from "../SearchResults/SearchResults"; | |||||
| import { arrayToDateString, decimalFormatter } from "@/app/utils/formatUtil"; | |||||
| import dayjs from "dayjs"; | |||||
| import { uniqBy } from "lodash"; | |||||
| // may need move to "index" or "actions" | // may need move to "index" or "actions" | ||||
| type RecordStructure = { | |||||
| id: number, | |||||
| scheduledPeriod: string, | |||||
| scheduledAt: string, | |||||
| productCount: number, | |||||
| }; | |||||
| // type RecordStructure = { | |||||
| // id: number, | |||||
| // scheduledPeriod: string, | |||||
| // scheduledAt: string, | |||||
| // productCount: number, | |||||
| // }; | |||||
| type Props = { | type Props = { | ||||
| records: RecordStructure[]; | |||||
| type: ScheduleType; | |||||
| // records: RecordStructure[]; | |||||
| defaultInputs: SearchProdSchedule; | |||||
| }; | }; | ||||
| type SearchQuery = Partial<Omit<RecordStructure, "id">>; | |||||
| type SearchQuery = Partial<Omit<SearchProdSchedule, "id" | "pageSize" | "pageNum">>; | |||||
| type SearchParamNames = keyof SearchQuery; | type SearchParamNames = keyof SearchQuery; | ||||
| const DSOverview: React.FC<Props> = ({ records }) => { | |||||
| const [filteredItems, setFilteredItems] = useState<RecordStructure[]>(records ?? []); | |||||
| const { t } = useTranslation("detailScheduling"); | |||||
| const DSOverview: React.FC<Props> = ({ type, defaultInputs }) => { | |||||
| const [filteredSchedules, setFilteredSchedules] = useState<ProdScheduleResult[]>([]); | |||||
| const { t } = useTranslation("schedule"); | |||||
| const router = useRouter(); | const router = useRouter(); | ||||
| const [filterObj, setFilterObj] = useState({}); | |||||
| const [tempSelectedValue, setTempSelectedValue] = useState({}); | |||||
| const [pagingController, setPagingController] = useState({ | |||||
| pageNum: 1, | |||||
| pageSize: 10, | |||||
| totalCount: 0, | |||||
| }) | |||||
| const [mode, redirPath] = useMemo(() => { | |||||
| // var typeId = TypeEnum.CONSUMABLE_ID | |||||
| let title = ""; | |||||
| const mode = "Search"; | |||||
| let redirPath = ""; | |||||
| title = "Product"; | |||||
| redirPath = "/scheduling/detail"; | |||||
| return [mode, redirPath]; | |||||
| }, []); | |||||
| // const [filterObj, setFilterObj] = useState({}); | |||||
| // const [tempSelectedValue, setTempSelectedValue] = useState({}); | |||||
| const [pagingController, setPagingController] = useState(defaultPagingController) | |||||
| const [totalCount, setTotalCount] = useState(0) | |||||
| const [inputs, setInputs] = useState(defaultInputs) | |||||
| const typeOptions = [ | |||||
| { | |||||
| value: "detailed", | |||||
| label: t("Detailed") | |||||
| }, | |||||
| { | |||||
| value: "manual", | |||||
| label: t("Manual") | |||||
| }, | |||||
| ] | |||||
| const searchCriteria: Criterion<SearchParamNames>[] = useMemo( | const searchCriteria: Criterion<SearchParamNames>[] = useMemo( | ||||
| () => | |||||
| [ | |||||
| { label: t("Schedule Period"), paramName: "scheduledPeriod", type: "dateRange" }, | |||||
| { label: t("Scheduled At"), paramName: "scheduledAt", type: "dateRange" }, | |||||
| { label: t("Product Count"), paramName: "productCount", type: "text" }, | |||||
| () => { | |||||
| var searchCriteria: Criterion<SearchParamNames>[] = [ | |||||
| { label: t("Schedule Period"), label2: t("Schedule Period To"), paramName: "schedulePeriod", type: "dateRange" }, | |||||
| { label: t("Production Date"), paramName: "scheduleAt", type: "date" }, | |||||
| { label: t("Product Count"), paramName: "totalEstProdCount", type: "text" }, | |||||
| { label: t("Type"), paramName: "types", type: "autocomplete", options: typeOptions }, | |||||
| ] | ] | ||||
| , | |||||
| [t, records] | |||||
| return searchCriteria | |||||
| }, | |||||
| [t] | |||||
| ); | ); | ||||
| // const onDetailClick = useCallback( | // const onDetailClick = useCallback( | ||||
| @@ -71,36 +79,54 @@ const DSOverview: React.FC<Props> = ({ records }) => { | |||||
| // [router] | // [router] | ||||
| // ); | // ); | ||||
| const onDeleteClick = useCallback( | |||||
| (item: ItemsResult) => {}, | |||||
| [router] | |||||
| ); | |||||
| // const onDeleteClick = useCallback( | |||||
| // (item: ItemsResult) => {}, | |||||
| // [router] | |||||
| // ); | |||||
| const onDetailClick = (record: any) => { | |||||
| const onDetailClick = (record: ProdScheduleResult) => { | |||||
| console.log("[debug] record", record); | console.log("[debug] record", record); | ||||
| router.push(`/scheduling/detail/edit?id=${record.id}`); | router.push(`/scheduling/detail/edit?id=${record.id}`); | ||||
| } | } | ||||
| const columns = useMemo<Column<RecordStructure>[]>( | |||||
| const columns = useMemo<Column<ProdScheduleResult>[]>( | |||||
| () => [ | () => [ | ||||
| { | { | ||||
| name: "id", | name: "id", | ||||
| label: t("Details"), | label: t("Details"), | ||||
| onClick: (record)=>onDetailClick(record), | |||||
| onClick: (record) => onDetailClick(record), | |||||
| buttonIcon: <EditNote />, | buttonIcon: <EditNote />, | ||||
| }, | }, | ||||
| { | { | ||||
| name: "scheduledPeriod", | |||||
| name: "schedulePeriod", | |||||
| label: t("Demand Forecast Period"), | label: t("Demand Forecast Period"), | ||||
| renderCell: (params) => { | |||||
| return `${arrayToDateString(params.schedulePeriod)} - ${arrayToDateString(params.schedulePeriodTo)}` | |||||
| } | |||||
| }, | }, | ||||
| { | { | ||||
| name: "scheduledAt", | |||||
| label: t("Scheduled At"), | |||||
| name: "scheduleAt", | |||||
| label: t("Production Date"), | |||||
| renderCell: (params) => { | |||||
| return arrayToDateString(params.scheduleAt) | |||||
| } | |||||
| }, | }, | ||||
| { | { | ||||
| name: "productCount", | |||||
| name: "totalEstProdCount", | |||||
| label: t("Product Count(s)"), | label: t("Product Count(s)"), | ||||
| headerAlign: "right", | |||||
| align: "right", | |||||
| renderCell: (params) => { | |||||
| return decimalFormatter.format(params.totalEstProdCount) | |||||
| } | |||||
| }, | |||||
| { | |||||
| name: "type", | |||||
| label: t("Type"), | |||||
| renderCell: (params) => { | |||||
| return t(params.type) | |||||
| } | |||||
| }, | }, | ||||
| // { | // { | ||||
| // name: "action", | // name: "action", | ||||
| @@ -109,92 +135,138 @@ const DSOverview: React.FC<Props> = ({ records }) => { | |||||
| // onClick: onDeleteClick, | // onClick: onDeleteClick, | ||||
| // }, | // }, | ||||
| ], | ], | ||||
| [filteredItems] | |||||
| [filteredSchedules] | |||||
| ); | ); | ||||
| const refetchData = useCallback(async (query: Record<SearchParamNames, string> | SearchProdSchedule, actionType: "reset" | "search" | "paging") => { | |||||
| // console.log(query) | |||||
| const defaultTypes = ["detailed", "manual"] | |||||
| const convertedTypes = (query.types == undefined || typeof (query.types) == "string" ? query.types?.toLowerCase() == "all" ? defaultTypes : [query.types] | |||||
| : query.types.some((ele) => ele.toLowerCase() === "all") ? defaultTypes : query.types) as ScheduleType[]; | |||||
| console.log(convertedTypes) | |||||
| console.log(query.types) | |||||
| const params: SearchProdSchedule = { | |||||
| scheduleAt: dayjs(query?.scheduleAt).isValid() ? query?.scheduleAt : undefined, | |||||
| schedulePeriod: dayjs(query?.schedulePeriod).isValid() ? query?.schedulePeriod : undefined, | |||||
| schedulePeriodTo: dayjs(query?.schedulePeriodTo).isValid() ? query?.schedulePeriodTo : undefined, | |||||
| totalEstProdCount: query?.totalEstProdCount ? Number(query?.totalEstProdCount) : undefined, | |||||
| types: convertedTypes, | |||||
| pageNum: pagingController.pageNum - 1, | |||||
| pageSize: pagingController.pageSize | |||||
| } | |||||
| const response = await fetchProdSchedules(params) | |||||
| // console.log(response) | |||||
| if (response) { | |||||
| setTotalCount(response.total) | |||||
| switch (actionType) { | |||||
| case "reset": | |||||
| case "search": | |||||
| setFilteredSchedules(() => response.records) | |||||
| break; | |||||
| case "paging": | |||||
| setFilteredSchedules((fs) => uniqBy([...fs, ...response.records], "id")) | |||||
| break; | |||||
| } | |||||
| } | |||||
| }, [pagingController, setPagingController]) | |||||
| useEffect(() => { | useEffect(() => { | ||||
| refetchData(filterObj); | |||||
| refetchData(inputs, "paging") | |||||
| }, [pagingController]) | |||||
| }, [filterObj, pagingController.pageNum, pagingController.pageSize]); | |||||
| // useEffect(() => { | |||||
| // refetchData(filterObj); | |||||
| const refetchData = async (filterObj: SearchQuery | null) => { | |||||
| // }, [filterObj, pagingController.pageNum, pagingController.pageSize]); | |||||
| const authHeader = axiosInstance.defaults.headers['Authorization']; | |||||
| if (!authHeader) { | |||||
| return; // Exit the function if the token is not set | |||||
| } | |||||
| // const refetchData = async (filterObj: SearchQuery | null) => { | |||||
| const params ={ | |||||
| pageNum: pagingController.pageNum, | |||||
| pageSize: pagingController.pageSize, | |||||
| ...filterObj, | |||||
| ...tempSelectedValue, | |||||
| } | |||||
| // const authHeader = axiosInstance.defaults.headers['Authorization']; | |||||
| // if (!authHeader) { | |||||
| // return; // Exit the function if the token is not set | |||||
| // } | |||||
| try { | |||||
| const response = await axiosInstance.get<ItemsResult[]>(`${NEXT_PUBLIC_API_URL}/items/getRecordByPage`, { | |||||
| params, | |||||
| paramsSerializer: (params) => { | |||||
| return Qs.stringify(params, { arrayFormat: 'repeat' }); | |||||
| }, | |||||
| }); | |||||
| //setFilteredItems(response.data.records); | |||||
| setFilteredItems([ | |||||
| { | |||||
| id: 1, | |||||
| scheduledPeriod: "2025-05-11 to 2025-05-17", | |||||
| scheduledAt: "2025-05-07", | |||||
| productCount: 13, | |||||
| }, | |||||
| { | |||||
| id: 2, | |||||
| scheduledPeriod: "2025-05-18 to 2025-05-24", | |||||
| scheduledAt: "2025-05-14", | |||||
| productCount: 15, | |||||
| }, | |||||
| { | |||||
| id: 3, | |||||
| scheduledPeriod: "2025-05-25 to 2025-05-31", | |||||
| scheduledAt: "2025-05-21", | |||||
| productCount: 13, | |||||
| }, | |||||
| ]) | |||||
| setPagingController({ | |||||
| ...pagingController, | |||||
| totalCount: response.data.total | |||||
| }) | |||||
| return response; // Return the data from the response | |||||
| } catch (error) { | |||||
| console.error('Error fetching items:', error); | |||||
| throw error; // Rethrow the error for further handling | |||||
| } | |||||
| }; | |||||
| // const params = { | |||||
| // pageNum: pagingController.pageNum, | |||||
| // pageSize: pagingController.pageSize, | |||||
| // ...filterObj, | |||||
| // ...tempSelectedValue, | |||||
| // } | |||||
| // try { | |||||
| // const response = await axiosInstance.get<ItemsResult[]>(`${NEXT_PUBLIC_API_URL}/items/getRecordByPage`, { | |||||
| // params, | |||||
| // paramsSerializer: (params) => { | |||||
| // return Qs.stringify(params, { arrayFormat: 'repeat' }); | |||||
| // }, | |||||
| // }); | |||||
| // //setFilteredItems(response.data.records); | |||||
| // setFilteredItems([ | |||||
| // { | |||||
| // id: 1, | |||||
| // scheduledPeriod: "2025-05-11 to 2025-05-17", | |||||
| // scheduledAt: "2025-05-07", | |||||
| // productCount: 13, | |||||
| // }, | |||||
| // { | |||||
| // id: 2, | |||||
| // scheduledPeriod: "2025-05-18 to 2025-05-24", | |||||
| // scheduledAt: "2025-05-14", | |||||
| // productCount: 15, | |||||
| // }, | |||||
| // { | |||||
| // id: 3, | |||||
| // scheduledPeriod: "2025-05-25 to 2025-05-31", | |||||
| // scheduledAt: "2025-05-21", | |||||
| // productCount: 13, | |||||
| // }, | |||||
| // ]) | |||||
| // setPagingController({ | |||||
| // ...pagingController, | |||||
| // totalCount: response.data.total | |||||
| // }) | |||||
| // return response; // Return the data from the response | |||||
| // } catch (error) { | |||||
| // console.error('Error fetching items:', error); | |||||
| // throw error; // Rethrow the error for further handling | |||||
| // } | |||||
| // }; | |||||
| const onReset = useCallback(() => { | const onReset = useCallback(() => { | ||||
| //setFilteredItems(items ?? []); | //setFilteredItems(items ?? []); | ||||
| setFilterObj({}); | |||||
| setTempSelectedValue({}); | |||||
| refetchData(null); | |||||
| }, [records]); | |||||
| // setFilterObj({}); | |||||
| // setTempSelectedValue({}); | |||||
| refetchData(inputs, "reset"); | |||||
| }, []); | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| <SearchBox | <SearchBox | ||||
| criteria={searchCriteria} | criteria={searchCriteria} | ||||
| onSearch={(query) => { | onSearch={(query) => { | ||||
| setFilterObj({ | |||||
| ...query | |||||
| }) | |||||
| setInputs(() => ( | |||||
| { | |||||
| scheduleAt: query?.scheduleAt, | |||||
| schedulePeriod: query?.schedulePeriod, | |||||
| schedulePeriodTo: query?.schedulePeriodTo, | |||||
| totalEstProdCount: Number(query?.totalEstProdCount), | |||||
| types: query.types as unknown as ScheduleType[] | |||||
| } | |||||
| )) | |||||
| refetchData(query, "search") | |||||
| }} | }} | ||||
| onReset={onReset} | onReset={onReset} | ||||
| /> | /> | ||||
| <SearchResults<RecordStructure> | |||||
| items={filteredItems} | |||||
| <SearchResults<ProdScheduleResult> | |||||
| items={filteredSchedules} | |||||
| columns={columns} | columns={columns} | ||||
| setPagingController={setPagingController} | setPagingController={setPagingController} | ||||
| pagingController={pagingController} | pagingController={pagingController} | ||||
| isAutoPaging={false} | |||||
| // hasCollapse={false} | |||||
| totalCount={totalCount} | |||||
| // isAutoPaging={false} | |||||
| // hasCollapse={false} | |||||
| /> | /> | ||||
| </> | </> | ||||
| ); | ); | ||||
| @@ -1,14 +1,26 @@ | |||||
| import React from "react"; | import React from "react"; | ||||
| import {DetailScheduleLoading} from "./DetailScheduleLoading"; | import {DetailScheduleLoading} from "./DetailScheduleLoading"; | ||||
| import DSOverview from "./DetailScheduleSearchView"; | import DSOverview from "./DetailScheduleSearchView"; | ||||
| import { ScheduleType } from "@/app/api/scheduling"; | |||||
| import { SearchProdSchedule } from "@/app/api/scheduling/actions"; | |||||
| interface SubComponents { | interface SubComponents { | ||||
| Loading: typeof DetailScheduleLoading; | Loading: typeof DetailScheduleLoading; | ||||
| } | } | ||||
| const DetailScheduleWrapper: React.FC & SubComponents = async () => { | |||||
| type Props = { | |||||
| type: ScheduleType | |||||
| } | |||||
| const DetailScheduleWrapper: React.FC<Props> & SubComponents = async ({ | |||||
| type | |||||
| }) => { | |||||
| const defaultInputs: SearchProdSchedule = { | |||||
| types: ["detailed", "manual"] | |||||
| } | |||||
| return <DSOverview records={[]} />; | |||||
| return <DSOverview type={type} defaultInputs={defaultInputs} />; | |||||
| }; | }; | ||||
| DetailScheduleWrapper.Loading = DetailScheduleLoading; | DetailScheduleWrapper.Loading = DetailScheduleLoading; | ||||
| @@ -23,11 +23,14 @@ import { SaveDetailSchedule } from "./DetailScheudleDetailView"; | |||||
| // temp interface input | // temp interface input | ||||
| type Props = { | type Props = { | ||||
| recordDetails: SaveDetailSchedule; | |||||
| // recordDetails: SaveDetailSchedule; | |||||
| isEditing: boolean; | isEditing: boolean; | ||||
| }; | }; | ||||
| const DetailInfoCard: React.FC<Props> = ({ recordDetails, isEditing }) => { | |||||
| const DetailInfoCard: React.FC<Props> = ({ | |||||
| // recordDetails, | |||||
| isEditing | |||||
| }) => { | |||||
| const { | const { | ||||
| t, | t, | ||||
| i18n: { language }, | i18n: { language }, | ||||
| @@ -39,12 +42,12 @@ const DetailInfoCard: React.FC<Props> = ({ recordDetails, isEditing }) => { | |||||
| formState: { errors, defaultValues, touchedFields }, | formState: { errors, defaultValues, touchedFields }, | ||||
| } = useFormContext<SaveDetailSchedule>(); | } = useFormContext<SaveDetailSchedule>(); | ||||
| const [details, setDetails] = useState<SaveDetailSchedule|null>(null); | |||||
| const [details, setDetails] = useState<SaveDetailSchedule | undefined>(undefined); | |||||
| useEffect(() => { | useEffect(() => { | ||||
| console.log("[debug] record details", recordDetails) | |||||
| setDetails(recordDetails); | |||||
| }, [recordDetails]) | |||||
| console.log("[debug] record details", defaultValues) | |||||
| setDetails(defaultValues as SaveDetailSchedule); | |||||
| }, [defaultValues]) | |||||
| useEffect(() => { | useEffect(() => { | ||||
| console.log("[debug] isEdit", isEditing) | console.log("[debug] isEdit", isEditing) | ||||
| @@ -36,7 +36,7 @@ type Props = { | |||||
| isEditMode: boolean; | isEditMode: boolean; | ||||
| // type: TypeEnum; | // type: TypeEnum; | ||||
| defaultValues: Partial<SaveDetailSchedule> | undefined; | defaultValues: Partial<SaveDetailSchedule> | undefined; | ||||
| qcChecks: ItemQc[] | |||||
| // qcChecks: ItemQc[] | |||||
| }; | }; | ||||
| const DetailScheduleDetailView: React.FC<Props> = ({ | const DetailScheduleDetailView: React.FC<Props> = ({ | ||||
| @@ -89,7 +89,7 @@ const DetailScheduleDetailView: React.FC<Props> = ({ | |||||
| productionDate: "2025-05-07", | productionDate: "2025-05-07", | ||||
| totalJobOrders: 13, | totalJobOrders: 13, | ||||
| totalProductionQty: 21000, | totalProductionQty: 21000, | ||||
| }, | |||||
| } as SaveDetailSchedule, | |||||
| }); | }); | ||||
| const errors = formProps.formState.errors; | const errors = formProps.formState.errors; | ||||
| @@ -157,7 +157,7 @@ const DetailScheduleDetailView: React.FC<Props> = ({ | |||||
| {/* </Typography>*/} | {/* </Typography>*/} | ||||
| {/*</Grid>*/} | {/*</Grid>*/} | ||||
| <DetailInfoCard | <DetailInfoCard | ||||
| recordDetails={formProps.formState.defaultValues as SaveDetailSchedule} | |||||
| // recordDetails={formProps.formState.defaultValues} | |||||
| isEditing={isEdit} | isEditing={isEdit} | ||||
| /> | /> | ||||
| <Stack | <Stack | ||||
| @@ -2,7 +2,7 @@ | |||||
| import { useCallback, useEffect, useMemo, useState } from "react"; | import { useCallback, useEffect, useMemo, useState } from "react"; | ||||
| import SearchBox, { Criterion } from "../SearchBox"; | import SearchBox, { Criterion } from "../SearchBox"; | ||||
| import { ItemsResult } from "@/app/api/settings/item"; | |||||
| import { ItemsResult, ItemsResultResponse } from "@/app/api/settings/item"; | |||||
| import { useTranslation } from "react-i18next"; | import { useTranslation } from "react-i18next"; | ||||
| import SearchResults, { Column } from "../SearchResults"; | import SearchResults, { Column } from "../SearchResults"; | ||||
| import { EditNote } from "@mui/icons-material"; | import { EditNote } from "@mui/icons-material"; | ||||
| @@ -85,7 +85,7 @@ const ItemsSearch: React.FC<Props> = ({ items }) => { | |||||
| ...filterObj, | ...filterObj, | ||||
| }; | }; | ||||
| try { | try { | ||||
| const response = await axiosInstance.get<ItemsResult[]>( | |||||
| const response = await axiosInstance.get<ItemsResultResponse>( | |||||
| `${NEXT_PUBLIC_API_URL}/items/getRecordByPage`, | `${NEXT_PUBLIC_API_URL}/items/getRecordByPage`, | ||||
| { params } | { params } | ||||
| ); | ); | ||||
| @@ -19,6 +19,7 @@ import { arrayToDateString, decimalFormatter } from "@/app/utils/formatUtil"; | |||||
| import { isEqual, uniqBy } from "lodash"; | import { isEqual, uniqBy } from "lodash"; | ||||
| import dayjs from "dayjs"; | import dayjs from "dayjs"; | ||||
| import { defaultPagingController } from "../SearchResults/SearchResults"; | import { defaultPagingController } from "../SearchResults/SearchResults"; | ||||
| import { ScheduleType } from "@/app/api/scheduling"; | |||||
| // type RecordStructure ={ | // type RecordStructure ={ | ||||
| // id: number, | // id: number, | ||||
| @@ -27,12 +28,12 @@ import { defaultPagingController } from "../SearchResults/SearchResults"; | |||||
| // }; | // }; | ||||
| type Props = { | type Props = { | ||||
| type: SearchProdSchedule["type"]; | |||||
| type: ScheduleType; | |||||
| // initProdSchedules: ProdScheduleResultByPage; | // initProdSchedules: ProdScheduleResultByPage; | ||||
| defaultInputs: SearchProdSchedule; | defaultInputs: SearchProdSchedule; | ||||
| }; | }; | ||||
| type SearchQuery = Partial<Omit<SearchProdSchedule, "id" | "type" | "pageSize" | "pageNum">>; | |||||
| type SearchQuery = Partial<Omit<SearchProdSchedule, "id" | "types" | "pageSize" | "pageNum">>; | |||||
| type SearchParamNames = keyof SearchQuery; | type SearchParamNames = keyof SearchQuery; | ||||
| const RSOverview: React.FC<Props> = ({ type, defaultInputs }) => { | const RSOverview: React.FC<Props> = ({ type, defaultInputs }) => { | ||||
| @@ -64,12 +65,12 @@ const RSOverview: React.FC<Props> = ({ type, defaultInputs }) => { | |||||
| // [router] | // [router] | ||||
| // ); | // ); | ||||
| const onDeleteClick = useCallback( | |||||
| (item: ItemsResult) => { }, | |||||
| [router] | |||||
| ); | |||||
| // const onDeleteClick = useCallback( | |||||
| // (item: ItemsResult) => { }, | |||||
| // [router] | |||||
| // ); | |||||
| const onDetailClick = (record: any) => { | |||||
| const onDetailClick = (record: ProdScheduleResult) => { | |||||
| console.log("[debug] record", record); | console.log("[debug] record", record); | ||||
| router.push(`/scheduling/rough/edit?id=${record.id}`); | router.push(`/scheduling/rough/edit?id=${record.id}`); | ||||
| } | } | ||||
| @@ -127,7 +128,7 @@ const RSOverview: React.FC<Props> = ({ type, defaultInputs }) => { | |||||
| schedulePeriod: dayjs(query?.schedulePeriod).isValid() ? query?.schedulePeriod : undefined, | schedulePeriod: dayjs(query?.schedulePeriod).isValid() ? query?.schedulePeriod : undefined, | ||||
| schedulePeriodTo: dayjs(query?.schedulePeriodTo).isValid() ? query?.schedulePeriodTo : undefined, | schedulePeriodTo: dayjs(query?.schedulePeriodTo).isValid() ? query?.schedulePeriodTo : undefined, | ||||
| totalEstProdCount: query?.totalEstProdCount ? Number(query?.totalEstProdCount) : undefined, | totalEstProdCount: query?.totalEstProdCount ? Number(query?.totalEstProdCount) : undefined, | ||||
| type: "rough", | |||||
| types: ["rough"], | |||||
| pageNum: pagingController.pageNum - 1, | pageNum: pagingController.pageNum - 1, | ||||
| pageSize: pagingController.pageSize | pageSize: pagingController.pageSize | ||||
| } | } | ||||
| @@ -2,13 +2,14 @@ import { fetchAllItems } from "@/app/api/settings/item"; | |||||
| import { RoughScheduleLoading } from "./RoughScheduleLoading"; | import { RoughScheduleLoading } from "./RoughScheduleLoading"; | ||||
| import RSOverview from "./RoughSchedileSearchView"; | import RSOverview from "./RoughSchedileSearchView"; | ||||
| import { SearchProdSchedule, fetchProdSchedules } from "@/app/api/scheduling/actions"; | import { SearchProdSchedule, fetchProdSchedules } from "@/app/api/scheduling/actions"; | ||||
| import { ScheduleType } from "@/app/api/scheduling"; | |||||
| interface SubComponents { | interface SubComponents { | ||||
| Loading: typeof RoughScheduleLoading; | Loading: typeof RoughScheduleLoading; | ||||
| } | } | ||||
| type Props = { | type Props = { | ||||
| type: SearchProdSchedule["type"] | |||||
| type: ScheduleType | |||||
| }; | }; | ||||
| const RoughScheduleWrapper: React.FC<Props> & SubComponents = async ( | const RoughScheduleWrapper: React.FC<Props> & SubComponents = async ( | ||||
| @@ -18,7 +19,7 @@ const RoughScheduleWrapper: React.FC<Props> & SubComponents = async ( | |||||
| ) => { | ) => { | ||||
| // console.log(type) | // console.log(type) | ||||
| const defaultInputs: SearchProdSchedule = { | const defaultInputs: SearchProdSchedule = { | ||||
| type: "rough" | |||||
| types: ["rough"] | |||||
| } | } | ||||
| // const [ | // const [ | ||||
| @@ -18,7 +18,7 @@ import { InputDataGridProps, TableRow } from "../InputDataGrid/InputDataGrid"; | |||||
| import { TypeEnum } from "@/app/utils/typeEnum"; | import { TypeEnum } from "@/app/utils/typeEnum"; | ||||
| import { NumberInputProps } from "@/components/CreateItem/NumberInputProps"; | import { NumberInputProps } from "@/components/CreateItem/NumberInputProps"; | ||||
| import { arrayToDateString, integerFormatter } from "@/app/utils/formatUtil"; | import { arrayToDateString, integerFormatter } from "@/app/utils/formatUtil"; | ||||
| import { ProdScheduleResult } from "@/app/api/scheduling"; | |||||
| import { RoughProdScheduleResult } from "@/app/api/scheduling"; | |||||
| import { DatePicker, LocalizationProvider } from "@mui/x-date-pickers"; | import { DatePicker, LocalizationProvider } from "@mui/x-date-pickers"; | ||||
| import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; | import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; | ||||
| @@ -38,12 +38,12 @@ const DetailInfoCard: React.FC<Props> = ({ isEditing }) => { | |||||
| getValues, | getValues, | ||||
| watch, | watch, | ||||
| formState: { errors, defaultValues, touchedFields }, | formState: { errors, defaultValues, touchedFields }, | ||||
| } = useFormContext<ProdScheduleResult>(); | |||||
| } = useFormContext<RoughProdScheduleResult>(); | |||||
| // const [details, setDetails] = useState(null); | // const [details, setDetails] = useState(null); | ||||
| useEffect(() => { | useEffect(() => { | ||||
| console.log("[debug] record details", getValues) | |||||
| console.log("[debug] record details", getValues()) | |||||
| // setDetails(recordDetails); | // setDetails(recordDetails); | ||||
| }, [getValues]) | }, [getValues]) | ||||
| @@ -15,7 +15,7 @@ type Props = { | |||||
| const RoughScheduleDetailWrapper: React.FC<Props> & SubComponents = async ({ id, type }) => { | const RoughScheduleDetailWrapper: React.FC<Props> & SubComponents = async ({ id, type }) => { | ||||
| const prodSchedule = id ? await fetchProdScheduleDetail(id) : undefined | const prodSchedule = id ? await fetchProdScheduleDetail(id) : undefined | ||||
| return ( | return ( | ||||
| <RoughScheduleDetailView | <RoughScheduleDetailView | ||||
| isEditMode={Boolean(id)} | isEditMode={Boolean(id)} | ||||
| @@ -24,13 +24,13 @@ import ViewByFGDetails from "@/components/RoughScheduleDetail/ViewByFGDetails"; | |||||
| import ViewByBomDetails from "@/components/RoughScheduleDetail/ViewByBomDetails"; | import ViewByBomDetails from "@/components/RoughScheduleDetail/ViewByBomDetails"; | ||||
| import ScheduleTable from "@/components/ScheduleTable"; | import ScheduleTable from "@/components/ScheduleTable"; | ||||
| import { Column } from "@/components/ScheduleTable/ScheduleTable"; | import { Column } from "@/components/ScheduleTable/ScheduleTable"; | ||||
| import { ProdScheduleResult, ScheduleType } from "@/app/api/scheduling"; | |||||
| import { RoughProdScheduleResult, ScheduleType } from "@/app/api/scheduling"; | |||||
| import { arrayToDayjs, dayjsToDateString } from "@/app/utils/formatUtil"; | import { arrayToDayjs, dayjsToDateString } from "@/app/utils/formatUtil"; | ||||
| type Props = { | type Props = { | ||||
| isEditMode: boolean; | isEditMode: boolean; | ||||
| type: ScheduleType; | type: ScheduleType; | ||||
| defaultValues: Partial<ProdScheduleResult> | undefined; | |||||
| defaultValues: Partial<RoughProdScheduleResult> | undefined; | |||||
| // qcChecks: ItemQc[] | // qcChecks: ItemQc[] | ||||
| }; | }; | ||||
| @@ -42,7 +42,6 @@ const RoughScheduleDetailView: React.FC<Props> = ({ | |||||
| // console.log(type) | // console.log(type) | ||||
| const apiRef = useGridApiRef(); | const apiRef = useGridApiRef(); | ||||
| const params = useSearchParams() | const params = useSearchParams() | ||||
| console.log(params.get("id")) | |||||
| const [serverError, setServerError] = useState(""); | const [serverError, setServerError] = useState(""); | ||||
| const [tabIndex, setTabIndex] = useState(0); | const [tabIndex, setTabIndex] = useState(0); | ||||
| const { t } = useTranslation("schedule") | const { t } = useTranslation("schedule") | ||||
| @@ -51,7 +50,7 @@ const RoughScheduleDetailView: React.FC<Props> = ({ | |||||
| //const title = "Demand Forecast Detail" | //const title = "Demand Forecast Detail" | ||||
| // console.log(typeId) | // console.log(typeId) | ||||
| const formProps = useForm<ProdScheduleResult>({ | |||||
| const formProps = useForm<RoughProdScheduleResult>({ | |||||
| defaultValues: defaultValues ? defaultValues : { | defaultValues: defaultValues ? defaultValues : { | ||||
| }, | }, | ||||
| }); | }); | ||||
| @@ -88,7 +87,7 @@ const RoughScheduleDetailView: React.FC<Props> = ({ | |||||
| router.replace(`/scheduling/rough`); | router.replace(`/scheduling/rough`); | ||||
| }; | }; | ||||
| const onSubmit = useCallback<SubmitHandler<ProdScheduleResult>>( | |||||
| const onSubmit = useCallback<SubmitHandler<RoughProdScheduleResult>>( | |||||
| async (data, event) => { | async (data, event) => { | ||||
| let hasErrors = false; | let hasErrors = false; | ||||
| console.log(errors) | console.log(errors) | ||||
| @@ -109,7 +108,7 @@ const RoughScheduleDetailView: React.FC<Props> = ({ | |||||
| ); | ); | ||||
| // multiple tabs | // multiple tabs | ||||
| const onSubmitError = useCallback<SubmitErrorHandler<ProdScheduleResult>>( | |||||
| const onSubmitError = useCallback<SubmitErrorHandler<RoughProdScheduleResult>>( | |||||
| (errors) => { }, | (errors) => { }, | ||||
| [] | [] | ||||
| ); | ); | ||||
| @@ -21,7 +21,7 @@ import { RiceBowl } from "@mui/icons-material"; | |||||
| // import EditableSearchResults, { Column } from "@/components/SearchResults/EditableSearchResults"; | // import EditableSearchResults, { Column } from "@/components/SearchResults/EditableSearchResults"; | ||||
| import { decimalFormatter } from "@/app/utils/formatUtil"; | import { decimalFormatter } from "@/app/utils/formatUtil"; | ||||
| import { GridRenderCellParams } from "@mui/x-data-grid"; | import { GridRenderCellParams } from "@mui/x-data-grid"; | ||||
| import { ProdScheduleLineResultByBom, ProdScheduleLineResultByBomByDate, ProdScheduleResult, ScheduleType } from "@/app/api/scheduling"; | |||||
| import { RoughProdScheduleLineResultByBom, RoughProdScheduleLineResultByBomByDate, RoughProdScheduleResult, ScheduleType } from "@/app/api/scheduling"; | |||||
| import ScheduleTable from "@/components/ScheduleTable"; | import ScheduleTable from "@/components/ScheduleTable"; | ||||
| import { Column } from "@/components/ScheduleTable/ScheduleTable"; | import { Column } from "@/components/ScheduleTable/ScheduleTable"; | ||||
| @@ -63,7 +63,7 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod }) | |||||
| control, | control, | ||||
| getValues, | getValues, | ||||
| formState: { errors, defaultValues, touchedFields }, | formState: { errors, defaultValues, touchedFields }, | ||||
| } = useFormContext<ProdScheduleResult>(); | |||||
| } = useFormContext<RoughProdScheduleResult>(); | |||||
| // const apiRef = useGridApiRef(); | // const apiRef = useGridApiRef(); | ||||
| const { fields } = useFieldArray({ | const { fields } = useFieldArray({ | ||||
| @@ -165,7 +165,7 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod }) | |||||
| style: { | style: { | ||||
| textAlign: "right", | textAlign: "right", | ||||
| }, | }, | ||||
| renderCell: (row: ProdScheduleLineResultByBom) => { | |||||
| renderCell: (row: RoughProdScheduleLineResultByBom) => { | |||||
| if (typeof (row.availableQty) == "number") { | if (typeof (row.availableQty) == "number") { | ||||
| return decimalFormatter.format(row.availableQty) | return decimalFormatter.format(row.availableQty) | ||||
| } | } | ||||
| @@ -180,7 +180,7 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod }) | |||||
| style: { | style: { | ||||
| textAlign: "right", | textAlign: "right", | ||||
| }, | }, | ||||
| renderCell: (row: ProdScheduleLineResultByBom) => { | |||||
| renderCell: (row: RoughProdScheduleLineResultByBom) => { | |||||
| if (typeof (row.totalDemandQty) == "number") { | if (typeof (row.totalDemandQty) == "number") { | ||||
| return decimalFormatter.format(row.totalDemandQty) | return decimalFormatter.format(row.totalDemandQty) | ||||
| } | } | ||||
| @@ -194,7 +194,7 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod }) | |||||
| style: { | style: { | ||||
| textAlign: "right", | textAlign: "right", | ||||
| }, | }, | ||||
| renderCell: (row: ProdScheduleLineResultByBom) => { | |||||
| renderCell: (row: RoughProdScheduleLineResultByBom) => { | |||||
| if (typeof (row.demandQty1) == "number") { | if (typeof (row.demandQty1) == "number") { | ||||
| return decimalFormatter.format(row.demandQty1) | return decimalFormatter.format(row.demandQty1) | ||||
| } | } | ||||
| @@ -208,7 +208,7 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod }) | |||||
| style: { | style: { | ||||
| textAlign: "right", | textAlign: "right", | ||||
| }, | }, | ||||
| renderCell: (row: ProdScheduleLineResultByBom) => { | |||||
| renderCell: (row: RoughProdScheduleLineResultByBom) => { | |||||
| if (typeof (row.demandQty2) == "number") { | if (typeof (row.demandQty2) == "number") { | ||||
| return decimalFormatter.format(row.demandQty2) | return decimalFormatter.format(row.demandQty2) | ||||
| } | } | ||||
| @@ -222,7 +222,7 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod }) | |||||
| style: { | style: { | ||||
| textAlign: "right", | textAlign: "right", | ||||
| }, | }, | ||||
| renderCell: (row: ProdScheduleLineResultByBom) => { | |||||
| renderCell: (row: RoughProdScheduleLineResultByBom) => { | |||||
| if (typeof (row.demandQty3) == "number") { | if (typeof (row.demandQty3) == "number") { | ||||
| return decimalFormatter.format(row.demandQty3) | return decimalFormatter.format(row.demandQty3) | ||||
| } | } | ||||
| @@ -236,7 +236,7 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod }) | |||||
| style: { | style: { | ||||
| textAlign: "right", | textAlign: "right", | ||||
| }, | }, | ||||
| renderCell: (row: ProdScheduleLineResultByBom) => { | |||||
| renderCell: (row: RoughProdScheduleLineResultByBom) => { | |||||
| if (typeof (row.demandQty4) == "number") { | if (typeof (row.demandQty4) == "number") { | ||||
| return decimalFormatter.format(row.demandQty4) | return decimalFormatter.format(row.demandQty4) | ||||
| } | } | ||||
| @@ -249,7 +249,7 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod }) | |||||
| style: { | style: { | ||||
| textAlign: "right", | textAlign: "right", | ||||
| }, | }, | ||||
| renderCell: (row: ProdScheduleLineResultByBom) => { | |||||
| renderCell: (row: RoughProdScheduleLineResultByBom) => { | |||||
| if (typeof (row.demandQty5) == "number") { | if (typeof (row.demandQty5) == "number") { | ||||
| return decimalFormatter.format(row.demandQty5) | return decimalFormatter.format(row.demandQty5) | ||||
| } | } | ||||
| @@ -263,7 +263,7 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod }) | |||||
| style: { | style: { | ||||
| textAlign: "right", | textAlign: "right", | ||||
| }, | }, | ||||
| renderCell: (row: ProdScheduleLineResultByBom) => { | |||||
| renderCell: (row: RoughProdScheduleLineResultByBom) => { | |||||
| if (typeof (row.demandQty6) == "number") { | if (typeof (row.demandQty6) == "number") { | ||||
| return decimalFormatter.format(row.demandQty6) | return decimalFormatter.format(row.demandQty6) | ||||
| } | } | ||||
| @@ -277,7 +277,7 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod }) | |||||
| style: { | style: { | ||||
| textAlign: "right", | textAlign: "right", | ||||
| }, | }, | ||||
| renderCell: (row: ProdScheduleLineResultByBom) => { | |||||
| renderCell: (row: RoughProdScheduleLineResultByBom) => { | |||||
| if (typeof (row.demandQty7) == "number") { | if (typeof (row.demandQty7) == "number") { | ||||
| return decimalFormatter.format(row.demandQty7) | return decimalFormatter.format(row.demandQty7) | ||||
| } | } | ||||
| @@ -288,7 +288,7 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod }) | |||||
| [t] | [t] | ||||
| ); | ); | ||||
| const columns = useMemo<Column<ProdScheduleLineResultByBomByDate>[]>( | |||||
| const columns = useMemo<Column<RoughProdScheduleLineResultByBomByDate>[]>( | |||||
| () => [ | () => [ | ||||
| { | { | ||||
| field: "code", | field: "code", | ||||
| @@ -317,7 +317,7 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod }) | |||||
| style: { | style: { | ||||
| textAlign: "right", | textAlign: "right", | ||||
| }, | }, | ||||
| renderCell: (row: ProdScheduleLineResultByBomByDate) => { | |||||
| renderCell: (row: RoughProdScheduleLineResultByBomByDate) => { | |||||
| if (typeof (row.availableQty) == "number") { | if (typeof (row.availableQty) == "number") { | ||||
| return decimalFormatter.format(row.availableQty) | return decimalFormatter.format(row.availableQty) | ||||
| } | } | ||||
| @@ -331,7 +331,7 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod }) | |||||
| style: { | style: { | ||||
| textAlign: "right", | textAlign: "right", | ||||
| }, | }, | ||||
| renderCell: (row: ProdScheduleLineResultByBomByDate) => { | |||||
| renderCell: (row: RoughProdScheduleLineResultByBomByDate) => { | |||||
| if (typeof (row.demandQty) == "number") { | if (typeof (row.demandQty) == "number") { | ||||
| return decimalFormatter.format(row.demandQty) | return decimalFormatter.format(row.demandQty) | ||||
| } | } | ||||
| @@ -342,15 +342,13 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod }) | |||||
| [] | [] | ||||
| ); | ); | ||||
| console.log(getValues("prodScheduleLinesByBom")) | |||||
| return ( | return ( | ||||
| <Grid container spacing={2}> | <Grid container spacing={2}> | ||||
| <Grid item xs={12} key={"all"}> | <Grid item xs={12} key={"all"}> | ||||
| <Typography variant="overline" display="block" marginBlockEnd={1}> | <Typography variant="overline" display="block" marginBlockEnd={1}> | ||||
| {t("Material Demand List (7 Days)")} | {t("Material Demand List (7 Days)")} | ||||
| </Typography> | </Typography> | ||||
| <ScheduleTable<ProdScheduleLineResultByBom> | |||||
| <ScheduleTable<RoughProdScheduleLineResultByBom> | |||||
| // index={7} | // index={7} | ||||
| type={type} | type={type} | ||||
| items={getValues("prodScheduleLinesByBom")} | items={getValues("prodScheduleLinesByBom")} | ||||
| @@ -368,7 +366,7 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod }) | |||||
| <Typography variant="overline" display="block" marginBlockEnd={1}> | <Typography variant="overline" display="block" marginBlockEnd={1}> | ||||
| {`${t("Material Demand Date")}: ${date}`} | {`${t("Material Demand Date")}: ${date}`} | ||||
| </Typography> | </Typography> | ||||
| <ScheduleTable<ProdScheduleLineResultByBomByDate> | |||||
| <ScheduleTable<RoughProdScheduleLineResultByBomByDate> | |||||
| // index={index} | // index={index} | ||||
| type={type} | type={type} | ||||
| items={getValues("prodScheduleLinesByBomByDate")[index + 1]} // Use the corresponding records for the day | items={getValues("prodScheduleLinesByBomByDate")[index + 1]} // Use the corresponding records for the day | ||||
| @@ -21,7 +21,7 @@ import { RiceBowl } from "@mui/icons-material"; | |||||
| import ScheduleTable from "@/components/ScheduleTable"; | import ScheduleTable from "@/components/ScheduleTable"; | ||||
| import { Column } from "@/components/ScheduleTable/ScheduleTable"; | import { Column } from "@/components/ScheduleTable/ScheduleTable"; | ||||
| import { arrayToDayjs, dayjsToDateString, decimalFormatter, integerFormatter } from "@/app/utils/formatUtil"; | import { arrayToDayjs, dayjsToDateString, decimalFormatter, integerFormatter } from "@/app/utils/formatUtil"; | ||||
| import { ProdScheduleLineResultByFg, ProdScheduleResult, ScheduleType } from "@/app/api/scheduling"; | |||||
| import { RoughProdScheduleLineResultByFg, RoughProdScheduleResult, ScheduleType } from "@/app/api/scheduling"; | |||||
| type Props = { | type Props = { | ||||
| apiRef: MutableRefObject<GridApiCommunity> | apiRef: MutableRefObject<GridApiCommunity> | ||||
| @@ -50,7 +50,7 @@ const ViewByFGDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod }) = | |||||
| control, | control, | ||||
| getValues, | getValues, | ||||
| formState: { errors, defaultValues, touchedFields }, | formState: { errors, defaultValues, touchedFields }, | ||||
| } = useFormContext<ProdScheduleResult>(); | |||||
| } = useFormContext<RoughProdScheduleResult>(); | |||||
| const { fields } = useFieldArray({ | const { fields } = useFieldArray({ | ||||
| control, | control, | ||||
| @@ -125,7 +125,7 @@ const ViewByFGDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod }) = | |||||
| }); | }); | ||||
| }; | }; | ||||
| const columns = useMemo<Column<ProdScheduleLineResultByFg>[]>( | |||||
| const columns = useMemo<Column<RoughProdScheduleLineResultByFg>[]>( | |||||
| () => [ | () => [ | ||||
| { | { | ||||
| field: "code", | field: "code", | ||||
| @@ -177,7 +177,7 @@ const ViewByFGDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod }) = | |||||
| [] | [] | ||||
| ); | ); | ||||
| const overallColumns = useMemo<Column<ProdScheduleLineResultByFg>[]>( | |||||
| const overallColumns = useMemo<Column<RoughProdScheduleLineResultByFg>[]>( | |||||
| () => [ | () => [ | ||||
| { | { | ||||
| field: "code", | field: "code", | ||||
| @@ -270,7 +270,7 @@ const ViewByFGDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod }) = | |||||
| <Typography variant="overline" display="block" marginBlockEnd={1}> | <Typography variant="overline" display="block" marginBlockEnd={1}> | ||||
| {t("FG Demand List (7 Days)")} | {t("FG Demand List (7 Days)")} | ||||
| </Typography> | </Typography> | ||||
| <ScheduleTable<ProdScheduleLineResultByFg> | |||||
| <ScheduleTable<RoughProdScheduleLineResultByFg> | |||||
| // index={7} | // index={7} | ||||
| type={type} | type={type} | ||||
| items={getValues("prodScheduleLinesByFg")} | items={getValues("prodScheduleLinesByFg")} | ||||
| @@ -288,9 +288,9 @@ const ViewByFGDetails: React.FC<Props> = ({ apiRef, isEdit, type, dayPeriod }) = | |||||
| <Typography variant="overline" display="block" marginBlockEnd={1}> | <Typography variant="overline" display="block" marginBlockEnd={1}> | ||||
| {`${t("FG Demand Date")}: ${date}`} | {`${t("FG Demand Date")}: ${date}`} | ||||
| </Typography> | </Typography> | ||||
| <ScheduleTable<ProdScheduleLineResultByFg> | |||||
| <ScheduleTable<RoughProdScheduleLineResultByFg> | |||||
| type={type} | type={type} | ||||
| items={getValues("prodScheduleLinesByFgByDate")[index + 1]} // Use the corresponding records for the day | |||||
| items={getValues("prodScheduleLinesByFgByDate") && Object.entries(getValues("prodScheduleLinesByFgByDate")).length > 0 ? getValues("prodScheduleLinesByFgByDate")[index + 1] : []} // Use the corresponding records for the day | |||||
| columns={columns} | columns={columns} | ||||
| setPagingController={updatePagingController} | setPagingController={updatePagingController} | ||||
| pagingController={pagingController[index]} | pagingController={pagingController[index]} | ||||
| @@ -36,14 +36,14 @@ import { useSearchParams } from "next/navigation"; | |||||
| import { decimalFormatter } from "@/app/utils/formatUtil"; | import { decimalFormatter } from "@/app/utils/formatUtil"; | ||||
| import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline'; | import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline'; | ||||
| import HighlightOffIcon from '@mui/icons-material/HighlightOff'; | import HighlightOffIcon from '@mui/icons-material/HighlightOff'; | ||||
| import { ProdScheduleLineBomMaterialResult, ScheduleType } from "@/app/api/scheduling"; | |||||
| import { RoughProdScheduleLineBomMaterialResult, ScheduleType } from "@/app/api/scheduling"; | |||||
| interface ResultWithId { | interface ResultWithId { | ||||
| id: number; | id: number; | ||||
| } | } | ||||
| interface Props { | interface Props { | ||||
| bomMaterial: ProdScheduleLineBomMaterialResult[]; | |||||
| bomMaterial: RoughProdScheduleLineBomMaterialResult[]; | |||||
| type: ScheduleType | type: ScheduleType | ||||
| } | } | ||||
| @@ -23,7 +23,7 @@ import KeyboardArrowUpIcon from "@mui/icons-material/KeyboardArrowUp"; | |||||
| import { decimalFormatter, integerFormatter } from "@/app/utils/formatUtil"; | import { decimalFormatter, integerFormatter } from "@/app/utils/formatUtil"; | ||||
| import PlayCircleOutlineIcon from '@mui/icons-material/PlayCircleOutline'; | import PlayCircleOutlineIcon from '@mui/icons-material/PlayCircleOutline'; | ||||
| import { useTranslation } from "react-i18next"; | import { useTranslation } from "react-i18next"; | ||||
| import { ProdScheduleLineBomMaterialResult, ProdScheduleLineResultByFg, ProdScheduleResult, ScheduleType } from "@/app/api/scheduling"; | |||||
| import { RoughProdScheduleLineBomMaterialResult, RoughProdScheduleLineResultByFg, RoughProdScheduleResult, ScheduleType } from "@/app/api/scheduling"; | |||||
| export interface ResultWithId { | export interface ResultWithId { | ||||
| id: string | number; | id: string | number; | ||||
| @@ -144,10 +144,10 @@ function ScheduleTable<T extends ResultWithId>({ | |||||
| return type === "rough"; | return type === "rough"; | ||||
| } | } | ||||
| function isDetailType( | |||||
| function isDetailedType( | |||||
| type: ScheduleType | type: ScheduleType | ||||
| ): type is "detail" { | |||||
| return type === "detail"; | |||||
| ): type is "detailed" { | |||||
| return type === "detailed"; | |||||
| } | } | ||||
| function Row(props: { row: T }) { | function Row(props: { row: T }) { | ||||
| @@ -157,7 +157,7 @@ function ScheduleTable<T extends ResultWithId>({ | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| <TableRow hover tabIndex={-1} key={row.id}> | <TableRow hover tabIndex={-1} key={row.id}> | ||||
| {isDetailType(type) && <TableCell> | |||||
| {isDetailedType(type) && <TableCell> | |||||
| <IconButton disabled={!isEdit}> | <IconButton disabled={!isEdit}> | ||||
| <PlayCircleOutlineIcon /> | <PlayCircleOutlineIcon /> | ||||
| </IconButton> | </IconButton> | ||||
| @@ -167,12 +167,12 @@ function ScheduleTable<T extends ResultWithId>({ | |||||
| {(editingRowId === row.id) ? ( | {(editingRowId === row.id) ? ( | ||||
| <> | <> | ||||
| { | { | ||||
| isDetailType(type) && isEditable && <IconButton disabled={!isEdit} onClick={() => handleSaveClick(row)}> | |||||
| isDetailedType(type) && isEditable && <IconButton disabled={!isEdit} onClick={() => handleSaveClick(row)}> | |||||
| <SaveIcon /> | <SaveIcon /> | ||||
| </IconButton> | </IconButton> | ||||
| } | } | ||||
| { | { | ||||
| isDetailType(type) && isEditable && <IconButton disabled={!isEdit} onClick={() => setEditingRowId(null)}> | |||||
| isDetailedType(type) && isEditable && <IconButton disabled={!isEdit} onClick={() => setEditingRowId(null)}> | |||||
| <CancelIcon /> | <CancelIcon /> | ||||
| </IconButton> | </IconButton> | ||||
| } | } | ||||
| @@ -190,13 +190,13 @@ function ScheduleTable<T extends ResultWithId>({ | |||||
| ) : ( | ) : ( | ||||
| <> | <> | ||||
| { | { | ||||
| isDetailType(type) && isEditable && <IconButton disabled={!isEdit} | |||||
| isDetailedType(type) && isEditable && <IconButton disabled={!isEdit} | |||||
| onClick={() => handleEditClick(row.id as number)}> | onClick={() => handleEditClick(row.id as number)}> | ||||
| <EditIcon /> | <EditIcon /> | ||||
| </IconButton> | </IconButton> | ||||
| } | } | ||||
| { | { | ||||
| isDetailType(type) && isEditable && <IconButton disabled={!isEdit} | |||||
| isDetailedType(type) && isEditable && <IconButton disabled={!isEdit} | |||||
| onClick={() => handleDeleteClick(row.id as number)}> | onClick={() => handleDeleteClick(row.id as number)}> | ||||
| <DeleteIcon /> | <DeleteIcon /> | ||||
| </IconButton> | </IconButton> | ||||
| @@ -278,7 +278,7 @@ function ScheduleTable<T extends ResultWithId>({ | |||||
| <TableCell> | <TableCell> | ||||
| <BomMaterialTable | <BomMaterialTable | ||||
| type={type} | type={type} | ||||
| bomMaterial={(row as unknown as ProdScheduleLineResultByFg).bomMaterials} | |||||
| bomMaterial={(row as unknown as RoughProdScheduleLineResultByFg).bomMaterials} | |||||
| /> | /> | ||||
| </TableCell> | </TableCell> | ||||
| </TableRow> | </TableRow> | ||||
| @@ -298,7 +298,7 @@ function ScheduleTable<T extends ResultWithId>({ | |||||
| <Table stickyHeader> | <Table stickyHeader> | ||||
| <TableHead> | <TableHead> | ||||
| <TableRow> | <TableRow> | ||||
| {isDetailType(type) && <TableCell>{t("Release")}</TableCell>} | |||||
| {isDetailedType(type) && <TableCell>{t("Release")}</TableCell>} | |||||
| {(isEditable || hasCollapse) && <TableCell>{t("Actions")}</TableCell>} {/* Action Column Header */} | {(isEditable || hasCollapse) && <TableCell>{t("Actions")}</TableCell>} {/* Action Column Header */} | ||||
| {columns.map((column, idx) => ( | {columns.map((column, idx) => ( | ||||
| <TableCell style={column.style} key={`${column.field.toString()}${idx}`}> | <TableCell style={column.style} key={`${column.field.toString()}${idx}`}> | ||||
| @@ -196,7 +196,7 @@ function SearchBox<T extends string>({ | |||||
| <Grid key={c.paramName} item xs={6}> | <Grid key={c.paramName} item xs={6}> | ||||
| {c.type === "text" && ( | {c.type === "text" && ( | ||||
| <TextField | <TextField | ||||
| label={c.label} | |||||
| label={t(c.label)} | |||||
| fullWidth | fullWidth | ||||
| onChange={makeInputChangeHandler(c.paramName)} | onChange={makeInputChangeHandler(c.paramName)} | ||||
| value={inputs[c.paramName]} | value={inputs[c.paramName]} | ||||
| @@ -204,7 +204,7 @@ function SearchBox<T extends string>({ | |||||
| )} | )} | ||||
| {c.type === "multi-select" && ( | {c.type === "multi-select" && ( | ||||
| <MultiSelect | <MultiSelect | ||||
| label={c.label} | |||||
| label={t(c.label)} | |||||
| options={c?.options} | options={c?.options} | ||||
| selectedValues={c.filterObj?.[c.paramName] ?? []} | selectedValues={c.filterObj?.[c.paramName] ?? []} | ||||
| onChange={c.handleSelectionChange} | onChange={c.handleSelectionChange} | ||||
| @@ -213,9 +213,9 @@ function SearchBox<T extends string>({ | |||||
| )} | )} | ||||
| {c.type === "select" && ( | {c.type === "select" && ( | ||||
| <FormControl fullWidth> | <FormControl fullWidth> | ||||
| <InputLabel>{c.label}</InputLabel> | |||||
| <InputLabel>{t(c.label)}</InputLabel> | |||||
| <Select | <Select | ||||
| label={c.label} | |||||
| label={t(c.label)} | |||||
| onChange={makeSelectChangeHandler(c.paramName)} | onChange={makeSelectChangeHandler(c.paramName)} | ||||
| value={inputs[c.paramName]} | value={inputs[c.paramName]} | ||||
| > | > | ||||
| @@ -230,9 +230,9 @@ function SearchBox<T extends string>({ | |||||
| )} | )} | ||||
| {c.type === "select-labelled" && ( | {c.type === "select-labelled" && ( | ||||
| <FormControl fullWidth> | <FormControl fullWidth> | ||||
| <InputLabel>{c.label}</InputLabel> | |||||
| <InputLabel>{t(c.label)}</InputLabel> | |||||
| <Select | <Select | ||||
| label={c.label} | |||||
| label={t(c.label)} | |||||
| onChange={makeSelectChangeHandler(c.paramName)} | onChange={makeSelectChangeHandler(c.paramName)} | ||||
| value={inputs[c.paramName]} | value={inputs[c.paramName]} | ||||
| > | > | ||||
| @@ -312,7 +312,7 @@ function SearchBox<T extends string>({ | |||||
| </MenuItem> | </MenuItem> | ||||
| ); | ); | ||||
| }} | }} | ||||
| renderInput={(params) => <TextField {...params} variant="outlined" label={c.label} />} | |||||
| renderInput={(params) => <TextField {...params} variant="outlined" label={t(c.label)} />} | |||||
| /> | /> | ||||
| )} | )} | ||||
| {c.type === "dateRange" && ( | {c.type === "dateRange" && ( | ||||
| @@ -324,7 +324,7 @@ function SearchBox<T extends string>({ | |||||
| <Box display="flex"> | <Box display="flex"> | ||||
| <FormControl fullWidth> | <FormControl fullWidth> | ||||
| <DatePicker | <DatePicker | ||||
| label={c.label} | |||||
| label={t(c.label)} | |||||
| onChange={makeDateChangeHandler(c.paramName)} | onChange={makeDateChangeHandler(c.paramName)} | ||||
| value={dayjs(inputs[c.paramName]).isValid() ? dayjs(inputs[c.paramName]) : null} | value={dayjs(inputs[c.paramName]).isValid() ? dayjs(inputs[c.paramName]) : null} | ||||
| /> | /> | ||||
| @@ -339,7 +339,7 @@ function SearchBox<T extends string>({ | |||||
| </Box> | </Box> | ||||
| <FormControl fullWidth> | <FormControl fullWidth> | ||||
| <DatePicker | <DatePicker | ||||
| label={c.label2} | |||||
| label={c.label2 ? t(c.label2) : null} | |||||
| onChange={makeDateToChangeHandler(c.paramName)} | onChange={makeDateToChangeHandler(c.paramName)} | ||||
| value={dayjs(inputs[`${c.paramName}To`]).isValid() ? dayjs(inputs[`${c.paramName}To`]) : null} | value={dayjs(inputs[`${c.paramName}To`]).isValid() ? dayjs(inputs[`${c.paramName}To`]) : null} | ||||
| /> | /> | ||||
| @@ -356,7 +356,7 @@ function SearchBox<T extends string>({ | |||||
| <Box display="flex"> | <Box display="flex"> | ||||
| <FormControl fullWidth> | <FormControl fullWidth> | ||||
| <DatePicker | <DatePicker | ||||
| label={c.label} | |||||
| label={t(c.label)} | |||||
| onChange={makeDateChangeHandler(c.paramName)} | onChange={makeDateChangeHandler(c.paramName)} | ||||
| /> | /> | ||||
| </FormControl> | </FormControl> | ||||
| @@ -1,6 +1,6 @@ | |||||
| "use client"; | "use client"; | ||||
| import React, { useEffect, useState } from "react"; | |||||
| import React, { CSSProperties, useEffect, useState } from "react"; | |||||
| import Paper from "@mui/material/Paper"; | import Paper from "@mui/material/Paper"; | ||||
| import Table from "@mui/material/Table"; | import Table from "@mui/material/Table"; | ||||
| import TableBody from "@mui/material/TableBody"; | import TableBody from "@mui/material/TableBody"; | ||||
| @@ -23,6 +23,7 @@ import KeyboardArrowUpIcon from "@mui/icons-material/KeyboardArrowUp"; | |||||
| import { decimalFormatter, integerFormatter } from "@/app/utils/formatUtil"; | import { decimalFormatter, integerFormatter } from "@/app/utils/formatUtil"; | ||||
| import PlayCircleOutlineIcon from '@mui/icons-material/PlayCircleOutline'; | import PlayCircleOutlineIcon from '@mui/icons-material/PlayCircleOutline'; | ||||
| import { useTranslation } from "react-i18next"; | import { useTranslation } from "react-i18next"; | ||||
| import { RoughProdScheduleLineResultByFg } from "@/app/api/scheduling"; | |||||
| export interface ResultWithId { | export interface ResultWithId { | ||||
| id: string | number; | id: string | number; | ||||
| } | } | ||||
| @@ -32,8 +33,9 @@ interface BaseColumn<T extends ResultWithId> { | |||||
| label: string; | label: string; | ||||
| type: string; | type: string; | ||||
| options?: T[]; | options?: T[]; | ||||
| renderCell?: (T) => void; | |||||
| style?: Partial<HTMLElement["style"]> & { [propName: string]: string }; | |||||
| renderCell?: (params: T) => React.ReactNode; | |||||
| style?: Partial<HTMLElement["style"]> & { [propName: string]: string } & CSSProperties; | |||||
| // style?: Partial<HTMLElement["style"]> & { [propName: string]: string }; | |||||
| } | } | ||||
| interface ColumnWithAction<T extends ResultWithId> extends BaseColumn<T> { | interface ColumnWithAction<T extends ResultWithId> extends BaseColumn<T> { | ||||
| @@ -52,7 +54,11 @@ interface Props<T extends ResultWithId> { | |||||
| noWrapper?: boolean, | noWrapper?: boolean, | ||||
| setPagingController: (value: { pageNum: number; pageSize: number; totalCount: number, index?: number }) => void, | setPagingController: (value: { pageNum: number; pageSize: number; totalCount: number, index?: number }) => void, | ||||
| pagingController: { pageNum: number; pageSize: number; totalCount: number }, | pagingController: { pageNum: number; pageSize: number; totalCount: number }, | ||||
| isAutoPaging: boolean | |||||
| isAutoPaging: boolean, | |||||
| index: any, | |||||
| isEdit: any, | |||||
| isEditable: any, | |||||
| hasCollapse: any, | |||||
| } | } | ||||
| function EditableSearchResults<T extends ResultWithId>({ | function EditableSearchResults<T extends ResultWithId>({ | ||||
| @@ -78,7 +84,7 @@ function EditableSearchResults<T extends ResultWithId>({ | |||||
| }, [items]) | }, [items]) | ||||
| const handleChangePage = (_event: unknown, newPage: number) => { | const handleChangePage = (_event: unknown, newPage: number) => { | ||||
| setPage(newPage); | setPage(newPage); | ||||
| setPagingController({ ...pagingController, pageNum: newPage + 1 }, (index ?? -1)); | |||||
| // setPagingController({ ...pagingController, pageNum: newPage + 1 }, (index ?? -1)); | |||||
| }; | }; | ||||
| const handleChangeRowsPerPage = (event: React.ChangeEvent<HTMLInputElement>) => { | const handleChangeRowsPerPage = (event: React.ChangeEvent<HTMLInputElement>) => { | ||||
| @@ -134,7 +140,7 @@ function EditableSearchResults<T extends ResultWithId>({ | |||||
| <> | <> | ||||
| <TableRow hover tabIndex={-1} key={row.id}> | <TableRow hover tabIndex={-1} key={row.id}> | ||||
| <TableCell> | <TableCell> | ||||
| <IconButton disable={!isEdit}> | |||||
| <IconButton disabled={!isEdit}> | |||||
| <PlayCircleOutlineIcon /> | <PlayCircleOutlineIcon /> | ||||
| </IconButton> | </IconButton> | ||||
| </TableCell> | </TableCell> | ||||
| @@ -208,15 +214,15 @@ function EditableSearchResults<T extends ResultWithId>({ | |||||
| onChange={(e) => handleInputChange(row.id as number, columnName, e.target.value)} | onChange={(e) => handleInputChange(row.id as number, columnName, e.target.value)} | ||||
| /> | /> | ||||
| ); | ); | ||||
| case 'multi-select': | |||||
| return ( | |||||
| <MultiSelect | |||||
| //label={column.label} | |||||
| options={column.options} | |||||
| selectedValues={[]} | |||||
| onChange={(selectedValues) => handleInputChange(row.id as number, columnName, selectedValues)} | |||||
| /> | |||||
| ); | |||||
| // case 'multi-select': | |||||
| // return ( | |||||
| // <MultiSelect | |||||
| // //label={column.label} | |||||
| // options={column.options} | |||||
| // selectedValues={[]} | |||||
| // onChange={(selectedValues) => handleInputChange(row.id as number, columnName, selectedValues)} | |||||
| // /> | |||||
| // ); | |||||
| case 'read-only': | case 'read-only': | ||||
| return ( | return ( | ||||
| <span> | <span> | ||||
| @@ -253,7 +259,7 @@ function EditableSearchResults<T extends ResultWithId>({ | |||||
| <TableRow> | <TableRow> | ||||
| <TableCell> | <TableCell> | ||||
| <TempInputGridForMockUp | <TempInputGridForMockUp | ||||
| stockInLine={row.lines as any[]} | |||||
| stockInLine={(row as unknown as {lines: string[]}).lines as any[]} | |||||
| /> | /> | ||||
| </TableCell> | </TableCell> | ||||
| </TableRow> | </TableRow> | ||||
| @@ -10,7 +10,8 @@ | |||||
| "Demand Forecast Detail": "需求預測詳情", | "Demand Forecast Detail": "需求預測詳情", | ||||
| "Details": "詳情", | "Details": "詳情", | ||||
| "Schedule": "排程", | "Schedule": "排程", | ||||
| "Schedule Period": "排程期間", | |||||
| "Schedule Period": "排程時期", | |||||
| "Schedule Period To": "排程時期至", | |||||
| "Schedule Detail": "排程詳情", | "Schedule Detail": "排程詳情", | ||||
| "Schedule At": "排程時間", | "Schedule At": "排程時間", | ||||
| "Search": "搜尋", | "Search": "搜尋", | ||||
| @@ -23,7 +24,7 @@ | |||||
| "CODE": "編號", | "CODE": "編號", | ||||
| "Product Count": "產品數量", | "Product Count": "產品數量", | ||||
| "Scheduled At": "排程時間", | "Scheduled At": "排程時間", | ||||
| "Demand Forecast Period": "需求預測期間", | |||||
| "Demand Forecast Period": "需求預測時期", | |||||
| "FG & Material Demand Forecast Detail": "成品及物料需求預測詳情", | "FG & Material Demand Forecast Detail": "成品及物料需求預測詳情", | ||||
| "FG & Material Demand Forecast": "成品及物料需求預測", | "FG & Material Demand Forecast": "成品及物料需求預測", | ||||
| "Total Estimated Demand Qty": "總預估需求量", | "Total Estimated Demand Qty": "總預估需求量", | ||||