@medalsocial/meda 3.6.0 → 3.6.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.
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { Check } from 'lucide-react';
|
|
4
4
|
import { cn } from '../../lib/utils.js';
|
|
5
|
+
import { labelText } from '../labels.js';
|
|
5
6
|
import { LiveStatus } from '../live-status.js';
|
|
6
7
|
import { slotClass } from '../slots.js';
|
|
7
8
|
import { renderLabel } from './label-parts.js';
|
|
@@ -38,13 +39,13 @@ export function PersonTabs({ people, active, done, onSelect, labels, labelledBy,
|
|
|
38
39
|
return (_jsx("div", { role: "tablist", "aria-labelledby": labelledBy, "aria-describedby": describedBy, onKeyDown: onKeyDown, className: "-mx-1 flex gap-2 overflow-x-auto px-1 py-1", children: people.map((person, index) => {
|
|
39
40
|
const selected = index === active;
|
|
40
41
|
const finished = done(index);
|
|
41
|
-
return (_jsxs("button", { type: "button", role: "tab", id: serviceTabId(index), "aria-selected": selected, "aria-controls": selected ? serviceTabPanelId(index) : undefined, tabIndex: selected ? 0 : -1, onClick: () => onSelect(index),
|
|
42
|
+
return (_jsxs("button", { type: "button", role: "tab", id: serviceTabId(index), "aria-selected": selected, "aria-label": finished ? `${person.label}, ${labelText(labels['service.tabDone'])}` : undefined, "aria-controls": selected ? serviceTabPanelId(index) : undefined, tabIndex: selected ? 0 : -1, onClick: () => onSelect(index),
|
|
42
43
|
// Weight and ring carry the open tab alongside the colour, as the
|
|
43
44
|
// category pills do. Focus is an outline, so it stacks on the
|
|
44
45
|
// selection ring instead of replacing it with a fainter one.
|
|
45
46
|
className: cn('inline-flex h-11 shrink-0 items-center gap-1.5 rounded-full border-[1.5px] px-4 text-sm whitespace-nowrap transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring', selected
|
|
46
47
|
? 'border-primary bg-primary/10 font-bold text-foreground ring-2 ring-primary'
|
|
47
|
-
: 'border-primary/35 font-normal text-primary hover:border-primary hover:bg-primary/5', classNames?.tab, selected && classNames?.tabSelected), children: [finished && _jsx(Check, { "aria-hidden": "true", className: "size-4 shrink-0" }), person.label
|
|
48
|
+
: 'border-primary/35 font-normal text-primary hover:border-primary hover:bg-primary/5', classNames?.tab, selected && classNames?.tabSelected), children: [finished && _jsx(Check, { "aria-hidden": "true", className: "size-4 shrink-0" }), person.label] }, person.key));
|
|
48
49
|
}) }));
|
|
49
50
|
}
|
|
50
51
|
/**
|
|
@@ -51,6 +51,12 @@ export interface ServiceScreenCategory {
|
|
|
51
51
|
key: string;
|
|
52
52
|
/** The pill's and the section heading's text. */
|
|
53
53
|
label: string;
|
|
54
|
+
/**
|
|
55
|
+
* Who the group is for. In a family, a child's menu is `childCategory` plus
|
|
56
|
+
* every group marked `'any'` (an ear piercing, say) — never a grown-ups'
|
|
57
|
+
* group. Absent: the group is a grown-ups' one, as before.
|
|
58
|
+
*/
|
|
59
|
+
audience?: 'child' | 'adult' | 'any';
|
|
54
60
|
}
|
|
55
61
|
/** A person's «same as last time», and the one-line note when it was swapped (e.g. for age). */
|
|
56
62
|
export interface ServiceSuggestion {
|
|
@@ -193,12 +193,19 @@ function defaultCategoryOf(categories) {
|
|
|
193
193
|
* What a person in a party can have is what the business takes online and —
|
|
194
194
|
* like the booking engine — nothing whose `maxPerBooking` is below the party's
|
|
195
195
|
* size: the strictest service in a request sets the limit for all of it. With
|
|
196
|
-
* a `childCategory`, a child gets that menu
|
|
197
|
-
*
|
|
196
|
+
* a `childCategory`, a child gets that menu plus the groups meant for anyone
|
|
197
|
+
* (`audience: 'any'`), and an adult everything but the children's — which is
|
|
198
|
+
* often nothing, and they are told so.
|
|
198
199
|
*/
|
|
199
200
|
function PartyServiceScreen({ services, categories, categoryOf, childCategory, serviceFits = allFit, party, selection, shared, }) {
|
|
200
201
|
const { Card, labels, classNames } = shared;
|
|
201
202
|
const fileUnder = categoryOf ?? defaultCategoryOf(categories);
|
|
203
|
+
const keysFor = (audience) => new Set(categories.filter((group) => group.audience === audience).map((group) => group.key));
|
|
204
|
+
// Children's groups: the configured one plus any group marked 'child'.
|
|
205
|
+
const forChildren = keysFor('child');
|
|
206
|
+
if (childCategory !== undefined)
|
|
207
|
+
forChildren.add(childCategory);
|
|
208
|
+
const forAnyone = keysFor('any');
|
|
202
209
|
const size = party.people.length;
|
|
203
210
|
const [active, setActive] = useState(0);
|
|
204
211
|
// Multi-select: the engine books a grown-up's visit alongside the
|
|
@@ -212,7 +219,17 @@ function PartyServiceScreen({ services, categories, categoryOf, childCategory, s
|
|
|
212
219
|
// note below that books the wrong thing.
|
|
213
220
|
childCategory === undefined
|
|
214
221
|
? fits
|
|
215
|
-
: fits.filter((service) =>
|
|
222
|
+
: fits.filter((service) => {
|
|
223
|
+
const key = fileUnder(service);
|
|
224
|
+
if (forChildren.has(key))
|
|
225
|
+
return !person.adult;
|
|
226
|
+
// A child gets an «anyone» group only through an EXPLICIT mapping:
|
|
227
|
+
// the caller's own `categoryOf` when it passes one (its mapping is
|
|
228
|
+
// its decision), else the service's own category — never the
|
|
229
|
+
// built-in display fallback, which files an unlisted (possibly
|
|
230
|
+
// grown-up) category under the last group.
|
|
231
|
+
return person.adult || forAnyone.has(categoryOf ? key : service.category);
|
|
232
|
+
}), (service) => serviceFits(service, index));
|
|
216
233
|
const ticked = selection ? tickedBy(selection, index) : null;
|
|
217
234
|
const chosen = party.choices[index]?.id ?? null;
|
|
218
235
|
const suggestion = person.suggestion ?? null;
|