@ai-matrx/records-ui 0.56.0 → 0.57.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 +25 -0
- package/dist/index.cjs +182 -177
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +182 -177
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# Changelog — @ai-matrx/records-ui
|
|
2
2
|
|
|
3
|
+
## 0.57.0
|
|
4
|
+
|
|
5
|
+
**The builders are usable where a person actually reaches them: a 384px rail.**
|
|
6
|
+
|
|
7
|
+
The first browser walk (lane BUILDERS, Ironline Fitness, 2026-09-21) pressed
|
|
8
|
+
"Build the form" on a real gym's members table and got a preview of an empty
|
|
9
|
+
form and **no controls at all**. `FormBuilder` was authored as two desktop
|
|
10
|
+
columns — controls left, live preview in a `w-96` aside right — and the rail it
|
|
11
|
+
is mounted in is itself `w-96`, so the fixed-width preview took the entire rail
|
|
12
|
+
and squeezed the controls to nothing. The screen looked like a builder and could
|
|
13
|
+
not build.
|
|
14
|
+
|
|
15
|
+
A viewport breakpoint cannot fix that: the viewport was 1680px wide while the
|
|
16
|
+
container was 384px. Every split in these four screens is now a **container
|
|
17
|
+
query**, so they are the same screen in a rail, a dialog or a full page:
|
|
18
|
+
|
|
19
|
+
* `FormBuilder` stacks to one column and its preview goes full-width below the
|
|
20
|
+
controls until the component itself is wide enough for two (`@3xl`).
|
|
21
|
+
* `BookingBuilder`, `PortalBuilder` and `DigestScheduler` drop their two-column
|
|
22
|
+
grids and fixed-width inputs to one column under `@md`.
|
|
23
|
+
|
|
24
|
+
**Consumer action:** none. The host must already scan this package's `dist` for
|
|
25
|
+
Tailwind classes (`@source "…/@ai-matrx/records-ui/dist"`), which matrx-frontend
|
|
26
|
+
does; the container variants are generated from there like every other class.
|
|
27
|
+
|
|
3
28
|
## 0.56.0
|
|
4
29
|
|
|
5
30
|
**A condition the builder cannot draw is said in words, not blanked.**
|
package/dist/index.cjs
CHANGED
|
@@ -8955,7 +8955,7 @@ function PortalBuilder({ tableId, portalId, onSaved, onClose, className }) {
|
|
|
8955
8955
|
const all = tables.data ?? [];
|
|
8956
8956
|
const missingTie = ticked.filter((e) => e.namesVia.trim() === "");
|
|
8957
8957
|
const ready = clientTableId !== null && ticked.length > 0 && missingTie.length === 0;
|
|
8958
|
-
return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("section", { className: (0, import_design_system30.cn)("flex flex-col gap-3", className), children: [
|
|
8958
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("section", { className: (0, import_design_system30.cn)("@container flex flex-col gap-3", className), children: [
|
|
8959
8959
|
/* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("header", { className: "flex items-center gap-2", children: [
|
|
8960
8960
|
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("h3", { className: "text-sm font-medium", children: existing ? "Portal" : "New client portal" }),
|
|
8961
8961
|
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "flex-1" }),
|
|
@@ -9096,7 +9096,7 @@ function PortalBuilder({ tableId, portalId, onSaved, onClose, className }) {
|
|
|
9096
9096
|
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
9097
9097
|
import_design_system30.BasicInput,
|
|
9098
9098
|
{
|
|
9099
|
-
className: "h-8 w-56",
|
|
9099
|
+
className: "h-8 w-full @md:w-56",
|
|
9100
9100
|
value: inviteEmail,
|
|
9101
9101
|
onChange: (e) => setInviteEmail(e.target.value)
|
|
9102
9102
|
}
|
|
@@ -9107,7 +9107,7 @@ function PortalBuilder({ tableId, portalId, onSaved, onClose, className }) {
|
|
|
9107
9107
|
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
9108
9108
|
import_design_system30.BasicInput,
|
|
9109
9109
|
{
|
|
9110
|
-
className: "h-8 w-80",
|
|
9110
|
+
className: "h-8 w-full @md:w-80",
|
|
9111
9111
|
placeholder: "the record id",
|
|
9112
9112
|
value: inviteRecordId,
|
|
9113
9113
|
onChange: (e) => setInviteRecordId(e.target.value)
|
|
@@ -9804,7 +9804,7 @@ function DigestScheduler({
|
|
|
9804
9804
|
setPreview(answered.data);
|
|
9805
9805
|
}
|
|
9806
9806
|
if (views === null && !error) return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_design_system33.Skeleton, { className: (0, import_design_system33.cn)("h-56 w-full", className) });
|
|
9807
|
-
return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("section", { className: (0, import_design_system33.cn)("flex flex-col gap-3", className), children: [
|
|
9807
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("section", { className: (0, import_design_system33.cn)("@container flex flex-col gap-3", className), children: [
|
|
9808
9808
|
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("header", { className: "flex items-center gap-2", children: [
|
|
9809
9809
|
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("h3", { className: "text-sm font-medium", children: "Send this on a schedule" }),
|
|
9810
9810
|
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "flex-1" }),
|
|
@@ -9839,7 +9839,7 @@ function DigestScheduler({
|
|
|
9839
9839
|
),
|
|
9840
9840
|
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "text-xs text-muted-foreground", children: "The first choice saves what is on screen as a view, so the summary and the screen stay the same thing." })
|
|
9841
9841
|
] }),
|
|
9842
|
-
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "grid grid-cols-
|
|
9842
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "grid grid-cols-1 gap-2 @md:grid-cols-2", children: [
|
|
9843
9843
|
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
9844
9844
|
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_design_system33.Label, { className: "text-xs font-medium", children: "How often" }),
|
|
9845
9845
|
/* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
@@ -10580,7 +10580,7 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
|
|
|
10580
10580
|
if (!rights.admin) {
|
|
10581
10581
|
return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("p", { className: (0, import_design_system36.cn)("text-xs text-muted-foreground", className), children: rights.why("structure") });
|
|
10582
10582
|
}
|
|
10583
|
-
return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: (0, import_design_system36.cn)("flex min-h-0 gap-3", className), children: [
|
|
10583
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: (0, import_design_system36.cn)("@container flex min-h-0 flex-col gap-3 @3xl:flex-row", className), children: [
|
|
10584
10584
|
/* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "flex min-w-0 flex-1 flex-col gap-2 overflow-auto", children: [
|
|
10585
10585
|
/* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "flex items-center gap-1 overflow-x-auto", role: "group", "aria-label": "Forms", children: [
|
|
10586
10586
|
forms.map((form) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
@@ -10741,7 +10741,7 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
|
|
|
10741
10741
|
] })
|
|
10742
10742
|
] })
|
|
10743
10743
|
] }),
|
|
10744
|
-
draft ? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("aside", { className: "w-
|
|
10744
|
+
draft ? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("aside", { className: "w-full shrink-0 overflow-auto rounded border p-2 @3xl:w-96", children: [
|
|
10745
10745
|
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)("h4", { className: "px-1 text-sm font-medium", children: draft.name }),
|
|
10746
10746
|
/* @__PURE__ */ (0, import_jsx_runtime39.jsx)(FormRunner, { form: draft, preview: true })
|
|
10747
10747
|
] }) : null
|
|
@@ -12507,195 +12507,200 @@ function BookingBuilder({ tableId, bookingId, onSaved, onClose, className }) {
|
|
|
12507
12507
|
}
|
|
12508
12508
|
const url = formId ? `${publicOrigin}${(0, import_records9.bookingPath)(formId)}` : null;
|
|
12509
12509
|
const shown = offer ?? null;
|
|
12510
|
-
return
|
|
12511
|
-
|
|
12512
|
-
|
|
12513
|
-
|
|
12514
|
-
|
|
12515
|
-
|
|
12516
|
-
|
|
12517
|
-
|
|
12518
|
-
|
|
12519
|
-
|
|
12520
|
-
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.BasicInput, { value: title, onChange: (e) => setTitle(e.target.value) })
|
|
12521
|
-
] }),
|
|
12522
|
-
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "grid grid-cols-2 gap-2", children: [
|
|
12523
|
-
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
12524
|
-
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "How long one appointment is" }),
|
|
12525
|
-
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
12526
|
-
"select",
|
|
12527
|
-
{
|
|
12528
|
-
className: "h-9 rounded border bg-background px-2 text-sm",
|
|
12529
|
-
value: minutes,
|
|
12530
|
-
onChange: (e) => setMinutes(Number(e.target.value)),
|
|
12531
|
-
children: LENGTHS.map((n) => /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("option", { value: n, children: [
|
|
12532
|
-
n,
|
|
12533
|
-
" minutes"
|
|
12534
|
-
] }, n))
|
|
12535
|
-
}
|
|
12536
|
-
)
|
|
12537
|
-
] }),
|
|
12538
|
-
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
12539
|
-
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "Gap kept after each one" }),
|
|
12540
|
-
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
12541
|
-
"select",
|
|
12542
|
-
{
|
|
12543
|
-
className: "h-9 rounded border bg-background px-2 text-sm",
|
|
12544
|
-
value: buffer,
|
|
12545
|
-
onChange: (e) => setBuffer(Number(e.target.value)),
|
|
12546
|
-
children: [0, 5, 10, 15, 30].map((n) => /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("option", { value: n, children: n === 0 ? "No gap \u2014 back to back" : `${n} minutes` }, n))
|
|
12547
|
-
}
|
|
12548
|
-
)
|
|
12549
|
-
] }),
|
|
12550
|
-
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
12551
|
-
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "Earliest somebody may book" }),
|
|
12552
|
-
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
12553
|
-
"select",
|
|
12554
|
-
{
|
|
12555
|
-
className: "h-9 rounded border bg-background px-2 text-sm",
|
|
12556
|
-
value: lead,
|
|
12557
|
-
onChange: (e) => setLead(Number(e.target.value)),
|
|
12558
|
-
children: [0, 60, 120, 240, 1440].map((n) => /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("option", { value: n, children: n === 0 ? "Right away" : n === 1440 ? "A day from now" : `${n / 60} hour${n === 60 ? "" : "s"} from now` }, n))
|
|
12559
|
-
}
|
|
12560
|
-
)
|
|
12510
|
+
return (
|
|
12511
|
+
// THE RAIL IS 384px WIDE AND THE VIEWPORT IS NOT (walk 1, 2026-09-21):
|
|
12512
|
+
// every split below is a CONTAINER query, so this screen is the same
|
|
12513
|
+
// screen in a rail, a dialog and a full page.
|
|
12514
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("section", { className: (0, import_design_system45.cn)("@container flex flex-col gap-3", className), children: [
|
|
12515
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("header", { className: "flex items-center gap-2", children: [
|
|
12516
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("h3", { className: "text-sm font-medium", children: existing ? "Booking page" : "New booking page" }),
|
|
12517
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "flex-1" }),
|
|
12518
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Button, { size: "sm", disabled: saving, onClick: () => void save(), children: saving ? "Saving\u2026" : "Save" }),
|
|
12519
|
+
onClose ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Button, { size: "sm", variant: "ghost", onClick: onClose, children: "Close" }) : null
|
|
12561
12520
|
] }),
|
|
12521
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(RefusalNotice, { error }) : null,
|
|
12562
12522
|
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
12563
|
-
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "
|
|
12564
|
-
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
12565
|
-
import_design_system45.BasicInput,
|
|
12566
|
-
{
|
|
12567
|
-
type: "number",
|
|
12568
|
-
min: 1,
|
|
12569
|
-
value: perDay,
|
|
12570
|
-
onChange: (e) => setPerDay(Math.max(1, Number(e.target.value) || 1))
|
|
12571
|
-
}
|
|
12572
|
-
)
|
|
12523
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "What it is called" }),
|
|
12524
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.BasicInput, { value: title, onChange: (e) => setTitle(e.target.value) })
|
|
12573
12525
|
] }),
|
|
12574
|
-
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("
|
|
12575
|
-
/* @__PURE__ */ (0, import_jsx_runtime48.
|
|
12576
|
-
|
|
12577
|
-
"select",
|
|
12578
|
-
{
|
|
12579
|
-
className: "h-9 rounded border bg-background px-2 text-sm",
|
|
12580
|
-
value: days,
|
|
12581
|
-
onChange: (e) => setDays(Number(e.target.value)),
|
|
12582
|
-
children: [7, 14, 30, 60, 90].map((n) => /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("option", { value: n, children: [
|
|
12583
|
-
n,
|
|
12584
|
-
" days"
|
|
12585
|
-
] }, n))
|
|
12586
|
-
}
|
|
12587
|
-
)
|
|
12588
|
-
] })
|
|
12589
|
-
] }),
|
|
12590
|
-
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex flex-col gap-1.5", children: [
|
|
12591
|
-
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "Hours you are free" }),
|
|
12592
|
-
windows.map((w, i) => /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
12593
|
-
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "flex w-20 items-center gap-1.5 text-xs", children: [
|
|
12526
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "grid grid-cols-1 gap-2 @md:grid-cols-2", children: [
|
|
12527
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
12528
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "How long one appointment is" }),
|
|
12594
12529
|
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
12595
|
-
|
|
12530
|
+
"select",
|
|
12596
12531
|
{
|
|
12597
|
-
|
|
12598
|
-
|
|
12532
|
+
className: "h-9 rounded border bg-background px-2 text-sm",
|
|
12533
|
+
value: minutes,
|
|
12534
|
+
onChange: (e) => setMinutes(Number(e.target.value)),
|
|
12535
|
+
children: LENGTHS.map((n) => /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("option", { value: n, children: [
|
|
12536
|
+
n,
|
|
12537
|
+
" minutes"
|
|
12538
|
+
] }, n))
|
|
12599
12539
|
}
|
|
12600
|
-
)
|
|
12601
|
-
DAYS[i]?.label
|
|
12540
|
+
)
|
|
12602
12541
|
] }),
|
|
12603
|
-
|
|
12542
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
12543
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "Gap kept after each one" }),
|
|
12604
12544
|
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
12605
|
-
|
|
12545
|
+
"select",
|
|
12606
12546
|
{
|
|
12607
|
-
|
|
12608
|
-
|
|
12609
|
-
|
|
12610
|
-
|
|
12547
|
+
className: "h-9 rounded border bg-background px-2 text-sm",
|
|
12548
|
+
value: buffer,
|
|
12549
|
+
onChange: (e) => setBuffer(Number(e.target.value)),
|
|
12550
|
+
children: [0, 5, 10, 15, 30].map((n) => /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("option", { value: n, children: n === 0 ? "No gap \u2014 back to back" : `${n} minutes` }, n))
|
|
12611
12551
|
}
|
|
12612
|
-
)
|
|
12613
|
-
|
|
12552
|
+
)
|
|
12553
|
+
] }),
|
|
12554
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
12555
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "Earliest somebody may book" }),
|
|
12556
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
12557
|
+
"select",
|
|
12558
|
+
{
|
|
12559
|
+
className: "h-9 rounded border bg-background px-2 text-sm",
|
|
12560
|
+
value: lead,
|
|
12561
|
+
onChange: (e) => setLead(Number(e.target.value)),
|
|
12562
|
+
children: [0, 60, 120, 240, 1440].map((n) => /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("option", { value: n, children: n === 0 ? "Right away" : n === 1440 ? "A day from now" : `${n / 60} hour${n === 60 ? "" : "s"} from now` }, n))
|
|
12563
|
+
}
|
|
12564
|
+
)
|
|
12565
|
+
] }),
|
|
12566
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
12567
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "Most in one day" }),
|
|
12614
12568
|
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
12615
12569
|
import_design_system45.BasicInput,
|
|
12616
12570
|
{
|
|
12617
|
-
type: "
|
|
12618
|
-
|
|
12619
|
-
value:
|
|
12620
|
-
onChange: (e) =>
|
|
12571
|
+
type: "number",
|
|
12572
|
+
min: 1,
|
|
12573
|
+
value: perDay,
|
|
12574
|
+
onChange: (e) => setPerDay(Math.max(1, Number(e.target.value) || 1))
|
|
12621
12575
|
}
|
|
12622
12576
|
)
|
|
12623
|
-
] })
|
|
12624
|
-
|
|
12625
|
-
|
|
12626
|
-
|
|
12627
|
-
|
|
12628
|
-
|
|
12577
|
+
] }),
|
|
12578
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
12579
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "How far ahead the page offers" }),
|
|
12580
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
12581
|
+
"select",
|
|
12582
|
+
{
|
|
12583
|
+
className: "h-9 rounded border bg-background px-2 text-sm",
|
|
12584
|
+
value: days,
|
|
12585
|
+
onChange: (e) => setDays(Number(e.target.value)),
|
|
12586
|
+
children: [7, 14, 30, 60, 90].map((n) => /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("option", { value: n, children: [
|
|
12587
|
+
n,
|
|
12588
|
+
" days"
|
|
12589
|
+
] }, n))
|
|
12590
|
+
}
|
|
12591
|
+
)
|
|
12592
|
+
] })
|
|
12593
|
+
] }),
|
|
12594
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex flex-col gap-1.5", children: [
|
|
12595
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "Hours you are free" }),
|
|
12596
|
+
windows.map((w, i) => /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
12597
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "flex w-20 items-center gap-1.5 text-xs", children: [
|
|
12598
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
12599
|
+
import_design_system45.Checkbox,
|
|
12600
|
+
{
|
|
12601
|
+
checked: w.on,
|
|
12602
|
+
onCheckedChange: (on) => setWindows((prev) => prev.map((x, j) => i === j ? { ...x, on: Boolean(on) } : x))
|
|
12603
|
+
}
|
|
12604
|
+
),
|
|
12605
|
+
DAYS[i]?.label
|
|
12606
|
+
] }),
|
|
12607
|
+
w.on ? /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(import_jsx_runtime48.Fragment, { children: [
|
|
12608
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
12609
|
+
import_design_system45.BasicInput,
|
|
12610
|
+
{
|
|
12611
|
+
type: "time",
|
|
12612
|
+
className: "h-8 w-28",
|
|
12613
|
+
value: w.from,
|
|
12614
|
+
onChange: (e) => setWindows((prev) => prev.map((x, j) => i === j ? { ...x, from: e.target.value } : x))
|
|
12615
|
+
}
|
|
12616
|
+
),
|
|
12617
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "text-xs text-muted-foreground", children: "to" }),
|
|
12618
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
12619
|
+
import_design_system45.BasicInput,
|
|
12620
|
+
{
|
|
12621
|
+
type: "time",
|
|
12622
|
+
className: "h-8 w-28",
|
|
12623
|
+
value: w.to,
|
|
12624
|
+
onChange: (e) => setWindows((prev) => prev.map((x, j) => i === j ? { ...x, to: e.target.value } : x))
|
|
12625
|
+
}
|
|
12626
|
+
)
|
|
12627
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "text-xs text-muted-foreground", children: "not taking bookings" })
|
|
12628
|
+
] }, w.weekday))
|
|
12629
|
+
] }),
|
|
12630
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex flex-col gap-1.5", children: [
|
|
12631
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "What to ask the person booking" }),
|
|
12632
|
+
askable.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("p", { className: "text-xs text-muted-foreground", children: "This table has no fields yet, so there is nothing a booking page could ask for. Add a field first \u2014 every question is one of this table's own fields." }) : /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "flex flex-wrap gap-x-4 gap-y-1.5", children: askable.map((f) => /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "flex items-center gap-1.5 text-xs", children: [
|
|
12633
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
12634
|
+
import_design_system45.Checkbox,
|
|
12635
|
+
{
|
|
12636
|
+
checked: asked.includes(f.key),
|
|
12637
|
+
onCheckedChange: (on) => setAsked((prev) => on ? [...prev, f.key] : prev.filter((k) => k !== f.key))
|
|
12638
|
+
}
|
|
12639
|
+
),
|
|
12640
|
+
fieldName(f)
|
|
12641
|
+
] }, f.key)) }),
|
|
12642
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("p", { className: "text-xs text-muted-foreground", children: "The time, whether it is booked or cancelled, and who it is with are filled in by the store \u2014 a booking page cannot ask a visitor for any of the three." })
|
|
12643
|
+
] }),
|
|
12644
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "flex flex-col gap-1", children: [
|
|
12645
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "What they see after booking" }),
|
|
12646
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
12647
|
+
import_design_system45.BasicTextarea,
|
|
12648
|
+
{
|
|
12649
|
+
rows: 2,
|
|
12650
|
+
value: confirmation,
|
|
12651
|
+
placeholder: "You're booked. We'll send a reminder the day before \u2014 reply to that message to move it.",
|
|
12652
|
+
onChange: (e) => setConfirmation(e.target.value)
|
|
12653
|
+
}
|
|
12654
|
+
)
|
|
12655
|
+
] }),
|
|
12656
|
+
shown ? /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("p", { className: "rounded-md border bg-muted/40 p-2.5 text-xs", children: [
|
|
12657
|
+
"Saved. The page offers ",
|
|
12658
|
+
shown.slot_minutes,
|
|
12659
|
+
"-minute appointments in ",
|
|
12660
|
+
shown.timezone,
|
|
12661
|
+
", up to",
|
|
12662
|
+
" ",
|
|
12663
|
+
shown.max_per_day,
|
|
12664
|
+
" a day, ",
|
|
12665
|
+
shown.days,
|
|
12666
|
+
" days ahead",
|
|
12667
|
+
shown.buffer_minutes > 0 ? `, with ${shown.buffer_minutes} minutes between them` : "",
|
|
12668
|
+
":",
|
|
12669
|
+
" ",
|
|
12670
|
+
shown.windows.map(
|
|
12671
|
+
(w) => `${DAYS.find((d) => d.weekday === w.weekday)?.label ?? w.weekday} ${w.from}\u2013${w.to}`
|
|
12672
|
+
).join(", "),
|
|
12673
|
+
"."
|
|
12674
|
+
] }) : null,
|
|
12675
|
+
url ? /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex flex-wrap items-center gap-2 rounded-md border p-2.5", children: [
|
|
12676
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "min-w-0 flex-1 break-all text-xs", children: url }),
|
|
12629
12677
|
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
12630
|
-
import_design_system45.
|
|
12678
|
+
import_design_system45.Button,
|
|
12631
12679
|
{
|
|
12632
|
-
|
|
12633
|
-
|
|
12680
|
+
size: "sm",
|
|
12681
|
+
variant: "outline",
|
|
12682
|
+
onClick: () => {
|
|
12683
|
+
void navigator.clipboard.writeText(url).then(() => {
|
|
12684
|
+
setCopied(true);
|
|
12685
|
+
window.setTimeout(() => setCopied(false), 1600);
|
|
12686
|
+
}).catch(() => setCopied(false));
|
|
12687
|
+
},
|
|
12688
|
+
children: copied ? "Copied" : "Copy link"
|
|
12634
12689
|
}
|
|
12635
12690
|
),
|
|
12636
|
-
|
|
12637
|
-
|
|
12638
|
-
|
|
12639
|
-
|
|
12640
|
-
|
|
12641
|
-
|
|
12642
|
-
|
|
12643
|
-
|
|
12644
|
-
|
|
12645
|
-
|
|
12646
|
-
|
|
12647
|
-
|
|
12648
|
-
|
|
12649
|
-
}
|
|
12650
|
-
)
|
|
12651
|
-
] }),
|
|
12652
|
-
shown ? /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("p", { className: "rounded-md border bg-muted/40 p-2.5 text-xs", children: [
|
|
12653
|
-
"Saved. The page offers ",
|
|
12654
|
-
shown.slot_minutes,
|
|
12655
|
-
"-minute appointments in ",
|
|
12656
|
-
shown.timezone,
|
|
12657
|
-
", up to",
|
|
12658
|
-
" ",
|
|
12659
|
-
shown.max_per_day,
|
|
12660
|
-
" a day, ",
|
|
12661
|
-
shown.days,
|
|
12662
|
-
" days ahead",
|
|
12663
|
-
shown.buffer_minutes > 0 ? `, with ${shown.buffer_minutes} minutes between them` : "",
|
|
12664
|
-
":",
|
|
12665
|
-
" ",
|
|
12666
|
-
shown.windows.map(
|
|
12667
|
-
(w) => `${DAYS.find((d) => d.weekday === w.weekday)?.label ?? w.weekday} ${w.from}\u2013${w.to}`
|
|
12668
|
-
).join(", "),
|
|
12669
|
-
"."
|
|
12670
|
-
] }) : null,
|
|
12671
|
-
url ? /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex flex-wrap items-center gap-2 rounded-md border p-2.5", children: [
|
|
12672
|
-
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "min-w-0 flex-1 break-all text-xs", children: url }),
|
|
12673
|
-
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
12674
|
-
import_design_system45.Button,
|
|
12675
|
-
{
|
|
12676
|
-
size: "sm",
|
|
12677
|
-
variant: "outline",
|
|
12678
|
-
onClick: () => {
|
|
12679
|
-
void navigator.clipboard.writeText(url).then(() => {
|
|
12680
|
-
setCopied(true);
|
|
12681
|
-
window.setTimeout(() => setCopied(false), 1600);
|
|
12682
|
-
}).catch(() => setCopied(false));
|
|
12683
|
-
},
|
|
12684
|
-
children: copied ? "Copied" : "Copy link"
|
|
12685
|
-
}
|
|
12686
|
-
),
|
|
12687
|
-
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
12688
|
-
import_design_system45.Button,
|
|
12689
|
-
{
|
|
12690
|
-
size: "sm",
|
|
12691
|
-
disabled: publishing,
|
|
12692
|
-
onClick: () => void publish(!(existing?.published_at && !existing.closed_at)),
|
|
12693
|
-
children: publishing ? "\u2026" : existing?.published_at && !existing.closed_at ? "Unpublish" : "Publish"
|
|
12694
|
-
}
|
|
12695
|
-
),
|
|
12696
|
-
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("p", { className: "w-full text-xs text-muted-foreground", children: existing?.published_at && !existing.closed_at ? "Open. Anyone with this link can book a time." : "Not open yet \u2014 the link does not take bookings until you publish it." })
|
|
12697
|
-
] }) : null
|
|
12698
|
-
] });
|
|
12691
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
12692
|
+
import_design_system45.Button,
|
|
12693
|
+
{
|
|
12694
|
+
size: "sm",
|
|
12695
|
+
disabled: publishing,
|
|
12696
|
+
onClick: () => void publish(!(existing?.published_at && !existing.closed_at)),
|
|
12697
|
+
children: publishing ? "\u2026" : existing?.published_at && !existing.closed_at ? "Unpublish" : "Publish"
|
|
12698
|
+
}
|
|
12699
|
+
),
|
|
12700
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)("p", { className: "w-full text-xs text-muted-foreground", children: existing?.published_at && !existing.closed_at ? "Open. Anyone with this link can book a time." : "Not open yet \u2014 the link does not take bookings until you publish it." })
|
|
12701
|
+
] }) : null
|
|
12702
|
+
] })
|
|
12703
|
+
);
|
|
12699
12704
|
}
|
|
12700
12705
|
|
|
12701
12706
|
// src/BookingSlots.tsx
|