@fayz-ai/orders 0.0.0-stage → 0.1.0

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.
Files changed (45) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +38 -2
  3. package/dist/chunk-A4AGOZHO.js +168 -0
  4. package/dist/chunk-A4AGOZHO.js.map +1 -0
  5. package/dist/components/CommercialOrderCard.d.ts +7 -0
  6. package/dist/components/CommercialOrderCard.d.ts.map +1 -0
  7. package/dist/components/CommercialOrderCard.js +18 -0
  8. package/dist/components/CommercialOrderCard.js.map +1 -0
  9. package/dist/components/OrderBoardCard.d.ts +10 -0
  10. package/dist/components/OrderBoardCard.d.ts.map +1 -0
  11. package/dist/components/OrderBoardCard.js +35 -0
  12. package/dist/components/OrderBoardCard.js.map +1 -0
  13. package/dist/components/OrderStatusDot.d.ts +8 -0
  14. package/dist/components/OrderStatusDot.d.ts.map +1 -0
  15. package/dist/components/OrderStatusDot.js +22 -0
  16. package/dist/components/OrderStatusDot.js.map +1 -0
  17. package/dist/components/PaymentStateBadge.d.ts +6 -0
  18. package/dist/components/PaymentStateBadge.d.ts.map +1 -0
  19. package/dist/components/PaymentStateBadge.js +27 -0
  20. package/dist/components/PaymentStateBadge.js.map +1 -0
  21. package/dist/data/mock.d.ts +3 -0
  22. package/dist/data/mock.d.ts.map +1 -0
  23. package/dist/data/mock.js +208 -0
  24. package/dist/data/mock.js.map +1 -0
  25. package/dist/data/platform.d.ts +19 -0
  26. package/dist/data/platform.d.ts.map +1 -0
  27. package/dist/data/platform.js +362 -0
  28. package/dist/data/platform.js.map +1 -0
  29. package/dist/data/provider.d.ts +14 -0
  30. package/dist/data/provider.d.ts.map +1 -0
  31. package/dist/data/provider.js +3 -0
  32. package/dist/data/provider.js.map +1 -0
  33. package/dist/data/supabase.d.ts +19 -0
  34. package/dist/data/supabase.d.ts.map +1 -0
  35. package/dist/data/supabase.js +316 -0
  36. package/dist/data/supabase.js.map +1 -0
  37. package/dist/domain/order.d.ts +172 -0
  38. package/dist/domain/order.d.ts.map +1 -0
  39. package/dist/domain/order.js +3 -0
  40. package/dist/domain/order.js.map +1 -0
  41. package/dist/store.d.ts +30 -0
  42. package/dist/store.d.ts.map +1 -0
  43. package/dist/store.js +146 -0
  44. package/dist/store.js.map +1 -0
  45. package/package.json +52 -3
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Faya Labs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,39 @@
1
- # Temporary Holding Version
1
+ # @fayz-ai/orders
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ > The orders bounded context: what an order is, how it moves through its kind's flow, where it is stored, and the UI pieces over it.
4
+
5
+ **Status:** beta — extracted from `@fayz-ai/plugin-orders`, which composes it and still exports every name it had. Pre-1.0: minor APIs may change before 1.0.
6
+
7
+ Built to the shape in [docs/platform/PATTERNS.md](../../docs/platform/PATTERNS.md). There is no entry file: each module is imported by its path.
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ npm install @fayz-ai/orders
13
+ ```
14
+
15
+ ## Modules
16
+
17
+ | Import | What it holds |
18
+ |---|---|
19
+ | `@fayz-ai/orders/domain/order` | `RestaurantOrder`, `RestaurantOrderItem`, `OrdersSummary` and the pure rules (`getNextStatus`, `canMoveTo`, `boardColumnFor`, `summarizeOrders`, `commercialColumnOf`…) |
20
+ | `@fayz-ai/orders/data/provider` | `OrdersDataProvider`, the repository port |
21
+ | `@fayz-ai/orders/data/supabase` | `createSupabaseOrdersProvider` over the core order archetype (`v_orders`), read-only unless given `writes` |
22
+ | `@fayz-ai/orders/data/platform` | `createFayzOrdersProvider` over the Fayz data API |
23
+ | `@fayz-ai/orders/data/mock` | `createMockOrdersProvider`, the same contract in memory |
24
+ | `@fayz-ai/orders/store` | `createOrdersStore(provider, hooks)`: lists, the active board, lifecycle events and hooks |
25
+ | `@fayz-ai/orders/components/*` | presentational pieces: `OrderBoardCard`, `CommercialOrderCard`, `OrderStatusDot`, `PaymentStateBadge` |
26
+
27
+ The screens stay in `@fayz-ai/plugin-orders`: they compose the shell's order list, detail rail and record picker,
28
+ which a domain package does not import.
29
+
30
+ ```ts
31
+ import { getNextStatus } from '@fayz-ai/orders/domain/order'
32
+ import { createMockOrdersProvider } from '@fayz-ai/orders/data/mock'
33
+ import { createOrdersStore } from '@fayz-ai/orders/store'
34
+
35
+ const store = createOrdersStore(createMockOrdersProvider())
36
+ await store.getState().fetchActiveOrders()
37
+ ```
38
+
39
+ Words used here are defined in [GLOSSARY.md](./GLOSSARY.md).
@@ -0,0 +1,168 @@
1
+ // src/domain/order.ts
2
+ var DEFAULT_STATUS_CONFIGS = [
3
+ { value: "new", label: "New", color: "#6366f1", icon: "PlusCircle" },
4
+ { value: "confirmed", label: "Confirmed", color: "#3b82f6", icon: "CheckCircle" },
5
+ { value: "preparing", label: "Preparing", color: "#f59e0b", icon: "ChefHat" },
6
+ { value: "ready", label: "Ready", color: "#10b981", icon: "Bell" },
7
+ { value: "served", label: "Served", color: "#06b6d4", icon: "Utensils" },
8
+ { value: "picked_up", label: "Picked Up", color: "#06b6d4", icon: "ShoppingBag" },
9
+ { value: "dispatched", label: "Dispatched", color: "#8b5cf6", icon: "Truck" },
10
+ { value: "delivered", label: "Delivered", color: "#06b6d4", icon: "PackageCheck" },
11
+ { value: "completed", label: "Completed", color: "#22c55e", icon: "CircleCheck" },
12
+ { value: "cancelled", label: "Cancelled", color: "#ef4444", icon: "XCircle" }
13
+ ];
14
+ var STATUS_FLOW = {
15
+ dine_in: ["draft", "new", "confirmed", "preparing", "ready", "served", "completed"],
16
+ takeout: ["draft", "new", "confirmed", "preparing", "ready", "picked_up", "completed"],
17
+ delivery: ["draft", "new", "confirmed", "preparing", "ready", "dispatched", "delivered", "completed"]
18
+ };
19
+ var OUT_STATUSES = ["served", "picked_up", "dispatched", "delivered"];
20
+ var ACTIVE_STATUSES = ["new", "confirmed", "preparing", "ready", ...OUT_STATUSES];
21
+ var KANBAN_COLUMNS = ["new", "confirmed", "preparing", "ready", "out", "completed"];
22
+ var ADVANCE_VERB = {
23
+ draft: "Salvar rascunho",
24
+ new: "Enviar",
25
+ confirmed: "Confirmar",
26
+ preparing: "Preparar",
27
+ ready: "Marcar pronto",
28
+ served: "Servir",
29
+ picked_up: "Entregar",
30
+ dispatched: "Despachar",
31
+ delivered: "Confirmar entrega",
32
+ completed: "Concluir",
33
+ cancelled: "Cancelar"
34
+ };
35
+ function isActive(status) {
36
+ return ACTIVE_STATUSES.includes(status);
37
+ }
38
+ function isClosed(status) {
39
+ return status === "completed" || status === "cancelled";
40
+ }
41
+ function getNextStatus(kind, current) {
42
+ const flow = STATUS_FLOW[kind];
43
+ let idx = flow.indexOf(current);
44
+ if (idx === -1 && OUT_STATUSES.includes(current)) {
45
+ idx = flow.findIndex((status) => OUT_STATUSES.includes(status));
46
+ }
47
+ return idx >= 0 && idx < flow.length - 1 ? flow[idx + 1] : null;
48
+ }
49
+ function getPreviousStatus(kind, current) {
50
+ const flow = STATUS_FLOW[kind];
51
+ const idx = flow.indexOf(current);
52
+ return idx > 0 ? flow[idx - 1] : null;
53
+ }
54
+ function canMoveTo(kind, from, to) {
55
+ if (to === "cancelled") return true;
56
+ const flow = STATUS_FLOW[kind];
57
+ const fromIdx = flow.indexOf(from);
58
+ const toIdx = flow.indexOf(to);
59
+ return toIdx >= 0 && (toIdx === fromIdx || toIdx === fromIdx + 1);
60
+ }
61
+ function mapToKanbanColumn(status) {
62
+ if (OUT_STATUSES.includes(status)) return "out";
63
+ if (KANBAN_COLUMNS.includes(status) || status === "cancelled") return status;
64
+ return "new";
65
+ }
66
+ function serviceOf(order) {
67
+ return order.kind === "dine_in" ? "salao" : "delivery";
68
+ }
69
+ function boardColumns(service) {
70
+ return service === "salao" ? KANBAN_COLUMNS.filter((id) => id !== "new") : KANBAN_COLUMNS;
71
+ }
72
+ function boardColumnOf(service, status) {
73
+ const column = mapToKanbanColumn(status);
74
+ return service === "salao" && column === "new" ? "confirmed" : column;
75
+ }
76
+ function boardColumnFor(service, order) {
77
+ return serviceOf(order) === service ? boardColumnOf(service, order.status) : null;
78
+ }
79
+ function nextBoardColumn(service, order) {
80
+ const next = getNextStatus(order.kind, order.status);
81
+ return next ? boardColumnOf(service, next) : null;
82
+ }
83
+ function lineTotal(item) {
84
+ return item.quantity * item.unitPrice - (item.discount ?? 0);
85
+ }
86
+ function orderTotals(items, adjustments = {}) {
87
+ const subtotal = items.reduce((sum, item) => sum + item.total, 0);
88
+ return { subtotal, total: subtotal - (adjustments.discount ?? 0) + (adjustments.tax ?? 0) };
89
+ }
90
+ function withCancellationNote(notes, reason) {
91
+ if (!reason) return notes;
92
+ return notes ? `${notes}
93
+ Cancelled: ${reason}` : `Cancelled: ${reason}`;
94
+ }
95
+ function isoDay(date = /* @__PURE__ */ new Date()) {
96
+ return (typeof date === "string" ? date : date.toISOString()).slice(0, 10);
97
+ }
98
+ function matchesQuery(order, query) {
99
+ if (query.kind && !asList(query.kind).includes(order.kind)) return false;
100
+ if (query.status && !asList(query.status).includes(order.status)) return false;
101
+ if (query.source && order.source !== query.source) return false;
102
+ if (query.tableId && order.tableId !== query.tableId) return false;
103
+ if (query.assigneeId && order.assigneeId !== query.assigneeId) return false;
104
+ if (query.dateRange) {
105
+ const created = isoDay(order.createdAt);
106
+ if (created < query.dateRange.from || created > query.dateRange.to) return false;
107
+ }
108
+ if (query.search) {
109
+ const search = query.search.toLowerCase();
110
+ return order.referenceNumber.toLowerCase().includes(search) || (order.partyName?.toLowerCase().includes(search) ?? false) || (order.tableName?.toLowerCase().includes(search) ?? false) || order.items.some((item) => item.name.toLowerCase().includes(search));
111
+ }
112
+ return true;
113
+ }
114
+ function paginate(items, page = 1, pageSize = 20) {
115
+ const start = (page - 1) * pageSize;
116
+ return { data: items.slice(start, start + pageSize), total: items.length };
117
+ }
118
+ function summarizeOrders(orders, dateRange, today = isoDay()) {
119
+ const from = dateRange?.from ?? today;
120
+ const to = dateRange?.to ?? today;
121
+ const inRange = orders.filter((order) => {
122
+ const created = isoDay(order.createdAt);
123
+ return created >= from && created <= to;
124
+ });
125
+ const billable = inRange.filter((order) => order.status !== "cancelled");
126
+ const revenue = billable.reduce((sum, order) => sum + order.total, 0);
127
+ const ordersByKind = { dine_in: 0, takeout: 0, delivery: 0 };
128
+ const ordersByStatus = {};
129
+ const top = /* @__PURE__ */ new Map();
130
+ for (const order of inRange) {
131
+ ordersByKind[order.kind] = (ordersByKind[order.kind] ?? 0) + 1;
132
+ ordersByStatus[order.status] = (ordersByStatus[order.status] ?? 0) + 1;
133
+ }
134
+ for (const order of billable) {
135
+ for (const item of order.items) {
136
+ const current = top.get(item.name) ?? { name: item.name, quantity: 0, revenue: 0 };
137
+ current.quantity += item.quantity;
138
+ current.revenue += item.total;
139
+ top.set(item.name, current);
140
+ }
141
+ }
142
+ return {
143
+ todayOrderCount: inRange.length,
144
+ todayRevenue: revenue,
145
+ averageTicket: billable.length > 0 ? revenue / billable.length : 0,
146
+ activeOrderCount: orders.filter((order) => isActive(order.status)).length,
147
+ ordersByKind,
148
+ ordersByStatus,
149
+ topItems: [...top.values()].sort((a, b) => b.quantity - a.quantity).slice(0, 5)
150
+ };
151
+ }
152
+ function paymentStateOf(order) {
153
+ return order.metadata?.paymentStatus ?? "none";
154
+ }
155
+ function commercialColumnOf(order) {
156
+ if (order.status === "cancelled") return "cancelled";
157
+ const state = paymentStateOf(order);
158
+ if (state === "paid") return "paid";
159
+ if (state === "none") return "no_invoice";
160
+ return "open";
161
+ }
162
+ function asList(value) {
163
+ return Array.isArray(value) ? value : [value];
164
+ }
165
+
166
+ export { ACTIVE_STATUSES, ADVANCE_VERB, DEFAULT_STATUS_CONFIGS, KANBAN_COLUMNS, OUT_STATUSES, STATUS_FLOW, boardColumnFor, boardColumnOf, boardColumns, canMoveTo, commercialColumnOf, getNextStatus, getPreviousStatus, isActive, isClosed, isoDay, lineTotal, mapToKanbanColumn, matchesQuery, nextBoardColumn, orderTotals, paginate, paymentStateOf, serviceOf, summarizeOrders, withCancellationNote };
167
+ //# sourceMappingURL=chunk-A4AGOZHO.js.map
168
+ //# sourceMappingURL=chunk-A4AGOZHO.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/domain/order.ts"],"names":[],"mappings":"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","file":"chunk-A4AGOZHO.js","sourcesContent":["export type OrderKind = 'dine_in' | 'takeout' | 'delivery'\n\nexport type DineInStatus = 'draft' | 'new' | 'confirmed' | 'preparing' | 'ready' | 'served' | 'completed' | 'cancelled'\nexport type TakeoutStatus = 'draft' | 'new' | 'confirmed' | 'preparing' | 'ready' | 'picked_up' | 'completed' | 'cancelled'\nexport type DeliveryStatus = 'draft' | 'new' | 'confirmed' | 'preparing' | 'ready' | 'dispatched' | 'delivered' | 'completed' | 'cancelled'\nexport type OrderStatus = DineInStatus | TakeoutStatus | DeliveryStatus\n\nexport type KanbanColumn = 'new' | 'confirmed' | 'preparing' | 'ready' | 'out' | 'completed' | 'cancelled'\n\nexport interface RestaurantOrder {\n id: string\n referenceNumber: string\n kind: OrderKind\n status: OrderStatus\n partyId?: string\n partyName?: string\n assigneeId?: string\n assigneeName?: string\n locationId?: string\n subtotal: number\n discount: number\n tax: number\n total: number\n currency: string\n notes?: string\n tags: string[]\n source: string\n tableId?: string\n tableName?: string\n estimatedMinutes?: number\n items: RestaurantOrderItem[]\n metadata?: Record<string, unknown>\n tenantId: string\n unitId?: string\n createdAt: string\n updatedAt: string\n completedAt?: string\n}\n\nexport interface RestaurantOrderItem {\n id: string\n orderId: string\n productId?: string\n name: string\n description?: string\n quantity: number\n unitPrice: number\n discount: number\n total: number\n sortOrder: number\n modifiers?: string\n kitchenNotes?: string\n metadata?: Record<string, unknown>\n createdAt: string\n}\n\nexport interface CreateOrderInput {\n kind: OrderKind\n source?: string\n tableId?: string\n partyId?: string\n assigneeId?: string\n notes?: string\n estimatedMinutes?: number\n items: CreateOrderItemInput[]\n}\n\nexport interface CreateOrderItemInput {\n productId?: string\n name: string\n quantity: number\n unitPrice: number\n discount?: number\n modifiers?: string\n kitchenNotes?: string\n}\n\nexport interface UpdateOrderStatusInput {\n orderId: string\n status: OrderStatus\n}\n\nexport interface OrderQuery {\n // Wider than OrderKind/OrderStatus: the list reads every sale of the account\n // (sale, course, appointment…), not only the restaurant's three kinds.\n kind?: OrderKind | OrderKind[] | (string & {}) | string[]\n status?: OrderStatus | OrderStatus[] | (string & {}) | string[]\n source?: string\n /** Sales channel as `orders.channel` holds it (balcao · shop · delivery…). */\n channel?: string\n /** unfulfilled · partially_fulfilled · fulfilled */\n fulfillmentStatus?: string\n /** Kinds left out — the sales list drops `purchase`, which shares the table. */\n excludeKinds?: string[]\n /** `false` skips the lines — a list row does not draw them. Default true. */\n withItems?: boolean\n tableId?: string\n assigneeId?: string\n dateRange?: DateRange\n search?: string\n page?: number\n pageSize?: number\n}\n\nexport interface DateRange {\n from: string\n to: string\n}\n\nexport interface PaginatedResult<T> {\n data: T[]\n total: number\n}\n\nexport interface OrdersSummary {\n todayOrderCount: number\n todayRevenue: number\n averageTicket: number\n activeOrderCount: number\n ordersByKind: Record<OrderKind, number>\n ordersByStatus: Record<string, number>\n topItems: Array<{ name: string; quantity: number; revenue: number }>\n}\n\nexport interface OrderStatusConfig {\n value: string\n label: string\n color: string\n icon?: string\n}\n\nexport const DEFAULT_STATUS_CONFIGS: OrderStatusConfig[] = [\n { value: 'new', label: 'New', color: '#6366f1', icon: 'PlusCircle' },\n { value: 'confirmed', label: 'Confirmed', color: '#3b82f6', icon: 'CheckCircle' },\n { value: 'preparing', label: 'Preparing', color: '#f59e0b', icon: 'ChefHat' },\n { value: 'ready', label: 'Ready', color: '#10b981', icon: 'Bell' },\n { value: 'served', label: 'Served', color: '#06b6d4', icon: 'Utensils' },\n { value: 'picked_up', label: 'Picked Up', color: '#06b6d4', icon: 'ShoppingBag' },\n { value: 'dispatched', label: 'Dispatched', color: '#8b5cf6', icon: 'Truck' },\n { value: 'delivered', label: 'Delivered', color: '#06b6d4', icon: 'PackageCheck' },\n { value: 'completed', label: 'Completed', color: '#22c55e', icon: 'CircleCheck' },\n { value: 'cancelled', label: 'Cancelled', color: '#ef4444', icon: 'XCircle' },\n]\n\n// `public.order_kinds` lists `draft` for all three kinds and allows `* → *`; the order lives here.\nexport const STATUS_FLOW: Record<OrderKind, OrderStatus[]> = {\n dine_in: ['draft', 'new', 'confirmed', 'preparing', 'ready', 'served', 'completed'],\n takeout: ['draft', 'new', 'confirmed', 'preparing', 'ready', 'picked_up', 'completed'],\n delivery: ['draft', 'new', 'confirmed', 'preparing', 'ready', 'dispatched', 'delivered', 'completed'],\n}\n\n/** The food has left the kitchen: one step, a different word per kind. */\nexport const OUT_STATUSES: readonly OrderStatus[] = ['served', 'picked_up', 'dispatched', 'delivered']\n\n/** Work in progress: on the board until it is completed or cancelled. */\nexport const ACTIVE_STATUSES: readonly OrderStatus[] = ['new', 'confirmed', 'preparing', 'ready', ...OUT_STATUSES]\n\nexport const KANBAN_COLUMNS: KanbanColumn[] = ['new', 'confirmed', 'preparing', 'ready', 'out', 'completed']\n\n/** The verb on the advance button, keyed by the status it moves to. */\nexport const ADVANCE_VERB: Record<OrderStatus, string> = {\n draft: 'Salvar rascunho',\n new: 'Enviar',\n confirmed: 'Confirmar',\n preparing: 'Preparar',\n ready: 'Marcar pronto',\n served: 'Servir',\n picked_up: 'Entregar',\n dispatched: 'Despachar',\n delivered: 'Confirmar entrega',\n completed: 'Concluir',\n cancelled: 'Cancelar',\n}\n\nexport function isActive(status: string): boolean {\n return (ACTIVE_STATUSES as readonly string[]).includes(status)\n}\n\n/** Completed or cancelled: nothing is added to it, advanced or cancelled again. */\nexport function isClosed(status: string | undefined): boolean {\n return status === 'completed' || status === 'cancelled'\n}\n\nexport function getNextStatus(kind: OrderKind, current: OrderStatus): OrderStatus | null {\n const flow = STATUS_FLOW[kind]\n let idx = flow.indexOf(current)\n // A derived status may carry a sibling kind's word for the out step (a dine_in reading `dispatched`).\n if (idx === -1 && OUT_STATUSES.includes(current)) {\n idx = flow.findIndex((status) => OUT_STATUSES.includes(status))\n }\n return idx >= 0 && idx < flow.length - 1 ? flow[idx + 1] : null\n}\n\nexport function getPreviousStatus(kind: OrderKind, current: OrderStatus): OrderStatus | null {\n const flow = STATUS_FLOW[kind]\n const idx = flow.indexOf(current)\n return idx > 0 ? flow[idx - 1] : null\n}\n\n/** Cancelling is always allowed; otherwise the order stays put or takes the next step of its flow. */\nexport function canMoveTo(kind: OrderKind, from: OrderStatus, to: OrderStatus): boolean {\n if (to === 'cancelled') return true\n const flow = STATUS_FLOW[kind]\n const fromIdx = flow.indexOf(from)\n const toIdx = flow.indexOf(to)\n return toIdx >= 0 && (toIdx === fromIdx || toIdx === fromIdx + 1)\n}\n\nexport function mapToKanbanColumn(status: OrderStatus): KanbanColumn {\n if (OUT_STATUSES.includes(status)) return 'out'\n if ((KANBAN_COLUMNS as string[]).includes(status) || status === 'cancelled') return status as KanbanColumn\n return 'new'\n}\n\n/** Which board an order runs on: the dining room pays after eating, delivery and takeout before. */\nexport type OrderService = 'salao' | 'delivery'\n\nexport function serviceOf(order: Pick<RestaurantOrder, 'kind'>): OrderService {\n return order.kind === 'dine_in' ? 'salao' : 'delivery'\n}\n\n/** The dining room has no \"new\" column: a comanda is open from the moment a waiter opens it. */\nexport function boardColumns(service: OrderService): KanbanColumn[] {\n return service === 'salao' ? KANBAN_COLUMNS.filter((id) => id !== 'new') : KANBAN_COLUMNS\n}\n\nexport function boardColumnOf(service: OrderService, status: OrderStatus): KanbanColumn {\n const column = mapToKanbanColumn(status)\n return service === 'salao' && column === 'new' ? 'confirmed' : column\n}\n\n/** The column this order sits in on `service`'s board, or null when it runs on the other board. */\nexport function boardColumnFor(service: OrderService, order: Pick<RestaurantOrder, 'kind' | 'status'>): KanbanColumn | null {\n return serviceOf(order) === service ? boardColumnOf(service, order.status) : null\n}\n\nexport function nextBoardColumn(service: OrderService, order: Pick<RestaurantOrder, 'kind' | 'status'>): KanbanColumn | null {\n const next = getNextStatus(order.kind, order.status)\n return next ? boardColumnOf(service, next) : null\n}\n\nexport function lineTotal(item: { quantity: number; unitPrice: number; discount?: number }): number {\n return item.quantity * item.unitPrice - (item.discount ?? 0)\n}\n\nexport function orderTotals(\n items: ReadonlyArray<{ total: number }>,\n adjustments: { discount?: number; tax?: number } = {},\n): { subtotal: number; total: number } {\n const subtotal = items.reduce((sum, item) => sum + item.total, 0)\n return { subtotal, total: subtotal - (adjustments.discount ?? 0) + (adjustments.tax ?? 0) }\n}\n\nexport function withCancellationNote(notes: string | undefined, reason?: string): string | undefined {\n if (!reason) return notes\n return notes ? `${notes}\\nCancelled: ${reason}` : `Cancelled: ${reason}`\n}\n\nexport function isoDay(date: Date | string = new Date()): string {\n return (typeof date === 'string' ? date : date.toISOString()).slice(0, 10)\n}\n\nexport function matchesQuery(order: RestaurantOrder, query: OrderQuery): boolean {\n if (query.kind && !asList(query.kind).includes(order.kind)) return false\n if (query.status && !asList(query.status).includes(order.status)) return false\n if (query.source && order.source !== query.source) return false\n if (query.tableId && order.tableId !== query.tableId) return false\n if (query.assigneeId && order.assigneeId !== query.assigneeId) return false\n if (query.dateRange) {\n const created = isoDay(order.createdAt)\n if (created < query.dateRange.from || created > query.dateRange.to) return false\n }\n if (query.search) {\n const search = query.search.toLowerCase()\n return order.referenceNumber.toLowerCase().includes(search)\n || (order.partyName?.toLowerCase().includes(search) ?? false)\n || (order.tableName?.toLowerCase().includes(search) ?? false)\n || order.items.some((item) => item.name.toLowerCase().includes(search))\n }\n return true\n}\n\nexport function paginate<T>(items: T[], page = 1, pageSize = 20): PaginatedResult<T> {\n const start = (page - 1) * pageSize\n return { data: items.slice(start, start + pageSize), total: items.length }\n}\n\n/** Counts orders created in the range (today by default); revenue and top items leave cancelled ones out. */\nexport function summarizeOrders(orders: RestaurantOrder[], dateRange?: DateRange, today = isoDay()): OrdersSummary {\n const from = dateRange?.from ?? today\n const to = dateRange?.to ?? today\n const inRange = orders.filter((order) => {\n const created = isoDay(order.createdAt)\n return created >= from && created <= to\n })\n const billable = inRange.filter((order) => order.status !== 'cancelled')\n const revenue = billable.reduce((sum, order) => sum + order.total, 0)\n const ordersByKind: Record<OrderKind, number> = { dine_in: 0, takeout: 0, delivery: 0 }\n const ordersByStatus: Record<string, number> = {}\n const top = new Map<string, { name: string; quantity: number; revenue: number }>()\n\n for (const order of inRange) {\n ordersByKind[order.kind] = (ordersByKind[order.kind] ?? 0) + 1\n ordersByStatus[order.status] = (ordersByStatus[order.status] ?? 0) + 1\n }\n for (const order of billable) {\n for (const item of order.items) {\n const current = top.get(item.name) ?? { name: item.name, quantity: 0, revenue: 0 }\n current.quantity += item.quantity\n current.revenue += item.total\n top.set(item.name, current)\n }\n }\n\n return {\n todayOrderCount: inRange.length,\n todayRevenue: revenue,\n averageTicket: billable.length > 0 ? revenue / billable.length : 0,\n activeOrderCount: orders.filter((order) => isActive(order.status)).length,\n ordersByKind,\n ordersByStatus,\n topItems: [...top.values()].sort((a, b) => b.quantity - a.quantity).slice(0, 5),\n }\n}\n\n/** Whether a sale produced a receivable (título), and how far it is paid. */\nexport type PaymentState = 'none' | 'pending' | 'partial' | 'paid' | 'overdue' | 'cancelled'\n\nexport function paymentStateOf(order: Pick<RestaurantOrder, 'metadata'>): PaymentState {\n return (order.metadata?.paymentStatus as PaymentState | undefined) ?? 'none'\n}\n\nexport type CommercialColumn = 'open' | 'no_invoice' | 'paid' | 'cancelled'\n\nexport function commercialColumnOf(order: Pick<RestaurantOrder, 'status' | 'metadata'>): CommercialColumn {\n if (order.status === 'cancelled') return 'cancelled'\n const state = paymentStateOf(order)\n if (state === 'paid') return 'paid'\n if (state === 'none') return 'no_invoice'\n return 'open'\n}\n\nfunction asList<T>(value: T | T[]): T[] {\n return Array.isArray(value) ? value : [value]\n}\n"]}
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ import type { RestaurantOrder } from '../domain/order';
3
+ export declare function CommercialOrderCard({ order, formatMoney }: {
4
+ order: RestaurantOrder;
5
+ formatMoney: (value: number) => string;
6
+ }): React.JSX.Element;
7
+ //# sourceMappingURL=CommercialOrderCard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CommercialOrderCard.d.ts","sourceRoot":"","sources":["../../src/components/CommercialOrderCard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEtD,wBAAgB,mBAAmB,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE;IAC1D,KAAK,EAAE,eAAe,CAAA;IACtB,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAA;CACvC,qBAcA"}
@@ -0,0 +1,18 @@
1
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
2
+
3
+ // src/components/CommercialOrderCard.tsx
4
+ function CommercialOrderCard({ order, formatMoney }) {
5
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
6
+ /* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center justify-between", children: [
7
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-bold", children: order.referenceNumber }),
8
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground", children: new Date(order.createdAt).toLocaleDateString("pt-BR") })
9
+ ] }),
10
+ order.partyName && /* @__PURE__ */ jsx("p", { className: "truncate text-sm font-medium", children: order.partyName }),
11
+ order.assigneeName && /* @__PURE__ */ jsx("p", { className: "truncate text-xs text-muted-foreground", children: order.assigneeName }),
12
+ /* @__PURE__ */ jsx("div", { className: "mt-3 border-t pt-2 text-sm font-bold", children: formatMoney(order.total) })
13
+ ] });
14
+ }
15
+
16
+ export { CommercialOrderCard };
17
+ //# sourceMappingURL=CommercialOrderCard.js.map
18
+ //# sourceMappingURL=CommercialOrderCard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/CommercialOrderCard.tsx"],"names":[],"mappings":";;;AAGO,SAAS,mBAAA,CAAoB,EAAE,KAAA,EAAO,WAAA,EAAY,EAGtD;AACD,EAAA,uBACE,IAAA,CAAA,QAAA,EAAA,EACE,QAAA,EAAA;AAAA,oBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,wCAAA,EACb,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,mBAAA,EAAqB,QAAA,EAAA,KAAA,CAAM,eAAA,EAAgB,CAAA;AAAA,sBAC3D,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,mCAAA,EACb,QAAA,EAAA,IAAI,IAAA,CAAK,KAAA,CAAM,SAAS,CAAA,CAAE,kBAAA,CAAmB,OAAO,CAAA,EACvD;AAAA,KAAA,EACF,CAAA;AAAA,IACC,MAAM,SAAA,oBAAa,GAAA,CAAC,OAAE,SAAA,EAAU,8BAAA,EAAgC,gBAAM,SAAA,EAAU,CAAA;AAAA,IAChF,MAAM,YAAA,oBAAgB,GAAA,CAAC,OAAE,SAAA,EAAU,wCAAA,EAA0C,gBAAM,YAAA,EAAa,CAAA;AAAA,wBAChG,KAAA,EAAA,EAAI,SAAA,EAAU,wCAAwC,QAAA,EAAA,WAAA,CAAY,KAAA,CAAM,KAAK,CAAA,EAAE;AAAA,GAAA,EAClF,CAAA;AAEJ","file":"CommercialOrderCard.js","sourcesContent":["import React from 'react'\nimport type { RestaurantOrder } from '../domain/order'\n\nexport function CommercialOrderCard({ order, formatMoney }: {\n order: RestaurantOrder\n formatMoney: (value: number) => string\n}) {\n return (\n <>\n <div className=\"mb-2 flex items-center justify-between\">\n <span className=\"text-sm font-bold\">{order.referenceNumber}</span>\n <span className=\"text-[10px] text-muted-foreground\">\n {new Date(order.createdAt).toLocaleDateString('pt-BR')}\n </span>\n </div>\n {order.partyName && <p className=\"truncate text-sm font-medium\">{order.partyName}</p>}\n {order.assigneeName && <p className=\"truncate text-xs text-muted-foreground\">{order.assigneeName}</p>}\n <div className=\"mt-3 border-t pt-2 text-sm font-bold\">{formatMoney(order.total)}</div>\n </>\n )\n}\n"]}
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import type { RestaurantOrder } from '../domain/order';
3
+ /** A card on the service board; `amount` is the host's money cell, so payment state can sit beside the total. */
4
+ export declare function OrderBoardCard({ order, sourceLabel, amount, now }: {
5
+ order: RestaurantOrder;
6
+ sourceLabel: string;
7
+ amount: React.ReactNode;
8
+ now?: number;
9
+ }): React.JSX.Element;
10
+ //# sourceMappingURL=OrderBoardCard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OrderBoardCard.d.ts","sourceRoot":"","sources":["../../src/components/OrderBoardCard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAQtD,iHAAiH;AACjH,wBAAgB,cAAc,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,GAAgB,EAAE,EAAE;IAC/E,KAAK,EAAE,eAAe,CAAA;IACtB,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,KAAK,CAAC,SAAS,CAAA;IACvB,GAAG,CAAC,EAAE,MAAM,CAAA;CACb,qBA6BA"}
@@ -0,0 +1,35 @@
1
+ import { Clock } from 'lucide-react';
2
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
3
+
4
+ // src/components/OrderBoardCard.tsx
5
+ function elapsed(createdAt, now) {
6
+ const minutes = Math.floor((now - new Date(createdAt).getTime()) / 6e4);
7
+ if (minutes < 1) return "agora";
8
+ return `${minutes}min`;
9
+ }
10
+ function OrderBoardCard({ order, sourceLabel, amount, now = Date.now() }) {
11
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
12
+ /* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center justify-between", children: [
13
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-bold", children: order.referenceNumber }),
14
+ /* @__PURE__ */ jsx("span", { className: "inline-flex items-center gap-1 rounded-full bg-muted px-2 py-0.5 text-[10px] font-medium", children: sourceLabel })
15
+ ] }),
16
+ order.partyName && /* @__PURE__ */ jsx("p", { className: "truncate text-sm font-medium", children: order.partyName }),
17
+ order.tableName && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: order.tableName }),
18
+ order.items.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-2 space-y-0.5", children: order.items.map((item) => /* @__PURE__ */ jsxs("p", { className: "truncate text-xs text-muted-foreground", children: [
19
+ item.quantity,
20
+ "x ",
21
+ item.name
22
+ ] }, item.id)) }),
23
+ /* @__PURE__ */ jsxs("div", { className: "mt-3 flex items-center justify-between gap-2 border-t pt-2", children: [
24
+ amount,
25
+ /* @__PURE__ */ jsxs("span", { className: "inline-flex shrink-0 items-center gap-0.5 text-[10px] text-muted-foreground", children: [
26
+ /* @__PURE__ */ jsx(Clock, { className: "h-3 w-3" }),
27
+ elapsed(order.createdAt, now)
28
+ ] })
29
+ ] })
30
+ ] });
31
+ }
32
+
33
+ export { OrderBoardCard };
34
+ //# sourceMappingURL=OrderBoardCard.js.map
35
+ //# sourceMappingURL=OrderBoardCard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/OrderBoardCard.tsx"],"names":[],"mappings":";;;;AAIA,SAAS,OAAA,CAAQ,WAAmB,GAAA,EAAqB;AACvD,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,KAAA,CAAA,CAAO,GAAA,GAAM,IAAI,KAAK,SAAS,CAAA,CAAE,OAAA,EAAQ,IAAK,GAAK,CAAA;AACxE,EAAA,IAAI,OAAA,GAAU,GAAG,OAAO,OAAA;AACxB,EAAA,OAAO,GAAG,OAAO,CAAA,GAAA,CAAA;AACnB;AAGO,SAAS,cAAA,CAAe,EAAE,KAAA,EAAO,WAAA,EAAa,QAAQ,GAAA,GAAM,IAAA,CAAK,GAAA,EAAI,EAAE,EAK3E;AACD,EAAA,uBACE,IAAA,CAAA,QAAA,EAAA,EACE,QAAA,EAAA;AAAA,oBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,wCAAA,EACb,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,mBAAA,EAAqB,QAAA,EAAA,KAAA,CAAM,eAAA,EAAgB,CAAA;AAAA,sBAC3D,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,0FAAA,EACb,QAAA,EAAA,WAAA,EACH;AAAA,KAAA,EACF,CAAA;AAAA,IACC,MAAM,SAAA,oBAAa,GAAA,CAAC,OAAE,SAAA,EAAU,8BAAA,EAAgC,gBAAM,SAAA,EAAU,CAAA;AAAA,IAChF,MAAM,SAAA,oBAAa,GAAA,CAAC,OAAE,SAAA,EAAU,+BAAA,EAAiC,gBAAM,SAAA,EAAU,CAAA;AAAA,IACjF,MAAM,KAAA,CAAM,MAAA,GAAS,CAAA,oBACpB,GAAA,CAAC,SAAI,SAAA,EAAU,kBAAA,EACZ,QAAA,EAAA,KAAA,CAAM,KAAA,CAAM,IAAI,CAAC,IAAA,qBAChB,IAAA,CAAC,GAAA,EAAA,EAAgB,WAAU,wCAAA,EACxB,QAAA,EAAA;AAAA,MAAA,IAAA,CAAK,QAAA;AAAA,MAAS,IAAA;AAAA,MAAG,IAAA,CAAK;AAAA,KAAA,EAAA,EADjB,IAAA,CAAK,EAEb,CACD,CAAA,EACH,CAAA;AAAA,oBAEF,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,4DAAA,EACZ,QAAA,EAAA;AAAA,MAAA,MAAA;AAAA,sBACD,IAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,6EAAA,EACd,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,KAAA,EAAA,EAAM,WAAU,SAAA,EAAU,CAAA;AAAA,QAC1B,OAAA,CAAQ,KAAA,CAAM,SAAA,EAAW,GAAG;AAAA,OAAA,EAC/B;AAAA,KAAA,EACF;AAAA,GAAA,EACF,CAAA;AAEJ","file":"OrderBoardCard.js","sourcesContent":["import React from 'react'\nimport { Clock } from 'lucide-react'\nimport type { RestaurantOrder } from '../domain/order'\n\nfunction elapsed(createdAt: string, now: number): string {\n const minutes = Math.floor((now - new Date(createdAt).getTime()) / 60000)\n if (minutes < 1) return 'agora'\n return `${minutes}min`\n}\n\n/** A card on the service board; `amount` is the host's money cell, so payment state can sit beside the total. */\nexport function OrderBoardCard({ order, sourceLabel, amount, now = Date.now() }: {\n order: RestaurantOrder\n sourceLabel: string\n amount: React.ReactNode\n now?: number\n}) {\n return (\n <>\n <div className=\"mb-2 flex items-center justify-between\">\n <span className=\"text-sm font-bold\">{order.referenceNumber}</span>\n <span className=\"inline-flex items-center gap-1 rounded-full bg-muted px-2 py-0.5 text-[10px] font-medium\">\n {sourceLabel}\n </span>\n </div>\n {order.partyName && <p className=\"truncate text-sm font-medium\">{order.partyName}</p>}\n {order.tableName && <p className=\"text-xs text-muted-foreground\">{order.tableName}</p>}\n {order.items.length > 0 && (\n <div className=\"mt-2 space-y-0.5\">\n {order.items.map((item) => (\n <p key={item.id} className=\"truncate text-xs text-muted-foreground\">\n {item.quantity}x {item.name}\n </p>\n ))}\n </div>\n )}\n <div className=\"mt-3 flex items-center justify-between gap-2 border-t pt-2\">\n {amount}\n <span className=\"inline-flex shrink-0 items-center gap-0.5 text-[10px] text-muted-foreground\">\n <Clock className=\"h-3 w-3\" />\n {elapsed(order.createdAt, now)}\n </span>\n </div>\n </>\n )\n}\n"]}
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import type { KanbanColumn } from '../domain/order';
3
+ export declare const KANBAN_COLUMN_COLOR: Record<KanbanColumn, string>;
4
+ export declare function OrderStatusDot({ column, label }: {
5
+ column: KanbanColumn;
6
+ label: string;
7
+ }): React.JSX.Element;
8
+ //# sourceMappingURL=OrderStatusDot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OrderStatusDot.d.ts","sourceRoot":"","sources":["../../src/components/OrderStatusDot.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAEnD,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAQ5D,CAAA;AAED,wBAAgB,cAAc,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,qBAOxF"}
@@ -0,0 +1,22 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+
3
+ // src/components/OrderStatusDot.tsx
4
+ var KANBAN_COLUMN_COLOR = {
5
+ new: "bg-violet-500",
6
+ confirmed: "bg-blue-500",
7
+ preparing: "bg-amber-500",
8
+ ready: "bg-emerald-500",
9
+ out: "bg-cyan-500",
10
+ completed: "bg-gray-400",
11
+ cancelled: "bg-red-500"
12
+ };
13
+ function OrderStatusDot({ column, label }) {
14
+ return /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1.5 text-sm", children: [
15
+ /* @__PURE__ */ jsx("span", { className: `h-2 w-2 rounded-full ${KANBAN_COLUMN_COLOR[column] ?? "bg-muted-foreground/40"}` }),
16
+ label
17
+ ] });
18
+ }
19
+
20
+ export { KANBAN_COLUMN_COLOR, OrderStatusDot };
21
+ //# sourceMappingURL=OrderStatusDot.js.map
22
+ //# sourceMappingURL=OrderStatusDot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/OrderStatusDot.tsx"],"names":[],"mappings":";;;AAGO,IAAM,mBAAA,GAAoD;AAAA,EAC/D,GAAA,EAAK,eAAA;AAAA,EACL,SAAA,EAAW,aAAA;AAAA,EACX,SAAA,EAAW,cAAA;AAAA,EACX,KAAA,EAAO,gBAAA;AAAA,EACP,GAAA,EAAK,aAAA;AAAA,EACL,SAAA,EAAW,aAAA;AAAA,EACX,SAAA,EAAW;AACb;AAEO,SAAS,cAAA,CAAe,EAAE,MAAA,EAAQ,KAAA,EAAM,EAA4C;AACzF,EAAA,uBACE,IAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,0CAAA,EACd,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,UAAK,SAAA,EAAW,CAAA,qBAAA,EAAwB,oBAAoB,MAAM,CAAA,IAAK,wBAAwB,CAAA,CAAA,EAAI,CAAA;AAAA,IACnG;AAAA,GAAA,EACH,CAAA;AAEJ","file":"OrderStatusDot.js","sourcesContent":["import React from 'react'\nimport type { KanbanColumn } from '../domain/order'\n\nexport const KANBAN_COLUMN_COLOR: Record<KanbanColumn, string> = {\n new: 'bg-violet-500',\n confirmed: 'bg-blue-500',\n preparing: 'bg-amber-500',\n ready: 'bg-emerald-500',\n out: 'bg-cyan-500',\n completed: 'bg-gray-400',\n cancelled: 'bg-red-500',\n}\n\nexport function OrderStatusDot({ column, label }: { column: KanbanColumn; label: string }) {\n return (\n <span className=\"inline-flex items-center gap-1.5 text-sm\">\n <span className={`h-2 w-2 rounded-full ${KANBAN_COLUMN_COLOR[column] ?? 'bg-muted-foreground/40'}`} />\n {label}\n </span>\n )\n}\n"]}
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ import type { PaymentState } from '../domain/order';
3
+ export declare function PaymentStateBadge({ state }: {
4
+ state: PaymentState;
5
+ }): React.JSX.Element;
6
+ //# sourceMappingURL=PaymentStateBadge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PaymentStateBadge.d.ts","sourceRoot":"","sources":["../../src/components/PaymentStateBadge.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAqBnD,wBAAgB,iBAAiB,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,YAAY,CAAA;CAAE,qBAEnE"}
@@ -0,0 +1,27 @@
1
+ import { Badge } from '@fayz-ai/ui';
2
+ import { jsx } from 'react/jsx-runtime';
3
+
4
+ // src/components/PaymentStateBadge.tsx
5
+ var LABEL = {
6
+ none: "Sem t\xEDtulo",
7
+ pending: "Em aberto",
8
+ partial: "Parcial",
9
+ paid: "Pago",
10
+ overdue: "Vencido",
11
+ cancelled: "Cancelado"
12
+ };
13
+ var VARIANT = {
14
+ none: "destructive",
15
+ pending: "warning",
16
+ partial: "info",
17
+ paid: "success",
18
+ overdue: "destructive",
19
+ cancelled: "default"
20
+ };
21
+ function PaymentStateBadge({ state }) {
22
+ return /* @__PURE__ */ jsx(Badge, { variant: VARIANT[state], children: LABEL[state] });
23
+ }
24
+
25
+ export { PaymentStateBadge };
26
+ //# sourceMappingURL=PaymentStateBadge.js.map
27
+ //# sourceMappingURL=PaymentStateBadge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/PaymentStateBadge.tsx"],"names":[],"mappings":";;;;AAIA,IAAM,KAAA,GAAsC;AAAA,EAC1C,IAAA,EAAM,eAAA;AAAA,EACN,OAAA,EAAS,WAAA;AAAA,EACT,OAAA,EAAS,SAAA;AAAA,EACT,IAAA,EAAM,MAAA;AAAA,EACN,OAAA,EAAS,SAAA;AAAA,EACT,SAAA,EAAW;AACb,CAAA;AAGA,IAAM,OAAA,GAAuD;AAAA,EAC3D,IAAA,EAAM,aAAA;AAAA,EACN,OAAA,EAAS,SAAA;AAAA,EACT,OAAA,EAAS,MAAA;AAAA,EACT,IAAA,EAAM,SAAA;AAAA,EACN,OAAA,EAAS,aAAA;AAAA,EACT,SAAA,EAAW;AACb,CAAA;AAEO,SAAS,iBAAA,CAAkB,EAAE,KAAA,EAAM,EAA4B;AACpE,EAAA,uBAAO,GAAA,CAAC,SAAM,OAAA,EAAS,OAAA,CAAQ,KAAK,CAAA,EAAI,QAAA,EAAA,KAAA,CAAM,KAAK,CAAA,EAAE,CAAA;AACvD","file":"PaymentStateBadge.js","sourcesContent":["import React from 'react'\nimport { Badge, type BadgeProps } from '@fayz-ai/ui'\nimport type { PaymentState } from '../domain/order'\n\nconst LABEL: Record<PaymentState, string> = {\n none: 'Sem título',\n pending: 'Em aberto',\n partial: 'Parcial',\n paid: 'Pago',\n overdue: 'Vencido',\n cancelled: 'Cancelado',\n}\n\n// \"Sem título\" has to catch the eye: it is the gap the commercial list exists to show.\nconst VARIANT: Record<PaymentState, BadgeProps['variant']> = {\n none: 'destructive',\n pending: 'warning',\n partial: 'info',\n paid: 'success',\n overdue: 'destructive',\n cancelled: 'default',\n}\n\nexport function PaymentStateBadge({ state }: { state: PaymentState }) {\n return <Badge variant={VARIANT[state]}>{LABEL[state]}</Badge>\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import type { OrdersDataProvider } from './provider';
2
+ export declare function createMockOrdersProvider(): OrdersDataProvider;
3
+ //# sourceMappingURL=mock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock.d.ts","sourceRoot":"","sources":["../../src/data/mock.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AA4FpD,wBAAgB,wBAAwB,IAAI,kBAAkB,CA0H7D"}