@mohasinac/appkit 3.4.3 → 3.4.5

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 (32) hide show
  1. package/dist/_internal/client/features/maintenance/views/AnalysisRunnerView.js +2 -9
  2. package/dist/features/account/components/NotificationPreferencesPanel.js +2 -11
  3. package/dist/features/account/components/UserSidebar.js +4 -4
  4. package/dist/features/admin/components/AdminBrandsView.js +7 -9
  5. package/dist/features/admin/components/AdminBundlesView.js +10 -14
  6. package/dist/features/admin/components/AdminCarouselEditorView.js +1 -5
  7. package/dist/features/admin/components/AdminCategoriesView.js +10 -14
  8. package/dist/features/admin/components/AdminFaqsView.js +7 -9
  9. package/dist/features/admin/components/AdminFeatureFlagsView.js +1 -1
  10. package/dist/features/admin/components/AdminFeaturesView.js +9 -18
  11. package/dist/features/admin/components/AdminNotificationsView.js +4 -6
  12. package/dist/features/admin/components/AdminSessionsView.js +7 -9
  13. package/dist/features/admin/components/AdminSidebar.js +4 -4
  14. package/dist/features/admin/components/AdminSiteSettingsView.js +1 -1
  15. package/dist/features/admin/components/QuickActionsPanel.js +2 -2
  16. package/dist/features/seller/components/PrintCenterView.js +8 -2
  17. package/dist/features/seller/components/SellerBidsView.js +4 -1
  18. package/dist/features/seller/components/SellerCouponsView.js +7 -9
  19. package/dist/features/seller/components/SellerReviewsView.js +4 -1
  20. package/dist/features/seller/components/SellerSidebar.js +4 -4
  21. package/dist/styles.css +40 -1
  22. package/dist/tailwind-utilities.css +1 -1
  23. package/dist/tokens/themes/default-dark.js +28 -0
  24. package/dist/tokens/themes/default-light.js +28 -0
  25. package/dist/tokens/themes/required.d.ts +1 -1
  26. package/dist/tokens/themes/required.js +30 -0
  27. package/dist/tokens/tokens.css +39 -0
  28. package/dist/ui/components/Toggle.d.ts +3 -1
  29. package/dist/ui/components/Toggle.js +2 -2
  30. package/dist/ui/components/surface-tokens.d.ts +113 -113
  31. package/dist/ui/components/surface-tokens.js +104 -102
  32. package/package.json +1 -1
@@ -2,7 +2,7 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { normalizeError } from "../../../../../errors/normalize";
4
4
  import * as React from "react";
5
- import { Div, Heading, Li, Section, Span, Table, Tbody, Td, Text, Th, Thead, Tr, Ul } from "@mohasinac/appkit";
5
+ import { Button, Div, Heading, Li, Section, Span, Table, Tbody, Td, Text, Th, Thead, Tr, Ul } from "@mohasinac/appkit";
6
6
  export function AnalysisRunnerView() {
7
7
  const [days, setDays] = React.useState(7);
8
8
  const [source, setSource] = React.useState("all");
@@ -34,14 +34,7 @@ export function AnalysisRunnerView() {
34
34
  setRunning(false);
35
35
  }
36
36
  }
37
- return (_jsxs(Div, { style: { padding: "1.5rem", maxWidth: "1200px", margin: "0 auto" }, children: [_jsx(Heading, { level: 1, style: { fontSize: "1.5rem", fontWeight: 600 }, children: "Maintenance analysis" }), _jsxs(Div, { style: { display: "flex", gap: "1rem", alignItems: "center", margin: "1rem 0" }, children: [_jsxs("label", { children: ["Days back:\u00A0", _jsx("input", { type: "number", min: 1, max: 30, value: days, onChange: (e) => setDays(Math.max(1, Math.min(30, Number(e.target.value) || 7))), style: { width: 80, padding: "0.35rem 0.5rem", border: "1px solid var(--appkit-color-border)", borderRadius: 4 } })] }), _jsxs("label", { children: ["Source:\u00A0", _jsxs("select", { value: source, onChange: (e) => setSource(e.target.value), style: { padding: "0.35rem 0.5rem", border: "1px solid var(--appkit-color-border)", borderRadius: 4 }, children: [_jsx("option", { value: "all", children: "all" }), _jsx("option", { value: "vercel", children: "server (vercel)" }), _jsx("option", { value: "client", children: "client" }), _jsx("option", { value: "function", children: "function" })] })] }), _jsx("button", { type: "button", onClick: run, disabled: running, style: {
38
- padding: "0.5rem 1rem",
39
- background: "var(--appkit-color-primary)",
40
- color: "var(--appkit-color-surface)",
41
- border: 0,
42
- borderRadius: 4,
43
- cursor: running ? "wait" : "pointer",
44
- }, children: running ? "Running…" : "Run analysis" })] }), error ? _jsx(Text, { as: "p", style: { color: "var(--appkit-color-error)" }, children: error }) : null, report ? _jsx(ReportView, { report: report }) : null] }));
37
+ return (_jsxs(Div, { style: { padding: "1.5rem", maxWidth: "1200px", margin: "0 auto" }, children: [_jsx(Heading, { level: 1, style: { fontSize: "1.5rem", fontWeight: 600 }, children: "Maintenance analysis" }), _jsxs(Div, { style: { display: "flex", gap: "1rem", alignItems: "center", margin: "1rem 0" }, children: [_jsxs("label", { children: ["Days back:\u00A0", _jsx("input", { type: "number", min: 1, max: 30, value: days, onChange: (e) => setDays(Math.max(1, Math.min(30, Number(e.target.value) || 7))), style: { width: 80, padding: "0.35rem 0.5rem", border: "1px solid var(--appkit-color-border)", borderRadius: 4 } })] }), _jsxs("label", { children: ["Source:\u00A0", _jsxs("select", { value: source, onChange: (e) => setSource(e.target.value), style: { padding: "0.35rem 0.5rem", border: "1px solid var(--appkit-color-border)", borderRadius: 4 }, children: [_jsx("option", { value: "all", children: "all" }), _jsx("option", { value: "vercel", children: "server (vercel)" }), _jsx("option", { value: "client", children: "client" }), _jsx("option", { value: "function", children: "function" })] })] }), _jsx(Button, { type: "button", onClick: run, isLoading: running, children: "Run analysis" })] }), error ? _jsx(Text, { as: "p", style: { color: "var(--appkit-color-error)" }, children: error }) : null, report ? _jsx(ReportView, { report: report }) : null] }));
45
38
  }
