@codemind.ec/medusa-plugin-invoice 1.0.6 → 1.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.
@@ -5,10 +5,9 @@ const ui = require("@medusajs/ui");
5
5
  const Medusa = require("@medusajs/js-sdk");
6
6
  const react = require("react");
7
7
  const reactQuery = require("@tanstack/react-query");
8
- const reactHookForm = require("react-hook-form");
9
- const zod = require("@medusajs/framework/zod");
10
8
  const reactRouterDom = require("react-router-dom");
11
9
  const icons = require("@medusajs/icons");
10
+ const reactHookForm = require("react-hook-form");
12
11
  const CodeMirror = require("@uiw/react-codemirror");
13
12
  const langHtml = require("@codemirror/lang-html");
14
13
  const themeOneDark = require("@codemirror/theme-one-dark");
@@ -72,202 +71,167 @@ const OrderInvoiceWidget = ({ data: order }) => {
72
71
  adminSdk.defineWidgetConfig({
73
72
  zone: "order.details.side.before"
74
73
  });
75
- zod.z.object({
76
- company_name: zod.z.string().optional(),
77
- company_ruc: zod.z.string().optional(),
78
- company_address: zod.z.string().optional(),
79
- company_phone: zod.z.string().optional(),
80
- company_email: zod.z.string().email().optional().or(zod.z.literal("")),
81
- company_logo: zod.z.string().optional(),
82
- notes: zod.z.string().optional(),
83
- admin_notification_email: zod.z.string().email().optional().or(zod.z.literal(""))
84
- });
85
74
  const InvoiceConfigPage = () => {
86
75
  const navigate = reactRouterDom.useNavigate();
87
- const { data, isLoading, refetch } = reactQuery.useQuery({
76
+ const { data: configData, isLoading: loadingConfigs } = reactQuery.useQuery({
88
77
  queryFn: () => sdk.client.fetch("/admin/invoice-config"),
89
- queryKey: ["invoice-config"]
78
+ queryKey: ["invoice-configs"]
90
79
  });
91
- const { mutateAsync, isPending } = reactQuery.useMutation({
92
- mutationFn: (payload) => sdk.client.fetch("/admin/invoice-config", {
93
- method: "POST",
94
- body: payload
95
- }),
80
+ const { data: templateData, isLoading: loadingTemplates } = reactQuery.useQuery({
81
+ queryFn: () => sdk.client.fetch("/admin/invoice-templates"),
82
+ queryKey: ["invoice-templates"]
83
+ });
84
+ const configs = (configData == null ? void 0 : configData.invoice_configs) ?? [];
85
+ const templates = (templateData == null ? void 0 : templateData.invoice_templates) ?? [];
86
+ const defaultCompany = configs.find((c) => c.is_default);
87
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
88
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-6 py-4", children: [
89
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h1", children: "Comprobantes y Cotizaciones" }),
90
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle mt-1", children: "Gestiona empresas emisoras y plantillas de documentos." })
91
+ ] }),
92
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4 p-6", children: [
93
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border border-ui-border-base rounded-lg p-5 flex flex-col gap-3", children: [
94
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
95
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", children: "Empresas" }),
96
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { color: configs.length > 0 ? "blue" : "grey", children: configs.length })
97
+ ] }),
98
+ loadingConfigs ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle text-sm", children: "Cargando..." }) : defaultCompany ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-subtle rounded-md p-3", children: [
99
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-sm font-medium", children: defaultCompany.company_name }),
100
+ defaultCompany.company_ruc && /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { className: "text-ui-fg-subtle text-xs", children: [
101
+ "RUC: ",
102
+ defaultCompany.company_ruc
103
+ ] }),
104
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { color: "green", className: "mt-1", children: "Default" })
105
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle text-sm", children: "No hay empresas configuradas." }),
106
+ /* @__PURE__ */ jsxRuntime.jsx(
107
+ ui.Button,
108
+ {
109
+ variant: "secondary",
110
+ className: "mt-auto",
111
+ onClick: () => navigate("/invoice-config/companies"),
112
+ children: "Gestionar Empresas"
113
+ }
114
+ )
115
+ ] }),
116
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border border-ui-border-base rounded-lg p-5 flex flex-col gap-3", children: [
117
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
118
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", children: "Plantillas" }),
119
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { color: templates.length > 0 ? "blue" : "grey", children: templates.length })
120
+ ] }),
121
+ loadingTemplates ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle text-sm", children: "Cargando..." }) : templates.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-subtle rounded-md p-3 flex flex-col gap-1", children: [
122
+ templates.slice(0, 3).map((t) => /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-sm", children: t.name }, t.id)),
123
+ templates.length > 3 && /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { className: "text-ui-fg-subtle text-xs", children: [
124
+ "+",
125
+ templates.length - 3,
126
+ " más..."
127
+ ] })
128
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle text-sm", children: "No hay plantillas. Se crearán al reiniciar el servidor." }),
129
+ /* @__PURE__ */ jsxRuntime.jsx(
130
+ ui.Button,
131
+ {
132
+ variant: "secondary",
133
+ className: "mt-auto",
134
+ onClick: () => navigate("/invoice-config/invoice-templates"),
135
+ children: "Gestionar Plantillas"
136
+ }
137
+ )
138
+ ] })
139
+ ] })
140
+ ] });
141
+ };
142
+ const config$1 = adminSdk.defineRouteConfig({
143
+ label: "Comprobantes y Cotizaciones"
144
+ });
145
+ const CompaniesPage = () => {
146
+ const navigate = reactRouterDom.useNavigate();
147
+ const queryClient = reactQuery.useQueryClient();
148
+ const { data, isLoading } = reactQuery.useQuery({
149
+ queryFn: () => sdk.client.fetch("/admin/invoice-config"),
150
+ queryKey: ["invoice-configs"]
151
+ });
152
+ const setDefaultMutation = reactQuery.useMutation({
153
+ mutationFn: (id) => sdk.client.fetch(`/admin/invoice-config/${id}/set-default`, { method: "POST" }),
96
154
  onSuccess: () => {
97
- refetch();
98
- ui.toast.success("Configuración actualizada exitosamente");
155
+ queryClient.invalidateQueries({ queryKey: ["invoice-configs"] });
156
+ ui.toast.success("Empresa marcada como default");
99
157
  },
100
- onError: () => {
101
- ui.toast.error("Error al guardar la configuración");
102
- }
158
+ onError: () => ui.toast.error("Error al cambiar empresa default")
103
159
  });
104
- const getFormDefaultValues = react.useCallback(() => {
105
- return {
106
- company_name: (data == null ? void 0 : data.invoice_config.company_name) || "",
107
- company_ruc: (data == null ? void 0 : data.invoice_config.company_ruc) || "",
108
- company_address: (data == null ? void 0 : data.invoice_config.company_address) || "",
109
- company_phone: (data == null ? void 0 : data.invoice_config.company_phone) || "",
110
- company_email: (data == null ? void 0 : data.invoice_config.company_email) || "",
111
- company_logo: (data == null ? void 0 : data.invoice_config.company_logo) || "",
112
- notes: (data == null ? void 0 : data.invoice_config.notes) || "",
113
- admin_notification_email: (data == null ? void 0 : data.invoice_config.admin_notification_email) || ""
114
- };
115
- }, [data]);
116
- const form = reactHookForm.useForm({
117
- defaultValues: getFormDefaultValues()
160
+ const deleteMutation = reactQuery.useMutation({
161
+ mutationFn: (id) => sdk.client.fetch(`/admin/invoice-config/${id}`, { method: "DELETE" }),
162
+ onSuccess: () => {
163
+ queryClient.invalidateQueries({ queryKey: ["invoice-configs"] });
164
+ ui.toast.success("Empresa eliminada");
165
+ },
166
+ onError: () => ui.toast.error("No se pudo eliminar la empresa")
118
167
  });
119
- const handleSubmit = form.handleSubmit((formData) => mutateAsync(formData));
120
- const uploadLogo = async (event) => {
121
- var _a;
122
- const file = (_a = event.target.files) == null ? void 0 : _a[0];
123
- if (!file) {
124
- return;
125
- }
126
- try {
127
- const { files } = await sdk.admin.upload.create({
128
- files: [file]
129
- });
130
- form.setValue("company_logo", files[0].url);
131
- } catch (error) {
132
- ui.toast.error("Error al subir el logo. Verifica que el archivo sea una imagen válida.");
133
- }
134
- };
135
- react.useEffect(() => {
136
- form.reset(getFormDefaultValues());
137
- }, [getFormDefaultValues]);
168
+ const configs = (data == null ? void 0 : data.invoice_configs) ?? [];
138
169
  return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
139
170
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-6 py-4", children: [
140
- /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h1", children: "Configuración de Comprobante" }),
141
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "secondary", onClick: () => navigate("/invoice-config/invoice-templates"), children: "Gestionar Plantillas" })
171
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
172
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h1", children: "Empresas" }),
173
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle text-sm mt-1", children: "Empresas emisoras de comprobantes y cotizaciones." })
174
+ ] }),
175
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2", children: [
176
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "secondary", onClick: () => navigate("/invoice-config"), children: "← Panel" }),
177
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { onClick: () => navigate("/invoice-config/companies/new"), children: "+ Nueva Empresa" })
178
+ ] })
142
179
  ] }),
