@admin-layout/client 12.2.4-alpha.85 → 12.2.5-alpha.15
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/lib/__tests__/__fixtures__/defaultSettingsExample.d.ts.map +1 -1
- package/lib/config/defaultSettings.d.ts +2 -0
- package/lib/config/defaultSettings.d.ts.map +1 -1
- package/lib/config/defaultSettings.js +4 -0
- package/lib/config/defaultSettings.js.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.native.js +1 -1
- package/lib/interfaces/settings.d.ts +1 -0
- package/lib/interfaces/settings.d.ts.map +1 -1
- package/lib/utils/flightCards.d.ts +198 -0
- package/lib/utils/flightCards.d.ts.map +1 -0
- package/lib/utils/flightCards.js +366 -0
- package/lib/utils/flightCards.js.map +1 -0
- package/lib/utils/flightCards.test.d.ts +2 -0
- package/lib/utils/flightCards.test.d.ts.map +1 -0
- package/lib/utils/index.d.ts +2 -0
- package/lib/utils/index.d.ts.map +1 -1
- package/lib/utils/resultCards.d.ts +241 -0
- package/lib/utils/resultCards.d.ts.map +1 -0
- package/lib/utils/resultCards.js +640 -0
- package/lib/utils/resultCards.js.map +1 -0
- package/lib/utils/resultCards.test.d.ts +2 -0
- package/lib/utils/resultCards.test.d.ts.map +1 -0
- package/package.json +4 -4
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Flight cards: the contract a travel result uses to describe a flight offer,
|
|
3
|
+
* and the pure view model that turns it into the strings a card shows.
|
|
4
|
+
*
|
|
5
|
+
* It lives here, in the platform-neutral client package, because two
|
|
6
|
+
* renderers share it: the tailwind chat card (ai-chat-ext) on the web and the
|
|
7
|
+
* gluestack card on mobile. One model means a flight reads identically on both.
|
|
8
|
+
*
|
|
9
|
+
* Times are the airport's local wall clock, read straight from the ISO string
|
|
10
|
+
* and never passed through `Date` in the viewer's zone: 11:05 in San
|
|
11
|
+
* Francisco must read 11:05 in Tokyo too.
|
|
12
|
+
*/
|
|
13
|
+
const WALL_CLOCK = /T(\d{2}):(\d{2})/;
|
|
14
|
+
const CALENDAR_DATE = /^(\d{4})-(\d{2})-(\d{2})/;
|
|
15
|
+
const wallClock = (iso) => {
|
|
16
|
+
const m = iso ? WALL_CLOCK.exec(iso) : null;
|
|
17
|
+
return m ? `${m[1]}:${m[2]}` : undefined;
|
|
18
|
+
};
|
|
19
|
+
const utcDay = (iso) => {
|
|
20
|
+
const m = iso ? CALENDAR_DATE.exec(iso) : null;
|
|
21
|
+
return m ? Date.UTC(Number(m[1]), Number(m[2]) - 1, Number(m[3])) : undefined;
|
|
22
|
+
};
|
|
23
|
+
const dayOffset = (departAt, arriveAt) => {
|
|
24
|
+
const a = utcDay(departAt);
|
|
25
|
+
const b = utcDay(arriveAt);
|
|
26
|
+
if (a == null || b == null)
|
|
27
|
+
return undefined;
|
|
28
|
+
const days = Math.round((b - a) / 86_400_000);
|
|
29
|
+
return days > 0 ? `+${days}` : undefined;
|
|
30
|
+
};
|
|
31
|
+
/** "Thu, Oct 16" from the calendar date in the ISO string. */
|
|
32
|
+
const dateLabel = (iso) => {
|
|
33
|
+
const day = utcDay(iso);
|
|
34
|
+
if (day == null)
|
|
35
|
+
return undefined;
|
|
36
|
+
return new Date(day).toLocaleDateString('en-US', {
|
|
37
|
+
weekday: 'short',
|
|
38
|
+
month: 'short',
|
|
39
|
+
day: 'numeric',
|
|
40
|
+
timeZone: 'UTC',
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
const stopsLabel = (stops) => {
|
|
44
|
+
if (typeof stops !== 'number' || !Number.isFinite(stops) || stops < 0)
|
|
45
|
+
return undefined;
|
|
46
|
+
if (stops === 0)
|
|
47
|
+
return 'Nonstop';
|
|
48
|
+
return stops === 1 ? '1 stop' : `${stops} stops`;
|
|
49
|
+
};
|
|
50
|
+
const durationLabel = (minutes) => {
|
|
51
|
+
if (typeof minutes !== 'number' || !Number.isFinite(minutes) || minutes <= 0)
|
|
52
|
+
return undefined;
|
|
53
|
+
const h = Math.floor(minutes / 60);
|
|
54
|
+
const m = Math.round(minutes % 60);
|
|
55
|
+
if (h === 0)
|
|
56
|
+
return `${m}m`;
|
|
57
|
+
return m === 0 ? `${h}h` : `${h}h ${m}m`;
|
|
58
|
+
};
|
|
59
|
+
const formatCurrency = (amount, currency) => {
|
|
60
|
+
try {
|
|
61
|
+
return (new Intl.NumberFormat('en-US', {
|
|
62
|
+
style: 'currency',
|
|
63
|
+
currency,
|
|
64
|
+
maximumFractionDigits: 0,
|
|
65
|
+
})
|
|
66
|
+
.format(amount)
|
|
67
|
+
// Intl pads "PKR 17,500" with a no-break space; a plain one wraps and compares sanely.
|
|
68
|
+
.replace(/\u00a0/g, ' '));
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
// An unknown currency code must not take the whole card down.
|
|
72
|
+
return `${Math.round(amount)} ${currency}`;
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
/** A provider label written as "<ISO code> <amount>", e.g. "USD 61.00" or "PKR 17,500". */
|
|
76
|
+
const CODE_AMOUNT = /^([A-Z]{3})\s+([\d,]+(?:\.\d+)?)$/;
|
|
77
|
+
const flightPrice = (item, currency = 'USD') => {
|
|
78
|
+
if (item.priceLabel) {
|
|
79
|
+
// "USD 61.00" reads as "$61": same currency, the way a fare is printed.
|
|
80
|
+
const m = CODE_AMOUNT.exec(item.priceLabel.trim());
|
|
81
|
+
if (m) {
|
|
82
|
+
const amount = Number(m[2].replace(/,/g, ''));
|
|
83
|
+
if (Number.isFinite(amount))
|
|
84
|
+
return formatCurrency(amount, m[1]);
|
|
85
|
+
}
|
|
86
|
+
return item.priceLabel;
|
|
87
|
+
}
|
|
88
|
+
if (typeof item.price !== 'number' || !Number.isFinite(item.price))
|
|
89
|
+
return undefined;
|
|
90
|
+
return formatCurrency(item.price, currency);
|
|
91
|
+
};
|
|
92
|
+
/** The numeric fare, from `price` or parsed out of the label; undefined when neither is usable. */
|
|
93
|
+
const flightPriceValue = (item) => {
|
|
94
|
+
if (typeof item.price === 'number' && Number.isFinite(item.price) && item.price > 0)
|
|
95
|
+
return item.price;
|
|
96
|
+
const digits = item.priceLabel?.replace(/[^\d.]/g, '');
|
|
97
|
+
const parsed = digits ? Number(digits) : NaN;
|
|
98
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : undefined;
|
|
99
|
+
};
|
|
100
|
+
const CABIN_LABELS = {
|
|
101
|
+
economy: 'Economy',
|
|
102
|
+
premium_economy: 'Premium economy',
|
|
103
|
+
premium: 'Premium economy',
|
|
104
|
+
business: 'Business',
|
|
105
|
+
first: 'First',
|
|
106
|
+
};
|
|
107
|
+
/** "premium_economy" → "Premium economy"; plain economy is the default and reads as nothing. */
|
|
108
|
+
const cabinLabel = (cabinClass) => {
|
|
109
|
+
const key = cabinClass
|
|
110
|
+
?.trim()
|
|
111
|
+
.toLowerCase()
|
|
112
|
+
.replace(/[\s-]+/g, '_');
|
|
113
|
+
if (!key || key === 'economy')
|
|
114
|
+
return undefined;
|
|
115
|
+
return CABIN_LABELS[key] ?? key.replace(/_/g, ' ').replace(/^\w/, (c) => c.toUpperCase());
|
|
116
|
+
};
|
|
117
|
+
const bagsLabel = (checked, carryOn) => {
|
|
118
|
+
const n = (v) => (typeof v === 'number' && Number.isFinite(v) && v >= 0 ? Math.floor(v) : undefined);
|
|
119
|
+
const bags = n(checked);
|
|
120
|
+
if (bags != null && bags > 0)
|
|
121
|
+
return bags === 1 ? '1 checked bag' : `${bags} checked bags`;
|
|
122
|
+
if (bags === 0)
|
|
123
|
+
return (n(carryOn) ?? 0) > 0 ? 'Carry-on only' : 'No checked bag';
|
|
124
|
+
return undefined;
|
|
125
|
+
};
|
|
126
|
+
/**
|
|
127
|
+
* "Lufthansa Economy Comfort · 1 checked bag · One way": the airline with its
|
|
128
|
+
* fare brand (or a non-economy cabin), the bags the fare includes, separate
|
|
129
|
+
* tickets when they are, and the trip type. Undefined when the offer says
|
|
130
|
+
* nothing about its fare beyond the trip type, so a card never shows a line
|
|
131
|
+
* of defaults.
|
|
132
|
+
*/
|
|
133
|
+
const fareLineLabel = (flight, roundTrip) => {
|
|
134
|
+
const brand = flight.fareBrand?.trim() || cabinLabel(flight.cabinClass);
|
|
135
|
+
const bags = bagsLabel(flight.checkedBags, flight.carryOnBags);
|
|
136
|
+
const selfTransfer = flight.selfTransfer === true ? 'Self-transfer (separate tickets)' : undefined;
|
|
137
|
+
if (!brand && !bags && !selfTransfer)
|
|
138
|
+
return undefined;
|
|
139
|
+
const fare = [flight.airline?.trim(), brand].filter(Boolean).join(' ') || undefined;
|
|
140
|
+
return [fare, bags, selfTransfer, roundTrip ? 'Round trip' : 'One way'].filter(Boolean).join(' · ');
|
|
141
|
+
};
|
|
142
|
+
/** An IATA (2 chars, at least one letter) or ICAO (3 letters) airline code, then the number. */
|
|
143
|
+
const FLIGHT_NUMBER = /^([A-Z]{2,3}|[A-Z][0-9]|[0-9][A-Z])\s*(\d{1,4}[A-Z]?)$/i;
|
|
144
|
+
/** "PA201" → "PA 201"; anything else is shown as written. */
|
|
145
|
+
const formatFlightNumber = (raw) => {
|
|
146
|
+
const m = FLIGHT_NUMBER.exec(raw.trim());
|
|
147
|
+
return m ? `${m[1].toUpperCase()} ${m[2].toUpperCase()}` : raw.trim();
|
|
148
|
+
};
|
|
149
|
+
const flightNumberLabel = (numbers) => {
|
|
150
|
+
const list = (numbers ?? []).map((n) => n?.trim()).filter(Boolean);
|
|
151
|
+
if (list.length === 0)
|
|
152
|
+
return undefined;
|
|
153
|
+
const shown = list.slice(0, 2).map(formatFlightNumber);
|
|
154
|
+
return list.length > 2 ? `${shown.join(' · ')} +${list.length - 2}` : shown.join(' · ');
|
|
155
|
+
};
|
|
156
|
+
/** The two-letter tile for an airline: its IATA prefix when a flight number carries one, else initials. */
|
|
157
|
+
const airlineCode = (airline, flightNumbers) => {
|
|
158
|
+
const first = flightNumbers?.find((n) => n && FLIGHT_NUMBER.test(n.trim()));
|
|
159
|
+
if (first)
|
|
160
|
+
return FLIGHT_NUMBER.exec(first.trim())[1].toUpperCase().slice(0, 2);
|
|
161
|
+
const words = (airline ?? '')
|
|
162
|
+
.split(/[\s,/&-]+/)
|
|
163
|
+
.map((w) => w.replace(/[^A-Za-z0-9]/g, ''))
|
|
164
|
+
.filter(Boolean);
|
|
165
|
+
if (words.length === 0)
|
|
166
|
+
return '✈';
|
|
167
|
+
if (words.length === 1)
|
|
168
|
+
return words[0].slice(0, 2).toUpperCase();
|
|
169
|
+
return (words[0][0] + words[1][0]).toUpperCase();
|
|
170
|
+
};
|
|
171
|
+
/** A stable palette slot for an airline name, so Airblue is the same colour on every card. */
|
|
172
|
+
const airlineTone = (airline, slots = 8) => {
|
|
173
|
+
const s = (airline ?? '').toLowerCase();
|
|
174
|
+
let h = 0;
|
|
175
|
+
for (let i = 0; i < s.length; i++)
|
|
176
|
+
h = (h * 31 + s.charCodeAt(i)) >>> 0;
|
|
177
|
+
return h % slots;
|
|
178
|
+
};
|
|
179
|
+
const sliceView = (s) => ({
|
|
180
|
+
origin: s.origin,
|
|
181
|
+
destination: s.destination,
|
|
182
|
+
departTime: wallClock(s.departAt),
|
|
183
|
+
arriveTime: wallClock(s.arriveAt),
|
|
184
|
+
dayOffset: dayOffset(s.departAt, s.arriveAt),
|
|
185
|
+
stops: stopsLabel(s.stops),
|
|
186
|
+
stopCount: typeof s.stops === 'number' && Number.isFinite(s.stops) && s.stops >= 0 ? s.stops : undefined,
|
|
187
|
+
duration: durationLabel(s.durationMinutes),
|
|
188
|
+
durationMinutes: typeof s.durationMinutes === 'number' && Number.isFinite(s.durationMinutes) && s.durationMinutes > 0
|
|
189
|
+
? s.durationMinutes
|
|
190
|
+
: undefined,
|
|
191
|
+
date: dateLabel(s.departAt),
|
|
192
|
+
});
|
|
193
|
+
/** True when the attachment is a flight result, so the card shows flights, not stays. */
|
|
194
|
+
const isFlightAttachment = (a) => !!a?.properties?.some((p) => (p.flight?.slices?.length ?? 0) > 0);
|
|
195
|
+
const toFlightCard = (item, index, currency) => {
|
|
196
|
+
const flight = item.flight;
|
|
197
|
+
const views = (flight?.slices ?? []).filter((s) => s?.origin && s?.destination).map(sliceView);
|
|
198
|
+
const roundTrip = views.length > 1;
|
|
199
|
+
const slices = views.map((v) => ({
|
|
200
|
+
...v,
|
|
201
|
+
meta: (roundTrip ? [v.duration, v.stops] : [v.duration]).filter(Boolean).join(' · ') || undefined,
|
|
202
|
+
}));
|
|
203
|
+
if (!flight || slices.length === 0)
|
|
204
|
+
return null;
|
|
205
|
+
const outbound = flight.slices[0];
|
|
206
|
+
const seller = flight.seller?.trim() || undefined;
|
|
207
|
+
const airline = flight.airline?.trim() || undefined;
|
|
208
|
+
const date = dateLabel(outbound.departAt);
|
|
209
|
+
const header = [seller, date].filter(Boolean).join(' · ') || `${slices[0].origin} to ${slices[0].destination}`;
|
|
210
|
+
// One direction: say how it flies. A round trip already shows stops per
|
|
211
|
+
// row, so the footer names the trip type instead of repeating them.
|
|
212
|
+
const how = roundTrip ? 'Round trip' : slices[0].stops;
|
|
213
|
+
const footer = [airline || item.title, how].filter(Boolean).join(' · ');
|
|
214
|
+
const fareLine = fareLineLabel(flight, roundTrip);
|
|
215
|
+
const price = flightPrice(item, currency);
|
|
216
|
+
const spoken = slices
|
|
217
|
+
.map((s) => `${s.origin} ${s.departTime ?? ''} to ${s.destination} ${s.arriveTime ?? ''}${s.dayOffset === '+1' ? ' next day' : s.dayOffset ? ` ${s.dayOffset.slice(1)} days later` : ''}${s.stops ? `, ${s.stops.toLowerCase()}` : ''}`)
|
|
218
|
+
.join('; returning ');
|
|
219
|
+
const minutes = slices.map((s) => s.durationMinutes);
|
|
220
|
+
const totalMinutes = minutes.every((m) => m != null) ? minutes.reduce((a, b) => a + b, 0) : undefined;
|
|
221
|
+
return {
|
|
222
|
+
key: item.id ?? `flight-${index}`,
|
|
223
|
+
url: item.url,
|
|
224
|
+
header,
|
|
225
|
+
sellerInitial: seller ? seller.charAt(0).toUpperCase() : undefined,
|
|
226
|
+
slices,
|
|
227
|
+
footer,
|
|
228
|
+
...(fareLine ? { fareLine } : {}),
|
|
229
|
+
price,
|
|
230
|
+
accessibleLabel: [
|
|
231
|
+
flight.airline,
|
|
232
|
+
spoken.replace(/\s+/g, ' ').trim(),
|
|
233
|
+
fareLine,
|
|
234
|
+
price,
|
|
235
|
+
date,
|
|
236
|
+
seller && `sold by ${seller}`,
|
|
237
|
+
]
|
|
238
|
+
.filter(Boolean)
|
|
239
|
+
.join(', '),
|
|
240
|
+
airline,
|
|
241
|
+
airlineCode: airlineCode(airline, flight.flightNumbers),
|
|
242
|
+
airlineTone: airlineTone(airline ?? item.title),
|
|
243
|
+
flightNumber: flightNumberLabel(flight.flightNumbers),
|
|
244
|
+
seller,
|
|
245
|
+
date,
|
|
246
|
+
cabin: cabinLabel(flight.cabinClass),
|
|
247
|
+
roundTrip,
|
|
248
|
+
...(flight.selfTransfer === true ? { selfTransfer: true } : {}),
|
|
249
|
+
priceValue: flightPriceValue(item),
|
|
250
|
+
totalMinutes,
|
|
251
|
+
badges: [],
|
|
252
|
+
};
|
|
253
|
+
};
|
|
254
|
+
const BADGE_WORDS = {
|
|
255
|
+
cheapest: 'cheapest',
|
|
256
|
+
fastest: 'fastest',
|
|
257
|
+
best: 'best value',
|
|
258
|
+
};
|
|
259
|
+
const flightBadgeLabel = (badge) => badge === 'best' ? 'Best value' : badge === 'cheapest' ? 'Cheapest' : 'Fastest';
|
|
260
|
+
/**
|
|
261
|
+
* Labels the standouts of a result set: the cheapest fare, the shortest trip,
|
|
262
|
+
* and, when it is a third card, the best price-for-time. Needs two priced
|
|
263
|
+
* offers to mean anything; a lone card gets no badge. Cards keep their order.
|
|
264
|
+
* Self-transfer fares only compete when the set has nothing else.
|
|
265
|
+
*/
|
|
266
|
+
const rankFlightCards = (cards) => {
|
|
267
|
+
// Separate tickets are never "Cheapest" or "Fastest" while a protected fare
|
|
268
|
+
// is in the set: the badge would sell a trip whose missed connection
|
|
269
|
+
// nobody covers.
|
|
270
|
+
const pricedAll = cards.filter((c) => c.priceValue != null);
|
|
271
|
+
const pricedProtected = pricedAll.filter((c) => !c.selfTransfer);
|
|
272
|
+
const priced = pricedProtected.length ? pricedProtected : pricedAll;
|
|
273
|
+
if (priced.length < 2)
|
|
274
|
+
return cards.map((c) => ({ ...c, badges: [] }));
|
|
275
|
+
const byPrice = (a, b) => a.priceValue - b.priceValue || (a.totalMinutes ?? Infinity) - (b.totalMinutes ?? Infinity);
|
|
276
|
+
const cheapest = [...priced].sort(byPrice)[0];
|
|
277
|
+
const timed = priced.filter((c) => c.totalMinutes != null);
|
|
278
|
+
const fastest = timed.length
|
|
279
|
+
? [...timed].sort((a, b) => a.totalMinutes - b.totalMinutes || a.priceValue - b.priceValue)[0]
|
|
280
|
+
: undefined;
|
|
281
|
+
let best;
|
|
282
|
+
if (fastest && timed.length >= 2) {
|
|
283
|
+
const minPrice = cheapest.priceValue;
|
|
284
|
+
const minMinutes = fastest.totalMinutes;
|
|
285
|
+
const score = (c) => c.priceValue / minPrice + c.totalMinutes / minMinutes;
|
|
286
|
+
best = [...timed].sort((a, b) => score(a) - score(b) || byPrice(a, b))[0];
|
|
287
|
+
}
|
|
288
|
+
return cards.map((c) => {
|
|
289
|
+
const badges = [];
|
|
290
|
+
if (c === cheapest)
|
|
291
|
+
badges.push('cheapest');
|
|
292
|
+
if (fastest && c === fastest)
|
|
293
|
+
badges.push('fastest');
|
|
294
|
+
// "Best value" only when it is a different card: the cheapest or
|
|
295
|
+
// fastest already says more than a derived score would.
|
|
296
|
+
if (best && c === best && c !== cheapest && c !== fastest)
|
|
297
|
+
badges.push('best');
|
|
298
|
+
if (badges.length === 0)
|
|
299
|
+
return { ...c, badges };
|
|
300
|
+
return {
|
|
301
|
+
...c,
|
|
302
|
+
badges,
|
|
303
|
+
accessibleLabel: `${badges.map((b) => BADGE_WORDS[b]).join(' and ')}, ${c.accessibleLabel}`,
|
|
304
|
+
};
|
|
305
|
+
});
|
|
306
|
+
};
|
|
307
|
+
/** Every offer as a ranked card; stays and unusable items are skipped. */
|
|
308
|
+
const toFlightCards = (a) => rankFlightCards((a.properties ?? [])
|
|
309
|
+
.map((p, i) => toFlightCard(p, i, a.currency))
|
|
310
|
+
.filter((c) => c !== null));
|
|
311
|
+
/** A stable ordering of the cards; `recommended` is the order the agent returned them in. */
|
|
312
|
+
const sortFlightCards = (cards, sort) => {
|
|
313
|
+
if (sort === 'recommended')
|
|
314
|
+
return cards;
|
|
315
|
+
const metric = (c) => {
|
|
316
|
+
if (sort === 'cheapest')
|
|
317
|
+
return c.priceValue ?? Infinity;
|
|
318
|
+
if (sort === 'fastest')
|
|
319
|
+
return c.totalMinutes ?? Infinity;
|
|
320
|
+
return c.slices[0]?.departTime ?? '99:99';
|
|
321
|
+
};
|
|
322
|
+
return cards
|
|
323
|
+
.map((c, index) => ({ c, index, m: metric(c) }))
|
|
324
|
+
.sort((a, b) => (a.m < b.m ? -1 : a.m > b.m ? 1 : 0) || a.index - b.index)
|
|
325
|
+
.map((x) => x.c);
|
|
326
|
+
};
|
|
327
|
+
const flightResultSummary = (a, cards = toFlightCards(a)) => {
|
|
328
|
+
const first = cards[0];
|
|
329
|
+
const out = first?.slices[0];
|
|
330
|
+
const back = first?.roundTrip ? first.slices[first.slices.length - 1] : undefined;
|
|
331
|
+
const roundTrip = !!back;
|
|
332
|
+
const dates = new Set(cards.map((c) => c.date ?? ''));
|
|
333
|
+
const sameDate = dates.size <= 1;
|
|
334
|
+
const outDate = sameDate ? first?.date : undefined;
|
|
335
|
+
const date = outDate ? [outDate, back?.date].filter(Boolean).join(' – ') : undefined;
|
|
336
|
+
const priced = cards.filter((c) => c.priceValue != null);
|
|
337
|
+
const cheapestCard = priced.length ? [...priced].sort((x, y) => x.priceValue - y.priceValue)[0] : undefined;
|
|
338
|
+
const sellers = new Set(cards.map((c) => c.seller ?? ''));
|
|
339
|
+
const seller = sellers.size === 1 ? first?.seller : undefined;
|
|
340
|
+
const picks = [];
|
|
341
|
+
for (const badge of ['cheapest', 'fastest', 'best']) {
|
|
342
|
+
const card = cards.find((c) => c.badges.includes(badge));
|
|
343
|
+
if (!card)
|
|
344
|
+
continue;
|
|
345
|
+
picks.push({
|
|
346
|
+
badge,
|
|
347
|
+
label: flightBadgeLabel(badge),
|
|
348
|
+
key: card.key,
|
|
349
|
+
price: card.price,
|
|
350
|
+
duration: durationLabel(card.totalMinutes),
|
|
351
|
+
airline: card.airline,
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
return {
|
|
355
|
+
route: out ? `${out.origin} ${roundTrip ? '⇄' : '→'} ${out.destination}` : undefined,
|
|
356
|
+
origin: out?.origin,
|
|
357
|
+
destination: out?.destination,
|
|
358
|
+
roundTrip,
|
|
359
|
+
date,
|
|
360
|
+
sameDate,
|
|
361
|
+
count: a.totalCount ?? cards.length,
|
|
362
|
+
fromPrice: cheapestCard?.price,
|
|
363
|
+
seller,
|
|
364
|
+
picks,
|
|
365
|
+
};
|
|
366
|
+
};export{airlineCode,airlineTone,cabinLabel,dateLabel,dayOffset,durationLabel,fareLineLabel,flightBadgeLabel,flightNumberLabel,flightPrice,flightPriceValue,flightResultSummary,isFlightAttachment,rankFlightCards,sortFlightCards,stopsLabel,toFlightCard,toFlightCards,wallClock};//# sourceMappingURL=flightCards.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flightCards.js","sources":["../../src/utils/flightCards.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flightCards.test.d.ts","sourceRoot":"","sources":["../../src/utils/flightCards.test.ts"],"names":[],"mappings":""}
|
package/lib/utils/index.d.ts
CHANGED
package/lib/utils/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,WAAW,CAAC;AAC1B,cAAc,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,WAAW,CAAC;AAC1B,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC"}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Result cards for every chat widget that is a list of things to pick from:
|
|
3
|
+
* stays, rental cars, trains and buses, products, movie showtimes and jobs,
|
|
4
|
+
* plus the single resume card. Flights keep their own model (flightCards.ts);
|
|
5
|
+
* this file reuses its time, price and monogram helpers so a train reads the
|
|
6
|
+
* way a flight does.
|
|
7
|
+
*
|
|
8
|
+
* Every renderer (the tailwind chat cards on the web, any native twin) builds
|
|
9
|
+
* from these views, so the strings a card shows are decided once, here.
|
|
10
|
+
*
|
|
11
|
+
* Nothing here knows a provider. A seller's name comes from the row itself
|
|
12
|
+
* (`provider`, `merchant`, `sourceLabel`) or from the host of its link, never
|
|
13
|
+
* from a table of known sites.
|
|
14
|
+
*/
|
|
15
|
+
/** A standout a card can be labelled with once its result set is ranked. */
|
|
16
|
+
export type ResultBadge = 'cheapest' | 'fastest' | 'top-rated';
|
|
17
|
+
export declare const resultBadgeLabel: (badge: ResultBadge) => string;
|
|
18
|
+
/** Orderings a result list offers. `recommended` keeps the order the agent returned. */
|
|
19
|
+
export type ResultSort = 'recommended' | 'cheapest' | 'fastest' | 'rating' | 'departure' | 'newest';
|
|
20
|
+
/** The fields of a result row every card may read. Each vertical adds its own. */
|
|
21
|
+
export interface ResultItemLike {
|
|
22
|
+
id?: string;
|
|
23
|
+
title?: string;
|
|
24
|
+
url?: string;
|
|
25
|
+
imageUrl?: string;
|
|
26
|
+
price?: number;
|
|
27
|
+
priceLabel?: string;
|
|
28
|
+
priceUnit?: string;
|
|
29
|
+
currency?: string;
|
|
30
|
+
rating?: number;
|
|
31
|
+
reviewCount?: number;
|
|
32
|
+
reviews?: number;
|
|
33
|
+
source?: string;
|
|
34
|
+
/** The seller or operator as the row names it. */
|
|
35
|
+
provider?: string;
|
|
36
|
+
/** Display name for the source, when the row carries one. */
|
|
37
|
+
sourceLabel?: string;
|
|
38
|
+
[key: string]: unknown;
|
|
39
|
+
}
|
|
40
|
+
export interface ResultSetLike {
|
|
41
|
+
title?: string;
|
|
42
|
+
subtitle?: string;
|
|
43
|
+
totalCount?: number;
|
|
44
|
+
actionLabel?: string;
|
|
45
|
+
currency?: string;
|
|
46
|
+
properties?: ResultItemLike[];
|
|
47
|
+
[key: string]: unknown;
|
|
48
|
+
}
|
|
49
|
+
export interface ResultCardBase {
|
|
50
|
+
key: string;
|
|
51
|
+
url?: string;
|
|
52
|
+
title: string;
|
|
53
|
+
price?: string;
|
|
54
|
+
priceValue?: number;
|
|
55
|
+
rating?: number;
|
|
56
|
+
/** Where the row is sold or listed: "booking.com", "Turo", "FlixBus". */
|
|
57
|
+
sourceLabel?: string;
|
|
58
|
+
badges: ResultBadge[];
|
|
59
|
+
/** One sentence a screen reader announces for the whole card. */
|
|
60
|
+
accessibleLabel: string;
|
|
61
|
+
}
|
|
62
|
+
/** One quick pick in a result header: "Cheapest · $89 · Hotel Lux". */
|
|
63
|
+
export interface ResultPick {
|
|
64
|
+
badge: ResultBadge;
|
|
65
|
+
label: string;
|
|
66
|
+
key: string;
|
|
67
|
+
/** The figure the chip shows: a price, a duration, or a rating. */
|
|
68
|
+
value?: string;
|
|
69
|
+
/** Which card it is, in a word or two. */
|
|
70
|
+
name?: string;
|
|
71
|
+
}
|
|
72
|
+
export interface ResultSummary {
|
|
73
|
+
title: string;
|
|
74
|
+
/** "6 stays · from $89 · Sep 5 – 8" */
|
|
75
|
+
subtitle: string;
|
|
76
|
+
count: number;
|
|
77
|
+
fromPrice?: string;
|
|
78
|
+
picks: ResultPick[];
|
|
79
|
+
}
|
|
80
|
+
/** "www.booking.com" → "booking.com"; undefined for a hash or relative link. */
|
|
81
|
+
export declare const hostLabel: (url?: string) => string | undefined;
|
|
82
|
+
/** The row's own name for where it is sold, else the link's host, else its source key. */
|
|
83
|
+
export declare const sourceLabelOf: (item: ResultItemLike) => string | undefined;
|
|
84
|
+
/** "4.6" or "9.1"; scores over 5 are on a 10 scale and keep one decimal too. */
|
|
85
|
+
export declare const ratingLabel: (rating?: number) => string | undefined;
|
|
86
|
+
/** "1,284" with a compact fallback for very large counts: "12k". */
|
|
87
|
+
export declare const countLabel: (n?: number) => string | undefined;
|
|
88
|
+
interface Rankable {
|
|
89
|
+
priceValue?: number;
|
|
90
|
+
rating?: number;
|
|
91
|
+
reviewCount?: number;
|
|
92
|
+
minutes?: number;
|
|
93
|
+
}
|
|
94
|
+
/** Orders any result cards; a metric a card lacks sorts it last. */
|
|
95
|
+
export declare const sortResultCards: <T extends ResultCardBase & Rankable & {
|
|
96
|
+
departTime?: string;
|
|
97
|
+
postedDays?: number;
|
|
98
|
+
}>(cards: T[], sort: ResultSort) => T[];
|
|
99
|
+
/** What a travel result set holds; flights are read by flightCards.ts. */
|
|
100
|
+
export type TravelResultKind = 'stay' | 'car' | 'train' | 'bus';
|
|
101
|
+
/** The kind of one travel row, from its own `kind`, then its source, then its price unit. */
|
|
102
|
+
export declare const travelItemKind: (item: ResultItemLike) => TravelResultKind;
|
|
103
|
+
/** The kind most rows in the set share, so one card style renders the whole row. */
|
|
104
|
+
export declare const travelResultKind: (a?: ResultSetLike) => TravelResultKind;
|
|
105
|
+
export interface StayCardView extends ResultCardBase, Rankable {
|
|
106
|
+
imageUrl?: string;
|
|
107
|
+
/** "Downtown · 1.2 km from center" or the city. */
|
|
108
|
+
location?: string;
|
|
109
|
+
ratingText?: string;
|
|
110
|
+
reviewsText?: string;
|
|
111
|
+
/** "night", "trip". */
|
|
112
|
+
unit?: string;
|
|
113
|
+
/** "Free cancellation", "Entire home" ... as the row states it. */
|
|
114
|
+
perks: string[];
|
|
115
|
+
description?: string;
|
|
116
|
+
}
|
|
117
|
+
export declare const toStayCard: (item: ResultItemLike, index: number, currency?: string) => StayCardView | null;
|
|
118
|
+
export declare const toStayCards: (a: ResultSetLike) => StayCardView[];
|
|
119
|
+
export interface CarCardView extends ResultCardBase, Rankable {
|
|
120
|
+
imageUrl?: string;
|
|
121
|
+
/** "SUV · 5 seats · Automatic" from whatever the row states. */
|
|
122
|
+
specs?: string;
|
|
123
|
+
description?: string;
|
|
124
|
+
ratingText?: string;
|
|
125
|
+
/** "128 trips" — Turo counts trips, a rental desk counts reviews. */
|
|
126
|
+
reviewsText?: string;
|
|
127
|
+
unit: string;
|
|
128
|
+
/** A search link to a rental site rather than a priced car. */
|
|
129
|
+
isLink: boolean;
|
|
130
|
+
}
|
|
131
|
+
export declare const toCarCard: (item: ResultItemLike, index: number, currency?: string) => CarCardView | null;
|
|
132
|
+
/** Priced cars first, search links after: a link has nothing to compare. */
|
|
133
|
+
export declare const toCarCards: (a: ResultSetLike) => CarCardView[];
|
|
134
|
+
export interface GroundCardView extends ResultCardBase, Rankable {
|
|
135
|
+
mode: 'train' | 'bus';
|
|
136
|
+
operator?: string;
|
|
137
|
+
/** Monogram tile for the operator. */
|
|
138
|
+
operatorCode: string;
|
|
139
|
+
operatorTone: number;
|
|
140
|
+
departTime?: string;
|
|
141
|
+
arriveTime?: string;
|
|
142
|
+
/** "+1" when it arrives a calendar day later. */
|
|
143
|
+
dayOffset?: string;
|
|
144
|
+
/** Station, else the city. */
|
|
145
|
+
origin?: string;
|
|
146
|
+
destination?: string;
|
|
147
|
+
duration?: string;
|
|
148
|
+
stops?: string;
|
|
149
|
+
stopCount?: number;
|
|
150
|
+
/** "Sun, Oct 4". */
|
|
151
|
+
date?: string;
|
|
152
|
+
travelClass?: string;
|
|
153
|
+
/** "3 seats left" when the row says so and it is few. */
|
|
154
|
+
seatsLeft?: string;
|
|
155
|
+
/** A route-planner link (Rome2Rio, Wanderu) rather than one departure. */
|
|
156
|
+
isLink: boolean;
|
|
157
|
+
description?: string;
|
|
158
|
+
}
|
|
159
|
+
export declare const toGroundCard: (item: ResultItemLike, index: number, currency?: string) => GroundCardView | null;
|
|
160
|
+
/** Departures first, planner links after. */
|
|
161
|
+
export declare const toGroundCards: (a: ResultSetLike) => GroundCardView[];
|
|
162
|
+
export interface ProductCardView extends ResultCardBase, Rankable {
|
|
163
|
+
imageUrl?: string;
|
|
164
|
+
ratingText?: string;
|
|
165
|
+
reviewsText?: string;
|
|
166
|
+
/** "Was $129" when the row carries an original price. */
|
|
167
|
+
wasPrice?: string;
|
|
168
|
+
/** "Free delivery", "In stock" as the row states it. */
|
|
169
|
+
note?: string;
|
|
170
|
+
}
|
|
171
|
+
export declare const toProductCard: (item: ResultItemLike, index: number, currency?: string) => ProductCardView | null;
|
|
172
|
+
export declare const toProductCards: (a: ResultSetLike) => ProductCardView[];
|
|
173
|
+
export interface MovieShowtime {
|
|
174
|
+
time: string;
|
|
175
|
+
/** Booking link for that time, when the row has one per time. */
|
|
176
|
+
url?: string;
|
|
177
|
+
}
|
|
178
|
+
export interface MovieCardView extends ResultCardBase, Rankable {
|
|
179
|
+
posterUrl?: string;
|
|
180
|
+
/** "PG-13 · 2h 46m · Sci-Fi". */
|
|
181
|
+
meta?: string;
|
|
182
|
+
ratingText?: string;
|
|
183
|
+
theater?: string;
|
|
184
|
+
/** "1.2 mi · 123 Main St". */
|
|
185
|
+
place?: string;
|
|
186
|
+
/** "Today", "Sat, Oct 4". */
|
|
187
|
+
when?: string;
|
|
188
|
+
format?: string;
|
|
189
|
+
times: MovieShowtime[];
|
|
190
|
+
/** Showtimes past the ones the card shows. */
|
|
191
|
+
moreTimes: number;
|
|
192
|
+
}
|
|
193
|
+
export declare const toMovieCard: (item: ResultItemLike, index: number, currency?: string) => MovieCardView | null;
|
|
194
|
+
export declare const toMovieCards: (a: ResultSetLike) => MovieCardView[];
|
|
195
|
+
export interface JobCardView extends ResultCardBase, Rankable {
|
|
196
|
+
company?: string;
|
|
197
|
+
companyCode: string;
|
|
198
|
+
companyTone: number;
|
|
199
|
+
logoUrl?: string;
|
|
200
|
+
location?: string;
|
|
201
|
+
/** "Remote", "Hybrid", "On-site". */
|
|
202
|
+
workplace?: string;
|
|
203
|
+
salary?: string;
|
|
204
|
+
employmentType?: string;
|
|
205
|
+
/** "Today", "3d ago", "2w ago". */
|
|
206
|
+
posted?: string;
|
|
207
|
+
postedDays?: number;
|
|
208
|
+
snippet?: string;
|
|
209
|
+
easyApply: boolean;
|
|
210
|
+
}
|
|
211
|
+
/** Whole days since an ISO date; undefined for anything unparseable. */
|
|
212
|
+
export declare const daysSince: (iso: string | undefined, now: number) => number | undefined;
|
|
213
|
+
export declare const postedLabel: (days?: number) => string | undefined;
|
|
214
|
+
export declare const toJobCard: (item: ResultItemLike, index: number, now?: number) => JobCardView | null;
|
|
215
|
+
/** Jobs get no badges: "cheapest" means nothing and a rating is rarely there. */
|
|
216
|
+
export declare const toJobCards: (a: ResultSetLike, now?: number) => JobCardView[];
|
|
217
|
+
export interface ResumeCardView {
|
|
218
|
+
title: string;
|
|
219
|
+
subtitle?: string;
|
|
220
|
+
/** The person's name and headline, when the attachment carries the resume. */
|
|
221
|
+
name?: string;
|
|
222
|
+
headline?: string;
|
|
223
|
+
/** Top skills or sections, a few words each. */
|
|
224
|
+
tags: string[];
|
|
225
|
+
template?: string;
|
|
226
|
+
openUrl?: string;
|
|
227
|
+
downloadUrl?: string;
|
|
228
|
+
imageUrl?: string;
|
|
229
|
+
actionLabel: string;
|
|
230
|
+
accessibleLabel: string;
|
|
231
|
+
}
|
|
232
|
+
export declare const toResumeCard: (a: Record<string, unknown> | undefined) => ResumeCardView | null;
|
|
233
|
+
export declare const travelResultNoun: (kind: TravelResultKind) => [string, string];
|
|
234
|
+
export declare const staySummary: (a: ResultSetLike, cards?: StayCardView[]) => ResultSummary;
|
|
235
|
+
export declare const carSummary: (a: ResultSetLike, cards?: CarCardView[]) => ResultSummary;
|
|
236
|
+
export declare const groundSummary: (a: ResultSetLike, cards?: GroundCardView[]) => ResultSummary;
|
|
237
|
+
export declare const productSummary: (a: ResultSetLike, cards?: ProductCardView[]) => ResultSummary;
|
|
238
|
+
export declare const movieSummary: (a: ResultSetLike, cards?: MovieCardView[]) => ResultSummary;
|
|
239
|
+
export declare const jobSummary: (a: ResultSetLike, cards?: JobCardView[]) => ResultSummary;
|
|
240
|
+
export {};
|
|
241
|
+
//# sourceMappingURL=resultCards.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resultCards.d.ts","sourceRoot":"","sources":["../../src/utils/resultCards.ts"],"names":[],"mappings":"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"}
|