medusajs-documents-plugin 0.0.0-stage → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/.medusa/server/src/admin/index.js +2427 -0
  2. package/.medusa/server/src/admin/index.mjs +2428 -0
  3. package/.medusa/server/src/api/admin/documents/[id]/document/route.js +36 -0
  4. package/.medusa/server/src/api/admin/documents/[id]/send/route.js +41 -0
  5. package/.medusa/server/src/api/admin/documents/[id]/sync-zoho/route.js +68 -0
  6. package/.medusa/server/src/api/admin/documents/custom/route.js +48 -0
  7. package/.medusa/server/src/api/admin/documents/manual/route.js +46 -0
  8. package/.medusa/server/src/api/admin/documents/route.js +36 -0
  9. package/.medusa/server/src/api/admin/documents/settings/route.js +44 -0
  10. package/.medusa/server/src/api/admin/documents/templates/preview/route.js +159 -0
  11. package/.medusa/server/src/api/admin/documents/zoho/list/route.js +51 -0
  12. package/.medusa/server/src/api/documents/[id]/document/route.js +36 -0
  13. package/.medusa/server/src/api/documents/r/[code]/route.js +29 -0
  14. package/.medusa/server/src/api/documents/templates/preview/route.js +159 -0
  15. package/.medusa/server/src/api/store/documents/r/[code]/route.js +22 -0
  16. package/.medusa/server/src/index.js +27 -0
  17. package/.medusa/server/src/modules/documents/index.js +13 -0
  18. package/.medusa/server/src/modules/documents/migrations/Migration20261012164601.js +23 -0
  19. package/.medusa/server/src/modules/documents/migrations/Migration20261014150000.js +20 -0
  20. package/.medusa/server/src/modules/documents/models/document-link.js +12 -0
  21. package/.medusa/server/src/modules/documents/models/document-record.js +33 -0
  22. package/.medusa/server/src/modules/documents/models/document-settings.js +61 -0
  23. package/.medusa/server/src/modules/documents/service.js +456 -0
  24. package/.medusa/server/src/services/notification-sender.js +293 -0
  25. package/.medusa/server/src/services/pdf-post-processor.js +64 -0
  26. package/.medusa/server/src/services/pdfkit-generator.js +438 -0
  27. package/.medusa/server/src/services/zoho-books.js +221 -0
  28. package/.medusa/server/src/subscribers/order-documents.js +178 -0
  29. package/.medusa/server/src/subscribers/repair-documents.js +162 -0
  30. package/.medusa/server/src/utils/integrate.js +37 -0
  31. package/.medusa/server/src/utils/payment-link.js +69 -0
  32. package/.medusa/server/src/workflows/create-manual-document.js +27 -0
  33. package/.medusa/server/src/workflows/generate-document.js +24 -0
  34. package/.medusa/server/src/workflows/index.js +20 -0
  35. package/.medusa/server/src/workflows/send-document-notification.js +41 -0
  36. package/CHANGELOG.md +87 -0
  37. package/LICENSE +21 -0
  38. package/README.md +201 -2
  39. package/package.json +86 -4