143
- /* @__PURE__ */ jsxRuntime.jsx(reactHookForm.FormProvider, { ...form, children: /* @__PURE__ */ jsxRuntime.jsxs(
144
- "form",
145
- {
146
- onSubmit: handleSubmit,
147
- className: "flex h-full flex-col overflow-hidden p-2 gap-2",
148
- children: [
149
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-ui-bg-subtle border border-ui-border-base rounded-lg p-3 mb-2", children: /* @__PURE__ */ jsxRuntime.jsx(
150
- reactHookForm.Controller,
151
- {
152
- control: form.control,
153
- name: "admin_notification_email",
154
- render: ({ field }) => {
155
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col space-y-2", children: [
156
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-x-1", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "small", weight: "plus", children: "📧 Email de Notificaciones (Admin)" }) }),
157
- /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { ...field, onChange: field.onChange, value: field.value, placeholder: "admin@mariquita.food" }),
158
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ui-fg-subtle text-xs", children: "Se enviarán notificaciones de nuevos pedidos y comprobantes de pago a este email." })
159
- ] });
160
- }
161
- }
162
- ) }),
163
- /* @__PURE__ */ jsxRuntime.jsx(
164
- reactHookForm.Controller,
165
- {
166
- control: form.control,
167
- name: "company_name",
168
- render: ({ field }) => {
169
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col space-y-2", children: [
170
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-x-1", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "small", weight: "plus", children: "Nombre de la Empresa" }) }),
171
- /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { ...field, onChange: field.onChange, value: field.value })
172
- ] });
173
- }
174
- }
175
- ),
176
- /* @__PURE__ */ jsxRuntime.jsx(
177
- reactHookForm.Controller,
178
- {
179
- control: form.control,
180
- name: "company_ruc",
181
- render: ({ field }) => {
182
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col space-y-2", children: [
183
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-x-1", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "small", weight: "plus", children: "RUC" }) }),
184
- /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { ...field, onChange: field.onChange, value: field.value, placeholder: "1234567890001" })
185
- ] });
186
- }
187
- }
188
- ),
189
- /* @__PURE__ */ jsxRuntime.jsx(
190
- reactHookForm.Controller,
191
- {
192
- control: form.control,
193
- name: "company_address",
194
- render: ({ field }) => {
195
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col space-y-2", children: [
196
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-x-1", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "small", weight: "plus", children: "Dirección de la Empresa" }) }),
197
- /* @__PURE__ */ jsxRuntime.jsx(ui.Textarea, { ...field })
198
- ] });
199
- }
200
- }
201
- ),
202
- /* @__PURE__ */ jsxRuntime.jsx(
203
- reactHookForm.Controller,
204
- {
205
- control: form.control,
206
- name: "company_phone",
207
- render: ({ field }) => {
208
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col space-y-2", children: [
209
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-x-1", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "small", weight: "plus", children: "Teléfono de la Empresa" }) }),
210
- /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { ...field })
211
- ] });
212
- }
213
- }
214
- ),
215
- /* @__PURE__ */ jsxRuntime.jsx(
216
- reactHookForm.Controller,
217
- {
218
- control: form.control,
219
- name: "company_email",
220
- render: ({ field }) => {
221
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col space-y-2", children: [
222
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-x-1", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "small", weight: "plus", children: "Email de la Empresa" }) }),
223
- /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { ...field })
224
- ] });
225
- }
226
- }
227
- ),
228
- /* @__PURE__ */ jsxRuntime.jsx(
229
- reactHookForm.Controller,
230
- {
231
- control: form.control,
232
- name: "notes",
233
- render: ({ field }) => {
234
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col space-y-2", children: [
235
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-x-1", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "small", weight: "plus", children: "Notas" }) }),
236
- /* @__PURE__ */ jsxRuntime.jsx(ui.Textarea, { ...field })
237
- ] });
238
- }
239
- }
240
- ),
241
- /* @__PURE__ */ jsxRuntime.jsx(
242
- reactHookForm.Controller,
243
- {
244
- control: form.control,
245
- name: "company_logo",
246
- render: ({ field }) => {
247
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col space-y-2", children: [
248
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-x-1", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "small", weight: "plus", children: "Logo de la Empresa" }) }),
249
- /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { type: "file", onChange: uploadLogo, className: "py-1" }),
250
- field.value && /* @__PURE__ */ jsxRuntime.jsx(
251
- "img",
252
- {
253
- src: field.value,
254
- alt: "Logo de la Empresa",
255
- className: "mt-2 h-24 w-24"
180
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 pb-4", children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center py-10 text-ui-fg-subtle", children: "Cargando..." }) : configs.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center py-10 text-ui-fg-subtle", children: "No hay empresas configuradas." }) : /* @__PURE__ */ jsxRuntime.jsxs(ui.Table, { children: [
181
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Header, { children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { children: [
182
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "Nombre" }),
183
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "RUC" }),
184
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "Email" }),
185
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "Teléfono" }),
186
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "Estado" }),
187
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { style: { textAlign: "right" }, children: "Acciones" })
188
+ ] }) }),
189
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Body, { children: configs.map((cfg) => /* @__PURE__ */ jsxRuntime.jsxs(
190
+ ui.Table.Row,
191
+ {
192
+ onClick: () => navigate(`/invoice-config/companies/${cfg.id}`),
193
+ style: { cursor: "pointer" },
194
+ children: [
195
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "font-medium", children: cfg.company_name }),
196
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx("code", { className: "text-xs", children: cfg.company_ruc || "—" }) }),
197
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: cfg.company_email }),
198
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: cfg.company_phone }),
199
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: cfg.is_default ? /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { color: "green", children: "Default" }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { color: "grey", children: "—" }) }),
200
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { style: { textAlign: "right" }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-2 justify-end", children: !cfg.is_default && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
201
+ /* @__PURE__ */ jsxRuntime.jsx(
202
+ ui.Button,
203
+ {
204
+ variant: "secondary",
205
+ size: "small",
206
+ onClick: (e) => {
207
+ e.stopPropagation();
208
+ setDefaultMutation.mutate(cfg.id);
209
+ },
210
+ children: "Default"
211
+ }
212
+ ),
213
+ /* @__PURE__ */ jsxRuntime.jsx(
214
+ ui.Button,
215
+ {
216
+ variant: "danger",
217
+ size: "small",
218
+ onClick: (e) => {
219
+ e.stopPropagation();
220
+ if (confirm("¿Eliminar esta empresa?")) {
221
+ deleteMutation.mutate(cfg.id);
256
222
  }
257
- )
258
- ] });
259
- }
260
- }
261
- ),
262
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { type: "submit", disabled: isLoading || isPending, children: "Guardar" })
263
- ]
264
- }
265
- ) })
223
+ },
224
+ children: "Eliminar"
225
+ }
226
+ )
227
+ ] }) }) })
228
+ ]
229
+ },
230
+ cfg.id
231
+ )) })
232
+ ] }) })
266
233
  ] });