46
39
  function ReportView({ report }) {
47
40
  return (_jsxs(Div, { children: [_jsxs(Text, { as: "p", style: { color: "var(--appkit-color-text-muted)" }, children: ["Generated ", report.generatedAt, ". Window: ", report.window.days, "d. Total: ", report.totalErrors, ". Unique users: ", report.uniqueUsers, "."] }), _jsx(ReportSection, { title: "Top codes", children: _jsxs(Table, { style: { width: "100%", fontSize: "0.85rem" }, children: [_jsx(Thead, { children: _jsxs(Tr, { children: [_jsx(Th, { align: "left", children: "Code" }), _jsx(Th, { align: "right", children: "Count" }), _jsx(Th, { align: "right", children: "User impact" })] }) }), _jsx(Tbody, { children: report.topCodes.map((c) => (_jsxs(Tr, { children: [_jsx(Td, { style: { fontFamily: "monospace" }, children: c.code }), _jsx(Td, { align: "right", children: c.count }), _jsx(Td, { align: "right", children: c.userImpact })] }, c.code))) })] }) }), _jsx(ReportSection, { title: "Top routes", children: _jsxs(Table, { style: { width: "100%", fontSize: "0.85rem" }, children: [_jsx(Thead, { children: _jsxs(Tr, { children: [_jsx(Th, { align: "left", children: "Route" }), _jsx(Th, { align: "left", children: "Source" }), _jsx(Th, { align: "right", children: "Count" })] }) }), _jsx(Tbody, { children: report.topRoutes.map((r) => (_jsxs(Tr, { children: [_jsx(Td, { style: { fontFamily: "monospace" }, children: r.route }), _jsx(Td, { children: r.source }), _jsx(Td, { align: "right", children: r.count })] }, `${r.source}:${r.route}`))) })] }) }), report.stackClusters.length > 0 ? (_jsx(ReportSection, { title: `Stack clusters (≥5)`, children: _jsx(Ul, { children: report.stackClusters.map((c) => (_jsxs(Li, { style: { marginBottom: "0.5rem", fontSize: "0.82rem" }, children: [_jsxs(Span, { weight: "bold", children: [c.count, "\u00D7"] }), " ", _jsx(Span, { style: { fontFamily: "monospace" }, children: c.signature }), _jsxs(Div, { style: { color: "var(--appkit-color-text-muted)" }, children: ["sample: ", c.sampleMessage] })] }, c.signature))) }) })) : null, report.burstWindows.length > 0 ? (_jsx(ReportSection, { title: "5xx burst windows", children: _jsx(Ul, { children: report.burstWindows.map((b) => (_jsxs(Li, { children: [b.start, " \u2014 ", b.count, " errors (", b.multiplier, "\u00D7 avg)"] }, b.start))) }) })) : null, _jsx(ReportSection, { title: "Recommendations", children: _jsx(Ul, { children: report.recommendations.map((r, i) => _jsx(Li, { children: r }, i)) }) })] }));
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useState, useEffect, useCallback } from "react";
4
- import { Button, Div, Row, Span, Stack, Text, useToast } from "../../../ui";
4
+ import { Button, Div, Row, Span, Stack, Text, Toggle, useToast } from "../../../ui";
5
5
  import { useSiteSettings } from "../../../core/hooks/useSiteSettings";
6
6
  import { normalizeError } from "../../../errors/normalize";
7
7
  const __O = {
@@ -19,16 +19,7 @@ const TYPE_ROWS = [
19
19
  ];
20
20
  // ─── Toggle row ─────────────────────────────────────────────────────────────
21
21
  function ToggleRow({ label, description, checked, onChange, disabled, }) {
22
- return (_jsxs(Row, { align: "center", justify: "between", gap: "md", className: "border-b last:border-0 border-[var(--appkit-color-border)]", padding: "y-sm", children: [_jsxs(Div, { className: "min-w-0", children: [_jsx(Text, { className: "text-[var(--appkit-color-text)]", size: "sm", weight: "medium", children: label }), _jsx(Text, { variant: "secondary", className: "mt-0.5", size: "xs", children: description })] }), _jsx("button", { type: "button", role: "switch", "aria-checked": checked, "aria-label": label, disabled: disabled, onClick: () => onChange(!checked), className: [
23
- "relative inline-flex h-5 w-9 shrink-0 cursor-pointer rounded-full border-2 border-transparent",
24
- "transition-colors duration-200 ease-in-out focus-visible:outline-none focus-visible:ring-2",
25
- "focus-visible:ring-[var(--appkit-color-primary)] focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
26
- checked ? "bg-[var(--appkit-color-primary)]" : "bg-[var(--appkit-color-text-faint)]",
27
- ].join(" "), children: _jsx(Span, { className: [
28
- "pointer-events-none inline-block h-4 w-4 transform rounded-full bg-[var(--appkit-color-surface)] shadow-lg",
29
- "ring-0 transition duration-200 ease-in-out",
30
- checked ? "translate-x-4" : "translate-x-0",
31
- ].join(" ") }) })] }));
22
+ return (_jsxs(Row, { align: "center", justify: "between", gap: "md", className: "border-b last:border-0 border-[var(--appkit-color-border)]", padding: "y-sm", children: [_jsxs(Div, { className: "min-w-0", children: [_jsx(Text, { className: "text-[var(--appkit-color-text)]", size: "sm", weight: "medium", children: label }), _jsx(Text, { variant: "secondary", className: "mt-0.5", size: "xs", children: description })] }), _jsx(Toggle, { checked: checked, ariaLabel: label, disabled: disabled, onChange: onChange, size: "sm" })] }));
32
23
  }
33
24
  // ─── Section card ───────────────────────────────────────────────────────────
34
25
  function SectionCard({ title, children }) {
@@ -4,7 +4,7 @@ import { useState, useCallback, useEffect } from "react";
4
4
  import { createPortal } from "react-dom";
5
5
  import Link from "next/link";
6
6
  import { usePathname } from "next/navigation";
7
- import { ConfirmDeleteModal, Div, Li, Nav, Row, Span, Stack, Ul } from "../../../ui";
7
+ import { Button, ConfirmDeleteModal, Div, IconButton, Li, Nav, Row, Span, Stack, Ul } from "../../../ui";
8
8
  import { BottomSheet } from "../../layout/BottomSheet";
9
9
  import { SidebarCollapseToggle } from "../../../_internal/client/features/layout/SidebarCollapseToggle";
10
10
  const __O = {
@@ -55,13 +55,13 @@ function DrawerContent({ groups, items, activeHref, onItemClick, }) {
55
55
  return (_jsx(Nav, { "aria-label": "User navigation", padding: "y-xs", children: groups.map((group) => {
56
56
  const isOpen = openGroups[group.title] ?? false;
57
57
  const hasActive = group.items.some((i) => activeHref === i.href || activeHref.startsWith(i.href + "/"));
58
- return (_jsxs(Div, { className: "mb-0.5", children: [_jsxs("button", { type: "button", onClick: () => toggle(group.title), className: `flex w-full items-center justify-between px-4 py-2 text-[0.6875rem] font-semibold uppercase tracking-widest transition-colors ${hasActive && !isOpen
58
+ return (_jsxs(Div, { className: "mb-0.5", children: [_jsx(Button, { type: "button", variant: "ghost", onClick: () => toggle(group.title), paddingX: "md", paddingY: "sm", weight: "semibold", rounded: "none", className: `w-full text-[0.6875rem] uppercase tracking-widest transition-colors ${hasActive && !isOpen
59
59
  ? "text-primary-600 dark:text-primary-400"
60
- : "text-[var(--appkit-color-text-faint)] hover:text-[var(--appkit-color-text-muted)] hover:text-[var(--appkit-color-text-muted)]"}`, children: [_jsx(Span, { children: group.title }), _jsx("svg", { className: `w-3 h-3 transition-transform duration-150 ${isOpen ? "rotate-180" : ""}`, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2.5, d: "M19 9l-7 7-7-7" }) })] }), isOpen && (_jsx(Ul, { paddingX: "x-sm", paddingY: "y-bottom-xs", spacing: "2xs", children: group.items.map((item) => (_jsx(Li, { children: _jsx(NavLink, { item: item, isActive: isNavItemActive(item, activeHref), onClick: onItemClick }) }, item.href))) }))] }, group.title));
60
+ : "text-[var(--appkit-color-text-faint)] hover:text-[var(--appkit-color-text-muted)]"}`, children: _jsxs(Row, { align: "center", justify: "between", className: "w-full", children: [_jsx(Span, { children: group.title }), _jsx("svg", { className: `w-3 h-3 transition-transform duration-150 ${isOpen ? "rotate-180" : ""}`, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2.5, d: "M19 9l-7 7-7-7" }) })] }) }), isOpen && (_jsx(Ul, { paddingX: "x-sm", paddingY: "y-bottom-xs", spacing: "2xs", children: group.items.map((item) => (_jsx(Li, { children: _jsx(NavLink, { item: item, isActive: isNavItemActive(item, activeHref), onClick: onItemClick }) }, item.href))) }))] }, group.title));
61
61
  }) }));
62
62
  }
63
63
  function DrawerPanel({ title, onClose, children, }) {
64
- return (_jsxs(Div, { className: "hidden lg:block", children: [_jsx(Div, { surface: "overlay-xs", className: "fixed inset-0 z-40 backdrop-blur-sm", onClick: onClose, "aria-hidden": "true" }), _jsxs(Stack, { border: "default", shadow: "2xl", role: "dialog", "aria-modal": "true", "aria-label": title, className: "fixed top-0 right-0 z-50 h-full w-64 border-l", surface: "default", children: [_jsxs(Row, { border: "bottom-subtle", paddingY: "y-sm-tall", className: "shrink-0", padding: "x-md", align: "center", justify: "between", children: [_jsx(Span, { size: "xs", weight: "semibold", transform: "uppercase", color: "muted", children: title }), _jsx("button", { type: "button", onClick: onClose, "aria-label": "Close", className: "flex items-center justify-center w-7 h-7 rounded-md text-zinc-400 hover:bg-[var(--appkit-color-surface)] hover:bg-[var(--appkit-color-surface-elevated)] hover:text-zinc-700 hover:text-[var(--appkit-color-text-muted)] transition-colors", children: _jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })] }), _jsx(Div, { className: `flex-1 ${__O.yAuto}`, children: children })] })] }));
64
+ return (_jsxs(Div, { className: "hidden lg:block", children: [_jsx(Div, { surface: "overlay-xs", className: "fixed inset-0 z-40 backdrop-blur-sm", onClick: onClose, "aria-hidden": "true" }), _jsxs(Stack, { border: "default", shadow: "2xl", role: "dialog", "aria-modal": "true", "aria-label": title, className: "fixed top-0 right-0 z-50 h-full w-64 border-l", surface: "default", children: [_jsxs(Row, { border: "bottom-subtle", paddingY: "y-sm-tall", className: "shrink-0", padding: "x-md", align: "center", justify: "between", children: [_jsx(Span, { size: "xs", weight: "semibold", transform: "uppercase", color: "muted", children: title }), _jsx(IconButton, { "aria-label": "Close", variant: "ghost", size: "sm", onClick: onClose, icon: _jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })] }), _jsx(Div, { className: `flex-1 ${__O.yAuto}`, children: children })] })] }));
65
65
  }
66
66
  export function UserSidebar({ items, groups, mobileOpen = false, onCloseMobile, desktopOpen = false, onToggle, variant = "overlay" }) {
67
67
  const pathname = usePathname();
@@ -1,9 +1,9 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { Row, SIEVE_OP, Stack, sieveFilter } from "@mohasinac/appkit";
3
+ import { SIEVE_OP, Stack, sieveFilter } from "@mohasinac/appkit";
4
4
  import { sortBy } from "@mohasinac/appkit";
5
5
  import React from "react";
6
- import { ListingLayout, Text } from "../../../ui";
6
+ import { FilterChipGroup, ListingLayout, Text } from "../../../ui";
7
7
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
8
8
  import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
9
9
  import { toRecordArray, toRelativeDate, toStringValue, } from "../hooks/useAdminListingData";
@@ -76,13 +76,11 @@ const ADMIN_BRANDS_CONFIG = {
76
76
  },
77
77
  },
78
78
  ],