@@ -0,0 +1,2428 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import { defineRouteConfig } from "@medusajs/admin-sdk";
3
+ import { Container, Heading, Text, Button, Input, Select, Table, Badge, Label, Switch, Textarea, FocusModal } from "@medusajs/ui";
4
+ import { useState, useEffect } from "react";
5
+ import { DocumentText, Plus, Sparkles, ArrowPath, ArrowDownTray, Envelope, Trash } from "@medusajs/icons";
6
+ const CUSTOM_DOC_PRESETS = [
7
+ {
8
+ id: "warranty",
9
+ name: "Warranty Certificate",
10
+ icon: "🛡️",
11
+ badge: "90-Day Coverage",
12
+ title: "Warranty Certificate",
13
+ subject: "Your Official Warranty Certificate - Urban Device Care",
14
+ body_text: `This certificate verifies that your device has undergone professional repairs with genuine OEM-specification components and has passed our multi-point quality assurance inspection.
15
+
16
+ All hardware replacements and associated workshop labor are covered under our comprehensive 90-day warranty against defects in parts and workmanship. Please retain this document for warranty verification.`,
17
+ items: [
18
+ { title: "OEM Component & Hardware Warranty", description: "90-Day Coverage from Date of Collection", quantity: 1, unit_price: 0 },
19
+ { title: "Workshop Diagnostic & Quality Clearance", description: "Multi-Point Hardware & Bench Testing", quantity: 1, unit_price: 0 }
20
+ ]
21
+ },
22
+ {
23
+ id: "diagnostic",
24
+ name: "Diagnostic & Inspection Report",
25
+ icon: "🔍",
26
+ badge: "Hardware Findings",
27
+ title: "Diagnostic & Hardware Inspection Report",
28
+ subject: "Device Diagnostic & Inspection Findings",
29
+ body_text: `Our certified repair specialists have completed a hardware and firmware inspection of your equipment. Below are the confirmed technical findings, component test measurements, and technician notes regarding the state of your device.`,
30
+ items: [
31
+ { title: "Logic Board & Power Rail Inspection", description: "Voltage drop and circuit continuity tested", quantity: 1, unit_price: 0 },
32
+ { title: "Display & Touch Digitizer Diagnostic", description: "Digitizer touch grid, TrueTone, and Ambient Sensor test", quantity: 1, unit_price: 0 },
33
+ { title: "Battery Health & Thermal Profiling", description: "Cycle count, capacity retention, and charge testing", quantity: 1, unit_price: 0 }
34
+ ]
35
+ },
36
+ {
37
+ id: "service_completion",
38
+ name: "Service Completion Certificate",
39
+ icon: "📜",
40
+ badge: "QC Cleared",
41
+ title: "Certificate of Service Completion",
42
+ subject: "Service Completion & Quality Assurance Sign-off",
43
+ body_text: `This document certifies that the requested overhaul, maintenance, and repair services have been executed in full accordance with industry service standards. The device has cleared bench testing and is ready for customer collection.`,
44
+ items: [
45
+ { title: "Hardware Servicing & Component Replacement", description: "Executed per work order specifications", quantity: 1, unit_price: 0 },
46
+ { title: "Final Bench Testing & Quality Control", description: "Passed 100% functional test criteria", quantity: 1, unit_price: 0 }
47
+ ]
48
+ },
49
+ {
50
+ id: "handover",
51
+ name: "Equipment Handover & Release",
52
+ icon: "🤝",
53
+ badge: "Custody Form",
54
+ title: "Equipment Handover & Custody Release Agreement",
55
+ subject: "Equipment Handover & Custody Release Form",
56
+ body_text: `This handover document certifies the return and physical custody release of customer equipment and associated accessories from Urban Device Care. The customer acknowledges receipt of equipment in verified working order.`,
57
+ items: [
58
+ { title: "Device Handover & Physical Release", description: "Customer custody confirmed", quantity: 1, unit_price: 0 },
59
+ { title: "Accessories Handover", description: "Chargers, cases, and cables returned in verified condition", quantity: 1, unit_price: 0 }
60
+ ]
61
+ },
62
+ {
63
+ id: "proforma",
64
+ name: "Commercial Quotation / Proforma",
65
+ icon: "💼",
66
+ badge: "Cost Estimate",
67
+ title: "Commercial Quotation (Proforma)",
68
+ subject: "Commercial Quotation & Scope of Work",
69
+ body_text: `Thank you for choosing Urban Device Care. Below is an itemized breakdown of estimated hardware parts, workshop labor, and turnaround schedule for your project. This quote is valid for 14 calendar days.`,
70
+ items: [
71
+ { title: "OEM Replacement Hardware Assembly", description: "Brand new replacement module", quantity: 1, unit_price: 150 },
72
+ { title: "Workshop Labor & Clean-Room Installation", description: "Certified technician installation & calibration", quantity: 1, unit_price: 45 }
73
+ ]
74
+ },
75
+ {
76
+ id: "blank",
77
+ name: "Blank Custom Document",
78
+ icon: "📝",
79
+ badge: "Custom",
80
+ title: "Official Document",
81
+ subject: "Official Document from Urban Device Care",
82
+ body_text: "",
83
+ items: [
84
+ { title: "", description: "", quantity: 1, unit_price: 0 }
85
+ ]
86
+ }
87
+ ];
88
+ const DocumentsPage = () => {
89
+ const [activeTab, setActiveTab] = useState("hub");
90
+ const [documents, setDocuments] = useState([]);
91
+ const [loading, setLoading] = useState(true);
92
+ const [searchTerm, setSearchTerm] = useState("");
93
+ const [typeFilter, setTypeFilter] = useState("all");
94
+ const [sourceFilter, setSourceFilter] = useState("all");
95
+ const [zohoLiveDocs, setZohoLiveDocs] = useState([]);
96
+ const [loadingZoho, setLoadingZoho] = useState(false);
97
+ const [manualModalOpen, setManualModalOpen] = useState(false);
98
+ const [customDocModalOpen, setCustomDocModalOpen] = useState(false);
99
+ const [sendModalOpen, setSendModalOpen] = useState(false);
100
+ const [selectedDoc, setSelectedDoc] = useState(null);
101
+ const [settings, setSettings] = useState({
102
+ company_name: "Store",
103
+ storefront_url: "",
104
+ email_notifications_enabled: true,
105
+ sms_notifications_enabled: true,
106
+ whatsapp_notifications_enabled: true,
107
+ // Automation event subscriber toggles
108
+ event_order_placed_enabled: true,
109
+ event_order_completed_enabled: true,
110
+ event_payment_captured_enabled: true,
111
+ event_order_fulfillment_enabled: true,
112
+ event_repair_status_changed_enabled: true,
113
+ event_repair_compliance_enabled: true,
114
+ event_repair_created_enabled: true,
115
+ event_repair_completed_enabled: true,
116
+ event_repair_reminder_enabled: true,
117
+ // Zoho Books
118
+ zoho_books_enabled: false,
119
+ zoho_domain: "com",
120
+ zoho_organization_id: "",
121
+ zoho_client_id: "",
122
+ zoho_client_secret: "",
123
+ zoho_refresh_token: "",
124
+ zoho_invoice_notes: "Thank you for your business.",
125
+ zoho_invoice_terms: "",
126
+ zoho_estimate_terms: "",
127
+ zoho_payment_terms_days: 0,
128
+ zoho_tax_inclusive: false,
129
+ zoho_invoice_prefix: "INV-",
130
+ // PDF Branding
131
+ pdf_logo_url: "",
132
+ pdf_address: "",
133
+ pdf_phone: "",
134
+ pdf_email: "",
135
+ pdf_website: "",
136
+ pdf_payment_details: "",
137
+ pdf_terms: "",
138
+ // Template Choices
139
+ invoice_template: "modern",
140
+ packing_slip_template: "modern",
141
+ receipt_template: "modern",
142
+ estimate_template: "modern",
143
+ job_card_template: "modern",
144
+ custom_doc_template: "modern",
145
+ // Customizable Notification Templates
146
+ email_subject_template: "",
147
+ email_body_template: "",
148
+ sms_body_template: "",
149
+ whatsapp_body_template: ""
150
+ });
151
+ const [isSaving, setIsSaving] = useState(false);
152
+ const [saveSuccessMsg, setSaveSuccessMsg] = useState(null);
153
+ const [previewLoading, setPreviewLoading] = useState(null);
154
+ const [previewModalOpen, setPreviewModalOpen] = useState(false);
155
+ const [previewStyle, setPreviewStyle] = useState("modern");
156
+ const [previewType, setPreviewType] = useState("invoice");
157
+ const [previewBlobUrl, setPreviewBlobUrl] = useState(null);
158
+ const [isPreviewModalLoading, setIsPreviewModalLoading] = useState(false);
159
+ const [isGeneratingManual, setIsGeneratingManual] = useState(false);
160
+ const [isGeneratingCustom, setIsGeneratingCustom] = useState(false);
161
+ const [manualForm, setManualForm] = useState({
162
+ title: "Tax Invoice",
163
+ type: "invoice",
164
+ customer_name: "",
165
+ customer_email: "",
166
+ customer_phone: "",
167
+ customer_address: "",
168
+ items: [{ title: "", description: "", quantity: 1, unit_price: 0 }],
169
+ currency_code: "usd",
170
+ notes: "",
171
+ force_source: "auto",
172
+ auto_send: false
173
+ });
174
+ const [customDocForm, setCustomDocForm] = useState({
175
+ preset_id: "warranty",
176
+ title: "Warranty Certificate",
177
+ customer_name: "",
178
+ customer_email: "",
179
+ customer_phone: "",
180
+ body_text: "This certificate verifies that your device has undergone professional repairs with genuine OEM-specification components and has passed our multi-point quality assurance inspection.\n\nAll hardware replacements and associated workshop labor are covered under our comprehensive 90-day warranty against defects in parts and workmanship. Please retain this document for warranty verification.",
181
+ items: [
182
+ { title: "OEM Component & Hardware Warranty", description: "90-Day Coverage from Date of Collection", quantity: 1, unit_price: 0 },
183
+ { title: "Workshop Diagnostic & Quality Clearance", description: "Multi-Point Hardware & Bench Testing", quantity: 1, unit_price: 0 }
184
+ ],
185
+ currency_code: "usd",
186
+ send_email_now: true,
187
+ email_subject: "Your Official Warranty Certificate - Urban Device Care"
188
+ });
189
+ const selectCustomDocPreset = (presetId) => {
190
+ const preset = CUSTOM_DOC_PRESETS.find((p) => p.id === presetId);
191
+ if (!preset) return;
192
+ setCustomDocForm((prev) => ({
193
+ ...prev,
194
+ preset_id: preset.id,
195
+ title: preset.title,
196
+ email_subject: preset.subject,
197
+ body_text: preset.body_text,
198
+ items: preset.items.map((it) => ({ ...it }))
199
+ }));
200
+ };
201
+ const [sendForm, setSendForm] = useState({
202
+ channels: ["email"],
203
+ custom_message: "",
204
+ subject: ""
205
+ });
206
+ const loadDocuments = () => {
207
+ setLoading(true);
208
+ fetch("/admin/documents", { credentials: "include" }).then((res) => res.json()).then((data) => {
209
+ setDocuments(data.documents || []);
210
+ }).catch((err) => console.error("Error loading documents:", err)).finally(() => setLoading(false));
211
+ };
212
+ const loadSettings = () => {
213
+ fetch("/admin/documents/settings", { credentials: "include" }).then((res) => res.json()).then((data) => {
214
+ if (data.settings) {
215
+ setSettings((prev) => ({ ...prev, ...data.settings }));
216
+ }
217
+ }).catch((err) => console.error("Error loading settings:", err));
218
+ };
219
+ const loadZohoLiveDocs = () => {
220
+ setLoadingZoho(true);
221
+ fetch("/admin/documents/zoho/list", { credentials: "include" }).then((res) => res.json()).then((data) => {
222
+ if (data.items) {
223
+ setZohoLiveDocs(data.items);
224
+ }
225
+ }).catch((err) => console.error("Error loading Zoho live docs:", err)).finally(() => setLoadingZoho(false));
226
+ };
227
+ useEffect(() => {
228
+ loadDocuments();
229
+ loadSettings();
230
+ }, []);
231
+ const saveSettings = async () => {
232
+ setIsSaving(true);
233
+ setSaveSuccessMsg(null);
234
+ try {
235
+ const res = await fetch("/admin/documents/settings", {
236
+ method: "POST",
237
+ credentials: "include",
238
+ headers: { "Content-Type": "application/json" },
239
+ body: JSON.stringify(settings)
240
+ });
241
+ const data = await res.json().catch(() => ({}));
242
+ if (res.ok && data.success) {
243
+ setSaveSuccessMsg("Preferences saved successfully!");
244
+ setTimeout(() => setSaveSuccessMsg(null), 4e3);
245
+ alert("Settings saved successfully!");
246
+ } else {
247
+ alert(`Failed to save settings: ${data.message || res.statusText || "Unknown error"}`);
248
+ }
249
+ } catch (e) {
250
+ console.error(e);
251
+ alert(`Error saving settings: ${e.message}`);
252
+ } finally {
253
+ setIsSaving(false);
254
+ }
255
+ };
256
+ const updateSettingField = (key, val) => {
257
+ setSettings((prev) => ({ ...prev, [key]: val }));
258
+ };
259
+ const handleCreateManual = async () => {
260
+ var _a;
261
+ if (!((_a = manualForm.customer_name) == null ? void 0 : _a.trim())) {
262
+ alert("Please provide a Customer Name.");
263
+ return;
264
+ }
265
+ const validItems = manualForm.items.filter((it) => it.title.trim() !== "");
266
+ if (validItems.length === 0) {
267
+ alert("Please add at least one line item with a title.");
268
+ return;
269
+ }
270
+ setIsGeneratingManual(true);
271
+ try {
272
+ const res = await fetch("/admin/documents/manual", {
273
+ method: "POST",
274
+ credentials: "include",
275
+ headers: { "Content-Type": "application/json" },
276
+ body: JSON.stringify({
277
+ title: manualForm.title,
278
+ type: manualForm.type,
279
+ customer: {
280
+ name: manualForm.customer_name,
281
+ email: manualForm.customer_email,
282
+ phone: manualForm.customer_phone,
283
+ address: manualForm.customer_address
284
+ },
285
+ items: validItems,
286
+ currency_code: manualForm.currency_code,
287
+ notes: manualForm.notes,
288
+ force_source: manualForm.force_source === "auto" ? void 0 : manualForm.force_source,
289
+ auto_send: manualForm.auto_send
290
+ })
291
+ });
292
+ const data = await res.json().catch(() => ({}));
293
+ if (res.ok && data.success) {
294
+ alert("Document created successfully!");
295
+ setManualModalOpen(false);
296
+ setManualForm({
297
+ title: "Tax Invoice",
298
+ type: "invoice",
299
+ customer_name: "",
300
+ customer_email: "",
301
+ customer_phone: "",
302
+ customer_address: "",
303
+ items: [{ title: "", description: "", quantity: 1, unit_price: 0 }],
304
+ currency_code: "usd",
305
+ notes: "",
306
+ force_source: "auto",
307
+ auto_send: false
308
+ });
309
+ loadDocuments();
310
+ } else {
311
+ alert(`Failed to create document: ${data.message || res.statusText}`);
312
+ }
313
+ } catch (e) {
314
+ alert(`Error creating document: ${e.message}`);
315
+ } finally {
316
+ setIsGeneratingManual(false);
317
+ }
318
+ };
319
+ const handleCreateCustomDoc = async () => {
320
+ var _a, _b;
321
+ if (!((_a = customDocForm.title) == null ? void 0 : _a.trim())) {
322
+ alert("Please provide a Document Title.");
323
+ return;
324
+ }
325
+ if (!((_b = customDocForm.customer_name) == null ? void 0 : _b.trim())) {
326
+ alert("Please provide a Customer / Recipient Name.");
327
+ return;
328
+ }
329
+ setIsGeneratingCustom(true);
330
+ try {
331
+ const res = await fetch("/admin/documents/custom", {
332
+ method: "POST",
333
+ credentials: "include",
334
+ headers: { "Content-Type": "application/json" },
335
+ body: JSON.stringify({
336
+ title: customDocForm.title,
337
+ customer: {
338
+ name: customDocForm.customer_name,
339
+ email: customDocForm.customer_email,
340
+ phone: customDocForm.customer_phone
341
+ },
342
+ body_text: customDocForm.body_text,
343
+ items: customDocForm.items.filter((it) => it.title.trim() !== ""),
344
+ currency_code: customDocForm.currency_code,
345
+ send_email_now: customDocForm.send_email_now,
346
+ email_subject: customDocForm.email_subject,
347
+ custom_email_message: customDocForm.body_text
348
+ })
349
+ });
350
+ const data = await res.json().catch(() => ({}));
351
+ if (res.ok && data.success) {
352
+ alert(
353
+ customDocForm.send_email_now ? "Custom document generated & emailed successfully!" : "Custom document generated and saved to Documents Hub!"
354
+ );
355
+ setCustomDocModalOpen(false);
356
+ loadDocuments();
357
+ } else {
358
+ alert(`Failed to generate custom document: ${data.message || res.statusText}`);
359
+ }
360
+ } catch (e) {
361
+ alert(`Error generating custom document: ${e.message}`);
362
+ } finally {
363
+ setIsGeneratingCustom(false);
364
+ }
365
+ };
366
+ const loadPreviewBlob = async (style, type) => {
367
+ setIsPreviewModalLoading(true);
368
+ try {
369
+ const res = await fetch(`/admin/documents/templates/preview?style=${style}&type=${type}`, {
370
+ credentials: "include"
371
+ });
372
+ if (!res.ok) {
373
+ const errText = await res.text();
374
+ alert(`Preview failed: ${errText || res.statusText}`);
375
+ return;
376
+ }
377
+ const blob = await res.blob();
378
+ const blobUrl = URL.createObjectURL(blob);
379
+ setPreviewBlobUrl((old) => {
380
+ if (old) URL.revokeObjectURL(old);
381
+ return blobUrl;
382
+ });
383
+ } catch (e) {
384
+ alert(`Error previewing template: ${e.message}`);
385
+ } finally {
386
+ setIsPreviewModalLoading(false);
387
+ setPreviewLoading(null);
388
+ }
389
+ };
390
+ const handlePreviewTemplate = async (style, type) => {
391
+ const key = `${style}-${type}`;
392
+ setPreviewLoading(key);
393
+ setPreviewStyle(style);
394
+ setPreviewType(type);
395
+ setPreviewModalOpen(true);
396
+ await loadPreviewBlob(style, type);
397
+ };
398
+ const switchPreview = async (style, type) => {
399
+ setPreviewStyle(style);
400
+ setPreviewType(type);
401
+ await loadPreviewBlob(style, type);
402
+ };
403
+ const handleOpenPreviewNewTab = () => {
404
+ window.open(`/admin/documents/templates/preview?style=${previewStyle}&type=${previewType}`, "_blank");
405
+ };
406
+ const handleDownloadPreview = () => {
407
+ if (!previewBlobUrl) return;
408
+ const a = document.createElement("a");
409
+ a.href = previewBlobUrl;
410
+ a.download = `preview-${previewStyle}-${previewType}.pdf`;
411
+ document.body.appendChild(a);
412
+ a.click();
413
+ document.body.removeChild(a);
414
+ };
415
+ const handleViewDocument = (id, displayId) => {
416
+ window.open(`/admin/documents/${id}/document`, "_blank");
417
+ };
418
+ const handleSendNotification = async () => {
419
+ if (!selectedDoc) return;
420
+ try {
421
+ const res = await fetch(`/admin/documents/${selectedDoc.id}/send`, {
422
+ method: "POST",
423
+ credentials: "include",
424
+ headers: { "Content-Type": "application/json" },
425
+ body: JSON.stringify({
426
+ channels: sendForm.channels,
427
+ custom_message: sendForm.custom_message,
428
+ subject: sendForm.subject || void 0
429
+ })
430
+ });
431
+ if (res.ok) {
432
+ alert("Notification dispatched successfully!");
433
+ setSendModalOpen(false);
434
+ } else {
435
+ alert("Failed to dispatch notification.");
436
+ }
437
+ } catch (e) {
438
+ alert("Error sending notification.");
439
+ }
440
+ };
441
+ const handleSyncToZoho = async (docId) => {
442
+ try {
443
+ const res = await fetch(`/admin/documents/${docId}/sync-zoho`, {
444
+ method: "POST",
445
+ credentials: "include"
446
+ });
447
+ const data = await res.json();
448
+ if (res.ok && data.success) {
449
+ alert(`Successfully synced to Zoho Books! (Zoho ID: ${data.zoho_document_id})`);
450
+ loadDocuments();
451
+ } else {
452
+ alert(`Zoho Sync Failed: ${data.message || "Unknown error"}`);
453
+ }
454
+ } catch (e) {
455
+ alert("Error syncing to Zoho Books.");
456
+ }
457
+ };
458
+ const filteredDocs = documents.filter((doc) => {
459
+ var _a, _b, _c, _d;
460
+ if (typeFilter !== "all" && doc.type !== typeFilter) return false;
461
+ if (sourceFilter !== "all" && doc.source !== sourceFilter) return false;
462
+ if (searchTerm) {
463
+ const q = searchTerm.toLowerCase();
464
+ return ((_a = doc.display_id) == null ? void 0 : _a.toLowerCase().includes(q)) || ((_b = doc.customer_name) == null ? void 0 : _b.toLowerCase().includes(q)) || ((_c = doc.customer_email) == null ? void 0 : _c.toLowerCase().includes(q)) || ((_d = doc.title) == null ? void 0 : _d.toLowerCase().includes(q));
465
+ }
466
+ return true;
467
+ });
468
+ return /* @__PURE__ */ jsxs(Container, { className: "p-0", children: [
469
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col md:flex-row md:items-center justify-between p-6 border-b border-ui-border-base gap-4 bg-ui-bg-base", children: [
470
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
471
+ /* @__PURE__ */ jsx("div", { className: "p-2.5 bg-ui-bg-subtle rounded-lg border border-ui-border-base", children: /* @__PURE__ */ jsx(DocumentText, { className: "text-ui-fg-interactive w-5 h-5" }) }),
472
+ /* @__PURE__ */ jsxs("div", { children: [
473
+ /* @__PURE__ */ jsx(Heading, { level: "h1", className: "text-xl font-semibold", children: "Documents Hub" }),
474
+ /* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-subtle", children: "Unified document generation with Zoho Books, PDFKit templates & multi-channel dispatch" })
475
+ ] })
476
+ ] }),
477
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
478
+ /* @__PURE__ */ jsxs(Button, { variant: "secondary", size: "small", onClick: () => setManualModalOpen(true), children: [
479
+ /* @__PURE__ */ jsx(Plus, { className: "w-4 h-4 mr-1" }),
480
+ " Create Invoice"
481
+ ] }),
482
+ /* @__PURE__ */ jsxs(Button, { variant: "secondary", size: "small", onClick: () => setCustomDocModalOpen(true), children: [
483
+ /* @__PURE__ */ jsx(Sparkles, { className: "w-4 h-4 mr-1" }),
484
+ " Custom Document"
485
+ ] }),
486
+ /* @__PURE__ */ jsx(Button, { variant: "transparent", size: "small", onClick: loadDocuments, children: /* @__PURE__ */ jsx(ArrowPath, { className: "w-4 h-4" }) })
487
+ ] })
488
+ ] }),
489
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-6 px-6 border-b border-ui-border-base bg-ui-bg-subtle text-sm", children: [
490
+ /* @__PURE__ */ jsxs(
491
+ "button",
492
+ {
493
+ onClick: () => setActiveTab("hub"),
494
+ className: `py-3 font-medium border-b-2 transition-colors ${activeTab === "hub" ? "border-ui-border-interactive text-ui-fg-base" : "border-transparent text-ui-fg-muted hover:text-ui-fg-subtle"}`,
495
+ children: [
496
+ "All Documents (",
497
+ documents.length,
498
+ ")"
499
+ ]
500
+ }
501
+ ),
502
+ /* @__PURE__ */ jsx(
503
+ "button",
504
+ {
505
+ onClick: () => setActiveTab("templates"),
506
+ className: `py-3 font-medium border-b-2 transition-colors ${activeTab === "templates" ? "border-ui-border-interactive text-ui-fg-base" : "border-transparent text-ui-fg-muted hover:text-ui-fg-subtle"}`,
507
+ children: "PDF Templates"
508
+ }
509
+ ),
510
+ /* @__PURE__ */ jsx(
511
+ "button",
512
+ {
513
+ onClick: () => setActiveTab("automations"),
514
+ className: `py-3 font-medium border-b-2 transition-colors ${activeTab === "automations" ? "border-ui-border-interactive text-ui-fg-base" : "border-transparent text-ui-fg-muted hover:text-ui-fg-subtle"}`,
515
+ children: "Automations / Events"
516
+ }
517
+ ),
518
+ /* @__PURE__ */ jsx(
519
+ "button",
520
+ {
521
+ onClick: () => setActiveTab("settings"),
522
+ className: `py-3 font-medium border-b-2 transition-colors ${activeTab === "settings" ? "border-ui-border-interactive text-ui-fg-base" : "border-transparent text-ui-fg-muted hover:text-ui-fg-subtle"}`,
523
+ children: "Settings & Zoho"
524
+ }
525
+ )
526
+ ] }),
527
+ activeTab === "hub" && /* @__PURE__ */ jsxs("div", { className: "p-6 flex flex-col gap-4", children: [
528
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [
529
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2 flex-1 max-w-sm", children: /* @__PURE__ */ jsx(
530
+ Input,
531
+ {
532
+ placeholder: "Search reference, customer, or title...",
533
+ value: searchTerm,
534
+ onChange: (e) => setSearchTerm(e.target.value),
535
+ size: "small"
536
+ }
537
+ ) }),
538
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
539
+ /* @__PURE__ */ jsxs(Select, { value: typeFilter, onValueChange: (v) => setTypeFilter(v), children: [
540
+ /* @__PURE__ */ jsx(Select.Trigger, { size: "small", children: /* @__PURE__ */ jsx(Select.Value, { placeholder: "Document Type" }) }),
541
+ /* @__PURE__ */ jsxs(Select.Content, { children: [
542
+ /* @__PURE__ */ jsx(Select.Item, { value: "all", children: "All Types" }),
543
+ /* @__PURE__ */ jsx(Select.Item, { value: "invoice", children: "Invoices" }),
544
+ /* @__PURE__ */ jsx(Select.Item, { value: "receipt", children: "Receipts" }),
545
+ /* @__PURE__ */ jsx(Select.Item, { value: "estimate", children: "Estimates / Quotes" }),
546
+ /* @__PURE__ */ jsx(Select.Item, { value: "job_card", children: "Job Cards" }),
547
+ /* @__PURE__ */ jsx(Select.Item, { value: "packing_slip", children: "Packing Slips" }),
548
+ /* @__PURE__ */ jsx(Select.Item, { value: "custom", children: "Custom Documents" })
549
+ ] })
550
+ ] }),
551
+ /* @__PURE__ */ jsxs(Select, { value: sourceFilter, onValueChange: (v) => setSourceFilter(v), children: [
552
+ /* @__PURE__ */ jsx(Select.Trigger, { size: "small", children: /* @__PURE__ */ jsx(Select.Value, { placeholder: "Source" }) }),
553
+ /* @__PURE__ */ jsxs(Select.Content, { children: [
554
+ /* @__PURE__ */ jsx(Select.Item, { value: "all", children: "All Sources" }),
555
+ /* @__PURE__ */ jsx(Select.Item, { value: "zoho", children: "Zoho Books" }),
556
+ /* @__PURE__ */ jsx(Select.Item, { value: "pdfkit", children: "PDFKit Local" })
557
+ ] })
558
+ ] }),
559
+ settings.zoho_books_enabled && /* @__PURE__ */ jsxs(
560
+ Button,
561
+ {
562
+ variant: "secondary",
563
+ size: "small",
564
+ onClick: loadZohoLiveDocs,
565
+ isLoading: loadingZoho,
566
+ children: [
567
+ /* @__PURE__ */ jsx(ArrowPath, { className: "w-3.5 h-3.5 mr-1" }),
568
+ " View Live Zoho List"
569
+ ]
570
+ }
571
+ )
572
+ ] })
573
+ ] }),
574
+ loading ? /* @__PURE__ */ jsx("div", { className: "py-12 text-center text-ui-fg-muted text-sm", children: "Loading documents..." }) : filteredDocs.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "py-12 text-center text-ui-fg-muted border border-dashed border-ui-border-base rounded-lg", children: [
575
+ /* @__PURE__ */ jsx(Text, { className: "text-sm", children: "No documents found." }),
576
+ /* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-subtle mt-1", children: "Create a manual invoice or process an order to generate your first document." })
577
+ ] }) : /* @__PURE__ */ jsxs(Table, { children: [
578
+ /* @__PURE__ */ jsx(Table.Header, { children: /* @__PURE__ */ jsxs(Table.Row, { children: [
579
+ /* @__PURE__ */ jsx(Table.HeaderCell, { children: "Reference" }),
580
+ /* @__PURE__ */ jsx(Table.HeaderCell, { children: "Type" }),
581
+ /* @__PURE__ */ jsx(Table.HeaderCell, { children: "Recipient" }),
582
+ /* @__PURE__ */ jsx(Table.HeaderCell, { children: "Amount" }),
583
+ /* @__PURE__ */ jsx(Table.HeaderCell, { children: "Status" }),
584
+ /* @__PURE__ */ jsx(Table.HeaderCell, { children: "Source" }),
585
+ /* @__PURE__ */ jsx(Table.HeaderCell, { children: "Date" }),
586
+ /* @__PURE__ */ jsx(Table.HeaderCell, { className: "text-right", children: "Actions" })
587
+ ] }) }),
588
+ /* @__PURE__ */ jsx(Table.Body, { children: filteredDocs.map((doc) => {
589
+ const isPaid = doc.payment_status === "paid" || doc.status === "paid";
590
+ const isZoho = doc.source === "zoho";
591
+ return /* @__PURE__ */ jsxs(Table.Row, { className: "hover:bg-ui-bg-subtle-hover transition-colors", children: [
592
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(
593
+ "button",
594
+ {
595
+ type: "button",
596
+ onClick: () => handleViewDocument(doc.id, doc.display_id),
597
+ className: "font-medium text-ui-fg-interactive hover:underline text-left cursor-pointer bg-transparent border-0 p-0",
598
+ children: doc.display_id
599
+ }
600
+ ) }),
601
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-ui-fg-base", children: doc.title }) }),
602
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
603
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium", children: doc.customer_name || "Guest" }),
604
+ /* @__PURE__ */ jsx("span", { className: "text-[11px] text-ui-fg-subtle", children: doc.customer_email || doc.customer_phone || "-" })
605
+ ] }) }),
606
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx("span", { className: "text-xs font-semibold", children: new Intl.NumberFormat("en-US", {
607
+ style: "currency",
608
+ currency: (doc.currency_code || "usd").toUpperCase()
609
+ }).format(Number(doc.total_amount || 0)) }) }),
610
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Badge, { color: isPaid ? "green" : doc.payment_status === "unpaid" ? "red" : "blue", size: "small", children: doc.payment_status || doc.status }) }),
611
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Badge, { color: isZoho ? "purple" : "grey", size: "small", children: isZoho ? "Zoho Books" : "PDFKit" }) }),
612
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx("span", { className: "text-xs text-ui-fg-subtle", children: new Date(doc.created_at).toLocaleDateString() }) }),
613
+ /* @__PURE__ */ jsx(Table.Cell, { className: "text-right", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-1.5", children: [
614
+ /* @__PURE__ */ jsx(
615
+ "button",
616
+ {
617
+ type: "button",
618
+ onClick: () => handleViewDocument(doc.id, doc.display_id),
619
+ className: "p-1.5 rounded hover:bg-ui-bg-subtle text-ui-fg-subtle hover:text-ui-fg-base cursor-pointer",
620
+ title: "View / Download PDF",
621
+ children: /* @__PURE__ */ jsx(ArrowDownTray, { className: "w-4 h-4" })
622
+ }
623
+ ),
624
+ /* @__PURE__ */ jsx(
625
+ "button",
626
+ {
627
+ onClick: () => {
628
+ setSelectedDoc(doc);
629
+ setSendForm({
630
+ channels: ["email"],
631
+ custom_message: "",
632
+ subject: `${settings.company_name}: ${doc.title} #${doc.display_id}`
633
+ });
634
+ setSendModalOpen(true);
635
+ },
636
+ className: "p-1.5 rounded hover:bg-ui-bg-subtle text-ui-fg-subtle hover:text-ui-fg-base",
637
+ title: "Send via Email / SMS / WhatsApp",
638
+ children: /* @__PURE__ */ jsx(Envelope, { className: "w-4 h-4" })
639
+ }
640
+ ),
641
+ !isZoho && settings.zoho_books_enabled && /* @__PURE__ */ jsx(
642
+ Button,
643
+ {
644
+ variant: "transparent",
645
+ size: "small",
646
+ onClick: () => handleSyncToZoho(doc.id),
647
+ className: "text-xs text-purple-600 hover:text-purple-700",
648
+ children: "Push Zoho"
649
+ }
650
+ ),
651
+ doc.short_payment_link && /* @__PURE__ */ jsx(
652
+ "button",
653
+ {
654
+ onClick: () => {
655
+ navigator.clipboard.writeText(doc.short_payment_link);
656
+ alert("Short payment link copied to clipboard!");
657
+ },
658
+ className: "text-[11px] text-ui-fg-interactive hover:underline px-1.5 py-1",
659
+ title: "Copy Short Payment Link",
660
+ children: "Copy Link"
661
+ }
662
+ )
663
+ ] }) })
664
+ ] }, doc.id);
665
+ }) })
666
+ ] }),
667
+ zohoLiveDocs.length > 0 && /* @__PURE__ */ jsxs("div", { className: "mt-8 border border-ui-border-base rounded-lg p-4 bg-ui-bg-subtle", children: [
668
+ /* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-sm font-semibold mb-3", children: "Live Zoho Books Invoices" }),
669
+ /* @__PURE__ */ jsxs(Table, { children: [
670
+ /* @__PURE__ */ jsx(Table.Header, { children: /* @__PURE__ */ jsxs(Table.Row, { children: [
671
+ /* @__PURE__ */ jsx(Table.HeaderCell, { children: "Invoice #" }),
672
+ /* @__PURE__ */ jsx(Table.HeaderCell, { children: "Customer Name" }),
673
+ /* @__PURE__ */ jsx(Table.HeaderCell, { children: "Total" }),
674
+ /* @__PURE__ */ jsx(Table.HeaderCell, { children: "Status" }),
675
+ /* @__PURE__ */ jsx(Table.HeaderCell, { children: "Date" })
676
+ ] }) }),
677
+ /* @__PURE__ */ jsx(Table.Body, { children: zohoLiveDocs.map((zi) => /* @__PURE__ */ jsxs(Table.Row, { children: [
678
+ /* @__PURE__ */ jsx(Table.Cell, { className: "font-medium", children: zi.invoice_number }),
679
+ /* @__PURE__ */ jsx(Table.Cell, { children: zi.customer_name }),
680
+ /* @__PURE__ */ jsx(Table.Cell, { children: zi.total }),
681
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Badge, { color: zi.status === "paid" ? "green" : "red", size: "small", children: zi.status }) }),
682
+ /* @__PURE__ */ jsx(Table.Cell, { children: zi.date })
683
+ ] }, zi.invoice_id)) })
684
+ ] })
685
+ ] })
686
+ ] }),
687
+ activeTab === "templates" && /* @__PURE__ */ jsxs("div", { className: "p-6 max-w-4xl flex flex-col gap-6", children: [
688
+ /* @__PURE__ */ jsxs("div", { children: [
689
+ /* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-base font-semibold", children: "PDFKit Fallback Templates" }),
690
+ /* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-subtle", children: "Configure different styling templates for each document type when generated locally via PDFKit." })
691
+ ] }),
692
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-6", children: [
693
+ /* @__PURE__ */ jsxs("div", { className: "p-4 border border-ui-border-base rounded-lg bg-ui-bg-base flex flex-col justify-between", children: [
694
+ /* @__PURE__ */ jsxs("div", { children: [
695
+ /* @__PURE__ */ jsx(Label, { className: "font-semibold text-sm", children: "Invoice Template" }),
696
+ /* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-subtle mb-3", children: "Used for standard customer order & repair invoices." }),
697
+ /* @__PURE__ */ jsxs(
698
+ Select,
699
+ {
700
+ value: settings.invoice_template || "modern",
701
+ onValueChange: (v) => updateSettingField("invoice_template", v),
702
+ children: [
703
+ /* @__PURE__ */ jsx(Select.Trigger, { size: "small", children: /* @__PURE__ */ jsx(Select.Value, {}) }),
704
+ /* @__PURE__ */ jsxs(Select.Content, { children: [
705
+ /* @__PURE__ */ jsx(Select.Item, { value: "modern", children: "Modern Minimalist" }),
706
+ /* @__PURE__ */ jsx(Select.Item, { value: "classic", children: "Classic Corporate" }),
707
+ /* @__PURE__ */ jsx(Select.Item, { value: "minimal", children: "Clean Tech Monospace" })
708
+ ] })
709
+ ]
710
+ }
711
+ )
712
+ ] }),
713
+ /* @__PURE__ */ jsx("div", { className: "mt-4 pt-3 border-t border-ui-border-base flex justify-end", children: /* @__PURE__ */ jsxs(
714
+ Button,
715
+ {
716
+ variant: "secondary",
717
+ size: "small",
718
+ onClick: () => handlePreviewTemplate(settings.invoice_template || "modern", "invoice"),
719
+ isLoading: previewLoading === `${settings.invoice_template || "modern"}-invoice`,
720
+ children: [
721
+ /* @__PURE__ */ jsx(ArrowDownTray, { className: "w-3.5 h-3.5 mr-1" }),
722
+ " Preview Invoice Template"
723
+ ]
724
+ }
725
+ ) })
726
+ ] }),
727
+ /* @__PURE__ */ jsxs("div", { className: "p-4 border border-ui-border-base rounded-lg bg-ui-bg-base flex flex-col justify-between", children: [
728
+ /* @__PURE__ */ jsxs("div", { children: [
729
+ /* @__PURE__ */ jsx(Label, { className: "font-semibold text-sm", children: "Packing Slip Template" }),
730
+ /* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-subtle mb-3", children: "Used for warehouse fulfillment & shipping packing slips." }),
731
+ /* @__PURE__ */ jsxs(
732
+ Select,
733
+ {
734
+ value: settings.packing_slip_template || "modern",
735
+ onValueChange: (v) => updateSettingField("packing_slip_template", v),
736
+ children: [
737
+ /* @__PURE__ */ jsx(Select.Trigger, { size: "small", children: /* @__PURE__ */ jsx(Select.Value, {}) }),
738
+ /* @__PURE__ */ jsxs(Select.Content, { children: [
739
+ /* @__PURE__ */ jsx(Select.Item, { value: "modern", children: "Modern Minimalist" }),
740
+ /* @__PURE__ */ jsx(Select.Item, { value: "classic", children: "Classic Corporate" }),
741
+ /* @__PURE__ */ jsx(Select.Item, { value: "minimal", children: "Clean Tech Monospace" })
742
+ ] })
743
+ ]
744
+ }
745
+ )
746
+ ] }),
747
+ /* @__PURE__ */ jsx("div", { className: "mt-4 pt-3 border-t border-ui-border-base flex justify-end", children: /* @__PURE__ */ jsxs(
748
+ Button,
749
+ {
750
+ variant: "secondary",
751
+ size: "small",
752
+ onClick: () => handlePreviewTemplate(settings.packing_slip_template || "modern", "packing_slip"),
753
+ isLoading: previewLoading === `${settings.packing_slip_template || "modern"}-packing_slip`,
754
+ children: [
755
+ /* @__PURE__ */ jsx(ArrowDownTray, { className: "w-3.5 h-3.5 mr-1" }),
756
+ " Preview Packing Slip Template"
757
+ ]
758
+ }
759
+ ) })
760
+ ] }),
761
+ /* @__PURE__ */ jsxs("div", { className: "p-4 border border-ui-border-base rounded-lg bg-ui-bg-base flex flex-col justify-between", children: [
762
+ /* @__PURE__ */ jsxs("div", { children: [
763
+ /* @__PURE__ */ jsx(Label, { className: "font-semibold text-sm", children: "Payment Receipt Template" }),
764
+ /* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-subtle mb-3", children: "Issued when orders or repairs are captured and paid in full." }),
765
+ /* @__PURE__ */ jsxs(
766
+ Select,
767
+ {
768
+ value: settings.receipt_template || "modern",
769
+ onValueChange: (v) => updateSettingField("receipt_template", v),
770
+ children: [
771
+ /* @__PURE__ */ jsx(Select.Trigger, { size: "small", children: /* @__PURE__ */ jsx(Select.Value, {}) }),
772
+ /* @__PURE__ */ jsxs(Select.Content, { children: [
773
+ /* @__PURE__ */ jsx(Select.Item, { value: "modern", children: "Modern Minimalist" }),
774
+ /* @__PURE__ */ jsx(Select.Item, { value: "classic", children: "Classic Corporate" }),
775
+ /* @__PURE__ */ jsx(Select.Item, { value: "minimal", children: "Clean Tech Monospace" })
776
+ ] })
777
+ ]
778
+ }
779
+ )
780
+ ] }),
781
+ /* @__PURE__ */ jsx("div", { className: "mt-4 pt-3 border-t border-ui-border-base flex justify-end", children: /* @__PURE__ */ jsxs(
782
+ Button,
783
+ {
784
+ variant: "secondary",
785
+ size: "small",
786
+ onClick: () => handlePreviewTemplate(settings.receipt_template || "modern", "receipt"),
787
+ isLoading: previewLoading === `${settings.receipt_template || "modern"}-receipt`,
788
+ children: [
789
+ /* @__PURE__ */ jsx(ArrowDownTray, { className: "w-3.5 h-3.5 mr-1" }),
790
+ " Preview Receipt Template"
791
+ ]
792
+ }
793
+ ) })
794
+ ] }),
795
+ /* @__PURE__ */ jsxs("div", { className: "p-4 border border-ui-border-base rounded-lg bg-ui-bg-base flex flex-col justify-between", children: [
796
+ /* @__PURE__ */ jsxs("div", { children: [
797
+ /* @__PURE__ */ jsx(Label, { className: "font-semibold text-sm", children: "Estimate / Quotation Template" }),
798
+ /* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-subtle mb-3", children: "Issued for customer repair quotations, diagnostics, and price estimates." }),
799
+ /* @__PURE__ */ jsxs(
800
+ Select,
801
+ {
802
+ value: settings.estimate_template || "modern",
803
+ onValueChange: (v) => updateSettingField("estimate_template", v),
804
+ children: [
805
+ /* @__PURE__ */ jsx(Select.Trigger, { size: "small", children: /* @__PURE__ */ jsx(Select.Value, {}) }),
806
+ /* @__PURE__ */ jsxs(Select.Content, { children: [
807
+ /* @__PURE__ */ jsx(Select.Item, { value: "modern", children: "Modern Minimalist" }),
808
+ /* @__PURE__ */ jsx(Select.Item, { value: "classic", children: "Classic Corporate" }),
809
+ /* @__PURE__ */ jsx(Select.Item, { value: "minimal", children: "Clean Tech Monospace" })
810
+ ] })
811
+ ]
812
+ }
813
+ )
814
+ ] }),
815
+ /* @__PURE__ */ jsx("div", { className: "mt-4 pt-3 border-t border-ui-border-base flex justify-end", children: /* @__PURE__ */ jsxs(
816
+ Button,
817
+ {
818
+ variant: "secondary",
819
+ size: "small",
820
+ onClick: () => handlePreviewTemplate(settings.estimate_template || "modern", "estimate"),
821
+ isLoading: previewLoading === `${settings.estimate_template || "modern"}-estimate`,
822
+ children: [
823
+ /* @__PURE__ */ jsx(ArrowDownTray, { className: "w-3.5 h-3.5 mr-1" }),
824
+ " Preview Estimate Template"
825
+ ]
826
+ }
827
+ ) })
828
+ ] }),
829
+ /* @__PURE__ */ jsxs("div", { className: "p-4 border border-ui-border-base rounded-lg bg-ui-bg-base flex flex-col justify-between", children: [
830
+ /* @__PURE__ */ jsxs("div", { children: [
831
+ /* @__PURE__ */ jsx(Label, { className: "font-semibold text-sm", children: "Custom Document Template" }),
832
+ /* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-subtle mb-3", children: "Used for certificates, agreements, and customized memos." }),
833
+ /* @__PURE__ */ jsxs(
834
+ Select,
835
+ {
836
+ value: settings.custom_doc_template || "modern",
837
+ onValueChange: (v) => updateSettingField("custom_doc_template", v),
838
+ children: [
839
+ /* @__PURE__ */ jsx(Select.Trigger, { size: "small", children: /* @__PURE__ */ jsx(Select.Value, {}) }),
840
+ /* @__PURE__ */ jsxs(Select.Content, { children: [
841
+ /* @__PURE__ */ jsx(Select.Item, { value: "modern", children: "Modern Minimalist" }),
842
+ /* @__PURE__ */ jsx(Select.Item, { value: "classic", children: "Classic Corporate" }),
843
+ /* @__PURE__ */ jsx(Select.Item, { value: "minimal", children: "Clean Tech Monospace" })
844
+ ] })
845
+ ]
846
+ }
847
+ )
848
+ ] }),
849
+ /* @__PURE__ */ jsx("div", { className: "mt-4 pt-3 border-t border-ui-border-base flex justify-end", children: /* @__PURE__ */ jsxs(
850
+ Button,
851
+ {
852
+ variant: "secondary",
853
+ size: "small",
854
+ onClick: () => handlePreviewTemplate(settings.custom_doc_template || "modern", "custom"),
855
+ isLoading: previewLoading === `${settings.custom_doc_template || "modern"}-custom`,
856
+ children: [
857
+ /* @__PURE__ */ jsx(ArrowDownTray, { className: "w-3.5 h-3.5 mr-1" }),
858
+ " Preview Custom Doc Template"
859
+ ]
860
+ }
861
+ ) })
862
+ ] }),
863
+ /* @__PURE__ */ jsxs("div", { className: "p-4 border border-ui-border-base rounded-lg bg-ui-bg-base flex flex-col justify-between", children: [
864
+ /* @__PURE__ */ jsxs("div", { children: [
865
+ /* @__PURE__ */ jsx(Label, { className: "font-semibold text-sm", children: "Repair Job Card Template" }),
866
+ /* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-subtle mb-3", children: "Workshop intake job card with device specs, inspection checklist & technician sign-off." }),
867
+ /* @__PURE__ */ jsxs(
868
+ Select,
869
+ {
870
+ value: settings.job_card_template || "modern",
871
+ onValueChange: (v) => updateSettingField("job_card_template", v),
872
+ children: [
873
+ /* @__PURE__ */ jsx(Select.Trigger, { size: "small", children: /* @__PURE__ */ jsx(Select.Value, {}) }),
874
+ /* @__PURE__ */ jsxs(Select.Content, { children: [
875
+ /* @__PURE__ */ jsx(Select.Item, { value: "modern", children: "Modern Minimalist" }),
876
+ /* @__PURE__ */ jsx(Select.Item, { value: "classic", children: "Classic Corporate" }),
877
+ /* @__PURE__ */ jsx(Select.Item, { value: "minimal", children: "Clean Tech Monospace" })
878
+ ] })
879
+ ]
880
+ }
881
+ )
882
+ ] }),
883
+ /* @__PURE__ */ jsx("div", { className: "mt-4 pt-3 border-t border-ui-border-base flex justify-end", children: /* @__PURE__ */ jsxs(
884
+ Button,
885
+ {
886
+ variant: "secondary",
887
+ size: "small",
888
+ onClick: () => handlePreviewTemplate(settings.job_card_template || "modern", "job_card"),
889
+ isLoading: previewLoading === `${settings.job_card_template || "modern"}-job_card`,
890
+ children: [
891
+ /* @__PURE__ */ jsx(ArrowDownTray, { className: "w-3.5 h-3.5 mr-1" }),
892
+ " Preview Job Card Template"
893
+ ]
894
+ }
895
+ ) })
896
+ ] })
897
+ ] }),
898
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-3 mt-4", children: [
899
+ saveSuccessMsg && /* @__PURE__ */ jsxs("span", { className: "text-xs text-ui-fg-interactive font-medium", children: [
900
+ "✓ ",
901
+ saveSuccessMsg
902
+ ] }),
903
+ /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: saveSettings, isLoading: isSaving, children: "Save Template Preferences" })
904
+ ] })
905
+ ] }),
906
+ activeTab === "automations" && /* @__PURE__ */ jsxs("div", { className: "p-6 max-w-4xl flex flex-col gap-6", children: [
907
+ /* @__PURE__ */ jsxs("div", { children: [
908
+ /* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-base font-semibold", children: "Event Subscribers & Automations" }),
909
+ /* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-subtle", children: "Toggle automated document generation on or off for captured Medusa order and repair events." })
910
+ ] }),
911
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
912
+ /* @__PURE__ */ jsxs("div", { className: "p-4 border border-ui-border-base rounded-lg bg-ui-bg-base flex flex-col gap-4", children: [
913
+ /* @__PURE__ */ jsx(Heading, { level: "h3", className: "text-sm font-semibold text-ui-fg-base", children: "E-commerce Order Events" }),
914
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between py-2 border-b border-ui-border-base", children: [
915
+ /* @__PURE__ */ jsxs("div", { children: [
916
+ /* @__PURE__ */ jsx(Label, { className: "font-semibold text-sm", children: "Order Placed (`order.placed`)" }),
917
+ /* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-subtle", children: "Autogenerates Tax Invoice, embeds Paystack QR payment link for unpaid balances, and dispatches to customer." })
918
+ ] }),
919
+ /* @__PURE__ */ jsx(
920
+ Switch,
921
+ {
922
+ checked: settings.event_order_placed_enabled,
923
+ onCheckedChange: (v) => updateSettingField("event_order_placed_enabled", v)
924
+ }
925
+ )
926
+ ] }),
927
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between py-2 border-b border-ui-border-base", children: [
928
+ /* @__PURE__ */ jsxs("div", { children: [
929
+ /* @__PURE__ */ jsx(Label, { className: "font-semibold text-sm", children: "Payment Captured (`payment.captured`)" }),
930
+ /* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-subtle", children: "Autogenerates official Payment Receipt and delivers download link to customer." })
931
+ ] }),
932
+ /* @__PURE__ */ jsx(
933
+ Switch,
934
+ {
935
+ checked: settings.event_payment_captured_enabled,
936
+ onCheckedChange: (v) => updateSettingField("event_payment_captured_enabled", v)
937
+ }
938
+ )
939
+ ] }),
940
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between py-2 border-b border-ui-border-base", children: [
941
+ /* @__PURE__ */ jsxs("div", { children: [
942
+ /* @__PURE__ */ jsx(Label, { className: "font-semibold text-sm", children: "Order Completed (`order.completed`)" }),
943
+ /* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-subtle", children: "Autogenerates Packing Slip and final delivery documents." })
944
+ ] }),
945
+ /* @__PURE__ */ jsx(
946
+ Switch,
947
+ {
948
+ checked: settings.event_order_completed_enabled,
949
+ onCheckedChange: (v) => updateSettingField("event_order_completed_enabled", v)
950
+ }
951
+ )
952
+ ] }),
953
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between py-2", children: [
954
+ /* @__PURE__ */ jsxs("div", { children: [
955
+ /* @__PURE__ */ jsx(Label, { className: "font-semibold text-sm", children: "Fulfillment Created (`order.fulfillment_created`)" }),
956
+ /* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-subtle", children: "Autogenerates Packing Slip for fulfillment staff and warehouse tracking." })
957
+ ] }),
958
+ /* @__PURE__ */ jsx(
959
+ Switch,
960
+ {
961
+ checked: settings.event_order_fulfillment_enabled,
962
+ onCheckedChange: (v) => updateSettingField("event_order_fulfillment_enabled", v)
963
+ }
964
+ )
965
+ ] })
966
+ ] }),
967
+ /* @__PURE__ */ jsxs("div", { className: "p-4 border border-ui-border-base rounded-lg bg-ui-bg-base flex flex-col gap-4", children: [
968
+ /* @__PURE__ */ jsx(Heading, { level: "h3", className: "text-sm font-semibold text-ui-fg-base", children: "Repair Plugin Events" }),
969
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between py-2 border-b border-ui-border-base", children: [
970
+ /* @__PURE__ */ jsxs("div", { children: [
971
+ /* @__PURE__ */ jsx(Label, { className: "font-semibold text-sm", children: "Repair Status Changed (`repair.status_changed`)" }),
972
+ /* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-subtle", children: "Autogenerates updated repair invoice or quote with device details and payment link." })
973
+ ] }),
974
+ /* @__PURE__ */ jsx(
975
+ Switch,
976
+ {
977
+ checked: settings.event_repair_status_changed_enabled,
978
+ onCheckedChange: (v) => updateSettingField("event_repair_status_changed_enabled", v)
979
+ }
980
+ )
981
+ ] }),
982
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between py-2 border-b border-ui-border-base", children: [
983
+ /* @__PURE__ */ jsxs("div", { children: [
984
+ /* @__PURE__ */ jsx(Label, { className: "font-semibold text-sm", children: "Compliance Requested (`repair.ticket.compliance_requested`)" }),
985
+ /* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-subtle", children: "Autogenerates Quotation and sends approval link to customer." })
986
+ ] }),
987
+ /* @__PURE__ */ jsx(
988
+ Switch,
989
+ {
990
+ checked: settings.event_repair_compliance_enabled,
991
+ onCheckedChange: (v) => updateSettingField("event_repair_compliance_enabled", v)
992
+ }
993
+ )
994
+ ] }),
995
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between py-2 border-b border-ui-border-base", children: [
996
+ /* @__PURE__ */ jsxs("div", { children: [
997
+ /* @__PURE__ */ jsx(Label, { className: "font-semibold text-sm", children: "Repair Created (`repair.created`)" }),
998
+ /* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-subtle", children: "Generates initial Job Card / Estimate when a new repair ticket is filed." })
999
+ ] }),
1000
+ /* @__PURE__ */ jsx(
1001
+ Switch,
1002
+ {
1003
+ checked: settings.event_repair_created_enabled,
1004
+ onCheckedChange: (v) => updateSettingField("event_repair_created_enabled", v)
1005
+ }
1006
+ )
1007
+ ] }),
1008
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between py-2 border-b border-ui-border-base", children: [
1009
+ /* @__PURE__ */ jsxs("div", { children: [
1010
+ /* @__PURE__ */ jsx(Label, { className: "font-semibold text-sm", children: "Repair Completed (`repair.completed`)" }),
1011
+ /* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-subtle", children: "Generates final repair invoice with breakdown of parts and labor charges." })
1012
+ ] }),
1013
+ /* @__PURE__ */ jsx(
1014
+ Switch,
1015
+ {
1016
+ checked: settings.event_repair_completed_enabled,
1017
+ onCheckedChange: (v) => updateSettingField("event_repair_completed_enabled", v)
1018
+ }
1019
+ )
1020
+ ] }),
1021
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between py-2", children: [
1022
+ /* @__PURE__ */ jsxs("div", { children: [
1023
+ /* @__PURE__ */ jsx(Label, { className: "font-semibold text-sm", children: "Customer Reminder (`repair.customer_reminder`)" }),
1024
+ /* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-subtle", children: "Nudges customer with short document link and outstanding balance reminder." })
1025
+ ] }),
1026
+ /* @__PURE__ */ jsx(
1027
+ Switch,
1028
+ {
1029
+ checked: settings.event_repair_reminder_enabled,
1030
+ onCheckedChange: (v) => updateSettingField("event_repair_reminder_enabled", v)
1031
+ }
1032
+ )
1033
+ ] })
1034
+ ] })
1035
+ ] }),
1036
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-3 mt-4", children: [
1037
+ saveSuccessMsg && /* @__PURE__ */ jsxs("span", { className: "text-xs text-ui-fg-interactive font-medium", children: [
1038
+ "✓ ",
1039
+ saveSuccessMsg
1040
+ ] }),
1041
+ /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: saveSettings, isLoading: isSaving, children: "Save Automations" })
1042
+ ] })
1043
+ ] }),
1044
+ activeTab === "settings" && /* @__PURE__ */ jsxs("div", { className: "p-6 max-w-4xl flex flex-col gap-8", children: [
1045
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
1046
+ /* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-base font-semibold", children: "General Branding & Details" }),
1047
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [
1048
+ /* @__PURE__ */ jsxs("div", { children: [
1049
+ /* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Company Name" }),
1050
+ /* @__PURE__ */ jsx(
1051
+ Input,
1052
+ {
1053
+ value: settings.company_name,
1054
+ onChange: (e) => updateSettingField("company_name", e.target.value),
1055
+ placeholder: "Urban Device Care Ltd",
1056
+ size: "small"
1057
+ }
1058
+ )
1059
+ ] }),
1060
+ /* @__PURE__ */ jsxs("div", { children: [
1061
+ /* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Storefront URL" }),
1062
+ /* @__PURE__ */ jsx(
1063
+ Input,
1064
+ {
1065
+ value: settings.storefront_url,
1066
+ onChange: (e) => updateSettingField("storefront_url", e.target.value),
1067
+ placeholder: "https://store.example.com",
1068
+ size: "small"
1069
+ }
1070
+ )
1071
+ ] }),
1072
+ /* @__PURE__ */ jsxs("div", { children: [
1073
+ /* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Logo URL" }),
1074
+ /* @__PURE__ */ jsx(
1075
+ Input,
1076
+ {
1077
+ value: settings.pdf_logo_url,
1078
+ onChange: (e) => updateSettingField("pdf_logo_url", e.target.value),
1079
+ placeholder: "https://example.com/logo.png",
1080
+ size: "small"
1081
+ }
1082
+ )
1083
+ ] }),
1084
+ /* @__PURE__ */ jsxs("div", { children: [
1085
+ /* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Phone Numbers" }),
1086
+ /* @__PURE__ */ jsx(
1087
+ Input,
1088
+ {
1089
+ value: settings.pdf_phone,
1090
+ onChange: (e) => updateSettingField("pdf_phone", e.target.value),
1091
+ placeholder: "+44 20 7946 0991",
1092
+ size: "small"
1093
+ }
1094
+ )
1095
+ ] }),
1096
+ /* @__PURE__ */ jsxs("div", { children: [
1097
+ /* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Support Email" }),
1098
+ /* @__PURE__ */ jsx(
1099
+ Input,
1100
+ {
1101
+ value: settings.pdf_email,
1102
+ onChange: (e) => updateSettingField("pdf_email", e.target.value),
1103
+ placeholder: "support@example.com",
1104
+ size: "small"
1105
+ }
1106
+ )
1107
+ ] }),
1108
+ /* @__PURE__ */ jsxs("div", { children: [
1109
+ /* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Website" }),
1110
+ /* @__PURE__ */ jsx(
1111
+ Input,
1112
+ {
1113
+ value: settings.pdf_website,
1114
+ onChange: (e) => updateSettingField("pdf_website", e.target.value),
1115
+ placeholder: "www.example.com",
1116
+ size: "small"
1117
+ }
1118
+ )
1119
+ ] }),
1120
+ /* @__PURE__ */ jsxs("div", { className: "md:col-span-2", children: [
1121
+ /* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Address" }),
1122
+ /* @__PURE__ */ jsx(
1123
+ Input,
1124
+ {
1125
+ value: settings.pdf_address,
1126
+ onChange: (e) => updateSettingField("pdf_address", e.target.value),
1127
+ placeholder: "123 High Street, Tech Park, London",
1128
+ size: "small"
1129
+ }
1130
+ )
1131
+ ] }),
1132
+ /* @__PURE__ */ jsxs("div", { className: "md:col-span-2", children: [
1133
+ /* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Payment Instructions / Bank Details" }),
1134
+ /* @__PURE__ */ jsx(
1135
+ Textarea,
1136
+ {
1137
+ value: settings.pdf_payment_details,
1138
+ onChange: (e) => updateSettingField("pdf_payment_details", e.target.value),
1139
+ placeholder: "Bank: Barclays | Acct: 12345678 | MPESA Till: 123456",
1140
+ rows: 2
1141
+ }
1142
+ )
1143
+ ] }),
1144
+ /* @__PURE__ */ jsxs("div", { className: "md:col-span-2", children: [
1145
+ /* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Default Terms & Conditions" }),
1146
+ /* @__PURE__ */ jsx(
1147
+ Textarea,
1148
+ {
1149
+ value: settings.pdf_terms,
1150
+ onChange: (e) => updateSettingField("pdf_terms", e.target.value),
1151
+ placeholder: "All items come with 90-day warranty. Invoices payable within 14 days.",
1152
+ rows: 3
1153
+ }
1154
+ )
1155
+ ] })
1156
+ ] })
1157
+ ] }),
1158
+ /* @__PURE__ */ jsx("div", { className: "border-b border-ui-border-base" }),
1159
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
1160
+ /* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-base font-semibold", children: "Notification Channels" }),
1161
+ /* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-subtle", children: "Toggle which channels are active for auto-delivering document notifications." }),
1162
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
1163
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between p-3 border border-ui-border-base rounded-lg bg-ui-bg-base", children: [
1164
+ /* @__PURE__ */ jsxs("div", { children: [
1165
+ /* @__PURE__ */ jsx(Label, { className: "font-semibold text-sm", children: "Email Channel" }),
1166
+ /* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-subtle", children: "Deliver HTML documents and payment buttons via Email." })
1167
+ ] }),
1168
+ /* @__PURE__ */ jsx(
1169
+ Switch,
1170
+ {
1171
+ checked: settings.email_notifications_enabled,
1172
+ onCheckedChange: (v) => updateSettingField("email_notifications_enabled", v)
1173
+ }
1174
+ )
1175
+ ] }),
1176
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between p-3 border border-ui-border-base rounded-lg bg-ui-bg-base", children: [
1177
+ /* @__PURE__ */ jsxs("div", { children: [
1178
+ /* @__PURE__ */ jsx(Label, { className: "font-semibold text-sm", children: "SMS Channel" }),
1179
+ /* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-subtle", children: "Send concise texts with shortlinks via SMS provider." })
1180
+ ] }),
1181
+ /* @__PURE__ */ jsx(
1182
+ Switch,
1183
+ {
1184
+ checked: settings.sms_notifications_enabled,
1185
+ onCheckedChange: (v) => updateSettingField("sms_notifications_enabled", v)
1186
+ }
1187
+ )
1188
+ ] }),
1189
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between p-3 border border-ui-border-base rounded-lg bg-ui-bg-base", children: [
1190
+ /* @__PURE__ */ jsxs("div", { children: [
1191
+ /* @__PURE__ */ jsx(Label, { className: "font-semibold text-sm", children: "WhatsApp Channel" }),
1192
+ /* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-subtle", children: "Send formatted message with shortlinks via WhatsApp provider." })
1193
+ ] }),
1194
+ /* @__PURE__ */ jsx(
1195
+ Switch,
1196
+ {
1197
+ checked: settings.whatsapp_notifications_enabled,
1198
+ onCheckedChange: (v) => updateSettingField("whatsapp_notifications_enabled", v)
1199
+ }
1200
+ )
1201
+ ] })
1202
+ ] })
1203
+ ] }),
1204
+ /* @__PURE__ */ jsx("div", { className: "border-b border-ui-border-base" }),
1205
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-5", children: [
1206
+ /* @__PURE__ */ jsxs("div", { children: [
1207
+ /* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-base font-semibold", children: "Customizable Notification Message Templates" }),
1208
+ /* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-subtle", children: "Customize the exact message format and body text dispatched across Email, SMS, and WhatsApp. Click on any tag below each editor to insert dynamic placeholders." })
1209
+ ] }),
1210
+ /* @__PURE__ */ jsxs("div", { className: "p-4 border border-ui-border-base rounded-lg bg-ui-bg-base flex flex-col gap-4", children: [
1211
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
1212
+ /* @__PURE__ */ jsxs("div", { children: [
1213
+ /* @__PURE__ */ jsxs(Label, { className: "font-semibold text-sm flex items-center gap-2", children: [
1214
+ /* @__PURE__ */ jsx(Envelope, { className: "w-4 h-4 text-ui-fg-interactive" }),
1215
+ "Email Notification Customizer"
1216
+ ] }),
1217
+ /* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-subtle", children: "Customize email subject line and HTML/text message body." })
1218
+ ] }),
1219
+ /* @__PURE__ */ jsx(
1220
+ Button,
1221
+ {
1222
+ variant: "secondary",
1223
+ size: "small",
1224
+ onClick: () => {
1225
+ updateSettingField("email_subject_template", "");
1226
+ updateSettingField("email_body_template", "");
1227
+ },
1228
+ children: "Reset to Default"
1229
+ }
1230
+ )
1231
+ ] }),
1232
+ /* @__PURE__ */ jsxs("div", { children: [
1233
+ /* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Email Subject Template" }),
1234
+ /* @__PURE__ */ jsx(
1235
+ Input,
1236
+ {
1237
+ value: settings.email_subject_template || "",
1238
+ onChange: (e) => updateSettingField("email_subject_template", e.target.value),
1239
+ placeholder: "{company_name}: {document_title} #{display_id}",
1240
+ size: "small",
1241
+ className: "mt-1 font-mono text-xs"
1242
+ }
1243
+ ),
1244
+ /* @__PURE__ */ jsxs(Text, { className: "text-[11px] text-ui-fg-muted mt-1", children: [
1245
+ "Default: ",
1246
+ /* @__PURE__ */ jsx("code", { children: "{company_name}: {document_title} #{display_id}" })
1247
+ ] })
1248
+ ] }),
1249
+ /* @__PURE__ */ jsxs("div", { children: [
1250
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-1", children: [
1251
+ /* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Email Body Template (HTML / Text)" }),
1252
+ /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1", children: [
1253
+ "{customer_name}",
1254
+ "{document_title}",
1255
+ "{display_id}",
1256
+ "{total_amount}",
1257
+ "{company_name}",
1258
+ "{payment_link}",
1259
+ "{document_link}",
1260
+ "{payment_button}",
1261
+ "{download_button}"
1262
+ ].map((tag) => /* @__PURE__ */ jsxs(
1263
+ "button",
1264
+ {
1265
+ type: "button",
1266
+ onClick: () => {
1267
+ const cur = settings.email_body_template || "";
1268
+ updateSettingField("email_body_template", cur + (cur ? " " : "") + tag);
1269
+ },
1270
+ className: "text-[10px] px-1.5 py-0.5 rounded bg-ui-bg-subtle hover:bg-ui-bg-subtle-hover text-ui-fg-subtle border border-ui-border-base font-mono cursor-pointer transition-colors",
1271
+ children: [
1272
+ "+",
1273
+ tag
1274
+ ]
1275
+ },
1276
+ tag
1277
+ )) })
1278
+ ] }),
1279
+ /* @__PURE__ */ jsx(
1280
+ Textarea,
1281
+ {
1282
+ value: settings.email_body_template || "",
1283
+ onChange: (e) => updateSettingField("email_body_template", e.target.value),
1284
+ placeholder: `<p>Hello <strong>{customer_name}</strong>,</p>
1285
+ <p>Your {document_title} <strong>#{display_id}</strong> is ready.</p>
1286
+ {payment_button}
1287
+ {download_button}
1288
+ <p>Thank you for choosing {company_name}.</p>`,
1289
+ rows: 5,
1290
+ className: "font-mono text-xs"
1291
+ }
1292
+ ),
1293
+ /* @__PURE__ */ jsx(Text, { className: "text-[11px] text-ui-fg-muted mt-1", children: "Leave blank to use default responsive layout with company banner, payment button, and PDF download button." })
1294
+ ] })
1295
+ ] }),
1296
+ /* @__PURE__ */ jsxs("div", { className: "p-4 border border-ui-border-base rounded-lg bg-ui-bg-base flex flex-col gap-4", children: [
1297
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
1298
+ /* @__PURE__ */ jsxs("div", { children: [
1299
+ /* @__PURE__ */ jsx(Label, { className: "font-semibold text-sm", children: "SMS Message Body Template" }),
1300
+ /* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-subtle", children: "Concise text message dispatched via your SMS provider." })
1301
+ ] }),
1302
+ /* @__PURE__ */ jsx(
1303
+ Button,
1304
+ {
1305
+ variant: "secondary",
1306
+ size: "small",
1307
+ onClick: () => updateSettingField("sms_body_template", ""),
1308
+ children: "Reset to Default"
1309
+ }
1310
+ )
1311
+ ] }),
1312
+ /* @__PURE__ */ jsxs("div", { children: [
1313
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-1", children: [
1314
+ /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1", children: [
1315
+ "{company_name}",
1316
+ "{customer_name}",
1317
+ "{document_title}",
1318
+ "{display_id}",
1319
+ "{total_amount}",
1320
+ "{payment_link}",
1321
+ "{document_link}"
1322
+ ].map((tag) => /* @__PURE__ */ jsxs(
1323
+ "button",
1324
+ {
1325
+ type: "button",
1326
+ onClick: () => {
1327
+ const cur = settings.sms_body_template || "";
1328
+ updateSettingField("sms_body_template", cur + (cur ? " " : "") + tag);
1329
+ },
1330
+ className: "text-[10px] px-1.5 py-0.5 rounded bg-ui-bg-subtle hover:bg-ui-bg-subtle-hover text-ui-fg-subtle border border-ui-border-base font-mono cursor-pointer transition-colors",
1331
+ children: [
1332
+ "+",
1333
+ tag
1334
+ ]
1335
+ },
1336
+ tag
1337
+ )) }),
1338
+ /* @__PURE__ */ jsxs("span", { className: "text-[11px] text-ui-fg-muted font-mono", children: [
1339
+ (settings.sms_body_template || "").length,
1340
+ " chars"
1341
+ ] })
1342
+ ] }),
1343
+ /* @__PURE__ */ jsx(
1344
+ Textarea,
1345
+ {
1346
+ value: settings.sms_body_template || "",
1347
+ onChange: (e) => updateSettingField("sms_body_template", e.target.value),
1348
+ placeholder: "[{company_name}] Hi {customer_name}, your {document_title} #{display_id} is ready. Total: {total_amount}. Pay: {payment_link} View: {document_link}",
1349
+ rows: 3,
1350
+ className: "font-mono text-xs"
1351
+ }
1352
+ ),
1353
+ /* @__PURE__ */ jsxs(Text, { className: "text-[11px] text-ui-fg-muted mt-1", children: [
1354
+ "Default: ",
1355
+ /* @__PURE__ */ jsx("code", { children: "[{company_name}] Hi {customer_name}, your {document_title} #{display_id} is ready. Total: {total_amount}. Pay: {payment_link} View: {document_link}" })
1356
+ ] })
1357
+ ] })
1358
+ ] }),
1359
+ /* @__PURE__ */ jsxs("div", { className: "p-4 border border-ui-border-base rounded-lg bg-ui-bg-base flex flex-col gap-4", children: [
1360
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
1361
+ /* @__PURE__ */ jsxs("div", { children: [
1362
+ /* @__PURE__ */ jsx(Label, { className: "font-semibold text-sm", children: "WhatsApp Message Body Template" }),
1363
+ /* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-subtle", children: "Formatted message supporting WhatsApp formatting (*bold*, _italics_)." })
1364
+ ] }),
1365
+ /* @__PURE__ */ jsx(
1366
+ Button,
1367
+ {
1368
+ variant: "secondary",
1369
+ size: "small",
1370
+ onClick: () => updateSettingField("whatsapp_body_template", ""),
1371
+ children: "Reset to Default"
1372
+ }
1373
+ )
1374
+ ] }),
1375
+ /* @__PURE__ */ jsxs("div", { children: [
1376
+ /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between mb-1", children: /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1", children: [
1377
+ "{company_name}",
1378
+ "{customer_name}",
1379
+ "{document_title}",
1380
+ "{display_id}",
1381
+ "{total_amount}",
1382
+ "{payment_link}",
1383
+ "{document_link}"
1384
+ ].map((tag) => /* @__PURE__ */ jsxs(
1385
+ "button",
1386
+ {
1387
+ type: "button",
1388
+ onClick: () => {
1389
+ const cur = settings.whatsapp_body_template || "";
1390
+ updateSettingField("whatsapp_body_template", cur + (cur ? " " : "") + tag);
1391
+ },
1392
+ className: "text-[10px] px-1.5 py-0.5 rounded bg-ui-bg-subtle hover:bg-ui-bg-subtle-hover text-ui-fg-subtle border border-ui-border-base font-mono cursor-pointer transition-colors",
1393
+ children: [
1394
+ "+",
1395
+ tag
1396
+ ]
1397
+ },
1398
+ tag
1399
+ )) }) }),
1400
+ /* @__PURE__ */ jsx(
1401
+ Textarea,
1402
+ {
1403
+ value: settings.whatsapp_body_template || "",
1404
+ onChange: (e) => updateSettingField("whatsapp_body_template", e.target.value),
1405
+ placeholder: `*{company_name}*
1406
+ Hello *{customer_name}*,
1407
+ Your *{document_title} #{display_id}* has been generated.
1408
+ *Amount:* {total_amount}
1409
+ *Pay Online:* {payment_link}
1410
+ *Download PDF:* {document_link}`,
1411
+ rows: 4,
1412
+ className: "font-mono text-xs"
1413
+ }
1414
+ ),
1415
+ /* @__PURE__ */ jsxs(Text, { className: "text-[11px] text-ui-fg-muted mt-1", children: [
1416
+ "Default: ",
1417
+ /* @__PURE__ */ jsx("code", { children: "*{company_name}*\\nHello *{customer_name}*,\\nYour *{document_title} #{display_id}* has been generated.\\n*Amount:* {total_amount}\\n*Pay Online:* {payment_link}\\n*Download PDF:* {document_link}" })
1418
+ ] })
1419
+ ] })
1420
+ ] })
1421
+ ] }),
1422
+ /* @__PURE__ */ jsx("div", { className: "border-b border-ui-border-base" }),
1423
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
1424
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
1425
+ /* @__PURE__ */ jsxs("div", { children: [
1426
+ /* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-base font-semibold", children: "Zoho Books Integration" }),
1427
+ /* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-subtle", children: "Sync invoices and estimates with your official Zoho Books accounting account." })
1428
+ ] }),
1429
+ /* @__PURE__ */ jsx(
1430
+ Switch,
1431
+ {
1432
+ checked: settings.zoho_books_enabled,
1433
+ onCheckedChange: (v) => updateSettingField("zoho_books_enabled", v)
1434
+ }
1435
+ )
1436
+ ] }),
1437
+ settings.zoho_books_enabled && /* @__PURE__ */ jsxs("div", { className: "p-4 border border-ui-border-base rounded-lg bg-ui-bg-subtle flex flex-col gap-4", children: [
1438
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [
1439
+ /* @__PURE__ */ jsxs("div", { children: [
1440
+ /* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Zoho Data Center Domain" }),
1441
+ /* @__PURE__ */ jsxs(
1442
+ Select,
1443
+ {
1444
+ value: settings.zoho_domain || "com",
1445
+ onValueChange: (v) => updateSettingField("zoho_domain", v),
1446
+ children: [
1447
+ /* @__PURE__ */ jsx(Select.Trigger, { size: "small", children: /* @__PURE__ */ jsx(Select.Value, {}) }),
1448
+ /* @__PURE__ */ jsxs(Select.Content, { children: [
1449
+ /* @__PURE__ */ jsx(Select.Item, { value: "com", children: ".com (Global / US)" }),
1450
+ /* @__PURE__ */ jsx(Select.Item, { value: "eu", children: ".eu (Europe)" }),
1451
+ /* @__PURE__ */ jsx(Select.Item, { value: "in", children: ".in (India)" }),
1452
+ /* @__PURE__ */ jsx(Select.Item, { value: "com.au", children: ".com.au (Australia)" }),
1453
+ /* @__PURE__ */ jsx(Select.Item, { value: "jp", children: ".jp (Japan)" })
1454
+ ] })
1455
+ ]
1456
+ }
1457
+ )
1458
+ ] }),
1459
+ /* @__PURE__ */ jsxs("div", { children: [
1460
+ /* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Organization ID" }),
1461
+ /* @__PURE__ */ jsx(
1462
+ Input,
1463
+ {
1464
+ value: settings.zoho_organization_id,
1465
+ onChange: (e) => updateSettingField("zoho_organization_id", e.target.value),
1466
+ placeholder: "e.g. 12345678",
1467
+ size: "small"
1468
+ }
1469
+ )
1470
+ ] }),
1471
+ /* @__PURE__ */ jsxs("div", { children: [
1472
+ /* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Client ID" }),
1473
+ /* @__PURE__ */ jsx(
1474
+ Input,
1475
+ {
1476
+ value: settings.zoho_client_id,
1477
+ onChange: (e) => updateSettingField("zoho_client_id", e.target.value),
1478
+ placeholder: "1000.XXXXXXXXXXXXXXXXXXXXXXXX",
1479
+ size: "small"
1480
+ }
1481
+ )
1482
+ ] }),
1483
+ /* @__PURE__ */ jsxs("div", { children: [
1484
+ /* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Client Secret" }),
1485
+ /* @__PURE__ */ jsx(
1486
+ Input,
1487
+ {
1488
+ type: "password",
1489
+ value: settings.zoho_client_secret,
1490
+ onChange: (e) => updateSettingField("zoho_client_secret", e.target.value),
1491
+ placeholder: "Enter Client Secret",
1492
+ size: "small"
1493
+ }
1494
+ )
1495
+ ] }),
1496
+ /* @__PURE__ */ jsxs("div", { className: "md:col-span-2", children: [
1497
+ /* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Refresh Token" }),
1498
+ /* @__PURE__ */ jsx(
1499
+ Input,
1500
+ {
1501
+ type: "password",
1502
+ value: settings.zoho_refresh_token,
1503
+ onChange: (e) => updateSettingField("zoho_refresh_token", e.target.value),
1504
+ placeholder: "1000.XXXXXXXXXXXXXXXXXXXXXXXX",
1505
+ size: "small"
1506
+ }
1507
+ )
1508
+ ] })
1509
+ ] }),
1510
+ /* @__PURE__ */ jsxs("div", { className: "pt-4 border-t border-ui-border-base flex flex-col gap-4", children: [
1511
+ /* @__PURE__ */ jsx(Heading, { level: "h3", className: "text-sm font-semibold text-ui-fg-base", children: "Exposed Zoho Invoice Customizations" }),
1512
+ /* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-subtle", children: "Configure invoice options directly here without needing to log in to Zoho Books." }),
1513
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [
1514
+ /* @__PURE__ */ jsxs("div", { children: [
1515
+ /* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Invoice Number Prefix" }),
1516
+ /* @__PURE__ */ jsx(
1517
+ Input,
1518
+ {
1519
+ value: settings.zoho_invoice_prefix,
1520
+ onChange: (e) => updateSettingField("zoho_invoice_prefix", e.target.value),
1521
+ placeholder: "INV-",
1522
+ size: "small"
1523
+ }
1524
+ )
1525
+ ] }),
1526
+ /* @__PURE__ */ jsxs("div", { children: [
1527
+ /* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Payment Due Terms (Days)" }),
1528
+ /* @__PURE__ */ jsxs(
1529
+ Select,
1530
+ {
1531
+ value: String(settings.zoho_payment_terms_days || 0),
1532
+ onValueChange: (v) => updateSettingField("zoho_payment_terms_days", Number(v)),
1533
+ children: [
1534
+ /* @__PURE__ */ jsx(Select.Trigger, { size: "small", children: /* @__PURE__ */ jsx(Select.Value, {}) }),
1535
+ /* @__PURE__ */ jsxs(Select.Content, { children: [
1536
+ /* @__PURE__ */ jsx(Select.Item, { value: "0", children: "Due on Receipt (Net 0)" }),
1537
+ /* @__PURE__ */ jsx(Select.Item, { value: "7", children: "Net 7 Days" }),
1538
+ /* @__PURE__ */ jsx(Select.Item, { value: "15", children: "Net 15 Days" }),
1539
+ /* @__PURE__ */ jsx(Select.Item, { value: "30", children: "Net 30 Days" }),
1540
+ /* @__PURE__ */ jsx(Select.Item, { value: "60", children: "Net 60 Days" })
1541
+ ] })
1542
+ ]
1543
+ }
1544
+ )
1545
+ ] }),
1546
+ /* @__PURE__ */ jsxs("div", { className: "md:col-span-2 flex items-center justify-between p-3 border border-ui-border-base rounded bg-ui-bg-base", children: [
1547
+ /* @__PURE__ */ jsxs("div", { children: [
1548
+ /* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Embed Payment QR Code on Zoho Invoices" }),
1549
+ /* @__PURE__ */ jsx(Text, { className: "text-[11px] text-ui-fg-subtle", children: "Automatically generate & embed Paystack scan-to-pay QR code on Zoho invoice PDFs." })
1550
+ ] }),
1551
+ /* @__PURE__ */ jsx(
1552
+ Switch,
1553
+ {
1554
+ checked: settings.zoho_include_payment_qr !== false,
1555
+ onCheckedChange: (v) => updateSettingField("zoho_include_payment_qr", v)
1556
+ }
1557
+ )
1558
+ ] }),
1559
+ /* @__PURE__ */ jsxs("div", { children: [
1560
+ /* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Custom Field Name for Payment Link (Optional)" }),
1561
+ /* @__PURE__ */ jsx(
1562
+ Input,
1563
+ {
1564
+ value: settings.zoho_custom_field_payment_link || "",
1565
+ onChange: (e) => updateSettingField("zoho_custom_field_payment_link", e.target.value),
1566
+ placeholder: "Payment Link",
1567
+ size: "small"
1568
+ }
1569
+ )
1570
+ ] }),
1571
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between p-3 border border-ui-border-base rounded bg-ui-bg-base", children: [
1572
+ /* @__PURE__ */ jsxs("div", { children: [
1573
+ /* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Tax Inclusive Treatment" }),
1574
+ /* @__PURE__ */ jsx(Text, { className: "text-[11px] text-ui-fg-subtle", children: "Include taxes in unit prices on Zoho line items." })
1575
+ ] }),
1576
+ /* @__PURE__ */ jsx(
1577
+ Switch,
1578
+ {
1579
+ checked: settings.zoho_tax_inclusive,
1580
+ onCheckedChange: (v) => updateSettingField("zoho_tax_inclusive", v)
1581
+ }
1582
+ )
1583
+ ] }),
1584
+ /* @__PURE__ */ jsxs("div", { className: "md:col-span-2", children: [
1585
+ /* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Default Zoho Customer Notes" }),
1586
+ /* @__PURE__ */ jsx(
1587
+ Textarea,
1588
+ {
1589
+ value: settings.zoho_invoice_notes,
1590
+ onChange: (e) => updateSettingField("zoho_invoice_notes", e.target.value),
1591
+ placeholder: "Thank you for your business. Please retain this invoice for your records.",
1592
+ rows: 2
1593
+ }
1594
+ )
1595
+ ] }),
1596
+ /* @__PURE__ */ jsxs("div", { className: "md:col-span-2", children: [
1597
+ /* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Default Zoho Invoice Terms & Conditions" }),
1598
+ /* @__PURE__ */ jsx(
1599
+ Textarea,
1600
+ {
1601
+ value: settings.zoho_invoice_terms,
1602
+ onChange: (e) => updateSettingField("zoho_invoice_terms", e.target.value),
1603
+ placeholder: "Terms & Conditions printed on all Zoho Invoices.",
1604
+ rows: 2
1605
+ }
1606
+ )
1607
+ ] })
1608
+ ] })
1609
+ ] })
1610
+ ] })
1611
+ ] }),
1612
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-3 mt-4", children: [
1613
+ saveSuccessMsg && /* @__PURE__ */ jsxs("span", { className: "text-xs text-ui-fg-interactive font-medium", children: [
1614
+ "✓ ",
1615
+ saveSuccessMsg
1616
+ ] }),
1617
+ /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: saveSettings, isLoading: isSaving, children: "Save All Settings" })
1618
+ ] })
1619
+ ] }),
1620
+ manualModalOpen && /* @__PURE__ */ jsx(FocusModal, { open: manualModalOpen, onOpenChange: setManualModalOpen, children: /* @__PURE__ */ jsxs(FocusModal.Content, { children: [
1621
+ /* @__PURE__ */ jsx(FocusModal.Header, { children: /* @__PURE__ */ jsx(Heading, { level: "h2", children: "Create Manual Invoice / Document" }) }),
1622
+ /* @__PURE__ */ jsxs(FocusModal.Body, { className: "p-6 flex flex-col gap-6 max-w-2xl mx-auto overflow-y-auto max-h-[80vh]", children: [
1623
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
1624
+ /* @__PURE__ */ jsxs("div", { children: [
1625
+ /* @__PURE__ */ jsx(Label, { className: "text-xs", children: "Document Type" }),
1626
+ /* @__PURE__ */ jsxs(
1627
+ Select,
1628
+ {
1629
+ value: manualForm.type,
1630
+ onValueChange: (v) => setManualForm({ ...manualForm, type: v }),
1631
+ children: [
1632
+ /* @__PURE__ */ jsx(Select.Trigger, { size: "small", children: /* @__PURE__ */ jsx(Select.Value, {}) }),
1633
+ /* @__PURE__ */ jsxs(Select.Content, { children: [
1634
+ /* @__PURE__ */ jsx(Select.Item, { value: "invoice", children: "Tax Invoice" }),
1635
+ /* @__PURE__ */ jsx(Select.Item, { value: "estimate", children: "Estimate / Quote" })
1636
+ ] })
1637
+ ]
1638
+ }
1639
+ )
1640
+ ] }),
1641
+ /* @__PURE__ */ jsxs("div", { children: [
1642
+ /* @__PURE__ */ jsx(Label, { className: "text-xs", children: "Document Title" }),
1643
+ /* @__PURE__ */ jsx(
1644
+ Input,
1645
+ {
1646
+ value: manualForm.title,
1647
+ onChange: (e) => setManualForm({ ...manualForm, title: e.target.value }),
1648
+ size: "small"
1649
+ }
1650
+ )
1651
+ ] }),
1652
+ /* @__PURE__ */ jsxs("div", { children: [
1653
+ /* @__PURE__ */ jsx(Label, { className: "text-xs", children: "Customer Name" }),
1654
+ /* @__PURE__ */ jsx(
1655
+ Input,
1656
+ {
1657
+ value: manualForm.customer_name,
1658
+ onChange: (e) => setManualForm({ ...manualForm, customer_name: e.target.value }),
1659
+ placeholder: "Customer Name",
1660
+ size: "small"
1661
+ }
1662
+ )
1663
+ ] }),
1664
+ /* @__PURE__ */ jsxs("div", { children: [
1665
+ /* @__PURE__ */ jsx(Label, { className: "text-xs", children: "Customer Email" }),
1666
+ /* @__PURE__ */ jsx(
1667
+ Input,
1668
+ {
1669
+ value: manualForm.customer_email,
1670
+ onChange: (e) => setManualForm({ ...manualForm, customer_email: e.target.value }),
1671
+ placeholder: "customer@example.com",
1672
+ size: "small"
1673
+ }
1674
+ )
1675
+ ] }),
1676
+ /* @__PURE__ */ jsxs("div", { children: [
1677
+ /* @__PURE__ */ jsx(Label, { className: "text-xs", children: "Customer Phone" }),
1678
+ /* @__PURE__ */ jsx(
1679
+ Input,
1680
+ {
1681
+ value: manualForm.customer_phone,
1682
+ onChange: (e) => setManualForm({ ...manualForm, customer_phone: e.target.value }),
1683
+ placeholder: "+44 7911 123456",
1684
+ size: "small"
1685
+ }
1686
+ )
1687
+ ] }),
1688
+ /* @__PURE__ */ jsxs("div", { children: [
1689
+ /* @__PURE__ */ jsx(Label, { className: "text-xs", children: "Generation Source" }),
1690
+ /* @__PURE__ */ jsxs(
1691
+ Select,
1692
+ {
1693
+ value: manualForm.force_source,
1694
+ onValueChange: (v) => setManualForm({ ...manualForm, force_source: v }),
1695
+ children: [
1696
+ /* @__PURE__ */ jsx(Select.Trigger, { size: "small", children: /* @__PURE__ */ jsx(Select.Value, {}) }),
1697
+ /* @__PURE__ */ jsxs(Select.Content, { children: [
1698
+ /* @__PURE__ */ jsx(Select.Item, { value: "auto", children: "Auto (Zoho if enabled, else PDFKit)" }),
1699
+ /* @__PURE__ */ jsx(Select.Item, { value: "zoho", children: "Force Zoho Books" }),
1700
+ /* @__PURE__ */ jsx(Select.Item, { value: "pdfkit", children: "Force Local PDFKit" })
1701
+ ] })
1702
+ ]
1703
+ }
1704
+ )
1705
+ ] })
1706
+ ] }),
1707
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
1708
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
1709
+ /* @__PURE__ */ jsx(Label, { className: "text-xs font-semibold", children: "Itemized Line Items" }),
1710
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1711
+ /* @__PURE__ */ jsx(Label, { className: "text-xs text-ui-fg-subtle", children: "Currency:" }),
1712
+ /* @__PURE__ */ jsxs(
1713
+ Select,
1714
+ {
1715
+ value: manualForm.currency_code,
1716
+ onValueChange: (v) => setManualForm({ ...manualForm, currency_code: v }),
1717
+ children: [
1718
+ /* @__PURE__ */ jsx(Select.Trigger, { size: "small", className: "w-24", children: /* @__PURE__ */ jsx(Select.Value, {}) }),
1719
+ /* @__PURE__ */ jsxs(Select.Content, { children: [
1720
+ /* @__PURE__ */ jsx(Select.Item, { value: "usd", children: "USD ($)" }),
1721
+ /* @__PURE__ */ jsx(Select.Item, { value: "gbp", children: "GBP (£)" }),
1722
+ /* @__PURE__ */ jsx(Select.Item, { value: "eur", children: "EUR (€)" }),
1723
+ /* @__PURE__ */ jsx(Select.Item, { value: "kes", children: "KES (KSh)" }),
1724
+ /* @__PURE__ */ jsx(Select.Item, { value: "cad", children: "CAD ($)" }),
1725
+ /* @__PURE__ */ jsx(Select.Item, { value: "aud", children: "AUD ($)" })
1726
+ ] })
1727
+ ]
1728
+ }
1729
+ )
1730
+ ] })
1731
+ ] }),
1732
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-12 gap-2 px-3 py-1.5 bg-ui-bg-subtle rounded border border-ui-border-base text-[11px] font-semibold text-ui-fg-muted uppercase tracking-wider", children: [
1733
+ /* @__PURE__ */ jsx("div", { className: "col-span-6", children: "Description / Item Details" }),
1734
+ /* @__PURE__ */ jsx("div", { className: "col-span-2 text-center", children: "Qty" }),
1735
+ /* @__PURE__ */ jsx("div", { className: "col-span-2 text-right", children: "Unit Price" }),
1736
+ /* @__PURE__ */ jsx("div", { className: "col-span-2 text-right", children: "Total" })
1737
+ ] }),
1738
+ manualForm.items.map((item, idx) => {
1739
+ const lineTotal = (Number(item.quantity) || 0) * (Number(item.unit_price) || 0);
1740
+ return /* @__PURE__ */ jsx(
1741
+ "div",
1742
+ {
1743
+ className: "p-3 border border-ui-border-base rounded-lg bg-ui-bg-base flex flex-col gap-2 relative group hover:border-ui-border-interactive transition-colors",
1744
+ children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-12 gap-2 items-start", children: [
1745
+ /* @__PURE__ */ jsxs("div", { className: "col-span-6 flex flex-col gap-1.5", children: [
1746
+ /* @__PURE__ */ jsxs("div", { children: [
1747
+ /* @__PURE__ */ jsx(Label, { className: "text-[11px] text-ui-fg-subtle mb-0.5", children: "Item Name / Service Title *" }),
1748
+ /* @__PURE__ */ jsx(
1749
+ Input,
1750
+ {
1751
+ placeholder: "e.g. Screen Replacement / Diagnostic",
1752
+ value: item.title,
1753
+ onChange: (e) => {
1754
+ const updated = [...manualForm.items];
1755
+ updated[idx].title = e.target.value;
1756
+ setManualForm({ ...manualForm, items: updated });
1757
+ },
1758
+ size: "small"
1759
+ }
1760
+ )
1761
+ ] }),
1762
+ /* @__PURE__ */ jsxs("div", { children: [
1763
+ /* @__PURE__ */ jsx(Label, { className: "text-[11px] text-ui-fg-subtle mb-0.5", children: "Specifications / Details (Optional)" }),
1764
+ /* @__PURE__ */ jsx(
1765
+ Input,
1766
+ {
1767
+ placeholder: "e.g. OEM grade component, includes installation",
1768
+ value: item.description || "",
1769
+ onChange: (e) => {
1770
+ const updated = [...manualForm.items];
1771
+ updated[idx].description = e.target.value;
1772
+ setManualForm({ ...manualForm, items: updated });
1773
+ },
1774
+ size: "small"
1775
+ }
1776
+ )
1777
+ ] })
1778
+ ] }),
1779
+ /* @__PURE__ */ jsxs("div", { className: "col-span-2 flex flex-col", children: [
1780
+ /* @__PURE__ */ jsx(Label, { className: "text-[11px] text-ui-fg-subtle mb-0.5", children: "Quantity" }),
1781
+ /* @__PURE__ */ jsx(
1782
+ Input,
1783
+ {
1784
+ type: "number",
1785
+ min: "1",
1786
+ step: "1",
1787
+ value: item.quantity,
1788
+ onChange: (e) => {
1789
+ const updated = [...manualForm.items];
1790
+ updated[idx].quantity = Math.max(1, Number(e.target.value) || 1);
1791
+ setManualForm({ ...manualForm, items: updated });
1792
+ },
1793
+ size: "small",
1794
+ className: "text-center font-medium"
1795
+ }
1796
+ )
1797
+ ] }),
1798
+ /* @__PURE__ */ jsxs("div", { className: "col-span-2 flex flex-col", children: [
1799
+ /* @__PURE__ */ jsx(Label, { className: "text-[11px] text-ui-fg-subtle mb-0.5", children: "Unit Price" }),
1800
+ /* @__PURE__ */ jsx(
1801
+ Input,
1802
+ {
1803
+ type: "number",
1804
+ min: "0",
1805
+ step: "0.01",
1806
+ value: item.unit_price,
1807
+ onChange: (e) => {
1808
+ const updated = [...manualForm.items];
1809
+ updated[idx].unit_price = Number(e.target.value);
1810
+ setManualForm({ ...manualForm, items: updated });
1811
+ },
1812
+ size: "small",
1813
+ className: "text-right font-medium"
1814
+ }
1815
+ )
1816
+ ] }),
1817
+ /* @__PURE__ */ jsxs("div", { className: "col-span-2 flex flex-col items-end justify-between self-stretch", children: [
1818
+ /* @__PURE__ */ jsx(Label, { className: "text-[11px] text-ui-fg-subtle mb-0.5", children: "Row Total" }),
1819
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-semibold text-ui-fg-base py-1", children: new Intl.NumberFormat("en-US", {
1820
+ style: "currency",
1821
+ currency: (manualForm.currency_code || "usd").toUpperCase()
1822
+ }).format(lineTotal) }),
1823
+ manualForm.items.length > 1 && /* @__PURE__ */ jsx(
1824
+ "button",
1825
+ {
1826
+ type: "button",
1827
+ onClick: () => {
1828
+ const updated = manualForm.items.filter((_, i) => i !== idx);
1829
+ setManualForm({ ...manualForm, items: updated });
1830
+ },
1831
+ className: "text-ui-fg-muted hover:text-red-500 p-1 rounded hover:bg-ui-bg-subtle transition-colors cursor-pointer",
1832
+ title: "Delete Item",
1833
+ children: /* @__PURE__ */ jsx(Trash, { className: "w-3.5 h-3.5" })
1834
+ }
1835
+ )
1836
+ ] })
1837
+ ] })
1838
+ },
1839
+ idx
1840
+ );
1841
+ }),
1842
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mt-1", children: [
1843
+ /* @__PURE__ */ jsxs(
1844
+ Button,
1845
+ {
1846
+ variant: "secondary",
1847
+ size: "small",
1848
+ className: "text-xs",
1849
+ onClick: () => setManualForm({
1850
+ ...manualForm,
1851
+ items: [
1852
+ ...manualForm.items,
1853
+ { title: "", description: "", quantity: 1, unit_price: 0 }
1854
+ ]
1855
+ }),
1856
+ children: [
1857
+ /* @__PURE__ */ jsx(Plus, { className: "w-3.5 h-3.5 mr-1" }),
1858
+ " Add Line Item"
1859
+ ]
1860
+ }
1861
+ ),
1862
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 bg-ui-bg-subtle px-4 py-2 rounded border border-ui-border-base", children: [
1863
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-ui-fg-subtle font-medium", children: "Document Total:" }),
1864
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-bold text-ui-fg-base", children: new Intl.NumberFormat("en-US", {
1865
+ style: "currency",
1866
+ currency: (manualForm.currency_code || "usd").toUpperCase()
1867
+ }).format(
1868
+ manualForm.items.reduce(
1869
+ (sum, it) => sum + (Number(it.quantity) || 0) * (Number(it.unit_price) || 0),
1870
+ 0
1871
+ )
1872
+ ) })
1873
+ ] })
1874
+ ] })
1875
+ ] }),
1876
+ /* @__PURE__ */ jsxs("div", { children: [
1877
+ /* @__PURE__ */ jsx(Label, { className: "text-xs", children: "Notes / Special Instructions" }),
1878
+ /* @__PURE__ */ jsx(
1879
+ Textarea,
1880
+ {
1881
+ value: manualForm.notes,
1882
+ onChange: (e) => setManualForm({ ...manualForm, notes: e.target.value }),
1883
+ placeholder: "Notes printed on document...",
1884
+ rows: 2
1885
+ }
1886
+ )
1887
+ ] }),
1888
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between p-3 border border-ui-border-base rounded bg-ui-bg-subtle", children: [
1889
+ /* @__PURE__ */ jsxs("div", { children: [
1890
+ /* @__PURE__ */ jsx(Label, { className: "text-xs font-semibold", children: "Auto-Send to Recipient" }),
1891
+ /* @__PURE__ */ jsx(Text, { className: "text-[11px] text-ui-fg-subtle", children: "Send immediately via active notification channels." })
1892
+ ] }),
1893
+ /* @__PURE__ */ jsx(
1894
+ Switch,
1895
+ {
1896
+ checked: manualForm.auto_send,
1897
+ onCheckedChange: (v) => setManualForm({ ...manualForm, auto_send: v })
1898
+ }
1899
+ )
1900
+ ] }),
1901
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2 mt-4", children: [
1902
+ /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => setManualModalOpen(false), children: "Cancel" }),
1903
+ /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: handleCreateManual, isLoading: isGeneratingManual, children: "Generate Document" })
1904
+ ] })
1905
+ ] })
1906
+ ] }) }),
1907
+ customDocModalOpen && /* @__PURE__ */ jsx(FocusModal, { open: customDocModalOpen, onOpenChange: setCustomDocModalOpen, children: /* @__PURE__ */ jsxs(FocusModal.Content, { children: [
1908
+ /* @__PURE__ */ jsx(FocusModal.Header, { children: /* @__PURE__ */ jsx(Heading, { level: "h2", children: "Create Custom Document & Send Email" }) }),
1909
+ /* @__PURE__ */ jsxs(FocusModal.Body, { className: "p-6 flex flex-col gap-6 max-w-2xl mx-auto overflow-y-auto max-h-[80vh]", children: [
1910
+ /* @__PURE__ */ jsx(Text, { className: "text-xs text-ui-fg-subtle", children: "Create a customized document (e.g. Warranty Certificate, Inspection Report, Service Clearance) and directly dispatch via email." }),
1911
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
1912
+ /* @__PURE__ */ jsx(Label, { className: "text-xs font-semibold", children: "Select a Document Preset (Optional)" }),
1913
+ /* @__PURE__ */ jsx(Text, { className: "text-[11px] text-ui-fg-subtle", children: "Pick a pre-configured template below to automatically populate title, certificate text, and itemized points." }),
1914
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 md:grid-cols-3 gap-2 mt-1", children: CUSTOM_DOC_PRESETS.map((preset) => {
1915
+ const isSelected = customDocForm.preset_id === preset.id;
1916
+ return /* @__PURE__ */ jsxs(
1917
+ "button",
1918
+ {
1919
+ type: "button",
1920
+ onClick: () => selectCustomDocPreset(preset.id),
1921
+ className: `p-3 rounded-lg border text-left flex flex-col justify-between transition-all cursor-pointer ${isSelected ? "border-ui-border-interactive bg-ui-bg-interactive-subtle shadow-sm ring-1 ring-ui-border-interactive" : "border-ui-border-base bg-ui-bg-base hover:border-ui-border-strong hover:bg-ui-bg-subtle"}`,
1922
+ children: [
1923
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-1.5", children: [
1924
+ /* @__PURE__ */ jsx("span", { className: "text-xl", children: preset.icon }),
1925
+ /* @__PURE__ */ jsx(Badge, { size: "small", color: isSelected ? "blue" : "grey", children: preset.badge })
1926
+ ] }),
1927
+ /* @__PURE__ */ jsx("div", { className: "text-xs font-semibold text-ui-fg-base leading-snug", children: preset.name })
1928
+ ]
1929
+ },
1930
+ preset.id
1931
+ );
1932
+ }) })
1933
+ ] }),
1934
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
1935
+ /* @__PURE__ */ jsxs("div", { className: "col-span-2", children: [
1936
+ /* @__PURE__ */ jsx(Label, { className: "text-xs font-semibold", children: "Document Title" }),
1937
+ /* @__PURE__ */ jsx(
1938
+ Input,
1939
+ {
1940
+ value: customDocForm.title,
1941
+ onChange: (e) => setCustomDocForm({ ...customDocForm, title: e.target.value }),
1942
+ placeholder: "e.g. Warranty Certificate / Diagnostic Report",
1943
+ size: "small"
1944
+ }
1945
+ )
1946
+ ] }),
1947
+ /* @__PURE__ */ jsxs("div", { children: [
1948
+ /* @__PURE__ */ jsx(Label, { className: "text-xs", children: "Customer Name *" }),
1949
+ /* @__PURE__ */ jsx(
1950
+ Input,
1951
+ {
1952
+ value: customDocForm.customer_name,
1953
+ onChange: (e) => setCustomDocForm({ ...customDocForm, customer_name: e.target.value }),
1954
+ placeholder: "Recipient Name",
1955
+ size: "small"
1956
+ }
1957
+ )
1958
+ ] }),
1959
+ /* @__PURE__ */ jsxs("div", { children: [
1960
+ /* @__PURE__ */ jsx(Label, { className: "text-xs", children: "Customer Email" }),
1961
+ /* @__PURE__ */ jsx(
1962
+ Input,
1963
+ {
1964
+ value: customDocForm.customer_email,
1965
+ onChange: (e) => setCustomDocForm({ ...customDocForm, customer_email: e.target.value }),
1966
+ placeholder: "recipient@example.com",
1967
+ size: "small"
1968
+ }
1969
+ )
1970
+ ] }),
1971
+ /* @__PURE__ */ jsxs("div", { className: "col-span-2", children: [
1972
+ /* @__PURE__ */ jsx(Label, { className: "text-xs", children: "Customer Phone (Optional)" }),
1973
+ /* @__PURE__ */ jsx(
1974
+ Input,
1975
+ {
1976
+ value: customDocForm.customer_phone,
1977
+ onChange: (e) => setCustomDocForm({ ...customDocForm, customer_phone: e.target.value }),
1978
+ placeholder: "+44 7911 123456",
1979
+ size: "small"
1980
+ }
1981
+ )
1982
+ ] })
1983
+ ] }),
1984
+ /* @__PURE__ */ jsxs("div", { children: [
1985
+ /* @__PURE__ */ jsx(Label, { className: "text-xs font-semibold", children: "Document Body / Certificate Details" }),
1986
+ /* @__PURE__ */ jsx(
1987
+ Textarea,
1988
+ {
1989
+ value: customDocForm.body_text,
1990
+ onChange: (e) => setCustomDocForm({ ...customDocForm, body_text: e.target.value }),
1991
+ placeholder: "Enter the main body text or terms to appear on this document...",
1992
+ rows: 4
1993
+ }
1994
+ )
1995
+ ] }),
1996
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
1997
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
1998
+ /* @__PURE__ */ jsx(Label, { className: "text-xs font-semibold", children: "Included Items / Service Specifications (Optional)" }),
1999
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
2000
+ /* @__PURE__ */ jsx(Label, { className: "text-xs text-ui-fg-subtle", children: "Currency:" }),
2001
+ /* @__PURE__ */ jsxs(
2002
+ Select,
2003
+ {
2004
+ value: customDocForm.currency_code,
2005
+ onValueChange: (v) => setCustomDocForm({ ...customDocForm, currency_code: v }),
2006
+ children: [
2007
+ /* @__PURE__ */ jsx(Select.Trigger, { size: "small", className: "w-24", children: /* @__PURE__ */ jsx(Select.Value, {}) }),
2008
+ /* @__PURE__ */ jsxs(Select.Content, { children: [
2009
+ /* @__PURE__ */ jsx(Select.Item, { value: "usd", children: "USD ($)" }),
2010
+ /* @__PURE__ */ jsx(Select.Item, { value: "gbp", children: "GBP (£)" }),
2011
+ /* @__PURE__ */ jsx(Select.Item, { value: "eur", children: "EUR (€)" }),
2012
+ /* @__PURE__ */ jsx(Select.Item, { value: "kes", children: "KES (KSh)" }),
2013
+ /* @__PURE__ */ jsx(Select.Item, { value: "cad", children: "CAD ($)" }),
2014
+ /* @__PURE__ */ jsx(Select.Item, { value: "aud", children: "AUD ($)" })
2015
+ ] })
2016
+ ]
2017
+ }
2018
+ )
2019
+ ] })
2020
+ ] }),
2021
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-12 gap-2 px-3 py-1.5 bg-ui-bg-subtle rounded border border-ui-border-base text-[11px] font-semibold text-ui-fg-muted uppercase tracking-wider", children: [
2022
+ /* @__PURE__ */ jsx("div", { className: "col-span-6", children: "Description / Item Details" }),
2023
+ /* @__PURE__ */ jsx("div", { className: "col-span-2 text-center", children: "Qty" }),
2024
+ /* @__PURE__ */ jsx("div", { className: "col-span-2 text-right", children: "Unit Price" }),
2025
+ /* @__PURE__ */ jsx("div", { className: "col-span-2 text-right", children: "Total" })
2026
+ ] }),
2027
+ customDocForm.items.map((item, idx) => {
2028
+ const lineTotal = (Number(item.quantity) || 0) * (Number(item.unit_price) || 0);
2029
+ return /* @__PURE__ */ jsx(
2030
+ "div",
2031
+ {
2032
+ className: "p-3 border border-ui-border-base rounded-lg bg-ui-bg-base flex flex-col gap-2 relative group hover:border-ui-border-interactive transition-colors",
2033
+ children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-12 gap-2 items-start", children: [
2034
+ /* @__PURE__ */ jsxs("div", { className: "col-span-6 flex flex-col gap-1.5", children: [
2035
+ /* @__PURE__ */ jsxs("div", { children: [
2036
+ /* @__PURE__ */ jsx(Label, { className: "text-[11px] text-ui-fg-subtle mb-0.5", children: "Item Name / Service Title" }),
2037
+ /* @__PURE__ */ jsx(
2038
+ Input,
2039
+ {
2040
+ placeholder: "e.g. Diagnostic / Inspection Finding",
2041
+ value: item.title,
2042
+ onChange: (e) => {
2043
+ const updated = [...customDocForm.items];
2044
+ updated[idx].title = e.target.value;
2045
+ setCustomDocForm({ ...customDocForm, items: updated });
2046
+ },
2047
+ size: "small"
2048
+ }
2049
+ )
2050
+ ] }),
2051
+ /* @__PURE__ */ jsxs("div", { children: [
2052
+ /* @__PURE__ */ jsx(Label, { className: "text-[11px] text-ui-fg-subtle mb-0.5", children: "Details / Specifications (Optional)" }),
2053
+ /* @__PURE__ */ jsx(
2054
+ Input,
2055
+ {
2056
+ placeholder: "e.g. Coverage terms, diagnostic measurement",
2057
+ value: item.description || "",
2058
+ onChange: (e) => {
2059
+ const updated = [...customDocForm.items];
2060
+ updated[idx].description = e.target.value;
2061
+ setCustomDocForm({ ...customDocForm, items: updated });
2062
+ },
2063
+ size: "small"
2064
+ }
2065
+ )
2066
+ ] })
2067
+ ] }),
2068
+ /* @__PURE__ */ jsxs("div", { className: "col-span-2 flex flex-col", children: [
2069
+ /* @__PURE__ */ jsx(Label, { className: "text-[11px] text-ui-fg-subtle mb-0.5", children: "Quantity" }),
2070
+ /* @__PURE__ */ jsx(
2071
+ Input,
2072
+ {
2073
+ type: "number",
2074
+ min: "1",
2075
+ step: "1",
2076
+ value: item.quantity,
2077
+ onChange: (e) => {
2078
+ const updated = [...customDocForm.items];
2079
+ updated[idx].quantity = Math.max(1, Number(e.target.value) || 1);
2080
+ setCustomDocForm({ ...customDocForm, items: updated });
2081
+ },
2082
+ size: "small",
2083
+ className: "text-center font-medium"
2084
+ }
2085
+ )
2086
+ ] }),
2087
+ /* @__PURE__ */ jsxs("div", { className: "col-span-2 flex flex-col", children: [
2088
+ /* @__PURE__ */ jsx(Label, { className: "text-[11px] text-ui-fg-subtle mb-0.5", children: "Unit Price" }),
2089
+ /* @__PURE__ */ jsx(
2090
+ Input,
2091
+ {
2092
+ type: "number",
2093
+ min: "0",
2094
+ step: "0.01",
2095
+ value: item.unit_price,
2096
+ onChange: (e) => {
2097
+ const updated = [...customDocForm.items];
2098
+ updated[idx].unit_price = Number(e.target.value);
2099
+ setCustomDocForm({ ...customDocForm, items: updated });
2100
+ },
2101
+ size: "small",
2102
+ className: "text-right font-medium"
2103
+ }
2104
+ )
2105
+ ] }),
2106
+ /* @__PURE__ */ jsxs("div", { className: "col-span-2 flex flex-col items-end justify-between self-stretch", children: [
2107
+ /* @__PURE__ */ jsx(Label, { className: "text-[11px] text-ui-fg-subtle mb-0.5", children: "Row Total" }),
2108
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-semibold text-ui-fg-base py-1", children: new Intl.NumberFormat("en-US", {
2109
+ style: "currency",
2110
+ currency: (customDocForm.currency_code || "usd").toUpperCase()
2111
+ }).format(lineTotal) }),
2112
+ customDocForm.items.length > 1 && /* @__PURE__ */ jsx(
2113
+ "button",
2114
+ {
2115
+ type: "button",
2116
+ onClick: () => {
2117
+ const updated = customDocForm.items.filter((_, i) => i !== idx);
2118
+ setCustomDocForm({ ...customDocForm, items: updated });
2119
+ },
2120
+ className: "text-ui-fg-muted hover:text-red-500 p-1 rounded hover:bg-ui-bg-subtle transition-colors cursor-pointer",
2121
+ title: "Delete Item",
2122
+ children: /* @__PURE__ */ jsx(Trash, { className: "w-3.5 h-3.5" })
2123
+ }
2124
+ )
2125
+ ] })
2126
+ ] })
2127
+ },
2128
+ idx
2129
+ );
2130
+ }),
2131
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mt-1", children: [
2132
+ /* @__PURE__ */ jsxs(
2133
+ Button,
2134
+ {
2135
+ variant: "secondary",
2136
+ size: "small",
2137
+ className: "text-xs",
2138
+ onClick: () => setCustomDocForm({
2139
+ ...customDocForm,
2140
+ items: [
2141
+ ...customDocForm.items,
2142
+ { title: "", description: "", quantity: 1, unit_price: 0 }
2143
+ ]
2144
+ }),
2145
+ children: [
2146
+ /* @__PURE__ */ jsx(Plus, { className: "w-3.5 h-3.5 mr-1" }),
2147
+ " Add Line Item"
2148
+ ]
2149
+ }
2150
+ ),
2151
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 bg-ui-bg-subtle px-4 py-2 rounded border border-ui-border-base", children: [
2152
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-ui-fg-subtle font-medium", children: "Document Total:" }),
2153
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-bold text-ui-fg-base", children: new Intl.NumberFormat("en-US", {
2154
+ style: "currency",
2155
+ currency: (customDocForm.currency_code || "usd").toUpperCase()
2156
+ }).format(
2157
+ customDocForm.items.reduce(
2158
+ (sum, it) => sum + (Number(it.quantity) || 0) * (Number(it.unit_price) || 0),
2159
+ 0
2160
+ )
2161
+ ) })
2162
+ ] })
2163
+ ] })
2164
+ ] }),
2165
+ /* @__PURE__ */ jsxs("div", { children: [
2166
+ /* @__PURE__ */ jsx(Label, { className: "text-xs font-semibold", children: "Email Subject" }),
2167
+ /* @__PURE__ */ jsx(
2168
+ Input,
2169
+ {
2170
+ value: customDocForm.email_subject,
2171
+ onChange: (e) => setCustomDocForm({ ...customDocForm, email_subject: e.target.value }),
2172
+ placeholder: "Email Subject",
2173
+ size: "small"
2174
+ }
2175
+ )
2176
+ ] }),
2177
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between p-3 border border-ui-border-base rounded bg-ui-bg-subtle", children: [
2178
+ /* @__PURE__ */ jsxs("div", { children: [
2179
+ /* @__PURE__ */ jsx(Label, { className: "text-xs font-semibold", children: "Send via Email Immediately" }),
2180
+ /* @__PURE__ */ jsx(Text, { className: "text-[11px] text-ui-fg-subtle", children: "Dispatches document PDF link and message via Medusa notification provider." })
2181
+ ] }),
2182
+ /* @__PURE__ */ jsx(
2183
+ Switch,
2184
+ {
2185
+ checked: customDocForm.send_email_now,
2186
+ onCheckedChange: (v) => setCustomDocForm({ ...customDocForm, send_email_now: v })
2187
+ }
2188
+ )
2189
+ ] }),
2190
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2 mt-4", children: [
2191
+ /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => setCustomDocModalOpen(false), children: "Cancel" }),
2192
+ /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: handleCreateCustomDoc, isLoading: isGeneratingCustom, children: "Generate & Deliver" })
2193
+ ] })
2194
+ ] })
2195
+ ] }) }),
2196
+ sendModalOpen && selectedDoc && /* @__PURE__ */ jsx(FocusModal, { open: sendModalOpen, onOpenChange: setSendModalOpen, children: /* @__PURE__ */ jsxs(FocusModal.Content, { children: [
2197
+ /* @__PURE__ */ jsx(FocusModal.Header, { children: /* @__PURE__ */ jsx(Heading, { level: "h2", children: "Dispatch Document Notification" }) }),
2198
+ /* @__PURE__ */ jsxs(FocusModal.Body, { className: "p-6 flex flex-col gap-5 max-w-lg mx-auto", children: [
2199
+ /* @__PURE__ */ jsxs("div", { children: [
2200
+ /* @__PURE__ */ jsxs(Text, { className: "text-sm font-semibold", children: [
2201
+ selectedDoc.title,
2202
+ " #",
2203
+ selectedDoc.display_id
2204
+ ] }),
2205
+ /* @__PURE__ */ jsxs(Text, { className: "text-xs text-ui-fg-subtle", children: [
2206
+ "Recipient: ",
2207
+ selectedDoc.customer_name,
2208
+ " (",
2209
+ selectedDoc.customer_email || selectedDoc.customer_phone || "No contact info",
2210
+ ")"
2211
+ ] })
2212
+ ] }),
2213
+ /* @__PURE__ */ jsxs("div", { children: [
2214
+ /* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Select Channels" }),
2215
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-4 mt-2", children: [
2216
+ /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-xs", children: [
2217
+ /* @__PURE__ */ jsx(
2218
+ "input",
2219
+ {
2220
+ type: "checkbox",
2221
+ checked: sendForm.channels.includes("email"),
2222
+ onChange: (e) => {
2223
+ const next = e.target.checked ? [...sendForm.channels, "email"] : sendForm.channels.filter((c) => c !== "email");
2224
+ setSendForm({ ...sendForm, channels: next });
2225
+ }
2226
+ }
2227
+ ),
2228
+ "Email"
2229
+ ] }),
2230
+ /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-xs", children: [
2231
+ /* @__PURE__ */ jsx(
2232
+ "input",
2233
+ {
2234
+ type: "checkbox",
2235
+ checked: sendForm.channels.includes("sms"),
2236
+ onChange: (e) => {
2237
+ const next = e.target.checked ? [...sendForm.channels, "sms"] : sendForm.channels.filter((c) => c !== "sms");
2238
+ setSendForm({ ...sendForm, channels: next });
2239
+ }
2240
+ }
2241
+ ),
2242
+ "SMS"
2243
+ ] }),
2244
+ /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-xs", children: [
2245
+ /* @__PURE__ */ jsx(
2246
+ "input",
2247
+ {
2248
+ type: "checkbox",
2249
+ checked: sendForm.channels.includes("whatsapp"),
2250
+ onChange: (e) => {
2251
+ const next = e.target.checked ? [...sendForm.channels, "whatsapp"] : sendForm.channels.filter((c) => c !== "whatsapp");
2252
+ setSendForm({ ...sendForm, channels: next });
2253
+ }
2254
+ }
2255
+ ),
2256
+ "WhatsApp"
2257
+ ] })
2258
+ ] })
2259
+ ] }),
2260
+ /* @__PURE__ */ jsxs("div", { children: [
2261
+ /* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Custom Email / Text Message (Optional)" }),
2262
+ /* @__PURE__ */ jsx(
2263
+ Textarea,
2264
+ {
2265
+ value: sendForm.custom_message,
2266
+ onChange: (e) => setSendForm({ ...sendForm, custom_message: e.target.value }),
2267
+ placeholder: "Add a personalized message to the notification...",
2268
+ rows: 3
2269
+ }
2270
+ )
2271
+ ] }),
2272
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2 mt-4", children: [
2273
+ /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => setSendModalOpen(false), children: "Cancel" }),
2274
+ /* @__PURE__ */ jsx(Button, { variant: "primary", onClick: handleSendNotification, children: "Dispatch Now" })
2275
+ ] })
2276
+ ] })
2277
+ ] }) }),
2278
+ previewModalOpen && /* @__PURE__ */ jsx(FocusModal, { open: previewModalOpen, onOpenChange: setPreviewModalOpen, children: /* @__PURE__ */ jsxs(FocusModal.Content, { children: [
2279
+ /* @__PURE__ */ jsxs(FocusModal.Header, { className: "flex items-center justify-between px-6 py-4", children: [
2280
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
2281
+ /* @__PURE__ */ jsx(Heading, { level: "h2", className: "text-base font-semibold", children: "Template Live Preview" }),
2282
+ /* @__PURE__ */ jsx(Badge, { color: "blue", size: "small", children: previewStyle.toUpperCase() }),
2283
+ /* @__PURE__ */ jsx(Badge, { color: "grey", size: "small", children: previewType.toUpperCase() })
2284
+ ] }),
2285
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
2286
+ /* @__PURE__ */ jsx(
2287
+ Button,
2288
+ {
2289
+ variant: "secondary",
2290
+ size: "small",
2291
+ onClick: handleOpenPreviewNewTab,
2292
+ children: "Open in New Window"
2293
+ }
2294
+ ),
2295
+ /* @__PURE__ */ jsxs(
2296
+ Button,
2297
+ {
2298
+ variant: "secondary",
2299
+ size: "small",
2300
+ onClick: handleDownloadPreview,
2301
+ disabled: !previewBlobUrl,
2302
+ children: [
2303
+ /* @__PURE__ */ jsx(ArrowDownTray, { className: "w-3.5 h-3.5 mr-1" }),
2304
+ "Download PDF"
2305
+ ]
2306
+ }
2307
+ ),
2308
+ /* @__PURE__ */ jsx(
2309
+ Button,
2310
+ {
2311
+ variant: "secondary",
2312
+ size: "small",
2313
+ onClick: () => setPreviewModalOpen(false),
2314
+ children: "Close"
2315
+ }
2316
+ )
2317
+ ] })
2318
+ ] }),
2319
+ /* @__PURE__ */ jsxs(FocusModal.Body, { className: "p-6 flex flex-col gap-4 max-w-5xl mx-auto h-[82vh]", children: [
2320
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-4 p-3 bg-ui-bg-subtle border border-ui-border-base rounded-lg", children: [
2321
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
2322
+ /* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Style:" }),
2323
+ /* @__PURE__ */ jsxs(Select, { value: previewStyle, onValueChange: (v) => switchPreview(v, previewType), children: [
2324
+ /* @__PURE__ */ jsx(Select.Trigger, { size: "small", className: "w-[180px]", children: /* @__PURE__ */ jsx(Select.Value, {}) }),
2325
+ /* @__PURE__ */ jsxs(Select.Content, { children: [
2326
+ /* @__PURE__ */ jsx(Select.Item, { value: "modern", children: "Modern Minimalist" }),
2327
+ /* @__PURE__ */ jsx(Select.Item, { value: "classic", children: "Classic Corporate" }),
2328
+ /* @__PURE__ */ jsx(Select.Item, { value: "minimal", children: "Clean Tech Monospace" })
2329
+ ] })
2330
+ ] })
2331
+ ] }),
2332
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
2333
+ /* @__PURE__ */ jsx(Label, { className: "text-xs font-medium", children: "Document Type:" }),
2334
+ /* @__PURE__ */ jsxs(Select, { value: previewType, onValueChange: (v) => switchPreview(previewStyle, v), children: [
2335
+ /* @__PURE__ */ jsx(Select.Trigger, { size: "small", className: "w-[190px]", children: /* @__PURE__ */ jsx(Select.Value, {}) }),
2336
+ /* @__PURE__ */ jsxs(Select.Content, { children: [
2337
+ /* @__PURE__ */ jsx(Select.Item, { value: "invoice", children: "Tax Invoice" }),
2338
+ /* @__PURE__ */ jsx(Select.Item, { value: "receipt", children: "Payment Receipt" }),
2339
+ /* @__PURE__ */ jsx(Select.Item, { value: "packing_slip", children: "Packing Slip" }),
2340
+ /* @__PURE__ */ jsx(Select.Item, { value: "estimate", children: "Estimate / Quote" }),
2341
+ /* @__PURE__ */ jsx(Select.Item, { value: "custom", children: "Custom Document" }),
2342
+ /* @__PURE__ */ jsx(Select.Item, { value: "job_card", children: "Repair Job Card" })
2343
+ ] })
2344
+ ] })
2345
+ ] }),
2346
+ /* @__PURE__ */ jsxs(
2347
+ Button,
2348
+ {
2349
+ variant: "secondary",
2350
+ size: "small",
2351
+ onClick: () => switchPreview(previewStyle, previewType),
2352
+ isLoading: isPreviewModalLoading,
2353
+ children: [
2354
+ /* @__PURE__ */ jsx(ArrowPath, { className: "w-3.5 h-3.5 mr-1" }),
2355
+ " Refresh Preview"
2356
+ ]
2357
+ }
2358
+ )
2359
+ ] }),
2360
+ /* @__PURE__ */ jsx("div", { className: "flex-1 w-full bg-ui-bg-subtle border border-ui-border-base rounded-lg overflow-hidden flex items-center justify-center relative min-h-[500px]", children: isPreviewModalLoading ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-3 text-ui-fg-subtle", children: [
2361
+ /* @__PURE__ */ jsx(ArrowPath, { className: "w-6 h-6 animate-spin text-ui-fg-interactive" }),
2362
+ /* @__PURE__ */ jsx(Text, { className: "text-xs", children: "Rendering live template preview..." })
2363
+ ] }) : previewBlobUrl ? /* @__PURE__ */ jsx(
2364
+ "iframe",
2365
+ {
2366
+ src: previewBlobUrl,
2367
+ className: "w-full h-full border-0 rounded-lg",
2368
+ title: "Live Template Preview"
2369
+ }
2370
+ ) : /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2 text-ui-fg-error", children: [
2371
+ /* @__PURE__ */ jsx(Text, { className: "text-xs font-medium", children: "Failed to generate PDF preview." }),
2372
+ /* @__PURE__ */ jsx(
2373
+ Button,
2374
+ {
2375
+ variant: "secondary",
2376
+ size: "small",
2377
+ onClick: () => switchPreview(previewStyle, previewType),
2378
+ children: "Try Again"
2379
+ }
2380
+ )
2381
+ ] }) })
2382
+ ] })
2383
+ ] }) })
2384
+ ] });
2385
+ };
2386
+ const config = defineRouteConfig({
2387
+ label: "Documents",
2388
+ icon: DocumentText
2389
+ });
2390
+ const widgetModule = { widgets: [] };
2391
+ const routeModule = {
2392
+ routes: [
2393
+ {
2394
+ Component: DocumentsPage,
2395
+ path: "/documents"
2396
+ }
2397
+ ]
2398
+ };
2399
+ const menuItemModule = {
2400
+ menuItems: [
2401
+ {
2402
+ label: config.label,
2403
+ icon: config.icon,
2404
+ path: "/documents",
2405
+ nested: void 0,
2406
+ rank: void 0,
2407
+ translationNs: void 0
2408
+ }
2409
+ ]
2410
+ };
2411
+ const formModule = { customFields: {} };
2412
+ const displayModule = {
2413
+ displays: {}
2414
+ };
2415
+ const i18nModule = { resources: {} };
2416
+ const layoutModule = { layouts: [] };
2417
+ const plugin = {
2418
+ widgetModule,
2419
+ routeModule,
2420
+ menuItemModule,
2421
+ formModule,
2422
+ displayModule,
2423
+ i18nModule,
2424
+ layoutModule
2425
+ };
2426
+ export {
2427
+ plugin as default
2428
+ };