@fayz-ai/plugin-orders 0.11.0 → 0.11.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/{OrdersPage-KNG54KEB.js → OrdersPage-CQ7O74ZW.js} +3 -3
- package/dist/{OrdersPage-KNG54KEB.js.map → OrdersPage-CQ7O74ZW.js.map} +1 -1
- package/dist/{chunk-LUFSNZYT.js → chunk-MTVIXIPL.js} +2 -2
- package/dist/{chunk-LUFSNZYT.js.map → chunk-MTVIXIPL.js.map} +1 -1
- package/dist/data/platform.d.ts +4 -3
- package/dist/data/platform.d.ts.map +1 -1
- package/dist/index.js +118 -38
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +7 -4
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { mapToKanbanColumn, KANBAN_COLUMNS, getNextStatus } from './chunk-
|
|
1
|
+
import { mapToKanbanColumn, KANBAN_COLUMNS, getNextStatus } from './chunk-MTVIXIPL.js';
|
|
2
2
|
import { createPluginContext, formatCurrency } from '@fayz-ai/admin';
|
|
3
3
|
import { useEffect, useMemo } from 'react';
|
|
4
4
|
import { ClipboardList, Clock, ChevronRight } from 'lucide-react';
|
|
@@ -151,5 +151,5 @@ function OrdersPage({ config, provider, store, registries }) {
|
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
export { OrdersPage };
|
|
154
|
-
//# sourceMappingURL=OrdersPage-
|
|
155
|
-
//# sourceMappingURL=OrdersPage-
|
|
154
|
+
//# sourceMappingURL=OrdersPage-CQ7O74ZW.js.map
|
|
155
|
+
//# sourceMappingURL=OrdersPage-CQ7O74ZW.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/context.tsx","../src/views/OrderKanbanView.tsx","../src/views/OrdersPage.tsx"],"names":["jsx"],"mappings":"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","file":"OrdersPage-KNG54KEB.js","sourcesContent":["import { createPluginContext, formatCurrency, type CurrencyConfig, type EntityLookup } from '@fayz-ai/admin'\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 '../context'\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-card 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 '../context'\nimport { OrderKanbanView } from './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"]}
|
|
1
|
+
{"version":3,"sources":["../src/context.tsx","../src/views/OrderKanbanView.tsx","../src/views/OrdersPage.tsx"],"names":["jsx"],"mappings":"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","file":"OrdersPage-CQ7O74ZW.js","sourcesContent":["import { createPluginContext, formatCurrency, type CurrencyConfig, type EntityLookup } from '@fayz-ai/admin'\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 '../context'\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-card 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 '../context'\nimport { OrderKanbanView } from './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"]}
|
|
@@ -19,5 +19,5 @@ function mapToKanbanColumn(status) {
|
|
|
19
19
|
var KANBAN_COLUMNS = ["new", "confirmed", "preparing", "ready", "out", "completed"];
|
|
20
20
|
|
|
21
21
|
export { KANBAN_COLUMNS, STATUS_FLOW, getNextStatus, mapToKanbanColumn };
|
|
22
|
-
//# sourceMappingURL=chunk-
|
|
23
|
-
//# sourceMappingURL=chunk-
|
|
22
|
+
//# sourceMappingURL=chunk-MTVIXIPL.js.map
|
|
23
|
+
//# sourceMappingURL=chunk-MTVIXIPL.js.map
|
|
@@ -1 +1 @@
|
|
|
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-
|
|
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-MTVIXIPL.js","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 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\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"]}
|
package/dist/data/platform.d.ts
CHANGED
|
@@ -8,11 +8,12 @@ export interface FayzOrdersProviderOptions extends FayzClientOptions {
|
|
|
8
8
|
orderItemsTable?: string;
|
|
9
9
|
/**
|
|
10
10
|
* Active tenant id (or a getter) used to scope reads and stamp writes on the
|
|
11
|
-
* orders
|
|
12
|
-
*
|
|
13
|
-
* parent order, so this never touches the order-items table.
|
|
11
|
+
* canonical orders and order_items tables. When omitted, scoping is left to
|
|
12
|
+
* the runtime/RLS context.
|
|
14
13
|
*/
|
|
15
14
|
tenantId?: string | (() => string | undefined | null);
|
|
15
|
+
/** Active unit id stamped on new orders and their items when available. */
|
|
16
|
+
unitId?: string | (() => string | undefined | null);
|
|
16
17
|
}
|
|
17
18
|
export declare function createFayzOrdersProvider(options?: FayzOrdersProviderOptions): OrdersDataProvider;
|
|
18
19
|
//# sourceMappingURL=platform.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../../src/data/platform.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,iBAAiB,EAAwB,MAAM,cAAc,CAAA;AAa7F,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAEjD,MAAM,WAAW,yBAA0B,SAAQ,iBAAiB;IAClE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB
|
|
1
|
+
{"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../../src/data/platform.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,iBAAiB,EAAwB,MAAM,cAAc,CAAA;AAa7F,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAEjD,MAAM,WAAW,yBAA0B,SAAQ,iBAAiB;IAClE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC,CAAA;IACrD,2EAA2E;IAC3E,MAAM,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC,CAAA;CACpD;AAwVD,wBAAgB,wBAAwB,CAAC,OAAO,GAAE,yBAA8B,GAAG,kBAAkB,CAmMpG"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getNextStatus, STATUS_FLOW } from './chunk-
|
|
1
|
+
import { getNextStatus, STATUS_FLOW } from './chunk-MTVIXIPL.js';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { createStore } from 'zustand/vanilla';
|
|
4
4
|
import { fayzConnectorOAuth, PluginSettingsPanel, dedup } from '@fayz-ai/admin';
|
|
@@ -1130,7 +1130,20 @@ var aiqfomeConnectorDef = {
|
|
|
1130
1130
|
};
|
|
1131
1131
|
var DEFAULT_ORDERS_TABLE = "orders";
|
|
1132
1132
|
var DEFAULT_ORDER_ITEMS_TABLE = "order_items";
|
|
1133
|
+
var ORDERS_METADATA_KEY = "fayzOrders";
|
|
1133
1134
|
var ACTIVE_STATUSES = /* @__PURE__ */ new Set(["new", "confirmed", "preparing", "ready", "served", "dispatched"]);
|
|
1135
|
+
var RESTAURANT_STATUSES = /* @__PURE__ */ new Set([
|
|
1136
|
+
"new",
|
|
1137
|
+
"confirmed",
|
|
1138
|
+
"preparing",
|
|
1139
|
+
"ready",
|
|
1140
|
+
"served",
|
|
1141
|
+
"picked_up",
|
|
1142
|
+
"dispatched",
|
|
1143
|
+
"delivered",
|
|
1144
|
+
"completed",
|
|
1145
|
+
"cancelled"
|
|
1146
|
+
]);
|
|
1134
1147
|
function nowIso() {
|
|
1135
1148
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
1136
1149
|
}
|
|
@@ -1145,10 +1158,40 @@ function dateKey(value) {
|
|
|
1145
1158
|
function referenceNumber() {
|
|
1146
1159
|
return `ORD-${Date.now().toString().slice(-6)}`;
|
|
1147
1160
|
}
|
|
1148
|
-
function
|
|
1161
|
+
function objectValue(value) {
|
|
1162
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
1163
|
+
}
|
|
1164
|
+
function canonicalStatus(status) {
|
|
1165
|
+
if (status === "new") return "draft";
|
|
1166
|
+
if (status === "completed" || status === "cancelled") return status;
|
|
1167
|
+
return "confirmed";
|
|
1168
|
+
}
|
|
1169
|
+
function restaurantStatus(rowStatus, metadata) {
|
|
1170
|
+
if (rowStatus === "completed" || rowStatus === "cancelled") return rowStatus;
|
|
1171
|
+
const stored = metadata.restaurantStatus;
|
|
1172
|
+
if (typeof stored === "string" && RESTAURANT_STATUSES.has(stored)) return stored;
|
|
1173
|
+
if (rowStatus === "draft") return "new";
|
|
1174
|
+
if (typeof rowStatus === "string" && RESTAURANT_STATUSES.has(rowStatus)) return rowStatus;
|
|
1175
|
+
return "confirmed";
|
|
1176
|
+
}
|
|
1177
|
+
function ordersMetadata(metadata) {
|
|
1178
|
+
return objectValue(metadata?.[ORDERS_METADATA_KEY]);
|
|
1179
|
+
}
|
|
1180
|
+
function mergeOrdersMetadata(metadata, patch) {
|
|
1181
|
+
const base = { ...metadata ?? {} };
|
|
1182
|
+
const current = ordersMetadata(base);
|
|
1183
|
+
const definedPatch = Object.fromEntries(
|
|
1184
|
+
Object.entries(patch).filter(([, value]) => value !== void 0)
|
|
1185
|
+
);
|
|
1186
|
+
const next = { ...current, ...definedPatch };
|
|
1187
|
+
return { ...base, [ORDERS_METADATA_KEY]: next };
|
|
1188
|
+
}
|
|
1189
|
+
function itemToRow(item, orderId, sortOrder, tenantId, unitId) {
|
|
1149
1190
|
const discount = item.discount ?? 0;
|
|
1150
1191
|
return {
|
|
1151
1192
|
order_id: orderId,
|
|
1193
|
+
...tenantId ? { tenant_id: tenantId } : {},
|
|
1194
|
+
...unitId ? { unit_id: unitId } : {},
|
|
1152
1195
|
product_id: item.productId ?? null,
|
|
1153
1196
|
name: item.name,
|
|
1154
1197
|
quantity: item.quantity,
|
|
@@ -1156,14 +1199,17 @@ function itemToRow(item, orderId, sortOrder) {
|
|
|
1156
1199
|
discount,
|
|
1157
1200
|
total: item.quantity * item.unitPrice - discount,
|
|
1158
1201
|
sort_order: sortOrder,
|
|
1159
|
-
|
|
1160
|
-
|
|
1202
|
+
metadata: mergeOrdersMetadata(void 0, {
|
|
1203
|
+
modifiers: item.modifiers ?? null,
|
|
1204
|
+
kitchenNotes: item.kitchenNotes ?? null
|
|
1205
|
+
})
|
|
1161
1206
|
};
|
|
1162
1207
|
}
|
|
1163
1208
|
function rowToItem(row) {
|
|
1164
1209
|
const quantity = numberValue(row.quantity);
|
|
1165
1210
|
const unitPrice = numberValue(row.unit_price);
|
|
1166
1211
|
const discount = numberValue(row.discount);
|
|
1212
|
+
const restaurant = ordersMetadata(row.metadata);
|
|
1167
1213
|
return {
|
|
1168
1214
|
id: row.id,
|
|
1169
1215
|
orderId: row.order_id ?? "",
|
|
@@ -1175,8 +1221,8 @@ function rowToItem(row) {
|
|
|
1175
1221
|
discount,
|
|
1176
1222
|
total: numberValue(row.total) || quantity * unitPrice - discount,
|
|
1177
1223
|
sortOrder: row.sort_order ?? 0,
|
|
1178
|
-
modifiers: row.modifiers ?? void 0,
|
|
1179
|
-
kitchenNotes: row.kitchen_notes ?? void 0,
|
|
1224
|
+
modifiers: row.modifiers ?? (typeof restaurant.modifiers === "string" ? restaurant.modifiers : void 0),
|
|
1225
|
+
kitchenNotes: row.kitchen_notes ?? (typeof restaurant.kitchenNotes === "string" ? restaurant.kitchenNotes : void 0),
|
|
1180
1226
|
metadata: row.metadata ?? {},
|
|
1181
1227
|
createdAt: row.created_at ?? nowIso()
|
|
1182
1228
|
};
|
|
@@ -1185,15 +1231,16 @@ function rowToOrder(row, items = []) {
|
|
|
1185
1231
|
const subtotal = numberValue(row.subtotal) || items.reduce((sum, item) => sum + item.total, 0);
|
|
1186
1232
|
const discount = numberValue(row.discount);
|
|
1187
1233
|
const tax = numberValue(row.tax);
|
|
1234
|
+
const restaurant = ordersMetadata(row.metadata);
|
|
1188
1235
|
return {
|
|
1189
1236
|
id: row.id,
|
|
1190
1237
|
referenceNumber: row.reference_number ?? row.id,
|
|
1191
1238
|
kind: row.kind ?? "dine_in",
|
|
1192
|
-
status: row.status
|
|
1239
|
+
status: restaurantStatus(row.status, restaurant),
|
|
1193
1240
|
partyId: row.party_id ?? void 0,
|
|
1194
|
-
partyName: row.party_name ?? void 0,
|
|
1241
|
+
partyName: row.party_name ?? (typeof restaurant.partyName === "string" ? restaurant.partyName : void 0),
|
|
1195
1242
|
assigneeId: row.assignee_id ?? void 0,
|
|
1196
|
-
assigneeName: row.assignee_name ?? void 0,
|
|
1243
|
+
assigneeName: row.assignee_name ?? (typeof restaurant.assigneeName === "string" ? restaurant.assigneeName : void 0),
|
|
1197
1244
|
locationId: row.location_id ?? void 0,
|
|
1198
1245
|
subtotal,
|
|
1199
1246
|
discount,
|
|
@@ -1202,13 +1249,14 @@ function rowToOrder(row, items = []) {
|
|
|
1202
1249
|
currency: row.currency ?? "BRL",
|
|
1203
1250
|
notes: row.notes ?? void 0,
|
|
1204
1251
|
tags: row.tags ?? [],
|
|
1205
|
-
source: row.source ?? "pos",
|
|
1206
|
-
tableId: row.table_id ?? void 0,
|
|
1207
|
-
tableName: row.table_name ?? void 0,
|
|
1208
|
-
estimatedMinutes: row.estimated_minutes ?? void 0,
|
|
1252
|
+
source: row.source ?? (typeof restaurant.source === "string" ? restaurant.source : "pos"),
|
|
1253
|
+
tableId: row.table_id ?? (typeof restaurant.tableId === "string" ? restaurant.tableId : void 0),
|
|
1254
|
+
tableName: row.table_name ?? (typeof restaurant.tableName === "string" ? restaurant.tableName : void 0),
|
|
1255
|
+
estimatedMinutes: row.estimated_minutes ?? (typeof restaurant.estimatedMinutes === "number" ? restaurant.estimatedMinutes : void 0),
|
|
1209
1256
|
items,
|
|
1210
1257
|
metadata: row.metadata ?? {},
|
|
1211
1258
|
tenantId: row.tenant_id ?? "runtime-tenant",
|
|
1259
|
+
unitId: row.unit_id ?? void 0,
|
|
1212
1260
|
createdAt: row.created_at ?? nowIso(),
|
|
1213
1261
|
updatedAt: row.updated_at ?? row.created_at ?? nowIso(),
|
|
1214
1262
|
completedAt: row.completed_at ?? void 0
|
|
@@ -1219,30 +1267,31 @@ function orderPayload(input) {
|
|
|
1219
1267
|
return {
|
|
1220
1268
|
reference_number: referenceNumber(),
|
|
1221
1269
|
kind: input.kind,
|
|
1222
|
-
status: "
|
|
1223
|
-
source: input.source ?? "pos",
|
|
1224
|
-
table_id: input.tableId ?? null,
|
|
1270
|
+
status: "draft",
|
|
1225
1271
|
party_id: input.partyId ?? null,
|
|
1226
1272
|
assignee_id: input.assigneeId ?? null,
|
|
1227
1273
|
notes: input.notes ?? null,
|
|
1228
|
-
estimated_minutes: input.estimatedMinutes ?? null,
|
|
1229
1274
|
subtotal,
|
|
1230
1275
|
discount: 0,
|
|
1231
1276
|
tax: 0,
|
|
1232
1277
|
total: subtotal,
|
|
1233
1278
|
currency: "BRL",
|
|
1234
|
-
tags: []
|
|
1279
|
+
tags: [],
|
|
1280
|
+
metadata: mergeOrdersMetadata(void 0, {
|
|
1281
|
+
source: input.source ?? "pos",
|
|
1282
|
+
tableId: input.tableId ?? null,
|
|
1283
|
+
estimatedMinutes: input.estimatedMinutes ?? null,
|
|
1284
|
+
restaurantStatus: "new"
|
|
1285
|
+
})
|
|
1235
1286
|
};
|
|
1236
1287
|
}
|
|
1237
|
-
function updatePayload(data) {
|
|
1288
|
+
function updatePayload(data, existingMetadata) {
|
|
1238
1289
|
const payload = {};
|
|
1239
1290
|
if (data.referenceNumber !== void 0) payload.reference_number = data.referenceNumber;
|
|
1240
1291
|
if (data.kind !== void 0) payload.kind = data.kind;
|
|
1241
|
-
if (data.status !== void 0) payload.status = data.status;
|
|
1292
|
+
if (data.status !== void 0) payload.status = canonicalStatus(data.status);
|
|
1242
1293
|
if (data.partyId !== void 0) payload.party_id = data.partyId;
|
|
1243
|
-
if (data.partyName !== void 0) payload.party_name = data.partyName;
|
|
1244
1294
|
if (data.assigneeId !== void 0) payload.assignee_id = data.assigneeId;
|
|
1245
|
-
if (data.assigneeName !== void 0) payload.assignee_name = data.assigneeName;
|
|
1246
1295
|
if (data.locationId !== void 0) payload.location_id = data.locationId;
|
|
1247
1296
|
if (data.subtotal !== void 0) payload.subtotal = data.subtotal;
|
|
1248
1297
|
if (data.discount !== void 0) payload.discount = data.discount;
|
|
@@ -1251,26 +1300,35 @@ function updatePayload(data) {
|
|
|
1251
1300
|
if (data.currency !== void 0) payload.currency = data.currency;
|
|
1252
1301
|
if (data.notes !== void 0) payload.notes = data.notes;
|
|
1253
1302
|
if (data.tags !== void 0) payload.tags = data.tags;
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1303
|
+
const metadataBase = data.metadata !== void 0 ? { ...existingMetadata ?? {}, ...data.metadata } : existingMetadata;
|
|
1304
|
+
const metadataPatch = {
|
|
1305
|
+
partyName: data.partyName,
|
|
1306
|
+
assigneeName: data.assigneeName,
|
|
1307
|
+
source: data.source,
|
|
1308
|
+
tableId: data.tableId,
|
|
1309
|
+
tableName: data.tableName,
|
|
1310
|
+
estimatedMinutes: data.estimatedMinutes,
|
|
1311
|
+
restaurantStatus: data.status
|
|
1312
|
+
};
|
|
1313
|
+
if (data.metadata !== void 0 || Object.values(metadataPatch).some((value) => value !== void 0)) {
|
|
1314
|
+
payload.metadata = mergeOrdersMetadata(metadataBase, metadataPatch);
|
|
1315
|
+
}
|
|
1259
1316
|
if (data.completedAt !== void 0) payload.completed_at = data.completedAt;
|
|
1260
1317
|
return payload;
|
|
1261
1318
|
}
|
|
1262
1319
|
function filtersFromQuery(query) {
|
|
1263
1320
|
const filters = [];
|
|
1264
1321
|
if (query.kind && !Array.isArray(query.kind)) filters.push({ column: "kind", operator: "eq", value: query.kind });
|
|
1265
|
-
if (query.status && !Array.isArray(query.status)) filters.push({ column: "status", operator: "eq", value: query.status });
|
|
1266
|
-
if (query.source) filters.push({ column: "source", operator: "eq", value: query.source });
|
|
1267
|
-
if (query.tableId) filters.push({ column: "table_id", operator: "eq", value: query.tableId });
|
|
1268
1322
|
if (query.assigneeId) filters.push({ column: "assignee_id", operator: "eq", value: query.assigneeId });
|
|
1269
1323
|
return filters;
|
|
1270
1324
|
}
|
|
1271
1325
|
function matchesClientQuery(order, query) {
|
|
1272
1326
|
if (Array.isArray(query.kind) && !query.kind.includes(order.kind)) return false;
|
|
1273
1327
|
if (Array.isArray(query.status) && !query.status.includes(order.status)) return false;
|
|
1328
|
+
if (query.status && !Array.isArray(query.status) && order.status !== query.status) return false;
|
|
1329
|
+
if (query.source && order.source !== query.source) return false;
|
|
1330
|
+
if (query.tableId && order.tableId !== query.tableId) return false;
|
|
1331
|
+
if (query.assigneeId && order.assigneeId !== query.assigneeId) return false;
|
|
1274
1332
|
if (query.dateRange) {
|
|
1275
1333
|
const created = dateKey(order.createdAt);
|
|
1276
1334
|
if (created < query.dateRange.from || created > query.dateRange.to) return false;
|
|
@@ -1330,6 +1388,10 @@ function createFayzOrdersProvider(options = {}) {
|
|
|
1330
1388
|
const value = typeof options.tenantId === "function" ? options.tenantId() : options.tenantId;
|
|
1331
1389
|
return value ?? void 0;
|
|
1332
1390
|
}
|
|
1391
|
+
function resolveUnit() {
|
|
1392
|
+
const value = typeof options.unitId === "function" ? options.unitId() : options.unitId;
|
|
1393
|
+
return value ?? void 0;
|
|
1394
|
+
}
|
|
1333
1395
|
function withTenant(filters) {
|
|
1334
1396
|
const tenantId = resolveTenant();
|
|
1335
1397
|
return tenantId ? [{ column: "tenant_id", operator: "eq", value: tenantId }, ...filters] : filters;
|
|
@@ -1391,15 +1453,20 @@ function createFayzOrdersProvider(options = {}) {
|
|
|
1391
1453
|
},
|
|
1392
1454
|
async createOrder(input) {
|
|
1393
1455
|
const tenantId = resolveTenant();
|
|
1456
|
+
const unitId = resolveUnit();
|
|
1394
1457
|
const orderRow = await client.data.createRow({
|
|
1395
1458
|
...tableOptions,
|
|
1396
1459
|
table: ordersTable,
|
|
1397
|
-
row:
|
|
1460
|
+
row: {
|
|
1461
|
+
...orderPayload(input),
|
|
1462
|
+
...tenantId ? { tenant_id: tenantId } : {},
|
|
1463
|
+
...unitId ? { unit_id: unitId } : {}
|
|
1464
|
+
}
|
|
1398
1465
|
});
|
|
1399
1466
|
await Promise.all(input.items.map((item, index) => client.data.createRow({
|
|
1400
1467
|
...tableOptions,
|
|
1401
1468
|
table: orderItemsTable,
|
|
1402
|
-
row: itemToRow(item, orderRow.id, index)
|
|
1469
|
+
row: itemToRow(item, orderRow.id, index, tenantId, unitId)
|
|
1403
1470
|
})));
|
|
1404
1471
|
return await getById(orderRow.id) ?? rowToOrder(orderRow);
|
|
1405
1472
|
},
|
|
@@ -1408,11 +1475,12 @@ function createFayzOrdersProvider(options = {}) {
|
|
|
1408
1475
|
return this.updateOrder(input.orderId, { status: input.status, completedAt });
|
|
1409
1476
|
},
|
|
1410
1477
|
async updateOrder(id, data) {
|
|
1478
|
+
const existing = await getById(id);
|
|
1411
1479
|
const row = await client.data.updateRow({
|
|
1412
1480
|
...tableOptions,
|
|
1413
1481
|
table: ordersTable,
|
|
1414
1482
|
primaryKeys: { id },
|
|
1415
|
-
row: updatePayload(data)
|
|
1483
|
+
row: updatePayload(data, existing?.metadata)
|
|
1416
1484
|
});
|
|
1417
1485
|
return await getById(row.id) ?? rowToOrder(row);
|
|
1418
1486
|
},
|
|
@@ -1429,7 +1497,7 @@ function createFayzOrdersProvider(options = {}) {
|
|
|
1429
1497
|
const row = await client.data.createRow({
|
|
1430
1498
|
...tableOptions,
|
|
1431
1499
|
table: orderItemsTable,
|
|
1432
|
-
row: itemToRow(item, orderId, order?.items.length ?? 0)
|
|
1500
|
+
row: itemToRow(item, orderId, order?.items.length ?? 0, order?.tenantId, order?.unitId ?? resolveUnit())
|
|
1433
1501
|
});
|
|
1434
1502
|
const created = rowToItem(row);
|
|
1435
1503
|
const items = [...order?.items ?? [], created];
|
|
@@ -1450,6 +1518,17 @@ function createFayzOrdersProvider(options = {}) {
|
|
|
1450
1518
|
}
|
|
1451
1519
|
},
|
|
1452
1520
|
async updateOrderItem(itemId, data) {
|
|
1521
|
+
const existingResult = await client.data.listRows({
|
|
1522
|
+
...tableOptions,
|
|
1523
|
+
table: orderItemsTable,
|
|
1524
|
+
filters: [{ column: "id", operator: "eq", value: itemId }],
|
|
1525
|
+
limit: 1
|
|
1526
|
+
});
|
|
1527
|
+
const existingMetadata = existingResult.rows[0]?.metadata ?? void 0;
|
|
1528
|
+
const metadataPatch = {
|
|
1529
|
+
modifiers: data.modifiers,
|
|
1530
|
+
kitchenNotes: data.kitchenNotes
|
|
1531
|
+
};
|
|
1453
1532
|
const row = await client.data.updateRow({
|
|
1454
1533
|
...tableOptions,
|
|
1455
1534
|
table: orderItemsTable,
|
|
@@ -1463,9 +1542,10 @@ function createFayzOrdersProvider(options = {}) {
|
|
|
1463
1542
|
discount: data.discount,
|
|
1464
1543
|
total: data.total,
|
|
1465
1544
|
sort_order: data.sortOrder,
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1545
|
+
metadata: data.metadata !== void 0 || Object.values(metadataPatch).some((value) => value !== void 0) ? mergeOrdersMetadata(
|
|
1546
|
+
data.metadata !== void 0 ? { ...existingMetadata ?? {}, ...data.metadata } : existingMetadata,
|
|
1547
|
+
metadataPatch
|
|
1548
|
+
) : void 0
|
|
1469
1549
|
}
|
|
1470
1550
|
});
|
|
1471
1551
|
return rowToItem(row);
|
|
@@ -1477,7 +1557,7 @@ function createFayzOrdersProvider(options = {}) {
|
|
|
1477
1557
|
}
|
|
1478
1558
|
|
|
1479
1559
|
// src/index.ts
|
|
1480
|
-
var OrdersPage = React.lazy(() => import('./OrdersPage-
|
|
1560
|
+
var OrdersPage = React.lazy(() => import('./OrdersPage-CQ7O74ZW.js').then((m) => ({ default: m.OrdersPage })));
|
|
1481
1561
|
var DEFAULT_LABELS = {
|
|
1482
1562
|
pageTitle: "Orders",
|
|
1483
1563
|
kanban: "Orders",
|