@fayz-ai/plugin-orders 0.8.0 → 0.9.0-next.1
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/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/package.json +15 -12
- package/src/index.ts +7 -0
- package/dist/OrdersPage-UJCY6ZYU.cjs +0 -157
- package/dist/OrdersPage-UJCY6ZYU.cjs.map +0 -1
- package/dist/chunk-7RWH37O4.cjs +0 -28
- package/dist/chunk-7RWH37O4.cjs.map +0 -1
- package/dist/index.cjs +0 -1185
- package/dist/index.cjs.map +0 -1
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var chunk7RWH37O4_cjs = require('./chunk-7RWH37O4.cjs');
|
|
4
|
-
var saas = require('@fayz-ai/saas');
|
|
5
|
-
var react = require('react');
|
|
6
|
-
var lucideReact = require('lucide-react');
|
|
7
|
-
var core = require('@fayz-ai/core');
|
|
8
|
-
var jsxRuntime = require('react/jsx-runtime');
|
|
9
|
-
|
|
10
|
-
var ctx = saas.createPluginContext("OrdersPage");
|
|
11
|
-
var OrdersContextProvider = ctx.ContextProvider;
|
|
12
|
-
var useOrdersConfig = ctx.useConfig;
|
|
13
|
-
ctx.useProvider;
|
|
14
|
-
var useOrdersStore = ctx.useStore;
|
|
15
|
-
var COLUMN_CONFIG = {
|
|
16
|
-
new: { color: "bg-violet-500" },
|
|
17
|
-
confirmed: { color: "bg-blue-500" },
|
|
18
|
-
preparing: { color: "bg-amber-500" },
|
|
19
|
-
ready: { color: "bg-emerald-500" },
|
|
20
|
-
out: { color: "bg-cyan-500" },
|
|
21
|
-
completed: { color: "bg-gray-400" },
|
|
22
|
-
cancelled: { color: "bg-red-500" }
|
|
23
|
-
};
|
|
24
|
-
function timeAgo(dateStr) {
|
|
25
|
-
const diff = Math.floor((Date.now() - new Date(dateStr).getTime()) / 6e4);
|
|
26
|
-
if (diff < 1) return "just now";
|
|
27
|
-
if (diff === 1) return "1min";
|
|
28
|
-
return `${diff}min`;
|
|
29
|
-
}
|
|
30
|
-
function OrderCard({
|
|
31
|
-
order,
|
|
32
|
-
onAdvance,
|
|
33
|
-
onSelect,
|
|
34
|
-
currency
|
|
35
|
-
}) {
|
|
36
|
-
const t = core.useTranslation();
|
|
37
|
-
const sourceLabel = t(`orders.source.${order.source}`) !== `orders.source.${order.source}` ? t(`orders.source.${order.source}`) : order.source;
|
|
38
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
39
|
-
"div",
|
|
40
|
-
{
|
|
41
|
-
className: "rounded-lg border bg-card p-3 hover:shadow-md transition-shadow cursor-pointer",
|
|
42
|
-
onClick: onSelect,
|
|
43
|
-
children: [
|
|
44
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-2", children: [
|
|
45
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-bold", children: order.referenceNumber }),
|
|
46
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex items-center gap-1 rounded-full bg-muted px-2 py-0.5 text-[10px] font-medium", children: sourceLabel })
|
|
47
|
-
] }),
|
|
48
|
-
order.partyName && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium truncate", children: order.partyName }),
|
|
49
|
-
order.tableName && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: order.tableName }),
|
|
50
|
-
order.items.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 space-y-0.5", children: order.items.map((item) => /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-muted-foreground truncate", children: [
|
|
51
|
-
item.quantity,
|
|
52
|
-
"x ",
|
|
53
|
-
item.name
|
|
54
|
-
] }, item.id)) }),
|
|
55
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mt-3 pt-2 border-t", children: [
|
|
56
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-bold", children: saas.formatCurrency(order.total, currency) }),
|
|
57
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-0.5 text-[10px] text-muted-foreground", children: [
|
|
58
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { className: "h-3 w-3" }),
|
|
59
|
-
timeAgo(order.createdAt)
|
|
60
|
-
] })
|
|
61
|
-
] }),
|
|
62
|
-
onAdvance && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
63
|
-
"button",
|
|
64
|
-
{
|
|
65
|
-
type: "button",
|
|
66
|
-
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",
|
|
67
|
-
onClick: (e) => {
|
|
68
|
-
e.stopPropagation();
|
|
69
|
-
onAdvance();
|
|
70
|
-
},
|
|
71
|
-
children: [
|
|
72
|
-
t("orders.kanban.advance"),
|
|
73
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-3 w-3" })
|
|
74
|
-
]
|
|
75
|
-
}
|
|
76
|
-
)
|
|
77
|
-
]
|
|
78
|
-
}
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
|
-
function SkeletonColumn() {
|
|
82
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-shrink-0 w-72", children: [
|
|
83
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-9 rounded-lg bg-muted animate-pulse mb-3" }),
|
|
84
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-3", children: [1, 2, 3].map((i) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-32 rounded-lg bg-muted/60 animate-pulse" }, i)) })
|
|
85
|
-
] });
|
|
86
|
-
}
|
|
87
|
-
function OrderKanbanView() {
|
|
88
|
-
const t = core.useTranslation();
|
|
89
|
-
const config = useOrdersConfig();
|
|
90
|
-
const activeOrders = useOrdersStore((s) => s.activeOrders);
|
|
91
|
-
const activeOrdersLoading = useOrdersStore((s) => s.activeOrdersLoading);
|
|
92
|
-
const fetchActiveOrders = useOrdersStore((s) => s.fetchActiveOrders);
|
|
93
|
-
const advanceOrderStatus = useOrdersStore((s) => s.advanceOrderStatus);
|
|
94
|
-
const selectOrder = useOrdersStore((s) => s.selectOrder);
|
|
95
|
-
react.useEffect(() => {
|
|
96
|
-
fetchActiveOrders();
|
|
97
|
-
}, [fetchActiveOrders]);
|
|
98
|
-
const grouped = react.useMemo(() => {
|
|
99
|
-
const map = {
|
|
100
|
-
new: [],
|
|
101
|
-
confirmed: [],
|
|
102
|
-
preparing: [],
|
|
103
|
-
ready: [],
|
|
104
|
-
out: [],
|
|
105
|
-
completed: [],
|
|
106
|
-
cancelled: []
|
|
107
|
-
};
|
|
108
|
-
for (const order of activeOrders) {
|
|
109
|
-
const col = chunk7RWH37O4_cjs.mapToKanbanColumn(order.status);
|
|
110
|
-
map[col].push(order);
|
|
111
|
-
}
|
|
112
|
-
return map;
|
|
113
|
-
}, [activeOrders]);
|
|
114
|
-
if (activeOrdersLoading && activeOrders.length === 0) {
|
|
115
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-4 overflow-x-auto pb-4", children: chunk7RWH37O4_cjs.KANBAN_COLUMNS.map((col) => /* @__PURE__ */ jsxRuntime.jsx(SkeletonColumn, {}, col)) });
|
|
116
|
-
}
|
|
117
|
-
if (!activeOrdersLoading && activeOrders.length === 0) {
|
|
118
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center h-64 text-center", children: [
|
|
119
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ClipboardList, { className: "h-12 w-12 text-muted-foreground/40 mb-3" }),
|
|
120
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-muted-foreground", children: t("orders.kanban.noOrders") }),
|
|
121
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground/70 mt-1", children: t("orders.kanban.noOrdersDesc") })
|
|
122
|
-
] });
|
|
123
|
-
}
|
|
124
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-4 overflow-x-auto pb-4", children: chunk7RWH37O4_cjs.KANBAN_COLUMNS.map((col) => {
|
|
125
|
-
const columnOrders = grouped[col];
|
|
126
|
-
const colConfig = COLUMN_CONFIG[col];
|
|
127
|
-
const label = t(`orders.kanban.column.${col}`);
|
|
128
|
-
const hasNext = (order) => chunk7RWH37O4_cjs.getNextStatus(order.kind, order.status) !== null;
|
|
129
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-shrink-0 w-72", children: [
|
|
130
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 px-3 py-2 rounded-lg mb-3", children: [
|
|
131
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: `h-2.5 w-2.5 rounded-full ${colConfig.color}` }),
|
|
132
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold", children: label }),
|
|
133
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-auto inline-flex items-center justify-center rounded-full bg-muted px-2 py-0.5 text-xs font-medium", children: columnOrders.length })
|
|
134
|
-
] }),
|
|
135
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3 max-h-[calc(100vh-16rem)] overflow-y-auto pr-1", children: [
|
|
136
|
-
columnOrders.map((order) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
137
|
-
OrderCard,
|
|
138
|
-
{
|
|
139
|
-
order,
|
|
140
|
-
currency: config.currency,
|
|
141
|
-
onSelect: () => selectOrder(order.id),
|
|
142
|
-
onAdvance: hasNext(order) ? () => advanceOrderStatus(order.id) : void 0
|
|
143
|
-
},
|
|
144
|
-
order.id
|
|
145
|
-
)),
|
|
146
|
-
columnOrders.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center py-8 text-sm text-muted-foreground rounded-lg border border-dashed", children: t("orders.kanban.noOrders") })
|
|
147
|
-
] })
|
|
148
|
-
] }, col);
|
|
149
|
-
}) });
|
|
150
|
-
}
|
|
151
|
-
function OrdersPage({ config, provider, store, registries }) {
|
|
152
|
-
return /* @__PURE__ */ jsxRuntime.jsx(OrdersContextProvider, { config, provider, store, children: /* @__PURE__ */ jsxRuntime.jsx(OrderKanbanView, {}) });
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
exports.OrdersPage = OrdersPage;
|
|
156
|
-
//# sourceMappingURL=OrdersPage-UJCY6ZYU.cjs.map
|
|
157
|
-
//# sourceMappingURL=OrdersPage-UJCY6ZYU.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/OrdersContext.tsx","../src/views/OrderKanbanView.tsx","../src/OrdersPage.tsx"],"names":["createPluginContext","useTranslation","jsxs","jsx","Clock","ChevronRight","useEffect","useMemo","mapToKanbanColumn","KANBAN_COLUMNS","ClipboardList","getNextStatus"],"mappings":"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","file":"OrdersPage-UJCY6ZYU.cjs","sourcesContent":["import { createPluginContext, formatCurrency, type CurrencyConfig, type EntityLookup } from '@fayz-ai/saas'\nimport type { OrdersDataProvider } from './data/types'\nimport type { OrdersUIState } from './store'\nimport type { RestaurantOrder } from './types'\n\n// ---------------------------------------------------------------------------\n// Resolved config — fully merged, no optionals\n// ---------------------------------------------------------------------------\n\nexport interface OrdersModules {\n delivery: boolean\n takeout: boolean\n}\n\nexport type OrdersCurrency = CurrencyConfig\n\nexport interface OrderSourceOption {\n value: string\n label: string\n icon?: string\n}\n\nexport interface OrdersPluginLabels {\n pageTitle: string\n pageSubtitle: string\n orderSingular: string\n orderPlural: string\n}\n\nexport interface ResolvedOrdersConfig {\n modules: OrdersModules\n labels: OrdersPluginLabels\n currency: OrdersCurrency\n orderSources: OrderSourceOption[]\n menuItemLookup?: EntityLookup\n staffLookup?: EntityLookup\n onOrderCompleted?: (order: RestaurantOrder) => Promise<void>\n}\n\nconst ctx = createPluginContext<ResolvedOrdersConfig, OrdersDataProvider, OrdersUIState>('OrdersPage')\n\nexport const OrdersContextProvider = ctx.ContextProvider\nexport const useOrdersConfig = ctx.useConfig\nexport const useOrdersProvider = ctx.useProvider\nexport const useOrdersStore = ctx.useStore\n\nexport { formatCurrency }\n","import React, { useEffect, useMemo } from 'react'\nimport { ChevronRight, Clock, Loader2, ClipboardList } from 'lucide-react'\nimport { useOrdersConfig, useOrdersStore, formatCurrency } from '../OrdersContext'\nimport { useTranslation } from '@fayz-ai/core'\nimport {\n KANBAN_COLUMNS,\n mapToKanbanColumn,\n getNextStatus,\n type KanbanColumn,\n type RestaurantOrder,\n} from '../types'\n\n// ---------------------------------------------------------------------------\n// Column config\n// ---------------------------------------------------------------------------\n\nconst COLUMN_CONFIG: Record<KanbanColumn, { color: string }> = {\n new: { color: 'bg-violet-500' },\n confirmed: { color: 'bg-blue-500' },\n preparing: { color: 'bg-amber-500' },\n ready: { color: 'bg-emerald-500' },\n out: { color: 'bg-cyan-500' },\n completed: { color: 'bg-gray-400' },\n cancelled: { color: 'bg-red-500' },\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction timeAgo(dateStr: string): string {\n const diff = Math.floor((Date.now() - new Date(dateStr).getTime()) / 60000)\n if (diff < 1) return 'just now'\n if (diff === 1) return '1min'\n return `${diff}min`\n}\n\n// ---------------------------------------------------------------------------\n// Order Card\n// ---------------------------------------------------------------------------\n\nfunction OrderCard({\n order,\n onAdvance,\n onSelect,\n currency,\n}: {\n order: RestaurantOrder\n onAdvance?: () => void\n onSelect: () => void\n currency: { code: string; locale: string; symbol: string }\n}) {\n const t = useTranslation()\n const sourceLabel = t(`orders.source.${order.source}`) !== `orders.source.${order.source}`\n ? t(`orders.source.${order.source}`)\n : order.source\n\n return (\n <div\n className=\"rounded-lg border bg-card p-3 hover:shadow-md transition-shadow cursor-pointer\"\n onClick={onSelect}\n >\n {/* Header: order number + source badge */}\n <div className=\"flex items-center justify-between mb-2\">\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\n {/* Customer + table */}\n {order.partyName && (\n <p className=\"text-sm font-medium truncate\">{order.partyName}</p>\n )}\n {order.tableName && (\n <p className=\"text-xs text-muted-foreground\">{order.tableName}</p>\n )}\n\n {/* Items */}\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=\"text-xs text-muted-foreground truncate\">\n {item.quantity}x {item.name}\n </p>\n ))}\n </div>\n )}\n\n {/* Total + time */}\n <div className=\"flex items-center justify-between mt-3 pt-2 border-t\">\n <span className=\"text-sm font-bold\">\n {formatCurrency(order.total, currency)}\n </span>\n <span className=\"inline-flex items-center gap-0.5 text-[10px] text-muted-foreground\">\n <Clock className=\"h-3 w-3\" />\n {timeAgo(order.createdAt)}\n </span>\n </div>\n\n {/* Advance button */}\n {onAdvance && (\n <button\n type=\"button\"\n 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\"\n onClick={(e) => {\n e.stopPropagation()\n onAdvance()\n }}\n >\n {t('orders.kanban.advance')}\n <ChevronRight className=\"h-3 w-3\" />\n </button>\n )}\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Skeleton column (loading state)\n// ---------------------------------------------------------------------------\n\nfunction SkeletonColumn() {\n return (\n <div className=\"flex-shrink-0 w-72\">\n <div className=\"h-9 rounded-lg bg-muted animate-pulse mb-3\" />\n <div className=\"space-y-3\">\n {[1, 2, 3].map((i) => (\n <div key={i} className=\"h-32 rounded-lg bg-muted/60 animate-pulse\" />\n ))}\n </div>\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// OrderKanbanView\n// ---------------------------------------------------------------------------\n\nexport function OrderKanbanView() {\n const t = useTranslation()\n const config = useOrdersConfig()\n\n const activeOrders = useOrdersStore((s) => s.activeOrders)\n const activeOrdersLoading = useOrdersStore((s) => s.activeOrdersLoading)\n const fetchActiveOrders = useOrdersStore((s) => s.fetchActiveOrders)\n const advanceOrderStatus = useOrdersStore((s) => s.advanceOrderStatus)\n const selectOrder = useOrdersStore((s) => s.selectOrder)\n\n useEffect(() => {\n fetchActiveOrders()\n }, [fetchActiveOrders])\n\n // Group orders by kanban column\n const grouped = useMemo(() => {\n const map: Record<KanbanColumn, RestaurantOrder[]> = {\n new: [],\n confirmed: [],\n preparing: [],\n ready: [],\n out: [],\n completed: [],\n cancelled: [],\n }\n for (const order of activeOrders) {\n const col = mapToKanbanColumn(order.status)\n map[col].push(order)\n }\n return map\n }, [activeOrders])\n\n // Loading state\n if (activeOrdersLoading && activeOrders.length === 0) {\n return (\n <div className=\"flex gap-4 overflow-x-auto pb-4\">\n {KANBAN_COLUMNS.map((col) => (\n <SkeletonColumn key={col} />\n ))}\n </div>\n )\n }\n\n // Empty state\n if (!activeOrdersLoading && activeOrders.length === 0) {\n return (\n <div className=\"flex flex-col items-center justify-center h-64 text-center\">\n <ClipboardList className=\"h-12 w-12 text-muted-foreground/40 mb-3\" />\n <p className=\"text-sm font-medium text-muted-foreground\">\n {t('orders.kanban.noOrders')}\n </p>\n <p className=\"text-xs text-muted-foreground/70 mt-1\">\n {t('orders.kanban.noOrdersDesc')}\n </p>\n </div>\n )\n }\n\n return (\n <div className=\"flex gap-4 overflow-x-auto pb-4\">\n {KANBAN_COLUMNS.map((col) => {\n const columnOrders = grouped[col]\n const colConfig = COLUMN_CONFIG[col]\n const label = t(`orders.kanban.column.${col}`)\n const hasNext = (order: RestaurantOrder) =>\n getNextStatus(order.kind, order.status) !== null\n\n return (\n <div key={col} className=\"flex-shrink-0 w-72\">\n {/* Column header */}\n <div className=\"flex items-center gap-2 px-3 py-2 rounded-lg mb-3\">\n <span className={`h-2.5 w-2.5 rounded-full ${colConfig.color}`} />\n <span className=\"text-sm font-semibold\">{label}</span>\n <span className=\"ml-auto inline-flex items-center justify-center rounded-full bg-muted px-2 py-0.5 text-xs font-medium\">\n {columnOrders.length}\n </span>\n </div>\n\n {/* Cards */}\n <div className=\"space-y-3 max-h-[calc(100vh-16rem)] overflow-y-auto pr-1\">\n {columnOrders.map((order) => (\n <OrderCard\n key={order.id}\n order={order}\n currency={config.currency}\n onSelect={() => selectOrder(order.id)}\n onAdvance={hasNext(order) ? () => advanceOrderStatus(order.id) : undefined}\n />\n ))}\n {columnOrders.length === 0 && (\n <div className=\"text-center py-8 text-sm text-muted-foreground rounded-lg border border-dashed\">\n {t('orders.kanban.noOrders')}\n </div>\n )}\n </div>\n </div>\n )\n })}\n </div>\n )\n}\n","import React from 'react'\nimport type { StoreApi } from 'zustand/vanilla'\nimport { OrdersContextProvider, type ResolvedOrdersConfig } from './OrdersContext'\nimport { OrderKanbanView } from './views/OrderKanbanView'\nimport type { OrdersDataProvider } from './data/types'\nimport type { OrdersUIState } from './store'\nimport type { PluginRegistryDef } from '@fayz-ai/core'\n\nexport function OrdersPage({ config, provider, store, registries }: {\n config: ResolvedOrdersConfig\n provider: OrdersDataProvider\n store: StoreApi<OrdersUIState>\n registries?: PluginRegistryDef[]\n}) {\n return (\n <OrdersContextProvider config={config} provider={provider} store={store}>\n <OrderKanbanView />\n </OrdersContextProvider>\n )\n}\n"]}
|
package/dist/chunk-7RWH37O4.cjs
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
// src/types.ts
|
|
4
|
-
var STATUS_FLOW = {
|
|
5
|
-
dine_in: ["new", "confirmed", "preparing", "ready", "served", "completed"],
|
|
6
|
-
takeout: ["new", "confirmed", "preparing", "ready", "picked_up", "completed"],
|
|
7
|
-
delivery: ["new", "confirmed", "preparing", "ready", "dispatched", "delivered", "completed"]
|
|
8
|
-
};
|
|
9
|
-
function getNextStatus(kind, current) {
|
|
10
|
-
const flow = STATUS_FLOW[kind];
|
|
11
|
-
const idx = flow.indexOf(current);
|
|
12
|
-
return idx >= 0 && idx < flow.length - 1 ? flow[idx + 1] : null;
|
|
13
|
-
}
|
|
14
|
-
function mapToKanbanColumn(status) {
|
|
15
|
-
if (["served", "picked_up", "dispatched", "delivered"].includes(status)) return "out";
|
|
16
|
-
if (["new", "confirmed", "preparing", "ready", "completed", "cancelled"].includes(status)) {
|
|
17
|
-
return status;
|
|
18
|
-
}
|
|
19
|
-
return "new";
|
|
20
|
-
}
|
|
21
|
-
var KANBAN_COLUMNS = ["new", "confirmed", "preparing", "ready", "out", "completed"];
|
|
22
|
-
|
|
23
|
-
exports.KANBAN_COLUMNS = KANBAN_COLUMNS;
|
|
24
|
-
exports.STATUS_FLOW = STATUS_FLOW;
|
|
25
|
-
exports.getNextStatus = getNextStatus;
|
|
26
|
-
exports.mapToKanbanColumn = mapToKanbanColumn;
|
|
27
|
-
//# sourceMappingURL=chunk-7RWH37O4.cjs.map
|
|
28
|
-
//# sourceMappingURL=chunk-7RWH37O4.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts"],"names":[],"mappings":";;;AAsBO,IAAM,WAAA,GAAgD;AAAA,EAC3D,SAAS,CAAC,KAAA,EAAO,aAAa,WAAA,EAAa,OAAA,EAAS,UAAU,WAAW,CAAA;AAAA,EACzE,SAAS,CAAC,KAAA,EAAO,aAAa,WAAA,EAAa,OAAA,EAAS,aAAa,WAAW,CAAA;AAAA,EAC5E,QAAA,EAAU,CAAC,KAAA,EAAO,WAAA,EAAa,aAAa,OAAA,EAAS,YAAA,EAAc,aAAa,WAAW;AAC7F;AAEO,SAAS,aAAA,CAAc,MAAiB,OAAA,EAA0C;AACvF,EAAA,MAAM,IAAA,GAAO,YAAY,IAAI,CAAA;AAC7B,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,OAAA,CAAQ,OAAO,CAAA;AAChC,EAAA,OAAO,GAAA,IAAO,KAAK,GAAA,GAAM,IAAA,CAAK,SAAS,CAAA,GAAI,IAAA,CAAK,GAAA,GAAM,CAAC,CAAA,GAAI,IAAA;AAC7D;AAQO,SAAS,kBAAkB,MAAA,EAAmC;AACnE,EAAA,IAAI,CAAC,UAAU,WAAA,EAAa,YAAA,EAAc,WAAW,CAAA,CAAE,QAAA,CAAS,MAAM,CAAA,EAAG,OAAO,KAAA;AAChF,EAAA,IAAI,CAAC,KAAA,EAAO,WAAA,EAAa,WAAA,EAAa,OAAA,EAAS,aAAa,WAAW,CAAA,CAAE,QAAA,CAAS,MAAM,CAAA,EAAG;AACzF,IAAA,OAAO,MAAA;AAAA,EACT;AACA,EAAA,OAAO,KAAA;AACT;AAEO,IAAM,iBAAiC,CAAC,KAAA,EAAO,aAAa,WAAA,EAAa,OAAA,EAAS,OAAO,WAAW","file":"chunk-7RWH37O4.cjs","sourcesContent":["// ---------------------------------------------------------------------------\n// Orders Plugin — Pure TypeScript types\n// ---------------------------------------------------------------------------\n\n// ============================================================\n// ENUMS / LITERALS\n// ============================================================\n\nexport type OrderKind = 'dine_in' | 'takeout' | 'delivery'\n\nexport type DineInStatus = 'new' | 'confirmed' | 'preparing' | 'ready' | 'served' | 'completed' | 'cancelled'\nexport type TakeoutStatus = 'new' | 'confirmed' | 'preparing' | 'ready' | 'picked_up' | 'completed' | 'cancelled'\nexport type DeliveryStatus = 'new' | 'confirmed' | 'preparing' | 'ready' | 'dispatched' | 'delivered' | 'completed' | 'cancelled'\nexport type OrderStatus = DineInStatus | TakeoutStatus | DeliveryStatus\n\n/** Unified columns for the kanban board */\nexport type KanbanColumn = 'new' | 'confirmed' | 'preparing' | 'ready' | 'out' | 'completed' | 'cancelled'\n\n// ============================================================\n// STATUS FLOW\n// ============================================================\n\nexport const STATUS_FLOW: Record<OrderKind, OrderStatus[]> = {\n dine_in: ['new', 'confirmed', 'preparing', 'ready', 'served', 'completed'],\n takeout: ['new', 'confirmed', 'preparing', 'ready', 'picked_up', 'completed'],\n delivery: ['new', 'confirmed', 'preparing', 'ready', 'dispatched', 'delivered', 'completed'],\n}\n\nexport function getNextStatus(kind: OrderKind, current: OrderStatus): OrderStatus | null {\n const flow = STATUS_FLOW[kind]\n const idx = flow.indexOf(current)\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\nexport function mapToKanbanColumn(status: OrderStatus): KanbanColumn {\n if (['served', 'picked_up', 'dispatched', 'delivered'].includes(status)) return 'out'\n if (['new', 'confirmed', 'preparing', 'ready', 'completed', 'cancelled'].includes(status)) {\n return status as KanbanColumn\n }\n return 'new'\n}\n\nexport const KANBAN_COLUMNS: KanbanColumn[] = ['new', 'confirmed', 'preparing', 'ready', 'out', 'completed']\n\n// ============================================================\n// CORE ENTITIES\n// ============================================================\n\n/** Restaurant order — public.orders + public.orders extension */\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 // Extension fields\n source: string\n tableId?: string\n tableName?: string\n estimatedMinutes?: number\n items: RestaurantOrderItem[]\n metadata?: Record<string, unknown>\n tenantId: 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\n// ============================================================\n// INPUT TYPES\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\n// ============================================================\n// QUERY TYPES\n// ============================================================\n\nexport interface OrderQuery {\n kind?: OrderKind | OrderKind[]\n status?: OrderStatus | OrderStatus[]\n source?: string\n tableId?: string\n assigneeId?: string\n dateRange?: { from: string; to: string }\n search?: string\n page?: number\n pageSize?: number\n}\n\nexport interface PaginatedResult<T> {\n data: T[]\n total: number\n}\n\n// ============================================================\n// AGGREGATION\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\n// ============================================================\n// STATUS CONFIG\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"]}
|