@voyantjs/promotions-ui 0.52.1 → 0.52.2

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.
@@ -1 +1 @@
1
- {"version":3,"file":"en.d.ts","sourceRoot":"","sources":["../../src/i18n/en.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAA;AAEzD,eAAO,MAAM,cAAc,EAAE,oBAgJ5B,CAAA"}
1
+ {"version":3,"file":"en.d.ts","sourceRoot":"","sources":["../../src/i18n/en.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAA;AAEzD,eAAO,MAAM,cAAc,EAAE,oBAiJ5B,CAAA"}
package/dist/i18n/en.js CHANGED
@@ -47,7 +47,8 @@ export const promotionsUiEn = {
47
47
  scopePlaceholder: "Scope",
48
48
  allScopes: "All scopes",
49
49
  validityRangePlaceholder: "Validity range",
50
- clearFilters: "Clear",
50
+ filtersButton: "Filters",
51
+ clearFilters: "Clear filters",
51
52
  loadFailed: "Failed to load promotions.",
52
53
  loadFailedPrefix: "Failed to load: {message}",
53
54
  empty: "No promotions match the current filters.",
@@ -25,6 +25,7 @@ export type PromotionsUiMessages = {
25
25
  scopePlaceholder: string;
26
26
  allScopes: string;
27
27
  validityRangePlaceholder: string;
28
+ filtersButton: string;
28
29
  clearFilters: string;
29
30
  loadFailed: string;
30
31
  loadFailedPrefix: string;
@@ -1 +1 @@
1
- {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/i18n/messages.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/i18n/messages.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ro.d.ts","sourceRoot":"","sources":["../../src/i18n/ro.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAA;AAEzD,eAAO,MAAM,cAAc,EAAE,oBAgJ5B,CAAA"}
1
+ {"version":3,"file":"ro.d.ts","sourceRoot":"","sources":["../../src/i18n/ro.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAA;AAEzD,eAAO,MAAM,cAAc,EAAE,oBAiJ5B,CAAA"}
package/dist/i18n/ro.js CHANGED
@@ -47,7 +47,8 @@ export const promotionsUiRo = {
47
47
  scopePlaceholder: "Domeniu",
48
48
  allScopes: "Toate domeniile",
49
49
  validityRangePlaceholder: "Interval valabilitate",
50
- clearFilters: "Sterge",
50
+ filtersButton: "Filtre",
51
+ clearFilters: "Sterge filtrele",
51
52
  loadFailed: "Promotiile nu au putut fi incarcate.",
52
53
  loadFailedPrefix: "Incarcarea a esuat: {message}",
53
54
  empty: "Nicio promotie nu se potriveste filtrelor curente.",
@@ -1 +1 @@
1
- {"version":3,"file":"promotion-dialog.d.ts","sourceRoot":"","sources":["../src/promotion-dialog.tsx"],"names":[],"mappings":"AAaA,OAAO,EACL,KAAK,sBAAsB,EAO5B,MAAM,4BAA4B,CAAA;AA0BnC,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,oDAAoD;IACpD,KAAK,CAAC,EAAE,sBAAsB,CAAA;CAC/B;AA4KD,wBAAgB,eAAe,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,EAAE,oBAAoB,2CA2SlF"}
1
+ {"version":3,"file":"promotion-dialog.d.ts","sourceRoot":"","sources":["../src/promotion-dialog.tsx"],"names":[],"mappings":"AAaA,OAAO,EACL,KAAK,sBAAsB,EAO5B,MAAM,4BAA4B,CAAA;AA2BnC,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,oDAAoD;IACpD,KAAK,CAAC,EAAE,sBAAsB,CAAA;CAC/B;AA4KD,wBAAgB,eAAe,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,EAAE,oBAAoB,2CAySlF"}
@@ -12,6 +12,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
12
12
  import { formatMessage } from "@voyantjs/i18n";
13
13
  import { promotionalOfferScopeSchema, useCreatePromotion, useUpdatePromotion, } from "@voyantjs/promotions-react";
14
14
  import { Button, Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, Input, Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Switch, Textarea, } from "@voyantjs/ui/components";
15
+ import { CurrencyCombobox } from "@voyantjs/ui/components/currency-combobox";
15
16
  import { CurrencyInput } from "@voyantjs/ui/components/currency-input";
16
17
  import { DateTimePicker } from "@voyantjs/ui/components/date-time-picker";
17
18
  import { useEffect, useState } from "react";
@@ -196,7 +197,7 @@ export function PromotionDialog({ open, onOpenChange, offer }) {
196
197
  return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { className: "max-h-[90vh] max-w-2xl overflow-y-auto", children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: isEdit ? dialogMessages.titles.edit : dialogMessages.titles.create }), _jsx(DialogDescription, { children: dialogMessages.description })] }), _jsxs("div", { className: "grid gap-4 py-2", children: [_jsxs("div", { className: "grid grid-cols-2 gap-3", children: [_jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { htmlFor: "promotion-name", children: dialogMessages.fields.name }), _jsx(Input, { id: "promotion-name", value: state.name, onChange: (e) => setField("name", e.target.value), placeholder: dialogMessages.placeholders.name })] }), _jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { htmlFor: "promotion-slug", children: dialogMessages.fields.slug }), _jsx(Input, { id: "promotion-slug", value: state.slug, onChange: (e) => setField("slug", e.target.value), placeholder: dialogMessages.placeholders.slug })] })] }), _jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { htmlFor: "promotion-description", children: dialogMessages.fields.description }), _jsx(Textarea, { id: "promotion-description", value: state.description, onChange: (e) => setField("description", e.target.value), rows: 2, placeholder: dialogMessages.placeholders.description })] }), _jsxs("div", { className: "grid grid-cols-3 gap-3", children: [_jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { children: dialogMessages.fields.type }), _jsxs(Select, { value: state.discountType, onValueChange: (v) => {
197
198
  if (v === "percentage" || v === "fixed_amount")
198
199
  setField("discountType", v);
199
- }, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "percentage", children: messages.common.discountTypeLabels.percentage }), _jsx(SelectItem, { value: "fixed_amount", children: messages.common.discountTypeLabels.fixed_amount })] })] })] }), state.discountType === "percentage" ? (_jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { htmlFor: "promotion-percent", children: dialogMessages.fields.percent }), _jsx(Input, { id: "promotion-percent", type: "number", step: "0.01", min: "0", max: "100", value: state.discountPercent, onChange: (e) => setField("discountPercent", e.target.value), placeholder: dialogMessages.placeholders.percent })] })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { htmlFor: "promotion-amount", children: dialogMessages.fields.amount }), _jsx(CurrencyInput, { id: "promotion-amount", value: state.discountAmountCents, onChange: (value) => setField("discountAmountCents", value), currency: state.currency, placeholder: dialogMessages.placeholders.amount })] }), _jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { htmlFor: "promotion-currency", children: dialogMessages.fields.currency }), _jsx(Input, { id: "promotion-currency", value: state.currency, onChange: (e) => setField("currency", e.target.value), placeholder: dialogMessages.placeholders.currency, maxLength: 3 })] })] }))] }), _jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { children: dialogMessages.fields.scope }), _jsxs(Select, { value: state.scopeKind, onValueChange: (v) => {
200
+ }, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "percentage", children: messages.common.discountTypeLabels.percentage }), _jsx(SelectItem, { value: "fixed_amount", children: messages.common.discountTypeLabels.fixed_amount })] })] })] }), state.discountType === "percentage" ? (_jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { htmlFor: "promotion-percent", children: dialogMessages.fields.percent }), _jsx(Input, { id: "promotion-percent", type: "number", step: "0.01", min: "0", max: "100", value: state.discountPercent, onChange: (e) => setField("discountPercent", e.target.value), placeholder: dialogMessages.placeholders.percent })] })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { htmlFor: "promotion-amount", children: dialogMessages.fields.amount }), _jsx(CurrencyInput, { id: "promotion-amount", value: state.discountAmountCents, onChange: (value) => setField("discountAmountCents", value), currency: state.currency, placeholder: dialogMessages.placeholders.amount })] }), _jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { htmlFor: "promotion-currency", children: dialogMessages.fields.currency }), _jsx(CurrencyCombobox, { value: state.currency || null, onChange: (next) => setField("currency", next ?? ""), placeholder: dialogMessages.placeholders.currency })] })] }))] }), _jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { children: dialogMessages.fields.scope }), _jsxs(Select, { value: state.scopeKind, onValueChange: (v) => {
200
201
  if (v != null && SCOPE_KINDS.includes(v)) {
201
202
  setField("scopeKind", v);
202
203
  }
@@ -1 +1 @@
1
- {"version":3,"file":"promotions-page.d.ts","sourceRoot":"","sources":["../src/promotions-page.tsx"],"names":[],"mappings":"AAEA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAExD,OAAO,EAKL,KAAK,sBAAsB,EAG3B,KAAK,uBAAuB,EAC5B,KAAK,mBAAmB,EAEzB,MAAM,4BAA4B,CAAA;AAsBnC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AA4BtC,MAAM,WAAW,0BAA0B;IACzC,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,KAAK,CAAC,EAAE,sBAAsB,CAAA;IAC9B,SAAS,EAAE,MAAM,IAAI,CAAA;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,eAAe,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,sBAAsB,KAAK,IAAI,CAAA;IAClF,qBAAqB,CAAC,EAAE,CAAC,KAAK,EAAE,0BAA0B,KAAK,SAAS,CAAA;CACzE;AAED,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,WAAW,EACxB,MAAM,CAAC,EAAE,OAAO,CAAC,uBAAuB,CAAC,EACzC,KAAK,GAAE,mBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAQhC;AAED,wBAAgB,cAAc,CAAC,EAC7B,SAAS,EACT,QAA4B,EAC5B,eAAe,EACf,qBAAqB,GACtB,GAAE,mBAAwB,2CAgS1B"}
1
+ {"version":3,"file":"promotions-page.d.ts","sourceRoot":"","sources":["../src/promotions-page.tsx"],"names":[],"mappings":"AAEA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAExD,OAAO,EAKL,KAAK,sBAAsB,EAG3B,KAAK,uBAAuB,EAC5B,KAAK,mBAAmB,EAEzB,MAAM,4BAA4B,CAAA;AAyBnC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AA4BtC,MAAM,WAAW,0BAA0B;IACzC,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,KAAK,CAAC,EAAE,sBAAsB,CAAA;IAC9B,SAAS,EAAE,MAAM,IAAI,CAAA;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,eAAe,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,sBAAsB,KAAK,IAAI,CAAA;IAClF,qBAAqB,CAAC,EAAE,CAAC,KAAK,EAAE,0BAA0B,KAAK,SAAS,CAAA;CACzE;AAED,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,WAAW,EACxB,MAAM,CAAC,EAAE,OAAO,CAAC,uBAAuB,CAAC,EACzC,KAAK,GAAE,mBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAQhC;AAED,wBAAgB,cAAc,CAAC,EAC7B,SAAS,EACT,QAA4B,EAC5B,eAAe,EACf,qBAAqB,GACtB,GAAE,mBAAwB,2CAwV1B"}
@@ -2,9 +2,9 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { formatMessage } from "@voyantjs/i18n";
4
4
  import { createPromotionsClientOptions, getPromotionsListQueryOptions, usePromotionsList, } from "@voyantjs/promotions-react";
5
- import { Badge, Button, DateRangePicker, Input, Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Skeleton, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@voyantjs/ui/components";
5
+ import { Badge, Button, DateRangePicker, Input, Label, Popover, PopoverContent, PopoverTrigger, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Skeleton, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@voyantjs/ui/components";
6
6
  import { cn } from "@voyantjs/ui/lib/utils";
7
- import { Plus, Search, X } from "lucide-react";
7
+ import { ListFilter, Plus, Search, X } from "lucide-react";
8
8
  import { useState } from "react";
9
9
  import { usePromotionsUiMessagesOrDefault } from "./i18n/provider.js";
10
10
  import { PromotionDialog } from "./promotion-dialog.js";
@@ -35,6 +35,7 @@ export function PromotionsPage({ className, pageSize = DEFAULT_PAGE_SIZE, onOpen
35
35
  const [pageIndex, setPageIndex] = useState(0);
36
36
  const [dialogOpen, setDialogOpen] = useState(false);
37
37
  const [editingOffer, setEditingOffer] = useState();
38
+ const [filtersOpen, setFiltersOpen] = useState(false);
38
39
  const query = {
39
40
  search: search || undefined,
40
41
  applicationMode: applicationMode === ALL ? undefined : applicationMode,
@@ -51,11 +52,11 @@ export function PromotionsPage({ className, pageSize = DEFAULT_PAGE_SIZE, onOpen
51
52
  const page = pageIndex + 1;
52
53
  const pageCount = Math.max(1, Math.ceil(total / pageSize));
53
54
  const showSkeleton = isPending || (isFetching && offers.length === 0);
54
- const hasActiveFilters = search !== "" ||
55
- applicationMode !== ALL ||
56
- status !== ALL ||
57
- scopeKind !== ALL ||
58
- Boolean(validityRange?.from || validityRange?.to);
55
+ const activeFilterCount = (applicationMode !== ALL ? 1 : 0) +
56
+ (status !== ALL ? 1 : 0) +
57
+ (scopeKind !== ALL ? 1 : 0) +
58
+ (validityRange?.from || validityRange?.to ? 1 : 0);
59
+ const hasActiveFilters = activeFilterCount > 0 || search !== "";
59
60
  const resetPage = () => setPageIndex(0);
60
61
  function openCreate() {
61
62
  setEditingOffer(undefined);
@@ -90,22 +91,30 @@ export function PromotionsPage({ className, pageSize = DEFAULT_PAGE_SIZE, onOpen
90
91
  void refetch();
91
92
  },
92
93
  })) : (_jsx(PromotionDialog, { open: dialogOpen, onOpenChange: setDialogOpen, offer: editingOffer }));
93
- return (_jsxs("div", { className: cn("flex flex-col gap-6 p-6", className), children: [_jsxs("div", { className: "flex items-center justify-between gap-4", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-2xl font-semibold tracking-tight", children: pageMessages.title }), _jsx("p", { className: "text-sm text-muted-foreground", children: pageMessages.description })] }), _jsxs(Button, { onClick: openCreate, children: [_jsx(Plus, { className: "mr-2 size-4", "aria-hidden": "true" }), pageMessages.newPromotion] })] }), _jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [_jsxs("div", { className: "relative min-w-[14rem] max-w-sm flex-1", children: [_jsx(Label, { htmlFor: "promotions-search", className: "sr-only", children: pageMessages.searchLabel }), _jsx(Search, { className: "absolute left-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground", "aria-hidden": "true" }), _jsx(Input, { id: "promotions-search", placeholder: pageMessages.searchPlaceholder, value: search, onChange: (event) => {
94
+ return (_jsxs("div", { className: cn("flex flex-col gap-6 p-6", className), children: [_jsx("div", { children: _jsx("h1", { className: "text-2xl font-bold tracking-tight", children: pageMessages.title }) }), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsxs("div", { className: "relative min-w-[14rem] flex-1", children: [_jsx(Label, { htmlFor: "promotions-search", className: "sr-only", children: pageMessages.searchLabel }), _jsx(Search, { className: "absolute left-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground", "aria-hidden": "true" }), _jsx(Input, { id: "promotions-search", placeholder: pageMessages.searchPlaceholder, value: search, onChange: (event) => {
94
95
  setSearch(event.target.value);
95
96
  resetPage();
96
- }, className: "pl-9" })] }), _jsxs(Select, { value: applicationMode, onValueChange: (value) => {
97
- setApplicationMode(value ?? ALL);
98
- resetPage();
99
- }, children: [_jsx(SelectTrigger, { className: "w-[10.5rem]", children: _jsx(SelectValue, { placeholder: pageMessages.modePlaceholder }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: ALL, children: pageMessages.allModes }), applicationModes.map((mode) => (_jsx(SelectItem, { value: mode, children: messages.common.applicationModeLabels[mode] }, mode)))] })] }), _jsxs(Select, { value: status, onValueChange: (value) => {
100
- setStatus(value ?? ALL);
101
- resetPage();
102
- }, children: [_jsx(SelectTrigger, { className: "w-[10.5rem]", children: _jsx(SelectValue, { placeholder: pageMessages.statusPlaceholder }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: ALL, children: pageMessages.allStatuses }), statusFilters.map((value) => (_jsx(SelectItem, { value: value, children: messages.common.statusLabels[value] }, value)))] })] }), _jsxs(Select, { value: scopeKind, onValueChange: (value) => {
103
- setScopeKind(value ?? ALL);
104
- resetPage();
105
- }, children: [_jsx(SelectTrigger, { className: "w-[11rem]", children: _jsx(SelectValue, { placeholder: pageMessages.scopePlaceholder }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: ALL, children: pageMessages.allScopes }), scopeKinds.map((value) => (_jsx(SelectItem, { value: value, children: messages.common.scopeKindLabels[value] }, value)))] })] }), _jsx(DateRangePicker, { value: validityRange, onChange: (value) => {
106
- setValidityRange(value);
107
- resetPage();
108
- }, placeholder: pageMessages.validityRangePlaceholder, className: "w-[15rem]" }), hasActiveFilters ? (_jsxs(Button, { variant: "ghost", onClick: clearFilters, children: [_jsx(X, { className: "mr-2 size-4", "aria-hidden": "true" }), pageMessages.clearFilters] })) : null] }), _jsx("div", { className: "rounded-md border", children: _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: pageMessages.columns.name }), _jsx(TableHead, { children: pageMessages.columns.mode }), _jsx(TableHead, { children: pageMessages.columns.scope }), _jsx(TableHead, { children: pageMessages.columns.discount }), _jsx(TableHead, { children: pageMessages.columns.validity }), _jsx(TableHead, { children: pageMessages.columns.code }), _jsx(TableHead, { children: pageMessages.columns.status })] }) }), _jsx(TableBody, { children: showSkeleton ? (_jsx(PromotionRowSkeleton, { rows: 6 })) : isError ? (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: TABLE_COLUMN_COUNT, className: "h-24 text-center text-sm text-destructive", children: formatMessage(pageMessages.loadFailedPrefix, {
97
+ }, className: "pl-9" })] }), _jsxs(Popover, { open: filtersOpen, onOpenChange: setFiltersOpen, children: [_jsx(PopoverTrigger, { render: _jsxs(Button, { variant: "outline", size: "default", children: [_jsx(ListFilter, { className: "mr-2 size-4" }), pageMessages.filtersButton, activeFilterCount > 0 && (_jsx(Badge, { variant: "secondary", className: "ml-2 px-1.5", children: activeFilterCount }))] }) }), _jsx(PopoverContent, { align: "start", className: "w-[22rem] p-4", children: _jsxs("div", { className: "flex flex-col gap-4", children: [_jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Label, { htmlFor: "promotions-filter-mode", children: pageMessages.modePlaceholder }), _jsxs(Select, { value: applicationMode, onValueChange: (value) => {
98
+ setApplicationMode(value ?? ALL);
99
+ resetPage();
100
+ }, children: [_jsx(SelectTrigger, { id: "promotions-filter-mode", className: "w-full", children: _jsx(SelectValue, { children: (value) => value === ALL
101
+ ? pageMessages.allModes
102
+ : (messages.common.applicationModeLabels[value] ?? value) }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: ALL, children: pageMessages.allModes }), applicationModes.map((mode) => (_jsx(SelectItem, { value: mode, children: messages.common.applicationModeLabels[mode] }, mode)))] })] })] }), _jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Label, { htmlFor: "promotions-filter-status", children: pageMessages.statusPlaceholder }), _jsxs(Select, { value: status, onValueChange: (value) => {
103
+ setStatus(value ?? ALL);
104
+ resetPage();
105
+ }, children: [_jsx(SelectTrigger, { id: "promotions-filter-status", className: "w-full", children: _jsx(SelectValue, { children: (value) => value === ALL
106
+ ? pageMessages.allStatuses
107
+ : (messages.common.statusLabels[value] ??
108
+ value) }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: ALL, children: pageMessages.allStatuses }), statusFilters.map((value) => (_jsx(SelectItem, { value: value, children: messages.common.statusLabels[value] }, value)))] })] })] }), _jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Label, { htmlFor: "promotions-filter-scope", children: pageMessages.scopePlaceholder }), _jsxs(Select, { value: scopeKind, onValueChange: (value) => {
109
+ setScopeKind(value ?? ALL);
110
+ resetPage();
111
+ }, children: [_jsx(SelectTrigger, { id: "promotions-filter-scope", className: "w-full", children: _jsx(SelectValue, { children: (value) => value === ALL
112
+ ? pageMessages.allScopes
113
+ : (messages.common.scopeKindLabels[value] ??
114
+ value) }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: ALL, children: pageMessages.allScopes }), scopeKinds.map((value) => (_jsx(SelectItem, { value: value, children: messages.common.scopeKindLabels[value] }, value)))] })] })] }), _jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Label, { htmlFor: "promotions-filter-validity", children: pageMessages.validityRangePlaceholder }), _jsx(DateRangePicker, { value: validityRange, onChange: (value) => {
115
+ setValidityRange(value);
116
+ resetPage();
117
+ }, placeholder: pageMessages.validityRangePlaceholder, className: "w-full" })] })] }) })] }), hasActiveFilters ? (_jsxs(Button, { variant: "ghost", size: "sm", onClick: clearFilters, children: [_jsx(X, { className: "mr-1 size-4", "aria-hidden": "true" }), pageMessages.clearFilters] })) : null, _jsx("div", { className: "ml-auto", children: _jsxs(Button, { onClick: openCreate, children: [_jsx(Plus, { className: "mr-1 size-4", "aria-hidden": "true" }), pageMessages.newPromotion] }) })] }), _jsx("div", { className: "rounded-md border", children: _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: pageMessages.columns.name }), _jsx(TableHead, { children: pageMessages.columns.mode }), _jsx(TableHead, { children: pageMessages.columns.scope }), _jsx(TableHead, { children: pageMessages.columns.discount }), _jsx(TableHead, { children: pageMessages.columns.validity }), _jsx(TableHead, { children: pageMessages.columns.code }), _jsx(TableHead, { children: pageMessages.columns.status })] }) }), _jsx(TableBody, { children: showSkeleton ? (_jsx(PromotionRowSkeleton, { rows: 6 })) : isError ? (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: TABLE_COLUMN_COUNT, className: "h-24 text-center text-sm text-destructive", children: formatMessage(pageMessages.loadFailedPrefix, {
109
118
  message: error instanceof Error ? error.message : String(error),
110
119
  }) }) })) : offers.length === 0 ? (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: TABLE_COLUMN_COUNT, className: "h-24 text-center text-sm text-muted-foreground", children: pageMessages.empty }) })) : (offers.map((offer) => (_jsxs(TableRow, { className: "cursor-pointer", onClick: () => openOffer(offer), children: [_jsxs(TableCell, { children: [_jsx("div", { className: "font-medium", children: offer.name }), _jsx("div", { className: "font-mono text-xs text-muted-foreground", children: offer.slug })] }), _jsx(TableCell, { children: _jsx(Badge, { variant: offer.code == null ? "secondary" : "outline", children: offer.code == null ? pageMessages.badges.auto : pageMessages.badges.code }) }), _jsx(TableCell, { className: "text-muted-foreground", children: summarizeScope(offer.scope, messages) }), _jsx(TableCell, { children: summarizeDiscount(offer, pageMessages) }), _jsx(TableCell, { className: "text-muted-foreground", children: summarizeValidity(offer.validFrom, offer.validUntil, pageMessages) }), _jsx(TableCell, { className: "font-mono text-xs", children: offer.code ?? pageMessages.summaries.noCode }), _jsx(TableCell, { children: _jsxs("div", { className: "flex flex-wrap gap-2", children: [_jsx(Badge, { variant: statusBadgeVariant(getOfferStatus(offer)), children: messages.common.statusLabels[getOfferStatus(offer)] }), offer.stackable ? (_jsx(Badge, { variant: "secondary", children: pageMessages.badges.stackable })) : null] }) })] }, offer.id)))) })] }) }), _jsx(PaginationBar, { shown: offers.length, total: total, page: page, pageCount: pageCount, onPrevious: () => setPageIndex((prev) => Math.max(0, prev - 1)), onNext: () => setPageIndex((prev) => prev + 1), canGoBack: pageIndex > 0, canGoForward: (pageIndex + 1) * pageSize < total, messages: pageMessages.pagination }), dialog] }));
