@voyant-travel/distribution-react 0.109.8

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 (312) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +82 -0
  3. package/dist/admin/index.d.ts +30 -0
  4. package/dist/admin/index.d.ts.map +1 -0
  5. package/dist/admin/index.js +65 -0
  6. package/dist/client.d.ts +14 -0
  7. package/dist/client.d.ts.map +1 -0
  8. package/dist/client.js +59 -0
  9. package/dist/components/booking-link-detail-page.d.ts +10 -0
  10. package/dist/components/booking-link-detail-page.d.ts.map +1 -0
  11. package/dist/components/booking-link-detail-page.js +51 -0
  12. package/dist/components/channel-detail-page.d.ts +12 -0
  13. package/dist/components/channel-detail-page.d.ts.map +1 -0
  14. package/dist/components/channel-detail-page.js +41 -0
  15. package/dist/components/channel-sync-controls.d.ts +15 -0
  16. package/dist/components/channel-sync-controls.d.ts.map +1 -0
  17. package/dist/components/channel-sync-controls.js +29 -0
  18. package/dist/components/channel-sync-deliveries-drawer.d.ts +12 -0
  19. package/dist/components/channel-sync-deliveries-drawer.d.ts.map +1 -0
  20. package/dist/components/channel-sync-deliveries-drawer.js +18 -0
  21. package/dist/components/channel-sync-page-utils.d.ts +99 -0
  22. package/dist/components/channel-sync-page-utils.d.ts.map +1 -0
  23. package/dist/components/channel-sync-page-utils.js +85 -0
  24. package/dist/components/channel-sync-page.d.ts +4 -0
  25. package/dist/components/channel-sync-page.d.ts.map +1 -0
  26. package/dist/components/channel-sync-page.js +141 -0
  27. package/dist/components/channels-page.d.ts +6 -0
  28. package/dist/components/channels-page.d.ts.map +1 -0
  29. package/dist/components/channels-page.js +132 -0
  30. package/dist/components/commission-rule-detail-page.d.ts +10 -0
  31. package/dist/components/commission-rule-detail-page.d.ts.map +1 -0
  32. package/dist/components/commission-rule-detail-page.js +57 -0
  33. package/dist/components/contract-detail-page.d.ts +10 -0
  34. package/dist/components/contract-detail-page.d.ts.map +1 -0
  35. package/dist/components/contract-detail-page.js +64 -0
  36. package/dist/components/distribution-overview.d.ts +19 -0
  37. package/dist/components/distribution-overview.d.ts.map +1 -0
  38. package/dist/components/distribution-overview.js +13 -0
  39. package/dist/components/distribution-page.d.ts +26 -0
  40. package/dist/components/distribution-page.d.ts.map +1 -0
  41. package/dist/components/distribution-page.js +190 -0
  42. package/dist/components/distribution-section-header.d.ts +7 -0
  43. package/dist/components/distribution-section-header.d.ts.map +1 -0
  44. package/dist/components/distribution-section-header.js +6 -0
  45. package/dist/components/distribution-shared.d.ts +32 -0
  46. package/dist/components/distribution-shared.d.ts.map +1 -0
  47. package/dist/components/distribution-shared.js +246 -0
  48. package/dist/components/distribution-tabs-primary.d.ts +57 -0
  49. package/dist/components/distribution-tabs-primary.d.ts.map +1 -0
  50. package/dist/components/distribution-tabs-primary.js +89 -0
  51. package/dist/components/distribution-tabs-secondary.d.ts +58 -0
  52. package/dist/components/distribution-tabs-secondary.d.ts.map +1 -0
  53. package/dist/components/distribution-tabs-secondary.js +89 -0
  54. package/dist/components/mapping-detail-page.d.ts +10 -0
  55. package/dist/components/mapping-detail-page.d.ts.map +1 -0
  56. package/dist/components/mapping-detail-page.js +51 -0
  57. package/dist/components/webhook-event-detail-page.d.ts +9 -0
  58. package/dist/components/webhook-event-detail-page.d.ts.map +1 -0
  59. package/dist/components/webhook-event-detail-page.js +46 -0
  60. package/dist/constants.d.ts +103 -0
  61. package/dist/constants.d.ts.map +1 -0
  62. package/dist/constants.js +48 -0
  63. package/dist/external-refs/client.d.ts +14 -0
  64. package/dist/external-refs/client.d.ts.map +1 -0
  65. package/dist/external-refs/client.js +58 -0
  66. package/dist/external-refs/components/entity-ref-picker.d.ts +21 -0
  67. package/dist/external-refs/components/entity-ref-picker.d.ts.map +1 -0
  68. package/dist/external-refs/components/entity-ref-picker.js +38 -0
  69. package/dist/external-refs/components/external-ref-dialog.d.ts +11 -0
  70. package/dist/external-refs/components/external-ref-dialog.d.ts.map +1 -0
  71. package/dist/external-refs/components/external-ref-dialog.js +120 -0
  72. package/dist/external-refs/components/external-refs-page.d.ts +16 -0
  73. package/dist/external-refs/components/external-refs-page.d.ts.map +1 -0
  74. package/dist/external-refs/components/external-refs-page.js +109 -0
  75. package/dist/external-refs/hooks/index.d.ts +3 -0
  76. package/dist/external-refs/hooks/index.d.ts.map +1 -0
  77. package/dist/external-refs/hooks/index.js +2 -0
  78. package/dist/external-refs/hooks/use-external-ref-mutation.d.ts +57 -0
  79. package/dist/external-refs/hooks/use-external-ref-mutation.d.ts.map +1 -0
  80. package/dist/external-refs/hooks/use-external-ref-mutation.js +40 -0
  81. package/dist/external-refs/hooks/use-external-refs.d.ts +26 -0
  82. package/dist/external-refs/hooks/use-external-refs.d.ts.map +1 -0
  83. package/dist/external-refs/hooks/use-external-refs.js +12 -0
  84. package/dist/external-refs/i18n/en.d.ts +3 -0
  85. package/dist/external-refs/i18n/en.d.ts.map +1 -0
  86. package/dist/external-refs/i18n/en.js +92 -0
  87. package/dist/external-refs/i18n/index.d.ts +5 -0
  88. package/dist/external-refs/i18n/index.d.ts.map +1 -0
  89. package/dist/external-refs/i18n/index.js +3 -0
  90. package/dist/external-refs/i18n/messages.d.ts +85 -0
  91. package/dist/external-refs/i18n/messages.d.ts.map +1 -0
  92. package/dist/external-refs/i18n/messages.js +1 -0
  93. package/dist/external-refs/i18n/provider.d.ts +26 -0
  94. package/dist/external-refs/i18n/provider.d.ts.map +1 -0
  95. package/dist/external-refs/i18n/provider.js +44 -0
  96. package/dist/external-refs/i18n/ro.d.ts +3 -0
  97. package/dist/external-refs/i18n/ro.d.ts.map +1 -0
  98. package/dist/external-refs/i18n/ro.js +92 -0
  99. package/dist/external-refs/index.d.ts +7 -0
  100. package/dist/external-refs/index.d.ts.map +1 -0
  101. package/dist/external-refs/index.js +6 -0
  102. package/dist/external-refs/provider.d.ts +2 -0
  103. package/dist/external-refs/provider.d.ts.map +1 -0
  104. package/dist/external-refs/provider.js +1 -0
  105. package/dist/external-refs/query-keys.d.ts +18 -0
  106. package/dist/external-refs/query-keys.d.ts.map +1 -0
  107. package/dist/external-refs/query-keys.js +6 -0
  108. package/dist/external-refs/query-options.d.ts +159 -0
  109. package/dist/external-refs/query-options.d.ts.map +1 -0
  110. package/dist/external-refs/query-options.js +31 -0
  111. package/dist/external-refs/schemas.d.ts +82 -0
  112. package/dist/external-refs/schemas.d.ts.map +1 -0
  113. package/dist/external-refs/schemas.js +20 -0
  114. package/dist/external-refs/ui.d.ts +5 -0
  115. package/dist/external-refs/ui.d.ts.map +1 -0
  116. package/dist/external-refs/ui.js +4 -0
  117. package/dist/hooks/index.d.ts +12 -0
  118. package/dist/hooks/index.d.ts.map +1 -0
  119. package/dist/hooks/index.js +12 -0
  120. package/dist/hooks/use-booking-links.d.ts +20 -0
  121. package/dist/hooks/use-booking-links.d.ts.map +1 -0
  122. package/dist/hooks/use-booking-links.js +9 -0
  123. package/dist/hooks/use-bookings.d.ts +14 -0
  124. package/dist/hooks/use-bookings.d.ts.map +1 -0
  125. package/dist/hooks/use-bookings.js +9 -0
  126. package/dist/hooks/use-channel-mutation.d.ts +69 -0
  127. package/dist/hooks/use-channel-mutation.d.ts.map +1 -0
  128. package/dist/hooks/use-channel-mutation.js +49 -0
  129. package/dist/hooks/use-channel.d.ts +16 -0
  130. package/dist/hooks/use-channel.d.ts.map +1 -0
  131. package/dist/hooks/use-channel.js +13 -0
  132. package/dist/hooks/use-channels.d.ts +20 -0
  133. package/dist/hooks/use-channels.d.ts.map +1 -0
  134. package/dist/hooks/use-channels.js +9 -0
  135. package/dist/hooks/use-commission-rules.d.ts +23 -0
  136. package/dist/hooks/use-commission-rules.d.ts.map +1 -0
  137. package/dist/hooks/use-commission-rules.js +9 -0
  138. package/dist/hooks/use-contracts.d.ts +22 -0
  139. package/dist/hooks/use-contracts.d.ts.map +1 -0
  140. package/dist/hooks/use-contracts.js +9 -0
  141. package/dist/hooks/use-mappings.d.ts +19 -0
  142. package/dist/hooks/use-mappings.d.ts.map +1 -0
  143. package/dist/hooks/use-mappings.js +9 -0
  144. package/dist/hooks/use-products.d.ts +14 -0
  145. package/dist/hooks/use-products.d.ts.map +1 -0
  146. package/dist/hooks/use-products.js +9 -0
  147. package/dist/hooks/use-suppliers.d.ts +14 -0
  148. package/dist/hooks/use-suppliers.d.ts.map +1 -0
  149. package/dist/hooks/use-suppliers.js +9 -0
  150. package/dist/hooks/use-webhook-events.d.ts +21 -0
  151. package/dist/hooks/use-webhook-events.d.ts.map +1 -0
  152. package/dist/hooks/use-webhook-events.js +9 -0
  153. package/dist/i18n/en.d.ts +592 -0
  154. package/dist/i18n/en.d.ts.map +1 -0
  155. package/dist/i18n/en.js +561 -0
  156. package/dist/i18n/index.d.ts +5 -0
  157. package/dist/i18n/index.d.ts.map +1 -0
  158. package/dist/i18n/index.js +3 -0
  159. package/dist/i18n/messages.d.ts +409 -0
  160. package/dist/i18n/messages.d.ts.map +1 -0
  161. package/dist/i18n/messages.js +1 -0
  162. package/dist/i18n/provider.d.ts +1207 -0
  163. package/dist/i18n/provider.d.ts.map +1 -0
  164. package/dist/i18n/provider.js +44 -0
  165. package/dist/i18n/ro.d.ts +592 -0
  166. package/dist/i18n/ro.d.ts.map +1 -0
  167. package/dist/i18n/ro.js +561 -0
  168. package/dist/i18n/utils.d.ts +4 -0
  169. package/dist/i18n/utils.d.ts.map +1 -0
  170. package/dist/i18n/utils.js +8 -0
  171. package/dist/index.d.ts +9 -0
  172. package/dist/index.d.ts.map +1 -0
  173. package/dist/index.js +8 -0
  174. package/dist/provider.d.ts +2 -0
  175. package/dist/provider.d.ts.map +1 -0
  176. package/dist/provider.js +1 -0
  177. package/dist/query-keys.d.ts +61 -0
  178. package/dist/query-keys.d.ts.map +1 -0
  179. package/dist/query-keys.js +30 -0
  180. package/dist/query-options.d.ts +999 -0
  181. package/dist/query-options.d.ts.map +1 -0
  182. package/dist/query-options.js +219 -0
  183. package/dist/schemas.d.ts +615 -0
  184. package/dist/schemas.d.ts.map +1 -0
  185. package/dist/schemas.js +144 -0
  186. package/dist/suppliers/admin/index.d.ts +69 -0
  187. package/dist/suppliers/admin/index.d.ts.map +1 -0
  188. package/dist/suppliers/admin/index.js +111 -0
  189. package/dist/suppliers/admin/pages/supplier-detail-page.d.ts +9 -0
  190. package/dist/suppliers/admin/pages/supplier-detail-page.d.ts.map +1 -0
  191. package/dist/suppliers/admin/pages/supplier-detail-page.js +11 -0
  192. package/dist/suppliers/admin/slots.d.ts +19 -0
  193. package/dist/suppliers/admin/slots.d.ts.map +1 -0
  194. package/dist/suppliers/admin/slots.js +18 -0
  195. package/dist/suppliers/admin/supplier-detail-host.d.ts +30 -0
  196. package/dist/suppliers/admin/supplier-detail-host.d.ts.map +1 -0
  197. package/dist/suppliers/admin/supplier-detail-host.js +34 -0
  198. package/dist/suppliers/admin/supplier-detail-skeleton.d.ts +9 -0
  199. package/dist/suppliers/admin/supplier-detail-skeleton.d.ts.map +1 -0
  200. package/dist/suppliers/admin/supplier-detail-skeleton.js +20 -0
  201. package/dist/suppliers/admin/suppliers-host.d.ts +11 -0
  202. package/dist/suppliers/admin/suppliers-host.d.ts.map +1 -0
  203. package/dist/suppliers/admin/suppliers-host.js +17 -0
  204. package/dist/suppliers/admin/suppliers-list-skeleton.d.ts +9 -0
  205. package/dist/suppliers/admin/suppliers-list-skeleton.d.ts.map +1 -0
  206. package/dist/suppliers/admin/suppliers-list-skeleton.js +24 -0
  207. package/dist/suppliers/client.d.ts +14 -0
  208. package/dist/suppliers/client.d.ts.map +1 -0
  209. package/dist/suppliers/client.js +59 -0
  210. package/dist/suppliers/components/message-format.d.ts +2 -0
  211. package/dist/suppliers/components/message-format.d.ts.map +1 -0
  212. package/dist/suppliers/components/message-format.js +3 -0
  213. package/dist/suppliers/components/rate-dialog.d.ts +11 -0
  214. package/dist/suppliers/components/rate-dialog.d.ts.map +1 -0
  215. package/dist/suppliers/components/rate-dialog.js +93 -0
  216. package/dist/suppliers/components/service-dialog.d.ts +10 -0
  217. package/dist/suppliers/components/service-dialog.d.ts.map +1 -0
  218. package/dist/suppliers/components/service-dialog.js +69 -0
  219. package/dist/suppliers/components/supplier-combobox.d.ts +13 -0
  220. package/dist/suppliers/components/supplier-combobox.d.ts.map +1 -0
  221. package/dist/suppliers/components/supplier-combobox.js +23 -0
  222. package/dist/suppliers/components/supplier-detail-page.d.ts +17 -0
  223. package/dist/suppliers/components/supplier-detail-page.d.ts.map +1 -0
  224. package/dist/suppliers/components/supplier-detail-page.js +105 -0
  225. package/dist/suppliers/components/supplier-dialog.d.ts +9 -0
  226. package/dist/suppliers/components/supplier-dialog.d.ts.map +1 -0
  227. package/dist/suppliers/components/supplier-dialog.js +118 -0
  228. package/dist/suppliers/components/supplier-service-row.d.ts +22 -0
  229. package/dist/suppliers/components/supplier-service-row.d.ts.map +1 -0
  230. package/dist/suppliers/components/supplier-service-row.js +18 -0
  231. package/dist/suppliers/components/suppliers-page.d.ts +10 -0
  232. package/dist/suppliers/components/suppliers-page.d.ts.map +1 -0
  233. package/dist/suppliers/components/suppliers-page.js +94 -0
  234. package/dist/suppliers/constants.d.ts +69 -0
  235. package/dist/suppliers/constants.d.ts.map +1 -0
  236. package/dist/suppliers/constants.js +34 -0
  237. package/dist/suppliers/hooks/index.d.ts +10 -0
  238. package/dist/suppliers/hooks/index.d.ts.map +1 -0
  239. package/dist/suppliers/hooks/index.js +10 -0
  240. package/dist/suppliers/hooks/use-supplier-mutation.d.ts +95 -0
  241. package/dist/suppliers/hooks/use-supplier-mutation.d.ts.map +1 -0
  242. package/dist/suppliers/hooks/use-supplier-mutation.js +41 -0
  243. package/dist/suppliers/hooks/use-supplier-note-mutation.d.ts +13 -0
  244. package/dist/suppliers/hooks/use-supplier-note-mutation.d.ts.map +1 -0
  245. package/dist/suppliers/hooks/use-supplier-note-mutation.js +20 -0
  246. package/dist/suppliers/hooks/use-supplier-notes.d.ts +13 -0
  247. package/dist/suppliers/hooks/use-supplier-notes.d.ts.map +1 -0
  248. package/dist/suppliers/hooks/use-supplier-notes.js +12 -0
  249. package/dist/suppliers/hooks/use-supplier-rate-mutation.d.ts +56 -0
  250. package/dist/suppliers/hooks/use-supplier-rate-mutation.d.ts.map +1 -0
  251. package/dist/suppliers/hooks/use-supplier-rate-mutation.js +41 -0
  252. package/dist/suppliers/hooks/use-supplier-service-mutation.d.ts +45 -0
  253. package/dist/suppliers/hooks/use-supplier-service-mutation.d.ts.map +1 -0
  254. package/dist/suppliers/hooks/use-supplier-service-mutation.js +44 -0
  255. package/dist/suppliers/hooks/use-supplier-service-rates.d.ts +20 -0
  256. package/dist/suppliers/hooks/use-supplier-service-rates.d.ts.map +1 -0
  257. package/dist/suppliers/hooks/use-supplier-service-rates.js +12 -0
  258. package/dist/suppliers/hooks/use-supplier-services.d.ts +19 -0
  259. package/dist/suppliers/hooks/use-supplier-services.d.ts.map +1 -0
  260. package/dist/suppliers/hooks/use-supplier-services.js +12 -0
  261. package/dist/suppliers/hooks/use-supplier.d.ts +38 -0
  262. package/dist/suppliers/hooks/use-supplier.d.ts.map +1 -0
  263. package/dist/suppliers/hooks/use-supplier.js +9 -0
  264. package/dist/suppliers/hooks/use-suppliers.d.ts +42 -0
  265. package/dist/suppliers/hooks/use-suppliers.d.ts.map +1 -0
  266. package/dist/suppliers/hooks/use-suppliers.js +9 -0
  267. package/dist/suppliers/i18n/en.d.ts +204 -0
  268. package/dist/suppliers/i18n/en.d.ts.map +1 -0
  269. package/dist/suppliers/i18n/en.js +203 -0
  270. package/dist/suppliers/i18n/index.d.ts +5 -0
  271. package/dist/suppliers/i18n/index.d.ts.map +1 -0
  272. package/dist/suppliers/i18n/index.js +3 -0
  273. package/dist/suppliers/i18n/messages.d.ts +187 -0
  274. package/dist/suppliers/i18n/messages.d.ts.map +1 -0
  275. package/dist/suppliers/i18n/messages.js +1 -0
  276. package/dist/suppliers/i18n/provider.d.ts +430 -0
  277. package/dist/suppliers/i18n/provider.d.ts.map +1 -0
  278. package/dist/suppliers/i18n/provider.js +44 -0
  279. package/dist/suppliers/i18n/ro.d.ts +204 -0
  280. package/dist/suppliers/i18n/ro.d.ts.map +1 -0
  281. package/dist/suppliers/i18n/ro.js +203 -0
  282. package/dist/suppliers/index.d.ts +9 -0
  283. package/dist/suppliers/index.d.ts.map +1 -0
  284. package/dist/suppliers/index.js +8 -0
  285. package/dist/suppliers/provider.d.ts +2 -0
  286. package/dist/suppliers/provider.d.ts.map +1 -0
  287. package/dist/suppliers/provider.js +1 -0
  288. package/dist/suppliers/query-keys.d.ts +29 -0
  289. package/dist/suppliers/query-keys.d.ts.map +1 -0
  290. package/dist/suppliers/query-keys.js +12 -0
  291. package/dist/suppliers/query-options.d.ts +467 -0
  292. package/dist/suppliers/query-options.d.ts.map +1 -0
  293. package/dist/suppliers/query-options.js +63 -0
  294. package/dist/suppliers/schemas.d.ts +363 -0
  295. package/dist/suppliers/schemas.d.ts.map +1 -0
  296. package/dist/suppliers/schemas.js +109 -0
  297. package/dist/suppliers/ui.d.ts +9 -0
  298. package/dist/suppliers/ui.d.ts.map +1 -0
  299. package/dist/suppliers/ui.js +8 -0
  300. package/dist/suppliers/utils.d.ts +4 -0
  301. package/dist/suppliers/utils.d.ts.map +1 -0
  302. package/dist/suppliers/utils.js +10 -0
  303. package/dist/ui.d.ts +16 -0
  304. package/dist/ui.d.ts.map +1 -0
  305. package/dist/ui.js +14 -0
  306. package/dist/utils.d.ts +10 -0
  307. package/dist/utils.d.ts.map +1 -0
  308. package/dist/utils.js +44 -0
  309. package/package.json +263 -0
  310. package/src/external-refs/styles.css +11 -0
  311. package/src/styles.css +11 -0
  312. package/src/suppliers/styles.css +11 -0
