@voyantjs/pricing-ui 0.15.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +11 -0
  2. package/dist/components/cancellation-policy-combobox.d.ts +1 -1
  3. package/dist/components/cancellation-policy-combobox.d.ts.map +1 -1
  4. package/dist/components/cancellation-policy-combobox.js +6 -4
  5. package/dist/components/cancellation-policy-rule-dialog.d.ts.map +1 -1
  6. package/dist/components/cancellation-policy-rule-dialog.js +23 -15
  7. package/dist/components/dropoff-price-rule-dialog.d.ts.map +1 -1
  8. package/dist/components/dropoff-price-rule-dialog.js +32 -15
  9. package/dist/components/extra-price-rule-dialog.d.ts.map +1 -1
  10. package/dist/components/extra-price-rule-dialog.js +28 -14
  11. package/dist/components/option-price-rule-combobox.d.ts +1 -1
  12. package/dist/components/option-price-rule-combobox.d.ts.map +1 -1
  13. package/dist/components/option-price-rule-combobox.js +6 -4
  14. package/dist/components/option-price-rule-dialog.d.ts.map +1 -1
  15. package/dist/components/option-price-rule-dialog.js +35 -23
  16. package/dist/components/option-start-time-rule-dialog.d.ts.map +1 -1
  17. package/dist/components/option-start-time-rule-dialog.js +33 -14
  18. package/dist/components/option-unit-price-rule-dialog.d.ts.map +1 -1
  19. package/dist/components/option-unit-price-rule-dialog.js +30 -16
  20. package/dist/components/option-unit-tier-dialog.d.ts.map +1 -1
  21. package/dist/components/option-unit-tier-dialog.js +24 -10
  22. package/dist/components/pickup-price-rule-dialog.d.ts.map +1 -1
  23. package/dist/components/pickup-price-rule-dialog.js +29 -13
  24. package/dist/components/price-catalog-combobox.d.ts +1 -1
  25. package/dist/components/price-catalog-combobox.d.ts.map +1 -1
  26. package/dist/components/price-catalog-combobox.js +6 -2
  27. package/dist/components/price-schedule-combobox.d.ts.map +1 -1
  28. package/dist/components/price-schedule-combobox.js +6 -4
  29. package/dist/components/price-schedule-dialog.d.ts.map +1 -1
  30. package/dist/components/price-schedule-dialog.js +26 -15
  31. package/dist/components/pricing-category-combobox.d.ts.map +1 -1
  32. package/dist/components/pricing-category-combobox.js +4 -2
  33. package/dist/components/pricing-category-dependency-dialog.d.ts.map +1 -1
  34. package/dist/components/pricing-category-dependency-dialog.js +5 -1
  35. package/dist/components/pricing-category-dependency-form.d.ts.map +1 -1
  36. package/dist/components/pricing-category-dependency-form.js +17 -8
  37. package/dist/components/pricing-category-dialog.d.ts.map +1 -1
  38. package/dist/components/pricing-category-dialog.js +7 -3
  39. package/dist/components/pricing-category-form.d.ts.map +1 -1
  40. package/dist/components/pricing-category-form.js +20 -13
  41. package/dist/components/pricing-category-list.d.ts.map +1 -1
  42. package/dist/components/pricing-category-list.js +10 -6
  43. package/dist/components/product-combobox.d.ts +1 -1
  44. package/dist/components/product-combobox.d.ts.map +1 -1
  45. package/dist/components/product-combobox.js +6 -2
  46. package/dist/components/product-option-combobox.d.ts.map +1 -1
  47. package/dist/components/product-option-combobox.js +7 -5
  48. package/dist/i18n/en.d.ts +426 -0
  49. package/dist/i18n/en.d.ts.map +1 -0
  50. package/dist/i18n/en.js +425 -0
  51. package/dist/i18n/index.d.ts +5 -0
  52. package/dist/i18n/index.d.ts.map +1 -0
  53. package/dist/i18n/index.js +3 -0
  54. package/dist/i18n/messages.d.ts +391 -0
  55. package/dist/i18n/messages.d.ts.map +1 -0
  56. package/dist/i18n/messages.js +17 -0
  57. package/dist/i18n/provider.d.ts +874 -0
  58. package/dist/i18n/provider.d.ts.map +1 -0
  59. package/dist/i18n/provider.js +44 -0
  60. package/dist/i18n/ro.d.ts +426 -0
  61. package/dist/i18n/ro.d.ts.map +1 -0
  62. package/dist/i18n/ro.js +425 -0
  63. package/dist/index.d.ts +2 -0
  64. package/dist/index.d.ts.map +1 -1
  65. package/dist/index.js +1 -0
  66. package/package.json +25 -9
@@ -8,16 +8,17 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "
8
8
  import { Switch } from "@voyantjs/ui/components/switch";
9
9
  import { Loader2 } from "lucide-react";
10
10
  import * as React from "react";
11
+ import { usePricingUiMessagesOrDefault } from "../i18n/provider";
11
12
  const CATEGORY_TYPES = [
12
- { value: "adult", label: "Adult" },
13
- { value: "child", label: "Child" },
14
- { value: "infant", label: "Infant" },
15
- { value: "senior", label: "Senior" },
16
- { value: "group", label: "Group" },
17
- { value: "room", label: "Room" },
18
- { value: "vehicle", label: "Vehicle" },
19
- { value: "service", label: "Service" },
20
- { value: "other", label: "Other" },
13
+ { value: "adult" },
14
+ { value: "child" },
15
+ { value: "infant" },
16
+ { value: "senior" },
17
+ { value: "group" },
18
+ { value: "room" },
19
+ { value: "vehicle" },
20
+ { value: "service" },
21
+ { value: "other" },
21
22
  ];
