Suggest doing "Remove-Item -Recurse -Force .next" in frontendproduction
| @@ -0,0 +1,267 @@ | |||||
| const fs = require('fs'); | |||||
| const path = require('path'); | |||||
| const en = { | |||||
| "pageTitle_delivery": "Delivery & Dispatch", | |||||
| "pageTitle_jobOrder": "Job Orders", | |||||
| "pageTitle_forecast": "Forecast & Planning", | |||||
| "pageTitle_warehouse": "Inventory & Warehouse", | |||||
| "pageTitle_equipmentBoard": "Equipment Usage Board", | |||||
| "pageTitle_processBoard": "Process Real-time Board", | |||||
| "pageTitle_jobOrderBoard": "Job Order Real-time Board", | |||||
| "pageTitle_purchase": "Purchase", | |||||
| "all": "All", | |||||
| "noData": "No data", | |||||
| "exportExcel": "Export Excel", | |||||
| "show": "Show", | |||||
| "laneX": "Lane X", | |||||
| "today": "Today", | |||||
| "yesterday": "Yesterday", | |||||
| "selectDate": "Select Date", | |||||
| "refresh": "Refresh", | |||||
| "otherBoards": "Other Boards", | |||||
| "autoRefresh": "Auto Refresh", | |||||
| "on": "On", | |||||
| "off": "Off", | |||||
| "intervalSeconds": "Interval (sec)", | |||||
| "minutes": "minutes", | |||||
| "minutesWithVal": "{{val}} min", | |||||
| "minuteAbbr": "min", | |||||
| "delivery_staffPerfDateError": "Staff performance start date cannot be later than end date", | |||||
| "delivery_ordersByDate": "Delivery Orders by Date", | |||||
| "delivery_ordersByDate_export": "Delivery_Orders_By_Date", | |||||
| "delivery_orderCount": "Order Count", | |||||
| "delivery_topItemsByCount": "Top Items by Delivery Count", | |||||
| "delivery_item": "Item", | |||||
| "delivery_itemPlaceholder": "Leave empty for all", | |||||
| "delivery_staffPerformanceTitle": "Staff Delivery Performance (Daily Pick Count & Duration)", | |||||
| "delivery_startDate": "Start Date", | |||||
| "delivery_endDate": "End Date", | |||||
| "delivery_store": "Store", | |||||
| "delivery_staff": "Staff", | |||||
| "delivery_staffPlaceholder": "Leave empty for all", | |||||
| "delivery_staffPerfCaption": "Per-person pick count & total duration for period", | |||||
| "delivery_colStaff": "Staff", | |||||
| "delivery_colPickCount": "Pick Count", | |||||
| "delivery_colTotalMin": "Total Min", | |||||
| "delivery_colAvgMin": "Avg Min/Order", | |||||
| "delivery_dailyByStaff": "Daily by Staff", | |||||
| "delivery_noDataDesc": "No delivery data available for the selected period.", | |||||
| "jo_byStatus": "Job Orders by Status", | |||||
| "jo_byStatus_export": "Job_Orders_By_Status", | |||||
| "jo_datePlanStart": "Date (Plan Start)", | |||||
| "jo_createdVsCompleted": "Job Orders Created vs Completed by Date", | |||||
| "jo_createdVsCompleted_export": "Job_Orders_Created_vs_Completed", | |||||
| "jo_detailSection": "Job Order Material / Process / Equipment", | |||||
| "jo_materialPendingPicked": "Material Pending / Picked (by Plan Date)", | |||||
| "jo_materialPendingPicked_export": "Material_Pending_vs_Picked", | |||||
| "jo_processPendingCompleted": "Process Pending / Completed (by Plan Date)", | |||||
| "jo_processPendingCompleted_export": "Process_Pending_vs_Completed", | |||||
| "jo_equipmentWorkingWorked": "Equipment In Use / Used (by Job Order)", | |||||
| "jo_equipmentWorkingWorked_export": "Equipment_In_Use_vs_Used", | |||||
| "board_jobOrderLive": "Job Order Live Board", | |||||
| "board_equipmentUsage": "Equipment Usage Board", | |||||
| "board_processLive": "Process Live Board", | |||||
| "board_jobOrderChart": "Job Order Chart", | |||||
| "forecast_plannedOutputByDate": "Planned Daily Output by Item (Forecast)", | |||||
| "forecast_plannedOutputByDate_export": "Planned_Daily_Output_By_Item", | |||||
| "forecast_itemCode": "Item Code", | |||||
| "forecast_noScheduleData": "No scheduling data for this date range.", | |||||
| "forecast_productionSchedule": "Production Schedule by Date (Estimated Output)", | |||||
| "forecast_productionSchedule_export": "Production_Schedule_By_Date", | |||||
| "warehouse_stockTxnByDate": "Stock Transactions by Date (In / Out / Total)", | |||||
| "warehouse_stockTxnByDate_export": "Stock_Transactions_By_Date", | |||||
| "warehouse_stockInOutByDate": "Stock In vs Out by Date", | |||||
| "warehouse_stockInOutByDate_export": "Stock_In_vs_Out", | |||||
| "warehouse_balanceTrend": "Stock Balance Trend", | |||||
| "warehouse_balanceTrend_export": "Stock_Balance_Trend", | |||||
| "warehouse_consumptionTrend": "Monthly Consumption Trend (Outbound)", | |||||
| "warehouse_consumptionTrend_export": "Monthly_Consumption_Trend", | |||||
| "warehouse_qty": "Qty", | |||||
| "warehouse_optional": "Optional", | |||||
| "warehouse_sumAll": "Sum all if empty", | |||||
| "warehouse_addItem": "Add item to split", | |||||
| "warehouse_exportFail": "Master export failed", | |||||
| "equipment_status": "Status", | |||||
| "equipment_equipment": "Equipment", | |||||
| "equipment_jobOrder": "Job Order", | |||||
| "equipment_process": "Process", | |||||
| "equipment_planStart": "Plan Start", | |||||
| "equipment_startTime": "Start Time", | |||||
| "equipment_endTime": "End Time", | |||||
| "equipment_operator": "Operator", | |||||
| "equipment_boardTitle": "Equipment Usage Board", | |||||
| "equipment_infoDescription1": "Shows equipment status in real-time: working, idle, or under maintenance.", | |||||
| "equipment_infoDescription2": "Each equipment card displays the current job order and process.", | |||||
| "equipment_infoDescription3": "Equipment with unclosed hours or missing time entries will be flagged.", | |||||
| "equipment_searchAndList": "Search & List", | |||||
| "equipment_notToday": "Not Today", | |||||
| "equipment_unclosedHours": "Equipment hours not closed", | |||||
| "equipment_missingHours": "Missing equipment hours", | |||||
| "equipment_completed": "Completed", | |||||
| "process_notStarted": "Not Started", | |||||
| "process_inProgress": "In Progress", | |||||
| "process_completed": "Completed", | |||||
| "process_nonToday": "Not Today", | |||||
| "dateRange_lastDays": "Last {{d}} days", | |||||
| "series_inbound": "Inbound", | |||||
| "series_outbound": "Outbound", | |||||
| "series_total": "Total", | |||||
| "series_balance": "Balance", | |||||
| "series_consumption": "Consumption", | |||||
| "series_created": "Created", | |||||
| "series_completed": "Completed", | |||||
| "series_month": "Month", | |||||
| "requestFailed": "Request failed" | |||||
| }; | |||||
| const zh = { | |||||
| "pageTitle_delivery": "發貨與配送", | |||||
| "pageTitle_jobOrder": "工單", | |||||
| "pageTitle_forecast": "預測與計劃", | |||||
| "pageTitle_warehouse": "庫存與倉儲", | |||||
| "pageTitle_equipmentBoard": "設備使用看板", | |||||
| "pageTitle_processBoard": "工序即時看板", | |||||
| "pageTitle_jobOrderBoard": "工單即時看板", | |||||
| "pageTitle_purchase": "採購", | |||||
| "all": "全部", | |||||
| "noData": "無數據", | |||||
| "exportExcel": "匯出 Excel", | |||||
| "show": "顯示", | |||||
| "laneX": "車線-X", | |||||
| "today": "今日", | |||||
| "yesterday": "昨日", | |||||
| "selectDate": "選擇日期", | |||||
| "refresh": "重新整理", | |||||
| "otherBoards": "其他看板", | |||||
| "autoRefresh": "自動重新整理", | |||||
| "on": "開啟", | |||||
| "off": "關閉", | |||||
| "intervalSeconds": "間隔(秒)", | |||||
| "minutes": "分鐘", | |||||
| "minutesWithVal": "{{val}} 分鐘", | |||||
| "minuteAbbr": "分", | |||||
| "delivery_staffPerfDateError": "員工發貨績效的起始日期不能晚於結束日期", | |||||
| "delivery_ordersByDate": "按日期發貨單數量", | |||||
| "delivery_ordersByDate_export": "發貨單數量_按日期", | |||||
| "delivery_orderCount": "單數", | |||||
| "delivery_topItemsByCount": "發貨數量排行(按物料)", | |||||
| "delivery_item": "物料", | |||||
| "delivery_itemPlaceholder": "不選則全部", | |||||
| "delivery_staffPerformanceTitle": "員工發貨績效(每日揀貨數量與耗時)", | |||||
| "delivery_startDate": "開始日期", | |||||
| "delivery_endDate": "結束日期", | |||||
| "delivery_store": "倉別", | |||||
| "delivery_staff": "員工", | |||||
| "delivery_staffPlaceholder": "不選則全部", | |||||
| "delivery_staffPerfCaption": "週期內每人揀單數及總耗時(首揀至完成)", | |||||
| "delivery_colStaff": "員工", | |||||
| "delivery_colPickCount": "揀單數", | |||||
| "delivery_colTotalMin": "總分鐘", | |||||
| "delivery_colAvgMin": "平均分鐘/單", | |||||
| "delivery_dailyByStaff": "每日按員工單數", | |||||
| "delivery_noDataDesc": "所選期間內暫無發貨記錄,請調整日期範圍後再試。", | |||||
| "jo_byStatus": "工單按狀態", | |||||
| "jo_byStatus_export": "工單_按狀態", | |||||
| "jo_datePlanStart": "日期(計劃開始)", | |||||
| "jo_createdVsCompleted": "工單創建與完成按日期", | |||||
| "jo_createdVsCompleted_export": "工單_創建與完成_按日期", | |||||
| "jo_detailSection": "工單物料/工序/設備", | |||||
| "jo_materialPendingPicked": "物料待領/已揀(按工單計劃日)", | |||||
| "jo_materialPendingPicked_export": "物料_待領_已揀", | |||||
| "jo_processPendingCompleted": "工序待完成/已完成(按工單計劃日)", | |||||
| "jo_processPendingCompleted_export": "工序_待完成_已完成", | |||||
| "jo_equipmentWorkingWorked": "設備使用中/已使用(按工單)", | |||||
| "jo_equipmentWorkingWorked_export": "設備_使用中_已使用", | |||||
| "board_jobOrderLive": "工單即時看板", | |||||
| "board_equipmentUsage": "設備使用看板", | |||||
| "board_processLive": "工序即時看板", | |||||
| "board_jobOrderChart": "工單圖表", | |||||
| "forecast_plannedOutputByDate": "按物料計劃日產量(預測)", | |||||
| "forecast_plannedOutputByDate_export": "計劃日產量_按物料", | |||||
| "forecast_itemCode": "物料編碼", | |||||
| "forecast_noScheduleData": "此日期範圍內尚無排程資料。", | |||||
| "forecast_productionSchedule": "按日期生產排程(預估產量)", | |||||
| "forecast_productionSchedule_export": "生產排程_按日期", | |||||
| "warehouse_stockTxnByDate": "按日期庫存流水(入/出/合計)", | |||||
| "warehouse_stockTxnByDate_export": "庫存流水_按日期", | |||||
| "warehouse_stockInOutByDate": "按日期入庫與出庫", | |||||
| "warehouse_stockInOutByDate_export": "入庫_出庫_按日期", | |||||
| "warehouse_balanceTrend": "庫存餘額趨勢", | |||||
| "warehouse_balanceTrend_export": "庫存餘額趨勢", | |||||
| "warehouse_consumptionTrend": "按月考勤消耗趨勢(出庫量)", | |||||
| "warehouse_consumptionTrend_export": "月考勤消耗趨勢", | |||||
| "warehouse_qty": "數量", | |||||
| "warehouse_optional": "可選", | |||||
| "warehouse_sumAll": "不選則全部合計", | |||||
| "warehouse_addItem": "新增物料以分項顯示", | |||||
| "warehouse_exportFail": "總表匯出失敗", | |||||
| "equipment_status": "狀態", | |||||
| "equipment_equipment": "設備", | |||||
| "equipment_jobOrder": "工單", | |||||
| "equipment_process": "工序", | |||||
| "equipment_planStart": "工單計劃開始", | |||||
| "equipment_startTime": "開工時間", | |||||
| "equipment_endTime": "完工時間", | |||||
| "equipment_operator": "操作員", | |||||
| "equipment_boardTitle": "設備使用看板", | |||||
| "equipment_infoDescription1": "即時顯示設備狀態:使用中、閒置或維護中。", | |||||
| "equipment_infoDescription2": "每張設備卡片顯示當前工單和工序。", | |||||
| "equipment_infoDescription3": "設備工時未結案或未填寫將被標記。", | |||||
| "equipment_searchAndList": "查詢與列表", | |||||
| "equipment_notToday": "非今日", | |||||
| "equipment_unclosedHours": "設備工時未結案", | |||||
| "equipment_missingHours": "未填設備工時", | |||||
| "equipment_completed": "已完工", | |||||
| "process_notStarted": "未開工", | |||||
| "process_inProgress": "進行中", | |||||
| "process_completed": "已完工", | |||||
| "process_nonToday": "非今日", | |||||
| "dateRange_lastDays": "最近 {{d}} 天", | |||||
| "series_inbound": "入庫", | |||||
| "series_outbound": "出庫", | |||||
| "series_total": "合計", | |||||
| "series_balance": "餘額", | |||||
| "series_consumption": "消耗", | |||||
| "series_created": "新建", | |||||
| "series_completed": "完成", | |||||
| "series_month": "月份", | |||||
| "requestFailed": "請求失敗" | |||||
| }; | |||||
| const i18nDir = path.join(__dirname, '..', 'src', 'i18n'); | |||||
| const enPath = path.join(i18nDir, 'en', 'chart.json'); | |||||
| const zhPath = path.join(i18nDir, 'zh', 'chart.json'); | |||||
| // Sort keys alphabetically | |||||
| const sortKeys = (obj) => { | |||||
| const sorted = {}; | |||||
| Object.keys(obj).sort().forEach(k => { sorted[k] = obj[k]; }); | |||||
| return sorted; | |||||
| }; | |||||
| fs.writeFileSync(enPath, JSON.stringify(sortKeys(en), null, 2) + '\n'); | |||||
| fs.writeFileSync(zhPath, JSON.stringify(sortKeys(zh), null, 2) + '\n'); | |||||
| console.log('Updated chart.json with', Object.keys(en).length, 'keys for each language'); | |||||
| @@ -9,7 +9,7 @@ export const metadata: Metadata = { | |||||
| } | } | ||||
| const bagPage: React.FC = async () => { | const bagPage: React.FC = async () => { | ||||
| const { t } = await getServerI18n("jo"); | |||||
| const { t } = await getServerI18n("bagUsage"); | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| @@ -23,7 +23,7 @@ const bagPage: React.FC = async () => { | |||||
| {t("Bag Usage")} | {t("Bag Usage")} | ||||
| </Typography> | </Typography> | ||||
| </Stack> | </Stack> | ||||
| <I18nProvider namespaces={["jo", "common"]}> | |||||
| <I18nProvider namespaces={["bagUsage","navigation","common","jo"]}> | |||||
| <Suspense fallback={<BagSearchWrapper.Loading />}> | <Suspense fallback={<BagSearchWrapper.Loading />}> | ||||
| <BagSearchWrapper /> | <BagSearchWrapper /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -1,23 +1,21 @@ | |||||
| import { I18nProvider } from "@/i18n"; | |||||
| import { Metadata } from "next"; | |||||
| import BagPrintSearch from "@/components/BagPrint/BagPrintSearch"; | import BagPrintSearch from "@/components/BagPrint/BagPrintSearch"; | ||||
| import { Stack, Typography } from "@mui/material"; | import { Stack, Typography } from "@mui/material"; | ||||
| import { Metadata } from "next"; | |||||
| import React from "react"; | |||||
| export const metadata: Metadata = { | export const metadata: Metadata = { | ||||
| title: "打袋機", | title: "打袋機", | ||||
| }; | }; | ||||
| const BagPrintPage: React.FC = () => { | |||||
| export default async function BagPrintPage() { | |||||
| return ( | return ( | ||||
| <> | |||||
| <I18nProvider namespaces={["bagPrint", "navigation", "common"]}> | |||||
| <Stack direction="row" justifyContent="space-between" flexWrap="wrap" rowGap={2}> | <Stack direction="row" justifyContent="space-between" flexWrap="wrap" rowGap={2}> | ||||
| <Typography variant="h4" marginInlineEnd={2}> | <Typography variant="h4" marginInlineEnd={2}> | ||||
| 打袋機 | 打袋機 | ||||
| </Typography> | </Typography> | ||||
| </Stack> | </Stack> | ||||
| <BagPrintSearch /> | <BagPrintSearch /> | ||||
| </> | |||||
| </I18nProvider> | |||||
| ); | ); | ||||
| }; | |||||
| export default BagPrintPage; | |||||
| } | |||||
| @@ -1,24 +1,13 @@ | |||||
| import { Metadata } from "next"; | |||||
| import { getServerSession } from "next-auth"; | |||||
| import { redirect } from "next/navigation"; | |||||
| import { authOptions } from "@/config/authConfig"; | |||||
| import { AUTH } from "@/authorities"; | |||||
| import { I18nProvider } from "@/i18n"; | |||||
| export const metadata: Metadata = { | |||||
| title: "圖表報告", | |||||
| }; | |||||
| export default async function ChartLayout({ | |||||
| export default function ChartLayout({ | |||||
| children, | children, | ||||
| }: { | }: { | ||||
| children: React.ReactNode; | children: React.ReactNode; | ||||
| }) { | }) { | ||||
| const session = await getServerSession(authOptions); | |||||
| const abilities = session?.user?.abilities ?? []; | |||||
| const canViewCharts = | |||||
| abilities.includes(AUTH.TESTING) || abilities.includes(AUTH.ADMIN); | |||||
| if (!canViewCharts) { | |||||
| redirect("/dashboard"); | |||||
| } | |||||
| return <>{children}</>; | |||||
| return ( | |||||
| <I18nProvider namespaces={["chart", "navigation", "common"]}> | |||||
| {children} | |||||
| </I18nProvider> | |||||
| ); | |||||
| } | } | ||||
| @@ -18,7 +18,7 @@ const Dashboard: React.FC<Props> = async ({ searchParams }) => { | |||||
| fetchEscalationLogsByUser() | fetchEscalationLogsByUser() | ||||
| return ( | return ( | ||||
| <I18nProvider namespaces={["dashboard", "common", "purchaseOrder"]}> | |||||
| <I18nProvider namespaces={["dashboard","navigation","common","purchaseOrder"]}> | |||||
| <Suspense fallback={<DashboardPage.Loading />}> | <Suspense fallback={<DashboardPage.Loading />}> | ||||
| <DashboardPage searchParams={searchParams} /> | <DashboardPage searchParams={searchParams} /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -24,7 +24,7 @@ const DoEdit: React.FC<Props> = async ({ searchParams }) => { | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| <PageTitleBar title={t("Edit Delivery Order Detail")} className="mb-4" /> | <PageTitleBar title={t("Edit Delivery Order Detail")} className="mb-4" /> | ||||
| <I18nProvider namespaces={["do", "common"]}> | |||||
| <I18nProvider namespaces={["do","navigation","common"]}> | |||||
| <Suspense fallback={<DoDetail.Loading />}> | <Suspense fallback={<DoDetail.Loading />}> | ||||
| <DoDetail id={parseInt(id)} /> | <DoDetail id={parseInt(id)} /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -17,7 +17,7 @@ const DeliveryOrder: React.FC = async () => { | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| <PageTitleBar title={t("Delivery Order")} className="mb-4" /> | <PageTitleBar title={t("Delivery Order")} className="mb-4" /> | ||||
| <I18nProvider namespaces={["do", "common"]}> | |||||
| <I18nProvider namespaces={["do","navigation","common"]}> | |||||
| <Suspense fallback={<DoSearch.Loading />}> | <Suspense fallback={<DoSearch.Loading />}> | ||||
| <DoSearch /> | <DoSearch /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -15,7 +15,7 @@ export const metadata: Metadata = { | |||||
| type Props = SearchParams; | type Props = SearchParams; | ||||
| const Page: React.FC<Props> = async ({ searchParams }) => { | const Page: React.FC<Props> = async ({ searchParams }) => { | ||||
| const { t } = await getServerI18n("do"); | |||||
| const { t } = await getServerI18n("doWorkbench"); | |||||
| const id = searchParams["id"]; | const id = searchParams["id"]; | ||||
| if (!id || isArray(id) || !isFinite(parseInt(id))) { | if (!id || isArray(id) || !isFinite(parseInt(id))) { | ||||
| @@ -34,7 +34,7 @@ const Page: React.FC<Props> = async ({ searchParams }) => { | |||||
| {t("DO Workbench Search", { defaultValue: "DO Workbench Search" })} | {t("DO Workbench Search", { defaultValue: "DO Workbench Search" })} | ||||
| </Link> | </Link> | ||||
| </p> | </p> | ||||
| <I18nProvider namespaces={["do", "common"]}> | |||||
| <I18nProvider namespaces={["doWorkbench","navigation","common","do"]}> | |||||
| <Suspense fallback={<DoDetail.Loading />}> | <Suspense fallback={<DoDetail.Loading />}> | ||||
| <DoDetail id={parseInt(id)} workbenchRelease /> | <DoDetail id={parseInt(id)} workbenchRelease /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -9,13 +9,13 @@ export const metadata: Metadata = { | |||||
| }; | }; | ||||
| const DoWorkbenchPage: React.FC = async () => { | const DoWorkbenchPage: React.FC = async () => { | ||||
| const { t } = await getServerI18n("do"); | |||||
| const { t } = await getServerI18n("doWorkbench"); | |||||
| const printerCombo = await fetchPrinterCombo(); | const printerCombo = await fetchPrinterCombo(); | ||||
| return ( | return ( | ||||
| <> | <> | ||||
| <PageTitleBar title={t("DO Workbench", { defaultValue: "DO Workbench" })} className="mb-4" /> | <PageTitleBar title={t("DO Workbench", { defaultValue: "DO Workbench" })} className="mb-4" /> | ||||
| <I18nProvider namespaces={["pickOrder", "common", "ticketReleaseTable", "do"]}> | |||||
| <I18nProvider namespaces={["doWorkbench","navigation","common","pickOrder","ticketReleaseTable","do"]}> | |||||
| <DoWorkbenchTabs printerCombo={printerCombo ?? []} /> | <DoWorkbenchTabs printerCombo={printerCombo ?? []} /> | ||||
| </I18nProvider> | </I18nProvider> | ||||
| </> | </> | ||||
| @@ -19,7 +19,7 @@ const DoWorkbenchSearchPage: React.FC = async () => { | |||||
| title={t("DO Workbench Search", { defaultValue: "DO Workbench Search" })} | title={t("DO Workbench Search", { defaultValue: "DO Workbench Search" })} | ||||
| className="mb-4" | className="mb-4" | ||||
| /> | /> | ||||
| <I18nProvider namespaces={["do", "common"]}> | |||||
| <I18nProvider namespaces={["doWorkbench","navigation","common","do"]}> | |||||
| <Suspense fallback={<GeneralLoading />}> | <Suspense fallback={<GeneralLoading />}> | ||||
| <DoSearchWorkbench /> | <DoSearchWorkbench /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -12,13 +12,13 @@ export const metadata: Metadata = { | |||||
| type Props = {} & SearchParams; | type Props = {} & SearchParams; | ||||
| const PickOrder: React.FC<Props> = async ({ searchParams }) => { | const PickOrder: React.FC<Props> = async ({ searchParams }) => { | ||||
| const { t } = await getServerI18n("pickOrder"); | |||||
| const { t } = await getServerI18n("finishedGood"); | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| <I18nProvider namespaces={["pickOrder", "common", "ticketReleaseTable"]}> | |||||
| <I18nProvider namespaces={["finishedGood","navigation","common","pickOrder","ticketReleaseTable"]}> | |||||
| <Suspense fallback={<FinishedGoodSearchWrapper.Loading />}> | <Suspense fallback={<FinishedGoodSearchWrapper.Loading />}> | ||||
| <FinishedGoodSearchWrapper /> | <FinishedGoodSearchWrapper /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -18,7 +18,7 @@ const Page = async () => { | |||||
| redirect("/dashboard"); | redirect("/dashboard"); | ||||
| } | } | ||||
| return ( | return ( | ||||
| <I18nProvider namespaces={["common"]}> | |||||
| <I18nProvider namespaces={["finishedgoodmanagement", "navigation"]}> | |||||
| <Suspense fallback={<FinishedGoodManagement.Loading />}> | <Suspense fallback={<FinishedGoodManagement.Loading />}> | ||||
| <FinishedGoodManagement /> | <FinishedGoodManagement /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -11,13 +11,13 @@ export const metadata: Metadata = { | |||||
| }; | }; | ||||
| const PickOrder: React.FC = async () => { | const PickOrder: React.FC = async () => { | ||||
| const { t } = await getServerI18n("pickOrder"); | |||||
| const { t } = await getServerI18n("finishedGood"); | |||||
| //PreloadPickOrder(); | //PreloadPickOrder(); | ||||
| return ( | return ( | ||||
| <> | <> | ||||
| <I18nProvider namespaces={["pickOrder", "common", "ticketReleaseTable"]}> | |||||
| <I18nProvider namespaces={["finishedGood","navigation","common","pickOrder","ticketReleaseTable"]}> | |||||
| <Suspense fallback={<FinishedGoodSearch.Loading />}> | <Suspense fallback={<FinishedGoodSearch.Loading />}> | ||||
| <FinishedGoodSearch /> | <FinishedGoodSearch /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -14,7 +14,7 @@ export const metadata: Metadata = { | |||||
| }; | }; | ||||
| const Inventory: React.FC = async () => { | const Inventory: React.FC = async () => { | ||||
| const { t } = await getServerI18n("inventory", "common"); | |||||
| const { t } = await getServerI18n("inventory"); | |||||
| preloadInventory(); | preloadInventory(); | ||||
| @@ -30,7 +30,7 @@ const Inventory: React.FC = async () => { | |||||
| {t("Inventory")} | {t("Inventory")} | ||||
| </Typography> | </Typography> | ||||
| </Stack> | </Stack> | ||||
| <I18nProvider namespaces={["common", "inventory"]}> | |||||
| <I18nProvider namespaces={["inventory","navigation","common"]}> | |||||
| <Suspense fallback={<InventorySearch.Loading />}> | <Suspense fallback={<InventorySearch.Loading />}> | ||||
| <InventorySearch /> | <InventorySearch /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -39,7 +39,7 @@ const JoEdit: React.FC<Props> = async ({ searchParams }) => { | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| <PageTitleBar title={t("Edit Job Order Detail")} className="mb-4" /> | <PageTitleBar title={t("Edit Job Order Detail")} className="mb-4" /> | ||||
| <I18nProvider namespaces={["jo", "common"]}> | |||||
| <I18nProvider namespaces={["jo","navigation","common"]}> | |||||
| <Suspense fallback={<JoSave.Loading />}> | <Suspense fallback={<JoSave.Loading />}> | ||||
| <JoSave id={parseInt(id)} /> | <JoSave id={parseInt(id)} /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -32,7 +32,7 @@ const Jo: React.FC = async () => { | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| <PageTitleBar title={t("Search Job Order/ Create Job Order")} className="mb-4" /> | <PageTitleBar title={t("Search Job Order/ Create Job Order")} className="mb-4" /> | ||||
| <I18nProvider namespaces={["jo", "common", "purchaseOrder", "dashboard"]}> | |||||
| <I18nProvider namespaces={["jo","navigation","common","purchaseOrder","dashboard"]}> | |||||
| <Suspense fallback={<GeneralLoading />}> | <Suspense fallback={<GeneralLoading />}> | ||||
| <JoWorkbenchSearch | <JoWorkbenchSearch | ||||
| defaultInputs={defaultInputs} | defaultInputs={defaultInputs} | ||||
| @@ -18,7 +18,7 @@ const JoWorkbenchPage = async () => { | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| <PageTitleBar title={t("Job Order Pickexcution", { defaultValue: "Job Order Pickexcution" })} className="mb-4" /> | <PageTitleBar title={t("Job Order Pickexcution", { defaultValue: "Job Order Pickexcution" })} className="mb-4" /> | ||||
| <I18nProvider namespaces={["jo", "common", "pickOrder", "purchaseOrder", "dashboard"]}> | |||||
| <I18nProvider namespaces={["jo","navigation","common","pickOrder","purchaseOrder","dashboard"]}> | |||||
| <Suspense fallback={<GeneralLoading />}> | <Suspense fallback={<GeneralLoading />}> | ||||
| <JoPickOrderList printerCombo={printerCombo ?? []} /> | <JoPickOrderList printerCombo={printerCombo ?? []} /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -38,7 +38,7 @@ const JodetailEdit: React.FC<Props> = async ({ searchParams }) => { | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| <PageTitleBar title={t("Edit Job Order Detail")} className="mb-4" /> | <PageTitleBar title={t("Edit Job Order Detail")} className="mb-4" /> | ||||
| <I18nProvider namespaces={["jo", "common"]}> | |||||
| <I18nProvider namespaces={["jo","navigation","common"]}> | |||||
| <Suspense fallback={<GeneralLoading />}> | <Suspense fallback={<GeneralLoading />}> | ||||
| <JoSave id={parseInt(id)} defaultValues={undefined} /> | <JoSave id={parseInt(id)} defaultValues={undefined} /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -18,7 +18,7 @@ const Jodetail: React.FC = async () => { | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| <PageTitleBar title={t("Job Order Pick Execution")} className="mb-4" /> | <PageTitleBar title={t("Job Order Pick Execution")} className="mb-4" /> | ||||
| <I18nProvider namespaces={["jo", "common", "pickOrder"]}> | |||||
| <I18nProvider namespaces={["jo","navigation","common","pickOrder"]}> | |||||
| <Suspense fallback={<GeneralLoading />}> | <Suspense fallback={<GeneralLoading />}> | ||||
| <JodetailSearchWrapper /> | <JodetailSearchWrapper /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -1,23 +1,21 @@ | |||||
| import { I18nProvider } from "@/i18n"; | |||||
| import { Metadata } from "next"; | |||||
| import LaserPrintSearch from "@/components/LaserPrint/LaserPrintSearch"; | import LaserPrintSearch from "@/components/LaserPrint/LaserPrintSearch"; | ||||
| import { Stack, Typography } from "@mui/material"; | import { Stack, Typography } from "@mui/material"; | ||||
| import { Metadata } from "next"; | |||||
| import React from "react"; | |||||
| export const metadata: Metadata = { | export const metadata: Metadata = { | ||||
| title: "檸檬機(激光機)", | title: "檸檬機(激光機)", | ||||
| }; | }; | ||||
| const LaserPrintPage: React.FC = () => { | |||||
| export default async function LaserPrintPage() { | |||||
| return ( | return ( | ||||
| <> | |||||
| <I18nProvider namespaces={["laserPrint", "navigation", "common"]}> | |||||
| <Stack direction="row" justifyContent="space-between" flexWrap="wrap" rowGap={2}> | <Stack direction="row" justifyContent="space-between" flexWrap="wrap" rowGap={2}> | ||||
| <Typography variant="h4" marginInlineEnd={2}> | <Typography variant="h4" marginInlineEnd={2}> | ||||
| 檸檬機(激光機) | 檸檬機(激光機) | ||||
| </Typography> | </Typography> | ||||
| </Stack> | </Stack> | ||||
| <LaserPrintSearch /> | <LaserPrintSearch /> | ||||
| </> | |||||
| </I18nProvider> | |||||
| ); | ); | ||||
| }; | |||||
| export default LaserPrintPage; | |||||
| } | |||||
| @@ -48,7 +48,7 @@ export default async function MainLayout({ | |||||
| /> | /> | ||||
| } | } | ||||
| mainContent={ | mainContent={ | ||||
| <I18nProvider namespaces={["common"]}> | |||||
| <I18nProvider namespaces={["navigation", "common"]}> | |||||
| <MainContentArea>{children}</MainContentArea> | <MainContentArea>{children}</MainContentArea> | ||||
| </I18nProvider> | </I18nProvider> | ||||
| } | } | ||||
| @@ -1,22 +1,13 @@ | |||||
| import { Metadata } from "next"; | |||||
| import { getServerSession } from "next-auth"; | |||||
| import { redirect } from "next/navigation"; | |||||
| import { authOptions } from "@/config/authConfig"; | |||||
| import { AUTH } from "@/authorities"; | |||||
| import { I18nProvider } from "@/i18n"; | |||||
| export const metadata: Metadata = { | |||||
| title: "M18 Sync", | |||||
| }; | |||||
| export default async function M18SynLayout({ | |||||
| export default function M18SyncLayout({ | |||||
| children, | children, | ||||
| }: { | }: { | ||||
| children: React.ReactNode; | children: React.ReactNode; | ||||
| }) { | }) { | ||||
| const session = await getServerSession(authOptions); | |||||
| const abilities = session?.user?.abilities ?? []; | |||||
| if (!abilities.includes(AUTH.ADMIN)) { | |||||
| redirect("/dashboard"); | |||||
| } | |||||
| return <>{children}</>; | |||||
| return ( | |||||
| <I18nProvider namespaces={["m18Sync", "navigation", "common"]}> | |||||
| {children} | |||||
| </I18nProvider> | |||||
| ); | |||||
| } | } | ||||
| @@ -18,7 +18,7 @@ const PickOrder: React.FC<Props> = async ({ searchParams }) => { | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| <I18nProvider namespaces={["pickOrder"]}> | |||||
| <I18nProvider namespaces={["pickOrder","navigation","common"]}> | |||||
| <Suspense fallback={<PickOrderDetail.Loading />}> | <Suspense fallback={<PickOrderDetail.Loading />}> | ||||
| <PickOrderDetail consoCode={`${searchParams["consoCode"]}`} /> | <PickOrderDetail consoCode={`${searchParams["consoCode"]}`} /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -17,7 +17,7 @@ const PickOrder: React.FC = async () => { | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| <I18nProvider namespaces={["pickOrder", "common"]}> | |||||
| <I18nProvider namespaces={["pickOrder","navigation","common"]}> | |||||
| <Suspense fallback={<PickOrderSearch.Loading />}> | <Suspense fallback={<PickOrderSearch.Loading />}> | ||||
| <PickOrderSearch /> | <PickOrderSearch /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -31,7 +31,7 @@ const PoEdit: React.FC<Props> = async ({ searchParams }) => { | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| {/* <Typography variant="h4">{t("Create Material")}</Typography> */} | {/* <Typography variant="h4">{t("Create Material")}</Typography> */} | ||||
| <I18nProvider namespaces={[type, "dashboard"]}> | |||||
| <I18nProvider namespaces={[type, "navigation", "common", "dashboard"]}> | |||||
| <Suspense fallback={<PoDetail.Loading />}> | <Suspense fallback={<PoDetail.Loading />}> | ||||
| <PoDetail id={id} /> | <PoDetail id={id} /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -17,7 +17,7 @@ const PurchaseOrder: React.FC = async () => { | |||||
| // preloadClaims(); | // preloadClaims(); | ||||
| return ( | return ( | ||||
| <> | <> | ||||
| <I18nProvider namespaces={["purchaseOrder", "common", "items","dashboard"]}> | |||||
| <I18nProvider namespaces={["purchaseOrder","navigation","common","dashboard"]}> | |||||
| <Stack | <Stack | ||||
| direction="row" | direction="row" | ||||
| justifyContent="space-between" | justifyContent="space-between" | ||||
| @@ -17,7 +17,7 @@ export default function PoWorkbenchPage() { | |||||
| flexDirection: "column", | flexDirection: "column", | ||||
| }} | }} | ||||
| > | > | ||||
| <I18nProvider namespaces={["poWorkbench", "purchaseOrder", "common"]}> | |||||
| <I18nProvider namespaces={["poWorkbench","navigation","common","purchaseOrder"]}> | |||||
| <PoWorkbenchPageClient /> | <PoWorkbenchPageClient /> | ||||
| </I18nProvider> | </I18nProvider> | ||||
| </Box> | </Box> | ||||
| @@ -15,7 +15,7 @@ export const metadata: Metadata = { | |||||
| }; | }; | ||||
| const production: React.FC = async () => { | const production: React.FC = async () => { | ||||
| const { t } = await getServerI18n("common"); | |||||
| const { t } = await getServerI18n("production", "common"); | |||||
| const printerCombo = await fetchPrinterCombo(); | const printerCombo = await fetchPrinterCombo(); | ||||
| return ( | return ( | ||||
| <> | <> | ||||
| @@ -38,7 +38,7 @@ const production: React.FC = async () => { | |||||
| {t("Create Process")} | {t("Create Process")} | ||||
| </Button> */} | </Button> */} | ||||
| </Stack> | </Stack> | ||||
| <I18nProvider namespaces={["common", "production","purchaseOrder","jo"]}> | |||||
| <I18nProvider namespaces={["production","productionProcess","navigation","common","purchaseOrder","jo"]}> | |||||
| <ProductionProcessPage printerCombo={printerCombo} /> {/* Use new component */} | <ProductionProcessPage printerCombo={printerCombo} /> {/* Use new component */} | ||||
| </I18nProvider> | </I18nProvider> | ||||
| </> | </> | ||||
| @@ -13,7 +13,7 @@ export const metadata: Metadata = { | |||||
| }; | }; | ||||
| const productionProcess: React.FC = async () => { | const productionProcess: React.FC = async () => { | ||||
| const { t } = await getServerI18n("common"); | |||||
| const { t } = await getServerI18n("productionProcess", "navigation", "common"); | |||||
| const printerCombo = await fetchPrinterCombo(); | const printerCombo = await fetchPrinterCombo(); | ||||
| return ( | return ( | ||||
| <> | <> | ||||
| @@ -36,7 +36,7 @@ const productionProcess: React.FC = async () => { | |||||
| {t("Create Process")} | {t("Create Process")} | ||||
| </Button> */} | </Button> */} | ||||
| </Stack> | </Stack> | ||||
| <I18nProvider namespaces={["common", "production","purchaseOrder","jo","dashboard"]}> | |||||
| <I18nProvider namespaces={["productionProcess","navigation","common","purchaseOrder","jo","dashboard"]}> | |||||
| <Suspense fallback={<ProductionProcessLoading />}> | <Suspense fallback={<ProductionProcessLoading />}> | ||||
| <ProductionProcessPage printerCombo={printerCombo} /> | <ProductionProcessPage printerCombo={printerCombo} /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -11,12 +11,12 @@ export const metadata: Metadata = { | |||||
| }; | }; | ||||
| const Projects: React.FC = async () => { | const Projects: React.FC = async () => { | ||||
| const { t } = await getServerI18n("projects"); | |||||
| const { t } = await getServerI18n("project"); | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| <Typography variant="h4">{t("Create Project")}</Typography> | <Typography variant="h4">{t("Create Project")}</Typography> | ||||
| <I18nProvider namespaces={["projects"]}> | |||||
| <I18nProvider namespaces={["project","navigation","common"]}> | |||||
| <CreateProject /> | <CreateProject /> | ||||
| </I18nProvider> | </I18nProvider> | ||||
| </> | </> | ||||
| @@ -20,7 +20,7 @@ export const metadata: Metadata = { | |||||
| }; | }; | ||||
| const Projects: React.FC = async () => { | const Projects: React.FC = async () => { | ||||
| const { t } = await getServerI18n("projects"); | |||||
| const { t } = await getServerI18n("project"); | |||||
| preloadProjects(); | preloadProjects(); | ||||
| return ( | return ( | ||||
| @@ -43,7 +43,7 @@ const Projects: React.FC = async () => { | |||||
| {t("Create Project")} | {t("Create Project")} | ||||
| </Button> | </Button> | ||||
| </Stack> | </Stack> | ||||
| <I18nProvider namespaces={["project"]}> | |||||
| <I18nProvider namespaces={["project","navigation","common"]}> | |||||
| <Suspense fallback={<ProjectSearch.Loading />}> | <Suspense fallback={<ProjectSearch.Loading />}> | ||||
| <ProjectSearch /> | <ProjectSearch /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -0,0 +1,13 @@ | |||||
| import { I18nProvider } from "@/i18n"; | |||||
| export default function PsLayout({ | |||||
| children, | |||||
| }: { | |||||
| children: React.ReactNode; | |||||
| }) { | |||||
| return ( | |||||
| <I18nProvider namespaces={["scheduling", "navigation", "common"]}> | |||||
| {children} | |||||
| </I18nProvider> | |||||
| ); | |||||
| } | |||||
| @@ -619,7 +619,7 @@ export default function ProductionSchedulePage() { | |||||
| return ( | return ( | ||||
| <div className="space-y-4"> | <div className="space-y-4"> | ||||
| <PageTitleBar | <PageTitleBar | ||||
| title="排程" | |||||
| title="生產排程" | |||||
| actions={ | actions={ | ||||
| <> | <> | ||||
| <button | <button | ||||
| @@ -28,7 +28,7 @@ const PutAway: React.FC = async () => { | |||||
| {t("Put Away")} | {t("Put Away")} | ||||
| </Typography> | </Typography> | ||||
| </Stack> | </Stack> | ||||
| <I18nProvider namespaces={["putAway", "purchaseOrder", "common"]}> | |||||
| <I18nProvider namespaces={["putAway","navigation","common","purchaseOrder"]}> | |||||
| <Suspense fallback={<PutAwayScan.Loading />}> | <Suspense fallback={<PutAwayScan.Loading />}> | ||||
| <PutAwayScan /> | <PutAwayScan /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -24,7 +24,7 @@ const PutAwayCamPage: React.FC = async () => { | |||||
| {t("Put Away")} | {t("Put Away")} | ||||
| </Typography> | </Typography> | ||||
| </Stack> | </Stack> | ||||
| <I18nProvider namespaces={["putAway", "purchaseOrder", "common"]}> | |||||
| <I18nProvider namespaces={["putAway","navigation","common","purchaseOrder"]}> | |||||
| <Suspense fallback={<PutAwayCamScanWrapper.Loading />}> | <Suspense fallback={<PutAwayCamScanWrapper.Loading />}> | ||||
| <PutAwayCamScanWrapper /> | <PutAwayCamScanWrapper /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -0,0 +1,13 @@ | |||||
| import { I18nProvider } from "@/i18n"; | |||||
| export default function ReportLayout({ | |||||
| children, | |||||
| }: { | |||||
| children: React.ReactNode; | |||||
| }) { | |||||
| return ( | |||||
| <I18nProvider namespaces={["report", "navigation", "common"]}> | |||||
| {children} | |||||
| </I18nProvider> | |||||
| ); | |||||
| } | |||||
| @@ -45,7 +45,7 @@ const DetailScheduling: React.FC<Props> = async ({ searchParams }) => { | |||||
| <Typography variant="h4" marginInlineEnd={2}> | <Typography variant="h4" marginInlineEnd={2}> | ||||
| {t("FG Production Schedule")} | {t("FG Production Schedule")} | ||||
| </Typography> | </Typography> | ||||
| <I18nProvider namespaces={["schedule", "common"]}> | |||||
| <I18nProvider namespaces={["schedule","navigation","common"]}> | |||||
| <Suspense fallback={<DetailedScheduleDetail.Loading />}> | <Suspense fallback={<DetailedScheduleDetail.Loading />}> | ||||
| <DetailedScheduleDetail type={type} id={parseInt(id)} /> | <DetailedScheduleDetail type={type} id={parseInt(id)} /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -31,7 +31,7 @@ const DetailScheduling: React.FC = async () => { | |||||
| {t("Detail Scheduling")} | {t("Detail Scheduling")} | ||||
| </Typography> | </Typography> | ||||
| </Stack> | </Stack> | ||||
| <I18nProvider namespaces={["schedule", "common"]}> | |||||
| <I18nProvider namespaces={["schedule","navigation","common"]}> | |||||
| <Suspense fallback={<DetailedSchedule.Loading />}> | <Suspense fallback={<DetailedSchedule.Loading />}> | ||||
| <DetailedSchedule type={type} /> | <DetailedSchedule type={type} /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -62,7 +62,7 @@ const roughSchedulingDetail: React.FC<Props> = async ({ searchParams }) => { | |||||
| {t("Create product")} | {t("Create product")} | ||||
| </Button> */} | </Button> */} | ||||
| </Stack> | </Stack> | ||||
| <I18nProvider namespaces={["schedule", "common"]}> | |||||
| <I18nProvider namespaces={["schedule","navigation","common"]}> | |||||
| <Suspense fallback={<RoughScheduleDetailView.Loading />}> | <Suspense fallback={<RoughScheduleDetailView.Loading />}> | ||||
| <RoughScheduleDetailView type={type} id={parseInt(id)} /> | <RoughScheduleDetailView type={type} id={parseInt(id)} /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -47,7 +47,7 @@ const roughScheduling: React.FC = async () => { | |||||
| {t("Test Rough Scheduling")} | {t("Test Rough Scheduling")} | ||||
| </Button> */} | </Button> */} | ||||
| </Stack> | </Stack> | ||||
| <I18nProvider namespaces={["schedule", "common"]}> | |||||
| <I18nProvider namespaces={["schedule","navigation","common"]}> | |||||
| <Suspense fallback={<RoughSchedule.Loading />}> | <Suspense fallback={<RoughSchedule.Loading />}> | ||||
| <RoughSchedule type={type} /> | <RoughSchedule type={type} /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -9,13 +9,13 @@ export const metadata: Metadata = { | |||||
| }; | }; | ||||
| const BomWeightingScorePage: React.FC = async () => { | const BomWeightingScorePage: React.FC = async () => { | ||||
| const { t } = await getServerI18n("common"); | |||||
| const { t } = await getServerI18n("bomWeighting"); | |||||
| const bomWeightingScores = await fetchBomWeightingScores(); | const bomWeightingScores = await fetchBomWeightingScores(); | ||||
| return ( | return ( | ||||
| <> | <> | ||||
| <PageTitleBar title={t("BOM Weighting Score List")} className="mb-4" /> | <PageTitleBar title={t("BOM Weighting Score List")} className="mb-4" /> | ||||
| <I18nProvider namespaces={["common"]}> | |||||
| <I18nProvider namespaces={["bomWeighting","navigation","common"]}> | |||||
| <BomWeightingTabs bomWeightingScores={bomWeightingScores} /> | <BomWeightingTabs bomWeightingScores={bomWeightingScores} /> | ||||
| </I18nProvider> | </I18nProvider> | ||||
| </> | </> | ||||
| @@ -1,3 +1,4 @@ | |||||
| import { I18nProvider } from "@/i18n"; | |||||
| import ClientMonitorPage from "@/components/ClientMonitor/ClientMonitorPage"; | import ClientMonitorPage from "@/components/ClientMonitor/ClientMonitorPage"; | ||||
| import { isMonitoringEnabled } from "@/config/monitoring"; | import { isMonitoringEnabled } from "@/config/monitoring"; | ||||
| import { Metadata } from "next"; | import { Metadata } from "next"; | ||||
| @@ -11,5 +12,9 @@ export default function ClientMonitorRoutePage() { | |||||
| if (!isMonitoringEnabled) { | if (!isMonitoringEnabled) { | ||||
| redirect("/settings/user"); | redirect("/settings/user"); | ||||
| } | } | ||||
| return <ClientMonitorPage />; | |||||
| return ( | |||||
| <I18nProvider namespaces={["clientMonitor", "navigation", "common"]}> | |||||
| <ClientMonitorPage /> | |||||
| </I18nProvider> | |||||
| ); | |||||
| } | } | ||||
| @@ -8,10 +8,10 @@ export const metadata: Metadata = { | |||||
| }; | }; | ||||
| export default async function DeliveryOrderFloorPage() { | export default async function DeliveryOrderFloorPage() { | ||||
| const { t } = await getServerI18n("deliveryOrderFloor", "common"); | |||||
| const { t } = await getServerI18n("deliveryOrderFloor"); | |||||
| return ( | return ( | ||||
| <I18nProvider namespaces={["deliveryOrderFloor", "common"]}> | |||||
| <I18nProvider namespaces={["deliveryOrderFloor","navigation"]}> | |||||
| <Stack spacing={2}> | <Stack spacing={2}> | ||||
| <Typography variant="h4">{t("title")}</Typography> | <Typography variant="h4">{t("title")}</Typography> | ||||
| <DeliveryOrderFloorSettings /> | <DeliveryOrderFloorSettings /> | ||||
| @@ -13,7 +13,7 @@ type EquipmentTabsProps = { | |||||
| const EquipmentTabs: React.FC<EquipmentTabsProps> = ({ onTabChange }) => { | const EquipmentTabs: React.FC<EquipmentTabsProps> = ({ onTabChange }) => { | ||||
| const router = useRouter(); | const router = useRouter(); | ||||
| const searchParams = useSearchParams(); | const searchParams = useSearchParams(); | ||||
| const { t } = useTranslation("common"); | |||||
| const { t } = useTranslation(["equipment", "common"]); | |||||
| const tabFromUrl = searchParams.get("tab"); | const tabFromUrl = searchParams.get("tab"); | ||||
| const initialTabIndex = tabFromUrl ? parseInt(tabFromUrl, 10) : 0; | const initialTabIndex = tabFromUrl ? parseInt(tabFromUrl, 10) : 0; | ||||
| @@ -9,8 +9,8 @@ import UpdateMaintenanceForm from "@/components/UpdateMaintenance/UpdateMaintena | |||||
| type Props = {} & SearchParams; | type Props = {} & SearchParams; | ||||
| const MaintenanceEditPage: React.FC<Props> = async ({ searchParams }) => { | const MaintenanceEditPage: React.FC<Props> = async ({ searchParams }) => { | ||||
| const type = "common"; | |||||
| const { t } = await getServerI18n(type); | |||||
| const type = "equipment"; | |||||
| const { t } = await getServerI18n(type, "navigation", "common"); | |||||
| const id = isString(searchParams["id"]) | const id = isString(searchParams["id"]) | ||||
| ? parseInt(searchParams["id"]) | ? parseInt(searchParams["id"]) | ||||
| : undefined; | : undefined; | ||||
| @@ -20,7 +20,7 @@ const MaintenanceEditPage: React.FC<Props> = async ({ searchParams }) => { | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| <Typography variant="h4">{t("Update Equipment Maintenance and Repair")}</Typography> | <Typography variant="h4">{t("Update Equipment Maintenance and Repair")}</Typography> | ||||
| <I18nProvider namespaces={[type]}> | |||||
| <I18nProvider namespaces={[type, "navigation", "common"]}> | |||||
| <UpdateMaintenanceForm id={id} /> | <UpdateMaintenanceForm id={id} /> | ||||
| </I18nProvider> | </I18nProvider> | ||||
| </> | </> | ||||
| @@ -9,11 +9,11 @@ type Props = {} & SearchParams; | |||||
| const materialSetting: React.FC<Props> = async ({ searchParams }) => { | const materialSetting: React.FC<Props> = async ({ searchParams }) => { | ||||
| // const type = TypeEnum.PRODUCT; | // const type = TypeEnum.PRODUCT; | ||||
| const { t } = await getServerI18n("common"); | |||||
| const { t } = await getServerI18n("equipment", "navigation", "common"); | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| {/* <Typography variant="h4">{t("Create Material")}</Typography> */} | {/* <Typography variant="h4">{t("Create Material")}</Typography> */} | ||||
| <I18nProvider namespaces={["common"]}> | |||||
| <I18nProvider namespaces={["equipment","navigation","common"]}> | |||||
| <CreateEquipmentType /> | <CreateEquipmentType /> | ||||
| </I18nProvider> | </I18nProvider> | ||||
| </> | </> | ||||
| @@ -9,8 +9,8 @@ import { notFound } from "next/navigation"; | |||||
| type Props = {} & SearchParams; | type Props = {} & SearchParams; | ||||
| const productSetting: React.FC<Props> = async ({ searchParams }) => { | const productSetting: React.FC<Props> = async ({ searchParams }) => { | ||||
| const type = "common"; | |||||
| const { t } = await getServerI18n(type); | |||||
| const type = "equipment"; | |||||
| const { t } = await getServerI18n(type, "navigation", "common"); | |||||
| const id = isString(searchParams["id"]) | const id = isString(searchParams["id"]) | ||||
| ? parseInt(searchParams["id"]) | ? parseInt(searchParams["id"]) | ||||
| : undefined; | : undefined; | ||||
| @@ -20,7 +20,7 @@ const productSetting: React.FC<Props> = async ({ searchParams }) => { | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| {/* <Typography variant="h4">{t("Create Material")}</Typography> */} | {/* <Typography variant="h4">{t("Create Material")}</Typography> */} | ||||
| <I18nProvider namespaces={[type]}> | |||||
| <I18nProvider namespaces={[type, "navigation", "common"]}> | |||||
| <CreateEquipmentType id={id} /> | <CreateEquipmentType id={id} /> | ||||
| </I18nProvider> | </I18nProvider> | ||||
| </> | </> | ||||
| @@ -19,8 +19,8 @@ export const metadata: Metadata = { | |||||
| }; | }; | ||||
| const productSetting: React.FC = async () => { | const productSetting: React.FC = async () => { | ||||
| const type = "common"; | |||||
| const { t } = await getServerI18n(type); | |||||
| const type = "equipment"; | |||||
| const { t } = await getServerI18n(type, "navigation", "common"); | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| @@ -35,7 +35,7 @@ const productSetting: React.FC = async () => { | |||||
| </Typography> | </Typography> | ||||
| </Stack> | </Stack> | ||||
| <Suspense fallback={<EquipmentSearchLoading />}> | <Suspense fallback={<EquipmentSearchLoading />}> | ||||
| <I18nProvider namespaces={["common", "project"]}> | |||||
| <I18nProvider namespaces={["equipment","navigation","common","project"]}> | |||||
| <EquipmentSearchWrapper /> | <EquipmentSearchWrapper /> | ||||
| </I18nProvider> | </I18nProvider> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -9,11 +9,11 @@ type Props = {} & SearchParams; | |||||
| const materialSetting: React.FC<Props> = async ({ searchParams }) => { | const materialSetting: React.FC<Props> = async ({ searchParams }) => { | ||||
| // const type = TypeEnum.PRODUCT; | // const type = TypeEnum.PRODUCT; | ||||
| const { t } = await getServerI18n("common"); | |||||
| const { t } = await getServerI18n("equipment", "navigation", "common"); | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| {/* <Typography variant="h4">{t("Create Material")}</Typography> */} | {/* <Typography variant="h4">{t("Create Material")}</Typography> */} | ||||
| <I18nProvider namespaces={["common"]}> | |||||
| <I18nProvider namespaces={["equipment","navigation","common"]}> | |||||
| <CreateEquipmentType /> | <CreateEquipmentType /> | ||||
| </I18nProvider> | </I18nProvider> | ||||
| </> | </> | ||||
| @@ -9,8 +9,8 @@ import { notFound } from "next/navigation"; | |||||
| type Props = {} & SearchParams; | type Props = {} & SearchParams; | ||||
| const productSetting: React.FC<Props> = async ({ searchParams }) => { | const productSetting: React.FC<Props> = async ({ searchParams }) => { | ||||
| const type = "common"; | |||||
| const { t } = await getServerI18n(type); | |||||
| const type = "equipment"; | |||||
| const { t } = await getServerI18n(type, "navigation", "common"); | |||||
| const id = isString(searchParams["id"]) | const id = isString(searchParams["id"]) | ||||
| ? parseInt(searchParams["id"]) | ? parseInt(searchParams["id"]) | ||||
| : undefined; | : undefined; | ||||
| @@ -20,7 +20,7 @@ const productSetting: React.FC<Props> = async ({ searchParams }) => { | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| {/* <Typography variant="h4">{t("Create Material")}</Typography> */} | {/* <Typography variant="h4">{t("Create Material")}</Typography> */} | ||||
| <I18nProvider namespaces={[type]}> | |||||
| <I18nProvider namespaces={[type, "navigation", "common"]}> | |||||
| <CreateEquipmentType id={id} /> | <CreateEquipmentType id={id} /> | ||||
| </I18nProvider> | </I18nProvider> | ||||
| </> | </> | ||||
| @@ -15,8 +15,8 @@ export const metadata: Metadata = { | |||||
| }; | }; | ||||
| const productSetting: React.FC = async () => { | const productSetting: React.FC = async () => { | ||||
| const type = "common"; | |||||
| const { t } = await getServerI18n(type); | |||||
| const type = "equipment"; | |||||
| const { t } = await getServerI18n(type, "navigation", "common"); | |||||
| const equipmentTypes = await fetchAllEquipmentTypes(); | const equipmentTypes = await fetchAllEquipmentTypes(); | ||||
| // preloadClaims(); | // preloadClaims(); | ||||
| @@ -41,7 +41,7 @@ const productSetting: React.FC = async () => { | |||||
| </Button> */} | </Button> */} | ||||
| </Stack> | </Stack> | ||||
| <Suspense fallback={<EquipmentTypeSearch.Loading />}> | <Suspense fallback={<EquipmentTypeSearch.Loading />}> | ||||
| <I18nProvider namespaces={["common", "project"]}> | |||||
| <I18nProvider namespaces={["equipment","navigation","common","project"]}> | |||||
| <EquipmentTypeSearch /> | <EquipmentTypeSearch /> | ||||
| </I18nProvider> | </I18nProvider> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -9,8 +9,8 @@ import UpdateMaintenanceForm from "@/components/UpdateMaintenance/UpdateMaintena | |||||
| type Props = {} & SearchParams; | type Props = {} & SearchParams; | ||||
| const MaintenanceEditPage: React.FC<Props> = async ({ searchParams }) => { | const MaintenanceEditPage: React.FC<Props> = async ({ searchParams }) => { | ||||
| const type = "common"; | |||||
| const { t } = await getServerI18n(type); | |||||
| const type = "importBom"; | |||||
| const { t } = await getServerI18n(type, "navigation", "common"); | |||||
| const id = isString(searchParams["id"]) | const id = isString(searchParams["id"]) | ||||
| ? parseInt(searchParams["id"]) | ? parseInt(searchParams["id"]) | ||||
| : undefined; | : undefined; | ||||
| @@ -20,10 +20,10 @@ const MaintenanceEditPage: React.FC<Props> = async ({ searchParams }) => { | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| <Typography variant="h4">{t("Update Equipment Maintenance and Repair")}</Typography> | <Typography variant="h4">{t("Update Equipment Maintenance and Repair")}</Typography> | ||||
| <I18nProvider namespaces={[type]}> | |||||
| <I18nProvider namespaces={[type, "navigation", "common"]}> | |||||
| <UpdateMaintenanceForm id={id} /> | <UpdateMaintenanceForm id={id} /> | ||||
| </I18nProvider> | </I18nProvider> | ||||
| </> | </> | ||||
| ); | ); | ||||
| }; | }; | ||||
| export default MaintenanceEditPage; | |||||
| export default MaintenanceEditPage; | |||||
| @@ -13,7 +13,7 @@ const materialSetting: React.FC<Props> = async ({ searchParams }) => { | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| {/* <Typography variant="h4">{t("Create Material")}</Typography> */} | {/* <Typography variant="h4">{t("Create Material")}</Typography> */} | ||||
| <I18nProvider namespaces={["common"]}> | |||||
| <I18nProvider namespaces={["importBom","navigation","common"]}> | |||||
| <CreateEquipmentType /> | <CreateEquipmentType /> | ||||
| </I18nProvider> | </I18nProvider> | ||||
| </> | </> | ||||
| @@ -1,16 +1,14 @@ | |||||
| import { SearchParams } from "@/app/utils/fetchUtil"; | import { SearchParams } from "@/app/utils/fetchUtil"; | ||||
| import { TypeEnum } from "@/app/utils/typeEnum"; | |||||
| import CreateEquipmentType from "@/components/CreateEquipment"; | import CreateEquipmentType from "@/components/CreateEquipment"; | ||||
| import { I18nProvider, getServerI18n } from "@/i18n"; | import { I18nProvider, getServerI18n } from "@/i18n"; | ||||
| import { Typography } from "@mui/material"; | |||||
| import isString from "lodash/isString"; | import isString from "lodash/isString"; | ||||
| import { notFound } from "next/navigation"; | import { notFound } from "next/navigation"; | ||||
| type Props = {} & SearchParams; | type Props = {} & SearchParams; | ||||
| const productSetting: React.FC<Props> = async ({ searchParams }) => { | const productSetting: React.FC<Props> = async ({ searchParams }) => { | ||||
| const type = "common"; | |||||
| const { t } = await getServerI18n(type); | |||||
| const type = "importBom"; | |||||
| await getServerI18n(type, "navigation", "common"); | |||||
| const id = isString(searchParams["id"]) | const id = isString(searchParams["id"]) | ||||
| ? parseInt(searchParams["id"]) | ? parseInt(searchParams["id"]) | ||||
| : undefined; | : undefined; | ||||
| @@ -19,8 +17,7 @@ const productSetting: React.FC<Props> = async ({ searchParams }) => { | |||||
| } | } | ||||
| return ( | return ( | ||||
| <> | <> | ||||
| {/* <Typography variant="h4">{t("Create Material")}</Typography> */} | |||||
| <I18nProvider namespaces={[type]}> | |||||
| <I18nProvider namespaces={[type, "navigation", "common"]}> | |||||
| <CreateEquipmentType id={id} /> | <CreateEquipmentType id={id} /> | ||||
| </I18nProvider> | </I18nProvider> | ||||
| </> | </> | ||||
| @@ -21,7 +21,7 @@ export default async function ImportBomPage() { | |||||
| Import BOM | Import BOM | ||||
| </Typography> | </Typography> | ||||
| </Stack> | </Stack> | ||||
| <I18nProvider namespaces={["common"]}> | |||||
| <I18nProvider namespaces={["importBom","navigation","common","importExcel"]}> | |||||
| <ImportBomWrapper /> | <ImportBomWrapper /> | ||||
| </I18nProvider> | </I18nProvider> | ||||
| </> | </> | ||||
| @@ -1,34 +1,34 @@ | |||||
| import { Metadata } from "next"; | |||||
| import { getServerI18n } from "@/i18n"; | |||||
| import { I18nProvider, getServerI18n } from "@/i18n"; | |||||
| import Stack from "@mui/material/Stack"; | import Stack from "@mui/material/Stack"; | ||||
| import Typography from "@mui/material/Typography"; | import Typography from "@mui/material/Typography"; | ||||
| import { Metadata } from "next"; | |||||
| import { Suspense } from "react"; | import { Suspense } from "react"; | ||||
| import ExcelFileImport from "@/components/ExcelFileImport"; | import ExcelFileImport from "@/components/ExcelFileImport"; | ||||
| export const metadata: Metadata = { | export const metadata: Metadata = { | ||||
| title: "Excel File Import", | |||||
| title: "Excel File Import", | |||||
| }; | }; | ||||
| const ImportExcel: React.FC = async () => { | const ImportExcel: React.FC = async () => { | ||||
| const { t } = await getServerI18n("common"); | |||||
| const { t } = await getServerI18n("importExcel", "navigation", "common"); | |||||
| return ( | |||||
| <> | |||||
| <Stack | |||||
| direction="row" | |||||
| justifyContent="space-between" | |||||
| flexWrap="wrap" | |||||
| rowGap={2} | |||||
| > | |||||
| <Typography variant="h4" marginInlineEnd={2}> | |||||
| {t("Excel File Import")} | |||||
| </Typography> | |||||
| </Stack> | |||||
| <Suspense> | |||||
| <ExcelFileImport /> | |||||
| </Suspense> | |||||
| </> | |||||
| ) | |||||
| return ( | |||||
| <I18nProvider namespaces={["importExcel", "navigation", "common"]}> | |||||
| <Stack | |||||
| direction="row" | |||||
| justifyContent="space-between" | |||||
| flexWrap="wrap" | |||||
| rowGap={2} | |||||
| > | |||||
| <Typography variant="h4" marginInlineEnd={2}> | |||||
| {t("title")} | |||||
| </Typography> | |||||
| </Stack> | |||||
| <Suspense> | |||||
| <ExcelFileImport /> | |||||
| </Suspense> | |||||
| </I18nProvider> | |||||
| ); | |||||
| }; | }; | ||||
| export default ImportExcel; | export default ImportExcel; | ||||
| @@ -9,13 +9,13 @@ export const metadata: Metadata = { | |||||
| }; | }; | ||||
| const ItemPriceSetting: React.FC = async () => { | const ItemPriceSetting: React.FC = async () => { | ||||
| const { t } = await getServerI18n("inventory", "common"); | |||||
| const { t } = await getServerI18n("itemPrice", "importExcel"); | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| <PageTitleBar title={t("Price Inquiry", { ns: "common" })} className="mb-4" /> | |||||
| <PageTitleBar title={t("Price Inquiry")} className="mb-4" /> | |||||
| <I18nProvider namespaces={["common", "inventory"]}> | |||||
| <I18nProvider namespaces={["itemPrice","navigation","common","inventory","importExcel"]}> | |||||
| <Suspense fallback={<ItemPriceSearch.Loading />}> | <Suspense fallback={<ItemPriceSearch.Loading />}> | ||||
| <ItemPriceSearch /> | <ItemPriceSearch /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -13,7 +13,7 @@ const materialSetting: React.FC<Props> = async ({ searchParams }) => { | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| {/* <Typography variant="h4">{t("Create Material")}</Typography> */} | {/* <Typography variant="h4">{t("Create Material")}</Typography> */} | ||||
| <I18nProvider namespaces={["items"]}> | |||||
| <I18nProvider namespaces={["items","navigation","common"]}> | |||||
| <CreateItem /> | <CreateItem /> | ||||
| </I18nProvider> | </I18nProvider> | ||||
| </> | </> | ||||
| @@ -24,7 +24,7 @@ const productSetting: React.FC<Props> = async ({ searchParams }) => { | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| {/* <Typography variant="h4">{t("Create Material")}</Typography> */} | {/* <Typography variant="h4">{t("Create Material")}</Typography> */} | ||||
| <I18nProvider namespaces={[type]}> | |||||
| <I18nProvider namespaces={[type, "navigation", "common"]}> | |||||
| <CreateProductMaterial id={id} /> | <CreateProductMaterial id={id} /> | ||||
| </I18nProvider> | </I18nProvider> | ||||
| </> | </> | ||||
| @@ -16,7 +16,7 @@ export const metadata: Metadata = { | |||||
| const productSetting: React.FC = async () => { | const productSetting: React.FC = async () => { | ||||
| const project = TypeEnum.PRODUCT; | const project = TypeEnum.PRODUCT; | ||||
| const { t } = await getServerI18n("project"); | |||||
| const { t } = await getServerI18n("items"); | |||||
| // preloadClaims(); | // preloadClaims(); | ||||
| return ( | return ( | ||||
| @@ -40,7 +40,7 @@ const productSetting: React.FC = async () => { | |||||
| </Button> */} | </Button> */} | ||||
| </Stack> | </Stack> | ||||
| <I18nProvider namespaces={["project", "common", "items"]}> | |||||
| <I18nProvider namespaces={["items","navigation","common"]}> | |||||
| <Suspense fallback={<ItemsSearch.Loading />}> | <Suspense fallback={<ItemsSearch.Loading />}> | ||||
| <ItemsSearch /> | <ItemsSearch /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -21,7 +21,7 @@ const M18ImportTestingPage: React.FC = async () => { | |||||
| rowGap={2} | rowGap={2} | ||||
| ></Stack> | ></Stack> | ||||
| <Suspense fallback={<M18ImportTesting.Loading />}> | <Suspense fallback={<M18ImportTesting.Loading />}> | ||||
| <I18nProvider namespaces={["common", "m18ImportTesting"]}> | |||||
| <I18nProvider namespaces={["m18ImportTesting","navigation","common"]}> | |||||
| <M18ImportTesting /> | <M18ImportTesting /> | ||||
| </I18nProvider> | </I18nProvider> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -29,7 +29,7 @@ const Customer: React.FC = async () => { | |||||
| {t("Mail")} | {t("Mail")} | ||||
| </Typography> | </Typography> | ||||
| </Stack> | </Stack> | ||||
| <I18nProvider namespaces={["mail", "common"]}> | |||||
| <I18nProvider namespaces={["mail","navigation","common"]}> | |||||
| <Suspense fallback={<MailSetting.Loading />}> | <Suspense fallback={<MailSetting.Loading />}> | ||||
| <MailSetting /> | <MailSetting /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -4,12 +4,12 @@ import { Suspense } from "react"; | |||||
| import CreatePrinter from "@/components/CreatePrinter"; | import CreatePrinter from "@/components/CreatePrinter"; | ||||
| const CreatePrinterPage: React.FC = async () => { | const CreatePrinterPage: React.FC = async () => { | ||||
| const { t } = await getServerI18n("common"); | |||||
| const { t } = await getServerI18n("printer"); | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| <Typography variant="h4">{t("Create Printer") || "新增列印機"}</Typography> | <Typography variant="h4">{t("Create Printer") || "新增列印機"}</Typography> | ||||
| <I18nProvider namespaces={["common"]}> | |||||
| <I18nProvider namespaces={["printer","navigation","common"]}> | |||||
| <Suspense fallback={<CreatePrinter.Loading />}> | <Suspense fallback={<CreatePrinter.Loading />}> | ||||
| <CreatePrinter /> | <CreatePrinter /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -10,7 +10,7 @@ import { fetchPrinterDetails } from "@/app/api/settings/printer/actions"; | |||||
| type Props = {} & SearchParams; | type Props = {} & SearchParams; | ||||
| const EditPrinterPage: React.FC<Props> = async ({ searchParams }) => { | const EditPrinterPage: React.FC<Props> = async ({ searchParams }) => { | ||||
| const { t } = await getServerI18n("common"); | |||||
| const { t } = await getServerI18n("printer"); | |||||
| const id = isString(searchParams["id"]) | const id = isString(searchParams["id"]) | ||||
| ? parseInt(searchParams["id"]) | ? parseInt(searchParams["id"]) | ||||
| : undefined; | : undefined; | ||||
| @@ -26,7 +26,7 @@ const EditPrinterPage: React.FC<Props> = async ({ searchParams }) => { | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| <Typography variant="h4">{t("Edit")} {t("Printer")}</Typography> | <Typography variant="h4">{t("Edit")} {t("Printer")}</Typography> | ||||
| <I18nProvider namespaces={["common"]}> | |||||
| <I18nProvider namespaces={["printer","navigation","common"]}> | |||||
| <Suspense fallback={<div>Loading...</div>}> | <Suspense fallback={<div>Loading...</div>}> | ||||
| <EditPrinter printer={printer} /> | <EditPrinter printer={printer} /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -13,7 +13,7 @@ export const metadata: Metadata = { | |||||
| }; | }; | ||||
| const Printer: React.FC = async () => { | const Printer: React.FC = async () => { | ||||
| const { t } = await getServerI18n("common"); | |||||
| const { t } = await getServerI18n("printer"); | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| @@ -35,7 +35,7 @@ const Printer: React.FC = async () => { | |||||
| {t("Create Printer") || "新增列印機"} | {t("Create Printer") || "新增列印機"} | ||||
| </Button> | </Button> | ||||
| </Stack> | </Stack> | ||||
| <I18nProvider namespaces={["common", "dashboard"]}> | |||||
| <I18nProvider namespaces={["printer","navigation","common","dashboard"]}> | |||||
| <Suspense fallback={<PrinterSearch.Loading />}> | <Suspense fallback={<PrinterSearch.Loading />}> | ||||
| <PrinterSearch /> | <PrinterSearch /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -43,7 +43,7 @@ const qcCategory: React.FC<Props> = async ({ searchParams }) => { | |||||
| <Typography variant="h4" marginInlineEnd={2}> | <Typography variant="h4" marginInlineEnd={2}> | ||||
| {t("Edit Qc Category")} | {t("Edit Qc Category")} | ||||
| </Typography> | </Typography> | ||||
| <I18nProvider namespaces={["qcCategory"]}> | |||||
| <I18nProvider namespaces={["qcCategory","navigation","common"]}> | |||||
| <QcCategorySave id={id} /> | <QcCategorySave id={id} /> | ||||
| </I18nProvider> | </I18nProvider> | ||||
| </> | </> | ||||
| @@ -16,7 +16,7 @@ const qcItem: React.FC = async () => { | |||||
| <Typography variant="h4" marginInlineEnd={2}> | <Typography variant="h4" marginInlineEnd={2}> | ||||
| {t("Create Qc Item")} | {t("Create Qc Item")} | ||||
| </Typography> | </Typography> | ||||
| <I18nProvider namespaces={["qcItem"]}> | |||||
| <I18nProvider namespaces={["qcItem","navigation","common"]}> | |||||
| <QcItemSave /> | <QcItemSave /> | ||||
| </I18nProvider> | </I18nProvider> | ||||
| </> | </> | ||||
| @@ -43,7 +43,7 @@ const qcItem: React.FC<Props> = async ({ searchParams }) => { | |||||
| <Typography variant="h4" marginInlineEnd={2}> | <Typography variant="h4" marginInlineEnd={2}> | ||||
| {t("Edit Qc Item")} | {t("Edit Qc Item")} | ||||
| </Typography> | </Typography> | ||||
| <I18nProvider namespaces={["qcItem"]}> | |||||
| <I18nProvider namespaces={["qcItem","navigation","common"]}> | |||||
| <QcItemSave id={id} /> | <QcItemSave id={id} /> | ||||
| </I18nProvider> | </I18nProvider> | ||||
| </> | </> | ||||
| @@ -37,7 +37,7 @@ const qcItem: React.FC = async () => { | |||||
| </Button> | </Button> | ||||
| </Stack> | </Stack> | ||||
| <Suspense fallback={<QcItemSearch.Loading />}> | <Suspense fallback={<QcItemSearch.Loading />}> | ||||
| <I18nProvider namespaces={["common", "qcItem"]}> | |||||
| <I18nProvider namespaces={["qcItem","navigation","common"]}> | |||||
| <QcItemSearch /> | <QcItemSearch /> | ||||
| </I18nProvider> | </I18nProvider> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -30,7 +30,7 @@ const qcItemAll: React.FC = async () => { | |||||
| </Typography> | </Typography> | ||||
| </Stack> | </Stack> | ||||
| <Suspense fallback={<div>Loading...</div>}> | <Suspense fallback={<div>Loading...</div>}> | ||||
| <I18nProvider namespaces={["common", "qcItemAll", "qcCategory", "qcItem"]}> | |||||
| <I18nProvider namespaces={["qcItemAll","navigation","common","qcCategory","qcItem"]}> | |||||
| <QcItemAllTabs | <QcItemAllTabs | ||||
| tab0Content={<Tab0ItemQcCategoryMapping />} | tab0Content={<Tab0ItemQcCategoryMapping />} | ||||
| tab1Content={<Tab1QcCategoryQcItemMapping />} | tab1Content={<Tab1QcCategoryQcItemMapping />} | ||||
| @@ -12,7 +12,7 @@ import Box from "@mui/material/Box"; | |||||
| export const metadata: Metadata = { title: "QR Code Handle" }; | export const metadata: Metadata = { title: "QR Code Handle" }; | ||||
| const QrCodeHandlePage: React.FC = async () => { | const QrCodeHandlePage: React.FC = async () => { | ||||
| const { t } = await getServerI18n("common"); | |||||
| const { t } = await getServerI18n("qrCodeHandle"); | |||||
| return ( | return ( | ||||
| <Box sx={{ width: "100%" }}> | <Box sx={{ width: "100%" }}> | ||||
| @@ -20,25 +20,25 @@ const QrCodeHandlePage: React.FC = async () => { | |||||
| {t("QR Code Handle")} | {t("QR Code Handle")} | ||||
| </Typography> | </Typography> | ||||
| <I18nProvider namespaces={["common", "user", "warehouse"]}> | |||||
| <I18nProvider namespaces={["qrCodeHandle","navigation","common","user","warehouse"]}> | |||||
| <QrCodeHandleTabs | <QrCodeHandleTabs | ||||
| userTabContent={ | userTabContent={ | ||||
| <Suspense fallback={<QrCodeHandleSearchWrapper.Loading />}> | <Suspense fallback={<QrCodeHandleSearchWrapper.Loading />}> | ||||
| <I18nProvider namespaces={["user", "common", "dashboard"]}> | |||||
| <I18nProvider namespaces={["qrCodeHandle","navigation","common","user","dashboard"]}> | |||||
| <QrCodeHandleSearchWrapper /> | <QrCodeHandleSearchWrapper /> | ||||
| </I18nProvider> | </I18nProvider> | ||||
| </Suspense> | </Suspense> | ||||
| } | } | ||||
| equipmentTabContent={ | equipmentTabContent={ | ||||
| <Suspense fallback={<QrCodeHandleEquipmentSearchWrapper.Loading />}> | <Suspense fallback={<QrCodeHandleEquipmentSearchWrapper.Loading />}> | ||||
| <I18nProvider namespaces={["common", "project", "dashboard"]}> | |||||
| <I18nProvider namespaces={["qrCodeHandle","navigation","common","project","dashboard"]}> | |||||
| <QrCodeHandleEquipmentSearchWrapper /> | <QrCodeHandleEquipmentSearchWrapper /> | ||||
| </I18nProvider> | </I18nProvider> | ||||
| </Suspense> | </Suspense> | ||||
| } | } | ||||
| warehouseTabContent={ | warehouseTabContent={ | ||||
| <Suspense fallback={<QrCodeHandleWarehouseSearchWrapper.Loading />}> | <Suspense fallback={<QrCodeHandleWarehouseSearchWrapper.Loading />}> | ||||
| <I18nProvider namespaces={["warehouse", "common", "dashboard"]}> | |||||
| <I18nProvider namespaces={["qrCodeHandle","navigation","common","warehouse","dashboard"]}> | |||||
| <QrCodeHandleWarehouseSearchWrapper /> | <QrCodeHandleWarehouseSearchWrapper /> | ||||
| </I18nProvider> | </I18nProvider> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -18,8 +18,7 @@ export const metadata: Metadata = { | |||||
| const roughScheduleSetting: React.FC = async () => { | const roughScheduleSetting: React.FC = async () => { | ||||
| //const project = TypeEnum.PRODUCT | //const project = TypeEnum.PRODUCT | ||||
| const project = "common" | |||||
| const { t } = await getServerI18n(project); | |||||
| const { t } = await getServerI18n("demandForecast", "navigation", "common"); | |||||
| // preloadClaims(); | // preloadClaims(); | ||||
| return ( | return ( | ||||
| @@ -43,7 +42,7 @@ const roughScheduleSetting: React.FC = async () => { | |||||
| </Button> */} | </Button> */} | ||||
| </Stack> | </Stack> | ||||
| <Suspense fallback={<RoughScheduleSettingWrapper.Loading />}> | <Suspense fallback={<RoughScheduleSettingWrapper.Loading />}> | ||||
| <I18nProvider namespaces={[ "common", "project",]}> | |||||
| <I18nProvider namespaces={["demandForecast", "navigation", "common", "project"]}> | |||||
| <RoughScheduleSetting items={[]} /> | <RoughScheduleSetting items={[]} /> | ||||
| </I18nProvider> | </I18nProvider> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -5,7 +5,7 @@ import GeneralLoading from "@/components/General/GeneralLoading"; | |||||
| import RouteBoard from "@/components/Shop/RouteBoard"; | import RouteBoard from "@/components/Shop/RouteBoard"; | ||||
| export default async function ShopRouteBoardPage() { | export default async function ShopRouteBoardPage() { | ||||
| await getServerI18n("shop", "common", "routeboard"); | |||||
| await getServerI18n("shop", "navigation"); | |||||
| return ( | return ( | ||||
| <Box | <Box | ||||
| sx={{ | sx={{ | ||||
| @@ -16,7 +16,7 @@ export default async function ShopRouteBoardPage() { | |||||
| flexDirection: "column", | flexDirection: "column", | ||||
| }} | }} | ||||
| > | > | ||||
| <I18nProvider namespaces={["shop", "common", "routeboard"]}> | |||||
| <I18nProvider namespaces={["shop","navigation"]}> | |||||
| <Suspense fallback={<GeneralLoading />}> | <Suspense fallback={<GeneralLoading />}> | ||||
| <RouteBoard /> | <RouteBoard /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -4,9 +4,9 @@ import { I18nProvider, getServerI18n } from "@/i18n"; | |||||
| import GeneralLoading from "@/components/General/GeneralLoading"; | import GeneralLoading from "@/components/General/GeneralLoading"; | ||||
| export default async function ShopDetailPage() { | export default async function ShopDetailPage() { | ||||
| const { t } = await getServerI18n("shop", "common"); | |||||
| await getServerI18n("shop"); | |||||
| return ( | return ( | ||||
| <I18nProvider namespaces={["shop", "common"]}> | |||||
| <I18nProvider namespaces={["shop","navigation"]}> | |||||
| <Suspense fallback={<GeneralLoading />}> | <Suspense fallback={<GeneralLoading />}> | ||||
| <ShopDetail /> | <ShopDetail /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -8,9 +8,9 @@ import { notFound } from "next/navigation"; | |||||
| export default async function ShopPage() { | export default async function ShopPage() { | ||||
| const { t } = await getServerI18n("shop", "common"); | |||||
| await getServerI18n("shop"); | |||||
| return ( | return ( | ||||
| <I18nProvider namespaces={["shop", "common"]}> | |||||
| <I18nProvider namespaces={["shop","navigation"]}> | |||||
| <Suspense fallback={<ShopWrapper.Loading />}> | <Suspense fallback={<ShopWrapper.Loading />}> | ||||
| <ShopWrapper /> | <ShopWrapper /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -4,9 +4,9 @@ import { I18nProvider, getServerI18n } from "@/i18n"; | |||||
| import GeneralLoading from "@/components/General/GeneralLoading"; | import GeneralLoading from "@/components/General/GeneralLoading"; | ||||
| export default async function TruckLaneDetailPage() { | export default async function TruckLaneDetailPage() { | ||||
| const { t } = await getServerI18n("shop", "common"); | |||||
| await getServerI18n("shop"); | |||||
| return ( | return ( | ||||
| <I18nProvider namespaces={["shop", "common"]}> | |||||
| <I18nProvider namespaces={["shop","navigation"]}> | |||||
| <Suspense fallback={<GeneralLoading />}> | <Suspense fallback={<GeneralLoading />}> | ||||
| <TruckLaneDetail /> | <TruckLaneDetail /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -17,7 +17,7 @@ const CreateStaffPage: React.FC = async () => { | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| <Typography variant="h4">{t("Create User")}</Typography> | <Typography variant="h4">{t("Create User")}</Typography> | ||||
| <I18nProvider namespaces={["user", "common"]}> | |||||
| <I18nProvider namespaces={["user","navigation","common"]}> | |||||
| <Suspense fallback={<CreateUser.Loading />}> | <Suspense fallback={<CreateUser.Loading />}> | ||||
| <CreateUser /> | <CreateUser /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -18,7 +18,7 @@ const User: React.FC<searchParamsProps> = async ({ searchParams }) => { | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| <Typography variant="h4">{t("Edit User")}</Typography> | <Typography variant="h4">{t("Edit User")}</Typography> | ||||
| <I18nProvider namespaces={["user", "common"]}> | |||||
| <I18nProvider namespaces={["user","navigation","common"]}> | |||||
| <Suspense fallback={<EditUser.Loading />}> | <Suspense fallback={<EditUser.Loading />}> | ||||
| <EditUser searchParams={searchParams} /> | <EditUser searchParams={searchParams} /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -47,7 +47,7 @@ const User: React.FC = async () => { | |||||
| {t("Create User")} | {t("Create User")} | ||||
| </Button> | </Button> | ||||
| </Stack> | </Stack> | ||||
| <I18nProvider namespaces={["user", "common", "dashboard"]}> | |||||
| <I18nProvider namespaces={["user","navigation","common","dashboard"]}> | |||||
| <UserExcelSheetView users={usersWithDetails} /> | <UserExcelSheetView users={usersWithDetails} /> | ||||
| </I18nProvider> | </I18nProvider> | ||||
| </> | </> | ||||
| @@ -9,7 +9,7 @@ const CreateWarehousePage: React.FC = async () => { | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| <Typography variant="h4">{t("Create Warehouse")}</Typography> | <Typography variant="h4">{t("Create Warehouse")}</Typography> | ||||
| <I18nProvider namespaces={["warehouse", "common"]}> | |||||
| <I18nProvider namespaces={["warehouse","navigation","common"]}> | |||||
| <Suspense fallback={<CreateWarehouse.Loading />}> | <Suspense fallback={<CreateWarehouse.Loading />}> | ||||
| <CreateWarehouse /> | <CreateWarehouse /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -31,7 +31,7 @@ const Warehouse: React.FC = async () => { | |||||
| {t("Create Warehouse")} | {t("Create Warehouse")} | ||||
| </Button> | </Button> | ||||
| </Stack> | </Stack> | ||||
| <I18nProvider namespaces={["warehouse", "common", "dashboard"]}> | |||||
| <I18nProvider namespaces={["warehouse","navigation","common","dashboard"]}> | |||||
| <Suspense fallback={null}> | <Suspense fallback={null}> | ||||
| <WarehouseTabs | <WarehouseTabs | ||||
| tab0Content={<WarehouseHandleWrapper />} | tab0Content={<WarehouseHandleWrapper />} | ||||
| @@ -11,7 +11,7 @@ export const metadata: Metadata = { | |||||
| const SearchView: React.FC = async () => { | const SearchView: React.FC = async () => { | ||||
| return ( | return ( | ||||
| <> | <> | ||||
| <I18nProvider namespaces={["inventory", "common"]}> | |||||
| <I18nProvider namespaces={["stockIssue", "navigation", "common"]}> | |||||
| <Suspense fallback={<SearchPage.Loading />}> | <Suspense fallback={<SearchPage.Loading />}> | ||||
| <SearchPage /> | <SearchPage /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -1,24 +1,18 @@ | |||||
| import { SearchParams } from "@/app/utils/fetchUtil"; | import { SearchParams } from "@/app/utils/fetchUtil"; | ||||
| import PickOrderDetail from "@/components/PickOrderDetail"; | import PickOrderDetail from "@/components/PickOrderDetail"; | ||||
| import { getServerI18n, I18nProvider } from "@/i18n"; | |||||
| import { Stack, Typography } from "@mui/material"; | |||||
| import { I18nProvider } from "@/i18n"; | |||||
| import { Metadata } from "next"; | import { Metadata } from "next"; | ||||
| import { Suspense } from "react"; | import { Suspense } from "react"; | ||||
| export const metadata: Metadata = { | export const metadata: Metadata = { | ||||
| title: "Consolidated Pick Order Flow", | |||||
| title: "Stock Out Issue Record Detail", | |||||
| }; | }; | ||||
| type Props = {} & SearchParams; | type Props = {} & SearchParams; | ||||
| const PickOrder: React.FC<Props> = async ({ searchParams }) => { | |||||
| const { t } = await getServerI18n("pickOrder"); | |||||
| const StockOutIssueRecordDetail: React.FC<Props> = async ({ searchParams }) => { | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| <I18nProvider namespaces={["pickOrder"]}> | |||||
| <I18nProvider namespaces={["pickOrder", "navigation", "common"]}> | |||||
| <Suspense fallback={<PickOrderDetail.Loading />}> | <Suspense fallback={<PickOrderDetail.Loading />}> | ||||
| <PickOrderDetail consoCode={`${searchParams["consoCode"]}`} /> | <PickOrderDetail consoCode={`${searchParams["consoCode"]}`} /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -27,4 +21,4 @@ const PickOrder: React.FC<Props> = async ({ searchParams }) => { | |||||
| ); | ); | ||||
| }; | }; | ||||
| export default PickOrder; | |||||
| export default StockOutIssueRecordDetail; | |||||
| @@ -1,23 +1,16 @@ | |||||
| import { PreloadPickOrder } from "@/app/api/pickOrder"; | |||||
| import PickOrderSearch from "@/components/PickOrderSearch"; | import PickOrderSearch from "@/components/PickOrderSearch"; | ||||
| import { getServerI18n } from "@/i18n"; | |||||
| import { I18nProvider } from "@/i18n"; | import { I18nProvider } from "@/i18n"; | ||||
| import { Stack, Typography } from "@mui/material"; | |||||
| import { Metadata } from "next"; | import { Metadata } from "next"; | ||||
| import { Suspense } from "react"; | import { Suspense } from "react"; | ||||
| export const metadata: Metadata = { | export const metadata: Metadata = { | ||||
| title: "Pick Order", | |||||
| title: "Stock Out Issue Record", | |||||
| }; | }; | ||||
| const PickOrder: React.FC = async () => { | |||||
| const { t } = await getServerI18n("pickOrder"); | |||||
| // PreloadPickOrder(); | |||||
| const StockOutIssueRecord: React.FC = async () => { | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| <I18nProvider namespaces={["pickOrder", "common"]}> | |||||
| <I18nProvider namespaces={["pickOrder", "navigation", "common"]}> | |||||
| <Suspense fallback={<PickOrderSearch.Loading />}> | <Suspense fallback={<PickOrderSearch.Loading />}> | ||||
| <PickOrderSearch /> | <PickOrderSearch /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -26,4 +19,4 @@ const PickOrder: React.FC = async () => { | |||||
| ); | ); | ||||
| }; | }; | ||||
| export default PickOrder; | |||||
| export default StockOutIssueRecord; | |||||
| @@ -9,11 +9,11 @@ export const metadata: Metadata = { | |||||
| }; | }; | ||||
| const SearchView: React.FC = async () => { | const SearchView: React.FC = async () => { | ||||
| const { t } = await getServerI18n("inventory"); | |||||
| const { t } = await getServerI18n("stockRecord"); | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| <I18nProvider namespaces={["inventory", "common"]}> | |||||
| <I18nProvider namespaces={["stockRecord", "navigation", "common"]}> | |||||
| <Suspense fallback={<SearchPage.Loading />}> | <Suspense fallback={<SearchPage.Loading />}> | ||||
| <SearchPage /> | <SearchPage /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -8,9 +8,9 @@ import { notFound } from "next/navigation"; | |||||
| export default async function InventoryManagementPage() { | export default async function InventoryManagementPage() { | ||||
| const { t } = await getServerI18n("inventory"); | |||||
| const { t } = await getServerI18n("stockTake"); | |||||
| return ( | return ( | ||||
| <I18nProvider namespaces={["inventory","common"]}> | |||||
| <I18nProvider namespaces={["stockTake", "navigation", "common"]}> | |||||
| <Suspense fallback={<StockTakeManagementWrapper.Loading />}> | <Suspense fallback={<StockTakeManagementWrapper.Loading />}> | ||||
| <StockTakeManagementWrapper /> | <StockTakeManagementWrapper /> | ||||
| </Suspense> | </Suspense> | ||||
| @@ -14,7 +14,7 @@ export const metadata: Metadata = { | |||||
| }; | }; | ||||
| const TaskTemplates: React.FC = async () => { | const TaskTemplates: React.FC = async () => { | ||||
| const { t } = await getServerI18n("projects"); | |||||
| const { t } = await getServerI18n("project"); | |||||
| preloadTaskTemplates(); | preloadTaskTemplates(); | ||||
| return ( | return ( | ||||
| @@ -492,6 +492,7 @@ export interface TruckLaneVersionResponse { | |||||
| truckLanceCode: string; | truckLanceCode: string; | ||||
| note: string | null; | note: string | null; | ||||
| created: string | null; | created: string | null; | ||||
| createdBy?: string | null; | |||||
| /** truck_lane_version.modifiedBy(BaseEntity) */ | /** truck_lane_version.modifiedBy(BaseEntity) */ | ||||
| modifiedBy?: string | null; | modifiedBy?: string | null; | ||||
| } | } | ||||
| @@ -602,4 +603,309 @@ export const updateTruckLaneVersionNoteAction = async ( | |||||
| body: JSON.stringify(data), | body: JSON.stringify(data), | ||||
| headers: { "Content-Type": "application/json" }, | headers: { "Content-Type": "application/json" }, | ||||
| }); | }); | ||||
| }; | |||||
| // ---- Truck lane schedule (server-side apply) ---- | |||||
| export type TruckLaneScheduleLineAction = | |||||
| | "MOVE" | |||||
| | "CREATE" | |||||
| | "DELETE" | |||||
| | "ENSURE_LANE"; | |||||
| export type TruckLaneMoveTargetRequest = { | |||||
| truckRowId: number; | |||||
| toTruckLanceCode: string; | |||||
| toRemark?: string | null; | |||||
| toStoreId: string; | |||||
| toLoadingSequence: number; | |||||
| toDistrictReference?: string | null; | |||||
| }; | |||||
| export type TruckLaneScheduleLineRequest = { | |||||
| action: TruckLaneScheduleLineAction; | |||||
| truckRowId?: number | null; | |||||
| toTruckLanceCode: string; | |||||
| toRemark?: string | null; | |||||
| toStoreId: string; | |||||
| toLoadingSequence?: number | null; | |||||
| toDistrictReference?: string | null; | |||||
| shopId?: number | null; | |||||
| shopCode?: string | null; | |||||
| shopName?: string | null; | |||||
| departureTime?: string | null; | |||||
| logisticId?: number | null; | |||||
| }; | |||||
| export type CreateTruckLaneScheduleRequest = { | |||||
| executeAt: string; | |||||
| note?: string | null; | |||||
| lines?: TruckLaneScheduleLineRequest[] | null; | |||||
| moves?: TruckLaneMoveTargetRequest[] | null; | |||||
| }; | |||||
| export type TruckLaneScheduleLineResponse = { | |||||
| id: number; | |||||
| action: TruckLaneScheduleLineAction; | |||||
| truckRowId: number | null; | |||||
| shopCode: string | null; | |||||
| shopName: string | null; | |||||
| fromTruckLanceCode: string | null; | |||||
| fromRemark: string | null; | |||||
| fromStoreId: string | null; | |||||
| fromLoadingSequence?: number | null; | |||||
| fromDistrictReference?: string | null; | |||||
| fromDepartureTime?: string | null; | |||||
| toTruckLanceCode: string; | |||||
| toRemark: string | null; | |||||
| toStoreId: string; | |||||
| toDistrictReference?: string | null; | |||||
| toLoadingSequence?: number | null; | |||||
| departureTime?: string | null; | |||||
| lineStatus: string; | |||||
| errorMessage: string | null; | |||||
| appliedAt: string | null; | |||||
| }; | |||||
| export type RouteExcelSchedulePlanPreviewRow = { | |||||
| action: TruckLaneScheduleLineAction; | |||||
| truckRowId: number | null; | |||||
| shopCode: string | null; | |||||
| shopName: string | null; | |||||
| toTruckLanceCode: string; | |||||
| toRemark: string | null; | |||||
| toStoreId: string; | |||||
| toLoadingSequence: number | null; | |||||
| }; | |||||
| export type RouteExcelSchedulePlanError = { | |||||
| shopCode: string; | |||||
| shopName: string; | |||||
| message: string; | |||||
| }; | |||||
| export type RouteExcelSchedulePlanCounts = { | |||||
| moves: number; | |||||
| creates: number; | |||||
| deletes: number; | |||||
| ensureLanes: number; | |||||
| }; | |||||
| export type RouteExcelSchedulePlanResponse = { | |||||
| sheetCount: number; | |||||
| rowCount: number; | |||||
| lines: TruckLaneScheduleLineRequest[]; | |||||
| previews: RouteExcelSchedulePlanPreviewRow[]; | |||||
| errors: RouteExcelSchedulePlanError[]; | |||||
| counts: RouteExcelSchedulePlanCounts; | |||||
| }; | |||||
| export type TruckLaneScheduleResponse = { | |||||
| id: number; | |||||
| executeAt: string; | |||||
| status: string; | |||||
| source: string; | |||||
| note: string | null; | |||||
| appliedAt: string | null; | |||||
| errorMessage: string | null; | |||||
| snapshotVersionId: number | null; | |||||
| preApplySnapshotVersionId?: number | null; | |||||
| created: string | null; | |||||
| createdBy?: string | null; | |||||
| modifiedBy: string | null; | |||||
| lines?: TruckLaneScheduleLineResponse[] | null; | |||||
| lineCounts?: { | |||||
| total: number; | |||||
| applied: number; | |||||
| failed: number; | |||||
| pending: number; | |||||
| } | null; | |||||
| }; | |||||
| export type PendingTruckRowIdsResponse = { | |||||
| truckRowIds: number[]; | |||||
| }; | |||||
| export type TruckLaneScheduleExcelPreviewRow = { | |||||
| rowIndex: number; | |||||
| shopCode: string; | |||||
| toTruckLanceCode: string; | |||||
| toRemark: string | null; | |||||
| toStoreId: string; | |||||
| executeAt: string | null; | |||||
| truckRowId: number | null; | |||||
| }; | |||||
| export type TruckLaneScheduleExcelRowError = { | |||||
| rowIndex: number; | |||||
| message: string; | |||||
| }; | |||||
| export type ParseTruckLaneScheduleExcelResponse = { | |||||
| rowCount: number; | |||||
| validCount: number; | |||||
| errorCount: number; | |||||
| rows: TruckLaneScheduleExcelPreviewRow[]; | |||||
| errors: TruckLaneScheduleExcelRowError[]; | |||||
| }; | |||||
| export const createTruckLaneScheduleAction = async ( | |||||
| data: CreateTruckLaneScheduleRequest, | |||||
| ): Promise<TruckLaneScheduleResponse> => { | |||||
| const endpoint = `${BASE_API_URL}/truckLaneSchedule`; | |||||
| return serverFetchJson<TruckLaneScheduleResponse>(endpoint, { | |||||
| method: "POST", | |||||
| body: JSON.stringify(data), | |||||
| headers: { "Content-Type": "application/json" }, | |||||
| }); | |||||
| }; | |||||
| export const planTruckLaneScheduleFromRouteExcelAction = async ( | |||||
| formData: FormData, | |||||
| ): Promise<RouteExcelSchedulePlanResponse> => { | |||||
| const response = await serverFetch( | |||||
| `${BASE_API_URL}/truckLaneSchedule/planFromRouteExcel`, | |||||
| { | |||||
| method: "POST", | |||||
| body: formData, | |||||
| }, | |||||
| ); | |||||
| if (!response.ok) { | |||||
| const text = await response.text().catch(() => ""); | |||||
| throw new ServerFetchError( | |||||
| `Plan import failed: ${response.status} ${text}`.trim(), | |||||
| response, | |||||
| ); | |||||
| } | |||||
| return (await response.json()) as RouteExcelSchedulePlanResponse; | |||||
| }; | |||||
| export const listTruckLaneSchedulesAction = async ( | |||||
| status?: string[], | |||||
| limit: number = 200, | |||||
| ): Promise<TruckLaneScheduleResponse[]> => { | |||||
| const params = new URLSearchParams(); | |||||
| for (const s of status ?? []) { | |||||
| params.append("status", s); | |||||
| } | |||||
| params.set("limit", String(limit)); | |||||
| const qs = params.toString(); | |||||
| const base = `${BASE_API_URL}/truckLaneSchedule`; | |||||
| return serverFetchJson<TruckLaneScheduleResponse[]>( | |||||
| `${base}${qs ? `?${qs}` : ""}`, | |||||
| { | |||||
| method: "GET", | |||||
| headers: { "Content-Type": "application/json" }, | |||||
| }, | |||||
| ); | |||||
| }; | |||||
| export const getTruckLaneScheduleAction = async ( | |||||
| id: number, | |||||
| ): Promise<TruckLaneScheduleResponse> => { | |||||
| const endpoint = `${BASE_API_URL}/truckLaneSchedule/${id}`; | |||||
| return serverFetchJson<TruckLaneScheduleResponse>(endpoint, { | |||||
| method: "GET", | |||||
| headers: { "Content-Type": "application/json" }, | |||||
| }); | |||||
| }; | |||||
| export const pendingTruckLaneScheduleShopIdsAction = | |||||
| async (): Promise<PendingTruckRowIdsResponse> => { | |||||
| const endpoint = `${BASE_API_URL}/truckLaneSchedule/pendingShopIds`; | |||||
| return serverFetchJson<PendingTruckRowIdsResponse>(endpoint, { | |||||
| method: "GET", | |||||
| headers: { "Content-Type": "application/json" }, | |||||
| }); | |||||
| }; | |||||
| export const cancelTruckLaneScheduleAction = async ( | |||||
| id: number, | |||||
| ): Promise<TruckLaneScheduleResponse> => { | |||||
| const endpoint = `${BASE_API_URL}/truckLaneSchedule/${id}/cancel`; | |||||
| return serverFetchJson<TruckLaneScheduleResponse>(endpoint, { | |||||
| method: "POST", | |||||
| headers: { "Content-Type": "application/json" }, | |||||
| }); | |||||
| }; | |||||
| export const applyNowTruckLaneScheduleAction = async ( | |||||
| id: number, | |||||
| ): Promise<TruckLaneScheduleResponse> => { | |||||
| const endpoint = `${BASE_API_URL}/truckLaneSchedule/${id}/applyNow`; | |||||
| return serverFetchJson<TruckLaneScheduleResponse>(endpoint, { | |||||
| method: "POST", | |||||
| headers: { "Content-Type": "application/json" }, | |||||
| }); | |||||
| }; | |||||
| export type RetryFailedTruckLaneScheduleRequest = { | |||||
| executeAt?: string | null; | |||||
| }; | |||||
| export const retryFailedTruckLaneScheduleAction = async ( | |||||
| id: number, | |||||
| body?: RetryFailedTruckLaneScheduleRequest, | |||||
| ): Promise<TruckLaneScheduleResponse> => { | |||||
| const endpoint = `${BASE_API_URL}/truckLaneSchedule/${id}/retry-failed`; | |||||
| return serverFetchJson<TruckLaneScheduleResponse>(endpoint, { | |||||
| method: "POST", | |||||
| body: JSON.stringify(body ?? {}), | |||||
| headers: { "Content-Type": "application/json" }, | |||||
| }); | |||||
| }; | |||||
| export const ignoreTruckLaneScheduleAction = async ( | |||||
| id: number, | |||||
| ): Promise<TruckLaneScheduleResponse> => { | |||||
| const endpoint = `${BASE_API_URL}/truckLaneSchedule/${id}/ignore`; | |||||
| return serverFetchJson<TruckLaneScheduleResponse>(endpoint, { | |||||
| method: "POST", | |||||
| headers: { "Content-Type": "application/json" }, | |||||
| }); | |||||
| }; | |||||
| export const parseTruckLaneScheduleExcelAction = async ( | |||||
| formData: FormData, | |||||
| defaultExecuteAt?: string | null, | |||||
| ): Promise<ParseTruckLaneScheduleExcelResponse> => { | |||||
| const qs = | |||||
| defaultExecuteAt != null && defaultExecuteAt !== "" | |||||
| ? `?defaultExecuteAt=${encodeURIComponent(defaultExecuteAt)}` | |||||
| : ""; | |||||
| const response = await serverFetch( | |||||
| `${BASE_API_URL}/truckLaneSchedule/parseExcel${qs}`, | |||||
| { method: "POST", body: formData }, | |||||
| ); | |||||
| if (!response.ok) { | |||||
| const text = await response.text().catch(() => ""); | |||||
| throw new ServerFetchError( | |||||
| `Parse schedule Excel failed: ${response.status} ${text}`.trim(), | |||||
| response, | |||||
| ); | |||||
| } | |||||
| return (await response.json()) as ParseTruckLaneScheduleExcelResponse; | |||||
| }; | |||||
| export const importTruckLaneScheduleExcelAction = async ( | |||||
| formData: FormData, | |||||
| defaultExecuteAt?: string | null, | |||||
| note?: string | null, | |||||
| ): Promise<TruckLaneScheduleResponse[]> => { | |||||
| const params = new URLSearchParams(); | |||||
| if (defaultExecuteAt) params.set("defaultExecuteAt", defaultExecuteAt); | |||||
| if (note) params.set("note", note); | |||||
| const qs = params.toString() ? `?${params.toString()}` : ""; | |||||
| const response = await serverFetch( | |||||
| `${BASE_API_URL}/truckLaneSchedule/importExcel${qs}`, | |||||
| { method: "POST", body: formData }, | |||||
| ); | |||||
| if (!response.ok) { | |||||
| const text = await response.text().catch(() => ""); | |||||
| throw new ServerFetchError( | |||||
| `Import schedule Excel failed: ${response.status} ${text}`.trim(), | |||||
| response, | |||||
| ); | |||||
| } | |||||
| return (await response.json()) as TruckLaneScheduleResponse[]; | |||||
| }; | }; | ||||
| @@ -30,7 +30,29 @@ import { | |||||
| diffTruckLaneVersionsAction, | diffTruckLaneVersionsAction, | ||||
| restoreTruckLaneVersionAction, | restoreTruckLaneVersionAction, | ||||
| updateTruckLaneVersionNoteAction, | updateTruckLaneVersionNoteAction, | ||||
| createTruckLaneScheduleAction, | |||||
| planTruckLaneScheduleFromRouteExcelAction, | |||||
| listTruckLaneSchedulesAction, | |||||
| getTruckLaneScheduleAction, | |||||
| pendingTruckLaneScheduleShopIdsAction, | |||||
| cancelTruckLaneScheduleAction, | |||||
| applyNowTruckLaneScheduleAction, | |||||
| retryFailedTruckLaneScheduleAction, | |||||
| ignoreTruckLaneScheduleAction, | |||||
| type RetryFailedTruckLaneScheduleRequest, | |||||
| parseTruckLaneScheduleExcelAction, | |||||
| importTruckLaneScheduleExcelAction, | |||||
| type CreateTruckLaneSnapshotRequest, | type CreateTruckLaneSnapshotRequest, | ||||
| type CreateTruckLaneScheduleRequest, | |||||
| type TruckLaneScheduleResponse, | |||||
| type TruckLaneScheduleLineRequest, | |||||
| type RouteExcelSchedulePlanPreviewRow, | |||||
| type RouteExcelSchedulePlanError, | |||||
| type RouteExcelSchedulePlanResponse, | |||||
| type RouteExcelSchedulePlanCounts, | |||||
| type TruckLaneMoveTargetRequest, | |||||
| type PendingTruckRowIdsResponse, | |||||
| type ParseTruckLaneScheduleExcelResponse, | |||||
| type UpdateTruckLaneVersionNoteRequest, | type UpdateTruckLaneVersionNoteRequest, | ||||
| type TruckLaneVersionResponse, | type TruckLaneVersionResponse, | ||||
| type TruckLaneVersionLineResponse, | type TruckLaneVersionLineResponse, | ||||
| @@ -184,4 +206,92 @@ export const updateTruckLaneVersionNoteClient = async ( | |||||
| return await updateTruckLaneVersionNoteAction(versionId, data); | return await updateTruckLaneVersionNoteAction(versionId, data); | ||||
| }; | }; | ||||
| export const planTruckLaneScheduleFromRouteExcelClient = async ( | |||||
| formData: FormData, | |||||
| ): Promise<RouteExcelSchedulePlanResponse> => { | |||||
| return await planTruckLaneScheduleFromRouteExcelAction(formData); | |||||
| }; | |||||
| export const createTruckLaneScheduleClient = async ( | |||||
| data: CreateTruckLaneScheduleRequest, | |||||
| ): Promise<TruckLaneScheduleResponse> => { | |||||
| return await createTruckLaneScheduleAction(data); | |||||
| }; | |||||
| export const listTruckLaneSchedulesClient = async ( | |||||
| status?: string[], | |||||
| limit: number = 200, | |||||
| ): Promise<TruckLaneScheduleResponse[]> => { | |||||
| return await listTruckLaneSchedulesAction(status, limit); | |||||
| }; | |||||
| export const getTruckLaneScheduleClient = async ( | |||||
| id: number, | |||||
| ): Promise<TruckLaneScheduleResponse> => { | |||||
| return await getTruckLaneScheduleAction(id); | |||||
| }; | |||||
| export const pendingTruckLaneScheduleShopIdsClient = | |||||
| async (): Promise<PendingTruckRowIdsResponse> => { | |||||
| return await pendingTruckLaneScheduleShopIdsAction(); | |||||
| }; | |||||
| export const cancelTruckLaneScheduleClient = async ( | |||||
| id: number, | |||||
| ): Promise<TruckLaneScheduleResponse> => { | |||||
| return await cancelTruckLaneScheduleAction(id); | |||||
| }; | |||||
| export const applyNowTruckLaneScheduleClient = async ( | |||||
| id: number, | |||||
| ): Promise<TruckLaneScheduleResponse> => { | |||||
| return await applyNowTruckLaneScheduleAction(id); | |||||
| }; | |||||
| export const retryFailedTruckLaneScheduleClient = async ( | |||||
| id: number, | |||||
| body?: RetryFailedTruckLaneScheduleRequest, | |||||
| ): Promise<TruckLaneScheduleResponse> => { | |||||
| return await retryFailedTruckLaneScheduleAction(id, body); | |||||
| }; | |||||
| export const ignoreTruckLaneScheduleClient = async ( | |||||
| id: number, | |||||
| ): Promise<TruckLaneScheduleResponse> => { | |||||
| return await ignoreTruckLaneScheduleAction(id); | |||||
| }; | |||||
| export const parseTruckLaneScheduleExcelClient = async ( | |||||
| formData: FormData, | |||||
| defaultExecuteAt?: string | null, | |||||
| ): Promise<ParseTruckLaneScheduleExcelResponse> => { | |||||
| return await parseTruckLaneScheduleExcelAction(formData, defaultExecuteAt); | |||||
| }; | |||||
| export const importTruckLaneScheduleExcelClient = async ( | |||||
| formData: FormData, | |||||
| defaultExecuteAt?: string | null, | |||||
| note?: string | null, | |||||
| ): Promise<TruckLaneScheduleResponse[]> => { | |||||
| return await importTruckLaneScheduleExcelAction( | |||||
| formData, | |||||
| defaultExecuteAt, | |||||
| note, | |||||
| ); | |||||
| }; | |||||
| export type { | |||||
| TruckLaneScheduleResponse, | |||||
| TruckLaneScheduleLineResponse, | |||||
| TruckLaneMoveTargetRequest, | |||||
| TruckLaneScheduleLineRequest, | |||||
| CreateTruckLaneScheduleRequest, | |||||
| PendingTruckRowIdsResponse, | |||||
| ParseTruckLaneScheduleExcelResponse, | |||||
| RouteExcelSchedulePlanResponse, | |||||
| RouteExcelSchedulePlanPreviewRow, | |||||
| RouteExcelSchedulePlanError, | |||||
| RouteExcelSchedulePlanCounts, | |||||
| } from "./actions"; | |||||
| export default fetchAllShopsClient; | export default fetchAllShopsClient; | ||||
| @@ -16,7 +16,7 @@ export interface AppBarProps { | |||||
| const AppBar: React.FC<AppBarProps> = ({ avatarImageSrc, profileName }) => { | const AppBar: React.FC<AppBarProps> = ({ avatarImageSrc, profileName }) => { | ||||
| return ( | return ( | ||||
| <I18nProvider namespaces={["common"]}> | |||||
| <I18nProvider namespaces={["navigation", "common"]}> | |||||
| <MUIAppBar position="sticky" color="default" elevation={0}> | <MUIAppBar position="sticky" color="default" elevation={0}> | ||||
| <Toolbar sx={{ minHeight: { xs: 56, sm: 64 }, px: 2 }}> | <Toolbar sx={{ minHeight: { xs: 56, sm: 64 }, px: 2 }}> | ||||
| <NavigationToggle /> | <NavigationToggle /> | ||||
| @@ -29,7 +29,7 @@ const Profile: React.FC<Props> = ({ avatarImageSrc, profileName }) => { | |||||
| return ( | return ( | ||||
| <> | <> | ||||
| <IconButton aria-label="profile" onClick={openProfileMenu}> | |||||
| <IconButton aria-label={t("profile")} onClick={openProfileMenu}> | |||||
| <Avatar src={avatarImageSrc} /> | <Avatar src={avatarImageSrc} /> | ||||
| </IconButton> | </IconButton> | ||||
| <Menu | <Menu | ||||
| @@ -12,19 +12,19 @@ interface Props { | |||||
| } | } | ||||
| const BomScoreTable: React.FC<Props> = ({ boms }) => { | const BomScoreTable: React.FC<Props> = ({ boms }) => { | ||||
| const { t } = useTranslation("common"); | |||||
| const { t } = useTranslation(["bomWeighting", "common"]); | |||||
| const columns = useMemo<GridColDef<BomScoreResult>[]>( | const columns = useMemo<GridColDef<BomScoreResult>[]>( | ||||
| () => [ | () => [ | ||||
| { | { | ||||
| field: "code", | field: "code", | ||||
| headerName: t("Code"), | |||||
| headerName: t("Item Code"), | |||||
| flex: 1, | flex: 1, | ||||
| minWidth: 150, | minWidth: 150, | ||||
| }, | }, | ||||
| { | { | ||||
| field: "name", | field: "name", | ||||
| headerName: t("Name"), | |||||
| headerName: t("Item Name"), | |||||
| flex: 1.5, | flex: 1.5, | ||||
| minWidth: 220, | minWidth: 220, | ||||
| }, | }, | ||||
| @@ -20,7 +20,7 @@ interface Props { | |||||
| } | } | ||||
| const BomWeightingScoreTable: React.FC<Props> & { Loading?: React.FC } = ({ bomWeightingScores: initialBomWeightingScores, onWeightingUpdated }) => { | const BomWeightingScoreTable: React.FC<Props> & { Loading?: React.FC } = ({ bomWeightingScores: initialBomWeightingScores, onWeightingUpdated }) => { | ||||
| const { t } = useTranslation("common"); | |||||
| const { t } = useTranslation(["bomWeighting", "common"]); | |||||
| const [bomWeightingScores, setBomWeightingScores] = useState(initialBomWeightingScores); | const [bomWeightingScores, setBomWeightingScores] = useState(initialBomWeightingScores); | ||||
| const [isEditMode, setIsEditMode] = useState(false); | const [isEditMode, setIsEditMode] = useState(false); | ||||
| const [isSaving, setIsSaving] = useState(false); | const [isSaving, setIsSaving] = useState(false); | ||||
| @@ -173,7 +173,7 @@ const BomWeightingScoreTable: React.FC<Props> & { Loading?: React.FC } = ({ bomW | |||||
| () => [ | () => [ | ||||
| { | { | ||||
| field: "name", | field: "name", | ||||
| headerName: t("Name"), | |||||
| headerName: t("Scoring Item"), | |||||
| flex: 1, | flex: 1, | ||||
| }, | }, | ||||
| { | { | ||||
| @@ -18,7 +18,7 @@ interface Props { | |||||
| } | } | ||||
| const BomWeightingTabs: React.FC<Props> = ({ bomWeightingScores: initialBomWeightingScores }) => { | const BomWeightingTabs: React.FC<Props> = ({ bomWeightingScores: initialBomWeightingScores }) => { | ||||
| const { t } = useTranslation("common"); | |||||
| const { t } = useTranslation(["bomWeighting", "common"]); | |||||
| const [tab, setTab] = useState(0); | const [tab, setTab] = useState(0); | ||||
| const [bomWeightingScores, setBomWeightingScores] = useState<BomWeightingScoreResult[]>(initialBomWeightingScores); | const [bomWeightingScores, setBomWeightingScores] = useState<BomWeightingScoreResult[]>(initialBomWeightingScores); | ||||
| const [bomScores, setBomScores] = useState<BomScoreResult[] | null>(null); | const [bomScores, setBomScores] = useState<BomScoreResult[] | null>(null); | ||||
| @@ -7,75 +7,86 @@ import MUILink from "@mui/material/Link"; | |||||
| import { usePathname } from "next/navigation"; | import { usePathname } from "next/navigation"; | ||||
| import { useTranslation } from "react-i18next"; | import { useTranslation } from "react-i18next"; | ||||
| const pathToLabelMap: { [path: string]: string } = { | |||||
| "": "總覽", | |||||
| "/chart": "圖表報告", | |||||
| "/chart/warehouse": "庫存與倉儲", | |||||
| "/chart/purchase": "採購", | |||||
| "/chart/delivery": "發貨與配送", | |||||
| "/chart/joborder": "工單", | |||||
| "/chart/joborder/board": "工單即時看板", | |||||
| "/chart/forecast": "預測與計劃", | |||||
| "/projects": "Projects", | |||||
| "/projects/create": "Create Project", | |||||
| "/tasks": "Task Template", | |||||
| "/tasks/create": "Create Task Template", | |||||
| "/settings/qcItem": "Qc Item", | |||||
| "/settings/qcItemAll": "QC Item All", | |||||
| "/settings/qrCodeHandle": "QR Code Handle", | |||||
| "/settings/rss": "Demand Forecast Setting", | |||||
| "/settings/equipment": "Equipment", | |||||
| "/settings/equipment/MaintenanceEdit": "MaintenanceEdit", | |||||
| "/settings/shop": "ShopAndTruck", | |||||
| "/settings/shop/board": "Route Board", | |||||
| "/settings/shop/detail": "Shop Detail", | |||||
| "/settings/shop/truckdetail": "Truck Lane Detail", | |||||
| "/settings/printer": "Printer", | |||||
| "/scheduling/rough": "Demand Forecast", | |||||
| "/scheduling/rough/edit": "FG & Material Demand Forecast Detail", | |||||
| "/scheduling/detailed": "Detail Scheduling", | |||||
| "/scheduling/detailed/edit": "FG Production Schedule", | |||||
| "/inventory": "Inventory", | |||||
| "/settings/importTesting": "Import Testing", | |||||
| "/do": "Delivery Order", | |||||
| "/doworkbench": "DO Workbench", | |||||
| "/doworkbenchsearch": "DO Workbench Search", | |||||
| "/doworkbench/pick": "DO Workbench pick", | |||||
| "/doworkbench/edit": "DO Workbench detail", | |||||
| "/pickOrder": "Pick Order", | |||||
| "/po": "Purchase Order", | |||||
| "/po/workbench": "PO Workbench", | |||||
| "/dashboard": "dashboard", | |||||
| "/jo": "Job Order", | |||||
| "/jo/edit": "Edit Job Order", | |||||
| "/jo/testing": "Job order testing", | |||||
| "/jo/workbench": "Job Order Workbench", | |||||
| "/putAway": "Put Away", | |||||
| "/stockIssue": "Stock Issue", | |||||
| "/report": "Report", | |||||
| "/m18Syn": "M18 Sync", | |||||
| "/bagPrint": "打袋機", | |||||
| "/laserPrint": "檸檬機(激光機)", | |||||
| "/settings/itemPrice": "Price Inquiry", | |||||
| "/finishedGood": "Finished Good Order", | |||||
| "/finishedGood/management": "Finished Good Management", | |||||
| const pathToLabelKey: { [path: string]: string } = { | |||||
| "": "nav.breadcrumb.home", | |||||
| "/chart": "nav.breadcrumb.chart", | |||||
| "/chart/warehouse": "nav.breadcrumb.chartWarehouse", | |||||
| "/chart/purchase": "nav.breadcrumb.chartPurchase", | |||||
| "/chart/delivery": "nav.breadcrumb.chartDelivery", | |||||
| "/chart/joborder": "nav.breadcrumb.chartJobOrder", | |||||
| "/chart/joborder/board": "nav.breadcrumb.chartJobOrderBoard", | |||||
| "/chart/forecast": "nav.breadcrumb.chartForecast", | |||||
| "/projects": "nav.breadcrumb.projects", | |||||
| "/projects/create": "nav.breadcrumb.projectsCreate", | |||||
| "/tasks": "nav.breadcrumb.tasks", | |||||
| "/tasks/create": "nav.breadcrumb.tasksCreate", | |||||
| "/settings/qcItem": "nav.breadcrumb.qcItem", | |||||
| "/settings/qcItemAll": "nav.breadcrumb.qcItemAll", | |||||
| "/settings/qrCodeHandle": "nav.breadcrumb.qrCodeHandle", | |||||
| "/settings/rss": "nav.breadcrumb.demandForecast", | |||||
| "/settings/equipment": "nav.breadcrumb.equipment", | |||||
| "/settings/equipment/MaintenanceEdit": "nav.breadcrumb.equipmentMaintenanceEdit", | |||||
| "/settings/shop": "nav.breadcrumb.shop", | |||||
| "/settings/shop/board": "nav.breadcrumb.routeBoard", | |||||
| "/settings/shop/detail": "nav.breadcrumb.shopDetail", | |||||
| "/settings/shop/truckdetail": "nav.breadcrumb.truckLaneDetail", | |||||
| "/settings/printer": "nav.breadcrumb.printer", | |||||
| "/scheduling/rough": "nav.breadcrumb.schedulingRough", | |||||
| "/scheduling/rough/edit": "nav.breadcrumb.schedulingRoughEdit", | |||||
| "/scheduling/detailed": "nav.breadcrumb.schedulingDetailed", | |||||
| "/scheduling/detailed/edit": "nav.breadcrumb.schedulingDetailedEdit", | |||||
| "/inventory": "nav.breadcrumb.inventory", | |||||
| "/settings/importTesting": "nav.breadcrumb.importTesting", | |||||
| "/settings/m18ImportTesting": "nav.breadcrumb.importTesting", | |||||
| "/do": "nav.deliveryOrder", | |||||
| "/doworkbench": "nav.store.doWorkbench", | |||||
| "/doworkbenchsearch": "nav.breadcrumb.doWorkbenchSearch", | |||||
| "/doworkbench/pick": "nav.breadcrumb.doWorkbenchPick", | |||||
| "/doworkbench/edit": "nav.breadcrumb.doWorkbenchEdit", | |||||
| "/pickOrder": "nav.store.pickOrder", | |||||
| "/po": "nav.store.purchaseOrder", | |||||
| "/po/edit": "nav.breadcrumb.poEdit", | |||||
| "/po/workbench": "nav.breadcrumb.poWorkbench", | |||||
| "/dashboard": "nav.dashboard", | |||||
| "/jo": "nav.jobOrder.searchCreate", | |||||
| "/jo/edit": "nav.breadcrumb.joEdit", | |||||
| "/jo/testing": "nav.breadcrumb.joTesting", | |||||
| "/jo/workbench": "nav.breadcrumb.joWorkbench", | |||||
| "/putAway": "nav.store.putAwayScan", | |||||
| "/stockIssue": "nav.store.stockIssue", | |||||
| "/stocktakemanagement": "nav.store.stockTake", | |||||
| "/stockRecord": "nav.store.stockRecord", | |||||
| "/report": "nav.breadcrumb.report", | |||||
| "/m18Syn": "nav.breadcrumb.m18Sync", | |||||
| "/bagPrint": "nav.breadcrumb.bagPrint", | |||||
| "/laserPrint": "nav.breadcrumb.laserPrint", | |||||
| "/settings/itemPrice": "nav.breadcrumb.priceInquiry", | |||||
| "/finishedGood": "nav.breadcrumb.finishedGood", | |||||
| "/finishedGood/management": "nav.breadcrumb.finishedGoodManagement", | |||||
| "/ps": "nav.scheduling", | |||||
| "/productionProcess": "nav.jobOrder.productionProcess", | |||||
| "/jodetail": "nav.jobOrder.pickExecution", | |||||
| "/bag": "nav.jobOrder.bagUsage", | |||||
| }; | }; | ||||
| const Breadcrumb = () => { | const Breadcrumb = () => { | ||||
| const pathname = usePathname(); | const pathname = usePathname(); | ||||
| const segments = pathname.split("/"); | const segments = pathname.split("/"); | ||||
| const { t } = useTranslation("common"); | |||||
| const { t } = useTranslation(["navigation", "common"]); | |||||
| return ( | return ( | ||||
| <Breadcrumbs> | <Breadcrumbs> | ||||
| {segments.map((segment, index) => { | {segments.map((segment, index) => { | ||||
| const href = segments.slice(0, index + 1).join("/"); | const href = segments.slice(0, index + 1).join("/"); | ||||
| const label = pathToLabelMap[href] || segment; | |||||
| const labelKey = pathToLabelKey[href]; | |||||
| const label = labelKey | |||||
| ? t(labelKey) | |||||
| : t(segment, { ns: "common", defaultValue: segment }); | |||||
| if (index === segments.length - 1) { | if (index === segments.length - 1) { | ||||
| return ( | return ( | ||||
| <Typography key={index} color="text.primary"> | <Typography key={index} color="text.primary"> | ||||
| {t(label)} | |||||
| {label} | |||||
| </Typography> | </Typography> | ||||
| ); | ); | ||||
| } else { | } else { | ||||
| @@ -87,7 +98,7 @@ const Breadcrumb = () => { | |||||
| component={Link} | component={Link} | ||||
| href={href || "/"} | href={href || "/"} | ||||
| > | > | ||||
| {t(label)} | |||||
| {label} | |||||
| </MUILink> | </MUILink> | ||||
| ); | ); | ||||
| } | } | ||||
| @@ -271,8 +271,8 @@ const ClaimInputGrid: React.FC<ClaimInputGridProps> = ({ ...props }) => { | |||||
| <GridActionsCellItem | <GridActionsCellItem | ||||
| key={`actions-${id}-save`} | key={`actions-${id}-save`} | ||||
| icon={<SaveIcon />} | icon={<SaveIcon />} | ||||
| title="Save" | |||||
| label="Save" | |||||
| title={t("Save")} | |||||
| label={t("Save")} | |||||
| sx={{ | sx={{ | ||||
| color: "primary.main", | color: "primary.main", | ||||
| }} | }} | ||||
| @@ -281,8 +281,8 @@ const ClaimInputGrid: React.FC<ClaimInputGridProps> = ({ ...props }) => { | |||||
| <GridActionsCellItem | <GridActionsCellItem | ||||
| key={`actions-${id}-cancel`} | key={`actions-${id}-cancel`} | ||||
| icon={<CancelIcon />} | icon={<CancelIcon />} | ||||
| title="Cancel" | |||||
| label="Cancel" | |||||
| title={t("Cancel")} | |||||
| label={t("Cancel")} | |||||
| className="textPrimary" | className="textPrimary" | ||||
| onClick={handleCancelClick(id)} | onClick={handleCancelClick(id)} | ||||
| color="inherit" | color="inherit" | ||||
| @@ -294,16 +294,16 @@ const ClaimInputGrid: React.FC<ClaimInputGridProps> = ({ ...props }) => { | |||||
| <GridActionsCellItem | <GridActionsCellItem | ||||
| key={`actions-${id}-edit`} | key={`actions-${id}-edit`} | ||||
| icon={<EditIcon />} | icon={<EditIcon />} | ||||
| title="Edit" | |||||
| label="Edit" | |||||
| title={t("Edit")} | |||||
| label={t("Edit")} | |||||
| className="textPrimary" | className="textPrimary" | ||||
| onClick={handleEditClick(id)} | onClick={handleEditClick(id)} | ||||
| color="inherit" | color="inherit" | ||||
| />, | />, | ||||
| <GridActionsCellItem | <GridActionsCellItem | ||||
| key={`actions-${id}-delete`} | key={`actions-${id}-delete`} | ||||
| title="Delete" | |||||
| label="Delete" | |||||
| title={t("Delete")} | |||||
| label={t("Delete")} | |||||
| icon={<DeleteIcon />} | icon={<DeleteIcon />} | ||||
| onClick={handleDeleteClick(id)} | onClick={handleDeleteClick(id)} | ||||
| sx={{ color: "red" }} | sx={{ color: "red" }} | ||||
| @@ -313,7 +313,7 @@ const ClaimInputGrid: React.FC<ClaimInputGridProps> = ({ ...props }) => { | |||||
| }, | }, | ||||
| { | { | ||||
| field: "date", | field: "date", | ||||
| headerName: "Invoice Date", | |||||
| headerName: t("Invoice Date"), | |||||
| // width: 220, | // width: 220, | ||||
| flex: 1, | flex: 1, | ||||
| editable: true, | editable: true, | ||||
| @@ -321,7 +321,7 @@ const ClaimInputGrid: React.FC<ClaimInputGridProps> = ({ ...props }) => { | |||||
| }, | }, | ||||
| { | { | ||||
| field: "description", | field: "description", | ||||
| headerName: "Description", | |||||
| headerName: t("Description"), | |||||
| // width: 220, | // width: 220, | ||||
| flex: 2, | flex: 2, | ||||
| editable: true, | editable: true, | ||||
| @@ -329,7 +329,7 @@ const ClaimInputGrid: React.FC<ClaimInputGridProps> = ({ ...props }) => { | |||||
| }, | }, | ||||
| { | { | ||||
| field: "cost", | field: "cost", | ||||
| headerName: "Cost (HKD)", | |||||
| headerName: t("Cost (HKD)"), | |||||
| editable: true, | editable: true, | ||||
| type: "number", | type: "number", | ||||
| valueFormatter: (params) => { | valueFormatter: (params) => { | ||||
| @@ -338,7 +338,7 @@ const ClaimInputGrid: React.FC<ClaimInputGridProps> = ({ ...props }) => { | |||||
| }, | }, | ||||
| { | { | ||||
| field: "document", | field: "document", | ||||
| headerName: "Supporting Document", | |||||
| headerName: t("Supporting Document"), | |||||
| type: "string", | type: "string", | ||||
| editable: true, | editable: true, | ||||
| flex: 2, | flex: 2, | ||||
| @@ -360,7 +360,7 @@ const ClaimInputGrid: React.FC<ClaimInputGridProps> = ({ ...props }) => { | |||||
| {params.value} | {params.value} | ||||
| </a> | </a> | ||||
| <Button | <Button | ||||
| title="Remove Document" | |||||
| title={t("Remove Document")} | |||||
| onClick={(event) => console.log(event)} | onClick={(event) => console.log(event)} | ||||
| > | > | ||||
| <ImageNotSupportedOutlinedIcon | <ImageNotSupportedOutlinedIcon | ||||
| @@ -369,7 +369,7 @@ const ClaimInputGrid: React.FC<ClaimInputGridProps> = ({ ...props }) => { | |||||
| </Button> | </Button> | ||||
| </span> | </span> | ||||
| ) : ( | ) : ( | ||||
| <Button title="Add Document"> | |||||
| <Button title={t("Add Document")}> | |||||
| <AddPhotoAlternateOutlinedIcon | <AddPhotoAlternateOutlinedIcon | ||||
| sx={{ fontSize: "25px", color: "green" }} | sx={{ fontSize: "25px", color: "green" }} | ||||
| /> | /> | ||||
| @@ -49,7 +49,7 @@ const CreateItem: React.FC<Props> = ({ | |||||
| console.log(params.get("id")); | 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("common"); | |||||
| const { t } = useTranslation(["equipment", "common"]); | |||||
| const router = useRouter(); | const router = useRouter(); | ||||
| const title = "Equipment"; | const title = "Equipment"; | ||||
| const [mode, redirPath] = useMemo(() => { | const [mode, redirPath] = useMemo(() => { | ||||
| @@ -33,7 +33,7 @@ const ProductDetails: React.FC<Props> = ({ isEditMode }) => { | |||||
| const { | const { | ||||
| t, | t, | ||||
| i18n: { language }, | i18n: { language }, | ||||
| } = useTranslation(); | |||||
| } = useTranslation(["equipment", "common"]); | |||||
| const { | const { | ||||
| register, | register, | ||||
| @@ -49,7 +49,7 @@ const CreateItem: React.FC<Props> = ({ | |||||
| console.log(params.get("id")); | 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("common"); | |||||
| const { t } = useTranslation(["equipment", "common"]); | |||||
| const router = useRouter(); | const router = useRouter(); | ||||
| const title = "Equipment Type"; | const title = "Equipment Type"; | ||||
| const [mode, redirPath] = useMemo(() => { | const [mode, redirPath] = useMemo(() => { | ||||
| @@ -33,7 +33,7 @@ const ProductDetails: React.FC<Props> = ({ isEditMode }) => { | |||||
| const { | const { | ||||
| t, | t, | ||||
| i18n: { language }, | i18n: { language }, | ||||
| } = useTranslation(); | |||||
| } = useTranslation(["equipment", "common"]); | |||||
| const { | const { | ||||
| register, | register, | ||||