@@ -1,6 +1,6 @@ | |||
import { TypeEnum } from "@/app/utils/typeEnum"; | |||
import RoughSchedule from "@/components/RoughSchedule"; | |||
import { getServerI18n } from "@/i18n"; | |||
import { getServerI18n, I18nProvider } from "@/i18n"; | |||
import Add from "@mui/icons-material/Add"; | |||
import Button from "@mui/material/Button"; | |||
import Stack from "@mui/material/Stack"; | |||
@@ -15,22 +15,22 @@ export const metadata: Metadata = { | |||
}; | |||
const roughSchedulingDetail: React.FC = async () => { | |||
const project = TypeEnum.PRODUCT | |||
const { t } = await getServerI18n(project); | |||
// const project = TypeEnum.PRODUCT | |||
const { t } = await getServerI18n("project"); | |||
// preloadClaims(); | |||
return ( | |||
<> | |||
<Stack | |||
direction="row" | |||
justifyContent="space-between" | |||
flexWrap="wrap" | |||
rowGap={2} | |||
> | |||
<Typography variant="h4" marginInlineEnd={2}> | |||
{t("Demand Forecast Detail")} | |||
</Typography> | |||
{/* <Button | |||
justifyContent="space-between" | |||
flexWrap="wrap" | |||
rowGap={2} | |||
> | |||
<Typography variant="h4" marginInlineEnd={2}> | |||
{t("Demand Forecast Detail")} | |||
</Typography> | |||
{/* <Button | |||
variant="contained" | |||
startIcon={<Add />} | |||
LinkComponent={Link} | |||
@@ -38,12 +38,14 @@ const roughSchedulingDetail: React.FC = async () => { | |||
> | |||
{t("Create product")} | |||
</Button> */} | |||
</Stack> | |||
<Suspense fallback={<RoughScheduleDetailView.Loading />}> | |||
<RoughScheduleDetailView /> | |||
</Suspense> | |||
</> | |||
); | |||
</Stack> | |||
<I18nProvider namespaces={["schedule"]}> | |||
<Suspense fallback={<RoughScheduleDetailView.Loading />}> | |||
<RoughScheduleDetailView /> | |||
</Suspense> | |||
</I18nProvider> | |||
</> | |||
); | |||
}; | |||
export default roughSchedulingDetail; |
@@ -1,6 +1,6 @@ | |||
import { TypeEnum } from "@/app/utils/typeEnum"; | |||
import RoughSchedule from "@/components/RoughSchedule"; | |||
import { getServerI18n } from "@/i18n"; | |||
import { getServerI18n, I18nProvider } from "@/i18n"; | |||
import Add from "@mui/icons-material/Add"; | |||
import Button from "@mui/material/Button"; | |||
import Stack from "@mui/material/Stack"; | |||
@@ -14,8 +14,8 @@ export const metadata: Metadata = { | |||
}; | |||
const roughScheduling: React.FC = async () => { | |||
const project = TypeEnum.PRODUCT | |||
const { t } = await getServerI18n(project); | |||
// const project = TypeEnum.PRODUCT | |||
const { t } = await getServerI18n("schedule"); | |||
// preloadClaims(); | |||
return ( | |||
@@ -38,9 +38,11 @@ const roughScheduling: React.FC = async () => { | |||
{t("Create product")} | |||
</Button> */} | |||
</Stack> | |||
<Suspense fallback={<RoughSchedule.Loading />}> | |||
<RoughSchedule /> | |||
</Suspense> | |||
<I18nProvider namespaces={["schedule"]}> | |||
<Suspense fallback={<RoughSchedule.Loading />}> | |||
<RoughSchedule /> | |||
</Suspense> | |||
</I18nProvider> | |||
</> | |||
); | |||
}; | |||
@@ -8,6 +8,14 @@ export const moneyFormatter = new Intl.NumberFormat("en-HK", { | |||
currency: "HKD", | |||
}); | |||
export const decimalFormatter = new Intl.NumberFormat("en-HK", { | |||
minimumFractionDigits: 2, | |||
}) | |||
export const integerFormatter = new Intl.NumberFormat("en-HK", { | |||
}) | |||
export const stockInLineStatusMap: { [status: string]: {key: string, value: number} } = { | |||
draft: { key: "draft", value: 0 }, | |||
pending: { key: "pending", value: 1 }, | |||
@@ -20,7 +20,7 @@ interface Props { | |||
type SearchQuery = Partial<Omit<QcItemResult, "id">>; | |||
type SearchParamNames = keyof SearchQuery; | |||
const qcItemSearch: React.FC<Props> = ({ qcItems }) => { | |||
const QcItemSearch: React.FC<Props> = ({ qcItems }) => { | |||
const { t } = useTranslation("qcItems"); | |||
const router = useRouter(); | |||
const pathname = usePathname() | |||
@@ -118,4 +118,4 @@ const qcItemSearch: React.FC<Props> = ({ qcItems }) => { | |||
) | |||
}; | |||
export default qcItemSearch; | |||
export default QcItemSearch; |
@@ -17,6 +17,7 @@ import { InputDataGridProps, TableRow } from "../InputDataGrid/InputDataGrid"; | |||
import { TypeEnum } from "@/app/utils/typeEnum"; | |||
import { CreateItemInputs } from "@/app/api/settings/item/actions"; | |||
import {NumberInputProps} from "@/components/CreateItem/NumberInputProps"; | |||
import { integerFormatter } from "@/app/utils/formatUtil"; | |||
type Props = { | |||
// isEditMode: boolean; | |||
@@ -68,7 +69,7 @@ const DetailInfoCard: React.FC<Props> = ({ recordDetails, isEditing}) => { | |||
</Grid> | |||
<Grid item xs={6}> | |||
<TextField | |||
label={t("Total FG Type")} | |||
label={t("Total FG Item")} | |||
fullWidth | |||
{...register("productCount", { | |||
required: "code required!", | |||
@@ -87,7 +88,7 @@ const DetailInfoCard: React.FC<Props> = ({ recordDetails, isEditing}) => { | |||
required: "type required!", | |||
})} | |||
disabled={!isEditing} | |||
defaultValue={details?.productionCount} | |||
defaultValue={typeof(details?.productionCount) == "number" ? integerFormatter.format(details?.productionCount) : details?.productionCount} | |||
error={Boolean(errors.type)} | |||
helperText={errors.type?.message} | |||
/> | |||
@@ -43,7 +43,7 @@ const RoughScheduleDetailView: React.FC<Props> = ({ | |||
console.log(params.get("id")) | |||
const [serverError, setServerError] = useState(""); | |||
const [tabIndex, setTabIndex] = useState(0); | |||
const { t } = useTranslation(); | |||
const { t } = useTranslation("schedule") | |||
const router = useRouter(); | |||
const [isEdit, setIsEdit] = useState(false); | |||
//const title = "Demand Forecast Detail" | |||
@@ -19,6 +19,8 @@ import { QcChecksInputs } from "@/app/api/settings/qcCheck/actions"; | |||
import { GridApiCommunity } from "@mui/x-data-grid/internals"; | |||
import { RiceBowl } from "@mui/icons-material"; | |||
import EditableSearchResults, {Column} from "@/components/SearchResults/EditableSearchResults"; | |||
import { decimalFormatter } from "@/app/utils/formatUtil"; | |||
import { GridRenderCellParams } from "@mui/x-data-grid"; | |||
type Props = { | |||
apiRef: MutableRefObject<GridApiCommunity> | |||
@@ -57,7 +59,7 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit }) => { | |||
const { | |||
t, | |||
i18n: { language }, | |||
} = useTranslation(); | |||
} = useTranslation("schedule"); | |||
const { | |||
formState: { errors, defaultValues, touchedFields }, | |||
@@ -316,7 +318,7 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit }) => { | |||
() => [ | |||
{ | |||
field: "name", | |||
label: "name", | |||
label: t("name"), | |||
type: 'read-only', | |||
}, | |||
{ | |||
@@ -329,46 +331,100 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit }) => { | |||
field: "inStockQty", | |||
label: "In Stock Amount", | |||
type: 'read-only', | |||
renderCell: (row: FGOverallRecord) => { | |||
if (typeof(row.inStockQty) == "number") { | |||
return decimalFormatter.format(row.inStockQty) | |||
} | |||
return row.inStockQty | |||
} | |||
// editable: true, | |||
}, | |||
{ | |||
field: "overallPurchaseQty", | |||
label: "Total Purchase Qty", | |||
label: t("Total Demand Qty"), | |||
type: 'read-only', | |||
renderCell: (row: FGOverallRecord) => { | |||
if (typeof(row.overallPurchaseQty) == "number") { | |||
return decimalFormatter.format(row.overallPurchaseQty) | |||
} | |||
return row.overallPurchaseQty | |||
} | |||
}, | |||
{ | |||
field: "purchaseQty1", | |||
label: "Purchase Qty (Day1)", | |||
label: t("Demand Qty (Day1)"), | |||
type: 'read-only', | |||
renderCell: (row: FGOverallRecord) => { | |||
if (typeof(row.purchaseQty1) == "number") { | |||
return decimalFormatter.format(row.purchaseQty1) | |||
} | |||
return row.purchaseQty1 | |||
} | |||
}, | |||
{ | |||
field: "purchaseQty2", | |||
label: "Purchase Qty (Day2)", | |||
label: t("Demand Qty (Day2)"), | |||
type: 'read-only', | |||
renderCell: (row: FGOverallRecord) => { | |||
if (typeof(row.purchaseQty2) == "number") { | |||
return decimalFormatter.format(row.purchaseQty2) | |||
} | |||
return row.purchaseQty2 | |||
} | |||
}, | |||
{ | |||
field: "purchaseQty3", | |||
label: "Purchase Qty (Day3)", | |||
label: t("Demand Qty (Day3)"), | |||
type: 'read-only', | |||
renderCell: (row: FGOverallRecord) => { | |||
if (typeof(row.purchaseQty3) == "number") { | |||
return decimalFormatter.format(row.purchaseQty3) | |||
} | |||
return row.purchaseQty3 | |||
} | |||
}, | |||
{ | |||
field: "purchaseQty4", | |||
label: "Purchase Qty (Day4)", | |||
label: t("Demand Qty (Day4)"), | |||
type: 'read-only', | |||
renderCell: (row: FGOverallRecord) => { | |||
if (typeof(row.purchaseQty4) == "number") { | |||
return decimalFormatter.format(row.purchaseQty4) | |||
} | |||
return row.purchaseQty4 | |||
} | |||
},{ | |||
field: "purchaseQty5", | |||
label: "Purchase Qty (Day5)", | |||
label: t("Demand Qty (Day5)"), | |||
type: 'read-only', | |||
renderCell: (row: FGOverallRecord) => { | |||
if (typeof(row.purchaseQty5) == "number") { | |||
return decimalFormatter.format(row.purchaseQty5) | |||
} | |||
return row.purchaseQty5 | |||
} | |||
}, | |||
{ | |||
field: "purchaseQty6", | |||
label: "Purchase Qty (Day6)", | |||
label: t("Demand Qty (Day6)"), | |||
type: 'read-only', | |||
renderCell: (row: FGOverallRecord) => { | |||
if (typeof(row.purchaseQty6) == "number") { | |||
return decimalFormatter.format(row.purchaseQty6) | |||
} | |||
return row.purchaseQty6 | |||
} | |||
}, | |||
{ | |||
field: "purchaseQty7", | |||
label: "Purchase Qty (Day7)", | |||
label: t("Demand Qty (Day7)"), | |||
type: 'read-only', | |||
renderCell: (row: FGOverallRecord) => { | |||
if (typeof(row.purchaseQty7) == "number") { | |||
return decimalFormatter.format(row.purchaseQty7) | |||
} | |||
return row.purchaseQty7 | |||
} | |||
}, | |||
], | |||
[] | |||
@@ -392,11 +448,23 @@ const ViewByBomDetails: React.FC<Props> = ({ apiRef, isEdit }) => { | |||
label: "In Stock Amount", | |||
type: 'read-only', | |||
// editable: true, | |||
renderCell: (row: FGRecord) => { | |||
if (typeof(row.inStockQty) == "number") { | |||
return decimalFormatter.format(row.inStockQty) | |||
} | |||
return row.inStockQty | |||
} | |||
}, | |||
{ | |||
field: "purchaseQty", | |||
label: "Purchase Qty", | |||
type: 'read-only', | |||
renderCell: (row: FGRecord) => { | |||
if (typeof(row.purchaseQty) == "number") { | |||
return decimalFormatter.format(row.purchaseQty) | |||
} | |||
return row.purchaseQty | |||
} | |||
}, | |||
], | |||
[] | |||
@@ -19,6 +19,7 @@ import { QcChecksInputs } from "@/app/api/settings/qcCheck/actions"; | |||
import { GridApiCommunity } from "@mui/x-data-grid/internals"; | |||
import { RiceBowl } from "@mui/icons-material"; | |||
import EditableSearchResults, {Column} from "@/components/SearchResults/EditableSearchResults"; | |||
import { decimalFormatter } from "@/app/utils/formatUtil"; | |||
type Props = { | |||
apiRef: MutableRefObject<GridApiCommunity> | |||
@@ -460,11 +461,23 @@ const ViewByFGDetails: React.FC<Props> = ({ apiRef, isEdit }) => { | |||
label: "In Stock Amount", | |||
type: 'read-only', | |||
// editable: true, | |||
renderCell: (row: FGRecord) => { | |||
if (typeof(row.inStockQty) == "number") { | |||
return decimalFormatter.format(row.inStockQty) | |||
} | |||
return row.inStockQty | |||
} | |||
}, | |||
{ | |||
field: "productionQty", | |||
label: "Production Qty", | |||
type: 'input', | |||
renderCell: (row: FGRecord) => { | |||
if (typeof(row.productionQty) == "number") { | |||
return decimalFormatter.format(row.productionQty ?? 0) | |||
} | |||
return row.productionQty | |||
} | |||
}, | |||
], | |||
[] | |||
@@ -487,24 +500,60 @@ const ViewByFGDetails: React.FC<Props> = ({ apiRef, isEdit }) => { | |||
field: "lastMonthAvgStock", | |||
label: "Last Month Average Stock", | |||
type: 'read-only', | |||
style: { | |||
textAlign: "center", | |||
}, | |||
renderCell: (row: FGRecord) => { | |||
if (typeof(row.lastMonthAvgStock) == "number") { | |||
return decimalFormatter.format(row.lastMonthAvgStock) | |||
} | |||
return row.lastMonthAvgStock | |||
} | |||
// editable: true, | |||
}, | |||
{ | |||
field: "safetyStock", | |||
label: "Safety Stock", | |||
type: 'read-only', | |||
type: 'read-only-int', | |||
style: { | |||
textAlign: "center", | |||
}, | |||
renderCell: (row: FGRecord) => { | |||
if (typeof(row.safetyStock) == "number") { | |||
return decimalFormatter.format(row.safetyStock) | |||
} | |||
return row.safetyStock | |||
} | |||
// editable: true, | |||
}, | |||
{ | |||
field: "inStockQty", | |||
label: "In Stock Amount", | |||
type: 'read-only', | |||
type: 'read-only-int', | |||
style: { | |||
textAlign: "center", | |||
}, | |||
renderCell: (row: FGRecord) => { | |||
if (typeof(row.inStockQty) == "number") { | |||
return decimalFormatter.format(row.inStockQty) | |||
} | |||
return row.inStockQty | |||
} | |||
// editable: true, | |||
}, | |||
{ | |||
field: "productionQty", | |||
label: "Production Qty", | |||
type: 'input', | |||
type: 'read-only-int', | |||
style: { | |||
textAlign: "right", | |||
}, | |||
renderCell: (row: FGRecord) => { | |||
if (typeof(row.productionQty) == "number") { | |||
return decimalFormatter.format(row.productionQty) | |||
} | |||
return row.productionQty | |||
} | |||
}, | |||
], | |||
[] | |||
@@ -1,6 +1,6 @@ | |||
"use client"; | |||
import React, {useEffect, useState} from "react"; | |||
import React, { useEffect, useState } from "react"; | |||
import Paper from "@mui/material/Paper"; | |||
import Table from "@mui/material/Table"; | |||
import TableBody from "@mui/material/TableBody"; | |||
@@ -20,6 +20,7 @@ import { Collapse } from "@mui/material"; | |||
import TempInputGridForMockUp from "./TempInputGridForMockUp"; | |||
import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown"; | |||
import KeyboardArrowUpIcon from "@mui/icons-material/KeyboardArrowUp"; | |||
import { decimalFormatter, integerFormatter } from "@/app/utils/formatUtil"; | |||
export interface ResultWithId { | |||
id: string | number; | |||
@@ -31,6 +32,7 @@ interface BaseColumn<T extends ResultWithId> { | |||
type: string; | |||
options?: T[]; | |||
renderCell?: (T) => void; | |||
style?: Partial<HTMLElement["style"]> & { [propName: string]: string }; | |||
} | |||
interface ColumnWithAction<T extends ResultWithId> extends BaseColumn<T> { | |||
@@ -47,31 +49,31 @@ interface Props<T extends ResultWithId> { | |||
items: T[], | |||
columns: Column<T>[], | |||
noWrapper?: boolean, | |||
setPagingController: (value: { pageNum: number; pageSize: number; totalCount: number, index?: number}) => void, | |||
setPagingController: (value: { pageNum: number; pageSize: number; totalCount: number, index?: number }) => void, | |||
pagingController: { pageNum: number; pageSize: number; totalCount: number }, | |||
isAutoPaging: boolean | |||
} | |||
function EditableSearchResults<T extends ResultWithId>({ | |||
index, | |||
items, | |||
columns, | |||
noWrapper, | |||
pagingController, | |||
setPagingController, | |||
isAutoPaging = true, | |||
isEdit = false, | |||
isEditable = true, | |||
hasCollapse = false, | |||
}: Props<T>) { | |||
index, | |||
items, | |||
columns, | |||
noWrapper, | |||
pagingController, | |||
setPagingController, | |||
isAutoPaging = true, | |||
isEdit = false, | |||
isEditable = true, | |||
hasCollapse = false, | |||
}: Props<T>) { | |||
const [page, setPage] = useState(0); | |||
const [rowsPerPage, setRowsPerPage] = useState(10); | |||
const [editingRowId, setEditingRowId] = useState<number | null>(null); | |||
const [editedItems, setEditedItems] = useState<T[]>(items); | |||
console.log(items) | |||
useEffect(()=>{ | |||
console.log(items) | |||
useEffect(() => { | |||
setEditedItems(items) | |||
},[items]) | |||
}, [items]) | |||
const handleChangePage = (_event: unknown, newPage: number) => { | |||
setPage(newPage); | |||
setPagingController({ ...pagingController, pageNum: newPage + 1 }, (index ?? -1)); | |||
@@ -80,7 +82,7 @@ function EditableSearchResults<T extends ResultWithId>({ | |||
const handleChangeRowsPerPage = (event: React.ChangeEvent<HTMLInputElement>) => { | |||
setRowsPerPage(+event.target.value); | |||
setPage(0); | |||
setPagingController({ ...pagingController, pageSize: +event.target.value, pageNum: 1 , index: index}); | |||
setPagingController({ ...pagingController, pageSize: +event.target.value, pageNum: 1, index: index }); | |||
}; | |||
const handleEditClick = (id: number) => { | |||
@@ -108,7 +110,7 @@ function EditableSearchResults<T extends ResultWithId>({ | |||
setEditedItems((prev) => prev.filter(item => item.id !== id)); | |||
}; | |||
useEffect(()=>{ | |||
useEffect(() => { | |||
console.log("[debug] isEdit in table", isEdit) | |||
//TODO: switch all record to not in edit mode and save the changes | |||
if (!isEdit) { | |||
@@ -120,7 +122,7 @@ function EditableSearchResults<T extends ResultWithId>({ | |||
setEditingRowId(null); | |||
} | |||
},[isEdit]) | |||
}, [isEdit]) | |||
function Row(props: { row: T }) { | |||
const { row } = props; | |||
@@ -128,128 +130,132 @@ function EditableSearchResults<T extends ResultWithId>({ | |||
console.log(row) | |||
return ( | |||
<> | |||
<TableRow hover tabIndex={-1} key={row.id}> | |||
{ | |||
(isEditable || hasCollapse) && <TableCell> | |||
{(editingRowId === row.id) ? ( | |||
<> | |||
{ | |||
isEditable && <IconButton disabled={!isEdit} onClick={() => handleSaveClick(row)}> | |||
<SaveIcon/> | |||
</IconButton> | |||
} | |||
{ | |||
isEditable && <IconButton disabled={!isEdit} onClick={() => setEditingRowId(null)}> | |||
<CancelIcon/> | |||
</IconButton> | |||
} | |||
{ | |||
hasCollapse && <IconButton | |||
aria-label="expand row" | |||
size="small" | |||
onClick={() => setOpen(!open)} | |||
> | |||
{open ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />} | |||
</IconButton> | |||
} | |||
</> | |||
) : ( | |||
<> | |||
{ | |||
isEditable && <IconButton disabled={!isEdit} | |||
onClick={() => handleEditClick(row.id as number)}> | |||
<EditIcon/> | |||
</IconButton> | |||
} | |||
{ | |||
isEditable && <IconButton disabled={!isEdit} | |||
onClick={() => handleDeleteClick(row.id as number)}> | |||
<DeleteIcon/> | |||
</IconButton> | |||
} | |||
{ | |||
hasCollapse && <IconButton | |||
aria-label="expand row" | |||
size="small" | |||
onClick={() => setOpen(!open)} | |||
> | |||
{open ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />} | |||
</IconButton> | |||
} | |||
</> | |||
)} | |||
</TableCell> | |||
} | |||
{columns.map((column, idx) => { | |||
console.log(column) | |||
const columnName = column.field; | |||
return ( | |||
<TableCell key={`${columnName.toString()}-${idx}`}> | |||
{editingRowId === row.id ? ( | |||
(() => { | |||
switch (column.type) { | |||
case 'input': | |||
console.log(column.type) | |||
return ( | |||
<TextField | |||
hiddenLabel={true} | |||
fullWidth | |||
defaultValue={row[columnName] as string} | |||
onChange={(e) => handleInputChange(row.id as number, columnName, e.target.value)} | |||
/> | |||
); | |||
case 'multi-select': | |||
return ( | |||
<MultiSelect | |||
//label={column.label} | |||
options={column.options} | |||
selectedValues={[]} | |||
onChange={(selectedValues) => handleInputChange(row.id as number, columnName, selectedValues)} | |||
/> | |||
); | |||
case 'read-only': | |||
return ( | |||
<span> | |||
{row[columnName] as string} | |||
</span> | |||
); | |||
default: | |||
return null; // Handle any default case if needed | |||
<TableRow hover tabIndex={-1} key={row.id}> | |||
{ | |||
(isEditable || hasCollapse) && <TableCell> | |||
{(editingRowId === row.id) ? ( | |||
<> | |||
{ | |||
isEditable && <IconButton disabled={!isEdit} onClick={() => handleSaveClick(row)}> | |||
<SaveIcon /> | |||
</IconButton> | |||
} | |||
{ | |||
isEditable && <IconButton disabled={!isEdit} onClick={() => setEditingRowId(null)}> | |||
<CancelIcon /> | |||
</IconButton> | |||
} | |||
})() | |||
{ | |||
hasCollapse && <IconButton | |||
aria-label="expand row" | |||
size="small" | |||
onClick={() => setOpen(!open)} | |||
> | |||
{open ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />} | |||
</IconButton> | |||
} | |||
</> | |||
) : ( | |||
column.renderCell ? | |||
column.renderCell(row) | |||
: | |||
<span onDoubleClick={() => isEdit && handleEditClick(row.id as number)}> | |||
{row[columnName] as string} | |||
</span> | |||
<> | |||
{ | |||
isEditable && <IconButton disabled={!isEdit} | |||
onClick={() => handleEditClick(row.id as number)}> | |||
<EditIcon /> | |||
</IconButton> | |||
} | |||
{ | |||
isEditable && <IconButton disabled={!isEdit} | |||
onClick={() => handleDeleteClick(row.id as number)}> | |||
<DeleteIcon /> | |||
</IconButton> | |||
} | |||
{ | |||
hasCollapse && <IconButton | |||
aria-label="expand row" | |||
size="small" | |||
onClick={() => setOpen(!open)} | |||
> | |||
{open ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />} | |||
</IconButton> | |||
} | |||
</> | |||
)} | |||
</TableCell> | |||
); | |||
})} | |||
</TableRow> | |||
<TableRow> | |||
{ | |||
hasCollapse && | |||
<TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={6}> | |||
<Collapse in={open} timeout="auto" unmountOnExit> | |||
<Table> | |||
<TableBody> | |||
<TableRow> | |||
<TableCell> | |||
<TempInputGridForMockUp | |||
stockInLine={row.lines as any[]} | |||
/> | |||
</TableCell> | |||
</TableRow> | |||
</TableBody> | |||
</Table> | |||
</Collapse> | |||
</TableCell> | |||
} | |||
</TableRow> | |||
</> | |||
} | |||
{columns.map((column, idx) => { | |||
console.log(column) | |||
const columnName = column.field; | |||
return ( | |||
<TableCell key={`${columnName.toString()}-${idx}`}> | |||
{editingRowId === row.id ? ( | |||
(() => { | |||
switch (column.type) { | |||
case 'input': | |||
console.log(column.type) | |||
return ( | |||
<TextField | |||
hiddenLabel={true} | |||
fullWidth | |||
defaultValue={row[columnName] as string} | |||
onChange={(e) => handleInputChange(row.id as number, columnName, e.target.value)} | |||
/> | |||
); | |||
case 'multi-select': | |||
return ( | |||
<MultiSelect | |||
//label={column.label} | |||
options={column.options} | |||
selectedValues={[]} | |||
onChange={(selectedValues) => handleInputChange(row.id as number, columnName, selectedValues)} | |||
/> | |||
); | |||
case 'read-only': | |||
return ( | |||
<span> | |||
{row[columnName] as string} | |||
</span> | |||
); | |||
default: | |||
return null; // Handle any default case if needed | |||
} | |||
})() | |||
) : ( | |||
column.renderCell ? | |||
<div style={column.style}> | |||
{column.renderCell(row)} | |||
</div> | |||
: | |||
<div style={column.style}> | |||
<span onDoubleClick={() => isEdit && handleEditClick(row.id as number)}> | |||
{row[columnName] as String} | |||
</span> | |||
</div> | |||
)} | |||
</TableCell> | |||
); | |||
})} | |||
</TableRow> | |||
<TableRow> | |||
{ | |||
hasCollapse && | |||
<TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={6}> | |||
<Collapse in={open} timeout="auto" unmountOnExit> | |||
<Table> | |||
<TableBody> | |||
<TableRow> | |||
<TableCell> | |||
<TempInputGridForMockUp | |||
stockInLine={row.lines as any[]} | |||
/> | |||
</TableCell> | |||
</TableRow> | |||
</TableBody> | |||
</Table> | |||
</Collapse> | |||
</TableCell> | |||
} | |||
</TableRow> | |||
</> | |||
) | |||
} | |||
@@ -261,7 +267,7 @@ function EditableSearchResults<T extends ResultWithId>({ | |||
<TableRow> | |||
{(isEditable || hasCollapse) && <TableCell>Actions</TableCell>} {/* Action Column Header */} | |||
{columns.map((column, idx) => ( | |||
<TableCell key={`${column.field.toString()}${idx}`}> | |||
<TableCell style={column.style} key={`${column.field.toString()}${idx}`}> | |||
{column.label} | |||
</TableCell> | |||
))} | |||
@@ -35,7 +35,7 @@ import { QcItemWithChecks } from "src/app/api/qc"; | |||
import PlayArrowIcon from "@mui/icons-material/PlayArrow"; | |||
import { createStockInLine, testFetch } from "@/app/api/po/actions"; | |||
import { useSearchParams } from "next/navigation"; | |||
import { stockInLineStatusMap } from "@/app/utils/formatUtil"; | |||
import { decimalFormatter, stockInLineStatusMap } from "@/app/utils/formatUtil"; | |||
interface ResultWithId { | |||
id: number; | |||
@@ -180,13 +180,19 @@ function TempInputGridForMockUp({ stockInLine }: Props) { | |||
flex: 0.5, | |||
type: "number", | |||
editable: true, | |||
renderCell: (row) => { | |||
return decimalFormatter.format(row.value) | |||
} | |||
// replace with tooltip + content | |||
}, | |||
{ | |||
field: "purchaseQty", | |||
headerName: "purchaseQty", | |||
flex: 0.5, | |||
editable: true | |||
editable: true, | |||
renderCell: (row) => { | |||
return decimalFormatter.format(row.value) | |||
} | |||
}, | |||
// { | |||
// field: "actions", | |||
@@ -0,0 +1,10 @@ | |||
{ | |||
"Total Demand Qty": "Total Demand Qty", | |||
"Demand Qty (Day1)": "Demand Qty (Day1)", | |||
"Demand Qty (Day2)": "Demand Qty (Day2)", | |||
"Demand Qty (Day3)": "Demand Qty (Day3)", | |||
"Demand Qty (Day4)": "Demand Qty (Day4)", | |||
"Demand Qty (Day5)": "Demand Qty (Day5)", | |||
"Demand Qty (Day6)": "Demand Qty (Day6)", | |||
"Demand Qty (Day7)": "Demand Qty (Day7)" | |||
} |
@@ -0,0 +1,10 @@ | |||
{ | |||
"Total Demand Qty": "Total Demand Qty", | |||
"Demand Qty (Day1)": "Demand Qty (Day1)", | |||
"Demand Qty (Day2)": "Demand Qty (Day2)", | |||
"Demand Qty (Day3)": "Demand Qty (Day3)", | |||
"Demand Qty (Day4)": "Demand Qty (Day4)", | |||
"Demand Qty (Day5)": "Demand Qty (Day5)", | |||
"Demand Qty (Day6)": "Demand Qty (Day6)", | |||
"Demand Qty (Day7)": "Demand Qty (Day7)" | |||
} |