79
- renderFilterPanel: ({ pendingFilters, setPendingFilters }) => (_jsxs(Stack, { gap: "sm", children: [_jsx(Text, { className: "tracking-widest", color: "muted", size: "xs", weight: "semibold", transform: "uppercase", children: "Status" }), _jsx(Row, { wrap: true, gap: "sm", children: [
80
- { label: "All", value: "" },
81
- { label: "Active", value: "true" },
82
- { label: "Inactive", value: "false" },
83
- ].map((opt) => (_jsx("button", { type: "button", onClick: () => setPendingFilters((p) => ({ ...p, isActive: opt.value })), className: `rounded-full px-3 py-1 text-xs font-medium border transition-colors ${(pendingFilters.isActive || "") === opt.value
84
- ? "bg-primary text-white border-primary"
85
- : "border-[var(--appkit-color-border)] text-[var(--appkit-color-text-muted)] hover:bg-zinc-50 hover:bg-[var(--appkit-color-surface-elevated)]"}`, children: opt.label }, opt.label))) })] })),
79
+ renderFilterPanel: ({ pendingFilters, setPendingFilters }) => (_jsx(FilterChipGroup, { label: "Status", tabs: [
80
+ { id: "All", label: "All" },
81
+ { id: "true", label: "Active" },
82
+ { id: "false", label: "Inactive" },
83
+ ], value: pendingFilters.isActive || "", onChange: (v) => setPendingFilters((p) => ({ ...p, isActive: v })) })),
86
84
  renderEditor: ({ editId, closePanel }) => (_jsx(AdminBrandEditorView, { brandId: editId ?? undefined, onSaved: closePanel, onDeleted: closePanel, embedded: true })),
87
85
  resolveEditorTitle: ({ isCreate }) => (isCreate ? "Add Brand" : "Edit Brand"),
88
86
  };
@@ -1,10 +1,10 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { normalizeError } from "../../../errors/normalize";
4
- import { Row, SIEVE_OP, sieveFilter } from "@mohasinac/appkit";
4
+ import { SIEVE_OP, sieveFilter } from "@mohasinac/appkit";
5
5
  import { sortBy } from "@mohasinac/appkit";
6
6
  import { useState, useCallback } from "react";
7
- import { Badge, Button, Stack, Text, TextLink, useToast } from "../../../ui";
7
+ import { Badge, Button, FilterChipGroup, Stack, Text, TextLink, useToast } from "../../../ui";
8
8
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
9
9
  import { toRecordArray, toRelativeDate, toStringValue, } from "../hooks/useAdminListingData";
10
10
  import { DataListingView } from "./DataListingView";
@@ -124,18 +124,14 @@ export function AdminBundlesView({ getEditHref, newHref }) {
124
124
  }),
125
125
  ],
126
126
  renderRowActions: (row) => (_jsx(Button, { variant: "ghost", size: "sm", isLoading: rebuildingId === row.id, disabled: rebuildingId === row.id, onClick: () => void handleRebuild(row.id), children: ACTIONS.ADMIN["rebuild-bundle"].label })),
