@ai-matrx/records-ui 0.58.0 → 0.59.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 CHANGED
@@ -1,5 +1,29 @@
1
1
  # Changelog — @ai-matrx/records-ui
2
2
 
3
+ ## 0.59.0
4
+
5
+ **Three things the browser walks found by using the builders on real businesses.**
6
+
7
+ * **A booking page's day rows lied about what it would offer.** Every day started
8
+ unticked and read "not taking bookings", while `custom._booking_availability`
9
+ substitutes Monday-to-Friday nine-to-five for an empty window list — so a
10
+ person who saved without touching the days was told the page offered nothing
11
+ and got a page offering the whole working week. `BookingBuilder` now opens on
12
+ the working week, and once the store has answered, the rows are ITS answer.
13
+ * **Both builders offered questions a stranger could never answer.** Ironclad
14
+ Mobile Mechanic ticked "Customer" on his booking page — a relation Field — a
15
+ visitor typed her name, and the store refused at the last step with *"Customer
16
+ points at something that is not there"*, after her slot was already held. A
17
+ relation holds the identity of a record in a Table she cannot open. The new
18
+ `publiclyAnswerable` / `askableFields` / `whyNotAskable` decide what a public
19
+ page may ask for (out: relation, member, attachment, formula, lookup, rollup)
20
+ and both `FormBuilder` and `BookingBuilder` use them — the Fields left out are
21
+ NAMED with the reason, in the place somebody would have ticked them.
22
+ * The Booking and Portal builders and the Digest scheduler carry the container
23
+ queries 0.57.0 gave the form builder, so all four are one column in a rail.
24
+
25
+ **Consumer action:** none.
26
+
3
27
  ## 0.58.0
4
28
 
5
29
  **A word pasted into a choice column becomes that option — and a paste is no
package/dist/index.cjs CHANGED
@@ -156,6 +156,7 @@ __export(src_exports, {
156
156
  actorBadge: () => actorBadge,
157
157
  actorWords: () => actorWords,
158
158
  addFields: () => addFields,
159
+ askableFields: () => askableFields,
159
160
  blockFromSpec: () => blockFromSpec,
160
161
  bodyForReading: () => bodyForReading,
161
162
  bodyFromKeys: () => bodyFromKeys,
@@ -208,6 +209,7 @@ __export(src_exports, {
208
209
  presentationDocument: () => presentationDocument,
209
210
  presentationIsEmpty: () => presentationIsEmpty,
210
211
  previewLine: () => previewLine,
212
+ publiclyAnswerable: () => publiclyAnswerable,
211
213
  recordName: () => recordName,
212
214
  recordsDataSource: () => recordsDataSource,
213
215
  refusalForAPerson: () => refusalForAPerson,
@@ -244,7 +246,8 @@ __export(src_exports, {
244
246
  whatIsMissing: () => whatIsMissing,
245
247
  whatYouMayDo: () => whatYouMayDo,
246
248
  whatYouMayDoWithTable: () => whatYouMayDoWithTable,
247
- whenWords: () => whenWords
249
+ whenWords: () => whenWords,
250
+ whyNotAskable: () => whyNotAskable
248
251
  });
249
252
  module.exports = __toCommonJS(src_exports);
250
253
 
@@ -10604,6 +10607,28 @@ function Question({
10604
10607
  ] });
10605
10608
  }
10606
10609
 
10610
+ // src/publicQuestions.ts
10611
+ var CANNOT_ASK = {
10612
+ relation: "points at a record in another table, and somebody with no account cannot see that table to pick from it",
10613
+ member: "is a person in this organization, and somebody outside it has no way to choose one",
10614
+ attachment: "holds a file in your own store, and a public page has nowhere to put one yet",
10615
+ formula: "is worked out by the store, so there is nothing for anybody to answer",
10616
+ lookup: "is read through a relation, so the store fills it in",
10617
+ rollup: "is added up by the store, so there is nothing for anybody to answer"
10618
+ };
10619
+ function publiclyAnswerable(field) {
10620
+ return !(field.type in CANNOT_ASK);
10621
+ }
10622
+ function askableFields(fields, hidden = []) {
10623
+ return fields.filter((f) => publiclyAnswerable(f) && !hidden.includes(f.key));
10624
+ }
10625
+ function whyNotAskable(fields, hidden = []) {
10626
+ const left = fields.filter((f) => !publiclyAnswerable(f) && !hidden.includes(f.key));
10627
+ if (left.length === 0) return null;
10628
+ const said = left.map((f) => `${f.label || f.key} ${CANNOT_ASK[f.type]}`);
10629
+ return said.length === 1 ? `${said[0]}, so it is not offered here.` : `These are not offered here: ${said.join("; ")}.`;
10630
+ }
10631
+
10607
10632
  // src/FormBuilder.tsx
10608
10633
  var import_jsx_runtime39 = require("react/jsx-runtime");
10609
10634
  function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
@@ -10836,7 +10861,7 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
10836
10861
  " fields"
10837
10862
  ] })
