@medalsocial/booking 0.2.1 → 0.3.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/CHANGELOG.md +22 -0
- package/README.md +21 -3
- package/dist/core/attempt-store.d.mts +1 -0
- package/dist/core/attempt-store.mjs +13 -0
- package/dist/core/attempt-store.mjs.map +1 -1
- package/dist/core/config.d.mts +37 -0
- package/dist/core/config.mjs +29 -0
- package/dist/core/config.mjs.map +1 -1
- package/dist/core/machine.d.mts +27 -1
- package/dist/core/machine.mjs +52 -4
- package/dist/core/machine.mjs.map +1 -1
- package/dist/next/medal.d.mts +8 -1
- package/dist/next/medal.mjs +16 -5
- package/dist/next/medal.mjs.map +1 -1
- package/dist/next/portal/medal-portal.mjs +1 -62
- package/dist/next/portal/medal-portal.mjs.map +1 -1
- package/dist/next/redact.mjs +76 -0
- package/dist/next/redact.mjs.map +1 -0
- package/dist/next/routes/create.mjs +67 -9
- package/dist/next/routes/create.mjs.map +1 -1
- package/dist/next/routes/shared.mjs +3 -0
- package/dist/next/routes/shared.mjs.map +1 -1
- package/dist/react/BookingWizard.mjs +139 -11
- package/dist/react/BookingWizard.mjs.map +1 -1
- package/dist/react/LoginSheet.d.mts +19 -1
- package/dist/react/LoginSheet.mjs +15 -1
- package/dist/react/LoginSheet.mjs.map +1 -1
- package/dist/react/Provider.d.mts +2 -1
- package/dist/react/Provider.mjs.map +1 -1
- package/dist/react/actions.d.mts +16 -5
- package/dist/react/actions.mjs +5 -1
- package/dist/react/actions.mjs.map +1 -1
- package/dist/react/index.d.mts +2 -2
- package/dist/react/kit.d.mts +6 -1
- package/dist/react/kit.mjs +4 -3
- package/dist/react/kit.mjs.map +1 -1
- package/dist/react/labels/login.d.mts +2 -0
- package/dist/react/labels/login.mjs +4 -2
- package/dist/react/labels/login.mjs.map +1 -1
- package/dist/react/labels/screens.mjs +58 -2
- package/dist/react/labels/screens.mjs.map +1 -1
- package/dist/react/labels/wizard.d.mts +8 -0
- package/dist/react/labels/wizard.mjs +6 -0
- package/dist/react/labels/wizard.mjs.map +1 -1
- package/dist/react/screen-labels.mjs +5 -0
- package/dist/react/screen-labels.mjs.map +1 -1
- package/dist/react/useBooking.d.mts +19 -1
- package/dist/react/useBooking.mjs +269 -42
- package/dist/react/useBooking.mjs.map +1 -1
- package/dist/react/wizard/adapters.mjs +66 -3
- package/dist/react/wizard/adapters.mjs.map +1 -1
- package/dist/react/wizard/index.d.mts +2 -2
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapters.mjs","names":[],"sources":["../../../src/react/wizard/adapters.ts"],"sourcesContent":["/**\n * What the wizard hands each meda screen, worked out of the site's kit.\n *\n * The screens are presentational: the domain rules they leave to their caller\n * — prices, the weekend note, ages and «last visit» lines, the category\n * filing, the possessive, the phone rules, the calendar file — are answered\n * here, once, so `<BookingWizard>` and anything else that draws a screen\n * (a test, a custom shell over `useBooking()`) answer them the same way.\n */\n\nimport type {\n ConfirmationProps,\n DetailsLine,\n ServicePartyPerson,\n WeekendNote,\n WhoGuestChoice,\n WhoPersonEntry,\n} from '@medalsocial/meda/booking';\nimport type { AgeRange } from '../../core/age';\nimport { normaliseCategory } from '../../core/categories';\nimport { fill, labelText } from '../../core/labels';\nimport { SELF_KEY, type WizardItem, type WizardPerson, type WizardState } from '../../core/machine';\nimport type { BookingFamilyMember, BookingServiceDto } from '../../core/types';\nimport { visitOf, visitServicesOf } from '../../core/visit';\nimport type { BookingKit } from '../kit';\nimport type { BookingLabels } from '../labels';\nimport type { BookingConfirmation, BookingSuggestion } from '../useBooking';\nimport { confirmationLines, personForChild } from '../useBooking';\n\n/** Step 1's guest chips: one to `maxPeople` children, then one grown-up. */\nexport function guestChoices(kit: BookingKit): WhoGuestChoice[] {\n const { wizard } = kit;\n return [\n ...Array.from({ length: wizard.maxPeople }, (_, index) => ({\n key: `children-${index + 1}`,\n people: Array.from({ length: index + 1 }, (_, seat) => wizard.guestChild(seat + 1)),\n })),\n { key: 'adult', people: [{ key: 'adult', adult: true }] },\n ];\n}\n\n/** «7 år», or `''` when the year is unknown — the age on the business day `dayKey`. */\nexport function ageLine(\n kit: BookingKit,\n birthYear: number | undefined,\n birthMonth: number | undefined,\n dayKey: string\n): string {\n if (birthYear === undefined) return '';\n const range = kit.age.ageOnDay(birthYear, birthMonth, dayKey);\n return range === null ? '' : kit.format.ageLabel(range);\n}\n\n/** «7 år · Sist: Gutteklipp, tor. 12. aug.», or the age alone for a first visit. */\nexport function childLine(kit: BookingKit, child: BookingFamilyMember, dayKey: string): string {\n const { labels } = kit;\n const parts = [ageLine(kit, child.birthYear, child.birthMonth, dayKey) || null];\n if (child.lastVisit) {\n parts.push(\n fill(labels['wizard.who.lastVisit'], {\n service: child.lastVisit.serviceName ?? labelText(labels['wizard.who.lastVisitFallback']),\n date: kit.clock.date(child.lastVisit.startTs),\n })\n );\n }\n return parts.filter((part) => part !== null).join(' · ');\n}\n\n/** A logged-in parent's children as step 1's cards. */\nexport function familyEntries(\n kit: BookingKit,\n family: readonly BookingFamilyMember[],\n dayKey: string\n): WhoPersonEntry[] {\n return family.map((child, index) => ({\n person: personForChild(child, index),\n line: childLine(kit, child, dayKey),\n }));\n}\n\n/** The children a guest named in the sheet, as ticked cards under the chips. */\nexport function addedChildEntries(\n kit: BookingKit,\n people: readonly WizardPerson[],\n dayKey: string\n): WhoPersonEntry[] {\n return people\n .filter((person) => person.key.startsWith('new:'))\n .map((person) => ({\n person,\n line: ageLine(kit, person.birthYear, person.birthMonth, dayKey),\n }));\n}\n\n/**\n * What step 2 calls each person: the child's name and age on the day, «Barn\n * 2» for a guest's second child, «Meg selv» / «Voksen» for a grown-up.\n */\nexport function partyPeople(\n kit: BookingKit,\n people: readonly WizardPerson[],\n ageOf: (person: WizardPerson) => AgeRange | null,\n suggestionFor: (person: WizardPerson) => BookingSuggestion | null\n): ServicePartyPerson[] {\n const { labels } = kit;\n return people.map((person, index) => {\n if (person.adult) {\n return {\n key: person.key,\n label: labelText(person.key === SELF_KEY ? labels['people.self'] : labels['people.adult']),\n adult: true,\n };\n }\n if (person.name === undefined) {\n return {\n key: person.key,\n label: fill(labels['wizard.party.child'], { n: index + 1 }),\n adult: false,\n };\n }\n const range = ageOf(person);\n return {\n key: person.key,\n label:\n range === null\n ? person.name\n : fill(labels['wizard.party.named'], {\n name: person.name,\n age: kit.format.ageLabel(range),\n }),\n name: person.name,\n adult: false,\n suggestion: suggestionFor(person),\n };\n });\n}\n\n/** The service step's site-wide answers: groups, filing, the kids' menu, the possessive. */\nexport function serviceScreenBase(kit: BookingKit) {\n return {\n categories: [...kit.categories],\n // Unknown Medal categories join the configured catch-all, never fall off the page.\n categoryOf: (service: BookingServiceDto) => normaliseCategory(kit.config, service.category),\n childCategory: kit.childCategory ?? undefined,\n possessive: kit.possessive,\n phone: kit.config.contact.phone,\n };\n}\n\n/** Whether a service suits the person at `index`, by their age on the day. */\nexport function serviceFitsFor(kit: BookingKit, ages: ReadonlyArray<AgeRange | null>) {\n return (service: BookingServiceDto, index: number) =>\n kit.age.fitsAge(service, ages[index] ?? null);\n}\n\n/**\n * The weekend note for one person or the whole family: the rate when every\n * line pays the same one (`null` when they differ), and the basket's total\n * priced on the day asked about. `null` when nothing in the basket pays.\n */\nexport function weekendNoteFor(\n kit: BookingKit,\n items: readonly WizardItem[],\n dayTs: number\n): WeekendNote | null {\n if (items.length === 0) return null;\n // Every service of every visit: a wash on a Saturday pays its own rate even\n // when the cut beside it does not.\n const rates = [\n ...new Set(\n items.flatMap((item) => visitServicesOf(item).map((service) => service.weekendSurchargePct))\n ),\n ];\n if (rates.every((rate) => rate <= 0)) return null;\n return {\n pct: rates.length === 1 ? rates[0] : null,\n priceOre: kit.wizard.totalPriceOre([...items], dayTs),\n };\n}\n\n/** One line per basket item: the start the machine seated it at, and its resolved stylist. */\nexport function detailsLines(kit: BookingKit, state: WizardState): DetailsLine[] {\n const starts = kit.wizard.itemStartTimes(state.items, state.startTs ?? 0, state.partyMode);\n const resourceIds = kit.wizard.itemResourceIds(state);\n return state.items.map((_, index) => ({\n startTs: starts[index],\n resourceId: resourceIds[index],\n }));\n}\n\n/** The details step's site-wide answers: the phone rules, the terms link, the marketing box. */\nexport function detailsScreenBase(kit: BookingKit) {\n const { phone, config } = kit;\n return {\n phoneLooksValid: phone.looksValid,\n normalisePhone: phone.nationalDigits,\n phone: config.contact.phone,\n // A link with no words is a link nobody can name: drawn only with its text.\n termsHref: labelText(kit.labels['details.terms.link']) ? config.consent.termsUrl : null,\n marketingConsent: config.consent.marketing !== null,\n };\n}\n\n/**\n * The confirmation card's data and its calendar file.\n *\n * One price per line from the same function the total is the sum of, so the\n * card adds up on a Saturday too. ONE calendar entry per line, keyed to that\n * line's own booking id (the UID is the booking id, unchanged), titled with\n * whose appointment it is and carrying that line's own manage link —\n * absolute when the site's origin is known.\n */\nexport function confirmationProps(\n kit: BookingKit,\n confirmation: BookingConfirmation,\n siteUrl?: string\n): Pick<\n ConfirmationProps,\n 'lines' | 'startTs' | 'totalOre' | 'address' | 'calendarHref' | 'calendarFileName' | 'portalHref'\n> {\n const { labels, wizard, config, format } = kit;\n const { submitted } = confirmation;\n const items = submitted.items;\n const starts = wizard.itemStartTimes(items, submitted.startTs, submitted.partyMode);\n const lines = confirmationLines(confirmation).map((line, index) => ({\n ...line,\n startTs: starts[index],\n // The WHOLE visit's price, each service with its own surcharge — the same\n // function `totalPriceOre` sums, so the lines add up to «Totalt».\n priceOre: wizard.visitItemPriceOre(line.item, submitted.startTs),\n }));\n const absolute = (href: string) => (siteUrl ? new URL(href, siteUrl).toString() : href);\n const calendarHref = kit.ics.icsDataUrl(\n kit.ics.buildIcs(\n lines.map((line) => {\n const { bookedForName } = line.item;\n // One calendar entry per person: as long as their whole visit, named\n // after every service in it.\n const names = visitServicesOf(line.item)\n .map((service) => service.name)\n .join(' + ');\n const description = [\n fill(labels['wizard.ics.price'], { price: format.price(line.priceOre) }),\n ];\n if (line.manageHref !== null) {\n description.push(fill(labels['wizard.ics.manage'], { url: absolute(line.manageHref) }));\n }\n return {\n uid: line.bookingId,\n startTs: line.startTs,\n endTs: line.startTs + visitOf(line.item).durationMinutes * 60_000,\n summary: fill(labels[bookedForName ? 'wizard.ics.titleFor' : 'wizard.ics.title'], {\n service: names,\n name: bookedForName ?? '',\n business: config.contact.name,\n }),\n description: description.join('\\n'),\n ...(config.contact.address ? { location: config.contact.address } : {}),\n };\n })\n )\n );\n return {\n lines,\n startTs: submitted.startTs,\n totalOre: wizard.totalPriceOre(items, submitted.startTs),\n address: config.contact.address,\n calendarHref,\n calendarFileName: labelText(labels['wizard.ics.fileName']),\n portalHref: config.paths.portal,\n };\n}\n\n/**\n * The party size as the copy spells it (`wizard.party.sizeWord.*`), for\n * `{sizeWord}` in the stylist step's party labels; `undefined` (meda fills in\n * the number) where the pack leaves it blank.\n */\nexport function partySizeWord(labels: Readonly<BookingLabels>, size: number): string | undefined {\n const suffix = size === 2 ? 'two' : size === 3 ? 'three' : 'other';\n return labelText(labels[`wizard.party.sizeWord.${suffix}`]) || undefined;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"adapters.mjs","names":[],"sources":["../../../src/react/wizard/adapters.ts"],"sourcesContent":["/**\n * What the wizard hands each meda screen, worked out of the site's kit.\n *\n * The screens are presentational: the domain rules they leave to their caller\n * — prices, the weekend note, ages and «last visit» lines, the category\n * filing, the possessive, the phone rules, the calendar file — are answered\n * here, once, so `<BookingWizard>` and anything else that draws a screen\n * (a test, a custom shell over `useBooking()`) answer them the same way.\n */\n\nimport type {\n BookingRecapAlternative,\n BookingRecapLine,\n ConfirmationProps,\n DetailsLine,\n ServicePartyPerson,\n WeekendNote,\n WhoGuestChoice,\n WhoPersonEntry,\n} from '@medalsocial/meda/booking';\nimport type { AgeRange } from '../../core/age';\nimport { normaliseCategory } from '../../core/categories';\nimport { fill, labelText } from '../../core/labels';\nimport { SELF_KEY, type WizardItem, type WizardPerson, type WizardState } from '../../core/machine';\nimport type {\n BookingFamilyMember,\n BookingResourceDto,\n BookingServiceDto,\n BookingSlotDto,\n} from '../../core/types';\nimport { visitOf, visitServicesOf } from '../../core/visit';\nimport type { BookingKit } from '../kit';\nimport type { BookingLabels } from '../labels';\nimport type { BookingConfirmation, BookingSuggestion } from '../useBooking';\nimport { confirmationLines, personForChild } from '../useBooking';\n\n/** Step 1's guest chips: one to `maxPeople` children, then one grown-up. */\nexport function guestChoices(kit: BookingKit): WhoGuestChoice[] {\n const { wizard } = kit;\n return [\n ...Array.from({ length: wizard.maxPeople }, (_, index) => ({\n key: `children-${index + 1}`,\n people: Array.from({ length: index + 1 }, (_, seat) => wizard.guestChild(seat + 1)),\n })),\n { key: 'adult', people: [{ key: 'adult', adult: true }] },\n ];\n}\n\n/** «7 år», or `''` when the year is unknown — the age on the business day `dayKey`. */\nexport function ageLine(\n kit: BookingKit,\n birthYear: number | undefined,\n birthMonth: number | undefined,\n dayKey: string\n): string {\n if (birthYear === undefined) return '';\n const range = kit.age.ageOnDay(birthYear, birthMonth, dayKey);\n return range === null ? '' : kit.format.ageLabel(range);\n}\n\n/** «7 år · Sist: Gutteklipp, tor. 12. aug.», or the age alone for a first visit. */\nexport function childLine(kit: BookingKit, child: BookingFamilyMember, dayKey: string): string {\n const { labels } = kit;\n const parts = [ageLine(kit, child.birthYear, child.birthMonth, dayKey) || null];\n if (child.lastVisit) {\n parts.push(\n fill(labels['wizard.who.lastVisit'], {\n service: child.lastVisit.serviceName ?? labelText(labels['wizard.who.lastVisitFallback']),\n date: kit.clock.date(child.lastVisit.startTs),\n })\n );\n }\n return parts.filter((part) => part !== null).join(' · ');\n}\n\n/** A logged-in parent's children as step 1's cards. */\nexport function familyEntries(\n kit: BookingKit,\n family: readonly BookingFamilyMember[],\n dayKey: string\n): WhoPersonEntry[] {\n return family.map((child, index) => ({\n person: personForChild(child, index),\n line: childLine(kit, child, dayKey),\n }));\n}\n\n/** The children a guest named in the sheet, as ticked cards under the chips. */\nexport function addedChildEntries(\n kit: BookingKit,\n people: readonly WizardPerson[],\n dayKey: string\n): WhoPersonEntry[] {\n return people\n .filter((person) => person.key.startsWith('new:'))\n .map((person) => ({\n person,\n line: ageLine(kit, person.birthYear, person.birthMonth, dayKey),\n }));\n}\n\n/**\n * What step 2 calls each person: the child's name and age on the day, «Barn\n * 2» for a guest's second child, «Meg selv» / «Voksen» for a grown-up.\n */\nexport function partyPeople(\n kit: BookingKit,\n people: readonly WizardPerson[],\n ageOf: (person: WizardPerson) => AgeRange | null,\n suggestionFor: (person: WizardPerson) => BookingSuggestion | null\n): ServicePartyPerson[] {\n const { labels } = kit;\n return people.map((person, index) => {\n if (person.adult) {\n return {\n key: person.key,\n label: labelText(person.key === SELF_KEY ? labels['people.self'] : labels['people.adult']),\n adult: true,\n };\n }\n if (person.name === undefined) {\n return {\n key: person.key,\n label: fill(labels['wizard.party.child'], { n: index + 1 }),\n adult: false,\n };\n }\n const range = ageOf(person);\n return {\n key: person.key,\n label:\n range === null\n ? person.name\n : fill(labels['wizard.party.named'], {\n name: person.name,\n age: kit.format.ageLabel(range),\n }),\n name: person.name,\n adult: false,\n suggestion: suggestionFor(person),\n };\n });\n}\n\n/** The service step's site-wide answers: groups, filing, the kids' menu, the possessive. */\nexport function serviceScreenBase(kit: BookingKit) {\n return {\n categories: [...kit.categories],\n // Unknown Medal categories join the configured catch-all, never fall off the page.\n categoryOf: (service: BookingServiceDto) => normaliseCategory(kit.config, service.category),\n childCategory: kit.childCategory ?? undefined,\n possessive: kit.possessive,\n phone: kit.config.contact.phone,\n };\n}\n\n/** Whether a service suits the person at `index`, by their age on the day. */\nexport function serviceFitsFor(\n kit: BookingKit,\n ages: ReadonlyArray<AgeRange | null>,\n people: ReadonlyArray<WizardPerson> = []\n) {\n // `screens.childMenuFirst`: a child's list leads with what is meant for\n // children and for anyone. A grown-ups' group moves below the divider, not\n // off the list, so the twelve-year-old who wants the men's cut still has it.\n const adultGroups = new Set(\n kit.config.screens.childMenuFirst\n ? kit.config.categories\n .filter((category) => category.audience === 'adult')\n .map((category) => category.key)\n : []\n );\n return (service: BookingServiceDto, index: number) => {\n if (!kit.age.fitsAge(service, ages[index] ?? null)) return false;\n const person = people[index];\n if (adultGroups.size === 0 || person === undefined || person.adult) return true;\n return !adultGroups.has(normaliseCategory(kit.config, service.category));\n };\n}\n\n/**\n * The weekend note for one person or the whole family: the rate when every\n * line pays the same one (`null` when they differ), and the basket's total\n * priced on the day asked about. `null` when nothing in the basket pays.\n */\nexport function weekendNoteFor(\n kit: BookingKit,\n items: readonly WizardItem[],\n dayTs: number\n): WeekendNote | null {\n if (items.length === 0) return null;\n // Every service of every visit: a wash on a Saturday pays its own rate even\n // when the cut beside it does not.\n const rates = [\n ...new Set(\n items.flatMap((item) => visitServicesOf(item).map((service) => service.weekendSurchargePct))\n ),\n ];\n if (rates.every((rate) => rate <= 0)) return null;\n return {\n pct: rates.length === 1 ? rates[0] : null,\n priceOre: kit.wizard.totalPriceOre([...items], dayTs),\n };\n}\n\n/** One line per basket item: the start the machine seated it at, and its resolved stylist. */\nexport function detailsLines(kit: BookingKit, state: WizardState): DetailsLine[] {\n const starts = kit.wizard.itemStartTimes(state.items, state.startTs ?? 0, state.partyMode);\n const resourceIds = kit.wizard.itemResourceIds(state);\n return state.items.map((_, index) => ({\n startTs: starts[index],\n resourceId: resourceIds[index],\n }));\n}\n\n/** The details step's site-wide answers: the phone rules, the terms link, the marketing box. */\nexport function detailsScreenBase(kit: BookingKit) {\n const { phone, config } = kit;\n return {\n phoneLooksValid: phone.looksValid,\n normalisePhone: phone.nationalDigits,\n phone: config.contact.phone,\n // A link with no words is a link nobody can name: drawn only with its text.\n termsHref: labelText(kit.labels['details.terms.link']) ? config.consent.termsUrl : null,\n marketingConsent: config.consent.marketing !== null,\n };\n}\n\n/**\n * The confirmation card's data and its calendar file.\n *\n * One price per line from the same function the total is the sum of, so the\n * card adds up on a Saturday too. ONE calendar entry per line, keyed to that\n * line's own booking id (the UID is the booking id, unchanged), titled with\n * whose appointment it is and carrying that line's own manage link —\n * absolute when the site's origin is known.\n */\nexport function confirmationProps(\n kit: BookingKit,\n confirmation: BookingConfirmation,\n siteUrl?: string\n): Pick<\n ConfirmationProps,\n 'lines' | 'startTs' | 'totalOre' | 'address' | 'calendarHref' | 'calendarFileName' | 'portalHref'\n> {\n const { labels, wizard, config, format } = kit;\n const { submitted } = confirmation;\n const items = submitted.items;\n const starts = wizard.itemStartTimes(items, submitted.startTs, submitted.partyMode);\n const lines = confirmationLines(confirmation).map((line, index) => ({\n ...line,\n startTs: starts[index],\n // The WHOLE visit's price, each service with its own surcharge — the same\n // function `totalPriceOre` sums, so the lines add up to «Totalt».\n priceOre: wizard.visitItemPriceOre(line.item, submitted.startTs),\n }));\n const absolute = (href: string) => (siteUrl ? new URL(href, siteUrl).toString() : href);\n const calendarHref = kit.ics.icsDataUrl(\n kit.ics.buildIcs(\n lines.map((line) => {\n const { bookedForName } = line.item;\n // One calendar entry per person: as long as their whole visit, named\n // after every service in it.\n const names = visitServicesOf(line.item)\n .map((service) => service.name)\n .join(' + ');\n const description = [\n fill(labels['wizard.ics.price'], { price: format.price(line.priceOre) }),\n ];\n if (line.manageHref !== null) {\n description.push(fill(labels['wizard.ics.manage'], { url: absolute(line.manageHref) }));\n }\n return {\n uid: line.bookingId,\n startTs: line.startTs,\n endTs: line.startTs + visitOf(line.item).durationMinutes * 60_000,\n summary: fill(labels[bookedForName ? 'wizard.ics.titleFor' : 'wizard.ics.title'], {\n service: names,\n name: bookedForName ?? '',\n business: config.contact.name,\n }),\n description: description.join('\\n'),\n ...(config.contact.address ? { location: config.contact.address } : {}),\n };\n })\n )\n );\n return {\n lines,\n startTs: submitted.startTs,\n totalOre: wizard.totalPriceOre(items, submitted.startTs),\n address: config.contact.address,\n calendarHref,\n calendarFileName: labelText(labels['wizard.ics.fileName']),\n portalHref: config.paths.portal,\n };\n}\n\n/**\n * The party size as the copy spells it (`wizard.party.sizeWord.*`), for\n * `{sizeWord}` in the stylist step's party labels; `undefined` (meda fills in\n * the number) where the pack leaves it blank.\n */\nexport function partySizeWord(labels: Readonly<BookingLabels>, size: number): string | undefined {\n const suffix = size === 2 ? 'two' : size === 3 ? 'three' : 'other';\n return labelText(labels[`wizard.party.sizeWord.${suffix}`]) || undefined;\n}\n\n/** The grown-up's seat a guest books with (`guestChoices` and `guestParty` share it). */\nexport const GUEST_ADULT_SEAT = { key: 'adult', adult: true } as const;\n\n/**\n * A stylist's name and photo by id, for the recap and the time step's «free\n * soon» row; `null` for nobody chosen yet or an id the catalogue no longer has.\n */\nexport function stylistFace(\n resources: readonly BookingResourceDto[],\n resourceId: string | null\n): { name: string; photoUrl: string | null } | null {\n const resource = resources.find((one) => one.id === resourceId);\n return resource ? { name: resource.name, photoUrl: resource.photoUrl } : null;\n}\n\n/**\n * The details step's recap: the same lines the submission is built from\n * (`detailsLines`), with each line's services, end and stylist named.\n *\n * `alternatives` are the other stylists free at the very start booked, for a\n * one-person visit whose stylist was left to «first available»: the one tap\n * that turns «first available gave me Ada» into «I would rather have Bo». Never for a\n * family (a party slot is a seating plan, not one stylist), nor for a named\n * stylist the parent chose themselves.\n */\nexport function recapProps(\n kit: BookingKit,\n state: WizardState,\n resources: readonly BookingResourceDto[],\n singleSlots: readonly BookingSlotDto[]\n): { lines: BookingRecapLine[]; alternatives: BookingRecapAlternative[] } {\n const lines = detailsLines(kit, state).map((line, index) => {\n const item = state.items[index] as WizardItem;\n return {\n startTs: line.startTs,\n endTs: kit.wizard.visitEndTs([item], line.startTs, 'sequential'),\n services: visitServicesOf(item).map((service) => service.name),\n stylist: stylistFace(resources, line.resourceId),\n who: item.bookedForName ?? null,\n };\n });\n\n const alternatives: BookingRecapAlternative[] = [];\n if (state.items.length === 1 && state.resourceId === null && state.startTs !== null) {\n const seen = new Set<string>();\n for (const slot of singleSlots) {\n const id = slot.resourceId;\n if (slot.startTs !== state.startTs || id === null || id === state.resolvedResourceId)\n continue;\n if (seen.has(id)) continue;\n seen.add(id);\n const face = stylistFace(resources, id);\n if (face) alternatives.push({ resourceId: id, ...face });\n }\n }\n return { lines, alternatives };\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ActionAnswer, ActionFailure, InvalidFailure, PersonActionInput, PersonActionResult, PersonActionTarget, PortalActions, ProfileActionResult, SafeActionEnvelope, SessionFailure } from "../actions.mjs";
|
|
1
|
+
import { ActionAnswer, ActionFailure, InvalidFailure, PersonActionInput, PersonActionResult, PersonActionTarget, PortalActions, ProfileActionResult, SafeActionEnvelope, SessionFailure, ThrottledFailure } from "../actions.mjs";
|
|
2
2
|
import { LoginLabels } from "../labels/login.mjs";
|
|
3
3
|
import { ScreenLabels } from "../labels/screens.mjs";
|
|
4
4
|
import { WizardLabels } from "../labels/wizard.mjs";
|
|
@@ -8,4 +8,4 @@ import { BookingClassNames, BookingComponents, BookingOverrides, BookingProvider
|
|
|
8
8
|
import { BookingConfirmation, BookingController, BookingSeed, BookingSuggestion, ConfirmedLine, UseBookingOptions, confirmationLines, isCompleteConfirmation, personForChild, useBooking } from "../useBooking.mjs";
|
|
9
9
|
import { BookingWizard, BookingWizardEvent, BookingWizardProps } from "../BookingWizard.mjs";
|
|
10
10
|
import { LoginSheet, LoginSheetProps, VippsConfirm } from "../LoginSheet.mjs";
|
|
11
|
-
export { type ActionAnswer, type ActionFailure, BookingClassNames, BookingComponents, BookingConfirmation, BookingController, type BookingKit, type BookingLabels, type BookingLabelsInput, BookingOverrides, BookingProvider, BookingProviderProps, BookingSeed, BookingSuggestion, BookingWizard, BookingWizardEvent, BookingWizardProps, ConfirmedLine, type InvalidFailure, type LoginLabels, LoginSheet, LoginSheetProps, type PersonActionInput, type PersonActionResult, type PersonActionTarget, type PortalActions, type ProfileActionResult, ResolvedBooking, type SafeActionEnvelope, type ScreenLabels, type SessionFailure, UseBookingOptions, type VippsConfirm, type WizardLabels, confirmationLines, isCompleteConfirmation, personForChild, useBooking, useBookingKit };
|
|
11
|
+
export { type ActionAnswer, type ActionFailure, BookingClassNames, BookingComponents, BookingConfirmation, BookingController, type BookingKit, type BookingLabels, type BookingLabelsInput, BookingOverrides, BookingProvider, BookingProviderProps, BookingSeed, BookingSuggestion, BookingWizard, BookingWizardEvent, BookingWizardProps, ConfirmedLine, type InvalidFailure, type LoginLabels, LoginSheet, LoginSheetProps, type PersonActionInput, type PersonActionResult, type PersonActionTarget, type PortalActions, type ProfileActionResult, ResolvedBooking, type SafeActionEnvelope, type ScreenLabels, type SessionFailure, type ThrottledFailure, UseBookingOptions, type VippsConfirm, type WizardLabels, confirmationLines, isCompleteConfirmation, personForChild, useBooking, useBookingKit };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@medalsocial/booking",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Medal Social booking: the wizard rules, clock, money and portal helpers behind a Medal booking site",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Medal Social / Ali Aljumaili",
|
|
@@ -80,11 +80,11 @@
|
|
|
80
80
|
"typescript"
|
|
81
81
|
],
|
|
82
82
|
"dependencies": {
|
|
83
|
-
"@medalsocial/sdk": "^1.
|
|
83
|
+
"@medalsocial/sdk": "^1.14.0",
|
|
84
84
|
"server-only": "^0.0.1"
|
|
85
85
|
},
|
|
86
86
|
"peerDependencies": {
|
|
87
|
-
"@medalsocial/meda": "^3.
|
|
87
|
+
"@medalsocial/meda": "^3.7.0",
|
|
88
88
|
"lucide-react": "^1.8.0",
|
|
89
89
|
"next": ">=16.3",
|
|
90
90
|
"react": ">=19",
|
|
@@ -100,7 +100,7 @@
|
|
|
100
100
|
}
|
|
101
101
|
},
|
|
102
102
|
"devDependencies": {
|
|
103
|
-
"@medalsocial/meda": "^3.
|
|
103
|
+
"@medalsocial/meda": "^3.7.0",
|
|
104
104
|
"@testing-library/jest-dom": "^7.0.1",
|
|
105
105
|
"@testing-library/react": "^16.3.3",
|
|
106
106
|
"@testing-library/user-event": "^14.6.7",
|