kaafil-react-uikit 0.1.0-beta.1
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.
- package/CHANGELOG.md +70 -0
- package/LICENSE +21 -0
- package/README.md +187 -0
- package/dist/OfflineFallbackScreen-B5dfaJBN.d.ts +37 -0
- package/dist/OfflineFallbackScreen-Ctm7nBa-.d.cts +37 -0
- package/dist/SessionExpiredScreen-CytQNuak.d.cts +50 -0
- package/dist/SessionExpiredScreen-D8GHyZc3.d.ts +50 -0
- package/dist/admin/index.cjs +23779 -0
- package/dist/admin/index.cjs.map +1 -0
- package/dist/admin/index.d.cts +1157 -0
- package/dist/admin/index.d.ts +1157 -0
- package/dist/admin/index.js +23724 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/chunk-6FPAGGFL.js +6028 -0
- package/dist/chunk-6FPAGGFL.js.map +1 -0
- package/dist/chunk-ACVU55PZ.cjs +294 -0
- package/dist/chunk-ACVU55PZ.cjs.map +1 -0
- package/dist/chunk-EM7JV3D7.cjs +6051 -0
- package/dist/chunk-EM7JV3D7.cjs.map +1 -0
- package/dist/chunk-IIPQ4JNC.js +287 -0
- package/dist/chunk-IIPQ4JNC.js.map +1 -0
- package/dist/chunk-LL243STJ.cjs +2195 -0
- package/dist/chunk-LL243STJ.cjs.map +1 -0
- package/dist/chunk-PJRZCOFF.cjs +958 -0
- package/dist/chunk-PJRZCOFF.cjs.map +1 -0
- package/dist/chunk-PTQ2CJKE.cjs +40 -0
- package/dist/chunk-PTQ2CJKE.cjs.map +1 -0
- package/dist/chunk-PZKXLQSU.js +10 -0
- package/dist/chunk-PZKXLQSU.js.map +1 -0
- package/dist/chunk-QHUDOVKW.cjs +111 -0
- package/dist/chunk-QHUDOVKW.cjs.map +1 -0
- package/dist/chunk-TOBZFADB.cjs +12 -0
- package/dist/chunk-TOBZFADB.cjs.map +1 -0
- package/dist/chunk-UUGMNP27.js +936 -0
- package/dist/chunk-UUGMNP27.js.map +1 -0
- package/dist/chunk-UYJ6LIWP.js +2154 -0
- package/dist/chunk-UYJ6LIWP.js.map +1 -0
- package/dist/chunk-VHTSTUCJ.cjs +346 -0
- package/dist/chunk-VHTSTUCJ.cjs.map +1 -0
- package/dist/chunk-WUAFL77X.js +340 -0
- package/dist/chunk-WUAFL77X.js.map +1 -0
- package/dist/chunk-XI7MK4Y7.js +38 -0
- package/dist/chunk-XI7MK4Y7.js.map +1 -0
- package/dist/chunk-YDGR7JSY.js +107 -0
- package/dist/chunk-YDGR7JSY.js.map +1 -0
- package/dist/core/index.cjs +1254 -0
- package/dist/core/index.cjs.map +1 -0
- package/dist/core/index.d.cts +1267 -0
- package/dist/core/index.d.ts +1267 -0
- package/dist/core/index.js +995 -0
- package/dist/core/index.js.map +1 -0
- package/dist/index.css +1 -0
- package/dist/manager/index.cjs +13562 -0
- package/dist/manager/index.cjs.map +1 -0
- package/dist/manager/index.d.cts +1054 -0
- package/dist/manager/index.d.ts +1054 -0
- package/dist/manager/index.js +13518 -0
- package/dist/manager/index.js.map +1 -0
- package/dist/testing/index.cjs +221 -0
- package/dist/testing/index.cjs.map +1 -0
- package/dist/testing/index.d.cts +269 -0
- package/dist/testing/index.d.ts +269 -0
- package/dist/testing/index.js +208 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/tokenStyle-CToG5oOS.d.cts +3 -0
- package/dist/tokenStyle-CToG5oOS.d.ts +3 -0
- package/dist/traveller/index.cjs +1799 -0
- package/dist/traveller/index.cjs.map +1 -0
- package/dist/traveller/index.d.cts +58 -0
- package/dist/traveller/index.d.ts +58 -0
- package/dist/traveller/index.js +1789 -0
- package/dist/traveller/index.js.map +1 -0
- package/dist/useAgencyTrip-BUYSIaC2.d.cts +454 -0
- package/dist/useAgencyTrip-BzyJB1D9.d.ts +454 -0
- package/dist/useNotifications-BZW1Z_ur.d.cts +356 -0
- package/dist/useNotifications-D262i5BQ.d.ts +356 -0
- package/dist/useVendors-DXOuZWhZ.d.cts +784 -0
- package/dist/useVendors-DXOuZWhZ.d.ts +784 -0
- package/package.json +95 -0
|
@@ -0,0 +1,995 @@
|
|
|
1
|
+
export { useConflicts, useManagerMe, useNotifications } from '../chunk-YDGR7JSY.js';
|
|
2
|
+
export { CLOSEOUT_ACTION_TAB, fromSearchParams, isTripTabKey, resolveBlockerDeepLink, toSearchParams, useAgencyAdminMe, useAgencyChecklistTemplates, useAgencyForms, useAgencyJourneyTriggers, useAgencyManagerProfile, useAgencySettings, useAgencyTrip, useAgencyTripManifest, useAgencyTrips, useBookings, useCapabilityStatuses, useDirectories, usePaginatedList, useShareLinks, useTravellerFormResponses } from '../chunk-UUGMNP27.js';
|
|
3
|
+
import { createDomainHook, useSnapshotList, classifyError } from '../chunk-UYJ6LIWP.js';
|
|
4
|
+
export { ERROR_HANDLING_PATH, classifyError, useChecklists, useCloseout, useCollections, useExpenses, useFiles, useFloat, useForms, useItinerary, useManagerToday, useManagers, useParties, usePickups, useRooming, useSeating, useSnapshotList, useTravellerProfile, useVendors } from '../chunk-UYJ6LIWP.js';
|
|
5
|
+
import { BrandShell } from '../chunk-WUAFL77X.js';
|
|
6
|
+
export { BrandShell, useKaafilBrand, useKaafilShareMeta, useShareForms, useShareSnapshot } from '../chunk-WUAFL77X.js';
|
|
7
|
+
export { useOfflineEngine } from '../chunk-PZKXLQSU.js';
|
|
8
|
+
import { useServerTime } from '../chunk-XI7MK4Y7.js';
|
|
9
|
+
export { useServerTime } from '../chunk-XI7MK4Y7.js';
|
|
10
|
+
import { useKaafilClient, useOfflineMutation, OfflineEngineContext, useOfflineEvent, usePersona, useCapabilityRows, isDevelopment, deriveCapabilityTriple, useRequiredContext, ConfigContext, tokenStyle, KaafilClientContext, useSession, SessionContext, I18nShell, useKaafilChrome } from '../chunk-6FPAGGFL.js';
|
|
11
|
+
export { I18nShell, createRegistry, useCapabilities, useCapability, useKaafilChrome, useKaafilClient, useOfflineEvent, useOfflineMutation, useOutboxStatus, usePersona, useSession } from '../chunk-6FPAGGFL.js';
|
|
12
|
+
import { SyncOpMethod, KaafilClient } from 'kaafil-js/client';
|
|
13
|
+
export { UnsatisfiableSchemeError } from 'kaafil-js/client';
|
|
14
|
+
import { useState, useCallback, useEffect, createContext, useContext, useRef, useMemo, Component, Fragment } from 'react';
|
|
15
|
+
import { createPortal } from 'react-dom';
|
|
16
|
+
import { jsx, Fragment as Fragment$1, jsxs } from 'react/jsx-runtime';
|
|
17
|
+
|
|
18
|
+
var NotImplementedError = class _NotImplementedError extends Error {
|
|
19
|
+
hookName;
|
|
20
|
+
specSection;
|
|
21
|
+
constructor(hookName, specSection) {
|
|
22
|
+
super(
|
|
23
|
+
`${hookName}() has no implementation in this build yet \u2014 see 08-core-hooks.md ${specSection} for its full signature and SDK binding.`
|
|
24
|
+
);
|
|
25
|
+
this.name = "NotImplementedError";
|
|
26
|
+
Object.setPrototypeOf(this, _NotImplementedError.prototype);
|
|
27
|
+
this.hookName = hookName;
|
|
28
|
+
this.specSection = specSection;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
function useBlobStatus(blobId) {
|
|
32
|
+
const engine = useContext(OfflineEngineContext);
|
|
33
|
+
const [, forceRefresh] = useState(0);
|
|
34
|
+
useOfflineEvent("sync.drained", () => forceRefresh((tick) => tick + 1));
|
|
35
|
+
useOfflineEvent("sync.error", () => forceRefresh((tick) => tick + 1));
|
|
36
|
+
const record = engine?.blobs?.all().find((candidate) => candidate.id === blobId);
|
|
37
|
+
if (record === void 0) {
|
|
38
|
+
return { status: "pending", progress: void 0 };
|
|
39
|
+
}
|
|
40
|
+
const status = record.status === "confirmed" ? "ready" : record.status === "parked" ? "orphaned" : record.attemptCount > 0 ? "uploading" : "pending";
|
|
41
|
+
return { status, progress: void 0 };
|
|
42
|
+
}
|
|
43
|
+
function useFeedbackNps(scope) {
|
|
44
|
+
const client = useKaafilClient();
|
|
45
|
+
const [summary, setSummary] = useState(void 0);
|
|
46
|
+
const [definitions, setDefinitions] = useState([]);
|
|
47
|
+
const [loaded, setLoaded] = useState(false);
|
|
48
|
+
const [lastFetchFailed, setLastFetchFailed] = useState(false);
|
|
49
|
+
const [syncedAt, setSyncedAt] = useState(void 0);
|
|
50
|
+
const formIdRef = useRef(void 0);
|
|
51
|
+
const refresh = useCallback(async () => {
|
|
52
|
+
try {
|
|
53
|
+
if (scope.kind === "trip") {
|
|
54
|
+
const response = await client.feedbackNps.trip({ tripRef: scope.tripRef });
|
|
55
|
+
setSummary(response.data);
|
|
56
|
+
formIdRef.current = response.data.configured ? response.data.formId : void 0;
|
|
57
|
+
setLoaded(true);
|
|
58
|
+
setLastFetchFailed(false);
|
|
59
|
+
setSyncedAt(response.meta.serverTime);
|
|
60
|
+
} else {
|
|
61
|
+
const response = await client.feedbackNps.agency({});
|
|
62
|
+
setDefinitions(response.data.definitions);
|
|
63
|
+
setLoaded(true);
|
|
64
|
+
setLastFetchFailed(false);
|
|
65
|
+
setSyncedAt(response.meta.serverTime);
|
|
66
|
+
}
|
|
67
|
+
} catch {
|
|
68
|
+
setLastFetchFailed(true);
|
|
69
|
+
}
|
|
70
|
+
}, [client, scope.kind, scope.kind === "trip" ? scope.tripRef : scope.agencyRef]);
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
void refresh();
|
|
73
|
+
}, [refresh]);
|
|
74
|
+
const dispatchMutation = useOfflineMutation({
|
|
75
|
+
tripRef: scope.kind === "trip" ? scope.tripRef : "",
|
|
76
|
+
enqueue: (engine, input) => {
|
|
77
|
+
const formId = formIdRef.current;
|
|
78
|
+
if (formId === void 0 || scope.kind !== "trip") {
|
|
79
|
+
throw new Error("useFeedbackNps: cannot dispatch before a feedback form is resolved");
|
|
80
|
+
}
|
|
81
|
+
return engine.enqueue({
|
|
82
|
+
tripRef: scope.tripRef,
|
|
83
|
+
method: SyncOpMethod.Post,
|
|
84
|
+
path: `/api/v1/trips/${scope.tripRef}/forms/${formId}/dispatch`,
|
|
85
|
+
// Hardcoded literal, not imported: `OperationId` is not exported
|
|
86
|
+
// from `kaafil-js/client`'s public surface — same convention as
|
|
87
|
+
// `useRooming.ts`'s own `'assignRoomingBed' as never`. Verified
|
|
88
|
+
// against `kaafil-js/src/generated/security.ts`
|
|
89
|
+
// (`OPERATION_SECURITY.dispatchForm`) this session.
|
|
90
|
+
operationId: "dispatchForm",
|
|
91
|
+
body: input ?? {}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
const dispatchMutate = dispatchMutation.mutate;
|
|
96
|
+
const dispatch = useCallback(
|
|
97
|
+
async (input) => {
|
|
98
|
+
const op = await dispatchMutate(input ?? {});
|
|
99
|
+
void refresh();
|
|
100
|
+
return op;
|
|
101
|
+
},
|
|
102
|
+
[dispatchMutate, refresh]
|
|
103
|
+
);
|
|
104
|
+
return {
|
|
105
|
+
kind: scope.kind,
|
|
106
|
+
summary,
|
|
107
|
+
definitions,
|
|
108
|
+
loaded,
|
|
109
|
+
lastFetchFailed,
|
|
110
|
+
syncedAt,
|
|
111
|
+
refresh,
|
|
112
|
+
dispatch,
|
|
113
|
+
dispatchStatus: dispatchMutation.status,
|
|
114
|
+
dispatchOp: dispatchMutation.op
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function useJourney(tripRef) {
|
|
118
|
+
const client = useKaafilClient();
|
|
119
|
+
const persona = usePersona();
|
|
120
|
+
const { rows } = useCapabilityRows(tripRef);
|
|
121
|
+
const [read, setRead] = useState(void 0);
|
|
122
|
+
const [liveRows, setLiveRows] = useState(void 0);
|
|
123
|
+
useEffect(() => {
|
|
124
|
+
if (persona === "share") {
|
|
125
|
+
if (isDevelopment()) {
|
|
126
|
+
throw new Error(
|
|
127
|
+
"useJourney() was called from a share session \u2014 it is manager/agencyAdmin only (08-core-hooks.md \xA73.2)."
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
let cancelled = false;
|
|
133
|
+
void client.journey.get({ tripRef }).then((response) => {
|
|
134
|
+
if (!cancelled) {
|
|
135
|
+
setRead(response);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
return () => {
|
|
139
|
+
cancelled = true;
|
|
140
|
+
};
|
|
141
|
+
}, [client, persona, tripRef]);
|
|
142
|
+
const refreshCapabilities = useCallback(async () => {
|
|
143
|
+
const response = await client.journey.capabilities({ tripRef, live: true });
|
|
144
|
+
setLiveRows(response);
|
|
145
|
+
}, [client, tripRef]);
|
|
146
|
+
const effectiveRows = liveRows ?? rows;
|
|
147
|
+
const capabilities = /* @__PURE__ */ new Map();
|
|
148
|
+
for (const row of effectiveRows) {
|
|
149
|
+
capabilities.set(row.capability, deriveCapabilityTriple(row));
|
|
150
|
+
}
|
|
151
|
+
return {
|
|
152
|
+
read,
|
|
153
|
+
capabilities,
|
|
154
|
+
refreshCapabilities,
|
|
155
|
+
triggers: {
|
|
156
|
+
list: (options) => client.journey.triggers.list(options),
|
|
157
|
+
patch: (options) => client.journey.triggers.patch(options)
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// src/core/hooks/useResolvedSetting.ts
|
|
163
|
+
function useResolvedSetting(key) {
|
|
164
|
+
const config = useRequiredContext(ConfigContext, "useResolvedSetting", "ConfigShell");
|
|
165
|
+
return config.resolveSetting(key);
|
|
166
|
+
}
|
|
167
|
+
function useSnapshotEntity(tripRef, listName, id) {
|
|
168
|
+
const engine = useContext(OfflineEngineContext);
|
|
169
|
+
const { rows } = useSnapshotList(tripRef, listName);
|
|
170
|
+
const row = rows.find((candidate) => candidate.id === id);
|
|
171
|
+
const syncedAt = engine === null ? void 0 : engine.snapshot.syncedAt(tripRef, listName, id);
|
|
172
|
+
return { row, syncedAt };
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// src/core/hooks/useStaleness.ts
|
|
176
|
+
function useStaleness(tripRef, listName) {
|
|
177
|
+
const { syncedAt } = useSnapshotList(tripRef, listName);
|
|
178
|
+
const { now } = useServerTime();
|
|
179
|
+
const thresholdSeconds = useResolvedSetting("stale.thresholdSeconds.default");
|
|
180
|
+
if (syncedAt === void 0) {
|
|
181
|
+
return { syncedAt: void 0, ageSeconds: void 0, isStale: false };
|
|
182
|
+
}
|
|
183
|
+
let ageSeconds;
|
|
184
|
+
try {
|
|
185
|
+
ageSeconds = (Date.parse(now()) - Date.parse(syncedAt)) / 1e3;
|
|
186
|
+
} catch {
|
|
187
|
+
ageSeconds = void 0;
|
|
188
|
+
}
|
|
189
|
+
const isStale = ageSeconds !== void 0 && thresholdSeconds !== void 0 && ageSeconds > thresholdSeconds;
|
|
190
|
+
return { syncedAt, ageSeconds, isStale };
|
|
191
|
+
}
|
|
192
|
+
var WALK_INS_PAGE_SIZE = 25;
|
|
193
|
+
var useTreksInternal = createDomainHook("treks", (tripRef) => {
|
|
194
|
+
const client = useKaafilClient();
|
|
195
|
+
const [boardData, setBoardData] = useState(void 0);
|
|
196
|
+
const [boardLoaded, setBoardLoaded] = useState(false);
|
|
197
|
+
const [boardFetchFailed, setBoardFetchFailed] = useState(false);
|
|
198
|
+
const [boardFetchedAt, setBoardFetchedAt] = useState(void 0);
|
|
199
|
+
const refreshBoard = useCallback(async () => {
|
|
200
|
+
try {
|
|
201
|
+
const response = await client.treks.board({ trekRef: tripRef });
|
|
202
|
+
setBoardData(response);
|
|
203
|
+
setBoardLoaded(true);
|
|
204
|
+
setBoardFetchFailed(false);
|
|
205
|
+
setBoardFetchedAt(response.meta.serverTime);
|
|
206
|
+
} catch {
|
|
207
|
+
setBoardFetchFailed(true);
|
|
208
|
+
}
|
|
209
|
+
}, [client, tripRef]);
|
|
210
|
+
useEffect(() => {
|
|
211
|
+
void refreshBoard();
|
|
212
|
+
}, [refreshBoard]);
|
|
213
|
+
const [walkInRows, setWalkInRows] = useState([]);
|
|
214
|
+
const [walkInsLoaded, setWalkInsLoaded] = useState(false);
|
|
215
|
+
const [walkInsFetchFailed, setWalkInsFetchFailed] = useState(false);
|
|
216
|
+
const [walkInsFetchedAt, setWalkInsFetchedAt] = useState(void 0);
|
|
217
|
+
const [walkInsCursor, setWalkInsCursor] = useState(void 0);
|
|
218
|
+
const [walkInsHasNext, setWalkInsHasNext] = useState(false);
|
|
219
|
+
const refreshWalkIns = useCallback(async () => {
|
|
220
|
+
try {
|
|
221
|
+
const page = await client.treks.walkIns.listPage({
|
|
222
|
+
trekRef: tripRef,
|
|
223
|
+
limit: WALK_INS_PAGE_SIZE
|
|
224
|
+
});
|
|
225
|
+
setWalkInRows(page);
|
|
226
|
+
setWalkInsLoaded(true);
|
|
227
|
+
setWalkInsFetchFailed(false);
|
|
228
|
+
setWalkInsFetchedAt(page.meta.serverTime);
|
|
229
|
+
setWalkInsCursor(page.meta.page.cursor ?? void 0);
|
|
230
|
+
setWalkInsHasNext(page.meta.page.hasNext);
|
|
231
|
+
} catch {
|
|
232
|
+
setWalkInsFetchFailed(true);
|
|
233
|
+
}
|
|
234
|
+
}, [client, tripRef]);
|
|
235
|
+
const loadMoreWalkIns = useCallback(async () => {
|
|
236
|
+
if (walkInsCursor === void 0 || !walkInsHasNext) {
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
try {
|
|
240
|
+
const page = await client.treks.walkIns.listPage({
|
|
241
|
+
trekRef: tripRef,
|
|
242
|
+
cursor: walkInsCursor,
|
|
243
|
+
limit: WALK_INS_PAGE_SIZE
|
|
244
|
+
});
|
|
245
|
+
setWalkInRows((existing) => [...existing, ...page]);
|
|
246
|
+
setWalkInsFetchedAt(page.meta.serverTime);
|
|
247
|
+
setWalkInsCursor(page.meta.page.cursor ?? void 0);
|
|
248
|
+
setWalkInsHasNext(page.meta.page.hasNext);
|
|
249
|
+
} catch {
|
|
250
|
+
setWalkInsFetchFailed(true);
|
|
251
|
+
}
|
|
252
|
+
}, [client, tripRef, walkInsCursor, walkInsHasNext]);
|
|
253
|
+
useEffect(() => {
|
|
254
|
+
void refreshWalkIns();
|
|
255
|
+
}, [refreshWalkIns]);
|
|
256
|
+
const [metaData, setMetaData] = useState(void 0);
|
|
257
|
+
const [metaLoaded, setMetaLoaded] = useState(false);
|
|
258
|
+
const [metaFetchFailed, setMetaFetchFailed] = useState(false);
|
|
259
|
+
const refreshMeta = useCallback(async () => {
|
|
260
|
+
try {
|
|
261
|
+
const response = await client.treks.walkIns.meta({ trekRef: tripRef });
|
|
262
|
+
setMetaData(response);
|
|
263
|
+
setMetaLoaded(true);
|
|
264
|
+
setMetaFetchFailed(false);
|
|
265
|
+
} catch {
|
|
266
|
+
setMetaFetchFailed(true);
|
|
267
|
+
}
|
|
268
|
+
}, [client, tripRef]);
|
|
269
|
+
useEffect(() => {
|
|
270
|
+
void refreshMeta();
|
|
271
|
+
}, [refreshMeta]);
|
|
272
|
+
const createWalkInMutation = useOfflineMutation({
|
|
273
|
+
tripRef,
|
|
274
|
+
enqueue: (engine, input) => engine.enqueue({
|
|
275
|
+
tripRef,
|
|
276
|
+
method: SyncOpMethod.Post,
|
|
277
|
+
path: `/api/v1/treks/${tripRef}/walk-ins`,
|
|
278
|
+
// `OperationId` is not exported from `kaafil-js/client`'s public
|
|
279
|
+
// surface — same documented gap `useFloat.ts`/`useRooming.ts` cast
|
|
280
|
+
// around for their own literal `operationId`s.
|
|
281
|
+
operationId: "createTrekWalkIn",
|
|
282
|
+
body: input
|
|
283
|
+
})
|
|
284
|
+
});
|
|
285
|
+
const postponeMutation = useOfflineMutation({
|
|
286
|
+
tripRef,
|
|
287
|
+
enqueue: (engine, input) => engine.enqueue({
|
|
288
|
+
tripRef,
|
|
289
|
+
method: SyncOpMethod.Post,
|
|
290
|
+
path: `/api/v1/treks/${tripRef}/postpone`,
|
|
291
|
+
operationId: "postponeTrek",
|
|
292
|
+
body: input
|
|
293
|
+
})
|
|
294
|
+
});
|
|
295
|
+
const reconcileMutation = useOfflineMutation({
|
|
296
|
+
tripRef,
|
|
297
|
+
enqueue: (engine, { walkInId, input }) => engine.enqueue({
|
|
298
|
+
tripRef,
|
|
299
|
+
method: SyncOpMethod.Post,
|
|
300
|
+
path: `/api/v1/treks/${tripRef}/walk-ins/${walkInId}/reconcile`,
|
|
301
|
+
operationId: "reconcileTrekWalkIn",
|
|
302
|
+
body: input
|
|
303
|
+
})
|
|
304
|
+
});
|
|
305
|
+
const createWalkInMutate = createWalkInMutation.mutate;
|
|
306
|
+
const createWalkIn = useCallback(
|
|
307
|
+
async (input) => {
|
|
308
|
+
const op = await createWalkInMutate(input);
|
|
309
|
+
void refreshBoard();
|
|
310
|
+
void refreshWalkIns();
|
|
311
|
+
return op;
|
|
312
|
+
},
|
|
313
|
+
[createWalkInMutate, refreshBoard, refreshWalkIns]
|
|
314
|
+
);
|
|
315
|
+
const postponeMutate = postponeMutation.mutate;
|
|
316
|
+
const postpone = useCallback(
|
|
317
|
+
async (input) => {
|
|
318
|
+
const op = await postponeMutate(input);
|
|
319
|
+
void refreshBoard();
|
|
320
|
+
return op;
|
|
321
|
+
},
|
|
322
|
+
[postponeMutate, refreshBoard]
|
|
323
|
+
);
|
|
324
|
+
const reconcileMutate = reconcileMutation.mutate;
|
|
325
|
+
const reconcileWalkIn = useCallback(
|
|
326
|
+
async (walkInId, input) => {
|
|
327
|
+
const op = await reconcileMutate({ walkInId, input });
|
|
328
|
+
void refreshWalkIns();
|
|
329
|
+
return op;
|
|
330
|
+
},
|
|
331
|
+
[reconcileMutate, refreshWalkIns]
|
|
332
|
+
);
|
|
333
|
+
return {
|
|
334
|
+
board: {
|
|
335
|
+
data: boardData,
|
|
336
|
+
loaded: boardLoaded,
|
|
337
|
+
lastFetchFailed: boardFetchFailed,
|
|
338
|
+
fetchedAt: boardFetchedAt,
|
|
339
|
+
refresh: refreshBoard
|
|
340
|
+
},
|
|
341
|
+
walkIns: {
|
|
342
|
+
rows: walkInRows,
|
|
343
|
+
loaded: walkInsLoaded,
|
|
344
|
+
lastFetchFailed: walkInsFetchFailed,
|
|
345
|
+
fetchedAt: walkInsFetchedAt,
|
|
346
|
+
hasMore: walkInsHasNext,
|
|
347
|
+
refresh: refreshWalkIns,
|
|
348
|
+
loadMore: loadMoreWalkIns
|
|
349
|
+
},
|
|
350
|
+
walkInMeta: {
|
|
351
|
+
data: metaData,
|
|
352
|
+
loaded: metaLoaded,
|
|
353
|
+
lastFetchFailed: metaFetchFailed,
|
|
354
|
+
refresh: refreshMeta
|
|
355
|
+
},
|
|
356
|
+
createWalkIn,
|
|
357
|
+
postpone,
|
|
358
|
+
reconcileWalkIn
|
|
359
|
+
};
|
|
360
|
+
});
|
|
361
|
+
function useTreks(tripRef) {
|
|
362
|
+
return useTreksInternal(tripRef);
|
|
363
|
+
}
|
|
364
|
+
var ThemeAttributesContext = createContext(null);
|
|
365
|
+
var FAMILY_DEFAULT_FRAME = {
|
|
366
|
+
admin: "desk",
|
|
367
|
+
manager: "field",
|
|
368
|
+
traveller: "document"
|
|
369
|
+
};
|
|
370
|
+
var DESK_MINIMUM_CONTAINER_WIDTH_PX = 640;
|
|
371
|
+
function ShadowIsolationBoundary({
|
|
372
|
+
className,
|
|
373
|
+
children
|
|
374
|
+
}) {
|
|
375
|
+
const hostRef = useRef(null);
|
|
376
|
+
const [shadowContainer, setShadowContainer] = useState(null);
|
|
377
|
+
useEffect(() => {
|
|
378
|
+
const host = hostRef.current;
|
|
379
|
+
if (host === null) {
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
const shadow = host.shadowRoot ?? host.attachShadow({ mode: "open" });
|
|
383
|
+
let container = shadow.querySelector("div[data-kf-shadow-content]");
|
|
384
|
+
if (container === null) {
|
|
385
|
+
container = document.createElement("div");
|
|
386
|
+
container.setAttribute("data-kf-shadow-content", "");
|
|
387
|
+
shadow.appendChild(container);
|
|
388
|
+
}
|
|
389
|
+
setShadowContainer(container);
|
|
390
|
+
}, []);
|
|
391
|
+
return /* @__PURE__ */ jsx("div", { ref: hostRef, className, "data-kf-isolation": "shadow", children: shadowContainer !== null ? createPortal(children, shadowContainer) : null });
|
|
392
|
+
}
|
|
393
|
+
function useDeskMinimumWidthWarning(rootRef, frame) {
|
|
394
|
+
useEffect(() => {
|
|
395
|
+
if (frame !== "desk" || !isDevelopment() || typeof ResizeObserver === "undefined") {
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
const node = rootRef.current;
|
|
399
|
+
if (node === null) {
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
let warned = false;
|
|
403
|
+
const observer = new ResizeObserver((entries) => {
|
|
404
|
+
const entry = entries[0];
|
|
405
|
+
if (entry === void 0 || warned) {
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
if (entry.contentRect.width < DESK_MINIMUM_CONTAINER_WIDTH_PX) {
|
|
409
|
+
warned = true;
|
|
410
|
+
console.warn(
|
|
411
|
+
`kaafil-react-uikit: the 'desk' frame's .kf-root is narrower than the stated minimum container width (05-theming-and-branding.md \xA74.4). AppShell never auto-swaps frames \u2014 mount the manager family, or pass frame="field" explicitly, for this container.`
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
observer.observe(node);
|
|
416
|
+
return () => observer.disconnect();
|
|
417
|
+
}, [rootRef, frame]);
|
|
418
|
+
}
|
|
419
|
+
function useUnfilledConnectivitySlotWarning(frame, connectivitySlot) {
|
|
420
|
+
useEffect(() => {
|
|
421
|
+
if (frame === "field" && connectivitySlot === void 0 && isDevelopment()) {
|
|
422
|
+
console.warn(
|
|
423
|
+
`kaafil-react-uikit: AppShell's "field" frame has no connectivitySlot filled \u2014 the permanently-visible connectivity/sync region this frame reserves is empty (01-app-shell.md, briefing \xA727.2).`
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
}, [frame, connectivitySlot]);
|
|
427
|
+
}
|
|
428
|
+
function AppShell({
|
|
429
|
+
frame,
|
|
430
|
+
family,
|
|
431
|
+
isolation = "scoped",
|
|
432
|
+
navSlot,
|
|
433
|
+
actionBarSlot,
|
|
434
|
+
connectivitySlot,
|
|
435
|
+
children,
|
|
436
|
+
style
|
|
437
|
+
}) {
|
|
438
|
+
const themeAttributes = useContext(ThemeAttributesContext);
|
|
439
|
+
const rootRef = useRef(null);
|
|
440
|
+
const resolvedFrame = frame ?? (family !== void 0 ? FAMILY_DEFAULT_FRAME[family] : "document");
|
|
441
|
+
useDeskMinimumWidthWarning(rootRef, resolvedFrame);
|
|
442
|
+
useUnfilledConnectivitySlotWarning(resolvedFrame, connectivitySlot);
|
|
443
|
+
const dataAttributes = {
|
|
444
|
+
"data-kf-frame": resolvedFrame
|
|
445
|
+
};
|
|
446
|
+
if (family !== void 0) {
|
|
447
|
+
dataAttributes["data-kf-family"] = family;
|
|
448
|
+
}
|
|
449
|
+
if (themeAttributes !== null) {
|
|
450
|
+
dataAttributes["data-kf-theme"] = themeAttributes.theme;
|
|
451
|
+
if (themeAttributes.density !== void 0) {
|
|
452
|
+
dataAttributes["data-kf-density"] = themeAttributes.density;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
const content = /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
456
|
+
resolvedFrame === "desk" && navSlot !== void 0 ? /* @__PURE__ */ jsx("div", { className: "kf-app-shell__nav", children: navSlot }) : null,
|
|
457
|
+
/* @__PURE__ */ jsx("div", { className: "kf-app-shell__content", children }),
|
|
458
|
+
resolvedFrame === "field" && actionBarSlot !== void 0 ? /* @__PURE__ */ jsx("div", { className: "kf-app-shell__action-bar", children: actionBarSlot }) : null,
|
|
459
|
+
resolvedFrame === "field" && connectivitySlot !== void 0 ? /* @__PURE__ */ jsx("div", { className: "kf-app-shell__connectivity", children: connectivitySlot }) : null,
|
|
460
|
+
/* @__PURE__ */ jsx("div", { className: "kf-app-shell__live-region", role: "status", "aria-live": "polite" })
|
|
461
|
+
] });
|
|
462
|
+
if (isolation === "shadow") {
|
|
463
|
+
return /* @__PURE__ */ jsx(
|
|
464
|
+
"div",
|
|
465
|
+
{
|
|
466
|
+
ref: rootRef,
|
|
467
|
+
className: "kf-root",
|
|
468
|
+
"data-kf-isolation": "shadow",
|
|
469
|
+
...dataAttributes,
|
|
470
|
+
style: tokenStyle(style),
|
|
471
|
+
children: /* @__PURE__ */ jsx(ShadowIsolationBoundary, { className: "kf-app-shell__shadow-host", children: content })
|
|
472
|
+
}
|
|
473
|
+
);
|
|
474
|
+
}
|
|
475
|
+
return /* @__PURE__ */ jsx(
|
|
476
|
+
"div",
|
|
477
|
+
{
|
|
478
|
+
ref: rootRef,
|
|
479
|
+
className: "kf-root",
|
|
480
|
+
"data-kf-isolation": "scoped",
|
|
481
|
+
...dataAttributes,
|
|
482
|
+
style: tokenStyle(style),
|
|
483
|
+
children: content
|
|
484
|
+
}
|
|
485
|
+
);
|
|
486
|
+
}
|
|
487
|
+
function ConfigShell({ seedConfig = {}, children }) {
|
|
488
|
+
const value = useMemo(
|
|
489
|
+
() => ({
|
|
490
|
+
resolveSetting(key) {
|
|
491
|
+
const agencyValue = seedConfig.agency?.[key];
|
|
492
|
+
if (agencyValue !== void 0) {
|
|
493
|
+
return agencyValue;
|
|
494
|
+
}
|
|
495
|
+
const tenantValue = seedConfig.tenant?.[key];
|
|
496
|
+
return tenantValue === void 0 ? void 0 : tenantValue;
|
|
497
|
+
}
|
|
498
|
+
}),
|
|
499
|
+
[seedConfig.agency, seedConfig.tenant]
|
|
500
|
+
);
|
|
501
|
+
return /* @__PURE__ */ jsx(ConfigContext.Provider, { value, children });
|
|
502
|
+
}
|
|
503
|
+
function classifyForFallback(error) {
|
|
504
|
+
const classification = classifyError(error);
|
|
505
|
+
if (classification.code === "RESOURCE_NOT_FOUND") {
|
|
506
|
+
return { classification: "isolation", code: classification.code };
|
|
507
|
+
}
|
|
508
|
+
if (classification.path === "parked" || classification.unsatisfiableScheme) {
|
|
509
|
+
return { classification: "parked", code: classification.code };
|
|
510
|
+
}
|
|
511
|
+
return { classification: "retryable", code: classification.code };
|
|
512
|
+
}
|
|
513
|
+
var FALLBACK_STYLE = {
|
|
514
|
+
fontFamily: "system-ui, sans-serif",
|
|
515
|
+
padding: "1.5rem",
|
|
516
|
+
border: "1px solid #999",
|
|
517
|
+
borderRadius: "4px",
|
|
518
|
+
color: "#1a1a1a",
|
|
519
|
+
background: "#fff"
|
|
520
|
+
};
|
|
521
|
+
function DefaultFallback({
|
|
522
|
+
ctx,
|
|
523
|
+
onRetry
|
|
524
|
+
}) {
|
|
525
|
+
const role = ctx.classification === "retryable" ? "status" : "alert";
|
|
526
|
+
const ariaLive = ctx.classification === "retryable" ? "polite" : "assertive";
|
|
527
|
+
const message = ctx.classification === "isolation" ? "Not found." : ctx.classification === "parked" ? "This action can't be completed right now." : "Something went wrong.";
|
|
528
|
+
return /* @__PURE__ */ jsxs("div", { style: FALLBACK_STYLE, role, "aria-live": ariaLive, children: [
|
|
529
|
+
/* @__PURE__ */ jsx("p", { style: { margin: 0 }, children: message }),
|
|
530
|
+
ctx.classification === "retryable" ? /* @__PURE__ */ jsx("button", { type: "button", onClick: onRetry, style: { marginTop: "0.75rem" }, children: "Try again" }) : null
|
|
531
|
+
] });
|
|
532
|
+
}
|
|
533
|
+
var ErrorShell = class extends Component {
|
|
534
|
+
state = { caught: null, retryKey: 0 };
|
|
535
|
+
static getDerivedStateFromError(error) {
|
|
536
|
+
return { caught: { error } };
|
|
537
|
+
}
|
|
538
|
+
handleRetry = () => {
|
|
539
|
+
this.setState((current) => ({ caught: null, retryKey: current.retryKey + 1 }));
|
|
540
|
+
};
|
|
541
|
+
render() {
|
|
542
|
+
if (this.state.caught !== null) {
|
|
543
|
+
const ctx = classifyForFallback(this.state.caught.error);
|
|
544
|
+
if (this.props.fallbackSlot !== void 0) {
|
|
545
|
+
return this.props.fallbackSlot(ctx);
|
|
546
|
+
}
|
|
547
|
+
return /* @__PURE__ */ jsx(DefaultFallback, { ctx, onRetry: this.handleRetry });
|
|
548
|
+
}
|
|
549
|
+
return /* @__PURE__ */ jsx(Fragment, { children: this.props.children }, this.state.retryKey);
|
|
550
|
+
}
|
|
551
|
+
};
|
|
552
|
+
var SessionExpiryBridgeContext = createContext(void 0);
|
|
553
|
+
function OfflineShell({
|
|
554
|
+
storage,
|
|
555
|
+
blob,
|
|
556
|
+
conflictResolver,
|
|
557
|
+
readEntity,
|
|
558
|
+
scope,
|
|
559
|
+
children
|
|
560
|
+
}) {
|
|
561
|
+
const client = useContext(KaafilClientContext);
|
|
562
|
+
const persona = usePersona();
|
|
563
|
+
const session = useSession();
|
|
564
|
+
const reportExpired = useContext(SessionExpiryBridgeContext);
|
|
565
|
+
const [engine, setEngine] = useState(null);
|
|
566
|
+
const engineRef = useRef(null);
|
|
567
|
+
const derivedScope = scope ?? `${persona}:${session.agencyRef ?? "share"}`;
|
|
568
|
+
useEffect(() => {
|
|
569
|
+
if (session.status !== "authenticated" || client === null) {
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
572
|
+
const newEngine = client.openOffline({
|
|
573
|
+
storage,
|
|
574
|
+
scope: derivedScope,
|
|
575
|
+
...readEntity !== void 0 ? { readEntity } : {},
|
|
576
|
+
...conflictResolver !== void 0 ? { conflictResolver } : {},
|
|
577
|
+
...blob !== void 0 ? { blob } : {}
|
|
578
|
+
// GAP flagged in this phase's report: a share session's local
|
|
579
|
+
// `expiresAt` enforcement (`OpenOfflineOptions.share`,
|
|
580
|
+
// `07-offline-and-sync.md §8`) needs an `expiresAt` this shell has no
|
|
581
|
+
// source for yet — it is not on `useSession()`'s derived shape and no
|
|
582
|
+
// prop carries it. Omitted here rather than guessed; a share engine
|
|
583
|
+
// opens without the local expiry/grace/purge enforcement until that
|
|
584
|
+
// value has a wire source.
|
|
585
|
+
});
|
|
586
|
+
engineRef.current = newEngine;
|
|
587
|
+
setEngine(newEngine);
|
|
588
|
+
const unsubscribeSessionExpired = persona !== "share" ? newEngine.events.on("session.expired", () => reportExpired?.("session")) : void 0;
|
|
589
|
+
const unsubscribeShareExpired = persona === "share" ? newEngine.events.on("share.expired", () => reportExpired?.("share")) : void 0;
|
|
590
|
+
const unsubscribeShareRevoked = persona === "share" ? newEngine.events.on("share.revoked", () => reportExpired?.("share")) : void 0;
|
|
591
|
+
return () => {
|
|
592
|
+
unsubscribeSessionExpired?.();
|
|
593
|
+
unsubscribeShareExpired?.();
|
|
594
|
+
unsubscribeShareRevoked?.();
|
|
595
|
+
newEngine.close();
|
|
596
|
+
if (engineRef.current === newEngine) {
|
|
597
|
+
engineRef.current = null;
|
|
598
|
+
}
|
|
599
|
+
};
|
|
600
|
+
}, [client, derivedScope, session.status, persona, reportExpired]);
|
|
601
|
+
return /* @__PURE__ */ jsx(OfflineEngineContext.Provider, { value: engine, children });
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// src/core/shells/internal/jwtKind.ts
|
|
605
|
+
function base64UrlDecode(segment) {
|
|
606
|
+
const padded = segment.replace(/-/g, "+").replace(/_/g, "/");
|
|
607
|
+
const withPadding = padded + "=".repeat((4 - padded.length % 4) % 4);
|
|
608
|
+
return atob(withPadding);
|
|
609
|
+
}
|
|
610
|
+
function decodeManagerOrAgencyAdminKind(accessToken) {
|
|
611
|
+
const segments = accessToken.split(".");
|
|
612
|
+
const payloadSegment = segments[1];
|
|
613
|
+
if (segments.length !== 3 || payloadSegment === void 0) {
|
|
614
|
+
throw new Error(
|
|
615
|
+
'SessionShell could not parse "accessToken" as a JWT \u2014 it does not have the three dot-separated segments every manager/agencyAdmin session token has.'
|
|
616
|
+
);
|
|
617
|
+
}
|
|
618
|
+
let claim;
|
|
619
|
+
try {
|
|
620
|
+
claim = JSON.parse(base64UrlDecode(payloadSegment));
|
|
621
|
+
} catch {
|
|
622
|
+
throw new Error(
|
|
623
|
+
`SessionShell could not decode "accessToken"'s payload segment as JSON \u2014 the value handed to <KaafilUIKitProvider accessToken> is not a well-formed JWT.`
|
|
624
|
+
);
|
|
625
|
+
}
|
|
626
|
+
const kind = claim.kind;
|
|
627
|
+
if (kind === "agencyAdmin") {
|
|
628
|
+
return "agencyAdmin";
|
|
629
|
+
}
|
|
630
|
+
if (kind === "managerSession" || kind === "manager") {
|
|
631
|
+
return "managerSession";
|
|
632
|
+
}
|
|
633
|
+
throw new Error(
|
|
634
|
+
`SessionShell read an unrecognised "kind" claim ("${String(kind)}") off "accessToken" \u2014 expected the manager or agencyAdmin session JWT shape (00-decisions.md U-003).`
|
|
635
|
+
);
|
|
636
|
+
}
|
|
637
|
+
async function resolveCredential(props) {
|
|
638
|
+
if (props.credentialResolver !== void 0) {
|
|
639
|
+
const resolved = await props.credentialResolver();
|
|
640
|
+
if ("shareToken" in resolved) {
|
|
641
|
+
return { kind: "share", shareToken: resolved.shareToken };
|
|
642
|
+
}
|
|
643
|
+
const kind2 = decodeManagerOrAgencyAdminKind(resolved.accessToken) === "agencyAdmin" ? "agencyAdmin" : "manager";
|
|
644
|
+
return { kind: kind2, ...resolved };
|
|
645
|
+
}
|
|
646
|
+
if (props.shareToken !== void 0) {
|
|
647
|
+
return { kind: "share", shareToken: props.shareToken };
|
|
648
|
+
}
|
|
649
|
+
const kind = decodeManagerOrAgencyAdminKind(props.accessToken) === "agencyAdmin" ? "agencyAdmin" : "manager";
|
|
650
|
+
return {
|
|
651
|
+
kind,
|
|
652
|
+
accessToken: props.accessToken,
|
|
653
|
+
refreshToken: props.refreshToken,
|
|
654
|
+
agencyRef: props.agencyRef
|
|
655
|
+
};
|
|
656
|
+
}
|
|
657
|
+
function SessionShell(props) {
|
|
658
|
+
const { environment = "live", onRefresh, onSessionExpired, children } = props;
|
|
659
|
+
const [state, setState] = useState(null);
|
|
660
|
+
const expiredCallbackFiredRef = useRef(false);
|
|
661
|
+
const currentPersonaRef = useRef("manager");
|
|
662
|
+
const reportExpired = useCallback(() => {
|
|
663
|
+
if (expiredCallbackFiredRef.current) {
|
|
664
|
+
return;
|
|
665
|
+
}
|
|
666
|
+
expiredCallbackFiredRef.current = true;
|
|
667
|
+
onSessionExpired?.(currentPersonaRef.current);
|
|
668
|
+
setState(
|
|
669
|
+
(current) => current === null ? current : { ...current, session: { ...current.session, status: "expired" } }
|
|
670
|
+
);
|
|
671
|
+
}, [onSessionExpired]);
|
|
672
|
+
const accessTokenDep = "accessToken" in props ? props.accessToken : void 0;
|
|
673
|
+
const refreshTokenDep = "refreshToken" in props ? props.refreshToken : void 0;
|
|
674
|
+
const agencyRefDep = "agencyRef" in props ? props.agencyRef : void 0;
|
|
675
|
+
const shareTokenDep = "shareToken" in props ? props.shareToken : void 0;
|
|
676
|
+
useEffect(() => {
|
|
677
|
+
let cancelled = false;
|
|
678
|
+
const client = new KaafilClient({ environment });
|
|
679
|
+
expiredCallbackFiredRef.current = false;
|
|
680
|
+
async function open() {
|
|
681
|
+
const credential = await resolveCredential(props);
|
|
682
|
+
if (cancelled) {
|
|
683
|
+
return;
|
|
684
|
+
}
|
|
685
|
+
currentPersonaRef.current = credential.kind;
|
|
686
|
+
if (credential.kind === "share") {
|
|
687
|
+
client.share.open({ token: credential.shareToken });
|
|
688
|
+
} else if (credential.kind === "agencyAdmin") {
|
|
689
|
+
client.admin.open({
|
|
690
|
+
accessToken: credential.accessToken,
|
|
691
|
+
refreshToken: credential.refreshToken,
|
|
692
|
+
agencyRef: credential.agencyRef,
|
|
693
|
+
...onRefresh !== void 0 ? { onRefresh } : {}
|
|
694
|
+
});
|
|
695
|
+
} else {
|
|
696
|
+
client.session.open({
|
|
697
|
+
accessToken: credential.accessToken,
|
|
698
|
+
refreshToken: credential.refreshToken,
|
|
699
|
+
agencyRef: credential.agencyRef,
|
|
700
|
+
...onRefresh !== void 0 ? { onRefresh } : {}
|
|
701
|
+
});
|
|
702
|
+
}
|
|
703
|
+
setState({
|
|
704
|
+
client,
|
|
705
|
+
session: {
|
|
706
|
+
status: "authenticated",
|
|
707
|
+
persona: credential.kind,
|
|
708
|
+
agencyRef: credential.agencyRef,
|
|
709
|
+
environment
|
|
710
|
+
}
|
|
711
|
+
});
|
|
712
|
+
}
|
|
713
|
+
void open();
|
|
714
|
+
return () => {
|
|
715
|
+
cancelled = true;
|
|
716
|
+
client.close();
|
|
717
|
+
};
|
|
718
|
+
}, [environment, accessTokenDep, refreshTokenDep, agencyRefDep, shareTokenDep]);
|
|
719
|
+
if (state === null) {
|
|
720
|
+
return /* @__PURE__ */ jsx(SessionExpiryBridgeContext.Provider, { value: reportExpired, children: /* @__PURE__ */ jsx(
|
|
721
|
+
SessionContext.Provider,
|
|
722
|
+
{
|
|
723
|
+
value: { status: "opening", persona: "manager", agencyRef: void 0, environment },
|
|
724
|
+
children
|
|
725
|
+
}
|
|
726
|
+
) });
|
|
727
|
+
}
|
|
728
|
+
return /* @__PURE__ */ jsx(SessionExpiryBridgeContext.Provider, { value: reportExpired, children: /* @__PURE__ */ jsx(KaafilClientContext.Provider, { value: state.client, children: /* @__PURE__ */ jsx(SessionContext.Provider, { value: state.session, children }) }) });
|
|
729
|
+
}
|
|
730
|
+
function emit(onEvent, event) {
|
|
731
|
+
if (onEvent === void 0) {
|
|
732
|
+
return;
|
|
733
|
+
}
|
|
734
|
+
try {
|
|
735
|
+
onEvent(event);
|
|
736
|
+
} catch {
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
function TelemetryShell({ onEvent, children }) {
|
|
740
|
+
const session = useSession();
|
|
741
|
+
const serverTime = useServerTime();
|
|
742
|
+
const previousStatusRef = useRef(void 0);
|
|
743
|
+
useEffect(() => {
|
|
744
|
+
const previousStatus = previousStatusRef.current;
|
|
745
|
+
if (serverTime.sinceLastSync !== void 0) {
|
|
746
|
+
if (session.status === "authenticated" && previousStatus !== "authenticated") {
|
|
747
|
+
emit(onEvent, {
|
|
748
|
+
type: "session.opened",
|
|
749
|
+
timestamp: serverTime.now(),
|
|
750
|
+
persona: session.persona
|
|
751
|
+
});
|
|
752
|
+
}
|
|
753
|
+
if (session.status === "expired" && previousStatus !== "expired") {
|
|
754
|
+
emit(onEvent, {
|
|
755
|
+
type: "session.expired",
|
|
756
|
+
timestamp: serverTime.now(),
|
|
757
|
+
persona: session.persona
|
|
758
|
+
});
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
previousStatusRef.current = session.status;
|
|
762
|
+
}, [session.status, serverTime.sinceLastSync]);
|
|
763
|
+
return /* @__PURE__ */ jsx(Fragment$1, { children });
|
|
764
|
+
}
|
|
765
|
+
function resolveSystemTheme() {
|
|
766
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
|
|
767
|
+
return "light";
|
|
768
|
+
}
|
|
769
|
+
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
770
|
+
}
|
|
771
|
+
function ThemeShell({ theme = "system", density, children }) {
|
|
772
|
+
const [systemTheme, setSystemTheme] = useState(
|
|
773
|
+
() => theme === "system" ? resolveSystemTheme() : theme
|
|
774
|
+
);
|
|
775
|
+
useEffect(() => {
|
|
776
|
+
if (theme !== "system" || typeof window === "undefined" || typeof window.matchMedia !== "function") {
|
|
777
|
+
return;
|
|
778
|
+
}
|
|
779
|
+
const query = window.matchMedia("(prefers-color-scheme: dark)");
|
|
780
|
+
const listener = (event) => {
|
|
781
|
+
setSystemTheme(event.matches ? "dark" : "light");
|
|
782
|
+
};
|
|
783
|
+
query.addEventListener("change", listener);
|
|
784
|
+
return () => query.removeEventListener("change", listener);
|
|
785
|
+
}, [theme]);
|
|
786
|
+
const resolvedTheme = theme === "system" ? systemTheme : theme;
|
|
787
|
+
const value = useMemo(() => ({ theme: resolvedTheme, density }), [resolvedTheme, density]);
|
|
788
|
+
return /* @__PURE__ */ jsx(ThemeAttributesContext.Provider, { value, children });
|
|
789
|
+
}
|
|
790
|
+
var DefaultCapabilityViewsContext = createContext({});
|
|
791
|
+
function useDefaultCapabilityViews() {
|
|
792
|
+
return useContext(DefaultCapabilityViewsContext);
|
|
793
|
+
}
|
|
794
|
+
function KaafilUIKitProvider(props) {
|
|
795
|
+
const {
|
|
796
|
+
environment,
|
|
797
|
+
onSessionExpired,
|
|
798
|
+
density,
|
|
799
|
+
theme,
|
|
800
|
+
brand,
|
|
801
|
+
locale,
|
|
802
|
+
isolation,
|
|
803
|
+
onEvent,
|
|
804
|
+
storage,
|
|
805
|
+
blob,
|
|
806
|
+
conflictResolver,
|
|
807
|
+
readEntity,
|
|
808
|
+
offlineScope,
|
|
809
|
+
seedConfig,
|
|
810
|
+
defaultCapabilityViews,
|
|
811
|
+
children,
|
|
812
|
+
...credential
|
|
813
|
+
} = props;
|
|
814
|
+
const inner = /* @__PURE__ */ jsx(DefaultCapabilityViewsContext.Provider, { value: defaultCapabilityViews ?? {}, children: /* @__PURE__ */ jsx(ConfigShell, { seedConfig, children: /* @__PURE__ */ jsx(
|
|
815
|
+
BrandShell,
|
|
816
|
+
{
|
|
817
|
+
appName: brand?.appName,
|
|
818
|
+
logo: brand?.logo,
|
|
819
|
+
logoMark: brand?.logoMark,
|
|
820
|
+
favicon: brand?.favicon,
|
|
821
|
+
headStrategy: brand?.headStrategy,
|
|
822
|
+
children: /* @__PURE__ */ jsx(TelemetryShell, { onEvent, children })
|
|
823
|
+
}
|
|
824
|
+
) }) });
|
|
825
|
+
return /* @__PURE__ */ jsx(ErrorShell, { children: /* @__PURE__ */ jsx(ThemeShell, { theme, density, children: /* @__PURE__ */ jsx(I18nShell, { locale, children: /* @__PURE__ */ jsx(AppShell, { isolation, children: /* @__PURE__ */ jsx(
|
|
826
|
+
SessionShell,
|
|
827
|
+
{
|
|
828
|
+
...credential,
|
|
829
|
+
environment,
|
|
830
|
+
onSessionExpired,
|
|
831
|
+
children: storage !== void 0 ? /* @__PURE__ */ jsx(
|
|
832
|
+
OfflineShell,
|
|
833
|
+
{
|
|
834
|
+
storage,
|
|
835
|
+
blob,
|
|
836
|
+
conflictResolver,
|
|
837
|
+
readEntity,
|
|
838
|
+
scope: offlineScope,
|
|
839
|
+
children: inner
|
|
840
|
+
}
|
|
841
|
+
) : inner
|
|
842
|
+
}
|
|
843
|
+
) }) }) }) });
|
|
844
|
+
}
|
|
845
|
+
var HAZARD_LABELS = {
|
|
846
|
+
"global-box-sizing-reset": "A global box-sizing reset escapes this widget's scope.",
|
|
847
|
+
"global-button-input-unset": "A global button/input unset rule is active.",
|
|
848
|
+
"tailwind-preflight-after-ours": "A Tailwind preflight is loaded after this widget's CSS.",
|
|
849
|
+
"global-margin-padding-reset": "A global margin/padding reset is active.",
|
|
850
|
+
"conflicting-layer-order": "A conflicting @layer declaration order was detected.",
|
|
851
|
+
"global-img-max-width": "A global img max-width rule fights this widget's media components.",
|
|
852
|
+
"host-css-reset-library": "A host-level CSS reset library (e.g. normalize.css) loads after this widget's CSS.",
|
|
853
|
+
"global-focus-outline-removed": "A global :focus outline removal defeats this widget's focus-visible ring."
|
|
854
|
+
};
|
|
855
|
+
function detectHazards() {
|
|
856
|
+
if (typeof document === "undefined") {
|
|
857
|
+
return [];
|
|
858
|
+
}
|
|
859
|
+
const probe = document.createElement("div");
|
|
860
|
+
probe.setAttribute("data-kf-host-css-probe", "");
|
|
861
|
+
probe.style.position = "absolute";
|
|
862
|
+
probe.style.visibility = "hidden";
|
|
863
|
+
probe.style.pointerEvents = "none";
|
|
864
|
+
document.body.appendChild(probe);
|
|
865
|
+
const button = document.createElement("button");
|
|
866
|
+
probe.appendChild(button);
|
|
867
|
+
const img = document.createElement("img");
|
|
868
|
+
probe.appendChild(img);
|
|
869
|
+
const buttonStyle = getComputedStyle(button);
|
|
870
|
+
const imgStyle = getComputedStyle(img);
|
|
871
|
+
const probeStyle = getComputedStyle(probe);
|
|
872
|
+
const hazards = [];
|
|
873
|
+
if (probeStyle.boxSizing !== "border-box" && probeStyle.boxSizing !== "content-box") {
|
|
874
|
+
hazards.push("global-box-sizing-reset");
|
|
875
|
+
}
|
|
876
|
+
if (buttonStyle.appearance === "none" && buttonStyle.border === "0px none") {
|
|
877
|
+
hazards.push("global-button-input-unset");
|
|
878
|
+
}
|
|
879
|
+
if (probeStyle.margin !== "" && probeStyle.margin === "0px" && probeStyle.padding === "0px") {
|
|
880
|
+
hazards.push("global-margin-padding-reset");
|
|
881
|
+
}
|
|
882
|
+
if (imgStyle.maxWidth === "100%") {
|
|
883
|
+
hazards.push("global-img-max-width");
|
|
884
|
+
}
|
|
885
|
+
if (buttonStyle.outlineStyle === "none") {
|
|
886
|
+
hazards.push("global-focus-outline-removed");
|
|
887
|
+
}
|
|
888
|
+
document.body.removeChild(probe);
|
|
889
|
+
return hazards;
|
|
890
|
+
}
|
|
891
|
+
function HostCssCompatibilityProbe({
|
|
892
|
+
style
|
|
893
|
+
} = {}) {
|
|
894
|
+
const chrome = useKaafilChrome();
|
|
895
|
+
const [hazards, setHazards] = useState(null);
|
|
896
|
+
useEffect(() => {
|
|
897
|
+
if (isDevelopment()) {
|
|
898
|
+
setHazards(detectHazards());
|
|
899
|
+
}
|
|
900
|
+
}, []);
|
|
901
|
+
if (!isDevelopment() || hazards === null) {
|
|
902
|
+
return null;
|
|
903
|
+
}
|
|
904
|
+
return /* @__PURE__ */ jsxs(
|
|
905
|
+
"div",
|
|
906
|
+
{
|
|
907
|
+
style: tokenStyle(style, {
|
|
908
|
+
border: "1px solid #999",
|
|
909
|
+
padding: "0.75rem",
|
|
910
|
+
borderRadius: "4px"
|
|
911
|
+
}),
|
|
912
|
+
children: [
|
|
913
|
+
/* @__PURE__ */ jsx("p", { style: { margin: 0, fontWeight: 600 }, children: chrome.t("probe.hostCss.title") }),
|
|
914
|
+
hazards.length === 0 ? /* @__PURE__ */ jsx("p", { style: { margin: "0.5rem 0 0" }, children: chrome.t("probe.hostCss.clean") }) : /* @__PURE__ */ jsx("ul", { style: { margin: "0.5rem 0 0" }, children: hazards.map((hazard) => /* @__PURE__ */ jsx("li", { children: HAZARD_LABELS[hazard] }, hazard)) }),
|
|
915
|
+
hazards.length > 0 ? /* @__PURE__ */ jsxs("p", { style: { margin: "0.5rem 0 0" }, children: [
|
|
916
|
+
"Recommended: pass ",
|
|
917
|
+
/* @__PURE__ */ jsx("code", { children: 'isolation="shadow"' }),
|
|
918
|
+
" to <KaafilUIKitProvider> (05-theming-and-branding.md \xA77, rung 2)."
|
|
919
|
+
] }) : null
|
|
920
|
+
]
|
|
921
|
+
}
|
|
922
|
+
);
|
|
923
|
+
}
|
|
924
|
+
function KaafilSessionProbe({
|
|
925
|
+
expectedEnvironment,
|
|
926
|
+
style
|
|
927
|
+
}) {
|
|
928
|
+
const session = useSession();
|
|
929
|
+
const chrome = useKaafilChrome();
|
|
930
|
+
if (session.status === "expired") {
|
|
931
|
+
return /* @__PURE__ */ jsx(
|
|
932
|
+
"div",
|
|
933
|
+
{
|
|
934
|
+
role: "status",
|
|
935
|
+
style: tokenStyle(style, {
|
|
936
|
+
border: "1px solid #c00",
|
|
937
|
+
padding: "0.75rem",
|
|
938
|
+
borderRadius: "4px"
|
|
939
|
+
}),
|
|
940
|
+
children: "Tokens invalid or already expired at mount \u2014 the values handed to <KaafilUIKitProvider> were rejected before a successful open (00-decisions.md U-014)."
|
|
941
|
+
}
|
|
942
|
+
);
|
|
943
|
+
}
|
|
944
|
+
if (expectedEnvironment !== void 0 && session.status === "authenticated" && session.environment !== expectedEnvironment) {
|
|
945
|
+
return /* @__PURE__ */ jsxs(
|
|
946
|
+
"div",
|
|
947
|
+
{
|
|
948
|
+
role: "status",
|
|
949
|
+
style: tokenStyle(style, {
|
|
950
|
+
border: "1px solid #c00",
|
|
951
|
+
padding: "0.75rem",
|
|
952
|
+
borderRadius: "4px"
|
|
953
|
+
}),
|
|
954
|
+
children: [
|
|
955
|
+
'Wrong environment \u2014 expected "',
|
|
956
|
+
expectedEnvironment,
|
|
957
|
+
'" but the opened credential is "',
|
|
958
|
+
session.environment,
|
|
959
|
+
'"',
|
|
960
|
+
session.environment === "test" && expectedEnvironment === "live" ? " (test key on live)." : "."
|
|
961
|
+
]
|
|
962
|
+
}
|
|
963
|
+
);
|
|
964
|
+
}
|
|
965
|
+
if (session.status === "opening") {
|
|
966
|
+
return /* @__PURE__ */ jsx("div", { role: "status", style: tokenStyle(style), children: chrome.t("chrome.loading") });
|
|
967
|
+
}
|
|
968
|
+
return /* @__PURE__ */ jsxs(
|
|
969
|
+
"div",
|
|
970
|
+
{
|
|
971
|
+
style: tokenStyle(style, {
|
|
972
|
+
border: "1px solid #0a0",
|
|
973
|
+
padding: "0.75rem",
|
|
974
|
+
borderRadius: "4px"
|
|
975
|
+
}),
|
|
976
|
+
children: [
|
|
977
|
+
/* @__PURE__ */ jsx("p", { style: { margin: 0 }, children: chrome.t("probe.session.ok") }),
|
|
978
|
+
/* @__PURE__ */ jsxs("dl", { style: { margin: "0.5rem 0 0" }, children: [
|
|
979
|
+
/* @__PURE__ */ jsx("dt", { children: chrome.t("probe.session.credentialKind") }),
|
|
980
|
+
/* @__PURE__ */ jsx("dd", { children: session.persona }),
|
|
981
|
+
/* @__PURE__ */ jsx("dt", { children: chrome.t("probe.session.environment") }),
|
|
982
|
+
/* @__PURE__ */ jsx("dd", { children: session.environment }),
|
|
983
|
+
session.agencyRef !== void 0 ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
984
|
+
/* @__PURE__ */ jsx("dt", { children: chrome.t("probe.session.agency") }),
|
|
985
|
+
/* @__PURE__ */ jsx("dd", { children: session.agencyRef })
|
|
986
|
+
] }) : null
|
|
987
|
+
] })
|
|
988
|
+
]
|
|
989
|
+
}
|
|
990
|
+
);
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
export { AppShell, ConfigShell, ErrorShell, HostCssCompatibilityProbe, KaafilSessionProbe, KaafilUIKitProvider, NotImplementedError, OfflineShell, SessionShell, TelemetryShell, ThemeShell, useBlobStatus, useDefaultCapabilityViews, useFeedbackNps, useJourney, useResolvedSetting, useSnapshotEntity, useStaleness, useTreks };
|
|
994
|
+
//# sourceMappingURL=index.js.map
|
|
995
|
+
//# sourceMappingURL=index.js.map
|