kaafil-react-uikit 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/dist/admin/index.cjs +565 -387
  3. package/dist/admin/index.cjs.map +1 -1
  4. package/dist/admin/index.d.cts +2 -2
  5. package/dist/admin/index.d.ts +2 -2
  6. package/dist/admin/index.js +231 -53
  7. package/dist/admin/index.js.map +1 -1
  8. package/dist/{chunk-YTSYRLGS.js → chunk-2LMFSKZU.js} +56 -17
  9. package/dist/chunk-2LMFSKZU.js.map +1 -0
  10. package/dist/{chunk-BBC5EX5O.cjs → chunk-2XW5EIMS.cjs} +17 -17
  11. package/dist/{chunk-BBC5EX5O.cjs.map → chunk-2XW5EIMS.cjs.map} +1 -1
  12. package/dist/{chunk-YU2242AR.js → chunk-3BEQYIFU.js} +5 -5
  13. package/dist/{chunk-YU2242AR.js.map → chunk-3BEQYIFU.js.map} +1 -1
  14. package/dist/{chunk-UALMCHNW.cjs → chunk-3N2EQ2KC.cjs} +84 -36
  15. package/dist/chunk-3N2EQ2KC.cjs.map +1 -0
  16. package/dist/{chunk-57SUK3GD.cjs → chunk-4QYI7TOF.cjs} +7 -7
  17. package/dist/{chunk-57SUK3GD.cjs.map → chunk-4QYI7TOF.cjs.map} +1 -1
  18. package/dist/{chunk-ECCQW5LN.cjs → chunk-6BY2NPBZ.cjs} +4 -4
  19. package/dist/{chunk-ECCQW5LN.cjs.map → chunk-6BY2NPBZ.cjs.map} +1 -1
  20. package/dist/{chunk-YNHOPYBK.cjs → chunk-7356B6YS.cjs} +12 -12
  21. package/dist/{chunk-YNHOPYBK.cjs.map → chunk-7356B6YS.cjs.map} +1 -1
  22. package/dist/{chunk-A4Z2YBEF.js → chunk-7G6IENKN.js} +84 -36
  23. package/dist/chunk-7G6IENKN.js.map +1 -0
  24. package/dist/{chunk-MNUCVVIE.cjs → chunk-A7C74SJT.cjs} +302 -148
  25. package/dist/chunk-A7C74SJT.cjs.map +1 -0
  26. package/dist/{chunk-KW5LH6KV.js → chunk-CLHAJBJS.js} +3 -3
  27. package/dist/{chunk-KW5LH6KV.js.map → chunk-CLHAJBJS.js.map} +1 -1
  28. package/dist/{chunk-GJ2J3PYN.js → chunk-E6ER25BG.js} +3 -3
  29. package/dist/{chunk-GJ2J3PYN.js.map → chunk-E6ER25BG.js.map} +1 -1
  30. package/dist/{chunk-HACH2NUM.cjs → chunk-KETEED2T.cjs} +9 -9
  31. package/dist/{chunk-HACH2NUM.cjs.map → chunk-KETEED2T.cjs.map} +1 -1
  32. package/dist/{chunk-RWLO6IFX.js → chunk-KTEXDGAA.js} +3 -3
  33. package/dist/{chunk-RWLO6IFX.js.map → chunk-KTEXDGAA.js.map} +1 -1
  34. package/dist/{chunk-VLP323AD.js → chunk-RBIEMGHT.js} +3 -3
  35. package/dist/{chunk-VLP323AD.js.map → chunk-RBIEMGHT.js.map} +1 -1
  36. package/dist/{chunk-WTTGPWMR.js → chunk-WPQB7JWS.js} +227 -73
  37. package/dist/chunk-WPQB7JWS.js.map +1 -0
  38. package/dist/{chunk-FVK7HMQ5.cjs → chunk-XBLAVNP3.cjs} +88 -48
  39. package/dist/chunk-XBLAVNP3.cjs.map +1 -0
  40. package/dist/core/index.cjs +124 -121
  41. package/dist/core/index.cjs.map +1 -1
  42. package/dist/core/index.d.cts +10 -1
  43. package/dist/core/index.d.ts +10 -1
  44. package/dist/core/index.js +20 -19
  45. package/dist/core/index.js.map +1 -1
  46. package/dist/index.css +1 -1
  47. package/dist/manager/index.cjs +239 -239
  48. package/dist/manager/index.js +6 -6
  49. package/dist/tokens.json +5013 -0
  50. package/dist/traveller/index.cjs +46 -40
  51. package/dist/traveller/index.cjs.map +1 -1
  52. package/dist/traveller/index.js +16 -10
  53. package/dist/traveller/index.js.map +1 -1
  54. package/dist/{useAgencyTrip-BUYSIaC2.d.cts → useAgencyTrip-C1YmfuQq.d.cts} +35 -1
  55. package/dist/{useAgencyTrip-BzyJB1D9.d.ts → useAgencyTrip-gZB0NILH.d.ts} +35 -1
  56. package/package.json +4 -3
  57. package/dist/chunk-A4Z2YBEF.js.map +0 -1
  58. package/dist/chunk-FVK7HMQ5.cjs.map +0 -1
  59. package/dist/chunk-MNUCVVIE.cjs.map +0 -1
  60. package/dist/chunk-UALMCHNW.cjs.map +0 -1
  61. package/dist/chunk-WTTGPWMR.js.map +0 -1
  62. package/dist/chunk-YTSYRLGS.js.map +0 -1
