@voyantjs/products-ui 0.101.1 → 0.101.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.
Files changed (121) hide show
  1. package/dist/components/product-detail/date-picker.d.ts +44 -0
  2. package/dist/components/product-detail/date-picker.d.ts.map +1 -0
  3. package/dist/components/product-detail/date-picker.js +125 -0
  4. package/dist/components/product-detail/host.d.ts +53 -0
  5. package/dist/components/product-detail/host.d.ts.map +1 -0
  6. package/dist/components/product-detail/host.js +24 -0
  7. package/dist/components/product-detail/index.d.ts +6 -0
  8. package/dist/components/product-detail/index.d.ts.map +1 -0
  9. package/dist/components/product-detail/index.js +5 -0
  10. package/dist/components/product-detail/product-activity-section.d.ts +4 -0
  11. package/dist/components/product-detail/product-activity-section.d.ts.map +1 -0
  12. package/dist/components/product-detail/product-activity-section.js +37 -0
  13. package/dist/components/product-detail/product-day-sheet.d.ts +14 -0
  14. package/dist/components/product-detail/product-day-sheet.d.ts.map +1 -0
  15. package/dist/components/product-detail/product-day-sheet.js +75 -0
  16. package/dist/components/product-detail/product-day-translation.d.ts +41 -0
  17. package/dist/components/product-detail/product-day-translation.d.ts.map +1 -0
  18. package/dist/components/product-detail/product-day-translation.js +111 -0
  19. package/dist/components/product-detail/product-departure-dialog.d.ts +11 -0
  20. package/dist/components/product-detail/product-departure-dialog.d.ts.map +1 -0
  21. package/dist/components/product-detail/product-departure-dialog.js +10 -0
  22. package/dist/components/product-detail/product-departure-form.d.ts +25 -0
  23. package/dist/components/product-detail/product-departure-form.d.ts.map +1 -0
  24. package/dist/components/product-detail/product-departure-form.js +217 -0
  25. package/dist/components/product-detail/product-departure-pricing-override-dialog.d.ts +8 -0
  26. package/dist/components/product-detail/product-departure-pricing-override-dialog.d.ts.map +1 -0
  27. package/dist/components/product-detail/product-departure-pricing-override-dialog.js +125 -0
  28. package/dist/components/product-detail/product-detail-day-row.d.ts +14 -0
  29. package/dist/components/product-detail/product-detail-day-row.d.ts.map +1 -0
  30. package/dist/components/product-detail/product-detail-day-row.js +43 -0
  31. package/dist/components/product-detail/product-detail-dialog.d.ts +10 -0
  32. package/dist/components/product-detail/product-detail-dialog.d.ts.map +1 -0
  33. package/dist/components/product-detail/product-detail-dialog.js +10 -0
  34. package/dist/components/product-detail/product-detail-form.d.ts +19 -0
  35. package/dist/components/product-detail/product-detail-form.d.ts.map +1 -0
  36. package/dist/components/product-detail/product-detail-form.js +177 -0
  37. package/dist/components/product-detail/product-detail-header.d.ts +12 -0
  38. package/dist/components/product-detail/product-detail-header.d.ts.map +1 -0
  39. package/dist/components/product-detail/product-detail-header.js +19 -0
  40. package/dist/components/product-detail/product-detail-itinerary-section.d.ts +4 -0
  41. package/dist/components/product-detail/product-detail-itinerary-section.d.ts.map +1 -0
  42. package/dist/components/product-detail/product-detail-itinerary-section.js +201 -0
  43. package/dist/components/product-detail/product-detail-page.d.ts +4 -0
  44. package/dist/components/product-detail/product-detail-page.d.ts.map +1 -0
  45. package/dist/components/product-detail/product-detail-page.js +97 -0
  46. package/dist/components/product-detail/product-detail-sections.d.ts +63 -0
  47. package/dist/components/product-detail/product-detail-sections.d.ts.map +1 -0
  48. package/dist/components/product-detail/product-detail-sections.js +143 -0
  49. package/dist/components/product-detail/product-detail-shared.d.ts +264 -0
  50. package/dist/components/product-detail/product-detail-shared.d.ts.map +1 -0
  51. package/dist/components/product-detail/product-detail-shared.js +157 -0
  52. package/dist/components/product-detail/product-detail-skeleton.d.ts +9 -0
  53. package/dist/components/product-detail/product-detail-skeleton.d.ts.map +1 -0
  54. package/dist/components/product-detail/product-detail-skeleton.js +53 -0
  55. package/dist/components/product-detail/product-extras-section.d.ts +4 -0
  56. package/dist/components/product-detail/product-extras-section.d.ts.map +1 -0
  57. package/dist/components/product-detail/product-extras-section.js +141 -0
  58. package/dist/components/product-detail/product-itinerary-form.d.ts +16 -0
  59. package/dist/components/product-detail/product-itinerary-form.d.ts.map +1 -0
  60. package/dist/components/product-detail/product-itinerary-form.js +38 -0
  61. package/dist/components/product-detail/product-market-rules-section.d.ts +6 -0
  62. package/dist/components/product-detail/product-market-rules-section.d.ts.map +1 -0
  63. package/dist/components/product-detail/product-market-rules-section.js +81 -0
  64. package/dist/components/product-detail/product-media-gallery.d.ts +19 -0
  65. package/dist/components/product-detail/product-media-gallery.d.ts.map +1 -0
  66. package/dist/components/product-detail/product-media-gallery.js +114 -0
  67. package/dist/components/product-detail/product-option-price-rule-dialog.d.ts +12 -0
  68. package/dist/components/product-detail/product-option-price-rule-dialog.d.ts.map +1 -0
  69. package/dist/components/product-detail/product-option-price-rule-dialog.js +10 -0
  70. package/dist/components/product-detail/product-option-price-rule-form.d.ts +29 -0
  71. package/dist/components/product-detail/product-option-price-rule-form.d.ts.map +1 -0
  72. package/dist/components/product-detail/product-option-price-rule-form.js +125 -0
  73. package/dist/components/product-detail/product-options-pricing.d.ts +6 -0
  74. package/dist/components/product-detail/product-options-pricing.d.ts.map +1 -0
  75. package/dist/components/product-detail/product-options-pricing.js +363 -0
  76. package/dist/components/product-detail/product-options-shared.d.ts +609 -0
  77. package/dist/components/product-detail/product-options-shared.d.ts.map +1 -0
  78. package/dist/components/product-detail/product-options-shared.js +34 -0
  79. package/dist/components/product-detail/product-payment-policy-section.d.ts +17 -0
  80. package/dist/components/product-detail/product-payment-policy-section.d.ts.map +1 -0
  81. package/dist/components/product-detail/product-payment-policy-section.js +58 -0
  82. package/dist/components/product-detail/product-schedule-dialog.d.ts +11 -0
  83. package/dist/components/product-detail/product-schedule-dialog.d.ts.map +1 -0
  84. package/dist/components/product-detail/product-schedule-dialog.js +10 -0
  85. package/dist/components/product-detail/product-schedule-form.d.ts +17 -0
  86. package/dist/components/product-detail/product-schedule-form.d.ts.map +1 -0
  87. package/dist/components/product-detail/product-schedule-form.js +222 -0
  88. package/dist/components/product-detail/product-service-dialog.d.ts +12 -0
  89. package/dist/components/product-detail/product-service-dialog.d.ts.map +1 -0
  90. package/dist/components/product-detail/product-service-dialog.js +10 -0
  91. package/dist/components/product-detail/product-service-form.d.ts +22 -0
  92. package/dist/components/product-detail/product-service-form.d.ts.map +1 -0
  93. package/dist/components/product-detail/product-service-form.js +154 -0
  94. package/dist/components/product-detail/product-translation-popover.d.ts +91 -0
  95. package/dist/components/product-detail/product-translation-popover.d.ts.map +1 -0
  96. package/dist/components/product-detail/product-translation-popover.js +217 -0
  97. package/dist/components/product-detail/product-unit-dialog.d.ts +12 -0
  98. package/dist/components/product-detail/product-unit-dialog.d.ts.map +1 -0
  99. package/dist/components/product-detail/product-unit-dialog.js +10 -0
  100. package/dist/components/product-detail/product-unit-form.d.ts +26 -0
  101. package/dist/components/product-detail/product-unit-form.d.ts.map +1 -0
  102. package/dist/components/product-detail/product-unit-form.js +109 -0
  103. package/dist/components/product-detail/product-unit-price-rule-dialog.d.ts +16 -0
  104. package/dist/components/product-detail/product-unit-price-rule-dialog.d.ts.map +1 -0
  105. package/dist/components/product-detail/product-unit-price-rule-dialog.js +10 -0
  106. package/dist/components/product-detail/product-unit-price-rule-form.d.ts +28 -0
  107. package/dist/components/product-detail/product-unit-price-rule-form.d.ts.map +1 -0
  108. package/dist/components/product-detail/product-unit-price-rule-form.js +126 -0
  109. package/dist/components/product-detail/timezone-options.d.ts +9 -0
  110. package/dist/components/product-detail/timezone-options.d.ts.map +1 -0
  111. package/dist/components/product-detail/timezone-options.js +28 -0
  112. package/dist/components/product-detail/use-product-detail-data.d.ts +41 -0
  113. package/dist/components/product-detail/use-product-detail-data.d.ts.map +1 -0
  114. package/dist/components/product-detail/use-product-detail-data.js +143 -0
  115. package/dist/components/product-detail/use-product-detail-dialogs.d.ts +24 -0
  116. package/dist/components/product-detail/use-product-detail-dialogs.d.ts.map +1 -0
  117. package/dist/components/product-detail/use-product-detail-dialogs.js +40 -0
  118. package/dist/components/product-detail/zod-resolver.d.ts +4 -0
  119. package/dist/components/product-detail/zod-resolver.d.ts.map +1 -0
  120. package/dist/components/product-detail/zod-resolver.js +39 -0
  121. package/package.json +38 -19