22
23
  function initialState(mode) {
23
24
  if (mode.kind === "edit") {
@@ -70,6 +71,7 @@ export function PricingCategoryForm({ mode, onSuccess, onCancel }) {
70
71
  const [state, setState] = React.useState(() => initialState(mode));
71
72
  const [error, setError] = React.useState(null);
72
73
  const { create, update } = usePricingCategoryMutation();
74
+ const messages = usePricingUiMessagesOrDefault();
73
75
  React.useEffect(() => {
74
76
  setState(initialState(mode));
75
77
  setError(null);
@@ -79,7 +81,7 @@ export function PricingCategoryForm({ mode, onSuccess, onCancel }) {
79
81
  event.preventDefault();
80
82
  setError(null);
81
83
  if (!state.name.trim()) {
82
- setError("Category name is required.");
84
+ setError(messages.pricingCategoryForm.validation.nameRequired);
83
85
  return;
84
86
  }
85
87
  try {
@@ -89,11 +91,16 @@ export function PricingCategoryForm({ mode, onSuccess, onCancel }) {
89
91
  onSuccess?.(category);
90
92
  }
91
93
  catch (err) {
92
- setError(err instanceof Error ? err.message : "Failed to save pricing category.");
94
+ setError(err instanceof Error ? err.message : messages.pricingCategoryForm.validation.saveFailed);
93
95
  }
94
96
  };
95
- return (_jsxs("form", { "data-slot": "pricing-category-form", onSubmit: handleSubmit, className: "flex flex-col gap-4", children: [_jsxs("div", { className: "grid gap-4 sm:grid-cols-2", children: [_jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Label, { htmlFor: "pricing-category-name", children: "Name" }), _jsx(Input, { id: "pricing-category-name", required: true, autoFocus: true, value: state.name, onChange: (event) => setState((prev) => ({ ...prev, name: event.target.value })), placeholder: "Adult" })] }), _jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Label, { htmlFor: "pricing-category-code", children: "Code" }), _jsx(Input, { id: "pricing-category-code", value: state.code, onChange: (event) => setState((prev) => ({ ...prev, code: event.target.value })), placeholder: "adult" })] })] }), _jsxs("div", { className: "grid gap-4 sm:grid-cols-2", children: [_jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Label, { children: "Type" }), _jsxs(Select, { items: CATEGORY_TYPES, value: state.categoryType, onValueChange: (value) => setState((prev) => ({
97
+ return (_jsxs("form", { "data-slot": "pricing-category-form", onSubmit: handleSubmit, className: "flex flex-col gap-4", children: [_jsxs("div", { className: "grid gap-4 sm:grid-cols-2", children: [_jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Label, { htmlFor: "pricing-category-name", children: messages.pricingCategoryForm.fields.name }), _jsx(Input, { id: "pricing-category-name", required: true, autoFocus: true, value: state.name, onChange: (event) => setState((prev) => ({ ...prev, name: event.target.value })), placeholder: messages.pricingCategoryForm.placeholders.name })] }), _jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Label, { htmlFor: "pricing-category-code", children: messages.pricingCategoryForm.fields.code }), _jsx(Input, { id: "pricing-category-code", value: state.code, onChange: (event) => setState((prev) => ({ ...prev, code: event.target.value })), placeholder: messages.pricingCategoryForm.placeholders.code })] })] }), _jsxs("div", { className: "grid gap-4 sm:grid-cols-2", children: [_jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Label, { children: messages.pricingCategoryForm.fields.type }), _jsxs(Select, { items: CATEGORY_TYPES.map((type) => ({
98
+ label: messages.common.categoryTypeLabels[type.value],
99
+ value: type.value,
100
+ })), value: state.categoryType, onValueChange: (value) => setState((prev) => ({
96
101
  ...prev,
97
102
  categoryType: value,
98
- })), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: CATEGORY_TYPES.map((type) => (_jsx(SelectItem, { value: type.value, children: type.label }, type.value))) })] })] }), _jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Label, { htmlFor: "pricing-category-seat-occupancy", children: "Seat occupancy" }), _jsx(Input, { id: "pricing-category-seat-occupancy", type: "number", min: "0", value: state.seatOccupancy, onChange: (event) => setState((prev) => ({ ...prev, seatOccupancy: event.target.value })) })] })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Switch, { checked: state.isAgeQualified, onCheckedChange: (isAgeQualified) => setState((prev) => ({ ...prev, isAgeQualified })) }), _jsx(Label, { children: "Age qualified" })] }), state.isAgeQualified ? (_jsxs("div", { className: "grid gap-4 sm:grid-cols-2", children: [_jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Label, { htmlFor: "pricing-category-min-age", children: "Min age" }), _jsx(Input, { id: "pricing-category-min-age", type: "number", min: "0", value: state.minAge, onChange: (event) => setState((prev) => ({ ...prev, minAge: event.target.value })) })] }), _jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Label, { htmlFor: "pricing-category-max-age", children: "Max age" }), _jsx(Input, { id: "pricing-category-max-age", type: "number", min: "0", value: state.maxAge, onChange: (event) => setState((prev) => ({ ...prev, maxAge: event.target.value })) })] })] })) : null, _jsxs("div", { className: "grid gap-4 sm:grid-cols-2", children: [_jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Label, { htmlFor: "pricing-category-sort-order", children: "Sort order" }), _jsx(Input, { id: "pricing-category-sort-order", type: "number", value: state.sortOrder, onChange: (event) => setState((prev) => ({ ...prev, sortOrder: event.target.value })) })] }), _jsxs("div", { className: "flex items-center gap-2 pt-7", children: [_jsx(Switch, { checked: state.active, onCheckedChange: (active) => setState((prev) => ({ ...prev, active })) }), _jsx(Label, { children: "Active" })] })] }), error ? _jsx("p", { className: "text-sm text-destructive", children: error }) : null, _jsxs("div", { className: "flex items-center justify-end gap-2", children: [onCancel ? (_jsx(Button, { type: "button", variant: "ghost", onClick: onCancel, children: "Cancel" })) : null, _jsxs(Button, { type: "submit", disabled: isSubmitting, children: [isSubmitting ? (_jsx(Loader2, { className: "mr-2 size-4 animate-spin", "aria-hidden": "true" })) : null, mode.kind === "edit" ? "Save changes" : "Create category"] })] })] }));
103
+ })), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: CATEGORY_TYPES.map((type) => (_jsx(SelectItem, { value: type.value, children: messages.common.categoryTypeLabels[type.value] }, type.value))) })] })] }), _jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Label, { htmlFor: "pricing-category-seat-occupancy", children: messages.pricingCategoryForm.fields.seatOccupancy }), _jsx(Input, { id: "pricing-category-seat-occupancy", type: "number", min: "0", value: state.seatOccupancy, onChange: (event) => setState((prev) => ({ ...prev, seatOccupancy: event.target.value })) })] })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Switch, { checked: state.isAgeQualified, onCheckedChange: (isAgeQualified) => setState((prev) => ({ ...prev, isAgeQualified })) }), _jsx(Label, { children: messages.pricingCategoryForm.fields.ageQualified })] }), state.isAgeQualified ? (_jsxs("div", { className: "grid gap-4 sm:grid-cols-2", children: [_jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Label, { htmlFor: "pricing-category-min-age", children: messages.pricingCategoryForm.fields.minAge }), _jsx(Input, { id: "pricing-category-min-age", type: "number", min: "0", value: state.minAge, onChange: (event) => setState((prev) => ({ ...prev, minAge: event.target.value })) })] }), _jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Label, { htmlFor: "pricing-category-max-age", children: messages.pricingCategoryForm.fields.maxAge }), _jsx(Input, { id: "pricing-category-max-age", type: "number", min: "0", value: state.maxAge, onChange: (event) => setState((prev) => ({ ...prev, maxAge: event.target.value })) })] })] })) : null, _jsxs("div", { className: "grid gap-4 sm:grid-cols-2", children: [_jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Label, { htmlFor: "pricing-category-sort-order", children: messages.pricingCategoryForm.fields.sortOrder }), _jsx(Input, { id: "pricing-category-sort-order", type: "number", value: state.sortOrder, onChange: (event) => setState((prev) => ({ ...prev, sortOrder: event.target.value })) })] }), _jsxs("div", { className: "flex items-center gap-2 pt-7", children: [_jsx(Switch, { checked: state.active, onCheckedChange: (active) => setState((prev) => ({ ...prev, active })) }), _jsx(Label, { children: messages.pricingCategoryForm.fields.active })] })] }), error ? _jsx("p", { className: "text-sm text-destructive", children: error }) : null, _jsxs("div", { className: "flex items-center justify-end gap-2", children: [onCancel ? (_jsx(Button, { type: "button", variant: "ghost", onClick: onCancel, children: messages.common.cancel })) : null, _jsxs(Button, { type: "submit", disabled: isSubmitting, children: [isSubmitting ? (_jsx(Loader2, { className: "mr-2 size-4 animate-spin", "aria-hidden": "true" })) : null, mode.kind === "edit"
104
+ ? messages.common.saveChanges
105
+ : messages.pricingCategoryForm.actions.create] })] })] }));
99
106
  }