@@ -2,8 +2,8 @@ export { B as BootErrorScreen, a as BootErrorScreenProps, b as BootFailureMode,
2
2
  export { L as LockedTripScreen, a as LockedTripScreenProps, N as NotFoundScreen, b as NotFoundScreenProps, S as SessionExpiredScreen, c as SessionExpiredScreenProps } from '../SessionExpiredScreen-CytQNuak.cjs';
3
3
  import { ReactNode, ComponentType } from 'react';
4
4
  import { K as KaafilTokenOverrides } from '../tokenStyle-CToG5oOS.cjs';
5
- import { C as ChecklistTemplateRow, a as ChecklistTemplateItemRow, F as FormDetailRow, b as FormFieldRow, c as FormRow, M as ManagerListRowResponse, T as TravellerDirectoryItemResponse, J as JourneyTriggerRow, A as AgencyTripRow, d as TripManifestRow, e as CollectionDeltaRow, f as AgencyTripRead } from '../useAgencyTrip-BUYSIaC2.cjs';
6
- export { g as AgencySettingsDocument, B as FormBuilderBindingRow, h as FormSectionRow } from '../useAgencyTrip-BUYSIaC2.cjs';
5
+ import { C as ChecklistTemplateRow, a as ChecklistTemplateItemRow, F as FormDetailRow, b as FormFieldRow, c as FormRow, M as ManagerListRowResponse, T as TravellerDirectoryItemResponse, J as JourneyTriggerRow, A as AgencyTripRow, d as TripManifestRow, e as CollectionDeltaRow, f as AgencyTripRead } from '../useAgencyTrip-C1YmfuQq.cjs';
6
+ export { g as AgencySettingsDocument, B as FormBuilderBindingRow, h as FormSectionRow } from '../useAgencyTrip-C1YmfuQq.cjs';
7
7
  import { ManagerAgencyProfileResponse, TravellerAgencyProfileResponse, BookingListRow, PickupStopDeltaRow, RoomingRoomDeltaRow, SeatingVehicleDeltaRow } from 'kaafil-js/client';
8
8
  export { BookingListRow, ManagerAgencyProfileResponse, SeatingOccupant, TravellerAgencyProfileResponse, AgencyTripSegmentCounts as TripDirectorySegmentCounts, TripManifestFacets } from 'kaafil-js/client';
9
9
  import { C as ChecklistSectionRow, a as ChecklistsReady, F as FileListItem, E as ExpenseDeltaRow, b as FloatMovementRow, T as TripFormRow, c as TripFormResponseRow, I as ItineraryDayRow, d as ItineraryItemRow, R as RoomingStayWindowRow, e as TripVendorRow } from '../useVendors-DXOuZWhZ.cjs';
@@ -2,8 +2,8 @@ export { B as BootErrorScreen, a as BootErrorScreenProps, b as BootFailureMode,
2
2
  export { L as LockedTripScreen, a as LockedTripScreenProps, N as NotFoundScreen, b as NotFoundScreenProps, S as SessionExpiredScreen, c as SessionExpiredScreenProps } from '../SessionExpiredScreen-D8GHyZc3.js';
3
3
  import { ReactNode, ComponentType } from 'react';
4
4
  import { K as KaafilTokenOverrides } from '../tokenStyle-CToG5oOS.js';
5
- import { C as ChecklistTemplateRow, a as ChecklistTemplateItemRow, F as FormDetailRow, b as FormFieldRow, c as FormRow, M as ManagerListRowResponse, T as TravellerDirectoryItemResponse, J as JourneyTriggerRow, A as AgencyTripRow, d as TripManifestRow, e as CollectionDeltaRow, f as AgencyTripRead } from '../useAgencyTrip-BzyJB1D9.js';
6
- export { g as AgencySettingsDocument, B as FormBuilderBindingRow, h as FormSectionRow } from '../useAgencyTrip-BzyJB1D9.js';
5
+ import { C as ChecklistTemplateRow, a as ChecklistTemplateItemRow, F as FormDetailRow, b as FormFieldRow, c as FormRow, M as ManagerListRowResponse, T as TravellerDirectoryItemResponse, J as JourneyTriggerRow, A as AgencyTripRow, d as TripManifestRow, e as CollectionDeltaRow, f as AgencyTripRead } from '../useAgencyTrip-gZB0NILH.js';
6
+ export { g as AgencySettingsDocument, B as FormBuilderBindingRow, h as FormSectionRow } from '../useAgencyTrip-gZB0NILH.js';
7
7
  import { ManagerAgencyProfileResponse, TravellerAgencyProfileResponse, BookingListRow, PickupStopDeltaRow, RoomingRoomDeltaRow, SeatingVehicleDeltaRow } from 'kaafil-js/client';
8
8
  export { BookingListRow, ManagerAgencyProfileResponse, SeatingOccupant, TravellerAgencyProfileResponse, AgencyTripSegmentCounts as TripDirectorySegmentCounts, TripManifestFacets } from 'kaafil-js/client';
9
9
  import { C as ChecklistSectionRow, a as ChecklistsReady, F as FileListItem, E as ExpenseDeltaRow, b as FloatMovementRow, T as TripFormRow, c as TripFormResponseRow, I as ItineraryDayRow, d as ItineraryItemRow, R as RoomingStayWindowRow, e as TripVendorRow } from '../useVendors-DXOuZWhZ.js';
@@ -1,8 +1,8 @@
1
- import { useAgencySettings, useAgencyChecklistTemplates, useAgencyForms, useAgencyManagerProfile, useAgencyJourneyTriggers, useBookings, useDirectories, useCapabilityStatuses, useAgencyTrip, useAgencyAdminMe, useTravellerFormResponses, familySafeSections, useShareLinks, usePaginatedList, useAgencyTrips, useAgencyTripManifest, resolveBlockerDeepLink } from '../chunk-YTSYRLGS.js';
2
- import { useChecklists, useFiles, useExpenses, useVendors, useFloat, useManagers, useForms, useItinerary, useCollections, useParties, usePickups, useRooming, useSeating, classifyError, useTravellerProfile, roomingHeuristicSeverity, useManagerToday, useCloseout, parseRoomingTone, TONE_FAMILIES, SHADES_PER_FAMILY, FALLBACK_GLYPH } from '../chunk-WTTGPWMR.js';
3
- import '../chunk-VLP323AD.js';
4
- export { BootErrorScreen, LockedTripScreen, NotFoundScreen, OfflineFallbackScreen, PlanLockedScreen, SessionExpiredScreen } from '../chunk-GJ2J3PYN.js';
5
- import { createRegistry, useKaafilChrome, tokenStyle, useSession, useKaafilClient } from '../chunk-A4Z2YBEF.js';
1
+ import { useAgencySettings, useAgencyChecklistTemplates, useAgencyForms, useAgencyManagerProfile, useAgencyJourneyTriggers, useBookings, useDirectories, useCapabilityStatuses, useAgencyTrip, useAgencyAdminMe, useTravellerFormResponses, useResolvedSetting, familySafeSections, useShareLinks, usePaginatedList, useAgencyTrips, useAgencyTripManifest, resolveBlockerDeepLink } from '../chunk-2LMFSKZU.js';
2
+ import { useChecklists, useFiles, useExpenses, useVendors, useFloat, useManagers, useForms, useItinerary, useCollections, useParties, usePickups, useRooming, useSeating, classifyError, useTravellerProfile, roomingHeuristicSeverity, useManagerToday, useCloseout, parseRoomingTone, TONE_FAMILIES, SHADES_PER_FAMILY, FALLBACK_GLYPH } from '../chunk-WPQB7JWS.js';
3
+ import '../chunk-RBIEMGHT.js';
4
+ export { BootErrorScreen, LockedTripScreen, NotFoundScreen, OfflineFallbackScreen, PlanLockedScreen, SessionExpiredScreen } from '../chunk-E6ER25BG.js';
5
+ import { createRegistry, useKaafilChrome, tokenStyle, useSession, useKaafilClient } from '../chunk-7G6IENKN.js';
6
6
  import { useState, useEffect, useCallback, useMemo, useId, useRef, Children } from 'react';
7
7
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
8
 
@@ -4572,6 +4572,11 @@ function FormBuilder({ formId, onBack, components, style }) {
4572
4572
  ] });
