@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/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
- }
@@ -1,4 +0,0 @@
1
- import { en } from './en'
2
- import { ptBR } from './pt-BR'
3
-
4
- export const ordersLocales: Record<string, Record<string, string>> = { en, 'pt-BR': ptBR }
@@ -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
- ]