@@ -1 +1 @@
1
- {"version":3,"file":"pricing-category-list.d.ts","sourceRoot":"","sources":["../../src/components/pricing-category-list.tsx"],"names":[],"mappings":"AA8BA,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,wBAAgB,mBAAmB,CAAC,EAAE,QAAa,EAAE,GAAE,wBAA6B,2CAyKnF"}
1
+ {"version":3,"file":"pricing-category-list.d.ts","sourceRoot":"","sources":["../../src/components/pricing-category-list.tsx"],"names":[],"mappings":"AA+BA,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,wBAAgB,mBAAmB,CAAC,EAAE,QAAa,EAAE,GAAE,wBAA6B,2CAyLnF"}
@@ -8,8 +8,10 @@ import { Input } from "@voyantjs/ui/components/input";
8
8
  import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@voyantjs/ui/components/table";
9
9
  import { Loader2, MoreHorizontal, Pencil, Plus, Search, Trash2 } from "lucide-react";
10
10
  import * as React from "react";
11
+ import { usePricingUiMessagesOrDefault } from "../i18n/provider";
11
12
  import { PricingCategoryDialog } from "./pricing-category-dialog";
12
13
  export function PricingCategoryList({ pageSize = 25 } = {}) {
14
+ const messages = usePricingUiMessagesOrDefault();
13
15
  const [dialogOpen, setDialogOpen] = React.useState(false);
14
16
  const [editing, setEditing] = React.useState(undefined);
15
17
  const [search, setSearch] = React.useState("");
@@ -25,20 +27,22 @@ export function PricingCategoryList({ pageSize = 25 } = {}) {
25
27
  const total = data?.total ?? 0;
26
28
  const page = Math.floor(offset / pageSize) + 1;
27
29
  const pageCount = Math.max(1, Math.ceil(total / pageSize));
28
- return (_jsxs("div", { "data-slot": "pricing-category-list", className: "flex flex-col gap-4", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsxs("div", { className: "relative w-full max-w-sm", children: [_jsx(Search, { className: "absolute left-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground" }), _jsx(Input, { placeholder: "Search pricing categories\u2026", value: search, onChange: (event) => {
30
+ return (_jsxs("div", { "data-slot": "pricing-category-list", className: "flex flex-col gap-4", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsxs("div", { className: "relative w-full max-w-sm", children: [_jsx(Search, { className: "absolute left-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground" }), _jsx(Input, { placeholder: messages.pricingCategoryList.searchPlaceholder, value: search, onChange: (event) => {
29
31
  setSearch(event.target.value);
30
32
  setOffset(0);
31
33
  }, className: "pl-9" })] }), _jsxs(Button, { onClick: () => {
32
34
  setEditing(undefined);
33
35
  setDialogOpen(true);
34
- }, children: [_jsx(Plus, { className: "mr-2 size-4" }), "New category"] })] }), _jsx("div", { className: "rounded-md border", children: _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: "Name" }), _jsx(TableHead, { children: "Code" }), _jsx(TableHead, { children: "Type" }), _jsx(TableHead, { children: "Age" }), _jsx(TableHead, { children: "Seat" }), _jsx(TableHead, { children: "Sort" }), _jsx(TableHead, { children: "Status" }), _jsx(TableHead, { className: "w-[80px] text-right", children: "Actions" })] }) }), _jsx(TableBody, { children: isPending ? (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: 8, className: "h-24 text-center", children: _jsx(Loader2, { className: "mx-auto size-4 animate-spin text-muted-foreground" }) }) })) : isError ? (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: 8, className: "h-24 text-center text-sm text-destructive", children: "Failed to load pricing categories." }) })) : categories.length === 0 ? (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: 8, className: "h-24 text-center text-sm text-muted-foreground", children: "No pricing categories found." }) })) : (categories.map((category) => (_jsxs(TableRow, { children: [_jsx(TableCell, { className: "font-medium", children: category.name }), _jsx(TableCell, { className: "font-mono text-xs text-muted-foreground", children: category.code ?? "—" }), _jsx(TableCell, { children: _jsx(Badge, { variant: "outline", className: "capitalize", children: category.categoryType }) }), _jsx(TableCell, { className: "text-xs text-muted-foreground", children: category.isAgeQualified
36
+ }, children: [_jsx(Plus, { className: "mr-2 size-4" }), messages.pricingCategoryList.add] })] }), _jsx("div", { className: "rounded-md border", children: _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: messages.pricingCategoryList.columns.name }), _jsx(TableHead, { children: messages.pricingCategoryList.columns.code }), _jsx(TableHead, { children: messages.pricingCategoryList.columns.type }), _jsx(TableHead, { children: messages.pricingCategoryList.columns.age }), _jsx(TableHead, { children: messages.pricingCategoryList.columns.seat }), _jsx(TableHead, { children: messages.pricingCategoryList.columns.sort }), _jsx(TableHead, { children: messages.pricingCategoryList.columns.status }), _jsx(TableHead, { className: "w-[80px] text-right", children: messages.pricingCategoryList.columns.actions })] }) }), _jsx(TableBody, { children: isPending ? (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: 8, className: "h-24 text-center", children: _jsx(Loader2, { className: "mx-auto size-4 animate-spin text-muted-foreground" }) }) })) : isError ? (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: 8, className: "h-24 text-center text-sm text-destructive", children: messages.pricingCategoryList.loadingError }) })) : categories.length === 0 ? (_jsx(TableRow, { children: _jsx(TableCell, { colSpan: 8, className: "h-24 text-center text-sm text-muted-foreground", children: messages.pricingCategoryList.empty }) })) : (categories.map((category) => (_jsxs(TableRow, { children: [_jsx(TableCell, { className: "font-medium", children: category.name }), _jsx(TableCell, { className: "font-mono text-xs text-muted-foreground", children: category.code ?? messages.common.none }), _jsx(TableCell, { children: _jsx(Badge, { variant: "outline", children: messages.common.categoryTypeLabels[category.categoryType] }) }), _jsx(TableCell, { className: "text-xs text-muted-foreground", children: category.isAgeQualified
35
37
  ? `${category.minAge ?? 0}–${category.maxAge ?? "∞"}`
36
- : "—" }), _jsx(TableCell, { className: "font-mono", children: category.seatOccupancy }), _jsx(TableCell, { className: "font-mono", children: category.sortOrder }), _jsx(TableCell, { children: _jsx(Badge, { variant: category.active ? "default" : "outline", children: category.active ? "Active" : "Inactive" }) }), _jsx(TableCell, { className: "text-right", children: _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { className: "inline-flex size-8 items-center justify-center rounded-md text-muted-foreground outline-hidden hover:bg-accent hover:text-accent-foreground", children: _jsx(MoreHorizontal, { className: "size-4" }) }), _jsxs(DropdownMenuContent, { align: "end", children: [_jsxs(DropdownMenuItem, { onClick: () => {
38
+ : messages.common.none }), _jsx(TableCell, { className: "font-mono", children: category.seatOccupancy }), _jsx(TableCell, { className: "font-mono", children: category.sortOrder }), _jsx(TableCell, { children: _jsx(Badge, { variant: category.active ? "default" : "outline", children: category.active ? messages.common.active : messages.common.inactive }) }), _jsx(TableCell, { className: "text-right", children: _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { className: "inline-flex size-8 items-center justify-center rounded-md text-muted-foreground outline-hidden hover:bg-accent hover:text-accent-foreground", children: _jsx(MoreHorizontal, { className: "size-4" }) }), _jsxs(DropdownMenuContent, { align: "end", children: [_jsxs(DropdownMenuItem, { onClick: () => {
37
39
  setEditing(category);
38
40
  setDialogOpen(true);
39
- }, children: [_jsx(Pencil, { className: "size-4" }), "Edit"] }), _jsx(DropdownMenuSeparator, {}), _jsxs(DropdownMenuItem, { variant: "destructive", onClick: () => {
40
- if (confirm(`Delete category "${category.name}"?`)) {
41
+ }, children: [_jsx(Pencil, { className: "size-4" }), messages.pricingCategoryList.edit] }), _jsx(DropdownMenuSeparator, {}), _jsxs(DropdownMenuItem, { variant: "destructive", onClick: () => {
42
+ if (confirm(messages.pricingCategoryList.deleteConfirm.replace("{name}", category.name))) {
41
43
  remove.mutate(category.id);
42
44
  }
43
- }, children: [_jsx(Trash2, { className: "size-4" }), "Delete"] })] })] }) })] }, category.id)))) })] }) }), _jsxs("div", { className: "flex items-center justify-between text-sm text-muted-foreground", children: [_jsxs("span", { children: ["Showing ", categories.length, " of ", total] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { variant: "outline", size: "sm", disabled: offset === 0, onClick: () => setOffset((prev) => Math.max(0, prev - pageSize)), children: "Previous" }), _jsxs("span", { children: ["Page ", page, " / ", pageCount] }), _jsx(Button, { variant: "outline", size: "sm", disabled: offset + pageSize >= total, onClick: () => setOffset((prev) => prev + pageSize), children: "Next" })] })] }), _jsx(PricingCategoryDialog, { open: dialogOpen, onOpenChange: setDialogOpen, category: editing })] }));
45
+ }, children: [_jsx(Trash2, { className: "size-4" }), messages.pricingCategoryList.delete] })] })] }) })] }, category.id)))) })] }) }), _jsxs("div", { className: "flex items-center justify-between text-sm text-muted-foreground", children: [_jsx("span", { children: messages.pricingCategoryList.showingSummary
46
+ .replace("{count}", String(categories.length))
47
+ .replace("{total}", String(total)) }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { variant: "outline", size: "sm", disabled: offset === 0, onClick: () => setOffset((prev) => Math.max(0, prev - pageSize)), children: messages.common.previous }), _jsxs("span", { children: [messages.common.page, " ", page, " / ", pageCount] }), _jsx(Button, { variant: "outline", size: "sm", disabled: offset + pageSize >= total, onClick: () => setOffset((prev) => prev + pageSize), children: messages.common.next })] })] }), _jsx(PricingCategoryDialog, { open: dialogOpen, onOpenChange: setDialogOpen, category: editing })] }));
44
48
  }