127
- renderFilterPanel: ({ pendingFilters, setPendingFilters }) => (_jsxs(_Fragment, { children: [_jsxs(Stack, { gap: "sm", children: [_jsx(Text, { className: "tracking-widest", color: "muted", size: "xs", weight: "semibold", transform: "uppercase", children: "Status" }), _jsx(Row, { wrap: true, gap: "sm", children: [
128
- { label: "All", value: "" },
129
- { label: "Active", value: "true" },
130
- { label: "Inactive", value: "false" },
131
- ].map((opt) => (_jsx("button", { type: "button", onClick: () => setPendingFilters((p) => ({ ...p, isActive: opt.value })), className: `rounded-full px-3 py-1 text-xs font-medium border transition-colors ${(pendingFilters.isActive || "") === opt.value
132
- ? "bg-primary text-white border-primary"
133
- : "border-[var(--appkit-color-border)] text-[var(--appkit-color-text-muted)] hover:bg-zinc-50 hover:bg-[var(--appkit-color-surface-elevated)]"}`, children: opt.label }, opt.label))) })] }), _jsxs(Stack, { gap: "sm", children: [_jsx(Text, { className: "tracking-widest", color: "muted", size: "xs", weight: "semibold", transform: "uppercase", children: "Stock" }), _jsx(Row, { wrap: true, gap: "sm", children: [
134
- { label: "All", value: "" },
135
- { label: "Sold out", value: "out_of_stock" },
136
- ].map((opt) => (_jsx("button", { type: "button", onClick: () => setPendingFilters((p) => ({ ...p, bundleStockStatus: opt.value })), className: `rounded-full px-3 py-1 text-xs font-medium border transition-colors ${(pendingFilters.bundleStockStatus || "") === opt.value
137
- ? "bg-primary text-white border-primary"
138
- : "border-[var(--appkit-color-border)] text-[var(--appkit-color-text-muted)] hover:bg-zinc-50 hover:bg-[var(--appkit-color-surface-elevated)]"}`, children: opt.label }, opt.label))) })] })] })),
127
+ renderFilterPanel: ({ pendingFilters, setPendingFilters }) => (_jsxs(_Fragment, { children: [_jsx(FilterChipGroup, { label: "Status", tabs: [
128
+ { id: "All", label: "All" },
129
+ { id: "true", label: "Active" },
130
+ { id: "false", label: "Inactive" },
131
+ ], value: pendingFilters.isActive || "", onChange: (v) => setPendingFilters((p) => ({ ...p, isActive: v })) }), _jsx(FilterChipGroup, { label: "Stock", tabs: [
132
+ { id: "All", label: "All" },
133
+ { id: "out_of_stock", label: "Sold out" },
134
+ ], value: pendingFilters.bundleStockStatus || "", onChange: (v) => setPendingFilters((p) => ({ ...p, bundleStockStatus: v })) })] })),
139
135
  };
140
136
  return _jsx(DataListingView, { config: config });
141
137
  }
@@ -69,11 +69,7 @@ function ZonePicker({ selected, onChange, disabled, }) {
69
69
  const zones = [1, 2, 3, 4, 5, 6];
70
70
  return (_jsxs(Div, { children: [_jsx(Text, { className: "mb-1", color: "muted", size: "xs", children: "Zone (row \u00D7 col grid)" }), _jsx(Div, { layout: "grid", gap: "1", className: "grid-rows-2 grid-cols-3 w-[150px]", children: zones.map((z) => {
71
71
  const isDisabled = disabled?.(z) ?? false;
72
- return (_jsx("button", { type: "button", disabled: isDisabled, onClick: () => !isDisabled && onChange(z), className: `rounded text-xs font-mono py-2 border transition-colors ${selected === z
73
- ? "bg-primary text-white border-primary"
74
- : isDisabled
75
- ? "bg-[var(--appkit-color-surface)] text-zinc-300 border-zinc-200 bg-[var(--appkit-color-surface-elevated)] border-[var(--appkit-color-border)] cursor-not-allowed"
76
- : "bg-[var(--appkit-color-surface)] border-zinc-300 text-zinc-700 hover:border-primary bg-[var(--appkit-color-surface)] border-[var(--appkit-color-border)] text-[var(--appkit-color-text-muted)]"}`, children: z }, z));
72
+ return (_jsx(Button, { type: "button", variant: selected === z ? "primary" : "outline", size: "sm", disabled: isDisabled, paddingY: "sm", textSize: "xs", className: "font-mono", onClick: () => !isDisabled && onChange(z), children: z }, z));
77
73
  }) }), _jsx(Text, { className: "text-[10px] mt-1", color: "faint", children: "Row 1 = zones 1\u20133 \u00B7 Row 2 = zones 4\u20136" })] }));
78
74
  }
79
75
  // ── Background Editor ────────────────────────────────────────────────────────
@@ -1,9 +1,9 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { Row, SIEVE_OP, Stack, sieveFilter } from "@mohasinac/appkit";
3
+ import { SIEVE_OP, Stack, sieveFilter } from "@mohasinac/appkit";
4
4
  import { sortBy } from "@mohasinac/appkit";
5
5
  import React from "react";
6
- import { Heading, ListingLayout, Span, Text } from "../../../ui";
6
+ import { FilterChipGroup, Heading, ListingLayout, Span, Text } from "../../../ui";
7
7
  import { CATEGORY_ENDPOINTS } from "../../../constants/api-endpoints";
8
8
  import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
9
9
  import { toRecordArray, toRelativeDate, toStringValue, } from "../hooks/useAdminListingData";
@@ -85,18 +85,14 @@ const ADMIN_CATEGORIES_CONFIG = {
85
85
  },
86
86
  },
87
87
  ],
88
- renderFilterPanel: ({ pendingFilters, setPendingFilters }) => (_jsxs(_Fragment, { children: [_jsxs(Stack, { gap: "sm", children: [_jsx(Text, { className: "tracking-widest", color: "muted", size: "xs", weight: "semibold", transform: "uppercase", children: "Active" }), _jsx(Row, { wrap: true, gap: "sm", children: [
89
- { label: "All", value: "" },
90
- { label: "Active", value: "true" },
91
- { label: "Inactive", value: "false" },
92
- ].map((opt) => (_jsx("button", { type: "button", onClick: () => setPendingFilters((p) => ({ ...p, isActive: opt.value })), className: `rounded-full px-3 py-1 text-xs font-medium border transition-colors ${(pendingFilters.isActive || "") === opt.value
93
- ? "bg-primary text-white border-primary"
94
- : "border-[var(--appkit-color-border)] text-[var(--appkit-color-text-muted)] hover:bg-zinc-50 hover:bg-[var(--appkit-color-surface-elevated)]"}`, children: opt.label }, opt.label))) })] }), _jsxs(Stack, { gap: "sm", children: [_jsx(Text, { className: "tracking-widest", color: "muted", size: "xs", weight: "semibold", transform: "uppercase", children: "Featured" }), _jsx(Row, { wrap: true, gap: "sm", children: [
95
- { label: "All", value: "" },
96
- { label: "Featured only", value: "true" },
97
- ].map((opt) => (_jsx("button", { type: "button", onClick: () => setPendingFilters((p) => ({ ...p, isFeatured: opt.value })), className: `rounded-full px-3 py-1 text-xs font-medium border transition-colors ${(pendingFilters.isFeatured || "") === opt.value
98
- ? "bg-primary text-white border-primary"
99
- : "border-[var(--appkit-color-border)] text-[var(--appkit-color-text-muted)] hover:bg-zinc-50 hover:bg-[var(--appkit-color-surface-elevated)]"}`, children: opt.label }, opt.label))) })] })] })),
88
+ renderFilterPanel: ({ pendingFilters, setPendingFilters }) => (_jsxs(_Fragment, { children: [_jsx(FilterChipGroup, { label: "Active", tabs: [
89
+ { id: "All", label: "All" },
90
+ { id: "true", label: "Active" },
91
+ { id: "false", label: "Inactive" },
92
+ ], value: pendingFilters.isActive || "", onChange: (v) => setPendingFilters((p) => ({ ...p, isActive: v })) }), _jsx(FilterChipGroup, { label: "Featured", tabs: [
93
+ { id: "All", label: "All" },
94
+ { id: "true", label: "Featured only" },
95
+ ], value: pendingFilters.isFeatured || "", onChange: (v) => setPendingFilters((p) => ({ ...p, isFeatured: v })) })] })),
100
96
  renderEditor: ({ editId, closePanel }) => (_jsx(AdminCategoryEditorView, { categoryId: editId ?? undefined, onSaved: closePanel, onDeleted: closePanel, embedded: true })),
101
97
  resolveEditorTitle: ({ isCreate }) => (isCreate ? "Add Category" : "Edit Category"),
102
98
  };
@@ -1,9 +1,9 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { Row, SIEVE_OP, Stack, sieveFilter } from "@mohasinac/appkit";
3
+ import { SIEVE_OP, Stack, sieveFilter } from "@mohasinac/appkit";
4
4
  import { sortBy } from "@mohasinac/appkit";