@@ -0,0 +1,59 @@
1
+ export const defaultFetcher = (url, init) => fetch(url, { credentials: "include", ...init });
2
+ export class VoyantApiError extends Error {
3
+ status;
4
+ body;
5
+ constructor(message, status, body) {
6
+ super(message);
7
+ this.name = "VoyantApiError";
8
+ this.status = status;
9
+ this.body = body;
10
+ }
11
+ }
12
+ function extractErrorMessage(status, statusText, body) {
13
+ if (typeof body === "object" && body !== null && "error" in body) {
14
+ const err = body.error;
15
+ if (typeof err === "string")
16
+ return err;
17
+ if (typeof err === "object" && err !== null && "message" in err) {
18
+ return String(err.message);
19
+ }
20
+ }
21
+ return `Voyant API error: ${status} ${statusText}`;
22
+ }
23
+ export async function fetchWithValidation(path, schema, options, init) {
24
+ const url = joinUrl(options.baseUrl, path);
25
+ const headers = new Headers(init?.headers);
26
+ if (init?.body !== undefined && !headers.has("Content-Type")) {
27
+ headers.set("Content-Type", "application/json");
28
+ }
29
+ const response = await options.fetcher(url, { ...init, headers });
30
+ if (!response.ok) {
31
+ const body = await safeJson(response);
32
+ throw new VoyantApiError(extractErrorMessage(response.status, response.statusText, body), response.status, body);
33
+ }
34
+ if (response.status === 204) {
35
+ return schema.parse(undefined);
36
+ }
37
+ const body = await safeJson(response);
38
+ const parsed = schema.safeParse(body);
39
+ if (!parsed.success) {
40
+ throw new VoyantApiError(`Voyant API response failed validation: ${parsed.error.message}`, response.status, body);
41
+ }
42
+ return parsed.data;
43
+ }
44
+ async function safeJson(response) {
45
+ const text = await response.text();
46
+ if (!text)
47
+ return undefined;
48
+ try {
49
+ return JSON.parse(text);
50
+ }
51
+ catch {
52
+ return text;
53
+ }
54
+ }
55
+ function joinUrl(baseUrl, path) {
56
+ const trimmedBase = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
57
+ const trimmedPath = path.startsWith("/") ? path : `/${path}`;
58
+ return `${trimmedBase}${trimmedPath}`;
59
+ }
@@ -0,0 +1,2 @@
1
+ export declare function formatMessage(template: string, values: Record<string, string | number>): string;
2
+ //# sourceMappingURL=message-format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"message-format.d.ts","sourceRoot":"","sources":["../../../src/suppliers/components/message-format.ts"],"names":[],"mappings":"AAAA,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,UAEtF"}
@@ -0,0 +1,3 @@
1
+ export function formatMessage(template, values) {
2
+ return template.replace(/\{(\w+)\}/g, (_match, key) => String(values[key] ?? ""));
3
+ }
@@ -0,0 +1,11 @@
1
+ import { type SupplierRate } from "../index.js";
2
+ export type RateDialogProps = {
3
+ open: boolean;
4
+ onOpenChange: (open: boolean) => void;
5
+ supplierId: string;
6
+ serviceId: string;
7
+ rate?: SupplierRate;
8
+ onSuccess?: (rate: SupplierRate) => void;
9
+ };
10
+ export declare function RateDialog({ open, onOpenChange, supplierId, serviceId, rate, onSuccess, }: RateDialogProps): import("react/jsx-runtime").JSX.Element;
11
+ //# sourceMappingURL=rate-dialog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-dialog.d.ts","sourceRoot":"","sources":["../../../src/suppliers/components/rate-dialog.tsx"],"names":[],"mappings":"AA2BA,OAAO,EAAc,KAAK,YAAY,EAA2B,MAAM,aAAa,CAAA;AAiBpF,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,CAAC,EAAE,YAAY,CAAA;IACnB,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAA;CACzC,CAAA;AAED,wBAAgB,UAAU,CAAC,EACzB,IAAI,EACJ,YAAY,EACZ,UAAU,EACV,SAAS,EACT,IAAI,EACJ,SAAS,GACV,EAAE,eAAe,2CA0KjB"}
@@ -0,0 +1,93 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Button, Dialog, DialogBody, DialogContent, DialogFooter, DialogHeader, DialogTitle, Input, Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Textarea, } from "@voyant-travel/ui/components";
4
+ import { CurrencyCombobox } from "@voyant-travel/ui/components/currency-combobox";
5
+ import { DatePicker } from "@voyant-travel/ui/components/date-picker";
6
+ import { zodResolver } from "@voyant-travel/ui/lib/zod-resolver";
7
+ import { Loader2 } from "lucide-react";
8
+ import * as React from "react";
9
+ import { useForm } from "react-hook-form";
10
+ import { z } from "zod/v4";
11
+ import { useSuppliersUiMessagesOrDefault } from "../i18n/index.js";
12
+ import { RATE_UNITS, useSupplierRateMutation } from "../index.js";
13
+ function getRateSchema(messages) {
14
+ const dialog = messages.dialogs.rate;
15
+ return z.object({
16
+ name: z.string().min(1, dialog.validationNameRequired),
17
+ currency: z.string().min(3, dialog.validationIsoCurrency).max(3, dialog.validationIsoCurrency),
18
+ amount: z.coerce.number().min(0, dialog.validationNonNegative),
19
+ unit: z.enum(["per_person", "per_group", "per_night", "per_vehicle", "flat"]),
20
+ validFrom: z.string().optional().nullable(),
21
+ validTo: z.string().optional().nullable(),
22
+ minPax: z.coerce.number().int().positive().optional().or(z.literal("")).nullable(),
23
+ maxPax: z.coerce.number().int().positive().optional().or(z.literal("")).nullable(),
24
+ notes: z.string().optional().nullable(),
25
+ });
26
+ }
27
+ export function RateDialog({ open, onOpenChange, supplierId, serviceId, rate, onSuccess, }) {
28
+ const messages = useSuppliersUiMessagesOrDefault();
29
+ const dialog = messages.dialogs.rate;
30
+ const schema = React.useMemo(() => getRateSchema(messages), [messages]);
31
+ const rateMutation = useSupplierRateMutation(supplierId);
32
+ const isEditing = !!rate;
33
+ const form = useForm({
34
+ resolver: zodResolver(schema),
35
+ defaultValues: {
36
+ name: "",
37
+ currency: "EUR",
38
+ amount: 0,
39
+ unit: "per_person",
40
+ validFrom: "",
41
+ validTo: "",
42
+ minPax: "",
43
+ maxPax: "",
44
+ notes: "",
45
+ },
46
+ });
47
+ React.useEffect(() => {
48
+ if (!open)
49
+ return;
50
+ form.reset({
51
+ name: rate?.name ?? "",
52
+ currency: rate?.currency ?? "EUR",
53
+ amount: rate ? rate.amountCents / 100 : 0,
54
+ unit: rate?.unit ?? "per_person",
55
+ validFrom: rate?.validFrom ?? "",
56
+ validTo: rate?.validTo ?? "",
57
+ minPax: rate?.minPax ?? "",
58
+ maxPax: rate?.maxPax ?? "",
59
+ notes: rate?.notes ?? "",
60
+ });
61
+ }, [form, open, rate]);
62
+ async function onSubmit(values) {
63
+ const input = {
64
+ name: values.name,
65
+ currency: values.currency.toUpperCase(),
66
+ amountCents: Math.round(values.amount * 100),
67
+ unit: values.unit,
68
+ validFrom: values.validFrom || null,
69
+ validTo: values.validTo || null,
70
+ minPax: values.minPax && typeof values.minPax === "number" ? values.minPax : null,
71
+ maxPax: values.maxPax && typeof values.maxPax === "number" ? values.maxPax : null,
72
+ notes: values.notes || null,
73
+ };
74
+ const saved = isEditing
75
+ ? await rateMutation.update.mutateAsync({ serviceId, rateId: rate.id, input })
76
+ : await rateMutation.create.mutateAsync({ serviceId, input });
77
+ onSuccess?.(saved);
78
+ onOpenChange(false);
79
+ }
80
+ return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { children: [_jsx(DialogHeader, { children: _jsx(DialogTitle, { children: isEditing ? dialog.editTitle : dialog.newTitle }) }), _jsxs("form", { onSubmit: form.handleSubmit(onSubmit), children: [_jsxs(DialogBody, { className: "grid gap-4", children: [_jsx(Field, { label: dialog.seasonNameLabel, error: form.formState.errors.name?.message, children: _jsx(Input, { ...form.register("name"), placeholder: dialog.seasonNamePlaceholder }) }), _jsxs("div", { className: "grid gap-4 sm:grid-cols-3", children: [_jsx(Field, { label: dialog.currencyLabel, error: form.formState.errors.currency?.message, children: _jsx(CurrencyCombobox, { value: form.watch("currency") || null, onChange: (next) => form.setValue("currency", next ?? "", {
81
+ shouldValidate: true,
82
+ shouldDirty: true,
83
+ }), placeholder: dialog.currencyPlaceholder }) }), _jsx(Field, { label: dialog.amountLabel, error: form.formState.errors.amount?.message, children: _jsx(Input, { ...form.register("amount"), type: "number", min: "0", step: "0.01", placeholder: dialog.amountPlaceholder }) }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: dialog.unitLabel }), _jsxs(Select, { value: form.watch("unit"), onValueChange: (value) => form.setValue("unit", value), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: RATE_UNITS.map((unit) => (_jsx(SelectItem, { value: unit.value, children: messages.common.rateUnitLabels[unit.value] }, unit.value))) })] })] })] }), _jsxs("div", { className: "grid gap-4 sm:grid-cols-2", children: [_jsx(Field, { label: dialog.validFromLabel, children: _jsx(DatePicker, { value: form.watch("validFrom") || null, onChange: (nextValue) => form.setValue("validFrom", nextValue ?? "", {
84
+ shouldDirty: true,
85
+ shouldValidate: true,
86
+ }) }) }), _jsx(Field, { label: dialog.validToLabel, children: _jsx(DatePicker, { value: form.watch("validTo") || null, onChange: (nextValue) => form.setValue("validTo", nextValue ?? "", {
87
+ shouldDirty: true,
88
+ shouldValidate: true,
89
+ }) }) })] }), _jsxs("div", { className: "grid gap-4 sm:grid-cols-2", children: [_jsx(Field, { label: dialog.minPaxLabel, children: _jsx(Input, { ...form.register("minPax"), type: "number", min: "1", placeholder: dialog.minPaxPlaceholder }) }), _jsx(Field, { label: dialog.maxPaxLabel, children: _jsx(Input, { ...form.register("maxPax"), type: "number", min: "1", placeholder: dialog.maxPaxPlaceholder }) })] }), _jsx(Field, { label: dialog.notesLabel, children: _jsx(Textarea, { ...form.register("notes"), placeholder: dialog.notesPlaceholder }) })] }), _jsxs(DialogFooter, { children: [_jsx(Button, { type: "button", variant: "ghost", onClick: () => onOpenChange(false), children: messages.common.cancel }), _jsxs(Button, { type: "submit", disabled: form.formState.isSubmitting, children: [form.formState.isSubmitting && _jsx(Loader2, { className: "animate-spin" }), isEditing ? messages.common.save : messages.common.create] })] })] })] }) }));
90
+ }
91
+ function Field({ label, error, children, }) {
92
+ return (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: label }), children, error && _jsx("p", { className: "text-xs text-destructive", children: error })] }));
93
+ }
@@ -0,0 +1,10 @@
1
+ import { type SupplierService } from "../index.js";
2
+ export type ServiceDialogProps = {
3
+ open: boolean;
4
+ onOpenChange: (open: boolean) => void;
5
+ supplierId: string;
6
+ service?: SupplierService;
7
+ onSuccess?: (service: SupplierService) => void;
8
+ };
9
+ export declare function ServiceDialog({ open, onOpenChange, supplierId, service, onSuccess, }: ServiceDialogProps): import("react/jsx-runtime").JSX.Element;
10
+ //# sourceMappingURL=service-dialog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-dialog.d.ts","sourceRoot":"","sources":["../../../src/suppliers/components/service-dialog.tsx"],"names":[],"mappings":"AA0BA,OAAO,EAAiB,KAAK,eAAe,EAA8B,MAAM,aAAa,CAAA;AAa7F,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,CAAC,EAAE,eAAe,CAAA;IACzB,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAA;CAC/C,CAAA;AAED,wBAAgB,aAAa,CAAC,EAC5B,IAAI,EACJ,YAAY,EACZ,UAAU,EACV,OAAO,EACP,SAAS,GACV,EAAE,kBAAkB,2CAuHpB"}
@@ -0,0 +1,69 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Button, Dialog, DialogBody, DialogContent, DialogFooter, DialogHeader, DialogTitle, Input, Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Switch, Textarea, } from "@voyant-travel/ui/components";
4
+ import { zodResolver } from "@voyant-travel/ui/lib/zod-resolver";
5
+ import { Loader2 } from "lucide-react";
6
+ import * as React from "react";
7
+ import { useForm } from "react-hook-form";
8
+ import { z } from "zod/v4";
9
+ import { useSuppliersUiMessagesOrDefault } from "../i18n/index.js";
10
+ import { SERVICE_TYPES, useSupplierServiceMutation } from "../index.js";
11
+ function getServiceSchema(messages) {
12
+ return z.object({
13
+ serviceType: z.enum(["accommodation", "transfer", "experience", "guide", "meal", "other"]),
14
+ name: z.string().min(1, messages.dialogs.service.validationNameRequired),
15
+ description: z.string().optional().nullable(),
16
+ duration: z.string().optional().nullable(),
17
+ capacity: z.coerce.number().int().positive().optional().or(z.literal("")).nullable(),
18
+ active: z.boolean().default(true),
19
+ });
20
+ }
21
+ export function ServiceDialog({ open, onOpenChange, supplierId, service, onSuccess, }) {
22
+ const messages = useSuppliersUiMessagesOrDefault();
23
+ const dialog = messages.dialogs.service;
24
+ const schema = React.useMemo(() => getServiceSchema(messages), [messages]);
25
+ const serviceMutation = useSupplierServiceMutation(supplierId);
26
+ const isEditing = !!service;
27
+ const form = useForm({
28
+ resolver: zodResolver(schema),
29
+ defaultValues: {
30
+ serviceType: "accommodation",
31
+ name: "",
32
+ description: "",
33
+ duration: "",
34
+ capacity: "",
35
+ active: true,
36
+ },
37
+ });
38
+ React.useEffect(() => {
39
+ if (!open)
40
+ return;
41
+ form.reset({
42
+ serviceType: service?.serviceType ?? "accommodation",
43
+ name: service?.name ?? "",
44
+ description: service?.description ?? "",
45
+ duration: service?.duration ?? "",
46
+ capacity: service?.capacity ?? "",
47
+ active: service?.active ?? true,
48
+ });
49
+ }, [form, open, service]);
50
+ async function onSubmit(values) {
51
+ const input = {
52
+ serviceType: values.serviceType,
53
+ name: values.name,
54
+ description: values.description || null,
55
+ duration: values.duration || null,
56
+ capacity: values.capacity && typeof values.capacity === "number" ? values.capacity : null,
57
+ active: values.active,
58
+ };
59
+ const saved = isEditing
60
+ ? await serviceMutation.update.mutateAsync({ serviceId: service.id, input })
61
+ : await serviceMutation.create.mutateAsync(input);
62
+ onSuccess?.(saved);
63
+ onOpenChange(false);
64
+ }
65
+ return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { children: [_jsx(DialogHeader, { children: _jsx(DialogTitle, { children: isEditing ? dialog.editTitle : dialog.newTitle }) }), _jsxs("form", { onSubmit: form.handleSubmit(onSubmit), children: [_jsxs(DialogBody, { className: "grid gap-4", children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: dialog.serviceTypeLabel }), _jsxs(Select, { value: form.watch("serviceType"), onValueChange: (value) => form.setValue("serviceType", value), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: SERVICE_TYPES.map((type) => (_jsx(SelectItem, { value: type.value, children: messages.common.serviceTypeLabels[type.value] }, type.value))) })] })] }), _jsx(Field, { label: dialog.nameLabel, error: form.formState.errors.name?.message, children: _jsx(Input, { ...form.register("name"), placeholder: dialog.namePlaceholder }) }), _jsx(Field, { label: dialog.descriptionLabel, children: _jsx(Textarea, { ...form.register("description"), placeholder: dialog.descriptionPlaceholder }) }), _jsxs("div", { className: "grid gap-4 sm:grid-cols-2", children: [_jsx(Field, { label: dialog.durationLabel, children: _jsx(Input, { ...form.register("duration"), placeholder: dialog.durationPlaceholder }) }), _jsx(Field, { label: dialog.capacityLabel, children: _jsx(Input, { ...form.register("capacity"), type: "number", min: "1", placeholder: dialog.capacityPlaceholder }) })] }), _jsxs("div", { className: "flex items-center gap-3", children: [_jsx(Switch, { checked: form.watch("active"), onCheckedChange: (value) => form.setValue("active", value) }), _jsx(Label, { children: dialog.activeLabel })] })] }), _jsxs(DialogFooter, { children: [_jsx(Button, { type: "button", variant: "ghost", onClick: () => onOpenChange(false), children: messages.common.cancel }), _jsxs(Button, { type: "submit", disabled: form.formState.isSubmitting, children: [form.formState.isSubmitting && _jsx(Loader2, { className: "animate-spin" }), isEditing ? messages.common.save : messages.common.create] })] })] })] }) }));
66
+ }
67
+ function Field({ label, error, children, }) {
68
+ return (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: label }), children, error && _jsx("p", { className: "text-xs text-destructive", children: error })] }));
69
+ }
@@ -0,0 +1,13 @@
1
+ export interface SupplierComboboxProps {
2
+ value: string | null | undefined;
3
+ onChange: (value: string | null) => void;
4
+ placeholder?: string;
5
+ emptyText?: string;
6
+ disabled?: boolean;
7
+ className?: string;
8
+ triggerClassName?: string;
9
+ clearable?: boolean;
10
+ limit?: number;
11
+ }
12
+ export declare function SupplierCombobox({ value, onChange, placeholder, emptyText, disabled, className, triggerClassName, clearable, limit, }: SupplierComboboxProps): import("react/jsx-runtime").JSX.Element;
13
+ //# sourceMappingURL=supplier-combobox.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supplier-combobox.d.ts","sourceRoot":"","sources":["../../../src/suppliers/components/supplier-combobox.tsx"],"names":[],"mappings":"AAOA,MAAM,WAAW,qBAAqB;IACpC,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,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAYD,wBAAgB,gBAAgB,CAAC,EAC/B,KAAK,EACL,QAAQ,EACR,WAAW,EACX,SAAS,EACT,QAAQ,EACR,SAAS,EACT,gBAAgB,EAChB,SAAgB,EAChB,KAAqB,GACtB,EAAE,qBAAqB,2CA6BvB"}
@@ -0,0 +1,23 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { AsyncCombobox } from "@voyant-travel/ui/components/async-combobox";
4
+ import * as React from "react";
5
+ import { useSuppliersUiMessagesOrDefault } from "../i18n/index.js";
6
+ import { useSupplier, useSuppliers } from "../index.js";
7
+ const DEFAULT_LIMIT = 20;
8
+ function compact(parts) {
9
+ return parts.map((part) => part?.trim()).filter(Boolean);
10
+ }
11
+ function formatSupplierSecondary(supplier) {
12
+ return compact([supplier.city, supplier.country, supplier.defaultCurrency]).join(" - ");
13
+ }
14
+ export function SupplierCombobox({ value, onChange, placeholder, emptyText, disabled, className, triggerClassName, clearable = true, limit = DEFAULT_LIMIT, }) {
15
+ const messages = useSuppliersUiMessagesOrDefault();
16
+ const comboboxMessages = messages.supplierCombobox;
17
+ const [search, setSearch] = React.useState("");
18
+ const listQuery = useSuppliers({ search: search || undefined, limit });
19
+ const selectedQuery = useSupplier(value ?? "", { enabled: Boolean(value) });
20
+ return (_jsx(AsyncCombobox, { value: value ?? null, onChange: onChange, items: listQuery.data?.data ?? [], selectedItem: selectedQuery.data?.data ?? null, getKey: (supplier) => supplier.id, getLabel: (supplier) => supplier.name, getSecondary: formatSupplierSecondary, onSearchChange: setSearch, placeholder: placeholder ?? comboboxMessages.placeholder, emptyText: listQuery.isPending || selectedQuery.isPending
21
+ ? comboboxMessages.loading
22
+ : (emptyText ?? comboboxMessages.empty), disabled: disabled, className: className, triggerClassName: triggerClassName, clearable: clearable }));
23
+ }
@@ -0,0 +1,17 @@
1
+ import * as React from "react";
2
+ import { type Supplier, type UpdateSupplierInput } from "../index.js";
3
+ export type SupplierDetailPageProps = {
4
+ id: string;
5
+ locale?: string;
6
+ onBack?: () => void;
7
+ onDeleted?: () => void;
8
+ confirmAction?: (message: string) => boolean;
9
+ className?: string;
10
+ renderCustomerPaymentPolicy?: (args: {
11
+ supplier: Supplier;
12
+ updateSupplier: (input: UpdateSupplierInput) => Promise<Supplier>;
13
+ isUpdating: boolean;
14
+ }) => React.ReactNode;
15
+ };
16
+ export declare function SupplierDetailPage({ id, locale, onBack, onDeleted, confirmAction, className, renderCustomerPaymentPolicy, }: SupplierDetailPageProps): import("react/jsx-runtime").JSX.Element;
17
+ //# sourceMappingURL=supplier-detail-page.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supplier-detail-page.d.ts","sourceRoot":"","sources":["../../../src/suppliers/components/supplier-detail-page.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,EACL,KAAK,QAAQ,EAIb,KAAK,mBAAmB,EAQzB,MAAM,aAAa,CAAA;AAMpB,MAAM,MAAM,uBAAuB,GAAG;IACpC,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;IACtB,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAA;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,2BAA2B,CAAC,EAAE,CAAC,IAAI,EAAE;QACnC,QAAQ,EAAE,QAAQ,CAAA;QAClB,cAAc,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAA;QACjE,UAAU,EAAE,OAAO,CAAA;KACpB,KAAK,KAAK,CAAC,SAAS,CAAA;CACtB,CAAA;AAED,wBAAgB,kBAAkB,CAAC,EACjC,EAAE,EACF,MAAgB,EAChB,MAAM,EACN,SAAS,EACT,aAAkE,EAClE,SAAS,EACT,2BAA2B,GAC5B,EAAE,uBAAuB,2CA6SzB"}
@@ -0,0 +1,105 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { Badge, Button, Card, CardContent, CardHeader, CardTitle, Textarea, } from "@voyant-travel/ui/components";
4
+ import { cn } from "@voyant-travel/ui/lib/utils";
5
+ import { ArrowLeft, Loader2, Pencil, Plus, Trash2 } from "lucide-react";
6
+ import * as React from "react";
7
+ import { useSuppliersUiMessagesOrDefault } from "../i18n/index.js";
8
+ import { statusVariant, useSupplier, useSupplierMutation, useSupplierNoteMutation, useSupplierNotes, useSupplierRateMutation, useSupplierServiceMutation, useSupplierServices, } from "../index.js";
9
+ import { RateDialog } from "./rate-dialog.js";
10
+ import { ServiceDialog } from "./service-dialog.js";
11
+ import { SupplierDialog } from "./supplier-dialog.js";
12
+ import { SupplierServiceRow } from "./supplier-service-row.js";
13
+ export function SupplierDetailPage({ id, locale = "en-US", onBack, onDeleted, confirmAction = (message) => globalThis.confirm?.(message) ?? true, className, renderCustomerPaymentPolicy, }) {
14
+ const messages = useSuppliersUiMessagesOrDefault();
15
+ const detail = messages.supplierDetailPage;
16
+ const supplierQuery = useSupplier(id);
17
+ const servicesQuery = useSupplierServices(id);
18
+ const notesQuery = useSupplierNotes(id);
19
+ const supplierMutation = useSupplierMutation();
20
+ const serviceMutation = useSupplierServiceMutation(id);
21
+ const rateMutation = useSupplierRateMutation(id);
22
+ const noteMutation = useSupplierNoteMutation(id);
23
+ const [editOpen, setEditOpen] = React.useState(false);
24
+ const [serviceDialogOpen, setServiceDialogOpen] = React.useState(false);
25
+ const [editingService, setEditingService] = React.useState();
26
+ const [rateDialog, setRateDialog] = React.useState({ open: false, serviceId: "" });
27
+ const [expandedServiceId, setExpandedServiceId] = React.useState(null);
28
+ const [noteContent, setNoteContent] = React.useState("");
29
+ const supplier = supplierQuery.data?.data;
30
+ async function deleteSupplier() {
31
+ if (!supplier || !confirmAction(detail.deleteSupplierConfirm))
32
+ return;
33
+ await supplierMutation.remove.mutateAsync(supplier.id);
34
+ onDeleted?.();
35
+ }
36
+ async function deleteService(serviceId) {
37
+ if (!confirmAction(detail.deleteServiceConfirm))
38
+ return;
39
+ await serviceMutation.remove.mutateAsync(serviceId);
40
+ if (expandedServiceId === serviceId)
41
+ setExpandedServiceId(null);
42
+ }
43
+ async function deleteRate(serviceId, rateId) {
44
+ if (!confirmAction(detail.deleteRateConfirm))
45
+ return;
46
+ await rateMutation.remove.mutateAsync({ serviceId, rateId });
47
+ }
48
+ async function addNote() {
49
+ const content = noteContent.trim();
50
+ if (!content)
51
+ return;
52
+ await noteMutation.create.mutateAsync({ content });
53
+ setNoteContent("");
54
+ }
55
+ if (supplierQuery.isPending)
56
+ return _jsx(SupplierDetailSkeleton, { className: className });
57
+ if (supplierQuery.isError) {
58
+ return (_jsx(EmptyState, { message: detail.loadFailed, onBack: onBack, backLabel: detail.backToSuppliers, className: className }));
59
+ }
60
+ if (!supplier) {
61
+ return (_jsx(EmptyState, { message: detail.notFound, onBack: onBack, backLabel: detail.backToSuppliers, className: className }));
62
+ }
63
+ const services = servicesQuery.data?.data ?? [];
64
+ const notes = notesQuery.data?.data ?? [];
65
+ return (_jsxs("div", { "data-slot": "supplier-detail-page", className: cn("flex flex-col gap-6 p-6", className), children: [_jsxs("div", { className: "flex flex-col gap-4 md:flex-row md:items-start md:justify-between", children: [_jsxs("div", { className: "flex flex-col gap-3", children: [onBack && (_jsxs(Button, { type: "button", variant: "ghost", className: "w-fit px-0", onClick: onBack, children: [_jsx(ArrowLeft, {}), detail.backToSuppliers] })), _jsxs("div", { children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("h1", { className: "text-3xl font-semibold tracking-tight", children: supplier.name }), _jsx(Badge, { variant: statusVariant[supplier.status], children: messages.common.supplierStatusLabels[supplier.status] })] }), _jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: supplier.description })] })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs(Button, { type: "button", variant: "outline", onClick: () => setEditOpen(true), children: [_jsx(Pencil, {}), messages.common.edit] }), _jsxs(Button, { type: "button", variant: "destructive", onClick: deleteSupplier, disabled: supplierMutation.remove.isPending, children: [_jsx(Trash2, {}), messages.common.delete] })] })] }), _jsxs("div", { className: "grid gap-4 lg:grid-cols-2", children: [_jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx(CardTitle, { children: detail.details }) }), _jsxs(CardContent, { className: "grid gap-3 text-sm", children: [_jsx(Detail, { label: detail.labels.type, children: messages.common.supplierTypeLabels[supplier.type] }), _jsx(Detail, { label: detail.labels.status, children: messages.common.supplierStatusLabels[supplier.status] }), _jsx(Detail, { label: detail.labels.city, children: supplier.city ?? messages.common.none }), _jsx(Detail, { label: detail.labels.country, children: supplier.country ?? messages.common.none }), _jsx(Detail, { label: detail.labels.currency, children: supplier.defaultCurrency ?? messages.common.none }), _jsx(Detail, { label: detail.labels.reservationTimeout, children: supplier.reservationTimeoutMinutes == null
66
+ ? messages.common.none
67
+ : String(supplier.reservationTimeoutMinutes) }), _jsx(Detail, { label: detail.labels.created, children: formatDate(supplier.createdAt, locale) }), _jsx(Detail, { label: detail.labels.updated, children: formatDate(supplier.updatedAt, locale) })] })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx(CardTitle, { children: detail.contact }) }), _jsx(CardContent, { className: "grid gap-3 text-sm", children: !hasContactDetails(supplier) ? (_jsx("p", { className: "text-muted-foreground", children: detail.noContact })) : (_jsxs(_Fragment, { children: [_jsx(Detail, { label: detail.labels.email, children: supplier.email ?? messages.common.none }), _jsx(Detail, { label: detail.labels.phone, children: supplier.phone ?? messages.common.none }), _jsx(Detail, { label: detail.labels.website, children: supplier.website ? (_jsx("a", { href: supplier.website, className: "text-primary underline-offset-4 hover:underline", children: supplier.website })) : (messages.common.none) }), _jsx(Detail, { label: detail.labels.address, children: supplier.address ?? messages.common.none }), _jsx(Detail, { label: detail.labels.contactName, children: supplier.contactName ?? messages.common.none }), _jsx(Detail, { label: detail.labels.contactEmail, children: supplier.contactEmail ?? messages.common.none }), _jsx(Detail, { label: detail.labels.contactPhone, children: supplier.contactPhone ?? messages.common.none })] })) })] })] }), renderCustomerPaymentPolicy?.({
68
+ supplier,
69
+ updateSupplier: (input) => supplierMutation.update.mutateAsync({ id: supplier.id, input }),
70
+ isUpdating: supplierMutation.update.isPending,
71
+ }), _jsxs(Card, { children: [_jsxs(CardHeader, { className: "flex flex-row items-center justify-between gap-4", children: [_jsx(CardTitle, { children: detail.services }), _jsxs(Button, { type: "button", onClick: () => {
72
+ setEditingService(undefined);
73
+ setServiceDialogOpen(true);
74
+ }, children: [_jsx(Plus, {}), detail.addService] })] }), _jsx(CardContent, { className: "flex flex-col gap-3", children: servicesQuery.isPending ? (_jsx(LoadingLine, {})) : services.length === 0 ? (_jsx("p", { className: "py-4 text-center text-sm text-muted-foreground", children: detail.noServices })) : (services.map((service) => (_jsx(SupplierServiceRow, { service: service, supplierId: supplier.id, expanded: expandedServiceId === service.id, onToggle: () => setExpandedServiceId((current) => (current === service.id ? null : service.id)), onEdit: () => {
75
+ setEditingService(service);
76
+ setServiceDialogOpen(true);
77
+ }, onDelete: () => void deleteService(service.id), onAddRate: () => setRateDialog({ open: true, serviceId: service.id }), onEditRate: (rate) => setRateDialog({ open: true, serviceId: service.id, rate }), onDeleteRate: (rateId) => void deleteRate(service.id, rateId) }, service.id)))) })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx(CardTitle, { children: detail.notes }) }), _jsxs(CardContent, { className: "flex flex-col gap-4", children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Textarea, { value: noteContent, onChange: (event) => setNoteContent(event.target.value), placeholder: detail.notePlaceholder }), _jsxs(Button, { type: "button", className: "w-fit", onClick: () => void addNote(), disabled: !noteContent.trim() || noteMutation.create.isPending, children: [noteMutation.create.isPending && _jsx(Loader2, { className: "animate-spin" }), detail.addNote] })] }), notesQuery.isPending ? (_jsx(LoadingLine, {})) : notes.length === 0 ? (_jsx("p", { className: "py-4 text-center text-sm text-muted-foreground", children: detail.noNotes })) : (_jsx("div", { className: "flex flex-col gap-3", children: notes.map((note) => (_jsxs("div", { className: "rounded-md border p-3", children: [_jsx("p", { className: "whitespace-pre-wrap text-sm", children: note.content }), _jsx("p", { className: "mt-2 text-xs text-muted-foreground", children: formatDate(note.createdAt, locale) })] }, note.id))) }))] })] }), _jsx(SupplierDialog, { open: editOpen, onOpenChange: setEditOpen, supplier: supplier, onSuccess: () => setEditOpen(false) }), _jsx(ServiceDialog, { open: serviceDialogOpen, onOpenChange: setServiceDialogOpen, supplierId: supplier.id, service: editingService, onSuccess: () => {
78
+ setServiceDialogOpen(false);
79
+ setEditingService(undefined);
80
+ } }), _jsx(RateDialog, { open: rateDialog.open, onOpenChange: (open) => setRateDialog((current) => ({ ...current, open })), supplierId: supplier.id, serviceId: rateDialog.serviceId, rate: rateDialog.rate, onSuccess: () => setRateDialog({ open: false, serviceId: "" }) })] }));
81
+ }
82
+ function Detail({ label, children }) {
83
+ return (_jsxs("div", { className: "grid grid-cols-[10rem_minmax(0,1fr)] gap-3", children: [_jsx("span", { className: "text-muted-foreground", children: label }), _jsx("span", { className: "min-w-0 break-words", children: children })] }));
84
+ }
85
+ function EmptyState({ message, onBack, backLabel, className, }) {
86
+ return (_jsxs("div", { className: cn("flex min-h-80 flex-col items-center justify-center gap-4 p-6 text-center", className), children: [_jsx("p", { className: "text-muted-foreground", children: message }), onBack && (_jsxs(Button, { type: "button", variant: "outline", onClick: onBack, children: [_jsx(ArrowLeft, {}), backLabel] }))] }));
87
+ }
88
+ function SupplierDetailSkeleton({ className }) {
89
+ return (_jsxs("div", { className: cn("flex flex-col gap-6 p-6", className), children: [_jsx("div", { className: "h-9 w-72 animate-pulse rounded bg-muted" }), _jsxs("div", { className: "grid gap-4 lg:grid-cols-2", children: [_jsx("div", { className: "h-64 animate-pulse rounded-md bg-muted" }), _jsx("div", { className: "h-64 animate-pulse rounded-md bg-muted" })] }), _jsx("div", { className: "h-96 animate-pulse rounded-md bg-muted" })] }));
90
+ }
91
+ function LoadingLine() {
92
+ return _jsx("div", { className: "h-4 w-40 animate-pulse rounded bg-muted" });
93
+ }
94
+ function hasContactDetails(supplier) {
95
+ return Boolean(supplier.email ||
96
+ supplier.phone ||
97
+ supplier.website ||
98
+ supplier.address ||
99
+ supplier.contactName ||
100
+ supplier.contactEmail ||
101
+ supplier.contactPhone);
102
+ }
103
+ function formatDate(value, locale) {
104
+ return new Intl.DateTimeFormat(locale, { dateStyle: "medium", timeStyle: "short" }).format(new Date(value));
105
+ }
@@ -0,0 +1,9 @@
1
+ import { type Supplier } from "../index.js";
2
+ export type SupplierDialogProps = {
3
+ open: boolean;
4
+ onOpenChange: (open: boolean) => void;
5
+ supplier?: Supplier;
6
+ onSuccess?: (supplier: Supplier) => void;
7
+ };
8
+ export declare function SupplierDialog({ open, onOpenChange, supplier, onSuccess }: SupplierDialogProps): import("react/jsx-runtime").JSX.Element;
9
+ //# sourceMappingURL=supplier-dialog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supplier-dialog.d.ts","sourceRoot":"","sources":["../../../src/suppliers/components/supplier-dialog.tsx"],"names":[],"mappings":"AA2BA,OAAO,EAAqC,KAAK,QAAQ,EAAuB,MAAM,aAAa,CAAA;AA0BnG,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,QAAQ,CAAC,EAAE,QAAQ,CAAA;IACnB,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAA;CACzC,CAAA;AAED,wBAAgB,cAAc,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,mBAAmB,2CA6O9F"}
@@ -0,0 +1,118 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Button, Dialog, DialogBody, DialogContent, DialogFooter, DialogHeader, DialogTitle, Input, Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Textarea, } from "@voyant-travel/ui/components";
4
+ import { CountryCombobox } from "@voyant-travel/ui/components/country-combobox";
5
+ import { CurrencyCombobox } from "@voyant-travel/ui/components/currency-combobox";
6
+ import { zodResolver } from "@voyant-travel/ui/lib/zod-resolver";
7
+ import { Loader2 } from "lucide-react";
8
+ import * as React from "react";
9
+ import { useForm } from "react-hook-form";
10
+ import { z } from "zod/v4";
11
+ import { useSuppliersUiMessagesOrDefault } from "../i18n/index.js";
12
+ import { SUPPLIER_STATUSES, SUPPLIER_TYPES, useSupplierMutation } from "../index.js";
13
+ function getSupplierSchema(messages) {
14
+ const dialog = messages.dialogs.supplier;
15
+ return z.object({
16
+ name: z.string().min(1, dialog.validationNameRequired),
17
+ type: z.enum(["hotel", "transfer", "guide", "experience", "airline", "restaurant", "other"]),
18
+ status: z.enum(["active", "inactive", "pending"]),
19
+ description: z.string().optional().nullable(),
20
+ email: z.string().email().optional().or(z.literal("")).nullable(),
21
+ phone: z.string().optional().nullable(),
22
+ website: z.string().url().optional().or(z.literal("")).nullable(),
23
+ address: z.string().optional().nullable(),
24
+ city: z.string().optional().nullable(),
25
+ country: z.string().optional().nullable(),
26
+ defaultCurrency: z.string().max(3, dialog.validationIsoCurrency).optional().nullable(),
27
+ reservationTimeoutMinutes: z
28
+ .union([z.literal(""), z.coerce.number().int().min(0, dialog.validationReservationTimeout)])
29
+ .optional()
30
+ .nullable(),
31
+ contactName: z.string().optional().nullable(),
32
+ contactEmail: z.string().email().optional().or(z.literal("")).nullable(),
33
+ contactPhone: z.string().optional().nullable(),
34
+ });
35
+ }
36
+ export function SupplierDialog({ open, onOpenChange, supplier, onSuccess }) {
37
+ const messages = useSuppliersUiMessagesOrDefault();
38
+ const dialog = messages.dialogs.supplier;
39
+ const schema = React.useMemo(() => getSupplierSchema(messages), [messages]);
40
+ const supplierMutation = useSupplierMutation();
41
+ const isEditing = !!supplier;
42
+ const form = useForm({
43
+ resolver: zodResolver(schema),
44
+ defaultValues: {
45
+ name: "",
46
+ type: "hotel",
47
+ status: "active",
48
+ description: "",
49
+ email: "",
50
+ phone: "",
51
+ website: "",
52
+ address: "",
53
+ city: "",
54
+ country: "",
55
+ defaultCurrency: "",
56
+ reservationTimeoutMinutes: "",
57
+ contactName: "",
58
+ contactEmail: "",
59
+ contactPhone: "",
60
+ },
61
+ });
62
+ React.useEffect(() => {
63
+ if (!open)
64
+ return;
65
+ form.reset({
66
+ name: supplier?.name ?? "",
67
+ type: supplier?.type ?? "hotel",
68
+ status: supplier?.status ?? "active",
69
+ description: supplier?.description ?? "",
70
+ email: supplier?.email ?? "",
71
+ phone: supplier?.phone ?? "",
72
+ website: supplier?.website ?? "",
73
+ address: supplier?.address ?? "",
74
+ city: supplier?.city ?? "",
75
+ country: supplier?.country ?? "",
76
+ defaultCurrency: supplier?.defaultCurrency ?? "",
77
+ reservationTimeoutMinutes: supplier?.reservationTimeoutMinutes == null
78
+ ? ""
79
+ : String(supplier.reservationTimeoutMinutes),
80
+ contactName: supplier?.contactName ?? "",
81
+ contactEmail: supplier?.contactEmail ?? "",
82
+ contactPhone: supplier?.contactPhone ?? "",
83
+ });
84
+ }, [form, open, supplier]);
85
+ async function onSubmit(values) {
86
+ const input = {
87
+ ...values,
88
+ description: values.description || null,
89
+ email: values.email || null,
90
+ phone: values.phone || null,
91
+ website: values.website || null,
92
+ address: values.address || null,
93
+ city: values.city || null,
94
+ country: values.country || null,
95
+ defaultCurrency: values.defaultCurrency || null,
96
+ reservationTimeoutMinutes: values.reservationTimeoutMinutes === "" ||
97
+ values.reservationTimeoutMinutes === null ||
98
+ values.reservationTimeoutMinutes === undefined
99
+ ? null
100
+ : values.reservationTimeoutMinutes,
101
+ contactName: values.contactName || null,
102
+ contactEmail: values.contactEmail || null,
103
+ contactPhone: values.contactPhone || null,
104
+ };
105
+ const saved = isEditing
106
+ ? await supplierMutation.update.mutateAsync({ id: supplier.id, input })
107
+ : await supplierMutation.create.mutateAsync(input);
108
+ onSuccess?.(saved);
109
+ onOpenChange(false);
110
+ }
111
+ return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { size: "lg", children: [_jsx(DialogHeader, { children: _jsx(DialogTitle, { children: isEditing ? dialog.editTitle : dialog.newTitle }) }), _jsxs("form", { onSubmit: form.handleSubmit(onSubmit), children: [_jsxs(DialogBody, { className: "grid gap-4", children: [_jsxs("div", { className: "grid gap-4 sm:grid-cols-2", children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: dialog.typeLabel }), _jsxs(Select, { value: form.watch("type"), onValueChange: (value) => form.setValue("type", value), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: SUPPLIER_TYPES.map((type) => (_jsx(SelectItem, { value: type.value, children: messages.common.supplierTypeLabels[type.value] }, type.value))) })] })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: dialog.statusLabel }), _jsxs(Select, { value: form.watch("status"), onValueChange: (value) => form.setValue("status", value), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: SUPPLIER_STATUSES.map((status) => (_jsx(SelectItem, { value: status.value, children: messages.common.supplierStatusLabels[status.value] }, status.value))) })] })] })] }), _jsx(Field, { label: dialog.nameLabel, error: form.formState.errors.name?.message, children: _jsx(Input, { ...form.register("name"), placeholder: dialog.namePlaceholder }) }), _jsx(Field, { label: dialog.descriptionLabel, children: _jsx(Textarea, { ...form.register("description"), placeholder: dialog.descriptionPlaceholder }) }), _jsxs("div", { className: "grid gap-4 sm:grid-cols-2", children: [_jsx(Field, { label: dialog.emailLabel, error: form.formState.errors.email?.message, children: _jsx(Input, { ...form.register("email"), type: "email", placeholder: dialog.emailPlaceholder }) }), _jsx(Field, { label: dialog.phoneLabel, children: _jsx(Input, { ...form.register("phone"), placeholder: dialog.phonePlaceholder }) })] }), _jsx(Field, { label: dialog.websiteLabel, error: form.formState.errors.website?.message, children: _jsx(Input, { ...form.register("website"), placeholder: dialog.websitePlaceholder }) }), _jsxs("div", { className: "grid gap-4 sm:grid-cols-2", children: [_jsx(Field, { label: dialog.cityLabel, children: _jsx(Input, { ...form.register("city"), placeholder: dialog.cityPlaceholder }) }), _jsx(Field, { label: dialog.countryLabel, children: _jsx(CountryCombobox, { value: form.watch("country"), onChange: (value) => form.setValue("country", value ?? ""), placeholder: dialog.countryPlaceholder }) })] }), _jsx(Field, { label: dialog.addressLabel, children: _jsx(Textarea, { ...form.register("address"), placeholder: dialog.addressPlaceholder }) }), _jsxs("div", { className: "grid gap-4 sm:grid-cols-2", children: [_jsx(Field, { label: dialog.defaultCurrencyLabel, error: form.formState.errors.defaultCurrency?.message, children: _jsx(CurrencyCombobox, { value: form.watch("defaultCurrency") || null, onChange: (next) => form.setValue("defaultCurrency", next ?? "", {
112
+ shouldValidate: true,
113
+ shouldDirty: true,
114
+ }), placeholder: dialog.defaultCurrencyPlaceholder }) }), _jsx(Field, { label: dialog.reservationTimeoutLabel, error: form.formState.errors.reservationTimeoutMinutes?.message, children: _jsx(Input, { ...form.register("reservationTimeoutMinutes"), type: "number", min: "0", placeholder: dialog.reservationTimeoutPlaceholder }) })] }), _jsxs("div", { className: "grid gap-4 sm:grid-cols-3", children: [_jsx(Field, { label: dialog.contactNameLabel, children: _jsx(Input, { ...form.register("contactName"), placeholder: dialog.contactNamePlaceholder }) }), _jsx(Field, { label: dialog.contactEmailLabel, error: form.formState.errors.contactEmail?.message, children: _jsx(Input, { ...form.register("contactEmail"), type: "email", placeholder: dialog.contactEmailPlaceholder }) }), _jsx(Field, { label: dialog.contactPhoneLabel, children: _jsx(Input, { ...form.register("contactPhone"), placeholder: dialog.contactPhonePlaceholder }) })] })] }), _jsxs(DialogFooter, { children: [_jsx(Button, { type: "button", variant: "ghost", onClick: () => onOpenChange(false), children: messages.common.cancel }), _jsxs(Button, { type: "submit", disabled: form.formState.isSubmitting, children: [form.formState.isSubmitting && _jsx(Loader2, { className: "animate-spin" }), isEditing ? messages.common.save : messages.common.create] })] })] })] }) }));
115
+ }
116
+ function Field({ label, error, children, }) {
117
+ return (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: label }), children, error && _jsx("p", { className: "text-xs text-destructive", children: error })] }));
118
+ }
@@ -0,0 +1,22 @@
1
+ import { type SupplierRate, type SupplierService } from "../index.js";
2
+ export declare function SupplierServiceRow({ service, supplierId, rates, expanded, onToggle, onEdit, onDelete, onAddRate, onEditRate, onDeleteRate, }: {
3
+ service: SupplierService;
4
+ /**
5
+ * Optional. When set (and `rates` is not), the row fetches rates lazily on
6
+ * expand via `useSupplierServiceRates`.
7
+ */
8
+ supplierId?: string;
9
+ /**
10
+ * Optional. When provided, the caller owns rate fetching. When omitted and
11
+ * `supplierId` is set, rates are fetched internally on expand.
12
+ */
13
+ rates?: SupplierRate[];
14
+ expanded: boolean;
15
+ onToggle: () => void;
16
+ onEdit: () => void;
17
+ onDelete: () => void;
18
+ onAddRate: () => void;
19
+ onEditRate: (rate: SupplierRate) => void;
20
+ onDeleteRate: (rateId: string) => void;
21
+ }): import("react/jsx-runtime").JSX.Element;
22
+ //# sourceMappingURL=supplier-service-row.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supplier-service-row.d.ts","sourceRoot":"","sources":["../../../src/suppliers/components/supplier-service-row.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,eAAe,EAA2B,MAAM,aAAa,CAAA;AAE9F,wBAAgB,kBAAkB,CAAC,EACjC,OAAO,EACP,UAAU,EACV,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,MAAM,EACN,QAAQ,EACR,SAAS,EACT,UAAU,EACV,YAAY,GACb,EAAE;IACD,OAAO,EAAE,eAAe,CAAA;IACxB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;OAGG;IACH,KAAK,CAAC,EAAE,YAAY,EAAE,CAAA;IACtB,QAAQ,EAAE,OAAO,CAAA;IACjB,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,SAAS,EAAE,MAAM,IAAI,CAAA;IACrB,UAAU,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAA;IACxC,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAA;CACvC,2CA0JA"}