@@ -4,6 +4,6 @@ type Props = {
4
4
  placeholder?: string;
5
5
  disabled?: boolean;
6
6
  };
7
- export declare function ProductCombobox({ value, onChange, placeholder, disabled, }: Props): import("react/jsx-runtime").JSX.Element;
7
+ export declare function ProductCombobox({ value, onChange, placeholder, disabled }: Props): import("react/jsx-runtime").JSX.Element;
8
8
  export {};
9
9
  //# sourceMappingURL=product-combobox.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"product-combobox.d.ts","sourceRoot":"","sources":["../../src/components/product-combobox.tsx"],"names":[],"mappings":"AAYA,KAAK,KAAK,GAAG;IACX,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;IAChC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAA;IACxC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAID,wBAAgB,eAAe,CAAC,EAC9B,KAAK,EACL,QAAQ,EACR,WAAgC,EAChC,QAAQ,GACT,EAAE,KAAK,2CAkEP"}
1
+ {"version":3,"file":"product-combobox.d.ts","sourceRoot":"","sources":["../../src/components/product-combobox.tsx"],"names":[],"mappings":"AAcA,KAAK,KAAK,GAAG;IACX,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;IAChC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAA;IACxC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAID,wBAAgB,eAAe,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,EAAE,KAAK,2CAwEhF"}
@@ -2,8 +2,10 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useProduct, useProducts } from "@voyantjs/products-react";
3
3
  import { Combobox, ComboboxCollection, ComboboxContent, ComboboxEmpty, ComboboxInput, ComboboxItem, ComboboxList, } from "@voyantjs/ui/components/combobox";
