List Order Table Block
The ListOrderTable Component is a fully customizable and accessible order table interface built with React and TypeScript. It provides a complete tabular order listing experience with modern design patterns, sortable columns, action dropdowns, tabs, pagination support, loading states, and flexible customization options for advanced order management applications.
π Installationβ
npm install @nodeblocks/frontend-list-order-table-block@0.1.0
π Usageβ
import {ListOrderTable} from '@nodeblocks/frontend-list-order-table-block';
- Basic Usage
- Advanced Usage
function BasicListOrderTable() { const [currentTab, setCurrentTab] = useState('pending'); const [isLoading] = useState(false); const orderData = [ { id: '1', createdAt: '2024-01-15T10:30:00Z', orderName: 'ORD-001', title: 'Office Supplies Order', status: 'pending', }, { id: '2', createdAt: '2024-01-14T14:20:00Z', orderName: 'ORD-002', title: 'Software License', status: 'accepted', }, ]; const tabs = [{label: 'Pending Orders'}, {label: 'Accepted Orders'}, {label: 'Canceled Orders'}]; const labels = { emptyStateMessage: 'No orders found', actions: { headerAction: 'Create Order', }, headerRow: { createdAt: 'Created', title: 'Order Title', orderName: 'Order ID', }, rowActions: { accepted: 'Accept Order', canceled: 'Cancel Order', processing: 'Mark Processing', }, }; const handleOrderAccepted = (orderId, title) => { console.log('Order accepted:', orderId, title); }; const handleOrderRejected = (orderId, title) => { console.log('Order rejected:', orderId, title); }; const handleOrderProcessing = (orderId, title) => { console.log('Order processing:', orderId, title); }; const handleNavigate = (path) => { console.log('Navigate to:', path); }; const getRowHref = (row) => `#${row.id}`; const getUpdateRowHref = (row) => `#${row.id}/edit`; return ( <ListOrderTable listOrderTableTitle="Order Management" labels={labels} isLoading={isLoading} onNavigate={handleNavigate} onOrderAccepted={handleOrderAccepted} onOrderRejected={handleOrderRejected} onOrderProcessing={handleOrderProcessing} data={orderData} rowHref={getRowHref} updateRowHref={getUpdateRowHref} tabs={tabs} currentTab={currentTab} onTabChange={setCurrentTab} createHref="#new" style={{ backgroundColor: 'white', padding: '8px', }} > <ListOrderTable.Header style={{display: 'flex', justifyContent: 'space-between'}}> <ListOrderTable.Title /> <ListOrderTable.Action /> </ListOrderTable.Header> <ListOrderTable.Content> {isLoading ? ( <ListOrderTable.Loader /> ) : ( <> <ListOrderTable.Tabs /> <ListOrderTable.Table /> </> )} </ListOrderTable.Content> </ListOrderTable> ); }
function AdvancedOrderTable() { const [currentTab, setCurrentTab] = useState('pending'); const [isLoading] = useState(false); const orderData = [ { id: '1', createdAt: '2024-01-15T10:30:00Z', orderName: 'π¦ ORD-2024-001', title: 'Premium Office Supplies Package', status: 'pending', }, { id: '2', createdAt: '2024-01-14T14:20:00Z', orderName: 'π» ORD-2024-002', title: 'Software License Renewal Bundle', status: 'accepted', }, { id: '3', createdAt: '2024-01-13T09:15:00Z', orderName: 'π§ ORD-2024-003', title: 'IT Equipment Maintenance Contract', status: 'processing', }, ]; const tabs = [ {label: 'β³ Pending Orders', key: 'pending'}, {label: 'β Accepted Orders', key: 'accepted'}, {label: 'π« Canceled Orders', key: 'canceled'}, ]; const labels = { emptyStateMessage: 'No orders found in this category', actions: { headerAction: 'β¨ Create New Order', }, headerRow: { createdAt: 'Order Date', title: 'Order Description', orderName: 'Order Reference', }, rowActions: { accepted: 'π― Accept Order', canceled: 'β Cancel Order', processing: 'β‘ Start Processing', }, }; return ( <ListOrderTable listOrderTableTitle="π Enterprise Order Dashboard" labels={labels} isLoading={isLoading} onNavigate={path => console.log('Navigate to:', path)} onOrderAccepted={(id, title) => console.log('Accepting order:', title)} onOrderRejected={(id, title) => console.log('Canceling order:', title)} onOrderProcessing={(id, title) => console.log('Processing order:', title)} data={orderData} rowHref={row => `#${row.id}`} updateRowHref={row => `#${row.id}/edit`} tabs={tabs} currentTab={currentTab} onTabChange={setCurrentTab} style={{ backgroundColor: 'white', padding: '8px', }} createHref="#new" > {({defaultBlocks, defaultBlockOrder}) => ({ blocks: { // Enhanced header with gradient styling header: { ...defaultBlocks.header, props: { ...defaultBlocks.header.props, style: { background: 'white', borderRadius: '20px', padding: '32px', color: 'black', width: 'calc(100% - 48px)', margin: '0 auto', marginTop: '12px', boxShadow: '0 15px 35px rgba(0,0,0,0.1)', border: '0.5px solid rgb(0, 0, 0)', }, }, }, // Enhanced content with modern styling content: { ...defaultBlocks.content, props: { ...defaultBlocks.content.props, style: { background: 'white', borderRadius: '16px', padding: '24px', boxShadow: '0 10px 30px rgba(0,0,0,0.05)', width: 'calc(100% - 48px)', margin: '0 auto', marginTop: '24px', border: '0.5px solid rgb(0, 0, 0)', }, }, }, }, blockOrder: defaultBlockOrder, })} </ListOrderTable> ); }
π§ Props Referenceβ
Main Component Propsβ
| Prop | Type | Default | Description |
|---|---|---|---|
listOrderTableTitle | ReactNode | Required | Title for the order table section |
labels | TableLabels | Required | Labels object for table headers, actions, and messages |
isLoading | boolean | undefined | Whether the table is currently loading |
onNavigate | (to: string) => void | Required | Callback function for navigation |
onOrderAccepted | (id: string, title?: string) => void | Required | Callback function when order is accepted |
onOrderRejected | (id: string, title?: string) => void | Required | Callback function when order is rejected |
onOrderProcessing | (id: string, title?: string) => void | Required | Callback function when order is marked as processing |
data | ListOrderTableRowData[] | Required | Array of order data objects |
rowHref | (row: ListOrderTableRowData) => string | Required | Function to generate row link URLs |
updateRowHref | (row: ListOrderTableRowData) => string | Required | Function to generate update row link URLs |
tabs | TabData[] | Required | Array of tab configuration objects |
currentTab | string | undefined | Currently active tab identifier |
onTabChange | (tab: string) => void | undefined | Callback function when tab is changed |
createHref | string | Required | URL for creating new orders |
pagination | {currentPage: number; onPageChange: (page: number) => void; totalPages: number} | undefined | Pagination configuration object |
className | string | undefined | Additional CSS class name for styling the container |
children | BlocksOverride | undefined | Function to override default blocks or custom component rendering |
Note: The main component inherits MUI Stack props.
Sub-Componentsβ
The ListOrderTable component provides several sub-components. All sub-components receive their default values from the main component's context and can override these values through props.
ListOrderTable.Titleβ
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | From context | Title content - overrides listOrderTableTitle from context |
listOrderTableTitle | ReactNode | From context | Title text when children not provided |
variant | TypographyProps['variant'] | "h4" | MUI Typography variant |
component | ElementType | "h1" | HTML element to render |
className | string | undefined | Additional CSS class name for styling |
Note: This component inherits all MUI Typography props.
ListOrderTable.Actionβ
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | undefined | Custom content to override default action rendering |
createHref | string | From context | URL for the create action button |
labels | TableLabels | From context | Labels for action text |
onNavigate | (to: string) => void | From context | Navigation callback for the create button |
className | string | undefined | Additional CSS class name for styling |
Note: This component inherits MUI Stack props (except direction which is fixed to "row").
ListOrderTable.Headerβ
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | undefined | Custom content to override default header rendering |
className | string | undefined | Additional CSS class name for styling |
Note: This component inherits MUI Stack props. Default layout is direction="row" with justifyContent: 'space-between' and alignItems: 'center'.
ListOrderTable.Loaderβ
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | CircularProgress | Custom loading indicator content |
className | string | undefined | Additional CSS class name for styling |
Note: This component inherits MUI Stack props. Default alignment is alignItems: 'center'.
ListOrderTable.Contentβ
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | undefined | Custom content to override default content rendering |
isLoading | boolean | From context | Loading state from context |
className | string | undefined | Additional CSS class name for styling |
Note: This component inherits MUI Box props. When not using custom children and not loading, it renders Tabs and Table in a Stack with spacing={3}.
ListOrderTable.Tabsβ
| Prop | Type | Default | Description |
|---|---|---|---|
tabs | TabData[] | From context | Array of tab configuration objects |
currentTab | string | From context | Currently active tab label |
onTabChange | (tab: string) => void | From context | Tab change callback function |
className | string | undefined | Additional CSS class name for styling |
Note: This component inherits MUI Tabs props (except value, onChange, and variant which are managed internally). Uses variant="fullWidth" by default.
ListOrderTable.Tableβ
| Prop | Type | Default | Description |
|---|---|---|---|
labels | TableLabels | From context | Labels object for table headers, actions, and messages |
data | ListOrderTableRowData[] | From context | Array of table data |
rowHref | (row: ListOrderTableRowData) => string | From context | Function to generate row link URLs |
onNavigate | (to: string) => void | From context | Navigation callback for row clicks |
onOrderAccepted | DropdownItemAction | From context | Callback when order is accepted |
onOrderRejected | DropdownItemAction | From context | Callback when order is rejected |
onOrderProcessing | DropdownItemAction | From context | Callback when order is marked as processing |
pagination | PaginationProps | From context | Pagination configuration object |
spacing | number | 3 | Stack spacing between elements |
className | string | undefined | Additional CSS class name for styling |
Note: This component inherits MUI Stack props.
π¨ Configuration examplesβ
Custom Header Stylingβ
<ListOrderTable.Header
sx={{
bgcolor: 'primary.light',
borderRadius: 2,
p: 2
}}
/>
Custom Title Stylingβ
<ListOrderTable.Title
variant="h3"
component="h2"
sx={{ color: 'primary.main', fontWeight: 700 }}
/>
Custom Action Buttonβ
<ListOrderTable.Action>
<Button variant="outlined" startIcon={<Add />}>
Custom Create Button
</Button>
</ListOrderTable.Action>
Custom Table Stylingβ
<ListOrderTable.Table
sx={{
'& .MuiTableCell-root': {
borderBottom: '2px solid',
borderColor: 'divider'
}
}}
/>
Using Block Override Patternβ
<ListOrderTable {...props}>
{({defaultBlocks, defaultBlockOrder}) => ({
blocks: {
header: {
...defaultBlocks.header,
props: {
...defaultBlocks.header.props,
sx: {background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)'},
},
},
},
blockOrder: defaultBlockOrder,
})}
</ListOrderTable>
π§ TypeScript Supportβ
Full TypeScript support with comprehensive type definitions:
import {ListOrderTable} from '@nodeblocks/frontend-list-order-table-block';
import {Stack} from '@mui/material';
import {ComponentProps, ReactNode} from 'react';
// Tab data interface
interface TabData {
key?: string;
label: string;
isDisabled?: boolean;
subtitle?: string;
}
// Main component interface
interface ListOrderTableProps<Tabs extends TabData[]> extends Omit<ComponentProps<typeof Stack>, 'children'> {
listOrderTableTitle: ReactNode;
labels: TableLabels;
isLoading?: boolean;
onNavigate: (to: string) => void;
onOrderAccepted: DropdownItemAction;
onOrderRejected: DropdownItemAction;
onOrderProcessing: DropdownItemAction;
data: ListOrderTableRowData[];
rowHref: (row: ListOrderTableRowData) => string;
updateRowHref: (row: ListOrderTableRowData) => string;
tabs: Tabs;
currentTab?: Tabs[number]['label'];
onTabChange?: (tab: Tabs[number]['label']) => void;
createHref: string;
pagination?: PaginationProps;
children?: BlocksOverride;
}
// Row data interface
export interface ListOrderTableRowData {
createdAt: string;
id: string;
orderName: string;
title: string;
status: string;
}
// Action callback type
export type DropdownItemAction = (
order: ListOrderTableRowData['id'],
title?: ListOrderTableRowData['title'],
) => void;
// Pagination props interface
export interface PaginationProps {
className?: string;
currentPage: number;
onPageChange: (page: number) => void;
totalPages: number;
}
// Labels interface
interface TableLabels {
emptyStateMessage: string;
actions?: {
headerAction: string;
};
headerRow: {
createdAt: string;
title: string;
orderName: string;
};
rowActions: {
canceled: string;
processing: string;
accepted: string;
};
}
// Usage example with full typing
function TypedListOrderTableExample() {
const [currentTab, setCurrentTab] = useState('pending');
const [isLoading] = useState(false);
const orders: ListOrderTableRowData[] = [
{
createdAt: '2024-01-15T10:30:00Z',
id: '1',
orderName: 'ORD-001',
title: 'Order Title',
status: 'pending',
},
];
const tableTabs: TabData[] = [
{label: 'Pending', key: 'pending'},
{label: 'Accepted', key: 'accepted'},
{label: 'Rejected', key: 'rejected'},
];
const tableLabels: TableLabels = {
emptyStateMessage: 'No orders available',
actions: {headerAction: 'New Order'},
headerRow: {
createdAt: 'Date Created',
title: 'Order Title',
orderName: 'Order Number',
},
rowActions: {
accepted: 'Accept',
canceled: 'Reject',
processing: 'Process',
},
};
const onAcceptOrder: DropdownItemAction = (id, title) => {
console.log('Accept order:', id, title);
};
const onRejectOrder: DropdownItemAction = (id, title) => {
console.log('Reject order:', id, title);
};
const onProcessOrder: DropdownItemAction = (id, title) => {
console.log('Process order:', id, title);
};
return (
<ListOrderTable
listOrderTableTitle="Orders Dashboard"
labels={tableLabels}
isLoading={isLoading}
onNavigate={path => console.log('Navigate:', path)}
onOrderAccepted={onAcceptOrder}
onOrderRejected={onRejectOrder}
onOrderProcessing={onProcessOrder}
data={orders}
rowHref={row => `/orders/${row.id}`}
updateRowHref={row => `/orders/${row.id}/edit`}
tabs={tableTabs}
currentTab={currentTab}
onTabChange={setCurrentTab}
createHref="#orders/create"
>
<ListOrderTable.Header />
<ListOrderTable.Content />
<ListOrderTable.Table />
</ListOrderTable>
);
}
π Notesβ
- The root component uses MUI's
Stackwith defaultspacing={3}andsx={{ p: 3 }}padding - Dates are formatted using the
luxonlibrary with formatyyyy/M/d HH:mm - Row titles have a tooltip showing full datetime on hover
- The table uses MUI
Table,TableContainer,TableHead,TableBody, andTableRowcomponents - Row actions are displayed in a dropdown menu using MUI
MenuandMenuItemcomponents with icons - The
Tabscomponent returnsnullif no tabs are provided or tabs array is empty - Empty state displays a
Personicon with theemptyStateMessagefrom labels - Pagination uses MUI
Paginationcomponent withvariant="outlined"andshape="rounded" - Table rows are clickable when
rowHrefreturns a valid URL (cursor changes to pointer) - All sub-components inherit MUI component props and support the
sxprop for styling - Block override pattern allows customizing, replacing, or reordering default blocks
Built with β€οΈ using React, TypeScript, and MUI.