@fayz-ai/plugin-shop 0.2.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/LICENSE +21 -0
- package/README.md +48 -0
- package/dist/ShopPage-65PPVKBD.js +271 -0
- package/dist/ShopPage-65PPVKBD.js.map +1 -0
- package/dist/ShopPage-PG5GKOZU.cjs +273 -0
- package/dist/ShopPage-PG5GKOZU.cjs.map +1 -0
- package/dist/ShopPage.d.ts +8 -0
- package/dist/ShopPage.d.ts.map +1 -0
- package/dist/index.cjs +119 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +113 -0
- package/dist/index.js.map +1 -0
- package/package.json +55 -0
- package/src/ShopPage.tsx +323 -0
- package/src/index.ts +137 -0
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var react = require('react');
|
|
4
|
+
var ui = require('@fayz-ai/ui');
|
|
5
|
+
var shop = require('@fayz-ai/shop');
|
|
6
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
7
|
+
|
|
8
|
+
// src/ShopPage.tsx
|
|
9
|
+
function currency(value, code = "BRL", locale = "pt-BR") {
|
|
10
|
+
return new Intl.NumberFormat(locale, { style: "currency", currency: code }).format(value);
|
|
11
|
+
}
|
|
12
|
+
function badge(label, color) {
|
|
13
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: `inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium ${color}`, children: label });
|
|
14
|
+
}
|
|
15
|
+
var statusColors = {
|
|
16
|
+
active: "bg-emerald-100 text-emerald-800",
|
|
17
|
+
draft: "bg-gray-100 text-gray-700",
|
|
18
|
+
archived: "bg-orange-100 text-orange-700",
|
|
19
|
+
open: "bg-blue-100 text-blue-800",
|
|
20
|
+
cancelled: "bg-red-100 text-red-700",
|
|
21
|
+
paid: "bg-emerald-100 text-emerald-800",
|
|
22
|
+
pending: "bg-yellow-100 text-yellow-800",
|
|
23
|
+
fulfilled: "bg-emerald-100 text-emerald-800",
|
|
24
|
+
unfulfilled: "bg-gray-100 text-gray-700",
|
|
25
|
+
"partially_fulfilled": "bg-blue-100 text-blue-800"
|
|
26
|
+
};
|
|
27
|
+
function resolveShopProvider(provider) {
|
|
28
|
+
return typeof provider === "function" ? provider() : provider ?? shop.getShopProvider();
|
|
29
|
+
}
|
|
30
|
+
function ProductsTab({ provider }) {
|
|
31
|
+
const [products, setProducts] = react.useState([]);
|
|
32
|
+
const [loading, setLoading] = react.useState(true);
|
|
33
|
+
const [search, setSearch] = react.useState("");
|
|
34
|
+
const load = react.useCallback(async (opts) => {
|
|
35
|
+
setLoading(true);
|
|
36
|
+
try {
|
|
37
|
+
const data = await resolveShopProvider(provider).listProducts(opts);
|
|
38
|
+
setProducts(data);
|
|
39
|
+
} finally {
|
|
40
|
+
setLoading(false);
|
|
41
|
+
}
|
|
42
|
+
}, [provider]);
|
|
43
|
+
react.useEffect(() => {
|
|
44
|
+
load();
|
|
45
|
+
}, [load]);
|
|
46
|
+
const handleSearch = (e) => {
|
|
47
|
+
const q = e.target.value;
|
|
48
|
+
setSearch(q);
|
|
49
|
+
load(q ? { search: q } : void 0);
|
|
50
|
+
};
|
|
51
|
+
const columns = react.useMemo(() => [
|
|
52
|
+
{ accessorKey: "name", header: "Produto", cell: ({ getValue }) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: getValue() }) },
|
|
53
|
+
{ accessorKey: "sku", header: "SKU", cell: ({ getValue }) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: getValue() ?? "\u2014" }) },
|
|
54
|
+
{
|
|
55
|
+
accessorKey: "price",
|
|
56
|
+
header: () => /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block text-right", children: "Pre\xE7o" }),
|
|
57
|
+
cell: ({ getValue, row }) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right", children: currency(getValue(), row.original.currency) })
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
accessorKey: "inventoryCount",
|
|
61
|
+
header: () => /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block text-right", children: "Estoque" }),
|
|
62
|
+
cell: ({ getValue }) => {
|
|
63
|
+
const count = getValue();
|
|
64
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: count === 0 ? "text-red-600 font-medium" : "", children: count }) });
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
accessorKey: "status",
|
|
69
|
+
header: "Status",
|
|
70
|
+
cell: ({ getValue }) => {
|
|
71
|
+
const status = getValue();
|
|
72
|
+
return badge(status, statusColors[status] ?? "bg-gray-100 text-gray-700");
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
], []);
|
|
76
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
77
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-4", children: [
|
|
78
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
79
|
+
"input",
|
|
80
|
+
{
|
|
81
|
+
type: "search",
|
|
82
|
+
value: search,
|
|
83
|
+
onChange: handleSearch,
|
|
84
|
+
placeholder: "Buscar produtos...",
|
|
85
|
+
className: "border rounded-lg px-3 py-2 text-sm w-64 focus:outline-none focus:ring-2 focus:ring-primary/50"
|
|
86
|
+
}
|
|
87
|
+
),
|
|
88
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm text-muted-foreground", children: [
|
|
89
|
+
products.length,
|
|
90
|
+
" produtos"
|
|
91
|
+
] })
|
|
92
|
+
] }),
|
|
93
|
+
loading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-12 text-center text-sm text-muted-foreground", children: "Carregando..." }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
94
|
+
ui.DataTable,
|
|
95
|
+
{
|
|
96
|
+
columns,
|
|
97
|
+
data: products,
|
|
98
|
+
variant: "card",
|
|
99
|
+
emptyMessage: "Nenhum produto encontrado."
|
|
100
|
+
}
|
|
101
|
+
)
|
|
102
|
+
] });
|
|
103
|
+
}
|
|
104
|
+
function OrdersTab({ provider }) {
|
|
105
|
+
const [orders, setOrders] = react.useState([]);
|
|
106
|
+
const [loading, setLoading] = react.useState(true);
|
|
107
|
+
react.useEffect(() => {
|
|
108
|
+
resolveShopProvider(provider).listOrders({ limit: 50 }).then(setOrders).finally(() => setLoading(false));
|
|
109
|
+
}, [provider]);
|
|
110
|
+
const columns = react.useMemo(() => [
|
|
111
|
+
{ accessorKey: "orderNumber", header: "Pedido", cell: ({ getValue }) => /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-medium", children: [
|
|
112
|
+
"#",
|
|
113
|
+
getValue()
|
|
114
|
+
] }) },
|
|
115
|
+
{
|
|
116
|
+
id: "customer",
|
|
117
|
+
accessorFn: (o) => o.customerName ?? o.customerEmail ?? "\u2014",
|
|
118
|
+
header: "Cliente",
|
|
119
|
+
cell: ({ getValue }) => /* @__PURE__ */ jsxRuntime.jsx("span", { children: getValue() })
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
accessorKey: "total",
|
|
123
|
+
header: () => /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block text-right", children: "Total" }),
|
|
124
|
+
cell: ({ getValue, row }) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right font-medium", children: currency(getValue(), row.original.currency) })
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
accessorKey: "financialStatus",
|
|
128
|
+
header: "Pagamento",
|
|
129
|
+
cell: ({ getValue }) => {
|
|
130
|
+
const status = getValue();
|
|
131
|
+
return badge(status, statusColors[status] ?? "bg-gray-100 text-gray-700");
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
accessorKey: "fulfillmentStatus",
|
|
136
|
+
header: "Entrega",
|
|
137
|
+
cell: ({ getValue }) => {
|
|
138
|
+
const status = getValue();
|
|
139
|
+
return badge(status, statusColors[status] ?? "bg-gray-100 text-gray-700");
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
accessorKey: "createdAt",
|
|
144
|
+
header: "Data",
|
|
145
|
+
cell: ({ getValue }) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: new Date(getValue()).toLocaleDateString("pt-BR") })
|
|
146
|
+
}
|
|
147
|
+
], []);
|
|
148
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { children: loading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-12 text-center text-sm text-muted-foreground", children: "Carregando..." }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
149
|
+
ui.DataTable,
|
|
150
|
+
{
|
|
151
|
+
columns,
|
|
152
|
+
data: orders,
|
|
153
|
+
variant: "card",
|
|
154
|
+
emptyMessage: "Nenhum pedido ainda."
|
|
155
|
+
}
|
|
156
|
+
) });
|
|
157
|
+
}
|
|
158
|
+
function CustomersTab({ provider }) {
|
|
159
|
+
const [customers, setCustomers] = react.useState([]);
|
|
160
|
+
const [loading, setLoading] = react.useState(true);
|
|
161
|
+
react.useEffect(() => {
|
|
162
|
+
resolveShopProvider(provider).listCustomers({ limit: 50 }).then(setCustomers).finally(() => setLoading(false));
|
|
163
|
+
}, [provider]);
|
|
164
|
+
const columns = react.useMemo(() => [
|
|
165
|
+
{
|
|
166
|
+
id: "name",
|
|
167
|
+
accessorFn: (c) => `${c.firstName} ${c.lastName}`,
|
|
168
|
+
header: "Nome",
|
|
169
|
+
cell: ({ row }) => /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-medium", children: [
|
|
170
|
+
row.original.firstName,
|
|
171
|
+
" ",
|
|
172
|
+
row.original.lastName
|
|
173
|
+
] })
|
|
174
|
+
},
|
|
175
|
+
{ accessorKey: "email", header: "Email", cell: ({ getValue }) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: getValue() ?? "\u2014" }) },
|
|
176
|
+
{ accessorKey: "phone", header: "Telefone", cell: ({ getValue }) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: getValue() ?? "\u2014" }) },
|
|
177
|
+
{
|
|
178
|
+
accessorKey: "ordersCount",
|
|
179
|
+
header: () => /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block text-right", children: "Pedidos" }),
|
|
180
|
+
cell: ({ getValue }) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right", children: getValue() })
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
accessorKey: "totalSpent",
|
|
184
|
+
header: () => /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block text-right", children: "Total Gasto" }),
|
|
185
|
+
cell: ({ getValue }) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right", children: currency(getValue()) })
|
|
186
|
+
}
|
|
187
|
+
], []);
|
|
188
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { children: loading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-12 text-center text-sm text-muted-foreground", children: "Carregando..." }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
189
|
+
ui.DataTable,
|
|
190
|
+
{
|
|
191
|
+
columns,
|
|
192
|
+
data: customers,
|
|
193
|
+
variant: "card",
|
|
194
|
+
emptyMessage: "Nenhum cliente ainda."
|
|
195
|
+
}
|
|
196
|
+
) });
|
|
197
|
+
}
|
|
198
|
+
function DiscountsTab({ provider }) {
|
|
199
|
+
const [discounts, setDiscounts] = react.useState([]);
|
|
200
|
+
const [loading, setLoading] = react.useState(true);
|
|
201
|
+
react.useEffect(() => {
|
|
202
|
+
resolveShopProvider(provider).listDiscounts({ limit: 50 }).then(setDiscounts).finally(() => setLoading(false));
|
|
203
|
+
}, [provider]);
|
|
204
|
+
const columns = react.useMemo(() => [
|
|
205
|
+
{ accessorKey: "title", header: "T\xEDtulo", cell: ({ getValue }) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: getValue() }) },
|
|
206
|
+
{ accessorKey: "code", header: "C\xF3digo", cell: ({ getValue }) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-sm", children: getValue() ?? "\u2014" }) },
|
|
207
|
+
{ accessorKey: "type", header: "Tipo", cell: ({ getValue }) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: getValue() }) },
|
|
208
|
+
{
|
|
209
|
+
accessorKey: "value",
|
|
210
|
+
header: () => /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block text-right", children: "Valor" }),
|
|
211
|
+
cell: ({ row }) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-right", children: row.original.type === "percentage" ? `${row.original.value}%` : currency(row.original.value) })
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
id: "usos",
|
|
215
|
+
accessorKey: "timesUsed",
|
|
216
|
+
header: () => /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block text-right", children: "Usos" }),
|
|
217
|
+
cell: ({ row }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-right", children: [
|
|
218
|
+
row.original.timesUsed,
|
|
219
|
+
row.original.usageLimit ? ` / ${row.original.usageLimit}` : ""
|
|
220
|
+
] })
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
accessorKey: "status",
|
|
224
|
+
header: "Status",
|
|
225
|
+
cell: ({ getValue }) => {
|
|
226
|
+
const status = getValue();
|
|
227
|
+
return badge(status, statusColors[status] ?? "bg-gray-100 text-gray-700");
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
], []);
|
|
231
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { children: loading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-12 text-center text-sm text-muted-foreground", children: "Carregando..." }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
232
|
+
ui.DataTable,
|
|
233
|
+
{
|
|
234
|
+
columns,
|
|
235
|
+
data: discounts,
|
|
236
|
+
variant: "card",
|
|
237
|
+
emptyMessage: "Nenhum desconto cadastrado."
|
|
238
|
+
}
|
|
239
|
+
) });
|
|
240
|
+
}
|
|
241
|
+
var TABS = [
|
|
242
|
+
{ id: "products", label: "Produtos" },
|
|
243
|
+
{ id: "orders", label: "Pedidos" },
|
|
244
|
+
{ id: "customers", label: "Clientes" },
|
|
245
|
+
{ id: "discounts", label: "Descontos" }
|
|
246
|
+
];
|
|
247
|
+
var ShopPage = ({ provider }) => {
|
|
248
|
+
const [tab, setTab] = react.useState("products");
|
|
249
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-6 max-w-7xl mx-auto", children: [
|
|
250
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-6", children: [
|
|
251
|
+
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-2xl font-semibold", children: "Loja" }),
|
|
252
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground mt-1", children: "Gerencie produtos, pedidos, clientes e descontos." })
|
|
253
|
+
] }),
|
|
254
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b mb-6", children: /* @__PURE__ */ jsxRuntime.jsx("nav", { className: "flex gap-1", children: TABS.map((t) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
255
|
+
"button",
|
|
256
|
+
{
|
|
257
|
+
onClick: () => setTab(t.id),
|
|
258
|
+
className: `px-4 py-2 text-sm font-medium border-b-2 transition-colors ${tab === t.id ? "border-primary text-primary" : "border-transparent text-muted-foreground hover:text-foreground"}`,
|
|
259
|
+
children: t.label
|
|
260
|
+
},
|
|
261
|
+
t.id
|
|
262
|
+
)) }) }),
|
|
263
|
+
tab === "products" && /* @__PURE__ */ jsxRuntime.jsx(ProductsTab, { provider }),
|
|
264
|
+
tab === "orders" && /* @__PURE__ */ jsxRuntime.jsx(OrdersTab, { provider }),
|
|
265
|
+
tab === "customers" && /* @__PURE__ */ jsxRuntime.jsx(CustomersTab, { provider }),
|
|
266
|
+
tab === "discounts" && /* @__PURE__ */ jsxRuntime.jsx(DiscountsTab, { provider })
|
|
267
|
+
] });
|
|
268
|
+
};
|
|
269
|
+
ShopPage.displayName = "ShopPage";
|
|
270
|
+
|
|
271
|
+
exports.ShopPage = ShopPage;
|
|
272
|
+
//# sourceMappingURL=ShopPage-PG5GKOZU.cjs.map
|
|
273
|
+
//# sourceMappingURL=ShopPage-PG5GKOZU.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/ShopPage.tsx"],"names":["getShopProvider","useState","useCallback","useEffect","useMemo","jsx","jsxs","DataTable"],"mappings":"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","file":"ShopPage-PG5GKOZU.cjs","sourcesContent":["import React, { useEffect, useState, useCallback, useMemo } from 'react'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { DataTable } from '@fayz-ai/ui'\nimport { getShopProvider } from '@fayz-ai/shop'\nimport type { Product, Order, ShopCustomer, Discount, ListProductsOptions, ShopProvider } from '@fayz-ai/shop'\n\nexport type ShopProviderResolver = ShopProvider | (() => ShopProvider)\n\nexport interface ShopPageProps {\n provider?: ShopProviderResolver\n}\n\n// ---------------------------------------------------------------------------\n// Shared helpers\n// ---------------------------------------------------------------------------\n\nfunction currency(value: number, code = 'BRL', locale = 'pt-BR') {\n return new Intl.NumberFormat(locale, { style: 'currency', currency: code }).format(value)\n}\n\nfunction badge(label: string, color: string) {\n return (\n <span className={`inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium ${color}`}>\n {label}\n </span>\n )\n}\n\nconst statusColors: Record<string, string> = {\n active: 'bg-emerald-100 text-emerald-800',\n draft: 'bg-gray-100 text-gray-700',\n archived: 'bg-orange-100 text-orange-700',\n open: 'bg-blue-100 text-blue-800',\n cancelled: 'bg-red-100 text-red-700',\n paid: 'bg-emerald-100 text-emerald-800',\n pending: 'bg-yellow-100 text-yellow-800',\n fulfilled: 'bg-emerald-100 text-emerald-800',\n unfulfilled: 'bg-gray-100 text-gray-700',\n 'partially_fulfilled': 'bg-blue-100 text-blue-800',\n}\n\nfunction resolveShopProvider(provider?: ShopProviderResolver): ShopProvider {\n return typeof provider === 'function' ? provider() : provider ?? getShopProvider()\n}\n\n// ---------------------------------------------------------------------------\n// Products tab\n// ---------------------------------------------------------------------------\n\nfunction ProductsTab({ provider }: ShopPageProps) {\n const [products, setProducts] = useState<Product[]>([])\n const [loading, setLoading] = useState(true)\n const [search, setSearch] = useState('')\n\n const load = useCallback(async (opts?: ListProductsOptions) => {\n setLoading(true)\n try {\n const data = await resolveShopProvider(provider).listProducts(opts)\n setProducts(data)\n } finally {\n setLoading(false)\n }\n }, [provider])\n\n useEffect(() => { load() }, [load])\n\n const handleSearch = (e: React.ChangeEvent<HTMLInputElement>) => {\n const q = e.target.value\n setSearch(q)\n load(q ? { search: q } : undefined)\n }\n\n const columns = useMemo<ColumnDef<Product, any>[]>(() => [\n { accessorKey: 'name', header: 'Produto', cell: ({ getValue }) => <span className=\"font-medium\">{getValue() as string}</span> },\n { accessorKey: 'sku', header: 'SKU', cell: ({ getValue }) => <span className=\"text-muted-foreground\">{(getValue() as string | undefined) ?? '—'}</span> },\n {\n accessorKey: 'price', header: () => <span className=\"block text-right\">Preço</span>,\n cell: ({ getValue, row }) => <div className=\"text-right\">{currency(getValue() as number, row.original.currency)}</div>,\n },\n {\n accessorKey: 'inventoryCount', header: () => <span className=\"block text-right\">Estoque</span>,\n cell: ({ getValue }) => {\n const count = getValue() as number\n return <div className=\"text-right\"><span className={count === 0 ? 'text-red-600 font-medium' : ''}>{count}</span></div>\n },\n },\n {\n accessorKey: 'status', header: 'Status',\n cell: ({ getValue }) => {\n const status = getValue() as string\n return badge(status, statusColors[status] ?? 'bg-gray-100 text-gray-700')\n },\n },\n ], [])\n\n return (\n <div>\n <div className=\"flex items-center justify-between mb-4\">\n <input\n type=\"search\" value={search} onChange={handleSearch}\n placeholder=\"Buscar produtos...\"\n className=\"border rounded-lg px-3 py-2 text-sm w-64 focus:outline-none focus:ring-2 focus:ring-primary/50\"\n />\n <span className=\"text-sm text-muted-foreground\">{products.length} produtos</span>\n </div>\n\n {loading ? (\n <div className=\"py-12 text-center text-sm text-muted-foreground\">Carregando...</div>\n ) : (\n <DataTable\n columns={columns}\n data={products}\n variant=\"card\"\n emptyMessage=\"Nenhum produto encontrado.\"\n />\n )}\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Orders tab\n// ---------------------------------------------------------------------------\n\nfunction OrdersTab({ provider }: ShopPageProps) {\n const [orders, setOrders] = useState<Order[]>([])\n const [loading, setLoading] = useState(true)\n\n useEffect(() => {\n resolveShopProvider(provider).listOrders({ limit: 50 }).then(setOrders).finally(() => setLoading(false))\n }, [provider])\n\n const columns = useMemo<ColumnDef<Order, any>[]>(() => [\n { accessorKey: 'orderNumber', header: 'Pedido', cell: ({ getValue }) => <span className=\"font-medium\">#{getValue() as string}</span> },\n {\n id: 'customer', accessorFn: (o) => o.customerName ?? o.customerEmail ?? '—', header: 'Cliente',\n cell: ({ getValue }) => <span>{getValue() as string}</span>,\n },\n {\n accessorKey: 'total', header: () => <span className=\"block text-right\">Total</span>,\n cell: ({ getValue, row }) => <div className=\"text-right font-medium\">{currency(getValue() as number, row.original.currency)}</div>,\n },\n {\n accessorKey: 'financialStatus', header: 'Pagamento',\n cell: ({ getValue }) => {\n const status = getValue() as string\n return badge(status, statusColors[status] ?? 'bg-gray-100 text-gray-700')\n },\n },\n {\n accessorKey: 'fulfillmentStatus', header: 'Entrega',\n cell: ({ getValue }) => {\n const status = getValue() as string\n return badge(status, statusColors[status] ?? 'bg-gray-100 text-gray-700')\n },\n },\n {\n accessorKey: 'createdAt', header: 'Data',\n cell: ({ getValue }) => <span className=\"text-muted-foreground\">{new Date(getValue() as string).toLocaleDateString('pt-BR')}</span>,\n },\n ], [])\n\n return (\n <div>\n {loading ? (\n <div className=\"py-12 text-center text-sm text-muted-foreground\">Carregando...</div>\n ) : (\n <DataTable\n columns={columns}\n data={orders}\n variant=\"card\"\n emptyMessage=\"Nenhum pedido ainda.\"\n />\n )}\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Customers tab\n// ---------------------------------------------------------------------------\n\nfunction CustomersTab({ provider }: ShopPageProps) {\n const [customers, setCustomers] = useState<ShopCustomer[]>([])\n const [loading, setLoading] = useState(true)\n\n useEffect(() => {\n resolveShopProvider(provider).listCustomers({ limit: 50 }).then(setCustomers).finally(() => setLoading(false))\n }, [provider])\n\n const columns = useMemo<ColumnDef<ShopCustomer, any>[]>(() => [\n {\n id: 'name', accessorFn: (c) => `${c.firstName} ${c.lastName}`, header: 'Nome',\n cell: ({ row }) => <span className=\"font-medium\">{row.original.firstName} {row.original.lastName}</span>,\n },\n { accessorKey: 'email', header: 'Email', cell: ({ getValue }) => <span className=\"text-muted-foreground\">{(getValue() as string | undefined) ?? '—'}</span> },\n { accessorKey: 'phone', header: 'Telefone', cell: ({ getValue }) => <span className=\"text-muted-foreground\">{(getValue() as string | undefined) ?? '—'}</span> },\n {\n accessorKey: 'ordersCount', header: () => <span className=\"block text-right\">Pedidos</span>,\n cell: ({ getValue }) => <div className=\"text-right\">{getValue() as number}</div>,\n },\n {\n accessorKey: 'totalSpent', header: () => <span className=\"block text-right\">Total Gasto</span>,\n cell: ({ getValue }) => <div className=\"text-right\">{currency(getValue() as number)}</div>,\n },\n ], [])\n\n return (\n <div>\n {loading ? (\n <div className=\"py-12 text-center text-sm text-muted-foreground\">Carregando...</div>\n ) : (\n <DataTable\n columns={columns}\n data={customers}\n variant=\"card\"\n emptyMessage=\"Nenhum cliente ainda.\"\n />\n )}\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Discounts tab\n// ---------------------------------------------------------------------------\n\nfunction DiscountsTab({ provider }: ShopPageProps) {\n const [discounts, setDiscounts] = useState<Discount[]>([])\n const [loading, setLoading] = useState(true)\n\n useEffect(() => {\n resolveShopProvider(provider).listDiscounts({ limit: 50 }).then(setDiscounts).finally(() => setLoading(false))\n }, [provider])\n\n const columns = useMemo<ColumnDef<Discount, any>[]>(() => [\n { accessorKey: 'title', header: 'Título', cell: ({ getValue }) => <span className=\"font-medium\">{getValue() as string}</span> },\n { accessorKey: 'code', header: 'Código', cell: ({ getValue }) => <span className=\"font-mono text-sm\">{(getValue() as string | undefined) ?? '—'}</span> },\n { accessorKey: 'type', header: 'Tipo', cell: ({ getValue }) => <span className=\"text-muted-foreground\">{getValue() as string}</span> },\n {\n accessorKey: 'value', header: () => <span className=\"block text-right\">Valor</span>,\n cell: ({ row }) => <div className=\"text-right\">{row.original.type === 'percentage' ? `${row.original.value}%` : currency(row.original.value)}</div>,\n },\n {\n id: 'usos', accessorKey: 'timesUsed', header: () => <span className=\"block text-right\">Usos</span>,\n cell: ({ row }) => <div className=\"text-right\">{row.original.timesUsed}{row.original.usageLimit ? ` / ${row.original.usageLimit}` : ''}</div>,\n },\n {\n accessorKey: 'status', header: 'Status',\n cell: ({ getValue }) => {\n const status = getValue() as string\n return badge(status, statusColors[status] ?? 'bg-gray-100 text-gray-700')\n },\n },\n ], [])\n\n return (\n <div>\n {loading ? (\n <div className=\"py-12 text-center text-sm text-muted-foreground\">Carregando...</div>\n ) : (\n <DataTable\n columns={columns}\n data={discounts}\n variant=\"card\"\n emptyMessage=\"Nenhum desconto cadastrado.\"\n />\n )}\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Main page\n// ---------------------------------------------------------------------------\n\nconst TABS = [\n { id: 'products', label: 'Produtos' },\n { id: 'orders', label: 'Pedidos' },\n { id: 'customers', label: 'Clientes' },\n { id: 'discounts', label: 'Descontos' },\n] as const\n\ntype TabId = typeof TABS[number]['id']\n\nexport const ShopPage: React.FC<ShopPageProps> = ({ provider }) => {\n const [tab, setTab] = useState<TabId>('products')\n\n return (\n <div className=\"p-6 max-w-7xl mx-auto\">\n <div className=\"mb-6\">\n <h1 className=\"text-2xl font-semibold\">Loja</h1>\n <p className=\"text-muted-foreground mt-1\">Gerencie produtos, pedidos, clientes e descontos.</p>\n </div>\n\n {/* Tabs */}\n <div className=\"border-b mb-6\">\n <nav className=\"flex gap-1\">\n {TABS.map(t => (\n <button\n key={t.id}\n onClick={() => setTab(t.id)}\n className={`px-4 py-2 text-sm font-medium border-b-2 transition-colors ${\n tab === t.id\n ? 'border-primary text-primary'\n : 'border-transparent text-muted-foreground hover:text-foreground'\n }`}\n >\n {t.label}\n </button>\n ))}\n </nav>\n </div>\n\n {tab === 'products' && <ProductsTab provider={provider} />}\n {tab === 'orders' && <OrdersTab provider={provider} />}\n {tab === 'customers' && <CustomersTab provider={provider} />}\n {tab === 'discounts' && <DiscountsTab provider={provider} />}\n </div>\n )\n}\n\nShopPage.displayName = 'ShopPage'\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { ShopProvider } from '@fayz-ai/shop';
|
|
3
|
+
export type ShopProviderResolver = ShopProvider | (() => ShopProvider);
|
|
4
|
+
export interface ShopPageProps {
|
|
5
|
+
provider?: ShopProviderResolver;
|
|
6
|
+
}
|
|
7
|
+
export declare const ShopPage: React.FC<ShopPageProps>;
|
|
8
|
+
//# sourceMappingURL=ShopPage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ShopPage.d.ts","sourceRoot":"","sources":["../src/ShopPage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoD,MAAM,OAAO,CAAA;AAIxE,OAAO,KAAK,EAA+D,YAAY,EAAE,MAAM,eAAe,CAAA;AAE9G,MAAM,MAAM,oBAAoB,GAAG,YAAY,GAAG,CAAC,MAAM,YAAY,CAAC,CAAA;AAEtE,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,oBAAoB,CAAA;CAChC;AAmRD,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CAmC5C,CAAA"}
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var React = require('react');
|
|
4
|
+
var shop = require('@fayz-ai/shop');
|
|
5
|
+
var saas = require('@fayz-ai/saas');
|
|
6
|
+
|
|
7
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
8
|
+
|
|
9
|
+
var React__default = /*#__PURE__*/_interopDefault(React);
|
|
10
|
+
|
|
11
|
+
// src/index.ts
|
|
12
|
+
var ShopPage = React__default.default.lazy(() => import('./ShopPage-PG5GKOZU.cjs').then((m) => ({ default: m.ShopPage })));
|
|
13
|
+
function createShopPlugin(options) {
|
|
14
|
+
const curr = { code: "BRL", symbol: "R$", ...options?.currency };
|
|
15
|
+
shop.setShopTenantResolver(() => saas.useOrganizationStore.getState().currentOrg?.id);
|
|
16
|
+
const PageComponent = () => React__default.default.createElement(
|
|
17
|
+
React__default.default.Suspense,
|
|
18
|
+
{ fallback: null },
|
|
19
|
+
React__default.default.createElement(ShopPage, {
|
|
20
|
+
provider: options?.provider
|
|
21
|
+
})
|
|
22
|
+
);
|
|
23
|
+
PageComponent.displayName = "ShopPageWrapper";
|
|
24
|
+
return {
|
|
25
|
+
id: "shop",
|
|
26
|
+
name: options?.navLabel ?? "Shop",
|
|
27
|
+
icon: "ShoppingBag",
|
|
28
|
+
version: "1.0.0",
|
|
29
|
+
scope: options?.scope ?? "vertical",
|
|
30
|
+
verticalId: options?.verticalId,
|
|
31
|
+
defaultEnabled: true,
|
|
32
|
+
dependencies: [],
|
|
33
|
+
navigation: [
|
|
34
|
+
{
|
|
35
|
+
section: options?.navSection ?? "main",
|
|
36
|
+
position: options?.navPosition ?? 6,
|
|
37
|
+
label: options?.navLabel ?? "Shop",
|
|
38
|
+
route: "/shop",
|
|
39
|
+
icon: "ShoppingBag",
|
|
40
|
+
permission: { feature: "shop", action: "read" }
|
|
41
|
+
}
|
|
42
|
+
],
|
|
43
|
+
routes: [
|
|
44
|
+
{
|
|
45
|
+
path: "/shop",
|
|
46
|
+
component: PageComponent,
|
|
47
|
+
permission: { feature: "shop", action: "read" }
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
widgets: [],
|
|
51
|
+
aiTools: [
|
|
52
|
+
{
|
|
53
|
+
id: "shop.list-products",
|
|
54
|
+
name: "listProducts",
|
|
55
|
+
description: "Lists products in the shop catalog.",
|
|
56
|
+
icon: "Package",
|
|
57
|
+
mode: "read",
|
|
58
|
+
category: "Shop",
|
|
59
|
+
parameters: {
|
|
60
|
+
type: "object",
|
|
61
|
+
properties: {
|
|
62
|
+
search: { type: "string", description: "Filter by name" },
|
|
63
|
+
status: { type: "string", enum: ["draft", "active", "archived"] }
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
suggestions: [
|
|
67
|
+
{ label: "What products are available?" },
|
|
68
|
+
{ label: "Which products are out of stock?" }
|
|
69
|
+
]
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
id: "shop.list-orders",
|
|
73
|
+
name: "listOrders",
|
|
74
|
+
description: "Lists recent shop orders.",
|
|
75
|
+
icon: "ShoppingCart",
|
|
76
|
+
mode: "read",
|
|
77
|
+
category: "Shop",
|
|
78
|
+
parameters: {
|
|
79
|
+
type: "object",
|
|
80
|
+
properties: {
|
|
81
|
+
financialStatus: { type: "string", enum: ["pending", "paid", "refunded", "voided"] },
|
|
82
|
+
fulfillmentStatus: { type: "string", enum: ["unfulfilled", "partially_fulfilled", "fulfilled"] }
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
suggestions: [
|
|
86
|
+
{ label: "Show me pending orders" },
|
|
87
|
+
{ label: "How many orders were paid today?" }
|
|
88
|
+
]
|
|
89
|
+
}
|
|
90
|
+
],
|
|
91
|
+
settings: [
|
|
92
|
+
{
|
|
93
|
+
id: "shop",
|
|
94
|
+
label: "Shop",
|
|
95
|
+
icon: "ShoppingBag",
|
|
96
|
+
component: (() => {
|
|
97
|
+
const ShopSettingsTab = () => React__default.default.createElement(
|
|
98
|
+
"div",
|
|
99
|
+
{ className: "p-4 space-y-2" },
|
|
100
|
+
React__default.default.createElement("h2", { className: "text-lg font-semibold" }, "Configura\xE7\xF5es da Loja"),
|
|
101
|
+
React__default.default.createElement(
|
|
102
|
+
"p",
|
|
103
|
+
{ className: "text-sm text-muted-foreground" },
|
|
104
|
+
`Moeda: ${curr.symbol} (${curr.code})`
|
|
105
|
+
)
|
|
106
|
+
);
|
|
107
|
+
ShopSettingsTab.displayName = "ShopSettingsTab";
|
|
108
|
+
return ShopSettingsTab;
|
|
109
|
+
})(),
|
|
110
|
+
order: 30,
|
|
111
|
+
permission: { feature: "shop", action: "read" }
|
|
112
|
+
}
|
|
113
|
+
]
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
exports.createShopPlugin = createShopPlugin;
|
|
118
|
+
//# sourceMappingURL=index.cjs.map
|
|
119
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":["React","setShopTenantResolver","useOrganizationStore"],"mappings":"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","file":"index.cjs","sourcesContent":["import React from 'react'\nimport type { PluginManifest, PluginScope, VerticalId } from '@fayz-ai/core'\nimport { setShopTenantResolver } from '@fayz-ai/shop'\nimport { useOrganizationStore } from '@fayz-ai/saas'\nimport type { ShopProviderResolver } from './ShopPage'\n\nconst ShopPage = React.lazy(() => import('./ShopPage').then((m) => ({ default: m.ShopPage })))\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\nexport interface ShopPluginOptions {\n navPosition?: number\n navSection?: 'main' | 'secondary' | 'settings'\n navLabel?: string\n scope?: PluginScope\n verticalId?: VerticalId\n currency?: { code?: string; locale?: string; symbol?: string }\n provider?: ShopProviderResolver\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\nexport function createShopPlugin(options?: ShopPluginOptions): PluginManifest {\n const curr = { code: 'BRL', locale: 'pt-BR', symbol: 'R$', ...options?.currency }\n\n // Scope fallback shop queries to the active organization. Apps can inject a\n // provider when they want SDK-owned data access instead of the global runtime.\n setShopTenantResolver(() => useOrganizationStore.getState().currentOrg?.id)\n\n const PageComponent: React.ComponentType<unknown> = () =>\n React.createElement(React.Suspense, { fallback: null },\n React.createElement(ShopPage as React.ComponentType<{ provider?: ShopProviderResolver }>, {\n provider: options?.provider,\n })\n )\n PageComponent.displayName = 'ShopPageWrapper'\n\n return {\n id: 'shop',\n name: options?.navLabel ?? 'Shop',\n icon: 'ShoppingBag',\n version: '1.0.0',\n scope: options?.scope ?? 'vertical',\n verticalId: options?.verticalId,\n defaultEnabled: true,\n dependencies: [],\n navigation: [\n {\n section: options?.navSection ?? 'main',\n position: options?.navPosition ?? 6,\n label: options?.navLabel ?? 'Shop',\n route: '/shop',\n icon: 'ShoppingBag',\n permission: { feature: 'shop', action: 'read' as const },\n },\n ],\n routes: [\n {\n path: '/shop',\n component: PageComponent,\n permission: { feature: 'shop', action: 'read' as const },\n },\n ],\n widgets: [],\n aiTools: [\n {\n id: 'shop.list-products',\n name: 'listProducts',\n description: 'Lists products in the shop catalog.',\n icon: 'Package',\n mode: 'read' as const,\n category: 'Shop',\n parameters: {\n type: 'object' as const,\n properties: {\n search: { type: 'string' as const, description: 'Filter by name' },\n status: { type: 'string' as const, enum: ['draft', 'active', 'archived'] },\n },\n },\n suggestions: [\n { label: 'What products are available?' },\n { label: 'Which products are out of stock?' },\n ],\n },\n {\n id: 'shop.list-orders',\n name: 'listOrders',\n description: 'Lists recent shop orders.',\n icon: 'ShoppingCart',\n mode: 'read' as const,\n category: 'Shop',\n parameters: {\n type: 'object' as const,\n properties: {\n financialStatus: { type: 'string' as const, enum: ['pending', 'paid', 'refunded', 'voided'] },\n fulfillmentStatus: { type: 'string' as const, enum: ['unfulfilled', 'partially_fulfilled', 'fulfilled'] },\n },\n },\n suggestions: [\n { label: 'Show me pending orders' },\n { label: 'How many orders were paid today?' },\n ],\n },\n ],\n settings: [\n {\n id: 'shop',\n label: 'Shop',\n icon: 'ShoppingBag',\n component: (() => {\n const ShopSettingsTab: React.ComponentType<unknown> = () =>\n React.createElement('div', { className: 'p-4 space-y-2' },\n React.createElement('h2', { className: 'text-lg font-semibold' }, 'Configurações da Loja'),\n React.createElement('p', { className: 'text-sm text-muted-foreground' },\n `Moeda: ${curr.symbol} (${curr.code})`\n )\n )\n ShopSettingsTab.displayName = 'ShopSettingsTab'\n return ShopSettingsTab\n })(),\n order: 30,\n permission: { feature: 'shop', action: 'read' as const },\n },\n ],\n }\n}\n\n// Re-export shop types so consumer apps only need @fayz-ai/plugin-shop\nexport type {\n Product, Order, ShopCustomer, Discount, Category,\n CreateProductInput, UpdateProductInput, ListProductsOptions,\n CreateOrderInput, UpdateOrderInput, ListOrdersOptions,\n} from '@fayz-ai/shop'\n"]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { PluginManifest, PluginScope, VerticalId } from '@fayz-ai/core';
|
|
2
|
+
import type { ShopProviderResolver } from './ShopPage';
|
|
3
|
+
export interface ShopPluginOptions {
|
|
4
|
+
navPosition?: number;
|
|
5
|
+
navSection?: 'main' | 'secondary' | 'settings';
|
|
6
|
+
navLabel?: string;
|
|
7
|
+
scope?: PluginScope;
|
|
8
|
+
verticalId?: VerticalId;
|
|
9
|
+
currency?: {
|
|
10
|
+
code?: string;
|
|
11
|
+
locale?: string;
|
|
12
|
+
symbol?: string;
|
|
13
|
+
};
|
|
14
|
+
provider?: ShopProviderResolver;
|
|
15
|
+
}
|
|
16
|
+
export declare function createShopPlugin(options?: ShopPluginOptions): PluginManifest;
|
|
17
|
+
export type { Product, Order, ShopCustomer, Discount, Category, CreateProductInput, UpdateProductInput, ListProductsOptions, CreateOrderInput, UpdateOrderInput, ListOrdersOptions, } from '@fayz-ai/shop';
|
|
18
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +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;AAG5E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAQtD,MAAM,WAAW,iBAAiB;IAChC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,UAAU,CAAA;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,WAAW,CAAA;IACnB,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,QAAQ,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC9D,QAAQ,CAAC,EAAE,oBAAoB,CAAA;CAChC;AAMD,wBAAgB,gBAAgB,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,cAAc,CAuG5E;AAGD,YAAY,EACV,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAChD,kBAAkB,EAAE,kBAAkB,EAAE,mBAAmB,EAC3D,gBAAgB,EAAE,gBAAgB,EAAE,iBAAiB,GACtD,MAAM,eAAe,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { setShopTenantResolver } from '@fayz-ai/shop';
|
|
3
|
+
import { useOrganizationStore } from '@fayz-ai/saas';
|
|
4
|
+
|
|
5
|
+
// src/index.ts
|
|
6
|
+
var ShopPage = React.lazy(() => import('./ShopPage-65PPVKBD.js').then((m) => ({ default: m.ShopPage })));
|
|
7
|
+
function createShopPlugin(options) {
|
|
8
|
+
const curr = { code: "BRL", symbol: "R$", ...options?.currency };
|
|
9
|
+
setShopTenantResolver(() => useOrganizationStore.getState().currentOrg?.id);
|
|
10
|
+
const PageComponent = () => React.createElement(
|
|
11
|
+
React.Suspense,
|
|
12
|
+
{ fallback: null },
|
|
13
|
+
React.createElement(ShopPage, {
|
|
14
|
+
provider: options?.provider
|
|
15
|
+
})
|
|
16
|
+
);
|
|
17
|
+
PageComponent.displayName = "ShopPageWrapper";
|
|
18
|
+
return {
|
|
19
|
+
id: "shop",
|
|
20
|
+
name: options?.navLabel ?? "Shop",
|
|
21
|
+
icon: "ShoppingBag",
|
|
22
|
+
version: "1.0.0",
|
|
23
|
+
scope: options?.scope ?? "vertical",
|
|
24
|
+
verticalId: options?.verticalId,
|
|
25
|
+
defaultEnabled: true,
|
|
26
|
+
dependencies: [],
|
|
27
|
+
navigation: [
|
|
28
|
+
{
|
|
29
|
+
section: options?.navSection ?? "main",
|
|
30
|
+
position: options?.navPosition ?? 6,
|
|
31
|
+
label: options?.navLabel ?? "Shop",
|
|
32
|
+
route: "/shop",
|
|
33
|
+
icon: "ShoppingBag",
|
|
34
|
+
permission: { feature: "shop", action: "read" }
|
|
35
|
+
}
|
|
36
|
+
],
|
|
37
|
+
routes: [
|
|
38
|
+
{
|
|
39
|
+
path: "/shop",
|
|
40
|
+
component: PageComponent,
|
|
41
|
+
permission: { feature: "shop", action: "read" }
|
|
42
|
+
}
|
|
43
|
+
],
|
|
44
|
+
widgets: [],
|
|
45
|
+
aiTools: [
|
|
46
|
+
{
|
|
47
|
+
id: "shop.list-products",
|
|
48
|
+
name: "listProducts",
|
|
49
|
+
description: "Lists products in the shop catalog.",
|
|
50
|
+
icon: "Package",
|
|
51
|
+
mode: "read",
|
|
52
|
+
category: "Shop",
|
|
53
|
+
parameters: {
|
|
54
|
+
type: "object",
|
|
55
|
+
properties: {
|
|
56
|
+
search: { type: "string", description: "Filter by name" },
|
|
57
|
+
status: { type: "string", enum: ["draft", "active", "archived"] }
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
suggestions: [
|
|
61
|
+
{ label: "What products are available?" },
|
|
62
|
+
{ label: "Which products are out of stock?" }
|
|
63
|
+
]
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
id: "shop.list-orders",
|
|
67
|
+
name: "listOrders",
|
|
68
|
+
description: "Lists recent shop orders.",
|
|
69
|
+
icon: "ShoppingCart",
|
|
70
|
+
mode: "read",
|
|
71
|
+
category: "Shop",
|
|
72
|
+
parameters: {
|
|
73
|
+
type: "object",
|
|
74
|
+
properties: {
|
|
75
|
+
financialStatus: { type: "string", enum: ["pending", "paid", "refunded", "voided"] },
|
|
76
|
+
fulfillmentStatus: { type: "string", enum: ["unfulfilled", "partially_fulfilled", "fulfilled"] }
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
suggestions: [
|
|
80
|
+
{ label: "Show me pending orders" },
|
|
81
|
+
{ label: "How many orders were paid today?" }
|
|
82
|
+
]
|
|
83
|
+
}
|
|
84
|
+
],
|
|
85
|
+
settings: [
|
|
86
|
+
{
|
|
87
|
+
id: "shop",
|
|
88
|
+
label: "Shop",
|
|
89
|
+
icon: "ShoppingBag",
|
|
90
|
+
component: (() => {
|
|
91
|
+
const ShopSettingsTab = () => React.createElement(
|
|
92
|
+
"div",
|
|
93
|
+
{ className: "p-4 space-y-2" },
|
|
94
|
+
React.createElement("h2", { className: "text-lg font-semibold" }, "Configura\xE7\xF5es da Loja"),
|
|
95
|
+
React.createElement(
|
|
96
|
+
"p",
|
|
97
|
+
{ className: "text-sm text-muted-foreground" },
|
|
98
|
+
`Moeda: ${curr.symbol} (${curr.code})`
|
|
99
|
+
)
|
|
100
|
+
);
|
|
101
|
+
ShopSettingsTab.displayName = "ShopSettingsTab";
|
|
102
|
+
return ShopSettingsTab;
|
|
103
|
+
})(),
|
|
104
|
+
order: 30,
|
|
105
|
+
permission: { feature: "shop", action: "read" }
|
|
106
|
+
}
|
|
107
|
+
]
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export { createShopPlugin };
|
|
112
|
+
//# sourceMappingURL=index.js.map
|
|
113
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import React from 'react'\nimport type { PluginManifest, PluginScope, VerticalId } from '@fayz-ai/core'\nimport { setShopTenantResolver } from '@fayz-ai/shop'\nimport { useOrganizationStore } from '@fayz-ai/saas'\nimport type { ShopProviderResolver } from './ShopPage'\n\nconst ShopPage = React.lazy(() => import('./ShopPage').then((m) => ({ default: m.ShopPage })))\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\nexport interface ShopPluginOptions {\n navPosition?: number\n navSection?: 'main' | 'secondary' | 'settings'\n navLabel?: string\n scope?: PluginScope\n verticalId?: VerticalId\n currency?: { code?: string; locale?: string; symbol?: string }\n provider?: ShopProviderResolver\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\nexport function createShopPlugin(options?: ShopPluginOptions): PluginManifest {\n const curr = { code: 'BRL', locale: 'pt-BR', symbol: 'R$', ...options?.currency }\n\n // Scope fallback shop queries to the active organization. Apps can inject a\n // provider when they want SDK-owned data access instead of the global runtime.\n setShopTenantResolver(() => useOrganizationStore.getState().currentOrg?.id)\n\n const PageComponent: React.ComponentType<unknown> = () =>\n React.createElement(React.Suspense, { fallback: null },\n React.createElement(ShopPage as React.ComponentType<{ provider?: ShopProviderResolver }>, {\n provider: options?.provider,\n })\n )\n PageComponent.displayName = 'ShopPageWrapper'\n\n return {\n id: 'shop',\n name: options?.navLabel ?? 'Shop',\n icon: 'ShoppingBag',\n version: '1.0.0',\n scope: options?.scope ?? 'vertical',\n verticalId: options?.verticalId,\n defaultEnabled: true,\n dependencies: [],\n navigation: [\n {\n section: options?.navSection ?? 'main',\n position: options?.navPosition ?? 6,\n label: options?.navLabel ?? 'Shop',\n route: '/shop',\n icon: 'ShoppingBag',\n permission: { feature: 'shop', action: 'read' as const },\n },\n ],\n routes: [\n {\n path: '/shop',\n component: PageComponent,\n permission: { feature: 'shop', action: 'read' as const },\n },\n ],\n widgets: [],\n aiTools: [\n {\n id: 'shop.list-products',\n name: 'listProducts',\n description: 'Lists products in the shop catalog.',\n icon: 'Package',\n mode: 'read' as const,\n category: 'Shop',\n parameters: {\n type: 'object' as const,\n properties: {\n search: { type: 'string' as const, description: 'Filter by name' },\n status: { type: 'string' as const, enum: ['draft', 'active', 'archived'] },\n },\n },\n suggestions: [\n { label: 'What products are available?' },\n { label: 'Which products are out of stock?' },\n ],\n },\n {\n id: 'shop.list-orders',\n name: 'listOrders',\n description: 'Lists recent shop orders.',\n icon: 'ShoppingCart',\n mode: 'read' as const,\n category: 'Shop',\n parameters: {\n type: 'object' as const,\n properties: {\n financialStatus: { type: 'string' as const, enum: ['pending', 'paid', 'refunded', 'voided'] },\n fulfillmentStatus: { type: 'string' as const, enum: ['unfulfilled', 'partially_fulfilled', 'fulfilled'] },\n },\n },\n suggestions: [\n { label: 'Show me pending orders' },\n { label: 'How many orders were paid today?' },\n ],\n },\n ],\n settings: [\n {\n id: 'shop',\n label: 'Shop',\n icon: 'ShoppingBag',\n component: (() => {\n const ShopSettingsTab: React.ComponentType<unknown> = () =>\n React.createElement('div', { className: 'p-4 space-y-2' },\n React.createElement('h2', { className: 'text-lg font-semibold' }, 'Configurações da Loja'),\n React.createElement('p', { className: 'text-sm text-muted-foreground' },\n `Moeda: ${curr.symbol} (${curr.code})`\n )\n )\n ShopSettingsTab.displayName = 'ShopSettingsTab'\n return ShopSettingsTab\n })(),\n order: 30,\n permission: { feature: 'shop', action: 'read' as const },\n },\n ],\n }\n}\n\n// Re-export shop types so consumer apps only need @fayz-ai/plugin-shop\nexport type {\n Product, Order, ShopCustomer, Discount, Category,\n CreateProductInput, UpdateProductInput, ListProductsOptions,\n CreateOrderInput, UpdateOrderInput, ListOrdersOptions,\n} from '@fayz-ai/shop'\n"]}
|