4
4
  import * as React from "react";
5
+ import { usePricingUiMessagesOrDefault } from "../i18n/provider";
5
6
  const PAGE_SIZE = 25;
6
- export function ProductCombobox({ value, onChange, placeholder = "Search products…", disabled, }) {
7
+ export function ProductCombobox({ value, onChange, placeholder, disabled }) {
8
+ const messages = usePricingUiMessagesOrDefault();
7
9
  const [search, setSearch] = React.useState("");
8
10
  const listQuery = useProducts({ search: search || undefined, limit: PAGE_SIZE });
9
11
  const selectedQuery = useProduct(value ?? undefined, { enabled: !!value });
@@ -32,7 +34,9 @@ export function ProductCombobox({ value, onChange, placeholder = "Search product
32
34
  const id = next ?? null;
33
35
  onChange(id);
34
36
  setInputValue(id ? (itemMap.get(id)?.name ?? "") : "");
35
- }, children: [_jsx(ComboboxInput, { placeholder: placeholder, showClear: !!value }), _jsxs(ComboboxContent, { children: [_jsx(ComboboxEmpty, { children: listQuery.isPending || selectedQuery.isPending ? "Loading…" : "No products found." }), _jsx(ComboboxList, { children: _jsx(ComboboxCollection, { children: (id) => {
37
+ }, children: [_jsx(ComboboxInput, { placeholder: placeholder ?? messages.comboboxes.product.placeholder, showClear: !!value }), _jsxs(ComboboxContent, { children: [_jsx(ComboboxEmpty, { children: listQuery.isPending || selectedQuery.isPending
38
+ ? messages.common.loading
39
+ : messages.comboboxes.product.empty }), _jsx(ComboboxList, { children: _jsx(ComboboxCollection, { children: (id) => {
36
40
  const item = itemMap.get(id);
37
41
  if (!item)
38
42
  return null;
@@ -1 +1 @@
1
- {"version":3,"file":"product-option-combobox.d.ts","sourceRoot":"","sources":["../../src/components/product-option-combobox.tsx"],"names":[],"mappings":"AAgBA,KAAK,KAAK,GAAG;IACX,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;IAChC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAA;IACxC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAID,wBAAgB,qBAAqB,CAAC,EACpC,SAAS,EACT,KAAK,EACL,QAAQ,EACR,WAAsC,EACtC,QAAQ,GACT,EAAE,KAAK,2CA4EP"}
1
+ {"version":3,"file":"product-option-combobox.d.ts","sourceRoot":"","sources":["../../src/components/product-option-combobox.tsx"],"names":[],"mappings":"AAkBA,KAAK,KAAK,GAAG;IACX,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;IAChC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAA;IACxC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAID,wBAAgB,qBAAqB,CAAC,EACpC,SAAS,EACT,KAAK,EACL,QAAQ,EACR,WAAW,EACX,QAAQ,GACT,EAAE,KAAK,2CAgFP"}
@@ -2,8 +2,10 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useProductOption, useProductOptions, } from "@voyantjs/products-react";
3
3
  import { Combobox, ComboboxCollection, ComboboxContent, ComboboxEmpty, ComboboxInput, ComboboxItem, ComboboxList, } from "@voyantjs/ui/components/combobox";
4
4
  import * as React from "react";
5
+ import { usePricingUiMessagesOrDefault } from "../i18n/provider";
5
6
  const PAGE_SIZE = 100;
6
- export function ProductOptionCombobox({ productId, value, onChange, placeholder = "Select product option…", disabled, }) {
7
+ export function ProductOptionCombobox({ productId, value, onChange, placeholder, disabled, }) {
8
+ const messages = usePricingUiMessagesOrDefault();
7
9
  const [search, setSearch] = React.useState("");
8
10
  const listQuery = useProductOptions({
9
11
  productId: productId || undefined,
@@ -38,11 +40,11 @@ export function ProductOptionCombobox({ productId, value, onChange, placeholder
38
40
  const id = next ?? null;
39
41
  onChange(id);
40
42
  setInputValue(id ? (itemMap.get(id)?.name ?? "") : "");
41
- }, children: [_jsx(ComboboxInput, { placeholder: placeholder, showClear: !!value }), _jsxs(ComboboxContent, { children: [_jsx(ComboboxEmpty, { children: listQuery.isPending || selectedQuery.isPending
42
- ? "Loading…"
43
+ }, children: [_jsx(ComboboxInput, { placeholder: placeholder ?? messages.comboboxes.productOption.placeholder, showClear: !!value }), _jsxs(ComboboxContent, { children: [_jsx(ComboboxEmpty, { children: listQuery.isPending || selectedQuery.isPending
44
+ ? messages.common.loading
43
45
  : productId
44
- ? "No product options found."
45
- : "Select a product first." }), _jsx(ComboboxList, { children: _jsx(ComboboxCollection, { children: (id) => {
46
+ ? messages.comboboxes.productOption.empty
47
+ : messages.comboboxes.productOption.missingParent }), _jsx(ComboboxList, { children: _jsx(ComboboxCollection, { children: (id) => {
46
48
  const item = itemMap.get(id);
47
49
  if (!item)
48
50
  return null;
@@ -0,0 +1,426 @@
1
+ export declare const pricingUiEn: {
2
+ common: {
3
+ cancel: string;
4
+ saveChanges: string;
5
+ create: string;
6
+ add: string;
7
+ loading: string;
8
+ none: string;
9
+ previous: string;
10
+ next: string;
11
+ page: string;
12
+ active: string;
13
+ inactive: string;
14
+ categoryTypeLabels: {
15
+ adult: string;
16
+ child: string;
17
+ infant: string;
18
+ senior: string;
19
+ group: string;
20
+ room: string;
21
+ vehicle: string;
22
+ service: string;
23
+ other: string;
24
+ };
25
+ dependencyTypeLabels: {
26
+ requires: string;
27
+ limits_per_master: string;
28
+ limits_sum: string;
29
+ excludes: string;
30
+ };
31
+ chargeTypeLabels: {
32
+ none: string;
33
+ amount: string;
34
+ percentage: string;
35
+ };
36
+ addonPricingModeLabels: {
37
+ included: string;
38
+ per_person: string;
39
+ per_booking: string;
40
+ on_request: string;
41
+ unavailable: string;
42
+ };
43
+ optionPriceRulePricingModeLabels: {
44
+ per_person: string;
45
+ per_booking: string;
46
+ starting_from: string;
47
+ free: string;
48
+ on_request: string;
49
+ };
50
+ startTimeRuleModeLabels: {
51
+ included: string;
52
+ excluded: string;
53
+ override: string;
54
+ adjustment: string;
55
+ };
56
+ adjustmentTypeLabels: {
57
+ fixed: string;
58
+ percentage: string;
59
+ };
60
+ unitPricingModeLabels: {
61
+ per_unit: string;
62
+ per_person: string;
63
+ per_booking: string;
64
+ included: string;
65
+ free: string;
66
+ on_request: string;
67
+ };
68
+ };
69
+ comboboxes: {
70
+ pricingCategory: {
71
+ placeholder: string;
72
+ empty: string;
73
+ };
74
+ priceCatalog: {
75
+ placeholder: string;
76
+ empty: string;
77
+ };
78
+ priceSchedule: {
79
+ placeholder: string;
80
+ empty: string;
81
+ };
82
+ cancellationPolicy: {
83
+ placeholder: string;
84
+ empty: string;
85
+ };
86
+ optionPriceRule: {
87
+ placeholder: string;
88
+ empty: string;
89
+ };
90
+ product: {
91
+ placeholder: string;
92
+ empty: string;
93
+ };
94
+ productOption: {
95
+ placeholder: string;
96
+ empty: string;
97
+ missingParent: string;
98
+ };
99
+ };
100
+ pricingCategoryDialog: {
101
+ titles: {
102
+ create: string;
103
+ edit: string;
104
+ };
105
+ descriptions: {
106
+ create: string;
107
+ edit: string;
108
+ };
109
+ };
110
+ pricingCategoryForm: {
111
+ fields: {
112
+ name: string;
113
+ code: string;
114
+ type: string;
115
+ seatOccupancy: string;
116
+ ageQualified: string;
117
+ minAge: string;
118
+ maxAge: string;
119
+ sortOrder: string;
120
+ active: string;
121
+ };
122
+ placeholders: {
123
+ name: string;
124
+ code: string;
125
+ };
126
+ validation: {
127
+ nameRequired: string;
128
+ saveFailed: string;
129
+ };
130
+ actions: {
131
+ create: string;
132
+ };
133
+ };
134
+ pricingCategoryList: {
135
+ searchPlaceholder: string;
136
+ add: string;
137
+ columns: {
138
+ name: string;
139
+ code: string;
140
+ type: string;
141
+ age: string;
142
+ seat: string;
143
+ sort: string;
144
+ status: string;
145
+ actions: string;
146
+ };
147
+ loadingError: string;
148
+ empty: string;
149
+ edit: string;
150
+ delete: string;
151
+ deleteConfirm: string;
152
+ showingSummary: string;
153
+ };
154
+ pricingCategoryDependencyDialog: {
155
+ titles: {
156
+ create: string;
157
+ edit: string;
158
+ };
159
+ description: string;
160
+ };
161
+ pricingCategoryDependencyForm: {
162
+ fields: {
163
+ masterCategory: string;
164
+ dependentCategory: string;
165
+ dependencyType: string;
166
+ maxPerMaster: string;
167
+ maxDependentSum: string;
168
+ active: string;
169
+ notes: string;
170
+ };
171
+ placeholders: {
172
+ categorySearch: string;
173
+ };
174
+ validation: {
175
+ categoriesRequired: string;
176
+ saveFailed: string;
177
+ };
178
+ actions: {
179
+ create: string;
180
+ };
181
+ };
182
+ priceScheduleDialog: {
183
+ titles: {
184
+ create: string;
185
+ edit: string;
186
+ };
187
+ fields: {
188
+ catalog: string;
189
+ name: string;
190
+ code: string;
191
+ recurrenceRule: string;
192
+ validFrom: string;
193
+ validTo: string;
194
+ timezone: string;
195
+ priority: string;
196
+ active: string;
197
+ notes: string;
198
+ };
199
+ placeholders: {
200
+ catalog: string;
201
+ name: string;
202
+ code: string;
203
+ recurrenceRule: string;
204
+ validFrom: string;
205
+ validTo: string;
206
+ timezone: string;
207
+ };
208
+ validation: {
209
+ catalogRequired: string;
210
+ nameRequired: string;
211
+ recurrenceRuleRequired: string;
212
+ };
213
+ helpText: {
214
+ recurrenceRuleExample: string;
215
+ };
216
+ actions: {
217
+ create: string;
218
+ };
219
+ };
220
+ cancellationPolicyRuleDialog: {
221
+ titles: {
222
+ create: string;
223
+ edit: string;
224
+ };
225
+ fields: {
226
+ cutoffMinutesBefore: string;
227
+ sortOrder: string;
228
+ chargeType: string;
229
+ chargeAmount: string;
230
+ chargePercent: string;
231
+ active: string;
232
+ notes: string;
233
+ };
234
+ placeholders: {
235
+ cutoffMinutesBefore: string;
236
+ chargePercent: string;
237
+ };
238
+ helpText: {
239
+ cutoffMinutesBefore: string;
240
+ };
241
+ actions: {
242
+ create: string;
243
+ };
244
+ };
245
+ optionPriceRuleDialog: {
246
+ titles: {
247
+ create: string;
248
+ edit: string;
249
+ };
250
+ fields: {
251
+ product: string;
252
+ option: string;
253
+ name: string;
254
+ code: string;
255
+ catalog: string;
256
+ schedule: string;
257
+ cancellationPolicy: string;
258
+ pricingMode: string;
259
+ baseSell: string;
260
+ baseCost: string;
261
+ minPerBooking: string;
262
+ maxPerBooking: string;
263
+ description: string;
264
+ allPricingCategories: string;
265
+ defaultRule: string;
266
+ active: string;
267
+ notes: string;
268
+ };
269
+ validation: {
270
+ productRequired: string;
271
+ optionRequired: string;
272
+ catalogRequired: string;
273
+ nameRequired: string;
274
+ };
275
+ actions: {
276
+ create: string;
277
+ };
278
+ };
279
+ locationPriceRuleDialog: {
280
+ fields: {
281
+ optionPriceRule: string;
282
+ optionId: string;
283
+ facilityId: string;
284
+ pickupPointId: string;
285
+ dropoffName: string;
286
+ dropoffCode: string;
287
+ pricingMode: string;
288
+ sellAmount: string;
289
+ costAmount: string;
290
+ sortOrder: string;
291
+ active: string;
292
+ notes: string;
293
+ };
294
+ placeholders: {
295
+ optionId: string;
296
+ facilityId: string;
297
+ pickupPointId: string;
298
+ };
299
+ validation: {
300
+ optionPriceRuleRequired: string;
301
+ optionIdRequired: string;
302
+ pickupPointIdRequired: string;
303
+ dropoffNameRequired: string;
304
+ };
305
+ actions: {
306
+ createRule: string;
307
+ saveRule: string;
308
+ };
309
+ pickup: {
310
+ titles: {
311
+ create: string;
312
+ edit: string;
313
+ };
314
+ };
315
+ dropoff: {
316
+ titles: {
317
+ create: string;
318
+ edit: string;
319
+ };
320
+ };
321
+ extra: {
322
+ titles: {
323
+ create: string;
324
+ edit: string;
325
+ };
326
+ fields: {
327
+ productExtraId: string;
328
+ optionExtraConfigId: string;
329
+ };
330
+ placeholders: {
331
+ productExtraId: string;
332
+ optionExtraConfigId: string;
333
+ };
334
+ };
335
+ };
336
+ optionStartTimeRuleDialog: {
337
+ titles: {
338
+ create: string;
339
+ edit: string;
340
+ };
341
+ fields: {
342
+ optionPriceRule: string;
343
+ optionId: string;
344
+ startTimeId: string;
345
+ ruleMode: string;
346
+ adjustmentType: string;
347
+ sellAdjustment: string;
348
+ costAdjustment: string;
349
+ adjustmentPercent: string;
350
+ active: string;
351
+ notes: string;
352
+ };
353
+ placeholders: {
354
+ optionId: string;
355
+ startTimeId: string;
356
+ select: string;
357
+ };
358
+ validation: {
359
+ optionPriceRuleRequired: string;
360
+ optionIdRequired: string;
361
+ startTimeIdRequired: string;
362
+ };
363
+ actions: {
364
+ create: string;
365
+ };
366
+ };
367
+ optionUnitPriceRuleDialog: {
368
+ titles: {
369
+ create: string;
370
+ edit: string;
371
+ };
372
+ fields: {
373
+ optionPriceRule: string;
374
+ optionId: string;
375
+ unitId: string;
376
+ pricingCategory: string;
377
+ pricingMode: string;
378
+ sellAmount: string;
379
+ costAmount: string;
380
+ minQuantity: string;
381
+ maxQuantity: string;
382
+ sortOrder: string;
383
+ active: string;
384
+ notes: string;
385
+ };
386
+ placeholders: {
387
+ optionId: string;
388
+ unitId: string;
389
+ pricingCategory: string;
390
+ };
391
+ validation: {
392
+ optionPriceRuleRequired: string;
393
+ optionIdRequired: string;
394
+ unitIdRequired: string;
395
+ };
396
+ actions: {
397
+ create: string;
398
+ };
399
+ };
400
+ optionUnitTierDialog: {
401
+ titles: {
402
+ create: string;
403
+ edit: string;
404
+ };
405
+ fields: {
406
+ optionUnitPriceRuleId: string;
407
+ minQuantity: string;
408
+ maxQuantity: string;
409
+ sellAmount: string;
410
+ costAmount: string;
411
+ sortOrder: string;
412
+ active: string;
413
+ };
414
+ placeholders: {
415
+ optionUnitPriceRuleId: string;
416
+ };
417
+ validation: {
418
+ optionUnitPriceRuleIdRequired: string;
419
+ minQuantityMin: string;
420
+ };
421
+ actions: {
422
+ create: string;
423
+ };
424
+ };
425
+ };
426
+ //# sourceMappingURL=en.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"en.d.ts","sourceRoot":"","sources":["../../src/i18n/en.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyaK,CAAA"}