@fayz-ai/plugin-orders 0.9.3 → 0.11.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.
@@ -36,7 +36,7 @@ function OrderCard({
36
36
  return /* @__PURE__ */ jsxs(
37
37
  "div",
38
38
  {
39
- className: "rounded-lg border bg-card p-3 hover:shadow-md transition-shadow cursor-pointer",
39
+ className: "rounded-card border bg-card p-3 hover:shadow-md transition-shadow cursor-pointer",
40
40
  onClick: onSelect,
41
41
  children: [
42
42
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-2", children: [
@@ -151,5 +151,5 @@ function OrdersPage({ config, provider, store, registries }) {
151
151
  }
152
152
 
153
153
  export { OrdersPage };
154
- //# sourceMappingURL=OrdersPage-YTSYE573.js.map
155
- //# sourceMappingURL=OrdersPage-YTSYE573.js.map
154
+ //# sourceMappingURL=OrdersPage-KNG54KEB.js.map
155
+ //# sourceMappingURL=OrdersPage-KNG54KEB.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-YTSYE573.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-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 '../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-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"]}
package/dist/index.d.ts CHANGED
@@ -35,6 +35,7 @@ export interface OrdersPluginOptions {
35
35
  orderSources?: OrderSourceOption[];
36
36
  }
37
37
  export declare function createOrdersPlugin(options?: OrdersPluginOptions): PluginManifest;
38
+ export * from './integrations';
38
39
  export type { OrdersDataProvider } from './data/types';
39
40
  export { createFayzOrdersProvider } from './data/platform';
40
41
  export type { FayzOrdersProviderOptions } from './data/platform';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAC5E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAClD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AACtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAa9C,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;CAClB;AAeD,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAWD,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,EAAE;QACR,QAAQ,CAAC,EAAE,OAAO,CAAA;QAClB,OAAO,CAAC,EAAE,OAAO,CAAA;KAClB,CAAA;IACD,MAAM,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAA;IACpC,QAAQ,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC9D,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,GAAG,WAAW,CAAA;IACjC,KAAK,CAAC,EAAE,WAAW,CAAA;IACnB,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,YAAY,CAAC,EAAE,kBAAkB,CAAA;IACjC,cAAc,CAAC,EAAE,YAAY,CAAA;IAC7B,WAAW,CAAC,EAAE,YAAY,CAAA;IAC1B,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC5D,YAAY,CAAC,EAAE,iBAAiB,EAAE,CAAA;CACnC;AAyBD,wBAAgB,kBAAkB,CAAC,OAAO,CAAC,EAAE,mBAAmB,GAAG,cAAc,CA6HhF;AAED,YAAY,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AACtD,OAAO,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAA;AAC1D,YAAY,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAA;AAChE,YAAY,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAC5E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAClD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AACtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAmB9C,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;CAClB;AAeD,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAWD,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,EAAE;QACR,QAAQ,CAAC,EAAE,OAAO,CAAA;QAClB,OAAO,CAAC,EAAE,OAAO,CAAA;KAClB,CAAA;IACD,MAAM,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAA;IACpC,QAAQ,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC9D,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,GAAG,WAAW,CAAA;IACjC,KAAK,CAAC,EAAE,WAAW,CAAA;IACnB,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,YAAY,CAAC,EAAE,kBAAkB,CAAA;IACjC,cAAc,CAAC,EAAE,YAAY,CAAA;IAC7B,WAAW,CAAC,EAAE,YAAY,CAAA;IAC1B,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC5D,YAAY,CAAC,EAAE,iBAAiB,EAAE,CAAA;CACnC;AAyBD,wBAAgB,kBAAkB,CAAC,OAAO,CAAC,EAAE,mBAAmB,GAAG,cAAc,CAuIhF;AAED,cAAc,gBAAgB,CAAA;AAE9B,YAAY,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AACtD,OAAO,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAA;AAC1D,YAAY,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAA;AAChE,YAAY,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAA"}
package/dist/index.js CHANGED
@@ -1,8 +1,9 @@
1
1
  import { getNextStatus, STATUS_FLOW } from './chunk-LUFSNZYT.js';
2
2
  import React from 'react';
3
3
  import { createStore } from 'zustand/vanilla';
4
- import { PluginSettingsPanel, dedup } from '@fayz-ai/admin';
4
+ import { fayzConnectorOAuth, PluginSettingsPanel, dedup } from '@fayz-ai/admin';
5
5
  import { toast } from 'sonner';
6
+ import { createConnectionStore, connectionRuns, connectionSettings, connectionStatus, settingsStatus } from '@fayz-ai/core';
6
7
  import { createFayzClient } from '@fayz-ai/sdk';
7
8
 
8
9
  // src/data/mock.ts
@@ -680,6 +681,453 @@ var ptBR = {
680
681
 
681
682
  // src/locales/index.ts
682
683
  var ordersLocales = { en, "pt-BR": ptBR };
684
+
685
+ // src/integrations/shared.ts
686
+ function marketplacePermissions(provider) {
687
+ return [
688
+ {
689
+ kind: "data",
690
+ resource: "order",
691
+ actions: ["read", "write"],
692
+ reason: `Trazer para c\xE1 cada pedido feito no ${provider} \u2014 itens, observa\xE7\xF5es, forma de pagamento e o total \u2014 e ler o pedido de volta para avisar o ${provider} quando ele for confirmado, sair para entrega ou for cancelado.`,
693
+ sensitive: true
694
+ },
695
+ {
696
+ kind: "data",
697
+ resource: "menu_item",
698
+ actions: ["read"],
699
+ reason: `Descobrir qual item do seu card\xE1pio corresponde ao que foi vendido no ${provider}. Nenhum item \xE9 alterado.`
700
+ },
701
+ {
702
+ kind: "data",
703
+ resource: "customer",
704
+ actions: ["write"],
705
+ reason: `Registrar quem pediu, com o nome, o telefone e o endere\xE7o que o ${provider} envia junto do pedido.`,
706
+ sensitive: true
707
+ }
708
+ ];
709
+ }
710
+ var AUTO_ACCEPT_SETTING = {
711
+ key: "autoAccept",
712
+ label: "Confirmar o pedido automaticamente",
713
+ description: "Ligado, o pedido j\xE1 entra confirmado. Desligado, ele espera algu\xE9m aceitar na tela de Pedidos.",
714
+ type: "toggle",
715
+ defaultValue: false
716
+ };
717
+ var PREP_TIME_SETTING = {
718
+ key: "prepTimeMinutes",
719
+ label: "Tempo de preparo",
720
+ description: "Quantos minutos s\xE3o informados ao aplicativo quando o pedido \xE9 confirmado.",
721
+ type: "text",
722
+ // 5–120: outside that the providers refuse, and the first order is a bad place to find out.
723
+ pattern: "[5-9]|[1-9]\\d|1[01]\\d|120",
724
+ patternHint: "De 5 a 120 minutos.",
725
+ placeholder: "30",
726
+ defaultValue: "30"
727
+ };
728
+ function serviceModesDetail(labels, value) {
729
+ const list = Array.isArray(value) ? value : typeof value === "string" ? value.split(",") : [];
730
+ const named = list.map((v) => labels[String(v).trim()] ?? String(v).trim()).filter(Boolean);
731
+ return named.length > 0 ? named.join(", ") : void 0;
732
+ }
733
+
734
+ // src/integrations/ifood/connectorDef.tsx
735
+ var IFOOD_CONNECTOR_ID = "ifood";
736
+ var ORDER_TYPE_LABELS = {
737
+ DELIVERY: "Entrega",
738
+ TAKEOUT: "Retirada",
739
+ INDOOR: "Consumo no local"
740
+ };
741
+ var IFOOD_SETTINGS = [
742
+ {
743
+ key: "orderTypes",
744
+ label: "Quais pedidos trazer",
745
+ description: "iFood entrega, deixa retirar e atende no sal\xE3o; estes s\xE3o os que viram pedido aqui.",
746
+ type: "multi-select",
747
+ options: [
748
+ { value: "DELIVERY", label: ORDER_TYPE_LABELS.DELIVERY },
749
+ { value: "TAKEOUT", label: ORDER_TYPE_LABELS.TAKEOUT },
750
+ { value: "INDOOR", label: ORDER_TYPE_LABELS.INDOOR }
751
+ ],
752
+ // Required to OPERATE, not to connect: nothing selected reads as "conectado, falta configurar".
753
+ requiredToOperate: true,
754
+ defaultValue: ["DELIVERY", "TAKEOUT"]
755
+ },
756
+ AUTO_ACCEPT_SETTING,
757
+ PREP_TIME_SETTING
758
+ ];
759
+ var store = createConnectionStore(IFOOD_CONNECTOR_ID, {
760
+ settings: IFOOD_SETTINGS,
761
+ settingsKeys: ["merchantId"]
762
+ });
763
+ var ifoodConnectorDef = {
764
+ id: IFOOD_CONNECTOR_ID,
765
+ hostPluginId: "orders",
766
+ name: "iFood",
767
+ description: "Traga para a cozinha cada pedido feito no iFood, e avise o iFood quando ele for confirmado e sair.",
768
+ icon: "Bike",
769
+ category: "marketplace",
770
+ authKind: "oauth",
771
+ direction: "inbound",
772
+ planes: ["sync"],
773
+ docsUrl: "https://developer.ifood.com.br/pt-BR/docs/guides/modules/order/workflow/",
774
+ // A ceiling for the scheduler, not the cadence: iFood asks for one poll every 30s.
775
+ rateLimit: { perSecond: 1 },
776
+ permissions: marketplacePermissions("iFood"),
777
+ // No form. The client pair is OURS, held by the platform, and the restaurant
778
+ // authorizes on iFood's own screen — it never sees a credential of ours.
779
+ fields: [],
780
+ settings: IFOOD_SETTINGS,
781
+ howItSyncs: [
782
+ "A liga\xE7\xE3o com o iFood \xE9 lida de tempos em tempos e cada pedido novo entra na tela de Pedidos.",
783
+ "Um pedido j\xE1 trazido n\xE3o entra duas vezes: ele guarda o n\xFAmero que tem no iFood.",
784
+ "Confirmar, despachar ou cancelar aqui \xE9 o que avisa o iFood \u2014 o cliente acompanha pelo aplicativo dele."
785
+ ],
786
+ ...connectionStatus(
787
+ IFOOD_CONNECTOR_ID,
788
+ (connection) => ({
789
+ connected: !!connection?.active,
790
+ detail: serviceModesDetail(ORDER_TYPE_LABELS, connection?.settings?.orderTypes),
791
+ plane: "sync",
792
+ ...settingsStatus(IFOOD_SETTINGS, connection)
793
+ }),
794
+ { store: () => store }
795
+ ),
796
+ ...connectionSettings(store),
797
+ ...connectionRuns(store),
798
+ startOAuth: fayzConnectorOAuth(IFOOD_CONNECTOR_ID),
799
+ // Runs on the way back, to say the account is linked. No values: the grant is
800
+ // the platform's and there is nothing configured yet.
801
+ saveConnection: async () => {
802
+ await store.save({ active: true });
803
+ },
804
+ disconnect: () => store.disconnect(),
805
+ disconnectNote: "Desconectar para de trazer pedidos novos. Os pedidos que j\xE1 entraram continuam aqui."
806
+ };
807
+ var NINETY_NINE_FOOD_CONNECTOR_ID = "99food";
808
+ var SERVICE_MODE_LABELS = { DELIVERY: "Entrega", PICKUP: "Retirada" };
809
+ var NINETY_NINE_FOOD_SETTINGS = [
810
+ {
811
+ key: "serviceModes",
812
+ label: "Quais pedidos trazer",
813
+ description: "99Food entrega e deixa retirar; estes s\xE3o os que viram pedido aqui.",
814
+ type: "multi-select",
815
+ options: [
816
+ { value: "DELIVERY", label: SERVICE_MODE_LABELS.DELIVERY },
817
+ { value: "PICKUP", label: SERVICE_MODE_LABELS.PICKUP }
818
+ ],
819
+ requiredToOperate: true,
820
+ defaultValue: ["DELIVERY"]
821
+ },
822
+ AUTO_ACCEPT_SETTING,
823
+ PREP_TIME_SETTING
824
+ ];
825
+ var store2 = createConnectionStore(NINETY_NINE_FOOD_CONNECTOR_ID, {
826
+ settings: NINETY_NINE_FOOD_SETTINGS,
827
+ settingsKeys: ["storeId"]
828
+ });
829
+ var nineNineFoodConnectorDef = {
830
+ id: NINETY_NINE_FOOD_CONNECTOR_ID,
831
+ hostPluginId: "orders",
832
+ name: "99Food",
833
+ description: "Traga para a cozinha cada pedido feito no 99Food, e avise o 99Food quando ele for confirmado e sair.",
834
+ icon: "Bike",
835
+ category: "marketplace",
836
+ // Declared as the same open-platform shape Keeta turned out to be — see the
837
+ // header for what that assumption rests on.
838
+ authKind: "oauth",
839
+ direction: "inbound",
840
+ planes: ["sync"],
841
+ docsUrl: "https://developer-food.99app.com/",
842
+ // No rateLimit: whether we poll at all is part of what is unverified.
843
+ permissions: marketplacePermissions("99Food"),
844
+ fields: [],
845
+ settings: NINETY_NINE_FOOD_SETTINGS,
846
+ howItSyncs: [
847
+ "Cada pedido novo no 99Food entra na tela de Pedidos.",
848
+ "Um pedido j\xE1 trazido n\xE3o entra duas vezes: ele guarda o n\xFAmero que tem no 99Food.",
849
+ "Confirmar, despachar ou cancelar aqui \xE9 o que avisa o 99Food."
850
+ ],
851
+ ...connectionStatus(
852
+ NINETY_NINE_FOOD_CONNECTOR_ID,
853
+ (connection) => ({
854
+ connected: !!connection?.active,
855
+ detail: serviceModesDetail(SERVICE_MODE_LABELS, connection?.settings?.serviceModes),
856
+ plane: "sync",
857
+ ...settingsStatus(NINETY_NINE_FOOD_SETTINGS, connection)
858
+ }),
859
+ { store: () => store2 }
860
+ ),
861
+ ...connectionSettings(store2),
862
+ ...connectionRuns(store2),
863
+ startOAuth: fayzConnectorOAuth(NINETY_NINE_FOOD_CONNECTOR_ID),
864
+ saveConnection: async () => {
865
+ await store2.save({ active: true });
866
+ },
867
+ disconnect: () => store2.disconnect(),
868
+ disconnectNote: "Desconectar para de trazer pedidos novos. Os pedidos que j\xE1 entraram continuam aqui."
869
+ };
870
+ var KEETA_CONNECTOR_ID = "keeta";
871
+ var SERVICE_MODE_LABELS2 = { DELIVERY: "Entrega", PICKUP: "Retirada" };
872
+ var KEETA_SETTINGS = [
873
+ {
874
+ key: "serviceModes",
875
+ label: "Quais pedidos trazer",
876
+ description: "Keeta entrega e deixa retirar; estes s\xE3o os que viram pedido aqui.",
877
+ type: "multi-select",
878
+ options: [
879
+ { value: "DELIVERY", label: SERVICE_MODE_LABELS2.DELIVERY },
880
+ { value: "PICKUP", label: SERVICE_MODE_LABELS2.PICKUP }
881
+ ],
882
+ requiredToOperate: true,
883
+ defaultValue: ["DELIVERY"]
884
+ },
885
+ AUTO_ACCEPT_SETTING,
886
+ PREP_TIME_SETTING
887
+ ];
888
+ var store3 = createConnectionStore(KEETA_CONNECTOR_ID, {
889
+ settings: KEETA_SETTINGS,
890
+ settingsKeys: ["shopId"]
891
+ });
892
+ var keetaConnectorDef = {
893
+ id: KEETA_CONNECTOR_ID,
894
+ hostPluginId: "orders",
895
+ name: "Keeta",
896
+ description: "Traga para a cozinha cada pedido feito no Keeta, e avise o Keeta quando ele for confirmado e sair.",
897
+ icon: "Bike",
898
+ category: "marketplace",
899
+ // Keeta's own words: the credentials are software-level and the merchant
900
+ // self-authorizes, which is the redirect flow this declares.
901
+ authKind: "oauth",
902
+ // `inbound` is about the data, not who dials: Keeta dials us, iFood does not.
903
+ direction: "inbound",
904
+ planes: ["sync"],
905
+ docsUrl: "https://api-docs.mykeeta.com/apis/standard/docs/intro",
906
+ // No rateLimit: a budget describes what we spend, and nothing here polls Keeta.
907
+ permissions: marketplacePermissions("Keeta"),
908
+ fields: [],
909
+ settings: KEETA_SETTINGS,
910
+ howItSyncs: [
911
+ "O Keeta avisa assim que um pedido \xE9 feito, e ele entra na tela de Pedidos.",
912
+ "Se o aviso n\xE3o chegar de primeira, o Keeta tenta de novo \u2014 e um pedido j\xE1 trazido n\xE3o entra duas vezes.",
913
+ "Confirmar, despachar ou cancelar aqui \xE9 o que avisa o Keeta."
914
+ ],
915
+ ...connectionStatus(
916
+ KEETA_CONNECTOR_ID,
917
+ (connection) => ({
918
+ connected: !!connection?.active,
919
+ detail: serviceModesDetail(SERVICE_MODE_LABELS2, connection?.settings?.serviceModes),
920
+ plane: "sync",
921
+ ...settingsStatus(KEETA_SETTINGS, connection)
922
+ }),
923
+ { store: () => store3 }
924
+ ),
925
+ ...connectionSettings(store3),
926
+ ...connectionRuns(store3),
927
+ startOAuth: fayzConnectorOAuth(KEETA_CONNECTOR_ID),
928
+ saveConnection: async () => {
929
+ await store3.save({ active: true });
930
+ },
931
+ disconnect: () => store3.disconnect(),
932
+ disconnectNote: "Desconectar para de trazer pedidos novos. Os pedidos que j\xE1 entraram continuam aqui."
933
+ };
934
+ var UBER_EATS_CONNECTOR_ID = "ubereats";
935
+ var SERVICE_MODE_LABELS3 = { DELIVERY: "Entrega", PICKUP: "Retirada" };
936
+ var UBER_EATS_SETTINGS = [
937
+ {
938
+ key: "serviceModes",
939
+ label: "Quais pedidos trazer",
940
+ description: "O Uber Eats entrega e deixa retirar; estes s\xE3o os que viram pedido aqui.",
941
+ type: "multi-select",
942
+ options: [
943
+ { value: "DELIVERY", label: SERVICE_MODE_LABELS3.DELIVERY },
944
+ { value: "PICKUP", label: SERVICE_MODE_LABELS3.PICKUP }
945
+ ],
946
+ requiredToOperate: true,
947
+ defaultValue: ["DELIVERY"]
948
+ },
949
+ AUTO_ACCEPT_SETTING,
950
+ PREP_TIME_SETTING
951
+ ];
952
+ var store4 = createConnectionStore(UBER_EATS_CONNECTOR_ID, {
953
+ settings: UBER_EATS_SETTINGS,
954
+ settingsKeys: ["storeId"]
955
+ });
956
+ var uberEatsConnectorDef = {
957
+ id: UBER_EATS_CONNECTOR_ID,
958
+ hostPluginId: "orders",
959
+ name: "Uber Eats",
960
+ description: "Traga para a cozinha cada pedido feito no Uber Eats, e avise o Uber Eats quando ele for confirmado e sair.",
961
+ icon: "Bike",
962
+ category: "marketplace",
963
+ // Two grants, one merchant-facing: `client_credentials` for the day-to-day
964
+ // calls and `authorization_code` for the store activation. It is the second
965
+ // that this button opens.
966
+ authKind: "oauth",
967
+ // `inbound` is about the data, not who dials: Uber Eats pushes, like Keeta.
968
+ direction: "inbound",
969
+ planes: ["sync"],
970
+ docsUrl: "https://developer.uber.com/docs/eats/introduction",
971
+ // No rateLimit: a budget describes what we spend, and nothing here polls Uber.
972
+ permissions: marketplacePermissions("Uber Eats"),
973
+ fields: [],
974
+ settings: UBER_EATS_SETTINGS,
975
+ howItSyncs: [
976
+ "O Uber Eats avisa assim que um pedido \xE9 feito, e ele entra na tela de Pedidos.",
977
+ "Um pedido j\xE1 trazido n\xE3o entra duas vezes: ele guarda o n\xFAmero que tem no Uber Eats.",
978
+ "Confirmar, despachar ou cancelar aqui \xE9 o que avisa o Uber Eats."
979
+ ],
980
+ ...connectionStatus(
981
+ UBER_EATS_CONNECTOR_ID,
982
+ (connection) => ({
983
+ connected: !!connection?.active,
984
+ detail: serviceModesDetail(SERVICE_MODE_LABELS3, connection?.settings?.serviceModes),
985
+ plane: "sync",
986
+ ...settingsStatus(UBER_EATS_SETTINGS, connection)
987
+ }),
988
+ { store: () => store4 }
989
+ ),
990
+ ...connectionSettings(store4),
991
+ ...connectionRuns(store4),
992
+ startOAuth: fayzConnectorOAuth(UBER_EATS_CONNECTOR_ID),
993
+ saveConnection: async () => {
994
+ await store4.save({ active: true });
995
+ },
996
+ disconnect: () => store4.disconnect(),
997
+ disconnectNote: "Desconectar para de trazer pedidos novos. Os pedidos que j\xE1 entraram continuam aqui."
998
+ };
999
+ var RAPPI_CONNECTOR_ID = "rappi";
1000
+ var SERVICE_MODE_LABELS4 = { DELIVERY: "Entrega", PICKUP: "Retirada" };
1001
+ var RAPPI_SETTINGS = [
1002
+ {
1003
+ key: "serviceModes",
1004
+ label: "Quais pedidos trazer",
1005
+ description: "O Rappi entrega e deixa retirar; estes s\xE3o os que viram pedido aqui.",
1006
+ type: "multi-select",
1007
+ options: [
1008
+ { value: "DELIVERY", label: SERVICE_MODE_LABELS4.DELIVERY },
1009
+ { value: "PICKUP", label: SERVICE_MODE_LABELS4.PICKUP }
1010
+ ],
1011
+ requiredToOperate: true,
1012
+ defaultValue: ["DELIVERY"]
1013
+ },
1014
+ AUTO_ACCEPT_SETTING,
1015
+ PREP_TIME_SETTING
1016
+ ];
1017
+ var store5 = createConnectionStore(RAPPI_CONNECTOR_ID, {
1018
+ settings: RAPPI_SETTINGS,
1019
+ settingsKeys: ["storeId"]
1020
+ });
1021
+ var rappiConnectorDef = {
1022
+ id: RAPPI_CONNECTOR_ID,
1023
+ hostPluginId: "orders",
1024
+ name: "Rappi",
1025
+ description: "Traga para a cozinha cada pedido feito no Rappi, e avise o Rappi quando ele for confirmado e sair.",
1026
+ icon: "Bike",
1027
+ category: "marketplace",
1028
+ authKind: "api-key",
1029
+ direction: "inbound",
1030
+ planes: ["sync"],
1031
+ docsUrl: "https://dev-portal.rappi.com/pt/",
1032
+ // No `providerInstall`: there is no panel where the restaurant fetches a key,
1033
+ // because there is no key for the restaurant to fetch.
1034
+ //
1035
+ // No rateLimit: Rappi's own standard is a request every 45 seconds, and that
1036
+ // budget belongs with the job that spends it — which is not written yet.
1037
+ permissions: marketplacePermissions("Rappi"),
1038
+ // Nothing to fill in: the pair is registered in Fayz, and the connect step
1039
+ // says exactly that instead of drawing an empty grid.
1040
+ fields: [],
1041
+ settings: RAPPI_SETTINGS,
1042
+ howItSyncs: [
1043
+ "De tempos em tempos, os pedidos novos do Rappi entram na tela de Pedidos.",
1044
+ "Um pedido j\xE1 trazido n\xE3o entra duas vezes: ele guarda o n\xFAmero que tem no Rappi.",
1045
+ "Confirmar, despachar ou cancelar aqui \xE9 o que avisa o Rappi."
1046
+ ],
1047
+ ...connectionStatus(
1048
+ RAPPI_CONNECTOR_ID,
1049
+ (connection) => ({
1050
+ connected: !!connection?.active,
1051
+ detail: serviceModesDetail(SERVICE_MODE_LABELS4, connection?.settings?.serviceModes),
1052
+ plane: "sync",
1053
+ ...settingsStatus(RAPPI_SETTINGS, connection)
1054
+ }),
1055
+ { store: () => store5 }
1056
+ ),
1057
+ ...connectionSettings(store5),
1058
+ ...connectionRuns(store5),
1059
+ // No `testConnection`, for PlugBank's reason: the credential is not in this
1060
+ // app, so there is nothing this side can validate — and ConnectorDetail
1061
+ // renders the button only when the verb exists.
1062
+ saveConnection: async () => {
1063
+ await store5.save({ active: true });
1064
+ },
1065
+ disconnect: () => store5.disconnect(),
1066
+ disconnectNote: "Desconectar para de trazer pedidos novos. Os pedidos que j\xE1 entraram continuam aqui."
1067
+ };
1068
+ var AIQFOME_CONNECTOR_ID = "aiqfome";
1069
+ var SERVICE_MODE_LABELS5 = { DELIVERY: "Entrega", PICKUP: "Retirada" };
1070
+ var AIQFOME_SETTINGS = [
1071
+ {
1072
+ key: "serviceModes",
1073
+ label: "Quais pedidos trazer",
1074
+ description: "O aiqfome entrega e deixa retirar; estes s\xE3o os que viram pedido aqui.",
1075
+ type: "multi-select",
1076
+ options: [
1077
+ { value: "DELIVERY", label: SERVICE_MODE_LABELS5.DELIVERY },
1078
+ { value: "PICKUP", label: SERVICE_MODE_LABELS5.PICKUP }
1079
+ ],
1080
+ requiredToOperate: true,
1081
+ defaultValue: ["DELIVERY"]
1082
+ },
1083
+ AUTO_ACCEPT_SETTING,
1084
+ PREP_TIME_SETTING
1085
+ ];
1086
+ var store6 = createConnectionStore(AIQFOME_CONNECTOR_ID, {
1087
+ settings: AIQFOME_SETTINGS,
1088
+ settingsKeys: ["storeId"]
1089
+ });
1090
+ var aiqfomeConnectorDef = {
1091
+ id: AIQFOME_CONNECTOR_ID,
1092
+ hostPluginId: "orders",
1093
+ name: "aiqfome",
1094
+ description: "Traga para a cozinha cada pedido feito no aiqfome, e avise o aiqfome quando ele for confirmado e sair.",
1095
+ icon: "Bike",
1096
+ category: "marketplace",
1097
+ // Magalu ID: authorization code, `access_token` + `refresh_token`, and the
1098
+ // consent lives on the seller's own panel.
1099
+ authKind: "oauth",
1100
+ direction: "inbound",
1101
+ planes: ["sync"],
1102
+ docsUrl: "https://developer.aiqfome.com/docs/api/versions",
1103
+ // No rateLimit: how often the orders are read is part of what is unverified.
1104
+ permissions: marketplacePermissions("aiqfome"),
1105
+ fields: [],
1106
+ settings: AIQFOME_SETTINGS,
1107
+ howItSyncs: [
1108
+ "Cada pedido novo no aiqfome entra na tela de Pedidos.",
1109
+ "Um pedido j\xE1 trazido n\xE3o entra duas vezes: ele guarda o n\xFAmero que tem no aiqfome.",
1110
+ "Confirmar, despachar ou cancelar aqui \xE9 o que avisa o aiqfome."
1111
+ ],
1112
+ ...connectionStatus(
1113
+ AIQFOME_CONNECTOR_ID,
1114
+ (connection) => ({
1115
+ connected: !!connection?.active,
1116
+ detail: serviceModesDetail(SERVICE_MODE_LABELS5, connection?.settings?.serviceModes),
1117
+ plane: "sync",
1118
+ ...settingsStatus(AIQFOME_SETTINGS, connection)
1119
+ }),
1120
+ { store: () => store6 }
1121
+ ),
1122
+ ...connectionSettings(store6),
1123
+ ...connectionRuns(store6),
1124
+ startOAuth: fayzConnectorOAuth(AIQFOME_CONNECTOR_ID),
1125
+ saveConnection: async () => {
1126
+ await store6.save({ active: true });
1127
+ },
1128
+ disconnect: () => store6.disconnect(),
1129
+ disconnectNote: "Desconectar para de trazer pedidos novos. Os pedidos que j\xE1 entraram continuam aqui."
1130
+ };
683
1131
  var DEFAULT_ORDERS_TABLE = "orders";
684
1132
  var DEFAULT_ORDER_ITEMS_TABLE = "order_items";
685
1133
  var ACTIVE_STATUSES = /* @__PURE__ */ new Set(["new", "confirmed", "preparing", "ready", "served", "dispatched"]);
@@ -1029,7 +1477,7 @@ function createFayzOrdersProvider(options = {}) {
1029
1477
  }
1030
1478
 
1031
1479
  // src/index.ts
1032
- var OrdersPage = React.lazy(() => import('./OrdersPage-YTSYE573.js').then((m) => ({ default: m.OrdersPage })));
1480
+ var OrdersPage = React.lazy(() => import('./OrdersPage-KNG54KEB.js').then((m) => ({ default: m.OrdersPage })));
1033
1481
  var DEFAULT_LABELS = {
1034
1482
  pageTitle: "Orders",
1035
1483
  kanban: "Orders",
@@ -1058,14 +1506,15 @@ function resolveConfig(options) {
1058
1506
  function createOrdersPlugin(options) {
1059
1507
  const config = resolveConfig(options);
1060
1508
  const provider = options?.dataProvider ?? createMockOrdersProvider();
1061
- const store = createOrdersStore(provider);
1509
+ const store7 = createOrdersStore(provider);
1062
1510
  const PageComponent = () => React.createElement(
1063
1511
  React.Suspense,
1064
1512
  { fallback: null },
1065
- React.createElement(OrdersPage, { config, provider, store, registries: ordersRegistries })
1513
+ React.createElement(OrdersPage, { config, provider, store: store7, registries: ordersRegistries })
1066
1514
  );
1067
1515
  return {
1068
1516
  id: "orders",
1517
+ defaultAgentRole: "operations",
1069
1518
  name: config.labels.pageTitle,
1070
1519
  icon: "ClipboardList",
1071
1520
  version: "1.0.0",
@@ -1165,7 +1614,6 @@ function createOrdersPlugin(options) {
1165
1614
  component: (() => {
1166
1615
  const OrdersSettingsTab = () => React.createElement(PluginSettingsPanel, {
1167
1616
  title: "Orders Settings",
1168
- subtitle: "Order sources and preferences",
1169
1617
  registries: ordersRegistries,
1170
1618
  routeBase: "/settings/orders"
1171
1619
  });
@@ -1176,10 +1624,20 @@ function createOrdersPlugin(options) {
1176
1624
  permission: { feature: "orders", action: "read" }
1177
1625
  }
1178
1626
  ],
1179
- locales: ordersLocales
1627
+ locales: ordersLocales,
1628
+ // Offered regardless of `modules.delivery` — a takeout-only house still takes
1629
+ // iFood retirada orders. Control plane only: src/integrations/DELIVERY-MARKETPLACES.md.
1630
+ connectors: [
1631
+ ifoodConnectorDef,
1632
+ nineNineFoodConnectorDef,
1633
+ keetaConnectorDef,
1634
+ uberEatsConnectorDef,
1635
+ rappiConnectorDef,
1636
+ aiqfomeConnectorDef
1637
+ ]
1180
1638
  };
1181
1639
  }
1182
1640
 
1183
- export { createFayzOrdersProvider, createOrdersPlugin };
1641
+ export { AIQFOME_CONNECTOR_ID, AIQFOME_SETTINGS, AUTO_ACCEPT_SETTING, IFOOD_CONNECTOR_ID, IFOOD_SETTINGS, KEETA_CONNECTOR_ID, KEETA_SETTINGS, NINETY_NINE_FOOD_CONNECTOR_ID, NINETY_NINE_FOOD_SETTINGS, PREP_TIME_SETTING, RAPPI_CONNECTOR_ID, RAPPI_SETTINGS, UBER_EATS_CONNECTOR_ID, UBER_EATS_SETTINGS, aiqfomeConnectorDef, createFayzOrdersProvider, createOrdersPlugin, ifoodConnectorDef, keetaConnectorDef, marketplacePermissions, nineNineFoodConnectorDef, rappiConnectorDef, uberEatsConnectorDef };
1184
1642
  //# sourceMappingURL=index.js.map
1185
1643
  //# sourceMappingURL=index.js.map