payload-reserve 2.1.1 → 2.2.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.
- package/README.md +58 -1
- package/dist/components/CalendarView/CalendarView.module.css +11 -0
- package/dist/components/CalendarView/LaneTimelineView.js +3 -1
- package/dist/components/CalendarView/LaneTimelineView.js.map +1 -1
- package/dist/components/CalendarView/index.js +8 -0
- package/dist/components/CalendarView/index.js.map +1 -1
- package/dist/defaults.js +1 -0
- package/dist/defaults.js.map +1 -1
- package/dist/endpoints/checkAvailability.js +1 -0
- package/dist/endpoints/checkAvailability.js.map +1 -1
- package/dist/endpoints/getSlots.js +1 -0
- package/dist/endpoints/getSlots.js.map +1 -1
- package/dist/endpoints/resourceAvailability.d.ts +6 -2
- package/dist/endpoints/resourceAvailability.js +19 -1
- package/dist/endpoints/resourceAvailability.js.map +1 -1
- package/dist/hooks/reservations/validateConflicts.js +1 -0
- package/dist/hooks/reservations/validateConflicts.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js.map +1 -1
- package/dist/services/AvailabilityService.d.ts +9 -2
- package/dist/services/AvailabilityService.js +26 -3
- package/dist/services/AvailabilityService.js.map +1 -1
- package/dist/translations/ar.json +1 -0
- package/dist/translations/de.json +1 -0
- package/dist/translations/en.json +1 -0
- package/dist/translations/es.json +1 -0
- package/dist/translations/fa.json +1 -0
- package/dist/translations/fr.json +1 -0
- package/dist/translations/hi.json +1 -0
- package/dist/translations/id.json +1 -0
- package/dist/translations/pl.json +1 -0
- package/dist/translations/ru.json +1 -0
- package/dist/translations/tr.json +1 -0
- package/dist/translations/zh.json +1 -0
- package/dist/types.d.ts +27 -0
- package/dist/types.js.map +1 -1
- package/dist/utilities/computeSlotStates.d.ts +2 -1
- package/dist/utilities/computeSlotStates.js +5 -1
- package/dist/utilities/computeSlotStates.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -37,6 +37,7 @@ Designed for salons, clinics, hotels, restaurants, event venues, and any busines
|
|
|
37
37
|
- **Recurring and Manual Schedules** — Weekly patterns with exception dates, or specific one-off dates
|
|
38
38
|
- **12 Bundled Languages** — Every admin string is translatable; ships with English, French, German, Spanish, Russian, Polish, Turkish, Arabic, Simplified Chinese, Indonesian, Persian/Farsi, and Hindi. Override any string or add your own language
|
|
39
39
|
- **Localization Support** — Collection field *content* can be localized when Payload localization is enabled (separate from the admin-UI language above)
|
|
40
|
+
- **External Busy** — Optional `getExternalBusy` resolver folds busy time from calendar sync, legacy booking systems, or ops tooling into availability, with distinct calendar display and fail-open error handling
|
|
40
41
|
- **Type-Safe** — Full TypeScript support with exported types
|
|
41
42
|
|
|
42
43
|
---
|
|
@@ -311,6 +312,62 @@ The `services` relationship on Resources is now optional. This lets a freshly pr
|
|
|
311
312
|
|
|
312
313
|
---
|
|
313
314
|
|
|
315
|
+
## External Busy (Calendar Sync & Other Sources)
|
|
316
|
+
|
|
317
|
+
`getExternalBusy` lets your app fold busy time that payload-reserve doesn't manage — an external calendar, a legacy booking system, ops tooling — into a resource's availability. The plugin never talks to any calendar API itself; it calls a resolver you provide once per candidate window and treats whatever it returns as busy time for that resource.
|
|
318
|
+
|
|
319
|
+
Use it to:
|
|
320
|
+
|
|
321
|
+
- Import busy time from two-way calendar sync (Google Calendar, Outlook, iCal feeds)
|
|
322
|
+
- Respect bookings made in another/legacy booking system during a migration
|
|
323
|
+
- Block maintenance/cleaning windows tracked in an ops system
|
|
324
|
+
- Reflect staff leave recorded in an HR system that isn't modeled as plugin time-off
|
|
325
|
+
|
|
326
|
+
A realistic setup keeps a local collection in sync (via webhooks or a cron job) and has the resolver run a single indexed query against it — the resolver itself never calls a remote API:
|
|
327
|
+
|
|
328
|
+
```ts
|
|
329
|
+
import type { ExternalBusyInterval, GetExternalBusy } from 'payload-reserve'
|
|
330
|
+
|
|
331
|
+
// A sync job (webhook handler or scheduled cron task) keeps this collection's
|
|
332
|
+
// rows current from whatever external source you're integrating — a
|
|
333
|
+
// Google/Outlook calendar sync, a legacy system export, an ops tool, etc.
|
|
334
|
+
// The resolver below never calls out itself; it only reads what the sync
|
|
335
|
+
// job already wrote, so it stays a single cheap, indexed query.
|
|
336
|
+
const getExternalBusy: GetExternalBusy = async ({ end, req, resourceId, start }) => {
|
|
337
|
+
const result = await req.payload.find({
|
|
338
|
+
collection: 'external-busy', // your locally-synced collection
|
|
339
|
+
where: {
|
|
340
|
+
and: [
|
|
341
|
+
{ resource: { equals: resourceId } },
|
|
342
|
+
{ start: { less_than: end.toISOString() } },
|
|
343
|
+
{ end: { greater_than: start.toISOString() } },
|
|
344
|
+
],
|
|
345
|
+
},
|
|
346
|
+
depth: 0,
|
|
347
|
+
limit: 0,
|
|
348
|
+
})
|
|
349
|
+
|
|
350
|
+
return result.docs.map(
|
|
351
|
+
(doc): ExternalBusyInterval => ({
|
|
352
|
+
start: doc.start,
|
|
353
|
+
end: doc.end,
|
|
354
|
+
label: doc.label,
|
|
355
|
+
}),
|
|
356
|
+
)
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
payloadReserve({
|
|
360
|
+
getExternalBusy,
|
|
361
|
+
})
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
- **Enforcement:** any booking (hooks, endpoints, slot listings) overlapping an interval is unavailable. An interval blocks the WHOLE resource (all `quantity` units) — external calendars aren't unit-aware.
|
|
365
|
+
- **Display:** the `resource-availability` endpoint returns the intervals as a separate `external[]` array (not mixed into `busy`), and the calendar renders them as a distinct, non-clickable hatched "External event" slot.
|
|
366
|
+
- **Fail-open:** if the resolver throws, the plugin treats it as no external busy for that call — a sync failure never blocks a real booking or breaks the grid.
|
|
367
|
+
- **Performance:** the resolver is called once per candidate window during slot computation, so keep it cheap — a local table lookup or a per-request cache, never a remote API call per invocation.
|
|
368
|
+
|
|
369
|
+
---
|
|
370
|
+
|
|
314
371
|
## Internationalization
|
|
315
372
|
|
|
316
373
|
Every admin string the plugin renders — field labels, descriptions, select options, calendar/dashboard components, and validation errors — is translatable. The plugin ships **12 languages**: English, French (`fr`), German (`de`), Spanish (`es`), Russian (`ru`), Polish (`pl`), Turkish (`tr`), Arabic (`ar`), Simplified Chinese (`zh`), Indonesian (`id`), Persian/Farsi (`fa`), and Hindi (`hi`). All but Hindi ship in Payload core and appear in the admin language switcher automatically.
|
|
@@ -340,7 +397,7 @@ This is separate from Payload **field localization** (localizing the *content* o
|
|
|
340
397
|
| Topic | Contents |
|
|
341
398
|
|-------|----------|
|
|
342
399
|
| [Getting Started](https://github.com/elghaied/payload-reserve/blob/main/docs/getting-started.md) | Installation, quick start, what gets created |
|
|
343
|
-
| [Configuration](https://github.com/elghaied/payload-reserve/blob/main/docs/configuration.md) | All plugin options with types and defaults, including `resourceOwnerMode` |
|
|
400
|
+
| [Configuration](https://github.com/elghaied/payload-reserve/blob/main/docs/configuration.md) | All plugin options with types and defaults, including `resourceOwnerMode` and `getExternalBusy` |
|
|
344
401
|
| [Collections](https://github.com/elghaied/payload-reserve/blob/main/docs/collections.md) | Services, Resources, Schedules, Customers, Reservations schemas |
|
|
345
402
|
| [Status Machine](https://github.com/elghaied/payload-reserve/blob/main/docs/status-machine.md) | Default flow, custom machines, business logic hooks, escape hatch |
|
|
346
403
|
| [Booking Features](https://github.com/elghaied/payload-reserve/blob/main/docs/booking-features.md) | Duration types, multi-resource bookings, capacity modes |
|
|
@@ -520,6 +520,17 @@
|
|
|
520
520
|
cursor: not-allowed;
|
|
521
521
|
}
|
|
522
522
|
|
|
523
|
+
.slotExternal {
|
|
524
|
+
background: repeating-linear-gradient(
|
|
525
|
+
45deg,
|
|
526
|
+
var(--theme-elevation-100),
|
|
527
|
+
var(--theme-elevation-100) 6px,
|
|
528
|
+
var(--theme-error-50) 6px,
|
|
529
|
+
var(--theme-error-50) 12px
|
|
530
|
+
);
|
|
531
|
+
cursor: not-allowed;
|
|
532
|
+
}
|
|
533
|
+
|
|
523
534
|
.slotFree {
|
|
524
535
|
cursor: pointer;
|
|
525
536
|
}
|
|
@@ -7,6 +7,7 @@ import { getDayKeyInTimezone } from '../../utilities/timezoneUtils.js';
|
|
|
7
7
|
import styles from './CalendarView.module.css';
|
|
8
8
|
import { useResourceAvailability } from './useResourceAvailability.js';
|
|
9
9
|
const SLOT_STATE_KEYS = {
|
|
10
|
+
external: 'reservation:slotExternal',
|
|
10
11
|
free: 'reservation:slotFree',
|
|
11
12
|
full: 'reservation:slotFull',
|
|
12
13
|
'off-shift': 'reservation:slotOffShift',
|
|
@@ -27,6 +28,7 @@ function Lane({ apiBase, day, endHour, onBook, resource, startHour, timeZone })
|
|
|
27
28
|
capacityMode: data.capacityMode,
|
|
28
29
|
dayEnd,
|
|
29
30
|
dayStart,
|
|
31
|
+
external: data.external,
|
|
30
32
|
quantity: data.quantity,
|
|
31
33
|
requiredPools: data.requiredPools,
|
|
32
34
|
shiftWindows: dayAvail.shiftWindows,
|
|
@@ -43,7 +45,7 @@ function Lane({ apiBase, day, endHour, onBook, resource, startHour, timeZone })
|
|
|
43
45
|
/*#__PURE__*/ _jsx("div", {
|
|
44
46
|
className: styles.laneTrack,
|
|
45
47
|
children: slots.map((s)=>{
|
|
46
|
-
const cls = s.state === 'off-shift' ? styles.slotOffShift : s.state === 'time-off' ? styles.slotTimeOff : s.state === 'full' ? styles.slotFull : styles.slotFree;
|
|
48
|
+
const cls = s.state === 'off-shift' ? styles.slotOffShift : s.state === 'time-off' ? styles.slotTimeOff : s.state === 'external' ? styles.slotExternal : s.state === 'full' ? styles.slotFull : styles.slotFree;
|
|
47
49
|
const isFree = s.state === 'free';
|
|
48
50
|
const slotLabel = `${s.start.toLocaleTimeString([], {
|
|
49
51
|
hour: '2-digit',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/CalendarView/LaneTimelineView.tsx"],"sourcesContent":["'use client'\nimport { useTranslation } from '@payloadcms/ui'\nimport React from 'react'\n\nimport type { PluginT } from '../../translations/index.js'\nimport type { SlotState } from '../../utilities/computeSlotStates.js'\n\nimport { computeSlotStates } from '../../utilities/computeSlotStates.js'\nimport { getDayKeyInTimezone } from '../../utilities/timezoneUtils.js'\nimport styles from './CalendarView.module.css'\nimport { useResourceAvailability } from './useResourceAvailability.js'\n\ntype LaneResource = { id: string; name: string }\n\nconst SLOT_STATE_KEYS: Record<SlotState, string> = {\n free: 'reservation:slotFree',\n full: 'reservation:slotFull',\n 'off-shift': 'reservation:slotOffShift',\n 'time-off': 'reservation:slotTimeOff',\n}\n\nfunction Lane({\n apiBase,\n day,\n endHour,\n onBook,\n resource,\n startHour,\n timeZone,\n}: {\n apiBase: string\n day: Date\n endHour: number\n onBook: (resourceId: string, startIso: string) => void\n resource: LaneResource\n startHour: number\n timeZone: string\n}) {\n const { t: _t } = useTranslation()\n const t = _t as PluginT\n\n const dayStart = new Date(day)\n dayStart.setHours(startHour, 0, 0, 0)\n const dayEnd = new Date(day)\n dayEnd.setHours(endHour, 0, 0, 0)\n\n const { data } = useResourceAvailability(apiBase, resource.id, dayStart, dayEnd)\n const isoDay = getDayKeyInTimezone(day, timeZone)\n const dayAvail = data?.days.find((d) => d.date === isoDay)\n\n const slots = dayAvail\n ? computeSlotStates({\n busy: data!.busy,\n capacityMode: data!.capacityMode,\n dayEnd,\n dayStart,\n quantity: data!.quantity,\n requiredPools: data!.requiredPools,\n shiftWindows: dayAvail.shiftWindows,\n step: 60,\n timeOff: dayAvail.timeOff,\n })\n : []\n\n return (\n <div className={styles.lane}>\n <div className={styles.laneLabel}>{resource.name}</div>\n <div className={styles.laneTrack}>\n {slots.map((s) => {\n const cls =\n s.state === 'off-shift'\n ? styles.slotOffShift\n : s.state === 'time-off'\n ? styles.slotTimeOff\n : s.state === '
|
|
1
|
+
{"version":3,"sources":["../../../src/components/CalendarView/LaneTimelineView.tsx"],"sourcesContent":["'use client'\nimport { useTranslation } from '@payloadcms/ui'\nimport React from 'react'\n\nimport type { PluginT } from '../../translations/index.js'\nimport type { SlotState } from '../../utilities/computeSlotStates.js'\n\nimport { computeSlotStates } from '../../utilities/computeSlotStates.js'\nimport { getDayKeyInTimezone } from '../../utilities/timezoneUtils.js'\nimport styles from './CalendarView.module.css'\nimport { useResourceAvailability } from './useResourceAvailability.js'\n\ntype LaneResource = { id: string; name: string }\n\nconst SLOT_STATE_KEYS: Record<SlotState, string> = {\n external: 'reservation:slotExternal',\n free: 'reservation:slotFree',\n full: 'reservation:slotFull',\n 'off-shift': 'reservation:slotOffShift',\n 'time-off': 'reservation:slotTimeOff',\n}\n\nfunction Lane({\n apiBase,\n day,\n endHour,\n onBook,\n resource,\n startHour,\n timeZone,\n}: {\n apiBase: string\n day: Date\n endHour: number\n onBook: (resourceId: string, startIso: string) => void\n resource: LaneResource\n startHour: number\n timeZone: string\n}) {\n const { t: _t } = useTranslation()\n const t = _t as PluginT\n\n const dayStart = new Date(day)\n dayStart.setHours(startHour, 0, 0, 0)\n const dayEnd = new Date(day)\n dayEnd.setHours(endHour, 0, 0, 0)\n\n const { data } = useResourceAvailability(apiBase, resource.id, dayStart, dayEnd)\n const isoDay = getDayKeyInTimezone(day, timeZone)\n const dayAvail = data?.days.find((d) => d.date === isoDay)\n\n const slots = dayAvail\n ? computeSlotStates({\n busy: data!.busy,\n capacityMode: data!.capacityMode,\n dayEnd,\n dayStart,\n external: data!.external,\n quantity: data!.quantity,\n requiredPools: data!.requiredPools,\n shiftWindows: dayAvail.shiftWindows,\n step: 60,\n timeOff: dayAvail.timeOff,\n })\n : []\n\n return (\n <div className={styles.lane}>\n <div className={styles.laneLabel}>{resource.name}</div>\n <div className={styles.laneTrack}>\n {slots.map((s) => {\n const cls =\n s.state === 'off-shift'\n ? styles.slotOffShift\n : s.state === 'time-off'\n ? styles.slotTimeOff\n : s.state === 'external'\n ? styles.slotExternal\n : s.state === 'full'\n ? styles.slotFull\n : styles.slotFree\n const isFree = s.state === 'free'\n const slotLabel = `${s.start.toLocaleTimeString([], {\n hour: '2-digit',\n minute: '2-digit',\n timeZone,\n })} — ${t(SLOT_STATE_KEYS[s.state])}`\n return isFree ? (\n <div\n aria-label={slotLabel}\n className={`${styles.laneCell} ${cls}`}\n key={s.start.toISOString()}\n onClick={() => onBook(resource.id, s.start.toISOString())}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n onBook(resource.id, s.start.toISOString())\n }\n }}\n role=\"button\"\n tabIndex={0}\n title={slotLabel}\n />\n ) : (\n <div\n className={`${styles.laneCell} ${cls}`}\n key={s.start.toISOString()}\n title={slotLabel}\n />\n )\n })}\n </div>\n </div>\n )\n}\n\nexport function LaneTimelineView({\n apiBase,\n day,\n endHour,\n onBook,\n resources,\n startHour,\n timeZone,\n}: {\n apiBase: string\n day: Date\n endHour: number\n onBook: (resourceId: string, startIso: string) => void\n resources: LaneResource[]\n startHour: number\n timeZone: string\n}) {\n const { t: _t } = useTranslation()\n const t = _t as PluginT\n if (resources.length === 0) {\n return <p className={styles.hint}>{t('reservation:laneNoResources')}</p>\n }\n const hours = Array.from({ length: endHour - startHour }, (_, i) => startHour + i)\n return (\n <div className={styles.lanes}>\n <div className={styles.laneHeader}>\n <div className={styles.laneLabel} />\n <div className={styles.laneTrack}>\n {hours.map((h) => (\n <div className={styles.laneTime} key={h}>\n {String(h).padStart(2, '0')}:00\n </div>\n ))}\n </div>\n </div>\n {resources.map((r) => (\n <Lane\n apiBase={apiBase}\n day={day}\n endHour={endHour}\n key={r.id}\n onBook={onBook}\n resource={r}\n startHour={startHour}\n timeZone={timeZone}\n />\n ))}\n </div>\n )\n}\n"],"names":["useTranslation","React","computeSlotStates","getDayKeyInTimezone","styles","useResourceAvailability","SLOT_STATE_KEYS","external","free","full","Lane","apiBase","day","endHour","onBook","resource","startHour","timeZone","t","_t","dayStart","Date","setHours","dayEnd","data","id","isoDay","dayAvail","days","find","d","date","slots","busy","capacityMode","quantity","requiredPools","shiftWindows","step","timeOff","div","className","lane","laneLabel","name","laneTrack","map","s","cls","state","slotOffShift","slotTimeOff","slotExternal","slotFull","slotFree","isFree","slotLabel","start","toLocaleTimeString","hour","minute","aria-label","laneCell","onClick","toISOString","onKeyDown","e","key","preventDefault","role","tabIndex","title","LaneTimelineView","resources","length","p","hint","hours","Array","from","_","i","lanes","laneHeader","h","laneTime","String","padStart","r"],"mappings":"AAAA;;AACA,SAASA,cAAc,QAAQ,iBAAgB;AAC/C,OAAOC,WAAW,QAAO;AAKzB,SAASC,iBAAiB,QAAQ,uCAAsC;AACxE,SAASC,mBAAmB,QAAQ,mCAAkC;AACtE,OAAOC,YAAY,4BAA2B;AAC9C,SAASC,uBAAuB,QAAQ,+BAA8B;AAItE,MAAMC,kBAA6C;IACjDC,UAAU;IACVC,MAAM;IACNC,MAAM;IACN,aAAa;IACb,YAAY;AACd;AAEA,SAASC,KAAK,EACZC,OAAO,EACPC,GAAG,EACHC,OAAO,EACPC,MAAM,EACNC,QAAQ,EACRC,SAAS,EACTC,QAAQ,EAST;IACC,MAAM,EAAEC,GAAGC,EAAE,EAAE,GAAGnB;IAClB,MAAMkB,IAAIC;IAEV,MAAMC,WAAW,IAAIC,KAAKT;IAC1BQ,SAASE,QAAQ,CAACN,WAAW,GAAG,GAAG;IACnC,MAAMO,SAAS,IAAIF,KAAKT;IACxBW,OAAOD,QAAQ,CAACT,SAAS,GAAG,GAAG;IAE/B,MAAM,EAAEW,IAAI,EAAE,GAAGnB,wBAAwBM,SAASI,SAASU,EAAE,EAAEL,UAAUG;IACzE,MAAMG,SAASvB,oBAAoBS,KAAKK;IACxC,MAAMU,WAAWH,MAAMI,KAAKC,KAAK,CAACC,IAAMA,EAAEC,IAAI,KAAKL;IAEnD,MAAMM,QAAQL,WACVzB,kBAAkB;QAChB+B,MAAMT,KAAMS,IAAI;QAChBC,cAAcV,KAAMU,YAAY;QAChCX;QACAH;QACAb,UAAUiB,KAAMjB,QAAQ;QACxB4B,UAAUX,KAAMW,QAAQ;QACxBC,eAAeZ,KAAMY,aAAa;QAClCC,cAAcV,SAASU,YAAY;QACnCC,MAAM;QACNC,SAASZ,SAASY,OAAO;IAC3B,KACA,EAAE;IAEN,qBACE,MAACC;QAAIC,WAAWrC,OAAOsC,IAAI;;0BACzB,KAACF;gBAAIC,WAAWrC,OAAOuC,SAAS;0BAAG5B,SAAS6B,IAAI;;0BAChD,KAACJ;gBAAIC,WAAWrC,OAAOyC,SAAS;0BAC7Bb,MAAMc,GAAG,CAAC,CAACC;oBACV,MAAMC,MACJD,EAAEE,KAAK,KAAK,cACR7C,OAAO8C,YAAY,GACnBH,EAAEE,KAAK,KAAK,aACV7C,OAAO+C,WAAW,GAClBJ,EAAEE,KAAK,KAAK,aACV7C,OAAOgD,YAAY,GACnBL,EAAEE,KAAK,KAAK,SACV7C,OAAOiD,QAAQ,GACfjD,OAAOkD,QAAQ;oBAC3B,MAAMC,SAASR,EAAEE,KAAK,KAAK;oBAC3B,MAAMO,YAAY,GAAGT,EAAEU,KAAK,CAACC,kBAAkB,CAAC,EAAE,EAAE;wBAClDC,MAAM;wBACNC,QAAQ;wBACR3C;oBACF,GAAG,GAAG,EAAEC,EAAEZ,eAAe,CAACyC,EAAEE,KAAK,CAAC,GAAG;oBACrC,OAAOM,uBACL,KAACf;wBACCqB,cAAYL;wBACZf,WAAW,GAAGrC,OAAO0D,QAAQ,CAAC,CAAC,EAAEd,KAAK;wBAEtCe,SAAS,IAAMjD,OAAOC,SAASU,EAAE,EAAEsB,EAAEU,KAAK,CAACO,WAAW;wBACtDC,WAAW,CAACC;4BACV,IAAIA,EAAEC,GAAG,KAAK,WAAWD,EAAEC,GAAG,KAAK,KAAK;gCACtCD,EAAEE,cAAc;gCAChBtD,OAAOC,SAASU,EAAE,EAAEsB,EAAEU,KAAK,CAACO,WAAW;4BACzC;wBACF;wBACAK,MAAK;wBACLC,UAAU;wBACVC,OAAOf;uBAVFT,EAAEU,KAAK,CAACO,WAAW,oBAa1B,KAACxB;wBACCC,WAAW,GAAGrC,OAAO0D,QAAQ,CAAC,CAAC,EAAEd,KAAK;wBAEtCuB,OAAOf;uBADFT,EAAEU,KAAK,CAACO,WAAW;gBAI9B;;;;AAIR;AAEA,OAAO,SAASQ,iBAAiB,EAC/B7D,OAAO,EACPC,GAAG,EACHC,OAAO,EACPC,MAAM,EACN2D,SAAS,EACTzD,SAAS,EACTC,QAAQ,EAST;IACC,MAAM,EAAEC,GAAGC,EAAE,EAAE,GAAGnB;IAClB,MAAMkB,IAAIC;IACV,IAAIsD,UAAUC,MAAM,KAAK,GAAG;QAC1B,qBAAO,KAACC;YAAElC,WAAWrC,OAAOwE,IAAI;sBAAG1D,EAAE;;IACvC;IACA,MAAM2D,QAAQC,MAAMC,IAAI,CAAC;QAAEL,QAAQ7D,UAAUG;IAAU,GAAG,CAACgE,GAAGC,IAAMjE,YAAYiE;IAChF,qBACE,MAACzC;QAAIC,WAAWrC,OAAO8E,KAAK;;0BAC1B,MAAC1C;gBAAIC,WAAWrC,OAAO+E,UAAU;;kCAC/B,KAAC3C;wBAAIC,WAAWrC,OAAOuC,SAAS;;kCAChC,KAACH;wBAAIC,WAAWrC,OAAOyC,SAAS;kCAC7BgC,MAAM/B,GAAG,CAAC,CAACsC,kBACV,MAAC5C;gCAAIC,WAAWrC,OAAOiF,QAAQ;;oCAC5BC,OAAOF,GAAGG,QAAQ,CAAC,GAAG;oCAAK;;+BADQH;;;;YAM3CX,UAAU3B,GAAG,CAAC,CAAC0C,kBACd,KAAC9E;oBACCC,SAASA;oBACTC,KAAKA;oBACLC,SAASA;oBAETC,QAAQA;oBACRC,UAAUyE;oBACVxE,WAAWA;oBACXC,UAAUA;mBAJLuE,EAAE/D,EAAE;;;AASnB"}
|
|
@@ -846,6 +846,7 @@ export const CalendarView = ()=>{
|
|
|
846
846
|
capacityMode: availability.capacityMode,
|
|
847
847
|
dayEnd,
|
|
848
848
|
dayStart,
|
|
849
|
+
external: availability.external,
|
|
849
850
|
quantity: availability.quantity,
|
|
850
851
|
requiredPools: availability.requiredPools,
|
|
851
852
|
shiftWindows: dayAvail.shiftWindows,
|
|
@@ -907,6 +908,9 @@ export const CalendarView = ()=>{
|
|
|
907
908
|
} else if (slotInfo.state === 'time-off') {
|
|
908
909
|
slotClass = styles.slotTimeOff;
|
|
909
910
|
isNonInteractive = true;
|
|
911
|
+
} else if (slotInfo.state === 'external') {
|
|
912
|
+
slotClass = styles.slotExternal;
|
|
913
|
+
isNonInteractive = true;
|
|
910
914
|
} else if (slotInfo.state === 'full') {
|
|
911
915
|
slotClass = styles.slotFull;
|
|
912
916
|
isNonInteractive = true;
|
|
@@ -981,6 +985,7 @@ export const CalendarView = ()=>{
|
|
|
981
985
|
capacityMode: availability.capacityMode,
|
|
982
986
|
dayEnd,
|
|
983
987
|
dayStart,
|
|
988
|
+
external: availability.external,
|
|
984
989
|
quantity: availability.quantity,
|
|
985
990
|
requiredPools: availability.requiredPools,
|
|
986
991
|
shiftWindows: dayAvail.shiftWindows,
|
|
@@ -1013,6 +1018,9 @@ export const CalendarView = ()=>{
|
|
|
1013
1018
|
} else if (slotInfo.state === 'time-off') {
|
|
1014
1019
|
slotClass = styles.slotTimeOff;
|
|
1015
1020
|
isNonInteractive = true;
|
|
1021
|
+
} else if (slotInfo.state === 'external') {
|
|
1022
|
+
slotClass = styles.slotExternal;
|
|
1023
|
+
isNonInteractive = true;
|
|
1016
1024
|
} else if (slotInfo.state === 'full') {
|
|
1017
1025
|
slotClass = styles.slotFull;
|
|
1018
1026
|
isNonInteractive = true;
|