@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.
- package/dist/{OrdersPage-YTSYE573.js → OrdersPage-KNG54KEB.js} +3 -3
- package/dist/{OrdersPage-YTSYE573.js.map → OrdersPage-KNG54KEB.js.map} +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +465 -7
- package/dist/index.js.map +1 -1
- package/dist/integrations/99food/connectorDef.d.ts +5 -0
- package/dist/integrations/99food/connectorDef.d.ts.map +1 -0
- package/dist/integrations/aiqfome/connectorDef.d.ts +5 -0
- package/dist/integrations/aiqfome/connectorDef.d.ts.map +1 -0
- package/dist/integrations/ifood/connectorDef.d.ts +5 -0
- package/dist/integrations/ifood/connectorDef.d.ts.map +1 -0
- package/dist/integrations/index.d.ts +8 -0
- package/dist/integrations/index.d.ts.map +1 -0
- package/dist/integrations/keeta/connectorDef.d.ts +5 -0
- package/dist/integrations/keeta/connectorDef.d.ts.map +1 -0
- package/dist/integrations/rappi/connectorDef.d.ts +5 -0
- package/dist/integrations/rappi/connectorDef.d.ts.map +1 -0
- package/dist/integrations/shared.d.ts +7 -0
- package/dist/integrations/shared.d.ts.map +1 -0
- package/dist/integrations/ubereats/connectorDef.d.ts +5 -0
- package/dist/integrations/ubereats/connectorDef.d.ts.map +1 -0
- package/package.json +11 -9
|
@@ -36,7 +36,7 @@ function OrderCard({
|
|
|
36
36
|
return /* @__PURE__ */ jsxs(
|
|
37
37
|
"div",
|
|
38
38
|
{
|
|
39
|
-
className: "rounded-
|
|
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-
|
|
155
|
-
//# sourceMappingURL=OrdersPage-
|
|
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';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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;
|
|
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-
|
|
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
|
|
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
|