- deal-dashboard: Overview stats, won/lost ratio, revenue forecast - deal-detail: Full deal with products, activities, participants, timeline - deal-grid: Sortable deal list with filters - pipeline-kanban: Drag-drop pipeline board - pipeline-analytics: Conversion rates, velocity, bottleneck analysis - pipeline-funnel: Visual funnel with stage metrics - person-detail: Contact card with deals, activities, files - person-grid: Contact directory with search - org-detail: Organization with people, deals, activities - org-grid: Organization directory - activity-dashboard: Activity calendar/list with completion tracking - activity-calendar: Monthly calendar view - lead-inbox: Lead list with labels and quick actions - product-catalog: Product list with pricing - goal-tracker: Goals with progress bars - revenue-dashboard: Revenue analytics, forecasting - email-inbox: Mail threads with preview - deals-timeline: Timeline of deal progression - search-results: Universal search - won-deals: Closed-won deals celebration view All apps use React with dark theme. Self-contained with inline shared components. Each app has App.tsx, index.html, and vite.config.ts. Ports 3000-3019 for dev servers.
143 lines
3.9 KiB
TypeScript
143 lines
3.9 KiB
TypeScript
import React, { useState } from 'react';
|
|
|
|
interface Order {
|
|
id: number;
|
|
customer: string;
|
|
date: string;
|
|
status: string;
|
|
total: number;
|
|
items: number;
|
|
}
|
|
|
|
export default function OrderGrid() {
|
|
const [orders] = useState<Order[]>([
|
|
{ id: 1001, customer: 'John Doe', date: '2024-01-15', status: 'Completed', total: 159.99, items: 3 },
|
|
{ id: 1002, customer: 'Jane Smith', date: '2024-01-16', status: 'Processing', total: 89.50, items: 2 },
|
|
{ id: 1003, customer: 'Bob Johnson', date: '2024-01-16', status: 'Shipped', total: 249.99, items: 5 },
|
|
{ id: 1004, customer: 'Alice Brown', date: '2024-01-17', status: 'Pending', total: 45.00, items: 1 },
|
|
{ id: 1005, customer: 'Charlie Wilson', date: '2024-01-17', status: 'Completed', total: 189.99, items: 4 },
|
|
{ id: 1006, customer: 'Diana Martinez', date: '2024-01-18', status: 'Processing', total: 129.50, items: 3 },
|
|
]);
|
|
|
|
const getStatusColor = (status: string) => {
|
|
const colors: Record<string, string> = {
|
|
Completed: '#10b981',
|
|
Processing: '#3b82f6',
|
|
Shipped: '#8b5cf6',
|
|
Pending: '#f59e0b',
|
|
};
|
|
return colors[status] || '#6b7280';
|
|
};
|
|
|
|
return (
|
|
<div style={styles.container}>
|
|
<h1 style={styles.title}>Order Grid</h1>
|
|
|
|
<div style={styles.grid}>
|
|
{orders.map(order => (
|
|
<div key={order.id} style={styles.card}>
|
|
<div style={styles.cardHeader}>
|
|
<span style={styles.orderId}>#{order.id}</span>
|
|
<span style={{
|
|
...styles.badge,
|
|
backgroundColor: `${getStatusColor(order.status)}33`,
|
|
color: getStatusColor(order.status)
|
|
}}>
|
|
{order.status}
|
|
</span>
|
|
</div>
|
|
<div style={styles.cardBody}>
|
|
<div style={styles.infoRow}>
|
|
<span style={styles.label}>Customer:</span>
|
|
<span style={styles.value}>{order.customer}</span>
|
|
</div>
|
|
<div style={styles.infoRow}>
|
|
<span style={styles.label}>Date:</span>
|
|
<span style={styles.value}>{order.date}</span>
|
|
</div>
|
|
<div style={styles.infoRow}>
|
|
<span style={styles.label}>Items:</span>
|
|
<span style={styles.value}>{order.items}</span>
|
|
</div>
|
|
</div>
|
|
<div style={styles.cardFooter}>
|
|
<span style={styles.total}>${order.total.toFixed(2)}</span>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const styles: Record<string, React.CSSProperties> = {
|
|
container: {
|
|
padding: '2rem',
|
|
backgroundColor: '#111827',
|
|
minHeight: '100vh',
|
|
color: '#f9fafb',
|
|
fontFamily: 'system-ui, -apple-system, sans-serif',
|
|
},
|
|
title: {
|
|
fontSize: '2rem',
|
|
fontWeight: 'bold',
|
|
marginBottom: '2rem',
|
|
color: '#f9fafb',
|
|
},
|
|
grid: {
|
|
display: 'grid',
|
|
gridTemplateColumns: 'repeat(auto-fill, minmax(300px, 1fr))',
|
|
gap: '1.5rem',
|
|
},
|
|
card: {
|
|
backgroundColor: '#1f2937',
|
|
borderRadius: '0.5rem',
|
|
border: '1px solid #374151',
|
|
overflow: 'hidden',
|
|
},
|
|
cardHeader: {
|
|
display: 'flex',
|
|
justifyContent: 'space-between',
|
|
alignItems: 'center',
|
|
padding: '1rem',
|
|
backgroundColor: '#374151',
|
|
},
|
|
orderId: {
|
|
fontWeight: 'bold',
|
|
fontSize: '1.125rem',
|
|
color: '#f9fafb',
|
|
},
|
|
badge: {
|
|
padding: '0.25rem 0.75rem',
|
|
borderRadius: '9999px',
|
|
fontSize: '0.75rem',
|
|
fontWeight: '500',
|
|
},
|
|
cardBody: {
|
|
padding: '1rem',
|
|
},
|
|
infoRow: {
|
|
display: 'flex',
|
|
justifyContent: 'space-between',
|
|
marginBottom: '0.5rem',
|
|
},
|
|
label: {
|
|
color: '#9ca3af',
|
|
fontSize: '0.875rem',
|
|
},
|
|
value: {
|
|
color: '#d1d5db',
|
|
fontSize: '0.875rem',
|
|
},
|
|
cardFooter: {
|
|
padding: '1rem',
|
|
borderTop: '1px solid #374151',
|
|
textAlign: 'right',
|
|
},
|
|
total: {
|
|
fontSize: '1.5rem',
|
|
fontWeight: 'bold',
|
|
color: '#3b82f6',
|
|
},
|
|
};
|