111
120
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voyantjs/promotions-ui",
3
- "version": "0.52.1",
3
+ "version": "0.52.2",
4
4
  "license": "Apache-2.0",
5
5
  "repository": {
6
6
  "type": "git",
@@ -41,11 +41,11 @@
41
41
  "react": "^19.0.0",
42
42
  "react-dom": "^19.0.0",
43
43
  "zod": "^4.3.6",
44
- "@voyantjs/promotions-react": "0.52.1",
45
- "@voyantjs/ui": "0.52.1"
44
+ "@voyantjs/promotions-react": "0.52.2",
45
+ "@voyantjs/ui": "0.52.2"
46
46
  },
47
47
  "dependencies": {
48
- "@voyantjs/i18n": "0.52.1"
48
+ "@voyantjs/i18n": "0.52.2"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@tanstack/react-query": "^5.96.2",
@@ -57,9 +57,9 @@
57
57
  "typescript": "^6.0.2",
58
58
  "vitest": "^4.1.2",
59
59
  "zod": "^4.3.6",
60
- "@voyantjs/i18n": "0.52.1",
61
- "@voyantjs/promotions-react": "0.52.1",
62
- "@voyantjs/ui": "0.52.1",
60
+ "@voyantjs/i18n": "0.52.2",
61
+ "@voyantjs/promotions-react": "0.52.2",
62
+ "@voyantjs/ui": "0.52.2",
63
63
  "@voyantjs/voyant-typescript-config": "0.1.0"
64
64
  },
65
65
  "files": [