5
5
  import React, { useMemo } from "react";
6
- import { Heading, ListingLayout, Span, Text } from "../../../ui";
6
+ import { FilterChipGroup, Heading, ListingLayout, Span, Text } from "../../../ui";
7
7
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
8
8
  import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
9
9
  import { buildBulkAction } from "../../../_internal/shared/actions/bulk-helpers";
@@ -81,13 +81,11 @@ export function AdminFaqsView({ children, onBulkArchive, onBulkDelete, ...props
81
81
  ]
82
82
  : []),
83
83
  ],
84
- renderFilterPanel: ({ pendingFilters, setPendingFilters }) => (_jsxs(Stack, { gap: "sm", children: [_jsx(Text, { className: "tracking-widest", color: "muted", size: "xs", weight: "semibold", transform: "uppercase", children: "Status" }), _jsx(Row, { wrap: true, gap: "sm", children: [
85
- { label: "All", value: "" },
86
- { label: "Published", value: "true" },
87
- { label: "Draft", value: "false" },
88
- ].map((opt) => (_jsx("button", { type: "button", onClick: () => setPendingFilters((p) => ({ ...p, isActive: opt.value })), className: `rounded-full px-3 py-1 text-xs font-medium border transition-colors ${(pendingFilters.isActive || "") === opt.value
89
- ? "bg-primary text-white border-primary"
90
- : "border-[var(--appkit-color-border)] text-[var(--appkit-color-text-muted)] hover:bg-zinc-50 hover:bg-[var(--appkit-color-surface-elevated)]"}`, children: opt.label }, opt.label))) })] })),
84
+ renderFilterPanel: ({ pendingFilters, setPendingFilters }) => (_jsx(FilterChipGroup, { label: "Status", tabs: [
85
+ { id: "All", label: "All" },
86
+ { id: "true", label: "Published" },
87
+ { id: "false", label: "Draft" },
88
+ ], value: pendingFilters.isActive || "", onChange: (v) => setPendingFilters((p) => ({ ...p, isActive: v })) })),
91
89
  renderEditor: ({ editId, closePanel }) => (_jsx(AdminFaqEditorView, { faqId: editId ?? undefined, onSaved: closePanel, onDeleted: closePanel, embedded: true })),
92
90
  resolveEditorTitle: ({ isCreate }) => (isCreate ? "Add FAQ" : "Edit FAQ"),
93
91
  }), [onBulkArchive, onBulkDelete]);
@@ -42,7 +42,7 @@ const CATEGORY_TYPE_FLAGS = [
42
42
  ];
43
43
  function AccordionSection({ title, defaultOpen = true, children }) {
44
44
  const [open, setOpen] = React.useState(defaultOpen);
45
- return (_jsxs(Div, { className: `${__O.hidden}`, rounded: "lg", border: "default", children: [_jsxs("button", { type: "button", onClick: () => setOpen((v) => !v), className: "w-full flex items-center justify-between px-4 py-3 bg-[var(--appkit-color-surface-elevated)]/60 text-left", "aria-expanded": open, children: [_jsx(Text, { className: "tracking-widest", color: "muted", size: "xs", weight: "semibold", transform: "uppercase", children: title }), _jsx("svg", { className: `h-4 w-4 text-zinc-400 transition-transform ${open ? "rotate-180" : ""}`, fill: "none", stroke: "currentColor", strokeWidth: 2, viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) })] }), open && (_jsx(Div, { className: "divide-y divide-zinc-100 divide-[var(--appkit-color-border-subtle)]", children: children }))] }));
45
+ return (_jsxs(Div, { className: `${__O.hidden}`, rounded: "lg", border: "default", children: [_jsx(Button, { type: "button", variant: "ghost", onClick: () => setOpen((v) => !v), paddingX: "md", paddingY: "md", className: "w-full text-left bg-[var(--appkit-color-surface-elevated)]/60", "aria-expanded": open, children: _jsxs(Row, { align: "center", justify: "between", className: "w-full", children: [_jsx(Text, { className: "tracking-widest", color: "muted", size: "xs", weight: "semibold", transform: "uppercase", children: title }), _jsx("svg", { className: `h-4 w-4 text-zinc-400 transition-transform ${open ? "rotate-180" : ""}`, fill: "none", stroke: "currentColor", strokeWidth: 2, viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) })] }) }), open && (_jsx(Div, { className: "divide-y divide-zinc-100 divide-[var(--appkit-color-border-subtle)]", children: children }))] }));
46
46
  }
47
47
  function FlagRow({ label, desc, checked, onChange, rollout, onRolloutChange, showRollout }) {
48
48
  return (_jsxs(Row, { surface: "default", padding: "inline", align: "center", justify: "between", gap: "md", children: [_jsxs(Div, { className: "flex-1 min-w-0", children: [_jsx(Toggle, { checked: checked, onChange: onChange, label: label }), _jsx(Text, { className: "mt-0.5 ml-10 truncate", color: "faint", size: "xs", children: desc })] }), showRollout && (_jsxs(Stack, { className: "w-28 shrink-0", gap: "xs", children: [_jsx(Text, { size: "xs", color: "muted", children: "Rollout %" }), _jsx(Input, { type: "number", min: 0, max: 100, value: rollout ?? 100, onChange: (e) => onRolloutChange?.(Math.min(100, Math.max(0, Number(e.target.value)))), disabled: !checked, className: "w-full" })] }))] }));
@@ -3,7 +3,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import { sortBy } from "@mohasinac/appkit";
4
4
  import React from "react";
5
5
  import { useRouter, useSearchParams, usePathname } from "next/navigation";
6
- import { ListingLayout, Row } from "../../../ui";
6
+ import { FilterChipGroup, ListingLayout } from "../../../ui";
7
7
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
8
8
  import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
9
9
  import { toRecordArray, toRelativeDate, toStringValue, } from "../hooks/useAdminListingData";
@@ -12,10 +12,7 @@ import { AdminFeatureEditorView } from "./AdminFeatureEditorView";
12
12
  import { PRODUCT_FEATURE_SCOPE_TABS } from "../../products/constants/product-features.constants";
13
13
  const PAGE_SIZE = 50;
14
14
  const DEFAULT_SCOPE = "platform";
15
- const STICKY_TABS_CLASS = "sticky top-[calc(var(--header-height,0px)+44px)] z-10 flex gap-2 bg-white/95 bg-[var(--appkit-color-surface)]/95 backdrop-blur-sm border-b border-[var(--appkit-color-border)] px-3 py-2";
16
- const TAB_BASE_CLASS = "rounded-full px-3 py-1 text-xs font-medium border transition-colors";
17
- const TAB_ACTIVE_CLASS = "bg-primary text-white border-primary";
18
- const TAB_INACTIVE_CLASS = "border-[var(--appkit-color-border)] text-[var(--appkit-color-text-muted)] hover:bg-zinc-50 hover:bg-[var(--appkit-color-surface-elevated)]";
15
+ const STICKY_TABS_CLASS = "sticky top-[calc(var(--header-height,0px)+44px)] z-10 bg-white/95 bg-[var(--appkit-color-surface)]/95 backdrop-blur-sm border-b border-[var(--appkit-color-border)] px-3 py-2";
19
16
  function mapFeatureRow(item, index) {
20
17
  const productTypes = Array.isArray(item.productTypes) ? item.productTypes : [];
21
18
  const isActive = typeof item.isActive === "boolean" ? item.isActive : true;
@@ -34,6 +31,8 @@ function mapFeatureRow(item, index) {
34
31
  };
35
32
  }
36
33
  export function AdminFeaturesView({ children, ...props }) {
34
+ const router = useRouter();
35
+ const pathname = usePathname();
37
36
  const searchParams = useSearchParams();
38
37
  const scopeFilter = searchParams.get("scope") || DEFAULT_SCOPE;
39
38
  if (React.Children.count(children) > 0) {
@@ -70,21 +69,13 @@ export function AdminFeaturesView({ children, ...props }) {
70
69
  onClick: () => selection.clearSelection(),
71
70
  },
72
71
  ],
73
- renderAboveContent: () => (_jsx(Row, { className: STICKY_TABS_CLASS, gap: "xs", children: PRODUCT_FEATURE_SCOPE_TABS.map((tab) => (_jsx(ScopeTabButton, { value: tab.value, label: tab.label, current: scopeFilter }, tab.value))) })),
72
+ renderAboveContent: () => (_jsx(FilterChipGroup, { label: "Scope", className: STICKY_TABS_CLASS, tabs: PRODUCT_FEATURE_SCOPE_TABS.map((tab) => ({ id: tab.value, label: tab.label })), value: scopeFilter, onChange: (value) => {
73
+ const params = new URLSearchParams(searchParams.toString());
74
+ params.set("scope", value);
75
+ router.replace(`${pathname}?${params.toString()}`);
76
+ } })),
74
77
  renderEditor: ({ editId, closePanel }) => (_jsx(AdminFeatureEditorView, { featureId: editId ?? undefined, onSaved: closePanel, onDeleted: closePanel, embedded: true })),
75
78
  resolveEditorTitle: ({ isCreate }) => (isCreate ? "Add Feature" : "Edit Feature"),
76
79
  };
77
80
  return _jsx(DataListingView, { config: config });
78
81
  }
