@alfadocs/ui-kit 1.15.1 → 1.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/dist/_chunks/{calendar-CHT9Rm3M.js → calendar-PFO-NlYw.js} +2 -2
  2. package/dist/_chunks/{calendar-event-card-BjdHZaqz.js → calendar-event-card-66CEEWU6.js} +38 -20
  3. package/dist/_chunks/calendar-workspace-B87-QI8L.js +7606 -0
  4. package/dist/agent-catalog.json +1 -1
  5. package/dist/components/calendar/index.js +1 -1
  6. package/dist/components/calendar-event-card/index.js +1 -1
  7. package/dist/i18n/locales/ar.d.ts +2 -0
  8. package/dist/i18n/locales/ar.js +2 -0
  9. package/dist/i18n/locales/de.d.ts +2 -0
  10. package/dist/i18n/locales/de.js +2 -0
  11. package/dist/i18n/locales/el.d.ts +2 -0
  12. package/dist/i18n/locales/el.js +2 -0
  13. package/dist/i18n/locales/en.d.ts +2 -0
  14. package/dist/i18n/locales/en.js +2 -0
  15. package/dist/i18n/locales/es.d.ts +2 -0
  16. package/dist/i18n/locales/es.js +2 -0
  17. package/dist/i18n/locales/fr.d.ts +2 -0
  18. package/dist/i18n/locales/fr.js +2 -0
  19. package/dist/i18n/locales/hi.d.ts +2 -0
  20. package/dist/i18n/locales/hi.js +2 -0
  21. package/dist/i18n/locales/it.d.ts +2 -0
  22. package/dist/i18n/locales/it.js +2 -0
  23. package/dist/i18n/locales/ja.d.ts +2 -0
  24. package/dist/i18n/locales/ja.js +2 -0
  25. package/dist/i18n/locales/nl.d.ts +2 -0
  26. package/dist/i18n/locales/nl.js +2 -0
  27. package/dist/i18n/locales/pl.d.ts +2 -0
  28. package/dist/i18n/locales/pl.js +2 -0
  29. package/dist/i18n/locales/pt.d.ts +2 -0
  30. package/dist/i18n/locales/pt.js +2 -0
  31. package/dist/i18n/locales/ro.d.ts +2 -0
  32. package/dist/i18n/locales/ro.js +2 -0
  33. package/dist/i18n/locales/ru.d.ts +2 -0
  34. package/dist/i18n/locales/ru.js +2 -0
  35. package/dist/i18n/locales/sq.d.ts +2 -0
  36. package/dist/i18n/locales/sq.js +2 -0
  37. package/dist/i18n/locales/sv.d.ts +2 -0
  38. package/dist/i18n/locales/sv.js +2 -0
  39. package/dist/i18n/locales/tr.d.ts +2 -0
  40. package/dist/i18n/locales/tr.js +2 -0
  41. package/dist/i18n/locales/zh.d.ts +2 -0
  42. package/dist/i18n/locales/zh.js +2 -0
  43. package/dist/index.js +3 -3
  44. package/dist/locales/ar.json +2 -0
  45. package/dist/locales/de.json +2 -0
  46. package/dist/locales/el.json +2 -0
  47. package/dist/locales/en.json +2 -0
  48. package/dist/locales/es.json +2 -0
  49. package/dist/locales/fr.json +2 -0
  50. package/dist/locales/hi.json +2 -0
  51. package/dist/locales/it.json +2 -0
  52. package/dist/locales/ja.json +2 -0
  53. package/dist/locales/nl.json +2 -0
  54. package/dist/locales/pl.json +2 -0
  55. package/dist/locales/pt.json +2 -0
  56. package/dist/locales/ro.json +2 -0
  57. package/dist/locales/ru.json +2 -0
  58. package/dist/locales/sq.json +2 -0
  59. package/dist/locales/sv.json +2 -0
  60. package/dist/locales/tr.json +2 -0
  61. package/dist/locales/zh.json +2 -0
  62. package/dist/patterns/calendar/calendar-workspace.model.d.ts +59 -13
  63. package/dist/patterns/calendar/calendar.model.d.ts +18 -5
  64. package/dist/patterns/calendar/calendar.sheets.d.ts +6 -5
  65. package/dist/patterns/calendar/calendar.types.d.ts +79 -13
  66. package/dist/patterns/calendar/index.js +1 -1
  67. package/dist/tokens.css +1 -1
  68. package/package.json +1 -1
  69. package/dist/_chunks/calendar-workspace-CqVe4v5s.js +0 -7481
