@infuro/cms-core 1.0.45 → 1.0.46

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 (65) hide show
  1. package/README.md +19 -2
  2. package/dist/admin.cjs +873 -214
  3. package/dist/admin.d.cts +7 -1
  4. package/dist/admin.d.ts +7 -1
  5. package/dist/admin.js +874 -215
  6. package/dist/api.cjs +40 -37
  7. package/dist/api.d.cts +1 -1
  8. package/dist/api.d.ts +1 -1
  9. package/dist/api.js +8 -5
  10. package/dist/auth.cjs +23 -23
  11. package/dist/auth.d.cts +1 -0
  12. package/dist/auth.d.ts +1 -0
  13. package/dist/auth.js +2 -2
  14. package/dist/chunk-2KUCQVAQ.js +936 -0
  15. package/dist/chunk-3K5AIEIZ.js +256 -0
  16. package/dist/{chunk-I6NH72MO.js → chunk-57O3HZPG.js} +9 -1
  17. package/dist/chunk-7PMHZRF3.cjs +872 -0
  18. package/dist/chunk-BXYZDMTZ.cjs +953 -0
  19. package/dist/chunk-CQHXW4TR.js +107 -0
  20. package/dist/{chunk-NNQBWDCI.js → chunk-CRYKVJTO.js} +55 -959
  21. package/dist/chunk-DBPSJYLZ.js +47 -0
  22. package/dist/{chunk-TAHX46EI.cjs → chunk-FBKDMRQL.cjs} +9 -1
  23. package/dist/chunk-GUSHM5HN.js +862 -0
  24. package/dist/chunk-HY3AXLOI.cjs +265 -0
  25. package/dist/chunk-L3525VXI.js +243 -0
  26. package/dist/{chunk-ZMRQ72F6.cjs → chunk-NBY4NVTY.cjs} +3 -3
  27. package/dist/chunk-OY2YTBMP.cjs +50 -0
  28. package/dist/{chunk-BLR6H5GL.js → chunk-SF2XKMCI.js} +3 -3
  29. package/dist/{chunk-22FFHLTO.cjs → chunk-TCSGFAWB.cjs} +56 -970
  30. package/dist/{chunk-F5XFHYTG.cjs → chunk-UDVLFVEC.cjs} +661 -382
  31. package/dist/{chunk-MVXLRANV.js → chunk-UKC3HYXI.js} +591 -323
  32. package/dist/chunk-V25RDUOU.cjs +248 -0
  33. package/dist/chunk-XMRMZ6NQ.cjs +109 -0
  34. package/dist/cli.cjs +9 -4
  35. package/dist/cli.js +9 -4
  36. package/dist/{email-queue-TPZWLTIV.cjs → email-queue-6NJY6HNM.cjs} +7 -5
  37. package/dist/email-queue-OI2HSCGE.js +4 -0
  38. package/dist/erp-order-invoice-3GXDE443.js +3 -0
  39. package/dist/erp-order-invoice-EYYNR526.cjs +24 -0
  40. package/dist/index.cjs +391 -364
  41. package/dist/index.d.cts +267 -14
  42. package/dist/index.d.ts +267 -14
  43. package/dist/index.js +12 -110
  44. package/dist/migrations/1781810000000-OrderItemsVariantId.ts +44 -0
  45. package/dist/migrations/1781900000000-UserInviteStatusToken.ts +46 -0
  46. package/dist/migrations/1782000000000-ComboSlug.ts +58 -0
  47. package/dist/migrations/1782100000000-DiscountDeviceType.ts +20 -0
  48. package/dist/order-inventory-2MYRKEPC.cjs +39 -0
  49. package/dist/order-inventory-76V4XIGW.js +2 -0
  50. package/dist/order-notification-dispatcher-SBQAMM5V.cjs +21 -0
  51. package/dist/{order-notification-dispatcher-XWIJYDGA.js → order-notification-dispatcher-ZJZB2HUN.js} +5 -2
  52. package/dist/retire-soft-deleted-unique-5VXBA5XX.cjs +15 -0
  53. package/dist/retire-soft-deleted-unique-NXQIH4BC.js +2 -0
  54. package/dist/send-order-placed-emails-B5ZVJT7T.cjs +15 -0
  55. package/dist/send-order-placed-emails-WPI37KRZ.js +6 -0
  56. package/package.json +5 -4
  57. package/src/admin/admin.css +27 -24
  58. package/dist/chunk-5ELSW2UP.js +0 -150
  59. package/dist/chunk-PNOKNSG2.cjs +0 -222
  60. package/dist/chunk-WEMDMVHQ.js +0 -216
  61. package/dist/chunk-XW5ATPRW.cjs +0 -155
  62. package/dist/email-queue-CGZBVVAS.js +0 -2
  63. package/dist/erp-order-invoice-3YISSOWW.js +0 -3
  64. package/dist/erp-order-invoice-ZR5F2KTA.cjs +0 -12
  65. package/dist/order-notification-dispatcher-RU7BTGGX.cjs +0 -18
package/dist/admin.js CHANGED
@@ -10,7 +10,7 @@ import { Slot } from '@radix-ui/react-slot';
10
10
  import { cva } from 'class-variance-authority';
11
11
  import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
12
12
  import * as LucideIcons from 'lucide-react';
13
- import { ChevronDown, User, Settings, LogOut, LayoutDashboard, Store, FolderTree, Layers, Building2, CalendarDays, ShoppingBag, Package, Receipt, BadgePercent, ShoppingCart, CreditCard, Users, Inbox, File, LinkIcon, ClipboardList, MessageSquare, Image as Image$1, FileText, Shield, Puzzle, X, Plus, MoreVertical, Upload, Download, Edit, Copy, RefreshCw, Trash2, Save, Check, Search, AlertCircle, MapPin, BarChart3, TrendingUp, UserCheck, Activity, Globe, Eye, MousePointer, ArrowLeftRight, RotateCcw, KeyRound, Loader2, CalendarClock, Rss, ArrowLeft, Pencil, FolderPlus, LayoutGrid, List, Move, Archive, Edit2, ExternalLink, Power, Star, ChevronUp, Mail, Zap, Filter, CheckCircle2, ImageIcon, GripVertical, ChevronRight, ArrowRight, ArrowUpRight, IndianRupee, XCircle, Clock, Play, MessageCircle, Bot, FileUp, Tag, Box, SlidersHorizontal, Calculator, Link2 as Link2$1, Unlink, Gift, MoreHorizontal, Bell, QrCode, Car, Circle, Settings2, DollarSign, Hash, ChevronLeft, Share2, Smartphone, HardDrive, Folder, Film } from 'lucide-react';
13
+ import { ChevronDown, User, Settings, LogOut, LayoutDashboard, Store, FolderTree, Layers, Building2, CalendarDays, ShoppingBag, Package, Receipt, BadgePercent, ShoppingCart, CreditCard, Users, Inbox, File, LinkIcon, ClipboardList, MessageSquare, Image as Image$1, FileText, Shield, Puzzle, X, Plus, MoreVertical, Upload, Download, Edit, Copy, RefreshCw, Trash2, Mail, Check, Save, Search, AlertCircle, MapPin, BarChart3, TrendingUp, UserCheck, Activity, Globe, Eye, MousePointer, ArrowLeftRight, RotateCcw, KeyRound, Loader2, CalendarClock, Rss, ArrowLeft, Pencil, FolderPlus, LayoutGrid, List, Move, Archive, Edit2, ExternalLink, Power, Star, ChevronUp, Zap, Filter, CheckCircle2, ImageIcon, GripVertical, ChevronRight, ArrowRight, ArrowUpRight, IndianRupee, XCircle, Clock, Play, MessageCircle, Bot, FileUp, Tag, Box, SlidersHorizontal, Calculator, Link2 as Link2$1, Unlink, Gift, MoreHorizontal, Bell, QrCode, Car, Circle, Settings2, DollarSign, Hash, ChevronLeft, Share2, Smartphone, HardDrive, Folder, Film } from 'lucide-react';
14
14
  import Image from 'next/image';
15
15
  import Link2 from 'next/link';
16
16
  import { usePathname, useSearchParams, useRouter } from 'next/navigation';
