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
@@ -1,5 +1,5 @@
1
- import { OfflineEngineContext, KaafilClientContext, useCapabilityRows, UNKNOWN_CAPABILITY_TRIPLE, deriveCapabilityTriple, darkReasonFor, useKaafilClient, useOfflineMutation, usePersona, isDevelopment, useOfflineEvent } from './chunk-A4Z2YBEF.js';
2
- import { UnsatisfiableSchemeError, isKaafilError, SyncOpMethod } from 'kaafil-js/client';
1
+ import { OfflineEngineContext, KaafilClientContext, useCapabilityRows, UNKNOWN_CAPABILITY_TRIPLE, deriveCapabilityTriple, darkReasonFor, useKaafilClient, useOfflineMutation, usePersona, isDevelopment, useOfflineEvent } from './chunk-7G6IENKN.js';
2
+ import { UnsatisfiableSchemeError, isKaafilError, SyncOpMethod, normalizeDateTimeInput } from 'kaafil-js/client';
3
3
  export { FALLBACK_GLYPH, SHADES_PER_FAMILY, TONE_FAMILIES, parseRoomingTone, roomingHeuristicSeverity } from 'kaafil-js/client';
4
4
  import { useContext, useState, useRef, useCallback, useEffect } from 'react';
5
5
 
@@ -176,6 +176,43 @@ function createDomainHook(moduleKey, build) {
176
176
  }
177
177
 
178
178
  // src/core/hooks/useChecklists.ts