@@ -0,0 +1,28 @@
1
+ import { timezones } from "@voyantjs/utils/timezones";
2
+ function buildTimezoneOptions() {
3
+ const seen = new Map();
4
+ for (const tz of timezones) {
5
+ for (const id of tz.utc) {
6
+ if (seen.has(id))
7
+ continue;
8
+ seen.set(id, { id, label: tz.text, offset: tz.offset });
9
+ }
10
+ }
11
+ // Include the browser-resolved zone if not already present
12
+ const browserZone = typeof Intl !== "undefined" ? Intl.DateTimeFormat().resolvedOptions().timeZone : null;
13
+ if (browserZone && !seen.has(browserZone)) {
14
+ seen.set(browserZone, { id: browserZone, label: browserZone, offset: 0 });
15
+ }
16
+ return Array.from(seen.values()).sort((a, b) => {
17
+ if (a.offset !== b.offset)
18
+ return a.offset - b.offset;
19
+ return a.id.localeCompare(b.id);
20
+ });
21
+ }
22
+ export const TIMEZONE_OPTIONS = buildTimezoneOptions();
23
+ export const TIMEZONE_IDS = TIMEZONE_OPTIONS.map((t) => t.id);
24
+ const TIMEZONE_BY_ID = new Map(TIMEZONE_OPTIONS.map((t) => [t.id, t]));
25
+ export function getTimezoneLabel(id) {
26
+ const tz = TIMEZONE_BY_ID.get(id);
27
+ return tz ? `${id} — ${tz.label}` : id;
28
+ }
@@ -0,0 +1,41 @@
1
+ import { useMutation } from "@tanstack/react-query";
2
+ import { useProduct } from "@voyantjs/products-react";
3
+ import { type AvailabilityRule, type ChannelInfo, type ChannelProductMapping, type DepartureSlot, type ProductMediaItem } from "./product-detail-shared.js";
4
+ export interface UseProductDetailDataResult {
5
+ product: ReturnType<typeof useProduct>["data"];
6
+ isPending: boolean;
7
+ slots: DepartureSlot[];
8
+ rules: AvailabilityRule[];
9
+ channels: ChannelInfo[];
10
+ mappings: ChannelProductMapping[];
11
+ media: ProductMediaItem[];
12
+ itineraryNameById: Map<string, string>;
13
+ refetch: {
14
+ slots: () => void;
15
+ rules: () => void;
16
+ mappings: () => void;
17
+ media: () => void;
18
+ };
19
+ mutations: {
20
+ addChannelMapping: ReturnType<typeof useMutation<unknown, Error, string>>;
21
+ removeChannelMapping: ReturnType<typeof useMutation<unknown, Error, string>>;
22
+ duplicateProduct: ReturnType<typeof useMutation<{
23
+ data: {
24
+ id: string;
25
+ };
26
+ }, Error, void>>;
27
+ deleteProduct: ReturnType<typeof useMutation<unknown, Error, void>>;
28
+ deleteSlot: ReturnType<typeof useMutation<unknown, Error, string>>;
29
+ deleteRule: ReturnType<typeof useMutation<unknown, Error, string>>;
30
+ uploadMedia: ReturnType<typeof useMutation<unknown, Error, {
31
+ file: File;
32
+ dayId?: string;
33
+ }>>;
34
+ deleteMedia: ReturnType<typeof useMutation<unknown, Error, string>>;
35
+ setCover: ReturnType<typeof useMutation<unknown, Error, string>>;
36
+ generateBrochure: ReturnType<typeof useMutation<unknown, Error, void>>;
37
+ };
38
+ invalidateProduct: () => void;
39
+ }
40
+ export declare function useProductDetailData(productId: string): UseProductDetailDataResult;
41
+ //# sourceMappingURL=use-product-detail-data.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-product-detail-data.d.ts","sourceRoot":"","sources":["../../../src/components/product-detail/use-product-detail-data.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAA4B,MAAM,uBAAuB,CAAA;AAC7E,OAAO,EAAqB,UAAU,EAAyB,MAAM,0BAA0B,CAAA;AAK/F,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,qBAAqB,EAC1B,KAAK,aAAa,EAMlB,KAAK,gBAAgB,EACtB,MAAM,4BAA4B,CAAA;AAEnC,MAAM,WAAW,0BAA0B;IACzC,OAAO,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,CAAC,CAAA;IAC9C,SAAS,EAAE,OAAO,CAAA;IAClB,KAAK,EAAE,aAAa,EAAE,CAAA;IACtB,KAAK,EAAE,gBAAgB,EAAE,CAAA;IACzB,QAAQ,EAAE,WAAW,EAAE,CAAA;IACvB,QAAQ,EAAE,qBAAqB,EAAE,CAAA;IACjC,KAAK,EAAE,gBAAgB,EAAE,CAAA;IACzB,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACtC,OAAO,EAAE;QACP,KAAK,EAAE,MAAM,IAAI,CAAA;QACjB,KAAK,EAAE,MAAM,IAAI,CAAA;QACjB,QAAQ,EAAE,MAAM,IAAI,CAAA;QACpB,KAAK,EAAE,MAAM,IAAI,CAAA;KAClB,CAAA;IACD,SAAS,EAAE;QACT,iBAAiB,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAA;QACzE,oBAAoB,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAA;QAC5E,gBAAgB,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC;YAAE,IAAI,EAAE;gBAAE,EAAE,EAAE,MAAM,CAAA;aAAE,CAAA;SAAE,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAA;QACvF,aAAa,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAA;QACnE,UAAU,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAA;QAClE,UAAU,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAA;QAClE,WAAW,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,OAAO,EAAE,KAAK,EAAE;YAAE,IAAI,EAAE,IAAI,CAAC;YAAC,KAAK,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC,CAAA;QAC3F,WAAW,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAA;QACnE,QAAQ,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAA;QAChE,gBAAgB,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAA;KACvE,CAAA;IACD,iBAAiB,EAAE,MAAM,IAAI,CAAA;CAC9B;AAED,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,0BAA0B,CAiKlF"}
@@ -0,0 +1,143 @@
1
+ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
2
+ import { productsQueryKeys, useProduct, useProductItineraries } from "@voyantjs/products-react";
3
+ import { useMemo } from "react";
4
+ import { useProductDetailHost, useProductDetailMessages } from "./host.js";
5
+ import { getChannelsQueryOptions, getProductChannelMappingsQueryOptions, getProductMediaQueryOptions, getProductRulesQueryOptions, getProductSlotsQueryOptions, } from "./product-detail-shared.js";
6
+ export function useProductDetailData(productId) {
7
+ const queryClient = useQueryClient();
8
+ const host = useProductDetailHost();
9
+ const api = host.api;
10
+ const messages = useProductDetailMessages();
11
+ const productMessages = messages.products.core;
12
+ const productQuery = useProduct(productId);
13
+ const itinerariesQuery = useProductItineraries(productId);
14
+ const productActionLedgerQueryKey = [...productsQueryKeys.product(productId), "action-ledger"];
15
+ const slotsQuery = useQuery(getProductSlotsQueryOptions(api, productId));
16
+ const rulesQuery = useQuery(getProductRulesQueryOptions(api, productId));
17
+ const channelsQuery = useQuery(getChannelsQueryOptions(api));
18
+ const mappingsQuery = useQuery(getProductChannelMappingsQueryOptions(api, productId));
19
+ const mediaQuery = useQuery(getProductMediaQueryOptions(api, productId));
20
+ const addChannelMapping = useMutation({
21
+ mutationFn: (channelId) => api.post("/v1/distribution/product-mappings", {
22
+ channelId,
23
+ productId,
24
+ active: true,
25
+ }),
26
+ onSuccess: () => {
27
+ void mappingsQuery.refetch();
28
+ void queryClient.invalidateQueries({ queryKey: productActionLedgerQueryKey });
29
+ },
30
+ });
31
+ const removeChannelMapping = useMutation({
32
+ mutationFn: (mappingId) => api.delete(`/v1/distribution/product-mappings/${mappingId}`),
33
+ onSuccess: () => {
34
+ void mappingsQuery.refetch();
35
+ void queryClient.invalidateQueries({ queryKey: productActionLedgerQueryKey });
36
+ },
37
+ });
38
+ const deleteProduct = useMutation({
39
+ mutationFn: () => api.delete(`/v1/products/${productId}`),
40
+ onSuccess: () => {
41
+ void queryClient.invalidateQueries({ queryKey: ["products"] });
42
+ void queryClient.invalidateQueries({ queryKey: productActionLedgerQueryKey });
43
+ },
44
+ });
45
+ const duplicateProduct = useMutation({
46
+ mutationFn: () => api.post(`/v1/admin/products/${productId}/duplicate`),
47
+ onSuccess: () => {
48
+ void queryClient.invalidateQueries({ queryKey: productsQueryKeys.products() });
49
+ },
50
+ });
51
+ const deleteSlot = useMutation({
52
+ mutationFn: (slotId) => api.delete(`/v1/availability/slots/${slotId}`),
53
+ onSuccess: () => {
54
+ void slotsQuery.refetch();
55
+ void queryClient.invalidateQueries({ queryKey: productActionLedgerQueryKey });
56
+ },
57
+ });
58
+ const deleteRule = useMutation({
59
+ mutationFn: (ruleId) => api.delete(`/v1/availability/rules/${ruleId}`),
60
+ onSuccess: () => {
61
+ void rulesQuery.refetch();
62
+ void queryClient.invalidateQueries({ queryKey: productActionLedgerQueryKey });
63
+ },
64
+ });
65
+ const uploadMedia = useMutation({
66
+ mutationFn: async ({ file, dayId }) => {
67
+ if (!host.uploadMedia)
68
+ throw new Error(productMessages.uploadFailed);
69
+ const result = await host.uploadMedia(file, { productId, dayId });
70
+ const endpoint = dayId
71
+ ? `/v1/products/${productId}/days/${dayId}/media`
72
+ : `/v1/products/${productId}/media`;
73
+ return api.post(endpoint, {
74
+ mediaType: result.mediaType,
75
+ name: result.name,
76
+ url: result.url,
77
+ storageKey: result.storageKey,
78
+ mimeType: result.mimeType,
79
+ fileSize: result.fileSize,
80
+ });
81
+ },
82
+ onSuccess: () => {
83
+ void mediaQuery.refetch();
84
+ void queryClient.invalidateQueries({ queryKey: productActionLedgerQueryKey });
85
+ },
86
+ });
87
+ const deleteMedia = useMutation({
88
+ mutationFn: (mediaId) => api.delete(`/v1/products/media/${mediaId}`),
89
+ onSuccess: () => {
90
+ void mediaQuery.refetch();
91
+ void queryClient.invalidateQueries({ queryKey: productActionLedgerQueryKey });
92
+ },
93
+ });
94
+ const setCover = useMutation({
95
+ mutationFn: (mediaId) => api.patch(`/v1/products/media/${mediaId}/set-cover`, {}),
96
+ onSuccess: () => {
97
+ void mediaQuery.refetch();
98
+ void queryClient.invalidateQueries({ queryKey: productActionLedgerQueryKey });
99
+ },
100
+ });
101
+ const generateBrochure = useMutation({
102
+ mutationFn: () => api.post(`/v1/admin/products/${productId}/brochure/generate`, {}),
103
+ onSuccess: () => {
104
+ void mediaQuery.refetch();
105
+ void queryClient.invalidateQueries({ queryKey: productActionLedgerQueryKey });
106
+ },
107
+ });
108
+ const itineraryNameById = useMemo(() => new Map((itinerariesQuery.data?.data ?? []).map((itinerary) => [itinerary.id, itinerary.name])), [itinerariesQuery.data]);
109
+ const invalidateProduct = () => {
110
+ void queryClient.invalidateQueries({ queryKey: productsQueryKeys.product(productId) });
111
+ void queryClient.invalidateQueries({ queryKey: productsQueryKeys.products() });
112
+ void queryClient.invalidateQueries({ queryKey: productActionLedgerQueryKey });
113
+ };
114
+ return {
115
+ product: productQuery.data,
116
+ isPending: productQuery.isPending,
117
+ slots: slotsQuery.data?.data ?? [],
118
+ rules: rulesQuery.data?.data ?? [],
119
+ channels: channelsQuery.data?.data ?? [],
120
+ mappings: mappingsQuery.data?.data ?? [],
121
+ media: mediaQuery.data?.data ?? [],
122
+ itineraryNameById,
123
+ refetch: {
124
+ slots: () => void slotsQuery.refetch(),
125
+ rules: () => void rulesQuery.refetch(),
126
+ mappings: () => void mappingsQuery.refetch(),
127
+ media: () => void mediaQuery.refetch(),
128
+ },
129
+ mutations: {
130
+ addChannelMapping,
131
+ removeChannelMapping,
132
+ duplicateProduct,
133
+ deleteProduct,
134
+ deleteSlot,
135
+ deleteRule,
136
+ uploadMedia,
137
+ deleteMedia,
138
+ setCover,
139
+ generateBrochure,
140
+ },
141
+ invalidateProduct,
142
+ };
143
+ }
@@ -0,0 +1,24 @@
1
+ import type { AvailabilityRule, DepartureSlot } from "./product-detail-shared.js";
2
+ export interface Toggle {
3
+ open: boolean;
4
+ setOpen: (open: boolean) => void;
5
+ openNow: () => void;
6
+ close: () => void;
7
+ }
8
+ export interface EditingToggle<T> {
9
+ open: boolean;
10
+ setOpen: (open: boolean) => void;
11
+ editing: T | undefined;
12
+ openNew: () => void;
13
+ openEdit: (item: T) => void;
14
+ close: () => void;
15
+ }
16
+ export interface UseProductDetailDialogsResult {
17
+ edit: Toggle;
18
+ bookingCreate: Toggle;
19
+ departure: EditingToggle<DepartureSlot>;
20
+ departureOverride: EditingToggle<DepartureSlot>;
21
+ schedule: EditingToggle<AvailabilityRule>;
22
+ }
23
+ export declare function useProductDetailDialogs(): UseProductDetailDialogsResult;
24
+ //# sourceMappingURL=use-product-detail-dialogs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-product-detail-dialogs.d.ts","sourceRoot":"","sources":["../../../src/components/product-detail/use-product-detail-dialogs.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAA;AAEjF,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,OAAO,CAAA;IACb,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IAChC,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,KAAK,EAAE,MAAM,IAAI,CAAA;CAClB;AAED,MAAM,WAAW,aAAa,CAAC,CAAC;IAC9B,IAAI,EAAE,OAAO,CAAA;IACb,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IAChC,OAAO,EAAE,CAAC,GAAG,SAAS,CAAA;IACtB,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAA;IAC3B,KAAK,EAAE,MAAM,IAAI,CAAA;CAClB;AAED,MAAM,WAAW,6BAA6B;IAC5C,IAAI,EAAE,MAAM,CAAA;IACZ,aAAa,EAAE,MAAM,CAAA;IACrB,SAAS,EAAE,aAAa,CAAC,aAAa,CAAC,CAAA;IACvC,iBAAiB,EAAE,aAAa,CAAC,aAAa,CAAC,CAAA;IAC/C,QAAQ,EAAE,aAAa,CAAC,gBAAgB,CAAC,CAAA;CAC1C;AAkCD,wBAAgB,uBAAuB,IAAI,6BAA6B,CAQvE"}
@@ -0,0 +1,40 @@
1
+ import { useState } from "react";
2
+ function useToggle() {
3
+ const [open, setOpen] = useState(false);
4
+ return {
5
+ open,
6
+ setOpen,
7
+ openNow: () => setOpen(true),
8
+ close: () => setOpen(false),
9
+ };
10
+ }
11
+ function useEditingToggle() {
12
+ const [open, setOpen] = useState(false);
13
+ const [editing, setEditing] = useState();
14
+ return {
15
+ open,
16
+ setOpen,
17
+ editing,
18
+ openNew: () => {
19
+ setEditing(undefined);
20
+ setOpen(true);
21
+ },
22
+ openEdit: (item) => {
23
+ setEditing(item);
24
+ setOpen(true);
25
+ },
26
+ close: () => {
27
+ setOpen(false);
28
+ setEditing(undefined);
29
+ },
30
+ };
31
+ }
32
+ export function useProductDetailDialogs() {
33
+ return {
34
+ edit: useToggle(),
35
+ bookingCreate: useToggle(),
36
+ departure: useEditingToggle(),
37
+ departureOverride: useEditingToggle(),
38
+ schedule: useEditingToggle(),
39
+ };
40
+ }
@@ -0,0 +1,4 @@
1
+ import type { FieldValues, Resolver } from "react-hook-form";
2
+ import type { z } from "zod/v4";
3
+ export declare function zodResolver<TSchema extends z.ZodType<FieldValues, FieldValues>>(schema: TSchema): Resolver<z.input<TSchema>, unknown, z.output<TSchema>>;
4
+ //# sourceMappingURL=zod-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zod-resolver.d.ts","sourceRoot":"","sources":["../../../src/components/product-detail/zod-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,WAAW,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AACzE,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAA;AA+B/B,wBAAgB,WAAW,CAAC,OAAO,SAAS,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,WAAW,CAAC,EAC7E,MAAM,EAAE,OAAO,GACd,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CA6BxD"}
@@ -0,0 +1,39 @@
1
+ function setFieldError(target, path, error) {
2
+ let current = target;
3
+ for (let index = 0; index < path.length; index += 1) {
4
+ const key = String(path[index] ?? "root");
5
+ if (index === path.length - 1) {
6
+ current[key] = error;
7
+ return;
8
+ }
9
+ const next = current[key];
10
+ if (typeof next !== "object" || next === null) {
11
+ current[key] = {};
12
+ }
13
+ current = current[key];
14
+ }
15
+ }
16
+ export function zodResolver(schema) {
17
+ return async (values) => {
18
+ const result = await schema.safeParseAsync(values);
19
+ if (result.success) {
20
+ return {
21
+ values: result.data,
22
+ errors: {},
23
+ };
24
+ }
25
+ const errors = {};
26
+ for (const issue of result.error.issues) {
27
+ const path = issue.path.filter((segment) => typeof segment !== "symbol");
28
+ const normalizedPath = path.length > 0 ? path : ["root"];
29
+ setFieldError(errors, normalizedPath, {
30
+ type: issue.code,
31
+ message: issue.message,
32
+ });
33
+ }
34
+ return {
35
+ values: {},
36
+ errors: errors,
37
+ };
38
+ };
39
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voyantjs/products-ui",
3
- "version": "0.101.1",
3
+ "version": "0.101.2",
4
4
  "license": "Apache-2.0",
5
5
  "repository": {
6
6
  "type": "git",
@@ -33,6 +33,11 @@
33
33
  "import": "./dist/i18n/ro.js",
34
34
  "default": "./dist/i18n/ro.js"
35
35
  },
36
+ "./components/product-detail": {
37
+ "types": "./dist/components/product-detail/index.d.ts",
38
+ "import": "./dist/components/product-detail/index.js",
39
+ "default": "./dist/components/product-detail/index.js"
40
+ },
36
41
  "./components/*": {
37
42
  "types": "./dist/components/*.d.ts",
38
43
  "import": "./dist/components/*.js",
@@ -45,17 +50,26 @@
45
50
  "react-dom": "^19.0.0",
46
51
  "react-hook-form": "^7.60.0",
47
52
  "zod": "^4.3.6",
48
- "@voyantjs/availability-react": "0.101.1",
49
- "@voyantjs/catalog-react": "0.101.1",
50
- "@voyantjs/finance": "0.101.1",
51
- "@voyantjs/finance-ui": "0.101.1",
52
- "@voyantjs/pricing-react": "0.101.1",
53
- "@voyantjs/products-react": "0.101.1",
54
- "@voyantjs/suppliers-react": "0.101.1",
55
- "@voyantjs/ui": "0.101.1"
53
+ "@voyantjs/availability": "0.101.2",
54
+ "@voyantjs/availability-react": "0.101.2",
55
+ "@voyantjs/catalog-react": "0.101.2",
56
+ "@voyantjs/extras-react": "0.101.2",
57
+ "@voyantjs/finance": "0.101.2",
58
+ "@voyantjs/finance-ui": "0.101.2",
59
+ "@voyantjs/markets-react": "0.101.2",
60
+ "@voyantjs/pricing-react": "0.101.2",
61
+ "@voyantjs/pricing-ui": "0.101.2",
62
+ "@voyantjs/products-react": "0.101.2",
63
+ "@voyantjs/suppliers-react": "0.101.2",
64
+ "@voyantjs/ui": "0.101.2",
65
+ "@voyantjs/utils": "0.101.2"
56
66
  },
57
67
  "dependencies": {
58
- "@voyantjs/i18n": "0.101.1"
68
+ "date-fns": "^4.1.0",
69
+ "motion": "^12.38.0",
70
+ "react-day-picker": "^9.8.0",
71
+ "sonner": "^2.0.7",
72
+ "@voyantjs/i18n": "0.101.2"
59
73
  },
60
74
  "devDependencies": {
61
75
  "@tanstack/react-query": "^5.100.11",
@@ -68,15 +82,20 @@
68
82
  "typescript": "^6.0.2",
69
83
  "vitest": "^4.1.2",
70
84
  "zod": "^4.3.6",
71
- "@voyantjs/availability-react": "0.101.1",
72
- "@voyantjs/catalog-react": "0.101.1",
73
- "@voyantjs/finance": "0.101.1",
74
- "@voyantjs/finance-ui": "0.101.1",
75
- "@voyantjs/i18n": "0.101.1",
76
- "@voyantjs/pricing-react": "0.101.1",
77
- "@voyantjs/products-react": "0.101.1",
78
- "@voyantjs/suppliers-react": "0.101.1",
79
- "@voyantjs/ui": "0.101.1",
85
+ "@voyantjs/availability": "0.101.2",
86
+ "@voyantjs/availability-react": "0.101.2",
87
+ "@voyantjs/catalog-react": "0.101.2",
88
+ "@voyantjs/extras-react": "0.101.2",
89
+ "@voyantjs/finance": "0.101.2",
90
+ "@voyantjs/finance-ui": "0.101.2",
91
+ "@voyantjs/i18n": "0.101.2",
92
+ "@voyantjs/markets-react": "0.101.2",
93
+ "@voyantjs/pricing-react": "0.101.2",
94
+ "@voyantjs/pricing-ui": "0.101.2",
95
+ "@voyantjs/products-react": "0.101.2",
96
+ "@voyantjs/suppliers-react": "0.101.2",
97
+ "@voyantjs/ui": "0.101.2",
98
+ "@voyantjs/utils": "0.101.2",
80
99
  "@voyantjs/voyant-typescript-config": "0.1.0"
81
100
  },
82
101
  "files": [