@@ -459,7 +459,7 @@ var init_admin_config_context = __esm({
459
459
  var CMS_VERSION;
460
460
  var init_cms_version = __esm({
461
461
  "src/lib/cms-version.ts"() {
462
- CMS_VERSION = "1.0.45" ;
462
+ CMS_VERSION = "1.0.46" ;
463
463
  }
464
464
  });
465
465
  function useCatalogCategories(enabled = true) {
@@ -1061,8 +1061,10 @@ var init_admin_theme = __esm({
1061
1061
  "src/admin/admin-theme.ts"() {
1062
1062
  ADMIN_THEME_CSS = `
1063
1063
  @import url("https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap");
1064
+ html{color-scheme:light}
1064
1065
  :root{--background:0 0% 100%;--foreground:0 0% 9%;--card:0 0% 100%;--card-foreground:0 0% 9%;--popover:0 0% 100%;--popover-foreground:0 0% 9%;--primary:0 0% 9%;--primary-foreground:0 0% 98%;--secondary:0 0% 96.1%;--secondary-foreground:0 0% 9%;--muted:0 0% 96.1%;--muted-foreground:0 0% 45.1%;--accent:0 0% 96.1%;--accent-foreground:0 0% 9%;--destructive:0 84.2% 60.2%;--destructive-foreground:0 0% 98%;--border:0 0% 89.8%;--input:0 0% 89.8%;--ring:0 0% 3.9%;--chart-1:0 0% 40%;--chart-2:0 0% 55%;--chart-3:0 0% 70%;--chart-4:0 0% 45%;--chart-5:0 0% 60%;--radius:0.375rem;--sidebar-background:0 0% 100%;--sidebar-foreground:0 0% 9%;--sidebar-primary:0 0% 9%;--sidebar-primary-foreground:0 0% 98%;--sidebar-accent:0 0% 96.1%;--sidebar-accent-foreground:0 0% 9%;--sidebar-border:0 0% 89.8%;--sidebar-ring:0 0% 9%}
1065
- .dark{--background:0 0% 3.9%;--foreground:0 0% 98%;--card:0 0% 3.9%;--card-foreground:0 0% 98%;--primary:0 0% 98%;--primary-foreground:0 0% 9%;--secondary:0 0% 14.9%;--secondary-foreground:0 0% 98%;--muted:0 0% 14.9%;--muted-foreground:0 0% 63.9%;--border:0 0% 14.9%;--input:0 0% 14.9%;--ring:0 0% 83.1%;--sidebar-background:0 0% 9%;--sidebar-foreground:0 0% 98%;--sidebar-primary:0 0% 98%;--sidebar-primary-foreground:0 0% 9%;--sidebar-accent:0 0% 14.9%;--sidebar-accent-foreground:0 0% 98%;--sidebar-border:0 0% 14.9%;--sidebar-ring:0 0% 83.1%}
1066
+ /* Dark mode disabled: keep light tokens even if a host app adds .dark on <html> */
1067
+ .dark{--background:0 0% 100%;--foreground:0 0% 9%;--card:0 0% 100%;--card-foreground:0 0% 9%;--popover:0 0% 100%;--popover-foreground:0 0% 9%;--primary:0 0% 9%;--primary-foreground:0 0% 98%;--secondary:0 0% 96.1%;--secondary-foreground:0 0% 9%;--muted:0 0% 96.1%;--muted-foreground:0 0% 45.1%;--accent:0 0% 96.1%;--accent-foreground:0 0% 9%;--destructive:0 84.2% 60.2%;--destructive-foreground:0 0% 98%;--border:0 0% 89.8%;--input:0 0% 89.8%;--ring:0 0% 3.9%;--sidebar-background:0 0% 100%;--sidebar-foreground:0 0% 9%;--sidebar-primary:0 0% 9%;--sidebar-primary-foreground:0 0% 98%;--sidebar-accent:0 0% 96.1%;--sidebar-accent-foreground:0 0% 9%;--sidebar-border:0 0% 89.8%;--sidebar-ring:0 0% 9%}
1066
1068
  *,*::before,*::after{border-color:hsl(var(--border))}
1067
1069
  body{font-family:"Inter",ui-sans-serif,system-ui,sans-serif;font-size:14px}
1068
1070
  .admin-app{font-size:13.5px}
@@ -1177,6 +1179,39 @@ var init_auth_debug = __esm({
1177
1179
  __name(summarizeSessionUserForLog, "summarizeSessionUserForLog");
1178
1180
  }
1179
1181
  });
1182
+ function useForceAdminLightMode() {
1183
+ useEffect(() => {
1184
+ const root = document.documentElement;
1185
+ const hadDark = root.classList.contains("dark");
1186
+ const prevColorScheme = root.style.colorScheme;
1187
+ const applyLight = /* @__PURE__ */ __name(() => {
1188
+ root.classList.remove("dark");
1189
+ root.style.colorScheme = "light";
1190
+ }, "applyLight");
1191
+ applyLight();
1192
+ const observer = new MutationObserver(() => {
1193
+ if (root.classList.contains("dark")) applyLight();
1194
+ });
1195
+ observer.observe(root, {
1196
+ attributes: true,
1197
+ attributeFilter: [
1198
+ "class"
1199
+ ]
1200
+ });
1201
+ return () => {
1202
+ observer.disconnect();
1203
+ root.style.colorScheme = prevColorScheme;
1204
+ if (hadDark) root.classList.add("dark");
1205
+ else root.classList.remove("dark");
1206
+ };
1207
+ }, []);
1208
+ }
1209
+ var init_force_light_mode = __esm({
1210
+ "src/admin/force-light-mode.ts"() {
1211
+ "use client";
1212
+ __name(useForceAdminLightMode, "useForceAdminLightMode");
1213
+ }
1214
+ });
1180
1215
  function useAdminViewSettings() {
1181
1216
  useEffect(() => {
1182
1217
  fetch("/api/settings/admin_view").then((r) => r.ok ? r.json() : null).then((data) => {
@@ -1198,6 +1233,7 @@ function AdminLayoutInner({ children }) {
1198
1233
  const isMobile = useIsMobile();
1199
1234
  const vendorBlockRedirectRef = useRef(false);
1200
1235
  useAdminViewSettings();
1236
+ useForceAdminLightMode();
1201
1237
  const isPublicPath = PUBLIC_ADMIN_PATHS.includes(pathname);
1202
1238
  const isVendorOnlySession = session?.user?.isVendorPortal === true && session?.user?.isRBACAdmin !== true;
1203
1239
  useEffect(() => {
@@ -1486,6 +1522,7 @@ var init_AdminLayout = __esm({
1486
1522
  init_admin_config_context();
1487
1523
  init_builtin_plugin_descriptors();
1488
1524
  init_auth_debug();
1525
+ init_force_light_mode();
1489
1526
  PUBLIC_ADMIN_PATHS = [
1490
1527
  "/admin/signin",
1491
1528
  "/admin/forgot-password",
@@ -1736,6 +1773,225 @@ var init_file_upload = __esm({
1736
1773
  __name(FileUpload, "FileUpload");
1737
1774
  }
1738
1775
  });
1776
+
1777
+ // src/lib/media-url.ts
1778
+ function isVideoUploadMime(mime) {
1779
+ const t = String(mime ?? "").trim().toLowerCase();
1780
+ return VIDEO_UPLOAD_MIME_TYPES.includes(t);
1781
+ }
1782
+ function isVideoMediaUrl(url) {
1783
+ if (!url || typeof url !== "string") return false;
1784
+ const trimmed = url.trim();
1785
+ if (!trimmed) return false;
1786
+ try {
1787
+ if (/^https?:\/\//i.test(trimmed)) {
1788
+ return VIDEO_EXT_RE.test(new URL(trimmed).pathname);
1789
+ }
1790
+ } catch {
1791
+ }
1792
+ const path = trimmed.split("?")[0]?.split("#")[0] ?? trimmed;
1793
+ return VIDEO_EXT_RE.test(path);
1794
+ }
1795
+ var VIDEO_EXT_RE, IMAGE_UPLOAD_MIME_TYPES, VIDEO_UPLOAD_MIME_TYPES, MEDIA_UPLOAD_MIME_TYPES, VIDEO_UPLOAD_MAX_BYTES;
1796
+ var init_media_url = __esm({
1797
+ "src/lib/media-url.ts"() {
1798
+ VIDEO_EXT_RE = /\.(mp4|webm|mov)(?:$|[?#])/i;
1799
+ IMAGE_UPLOAD_MIME_TYPES = [
1800
+ "image/jpeg",
1801
+ "image/png",
1802
+ "image/gif",
1803
+ "image/webp"
1804
+ ];
1805
+ VIDEO_UPLOAD_MIME_TYPES = [
1806
+ "video/mp4",
1807
+ "video/webm",
1808
+ "video/quicktime"
1809
+ ];
1810
+ MEDIA_UPLOAD_MIME_TYPES = [
1811
+ ...IMAGE_UPLOAD_MIME_TYPES,
1812
+ ...VIDEO_UPLOAD_MIME_TYPES
1813
+ ];
1814
+ VIDEO_UPLOAD_MAX_BYTES = 100 * 1024 * 1024;
1815
+ __name(isVideoUploadMime, "isVideoUploadMime");
1816
+ __name(isVideoMediaUrl, "isVideoMediaUrl");
1817
+ }
1818
+ });
1819
+ function ImageOrUrlField({ label, value, onChange, placeholder = "https://\u2026", inputClassName = "w-full rounded-md border border-gray-300 px-2 py-1.5 text-sm", labelClassName = "block text-xs font-medium text-gray-600 mb-1", previewVariant = "banner", maxSizeMb = 10 }) {
1820
+ const fileInputRef = useRef(null);
1821
+ const [isUploading, setIsUploading] = useState(false);
1822
+ const [error, setError] = useState(null);
1823
+ const [lightboxOpen, setLightboxOpen] = useState(false);
1824
+ const previewCls = previewVariant === "logo" ? "h-20 w-20 rounded-md border border-gray-200 bg-white object-contain cursor-pointer" : "max-h-32 w-full rounded-md border border-gray-200 bg-gray-50 object-cover cursor-pointer";
1825
+ const closeLightbox = useCallback(() => setLightboxOpen(false), []);
1826
+ useEffect(() => {
1827
+ if (!lightboxOpen) return;
1828
+ const onKeyDown = /* @__PURE__ */ __name((e) => {
1829
+ if (e.key === "Escape") closeLightbox();
1830
+ }, "onKeyDown");
1831
+ window.addEventListener("keydown", onKeyDown);
1832
+ const prevOverflow = document.body.style.overflow;
1833
+ document.body.style.overflow = "hidden";
1834
+ return () => {
1835
+ window.removeEventListener("keydown", onKeyDown);
1836
+ document.body.style.overflow = prevOverflow;
1837
+ };
1838
+ }, [
1839
+ lightboxOpen,
1840
+ closeLightbox
1841
+ ]);
1842
+ const handleUpload = useCallback(async (file) => {
1843
+ setError(null);
1844
+ if (!MEDIA_UPLOAD_MIME_TYPES.includes(file.type)) {
1845
+ setError("Unsupported type. Use JPG, PNG, GIF, WEBP, or video MP4 / WebM / MOV");
1846
+ return;
1847
+ }
1848
+ const isVideo2 = isVideoUploadMime(file.type);
1849
+ const limit = isVideo2 ? VIDEO_UPLOAD_MAX_BYTES : maxSizeMb * 1024 * 1024;
1850
+ if (file.size > limit) {
1851
+ setError(isVideo2 ? `Video must be under ${VIDEO_UPLOAD_MAX_BYTES / (1024 * 1024)}MB` : `File must be under ${Math.round(limit / (1024 * 1024))}MB`);
1852
+ return;
1853
+ }
1854
+ setIsUploading(true);
1855
+ try {
1856
+ const formData = new FormData();
1857
+ formData.append("file", file);
1858
+ const response = await fetch("/api/upload", {
1859
+ method: "POST",
1860
+ body: formData
1861
+ });
1862
+ const data = await response.json();
1863
+ if (!response.ok) {
1864
+ throw new Error(data.error || data.details || "Upload failed");
1865
+ }
1866
+ onChange(data.filePath ?? "");
1867
+ } catch (err) {
1868
+ setError(err instanceof Error ? err.message : "Upload failed");
1869
+ } finally {
1870
+ setIsUploading(false);
1871
+ if (fileInputRef.current) fileInputRef.current.value = "";
1872
+ }
1873
+ }, [
1874
+ maxSizeMb,
1875
+ onChange
1876
+ ]);
1877
+ const onFileChange = useCallback((e) => {
1878
+ const file = e.target.files?.[0];
1879
+ if (file) void handleUpload(file);
1880
+ }, [
1881
+ handleUpload
1882
+ ]);
1883
+ const trimmed = value.trim();
1884
+ const isVideo = isVideoMediaUrl(trimmed);
1885
+ return /* @__PURE__ */ React.createElement("div", {
1886
+ className: "space-y-2"
1887
+ }, /* @__PURE__ */ React.createElement("label", {
1888
+ className: labelClassName
1889
+ }, label), trimmed ? /* @__PURE__ */ React.createElement("div", {
1890
+ className: "flex items-start gap-3"
1891
+ }, isVideo ? (
1892
+ // eslint-disable-next-line jsx-a11y/media-has-caption
1893
+ /* @__PURE__ */ React.createElement("video", {
1894
+ src: trimmed,
1895
+ className: previewCls,
1896
+ muted: true,
1897
+ playsInline: true,
1898
+ preload: "metadata",
1899
+ onClick: /* @__PURE__ */ __name(() => setLightboxOpen(true), "onClick"),
1900
+ title: "Click to enlarge"
1901
+ })
1902
+ ) : (
1903
+ // eslint-disable-next-line @next/next/no-img-element
1904
+ /* @__PURE__ */ React.createElement("img", {
1905
+ src: trimmed,
1906
+ alt: label,
1907
+ className: previewCls,
1908
+ role: "button",
1909
+ tabIndex: 0,
1910
+ title: "Click to enlarge",
1911
+ onClick: /* @__PURE__ */ __name(() => setLightboxOpen(true), "onClick"),
1912
+ onKeyDown: /* @__PURE__ */ __name((e) => {
1913
+ if (e.key === "Enter" || e.key === " ") {
1914
+ e.preventDefault();
1915
+ setLightboxOpen(true);
1916
+ }
1917
+ }, "onKeyDown"),
1918
+ onError: /* @__PURE__ */ __name((e) => {
1919
+ e.currentTarget.style.display = "none";
1920
+ }, "onError")
1921
+ })
1922
+ ), /* @__PURE__ */ React.createElement("button", {
1923
+ type: "button",
1924
+ onClick: /* @__PURE__ */ __name(() => onChange(""), "onClick"),
1925
+ className: "inline-flex items-center gap-1 rounded border border-gray-300 bg-white px-2 py-1 text-xs text-gray-600 hover:bg-gray-50"
1926
+ }, /* @__PURE__ */ React.createElement(X, {
1927
+ className: "h-3 w-3"
1928
+ }), "Clear")) : null, /* @__PURE__ */ React.createElement("div", {
1929
+ className: "flex flex-wrap gap-2"
1930
+ }, /* @__PURE__ */ React.createElement("input", {
1931
+ type: "text",
1932
+ inputMode: "url",
1933
+ autoComplete: "off",
1934
+ value,
1935
+ onChange: /* @__PURE__ */ __name((e) => {
1936
+ setError(null);
1937
+ onChange(e.target.value);
1938
+ }, "onChange"),
1939
+ placeholder,
1940
+ className: `${inputClassName} min-w-0 flex-1`
1941
+ }), /* @__PURE__ */ React.createElement("input", {
1942
+ ref: fileInputRef,
1943
+ type: "file",
1944
+ accept: ACCEPT,
1945
+ onChange: onFileChange,
1946
+ className: "hidden",
1947
+ disabled: isUploading
1948
+ }), /* @__PURE__ */ React.createElement("button", {
1949
+ type: "button",
1950
+ onClick: /* @__PURE__ */ __name(() => fileInputRef.current?.click(), "onClick"),
1951
+ disabled: isUploading,
1952
+ className: "inline-flex shrink-0 items-center gap-1.5 rounded-md border border-gray-300 bg-white px-3 py-1.5 text-sm font-medium text-gray-700 hover:bg-gray-50 disabled:opacity-50"
1953
+ }, /* @__PURE__ */ React.createElement(Upload, {
1954
+ className: "h-3.5 w-3.5"
1955
+ }), isUploading ? "Uploading\u2026" : "Upload")), error ? /* @__PURE__ */ React.createElement("p", {
1956
+ className: "flex items-center gap-1.5 text-xs text-red-600"
1957
+ }, /* @__PURE__ */ React.createElement(AlertCircle, {
1958
+ className: "h-3.5 w-3.5 shrink-0"
1959
+ }), error) : /* @__PURE__ */ React.createElement("p", {
1960
+ className: "text-xs text-gray-500"
1961
+ }, "Paste a URL or upload an image (PNG, JPG, GIF, WEBP up to ", maxSizeMb, "MB) or video (MP4, WebM, MOV up to", " ", VIDEO_UPLOAD_MAX_BYTES / (1024 * 1024), "MB)"), lightboxOpen && trimmed ? /* @__PURE__ */ React.createElement("div", {
1962
+ className: "fixed inset-0 z-[100] flex items-center justify-center bg-black/70 p-4",
1963
+ role: "dialog",
1964
+ "aria-modal": "true",
1965
+ "aria-label": `${label} preview`,
1966
+ onClick: closeLightbox
1967
+ }, isVideo ? (
1968
+ // eslint-disable-next-line jsx-a11y/media-has-caption
1969
+ /* @__PURE__ */ React.createElement("video", {
1970
+ src: trimmed,
1971
+ controls: true,
1972
+ autoPlay: true,
1973
+ className: "max-h-[90vh] max-w-[90vw] rounded-md shadow-lg",
1974
+ onClick: /* @__PURE__ */ __name((e) => e.stopPropagation(), "onClick")
1975
+ })
1976
+ ) : (
1977
+ // eslint-disable-next-line @next/next/no-img-element
1978
+ /* @__PURE__ */ React.createElement("img", {
1979
+ src: trimmed,
1980
+ alt: label,
1981
+ className: "max-h-[90vh] max-w-[90vw] rounded-md object-contain shadow-lg",
1982
+ onClick: /* @__PURE__ */ __name((e) => e.stopPropagation(), "onClick")
1983
+ })
1984
+ )) : null);
1985
+ }
1986
+ var ACCEPT;
1987
+ var init_ImageOrUrlField = __esm({
1988
+ "src/components/Admin/ImageOrUrlField.tsx"() {
1989
+ "use client";
1990
+ init_media_url();
1991
+ ACCEPT = MEDIA_UPLOAD_MIME_TYPES.join(",");
1992
+ __name(ImageOrUrlField, "ImageOrUrlField");
1993
+ }
1994
+ });
1739
1995
  function RelationAutocomplete({ apiEndpoint, value, onChange, labelField = "name", valueField = "id", placeholder = "Select\u2026", disabled = false, queryParams }) {
1740
1996
  const [open, setOpen] = useState(false);
1741
1997
  const [search, setSearch] = useState("");
@@ -2324,12 +2580,7 @@ function CreateEditForm({ isOpen, onClose, onSaveSuccess, apiEndpoint, columns,
2324
2580
  return;
2325
2581
  }
2326
2582
  const result = await res.json();
2327
- if (result.inviteLink) {
2328
- toast.success(`User invite created! Invite link: ${result.inviteLink}
2329
-
2330
- Note: ${result.note}`);
2331
- }
2332
- onSaveSuccess?.();
2583
+ onSaveSuccess?.(result);
2333
2584
  onClose();
2334
2585
  } catch (error) {
2335
2586
  console.error("Error saving data:", error);
@@ -2339,6 +2590,7 @@ Note: ${result.note}`);
2339
2590
  const visibleColumns = columns.filter((col) => {
2340
2591
  if (col.hideInForm) return false;
2341
2592
  if (!existingData && col.hideInCreate) return false;
2593
+ if (existingData && col.hideInEdit) return false;
2342
2594
  return true;
2343
2595
  });
2344
2596
  const isFieldDisabled = /* @__PURE__ */ __name((path) => {
@@ -2375,7 +2627,7 @@ Note: ${result.note}`);
2375
2627
  const selectValue = optionSet && rawStr !== "" && optionSet.has(rawStr) ? rawStr : void 0;
2376
2628
  return /* @__PURE__ */ React26__default.createElement(React26__default.Fragment, {
2377
2629
  key: path
2378
- }, /* @__PURE__ */ React26__default.createElement("div", null, /* @__PURE__ */ React26__default.createElement(Label3, {
2630
+ }, /* @__PURE__ */ React26__default.createElement("div", null, col.type !== "image" && /* @__PURE__ */ React26__default.createElement(Label3, {
2379
2631
  className: "block text-sm font-medium mb-1"
2380
2632
  }, col.displayName, [
2381
2633
  "subtotal",
@@ -2502,6 +2754,16 @@ Note: ${result.note}`);
2502
2754
  disabled
2503
2755
  }) : col.type === "file" ? /* @__PURE__ */ React26__default.createElement(FileUpload, {
2504
2756
  onUploadSuccess: /* @__PURE__ */ __name((url) => handleFileUpload(path, url), "onUploadSuccess")
2757
+ }) : col.type === "image" ? /* @__PURE__ */ React26__default.createElement(ImageOrUrlField, {
2758
+ label: col.displayName,
2759
+ value: typeof formData[path] === "string" ? formData[path] : "",
2760
+ onChange: /* @__PURE__ */ __name((url) => setFormData((prev) => ({
2761
+ ...prev,
2762
+ [path]: url
2763
+ })), "onChange"),
2764
+ placeholder: col.placeholder ?? "Image URL or upload",
2765
+ previewVariant: "logo",
2766
+ labelClassName: "block text-sm font-medium mb-1"
2505
2767
  }) : /* @__PURE__ */ React26__default.createElement(Input, {
2506
2768
  type: col.type || "text",
2507
2769
  placeholder: [
@@ -2547,6 +2809,7 @@ var init_CreateEditForm = __esm({
2547
2809
  init_switch();
2548
2810
  init_label();
2549
2811
  init_file_upload();
2812
+ init_ImageOrUrlField();
2550
2813
  init_RelationAutocomplete();
2551
2814
  init_RelationMultiSelect();
2552
2815
  init_use_mobile();
@@ -3898,11 +4161,7 @@ function formatArrayListCell(value, col) {
3898
4161
  return items.join(", ");
3899
4162
  }
3900
4163
  function formatCellValue(value, col) {
3901
- if (col.type === "boolean") return value ? /* @__PURE__ */ React.createElement(Check, {
3902
- className: "h-4 w-4 text-green-600"
3903
- }) : /* @__PURE__ */ React.createElement(X, {
3904
- className: "h-4 w-4 text-red-600"
3905
- });
4164
+ if (col.type === "boolean") return value ? "Yes" : "No";
3906
4165
  if (col.type === "date") return formatDate(value);
3907
4166
  if (col.type === "datetime") return formatDateTime(value);
3908
4167
  if (col.type === "multiSelect" || Array.isArray(value) || typeof value === "string" && value.trim().startsWith("[")) {
@@ -4083,6 +4342,9 @@ function AdminCRUD({ title, apiEndpoint, columns, addEditPageUrl, customViewPage
4083
4342
  const [bulkDialogOpen, setBulkDialogOpen] = useState(false);
4084
4343
  const [isRefetching, setIsRefetching] = useState(false);
4085
4344
  const [roleOptions, setRoleOptions] = useState([]);
4345
+ const [inviteDialog, setInviteDialog] = useState(null);
4346
+ const [sendingInviteEmail, setSendingInviteEmail] = useState(false);
4347
+ const [linkCopied, setLinkCopied] = useState(false);
4086
4348
  const hasLoadedRef = useRef(false);
4087
4349
  const isMobile = useIsMobile();
4088
4350
  const showGroupColumn = !!manageUserGroups && roleOptions.length > 0;
@@ -4541,22 +4803,77 @@ function AdminCRUD({ title, apiEndpoint, columns, addEditPageUrl, customViewPage
4541
4803
  method: "POST",
4542
4804
  headers: {
4543
4805
  "Content-Type": "application/json"
4544
- }
4806
+ },
4807
+ body: JSON.stringify({
4808
+ sendEmail: true,
4809
+ rotate: true
4810
+ })
4545
4811
  });
4546
4812
  if (!res.ok) {
4547
4813
  const error2 = await res.json();
4548
- throw new Error(error2.error || "Failed to regenerate invite");
4814
+ throw new Error(error2.error || "Failed to resend invite");
4549
4815
  }
4550
4816
  const result = await res.json();
4551
- if (result.inviteLink) {
4552
- const note = result.note ? ` ${result.note}` : "";
4553
- toast.success(`New invite link generated.${note}`);
4554
- }
4817
+ toast.success(result.message || "Invite resent. Previous invite link is no longer valid.");
4818
+ setRefreshKey((k) => k + 1);
4555
4819
  } catch (error2) {
4556
4820
  console.error("Error regenerating invite:", error2);
4557
- toast.error(error2 instanceof Error ? error2.message : "Failed to regenerate invite");
4821
+ toast.error(error2 instanceof Error ? error2.message : "Failed to resend invite");
4558
4822
  }
4559
4823
  }, "handleRegenerateInvite");
4824
+ const copyInviteLink = /* @__PURE__ */ __name(async () => {
4825
+ const inviteLink = inviteDialog?.inviteLink;
4826
+ if (!inviteLink) {
4827
+ toast.error("Invite link is not available");
4828
+ return;
4829
+ }
4830
+ try {
4831
+ await navigator.clipboard.writeText(inviteLink);
4832
+ setLinkCopied(true);
4833
+ toast.success("Invite link copied");
4834
+ window.setTimeout(() => setLinkCopied(false), 2e3);
4835
+ } catch {
4836
+ toast.error("Could not copy invite link");
4837
+ }
4838
+ }, "copyInviteLink");
4839
+ const sendInviteEmailFromDialog = /* @__PURE__ */ __name(async () => {
4840
+ if (!inviteDialog) return;
4841
+ setSendingInviteEmail(true);
4842
+ try {
4843
+ const res = await fetch(`/api/users/${inviteDialog.userId}/regenerate-invite`, {
4844
+ method: "POST",
4845
+ headers: {
4846
+ "Content-Type": "application/json"
4847
+ },
4848
+ body: JSON.stringify({
4849
+ sendEmail: true,
4850
+ rotate: false
4851
+ })
4852
+ });
4853
+ const data2 = await res.json();
4854
+ if (!res.ok) {
4855
+ toast.error(data2.error || data2.message || "Failed to send invite email");
4856
+ return;
4857
+ }
4858
+ const nextLink = typeof data2.inviteLink === "string" ? data2.inviteLink.trim() : "";
4859
+ if (nextLink) {
4860
+ setInviteDialog((prev) => prev ? {
4861
+ ...prev,
4862
+ inviteLink: nextLink
4863
+ } : prev);
4864
+ }
4865
+ toast.success(data2.emailSent ? "Invite email sent" : data2.message || "Invite email queued");
4866
+ } catch {
4867
+ toast.error("Failed to send invite email");
4868
+ } finally {
4869
+ setSendingInviteEmail(false);
4870
+ }
4871
+ }, "sendInviteEmailFromDialog");
4872
+ const closeInviteDialog = /* @__PURE__ */ __name(() => {
4873
+ setInviteDialog(null);
4874
+ setLinkCopied(false);
4875
+ setRefreshKey((k) => k + 1);
4876
+ }, "closeInviteDialog");
4560
4877
  const addEditPage = addEditPageUrl && addEditPageUrl.length > 0;
4561
4878
  const createQueryString = useMemo(() => {
4562
4879
  if (!createQueryParams || Object.keys(createQueryParams).length === 0) return "";
@@ -4834,11 +5151,11 @@ function AdminCRUD({ title, apiEndpoint, columns, addEditPageUrl, customViewPage
4834
5151
  onClick: /* @__PURE__ */ __name(() => handleDuplicateClick(item), "onClick")
4835
5152
  }, /* @__PURE__ */ React.createElement(Copy, {
4836
5153
  className: "h-4 w-4 mr-2"
4837
- }), "Duplicate")), resourceName === "users" && /* @__PURE__ */ React.createElement(DropdownMenuItem, {
5154
+ }), "Duplicate")), resourceName === "users" && String(item.inviteStatus ?? "") === "pending" && /* @__PURE__ */ React.createElement(DropdownMenuItem, {
4838
5155
  onClick: /* @__PURE__ */ __name(() => handleRegenerateInvite(Number(item.id)), "onClick")
4839
5156
  }, /* @__PURE__ */ React.createElement(RefreshCw, {
4840
5157
  className: "h-4 w-4 mr-2"
4841
- }), "Regenerate Invite"), /* @__PURE__ */ React.createElement(DropdownMenuItem, {
5158
+ }), "Resend invite"), /* @__PURE__ */ React.createElement(DropdownMenuItem, {
4842
5159
  onClick: /* @__PURE__ */ __name(() => handleDeleteClick(item), "onClick"),
4843
5160
  className: "text-red-600 focus:text-red-600"
4844
5161
  }, /* @__PURE__ */ React.createElement(Trash2, {
@@ -4942,17 +5259,17 @@ function AdminCRUD({ title, apiEndpoint, columns, addEditPageUrl, customViewPage
4942
5259
  className: "h-3.5 w-3.5"
4943
5260
  }), /* @__PURE__ */ React.createElement("span", {
4944
5261
  className: "sr-only"
4945
- }, "Duplicate")), resourceName === "users" && /* @__PURE__ */ React.createElement(Button, {
5262
+ }, "Duplicate")), resourceName === "users" && String(item.inviteStatus ?? "") === "pending" && /* @__PURE__ */ React.createElement(Button, {
4946
5263
  variant: "outline",
4947
5264
  size: "icon",
4948
5265
  className: "h-7 w-7",
4949
5266
  onClick: /* @__PURE__ */ __name(() => handleRegenerateInvite(Number(item.id)), "onClick"),
4950
- title: "Regenerate Invite"
5267
+ title: "Resend invite"
4951
5268
  }, /* @__PURE__ */ React.createElement(RefreshCw, {
4952
5269
  className: "h-3.5 w-3.5"
4953
5270
  }), /* @__PURE__ */ React.createElement("span", {
4954
5271
  className: "sr-only"
4955
- }, "Regenerate Invite")), /* @__PURE__ */ React.createElement(Button, {
5272
+ }, "Resend invite")), /* @__PURE__ */ React.createElement(Button, {
4956
5273
  variant: "outline",
4957
5274
  size: "icon",
4958
5275
  className: "h-7 w-7 border-red-300 text-red-600 hover:text-red-700",
@@ -5001,12 +5318,55 @@ function AdminCRUD({ title, apiEndpoint, columns, addEditPageUrl, customViewPage
5001
5318
  setIsFormOpen(false);
5002
5319
  setRefreshKey((k) => k + 1);
5003
5320
  }, "onClose"),
5321
+ onSaveSuccess: /* @__PURE__ */ __name((result) => {
5322
+ if (resourceName === "users" && result && typeof result.inviteLink === "string" && result.inviteLink.trim() && !editingItem) {
5323
+ const userId = Number(result.user?.id ?? result.id);
5324
+ const inviteLink = result.inviteLink.trim();
5325
+ if (Number.isFinite(userId) && userId > 0) {
5326
+ setLinkCopied(false);
5327
+ setInviteDialog({
5328
+ userId,
5329
+ inviteLink
5330
+ });
5331
+ toast.success(typeof result.message === "string" ? result.message : "User created successfully");
5332
+ return;
5333
+ }
5334
+ }
5335
+ setRefreshKey((k) => k + 1);
5336
+ }, "onSaveSuccess"),
5004
5337
  apiEndpoint,
5005
5338
  columns,
5006
5339
  existingData: editingItem,
5007
5340
  duplicateSeed,
5008
5341
  resource: resourceName
5009
5342
  }), /* @__PURE__ */ React.createElement(Dialog, {
5343
+ open: inviteDialog != null,
5344
+ onOpenChange: /* @__PURE__ */ __name((open) => {
5345
+ if (!open) closeInviteDialog();
5346
+ }, "onOpenChange")
5347
+ }, /* @__PURE__ */ React.createElement(DialogContent, {
5348
+ className: "max-w-md"
5349
+ }, /* @__PURE__ */ React.createElement(DialogHeader, null, /* @__PURE__ */ React.createElement(DialogTitle, null, "User created"), /* @__PURE__ */ React.createElement(DialogDescription, null, "Send an invite email, or copy the invite link to share another way. The link is not shown here.")), /* @__PURE__ */ React.createElement("div", {
5350
+ className: "flex flex-col gap-2 py-2"
5351
+ }, /* @__PURE__ */ React.createElement(Button, {
5352
+ type: "button",
5353
+ disabled: sendingInviteEmail,
5354
+ onClick: /* @__PURE__ */ __name(() => void sendInviteEmailFromDialog(), "onClick")
5355
+ }, /* @__PURE__ */ React.createElement(Mail, {
5356
+ className: "h-4 w-4 mr-2"
5357
+ }), sendingInviteEmail ? "Sending\u2026" : "Send email"), /* @__PURE__ */ React.createElement(Button, {
5358
+ type: "button",
5359
+ variant: "outline",
5360
+ onClick: /* @__PURE__ */ __name(() => void copyInviteLink(), "onClick")
5361
+ }, linkCopied ? /* @__PURE__ */ React.createElement(Check, {
5362
+ className: "h-4 w-4 mr-2"
5363
+ }) : /* @__PURE__ */ React.createElement(Copy, {
5364
+ className: "h-4 w-4 mr-2"
5365
+ }), linkCopied ? "Copied" : "Copy invite link")), /* @__PURE__ */ React.createElement(DialogFooter, null, /* @__PURE__ */ React.createElement(Button, {
5366
+ type: "button",
5367
+ variant: "secondary",
5368
+ onClick: closeInviteDialog
5369
+ }, "Done")))), /* @__PURE__ */ React.createElement(Dialog, {
5010
5370
  open: deleteDialogOpen,
5011
5371
  onOpenChange: /* @__PURE__ */ __name((open) => {
5012
5372
  console.debug("[CRUD][delete] dialog onOpenChange", {
@@ -7732,155 +8092,6 @@ var init_ComponentSettings = __esm({
7732
8092
  __name(ComponentSettings, "ComponentSettings");
7733
8093
  }
7734
8094
  });
7735
- function ImageOrUrlField({ label, value, onChange, placeholder = "https://\u2026", inputClassName = "w-full rounded-md border border-gray-300 px-2 py-1.5 text-sm", labelClassName = "block text-xs font-medium text-gray-600 mb-1", previewVariant = "banner", maxSizeMb = 10 }) {
7736
- const fileInputRef = useRef(null);
7737
- const [isUploading, setIsUploading] = useState(false);
7738
- const [error, setError] = useState(null);
7739
- const [lightboxOpen, setLightboxOpen] = useState(false);
7740
- const previewCls = previewVariant === "logo" ? "h-20 w-20 rounded-md border border-gray-200 bg-white object-contain cursor-pointer" : "max-h-32 w-full rounded-md border border-gray-200 bg-gray-50 object-cover cursor-pointer";
7741
- const closeLightbox = useCallback(() => setLightboxOpen(false), []);
7742
- useEffect(() => {
7743
- if (!lightboxOpen) return;
7744
- const onKeyDown = /* @__PURE__ */ __name((e) => {
7745
- if (e.key === "Escape") closeLightbox();
7746
- }, "onKeyDown");
7747
- window.addEventListener("keydown", onKeyDown);
7748
- const prevOverflow = document.body.style.overflow;
7749
- document.body.style.overflow = "hidden";
7750
- return () => {
7751
- window.removeEventListener("keydown", onKeyDown);
7752
- document.body.style.overflow = prevOverflow;
7753
- };
7754
- }, [
7755
- lightboxOpen,
7756
- closeLightbox
7757
- ]);
7758
- const handleUpload = useCallback(async (file) => {
7759
- setError(null);
7760
- if (!ACCEPTED_TYPES.includes(file.type)) {
7761
- setError(`Unsupported file type. Use: ${ACCEPTED_TYPES.map((t) => t.replace("image/", "")).join(", ")}`);
7762
- return;
7763
- }
7764
- if (file.size > maxSizeMb * 1024 * 1024) {
7765
- setError(`File must be under ${maxSizeMb}MB`);
7766
- return;
7767
- }
7768
- setIsUploading(true);
7769
- try {
7770
- const formData = new FormData();
7771
- formData.append("file", file);
7772
- const response = await fetch("/api/upload", {
7773
- method: "POST",
7774
- body: formData
7775
- });
7776
- const data = await response.json();
7777
- if (!response.ok) {
7778
- throw new Error(data.error || data.details || "Upload failed");
7779
- }
7780
- onChange(data.filePath ?? "");
7781
- } catch (err) {
7782
- setError(err instanceof Error ? err.message : "Upload failed");
7783
- } finally {
7784
- setIsUploading(false);
7785
- if (fileInputRef.current) fileInputRef.current.value = "";
7786
- }
7787
- }, [
7788
- maxSizeMb,
7789
- onChange
7790
- ]);
7791
- const onFileChange = useCallback((e) => {
7792
- const file = e.target.files?.[0];
7793
- if (file) void handleUpload(file);
7794
- }, [
7795
- handleUpload
7796
- ]);
7797
- const trimmed = value.trim();
7798
- return /* @__PURE__ */ React.createElement("div", {
7799
- className: "space-y-2"
7800
- }, /* @__PURE__ */ React.createElement("label", {
7801
- className: labelClassName
7802
- }, label), trimmed ? /* @__PURE__ */ React.createElement("div", {
7803
- className: "flex items-start gap-3"
7804
- }, /* @__PURE__ */ React.createElement("img", {
7805
- src: trimmed,
7806
- alt: label,
7807
- className: previewCls,
7808
- role: "button",
7809
- tabIndex: 0,
7810
- title: "Click to enlarge",
7811
- onClick: /* @__PURE__ */ __name(() => setLightboxOpen(true), "onClick"),
7812
- onKeyDown: /* @__PURE__ */ __name((e) => {
7813
- if (e.key === "Enter" || e.key === " ") {
7814
- e.preventDefault();
7815
- setLightboxOpen(true);
7816
- }
7817
- }, "onKeyDown"),
7818
- onError: /* @__PURE__ */ __name((e) => {
7819
- e.currentTarget.style.display = "none";
7820
- }, "onError")
7821
- }), /* @__PURE__ */ React.createElement("button", {
7822
- type: "button",
7823
- onClick: /* @__PURE__ */ __name(() => onChange(""), "onClick"),
7824
- className: "inline-flex items-center gap-1 rounded border border-gray-300 bg-white px-2 py-1 text-xs text-gray-600 hover:bg-gray-50"
7825
- }, /* @__PURE__ */ React.createElement(X, {
7826
- className: "h-3 w-3"
7827
- }), "Clear")) : null, /* @__PURE__ */ React.createElement("div", {
7828
- className: "flex flex-wrap gap-2"
7829
- }, /* @__PURE__ */ React.createElement("input", {
7830
- type: "url",
7831
- value,
7832
- onChange: /* @__PURE__ */ __name((e) => {
7833
- setError(null);
7834
- onChange(e.target.value);
7835
- }, "onChange"),
7836
- placeholder,
7837
- className: `${inputClassName} min-w-0 flex-1`
7838
- }), /* @__PURE__ */ React.createElement("input", {
7839
- ref: fileInputRef,
7840
- type: "file",
7841
- accept: ACCEPTED_TYPES.join(","),
7842
- onChange: onFileChange,
7843
- className: "hidden",
7844
- disabled: isUploading
7845
- }), /* @__PURE__ */ React.createElement("button", {
7846
- type: "button",
7847
- onClick: /* @__PURE__ */ __name(() => fileInputRef.current?.click(), "onClick"),
7848
- disabled: isUploading,
7849
- className: "inline-flex shrink-0 items-center gap-1.5 rounded-md border border-gray-300 bg-white px-3 py-1.5 text-sm font-medium text-gray-700 hover:bg-gray-50 disabled:opacity-50"
7850
- }, /* @__PURE__ */ React.createElement(Upload, {
7851
- className: "h-3.5 w-3.5"
7852
- }), isUploading ? "Uploading\u2026" : "Upload")), error ? /* @__PURE__ */ React.createElement("p", {
7853
- className: "flex items-center gap-1.5 text-xs text-red-600"
7854
- }, /* @__PURE__ */ React.createElement(AlertCircle, {
7855
- className: "h-3.5 w-3.5 shrink-0"
7856
- }), error) : /* @__PURE__ */ React.createElement("p", {
7857
- className: "text-xs text-gray-500"
7858
- }, "Paste a URL or upload an image (PNG, JPG, GIF, WEBP up to ", maxSizeMb, "MB)"), lightboxOpen && trimmed ? /* @__PURE__ */ React.createElement("div", {
7859
- className: "fixed inset-0 z-[100] flex items-center justify-center bg-black/70 p-4",
7860
- role: "dialog",
7861
- "aria-modal": "true",
7862
- "aria-label": `${label} preview`,
7863
- onClick: closeLightbox
7864
- }, /* @__PURE__ */ React.createElement("img", {
7865
- src: trimmed,
7866
- alt: label,
7867
- className: "max-h-[90vh] max-w-[90vw] rounded-md object-contain shadow-lg",
7868
- onClick: /* @__PURE__ */ __name((e) => e.stopPropagation(), "onClick")
7869
- })) : null);
7870
- }
7871
- var ACCEPTED_TYPES;
7872
- var init_ImageOrUrlField = __esm({
7873
- "src/components/Admin/ImageOrUrlField.tsx"() {
7874
- "use client";
7875
- ACCEPTED_TYPES = [
7876
- "image/jpeg",
7877
- "image/png",
7878
- "image/gif",
7879
- "image/webp"
7880
- ];
7881
- __name(ImageOrUrlField, "ImageOrUrlField");
7882
- }
7883
- });
7884
8095
  function generateId() {
7885
8096
  return `nav_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`;
7886
8097
  }
@@ -8880,7 +9091,7 @@ var init_AuthFooter = __esm({
8880
9091
  });
8881
9092
  function AuthPageLayout({ children }) {
8882
9093
  return /* @__PURE__ */ React.createElement("div", {
8883
- className: "min-h-screen flex flex-col bg-gray-50 dark:bg-dark"
9094
+ className: "min-h-screen flex flex-col bg-gray-50"
8884
9095
  }, /* @__PURE__ */ React.createElement("div", {
8885
9096
  className: "flex-1 flex items-center justify-center px-4 py-6"
8886
9097
  }, /* @__PURE__ */ React.createElement("div", {
@@ -8921,6 +9132,7 @@ var init_SignInPage = __esm({
8921
9132
  const [email, setEmail] = useState("");
8922
9133
  const [password, setPassword] = useState("");
8923
9134
  const [error, setError] = useState("");
9135
+ const [success, setSuccess] = useState("");
8924
9136
  const [loading, setLoading] = useState(false);
8925
9137
  const { status } = useSession();
8926
9138
  const searchParams = useSearchParams();
@@ -8928,6 +9140,9 @@ var init_SignInPage = __esm({
8928
9140
  if (searchParams.get("error")) {
8929
9141
  setError("Invalid email or password");
8930
9142
  }
9143
+ if (searchParams.get("activated") === "1") {
9144
+ setSuccess("Account activated. Sign in with your new password.");
9145
+ }
8931
9146
  }, [
8932
9147
  searchParams
8933
9148
  ]);
@@ -8988,41 +9203,45 @@ var init_SignInPage = __esm({
8988
9203
  }
8989
9204
  }, "handleSubmit");
8990
9205
  return /* @__PURE__ */ React.createElement(AuthPageLayout, null, /* @__PURE__ */ React.createElement("div", {
8991
- className: "w-full shadow-md rounded-lg bg-white dark:bg-dark px-4 py-6 sm:px-6 sm:py-8"
9206
+ className: "w-full shadow-md rounded-lg bg-white px-4 py-6 sm:px-6 sm:py-8"
8992
9207
  }, /* @__PURE__ */ React.createElement("h3", {
8993
- className: "mb-1 text-center text-xl font-bold text-black dark:text-white sm:text-2xl"
9208
+ className: "mb-1 text-center text-xl font-bold text-black sm:text-2xl"
8994
9209
  }, "Sign in"), /* @__PURE__ */ React.createElement("p", {
8995
9210
  className: "mb-6 text-center text-sm text-body-color"
8996
- }, "Enter your credentials"), error && /* @__PURE__ */ React.createElement("div", {
8997
- className: "mb-4 rounded-md bg-red-50 p-3 text-sm text-red-600 dark:bg-red-900/20 dark:text-red-400"
9211
+ }, "Enter your credentials"), success && /* @__PURE__ */ React.createElement("div", {
9212
+ className: "mb-4 rounded-md bg-green-50 p-3 text-sm text-green-700"
9213
+ }, success), error && /* @__PURE__ */ React.createElement("div", {
9214
+ className: "mb-4 rounded-md bg-red-50 p-3 text-sm text-red-600"
8998
9215
  }, error), /* @__PURE__ */ React.createElement("form", {
8999
9216
  onSubmit: handleSubmit
9000
9217
  }, /* @__PURE__ */ React.createElement("div", {
9001
9218
  className: "mb-4"
9002
9219
  }, /* @__PURE__ */ React.createElement("label", {
9003
9220
  htmlFor: "email",
9004
- className: "mb-1.5 block text-sm text-dark dark:text-white"
9221
+ className: "mb-1.5 block text-sm text-gray-900"
9005
9222
  }, "Email"), /* @__PURE__ */ React.createElement("input", {
9006
9223
  type: "email",
9007
9224
  name: "email",
9225
+ id: "email",
9008
9226
  value: email,
9009
9227
  onChange: /* @__PURE__ */ __name((e) => setEmail(e.target.value), "onChange"),
9010
9228
  placeholder: "Enter email",
9011
9229
  required: true,
9012
- className: "border border-gray-300 w-full rounded bg-gray-50 px-3 py-2 text-sm text-gray-900 outline-none focus:border-gray-500 focus:ring-1 focus:ring-gray-500 dark:bg-dark dark:border-gray-600"
9230
+ className: "border border-gray-300 w-full rounded bg-gray-50 px-3 py-2 text-sm text-gray-900 outline-none focus:border-gray-500 focus:ring-1 focus:ring-gray-500"
9013
9231
  })), /* @__PURE__ */ React.createElement("div", {
9014
9232
  className: "mb-4"
9015
9233
  }, /* @__PURE__ */ React.createElement("label", {
9016
9234
  htmlFor: "password",
9017
- className: "mb-1.5 block text-sm text-dark dark:text-white"
9235
+ className: "mb-1.5 block text-sm text-gray-900"
9018
9236
  }, "Password"), /* @__PURE__ */ React.createElement("input", {
9019
9237
  type: "password",
9020
9238
  name: "password",
9239
+ id: "password",
9021
9240
  value: password,
9022
9241
  onChange: /* @__PURE__ */ __name((e) => setPassword(e.target.value), "onChange"),
9023
9242
  placeholder: "Enter password",
9024
9243
  required: true,
9025
- className: "border border-gray-300 w-full rounded bg-gray-50 px-3 py-2 text-sm text-gray-900 outline-none focus:border-gray-500 focus:ring-1 focus:ring-gray-500 dark:bg-dark dark:border-gray-600"
9244
+ className: "border border-gray-300 w-full rounded bg-gray-50 px-3 py-2 text-sm text-gray-900 outline-none focus:border-gray-500 focus:ring-1 focus:ring-gray-500"
9026
9245
  })), /* @__PURE__ */ React.createElement("div", {
9027
9246
  className: "mb-4 flex items-center justify-between"
9028
9247
  }, /* @__PURE__ */ React.createElement("label", {
@@ -9036,7 +9255,7 @@ var init_SignInPage = __esm({
9036
9255
  }, "Forgot password?")), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("button", {
9037
9256
  type: "submit",
9038
9257
  disabled: loading,
9039
- className: "w-full rounded bg-gray-900 px-4 py-2 text-sm font-medium text-white hover:bg-gray-800 disabled:opacity-50 disabled:cursor-not-allowed dark:bg-gray-800 dark:hover:bg-gray-700"
9258
+ className: "w-full rounded bg-gray-900 px-4 py-2 text-sm font-medium text-white hover:bg-gray-800 disabled:opacity-50 disabled:cursor-not-allowed"
9040
9259
  }, loading ? "Signing in..." : "Sign in")))));
9041
9260
  }, "SigninPage");
9042
9261
  SignInPage_default = SigninPage;
@@ -9080,11 +9299,11 @@ function ForgotPasswordPage() {
9080
9299
  }
9081
9300
  }, "handleSubmit");
9082
9301
  return /* @__PURE__ */ React.createElement(AuthPageLayout, null, /* @__PURE__ */ React.createElement("div", {
9083
- className: "w-full space-y-4 p-5 sm:p-6 bg-white dark:bg-[#2C303B] rounded-lg shadow-md"
9302
+ className: "w-full space-y-4 p-5 sm:p-6 bg-white rounded-lg shadow-md"
9084
9303
  }, /* @__PURE__ */ React.createElement("div", {
9085
9304
  className: "text-center"
9086
9305
  }, /* @__PURE__ */ React.createElement("h2", {
9087
- className: "text-xl font-bold text-gray-900 dark:text-white"
9306
+ className: "text-xl font-bold text-gray-900"
9088
9307
  }, "Forgot password"), /* @__PURE__ */ React.createElement("p", {
9089
9308
  className: "mt-1 text-sm text-body-color"
9090
9309
  }, "Enter your email for a reset link.")), /* @__PURE__ */ React.createElement("form", {
@@ -9102,7 +9321,7 @@ function ForgotPasswordPage() {
9102
9321
  placeholder: "you@example.com",
9103
9322
  className: "mt-1 h-9 text-sm"
9104
9323
  })), message && /* @__PURE__ */ React.createElement("div", {
9105
- className: `p-2.5 rounded-md text-sm ${message.includes("receive") ? "bg-green-50 dark:bg-green-900/20 text-green-700 dark:text-green-400" : "bg-red-50 dark:bg-red-900/20 text-red-700 dark:text-red-400"}`
9324
+ className: `p-2.5 rounded-md text-sm ${message.includes("receive") ? "bg-green-50 text-green-700" : "bg-red-50 text-red-700"}`
9106
9325
  }, message), /* @__PURE__ */ React.createElement(Button, {
9107
9326
  type: "submit",
9108
9327
  disabled: loading,
@@ -9185,9 +9404,9 @@ function ResetPasswordPageContent() {
9185
9404
  }, "handleSubmit");
9186
9405
  if (!token) {
9187
9406
  return /* @__PURE__ */ React.createElement(AuthPageLayout, null, /* @__PURE__ */ React.createElement("div", {
9188
- className: "w-full space-y-4 p-5 sm:p-6 bg-white dark:bg-[#2C303B] rounded-lg shadow-md text-center"
9407
+ className: "w-full space-y-4 p-5 sm:p-6 bg-white rounded-lg shadow-md text-center"
9189
9408
  }, /* @__PURE__ */ React.createElement("h2", {
9190
- className: "text-xl font-bold text-gray-900 dark:text-white"
9409
+ className: "text-xl font-bold text-gray-900"
9191
9410
  }, "Invalid reset link"), /* @__PURE__ */ React.createElement("p", {
9192
9411
  className: "text-sm text-body-color"
9193
9412
  }, message), /* @__PURE__ */ React.createElement(Link2, {
@@ -9196,11 +9415,11 @@ function ResetPasswordPageContent() {
9196
9415
  }, "Request a new link")));
9197
9416
  }
9198
9417
  return /* @__PURE__ */ React.createElement(AuthPageLayout, null, /* @__PURE__ */ React.createElement("div", {
9199
- className: "w-full space-y-4 p-5 sm:p-6 bg-white dark:bg-[#2C303B] rounded-lg shadow-md"
9418
+ className: "w-full space-y-4 p-5 sm:p-6 bg-white rounded-lg shadow-md"
9200
9419
  }, /* @__PURE__ */ React.createElement("div", {
9201
9420
  className: "text-center"
9202
9421
  }, /* @__PURE__ */ React.createElement("h2", {
9203
- className: "text-xl font-bold text-gray-900 dark:text-white"
9422
+ className: "text-xl font-bold text-gray-900"
9204
9423
  }, "Set new password"), /* @__PURE__ */ React.createElement("p", {
9205
9424
  className: "mt-1 text-sm text-body-color"
9206
9425
  }, "Enter your new password.")), /* @__PURE__ */ React.createElement("form", {
@@ -9235,7 +9454,7 @@ function ResetPasswordPageContent() {
9235
9454
  }), "onChange"),
9236
9455
  className: "mt-1 h-9 text-sm"
9237
9456
  })), message && /* @__PURE__ */ React.createElement("div", {
9238
- className: `p-2.5 rounded-md text-sm ${message.includes("successfully") || message.includes("now sign in") ? "bg-green-50 dark:bg-green-900/20 text-green-700 dark:text-green-400" : "bg-red-50 dark:bg-red-900/20 text-red-700 dark:text-red-400"}`
9457
+ className: `p-2.5 rounded-md text-sm ${message.includes("successfully") || message.includes("now sign in") ? "bg-green-50 text-green-700" : "bg-red-50 text-red-700"}`
9239
9458
  }, message), /* @__PURE__ */ React.createElement(Button, {
9240
9459
  type: "submit",
9241
9460
  disabled: loading,
@@ -9250,7 +9469,7 @@ function ResetPasswordPageContent() {
9250
9469
  function ResetPasswordPage() {
9251
9470
  return /* @__PURE__ */ React.createElement(Suspense, {
9252
9471
  fallback: /* @__PURE__ */ React.createElement("div", {
9253
- className: "min-h-screen flex items-center justify-center bg-gray-50 dark:bg-dark"
9472
+ className: "min-h-screen flex items-center justify-center bg-gray-50"
9254
9473
  }, /* @__PURE__ */ React.createElement("div", {
9255
9474
  className: "max-w-[400px] w-full p-6 text-center"
9256
9475
  }, /* @__PURE__ */ React.createElement("div", {
@@ -9278,6 +9497,7 @@ __export(InvitePage_exports, {
9278
9497
  default: () => InvitePage
9279
9498
  });
9280
9499
  function InvitePageContent() {
9500
+ const router = useRouter();
9281
9501
  const searchParams = useSearchParams();
9282
9502
  const token = searchParams.get("token");
9283
9503
  const [formData, setFormData] = useState({
@@ -9304,8 +9524,13 @@ function InvitePageContent() {
9304
9524
  setInviteValid(true);
9305
9525
  setMessage("");
9306
9526
  } else {
9527
+ const err = typeof result.error === "string" ? result.error : "";
9528
+ if (/already (active|accepted)/i.test(err)) {
9529
+ router.replace("/admin/signin?activated=1");
9530
+ return;
9531
+ }
9307
9532
  setInviteValid(false);
9308
- setMessage(result.error || "This invitation is no longer valid.");
9533
+ setMessage(err || "This invitation is no longer valid.");
9309
9534
  }
9310
9535
  } catch {
9311
9536
  if (!cancelled) {
@@ -9347,11 +9572,8 @@ function InvitePageContent() {
9347
9572
  });
9348
9573
  const result = await res.json();
9349
9574
  if (res.ok) {
9350
- setMessage("Account activated successfully! You can now log in.");
9351
- setFormData({
9352
- password: "",
9353
- confirmPassword: ""
9354
- });
9575
+ router.replace("/admin/signin?activated=1");
9576
+ return;
9355
9577
  } else {
9356
9578
  setMessage(result.error || "Failed to activate account");
9357
9579
  }
@@ -9417,7 +9639,7 @@ function InvitePageContent() {
9417
9639
  }), "onChange"),
9418
9640
  className: "mt-1 h-9 text-sm"
9419
9641
  })), message && /* @__PURE__ */ React26__default.createElement("div", {
9420
- className: `p-2.5 rounded-md text-sm ${message.includes("successfully") ? "bg-green-50 text-green-700" : "bg-red-50 text-red-700"}`
9642
+ className: "p-2.5 rounded-md text-sm bg-red-50 text-red-700"
9421
9643
  }, message), /* @__PURE__ */ React26__default.createElement(Button, {
9422
9644
  type: "submit",
9423
9645
  disabled: loading,
@@ -11183,6 +11405,15 @@ function renderListPrice(value, item) {
11183
11405
  function renderListThumbnail(url) {
11184
11406
  const trimmed = url.trim();
11185
11407
  if (!trimmed) return "\u2014";
11408
+ if (isVideoMediaUrl(trimmed)) {
11409
+ return createElement("video", {
11410
+ src: trimmed,
11411
+ muted: true,
11412
+ playsInline: true,
11413
+ preload: "metadata",
11414
+ className: "h-10 w-10 rounded border border-gray-200 bg-black object-cover"
11415
+ });
11416
+ }
11186
11417
  return createElement("img", {
11187
11418
  src: trimmed,
11188
11419
  alt: "",
@@ -11203,6 +11434,7 @@ function productListImageUrl(item) {
11203
11434
  var STORE_CRUD_CONFIGS;
11204
11435
  var init_store_crud_configs = __esm({
11205
11436
  "src/admin/store-crud-configs.ts"() {
11437
+ init_media_url();
11206
11438
  __name(renderListPrice, "renderListPrice");
11207
11439
  __name(renderListThumbnail, "renderListThumbnail");
11208
11440
  __name(productListImageUrl, "productListImageUrl");
@@ -11415,6 +11647,10 @@ var init_store_crud_configs = __esm({
11415
11647
  field: "name",
11416
11648
  displayName: "Name"
11417
11649
  },
11650
+ {
11651
+ field: "slug",
11652
+ displayName: "Slug"
11653
+ },
11418
11654
  {
11419
11655
  field: "eventId",
11420
11656
  displayName: "Event",
@@ -11908,6 +12144,14 @@ var init_store_crud_configs = __esm({
11908
12144
  title: "Categories",
11909
12145
  apiEndpoint: "/api/product_categories",
11910
12146
  columns: [
12147
+ {
12148
+ field: "image",
12149
+ displayName: "Image",
12150
+ type: "image",
12151
+ listFilter: false,
12152
+ placeholder: "Image URL or upload",
12153
+ render: /* @__PURE__ */ __name((value) => renderListThumbnail(typeof value === "string" ? value : ""), "render")
12154
+ },
11911
12155
  {
11912
12156
  field: "name",
11913
12157
  displayName: "Name"
@@ -12514,6 +12758,134 @@ var SettingsPage_exports = {};
12514
12758
  __export(SettingsPage_exports, {
12515
12759
  default: () => SettingsPage
12516
12760
  });
12761
+ function InvoiceTemplatePreview({ id }) {
12762
+ if (id === "modern") {
12763
+ return /* @__PURE__ */ React.createElement("div", {
12764
+ className: "h-28 rounded-md border border-slate-200 bg-white overflow-hidden shadow-sm"
12765
+ }, /* @__PURE__ */ React.createElement("div", {
12766
+ className: "h-7 bg-teal-700 px-2 flex flex-col justify-center"
12767
+ }, /* @__PURE__ */ React.createElement("div", {
12768
+ className: "h-1.5 w-14 rounded bg-white/90"
12769
+ }), /* @__PURE__ */ React.createElement("div", {
12770
+ className: "h-1 w-10 rounded bg-white/50 mt-1"
12771
+ })), /* @__PURE__ */ React.createElement("div", {
12772
+ className: "p-2 space-y-1.5"
12773
+ }, /* @__PURE__ */ React.createElement("div", {
12774
+ className: "flex gap-2"
12775
+ }, /* @__PURE__ */ React.createElement("div", {
12776
+ className: "flex-1 space-y-1"
12777
+ }, /* @__PURE__ */ React.createElement("div", {
12778
+ className: "h-1 w-8 bg-teal-600/70 rounded"
12779
+ }), /* @__PURE__ */ React.createElement("div", {
12780
+ className: "h-1 w-full bg-slate-200 rounded"
12781
+ }), /* @__PURE__ */ React.createElement("div", {
12782
+ className: "h-1 w-4/5 bg-slate-200 rounded"
12783
+ })), /* @__PURE__ */ React.createElement("div", {
12784
+ className: "flex-1 space-y-1"
12785
+ }, /* @__PURE__ */ React.createElement("div", {
12786
+ className: "h-1 w-8 bg-teal-600/70 rounded"
12787
+ }), /* @__PURE__ */ React.createElement("div", {
12788
+ className: "h-1 w-full bg-slate-200 rounded"
12789
+ }))), /* @__PURE__ */ React.createElement("div", {
12790
+ className: "h-1 w-full bg-slate-100 rounded"
12791
+ }), /* @__PURE__ */ React.createElement("div", {
12792
+ className: "h-1 w-full bg-slate-100 rounded"
12793
+ }), /* @__PURE__ */ React.createElement("div", {
12794
+ className: "ml-auto h-1.5 w-12 bg-teal-700/80 rounded"
12795
+ })));
12796
+ }
12797
+ if (id === "compact") {
12798
+ return /* @__PURE__ */ React.createElement("div", {
12799
+ className: "h-28 rounded-md border border-slate-300 bg-white overflow-hidden shadow-sm p-1.5 space-y-1"
12800
+ }, /* @__PURE__ */ React.createElement("div", {
12801
+ className: "h-4 bg-slate-100 rounded flex items-center px-1"
12802
+ }, /* @__PURE__ */ React.createElement("div", {
12803
+ className: "h-1 w-10 bg-slate-700 rounded"
12804
+ })), /* @__PURE__ */ React.createElement("div", {
12805
+ className: "grid grid-cols-4 gap-0.5"
12806
+ }, Array.from({
12807
+ length: 8
12808
+ }).map((_, i) => /* @__PURE__ */ React.createElement("div", {
12809
+ key: i,
12810
+ className: "h-1 bg-slate-200 rounded"
12811
+ }))), /* @__PURE__ */ React.createElement("div", {
12812
+ className: "space-y-0.5"
12813
+ }, Array.from({
12814
+ length: 5
12815
+ }).map((_, i) => /* @__PURE__ */ React.createElement("div", {
12816
+ key: i,
12817
+ className: "flex gap-0.5"
12818
+ }, /* @__PURE__ */ React.createElement("div", {
12819
+ className: "h-1 flex-[3] bg-slate-200 rounded"
12820
+ }), /* @__PURE__ */ React.createElement("div", {
12821
+ className: "h-1 flex-1 bg-slate-300 rounded"
12822
+ }), /* @__PURE__ */ React.createElement("div", {
12823
+ className: "h-1 flex-1 bg-slate-300 rounded"
12824
+ })))), /* @__PURE__ */ React.createElement("div", {
12825
+ className: "ml-auto h-1 w-10 bg-slate-800 rounded"
12826
+ }));
12827
+ }
12828
+ if (id === "bold") {
12829
+ return /* @__PURE__ */ React.createElement("div", {
12830
+ className: "h-28 rounded-md border border-red-200 bg-white overflow-hidden shadow-sm"
12831
+ }, /* @__PURE__ */ React.createElement("div", {
12832
+ className: "h-9 bg-red-800 px-2 flex flex-col justify-center gap-1"
12833
+ }, /* @__PURE__ */ React.createElement("div", {
12834
+ className: "h-2 w-16 rounded bg-white"
12835
+ }), /* @__PURE__ */ React.createElement("div", {
12836
+ className: "h-1 w-12 rounded bg-white/60"
12837
+ })), /* @__PURE__ */ React.createElement("div", {
12838
+ className: "p-2 space-y-1.5"
12839
+ }, /* @__PURE__ */ React.createElement("div", {
12840
+ className: "h-1 w-20 bg-slate-300 rounded"
12841
+ }), /* @__PURE__ */ React.createElement("div", {
12842
+ className: "border border-red-100 rounded p-1 space-y-0.5 bg-red-50/40"
12843
+ }, /* @__PURE__ */ React.createElement("div", {
12844
+ className: "h-1 w-full bg-slate-200 rounded"
12845
+ }), /* @__PURE__ */ React.createElement("div", {
12846
+ className: "h-1 w-full bg-slate-200 rounded"
12847
+ }), /* @__PURE__ */ React.createElement("div", {
12848
+ className: "h-1.5 w-14 ml-auto bg-red-800 rounded"
12849
+ }))));
12850
+ }
12851
+ return /* @__PURE__ */ React.createElement("div", {
12852
+ className: "h-28 rounded-md border border-slate-200 bg-white overflow-hidden shadow-sm p-2 space-y-1.5"
12853
+ }, /* @__PURE__ */ React.createElement("div", {
12854
+ className: "h-5 rounded bg-slate-100 px-1.5 flex items-center justify-between"
12855
+ }, /* @__PURE__ */ React.createElement("div", {
12856
+ className: "h-1.5 w-12 bg-slate-700 rounded"
12857
+ }), /* @__PURE__ */ React.createElement("div", {
12858
+ className: "h-1 w-8 bg-slate-400 rounded"
12859
+ })), /* @__PURE__ */ React.createElement("div", {
12860
+ className: "flex gap-2"
12861
+ }, /* @__PURE__ */ React.createElement("div", {
12862
+ className: "flex-1 space-y-0.5"
12863
+ }, /* @__PURE__ */ React.createElement("div", {
12864
+ className: "h-1 w-6 bg-slate-600 rounded"
12865
+ }), /* @__PURE__ */ React.createElement("div", {
12866
+ className: "h-1 w-full bg-slate-200 rounded"
12867
+ }), /* @__PURE__ */ React.createElement("div", {
12868
+ className: "h-1 w-3/4 bg-slate-200 rounded"
12869
+ })), /* @__PURE__ */ React.createElement("div", {
12870
+ className: "flex-1 space-y-0.5"
12871
+ }, /* @__PURE__ */ React.createElement("div", {
12872
+ className: "h-1 w-6 bg-slate-600 rounded"
12873
+ }), /* @__PURE__ */ React.createElement("div", {
12874
+ className: "h-1 w-full bg-slate-200 rounded"
12875
+ }))), /* @__PURE__ */ React.createElement("div", {
12876
+ className: "border-t border-slate-200 pt-1 space-y-0.5"
12877
+ }, /* @__PURE__ */ React.createElement("div", {
12878
+ className: "h-1 w-full bg-slate-100 rounded"
12879
+ }), /* @__PURE__ */ React.createElement("div", {
12880
+ className: "h-1 w-full bg-slate-100 rounded"
12881
+ }), /* @__PURE__ */ React.createElement("div", {
12882
+ className: "h-1 w-full bg-slate-100 rounded"
12883
+ })), /* @__PURE__ */ React.createElement("div", {
12884
+ className: "flex justify-end"
12885
+ }, /* @__PURE__ */ React.createElement("div", {
12886
+ className: "h-1.5 w-10 bg-slate-700 rounded"
12887
+ })));
12888
+ }
12517
12889
  function hexToHsl(hex) {
12518
12890
  const r = parseInt(hex.slice(1, 3), 16) / 255;
12519
12891
  const g = parseInt(hex.slice(3, 5), 16) / 255;
@@ -12564,6 +12936,25 @@ function SettingsPage() {
12564
12936
  const [requireEventApproval, setRequireEventApproval] = useState(false);
12565
12937
  const [storeSettingsLoading, setStoreSettingsLoading] = useState(true);
12566
12938
  const [currency, setCurrency] = useState(DEFAULT_CURRENCY);
12939
+ const [invoiceTemplate, setInvoiceTemplate] = useState("classic");
12940
+ const [companyLogo, setCompanyLogo] = useState("");
12941
+ const [companyName, setCompanyName] = useState("");
12942
+ const [companyEmail, setCompanyEmail] = useState("");
12943
+ const [companyPhone, setCompanyPhone] = useState("");
12944
+ const [companyAddress, setCompanyAddress] = useState("");
12945
+ const handleStoreLogoChange = /* @__PURE__ */ __name((newLogo) => {
12946
+ setCompanyLogo(newLogo);
12947
+ setNavbarConfig((prev) => ({
12948
+ ...prev,
12949
+ logo: newLogo
12950
+ }));
12951
+ }, "handleStoreLogoChange");
12952
+ const handleNavbarConfigChange = /* @__PURE__ */ __name((newConfig) => {
12953
+ setNavbarConfig(newConfig);
12954
+ if (newConfig.logo !== companyLogo) {
12955
+ setCompanyLogo(newConfig.logo || "");
12956
+ }
12957
+ }, "handleNavbarConfigChange");
12567
12958
  const [currencies, setCurrencies] = useState([]);
12568
12959
  const [currenciesLoading, setCurrenciesLoading] = useState(true);
12569
12960
  const [showAddCurrency, setShowAddCurrency] = useState(false);
@@ -12608,7 +12999,11 @@ function SettingsPage() {
12608
12999
  setActiveThemeId((data.activeThemeId || "").trim());
12609
13000
  if (data.navbar) {
12610
13001
  try {
12611
- setNavbarConfig(JSON.parse(data.navbar));
13002
+ const parsed = JSON.parse(data.navbar);
13003
+ setNavbarConfig(parsed);
13004
+ if (parsed.logo) {
13005
+ setCompanyLogo((prev) => prev || parsed.logo);
13006
+ }
12612
13007
  } catch {
12613
13008
  }
12614
13009
  }
@@ -12618,6 +13013,19 @@ function SettingsPage() {
12618
13013
  fetch("/api/settings/store").then((r) => r.ok ? r.json() : {}).then((data) => {
12619
13014
  setStoreEnabled(data.enabled === "true");
12620
13015
  setCurrency(data.currency || DEFAULT_CURRENCY);
13016
+ setInvoiceTemplate(data.invoiceTemplate || "classic");
13017
+ const logo = data.invoiceLogoUrl || data.companyLogo || data.logo || "";
13018
+ setCompanyLogo((prev) => logo || prev);
13019
+ setCompanyName(data.companyName || data.invoiceCompanyName || data.name || "");
13020
+ setCompanyEmail(data.companyEmail || data.invoiceEmail || data.email || "");
13021
+ setCompanyPhone(data.companyPhone || data.invoicePhone || data.phone || "");
13022
+ setCompanyAddress(data.companyAddress || data.invoiceAddress || data.address || "");
13023
+ if (logo) {
13024
+ setNavbarConfig((prev) => ({
13025
+ ...prev,
13026
+ logo: prev.logo || logo
13027
+ }));
13028
+ }
12621
13029
  }).finally(() => setStoreSettingsLoading(false));
12622
13030
  fetch("/api/settings/multi_vendor").then((r) => r.ok ? r.json() : {}).then((data) => {
12623
13031
  setMultiVendorEnabled(data.enabled !== "false");
@@ -12722,6 +13130,27 @@ function SettingsPage() {
12722
13130
  }
12723
13131
  })
12724
13132
  });
13133
+ await fetch("/api/settings/store", {
13134
+ method: "PUT",
13135
+ headers: {
13136
+ "Content-Type": "application/json"
13137
+ },
13138
+ body: JSON.stringify({
13139
+ invoiceLogoUrl: {
13140
+ value: navbarConfig.logo || "",
13141
+ type: "public"
13142
+ },
13143
+ companyLogo: {
13144
+ value: navbarConfig.logo || "",
13145
+ type: "public"
13146
+ },
13147
+ logo: {
13148
+ value: navbarConfig.logo || "",
13149
+ type: "public"
13150
+ }
13151
+ })
13152
+ }).catch(() => {
13153
+ });
12725
13154
  toast.success("Navbar saved");
12726
13155
  } catch {
12727
13156
  toast.error("Failed to save");
@@ -12745,8 +13174,57 @@ function SettingsPage() {
12745
13174
  currency: {
12746
13175
  value: currency,
12747
13176
  type: "public"
13177
+ },
13178
+ invoiceTemplate: {
13179
+ value: invoiceTemplate || "classic",
13180
+ type: "public"
13181
+ },
13182
+ invoiceLogoUrl: {
13183
+ value: companyLogo,
13184
+ type: "public"
13185
+ },
13186
+ companyLogo: {
13187
+ value: companyLogo,
13188
+ type: "public"
13189
+ },
13190
+ logo: {
13191
+ value: companyLogo,
13192
+ type: "public"
13193
+ },
13194
+ companyName: {
13195
+ value: companyName,
13196
+ type: "public"
13197
+ },
13198
+ companyEmail: {
13199
+ value: companyEmail,
13200
+ type: "public"
13201
+ },
13202
+ companyPhone: {
13203
+ value: companyPhone,
13204
+ type: "public"
13205
+ },
13206
+ companyAddress: {
13207
+ value: companyAddress,
13208
+ type: "public"
13209
+ }
13210
+ })
13211
+ });
13212
+ const updatedNav = {
13213
+ ...navbarConfig,
13214
+ logo: companyLogo
13215
+ };
13216
+ await fetch("/api/settings/theme", {
13217
+ method: "PUT",
13218
+ headers: {
13219
+ "Content-Type": "application/json"
13220
+ },
13221
+ body: JSON.stringify({
13222
+ navbar: {
13223
+ value: JSON.stringify(updatedNav),
13224
+ type: "public"
12748
13225
  }
12749
13226
  })
13227
+ }).catch(() => {
12750
13228
  });
12751
13229
  await fetch("/api/settings/multi_vendor", {
12752
13230
  method: "PUT",
@@ -13030,7 +13508,7 @@ function SettingsPage() {
13030
13508
  className: "text-sm text-gray-500 mb-4"
13031
13509
  }, "Set logo and menu items."), /* @__PURE__ */ React.createElement(NavbarEditor, {
13032
13510
  config: navbarConfig,
13033
- onChange: setNavbarConfig
13511
+ onChange: handleNavbarConfigChange
13034
13512
  })), /* @__PURE__ */ React.createElement(Button, {
13035
13513
  onClick: handleSaveNavbar,
13036
13514
  disabled: saving
@@ -13116,7 +13594,80 @@ function SettingsPage() {
13116
13594
  className: "text-sm font-medium text-gray-700"
13117
13595
  }, "Require event approval"), /* @__PURE__ */ React.createElement("p", {
13118
13596
  className: "text-xs text-gray-500 mt-0.5"
13119
- }, "When on, new vendor events start as pending. Admins approve or reject; approval activates the event (live)."))) : null), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("div", {
13597
+ }, "When on, new vendor events start as pending. Admins approve or reject; approval activates the event (live)."))) : null), /* @__PURE__ */ React.createElement("div", {
13598
+ className: "space-y-4 p-4 bg-gray-50 rounded-lg border border-gray-200"
13599
+ }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("h3", {
13600
+ className: "text-base font-semibold text-gray-900"
13601
+ }, "Invoice Header & Store Details"), /* @__PURE__ */ React.createElement("p", {
13602
+ className: "text-xs text-gray-500 mt-0.5"
13603
+ }, "Configure company logo, name, email, phone, and address displayed on generated invoice headers.")), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(ImageOrUrlField, {
13604
+ label: "Company Logo",
13605
+ value: companyLogo,
13606
+ onChange: handleStoreLogoChange,
13607
+ previewVariant: "logo",
13608
+ placeholder: "Logo image URL or upload image"
13609
+ })), /* @__PURE__ */ React.createElement("div", {
13610
+ className: "grid grid-cols-1 sm:grid-cols-2 gap-4"
13611
+ }, /* @__PURE__ */ React.createElement("div", {
13612
+ className: "space-y-1.5"
13613
+ }, /* @__PURE__ */ React.createElement(Label3, {
13614
+ className: "text-xs font-medium text-gray-700"
13615
+ }, "Company Name"), /* @__PURE__ */ React.createElement(Input, {
13616
+ value: companyName,
13617
+ onChange: /* @__PURE__ */ __name((e) => setCompanyName(e.target.value), "onChange"),
13618
+ placeholder: "e.g. Acme Corp",
13619
+ className: "h-9 text-sm bg-white"
13620
+ })), /* @__PURE__ */ React.createElement("div", {
13621
+ className: "space-y-1.5"
13622
+ }, /* @__PURE__ */ React.createElement(Label3, {
13623
+ className: "text-xs font-medium text-gray-700"
13624
+ }, "Company Email"), /* @__PURE__ */ React.createElement(Input, {
13625
+ type: "email",
13626
+ value: companyEmail,
13627
+ onChange: /* @__PURE__ */ __name((e) => setCompanyEmail(e.target.value), "onChange"),
13628
+ placeholder: "e.g. support@acme.com",
13629
+ className: "h-9 text-sm bg-white"
13630
+ })), /* @__PURE__ */ React.createElement("div", {
13631
+ className: "space-y-1.5"
13632
+ }, /* @__PURE__ */ React.createElement(Label3, {
13633
+ className: "text-xs font-medium text-gray-700"
13634
+ }, "Company Phone"), /* @__PURE__ */ React.createElement(Input, {
13635
+ type: "tel",
13636
+ value: companyPhone,
13637
+ onChange: /* @__PURE__ */ __name((e) => setCompanyPhone(e.target.value), "onChange"),
13638
+ placeholder: "e.g. +1 555-0199",
13639
+ className: "h-9 text-sm bg-white"
13640
+ })), /* @__PURE__ */ React.createElement("div", {
13641
+ className: "space-y-1.5 sm:col-span-2"
13642
+ }, /* @__PURE__ */ React.createElement(Label3, {
13643
+ className: "text-xs font-medium text-gray-700"
13644
+ }, "Company Address"), /* @__PURE__ */ React.createElement(Textarea, {
13645
+ value: companyAddress,
13646
+ onChange: /* @__PURE__ */ __name((e) => setCompanyAddress(e.target.value), "onChange"),
13647
+ placeholder: "e.g. 123 Business Rd, Suite 100\nNew York, NY 10001",
13648
+ rows: 3,
13649
+ className: "text-sm bg-white"
13650
+ })))), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
13651
+ className: "block text-sm font-semibold text-gray-700 mb-1"
13652
+ }, "Invoice PDF template"), /* @__PURE__ */ React.createElement("p", {
13653
+ className: "text-xs text-gray-500 mb-3"
13654
+ }, "Used when generating invoices in the app (and as fallback when ERP invoice is unavailable). Company logo, name, email, phone, and address set above are shown in the invoice header."), /* @__PURE__ */ React.createElement("div", {
13655
+ className: "grid gap-3 sm:grid-cols-2"
13656
+ }, INVOICE_TEMPLATE_CARDS.map((opt) => {
13657
+ const selected = invoiceTemplate === opt.id;
13658
+ return /* @__PURE__ */ React.createElement("button", {
13659
+ key: opt.id,
13660
+ type: "button",
13661
+ onClick: /* @__PURE__ */ __name(() => setInvoiceTemplate(opt.id), "onClick"),
13662
+ className: `text-left rounded-lg border p-3 transition ${selected ? "border-blue-500 bg-blue-50 ring-1 ring-blue-500" : "border-gray-200 bg-white hover:border-gray-300"}`
13663
+ }, /* @__PURE__ */ React.createElement(InvoiceTemplatePreview, {
13664
+ id: opt.id
13665
+ }), /* @__PURE__ */ React.createElement("div", {
13666
+ className: "text-sm font-semibold text-gray-800 mt-2"
13667
+ }, opt.label), /* @__PURE__ */ React.createElement("div", {
13668
+ className: "text-xs text-gray-500 mt-0.5"
13669
+ }, opt.description));
13670
+ }))), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("div", {
13120
13671
  className: "flex items-center justify-between mb-1"
13121
13672
  }, /* @__PURE__ */ React.createElement("label", {
13122
13673
  className: "block text-sm font-semibold text-gray-700"
@@ -13304,7 +13855,7 @@ function SettingsPage() {
13304
13855
  className: "h-4 w-4 mr-2"
13305
13856
  }), saving ? "Saving..." : "Save")));
13306
13857
  }
13307
- var DEFAULT_CURRENCY, DEFAULTS;
13858
+ var DEFAULT_CURRENCY, DEFAULTS, INVOICE_TEMPLATE_CARDS;
13308
13859
  var init_SettingsPage = __esm({
13309
13860
  "src/admin/pages/SettingsPage.tsx"() {
13310
13861
  "use client";
@@ -13313,6 +13864,8 @@ var init_SettingsPage = __esm({
13313
13864
  init_switch();
13314
13865
  init_label();
13315
13866
  init_admin_config_context();
13867
+ init_textarea();
13868
+ init_ImageOrUrlField();
13316
13869
  init_NavbarEditor();
13317
13870
  DEFAULT_CURRENCY = "INR";
13318
13871
  DEFAULTS = {
@@ -13320,6 +13873,29 @@ var init_SettingsPage = __esm({
13320
13873
  secondaryColor: "#6366f1",
13321
13874
  compactView: "false"
13322
13875
  };
13876
+ INVOICE_TEMPLATE_CARDS = [
13877
+ {
13878
+ id: "classic",
13879
+ label: "Classic",
13880
+ description: "Traditional invoice with lined items and totals footer."
13881
+ },
13882
+ {
13883
+ id: "modern",
13884
+ label: "Modern",
13885
+ description: "Clean layout with accent header and open spacing."
13886
+ },
13887
+ {
13888
+ id: "compact",
13889
+ label: "Compact",
13890
+ description: "Dense layout suited to longer item lists."
13891
+ },
13892
+ {
13893
+ id: "bold",
13894
+ label: "Bold",
13895
+ description: "Strong header band and clear payment summary."
13896
+ }
13897
+ ];
13898
+ __name(InvoiceTemplatePreview, "InvoiceTemplatePreview");
13323
13899
  __name(hexToHsl, "hexToHsl");
13324
13900
  __name(genId, "genId");
13325
13901
  __name(SettingsPage, "SettingsPage");
@@ -31645,6 +32221,7 @@ function ComboEditPage({ comboId }) {
31645
32221
  const [saving, setSaving] = useState(false);
31646
32222
  const [errors, setErrors] = useState([]);
31647
32223
  const [name, setName] = useState("");
32224
+ const [slug, setSlug] = useState("");
31648
32225
  const [desc, setDesc] = useState("");
31649
32226
  const [eventId, setEventId] = useState("");
31650
32227
  const [priceStr, setPriceStr] = useState("");
@@ -31784,6 +32361,7 @@ function ComboEditPage({ comboId }) {
31784
32361
  const data = await res.json();
31785
32362
  if (cancelled) return;
31786
32363
  setName(data.name ?? "");
32364
+ setSlug(typeof data.slug === "string" ? data.slug : "");
31787
32365
  setDesc(data.desc ?? "");
31788
32366
  setEventId(data.eventId != null ? String(data.eventId) : "");
31789
32367
  if (data.eventId != null) {
@@ -31824,6 +32402,7 @@ function ComboEditPage({ comboId }) {
31824
32402
  if (create && duplicateSourceId) {
31825
32403
  const rawName = (data.name ?? "").trim() || "Combo";
31826
32404
  setName(rawName.toLowerCase().startsWith("copy of ") ? `${rawName} (copy)` : `Copy of ${rawName}`);
32405
+ setSlug("");
31827
32406
  }
31828
32407
  } catch {
31829
32408
  if (!cancelled) setErrors([
@@ -31909,15 +32488,15 @@ function ComboEditPage({ comboId }) {
31909
32488
  ]);
31910
32489
  return;
31911
32490
  }
31912
- if (addonItems.length > 0 && addonItems.length < minSelectableItems) {
32491
+ if (addonItems.length < minSelectableItems) {
31913
32492
  setErrors([
31914
- `Please add at least ${minSelectableItems} add-on item(s). Currently ${addonItems.length} selected.`
32493
+ `Please add at least ${minSelectableItems} add-on item(s) so customers can meet the minimum. Currently ${addonItems.length} selected.`
31915
32494
  ]);
31916
32495
  return;
31917
32496
  }
31918
- if (addonItems.length > maxSelectableItems) {
32497
+ if (maxSelectableItems > addonItems.length) {
31919
32498
  setErrors([
31920
- `You can select at most ${maxSelectableItems} add-on item(s). Currently ${addonItems.length} selected.`
32499
+ `Max add-on items (${maxSelectableItems}) cannot be greater than the number of add-on items selected (${addonItems.length}).`
31921
32500
  ]);
31922
32501
  return;
31923
32502
  }
@@ -31937,6 +32516,7 @@ function ComboEditPage({ comboId }) {
31937
32516
  const resolvedEventId = trimmedEventId && /^\d+$/.test(trimmedEventId) ? Number(trimmedEventId) : null;
31938
32517
  const payload = {
31939
32518
  name: trimmedName,
32519
+ slug: slug.trim() || void 0,
31940
32520
  desc: desc || null,
31941
32521
  eventId: resolvedEventId,
31942
32522
  price,
@@ -32028,6 +32608,14 @@ function ComboEditPage({ comboId }) {
32028
32608
  className: "w-full rounded-md border border-gray-300 px-3 py-2 text-sm"
32029
32609
  })), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
32030
32610
  className: "block text-xs font-medium text-gray-600 mb-1"
32611
+ }, "Slug"), /* @__PURE__ */ React.createElement("input", {
32612
+ type: "text",
32613
+ value: slug,
32614
+ onChange: /* @__PURE__ */ __name((e) => setSlug(e.target.value), "onChange"),
32615
+ placeholder: "Auto generate from name",
32616
+ className: "w-full rounded-md border border-gray-300 px-3 py-2 text-sm"
32617
+ })), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
32618
+ className: "block text-xs font-medium text-gray-600 mb-1"
32031
32619
  }, "Description"), /* @__PURE__ */ React.createElement("textarea", {
32032
32620
  value: desc,
32033
32621
  onChange: /* @__PURE__ */ __name((e) => setDesc(e.target.value), "onChange"),
@@ -32141,7 +32729,7 @@ function ComboEditPage({ comboId }) {
32141
32729
  className: "w-full rounded-md border border-gray-300 px-3 py-2 text-sm"
32142
32730
  }))), /* @__PURE__ */ React.createElement("p", {
32143
32731
  className: "text-xs text-gray-400 mt-1"
32144
- }, "Customers must select between ", minSelectableItems, " and ", maxSelectableItems, " add-on item(s)."))), /* @__PURE__ */ React.createElement("section", null, /* @__PURE__ */ React.createElement("h2", {
32732
+ }, "List all available add-ons above. Customers choose between ", minSelectableItems, " and", " ", maxSelectableItems, " of those items (max cannot exceed the add-on list size)."))), /* @__PURE__ */ React.createElement("section", null, /* @__PURE__ */ React.createElement("h2", {
32145
32733
  className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2"
32146
32734
  }, "Availability"), /* @__PURE__ */ React.createElement("div", {
32147
32735
  className: "min-w-0 overflow-hidden border border-gray-200 rounded-lg p-4 bg-gray-50/50 space-y-4"
@@ -33640,6 +34228,7 @@ var init_DiscountDetailsPage = __esm({
33640
34228
  category: "Category",
33641
34229
  cart: "Cart",
33642
34230
  paymentMethod: "Payment method",
34231
+ deviceType: "Device type",
33643
34232
  order: "Order",
33644
34233
  quantity: "Quantity",
33645
34234
  time: "Time",
@@ -33731,6 +34320,15 @@ function conditionToRule(c) {
33731
34320
  v: c.paymentMethod ?? ""
33732
34321
  }
33733
34322
  };
34323
+ case "deviceType":
34324
+ return {
34325
+ ...base,
34326
+ type: "deviceType",
34327
+ comparisonOperator: "eq",
34328
+ value: {
34329
+ v: c.deviceType ?? ""
34330
+ }
34331
+ };
33734
34332
  case "category":
33735
34333
  return {
33736
34334
  ...base,
@@ -33903,6 +34501,12 @@ function ruleTreeToFriendly(rules) {
33903
34501
  kind: "paymentMethod",
33904
34502
  paymentMethod: v
33905
34503
  };
34504
+ case "deviceType":
34505
+ return {
34506
+ id: rule._clientId ?? uid(),
34507
+ kind: "deviceType",
34508
+ deviceType: v
34509
+ };
33906
34510
  case "category":
33907
34511
  return {
33908
34512
  id: rule._clientId ?? uid(),
@@ -34465,6 +35069,9 @@ function ConditionCard({ condition, onChange, onRemove, eventsOn }) {
34465
35069
  paymentMethod: /* @__PURE__ */ React.createElement(DollarSign, {
34466
35070
  className: "h-3.5 w-3.5 text-indigo-500"
34467
35071
  }),
35072
+ deviceType: /* @__PURE__ */ React.createElement(DollarSign, {
35073
+ className: "h-3.5 w-3.5 text-cyan-500"
35074
+ }),
34468
35075
  category: /* @__PURE__ */ React.createElement(Package, {
34469
35076
  className: "h-3.5 w-3.5 text-teal-500"
34470
35077
  }),
@@ -34507,6 +35114,8 @@ function ConditionCard({ condition, onChange, onRemove, eventsOn }) {
34507
35114
  }, "User type"), /* @__PURE__ */ React.createElement(SelectItem, {
34508
35115
  value: "paymentMethod"
34509
35116
  }, "Payment method"), /* @__PURE__ */ React.createElement(SelectItem, {
35117
+ value: "deviceType"
35118
+ }, "Device type"), /* @__PURE__ */ React.createElement(SelectItem, {
34510
35119
  value: "category"
34511
35120
  }, "Category"), /* @__PURE__ */ React.createElement(SelectItem, {
34512
35121
  value: "customers"
@@ -34660,7 +35269,21 @@ function ConditionCard({ condition, onChange, onRemove, eventsOn }) {
34660
35269
  value: "cod"
34661
35270
  }, "Cash on Delivery"), /* @__PURE__ */ React.createElement(SelectItem, {
34662
35271
  value: "wallet"
34663
- }, "Wallet"))), condition.kind === "category" && /* @__PURE__ */ React.createElement(CategoryPicker, {
35272
+ }, "Wallet"))), condition.kind === "deviceType" && /* @__PURE__ */ React.createElement(Select, {
35273
+ value: condition.deviceType ?? "",
35274
+ onValueChange: /* @__PURE__ */ __name((v) => onChange({
35275
+ ...condition,
35276
+ deviceType: v
35277
+ }), "onValueChange")
35278
+ }, /* @__PURE__ */ React.createElement(SelectTrigger, {
35279
+ className: "h-8 text-xs"
35280
+ }, /* @__PURE__ */ React.createElement(SelectValue, {
35281
+ placeholder: "Select device type\u2026"
35282
+ })), /* @__PURE__ */ React.createElement(SelectContent, null, /* @__PURE__ */ React.createElement(SelectItem, {
35283
+ value: "web"
35284
+ }, "Web"), /* @__PURE__ */ React.createElement(SelectItem, {
35285
+ value: "mobile"
35286
+ }, "Mobile"))), condition.kind === "category" && /* @__PURE__ */ React.createElement(CategoryPicker, {
34664
35287
  value: condition.categoryId,
34665
35288
  label: condition.categoryName,
34666
35289
  onChange: /* @__PURE__ */ __name((id, name) => onChange({
@@ -37885,6 +38508,11 @@ var init_AdminPageResolver = __esm({
37885
38508
  field: "email",
37886
38509
  displayName: "Email"
37887
38510
  },
38511
+ {
38512
+ field: "inviteStatus",
38513
+ displayName: "Invite status",
38514
+ hideInForm: true
38515
+ },
37888
38516
  {
37889
38517
  field: "blocked",
37890
38518
  displayName: "Blocked",
@@ -38090,6 +38718,29 @@ function LayoutSettingsPage() {
38090
38718
  footer: JSON.stringify(footerValues)
38091
38719
  })
38092
38720
  });
38721
+ if (navbarConfig.logo) {
38722
+ await fetch("/api/settings/store", {
38723
+ method: "PUT",
38724
+ headers: {
38725
+ "Content-Type": "application/json"
38726
+ },
38727
+ body: JSON.stringify({
38728
+ invoiceLogoUrl: {
38729
+ value: navbarConfig.logo,
38730
+ type: "public"
38731
+ },
38732
+ companyLogo: {
38733
+ value: navbarConfig.logo,
38734
+ type: "public"
38735
+ },
38736
+ logo: {
38737
+ value: navbarConfig.logo,
38738
+ type: "public"
38739
+ }
38740
+ })
38741
+ }).catch(() => {
38742
+ });
38743
+ }
38093
38744
  } finally {
38094
38745
  setSaving(false);
38095
38746
  }
@@ -38516,18 +39167,26 @@ var init_config = __esm({
38516
39167
  ];
38517
39168
  }
38518
39169
  });
39170
+ function ForceAdminLightMode() {
39171
+ useForceAdminLightMode();
39172
+ return null;
39173
+ }
38519
39174
  function CmsProviders({ children }) {
38520
39175
  return /* @__PURE__ */ React.createElement(ThemeProvider, {
38521
39176
  attribute: "class",
38522
- defaultTheme: "system",
38523
- enableSystem: true
38524
- }, children, /* @__PURE__ */ React.createElement(Toaster, {
39177
+ defaultTheme: "light",
39178
+ forcedTheme: "light",
39179
+ enableSystem: false,
39180
+ enableColorScheme: true
39181
+ }, /* @__PURE__ */ React.createElement(ForceAdminLightMode, null), children, /* @__PURE__ */ React.createElement(Toaster, {
38525
39182
  position: "top-right"
38526
39183
  }));
38527
39184
  }
38528
39185
  var init_CmsProviders = __esm({
38529
39186
  "src/admin/CmsProviders.tsx"() {
38530
39187
  "use client";
39188
+ init_force_light_mode();
39189
+ __name(ForceAdminLightMode, "ForceAdminLightMode");
38531
39190
  __name(CmsProviders, "CmsProviders");
38532
39191
  }
38533
39192
  });