@@ -10,7 +10,7 @@
10
10
  import type { AppointmentItem } from '../../components/appointment-card';
11
11
  import type { CalendarResource } from '../../components/calendar';
12
12
  import type { CalendarData } from './calendar.data';
13
- import type { CalendarPatient, CalendarWaitingEntry } from './calendar.types';
13
+ import { type CalendarPatient, type CalendarWaitingEntry, type PatientChannelState, type PatientRef } from './calendar.types';
14
14
  import { type CalendarRow, type DisplaySettings, type EditorDraft, type EditorPrefill, type WaitingQuickView } from './calendar.model';
15
15
  export declare const WORKSPACE_TOOL: {
16
16
  readonly appointments: "appointments";
@@ -186,14 +186,36 @@ export declare function slotConflicts(rows: readonly CalendarRow[], slot: {
186
186
  export declare function devicesForCares(cares: readonly {
187
187
  careId?: string;
188
188
  }[] | undefined, devicesByCare: Readonly<Record<string, readonly string[]>>): string[];
189
- /** Which sign channels a patient can take a request on. */
190
- export declare function signChannelsFor(patient: CalendarPatient | undefined): {
191
- sms: boolean;
192
- email: boolean;
189
+ /**
190
+ * Which sign / notify channels a patient can take a request on — as the
191
+ * FOUR-state `PatientChannelState`, not a boolean.
192
+ *
193
+ * A boolean here was the bug: it folded "the record says the practice
194
+ * holds no number" together with "we were never told", and every caller
195
+ * then printed the first as the second ("No SMS-enabled number on
196
+ * file") for a patient the host had simply supplied without a `phone`.
197
+ * Callers now read the state: `channelReady` seeds a control ON,
198
+ * `channelOfferable` decides whether to disable it at all, and
199
+ * `channelReasonKey` gives a reason ONLY in the states that have one.
200
+ */
201
+ export declare function signChannelStates(ref: PatientRef): {
202
+ sms: PatientChannelState;
203
+ email: PatientChannelState;
193
204
  };
194
205
  /** The platform's default: SMS when the patient can take one, else
195
- * email, else nothing. */
196
- export declare function defaultSignMode(patient: CalendarPatient | undefined): RequiredDocsSignMode;
206
+ * email, else nothing. "Can take one" is `ready` alone — a channel we
207
+ * know nothing about is not a channel to send on by default. */
208
+ export declare function defaultSignMode(ref: PatientRef): RequiredDocsSignMode;
209
+ /** The patient's address as one line — the map link's search text, and
210
+ * the link's own label. Empty when the host supplied no address at all,
211
+ * which is the caller's signal to leave the map row out rather than
212
+ * offer a search for nothing. */
213
+ export declare function patientAddressLine(patient: CalendarPatient): string;
214
+ /** The map link's own LABEL — street and city, the pair the popover has
215
+ * always printed. The postcode belongs in the search query, not in the
216
+ * visible text, so widening `patientAddressLine` for the URL must not
217
+ * drag the label along with it. */
218
+ export declare function patientAddressLabel(patient: CalendarPatient): string;
197
219
  /** Google Maps search for the patient's address — the popover's map link. */
198
220
  export declare function patientMapsUrl(patient: CalendarPatient): string;
199
221
  /** A CREATE mode armed by a deep link (`createParameters`) or the
@@ -291,10 +313,22 @@ export declare function upcomingAppointmentRows(rows: CalendarRow[], bounds: {
291
313
  startMs: number;
292
314
  endMs: number;
293
315
  }): CalendarRow[];
294
- /** One agenda row as the kit timeline's item — identity, allocation and
295
- * care lines; the row id stays the event id so a click maps straight
296
- * back onto the grid. */
297
- export declare function upcomingAppointmentItem(row: CalendarRow, privacy: boolean, data: CalendarData): AppointmentItem;
316
+ /**
317
+ * One agenda row as the kit timeline's item — identity, allocation and
318
+ * care lines; the row id stays the event id so a click maps straight
319
+ * back onto the grid.
320
+ *
321
+ * The card prints its own "no patient assigned" whenever `patient` is
322
+ * absent, so absence here has to mean exactly that: the appointment
323
+ * carries NO patient id. A row that carries one but whose record the
324
+ * host could not resolve still names its patient — from the record, from
325
+ * the title the row already carries, and only then from
326
+ * `unresolvedPatientLabel`, which must say the record was not loaded and
327
+ * never that nobody is booked.
328
+ */
329
+ export declare function upcomingAppointmentItem(row: CalendarRow, privacy: boolean, data: CalendarData,
330
+ /** Localised name-of-last-resort for an unresolvable patient id. */
331
+ unresolvedPatientLabel: string): AppointmentItem;
298
332
  /** How far back the platform's booking query looks, on `createdAt`. */
299
333
  export declare const ONLINE_BOOKINGS_WINDOW_DAYS = 30;
300
334
  /**
@@ -355,16 +389,28 @@ export declare function waitingFiltersActiveCount(filters: WaitingListFilters):
355
389
  */
356
390
  export interface WaitingListRowView {
357
391
  entry: CalendarWaitingEntry;
358
- /** Platform `patientId` / `patientName` / `patientPhoneNumber`. */
392
+ /** The entry's OWN patient, id and record together. `assigned` is what
393
+ * decides whether this entry has a patient — the record may simply
394
+ * not have loaded. */
395
+ patientRef: PatientRef;
396
+ /** Platform `patientId` / `patientName` / `patientPhoneNumber` — the
397
+ * record alone, when the host could load it. */
359
398
  patient?: CalendarPatient;
360
399
  /** The linked appointment, live from the grid's rows. */
361
400
  appointment?: CalendarRow;
362
- /** Platform `appointmentPatientId` — the linked appointment's patient. */
401
+ /** Platform `appointmentPatientId` — the linked appointment's patient,
402
+ * id and record together. */
403
+ appointmentPatientRef: PatientRef;
404
+ /** The linked appointment's patient record, when it loaded. */
363
405
  appointmentPatient?: CalendarPatient;
364
406
  /** Platform `operatorName`. */
365
407
  operatorTitle?: string;
366
408
  /** Platform `appointmentName` — the linked appointment's care line. */
367
409
  appointmentName?: string;
410
+ /** Someone is booked on this row — the entry's own patient or the
411
+ * linked appointment's. Keyed on the IDS: a record we could not load
412
+ * is still a patient. */
413
+ patientAssigned: boolean;
368
414
  noConnection: boolean;
369
415
  }
370
416
  export declare function waitingListRowView(entry: CalendarWaitingEntry, rows: readonly CalendarRow[], data: CalendarData): WaitingListRowView;
@@ -12,7 +12,7 @@ import type { TFunction } from 'i18next';
12
12
  import { ThumbsUp } from 'lucide-react';
13
13
  import { type CalendarEvent, type CalendarEventStatus, type CalendarResource } from '../../components/calendar';
14
14
  import type { CalendarData } from './calendar.data';
15
- import { type CareDescriptionMode, type ColorAssociation, type CalendarBaseEvent, type CalendarBookingContact, type CalendarCareEntry, type CalendarCareLink, type CalendarClosure, type CalendarDayHours, type CalendarHistoryEntry, type CalendarPatient, type CalendarPhoneNumber, type CalendarSignDocument, type CalendarWaitingEntry } from './calendar.types';
15
+ import { type CareDescriptionMode, type ColorAssociation, type CalendarBaseEvent, type CalendarBookingContact, type CalendarCareEntry, type CalendarCareLink, type CalendarClosure, type CalendarDayHours, type CalendarHistoryEntry, type CalendarPatient, type CalendarPhoneNumber, type CalendarSignDocument, type CalendarWaitingEntry, type PatientRef } from './calendar.types';
16
16
  export declare const STATUS_UI_KEY: Record<CalendarEventStatus, string>;
17
17
  export interface CalendarRow {
18
18
  event: CalendarEvent;
@@ -47,6 +47,11 @@ export interface PendingMove {
47
47
  revert?: () => void;
48
48
  }
49
49
  export declare function movesSilently(event: CalendarEvent): boolean;
50
+ /** The reference for one patient id — the record when the host could
51
+ * answer, and always the id itself. */
52
+ export declare function patientRefById(id: string | number | null | undefined, data: CalendarData): PatientRef;
53
+ /** The reference for the patient an appointment carries. */
54
+ export declare function eventPatientRef(event: CalendarEvent, data: CalendarData): PatientRef;
50
55
  export declare function isPendingBooking(event: CalendarEvent): boolean;
51
56
  export declare function selectPendingBookings(rows: CalendarRow[]): CalendarRow[];
52
57
  /**
@@ -420,7 +425,11 @@ export declare function buildBacklog(args: {
420
425
  }, data: CalendarData): BacklogItem[];
421
426
  /** Per-type counts — the strip's segment badges. */
422
427
  export declare function backlogCounts(items: readonly BacklogItem[]): Record<BacklogType, number>;
423
- /** The patient behind a row (bookings have none — a typed name only). */
428
+ /** The patient behind a row (bookings have none — a typed name only),
429
+ * as the reference: `assigned` says whether anyone is booked at all,
430
+ * which is what a "no patient" label may key on — never the record. */
431
+ export declare function backlogPatientRef(item: BacklogItem, data: CalendarData): PatientRef;
432
+ /** The record behind a queue row, when the host could load it. */
424
433
  export declare function backlogPatient(item: BacklogItem, data: CalendarData): CalendarPatient | undefined;
425
434
  /** The row's headline — patient name, the booker's typed name, or the
426
435
  * free-text hold. */
@@ -448,9 +457,9 @@ export declare function waitingEntryInQuickView(entry: CalendarWaitingEntry, vie
448
457
  export declare function filterWaitingQuickView(items: readonly BacklogItem[], view: WaitingQuickView, data: CalendarData): BacklogItem[];
449
458
  /**
450
459
  * Process an online booking: the editor opens for THAT event with the
451
- * booker's typed details, a matching record pre-selected, and BOTH the
452
- * patient and the operator marked required — the two things the booking
453
- * needs before it leaves the queue.
460
+ * booker's typed details, a patient pre-selected — the id the booking
461
+ * already carries, or a typed-name match — and BOTH the patient and the
462
+ * operator marked required, the two things it needs to leave the queue.
454
463
  */
455
464
  export declare function processBookingPrefill(row: CalendarRow, data: CalendarData): EditorPrefill;
456
465
  /** Assign an operator: the editor opens for the event with the operator
@@ -621,6 +630,10 @@ export interface PrintSheetInput {
621
630
  /** A date-only start (all-day rows) is already a local day; anything
622
631
  * else parses as the wall clock the fixtures and the editor write. */
623
632
  export declare function parseEventDate(value: string | Date): Date;
633
+ /** The title privacy mode shows. TOTAL in the masked branch: a host
634
+ * that supplies an EMPTY `privacyModeTitle` gets the bullets, never a
635
+ * blank and never a fallback that would leak what we do or do not hold
636
+ * on the one surface whose job is to say nothing. */
624
637
  export declare function maskedTitle(event: CalendarEvent, privacy: boolean): string;
625
638
  export declare function printRowOf(row: CalendarRow, privacy: boolean, data: CalendarData): PrintRow;
626
639
  export declare function byStart(a: PrintRow, b: PrintRow): number;
@@ -24,7 +24,7 @@
24
24
  import { type ReactNode } from 'react';
25
25
  import { type CalendarEvent } from '../../components/calendar';
26
26
  import { type NotesPanelNote, type NotesPanelProps, type NotesPanelSubmission } from '../../components/notes-panel';
27
- import { type ColorAssociation, type CalendarCarePlan, type CalendarAnamnesisAnswer, type CalendarOperatorGroup, type CalendarPatient, type CalendarWaitingEntry, type CalendarHistoryEntry, type CalendarSignChannel } from './calendar.types';
27
+ import { type ColorAssociation, type CalendarCarePlan, type CalendarAnamnesisAnswer, type CalendarOperatorGroup, type CalendarPatient, type CalendarWaitingEntry, type CalendarHistoryEntry, type CalendarSignChannel, type PatientRef } from './calendar.types';
28
28
  import { type CalendarRow, type DisplaySettings, type EditorPrefill, type EditorDraft, type DraftSlot, type SlotPatch, type BacklogFilter, type BacklogItem, type WaitingEntryDraft, type CalendarFreeSlot, type PrintDaySection, type FindSlotsSeed, type AvailabilityContext } from './calendar.model';
29
29
  import { type EditorDraftExtras, type DeleteOptions } from './calendar-workspace.model';
30
30
  export declare function TaskDetailsPanel({ row, locale, }: {
@@ -206,9 +206,11 @@ export declare function AppointmentEditorPanel({ prefill, onSave, onDelete, onDu
206
206
  export declare function IndicatorChips({ event }: {
207
207
  event: CalendarEvent;
208
208
  }): import("react/jsx-runtime").JSX.Element | null;
209
- export declare function AppointmentIdentity({ row, patient, showAge, onOpenPatient, anamnesisAnswers, }: {
209
+ export declare function AppointmentIdentity({ row, patientRef, showAge, onOpenPatient, anamnesisAnswers, }: {
210
210
  row: CalendarRow;
211
- patient?: CalendarPatient;
211
+ /** Who this appointment is for: the id it carries and the record, when
212
+ * the host could resolve it. */
213
+ patientRef: PatientRef;
212
214
  /** Append the platform popover's "(NN anni)" to the name (audit C15). */
213
215
  showAge?: boolean;
214
216
  /** Set = the name becomes the platform's patient-folder link. */
@@ -217,8 +219,7 @@ export declare function AppointmentIdentity({ row, patient, showAge, onOpenPatie
217
219
  * details dialog lists them, the popover only counts (audit C16). */
218
220
  anamnesisAnswers?: readonly CalendarAnamnesisAnswer[];
219
221
  }): import("react/jsx-runtime").JSX.Element;
220
- export declare function SendReminderGroup({ patient, onWhatsApp, channels: allowed, }: {
221
- patient: CalendarPatient;
222
+ export declare function SendReminderGroup({ onWhatsApp, channels: allowed, }: {
222
223
  /** When set, the WhatsApp segment bridges to the legacy Snippets
223
224
  * island instead of the demo-fake send. */
224
225
  onWhatsApp?: () => void;
@@ -30,25 +30,36 @@ export interface CalendarAnamnesisAnswer {
30
30
  answer?: string;
31
31
  interviewIso: string;
32
32
  }
33
+ /**
34
+ * A patient as the HOST knows them. Only the identity — `id` and `name` —
35
+ * is required: a host whose appointment feed carries a patient id and a
36
+ * display name and nothing else supplies exactly those two, and every
37
+ * reader below treats each remaining field as "the host did not tell us".
38
+ *
39
+ * The rule for a reader: never render a row, chip or label that asserts a
40
+ * value for a field the host omitted — an empty fiscal code printed under
41
+ * a "Fiscal code" label is a claim about the record, not a blank. Omit the
42
+ * row; where every row of a section would go, omit the section.
43
+ */
33
44
  export interface CalendarPatient {
34
45
  id: string;
35
46
  name: string;
36
- dobIso: string;
37
- phone: string;
38
- email: string;
47
+ dobIso?: string;
48
+ phone?: string;
49
+ email?: string;
39
50
  smsEnabled?: boolean;
40
51
  emailEnabled?: boolean;
41
- city: string;
52
+ city?: string;
42
53
  /** Optional profile photo — Avatar falls back to the initials circle. */
43
54
  avatarSrc?: string;
44
- sex: 'f' | 'm';
45
- fiscalCode: string;
46
- address: string;
47
- province: string;
48
- postalCode: string;
49
- patientSinceIso: string;
50
- lastVisitIso: string;
51
- priceList: string;
55
+ sex?: 'f' | 'm';
56
+ fiscalCode?: string;
57
+ address?: string;
58
+ province?: string;
59
+ postalCode?: string;
60
+ patientSinceIso?: string;
61
+ lastVisitIso?: string;
62
+ priceList?: string;
52
63
  discountPct?: number;
53
64
  unpaidAmount?: number;
54
65
  allergies?: string;
@@ -390,8 +401,63 @@ export type CalendarHistoryEntry = {
390
401
  kind: 'deleted';
391
402
  });
392
403
  /** Every labelled phone number — the single `phone` is the mobile when a
393
- * patient carries no explicit list (platform prints each label: number). */
404
+ * patient carries no explicit list (platform prints each label: number).
405
+ * A patient the host supplied without either has no numbers to print,
406
+ * which is not the same as one labelled blank: the list comes back empty
407
+ * and the caller omits the block. */
394
408
  export declare function patientPhones(patient: CalendarPatient): CalendarPhoneNumber[];
409
+ /**
410
+ * A patient as the calendar can see them at one point: the id a row,
411
+ * an event or a waiting entry carries, plus the record if the host's
412
+ * `patientById` could answer.
413
+ */
414
+ export interface PatientRef {
415
+ /** The id, as a string. `''` — and ONLY `''` — means nobody is booked. */
416
+ readonly id: string;
417
+ /** The record, when the host could resolve the id. */
418
+ readonly record?: CalendarPatient;
419
+ /** Someone is booked here, resolved or not. The existence test. */
420
+ readonly assigned: boolean;
421
+ /** Someone is booked and their record did not load — state A. */
422
+ readonly unresolved: boolean;
423
+ }
424
+ /** A patient id as a string, `''` when there is none. A host id of `0`
425
+ * IS an id, so the test is `!= null` and never truthiness. */
426
+ export declare function patientIdOf(id: string | number | null | undefined): string;
427
+ /** Pair the id a row carries with whatever the host made of it. */
428
+ export declare function patientRefOf(id: string | number | null | undefined, record: CalendarPatient | undefined): PatientRef;
429
+ /** What to CALL this patient: the record's name, else the title the row
430
+ * already carries, else the caller's localised "record not loaded".
431
+ * Never blank — a blank name renders an initials-less avatar — and
432
+ * never the "no patient assigned" of an unbooked slot. */
433
+ export declare function patientRefName(ref: PatientRef, rowTitle: string | undefined, notLoadedLabel: string): string;
434
+ /** Why a notify / signing channel is or is not usable for a patient. */
435
+ export type PatientChannelState =
436
+ /** On file, and the patient takes messages there. */
437
+ 'ready'
438
+ /** On file, and the patient opted this channel out. */
439
+ | 'optedOut'
440
+ /** The record loaded and really carries nothing here — state C, the
441
+ * only state in which "none on file" may be said. */
442
+ | 'none'
443
+ /** We were not told: no record at all, or the record omits the field
444
+ * — states A and B. Says nothing about what the practice holds. */
445
+ | 'unknown';
446
+ /** The state of one channel for one patient reference. */
447
+ export declare function patientChannelState(ref: PatientRef, channel: 'sms' | 'email'): PatientChannelState;
448
+ /** A channel the kit can hand a destination to right now — the test for
449
+ * seeding a checkbox ON, or for defaulting a sign mode to it. */
450
+ export declare function channelReady(state: PatientChannelState): boolean;
451
+ /** A channel the kit must leave OFFERED. `unknown` belongs here: the
452
+ * host may well succeed on send, and disabling the control would claim
453
+ * the practice holds nothing — a claim about a record we never saw. */
454
+ export declare function channelOfferable(state: PatientChannelState): boolean;
455
+ /** The reason a channel is not offered — `null` when it IS offered, so
456
+ * a caller never has to invent a string for a state it cannot reach. */
457
+ export declare function channelReasonKey(state: PatientChannelState, keys: {
458
+ optedOut: string;
459
+ none: string;
460
+ }): string | null;
395
461
  /** Practice-level toggles the platform gates the editor and popover on. */
396
462
  export interface CalendarPracticeFeatures {
397
463
  /** `FIND_FREE_SLOTS_BY_CARE` — devices per care, the device line. */
@@ -1,4 +1,4 @@
1
- import { C as s, a as r, b as E, D as P, c as t, S, V as A, W as C, d, i as o, m as D, r as i, u as n, e as W, f as _ } from "../../_chunks/calendar-workspace-CqVe4v5s.js";
1
+ import { C as s, a as r, b as E, D as P, c as t, S, V as A, W as C, d, i as o, m as D, r as i, u as n, e as W, f as _ } from "../../_chunks/calendar-workspace-B87-QI8L.js";
2
2
  export {
3
3
  s as CALENDAR_PREFERENCE_KEYS,
4
4
  r as CalendarDataProvider,