@fayz-ai/plugin-orders 0.9.0 → 0.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/{OrdersPage-KKQCTFCN.js → OrdersPage-YTSYE573.js} +3 -3
- package/dist/OrdersPage-YTSYE573.js.map +1 -0
- package/dist/{OrdersContext.d.ts → context.d.ts} +2 -2
- package/dist/context.d.ts.map +1 -0
- package/dist/data/registries.d.ts.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/{OrdersPage.d.ts → views/OrdersPage.d.ts} +3 -3
- package/dist/views/OrdersPage.d.ts.map +1 -0
- package/package.json +5 -7
- package/dist/OrdersContext.d.ts.map +0 -1
- package/dist/OrdersPage-KKQCTFCN.js.map +0 -1
- package/dist/OrdersPage.d.ts.map +0 -1
- package/dist/registries.d.ts.map +0 -1
- package/src/OrdersContext.tsx +0 -47
- package/src/OrdersPage.tsx +0 -20
- package/src/data/mock.ts +0 -512
- package/src/data/platform.ts +0 -456
- package/src/data/types.ts +0 -23
- package/src/index.ts +0 -224
- package/src/locales/en.ts +0 -53
- package/src/locales/index.ts +0 -4
- package/src/locales/pt-BR.ts +0 -53
- package/src/registries.ts +0 -32
- package/src/store.ts +0 -191
- package/src/types.ts +0 -190
- package/src/views/OrderKanbanView.tsx +0 -240
- /package/dist/{registries.d.ts → data/registries.d.ts} +0 -0
package/src/locales/en.ts
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
export const en: Record<string, string> = {
|
|
2
|
-
'orders.title': 'Orders',
|
|
3
|
-
'orders.nav.kanban': 'Orders',
|
|
4
|
-
'orders.nav.list': 'History',
|
|
5
|
-
'orders.nav.new': 'New Order',
|
|
6
|
-
'orders.nav.dashboard': 'Dashboard',
|
|
7
|
-
'orders.kanban.title': 'Orders',
|
|
8
|
-
'orders.kanban.subtitle': 'Active orders',
|
|
9
|
-
'orders.kanban.noOrders': 'No active orders',
|
|
10
|
-
'orders.kanban.noOrdersDesc': 'Orders will appear here as they come in',
|
|
11
|
-
'orders.kanban.newOrder': 'New Order',
|
|
12
|
-
'orders.kanban.advance': 'Advance',
|
|
13
|
-
'orders.kanban.cancel': 'Cancel Order',
|
|
14
|
-
'orders.kanban.column.new': 'New',
|
|
15
|
-
'orders.kanban.column.confirmed': 'Confirmed',
|
|
16
|
-
'orders.kanban.column.preparing': 'Preparing',
|
|
17
|
-
'orders.kanban.column.ready': 'Ready',
|
|
18
|
-
'orders.kanban.column.out': 'Out',
|
|
19
|
-
'orders.kanban.column.completed': 'Completed',
|
|
20
|
-
'orders.kanban.column.cancelled': 'Cancelled',
|
|
21
|
-
'orders.detail.title': 'Order Details',
|
|
22
|
-
'orders.detail.items': 'Items',
|
|
23
|
-
'orders.detail.table': 'Table',
|
|
24
|
-
'orders.detail.customer': 'Customer',
|
|
25
|
-
'orders.detail.waiter': 'Waiter',
|
|
26
|
-
'orders.detail.source': 'Source',
|
|
27
|
-
'orders.detail.subtotal': 'Subtotal',
|
|
28
|
-
'orders.detail.discount': 'Discount',
|
|
29
|
-
'orders.detail.tax': 'Tax',
|
|
30
|
-
'orders.detail.total': 'Total',
|
|
31
|
-
'orders.detail.notes': 'Notes',
|
|
32
|
-
'orders.newOrder.title': 'New Order',
|
|
33
|
-
'orders.newOrder.selectKind': 'Order type',
|
|
34
|
-
'orders.newOrder.dineIn': 'Dine-in',
|
|
35
|
-
'orders.newOrder.takeout': 'Takeout',
|
|
36
|
-
'orders.newOrder.delivery': 'Delivery',
|
|
37
|
-
'orders.newOrder.selectTable': 'Select table',
|
|
38
|
-
'orders.newOrder.addItems': 'Add items',
|
|
39
|
-
'orders.newOrder.searchItems': 'Search menu...',
|
|
40
|
-
'orders.newOrder.noItems': 'No items added yet',
|
|
41
|
-
'orders.newOrder.confirm': 'Place Order',
|
|
42
|
-
'orders.newOrder.cancel': 'Cancel',
|
|
43
|
-
'orders.list.title': 'Order History',
|
|
44
|
-
'orders.list.subtitle': 'All orders',
|
|
45
|
-
'orders.list.search': 'Search orders...',
|
|
46
|
-
'orders.list.noOrders': 'No orders found',
|
|
47
|
-
'orders.source.dine_in': 'Dine-in',
|
|
48
|
-
'orders.source.takeout': 'Takeout',
|
|
49
|
-
'orders.source.ifood': 'iFood',
|
|
50
|
-
'orders.source.99food': '99Food',
|
|
51
|
-
'orders.source.delivery': 'Delivery',
|
|
52
|
-
'orders.settings.title': 'Orders Settings',
|
|
53
|
-
}
|
package/src/locales/index.ts
DELETED
package/src/locales/pt-BR.ts
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
export const ptBR: Record<string, string> = {
|
|
2
|
-
'orders.title': 'Pedidos',
|
|
3
|
-
'orders.nav.kanban': 'Pedidos',
|
|
4
|
-
'orders.nav.list': 'Histórico',
|
|
5
|
-
'orders.nav.new': 'Novo Pedido',
|
|
6
|
-
'orders.nav.dashboard': 'Painel',
|
|
7
|
-
'orders.kanban.title': 'Pedidos',
|
|
8
|
-
'orders.kanban.subtitle': 'Pedidos ativos',
|
|
9
|
-
'orders.kanban.noOrders': 'Nenhum pedido ativo',
|
|
10
|
-
'orders.kanban.noOrdersDesc': 'Os pedidos aparecerão aqui conforme chegarem',
|
|
11
|
-
'orders.kanban.newOrder': 'Novo Pedido',
|
|
12
|
-
'orders.kanban.advance': 'Avançar',
|
|
13
|
-
'orders.kanban.cancel': 'Cancelar Pedido',
|
|
14
|
-
'orders.kanban.column.new': 'Novo',
|
|
15
|
-
'orders.kanban.column.confirmed': 'Confirmado',
|
|
16
|
-
'orders.kanban.column.preparing': 'Preparando',
|
|
17
|
-
'orders.kanban.column.ready': 'Pronto',
|
|
18
|
-
'orders.kanban.column.out': 'Saiu',
|
|
19
|
-
'orders.kanban.column.completed': 'Concluído',
|
|
20
|
-
'orders.kanban.column.cancelled': 'Cancelado',
|
|
21
|
-
'orders.detail.title': 'Detalhes do Pedido',
|
|
22
|
-
'orders.detail.items': 'Itens',
|
|
23
|
-
'orders.detail.table': 'Mesa',
|
|
24
|
-
'orders.detail.customer': 'Cliente',
|
|
25
|
-
'orders.detail.waiter': 'Garçom',
|
|
26
|
-
'orders.detail.source': 'Origem',
|
|
27
|
-
'orders.detail.subtotal': 'Subtotal',
|
|
28
|
-
'orders.detail.discount': 'Desconto',
|
|
29
|
-
'orders.detail.tax': 'Imposto',
|
|
30
|
-
'orders.detail.total': 'Total',
|
|
31
|
-
'orders.detail.notes': 'Observações',
|
|
32
|
-
'orders.newOrder.title': 'Novo Pedido',
|
|
33
|
-
'orders.newOrder.selectKind': 'Tipo de pedido',
|
|
34
|
-
'orders.newOrder.dineIn': 'Mesa',
|
|
35
|
-
'orders.newOrder.takeout': 'Para Viagem',
|
|
36
|
-
'orders.newOrder.delivery': 'Delivery',
|
|
37
|
-
'orders.newOrder.selectTable': 'Selecionar mesa',
|
|
38
|
-
'orders.newOrder.addItems': 'Adicionar itens',
|
|
39
|
-
'orders.newOrder.searchItems': 'Buscar no cardápio...',
|
|
40
|
-
'orders.newOrder.noItems': 'Nenhum item adicionado',
|
|
41
|
-
'orders.newOrder.confirm': 'Fazer Pedido',
|
|
42
|
-
'orders.newOrder.cancel': 'Cancelar',
|
|
43
|
-
'orders.list.title': 'Histórico de Pedidos',
|
|
44
|
-
'orders.list.subtitle': 'Todos os pedidos',
|
|
45
|
-
'orders.list.search': 'Buscar pedidos...',
|
|
46
|
-
'orders.list.noOrders': 'Nenhum pedido encontrado',
|
|
47
|
-
'orders.source.dine_in': 'Mesa',
|
|
48
|
-
'orders.source.takeout': 'Para Viagem',
|
|
49
|
-
'orders.source.ifood': 'iFood',
|
|
50
|
-
'orders.source.99food': '99Food',
|
|
51
|
-
'orders.source.delivery': 'Delivery',
|
|
52
|
-
'orders.settings.title': 'Configurações de Pedidos',
|
|
53
|
-
}
|
package/src/registries.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import type { PluginRegistryDef } from '@fayz-ai/core'
|
|
2
|
-
import type { EntityDef } from '@fayz-ai/core'
|
|
3
|
-
|
|
4
|
-
const orderSourceEntity: EntityDef = {
|
|
5
|
-
name: 'Order Source',
|
|
6
|
-
namePlural: 'Order Sources',
|
|
7
|
-
icon: 'Globe',
|
|
8
|
-
displayField: 'name',
|
|
9
|
-
defaultSort: 'name',
|
|
10
|
-
fields: [
|
|
11
|
-
{ key: 'name', label: 'Name', type: 'text', required: true, showInTable: true },
|
|
12
|
-
{ key: 'icon', label: 'Icon', type: 'text', showInTable: true },
|
|
13
|
-
{ key: 'isActive', label: 'Active', type: 'boolean', showInTable: true, defaultValue: true },
|
|
14
|
-
],
|
|
15
|
-
data: { table: 'order_sources', tenantScoped: true },
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export const ordersRegistries: PluginRegistryDef[] = [
|
|
19
|
-
{
|
|
20
|
-
id: 'order-sources',
|
|
21
|
-
entity: orderSourceEntity,
|
|
22
|
-
icon: 'Globe',
|
|
23
|
-
description: 'Order sources and delivery platforms',
|
|
24
|
-
display: 'table',
|
|
25
|
-
seedData: [
|
|
26
|
-
{ id: 'os-dine', name: 'Dine-in', icon: '🍽️', isActive: true },
|
|
27
|
-
{ id: 'os-takeout', name: 'Takeout', icon: '🥡', isActive: true },
|
|
28
|
-
{ id: 'os-ifood', name: 'iFood', icon: '🔴', isActive: true },
|
|
29
|
-
{ id: 'os-99food', name: '99Food', icon: '🟡', isActive: true },
|
|
30
|
-
],
|
|
31
|
-
},
|
|
32
|
-
]
|
package/src/store.ts
DELETED
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
import { createStore, type StoreApi } from 'zustand/vanilla'
|
|
2
|
-
import { dedup } from '@fayz-ai/saas'
|
|
3
|
-
import { toast } from 'sonner'
|
|
4
|
-
import type { OrdersDataProvider } from './data/types'
|
|
5
|
-
import type {
|
|
6
|
-
RestaurantOrder, OrdersSummary,
|
|
7
|
-
OrderQuery, CreateOrderInput, CreateOrderItemInput,
|
|
8
|
-
UpdateOrderStatusInput,
|
|
9
|
-
} from './types'
|
|
10
|
-
import { getNextStatus } from './types'
|
|
11
|
-
|
|
12
|
-
// ---------------------------------------------------------------------------
|
|
13
|
-
// Store state
|
|
14
|
-
// ---------------------------------------------------------------------------
|
|
15
|
-
|
|
16
|
-
export interface OrdersUIState {
|
|
17
|
-
// Data cache
|
|
18
|
-
orders: RestaurantOrder[]
|
|
19
|
-
ordersTotal: number
|
|
20
|
-
ordersLoading: boolean
|
|
21
|
-
orderQuery: OrderQuery
|
|
22
|
-
|
|
23
|
-
activeOrders: RestaurantOrder[]
|
|
24
|
-
activeOrdersLoading: boolean
|
|
25
|
-
|
|
26
|
-
summary: OrdersSummary | null
|
|
27
|
-
summaryLoading: boolean
|
|
28
|
-
|
|
29
|
-
selectedOrderId: string | null
|
|
30
|
-
|
|
31
|
-
// Actions
|
|
32
|
-
fetchOrders(query: OrderQuery): Promise<void>
|
|
33
|
-
fetchActiveOrders(): Promise<void>
|
|
34
|
-
fetchSummary(dateRange?: { from: string; to: string }): Promise<void>
|
|
35
|
-
selectOrder(id: string | null): void
|
|
36
|
-
createOrder(input: CreateOrderInput): Promise<RestaurantOrder>
|
|
37
|
-
advanceOrderStatus(orderId: string): Promise<void>
|
|
38
|
-
updateOrderStatus(input: UpdateOrderStatusInput): Promise<void>
|
|
39
|
-
cancelOrder(id: string, reason?: string): Promise<void>
|
|
40
|
-
addOrderItem(orderId: string, item: CreateOrderItemInput): Promise<void>
|
|
41
|
-
removeOrderItem(itemId: string): Promise<void>
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// ---------------------------------------------------------------------------
|
|
45
|
-
// Store factory
|
|
46
|
-
// ---------------------------------------------------------------------------
|
|
47
|
-
|
|
48
|
-
export function createOrdersStore(provider: OrdersDataProvider): StoreApi<OrdersUIState> {
|
|
49
|
-
return createStore<OrdersUIState>((set, get) => ({
|
|
50
|
-
orders: [],
|
|
51
|
-
ordersTotal: 0,
|
|
52
|
-
ordersLoading: false,
|
|
53
|
-
orderQuery: {},
|
|
54
|
-
|
|
55
|
-
activeOrders: [],
|
|
56
|
-
activeOrdersLoading: false,
|
|
57
|
-
|
|
58
|
-
summary: null,
|
|
59
|
-
summaryLoading: false,
|
|
60
|
-
|
|
61
|
-
selectedOrderId: null,
|
|
62
|
-
|
|
63
|
-
async fetchOrders(query) {
|
|
64
|
-
return dedup('orders:list:' + JSON.stringify(query), async () => {
|
|
65
|
-
set({ ordersLoading: true, orderQuery: query })
|
|
66
|
-
const result = await provider.getOrders(query)
|
|
67
|
-
set({ orders: result.data, ordersTotal: result.total, ordersLoading: false })
|
|
68
|
-
})
|
|
69
|
-
},
|
|
70
|
-
|
|
71
|
-
async fetchActiveOrders() {
|
|
72
|
-
return dedup('orders:active', async () => {
|
|
73
|
-
set({ activeOrdersLoading: true })
|
|
74
|
-
const result = await provider.getOrders({
|
|
75
|
-
status: ['new', 'confirmed', 'preparing', 'ready'],
|
|
76
|
-
})
|
|
77
|
-
set({ activeOrders: result.data, activeOrdersLoading: false })
|
|
78
|
-
})
|
|
79
|
-
},
|
|
80
|
-
|
|
81
|
-
async fetchSummary(dateRange) {
|
|
82
|
-
return dedup('orders:summary', async () => {
|
|
83
|
-
set({ summaryLoading: true })
|
|
84
|
-
const summary = await provider.getSummary(dateRange)
|
|
85
|
-
set({ summary, summaryLoading: false })
|
|
86
|
-
})
|
|
87
|
-
},
|
|
88
|
-
|
|
89
|
-
selectOrder(id) {
|
|
90
|
-
set({ selectedOrderId: id })
|
|
91
|
-
},
|
|
92
|
-
|
|
93
|
-
async createOrder(input) {
|
|
94
|
-
try {
|
|
95
|
-
const order = await provider.createOrder(input)
|
|
96
|
-
const query = get().orderQuery
|
|
97
|
-
const [result, summary] = await Promise.all([
|
|
98
|
-
provider.getOrders(query),
|
|
99
|
-
provider.getSummary(),
|
|
100
|
-
])
|
|
101
|
-
set({ orders: result.data, ordersTotal: result.total, summary })
|
|
102
|
-
toast.success('Order created')
|
|
103
|
-
return order
|
|
104
|
-
} catch (err: any) {
|
|
105
|
-
toast.error('Failed to create order', { description: err?.message })
|
|
106
|
-
throw err
|
|
107
|
-
}
|
|
108
|
-
},
|
|
109
|
-
|
|
110
|
-
async advanceOrderStatus(orderId) {
|
|
111
|
-
try {
|
|
112
|
-
const { orders, activeOrders } = get()
|
|
113
|
-
const order = orders.find(o => o.id === orderId) ?? activeOrders.find(o => o.id === orderId)
|
|
114
|
-
if (!order) throw new Error('Order not found')
|
|
115
|
-
|
|
116
|
-
const nextStatus = getNextStatus(order.kind, order.status)
|
|
117
|
-
if (!nextStatus) throw new Error('No next status available')
|
|
118
|
-
|
|
119
|
-
await provider.updateOrderStatus({ orderId, status: nextStatus })
|
|
120
|
-
|
|
121
|
-
// Refresh active orders
|
|
122
|
-
const activeResult = await provider.getOrders({
|
|
123
|
-
status: ['new', 'confirmed', 'preparing', 'ready'],
|
|
124
|
-
})
|
|
125
|
-
set({ activeOrders: activeResult.data })
|
|
126
|
-
toast.success(`Order advanced to ${nextStatus.replace('_', ' ')}`)
|
|
127
|
-
} catch (err: any) {
|
|
128
|
-
toast.error('Failed to advance order', { description: err?.message })
|
|
129
|
-
throw err
|
|
130
|
-
}
|
|
131
|
-
},
|
|
132
|
-
|
|
133
|
-
async updateOrderStatus(input) {
|
|
134
|
-
try {
|
|
135
|
-
await provider.updateOrderStatus(input)
|
|
136
|
-
const query = get().orderQuery
|
|
137
|
-
const [result, summary] = await Promise.all([
|
|
138
|
-
provider.getOrders(query),
|
|
139
|
-
provider.getSummary(),
|
|
140
|
-
])
|
|
141
|
-
set({ orders: result.data, ordersTotal: result.total, summary })
|
|
142
|
-
toast.success('Order status updated')
|
|
143
|
-
} catch (err: any) {
|
|
144
|
-
toast.error('Failed to update status', { description: err?.message })
|
|
145
|
-
throw err
|
|
146
|
-
}
|
|
147
|
-
},
|
|
148
|
-
|
|
149
|
-
async cancelOrder(id, reason) {
|
|
150
|
-
try {
|
|
151
|
-
await provider.cancelOrder(id, reason)
|
|
152
|
-
const query = get().orderQuery
|
|
153
|
-
const [result, summary] = await Promise.all([
|
|
154
|
-
provider.getOrders(query),
|
|
155
|
-
provider.getSummary(),
|
|
156
|
-
])
|
|
157
|
-
set({ orders: result.data, ordersTotal: result.total, summary })
|
|
158
|
-
toast.success('Order cancelled')
|
|
159
|
-
} catch (err: any) {
|
|
160
|
-
toast.error('Failed to cancel order', { description: err?.message })
|
|
161
|
-
throw err
|
|
162
|
-
}
|
|
163
|
-
},
|
|
164
|
-
|
|
165
|
-
async addOrderItem(orderId, item) {
|
|
166
|
-
try {
|
|
167
|
-
await provider.addOrderItem(orderId, item)
|
|
168
|
-
const query = get().orderQuery
|
|
169
|
-
const result = await provider.getOrders(query)
|
|
170
|
-
set({ orders: result.data, ordersTotal: result.total })
|
|
171
|
-
toast.success('Item added')
|
|
172
|
-
} catch (err: any) {
|
|
173
|
-
toast.error('Failed to add item', { description: err?.message })
|
|
174
|
-
throw err
|
|
175
|
-
}
|
|
176
|
-
},
|
|
177
|
-
|
|
178
|
-
async removeOrderItem(itemId) {
|
|
179
|
-
try {
|
|
180
|
-
await provider.removeOrderItem(itemId)
|
|
181
|
-
const query = get().orderQuery
|
|
182
|
-
const result = await provider.getOrders(query)
|
|
183
|
-
set({ orders: result.data, ordersTotal: result.total })
|
|
184
|
-
toast.success('Item removed')
|
|
185
|
-
} catch (err: any) {
|
|
186
|
-
toast.error('Failed to remove item', { description: err?.message })
|
|
187
|
-
throw err
|
|
188
|
-
}
|
|
189
|
-
},
|
|
190
|
-
}))
|
|
191
|
-
}
|
package/src/types.ts
DELETED
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
// ---------------------------------------------------------------------------
|
|
2
|
-
// Orders Plugin — Pure TypeScript types
|
|
3
|
-
// ---------------------------------------------------------------------------
|
|
4
|
-
|
|
5
|
-
// ============================================================
|
|
6
|
-
// ENUMS / LITERALS
|
|
7
|
-
// ============================================================
|
|
8
|
-
|
|
9
|
-
export type OrderKind = 'dine_in' | 'takeout' | 'delivery'
|
|
10
|
-
|
|
11
|
-
export type DineInStatus = 'new' | 'confirmed' | 'preparing' | 'ready' | 'served' | 'completed' | 'cancelled'
|
|
12
|
-
export type TakeoutStatus = 'new' | 'confirmed' | 'preparing' | 'ready' | 'picked_up' | 'completed' | 'cancelled'
|
|
13
|
-
export type DeliveryStatus = 'new' | 'confirmed' | 'preparing' | 'ready' | 'dispatched' | 'delivered' | 'completed' | 'cancelled'
|
|
14
|
-
export type OrderStatus = DineInStatus | TakeoutStatus | DeliveryStatus
|
|
15
|
-
|
|
16
|
-
/** Unified columns for the kanban board */
|
|
17
|
-
export type KanbanColumn = 'new' | 'confirmed' | 'preparing' | 'ready' | 'out' | 'completed' | 'cancelled'
|
|
18
|
-
|
|
19
|
-
// ============================================================
|
|
20
|
-
// STATUS FLOW
|
|
21
|
-
// ============================================================
|
|
22
|
-
|
|
23
|
-
export const STATUS_FLOW: Record<OrderKind, OrderStatus[]> = {
|
|
24
|
-
dine_in: ['new', 'confirmed', 'preparing', 'ready', 'served', 'completed'],
|
|
25
|
-
takeout: ['new', 'confirmed', 'preparing', 'ready', 'picked_up', 'completed'],
|
|
26
|
-
delivery: ['new', 'confirmed', 'preparing', 'ready', 'dispatched', 'delivered', 'completed'],
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export function getNextStatus(kind: OrderKind, current: OrderStatus): OrderStatus | null {
|
|
30
|
-
const flow = STATUS_FLOW[kind]
|
|
31
|
-
const idx = flow.indexOf(current)
|
|
32
|
-
return idx >= 0 && idx < flow.length - 1 ? flow[idx + 1] : null
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export function getPreviousStatus(kind: OrderKind, current: OrderStatus): OrderStatus | null {
|
|
36
|
-
const flow = STATUS_FLOW[kind]
|
|
37
|
-
const idx = flow.indexOf(current)
|
|
38
|
-
return idx > 0 ? flow[idx - 1] : null
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export function mapToKanbanColumn(status: OrderStatus): KanbanColumn {
|
|
42
|
-
if (['served', 'picked_up', 'dispatched', 'delivered'].includes(status)) return 'out'
|
|
43
|
-
if (['new', 'confirmed', 'preparing', 'ready', 'completed', 'cancelled'].includes(status)) {
|
|
44
|
-
return status as KanbanColumn
|
|
45
|
-
}
|
|
46
|
-
return 'new'
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export const KANBAN_COLUMNS: KanbanColumn[] = ['new', 'confirmed', 'preparing', 'ready', 'out', 'completed']
|
|
50
|
-
|
|
51
|
-
// ============================================================
|
|
52
|
-
// CORE ENTITIES
|
|
53
|
-
// ============================================================
|
|
54
|
-
|
|
55
|
-
/** Restaurant order — public.orders + public.orders extension */
|
|
56
|
-
export interface RestaurantOrder {
|
|
57
|
-
id: string
|
|
58
|
-
referenceNumber: string
|
|
59
|
-
kind: OrderKind
|
|
60
|
-
status: OrderStatus
|
|
61
|
-
partyId?: string
|
|
62
|
-
partyName?: string
|
|
63
|
-
assigneeId?: string
|
|
64
|
-
assigneeName?: string
|
|
65
|
-
locationId?: string
|
|
66
|
-
subtotal: number
|
|
67
|
-
discount: number
|
|
68
|
-
tax: number
|
|
69
|
-
total: number
|
|
70
|
-
currency: string
|
|
71
|
-
notes?: string
|
|
72
|
-
tags: string[]
|
|
73
|
-
// Extension fields
|
|
74
|
-
source: string
|
|
75
|
-
tableId?: string
|
|
76
|
-
tableName?: string
|
|
77
|
-
estimatedMinutes?: number
|
|
78
|
-
items: RestaurantOrderItem[]
|
|
79
|
-
metadata?: Record<string, unknown>
|
|
80
|
-
tenantId: string
|
|
81
|
-
createdAt: string
|
|
82
|
-
updatedAt: string
|
|
83
|
-
completedAt?: string
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
export interface RestaurantOrderItem {
|
|
87
|
-
id: string
|
|
88
|
-
orderId: string
|
|
89
|
-
productId?: string
|
|
90
|
-
name: string
|
|
91
|
-
description?: string
|
|
92
|
-
quantity: number
|
|
93
|
-
unitPrice: number
|
|
94
|
-
discount: number
|
|
95
|
-
total: number
|
|
96
|
-
sortOrder: number
|
|
97
|
-
modifiers?: string
|
|
98
|
-
kitchenNotes?: string
|
|
99
|
-
metadata?: Record<string, unknown>
|
|
100
|
-
createdAt: string
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// ============================================================
|
|
104
|
-
// INPUT TYPES
|
|
105
|
-
// ============================================================
|
|
106
|
-
|
|
107
|
-
export interface CreateOrderInput {
|
|
108
|
-
kind: OrderKind
|
|
109
|
-
source?: string
|
|
110
|
-
tableId?: string
|
|
111
|
-
partyId?: string
|
|
112
|
-
assigneeId?: string
|
|
113
|
-
notes?: string
|
|
114
|
-
estimatedMinutes?: number
|
|
115
|
-
items: CreateOrderItemInput[]
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
export interface CreateOrderItemInput {
|
|
119
|
-
productId?: string
|
|
120
|
-
name: string
|
|
121
|
-
quantity: number
|
|
122
|
-
unitPrice: number
|
|
123
|
-
discount?: number
|
|
124
|
-
modifiers?: string
|
|
125
|
-
kitchenNotes?: string
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
export interface UpdateOrderStatusInput {
|
|
129
|
-
orderId: string
|
|
130
|
-
status: OrderStatus
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// ============================================================
|
|
134
|
-
// QUERY TYPES
|
|
135
|
-
// ============================================================
|
|
136
|
-
|
|
137
|
-
export interface OrderQuery {
|
|
138
|
-
kind?: OrderKind | OrderKind[]
|
|
139
|
-
status?: OrderStatus | OrderStatus[]
|
|
140
|
-
source?: string
|
|
141
|
-
tableId?: string
|
|
142
|
-
assigneeId?: string
|
|
143
|
-
dateRange?: { from: string; to: string }
|
|
144
|
-
search?: string
|
|
145
|
-
page?: number
|
|
146
|
-
pageSize?: number
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
export interface PaginatedResult<T> {
|
|
150
|
-
data: T[]
|
|
151
|
-
total: number
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// ============================================================
|
|
155
|
-
// AGGREGATION
|
|
156
|
-
// ============================================================
|
|
157
|
-
|
|
158
|
-
export interface OrdersSummary {
|
|
159
|
-
todayOrderCount: number
|
|
160
|
-
todayRevenue: number
|
|
161
|
-
averageTicket: number
|
|
162
|
-
activeOrderCount: number
|
|
163
|
-
ordersByKind: Record<OrderKind, number>
|
|
164
|
-
ordersByStatus: Record<string, number>
|
|
165
|
-
topItems: Array<{ name: string; quantity: number; revenue: number }>
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// ============================================================
|
|
169
|
-
// STATUS CONFIG
|
|
170
|
-
// ============================================================
|
|
171
|
-
|
|
172
|
-
export interface OrderStatusConfig {
|
|
173
|
-
value: string
|
|
174
|
-
label: string
|
|
175
|
-
color: string
|
|
176
|
-
icon?: string
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
export const DEFAULT_STATUS_CONFIGS: OrderStatusConfig[] = [
|
|
180
|
-
{ value: 'new', label: 'New', color: '#6366f1', icon: 'PlusCircle' },
|
|
181
|
-
{ value: 'confirmed', label: 'Confirmed', color: '#3b82f6', icon: 'CheckCircle' },
|
|
182
|
-
{ value: 'preparing', label: 'Preparing', color: '#f59e0b', icon: 'ChefHat' },
|
|
183
|
-
{ value: 'ready', label: 'Ready', color: '#10b981', icon: 'Bell' },
|
|
184
|
-
{ value: 'served', label: 'Served', color: '#06b6d4', icon: 'Utensils' },
|
|
185
|
-
{ value: 'picked_up', label: 'Picked Up', color: '#06b6d4', icon: 'ShoppingBag' },
|
|
186
|
-
{ value: 'dispatched', label: 'Dispatched', color: '#8b5cf6', icon: 'Truck' },
|
|
187
|
-
{ value: 'delivered', label: 'Delivered', color: '#06b6d4', icon: 'PackageCheck' },
|
|
188
|
-
{ value: 'completed', label: 'Completed', color: '#22c55e', icon: 'CircleCheck' },
|
|
189
|
-
{ value: 'cancelled', label: 'Cancelled', color: '#ef4444', icon: 'XCircle' },
|
|
190
|
-
]
|