4573
4573
  }
4574
4574
  var KEY_PATTERN2 = /^[a-z][a-z0-9_]{0,59}$/;
4575
+ var CREATE_FAILURE_KEY = {
4576
+ CONFLICT_VERSION: "chrome.formsLibrary.create.failedDuplicate",
4577
+ BUSINESS_RULE_VIOLATION: "chrome.formsLibrary.create.failedDuplicate",
4578
+ VALIDATION_ERROR: "chrome.formsLibrary.create.failedInvalid"
4579
+ };
4575
4580
  function slugifyFormKey(title) {
4576
4581
  const slug = title.trim().toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 60);
4577
4582
  return /^[a-z]/.test(slug) ? slug : `f_${slug}`.slice(0, 60);
@@ -4595,6 +4600,7 @@ function CreateFormSheet({ onSubmit, onClose }) {
4595
4600
  const [phase, setPhase] = useState("PRE_DEPARTURE");
4596
4601
  const [audience, setAudience] = useState("TRAVELLER");
4597
4602
  const [pending, setPending] = useState(false);
4603
+ const [errorCode, setErrorCode] = useState(void 0);
4598
4604
  const trimmedTitle = title.trim();
4599
4605
  const generatedKey = slugifyFormKey(trimmedTitle);
4600
4606
  const keyValid = KEY_PATTERN2.test(generatedKey);
@@ -4604,6 +4610,7 @@ function CreateFormSheet({ onSubmit, onClose }) {
4604
4610
  return;
4605
4611
  }
4606
4612
  setPending(true);
4613
+ setErrorCode(void 0);
4607
4614
  try {
4608
4615
  await onSubmit({
4609
4616
  key: generatedKey,
@@ -4613,6 +4620,8 @@ function CreateFormSheet({ onSubmit, onClose }) {
4613
4620
  audience
4614
4621
  });
4615
4622
  onClose();
4623
+ } catch (error) {
4624
+ setErrorCode(classifyError(error).code ?? "unknown");
4616
4625
  } finally {
4617
4626
  setPending(false);
4618
4627
  }
@@ -4624,15 +4633,25 @@ function CreateFormSheet({ onSubmit, onClose }) {
4624
4633
  title: t("chrome.formsLibrary.create.title"),
4625
4634
  onClose,
4626
4635
  closeLabel: t("chrome.close"),
4627
- footer: /* @__PURE__ */ jsx(
4628
- "button",
4629
- {
4630
- type: "button",
4631
- className: "kf-forms-library__sheet-submit",
4632
- disabled: !canSubmit || pending,
4633
- onClick: () => void handleSubmit(),
4634
- children: t("chrome.formsLibrary.create.submit")
4635
- }
4636
+ footer: (
4637
+ // A column, because this sheet's submit is a full-width button — the
4638
+ // shared footer is a flex ROW, so an error beside it would squeeze
4639
+ // both. Stacked, the reason sits directly above the control it
4640
+ // explains.
4641
+ /* @__PURE__ */ jsxs("div", { className: "kf-forms-library__sheet-actions", children: [
4642
+ errorCode === void 0 ? null : /* @__PURE__ */ jsx("p", { className: "kf-forms-library__sheet-error", role: "alert", children: t(CREATE_FAILURE_KEY[errorCode] ?? "chrome.formsLibrary.create.failed") }),
4643
+ /* @__PURE__ */ jsx(
4644
+ "button",
4645
+ {
4646
+ type: "button",
4647
+ className: "kf-forms-library__sheet-submit",
4648
+ disabled: !canSubmit || pending,
4649
+ onClick: () => void handleSubmit(),
4650
+ children: pending ? t("chrome.formsLibrary.create.submitting") : t("chrome.formsLibrary.create.submit")
4651
+ }
4652
+ ),
4653
+ canSubmit || pending ? null : /* @__PURE__ */ jsx("p", { className: "kf-forms-library__hint-copy", children: t("chrome.formsLibrary.create.needsTitle") })
4654
+ ] })
4636
4655
  ),
4637
4656
  children: [
4638
4657
  /* @__PURE__ */ jsx("p", { className: "kf-forms-library__field-label", children: t("chrome.formsLibrary.create.titleLabel") }),
@@ -14177,6 +14196,12 @@ function WarningIcon12(props) {
14177
14196
  /* @__PURE__ */ jsx("path", { d: "M12 9v4M12 17h.01" })
14178
14197
  ] });
14179
14198
  }
14199
+ var ADD_FAILURE_KEY = {
14200
+ LOCKED: "chrome.tripManifest.addFailedLocked",
14201
+ BUSINESS_RULE_VIOLATION: "chrome.tripManifest.addFailedRule",
14202
+ VALIDATION_ERROR: "chrome.tripManifest.addFailedInvalid",
14203
+ RESOURCE_NOT_FOUND: "chrome.tripManifest.addFailedGone"
14204
+ };
14180
14205
  function AddTravellerDialog({
14181
14206
  tripRef,
14182
14207
  onClose,
@@ -14192,16 +14217,17 @@ function AddTravellerDialog({
14192
14217
  const [errorCode, setErrorCode] = useState(void 0);
14193
14218
  const [newName, setNewName] = useState("");
14194
14219
  const [newPhone, setNewPhone] = useState("");
14220
+ const [pendingId, setPendingId] = useState(void 0);
14195
14221
  useEffect(() => {
14196
14222
  const timer = setTimeout(() => setDebounced(term.trim()), 300);
14197
14223
  return () => clearTimeout(timer);
14198
14224
  }, [term]);
14199
14225
  function reportFailure(error) {
14200
- const classification = error !== null && typeof error === "object" && "classification" in error ? error.classification : void 0;
14201
- setErrorCode(classification?.code ?? "unknown");
14226
+ setErrorCode(classifyError(error).code ?? "unknown");
14202
14227
  }
14203
14228
  async function addExisting(externalTravellerId, fullName) {
14204
14229
  setPending(true);
14230
+ setPendingId(externalTravellerId);
14205
14231
  setErrorCode(void 0);
14206
14232
  try {
14207
14233
  await addTraveller({ tripRef, externalTravellerId, fullName });
@@ -14210,6 +14236,7 @@ function AddTravellerDialog({
14210
14236
  reportFailure(error);
14211
14237
  } finally {
14212
14238
  setPending(false);
14239
+ setPendingId(void 0);
14213
14240
  }
14214
14241
  }
14215
14242
  async function createAndAdd() {
@@ -14243,6 +14270,7 @@ function AddTravellerDialog({
14243
14270
  onClose,
14244
14271
  closeLabel: t("chrome.tripManifest.close"),
14245
14272
  footer: /* @__PURE__ */ jsxs(Fragment, { children: [
14273
+ errorCode === void 0 ? null : /* @__PURE__ */ jsx("p", { className: "kf-trip-manifest-section__dialog-error", role: "alert", children: t(ADD_FAILURE_KEY[errorCode] ?? "chrome.tripManifest.addFailed") }),
14246
14274
  /* @__PURE__ */ jsx(
14247
14275
  "button",
14248
14276
  {
@@ -14307,6 +14335,7 @@ function AddTravellerDialog({
14307
14335
  {
14308
14336
  fetch: makeTravellersFetch(debounced.length > 0 ? { q: debounced } : {}),
14309
14337
  disabled: pending,
14338
+ ...pendingId !== void 0 ? { pendingId } : {},
14310
14339
  onPick: (externalTravellerId, fullName) => void addExisting(externalTravellerId, fullName)
14311
14340
  },
14312
14341
  debounced
@@ -14335,15 +14364,25 @@ function AddTravellerDialog({
14335
14364
  )
14336
14365
  ] }),
14337
14366
  /* @__PURE__ */ jsx("p", { className: "kf-trip-manifest-section__dialog-note", children: t("chrome.tripManifest.addCreateNote") })
14338
- ] }),
14339
- errorCode === void 0 ? null : /* @__PURE__ */ jsx("p", { className: "kf-trip-manifest-section__dialog-error", role: "alert", children: t("chrome.tripManifest.addFailed") })
14367
+ ] })
14340
14368
  ]
14341
14369
  }
14342
14370
  );
14343
14371
  }
14344
- function DirectoryResults({ fetch, disabled, onPick }) {
14372
+ function DirectoryResults({
14373
+ fetch,
14374
+ disabled,
14375
+ pendingId,
14376
+ onPick
14377
+ }) {
14345
14378
  const { t } = useKaafilChrome();
14346
- const { rows, hasNext, loadNext } = usePaginatedList(fetch);
14379
+ const { rows, hasNext, loadNext, settled, error } = usePaginatedList(fetch);
14380
+ if (!settled) {
14381
+ return /* @__PURE__ */ jsx("p", { className: "kf-trip-manifest-section__dialog-note", "aria-live": "polite", children: t("chrome.tripManifest.addSearching") });
14382
+ }
14383
+ if (error !== void 0) {
14384
+ return /* @__PURE__ */ jsx("p", { className: "kf-trip-manifest-section__dialog-error", role: "alert", children: t("chrome.tripManifest.addSearchFailed") });
14385
+ }
14347
14386
  if (rows.length === 0) {
14348
14387
  return /* @__PURE__ */ jsx("p", { className: "kf-trip-manifest-section__dialog-note", children: t("chrome.tripManifest.addNoMatches") });
14349
14388
  }
@@ -14366,7 +14405,7 @@ function DirectoryResults({ fetch, disabled, onPick }) {
14366
14405
  onPick(row.externalTravellerId, row.fullName);
14367
14406
  }
14368
14407
  },
14369
- children: t("chrome.tripManifest.addPick")
14408
+ children: pendingId !== void 0 && pendingId === row.externalTravellerId ? t("chrome.tripManifest.adding") : t("chrome.tripManifest.addPick")
14370
14409
  }
14371
14410
  )
14372
14411
  ] }, row.travellerId)) }),
