@medalsocial/meda 3.8.0 → 3.9.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.
|
@@ -18,7 +18,7 @@ import { UPCOMING_BOOKINGS_LABEL_KEYS } from './portal/upcoming-bookings.js';
|
|
|
18
18
|
import { VIPPS_LINK_ROW_LABEL_KEYS } from './portal/vipps-link-row.js';
|
|
19
19
|
import { VISIT_HISTORY_LABEL_KEYS } from './portal/visit-history.js';
|
|
20
20
|
import { SERVICE_SCREEN_LABEL_KEYS, SERVICE_SCREEN_MULTI_LABEL_KEYS } from './service-screen.js';
|
|
21
|
-
import { STYLIST_SCREEN_LABEL_KEYS } from './stylist-screen.js';
|
|
21
|
+
import { STYLIST_SCREEN_LABEL_KEYS, STYLIST_SCREEN_SEAT_LABEL_KEYS } from './stylist-screen.js';
|
|
22
22
|
import { SUMMARY_BAR_HINT_LABEL_KEYS, SUMMARY_BAR_LABEL_KEYS } from './summary-bar.js';
|
|
23
23
|
import { TIME_SCREEN_FINDER_LABEL_KEYS, TIME_SCREEN_LABEL_KEYS } from './time-screen.js';
|
|
24
24
|
import { WHO_SCREEN_LABEL_KEYS, WHO_SCREEN_PARTY_LABEL_KEYS } from './who-screen.js';
|
|
@@ -30,13 +30,13 @@ import { WHO_SCREEN_LABEL_KEYS, WHO_SCREEN_PARTY_LABEL_KEYS } from './who-screen
|
|
|
30
30
|
* (Screens that embed another screen already include its keys, e.g. the
|
|
31
31
|
* login sheet carries the login panel's, OTP slots' and Vipps button's.)
|
|
32
32
|
*/
|
|
33
|
-
export declare const BOOKING_LABEL_KEYS: readonly ("addChild.trigger" | "addChild.title" | "addChild.description.saved" | "addChild.description.local" | "addChild.name" | "addChild.birthYear" | "addChild.birthYearPlaceholder" | "addChild.birthMonth" | "addChild.birthMonthUnknown" | "addChild.notes" | "addChild.missing" | "addChild.submit" | "addChild.close" | "recap.label" | "recap.time" | "recap.line" | "recap.lineFor" | "recap.anyStylist" | "recap.total" | "recap.edit" | "recap.editLabel" | "recap.alsoFree" | "recap.swapTo" | "bookingSkeleton.opening" | "confirmation.heading" | "confirmation.serviceFor" | "confirmation.when" | "confirmation.party.heading" | "confirmation.party.line" | "confirmation.party.stylist" | "confirmation.party.total" | "confirmation.calendar" | "confirmation.manage" | "confirmation.manageFor" | "confirmation.portal" | "confirmation.startOver" | "details.heading" | "details.phone.label" | "details.phone.prefix" | "details.phone.error" | "details.name.label" | "details.known.label" | "details.known.for" | "details.known.self" | "details.known.adult" | "details.known.child" | "details.child.name" | "details.child.year" | "details.child.yearPlaceholder" | "details.email.label" | "details.email.help" | "details.email.lockedHelp" | "details.email.error" | "details.notes.label" | "details.notes.placeholder" | "details.terms.text" | "details.terms.link" | "details.marketing.text" | "details.error.maxParty" | "details.error.slotTaken" | "details.error.conflict" | "details.error.invalidInput" | "details.error.unconfigured" | "details.error.upstreamError" | "details.error.inProgress" | "details.call.link" | "details.call.none" | "details.submit" | "otp.label" | "vipps.button" | "vipps.unavailable" | "vipps.throttled" | "login.heading" | "login.codeHeading" | "login.or" | "login.continueEmail" | "login.emailIntro" | "login.emailLabel" | "login.sendCode" | "login.codeLabel" | "login.submitCode" | "login.codeHelp" | "login.codeHelpVipps" | "login.vippsSentTo" | "login.vippsSentToUnknown" | "login.cooldownWait" | "login.cooldownReady" | "login.resendIn" | "login.resend" | "login.switchEmail" | "login.useEmailInstead" | "login.notice.sent" | "login.notice.resent" | "login.notice.unreachable" | "login.notice.badEmail" | "login.notice.invalid" | "login.notice.throttled" | "login.notice.vippsInvalid" | "login.notice.vippsConflict" | "loginSheet.prompt" | "loginSheet.trigger" | "loginSheet.intro" | "loginSheet.vipps" | "loginSheet.close" | "time.heading" | "time.dayStrip.legend" | "time.nearest" | "time.current" | "time.nextFree" | "time.shortNotice" | "time.weekend.pct" | "time.weekend.mixed" | "time.month.show" | "time.month.hide" | "time.month.previous" | "time.month.next" | "time.month.heading" | "time.month.note" | "time.party.sequential" | "time.party.parallel" | "time.party.seat" | "time.party.seatSeparator" | "time.parallel.offer.two" | "time.parallel.offer.other" | "time.parallel.accept" | "time.empty.closed" | "time.empty.over" | "time.empty.full" | "time.empty.stylist" | "time.empty.unknown" | "time.empty.callLink" | "time.empty.callLinkAria" | "time.empty.callSuffix" | "time.empty.callPlain" | "time.loading" | "time.skeleton.dayPlaceholder" | "time.taken.message" | "time.taken.close" | "time.soonest.heading" | "time.soonest.pick" | "time.soonest.with" | "time.dayChip.free" | "time.dayChip.freeOne" | "time.dayChip.full" | "time.week.none" | "time.week.more" | "manage.heading" | "manage.serviceFallback" | "manage.card.named" | "manage.card.when" | "manage.card.whenWithStylist" | "manage.appointment.named" | "manage.appointment.namedSibilant" | "manage.appointment.unnamed" | "manage.ringUs" | "manage.ringUsOn" | "manage.callUs" | "manage.callUsOn" | "manage.error.windowPassed" | "manage.error.slotTaken" | "manage.error.notFound" | "manage.error.conflict" | "manage.error.invalidInput" | "manage.error.unavailable" | "manage.freeUntil" | "manage.remaining.in" | "manage.remaining.daysAndHours" | "manage.remaining.underMinute" | "manage.remaining.day.one" | "manage.remaining.day.other" | "manage.remaining.hour.one" | "manage.remaining.hour.other" | "manage.remaining.minute.one" | "manage.remaining.minute.other" | "manage.change" | "manage.cancel" | "manage.callToChange" | "manage.callToCancel" | "manage.blocked" | "manage.blocked.suffix" | "manage.blocked.plain" | "manage.calendar" | "manage.closed.cancelled" | "manage.closed.completed" | "manage.closed.noShow" | "manage.closed.pending" | "manage.closed.pendingCall" | "manage.closed.pendingCallPlain" | "manage.bookNew" | "manage.party.heading" | "manage.party.justThisOne" | "manage.party.unnamed" | "manage.party.note" | "manage.party.noteSuffix" | "manage.back" | "manage.reschedule.lead" | "manage.reschedule.leadWithStylist" | "manage.reschedule.failed" | "manage.reschedule.failedSuffix" | "manage.reschedule.loading" | "manage.move.question" | "manage.move.questionWithStylist" | "manage.move.surcharge" | "manage.move.confirm" | "manage.move.pickAnother" | "manage.cancel.question" | "manage.cancel.reasonLegend" | "manage.cancel.reason.illness" | "manage.cancel.reason.noLongerSuits" | "manage.cancel.reason.other" | "manage.cancel.confirm" | "manage.cancel.keep" | "manage.cancelled" | "manage.cancelled.findNew" | "manage.moved" | "manage.movedTo" | "manage.moved.view" | "manage.moved.noLink" | "manage.moved.noLinkSuffix" | "manage.portal" | "childCards.empty" | "childCards.neverVisited" | "childCards.lastVisit" | "childCards.lastVisitNoService" | "childCards.book" | "childCards.stylist" | "childCards.next" | "childCards.none" | "dataControls.heading" | "dataControls.export" | "dataControls.delete" | "dataControls.confirmHeading" | "dataControls.consequences" | "dataControls.confirmLabel" | "dataControls.confirmHelp" | "dataControls.wrongWord" | "dataControls.deleteForever" | "dataControls.cancel" | "dataControls.unreachable" | "dataControls.confirmWord" | "ageConfirm.heading" | "ageConfirm.lead" | "ageConfirm.legend" | "ageConfirm.birthYear" | "ageConfirm.birthMonth" | "ageConfirm.birthMonthUnknown" | "ageConfirm.confirm" | "ageConfirm.dismiss" | "familyEditor.heading" | "familyEditor.lead" | "familyEditor.empty" | "familyEditor.legend" | "familyEditor.add" | "familyEditor.name" | "familyEditor.birthYear" | "familyEditor.birthYearPlaceholder" | "familyEditor.birthMonth" | "familyEditor.birthMonthUnknown" | "familyEditor.stylist" | "familyEditor.stylistNone" | "familyEditor.stylistFormer" | "familyEditor.notes" | "familyEditor.notesPlaceholder" | "familyEditor.newRow" | "familyEditor.save" | "familyEditor.remove" | "familyEditor.removeNamed" | "familyEditor.removeRow" | "familyEditor.saved" | "familyEditor.savedNoDetails" | "familyEditor.partial" | "familyEditor.removed" | "familyEditor.unreachable" | "familyEditor.ageConfirmed" | "familyEditor.ageSaved" | "logout.button" | "logout.unreachable" | "portalShell.nav" | "portalShell.navBar" | "portalUnreachable.heading" | "portalUnreachable.body" | "portalUnreachable.retry" | "portalUnreachable.call" | "profileForm.heading" | "profileForm.firstName" | "profileForm.lastName" | "profileForm.phone" | "profileForm.email" | "profileForm.emailHelp" | "profileForm.save" | "profileForm.saved" | "profileForm.restored" | "profileForm.marketing" | "profileForm.unreachable" | "rebook.heading" | "rebook.empty" | "rebook.serviceFallback" | "rebook.anyStylist" | "rebook.cta" | "upcoming.heading" | "upcoming.empty" | "upcoming.book" | "upcoming.next" | "upcoming.today" | "upcoming.tomorrow" | "upcoming.inDays" | "upcoming.when" | "upcoming.serviceFallback" | "upcoming.anyStylist" | "upcoming.manage" | "upcoming.noManage" | "upcoming.noManageWithPhone" | "upcoming.call" | "vippsLink.heading" | "vippsLink.linked" | "vippsLink.pitch" | "vippsLink.button" | "vippsLink.success" | "vippsLink.conflict" | "vippsLink.failed" | "vippsLink.unavailable" | "vippsLink.throttled" | "history.heading" | "history.empty" | "history.serviceFallback" | "history.count.one" | "history.count.other" | "history.unknownAmount" | "service.multiHint" | "service.total" | "service.chooseFirst" | "service.continue" | "service.party.nothingBookable" | "service.tabDone" | "service.heading" | "service.categoriesLegend" | "service.sameAsLast" | "service.chooseOther" | "service.duration" | "service.phoneOnly" | "service.phoneOnlyLinkLabel" | "service.ageDivider.named" | "service.ageDivider.unnamed" | "service.party.listLabel" | "service.party.adultAlone" | "service.party.nothingFits" | "service.party.remove" | "stylist.heading" | "stylist.firstAvailable" | "stylist.firstAvailableSubtitle" | "stylist.firstAvailableBadge" | "stylist.pendingName" | "stylist.nextAvailable" | "stylist.loading" | "stylist.party.legend" | "stylist.party.sequential" | "stylist.party.sequentialMinutes" | "stylist.party.parallel.two" | "stylist.party.parallel.three" | "stylist.party.parallel.other" | "stylist.party.parallelMinutes" | "stylist.party.parallelNote.two" | "stylist.party.parallelNote.three" | "stylist.party.parallelNote.other" | "summary.placeholder.who" | "summary.placeholder.service" | "summary.next" | "summary.hint.who" | "summary.hint.service" | "summary.hint.when" | "who.heading" | "who.guest.groupLabel" | "who.guest.children.one" | "who.guest.children.other" | "who.guest.adult" | "who.guest.addedList" | "who.family.legend" | "who.family.self" | "who.family.limit" | "who.party.children" | "who.party.childrenNote" | "who.party.adult" | "who.party.adultNote" | "who.party.fewer" | "who.party.more" | "who.party.count")[];
|
|
33
|
+
export declare const BOOKING_LABEL_KEYS: readonly ("addChild.trigger" | "addChild.title" | "addChild.description.saved" | "addChild.description.local" | "addChild.name" | "addChild.birthYear" | "addChild.birthYearPlaceholder" | "addChild.birthMonth" | "addChild.birthMonthUnknown" | "addChild.notes" | "addChild.missing" | "addChild.submit" | "addChild.close" | "recap.label" | "recap.time" | "recap.line" | "recap.lineFor" | "recap.anyStylist" | "recap.total" | "recap.edit" | "recap.editLabel" | "recap.alsoFree" | "recap.swapTo" | "bookingSkeleton.opening" | "confirmation.heading" | "confirmation.serviceFor" | "confirmation.when" | "confirmation.party.heading" | "confirmation.party.line" | "confirmation.party.stylist" | "confirmation.party.total" | "confirmation.calendar" | "confirmation.manage" | "confirmation.manageFor" | "confirmation.portal" | "confirmation.startOver" | "details.heading" | "details.phone.label" | "details.phone.prefix" | "details.phone.error" | "details.name.label" | "details.known.label" | "details.known.for" | "details.known.self" | "details.known.adult" | "details.known.child" | "details.child.name" | "details.child.year" | "details.child.yearPlaceholder" | "details.email.label" | "details.email.help" | "details.email.lockedHelp" | "details.email.error" | "details.notes.label" | "details.notes.placeholder" | "details.terms.text" | "details.terms.link" | "details.marketing.text" | "details.error.maxParty" | "details.error.slotTaken" | "details.error.conflict" | "details.error.invalidInput" | "details.error.unconfigured" | "details.error.upstreamError" | "details.error.inProgress" | "details.call.link" | "details.call.none" | "details.submit" | "otp.label" | "vipps.button" | "vipps.unavailable" | "vipps.throttled" | "login.heading" | "login.codeHeading" | "login.or" | "login.continueEmail" | "login.emailIntro" | "login.emailLabel" | "login.sendCode" | "login.codeLabel" | "login.submitCode" | "login.codeHelp" | "login.codeHelpVipps" | "login.vippsSentTo" | "login.vippsSentToUnknown" | "login.cooldownWait" | "login.cooldownReady" | "login.resendIn" | "login.resend" | "login.switchEmail" | "login.useEmailInstead" | "login.notice.sent" | "login.notice.resent" | "login.notice.unreachable" | "login.notice.badEmail" | "login.notice.invalid" | "login.notice.throttled" | "login.notice.vippsInvalid" | "login.notice.vippsConflict" | "loginSheet.prompt" | "loginSheet.trigger" | "loginSheet.intro" | "loginSheet.vipps" | "loginSheet.close" | "time.heading" | "time.dayStrip.legend" | "time.nearest" | "time.current" | "time.nextFree" | "time.shortNotice" | "time.weekend.pct" | "time.weekend.mixed" | "time.month.show" | "time.month.hide" | "time.month.previous" | "time.month.next" | "time.month.heading" | "time.month.note" | "time.party.sequential" | "time.party.parallel" | "time.party.seat" | "time.party.seatSeparator" | "time.parallel.offer.two" | "time.parallel.offer.other" | "time.parallel.accept" | "time.empty.closed" | "time.empty.over" | "time.empty.full" | "time.empty.stylist" | "time.empty.unknown" | "time.empty.callLink" | "time.empty.callLinkAria" | "time.empty.callSuffix" | "time.empty.callPlain" | "time.loading" | "time.skeleton.dayPlaceholder" | "time.taken.message" | "time.taken.close" | "time.soonest.heading" | "time.soonest.pick" | "time.soonest.with" | "time.dayChip.free" | "time.dayChip.freeOne" | "time.dayChip.full" | "time.week.none" | "time.week.more" | "manage.heading" | "manage.serviceFallback" | "manage.card.named" | "manage.card.when" | "manage.card.whenWithStylist" | "manage.appointment.named" | "manage.appointment.namedSibilant" | "manage.appointment.unnamed" | "manage.ringUs" | "manage.ringUsOn" | "manage.callUs" | "manage.callUsOn" | "manage.error.windowPassed" | "manage.error.slotTaken" | "manage.error.notFound" | "manage.error.conflict" | "manage.error.invalidInput" | "manage.error.unavailable" | "manage.freeUntil" | "manage.remaining.in" | "manage.remaining.daysAndHours" | "manage.remaining.underMinute" | "manage.remaining.day.one" | "manage.remaining.day.other" | "manage.remaining.hour.one" | "manage.remaining.hour.other" | "manage.remaining.minute.one" | "manage.remaining.minute.other" | "manage.change" | "manage.cancel" | "manage.callToChange" | "manage.callToCancel" | "manage.blocked" | "manage.blocked.suffix" | "manage.blocked.plain" | "manage.calendar" | "manage.closed.cancelled" | "manage.closed.completed" | "manage.closed.noShow" | "manage.closed.pending" | "manage.closed.pendingCall" | "manage.closed.pendingCallPlain" | "manage.bookNew" | "manage.party.heading" | "manage.party.justThisOne" | "manage.party.unnamed" | "manage.party.note" | "manage.party.noteSuffix" | "manage.back" | "manage.reschedule.lead" | "manage.reschedule.leadWithStylist" | "manage.reschedule.failed" | "manage.reschedule.failedSuffix" | "manage.reschedule.loading" | "manage.move.question" | "manage.move.questionWithStylist" | "manage.move.surcharge" | "manage.move.confirm" | "manage.move.pickAnother" | "manage.cancel.question" | "manage.cancel.reasonLegend" | "manage.cancel.reason.illness" | "manage.cancel.reason.noLongerSuits" | "manage.cancel.reason.other" | "manage.cancel.confirm" | "manage.cancel.keep" | "manage.cancelled" | "manage.cancelled.findNew" | "manage.moved" | "manage.movedTo" | "manage.moved.view" | "manage.moved.noLink" | "manage.moved.noLinkSuffix" | "manage.portal" | "childCards.empty" | "childCards.neverVisited" | "childCards.lastVisit" | "childCards.lastVisitNoService" | "childCards.book" | "childCards.stylist" | "childCards.next" | "childCards.none" | "dataControls.heading" | "dataControls.export" | "dataControls.delete" | "dataControls.confirmHeading" | "dataControls.consequences" | "dataControls.confirmLabel" | "dataControls.confirmHelp" | "dataControls.wrongWord" | "dataControls.deleteForever" | "dataControls.cancel" | "dataControls.unreachable" | "dataControls.confirmWord" | "ageConfirm.heading" | "ageConfirm.lead" | "ageConfirm.legend" | "ageConfirm.birthYear" | "ageConfirm.birthMonth" | "ageConfirm.birthMonthUnknown" | "ageConfirm.confirm" | "ageConfirm.dismiss" | "familyEditor.heading" | "familyEditor.lead" | "familyEditor.empty" | "familyEditor.legend" | "familyEditor.add" | "familyEditor.name" | "familyEditor.birthYear" | "familyEditor.birthYearPlaceholder" | "familyEditor.birthMonth" | "familyEditor.birthMonthUnknown" | "familyEditor.stylist" | "familyEditor.stylistNone" | "familyEditor.stylistFormer" | "familyEditor.notes" | "familyEditor.notesPlaceholder" | "familyEditor.newRow" | "familyEditor.save" | "familyEditor.remove" | "familyEditor.removeNamed" | "familyEditor.removeRow" | "familyEditor.saved" | "familyEditor.savedNoDetails" | "familyEditor.partial" | "familyEditor.removed" | "familyEditor.unreachable" | "familyEditor.ageConfirmed" | "familyEditor.ageSaved" | "logout.button" | "logout.unreachable" | "portalShell.nav" | "portalShell.navBar" | "portalUnreachable.heading" | "portalUnreachable.body" | "portalUnreachable.retry" | "portalUnreachable.call" | "profileForm.heading" | "profileForm.firstName" | "profileForm.lastName" | "profileForm.phone" | "profileForm.email" | "profileForm.emailHelp" | "profileForm.save" | "profileForm.saved" | "profileForm.restored" | "profileForm.marketing" | "profileForm.unreachable" | "rebook.heading" | "rebook.empty" | "rebook.serviceFallback" | "rebook.anyStylist" | "rebook.cta" | "upcoming.heading" | "upcoming.empty" | "upcoming.book" | "upcoming.next" | "upcoming.today" | "upcoming.tomorrow" | "upcoming.inDays" | "upcoming.when" | "upcoming.serviceFallback" | "upcoming.anyStylist" | "upcoming.manage" | "upcoming.noManage" | "upcoming.noManageWithPhone" | "upcoming.call" | "vippsLink.heading" | "vippsLink.linked" | "vippsLink.pitch" | "vippsLink.button" | "vippsLink.success" | "vippsLink.conflict" | "vippsLink.failed" | "vippsLink.unavailable" | "vippsLink.throttled" | "history.heading" | "history.empty" | "history.serviceFallback" | "history.count.one" | "history.count.other" | "history.unknownAmount" | "service.multiHint" | "service.total" | "service.chooseFirst" | "service.continue" | "service.party.nothingBookable" | "service.tabDone" | "service.heading" | "service.categoriesLegend" | "service.sameAsLast" | "service.chooseOther" | "service.duration" | "service.phoneOnly" | "service.phoneOnlyLinkLabel" | "service.ageDivider.named" | "service.ageDivider.unnamed" | "service.party.listLabel" | "service.party.adultAlone" | "service.party.nothingFits" | "service.party.remove" | "stylist.heading" | "stylist.firstAvailable" | "stylist.firstAvailableSubtitle" | "stylist.firstAvailableBadge" | "stylist.pendingName" | "stylist.nextAvailable" | "stylist.loading" | "stylist.party.legend" | "stylist.party.sequential" | "stylist.party.sequentialMinutes" | "stylist.party.parallel.two" | "stylist.party.parallel.three" | "stylist.party.parallel.other" | "stylist.party.parallelMinutes" | "stylist.party.parallelNote.two" | "stylist.party.parallelNote.three" | "stylist.party.parallelNote.other" | "stylist.party.seatsHeading" | "stylist.party.seat" | "summary.placeholder.who" | "summary.placeholder.service" | "summary.next" | "summary.hint.who" | "summary.hint.service" | "summary.hint.when" | "who.heading" | "who.guest.groupLabel" | "who.guest.children.one" | "who.guest.children.other" | "who.guest.adult" | "who.guest.addedList" | "who.family.legend" | "who.family.self" | "who.family.limit" | "who.party.children" | "who.party.childrenNote" | "who.party.adult" | "who.party.adultNote" | "who.party.fewer" | "who.party.more" | "who.party.count")[];
|
|
34
34
|
export type BookingLabelKey = BookingRequiredLabelKey | BookingOptionalLabelKey;
|
|
35
35
|
/**
|
|
36
36
|
* Keys added after a screen first shipped, for a feature a caller opts into.
|
|
37
37
|
* A pack may leave them out; a screen using the feature needs them.
|
|
38
38
|
*/
|
|
39
|
-
export type BookingOptionalLabelKey = (typeof SERVICE_SCREEN_MULTI_LABEL_KEYS)[number] | (typeof BOOKING_RECAP_LABEL_KEYS)[number] | (typeof TIME_SCREEN_FINDER_LABEL_KEYS)[number] | (typeof SUMMARY_BAR_HINT_LABEL_KEYS)[number] | (typeof WHO_SCREEN_PARTY_LABEL_KEYS)[number];
|
|
39
|
+
export type BookingOptionalLabelKey = (typeof SERVICE_SCREEN_MULTI_LABEL_KEYS)[number] | (typeof BOOKING_RECAP_LABEL_KEYS)[number] | (typeof TIME_SCREEN_FINDER_LABEL_KEYS)[number] | (typeof STYLIST_SCREEN_SEAT_LABEL_KEYS)[number] | (typeof SUMMARY_BAR_HINT_LABEL_KEYS)[number] | (typeof WHO_SCREEN_PARTY_LABEL_KEYS)[number];
|
|
40
40
|
/** Keys every complete pack defines. */
|
|
41
41
|
export type BookingRequiredLabelKey = (typeof WHO_SCREEN_LABEL_KEYS)[number] | (typeof ADD_CHILD_SHEET_LABEL_KEYS)[number] | (typeof SERVICE_SCREEN_LABEL_KEYS)[number] | (typeof STYLIST_SCREEN_LABEL_KEYS)[number] | (typeof TIME_SCREEN_LABEL_KEYS)[number] | (typeof MANAGE_SCREEN_LABEL_KEYS)[number] | (typeof DETAILS_SCREEN_LABEL_KEYS)[number] | (typeof SUMMARY_BAR_LABEL_KEYS)[number] | (typeof CONFIRMATION_LABEL_KEYS)[number] | (typeof BOOKING_SKELETON_LABEL_KEYS)[number] | (typeof LOGIN_SHEET_LABEL_KEYS)[number] | (typeof PORTAL_SHELL_LABEL_KEYS)[number] | (typeof PORTAL_UNREACHABLE_LABEL_KEYS)[number] | (typeof UPCOMING_BOOKINGS_LABEL_KEYS)[number] | (typeof VISIT_HISTORY_LABEL_KEYS)[number] | (typeof REBOOK_CARDS_LABEL_KEYS)[number] | (typeof CHILD_CARDS_LABEL_KEYS)[number] | (typeof FAMILY_EDITOR_LABEL_KEYS)[number] | (typeof PROFILE_FORM_LABEL_KEYS)[number] | (typeof DATA_CONTROLS_LABEL_KEYS)[number] | (typeof LOGOUT_BUTTON_LABEL_KEYS)[number] | (typeof VIPPS_LINK_ROW_LABEL_KEYS)[number];
|
|
42
42
|
/** A complete label pack for one locale. The opt-in keys may be absent. */
|
|
@@ -17,7 +17,7 @@ import { UPCOMING_BOOKINGS_LABEL_KEYS } from './portal/upcoming-bookings.js';
|
|
|
17
17
|
import { VIPPS_LINK_ROW_LABEL_KEYS } from './portal/vipps-link-row.js';
|
|
18
18
|
import { VISIT_HISTORY_LABEL_KEYS } from './portal/visit-history.js';
|
|
19
19
|
import { SERVICE_SCREEN_LABEL_KEYS, SERVICE_SCREEN_MULTI_LABEL_KEYS } from './service-screen.js';
|
|
20
|
-
import { STYLIST_SCREEN_LABEL_KEYS } from './stylist-screen.js';
|
|
20
|
+
import { STYLIST_SCREEN_LABEL_KEYS, STYLIST_SCREEN_SEAT_LABEL_KEYS } from './stylist-screen.js';
|
|
21
21
|
import { SUMMARY_BAR_HINT_LABEL_KEYS, SUMMARY_BAR_LABEL_KEYS } from './summary-bar.js';
|
|
22
22
|
import { TIME_SCREEN_FINDER_LABEL_KEYS, TIME_SCREEN_LABEL_KEYS } from './time-screen.js';
|
|
23
23
|
import { WHO_SCREEN_LABEL_KEYS, WHO_SCREEN_PARTY_LABEL_KEYS } from './who-screen.js';
|
|
@@ -37,6 +37,7 @@ export const BOOKING_LABEL_KEYS = [
|
|
|
37
37
|
...SERVICE_SCREEN_LABEL_KEYS,
|
|
38
38
|
...SERVICE_SCREEN_MULTI_LABEL_KEYS,
|
|
39
39
|
...STYLIST_SCREEN_LABEL_KEYS,
|
|
40
|
+
...STYLIST_SCREEN_SEAT_LABEL_KEYS,
|
|
40
41
|
...TIME_SCREEN_LABEL_KEYS,
|
|
41
42
|
...TIME_SCREEN_FINDER_LABEL_KEYS,
|
|
42
43
|
...MANAGE_SCREEN_LABEL_KEYS,
|
|
@@ -21,7 +21,12 @@ import type { BookingResourceDto, PartyMode } from './types.js';
|
|
|
21
21
|
* available» included. Arrow keys move and choose, Tab enters and leaves once.
|
|
22
22
|
*/
|
|
23
23
|
export declare const STYLIST_SCREEN_LABEL_KEYS: readonly ["stylist.heading", "stylist.firstAvailable", "stylist.firstAvailableSubtitle", "stylist.firstAvailableBadge", "stylist.pendingName", "stylist.nextAvailable", "stylist.loading", "stylist.party.legend", "stylist.party.sequential", "stylist.party.sequentialMinutes", "stylist.party.parallel.two", "stylist.party.parallel.three", "stylist.party.parallel.other", "stylist.party.parallelMinutes", "stylist.party.parallelNote.two", "stylist.party.parallelNote.three", "stylist.party.parallelNote.other"];
|
|
24
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Opt-in keys, for `party.seats` (a stylist per person when seen at once).
|
|
26
|
+
* Placeholders: `stylist.party.seat` `{who}`.
|
|
27
|
+
*/
|
|
28
|
+
export declare const STYLIST_SCREEN_SEAT_LABEL_KEYS: readonly ["stylist.party.seatsHeading", "stylist.party.seat"];
|
|
29
|
+
export type StylistScreenLabels = Record<(typeof STYLIST_SCREEN_LABEL_KEYS)[number], BookingLabel> & Partial<Record<(typeof STYLIST_SCREEN_SEAT_LABEL_KEYS)[number], BookingLabel>>;
|
|
25
30
|
/**
|
|
26
31
|
* - `root` — the `<section>`
|
|
27
32
|
* - `heading` — the `<h2>`
|
|
@@ -147,6 +152,22 @@ export interface StylistScreenProps {
|
|
|
147
152
|
parallel: number;
|
|
148
153
|
};
|
|
149
154
|
onMode: (mode: PartyMode) => void;
|
|
155
|
+
/**
|
|
156
|
+
* Seen at once: one optional stylist per person, in basket order. Each
|
|
157
|
+
* offers «first available» and the stylists who can do that person's whole
|
|
158
|
+
* visit; the search seats the rest with anyone free at that minute. Needs
|
|
159
|
+
* the `stylist.party.seat*` labels; without `seats` the mode note stands
|
|
160
|
+
* alone, as before.
|
|
161
|
+
*/
|
|
162
|
+
seats?: Array<{
|
|
163
|
+
/** Who sits there, e.g. «Barn 1», «Deg», a child's name. */
|
|
164
|
+
who: string;
|
|
165
|
+
/** Every service of this person's visit. */
|
|
166
|
+
serviceIds: string[];
|
|
167
|
+
/** Their stylist, `null` for first available. */
|
|
168
|
+
resourceId: string | null;
|
|
169
|
+
}>;
|
|
170
|
+
onSeat?: (index: number, resourceId: string | null) => void;
|
|
150
171
|
};
|
|
151
172
|
classNames?: SlotClassNames<StylistScreenSlot>;
|
|
152
173
|
components?: StylistScreenComponents;
|
|
@@ -3,6 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import { useEffect, useId, useRef, } from 'react';
|
|
4
4
|
import { cn } from '../lib/utils.js';
|
|
5
5
|
import { renderLabel } from './internal/label-parts.js';
|
|
6
|
+
import { BOOKING_SELECT_CLASS } from './internal/ui.js';
|
|
6
7
|
import { labelText } from './labels.js';
|
|
7
8
|
import { LiveStatus } from './live-status.js';
|
|
8
9
|
import { slotClass } from './slots.js';
|
|
@@ -42,6 +43,16 @@ export const STYLIST_SCREEN_LABEL_KEYS = [
|
|
|
42
43
|
'stylist.party.parallelNote.three',
|
|
43
44
|
'stylist.party.parallelNote.other',
|
|
44
45
|
];
|
|
46
|
+
/**
|
|
47
|
+
* Opt-in keys, for `party.seats` (a stylist per person when seen at once).
|
|
48
|
+
* Placeholders: `stylist.party.seat` `{who}`.
|
|
49
|
+
*/
|
|
50
|
+
export const STYLIST_SCREEN_SEAT_LABEL_KEYS = [
|
|
51
|
+
/** The heading over the per-person choices, e.g. «Who cuts whom? (optional)». */
|
|
52
|
+
'stylist.party.seatsHeading',
|
|
53
|
+
/** One person's label: `{who}`, e.g. «Stylist for {who}». */
|
|
54
|
+
'stylist.party.seat',
|
|
55
|
+
];
|
|
45
56
|
/**
|
|
46
57
|
* One height per breakpoint for every option, filled or not, so nothing on the
|
|
47
58
|
* step — nor what is under it — moves when a list or a line lands: a 128 px
|
|
@@ -127,7 +138,10 @@ export function StylistScreen({ labels, format, now, serviceIds, resources, sele
|
|
|
127
138
|
minutes: party.minutes.sequential,
|
|
128
139
|
}), classNames: classNames }), _jsx(ModeCard, { selected: party.mode === 'parallel', onClick: () => party.onMode('parallel'), title: bySize(labels, 'stylist.party.parallel', party.size, party.sizeWord), subtitle: renderLabel(labels['stylist.party.parallelMinutes'], {
|
|
129
140
|
minutes: party.minutes.parallel,
|
|
130
|
-
}), classNames: classNames })] })), party?.mode === 'parallel' ? (_jsx("p", { className: "rounded-lg border border-border bg-card px-5 py-4 text-sm", children: bySize(labels, 'stylist.party.parallelNote', party.size, party.sizeWord) })
|
|
141
|
+
}), classNames: classNames })] })), party?.mode === 'parallel' ? (_jsxs("div", { className: "space-y-4", children: [_jsx("p", { className: "rounded-lg border border-border bg-card px-5 py-4 text-sm", children: bySize(labels, 'stylist.party.parallelNote', party.size, party.sizeWord) }), party.seats &&
|
|
142
|
+
party.onSeat &&
|
|
143
|
+
labels['stylist.party.seatsHeading'] &&
|
|
144
|
+
labels['stylist.party.seat'] && (_jsx(SeatChoices, { seats: party.seats, onSeat: party.onSeat, resources: resources, heading: labels['stylist.party.seatsHeading'], seatLabel: labels['stylist.party.seat'], anyone: labelText(labels['stylist.firstAvailable']), pending: labelText(labels['stylist.pendingName']), format: format }))] })) : (_jsx(StylistRadioGroup, { options: options, selectedResourceId: selectedResourceId,
|
|
131
145
|
// The held option takes one placeholder's place, so the row is
|
|
132
146
|
// exactly as long as it was and nothing after it moves.
|
|
133
147
|
skeletons: loading ? Math.max(0, skeletonCount - (options.length - 1)) : 0, busy: loading, onPick: onPick, labels: labels, classNames: classNames, edgeFade: edgeFade, row: row, Card: components?.StylistCard ?? DefaultStylistCard })), row && party?.mode !== 'parallel' && (_jsx(ChosenBio, { options: options, selectedResourceId: selectedResourceId })), _jsx(LiveStatus, { text: loading ? labelText(labels['stylist.loading']) : notice })] }));
|
|
@@ -276,3 +290,29 @@ function ChosenBio({ options, selectedResourceId, }) {
|
|
|
276
290
|
return null;
|
|
277
291
|
return (_jsxs("p", { "data-testid": "stylist-bio", className: "-mt-3 text-sm text-muted-foreground", children: [_jsx("span", { className: "font-medium text-foreground", children: chosen.name }), " \u00B7 ", chosen.subtitle] }));
|
|
278
292
|
}
|
|
293
|
+
/**
|
|
294
|
+
* Seen at once: «who cuts whom», one native select per person. A select, not a
|
|
295
|
+
* second row of avatar tiles: a family of three would be three radiogroups of
|
|
296
|
+
* the same faces, and the question is optional — most leave it on «first
|
|
297
|
+
* available». Each lists only the stylists who can do that person's whole visit,
|
|
298
|
+
* in the salon's order; one already chosen for another person is left out, as
|
|
299
|
+
* one stylist cannot cut two people at once.
|
|
300
|
+
*/
|
|
301
|
+
function SeatChoices({ seats, onSeat, resources, heading, seatLabel, anyone, pending, format, }) {
|
|
302
|
+
const id = useId();
|
|
303
|
+
const ordered = [...resources].sort((a, b) => a.sortOrder - b.sortOrder);
|
|
304
|
+
return (_jsxs("fieldset", { className: "space-y-3", children: [_jsx("legend", { className: "mb-1 font-sans text-base font-semibold", children: renderLabel(heading) }), seats.map((seat, index) => {
|
|
305
|
+
const takenElsewhere = new Set(seats.flatMap((other, at) => at !== index && other.resourceId !== null ? [other.resourceId] : []));
|
|
306
|
+
const options = ordered.filter((resource) => seat.serviceIds.every((serviceId) => resource.serviceIds.includes(serviceId)) &&
|
|
307
|
+
!takenElsewhere.has(resource.id));
|
|
308
|
+
const selectId = `${id}-seat-${index}`;
|
|
309
|
+
// A saved choice the list cannot show (still loading, gone, or no longer
|
|
310
|
+
// able to do the visit) stays the selected option, by name where known:
|
|
311
|
+
// shown as «first available» it would read as an answer never given.
|
|
312
|
+
const held = seat.resourceId !== null && !options.some((resource) => resource.id === seat.resourceId)
|
|
313
|
+
? seat.resourceId
|
|
314
|
+
: null;
|
|
315
|
+
const heldResource = held === null ? undefined : resources.find((r) => r.id === held);
|
|
316
|
+
return (_jsxs("div", { className: "space-y-1", children: [_jsx("label", { htmlFor: selectId, className: "block text-sm font-medium", children: renderLabel(seatLabel, { who: seat.who }) }), _jsxs("select", { id: selectId, value: seat.resourceId ?? '', onChange: (event) => onSeat(index, event.target.value === '' ? null : event.target.value), className: BOOKING_SELECT_CLASS, children: [_jsx("option", { value: "", children: anyone }), held !== null && (_jsx("option", { value: held, children: heldResource ? format.stylistName(heldResource.name) : pending })), options.map((resource) => (_jsx("option", { value: resource.id, children: format.stylistName(resource.name) }, resource.id)))] })] }, selectId));
|
|
317
|
+
})] }));
|
|
318
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ComponentType } from 'react';
|
|
1
|
+
import { type ComponentType, type ReactNode } from 'react';
|
|
2
2
|
import type { BookingDaypart, BookingFormat } from './format.js';
|
|
3
3
|
import { type BookingLabel } from './labels.js';
|
|
4
4
|
import { type SlotClassNames } from './slots.js';
|
|
@@ -70,8 +70,23 @@ export declare function dayFreeMarks(free: number): 0 | 1 | 2 | 3;
|
|
|
70
70
|
export declare function DefaultDayChip({ label, selected, className, onSelect, free, freeLabel, }: DayChipProps): import("react").JSX.Element;
|
|
71
71
|
export interface TimeChipProps {
|
|
72
72
|
startTs: number;
|
|
73
|
-
/**
|
|
73
|
+
/**
|
|
74
|
+
* «14:30», a party's «15:00 → 16:00», a simultaneous party's
|
|
75
|
+
* «15:00 (Mia with Ada · Leo with Bo)», or the current hour's
|
|
76
|
+
* «15:00 · Current time». Always the chip's whole sentence.
|
|
77
|
+
*/
|
|
74
78
|
label: string;
|
|
79
|
+
/**
|
|
80
|
+
* `label` as elements, in the label pack's own order, with a simultaneous
|
|
81
|
+
* party's seating in a span that may wrap — so a long seating breaks onto
|
|
82
|
+
* the next line instead of widening the chip past the screen.
|
|
83
|
+
*/
|
|
84
|
+
richLabel?: ReactNode;
|
|
85
|
+
/**
|
|
86
|
+
* What a week-grid column shows: too narrow for the seating, so only the
|
|
87
|
+
* hour, with `label` as the accessible name and the tooltip.
|
|
88
|
+
*/
|
|
89
|
+
compactLabel?: string;
|
|
75
90
|
/** One of the nearest alternatives to a slot that was just taken. */
|
|
76
91
|
nearest: boolean;
|
|
77
92
|
/** The screen-reader text that says so. */
|
|
@@ -83,7 +98,7 @@ export interface TimeChipProps {
|
|
|
83
98
|
onPick: () => void;
|
|
84
99
|
}
|
|
85
100
|
/** One time chip. */
|
|
86
|
-
export declare function DefaultTimeChip({ label, nearest, nearestLabel, current, className, onPick, }: TimeChipProps): import("react").JSX.Element;
|
|
101
|
+
export declare function DefaultTimeChip({ label, richLabel, compactLabel, nearest, nearestLabel, current, className, onPick, }: TimeChipProps): import("react").JSX.Element;
|
|
87
102
|
export interface TimeScreenComponents {
|
|
88
103
|
DayChip?: ComponentType<DayChipProps>;
|
|
89
104
|
TimeChip?: ComponentType<TimeChipProps>;
|
|
@@ -3,7 +3,7 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
|
|
|
3
3
|
import { ChevronDown, ChevronLeft, ChevronRight, ChevronUp, X } from 'lucide-react';
|
|
4
4
|
import { useEffect, useId, useRef, useState } from 'react';
|
|
5
5
|
import { cn } from '../lib/utils.js';
|
|
6
|
-
import { renderLabel } from './internal/label-parts.js';
|
|
6
|
+
import { labelParts, renderLabel } from './internal/label-parts.js';
|
|
7
7
|
import { BookingButton, bookingButtonClass } from './internal/ui.js';
|
|
8
8
|
import { visitName } from './internal/visit.js';
|
|
9
9
|
import { fillLabel, labelText } from './labels.js';
|
|
@@ -123,11 +123,13 @@ export function DefaultDayChip({ label, selected, className, onSelect, free, fre
|
|
|
123
123
|
return (_jsxs(BookingButton, { variant: "outline", size: "sm", "aria-pressed": selected, onClick: onSelect, className: cn('h-auto min-h-11 flex-col gap-1 py-1.5', free === 0 && !selected && 'text-muted-foreground', className), children: [_jsx("span", { children: label }), free === 0 && freeLabel ? (_jsx("span", { className: "text-[11px] font-medium leading-none", children: freeLabel })) : (_jsxs(_Fragment, { children: [_jsx("span", { "aria-hidden": "true", "data-testid": "day-free-marks", className: "flex gap-0.5", children: [1, 2, 3].map((mark) => (_jsx("span", { "data-filled": mark <= marks ? '' : undefined, className: cn('block h-[3px] w-2 rounded-full bg-current', mark > marks && 'opacity-25') }, mark))) }), freeLabel && _jsx("span", { className: "sr-only", children: freeLabel })] }))] }));
|
|
124
124
|
}
|
|
125
125
|
/** One time chip. */
|
|
126
|
-
export function DefaultTimeChip({ label, nearest, nearestLabel, current, className, onPick, }) {
|
|
126
|
+
export function DefaultTimeChip({ label, richLabel, compactLabel, nearest, nearestLabel, current, className, onPick, }) {
|
|
127
127
|
if (current) {
|
|
128
128
|
return (_jsx(BookingButton, { variant: "outline", size: "lg", disabled: true, "aria-current": "true", className: className, children: label }));
|
|
129
129
|
}
|
|
130
|
-
|
|
130
|
+
// A compact chip draws less than its sentence, so the sentence becomes its name.
|
|
131
|
+
const compact = compactLabel !== undefined;
|
|
132
|
+
return (_jsxs(BookingButton, { variant: "outline", size: "lg", onClick: onPick, "aria-label": compact ? `${label}${nearest ? ` ${nearestLabel}` : ''}` : undefined, title: compact ? label : undefined, className: cn(!compact && richLabel !== undefined && 'h-auto max-w-full py-2 whitespace-normal', className), children: [compact && compactLabel, !compact && richLabel !== undefined && (_jsx("span", { className: "min-w-0 text-center", children: richLabel })), !compact && richLabel === undefined && label, nearest && !compact && (_jsxs("span", { className: "sr-only", children: [" ", nearestLabel] }))] }));
|
|
131
133
|
}
|
|
132
134
|
// ---------------------------------------------------------------------------
|
|
133
135
|
// View logic
|
|
@@ -174,16 +176,19 @@ function buildDayStrip(clock, slots, days, takenSlotTs, currentSlotTs, openDays,
|
|
|
174
176
|
/**
|
|
175
177
|
* The one chip a family taps: `15:00 → 16:00`, or the parallel form
|
|
176
178
|
* `15:00 (Name with Stylist · Name with Stylist)`. The parallel chip names the
|
|
177
|
-
* people where the visitor has given a name and the service otherwise
|
|
179
|
+
* people where the visitor has given a name and the service otherwise; its
|
|
180
|
+
* seating is drawn so it can wrap, and a week column shows the hour alone.
|
|
178
181
|
*/
|
|
179
|
-
function
|
|
182
|
+
function partyChipText(labels, clock, slot, party) {
|
|
180
183
|
if (slot.mode === 'sequential') {
|
|
181
|
-
return
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
184
|
+
return {
|
|
185
|
+
label: fillLabel(labels['time.party.sequential'], {
|
|
186
|
+
start: clock.formatTime(slot.startTs),
|
|
187
|
+
end: clock.formatTime(party.chipEndTs(slot)),
|
|
188
|
+
}),
|
|
189
|
+
};
|
|
185
190
|
}
|
|
186
|
-
const
|
|
191
|
+
const names = slot.seats.map((seat, index) => {
|
|
187
192
|
const item = party.items[index];
|
|
188
193
|
const who = item?.bookedForName ?? (item ? visitName(item) : '');
|
|
189
194
|
const stylist = party.resolveStylistName(seat.resourceId);
|
|
@@ -191,10 +196,16 @@ function partyChipLabel(labels, clock, slot, party) {
|
|
|
191
196
|
// is a reload of the resource list, not a reason to hide the slot.
|
|
192
197
|
return stylist === null ? who : fillLabel(labels['time.party.seat'], { who, stylist });
|
|
193
198
|
});
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
199
|
+
const time = clock.formatTime(slot.startTs);
|
|
200
|
+
const seats = names.join(labelText(labels['time.party.seatSeparator']));
|
|
201
|
+
return {
|
|
202
|
+
label: fillLabel(labels['time.party.parallel'], { time, seats }),
|
|
203
|
+
richLabel: labelParts(labels['time.party.parallel'], {
|
|
204
|
+
time,
|
|
205
|
+
seats: _jsx("span", { className: "font-normal text-muted-foreground", children: seats }),
|
|
206
|
+
}),
|
|
207
|
+
compactLabel: time,
|
|
208
|
+
};
|
|
198
209
|
}
|
|
199
210
|
/**
|
|
200
211
|
* The instants on offer — ONE per instant. Availability is per (start,
|
|
@@ -426,7 +437,7 @@ function WeekGrid({ labels, words, format, days, offered, currentSlotTs, nearest
|
|
|
426
437
|
const partySlot = partyByStart.get(slot.startTs);
|
|
427
438
|
const current = slot.startTs === currentSlotTs;
|
|
428
439
|
const isNearest = !current && nearest.has(slot.startTs);
|
|
429
|
-
return (_jsx("li", { children: _jsx(TimeChip, { startTs: slot.startTs,
|
|
440
|
+
return (_jsx("li", { children: _jsx(TimeChip, { startTs: slot.startTs, ...chipText(labels, clock, slot, current, partySlot, party), nearest: isNearest, nearestLabel: labelText(labels['time.nearest']), current: current, onPick: () => (partySlot && party ? party.onPick(partySlot) : onPick(slot)), className: cn('h-auto min-h-11 w-full min-w-0 whitespace-normal px-1 tabular-nums', isNearest ? 'border-primary ring-2 ring-primary' : '', classNames?.chip, isNearest ? classNames?.chipNearest : undefined, current ? classNames?.chipCurrent : undefined) }) }, slot.startTs));
|
|
430
441
|
}) })), more > 0 && (_jsx(BookingButton, { variant: "link", size: "sm", onClick: () => setUnfolded(key), className: "w-full", children: renderLabel(words.more, { count: more }) })), bookable === 0 &&
|
|
431
442
|
(alternative && party ? (_jsx(BookingButton, { size: "sm", onClick: () => party.onPick(alternative), className: "h-auto min-h-11 w-full whitespace-normal tabular-nums", children: renderLabel(labels['time.parallel.accept'], {
|
|
432
443
|
time: clock.formatTime(alternative.startTs),
|
|
@@ -435,13 +446,13 @@ function WeekGrid({ labels, words, format, days, offered, currentSlotTs, nearest
|
|
|
435
446
|
return (_jsxs("div", { "data-testid": "time-week", className: cn('space-y-4', className), children: [_jsx("ol", { className: "grid grid-cols-7 gap-2", children: columns }), !anyBookable && empty, next, todayOpen && (_jsx(ShortNoticeLine, { labels: labels, format: format, phone: phone, className: classNames?.shortNotice }))] }));
|
|
436
447
|
}
|
|
437
448
|
/** A time chip's words: the hour, the held hour marked, or a family's whole visit. */
|
|
438
|
-
function
|
|
449
|
+
function chipText(labels, clock, slot, current, partySlot, party) {
|
|
439
450
|
const time = clock.formatTime(slot.startTs);
|
|
440
451
|
if (current)
|
|
441
|
-
return fillLabel(labels['time.current'], { time });
|
|
452
|
+
return { label: fillLabel(labels['time.current'], { time }) };
|
|
442
453
|
if (partySlot && party)
|
|
443
|
-
return
|
|
444
|
-
return time;
|
|
454
|
+
return partyChipText(labels, clock, partySlot, party);
|
|
455
|
+
return { label: time };
|
|
445
456
|
}
|
|
446
457
|
/** The weekend note as one plain sentence, for a card that books without the notice on screen. */
|
|
447
458
|
function weekendSentenceText(labels, format, note) {
|
|
@@ -594,7 +605,7 @@ function DaypartSections({ labels, clock, dayparts, daySlots, nearest, currentSl
|
|
|
594
605
|
const partySlot = partyByStart.get(slot.startTs);
|
|
595
606
|
const current = slot.startTs === currentSlotTs;
|
|
596
607
|
const isNearest = !current && nearest.has(slot.startTs);
|
|
597
|
-
return (_jsx(TimeChip, { startTs: slot.startTs,
|
|
608
|
+
return (_jsx(TimeChip, { startTs: slot.startTs, ...chipText(labels, clock, slot, current, partySlot, party), compactLabel: undefined, nearest: isNearest, nearestLabel: labelText(labels['time.nearest']), current: current, onPick: () => (partySlot && party ? party.onPick(partySlot) : onPick(slot)), className: cn('min-w-20 tabular-nums', isNearest ? 'border-primary ring-2 ring-primary' : '', classNames?.chip, isNearest ? classNames?.chipNearest : undefined, current ? classNames?.chipCurrent : undefined) }, slot.startTs));
|
|
598
609
|
}) })] }, daypart.key));
|
|
599
610
|
});
|
|
600
611
|
}
|