79
- function ScopeTabButton({ value, label, current, }) {
80
- const router = useRouter();
81
- const pathname = usePathname();
82
- const searchParams = useSearchParams();
83
- const handleClick = () => {
84
- const params = new URLSearchParams(searchParams.toString());
85
- params.set("scope", value);
86
- router.replace(`${pathname}?${params.toString()}`);
87
- };
88
- const isActive = current === value;
89
- return (_jsx("button", { type: "button", onClick: handleClick, className: `${TAB_BASE_CLASS} ${isActive ? TAB_ACTIVE_CLASS : TAB_INACTIVE_CLASS}`, children: label }));
90
- }
@@ -1,11 +1,11 @@
1
1
  "use client";
2
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useApiMutation } from "@mohasinac/appkit/client";
4
- import { Row, SIEVE_OP, Stack, sieveFilter } from "@mohasinac/appkit";
4
+ import { SIEVE_OP, sieveFilter } from "@mohasinac/appkit";
5
5
  import { sortBy } from "@mohasinac/appkit";
6
6
  import React, { useState } from "react";
7
7
  import { useQueryClient } from "@tanstack/react-query";
8
- import { ConfirmDeleteModal, ListingLayout, RowActionMenu, Text, useToast } from "../../../ui";
8
+ import { ConfirmDeleteModal, FilterChipGroup, ListingLayout, RowActionMenu, useToast } from "../../../ui";
9
9
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
10
10
  import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
11
11
  import { ROW_ACTION_META, ROW_ACTION_ID } from "../../products/constants/action-defs";
@@ -97,9 +97,7 @@ export function AdminNotificationsView({ children, ...props }) {
97
97
  onClick: () => setDeleteTarget(row),
98
98
  },
99
99
  ] })),
100
- renderFilterPanel: ({ pendingFilters, setPendingFilters }) => (_jsxs(Stack, { gap: "sm", children: [_jsx(Text, { className: "tracking-widest", color: "muted", size: "xs", weight: "semibold", transform: "uppercase", children: "Type" }), _jsx(Row, { wrap: true, gap: "sm", children: NOTIF_TYPES.map((opt) => (_jsx("button", { type: "button", onClick: () => setPendingFilters((p) => ({ ...p, type: opt === "All" ? "" : opt })), className: `rounded-full px-3 py-1 text-xs font-medium border transition-colors ${(pendingFilters.type || "All") === opt
101
- ? "bg-primary text-white border-primary"
102
- : "border-[var(--appkit-color-border)] text-[var(--appkit-color-text-muted)] hover:bg-zinc-50 hover:bg-[var(--appkit-color-surface-elevated)]"}`, children: opt }, opt))) })] })),
100
+ renderFilterPanel: ({ pendingFilters, setPendingFilters }) => (_jsx(FilterChipGroup, { label: "Type", tabs: NOTIF_TYPES.map((opt) => ({ id: opt, label: opt })), value: pendingFilters.type || "All", onChange: (v) => setPendingFilters((p) => ({ ...p, type: v })) })),
103
101
  };
