diff --git a/client/public/locales/en/common.json b/client/public/locales/en/common.json index ae191c2..f1326b2 100644 --- a/client/public/locales/en/common.json +++ b/client/public/locales/en/common.json @@ -109,35 +109,68 @@ "dashboard": { "title": "Dashboard" }, - "blog_posts": { - "blog_posts": "Blog Posts", + "spools": { + "spools": "Spools", "fields": { "id": "Id", - "title": "Title", - "content": "Content", - "status": "Status", - "category": "Category", - "createdAt": "Created At" + "filament_name": "Filament Name", + "used_weight": "Used Weight", + "remaining_weight": "Remaining Weight", + "location": "Location", + "lot_nr": "Lot Nr", + "first_used": "First Used", + "last_used": "Last Used", + "comment": "Comment" }, "titles": { - "create": "Create Blog Post", - "edit": "Edit Blog Post", - "list": "Blog Posts", - "show": "Show Blog Post" + "create": "Create Spool", + "clone": "Clone Spool", + "edit": "Edit Spool", + "list": "Spools", + "show": "Show Spool" } }, - "categories": { - "categories": "Categories", + "filaments": { + "filaments": "Filaments", "fields": { "id": "Id", - "title": "Title", - "createdAt": "Created At" + "vendor_name": "Vendor Name", + "name": "Name", + "material": "Material", + "price": "Price", + "density": "Density", + "diameter": "Diameter", + "weight": "Weight", + "spool_weight": "Spool Weight", + "article_number": "Article Number", + "registered": "Registered", + "comment": "Comment", + "settings_extruder_temp": "Extruder Temp", + "settings_bed_temp": "Bed Temp", + "color_hex": "Color" }, "titles": { - "create": "Create Category", - "edit": "Edit Category", - "list": "Categories", - "show": "Show Category" + "create": "Create Filament", + "clone": "Clone Filament", + "edit": "Edit Filament", + "list": "Filaments", + "show": "Show Filament" + } + }, + "vendors": { + "vendors": "Vendors", + "fields": { + "id": "Id", + "name": "Name", + "registered": "Registered", + "comment": "Comment" + }, + "titles": { + "create": "Create Vendor", + "clone": "Clone Vendor", + "edit": "Edit Vendor", + "list": "Vendors", + "show": "Show Vendor" } }, "table": { diff --git a/client/src/components/column.tsx b/client/src/components/column.tsx new file mode 100644 index 0000000..64243f8 --- /dev/null +++ b/client/src/components/column.tsx @@ -0,0 +1,170 @@ +import { Col, Row, Table } from "antd"; +import { ColumnProps as AntdColumnProps } from "antd/es/table"; +import { ColumnFilterItem } from "antd/es/table/interface"; +import { + getFiltersForField, + typeFilters, + useListFiltersForField, +} from "../utils/filtering"; +import { TableState } from "../utils/saveload"; +import { getSortOrderForField, typeSorters } from "../utils/sorting"; +import { NumberFieldUnit } from "./numberField"; +import dayjs from "dayjs"; +import utc from "dayjs/plugin/utc"; +import { DateField, TextField } from "@refinedev/antd"; +import Icon from "@ant-design/icons"; +import { ReactComponent as SpoolIcon } from "../icon_spool.svg"; + +dayjs.extend(utc); + +interface BaseColumnProps { + id: keyof Obj & string; + title: string; + dataSource: Obj[]; + tableState: TableState; +} + +interface FilteredColumnProps { + filters?: ColumnFilterItem[]; + filteredValue?: string[]; +} + +interface CustomColumnProps { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + render?: (value: any, record: Obj, index: number) => React.ReactNode; + onCell?: ( + data: Obj, + index?: number + // eslint-disable-next-line @typescript-eslint/no-explicit-any + ) => React.HTMLAttributes | React.TdHTMLAttributes; +} + +function Column( + props: BaseColumnProps & FilteredColumnProps & CustomColumnProps +) { + if ( + props.tableState.showColumns && + !props.tableState.showColumns.includes(props.id) + ) { + return <>; + } + const typedSorters = typeSorters(props.tableState.sorters); + const columnProps: AntdColumnProps = { + dataIndex: props.id, + title: props.title, + sorter: true, + sortOrder: getSortOrderForField(typedSorters, props.id), + }; + if (props.filters && props.filteredValue) { + columnProps.filters = props.filters; + columnProps.filteredValue = props.filteredValue; + } + if (props.render) { + columnProps.render = props.render; + } + if (props.onCell) { + columnProps.onCell = props.onCell; + } + return {...columnProps} />; +} + +export function SortedColumn(props: BaseColumnProps) { + // return ; + return Column(props); +} + +export function FilteredColumn(props: BaseColumnProps) { + const typedFilters = typeFilters(props.tableState.filters); + + const filters = useListFiltersForField(props.dataSource, props.id); + const filteredValue = getFiltersForField(typedFilters, props.id); + + return Column({ ...props, filters, filteredValue }); +} + +interface NumberColumnProps extends BaseColumnProps { + unit: string; + decimals?: number; +} + +export function NumberColumn(props: NumberColumnProps) { + return Column({ + ...props, + render: (value) => { + if (value === null || value === undefined) { + return ; + } + return ( + + ); + }, + }); +} + +export function DateColumn(props: BaseColumnProps) { + return Column({ + ...props, + render: (value) => { + return ( +