@@ -14388,7 +14427,7 @@ function deriveManifestGroups(rows) {
14388
14427
  const byParty = /* @__PURE__ */ new Map();
14389
14428
  const solos = [];
14390
14429
  for (const row of rows) {
14391
- if (row.party === null) {
14430
+ if (row.party == null) {
14392
14431
  solos.push(row);
14393
14432
  continue;
14394
14433
  }
@@ -14598,10 +14637,13 @@ function ManifestFacetTiles({ facets, filtered }) {
14598
14637
  /* @__PURE__ */ jsxs("div", { className: "kf-trip-manifest-section__tile", children: [
14599
14638
  /* @__PURE__ */ jsx("div", { className: "kf-trip-manifest-section__tile-label", children: t("chrome.tripManifest.tileDiet") }),
14600
14639
  /* @__PURE__ */ jsxs("div", { className: "kf-trip-manifest-section__tile-diet", children: [
14601
- shown.length === 0 ? /* @__PURE__ */ jsx("span", { className: "kf-trip-manifest-section__empty-value", children: t("chrome.tripManifest.noDiet") }) : shown.map(([key, count]) => /* @__PURE__ */ jsxs("span", { className: "kf-trip-manifest-section__tile-diet-entry", children: [
14602
- /* @__PURE__ */ jsx("span", { className: "kf-trip-manifest-section__tile-diet-count", children: count }),
14603
- /* @__PURE__ */ jsx("span", { className: "kf-trip-manifest-section__tile-diet-key", children: key === "unspecified" ? t("chrome.tripManifest.dietUnspecified") : key })
14604
- ] }, key)),
14640
+ shown.length === 0 ? /* @__PURE__ */ jsx("span", { className: "kf-trip-manifest-section__empty-value", children: t("chrome.tripManifest.noDiet") }) : shown.map(([key, count]) => {
14641
+ const label = key === "unspecified" ? t("chrome.tripManifest.dietUnspecified") : key;
14642
+ return /* @__PURE__ */ jsxs("span", { className: "kf-trip-manifest-section__tile-diet-entry", children: [
14643
+ /* @__PURE__ */ jsx("span", { className: "kf-trip-manifest-section__tile-diet-count", children: count }),
14644
+ /* @__PURE__ */ jsx("span", { className: "kf-trip-manifest-section__tile-diet-key", title: label, children: label })
14645
+ ] }, key);
14646
+ }),
14605
14647
  hiddenCount > 0 ? /* @__PURE__ */ jsx("span", { className: "kf-trip-manifest-section__tile-diet-more", children: t("chrome.tripManifest.dietMore").replace("{count}", String(hiddenCount)) }) : null
14606
14648
  ] })
14607
14649
  ] }),
@@ -14615,7 +14657,23 @@ function ManifestFacetTiles({ facets, filtered }) {
14615
14657
  children: facets.medicalCount
14616
14658
  }
14617
14659
  ),
14618
- /* @__PURE__ */ jsx("div", { className: "kf-trip-manifest-section__tile-sub", children: t("chrome.tripManifest.tileFlagsSub").replace("{due}", String(facets.dueCount)) })
14660
+ /* @__PURE__ */ jsx("div", { className: "kf-trip-manifest-section__tile-sub", children: t(
14661
+ facets.medicalCount === 1 ? "chrome.tripManifest.tileFlagsSubOne" : "chrome.tripManifest.tileFlagsSubMany"
14662
+ ) })
14663
+ ] }),
14664
+ /* @__PURE__ */ jsxs("div", { className: "kf-trip-manifest-section__tile", children: [
14665
+ /* @__PURE__ */ jsx("div", { className: "kf-trip-manifest-section__tile-label", children: t("chrome.tripManifest.tileBalance") }),
14666
+ /* @__PURE__ */ jsx(
14667
+ "div",
14668
+ {
14669
+ className: "kf-trip-manifest-section__tile-value",
14670
+ "data-tone": facets.dueCount > 0 ? "warn" : void 0,
14671
+ children: facets.dueCount
14672
+ }
14673
+ ),
14674
+ /* @__PURE__ */ jsx("div", { className: "kf-trip-manifest-section__tile-sub", children: t(
14675
+ facets.dueCount === 1 ? "chrome.tripManifest.tileBalanceSubOne" : "chrome.tripManifest.tileBalanceSubMany"
14676
+ ) })
14619
14677
  ] })
