List Order Block
The ListOrder Component is a fully customizable and accessible order list interface built with React and TypeScript. It provides a complete order listing experience with modern design patterns, clickable order cards, loading states, pagination support, and flexible customization options for order management applications.
🚀 Installation
npm install @nodeblocks/frontend-list-order-block@0.1.1
📖 Usage
import {ListOrder} from '@nodeblocks/frontend-list-order-block';
- Basic Usage
- Advanced Usage
function BasicListOrder() {
const [orders, setOrders] = useState([
{
id: '1',
logoUrl: '/img/icon-small.png',
title: 'Office Supplies Order',
subtitle: 'ABC Company',
date: '2024-01-15',
status: 'completed',
statusLabel: 'Completed',
},
{
id: '2',
logoUrl: '/img/icon-small.png',
title: 'Software License',
subtitle: 'Tech Corp',
date: '2024-01-14',
status: 'pending',
statusLabel: 'Pending',
},
]);
const [hasMore, setHasMore] = useState(true);
const [isLoading, setIsLoading] = useState(false);
const handleOrderClick = order => {
console.log('Order clicked:', order);
// Handle order navigation
};
const handleLoadMore = () => {
setIsLoading(true);
// Load more orders logic
setTimeout(() => {
setIsLoading(false);
setOrders([...orders, ...orders]);
setHasMore(false);
}, 1000);
};
return (
<ListOrder
orders={orders}
hasMore={hasMore}
onClickOrder={handleOrderClick}
onClickLoadMore={handleLoadMore}
isLoadingList={isLoading}>
<ListOrder.OrderListSection />
<ListOrder.OrderLoadingCircle />
<ListOrder.LoadMoreButton />
</ListOrder>
);
}
function AdvancedOrderList() {
const [orders, setOrders] = useState([
{
id: '1',
logoUrl: '/img/icon-small.png',
title: '🛒 Premium Enterprise Package',
subtitle: '💼 Global Tech Solutions',
date: '2024-01-15',
status: 'completed',
statusLabel: '✅ Delivered',
},
{
id: '2',
logoUrl: '/img/icon-small.png',
title: '💻 Software License Bundle',
subtitle: '🚀 Innovation Corp',
date: '2024-01-14',
status: 'processing',
statusLabel: '⚡ Processing',
},
{
id: '3',
logoUrl: '/img/icon-small.png',
title: '🔧 Hardware Maintenance Kit',
subtitle: '🏢 Enterprise Systems',
date: '2024-01-13',
status: 'pending',
statusLabel: '⏳ Pending Approval',
},
{
id: '4',
logoUrl: '/img/icon-small.png',
title: '📊 Analytics Dashboard Pro',
subtitle: '📈 Data Insights Ltd',
date: '2024-01-12',
status: 'completed',
statusLabel: '🎉 Successfully Delivered',
},
]);
const [hasMore, setHasMore] = useState(true);
const [isLoading, setIsLoading] = useState(false);
const handleOrderClick = order => {
console.log('Premium order selected:', order.title);
};
const handleLoadMore = () => {
setIsLoading(true);
setTimeout(() => {
setIsLoading(false);
setOrders([...orders, ...orders.map(order => ({...order, id: order.id + '_new'}))]);
setHasMore(false);
}, 1000);
};
return (
<ListOrder
orders={orders}
hasMore={hasMore}
onClickOrder={handleOrderClick}
onClickLoadMore={handleLoadMore}
isLoadingList={isLoading}
>
{({defaultBlocks, defaultBlockOrder}) => ({
blocks: {
// Enhanced order list section with modern styling
orderListSection: (
<>
{orders.map(order => (
<div
key={order.id}
onClick={() => handleOrderClick(order)}
style={{
width: '100%',
background: 'rgba(255, 255, 255, 0.95)',
borderRadius: '16px',
padding: '24px',
cursor: 'pointer',
boxShadow: '0 8px 25px rgba(0,0,0,0.08)',
border: '1px solid rgba(255,255,255,0.2)',
backdropFilter: 'blur(10px)',
transition: 'all 0.3s ease',
position: 'relative',
overflow: 'hidden',
}}
onMouseEnter={e => {
e.target.style.transform = 'translateY(-5px)';
e.target.style.boxShadow = '0 15px 40px rgba(0,0,0,0.12)';
}}
onMouseLeave={e => {
e.target.style.transform = 'translateY(0)';
e.target.style.boxShadow = '0 8px 25px rgba(0,0,0,0.08)';
}}
>
{/* Header Section */}
<div
style={{
display: 'flex',
alignItems: 'center',
marginBottom: '16px',
paddingRight: '60px',
}}
>
<img
src={order.logoUrl}
alt="Order Logo"
style={{
width: '48px',
height: '48px',
borderRadius: '12px',
marginRight: '16px',
objectFit: 'cover',
border: '2px solid rgba(105, 124, 213, 0.2)',
}}
/>
<div style={{flex: 1}}>
<h3
style={{
margin: '0 0 4px 0',
fontSize: '18px',
fontWeight: 'bold',
color: '#2c3e50',
lineHeight: '1.3',
}}
>
{order.title}
</h3>
<p
style={{
margin: 0,
fontSize: '14px',
color: '#7f8c8d',
fontWeight: '500',
}}
>
{order.subtitle}
</p>
</div>
</div>
{/* Status Badge */}
<div
style={{
marginTop: '16px',
marginBottom: '16px',
background:
order.status === 'completed'
? 'linear-gradient(135deg, #4CAF50, #45a049)'
: order.status === 'processing'
? 'linear-gradient(135deg, #FF9800, #F57C00)'
: 'linear-gradient(135deg, #2196F3, #1976D2)',
color: 'white',
padding: '6px 12px',
borderRadius: '20px',
fontSize: '12px',
fontWeight: 'bold',
boxShadow: '0 4px 12px rgba(0,0,0,0.15)',
}}
>
{order.statusLabel}
</div>
{/* Content Section */}
<div
style={{
background: 'rgba(105, 124, 213, 0.05)',
borderRadius: '12px',
padding: '16px',
marginBottom: '16px',
}}
>
<div
style={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
}}
>
<div>
<span
style={{
fontSize: '12px',
color: '#95a5a6',
textTransform: 'uppercase',
fontWeight: 'bold',
letterSpacing: '0.5px',
}}
>
Order Date
</span>
<div
style={{
fontSize: '16px',
fontWeight: 'bold',
color: '#34495e',
marginTop: '4px',
}}
>
{order.date}
</div>
</div>
<div
style={{
width: '40px',
height: '40px',
background: 'linear-gradient(135deg, rgb(105, 124, 213), rgb(85, 104, 193))',
borderRadius: '50%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
color: 'white',
fontSize: '18px',
}}
>
{order.status === 'completed' ? '✅' : order.status === 'processing' ? '⚡' : '⏳'}
</div>
</div>
</div>
{/* Action Footer */}
<div
style={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
paddingTop: '8px',
borderTop: '1px solid rgba(0,0,0,0.05)',
}}
>
<span
style={{
fontSize: '12px',
color: '#95a5a6',
fontWeight: '500',
}}
>
ID: {order.id}
</span>
<div
style={{
color: 'rgb(105, 124, 213)',
fontSize: '14px',
fontWeight: 'bold',
display: 'flex',
alignItems: 'center',
gap: '4px',
}}
>
View Details →
</div>
</div>
</div>
))}
</>
),
// Enhanced loading indicator
orderLoadingCircle: {
...defaultBlocks.orderLoadingCircle,
props: {
...defaultBlocks.orderLoadingCircle.props,
style: {
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
padding: '20px',
},
},
},
// Enhanced load more button
loadMoreButton: {
...defaultBlocks.loadMoreButton,
props: {
...defaultBlocks.loadMoreButton.props,
style: {
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
color: 'white',
border: 'none',
borderRadius: '50px',
padding: '16px 32px',
fontSize: '16px',
fontWeight: 'bold',
cursor: 'pointer',
boxShadow: '0 8px 16px rgba(102, 126, 234, 0.3)',
margin: '0 auto',
display: 'block',
transform: 'scale(1)',
transition: 'all 0.2s ease',
},
children: '🔄 Load More Premium Orders',
},
},
},
blockOrder: defaultBlockOrder,
})}
</ListOrder>
);
}
🔧 Props Reference
Main Component Props
| Prop | Type | Default | Description |
|---|---|---|---|
orders | Order[] | Required | Array of order objects to display |
hasMore | boolean | Required | Whether there are more orders to load |
onClickOrder | (order: Order) => void | undefined | Callback function triggered when an order is clicked |
onClickLoadMore | () => void | undefined | Callback function triggered when load more button is clicked |
isLoadingList | boolean | undefined | Whether the list is currently loading |
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 all HTML div element props.
Sub-Components
The ListOrder 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.
ListOrder.OrderListSection
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | undefined | Custom content to override default order list rendering |
className | string | undefined | Additional CSS class name for styling |
orders | Order[] | From context | Array of orders to display |
onClickOrder | (order: Order) => void | From context | Callback function for order click events |
Note: This component inherits all HTML div element props.
ListOrder.OrderCard
| Prop | Type | Default | Description |
|---|---|---|---|
order | Order | Required | Order object to display |
className | string | undefined | Additional CSS class name for styling |
onClick | () => void | undefined | Custom click handler for the order card |
children | ReactNode | undefined | Custom content to override default card rendering |
Note: This component inherits all HTML div element props.
ListOrder.OrderLogo
| Prop | Type | Default | Description |
|---|---|---|---|
src | string | Required | URL of the organization logo |
alt | string | "Organization Logo" | Alternative text for the logo image |
className | string | undefined | Additional CSS class name for styling |
Note: This component inherits all HTML img element props.
ListOrder.OrderTitle
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | Required | Title text for the order |
className | string | undefined | Additional CSS class name for styling |
Note: This component inherits all HTML h3 element props.
ListOrder.OrderSubtitle
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | Required | Subtitle text for the order (typically organization name) |
className | string | undefined | Additional CSS class name for styling |
Note: This component inherits all HTML h4 element props.
ListOrder.OrderDate
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | Required | Date text for the order |
className | string | undefined | Additional CSS class name for styling |
Note: This component inherits all HTML div element props.
ListOrder.OrderLoadingCircle
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | Default loading circle | Custom loading indicator content |
className | string | undefined | Additional CSS class name for styling |
width | string | "100" | Width of the loading circle |
height | string | "100" | Height of the loading circle |
Note: This component inherits all HTML svg element props.
ListOrder.LoadMoreButton
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | "Read More" | Button text content |
className | string | undefined | Additional CSS class name for styling |
hasMore | boolean | From context | Whether more items are available to load |
onClickLoadMore | () => void | From context | Function to load more orders |
onClick | () => void | undefined | Custom click handler for the button |
disabled | boolean | Based on loading state | Whether the button is disabled |
Note: This component inherits all HTML button element props.
🔧 TypeScript Support
Full TypeScript support with comprehensive type definitions:
import {ListOrder} from '@nodeblocks/frontend-list-order-block';
import {ComponentProps} from 'react';
// Order data interface
export type Order = {
id: string;
logoUrl: string;
title: string;
subtitle: string;
date: string;
status: string;
statusLabel: string;
};
// Main component interface
interface ListOrderProps extends Omit<ComponentProps<'div'>, 'children'> {
orders: Order[];
hasMore: boolean;
onClickOrder?: (order: Order) => void;
onClickLoadMore?: () => void;
isLoadingList?: boolean;
className?: string;
}
// Usage example with full typing
interface CustomOrderListProps {
orderData: Order[];
onOrderSelect: (order: Order) => void;
loadMoreOrders: () => void;
hasMoreData: boolean;
isLoading: boolean;
}
const OrderListComponent = ({
orderData,
onOrderSelect,
loadMoreOrders,
hasMoreData,
isLoading,
}: CustomOrderListProps) => {
return (
<ListOrder
orders={orderData}
hasMore={hasMoreData}
onClickOrder={onOrderSelect}
onClickLoadMore={loadMoreOrders}
isLoadingList={isLoading}>
<ListOrder.OrderListSection />
<ListOrder.OrderLoadingCircle />
<ListOrder.LoadMoreButton />
</ListOrder>
);
};
Built with ❤️ using React, TypeScript, and modern web standards.