267
234
  };
268
- const config$1 = adminSdk.defineRouteConfig({
269
- label: "Comprobante de Pedido"
270
- });
271
235
  const TYPE_LABELS = {
272
236
  order_invoice: "Comprobante de Pedido",
273
237
  quote_proforma: "Cotización Proforma"
@@ -279,6 +243,10 @@ const InvoiceTemplatesPage = () => {
279
243
  queryFn: () => sdk.client.fetch("/admin/invoice-templates"),
280
244
  queryKey: ["invoice-templates"]
281
245
  });
246
+ const { data: companiesData } = reactQuery.useQuery({
247
+ queryFn: () => sdk.client.fetch("/admin/invoice-config"),
248
+ queryKey: ["invoice-configs"]
249
+ });
282
250
  const deleteMutation = reactQuery.useMutation({
283
251
  mutationFn: (id) => sdk.client.fetch(`/admin/invoice-templates/${id}`, { method: "DELETE" }),
284
252
  onSuccess: () => {
@@ -290,19 +258,21 @@ const InvoiceTemplatesPage = () => {
290
258
  }
291
259
  });
292
260
  const templates = (data == null ? void 0 : data.invoice_templates) ?? [];
293
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { children: [
294
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 24 }, children: [
261
+ const companiesMap = new Map(((companiesData == null ? void 0 : companiesData.invoice_configs) ?? []).map((c) => [c.id, c.company_name]));
262
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
263
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-6 py-4", children: [
295
264
  /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h1", children: "Plantillas de Documentos" }),
296
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: 8 }, children: [
297
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "secondary", onClick: () => navigate("/invoice-config"), children: "Configuración" }),
265
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2", children: [
266
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "secondary", onClick: () => navigate("/invoice-config"), children: "← Panel" }),
298
267
  /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { onClick: () => navigate("/invoice-config/invoice-templates/new"), children: "+ Nueva Plantilla" })
299
268
  ] })
300
269
  ] }),
301
- isLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { textAlign: "center", padding: 40 }, children: "Cargando..." }) : templates.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { textAlign: "center", padding: 40, color: "#6c757d" }, children: "No hay plantillas. Se crearán automáticamente al reiniciar el servidor." }) : /* @__PURE__ */ jsxRuntime.jsxs(ui.Table, { children: [
270
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 pb-4", children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center py-10 text-ui-fg-subtle", children: "Cargando..." }) : templates.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center py-10 text-ui-fg-subtle", children: "No hay plantillas. Se crearán automáticamente al reiniciar el servidor." }) : /* @__PURE__ */ jsxRuntime.jsxs(ui.Table, { children: [
302
271
  /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Header, { children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { children: [
303
272
  /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "Nombre" }),
304
273
  /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "Slug" }),
305
274
  /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "Tipo" }),
275
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "Empresa" }),
306
276
  /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "Estado" }),
307
277
  /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "Actualizado" }),
308
278
  /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { style: { textAlign: "right" }, children: "Acciones" })
@@ -313,9 +283,10 @@ const InvoiceTemplatesPage = () => {
313
283
  onClick: () => navigate(`/invoice-config/invoice-templates/${tpl.id}`),
314
284
  style: { cursor: "pointer" },
315
285
  children: [
316
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: tpl.name }),
317
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx("code", { style: { fontSize: 12 }, children: tpl.slug }) }),
286
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "font-medium", children: tpl.name }),
287
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx("code", { className: "text-xs", children: tpl.slug }) }),
318
288
  /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: TYPE_LABELS[tpl.type] ?? tpl.type }),
289
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-sm", children: tpl.company_id ? companiesMap.get(tpl.company_id) ?? "—" : "—" }) }),
319
290
  /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: tpl.is_default ? /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { color: "blue", children: "Por defecto" }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { color: "grey", children: "Personalizada" }) }),
320
291
  /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: new Date(tpl.updated_at).toLocaleDateString("es-ES") }),
321
292
  /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { style: { textAlign: "right" }, children: /* @__PURE__ */ jsxRuntime.jsx(
@@ -337,13 +308,356 @@ const InvoiceTemplatesPage = () => {
337
308
  },
338
309
  tpl.id
339
310
  )) })
340
- ] })
311
+ ] }) })
341
312
  ] });
342
313
  };