14620
14678
  ] });
14621
14679
  }
@@ -15123,7 +15181,9 @@ function ManifestResultsBody({
15123
15181
  },
15124
15182
  [makeManifestFetch, filters, grouped, groupedPageSize]
15125
15183
  );
15126
- const { rows, hasNext, hasPrev, loadNext, loadPrev } = usePaginatedList(fetch);
15184
+ const { rows, hasNext, hasPrev, loadNext, loadPrev } = usePaginatedList(fetch, {
15185
+ accumulate: grouped
15186
+ });
15127
15187
  useEffect(() => {
15128
15188
  onFacetsChange?.(facets);
15129
15189
  }, [onFacetsChange, facets]);
@@ -15167,6 +15227,22 @@ function ManifestResultsBody({
15167
15227
  }
15168
15228
  if (grouped) {
15169
15229
  const groups = deriveManifestGroups(rows);
15230
+ if (groups.length === 0) {
15231
+ return /* @__PURE__ */ jsx(
15232
+ ManifestTable,
15233
+ {
15234
+ rows,
15235
+ serverTime,
15236
+ showHead: true,
15237
+ indexOffset: 0,
15238
+ onOpen,
15239
+ onRemove,
15240
+ onShareLink,
15241
+ ...onOpenProfile !== void 0 ? { onOpenProfile } : {},
15242
+ ...RowComponent !== void 0 ? { RowComponent } : {}
15243
+ }
15244
+ );
15245
+ }
15170
15246
  let offset = 0;
15171
15247
  return /* @__PURE__ */ jsx("div", { className: "kf-trip-manifest-section__groups", children: groups.map((group) => {
15172
15248
  const indexOffset = offset;
@@ -15365,6 +15441,18 @@ var SECTION_LABEL_KEY = {
15365
15441
  forms: "chrome.tripManifest.section.forms"
15366
15442
  };
15367
15443
  var TTL_CHOICES = [null, 7, 30, 90];
15444
+ var FULL_DATE_OPTS = {
15445
+ day: "2-digit",
15446
+ month: "short",
15447
+ year: "numeric"
15448
+ };
15449
+ var SHARE_BASE_URL_KEY = "share.baseUrl.default";
15450
+ function shareAddress(baseUrl, token) {
15451
+ if (baseUrl === void 0 || baseUrl.trim().length === 0) {
15452
+ return token;
15453
+ }
15454
+ return `${baseUrl.replace(/\/+$/, "")}/${token}`;
15455
+ }
15368
15456
  function ShareLinkDialog({
15369
15457
  tripRef,
15370
15458
  travellerRef,
@@ -15373,9 +15461,13 @@ function ShareLinkDialog({
15373
15461
  }) {
15374
15462
  const { t } = useKaafilChrome();
15375
15463
  const titleId = useId();
15464
+ const shareBaseUrl = useResolvedSetting(SHARE_BASE_URL_KEY);
15376
15465
  const isFamily = travellerRef === null;
15377
15466
  const offerable = familySafeSections(isFamily);
15378
- const { links, readFailed, mint, revoke, regenerate } = useShareLinks(tripRef, travellerRef);
15467
+ const { links, readFailed, mint, revoke, regenerate, reveal } = useShareLinks(
15468
+ tripRef,
15469
+ travellerRef
15470
+ );
15379
15471
  const [useAgencyDefault, setUseAgencyDefault] = useState(true);
15380
15472
  const [chosen, setChosen] = useState(/* @__PURE__ */ new Set());
15381
15473
  const [ttlDays, setTtlDays] = useState(null);
@@ -15383,6 +15475,19 @@ function ShareLinkDialog({
15383
15475
  const [pending, setPending] = useState(false);
15384
15476
  const [errorCode, setErrorCode] = useState(void 0);
15385
15477
  const [copied, setCopied] = useState(false);
15478
+ const [confirmingRevokeId, setConfirmingRevokeId] = useState(null);
15479
+ const [revealed, setRevealed] = useState({});
15480
+ async function showLink(id) {
15481
+ setRevealed((previous) => ({ ...previous, [id]: "pending" }));
15482
+ setErrorCode(void 0);
15483
+ try {
15484
+ const token = await reveal(id);
15485
+ setRevealed((previous) => ({ ...previous, [id]: token ?? "unrecoverable" }));
15486
+ } catch {
15487
+ setRevealed((previous) => ({ ...previous, [id]: void 0 }));
15488
+ setErrorCode("unknown");
15489
+ }
15490
+ }
15386
15491
  function toggle(key) {
15387
15492
  const next = new Set(chosen);
15388
15493
  if (next.has(key)) next.delete(key);
@@ -15447,7 +15552,11 @@ function ShareLinkDialog({
15447
15552
  ...useAgencyDefault ? {} : { sections: fullSections() },
15448
15553
  ...ttlDays !== null ? { ttlDays } : {}
15449
15554
  });
15450
- return { token: response.token, id: response.id };
15555
+ return {
15556
+ token: response.token,
15557
+ id: response.id,
15558
+ expiresAt: response.expiresAt
15559
+ };
15451
15560
  }),
15452
15561
  children: pending ? t("chrome.tripManifest.minting") : t(
15453
15562
  hasLiveLink ? "chrome.tripManifest.mintAnotherLink" : "chrome.tripManifest.mintLink"
@@ -15463,7 +15572,7 @@ function ShareLinkDialog({
15463
15572
  {
15464
15573
  readOnly: true,
15465
15574
  className: "kf-trip-manifest-section__minted-token",
15466
- value: minted.token,
15575
+ value: shareAddress(shareBaseUrl, minted.token),
15467
15576
  "aria-label": t("chrome.tripManifest.mintedTokenLabel"),
15468
15577
  onFocus: (event) => event.currentTarget.select()
15469
15578
  }
@@ -15473,10 +15582,14 @@ function ShareLinkDialog({
15473
15582
  {
15474
15583
  type: "button",
15475
15584
  className: "kf-trip-manifest-section__dialog-secondary",
15476
- onClick: () => void copy(minted.token),
15585
+ onClick: () => void copy(shareAddress(shareBaseUrl, minted.token)),
15477
15586
  children: copied ? t("chrome.tripManifest.copied") : t("chrome.tripManifest.copy")
15478
15587
  }
15479
- )
15588
+ ),
15589
+ minted.expiresAt === null ? null : /* @__PURE__ */ jsx("p", { className: "kf-trip-manifest-section__dialog-note", children: t("chrome.tripManifest.mintedExpiresAt").replace(
15590
+ "{date}",
15591
+ formatDay(minted.expiresAt, FULL_DATE_OPTS)
15592
+ ) })
15480
15593
  ] }),
15481
15594
  /* @__PURE__ */ jsxs("fieldset", { className: "kf-trip-manifest-section__share-fieldset", children: [
15482
15595
  /* @__PURE__ */ jsx("legend", { className: "kf-trip-manifest-section__share-legend", children: t("chrome.tripManifest.sectionsLegend") }),
@@ -15533,37 +15646,107 @@ function ShareLinkDialog({
15533
15646
  /* @__PURE__ */ jsx(StatusPill, { tone: link.status === "ACTIVE" ? "pos" : "mute", children: t(
15534
15647
  link.status === "ACTIVE" ? "chrome.tripManifest.linkActive" : "chrome.tripManifest.linkDead"
15535
15648
  ) }),
15536
- /* @__PURE__ */ jsx("span", { className: "kf-trip-manifest-section__link-meta", children: link.travellerId === null ? t("chrome.tripManifest.linkFamily") : t("chrome.tripManifest.linkTraveller") })
15649
+ /* @__PURE__ */ jsxs("span", { className: "kf-trip-manifest-section__link-meta", children: [
15650
+ link.travellerId === null ? t("chrome.tripManifest.linkFamily") : t("chrome.tripManifest.linkTraveller"),
15651
+ link.expiresAt === null ? null : ` \xB7 ${t("chrome.tripManifest.linkExpires").replace(
15652
+ "{date}",
15653
+ formatDay(link.expiresAt, FULL_DATE_OPTS)
15654
+ )}`
15655
+ ] })
15537
15656
  ] }),
15538
- /* @__PURE__ */ jsxs("span", { className: "kf-trip-manifest-section__link-actions", children: [
15657
+ confirmingRevokeId === link.id ? /* @__PURE__ */ jsxs("span", { className: "kf-trip-manifest-section__link-actions", role: "group", children: [
15658
+ /* @__PURE__ */ jsx("span", { className: "kf-trip-manifest-section__link-confirm-prompt", children: t("chrome.tripManifest.revokeConfirm") }),
15539
15659
  /* @__PURE__ */ jsx(
15540
15660
  "button",
15541
15661
  {
15542
15662
  type: "button",
15543
- className: "kf-trip-manifest-section__link-action",
15663
+ className: "kf-trip-manifest-section__link-action-button",
15544
15664
  disabled: pending,
15545
- onClick: () => void run(async () => {
15546
- const response = await regenerate(link.id);
15547
- return { token: response.token, id: response.id };
15548
- }),
15549
- children: t("chrome.tripManifest.regenerate")
15665
+ onClick: () => setConfirmingRevokeId(null),
15666
+ children: t("chrome.tripManifest.revokeKeep")
15550
15667
  }
15551
15668
  ),
15552
15669
  /* @__PURE__ */ jsx(
15553
15670
  "button",
15554
15671
  {
15555
15672
  type: "button",
15556
- className: "kf-trip-manifest-section__link-action",
15673
+ className: "kf-trip-manifest-section__link-action-button",
15557
15674
  "data-tone": "danger",
15558
15675
  disabled: pending,
15559
15676
  onClick: () => {
15677
+ setConfirmingRevokeId(null);
15560
15678
  setErrorCode(void 0);
15561
15679
  void revoke(link.id).catch(() => setErrorCode("unknown"));
15562
15680
  },
15681
+ children: t("chrome.tripManifest.revokeNow")
15682
+ }
15683
+ )
15684
+ ] }) : /* @__PURE__ */ jsxs("span", { className: "kf-trip-manifest-section__link-actions", children: [
15685
+ /* @__PURE__ */ jsx(
15686
+ "button",
15687
+ {
15688
+ type: "button",
15689
+ className: "kf-trip-manifest-section__link-action-button",
15690
+ disabled: pending || revealed[link.id] === "pending",
15691
+ onClick: () => void showLink(link.id),
15692
+ children: revealed[link.id] === "pending" ? t("chrome.tripManifest.revealing") : t("chrome.tripManifest.showLink")
15693
+ }
15694
+ ),
15695
+ /* @__PURE__ */ jsx(
15696
+ "button",
15697
+ {
15698
+ type: "button",
15699
+ className: "kf-trip-manifest-section__link-action-button",
15700
+ disabled: pending,
15701
+ onClick: () => void run(async () => {
15702
+ const response = await regenerate(link.id);
15703
+ return {
15704
+ token: response.token,
15705
+ id: response.id,
15706
+ expiresAt: response.expiresAt
15707
+ };
15708
+ }),
15709
+ children: t("chrome.tripManifest.regenerate")
15710
+ }
15711
+ ),
15712
+ /* @__PURE__ */ jsx(
15713
+ "button",
15714
+ {
15715
+ type: "button",
15716
+ className: "kf-trip-manifest-section__link-action-button",
15717
+ "data-tone": "danger",
15718
+ disabled: pending,
15719
+ onClick: () => setConfirmingRevokeId(link.id),
15563
15720
  children: t("chrome.tripManifest.revoke")
15564
15721
  }
15565
15722
  )
15566
- ] })
15723
+ ] }),
15724
+ revealed[link.id] === void 0 || revealed[link.id] === "pending" ? null : /* @__PURE__ */ jsx("span", { className: "kf-trip-manifest-section__link-revealed", children: revealed[link.id] === "unrecoverable" ? (
15725
+ // NOT an error. This link works; it simply predates
15726
+ // Kaafil keeping a copy it can read back, so Replace
15727
+ // is the only route to an address they can send.
15728
+ /* @__PURE__ */ jsx("span", { className: "kf-trip-manifest-section__dialog-note", children: t("chrome.tripManifest.linkNotRecoverable") })
15729
+ ) : /* @__PURE__ */ jsxs(Fragment, { children: [
15730
+ /* @__PURE__ */ jsx(
15731
+ "input",
15732
+ {
15733
+ readOnly: true,
15734
+ className: "kf-trip-manifest-section__minted-token",
15735
+ value: shareAddress(shareBaseUrl, String(revealed[link.id])),
15736
+ "aria-label": t("chrome.tripManifest.mintedTokenLabel"),
15737
+ onFocus: (event) => event.currentTarget.select()
15738
+ }
15739
+ ),
15740
+ /* @__PURE__ */ jsx(
15741
+ "button",
15742
+ {
15743
+ type: "button",
15744
+ className: "kf-trip-manifest-section__link-action-button",
15745
+ onClick: () => void copy(shareAddress(shareBaseUrl, String(revealed[link.id]))),
15746
+ children: copied ? t("chrome.tripManifest.copied") : t("chrome.tripManifest.copy")
15747
+ }
15748
+ )
15749
+ ] }) })
15567
15750
  ] }, link.id)) })
15568
15751
  ] })
15569
15752
  ] }),
