| @@ -0,0 +1,34 @@ | |||
| import { preloadInventory } from "@/app/api/inventory"; | |||
| import InventorySearch from "@/components/InventorySearch"; | |||
| import { getServerI18n } from "@/i18n"; | |||
| import { Stack, Typography } from "@mui/material"; | |||
| import { Metadata } from "next"; | |||
| import { Suspense } from "react"; | |||
| export const metadata: Metadata = { | |||
| title: "Inventory" | |||
| } | |||
| const Inventory: React.FC = async () => { | |||
| const { t } = await getServerI18n("inventory") | |||
| preloadInventory() | |||
| return <> | |||
| <Stack | |||
| direction="row" | |||
| justifyContent={"space-between"} | |||
| flexWrap={"wrap"} | |||
| rowGap={2} | |||
| > | |||
| <Typography variant="h4" marginInlineEnd={2}> | |||
| {t("Inventory")} | |||
| </Typography> | |||
| </Stack> | |||
| <Suspense fallback={<InventorySearch.Loading />}> | |||
| <InventorySearch /> | |||
| </Suspense> | |||
| </>; | |||
| } | |||
| export default Inventory; | |||
| @@ -1,19 +1,16 @@ | |||
| import { TypeEnum } from "@/app/utils/typeEnum"; | |||
| import ItemsSearch from "@/components/ItemsSearch"; | |||
| import DetailSchedule from "@/components/DetailSchedule"; | |||
| import { getServerI18n } from "@/i18n"; | |||
| import Add from "@mui/icons-material/Add"; | |||
| import Button from "@mui/material/Button"; | |||
| import Stack from "@mui/material/Stack"; | |||
| import Typography from "@mui/material/Typography"; | |||
| import { Metadata } from "next"; | |||
| import Link from "next/link"; | |||
| import { Suspense } from "react"; | |||
| export const metadata: Metadata = { | |||
| title: "Detail Scheduling", | |||
| }; | |||
| const detailScheduling: React.FC = async () => { | |||
| const DetailScheduling: React.FC = async () => { | |||
| const project = TypeEnum.PRODUCT | |||
| const { t } = await getServerI18n(project); | |||
| // preloadClaims(); | |||
| @@ -29,20 +26,12 @@ const detailScheduling: React.FC = async () => { | |||
| <Typography variant="h4" marginInlineEnd={2}> | |||
| {t("Detail Scheduling")} | |||
| </Typography> | |||
| {/* <Button | |||
| variant="contained" | |||
| startIcon={<Add />} | |||
| LinkComponent={Link} | |||
| href="product/create" | |||
| > | |||
| {t("Create product")} | |||
| </Button> */} | |||
| </Stack> | |||
| <Suspense fallback={<ItemsSearch.Loading />}> | |||
| <ItemsSearch /> | |||
| <Suspense fallback={<DetailSchedule.Loading />}> | |||
| <DetailSchedule /> | |||
| </Suspense> | |||
| </> | |||
| ); | |||
| }; | |||
| export default detailScheduling; | |||
| export default DetailScheduling; | |||
| @@ -0,0 +1,30 @@ | |||
| import { serverFetchJson } from "@/app/utils/fetchUtil"; | |||
| import { BASE_API_URL } from "@/config/api"; | |||
| import { cache } from "react"; | |||
| import "server-only"; | |||
| export interface InventoryResult { | |||
| id: number; | |||
| code: string; | |||
| name: string; | |||
| type: string; | |||
| qty: number; | |||
| uomCode: string; | |||
| uomUdfudesc: string; | |||
| germPerSmallestUnit: number; | |||
| qtyPerSmallestUnit: number; | |||
| smallestUnit: string; | |||
| price: number; | |||
| currencyName: string; | |||
| status: string; | |||
| } | |||
| export const preloadInventory = () => { | |||
| fetchInventories(); | |||
| } | |||
| export const fetchInventories = cache(async() => { | |||
| return serverFetchJson<InventoryResult[]>(`${BASE_API_URL}/inventory/list`, { | |||
| next: { tags: ["inventories"]} | |||
| }) | |||
| }) | |||
| @@ -18,6 +18,7 @@ const pathToLabelMap: { [path: string]: string } = { | |||
| "/scheduling/rough/edit": "FG & Material Demand Forecast Detail", | |||
| "/scheduling/detail": "Detail Scheduling", | |||
| "/scheduling/detail/edit": "FG Production Schedule", | |||
| "/inventory": "Inventory", | |||
| }; | |||
| const Breadcrumb = () => { | |||
| @@ -101,14 +101,14 @@ const ViewByFGDetails: React.FC<Props> = ({ apiRef, isEdit }) => { | |||
| () => [ | |||
| [ | |||
| { | |||
| id: 1, jobNo: "JO20250507001", priority: 85, code: "PP1193", type: "FG", name: "蔥油(1磅) ", inStockQty: 1322, productionQty: 661, | |||
| id: 1, jobNo: "JO20250507001", estimatedProductionTime: "1 hr", priority: 85, code: "PP1193", type: "FG", name: "蔥油(1磅) ", inStockQty: 1322, productionQty: 661, | |||
| lines: [ | |||
| { id: 1, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 100, purchaseQty: 20 }, | |||
| { id: 2, code: "FA0161", type: "Material", name: "洋蔥粒", inStockQty: 80, purchaseQty: 10 } | |||
| ] | |||
| }, | |||
| { | |||
| id: 2, jobNo: "JO20250507002", priority: 80, code: " PP1096", type: "FG", name: "白麵撈", inStockQty: 1040, productionQty: 520, | |||
| id: 2, jobNo: "JO20250507002", estimatedProductionTime: "2 hrs", priority: 80, code: " PP1096", type: "FG", name: "白麵撈", inStockQty: 1040, productionQty: 520, | |||
| lines: [ | |||
| { id: 1, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 1000, purchaseQty: 190.00 }, | |||
| { id: 1, code: "MH0040", type: "Material", name: "星加坡綠富貴花牌幼白麵粉 (50磅/包)", inStockQty: 1000, purchaseQty: 250.00 }, | |||
| @@ -116,7 +116,7 @@ const ViewByFGDetails: React.FC<Props> = ({ apiRef, isEdit }) => { | |||
| ] | |||
| }, | |||
| { | |||
| id: 3, jobNo: "JO20250507003", priority: 35, code: "PP1080", type: "FG", name: "咖哩汁", inStockQty: 2400, productionQty: 1200.0, | |||
| id: 3, jobNo: "JO20250507003", estimatedProductionTime: "5 hrs : 15 mins", priority: 35, code: "PP1080", type: "FG", name: "咖哩汁", inStockQty: 2400, productionQty: 1200.0, | |||
| lines: [ | |||
| { id: 1, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 0, purchaseQty: 108.88 }, | |||
| { id: 2, code: "GI3236", type: "Material", name: "清水(煮過牛腩)", inStockQty: 317.52, purchaseQty: 635.04 }, | |||
| @@ -132,7 +132,7 @@ const ViewByFGDetails: React.FC<Props> = ({ apiRef, isEdit }) => { | |||
| ] | |||
| }, | |||
| { | |||
| id: 4, jobNo: "JO20250507004", priority: 20, code: " PP1188", type: "FG", name: "咖喱膽", inStockQty: 1016.2, productionQty: 508.1, | |||
| id: 4, jobNo: "JO20250507004", estimatedProductionTime: "3 hrs", priority: 20, code: " PP1188", type: "FG", name: "咖喱膽", inStockQty: 1016.2, productionQty: 508.1, | |||
| lines: [ | |||
| { id: 1, code: "MH0040", type: "Material", name: "大豆油(1噸/桶)", inStockQty: 0, purchaseQty: 217.72 }, | |||
| { id: 2, code: "FA0161", type: "Material", name: "洋蔥粒", inStockQty: 0, purchaseQty: 18.15 }, | |||
| @@ -525,6 +525,14 @@ const ViewByFGDetails: React.FC<Props> = ({ apiRef, isEdit }) => { | |||
| return row.productionQty | |||
| } | |||
| }, | |||
| { | |||
| field: "estimatedProductionTime", | |||
| label: "Estimated Production Time", | |||
| type: "read-only", | |||
| style: { | |||
| textAlign: "right", | |||
| } | |||
| }, | |||
| { | |||
| field: "priority", | |||
| label: "Production Priority", | |||
| @@ -0,0 +1,139 @@ | |||
| "use client" | |||
| import { InventoryResult } from "@/app/api/inventory"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import SearchBox, { Criterion } from "../SearchBox"; | |||
| import { useCallback, useMemo, useState } from "react"; | |||
| import { uniq } from "lodash"; | |||
| import SearchResults, { Column } from "../SearchResults"; | |||
| import { CheckCircleOutline, DoDisturb } from "@mui/icons-material"; | |||
| interface Props { | |||
| inventories: InventoryResult[]; | |||
| } | |||
| type SearchQuery = Partial<Omit<InventoryResult, | |||
| | "id" | |||
| | "qty" | |||
| | "uomCode" | |||
| | "uomUdfudesc" | |||
| | "germPerSmallestUnit" | |||
| | "qtyPerSmallestUnit" | |||
| | "itemSmallestUnit" | |||
| | "price" | |||
| | "description" | |||
| | "category">>; | |||
| type SearchParamNames = keyof SearchQuery; | |||
| const InventorySearch: React.FC<Props> = ({ | |||
| inventories, | |||
| }) => { | |||
| const { t } = useTranslation("inventories"); | |||
| const [filteredInventories, setFilteredInventories] = useState(inventories) | |||
| const searchCriteria: Criterion<SearchParamNames>[] = useMemo(() => [ | |||
| { label: t("Code"), paramName: "code", type: "text" }, | |||
| { label: t("Name"), paramName: "name", type: "text" }, | |||
| { label: t("Type"), paramName: "type", type: "select", options: uniq(inventories.map(i => i.type)) }, | |||
| { label: t("Status"), paramName: "status", type: "select", options: uniq(inventories.map(i => i.status)) }, | |||
| ], [t] | |||
| ); | |||
| const onReset = useCallback(() => { | |||
| setFilteredInventories(inventories) | |||
| }, [inventories]) | |||
| const columns = useMemo<Column<InventoryResult>[]>( | |||
| () => [ | |||
| { | |||
| name: "code", | |||
| label: t("Code"), | |||
| }, | |||
| { | |||
| name: "name", | |||
| label: t("Name"), | |||
| }, | |||
| { | |||
| name: "type", | |||
| label: t("Type"), | |||
| }, | |||
| { | |||
| name: "qty", | |||
| label: t("Qty"), | |||
| align: "right", | |||
| headerAlign: "right", | |||
| type: "integer" | |||
| }, | |||
| { | |||
| name: "uomUdfudesc", | |||
| label: t("UoM"), | |||
| }, | |||
| { | |||
| name: "qtyPerSmallestUnit", | |||
| label: t("Qty Per Smallest Unit"), | |||
| align: "right", | |||
| headerAlign: "right", | |||
| type: "decimal" | |||
| }, | |||
| { | |||
| name: "smallestUnit", | |||
| label: t("Smallest Unit"), | |||
| }, | |||
| // { | |||
| // name: "price", | |||
| // label: t("Price"), | |||
| // align: "right", | |||
| // sx: { | |||
| // alignItems: "right", | |||
| // justifyContent: "end", | |||
| // } | |||
| // }, | |||
| // { | |||
| // name: "currencyName", | |||
| // label: t("Currency"), | |||
| // }, | |||
| // { | |||
| // name: "status", | |||
| // label: t("Status"), | |||
| // type: "icon", | |||
| // icons: { | |||
| // available: <CheckCircleOutline fontSize="small"/>, | |||
| // unavailable: <DoDisturb fontSize="small"/>, | |||
| // }, | |||
| // colors: { | |||
| // available: "success", | |||
| // unavailable: "error", | |||
| // } | |||
| // }, | |||
| ], [t] | |||
| ) | |||
| return ( | |||
| <> | |||
| <SearchBox | |||
| criteria={searchCriteria} | |||
| onSearch={(query) => { | |||
| console.log(query) | |||
| console.log(inventories) | |||
| setFilteredInventories( | |||
| inventories.filter( | |||
| (i) => | |||
| i.code.toLowerCase().includes(query.code.toLowerCase()) && | |||
| i.name.toLowerCase().includes(query.name.toLowerCase()) && | |||
| (query.type == "All" || i.type.toLowerCase().includes(query.type.toLowerCase())) && | |||
| (query.status == "All" || i.status.toLowerCase().includes(query.status.toLowerCase())) | |||
| ) | |||
| ) | |||
| }} | |||
| onReset={onReset} | |||
| /> | |||
| <SearchResults<InventoryResult> items={filteredInventories} columns={columns} pagingController={{ | |||
| pageNum: 0, | |||
| pageSize: 0, | |||
| totalCount: 0, | |||
| }} /> | |||
| </> | |||
| ) | |||
| } | |||
| export default InventorySearch | |||
| @@ -0,0 +1,24 @@ | |||
| import React from "react"; | |||
| import GeneralLoading from "../General/GeneralLoading" | |||
| import { fetchInventories } from "@/app/api/inventory"; | |||
| import InventorySearch from "./InventorySearch"; | |||
| interface SubComponents { | |||
| Loading: typeof GeneralLoading; | |||
| } | |||
| const InventorySearchWrapper: React.FC & SubComponents = async () => { | |||
| const [ | |||
| inventories | |||
| ] = await Promise.all([ | |||
| fetchInventories() | |||
| ]) | |||
| return <InventorySearch inventories={inventories}/> | |||
| } | |||
| InventorySearchWrapper.Loading = GeneralLoading; | |||
| export default InventorySearchWrapper | |||
| @@ -0,0 +1 @@ | |||
| export { default } from "./InventorySearchWrapper" | |||
| @@ -76,8 +76,8 @@ const NavigationContent: React.FC = () => { | |||
| }, | |||
| { | |||
| icon: <RequestQuote />, | |||
| label: "View item In-out And invertory Ledger", | |||
| path: "", | |||
| label: "View item In-out And inventory Ledger", | |||
| path: "/inventory", | |||
| }, | |||
| ], | |||
| }, | |||
| @@ -28,7 +28,7 @@ interface BaseCriterion<T extends string> { | |||
| label2?: string; | |||
| paramName: T; | |||
| paramName2?: T; | |||
| options?: T[]; | |||
| options?: T[] | string[]; | |||
| filterObj?: T; | |||
| handleSelectionChange?: (selectedOptions: T[]) => void; | |||
| } | |||
| @@ -39,11 +39,11 @@ interface TextCriterion<T extends string> extends BaseCriterion<T> { | |||
| interface SelectCriterion<T extends string> extends BaseCriterion<T> { | |||
| type: "select"; | |||
| options: T[]; | |||
| options: string[]; | |||
| } | |||
| interface MultiSelectCriterion<T extends string> extends BaseCriterion<T> { | |||
| type: "select"; | |||
| type: "multi-select"; | |||
| options: T[]; | |||
| selectedOptions: T[]; | |||
| handleSelectionChange: (selectedOptions: T[]) => void; | |||
| @@ -4,32 +4,62 @@ import React from "react"; | |||
| import Paper from "@mui/material/Paper"; | |||
| import Table from "@mui/material/Table"; | |||
| import TableBody from "@mui/material/TableBody"; | |||
| import TableCell from "@mui/material/TableCell"; | |||
| import TableCell, { TableCellProps } from "@mui/material/TableCell"; | |||
| import TableContainer from "@mui/material/TableContainer"; | |||
| import TableHead from "@mui/material/TableHead"; | |||
| import TablePagination, { | |||
| TablePaginationProps, | |||
| } from "@mui/material/TablePagination"; | |||
| import TableRow from "@mui/material/TableRow"; | |||
| import IconButton, {IconButtonOwnProps} from "@mui/material/IconButton"; | |||
| import IconButton, { IconButtonOwnProps } from "@mui/material/IconButton"; | |||
| import { ButtonOwnProps, Icon, IconOwnProps, SxProps, Theme } from "@mui/material"; | |||
| import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline'; | |||
| import { decimalFormatter, integerFormatter } from "@/app/utils/formatUtil"; | |||
| export interface ResultWithId { | |||
| id: string | number; | |||
| } | |||
| type ColumnType = "icon" | "decimal" | "integer"; | |||
| interface BaseColumn<T extends ResultWithId> { | |||
| name: keyof T; | |||
| label: string; | |||
| align?: TableCellProps["align"]; | |||
| headerAlign?: TableCellProps["align"]; | |||
| sx?: SxProps<Theme> | undefined; | |||
| style?: Partial<HTMLElement["style"]> & { [propName: string]: string }; | |||
| type?: ColumnType; | |||
| } | |||
| interface IconColumn<T extends ResultWithId> extends BaseColumn<T> { | |||
| name: keyof T; | |||
| type: "icon"; | |||
| icon?: React.ReactNode; | |||
| icons?: { [columnValue in keyof T]: React.ReactNode }; | |||
| color?: IconOwnProps["color"]; | |||
| colors?: { [columnValue in keyof T]: IconOwnProps["color"] }; | |||
| } | |||
| interface DecimalColumn<T extends ResultWithId> extends BaseColumn<T> { | |||
| type: "decimal"; | |||
| } | |||
| interface IntegerColumn<T extends ResultWithId> extends BaseColumn<T> { | |||
| type: "integer"; | |||
| } | |||
| interface ColumnWithAction<T extends ResultWithId> extends BaseColumn<T> { | |||
| onClick: (item: T) => void; | |||
| buttonIcon: React.ReactNode; | |||
| buttonIcons: { [columnValue in keyof T]: React.ReactNode }; | |||
| buttonColor?: IconButtonOwnProps["color"]; | |||
| } | |||
| export type Column<T extends ResultWithId> = | |||
| | BaseColumn<T> | |||
| | IconColumn<T> | |||
| | DecimalColumn<T> | |||
| | ColumnWithAction<T>; | |||
| interface Props<T extends ResultWithId> { | |||
| @@ -42,7 +72,7 @@ interface Props<T extends ResultWithId> { | |||
| totalCount: number | |||
| }) | { pageNum: number; pageSize: number; totalCount: number })) => void, | |||
| pagingController: { pageNum: number; pageSize: number; totalCount: number }, | |||
| isAutoPaging: boolean | |||
| isAutoPaging?: boolean | |||
| } | |||
| function isActionColumn<T extends ResultWithId>( | |||
| @@ -51,14 +81,67 @@ function isActionColumn<T extends ResultWithId>( | |||
| return Boolean((column as ColumnWithAction<T>).onClick); | |||
| } | |||
| function isIconColumn<T extends ResultWithId>( | |||
| column: Column<T>, | |||
| ): column is IconColumn<T> { | |||
| return column.type === "icon"; | |||
| } | |||
| function isDecimalColumn<T extends ResultWithId>( | |||
| column: Column<T>, | |||
| ): column is DecimalColumn<T> { | |||
| return column.type === "decimal"; | |||
| } | |||
| function isIntegerColumn<T extends ResultWithId>( | |||
| column: Column<T>, | |||
| ): column is IntegerColumn<T> { | |||
| return column.type === "integer"; | |||
| } | |||
| // Icon Component Functions | |||
| function convertObjectKeysToLowercase<T extends object>(obj: T): object | undefined { | |||
| return obj ? Object.fromEntries( | |||
| Object.entries(obj).map(([key, value]) => [key.toLowerCase(), value]) | |||
| ) : undefined; | |||
| } | |||
| function handleIconColors<T extends ResultWithId>( | |||
| column: IconColumn<T>, | |||
| value: T[keyof T], | |||
| ): IconOwnProps["color"] { | |||
| const colors = convertObjectKeysToLowercase(column.colors ?? {}); | |||
| const valueKey = String(value).toLowerCase() as keyof typeof colors; | |||
| if (colors && valueKey in colors) { | |||
| return colors[valueKey]; | |||
| } | |||
| return column.color ?? "primary"; | |||
| }; | |||
| function handleIconIcons<T extends ResultWithId>( | |||
| column: IconColumn<T>, | |||
| value: T[keyof T], | |||
| ): React.ReactNode { | |||
| const icons = convertObjectKeysToLowercase(column.icons ?? {}); | |||
| const valueKey = String(value).toLowerCase() as keyof typeof icons; | |||
| if (icons && valueKey in icons) { | |||
| return icons[valueKey]; | |||
| } | |||
| return column.icon ?? <CheckCircleOutlineIcon fontSize="small" />; | |||
| }; | |||
| function SearchResults<T extends ResultWithId>({ | |||
| items, | |||
| columns, | |||
| noWrapper, | |||
| pagingController, | |||
| setPagingController, | |||
| isAutoPaging = true, | |||
| }: Props<T>) { | |||
| items, | |||
| columns, | |||
| noWrapper, | |||
| pagingController, | |||
| setPagingController, | |||
| isAutoPaging = true, | |||
| }: Props<T>) { | |||
| const [page, setPage] = React.useState(0); | |||
| const [rowsPerPage, setRowsPerPage] = React.useState(10); | |||
| @@ -90,12 +173,12 @@ function SearchResults<T extends ResultWithId>({ | |||
| const table = ( | |||
| <> | |||
| <TableContainer sx={{maxHeight: 440}}> | |||
| <TableContainer sx={{ maxHeight: 440 }}> | |||
| <Table stickyHeader> | |||
| <TableHead> | |||
| <TableRow> | |||
| {columns.map((column, idx) => ( | |||
| <TableCell key={`${column.name.toString()}${idx}`}> | |||
| <TableCell align={column.headerAlign} sx={column.sx} key={`${column.name.toString()}${idx}`}> | |||
| {column.label} | |||
| </TableCell> | |||
| ))} | |||
| @@ -113,18 +196,7 @@ function SearchResults<T extends ResultWithId>({ | |||
| const columnName = column.name; | |||
| return ( | |||
| <TableCell key={`${columnName.toString()}-${idx}`}> | |||
| {isActionColumn(column) ? ( | |||
| <IconButton | |||
| color={column.buttonColor ?? "primary"} | |||
| onClick={() => column.onClick(item)} | |||
| > | |||
| {column.buttonIcon} | |||
| </IconButton> | |||
| ) : ( | |||
| <>{item[columnName] as string}</> | |||
| )} | |||
| </TableCell> | |||
| <TabelCells key={`${columnName.toString()}-${idx}`} column={column} columnName={columnName} idx={idx} item={item}/> | |||
| ); | |||
| })} | |||
| </TableRow> | |||
| @@ -139,19 +211,8 @@ function SearchResults<T extends ResultWithId>({ | |||
| const columnName = column.name; | |||
| return ( | |||
| <TableCell key={`${columnName.toString()}-${idx}`}> | |||
| {isActionColumn(column) ? ( | |||
| <IconButton | |||
| color={column.buttonColor ?? "primary"} | |||
| onClick={() => column.onClick(item)} | |||
| > | |||
| {column.buttonIcon} | |||
| </IconButton> | |||
| ) : ( | |||
| <>{item[columnName] as string}</> | |||
| )} | |||
| </TableCell> | |||
| ); | |||
| <TabelCells key={`${columnName.toString()}-${idx}`} column={column} columnName={columnName} idx={idx} item={item}/> | |||
| ); | |||
| })} | |||
| </TableRow> | |||
| ); | |||
| @@ -172,7 +233,49 @@ function SearchResults<T extends ResultWithId>({ | |||
| </> | |||
| ); | |||
| return noWrapper ? table : <Paper sx={{overflow: "hidden"}}>{table}</Paper>; | |||
| return noWrapper ? table : <Paper sx={{ overflow: "hidden" }}>{table}</Paper>; | |||
| } | |||
| // Table cells | |||
| interface TableCellsProps<T extends ResultWithId> { | |||
| column: Column<T>, | |||
| columnName: keyof T, | |||
| idx: number, | |||
| item: T, | |||
| } | |||
| function TabelCells<T extends ResultWithId>({ | |||
| column, | |||
| columnName, | |||
| idx, | |||
| item | |||
| }: TableCellsProps<T>) { | |||
| return ( | |||
| <TableCell align={column.align} sx={column.sx} key={`${columnName.toString()}-${idx}`}> | |||
| {isActionColumn(column) ? ( | |||
| <IconButton | |||
| color={column.buttonColor ?? "primary"} | |||
| onClick={() => column.onClick(item)} | |||
| > | |||
| {column.buttonIcon} | |||
| </IconButton> | |||
| ) : | |||
| isIconColumn(column) ? ( | |||
| <Icon | |||
| color={handleIconColors(column, item[columnName])} | |||
| > | |||
| {handleIconIcons(column, item[columnName])} | |||
| </Icon> | |||
| ) : | |||
| isDecimalColumn(column) ? ( | |||
| <>{decimalFormatter.format(Number(item[columnName]))}</> | |||
| ) : | |||
| isIntegerColumn(column) ? ( | |||
| <>{integerFormatter.format(Number(item[columnName]))}</> | |||
| ) : ( | |||
| <>{item[columnName] as string}</> | |||
| )} | |||
| </TableCell>) | |||
| } | |||
| export default SearchResults; | |||