10838
10863
  ] }),
10839
- (fields.data ?? []).map((field) => {
10864
+ askableFields(fields.data ?? []).map((field) => {
10840
10865
  const index = draft.questions.findIndex((q) => q.field === field.key);
10841
10866
  const asked = index >= 0;
10842
10867
  const question = asked ? draft.questions[index] : null;
@@ -10888,6 +10913,7 @@ function FormBuilder({ tableId, seed, activeFormId, onActiveForm, className }) {
10888
10913
  ] }) : null
10889
10914
  ] }, field.id);
10890
10915
  }),
10916
+ whyNotAskable(fields.data ?? []) ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("p", { className: "text-xs text-muted-foreground", children: whyNotAskable(fields.data ?? []) }) : null,
10891
10917
  draft.questions.filter((q) => !byKey.has(q.field)).map((q) => /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("p", { className: "text-xs text-destructive", children: [
10892
10918
  'This form asks for "',
10893
10919
  q.field,
@@ -12543,6 +12569,7 @@ var DAYS = [
12543
12569
  { weekday: 0, label: "Sun" }
12544
12570
  ];
12545
12571
  var LENGTHS = [15, 20, 30, 45, 60, 90, 120];
12572
+ var WORKING_WEEK = /* @__PURE__ */ new Set([1, 2, 3, 4, 5]);
12546
12573
  function draftWindows(availability) {
12547
12574
  return DAYS.map((day) => {
12548
12575
  const found = availability?.windows.find((w) => w.weekday === day.weekday);
@@ -12550,7 +12577,7 @@ function draftWindows(availability) {
12550
12577
  weekday: day.weekday,
12551
12578
  from: found?.from ?? "09:00",
12552
12579
  to: found?.to ?? "17:00",
12553
- on: Boolean(found)
12580
+ on: availability ? Boolean(found) : WORKING_WEEK.has(day.weekday)
12554
12581
  };
12555
12582
  });
12556
12583
  }
@@ -12579,9 +12606,11 @@ function BookingBuilder({ tableId, bookingId, onSaved, onClose, className }) {
12579
12606
  const [formId, setFormId] = (0, import_react90.useState)(bookingId ?? null);
12580
12607
  const publicOrigin = host.publicOrigin ?? (typeof window === "undefined" ? "" : window.location.origin);
12581
12608
  const askable = (0, import_react90.useMemo)(
12582
- () => (fields.data ?? []).filter(
12583
- (f) => !STORE_ANSWERS_THESE.includes(f.key)
12584
- ),
12609
+ () => askableFields(fields.data ?? [], STORE_ANSWERS_THESE),
12610
+ [fields.data]
12611
+ );
12612
+ const leftOut = (0, import_react90.useMemo)(
12613
+ () => whyNotAskable(fields.data ?? [], STORE_ANSWERS_THESE),
12585
12614
  [fields.data]
12586
12615
  );
12587
12616
  const load = (0, import_react90.useCallback)(async () => {
@@ -12607,6 +12636,15 @@ function BookingBuilder({ tableId, bookingId, onSaved, onClose, className }) {
12607
12636
  if (!existing) return;
12608
12637
  setMinutes(existing.slot_minutes);
12609
12638
  }, [existing]);
12639
+ (0, import_react90.useEffect)(() => {
12640
+ if (!offer) return;
12641
+ setWindows(draftWindows(offer));
12642
+ setMinutes(offer.slot_minutes);
12643
+ setBuffer(offer.buffer_minutes);
12644
+ setLead(offer.lead_minutes);
12645
+ setPerDay(offer.max_per_day);
12646
+ setDays(offer.days);
12647
+ }, [offer]);
12610
12648
  const availability = (0, import_react90.useCallback)(
12611
12649
  () => ({
12612
12650
  slot_minutes: minutes,
@@ -12794,7 +12832,8 @@ function BookingBuilder({ tableId, bookingId, onSaved, onClose, className }) {
12794
12832
  ),
12795
12833
  fieldName(f)
12796
12834
  ] }, f.key)) }),
12797
- /* @__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." })
12835
+ /* @__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." }),
12836
+ leftOut ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("p", { className: "text-xs text-muted-foreground", children: leftOut }) : null
12798
12837
  ] }),
12799
12838
  /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("label", { className: "flex flex-col gap-1", children: [
12800
12839
  /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_design_system45.Label, { className: "text-xs font-medium", children: "What they see after booking" }),