@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
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
import React, { useEffect, useMemo } from 'react'
|
|
2
|
-
import { ChevronRight, Clock, Loader2, ClipboardList } from 'lucide-react'
|
|
3
|
-
import { useOrdersConfig, useOrdersStore, formatCurrency } from '../OrdersContext'
|
|
4
|
-
import { useTranslation } from '@fayz-ai/core'
|
|
5
|
-
import {
|
|
6
|
-
KANBAN_COLUMNS,
|
|
7
|
-
mapToKanbanColumn,
|
|
8
|
-
getNextStatus,
|
|
9
|
-
type KanbanColumn,
|
|
10
|
-
type RestaurantOrder,
|
|
11
|
-
} from '../types'
|
|
12
|
-
|
|
13
|
-
// ---------------------------------------------------------------------------
|
|
14
|
-
// Column config
|
|
15
|
-
// ---------------------------------------------------------------------------
|
|
16
|
-
|
|
17
|
-
const COLUMN_CONFIG: Record<KanbanColumn, { color: string }> = {
|
|
18
|
-
new: { color: 'bg-violet-500' },
|
|
19
|
-
confirmed: { color: 'bg-blue-500' },
|
|
20
|
-
preparing: { color: 'bg-amber-500' },
|
|
21
|
-
ready: { color: 'bg-emerald-500' },
|
|
22
|
-
out: { color: 'bg-cyan-500' },
|
|
23
|
-
completed: { color: 'bg-gray-400' },
|
|
24
|
-
cancelled: { color: 'bg-red-500' },
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// ---------------------------------------------------------------------------
|
|
28
|
-
// Helpers
|
|
29
|
-
// ---------------------------------------------------------------------------
|
|
30
|
-
|
|
31
|
-
function timeAgo(dateStr: string): string {
|
|
32
|
-
const diff = Math.floor((Date.now() - new Date(dateStr).getTime()) / 60000)
|
|
33
|
-
if (diff < 1) return 'just now'
|
|
34
|
-
if (diff === 1) return '1min'
|
|
35
|
-
return `${diff}min`
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// ---------------------------------------------------------------------------
|
|
39
|
-
// Order Card
|
|
40
|
-
// ---------------------------------------------------------------------------
|
|
41
|
-
|
|
42
|
-
function OrderCard({
|
|
43
|
-
order,
|
|
44
|
-
onAdvance,
|
|
45
|
-
onSelect,
|
|
46
|
-
currency,
|
|
47
|
-
}: {
|
|
48
|
-
order: RestaurantOrder
|
|
49
|
-
onAdvance?: () => void
|
|
50
|
-
onSelect: () => void
|
|
51
|
-
currency: { code: string; locale: string; symbol: string }
|
|
52
|
-
}) {
|
|
53
|
-
const t = useTranslation()
|
|
54
|
-
const sourceLabel = t(`orders.source.${order.source}`) !== `orders.source.${order.source}`
|
|
55
|
-
? t(`orders.source.${order.source}`)
|
|
56
|
-
: order.source
|
|
57
|
-
|
|
58
|
-
return (
|
|
59
|
-
<div
|
|
60
|
-
className="rounded-lg border bg-card p-3 hover:shadow-md transition-shadow cursor-pointer"
|
|
61
|
-
onClick={onSelect}
|
|
62
|
-
>
|
|
63
|
-
{/* Header: order number + source badge */}
|
|
64
|
-
<div className="flex items-center justify-between mb-2">
|
|
65
|
-
<span className="text-sm font-bold">{order.referenceNumber}</span>
|
|
66
|
-
<span className="inline-flex items-center gap-1 rounded-full bg-muted px-2 py-0.5 text-[10px] font-medium">
|
|
67
|
-
{sourceLabel}
|
|
68
|
-
</span>
|
|
69
|
-
</div>
|
|
70
|
-
|
|
71
|
-
{/* Customer + table */}
|
|
72
|
-
{order.partyName && (
|
|
73
|
-
<p className="text-sm font-medium truncate">{order.partyName}</p>
|
|
74
|
-
)}
|
|
75
|
-
{order.tableName && (
|
|
76
|
-
<p className="text-xs text-muted-foreground">{order.tableName}</p>
|
|
77
|
-
)}
|
|
78
|
-
|
|
79
|
-
{/* Items */}
|
|
80
|
-
{order.items.length > 0 && (
|
|
81
|
-
<div className="mt-2 space-y-0.5">
|
|
82
|
-
{order.items.map((item) => (
|
|
83
|
-
<p key={item.id} className="text-xs text-muted-foreground truncate">
|
|
84
|
-
{item.quantity}x {item.name}
|
|
85
|
-
</p>
|
|
86
|
-
))}
|
|
87
|
-
</div>
|
|
88
|
-
)}
|
|
89
|
-
|
|
90
|
-
{/* Total + time */}
|
|
91
|
-
<div className="flex items-center justify-between mt-3 pt-2 border-t">
|
|
92
|
-
<span className="text-sm font-bold">
|
|
93
|
-
{formatCurrency(order.total, currency)}
|
|
94
|
-
</span>
|
|
95
|
-
<span className="inline-flex items-center gap-0.5 text-[10px] text-muted-foreground">
|
|
96
|
-
<Clock className="h-3 w-3" />
|
|
97
|
-
{timeAgo(order.createdAt)}
|
|
98
|
-
</span>
|
|
99
|
-
</div>
|
|
100
|
-
|
|
101
|
-
{/* Advance button */}
|
|
102
|
-
{onAdvance && (
|
|
103
|
-
<button
|
|
104
|
-
type="button"
|
|
105
|
-
className="mt-2 flex w-full items-center justify-center gap-1 rounded-md bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90 transition-colors"
|
|
106
|
-
onClick={(e) => {
|
|
107
|
-
e.stopPropagation()
|
|
108
|
-
onAdvance()
|
|
109
|
-
}}
|
|
110
|
-
>
|
|
111
|
-
{t('orders.kanban.advance')}
|
|
112
|
-
<ChevronRight className="h-3 w-3" />
|
|
113
|
-
</button>
|
|
114
|
-
)}
|
|
115
|
-
</div>
|
|
116
|
-
)
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// ---------------------------------------------------------------------------
|
|
120
|
-
// Skeleton column (loading state)
|
|
121
|
-
// ---------------------------------------------------------------------------
|
|
122
|
-
|
|
123
|
-
function SkeletonColumn() {
|
|
124
|
-
return (
|
|
125
|
-
<div className="flex-shrink-0 w-72">
|
|
126
|
-
<div className="h-9 rounded-lg bg-muted animate-pulse mb-3" />
|
|
127
|
-
<div className="space-y-3">
|
|
128
|
-
{[1, 2, 3].map((i) => (
|
|
129
|
-
<div key={i} className="h-32 rounded-lg bg-muted/60 animate-pulse" />
|
|
130
|
-
))}
|
|
131
|
-
</div>
|
|
132
|
-
</div>
|
|
133
|
-
)
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// ---------------------------------------------------------------------------
|
|
137
|
-
// OrderKanbanView
|
|
138
|
-
// ---------------------------------------------------------------------------
|
|
139
|
-
|
|
140
|
-
export function OrderKanbanView() {
|
|
141
|
-
const t = useTranslation()
|
|
142
|
-
const config = useOrdersConfig()
|
|
143
|
-
|
|
144
|
-
const activeOrders = useOrdersStore((s) => s.activeOrders)
|
|
145
|
-
const activeOrdersLoading = useOrdersStore((s) => s.activeOrdersLoading)
|
|
146
|
-
const fetchActiveOrders = useOrdersStore((s) => s.fetchActiveOrders)
|
|
147
|
-
const advanceOrderStatus = useOrdersStore((s) => s.advanceOrderStatus)
|
|
148
|
-
const selectOrder = useOrdersStore((s) => s.selectOrder)
|
|
149
|
-
|
|
150
|
-
useEffect(() => {
|
|
151
|
-
fetchActiveOrders()
|
|
152
|
-
}, [fetchActiveOrders])
|
|
153
|
-
|
|
154
|
-
// Group orders by kanban column
|
|
155
|
-
const grouped = useMemo(() => {
|
|
156
|
-
const map: Record<KanbanColumn, RestaurantOrder[]> = {
|
|
157
|
-
new: [],
|
|
158
|
-
confirmed: [],
|
|
159
|
-
preparing: [],
|
|
160
|
-
ready: [],
|
|
161
|
-
out: [],
|
|
162
|
-
completed: [],
|
|
163
|
-
cancelled: [],
|
|
164
|
-
}
|
|
165
|
-
for (const order of activeOrders) {
|
|
166
|
-
const col = mapToKanbanColumn(order.status)
|
|
167
|
-
map[col].push(order)
|
|
168
|
-
}
|
|
169
|
-
return map
|
|
170
|
-
}, [activeOrders])
|
|
171
|
-
|
|
172
|
-
// Loading state
|
|
173
|
-
if (activeOrdersLoading && activeOrders.length === 0) {
|
|
174
|
-
return (
|
|
175
|
-
<div className="flex gap-4 overflow-x-auto pb-4">
|
|
176
|
-
{KANBAN_COLUMNS.map((col) => (
|
|
177
|
-
<SkeletonColumn key={col} />
|
|
178
|
-
))}
|
|
179
|
-
</div>
|
|
180
|
-
)
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// Empty state
|
|
184
|
-
if (!activeOrdersLoading && activeOrders.length === 0) {
|
|
185
|
-
return (
|
|
186
|
-
<div className="flex flex-col items-center justify-center h-64 text-center">
|
|
187
|
-
<ClipboardList className="h-12 w-12 text-muted-foreground/40 mb-3" />
|
|
188
|
-
<p className="text-sm font-medium text-muted-foreground">
|
|
189
|
-
{t('orders.kanban.noOrders')}
|
|
190
|
-
</p>
|
|
191
|
-
<p className="text-xs text-muted-foreground/70 mt-1">
|
|
192
|
-
{t('orders.kanban.noOrdersDesc')}
|
|
193
|
-
</p>
|
|
194
|
-
</div>
|
|
195
|
-
)
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
return (
|
|
199
|
-
<div className="flex gap-4 overflow-x-auto pb-4">
|
|
200
|
-
{KANBAN_COLUMNS.map((col) => {
|
|
201
|
-
const columnOrders = grouped[col]
|
|
202
|
-
const colConfig = COLUMN_CONFIG[col]
|
|
203
|
-
const label = t(`orders.kanban.column.${col}`)
|
|
204
|
-
const hasNext = (order: RestaurantOrder) =>
|
|
205
|
-
getNextStatus(order.kind, order.status) !== null
|
|
206
|
-
|
|
207
|
-
return (
|
|
208
|
-
<div key={col} className="flex-shrink-0 w-72">
|
|
209
|
-
{/* Column header */}
|
|
210
|
-
<div className="flex items-center gap-2 px-3 py-2 rounded-lg mb-3">
|
|
211
|
-
<span className={`h-2.5 w-2.5 rounded-full ${colConfig.color}`} />
|
|
212
|
-
<span className="text-sm font-semibold">{label}</span>
|
|
213
|
-
<span className="ml-auto inline-flex items-center justify-center rounded-full bg-muted px-2 py-0.5 text-xs font-medium">
|
|
214
|
-
{columnOrders.length}
|
|
215
|
-
</span>
|
|
216
|
-
</div>
|
|
217
|
-
|
|
218
|
-
{/* Cards */}
|
|
219
|
-
<div className="space-y-3 max-h-[calc(100vh-16rem)] overflow-y-auto pr-1">
|
|
220
|
-
{columnOrders.map((order) => (
|
|
221
|
-
<OrderCard
|
|
222
|
-
key={order.id}
|
|
223
|
-
order={order}
|
|
224
|
-
currency={config.currency}
|
|
225
|
-
onSelect={() => selectOrder(order.id)}
|
|
226
|
-
onAdvance={hasNext(order) ? () => advanceOrderStatus(order.id) : undefined}
|
|
227
|
-
/>
|
|
228
|
-
))}
|
|
229
|
-
{columnOrders.length === 0 && (
|
|
230
|
-
<div className="text-center py-8 text-sm text-muted-foreground rounded-lg border border-dashed">
|
|
231
|
-
{t('orders.kanban.noOrders')}
|
|
232
|
-
</div>
|
|
233
|
-
)}
|
|
234
|
-
</div>
|
|
235
|
-
</div>
|
|
236
|
-
)
|
|
237
|
-
})}
|
|
238
|
-
</div>
|
|
239
|
-
)
|
|
240
|
-
}
|
|
File without changes
|