343
314
  const config = adminSdk.defineRouteConfig({
344
315
  label: "Plantillas PDF",
345
316
  icon: icons.DocumentText
346
317
  });
318
+ const EditCompanyPage = () => {
319
+ const { id } = reactRouterDom.useParams();
320
+ const navigate = reactRouterDom.useNavigate();
321
+ const queryClient = reactQuery.useQueryClient();
322
+ const { data, isLoading } = reactQuery.useQuery({
323
+ queryFn: () => sdk.client.fetch(`/admin/invoice-config/${id}`),
324
+ queryKey: ["invoice-config", id],
325
+ enabled: !!id
326
+ });
327
+ const config2 = data == null ? void 0 : data.invoice_config;
328
+ const getDefaults = react.useCallback(() => ({
329
+ company_name: (config2 == null ? void 0 : config2.company_name) || "",
330
+ company_ruc: (config2 == null ? void 0 : config2.company_ruc) || "",
331
+ company_address: (config2 == null ? void 0 : config2.company_address) || "",
332
+ company_phone: (config2 == null ? void 0 : config2.company_phone) || "",
333
+ company_email: (config2 == null ? void 0 : config2.company_email) || "",
334
+ company_logo: (config2 == null ? void 0 : config2.company_logo) || "",
335
+ notes: (config2 == null ? void 0 : config2.notes) || "",
336
+ admin_notification_email: (config2 == null ? void 0 : config2.admin_notification_email) || "",
337
+ is_default: (config2 == null ? void 0 : config2.is_default) || false
338
+ }), [config2]);
339
+ const form = reactHookForm.useForm({ defaultValues: getDefaults() });
340
+ react.useEffect(() => {
341
+ form.reset(getDefaults());
342
+ }, [getDefaults]);
343
+ const saveMutation = reactQuery.useMutation({
344
+ mutationFn: (payload) => sdk.client.fetch(`/admin/invoice-config/${id}`, {
345
+ method: "POST",
346
+ body: payload
347
+ }),
348
+ onSuccess: () => {
349
+ queryClient.invalidateQueries({ queryKey: ["invoice-config", id] });
350
+ queryClient.invalidateQueries({ queryKey: ["invoice-configs"] });
351
+ ui.toast.success("Empresa actualizada");
352
+ },
353
+ onError: () => ui.toast.error("Error al guardar")
354
+ });
355
+ const uploadLogo = async (event) => {
356
+ var _a;
357
+ const file = (_a = event.target.files) == null ? void 0 : _a[0];
358
+ if (!file) return;
359
+ try {
360
+ const { files } = await sdk.admin.upload.create({ files: [file] });
361
+ form.setValue("company_logo", files[0].url);
362
+ } catch {
363
+ ui.toast.error("Error al subir el logo.");
364
+ }
365
+ };
366
+ const handleSubmit = form.handleSubmit((data2) => saveMutation.mutate(data2));
367
+ if (isLoading) {
368
+ return /* @__PURE__ */ jsxRuntime.jsx(ui.Container, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center py-10", children: "Cargando..." }) });
369
+ }
370
+ if (!config2) {
371
+ return /* @__PURE__ */ jsxRuntime.jsx(ui.Container, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center py-10", children: "Empresa no encontrada" }) });
372
+ }
373
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
374
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-6 py-4", children: [
375
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h1", children: "Editar Empresa" }),
376
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "secondary", onClick: () => navigate("/invoice-config/companies"), children: "← Volver" })
377
+ ] }),
378
+ /* @__PURE__ */ jsxRuntime.jsx(reactHookForm.FormProvider, { ...form, children: /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, className: "flex flex-col gap-4 p-6 max-w-2xl", children: [
379
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-ui-bg-subtle border border-ui-border-base rounded-lg p-4 mb-2", children: /* @__PURE__ */ jsxRuntime.jsx(
380
+ reactHookForm.Controller,
381
+ {
382
+ control: form.control,
383
+ name: "admin_notification_email",
384
+ render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
385
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "small", weight: "plus", children: "📧 Email de Notificaciones (Admin)" }),
386
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { ...field, placeholder: "admin@empresa.com" }),
387
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle text-xs", children: "Notificaciones de nuevos pedidos a este email." })
388
+ ] })
389
+ }
390
+ ) }),
391
+ /* @__PURE__ */ jsxRuntime.jsx(
392
+ reactHookForm.Controller,
393
+ {
394
+ control: form.control,
395
+ name: "company_name",
396
+ render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
397
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "small", weight: "plus", children: "Nombre de la Empresa *" }),
398
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { ...field })
399
+ ] })
400
+ }
401
+ ),
402
+ /* @__PURE__ */ jsxRuntime.jsx(
403
+ reactHookForm.Controller,
404
+ {
405
+ control: form.control,
406
+ name: "company_ruc",
407
+ render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
408
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "small", weight: "plus", children: "RUC" }),
409
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { ...field, placeholder: "1234567890001" })
410
+ ] })
411
+ }
412
+ ),
413
+ /* @__PURE__ */ jsxRuntime.jsx(
414
+ reactHookForm.Controller,
415
+ {
416
+ control: form.control,
417
+ name: "company_address",
418
+ render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
419
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "small", weight: "plus", children: "Dirección" }),
420
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Textarea, { ...field })
421
+ ] })
422
+ }
423
+ ),
424
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
425
+ /* @__PURE__ */ jsxRuntime.jsx(
426
+ reactHookForm.Controller,
427
+ {
428
+ control: form.control,
429
+ name: "company_phone",
430
+ render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
431
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "small", weight: "plus", children: "Teléfono" }),
432
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { ...field })
433
+ ] })
434
+ }
435
+ ),
436
+ /* @__PURE__ */ jsxRuntime.jsx(
437
+ reactHookForm.Controller,
438
+ {
439
+ control: form.control,
440
+ name: "company_email",
441
+ render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
442
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "small", weight: "plus", children: "Email de la Empresa" }),
443
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { ...field })
444
+ ] })
445
+ }
446
+ )
447
+ ] }),
448
+ /* @__PURE__ */ jsxRuntime.jsx(
449
+ reactHookForm.Controller,
450
+ {
451
+ control: form.control,
452
+ name: "notes",
453
+ render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
454
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "small", weight: "plus", children: "Notas" }),
455
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Textarea, { ...field })
456
+ ] })
457
+ }
458
+ ),
459
+ /* @__PURE__ */ jsxRuntime.jsx(
460
+ reactHookForm.Controller,
461
+ {
462
+ control: form.control,
463
+ name: "company_logo",
464
+ render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
465
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "small", weight: "plus", children: "Logo de la Empresa" }),
466
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { type: "file", onChange: uploadLogo, className: "py-1" }),
467
+ field.value && /* @__PURE__ */ jsxRuntime.jsx("img", { src: field.value, alt: "Logo", className: "mt-2 h-24 w-24 object-contain" })
468
+ ] })
469
+ }
470
+ ),
471
+ /* @__PURE__ */ jsxRuntime.jsx(
472
+ reactHookForm.Controller,
473
+ {
474
+ control: form.control,
475
+ name: "is_default",
476
+ render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 bg-ui-bg-subtle rounded-lg p-3", children: [
477
+ /* @__PURE__ */ jsxRuntime.jsx(
478
+ ui.Switch,
479
+ {
480
+ checked: field.value,
481
+ onCheckedChange: field.onChange
482
+ }
483
+ ),
484
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
485
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "small", weight: "plus", children: "Empresa por defecto" }),
486
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle text-xs", children: "Se usará en plantillas que no tengan empresa asignada." })
487
+ ] })
488
+ ] })
489
+ }
490
+ ),
491
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2 pt-2", children: [
492
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "secondary", onClick: () => navigate("/invoice-config/companies"), children: "Cancelar" }),
493
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { type: "submit", isLoading: saveMutation.isPending, children: "Guardar Cambios" })
494
+ ] })
495
+ ] }) })
496
+ ] });
497
+ };
498
+ const NewCompanyPage = () => {
499
+ const navigate = reactRouterDom.useNavigate();
500
+ const form = reactHookForm.useForm({
501
+ defaultValues: {
502
+ company_name: "",
503
+ company_ruc: "",
504
+ company_address: "",
505
+ company_phone: "",
506
+ company_email: "",
507
+ company_logo: "",
508
+ notes: "",
509
+ admin_notification_email: "",
510
+ is_default: false
511
+ }
512
+ });
513
+ const createMutation = reactQuery.useMutation({
514
+ mutationFn: (payload) => sdk.client.fetch("/admin/invoice-config", {
515
+ method: "POST",
516
+ body: payload
517
+ }),
518
+ onSuccess: () => {
519
+ ui.toast.success("Empresa creada exitosamente");
520
+ navigate("/invoice-config/companies");
521
+ },
522
+ onError: () => ui.toast.error("Error al crear la empresa")
523
+ });
524
+ const uploadLogo = async (event) => {
525
+ var _a;
526
+ const file = (_a = event.target.files) == null ? void 0 : _a[0];
527
+ if (!file) return;
528
+ try {
529
+ const { files } = await sdk.admin.upload.create({ files: [file] });
530
+ form.setValue("company_logo", files[0].url);
531
+ } catch {
532
+ ui.toast.error("Error al subir el logo.");
533
+ }
534
+ };
535
+ const handleSubmit = form.handleSubmit((data) => createMutation.mutate(data));
536
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
537
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-6 py-4", children: [
538
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h1", children: "Nueva Empresa" }),
539
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "secondary", onClick: () => navigate("/invoice-config/companies"), children: "← Volver" })
540
+ ] }),
541
+ /* @__PURE__ */ jsxRuntime.jsx(reactHookForm.FormProvider, { ...form, children: /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, className: "flex flex-col gap-4 p-6 max-w-2xl", children: [
542
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-ui-bg-subtle border border-ui-border-base rounded-lg p-4 mb-2", children: /* @__PURE__ */ jsxRuntime.jsx(
543
+ reactHookForm.Controller,
544
+ {
545
+ control: form.control,
546
+ name: "admin_notification_email",
547
+ render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
548
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "small", weight: "plus", children: "📧 Email de Notificaciones (Admin)" }),
549
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { ...field, placeholder: "admin@empresa.com" }),
550
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle text-xs", children: "Notificaciones de nuevos pedidos a este email." })
551
+ ] })
552
+ }
553
+ ) }),
554
+ /* @__PURE__ */ jsxRuntime.jsx(
555
+ reactHookForm.Controller,
556
+ {
557
+ control: form.control,
558
+ name: "company_name",
559
+ render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
560
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "small", weight: "plus", children: "Nombre de la Empresa *" }),
561
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { ...field, placeholder: "Mi Empresa S.A.S." })
562
+ ] })
563
+ }
564
+ ),
565
+ /* @__PURE__ */ jsxRuntime.jsx(
566
+ reactHookForm.Controller,
567
+ {
568
+ control: form.control,
569
+ name: "company_ruc",
570
+ render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
571
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "small", weight: "plus", children: "RUC" }),
572
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { ...field, placeholder: "1234567890001" })
573
+ ] })
574
+ }
575
+ ),
576
+ /* @__PURE__ */ jsxRuntime.jsx(
577
+ reactHookForm.Controller,
578
+ {
579
+ control: form.control,
580
+ name: "company_address",
581
+ render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
582
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "small", weight: "plus", children: "Dirección" }),
583
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Textarea, { ...field, placeholder: "Av. Principal 123, Quito" })
584
+ ] })
585
+ }
586
+ ),
587
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
588
+ /* @__PURE__ */ jsxRuntime.jsx(
589
+ reactHookForm.Controller,
590
+ {
591
+ control: form.control,
592
+ name: "company_phone",
593
+ render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
594
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "small", weight: "plus", children: "Teléfono" }),
595
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { ...field, placeholder: "+593 99 123 4567" })
596
+ ] })
597
+ }
598
+ ),
599
+ /* @__PURE__ */ jsxRuntime.jsx(
600
+ reactHookForm.Controller,
601
+ {
602
+ control: form.control,
603
+ name: "company_email",
604
+ render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
605
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "small", weight: "plus", children: "Email de la Empresa" }),
606
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { ...field, placeholder: "info@empresa.com" })
607
+ ] })
608
+ }
609
+ )
610
+ ] }),
611
+ /* @__PURE__ */ jsxRuntime.jsx(
612
+ reactHookForm.Controller,
613
+ {
614
+ control: form.control,
615
+ name: "notes",
616
+ render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
617
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "small", weight: "plus", children: "Notas" }),
618
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Textarea, { ...field, placeholder: "Notas internas o pie de página del documento" })
619
+ ] })
620
+ }
621
+ ),
622
+ /* @__PURE__ */ jsxRuntime.jsx(
623
+ reactHookForm.Controller,
624
+ {
625
+ control: form.control,
626
+ name: "company_logo",
627
+ render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
628
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "small", weight: "plus", children: "Logo de la Empresa" }),
629
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { type: "file", onChange: uploadLogo, className: "py-1" }),
630
+ field.value && /* @__PURE__ */ jsxRuntime.jsx("img", { src: field.value, alt: "Logo", className: "mt-2 h-24 w-24 object-contain" })
631
+ ] })
632
+ }
633
+ ),
634
+ /* @__PURE__ */ jsxRuntime.jsx(
635
+ reactHookForm.Controller,
636
+ {
637
+ control: form.control,
638
+ name: "is_default",
639
+ render: ({ field }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 bg-ui-bg-subtle rounded-lg p-3", children: [
640
+ /* @__PURE__ */ jsxRuntime.jsx(
641
+ ui.Switch,
642
+ {
643
+ checked: field.value,
644
+ onCheckedChange: field.onChange
645
+ }
646
+ ),
647
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
648
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "small", weight: "plus", children: "Empresa por defecto" }),
649
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle text-xs", children: "Se usará en plantillas que no tengan empresa asignada." })
650
+ ] })
651
+ ] })
652
+ }
653
+ ),
654
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2 pt-2", children: [
655
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "secondary", onClick: () => navigate("/invoice-config/companies"), children: "Cancelar" }),
656
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { type: "submit", isLoading: createMutation.isPending, children: "Crear Empresa" })
657
+ ] })
658
+ ] }) })
659
+ ] });
660
+ };
347
661
  const NewTemplatePage = () => {
348
662
  const navigate = reactRouterDom.useNavigate();
349
663
  const [name, setName] = react.useState("");
@@ -434,66 +748,139 @@ function getDefaultHtml(type) {
434
748
  </body>
435
749
  </html>`;
436
750
  }
437
- const VARIABLES = {
438
- order_invoice: [
439
- "company_name",
440
- "company_ruc",
441
- "company_address",
442
- "company_phone",
443
- "company_email",
444
- "company_logo_base64",
445
- "invoice_id",
446
- "invoice_date",
447
- "order_display_id",
448
- "order_date",
449
- "billing_address",
450
- "shipping_address",
451
- "cedula",
452
- "subtotal",
453
- "tax_total",
454
- "shipping_total",
455
- "discount_total",
456
- "total",
457
- "is_home_delivery",
458
- "notes",
459
- "{{#each items}}",
460
- "this.title",
461
- "this.variant_title",
462
- "this.quantity",
463
- "this.unit_price",
464
- "this.total",
465
- "{{/each}}"
466
- ],
467
- quote_proforma: [
468
- "company_name",
469
- "company_website",
470
- "quote_number",
471
- "date_str",
472
- "service_name",
473
- "is_home_delivery",
474
- "{{#each config_fields}}",
475
- "this.label",
476
- "this.value",
477
- "{{/each}}",
478
- "{{#each breakdown}}",
479
- "this.label",
480
- "this.total_formatted",
481
- "{{/each}}",
482
- "totals.subtotal_formatted",
483
- "totals.extras_formatted",
484
- "totals.discount_formatted",
485
- "totals.shipping_formatted",
486
- "totals.taxes_provided",
487
- "totals.taxes_formatted",
488
- "totals.total_formatted",
489
- "{{#each includes_left}}",
490
- "{{#each includes_right}}",
491
- "{{#each contact_rows}}",
492
- "this.label",
493
- "this.value",
494
- "{{/each}}"
495
- ]
751
+ const COMPANY_VARIABLES = [
752
+ { name: "company_name" },
753
+ { name: "company_ruc" },
754
+ { name: "company_address" },
755
+ { name: "company_phone" },
756
+ { name: "company_email" },
757
+ { name: "company_logo_base64" }
758
+ ];
759
+ const ORDER_INVOICE_CATEGORIES = [
760
+ {
761
+ label: "Empresa",
762
+ icon: "🏢",
763
+ variables: COMPANY_VARIABLES
764
+ },
765
+ {
766
+ label: "Documento",
767
+ icon: "📄",
768
+ variables: [
769
+ { name: "invoice_id" },
770
+ { name: "invoice_date" },
771
+ { name: "order_display_id" },
772
+ { name: "order_date" }
773
+ ]
774
+ },
775
+ {
776
+ label: "Cliente",
777
+ icon: "👤",
778
+ variables: [
779
+ { name: "billing_address" },
780
+ { name: "shipping_address" },
781
+ { name: "cedula" }
782
+ ]
783
+ },
784
+ {
785
+ label: "Productos",
786
+ icon: "📦",
787
+ variables: [
788
+ { name: "{{#each items}}", isBlock: true },
789
+ { name: "this.title" },
790
+ { name: "this.variant_title" },
791
+ { name: "this.quantity" },
792
+ { name: "this.unit_price" },
793
+ { name: "this.total" },
794
+ { name: "{{/each}}", isBlock: true }
795
+ ]
796
+ },
797
+ {
798
+ label: "Totales",
799
+ icon: "💰",
800
+ variables: [
801
+ { name: "subtotal" },
802
+ { name: "tax_total" },
803
+ { name: "shipping_total" },
804
+ { name: "discount_total" },
805
+ { name: "total" }
806
+ ]
807
+ },
808
+ {
809
+ label: "Otros",
810
+ icon: "📝",
811
+ variables: [
812
+ { name: "is_home_delivery" },
813
+ { name: "notes" }
814
+ ]
815
+ }
816
+ ];
817
+ const QUOTE_PROFORMA_CATEGORIES = [
818
+ {
819
+ label: "Empresa",
820
+ icon: "🏢",
821
+ variables: [...COMPANY_VARIABLES, { name: "company_website" }]
822
+ },
823
+ {
824
+ label: "Documento",
825
+ icon: "📄",
826
+ variables: [
827
+ { name: "quote_number" },
828
+ { name: "date_str" },
829
+ { name: "service_name" },
830
+ { name: "is_home_delivery" }
831
+ ]
832
+ },
833
+ {
834
+ label: "Configuración",
835
+ icon: "⚙️",
836
+ variables: [
837
+ { name: "{{#each config_fields}}", isBlock: true },
838
+ { name: "this.label" },
839
+ { name: "this.value" },
840
+ { name: "{{/each}}", isBlock: true }
841
+ ]
842
+ },
843
+ {
844
+ label: "Desglose",
845
+ icon: "📊",
846
+ variables: [
847
+ { name: "{{#each breakdown}}", isBlock: true },
848
+ { name: "this.label" },
849
+ { name: "this.total_formatted" },
850
+ { name: "{{/each}}", isBlock: true }
851
+ ]
852
+ },
853
+ {
854
+ label: "Totales",
855
+ icon: "💰",
856
+ variables: [
857
+ { name: "totals.subtotal_formatted" },
858
+ { name: "totals.extras_formatted" },
859
+ { name: "totals.discount_formatted" },
860
+ { name: "totals.shipping_formatted" },
861
+ { name: "totals.taxes_provided" },
862
+ { name: "totals.taxes_formatted" },
863
+ { name: "totals.total_formatted" }
864
+ ]
865
+ },
866
+ {
867
+ label: "Incluye y Contacto",
868
+ icon: "📋",
869
+ variables: [
870
+ { name: "{{#each includes_left}}", isBlock: true },
871
+ { name: "{{#each includes_right}}", isBlock: true },
872
+ { name: "{{#each contact_rows}}", isBlock: true },
873
+ { name: "this.label" },
874
+ { name: "this.value" },
875
+ { name: "{{/each}}", isBlock: true }
876
+ ]
877
+ }
878
+ ];
879
+ const CATEGORIES = {
880
+ order_invoice: ORDER_INVOICE_CATEGORIES,
881
+ quote_proforma: QUOTE_PROFORMA_CATEGORIES
496
882
  };
883
+ const PLACEHOLDER_LOGO_BASE64 = "data:image/svg+xml;base64," + btoa(`<svg xmlns="http://www.w3.org/2000/svg" width="120" height="40" viewBox="0 0 120 40"><rect width="120" height="40" rx="4" fill="#e2e8f0"/><text x="60" y="24" text-anchor="middle" fill="#64748b" font-family="sans-serif" font-size="11">LOGO</text></svg>`);
497
884
  const SAMPLE_DATA = {
498
885
  order_invoice: {
499
886
  company_name: "Mi Empresa",
@@ -501,7 +888,7 @@ const SAMPLE_DATA = {
501
888
  company_address: "Av. Principal 123, Quito",
502
889
  company_phone: "+593 99 123 4567",
503
890
  company_email: "info@miempresa.com",
504
- company_logo_base64: "",
891
+ company_logo_base64: PLACEHOLDER_LOGO_BASE64,
505
892
  invoice_id: "INV-000001",
506
893
  invoice_date: "19/06/2025",
507
894
  order_display_id: "000042",
@@ -523,6 +910,11 @@ const SAMPLE_DATA = {
523
910
  },
524
911
  quote_proforma: {
525
912
  company_name: "Mi Empresa",
913
+ company_ruc: "1234567890001",
914
+ company_address: "Av. Principal 123, Quito",
915
+ company_phone: "+593 99 123 4567",
916
+ company_email: "info@miempresa.com",
917
+ company_logo_base64: PLACEHOLDER_LOGO_BASE64,
526
918
  company_website: "www.miempresa.com",
527
919
  quote_number: "QP-2025-0001",
528
920
  date_str: "19/06/2025",
@@ -566,14 +958,22 @@ const TemplateEditorPage = () => {
566
958
  queryKey: ["invoice-template", id],
567
959
  enabled: !!id
568
960
  });
961
+ const { data: companiesData } = reactQuery.useQuery({
962
+ queryFn: () => sdk.client.fetch("/admin/invoice-config"),
963
+ queryKey: ["invoice-configs"]
964
+ });
569
965
  const template = data == null ? void 0 : data.invoice_template;
966
+ const companies = (companiesData == null ? void 0 : companiesData.invoice_configs) ?? [];
570
967
  const [name, setName] = react.useState("");
571
968
  const [htmlContent, setHtmlContent] = react.useState("");
969
+ const [companyId, setCompanyId] = react.useState(null);
572
970
  const [showVariables, setShowVariables] = react.useState(false);
971
+ const [collapsedSections, setCollapsedSections] = react.useState({});
573
972
  react.useEffect(() => {
574
973
  if (template) {
575
974
  setName(template.name);
576
975
  setHtmlContent(template.html_content);
976
+ setCompanyId(template.company_id);
577
977
  }
578
978
  }, [template]);
579
979
  const saveMutation = reactQuery.useMutation({
@@ -590,7 +990,7 @@ const TemplateEditorPage = () => {
590
990
  }
591
991
  });
592
992
  const handleSave = () => {
593
- saveMutation.mutate({ name, html_content: htmlContent });
993
+ saveMutation.mutate({ name, html_content: htmlContent, company_id: companyId });
594
994
  };
595
995
  const handlePreviewPdf = async () => {
596
996
  try {
@@ -611,7 +1011,7 @@ const TemplateEditorPage = () => {
611
1011
  if (!(template == null ? void 0 : template.is_default)) return;
612
1012
  if (!confirm("¿Restaurar la plantilla a su contenido original?")) return;
613
1013
  try {
614
- const res = await sdk.client.fetch(
1014
+ await sdk.client.fetch(
615
1015
  `/admin/invoice-templates/${id}/restore`,
616
1016
  { method: "POST" }
617
1017
  );
@@ -630,77 +1030,102 @@ const TemplateEditorPage = () => {
630
1030
  return `<div style="color:red;padding:20px;">Error en la plantilla Handlebars</div>`;
631
1031
  }
632
1032
  }, [htmlContent, template]);
633
- const insertVariable = react.useCallback((variable) => {
634
- const isBlock = variable.startsWith("{{#") || variable.startsWith("{{/");
1033
+ const insertVariable = react.useCallback((variable, isBlock) => {
635
1034
  const insertion = isBlock ? variable : `{{${variable}}}`;
636
1035
  setHtmlContent((prev) => prev + insertion);
637
1036
  }, []);
638
- const availableVars = template ? VARIABLES[template.type] ?? [] : [];
1037
+ const toggleSection = react.useCallback((label) => {
1038
+ setCollapsedSections((prev) => ({ ...prev, [label]: !prev[label] }));
1039
+ }, []);
1040
+ const categories = template ? CATEGORIES[template.type] ?? [] : [];
639
1041
  if (isLoading) {
640
- return /* @__PURE__ */ jsxRuntime.jsx(ui.Container, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { textAlign: "center", padding: 40 }, children: "Cargando..." }) });
1042
+ return /* @__PURE__ */ jsxRuntime.jsx(ui.Container, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center py-10", children: "Cargando..." }) });
641
1043
  }
642
1044
  if (!template) {
643
- return /* @__PURE__ */ jsxRuntime.jsx(ui.Container, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { textAlign: "center", padding: 40 }, children: "Plantilla no encontrada" }) });
1045
+ return /* @__PURE__ */ jsxRuntime.jsx(ui.Container, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center py-10", children: "Plantilla no encontrada" }) });
644
1046
  }
645
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { children: [
646
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 16 }, children: [
647
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: 12 }, children: [
1047
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "p-0", children: [
1048
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4 py-3 border-b border-ui-border-base", children: [
1049
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
648
1050
  /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "secondary", size: "small", onClick: () => navigate("/invoice-config/invoice-templates"), children: "← Volver" }),
649
- /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(
1051
+ /* @__PURE__ */ jsxRuntime.jsx(
650
1052
  ui.Input,
651
1053
  {
652
1054
  value: name,
653
1055
  onChange: (e) => setName(e.target.value),
654
- style: { fontWeight: "bold", fontSize: 16 }
1056
+ className: "font-semibold text-base w-64"
655
1057
  }
656
- ) }),
657
- /* @__PURE__ */ jsxRuntime.jsxs("code", { style: { fontSize: 12, color: "#6c757d" }, children: [
1058
+ ),
1059
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { className: "text-ui-fg-muted text-xs", children: [
658
1060
  template.slug,
659
1061
  " (",
660
1062
  template.type,
661
1063
  ")"
662
1064
  ] })
663
1065
  ] }),
664
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: 8 }, children: [
665
- template.is_default && /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "secondary", size: "small", onClick: handleRestoreDefault, children: "Restaurar Default" }),
1066
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
1067
+ /* @__PURE__ */ jsxRuntime.jsxs(
1068
+ ui.Select,
1069
+ {
1070
+ value: companyId ?? "__none__",
1071
+ onValueChange: (v) => setCompanyId(v === "__none__" ? null : v),
1072
+ children: [
1073
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Trigger, { className: "w-48", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Value, { placeholder: "Empresa" }) }),
1074
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Select.Content, { children: [
1075
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Item, { value: "__none__", children: "Sin empresa (usa default)" }),
1076
+ companies.map((c) => /* @__PURE__ */ jsxRuntime.jsxs(ui.Select.Item, { value: c.id, children: [
1077
+ c.company_name,
1078
+ c.is_default ? " ★" : ""
1079
+ ] }, c.id))
1080
+ ] })
1081
+ ]
1082
+ }
1083
+ ),
1084
+ template.is_default && /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "secondary", size: "small", onClick: handleRestoreDefault, children: "Restaurar" }),
666
1085
  /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "secondary", size: "small", onClick: () => setShowVariables(!showVariables), children: showVariables ? "Ocultar Variables" : "Variables" }),
667
1086
  /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "secondary", size: "small", onClick: handlePreviewPdf, children: "Preview PDF" }),
668
1087
  /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { onClick: handleSave, isLoading: saveMutation.isPending, children: "Guardar" })
669
1088
  ] })
670
1089
  ] }),
671
- showVariables && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
672
- background: "#f8f9fa",
673
- border: "1px solid #e2e8f0",
674
- borderRadius: 8,
675
- padding: 12,
676
- marginBottom: 16,
677
- display: "flex",
678
- flexWrap: "wrap",
679
- gap: 6
680
- }, children: [
681
- /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { style: { width: "100%", marginBottom: 4 }, children: "Variables Handlebars — click para insertar:" }),
682
- availableVars.map((v, i) => /* @__PURE__ */ jsxRuntime.jsx(
683
- "button",
684
- {
685
- onClick: () => insertVariable(v),
686
- style: {
687
- background: v.startsWith("{{") ? "#e2e8f0" : "#dbeafe",
688
- border: "1px solid #cbd5e0",
689
- borderRadius: 4,
690
- padding: "2px 8px",
691
- fontSize: 11,
692
- cursor: "pointer",
693
- fontFamily: "monospace"
1090
+ showVariables && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-b border-ui-border-base bg-ui-bg-subtle px-4 py-3", children: [
1091
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { className: "block mb-2 text-sm", children: "Variables Handlebars — click para insertar" }),
1092
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-2", children: categories.map((cat) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border border-ui-border-base rounded-lg bg-ui-bg-base overflow-hidden", children: [
1093
+ /* @__PURE__ */ jsxRuntime.jsxs(
1094
+ "button",
1095
+ {
1096
+ type: "button",
1097
+ className: "w-full flex items-center justify-between px-3 py-2 text-left text-sm font-medium hover:bg-ui-bg-subtle-hover transition-colors",
1098
+ onClick: () => toggleSection(cat.label),
1099
+ children: [
1100
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
1101
+ cat.icon,
1102
+ " ",
1103
+ cat.label
1104
+ ] }),
1105
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-ui-fg-muted text-xs", children: [
1106
+ collapsedSections[cat.label] ? "" : "",
1107
+ " ",
1108
+ cat.variables.length
1109
+ ] })
1110
+ ]
1111
+ }
1112
+ ),
1113
+ !collapsedSections[cat.label] && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 pb-2 flex flex-wrap gap-1.5", children: cat.variables.map((v, i) => /* @__PURE__ */ jsxRuntime.jsx(
1114
+ ui.Badge,
1115
+ {
1116
+ color: v.isBlock ? "orange" : "blue",
1117
+ className: "cursor-pointer hover:opacity-80 transition-opacity text-xs",
1118
+ onClick: () => insertVariable(v.name, v.isBlock),
1119
+ children: v.isBlock ? v.name : `{{${v.name}}}`
694
1120
  },
695
- children: v.startsWith("{{") ? v : `{{${v}}}`
696
- },
697
- i
698
- ))
1121
+ `${cat.label}-${i}`
1122
+ )) })
1123
+ ] }, cat.label)) })
699
1124
  ] }),
700
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: 16, height: "calc(100vh - 260px)" }, children: [
1125
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: 16, height: "calc(100vh - 260px)", padding: 16 }, children: [
701
1126
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { flex: 1, display: "flex", flexDirection: "column", minWidth: 0 }, children: [
702
- /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { style: { marginBottom: 8 }, children: "Editor HTML + Handlebars" }),
703
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { flex: 1, border: "1px solid #e2e8f0", borderRadius: 8, overflow: "hidden" }, children: /* @__PURE__ */ jsxRuntime.jsx(
1127
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { className: "mb-2", children: "Editor HTML + Handlebars" }),
1128
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 border border-ui-border-base rounded-lg overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
704
1129
  CodeMirror__default.default,
705
1130
  {
706
1131
  ref: editorRef,
@@ -714,14 +1139,8 @@ const TemplateEditorPage = () => {
714
1139
  ) })
715
1140
  ] }),
716
1141
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { flex: 1, display: "flex", flexDirection: "column", minWidth: 0 }, children: [
717
- /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { style: { marginBottom: 8 }, children: "Preview en vivo (datos de ejemplo)" }),
718
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
719
- flex: 1,
720
- border: "1px solid #e2e8f0",
721
- borderRadius: 8,
722
- overflow: "auto",
723
- background: "#fff"
724
- }, children: /* @__PURE__ */ jsxRuntime.jsx(
1142
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { className: "mb-2", children: "Preview en vivo (datos de ejemplo)" }),
1143
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 border border-ui-border-base rounded-lg overflow-auto bg-white", children: /* @__PURE__ */ jsxRuntime.jsx(
725
1144
  "iframe",
726
1145
  {
727
1146
  srcDoc: previewHtml,
@@ -747,10 +1166,22 @@ const routeModule = {
747
1166
  Component: InvoiceConfigPage,
748
1167
  path: "/invoice-config"
749
1168
  },
1169
+ {
1170
+ Component: CompaniesPage,
1171
+ path: "/invoice-config/companies"
1172
+ },
750
1173
  {
751
1174
  Component: InvoiceTemplatesPage,
752
1175
  path: "/invoice-config/invoice-templates"
753
1176
  },
1177
+ {
1178
+ Component: EditCompanyPage,
1179
+ path: "/invoice-config/companies/:id"
1180
+ },
1181
+ {
1182
+ Component: NewCompanyPage,
1183
+ path: "/invoice-config/companies/new"
1184
+ },
754
1185
  {
755
1186
  Component: NewTemplatePage,
756
1187
  path: "/invoice-config/invoice-templates/new"