@@ -19336,7 +19519,7 @@ function TripRoomingSection({
19336
19519
  group,
19337
19520
  expanded: openWindowId === group.window.id,
19338
19521
  unassigned: pool === void 0 ? [] : pool.travellers,
19339
- unassignedLoaded: pool !== void 0 && pool.loaded,
19522
+ unassignedLoaded: pool?.loaded === true,
19340
19523
  drag,
19341
19524
  busy,
19342
19525
  onToggle: () => setOpenWindowId((current) => current === group.window.id ? null : group.window.id),
@@ -21370,7 +21553,7 @@ function VehicleFormDialog({
21370
21553
  const capacityValue = Number(capacity);
21371
21554
  const capacityOk = Number.isInteger(capacityValue) && capacityValue >= 1 && capacityValue <= MAX_CAPACITY2;
21372
21555
  const occupiedBeyond = vehicle === null || !vehicle.seatMapped || !capacityOk ? 0 : vehicle.seats.filter((seat, index) => seat.occupant !== null && index >= capacityValue).length;
21373
- const dropsSeatMap = vehicle !== null && vehicle.seatMapped && layout === null;
21556
+ const dropsSeatMap = vehicle?.seatMapped === true && layout === null;
21374
21557
  const seatedCount = vehicle === null || !vehicle.seatMapped ? 0 : vehicle.seats.filter((seat) => seat.occupant !== null).length;
21375
21558
  const canSubmit = trimmedReg.length >= 1 && capacityOk && !pending;
21376
21559
  const emptyToNull = (value) => {
@@ -22867,14 +23050,13 @@ function resolveTripTabs(eventType, capabilityStatuses) {
22867
23050
  if (TAB_BLOCKER[key] === "deferred") continue;
22868
23051
  const capability = TAB_CAPABILITY[key];
22869
23052
  if (capability === null) {
22870
- tabs.push({ key, lit: true, blocker: TAB_BLOCKER[key] });
23053
+ tabs.push({ key, blocker: TAB_BLOCKER[key] });
22871
23054
  continue;
22872
23055
  }
22873
23056
  const status = capabilityStatuses.get(capability);
22874
23057
  if (status === "mode-dark") continue;
22875
23058
  tabs.push({
22876
23059
  key,
22877
- lit: status === "lit",
22878
23060
  // A tab that is off for a capability reason reports THAT, not the
22879
23061
  // build-state blocker — the capability is the operative truth, and it
22880
23062
  // is the one the operator can act on (upgrade the plan, push the rows).
@@ -22922,17 +23104,13 @@ function TripTabRail({ tabs, activeKey, onSelect }) {
22922
23104
  "aria-label": t("chrome.tripWorkspace.tabRailLegend"),
22923
23105
  children: tabs.map((tab) => {
22924
23106
  const isActive = tab.key === activeKey;
22925
- const isDark = !tab.lit;
22926
23107
  return /* @__PURE__ */ jsx(
22927
23108
  "button",
22928
23109
  {
22929
23110
  type: "button",
22930
23111
  role: "tab",
22931
23112
  "aria-selected": isActive,
22932
- disabled: isDark,
22933
23113
  "data-active": isActive ? "true" : void 0,
22934
- "data-dark": isDark ? "true" : void 0,
22935
- title: isDark ? t("chrome.tripWorkspace.tabUnavailable") : void 0,
22936
23114
  onClick: () => onSelect(tab.key),
22937
23115
  className: "kf-trip-workspace__tab",
22938
23116
  children: /* @__PURE__ */ jsx("span", { children: t(TAB_LABEL_KEY[tab.key]) })
@@ -23053,11 +23231,11 @@ function TripWorkspaceBody({
23053
23231
  const Head = components?.TripWorkspaceHead ?? TripWorkspaceHead;
23054
23232
  const tabs = useMemo(() => resolveTripTabs(trip.eventType, statuses), [trip.eventType, statuses]);
23055
23233
  const [requestedTab, setRequestedTab] = useState(initialTab ?? "overview");
23056
- const activeTab = tabs.some((tab) => tab.key === requestedTab && tab.lit) ? requestedTab : "overview";
23234
+ const activeTab = tabs.some((tab) => tab.key === requestedTab) ? requestedTab : "overview";
23057
23235
  const activeResolved = tabs.find((tab) => tab.key === activeTab);
23058
23236
  const kpis = useMemo(() => deriveTripKpis(trip), [trip]);
23059
23237
  const litTabs = useMemo(
23060
- () => new Set(tabs.filter((tab) => tab.lit).map((tab) => tab.key)),
23238
+ () => new Set(tabs.filter((tab) => tab.blocker === null).map((tab) => tab.key)),
23061
23239
  [tabs]
23062
23240
  );
23063
23241
  const panelRegistry = useMemo(