179
+ function optimisticChecklistItem(input, sections, fetchedAt) {
180
+ return {
181
+ // Replaced by the id the engine mints — this hook never invents identity.
182
+ id: "pending",
183
+ // Cannot beat any server row in the snapshot's version-guarded merge.
184
+ version: 0,
185
+ // The write addresses a section by KEY; the board groups rows by ID. An
186
+ // unknown section leaves the row ungrouped rather than filing it under a
187
+ // heading that does not exist.
188
+ sectionId: sections.find((section) => section.key === input.sectionKey)?.id ?? "",
189
+ // The server derives the key from the title when one is not sent. Blank
190
+ // rather than a guessed slug: a key that disagrees with the server's is
191
+ // worse than an obviously-absent one, and nothing renders it.
192
+ key: input.key ?? "",
193
+ title: input.title,
194
+ subLine: null,
195
+ status: "OPEN",
196
+ // `=== true`, never `?? false` (hard rule #5): an omitted `mandatory` is
197
+ // the SERVER's default to apply, not this hook's to guess.
198
+ isMandatory: input.mandatory === true,
199
+ // `'NONE'`, never null. The add request carries no `gate` at all — the
200
+ // engine derives it from `phase` — and `'NONE'` is the one value that
201
+ // cannot make a pending item look like it is blocking the trip.
202
+ gate: "NONE",
203
+ dayOffset: null,
204
+ // Appended. The server's own ordering arrives with the canonical row.
205
+ sortOrder: Number.MAX_SAFE_INTEGER,
206
+ completedByManagerId: null,
207
+ performedByKind: null,
208
+ performedById: null,
209
+ completedAt: null,
210
+ // The last reading the SERVER gave this hook, never a device clock (hard
211
+ // rule #6). Blank when nothing has been fetched yet, which is the only
212
+ // honest answer and which the board already prefers `fetchedAt` over.
213
+ updatedAt: fetchedAt ?? ""
214
+ };
215
+ }
179
216
  function appendPendingRows(fromAggregate, fromSnapshot) {
180
217
  if (fromSnapshot.length === 0) {
181
218
  return fromAggregate;
@@ -283,28 +320,7 @@ var useChecklistsInternal = createDomainHook("checklists", (tripRef) => {
283
320
  // yet resolves to `''` and the row sits ungrouped until the write
284
321
  // lands — correct rather than clever: inventing a section id would
285
322
  // put the item under a heading that does not exist.
286
- optimistic: {
287
- id: "pending",
288
- version: 0,
289
- sectionId: aggregate.sections.find((section) => section.key === input.sectionKey)?.id ?? "",
290
- key: input.key ?? null,
291
- title: input.title,
292
- subLine: null,
293
- status: "OPEN",
294
- // `=== true`, never `?? false` (hard rule #5): an omitted
295
- // `mandatory` is the SERVER's default to apply, not this hook's to
296
- // guess. The optimistic row shows it unstarred for the moment it
297
- // takes the write to land, and the canonical row replaces it.
298
- isMandatory: input.mandatory === true,
299
- gate: null,
300
- dayOffset: null,
301
- sortOrder: Number.MAX_SAFE_INTEGER,
302
- completedByManagerId: null,
303
- performedByKind: null,
304
- performedById: null,
305
- completedAt: null,
306
- updatedAt: null
307
- }
323
+ optimistic: optimisticChecklistItem(input, aggregate.sections, aggregate.fetchedAt)
308
324
  }),
309
325
  // ── THE DESK LANE ─────────────────────────────────────────────────
310
326
  // All five checklist writes take the admin triple, and a desk console
@@ -539,6 +555,34 @@ var useCloseoutInternal = createDomainHook("closing-day", (tripRef) => {
539
555
  function useCloseout(tripRef) {
540
556
  return useCloseoutInternal(tripRef);
541
557
  }
558
+ function optimisticCollection(input, syncedAt) {
559
+ const collectedAt = input.collectedAt === void 0 ? "" : normalizeDateTimeInput(input.collectedAt, "collectedAt");
560
+ return {
561
+ // Replaced by the id the engine mints.
562
+ id: "pending",
563
+ version: 0,
564
+ travellerId: input.travellerId,
565
+ amountMinor: input.amountMinor,
566
+ // The request's own default, restated: this tenant's money unit.
567
+ currency: input.currency ?? "INR",
568
+ mode: input.mode,
569
+ reference: input.reference ?? null,
570
+ note: input.note ?? null,
571
+ collectedByManagerId: null,
572
+ performedByKind: null,
573
+ performedById: null,
574
+ collectedAt,
575
+ reportedAt: null,
576
+ voidedAt: null,
577
+ voidReason: null,
578
+ // The server's arithmetic, deliberately not guessed — see above.
579
+ outstandingMinor: null,
580
+ // The last reading the SERVER gave this list, never a device clock
581
+ // (hard rule #6).
582
+ createdAt: syncedAt ?? "",
583
+ updatedAt: syncedAt ?? ""
584
+ };
585
+ }
542
586
  var useCollectionsInternal = createDomainHook("collections", (tripRef) => {
543
587
  const client = useKaafilClient();
544
588
  const {
@@ -588,7 +632,12 @@ var useCollectionsInternal = createDomainHook("collections", (tripRef) => {
588
632
  // hardcoded literal, verified against
589
633
  // `kaafil-js/src/generated/security.ts` this session.
590
634
  operationId: "recordCollection",
591
- body: input
635
+ body: input,
636
+ // A payment recorded out of signal appears at once — see
637
+ // `optimisticCollection` for what it deliberately does not claim.
638
+ creates: true,
639
+ entity: { listName: "collections" },
640
+ optimistic: optimisticCollection(input, syncedAt)
592
641
  }),
593
642
  // The desk lane. `recordCollection` takes the admin triple, and a desk
594
643
  // console mounts no `OfflineShell` — without this the write has no
@@ -677,9 +726,19 @@ var useExpensesInternal = createDomainHook("expenses", (tripRef) => {
677
726
  useEffect(() => {
678
727
  void refreshTotals();
679
728
  }, [refreshTotals]);
729
+ const engine = useContext(OfflineEngineContext);
730
+ useEffect(() => {
731
+ if (engine === null) {
732
+ return;
733
+ }
734
+ const unsubscribe = engine.events.on("sync.drained", () => {
735
+ void refreshTotals();
736
+ });
737
+ return unsubscribe;
738
+ }, [engine, refreshTotals]);
680
739
  const logMutation = useOfflineMutation({
681
740
  tripRef,
682
- enqueue: (engine, input) => engine.enqueue({
741
+ enqueue: (engine2, input) => engine2.enqueue({
683
742
  tripRef,
684
743
  method: SyncOpMethod.Post,
685
744
  path: `/api/v1/trips/${tripRef}/expenses`,
@@ -700,9 +759,9 @@ var useExpensesInternal = createDomainHook("expenses", (tripRef) => {
700
759
  });
701
760
  const linkReceiptMutation = useOfflineMutation({
702
761
  tripRef,
703
- enqueue: (engine, input) => {
762
+ enqueue: (engine2, input) => {
704
763
  const { expenseId, ...body } = input;
705
- return engine.enqueue({
764
+ return engine2.enqueue({
706
765
  tripRef,
707
766
  method: SyncOpMethod.Patch,
708
767
  path: `/api/v1/trips/${tripRef}/expenses/${expenseId}/receipt`,
@@ -723,9 +782,9 @@ var useExpensesInternal = createDomainHook("expenses", (tripRef) => {
723
782
  });
724
783
  const voidMutation = useOfflineMutation({
725
784
  tripRef,
726
- enqueue: (engine, input) => {
785
+ enqueue: (engine2, input) => {
727
786
  const { expenseId, version, ...body } = input;
728
- return engine.enqueue({
787
+ return engine2.enqueue({
729
788
  tripRef,
730
789
  method: SyncOpMethod.Delete,
731
790
  path: `/api/v1/trips/${tripRef}/expenses/${expenseId}/void`,
@@ -738,9 +797,9 @@ var useExpensesInternal = createDomainHook("expenses", (tripRef) => {
738
797
  });
739
798
  const submitClaimMutation = useOfflineMutation({
740
799
  tripRef,
741
- enqueue: (engine, input) => {
800
+ enqueue: (engine2, input) => {
742
801
  const { expenseId } = input;
743
- return engine.enqueue({
802
+ return engine2.enqueue({
744
803
  tripRef,
745
804
  method: SyncOpMethod.Post,
746
805
  path: `/api/v1/trips/${tripRef}/expenses/${expenseId}/claim`,
@@ -751,9 +810,9 @@ var useExpensesInternal = createDomainHook("expenses", (tripRef) => {
751
810
  });
752
811
  const withdrawClaimMutation = useOfflineMutation({
753
812
  tripRef,
754
- enqueue: (engine, input) => {
813
+ enqueue: (engine2, input) => {
755
814
  const { expenseId, version } = input;
756
- return engine.enqueue({
815
+ return engine2.enqueue({
757
816
  tripRef,
758
817
  method: SyncOpMethod.Delete,
759
818
  path: `/api/v1/trips/${tripRef}/expenses/${expenseId}/claim/withdraw`,
@@ -1220,6 +1279,16 @@ function useItinerary(tripRef) {
1220
1279
  useEffect(() => {
1221
1280
  void refresh();
1222
1281
  }, [refresh]);
1282
+ const engine = useContext(OfflineEngineContext);
1283
+ const refreshAfterDrain = useCallback(() => {
1284
+ if (engine === null) {
1285
+ return;
1286
+ }
1287
+ const unsubscribe = engine.events.on("sync.drained", () => {
1288
+ unsubscribe();
1289
+ void refresh();
1290
+ });
1291
+ }, [engine, refresh]);
1223
1292
  const [changeLog, setChangeLog] = useState([]);
1224
1293
  const [changeLogLoaded, setChangeLogLoaded] = useState(false);
1225
1294
  const [changeLogFetchFailed, setChangeLogFetchFailed] = useState(false);
@@ -1238,9 +1307,9 @@ function useItinerary(tripRef) {
1238
1307
  );
1239
1308
  const patchDayMutation = useOfflineMutation({
1240
1309
  tripRef,
1241
- enqueue: (engine, input) => {
1310
+ enqueue: (engine2, input) => {
1242
1311
  const { dayIndex, version, ...body } = input;
1243
- return engine.enqueue({
1312
+ return engine2.enqueue({
1244
1313
  tripRef,
1245
1314
  method: SyncOpMethod.Patch,
1246
1315
  path: `/api/v1/trips/${tripRef}/itinerary/days/${dayIndex}`,
@@ -1256,13 +1325,14 @@ function useItinerary(tripRef) {
1256
1325
  async (input) => {
1257
1326
  const op = await patchDayMutate(input);
1258
1327
  void refresh();
1328
+ refreshAfterDrain();
1259
1329
  return op;
1260
1330
  },
1261
- [patchDayMutate, refresh]
1331
+ [patchDayMutate, refresh, refreshAfterDrain]
1262
1332
  );
1263
1333
  const addItemMutation = useOfflineMutation({
1264
1334
  tripRef,
1265
- enqueue: (engine, input) => engine.enqueue({
1335
+ enqueue: (engine2, input) => engine2.enqueue({
1266
1336
  tripRef,
1267
1337
  method: SyncOpMethod.Post,
1268
1338
  path: `/api/v1/trips/${tripRef}/itinerary/items`,
@@ -1276,15 +1346,16 @@ function useItinerary(tripRef) {
1276
1346
  async (input) => {
1277
1347
  const op = await addItemMutate(input);
1278
1348
  void refresh();
1349
+ refreshAfterDrain();
1279
1350
  return op;
1280
1351
  },
1281
- [addItemMutate, refresh]
1352
+ [addItemMutate, refresh, refreshAfterDrain]
1282
1353
  );
1283
1354
  const patchItemMutation = useOfflineMutation({
1284
1355
  tripRef,
1285
- enqueue: (engine, input) => {
1356
+ enqueue: (engine2, input) => {
1286
1357
  const { itemId, version, ...body } = input;
1287
- return engine.enqueue({
1358
+ return engine2.enqueue({
1288
1359
  tripRef,
1289
1360
  method: SyncOpMethod.Patch,
1290
1361
  path: `/api/v1/trips/${tripRef}/itinerary/items/${itemId}`,
@@ -1300,15 +1371,16 @@ function useItinerary(tripRef) {
1300
1371
  async (input) => {
1301
1372
  const op = await patchItemMutate(input);
1302
1373
  void refresh();
1374
+ refreshAfterDrain();
1303
1375
  return op;
1304
1376
  },
1305
- [patchItemMutate, refresh]
1377
+ [patchItemMutate, refresh, refreshAfterDrain]
1306
1378
  );
1307
1379
  const removeItemMutation = useOfflineMutation({
1308
1380
  tripRef,
1309
- enqueue: (engine, input) => {
1381
+ enqueue: (engine2, input) => {
1310
1382
  const { itemId, version } = input;
1311
- return engine.enqueue({
1383
+ return engine2.enqueue({
1312
1384
  tripRef,
1313
1385
  method: SyncOpMethod.Delete,
1314
1386
  path: `/api/v1/trips/${tripRef}/itinerary/items/${itemId}`,
@@ -1323,15 +1395,16 @@ function useItinerary(tripRef) {
1323
1395
  async (input) => {
1324
1396
  const op = await removeItemMutate(input);
1325
1397
  void refresh();
1398
+ refreshAfterDrain();
1326
1399
  return op;
1327
1400
  },
1328
- [removeItemMutate, refresh]
1401
+ [removeItemMutate, refresh, refreshAfterDrain]
1329
1402
  );
1330
1403
  const reorderItemMutation = useOfflineMutation({
1331
1404
  tripRef,
1332
- enqueue: (engine, input) => {
1405
+ enqueue: (engine2, input) => {
1333
1406
  const { itemId, ...body } = input;
1334
- return engine.enqueue({
1407
+ return engine2.enqueue({
1335
1408
  tripRef,
1336
1409
  method: SyncOpMethod.Post,
1337
1410
  path: `/api/v1/trips/${tripRef}/itinerary/items/${itemId}/reorder`,
@@ -1346,9 +1419,10 @@ function useItinerary(tripRef) {
1346
1419
  async (input) => {
1347
1420
  const op = await reorderItemMutate(input);
1348
1421
  void refresh();
1422
+ refreshAfterDrain();
1349
1423
  return op;
1350
1424
  },
1351
- [reorderItemMutate, refresh]
1425
+ [reorderItemMutate, refresh, refreshAfterDrain]
1352
1426
  );
1353
1427
  if (!loaded && !lastFetchFailed) {
1354
1428
  return { status: "loading" };
@@ -1576,6 +1650,34 @@ function useParties(tripRef) {
1576
1650
  remove
1577
1651
  };
1578
1652
  }
1653
+ function optimisticPickupStop(input, syncedAt) {
1654
+ return {
1655
+ // Replaced by the id the engine mints.
1656
+ id: "pending",
1657
+ version: 0,
1658
+ // The request's own default, restated rather than guessed: the SDK's
1659
+ // `kind` is optional and the engine treats an absent one as a pickup.
1660
+ kind: input.kind ?? "PICKUP",
1661
+ name: input.name,
1662
+ locationLabel: input.locationLabel ?? null,
1663
+ lat: input.lat ?? null,
1664
+ lng: input.lng ?? null,
1665
+ scheduledTime: normalizeDateTimeInput(input.scheduledTime, "scheduledTime"),
1666
+ // Appended; the server's ordering arrives with the canonical row.
1667
+ sortOrder: input.sortOrder ?? Number.MAX_SAFE_INTEGER,
1668
+ status: "OPEN",
1669
+ closedAt: null,
1670
+ closedByManagerId: null,
1671
+ performedByKind: null,
1672
+ performedById: null,
1673
+ rollup: "not_started",
1674
+ boardedCount: 0,
1675
+ expectedCount: 0,
1676
+ // The last reading the SERVER gave this list, never a device clock
1677
+ // (hard rule #6).
1678
+ updatedAt: syncedAt ?? ""
1679
+ };
1680
+ }
1579
1681
  var usePickupsInternal = createDomainHook("pickup-points", (tripRef) => {
1580
1682
  const client = useKaafilClient();
1581
1683
  const {
@@ -1599,7 +1701,14 @@ var usePickupsInternal = createDomainHook("pickup-points", (tripRef) => {
1599
1701
  // literal below is checked against `kaafil-js/src/generated/
1600
1702
  // security.ts`'s own operation-id table.
1601
1703
  operationId: "createPickupStop",
1602
- body: input
1704
+ body: input,
1705
+ // A stop added out of signal appears at once, keyed on an id the
1706
+ // ENGINE mints and swapped for the server's row when the write lands
1707
+ // — see `optimisticPickupStop` for why every field here is one the
1708
+ // client can honestly know.
1709
+ creates: true,
1710
+ entity: { listName: "pickups" },
1711
+ optimistic: optimisticPickupStop(input, syncedAt)
1603
1712
  }),
1604
1713
  // The desk lane. `board`, `close` and `reopen` below deliberately get
1605
1714
  // NONE — they are `managerAuth`-only on the wire, so a direct call from
@@ -1745,6 +1854,24 @@ var usePickupsInternal = createDomainHook("pickup-points", (tripRef) => {
1745
1854
  function usePickups(tripRef) {
1746
1855
  return usePickupsInternal(tripRef);
1747
1856
  }
1857
+ function optimisticStayWindow(input, syncedAt) {
1858
+ return {
1859
+ // Replaced by the id the engine mints.
1860
+ id: "pending",
1861
+ version: 0,
1862
+ label: input.label,
1863
+ startDate: normalizeDateTimeInput(input.startDate, "startDate"),
1864
+ endDate: normalizeDateTimeInput(input.endDate, "endDate"),
1865
+ // Appended; the server's ordering arrives with the canonical row.
1866
+ sortOrder: input.sortOrder ?? Number.MAX_SAFE_INTEGER,
1867
+ // A window created by hand has no CRM segment behind it. This is a fact
1868
+ // about the write, not a placeholder.
1869
+ sourceSegmentRef: null,
1870
+ sourceUpdatedAt: null,
1871
+ // The last reading the SERVER gave this list, never a device clock.
1872
+ updatedAt: syncedAt ?? ""
1873
+ };
1874
+ }
1748
1875
  var useRoomingInternal = createDomainHook("rooming", (tripRef) => {
1749
1876
  const client = useKaafilClient();
1750
1877
  const {
@@ -1772,7 +1899,7 @@ var useRoomingInternal = createDomainHook("rooming", (tripRef) => {
1772
1899
  }, [refreshRoomsLive, refreshWindowsLive]);
1773
1900
  const assignMutation = useOfflineMutation({
1774
1901
  tripRef,
1775
- enqueue: (engine, input) => engine.enqueue({
1902
+ enqueue: (engine2, input) => engine2.enqueue({
1776
1903
  tripRef,
1777
1904
  method: SyncOpMethod.Post,
1778
1905
  path: `/api/v1/trips/${tripRef}/rooming/assign`,
@@ -1816,6 +1943,16 @@ var useRoomingInternal = createDomainHook("rooming", (tripRef) => {
1816
1943
  useEffect(() => {
1817
1944
  void refreshUnassignedPool();
1818
1945
  }, [refreshUnassignedPool]);
1946
+ const engine = useContext(OfflineEngineContext);
1947
+ useEffect(() => {
1948
+ if (engine === null) {
1949
+ return;
1950
+ }
1951
+ const unsubscribe = engine.events.on("sync.drained", () => {
1952
+ void refreshUnassignedPool(lastRequestedStayWindowIdRef.current);
1953
+ });
1954
+ return unsubscribe;
1955
+ }, [engine, refreshUnassignedPool]);
1819
1956
  const assignMutate = assignMutation.mutate;
1820
1957
  const assign = useCallback(
1821
1958
  async (input) => {
@@ -1827,20 +1964,27 @@ var useRoomingInternal = createDomainHook("rooming", (tripRef) => {
1827
1964
  );
1828
1965
  const createWindowMutation = useOfflineMutation({
1829
1966
  tripRef,
1830
- enqueue: (engine, input) => engine.enqueue({
1967
+ enqueue: (engine2, input) => engine2.enqueue({
1831
1968
  tripRef,
1832
1969
  method: SyncOpMethod.Post,
1833
1970
  path: `/api/v1/trips/${tripRef}/rooming/stay-windows`,
1834
1971
  operationId: "createRoomingStayWindow",
1835
- body: input
1972
+ body: input,
1973
+ // A window added out of signal appears at once. Every field of a
1974
+ // stay window is either given by the caller or genuinely absent —
1975
+ // which is exactly what `createRoom` below cannot say, and why only
1976
+ // this one of the two gets an optimistic row.
1977
+ creates: true,
1978
+ entity: { listName: "stayWindows" },
1979
+ optimistic: optimisticStayWindow(input, windowsSyncedAt)
1836
1980
  }),
1837
1981
  direct: (liveClient, input) => liveClient.rooming.stayWindows.create({ tripRef, ...input })
1838
1982
  });
1839
1983
  const patchWindowMutation = useOfflineMutation({
1840
1984
  tripRef,
1841
- enqueue: (engine, input) => {
1985
+ enqueue: (engine2, input) => {
1842
1986
  const { windowId, version, ...body } = input;
1843
- return engine.enqueue({
1987
+ return engine2.enqueue({
1844
1988
  tripRef,
1845
1989
  method: SyncOpMethod.Patch,
1846
1990
  path: `/api/v1/trips/${tripRef}/rooming/stay-windows/${windowId}`,
@@ -1853,10 +1997,10 @@ var useRoomingInternal = createDomainHook("rooming", (tripRef) => {
1853
1997
  });
1854
1998
  const removeWindowMutation = useOfflineMutation({
1855
1999
  tripRef,
1856
- enqueue: (engine, input) => {
2000
+ enqueue: (engine2, input) => {
1857
2001
  const { windowId, version, force } = input;
1858
2002
  const query = force === true ? "?force=true" : "";
1859
- return engine.enqueue({
2003
+ return engine2.enqueue({
1860
2004
  tripRef,
1861
2005
  method: SyncOpMethod.Delete,
1862
2006
  path: `/api/v1/trips/${tripRef}/rooming/stay-windows/${windowId}${query}`,
@@ -1868,7 +2012,7 @@ var useRoomingInternal = createDomainHook("rooming", (tripRef) => {
1868
2012
  });
1869
2013
  const createRoomMutation = useOfflineMutation({
1870
2014
  tripRef,
1871
- enqueue: (engine, input) => engine.enqueue({
2015
+ enqueue: (engine2, input) => engine2.enqueue({
1872
2016
  tripRef,
1873
2017
  method: SyncOpMethod.Post,
1874
2018
  path: `/api/v1/trips/${tripRef}/rooming/rooms`,
@@ -1879,9 +2023,9 @@ var useRoomingInternal = createDomainHook("rooming", (tripRef) => {
1879
2023
  });
1880
2024
  const patchRoomMutation = useOfflineMutation({
1881
2025
  tripRef,
1882
- enqueue: (engine, input) => {
2026
+ enqueue: (engine2, input) => {
1883
2027
  const { roomId, version, ...body } = input;
1884
- return engine.enqueue({
2028
+ return engine2.enqueue({
1885
2029
  tripRef,
1886
2030
  method: SyncOpMethod.Patch,
1887
2031
  path: `/api/v1/trips/${tripRef}/rooming/rooms/${roomId}`,
@@ -1894,10 +2038,10 @@ var useRoomingInternal = createDomainHook("rooming", (tripRef) => {
1894
2038
  });
1895
2039
  const removeRoomMutation = useOfflineMutation({
1896
2040
  tripRef,
1897
- enqueue: (engine, input) => {
2041
+ enqueue: (engine2, input) => {
1898
2042
  const { roomId, version, force } = input;
1899
2043
  const query = force === true ? "?force=true" : "";
1900
- return engine.enqueue({
2044
+ return engine2.enqueue({
1901
2045
  tripRef,
1902
2046
  method: SyncOpMethod.Delete,
1903
2047
  path: `/api/v1/trips/${tripRef}/rooming/rooms/${roomId}${query}`,
@@ -1951,7 +2095,7 @@ var useSeatingInternal = createDomainHook("transport-seating", (tripRef) => {
1951
2095
  });
1952
2096
  const assignMutation = useOfflineMutation({
1953
2097
  tripRef,
1954
- enqueue: (engine, input) => engine.enqueue({
2098
+ enqueue: (engine2, input) => engine2.enqueue({
1955
2099
  tripRef,
1956
2100
  method: SyncOpMethod.Post,
1957
2101
  path: `/api/v1/trips/${tripRef}/seating/assign`,
@@ -1988,6 +2132,16 @@ var useSeatingInternal = createDomainHook("transport-seating", (tripRef) => {
1988
2132
  useEffect(() => {
1989
2133
  void refreshUnassignedPool();
1990
2134
  }, [refreshUnassignedPool]);
2135
+ const engine = useContext(OfflineEngineContext);
2136
+ useEffect(() => {
2137
+ if (engine === null) {
2138
+ return;
2139
+ }
2140
+ const unsubscribe = engine.events.on("sync.drained", () => {
2141
+ void refreshUnassignedPool();
2142
+ });
2143
+ return unsubscribe;
2144
+ }, [engine, refreshUnassignedPool]);
1991
2145
  const assignMutate = assignMutation.mutate;
1992
2146
  const assign = useCallback(
1993
2147
  async (input) => {
@@ -1999,7 +2153,7 @@ var useSeatingInternal = createDomainHook("transport-seating", (tripRef) => {
1999
2153
  );
2000
2154
  const createVehicleMutation = useOfflineMutation({
2001
2155
  tripRef,
2002
- enqueue: (engine, input) => engine.enqueue({
2156
+ enqueue: (engine2, input) => engine2.enqueue({
2003
2157
  tripRef,
2004
2158
  method: SyncOpMethod.Post,
2005
2159
  path: `/api/v1/trips/${tripRef}/seating/vehicles`,
@@ -2010,9 +2164,9 @@ var useSeatingInternal = createDomainHook("transport-seating", (tripRef) => {
2010
2164
  });
2011
2165
  const patchVehicleMutation = useOfflineMutation({
2012
2166
  tripRef,
2013
- enqueue: (engine, input) => {
2167
+ enqueue: (engine2, input) => {
2014
2168
  const { vehicleId, version, ...body } = input;
2015
- return engine.enqueue({
2169
+ return engine2.enqueue({
2016
2170
  tripRef,
2017
2171
  method: SyncOpMethod.Patch,
2018
2172
  path: `/api/v1/trips/${tripRef}/seating/vehicles/${vehicleId}`,
@@ -2025,9 +2179,9 @@ var useSeatingInternal = createDomainHook("transport-seating", (tripRef) => {
2025
2179
  });
2026
2180
  const removeVehicleMutation = useOfflineMutation({
2027
2181
  tripRef,
2028
- enqueue: (engine, input) => {
2182
+ enqueue: (engine2, input) => {
2029
2183
  const { vehicleId, version } = input;
2030
- return engine.enqueue({
2184
+ return engine2.enqueue({
2031
2185
  tripRef,
2032
2186
  method: SyncOpMethod.Delete,
2033
2187
  path: `/api/v1/trips/${tripRef}/seating/vehicles/${vehicleId}`,
@@ -2067,9 +2221,9 @@ var useSeatingInternal = createDomainHook("transport-seating", (tripRef) => {
2067
2221
  );
2068
2222
  const linkManagerMutation = useOfflineMutation({
2069
2223
  tripRef,
2070
- enqueue: (engine, input) => {
2224
+ enqueue: (engine2, input) => {
2071
2225
  const { vehicleId, ...body } = input;
2072
- return engine.enqueue({
2226
+ return engine2.enqueue({
2073
2227
  tripRef,
2074
2228
  method: SyncOpMethod.Post,
2075
2229
  path: `/api/v1/trips/${tripRef}/seating/vehicles/${vehicleId}/manager`,
@@ -2081,9 +2235,9 @@ var useSeatingInternal = createDomainHook("transport-seating", (tripRef) => {
2081
2235
  });
2082
2236
  const unlinkManagerMutation = useOfflineMutation({
2083
2237
  tripRef,
2084
- enqueue: (engine, input) => {
2238
+ enqueue: (engine2, input) => {
2085
2239
  const { vehicleId, version } = input;
2086
- return engine.enqueue({
2240
+ return engine2.enqueue({
2087
2241
  tripRef,
2088
2242
  method: SyncOpMethod.Delete,
2089
2243
  path: `/api/v1/trips/${tripRef}/seating/vehicles/${vehicleId}/manager`,
@@ -2221,5 +2375,5 @@ function useVendors(tripRef, agencyRef) {
2221
2375
  }
2222
2376
 
2223
2377
  export { ERROR_HANDLING_PATH, FORM_FIELD_KIND_SINGLE_BOOLEAN, classifyError, createDomainHook, useChecklists, useCloseout, useCollections, useExpenses, useFiles, useFloat, useForms, useItinerary, useManagerToday, useManagers, useParties, usePickups, useRooming, useSeating, useSnapshotList, useTravellerProfile, useVendors };
2224
- //# sourceMappingURL=chunk-WTTGPWMR.js.map
2225
- //# sourceMappingURL=chunk-WTTGPWMR.js.map
2378
+ //# sourceMappingURL=chunk-WPQB7JWS.js.map
2379
+ //# sourceMappingURL=chunk-WPQB7JWS.js.map