104
102
  return (_jsxs(_Fragment, { children: [_jsx(DataListingView, { config: config }), _jsx(ConfirmDeleteModal, { isOpen: Boolean(deleteTarget), onClose: () => setDeleteTarget(null), onConfirm: () => {
105
103
  if (deleteTarget)
@@ -1,11 +1,11 @@
1
1
  "use client";
2
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useApiMutation } from "@mohasinac/appkit/client";
4
- import { Row, SIEVE_OP, Stack, sieveFilter } from "@mohasinac/appkit";
4
+ import { SIEVE_OP, sieveFilter } from "@mohasinac/appkit";
5
5
  import { sortBy } from "@mohasinac/appkit";
6
6
  import React, { useState } from "react";
7
7
  import { useQueryClient } from "@tanstack/react-query";
8
- import { ConfirmDeleteModal, ListingLayout, RowActionMenu, Text, useToast } from "../../../ui";
8
+ import { ConfirmDeleteModal, FilterChipGroup, ListingLayout, RowActionMenu, useToast } from "../../../ui";
9
9
  import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
10
10
  import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
11
11
  import { ROW_ACTION_META, ROW_ACTION_ID } from "../../products/constants/action-defs";
@@ -91,12 +91,10 @@ export function AdminSessionsView({ children, ...props }) {
91
91
  onClick: () => setRevokeTarget(row),
92
92
  },
93
93
  ] })),
94
- renderFilterPanel: ({ pendingFilters, setPendingFilters }) => (_jsxs(Stack, { gap: "sm", children: [_jsx(Text, { className: "tracking-widest", color: "muted", size: "xs", weight: "semibold", transform: "uppercase", children: "Status" }), _jsx(Row, { wrap: true, gap: "sm", children: [
95
- { label: "All", value: "" },
96
- { label: "Active only", value: "true" },
97
- ].map((opt) => (_jsx("button", { type: "button", onClick: () => setPendingFilters((p) => ({ ...p, isActive: opt.value })), className: `rounded-full px-3 py-1 text-xs font-medium border transition-colors ${(pendingFilters.isActive || "") === opt.value
98
- ? "bg-primary text-white border-primary"
99
- : "border-[var(--appkit-color-border)] text-[var(--appkit-color-text-muted)] hover:bg-zinc-50 hover:bg-[var(--appkit-color-surface-elevated)]"}`, children: opt.label }, opt.label))) })] })),
94
+ renderFilterPanel: ({ pendingFilters, setPendingFilters }) => (_jsx(FilterChipGroup, { label: "Status", tabs: [
95
+ { id: "All", label: "All" },
96
+ { id: "true", label: "Active only" },
97
+ ], value: pendingFilters.isActive || "", onChange: (v) => setPendingFilters((p) => ({ ...p, isActive: v })) })),
100
98
  };
101
99
  return (_jsxs(_Fragment, { children: [_jsx(DataListingView, { config: config }), _jsx(ConfirmDeleteModal, { isOpen: Boolean(revokeTarget), onClose: () => setRevokeTarget(null), onConfirm: () => {
102
100
  if (revokeTarget)
@@ -3,7 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
3
3
  import { useEffect, useState, useCallback } from "react";
4
4
  import { createPortal } from "react-dom";
5
5
  import Link from "next/link";
6
- import { Div, Li, Nav, Row, Span, Stack, Ul } from "../../../ui";
6
+ import { Button, Div, IconButton, Li, Nav, Row, Span, Stack, Ul } from "../../../ui";
7
7
  import { BottomSheet } from "../../layout/BottomSheet";
8
8
  import { SidebarCollapseToggle } from "../../../_internal/client/features/layout/SidebarCollapseToggle";
9
9
  const __O = {
@@ -27,13 +27,13 @@ function GroupsContent({ groups, activePath, onItemClick, }) {
27
27
  return (_jsx(Nav, { "aria-label": "Admin navigation", padding: "y-xs", children: groups.map((group) => {
28
28
  const isOpen = openGroups[group.title] ?? false;
29
29
  const hasActive = group.items.some((i) => activePath === i.href || activePath.startsWith(i.href + "/"));
30
- return (_jsxs(Div, { className: "mb-0.5", children: [_jsxs("button", { type: "button", onClick: () => toggle(group.title), className: `flex w-full items-center justify-between px-4 py-2 text-[0.6875rem] font-semibold uppercase tracking-widest transition-colors ${hasActive && !isOpen
30
+ return (_jsxs(Div, { className: "mb-0.5", children: [_jsx(Button, { type: "button", variant: "ghost", onClick: () => toggle(group.title), paddingX: "md", paddingY: "sm", weight: "semibold", rounded: "none", className: `w-full text-[0.6875rem] uppercase tracking-widest transition-colors ${hasActive && !isOpen
31
31
  ? "text-[var(--appkit-color-text-muted)]"
32
- : "text-[var(--appkit-color-text-faint)] hover:text-[var(--appkit-color-text-muted)] hover:text-[var(--appkit-color-text-muted)]"}`, children: [_jsx(Span, { children: group.title }), _jsx("svg", { className: `w-3 h-3 transition-transform duration-150 ${isOpen ? "rotate-180" : ""}`, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2.5, d: "M19 9l-7 7-7-7" }) })] }), isOpen && (_jsx(Ul, { paddingX: "x-sm", paddingY: "y-bottom-xs", spacing: "2xs", children: group.items.map((item) => (_jsx(Li, { children: _jsx(NavLink, { item: item, isActive: isNavItemActive(item, activePath), onClick: onItemClick }) }, item.href))) }))] }, group.title));
32
+ : "text-[var(--appkit-color-text-faint)] hover:text-[var(--appkit-color-text-muted)]"}`, children: _jsxs(Row, { align: "center", justify: "between", className: "w-full", children: [_jsx(Span, { children: group.title }), _jsx("svg", { className: `w-3 h-3 transition-transform duration-150 ${isOpen ? "rotate-180" : ""}`, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2.5, d: "M19 9l-7 7-7-7" }) })] }) }), isOpen && (_jsx(Ul, { paddingX: "x-sm", paddingY: "y-bottom-xs", spacing: "2xs", children: group.items.map((item) => (_jsx(Li, { children: _jsx(NavLink, { item: item, isActive: isNavItemActive(item, activePath), onClick: onItemClick }) }, item.href))) }))] }, group.title));
33
33
  }) }));
34
34
  }
35
35
  function DrawerPanel({ title, onClose, children, }) {
36
- return (_jsxs(Div, { className: "hidden lg:block", children: [_jsx(Div, { surface: "overlay-xs", className: "fixed inset-0 z-40 backdrop-blur-sm", onClick: onClose, "aria-hidden": "true" }), _jsxs(Stack, { border: "default", shadow: "2xl", role: "dialog", "aria-modal": "true", "aria-label": title, className: "fixed top-0 right-0 z-50 h-full w-64 border-l", surface: "default", children: [_jsxs(Row, { border: "bottom-subtle", paddingY: "y-sm-tall", className: "shrink-0", padding: "x-md", align: "center", justify: "between", children: [_jsx(Span, { size: "xs", weight: "semibold", transform: "uppercase", color: "muted", children: title }), _jsx("button", { type: "button", onClick: onClose, "aria-label": "Close", className: "flex items-center justify-center w-7 h-7 rounded-md text-zinc-400 hover:bg-[var(--appkit-color-surface)] hover:bg-[var(--appkit-color-surface-elevated)] hover:text-zinc-700 hover:text-[var(--appkit-color-text-muted)] transition-colors", children: _jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })] }), _jsx(Div, { className: `flex-1 ${__O.yAuto}`, children: children })] })] }));
36
+ return (_jsxs(Div, { className: "hidden lg:block", children: [_jsx(Div, { surface: "overlay-xs", className: "fixed inset-0 z-40 backdrop-blur-sm", onClick: onClose, "aria-hidden": "true" }), _jsxs(Stack, { border: "default", shadow: "2xl", role: "dialog", "aria-modal": "true", "aria-label": title, className: "fixed top-0 right-0 z-50 h-full w-64 border-l", surface: "default", children: [_jsxs(Row, { border: "bottom-subtle", paddingY: "y-sm-tall", className: "shrink-0", padding: "x-md", align: "center", justify: "between", children: [_jsx(Span, { size: "xs", weight: "semibold", transform: "uppercase", color: "muted", children: title }), _jsx(IconButton, { "aria-label": "Close", variant: "ghost", size: "sm", onClick: onClose, icon: _jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })] }), _jsx(Div, { className: `flex-1 ${__O.yAuto}`, children: children })] })] }));
37
37
  }
38
38
  export function AdminSidebar({ renderNavItems, renderHeader, renderFooter, activePath = "", groups, mobileOpen = false, desktopOpen = false, variant = "overlay", onCloseMobile, onToggle, }) {
39
39
  const close = onCloseMobile ?? (() => { });
@@ -17,7 +17,7 @@ const __O = {
17
17
  // --- Helpers -----------------------------------------------------------------
18
18
  function MaskedInput({ label, value, onChange, placeholder, helperText, }) {
19
19
  const [revealed, setRevealed] = React.useState(false);
20
- return (_jsxs(Div, { className: "relative", children: [_jsx(Input, { label: label, value: value, onChange: (e) => onChange(e.target.value), type: revealed ? "text" : "password", placeholder: placeholder, helperText: helperText }), _jsx("button", { type: "button", onClick: () => setRevealed((r) => !r), className: "absolute right-3 top-8 text-xs text-zinc-400 hover:text-zinc-700 hover:text-[var(--appkit-color-text-muted)]", children: revealed ? "Hide" : "Reveal" })] }));
20
+ return (_jsxs(Div, { className: "relative", children: [_jsx(Input, { label: label, value: value, onChange: (e) => onChange(e.target.value), type: revealed ? "text" : "password", placeholder: placeholder, helperText: helperText }), _jsx(Button, { type: "button", variant: "ghost", textSize: "xs", textColor: "faint", paddingX: "none", paddingY: "none", onClick: () => setRevealed((r) => !r), className: "absolute right-3 top-8", children: revealed ? "Hide" : "Reveal" })] }));
21
21
  }
22
22
  const NOTIF_CHANNEL_INDENT = "space-y-4 pl-4 border-l-2 border-[var(--appkit-color-border)]";
23
23
  const CLS_TEXTAREA = "w-full rounded-md border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] p-3 text-sm text-[var(--appkit-color-text-muted)] resize-y focus:outline-none focus:ring-2 focus:ring-blue-500";
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Div, Heading, TextLink } from "../../../ui";
2
+ import { Button, Div, Heading, Row, TextLink } from "../../../ui";
3
3
  export function QuickActionsPanel({ title, actions, renderAction, className = "", }) {
4
- return (_jsxs(Div, { className: className, children: [title && (_jsx(Heading, { level: 3, className: "mb-4", children: title })), _jsx(Div, { layout: "grid", gap: "4", className: "grid-cols-1 md:grid-cols-3", children: actions.map((action) => (_jsx(Div, { children: renderAction ? (renderAction(action)) : action.onClick ? (_jsxs("button", { type: "button", onClick: action.onClick, className: "w-full inline-flex items-center justify-start gap-2 rounded-lg border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] text-[var(--appkit-color-text)] px-3 py-2 text-sm", children: [action.icon, action.label] })) : (_jsxs(TextLink, { variant: "bare", href: action.href ?? "#", rounded: "lg", paddingX: "sm", paddingY: "xs", size: "sm", layout: "inline-flex", align: "center", justify: "start", gap: "sm", className: "w-full border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] text-[var(--appkit-color-text)]", children: [action.icon, action.label] })) }, action.id))) })] }));
4
+ return (_jsxs(Div, { className: className, children: [title && (_jsx(Heading, { level: 3, className: "mb-4", children: title })), _jsx(Div, { layout: "grid", gap: "4", className: "grid-cols-1 md:grid-cols-3", children: actions.map((action) => (_jsx(Div, { children: renderAction ? (renderAction(action)) : action.onClick ? (_jsx(Button, { type: "button", variant: "outline", onClick: action.onClick, rounded: "lg", paddingX: "sm", paddingY: "sm", textSize: "sm", className: "w-full", children: _jsxs(Row, { align: "center", justify: "start", gap: "sm", className: "w-full", children: [action.icon, action.label] }) })) : (_jsxs(TextLink, { variant: "bare", href: action.href ?? "#", rounded: "lg", paddingX: "sm", paddingY: "xs", size: "sm", layout: "inline-flex", align: "center", justify: "start", gap: "sm", className: "w-full border border-[var(--appkit-color-border)] bg-[var(--appkit-color-surface)] text-[var(--appkit-color-text)]", children: [action.icon, action.label] })) }, action.id))) })] }));
5
5
  }
@@ -38,12 +38,18 @@ export function PrintCenterView({ store, brandName = "LetItRip", initialProducts
38
38
  const [selectedOrders, setSelectedOrders] = useState(new Set());
39
39
  const toggleProduct = (id) => setSelectedProducts((prev) => {
40
40
  const next = new Set(prev);
41
- next.has(id) ? next.delete(id) : next.add(id);
41
+ if (next.has(id))
42
+ next.delete(id);
43
+ else
44
+ next.add(id);
42
45
  return next;
43
46
  });
44
47
  const toggleOrder = (id) => setSelectedOrders((prev) => {
45
48
  const next = new Set(prev);
46
- next.has(id) ? next.delete(id) : next.add(id);
49
+ if (next.has(id))
50
+ next.delete(id);
51
+ else
52
+ next.add(id);
47
53
  return next;
48
54
  });
49
55
  const printSelected = () => window.print();
@@ -142,7 +142,10 @@ export function SellerBidsView({ endpoint = SELLER_ENDPOINTS.BIDS }) {
142
142
  }, [rows]);
143
143
  const toggleGroup = (id) => setCollapsedGroups((s) => {
144
144
  const next = new Set(s);
145
- next.has(id) ? next.delete(id) : next.add(id);
145
+ if (next.has(id))
146
+ next.delete(id);
147
+ else
148
+ next.add(id);
146
149
  return next;
147
150
  });
148
151
  // S-STORE-4-B — bulk actions: cancel / retract.
@@ -1,10 +1,10 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { Row, SIEVE_OP, Stack, sieveFilter } from "@mohasinac/appkit";
3
+ import { SIEVE_OP, Stack, sieveFilter } from "@mohasinac/appkit";
4
4
  import { sortBy } from "@mohasinac/appkit";
5
5
  import React, { useState, useCallback } from "react";
6
6
  import { useEntityDelete } from "../../../react/hooks/useEntityDelete";
7
- import { Div, ListingLayout, Text, useToast } from "../../../ui";
7
+ import { Div, FilterChipGroup, ListingLayout, useToast } from "../../../ui";
8
8
  import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
9
9
  import { toRecordArray, toStringValue, } from "../../admin/hooks/useAdminListingData";
10
10
  import { normalizeError } from "../../../errors/normalize";
@@ -71,13 +71,11 @@ export function SellerCouponsView({ onCreateClick, onEditClick, onToggle, onDele
71
71
  primaryAction: onCreateClick
72
72
  ? { label: "Add Coupon", onClick: () => onCreateClick() }
73
73
  : undefined,
74
- renderFilterPanel: ({ pendingFilters, setPendingFilters }) => (_jsxs(Stack, { gap: "sm", children: [_jsx(Text, { className: "tracking-widest", color: "muted", size: "xs", weight: "semibold", transform: "uppercase", children: "Status" }), _jsx(Row, { wrap: true, gap: "sm", children: [
75
- { label: "All", value: "" },
76
- { label: "Active", value: "true" },
77
- { label: "Inactive", value: "false" },
78
- ].map((opt) => (_jsx("button", { type: "button", onClick: () => setPendingFilters((p) => ({ ...p, isActive: opt.value })), className: `rounded-full px-3 py-1 text-xs font-medium border transition-colors ${(pendingFilters.isActive || "") === opt.value
79
- ? "bg-[var(--appkit-color-primary)] text-white border-[var(--appkit-color-primary)]"
80
- : "border-[var(--appkit-color-border)] text-[var(--appkit-color-text-muted)] hover:bg-zinc-50 hover:bg-[var(--appkit-color-surface-elevated)]"}`, children: opt.label }, opt.label))) })] })),
74
+ renderFilterPanel: ({ pendingFilters, setPendingFilters }) => (_jsx(FilterChipGroup, { label: "Status", tabs: [
75
+ { id: "All", label: "All" },
76
+ { id: "true", label: "Active" },
77
+ { id: "false", label: "Inactive" },
78
+ ], value: pendingFilters.isActive || "", onChange: (v) => setPendingFilters((p) => ({ ...p, isActive: v })) })),
81
79
  renderCards: (rows, _view, _selection, isLoading) => isLoading ? (_jsx(Div, { gap: "3", className: "fluid-grid-card", children: Array.from({ length: 6 }).map((_, i) => (_jsxs(Stack, { border: "skeleton", className: "animate-pulse", gap: "3", rounded: "xl", padding: "md", children: [_jsx(Div, { className: "h-6 w-2/3", surface: "subtle", rounded: "default" }), _jsx(Div, { className: "h-4 w-full", surface: "subtle", rounded: "default" }), _jsx(Div, { className: "h-3 w-1/2", surface: "subtle", rounded: "default" })] }, i))) })) : (_jsx(Div, { gap: "3", className: "fluid-grid-card", children: rows.map((row) => (_jsx(CouponCard, { coupon: row.raw, onEdit: onEditClick ? handleEdit : undefined, onToggleActive: onToggle ? handleToggle : undefined, onDelete: onDelete ? handleDelete : undefined, className: togglingId === row.id || deletingId === row.id
82
80
  ? "pointer-events-none opacity-60"
83
81
  : undefined }, row.id))) })),
@@ -49,7 +49,10 @@ export function SellerReviewsView({ reviewsApiBase = "/api/store/reviews", reply
49
49
  const toggleSelected = useCallback((id) => {
50
50
  setSelectedIds((prev) => {
51
51
  const next = new Set(prev);
52
- next.has(id) ? next.delete(id) : next.add(id);
52
+ if (next.has(id))
53
+ next.delete(id);
54
+ else
55
+ next.add(id);
53
56
  return next;
54
57
  });
55
58
  }, []);