@open-mercato/core 0.6.6-develop.6519.1.bdc91fb755 → 0.6.6-develop.6520.1.55df6df792

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.
Files changed (70) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/modules/customers/backend/calendar/page.js +9 -1
  3. package/dist/modules/customers/backend/calendar/page.js.map +2 -2
  4. package/dist/modules/customers/components/calendar/AgendaList.js +0 -11
  5. package/dist/modules/customers/components/calendar/AgendaList.js.map +2 -2
  6. package/dist/modules/customers/components/calendar/CalendarEventEditor.js +391 -235
  7. package/dist/modules/customers/components/calendar/CalendarEventEditor.js.map +2 -2
  8. package/dist/modules/customers/components/calendar/CalendarScreen.js +5 -5
  9. package/dist/modules/customers/components/calendar/CalendarScreen.js.map +2 -2
  10. package/dist/modules/customers/components/calendar/CalendarSettingsModal.js +2 -2
  11. package/dist/modules/customers/components/calendar/CalendarSettingsModal.js.map +2 -2
  12. package/dist/modules/customers/components/calendar/MonthGrid.js +1 -11
  13. package/dist/modules/customers/components/calendar/MonthGrid.js.map +2 -2
  14. package/dist/modules/customers/components/calendar/TimeGrid.js +162 -176
  15. package/dist/modules/customers/components/calendar/TimeGrid.js.map +2 -2
  16. package/dist/modules/customers/components/calendar/editor/LocationField.js +61 -14
  17. package/dist/modules/customers/components/calendar/editor/LocationField.js.map +2 -2
  18. package/dist/modules/customers/components/calendar/editor/PeopleField.js +10 -5
  19. package/dist/modules/customers/components/calendar/editor/PeopleField.js.map +2 -2
  20. package/dist/modules/customers/components/calendar/editor/PriorityField.js +85 -0
  21. package/dist/modules/customers/components/calendar/editor/PriorityField.js.map +7 -0
  22. package/dist/modules/customers/components/calendar/editor/RelatedToField.js +8 -3
  23. package/dist/modules/customers/components/calendar/editor/RelatedToField.js.map +2 -2
  24. package/dist/modules/customers/components/calendar/editor/ResourcesField.js +225 -0
  25. package/dist/modules/customers/components/calendar/editor/ResourcesField.js.map +7 -0
  26. package/dist/modules/customers/components/calendar/editor/SegmentGroup.js +12 -7
  27. package/dist/modules/customers/components/calendar/editor/SegmentGroup.js.map +2 -2
  28. package/dist/modules/customers/components/calendar/editor/inputs.js +68 -57
  29. package/dist/modules/customers/components/calendar/editor/inputs.js.map +2 -2
  30. package/dist/modules/customers/components/calendar/editor/lookups.js +82 -2
  31. package/dist/modules/customers/components/calendar/editor/lookups.js.map +2 -2
  32. package/dist/modules/customers/components/calendar/useCalendarItems.js +6 -1
  33. package/dist/modules/customers/components/calendar/useCalendarItems.js.map +2 -2
  34. package/dist/modules/customers/data/validators.js +3 -1
  35. package/dist/modules/customers/data/validators.js.map +2 -2
  36. package/dist/modules/customers/lib/calendar/editorPayload.js +53 -22
  37. package/dist/modules/customers/lib/calendar/editorPayload.js.map +2 -2
  38. package/dist/modules/entities/backend/entities/user/[entityId]/page.js +1 -1
  39. package/dist/modules/entities/backend/entities/user/[entityId]/page.js.map +2 -2
  40. package/package.json +7 -7
  41. package/src/modules/customers/backend/calendar/page.tsx +8 -1
  42. package/src/modules/customers/components/calendar/AgendaList.tsx +0 -10
  43. package/src/modules/customers/components/calendar/CalendarEventEditor.tsx +444 -261
  44. package/src/modules/customers/components/calendar/CalendarScreen.tsx +12 -5
  45. package/src/modules/customers/components/calendar/CalendarSettingsModal.tsx +6 -6
  46. package/src/modules/customers/components/calendar/MonthGrid.tsx +0 -11
  47. package/src/modules/customers/components/calendar/TimeGrid.tsx +1 -24
  48. package/src/modules/customers/components/calendar/editor/LocationField.tsx +64 -2
  49. package/src/modules/customers/components/calendar/editor/PeopleField.tsx +11 -4
  50. package/src/modules/customers/components/calendar/editor/PriorityField.tsx +90 -0
  51. package/src/modules/customers/components/calendar/editor/RelatedToField.tsx +8 -3
  52. package/src/modules/customers/components/calendar/editor/ResourcesField.tsx +264 -0
  53. package/src/modules/customers/components/calendar/editor/SegmentGroup.tsx +14 -6
  54. package/src/modules/customers/components/calendar/editor/inputs.tsx +91 -50
  55. package/src/modules/customers/components/calendar/editor/lookups.ts +115 -2
  56. package/src/modules/customers/components/calendar/useCalendarItems.ts +8 -1
  57. package/src/modules/customers/data/validators.ts +3 -1
  58. package/src/modules/customers/i18n/de.json +12 -2
  59. package/src/modules/customers/i18n/en.json +12 -2
  60. package/src/modules/customers/i18n/es.json +12 -2
  61. package/src/modules/customers/i18n/pl.json +12 -2
  62. package/src/modules/customers/lib/calendar/editorPayload.ts +94 -37
  63. package/src/modules/entities/backend/entities/user/[entityId]/page.tsx +1 -1
  64. package/src/modules/entities/i18n/de.json +120 -0
  65. package/src/modules/entities/i18n/en.json +120 -0
  66. package/src/modules/entities/i18n/es.json +120 -0
  67. package/src/modules/entities/i18n/pl.json +120 -0
  68. package/dist/modules/customers/components/calendar/editor/CategoryField.js +0 -75
  69. package/dist/modules/customers/components/calendar/editor/CategoryField.js.map +0 -7
  70. package/src/modules/customers/components/calendar/editor/CategoryField.tsx +0 -79
@@ -1,28 +1,75 @@
1
1
  "use client";
2
- import { jsx } from "react/jsx-runtime";
3
- import { MapPin } from "lucide-react";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { MapPin, Phone, Plus } from "lucide-react";
4
5
  import { useT } from "@open-mercato/shared/lib/i18n/context";
5
6
  import { Input } from "@open-mercato/ui/primitives/input";
6
7
  import { Field } from "./inputs.js";
8
+ import { fetchPeoplePhones } from "./lookups.js";
9
+ function PhoneSuggestions({
10
+ contactIds,
11
+ onPick
12
+ }) {
13
+ const t = useT();
14
+ const [contacts, setContacts] = React.useState([]);
15
+ const idsKey = contactIds.join(",");
16
+ React.useEffect(() => {
17
+ if (contactIds.length === 0) {
18
+ setContacts([]);
19
+ return;
20
+ }
21
+ const controller = new AbortController();
22
+ let cancelled = false;
23
+ fetchPeoplePhones(contactIds, controller.signal).then((found) => {
24
+ if (!cancelled) setContacts(found);
25
+ });
26
+ return () => {
27
+ cancelled = true;
28
+ controller.abort();
29
+ };
30
+ }, [idsKey]);
31
+ if (contacts.length === 0) return null;
32
+ return /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center gap-1.5 pt-1.5", children: contacts.map((contact) => /* @__PURE__ */ jsxs(
33
+ "button",
34
+ {
35
+ type: "button",
36
+ onClick: () => onPick(contact.phone),
37
+ title: t("customers.calendar.editor.phoneSuggestion.use", "Use {name}\u2019s number", { name: contact.name }),
38
+ className: "inline-flex max-w-full items-center gap-1.5 rounded-md border border-border bg-background px-2 py-1 text-xs text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
39
+ children: [
40
+ /* @__PURE__ */ jsx(Plus, { "aria-hidden": true, className: "size-3 shrink-0" }),
41
+ /* @__PURE__ */ jsx("span", { className: "shrink-0", children: t("customers.calendar.editor.phoneSuggestion.add", "Add") }),
42
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: contact.name }),
43
+ /* @__PURE__ */ jsx("span", { className: "shrink-0 tabular-nums text-foreground", children: contact.phone })
44
+ ]
45
+ },
46
+ contact.id
47
+ )) });
48
+ }
7
49
  function LocationField({
8
50
  variant,
9
51
  value,
10
- onChange
52
+ onChange,
53
+ phoneContactIds
11
54
  }) {
12
55
  const t = useT();
13
56
  const label = variant === "phoneLink" ? t("customers.calendar.editor.phoneLink", "Phone / link") : t("customers.calendar.editor.location", "Location");
14
57
  const placeholder = variant === "phoneLink" ? t("customers.calendar.editor.phoneLinkPlaceholder", "Add a phone number or link\u2026") : t("customers.calendar.editor.locationPlaceholder", "Add a location or link\u2026");
15
- return /* @__PURE__ */ jsx(Field, { label, children: /* @__PURE__ */ jsx(
16
- Input,
17
- {
18
- type: "text",
19
- value,
20
- onChange: (event) => onChange(event.target.value),
21
- placeholder,
22
- "aria-label": label,
23
- leftIcon: /* @__PURE__ */ jsx(MapPin, {})
24
- }
25
- ) });
58
+ const showSuggestions = variant === "phoneLink" && value.trim().length === 0;
59
+ return /* @__PURE__ */ jsxs(Field, { label, children: [
60
+ /* @__PURE__ */ jsx(
61
+ Input,
62
+ {
63
+ type: "text",
64
+ value,
65
+ onChange: (event) => onChange(event.target.value),
66
+ placeholder,
67
+ "aria-label": label,
68
+ leftIcon: variant === "phoneLink" ? /* @__PURE__ */ jsx(Phone, {}) : /* @__PURE__ */ jsx(MapPin, {})
69
+ }
70
+ ),
71
+ showSuggestions ? /* @__PURE__ */ jsx(PhoneSuggestions, { contactIds: phoneContactIds ?? [], onPick: (phone) => onChange(phone) }) : null
72
+ ] });
26
73
  }
27
74
  export {
28
75
  LocationField
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/customers/components/calendar/editor/LocationField.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { MapPin } from 'lucide-react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Field } from './inputs'\n\nexport function LocationField({\n variant,\n value,\n onChange,\n}: {\n variant: 'location' | 'phoneLink'\n value: string\n onChange(next: string): void\n}) {\n const t = useT()\n const label = variant === 'phoneLink'\n ? t('customers.calendar.editor.phoneLink', 'Phone / link')\n : t('customers.calendar.editor.location', 'Location')\n const placeholder = variant === 'phoneLink'\n ? t('customers.calendar.editor.phoneLinkPlaceholder', 'Add a phone number or link\u2026')\n : t('customers.calendar.editor.locationPlaceholder', 'Add a location or link\u2026')\n return (\n <Field label={label}>\n <Input\n type=\"text\"\n value={value}\n onChange={(event) => onChange(event.target.value)}\n placeholder={placeholder}\n aria-label={label}\n leftIcon={<MapPin />}\n />\n </Field>\n )\n}\n"],
5
- "mappings": ";AAgCkB;AA7BlB,SAAS,cAAc;AACvB,SAAS,YAAY;AACrB,SAAS,aAAa;AACtB,SAAS,aAAa;AAEf,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,IAAI,KAAK;AACf,QAAM,QAAQ,YAAY,cACtB,EAAE,uCAAuC,cAAc,IACvD,EAAE,sCAAsC,UAAU;AACtD,QAAM,cAAc,YAAY,cAC5B,EAAE,kDAAkD,kCAA6B,IACjF,EAAE,iDAAiD,8BAAyB;AAChF,SACE,oBAAC,SAAM,OACL;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL;AAAA,MACA,UAAU,CAAC,UAAU,SAAS,MAAM,OAAO,KAAK;AAAA,MAChD;AAAA,MACA,cAAY;AAAA,MACZ,UAAU,oBAAC,UAAO;AAAA;AAAA,EACpB,GACF;AAEJ;",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { MapPin, Phone, Plus } from 'lucide-react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Field } from './inputs'\nimport { fetchPeoplePhones, type ContactPhone } from './lookups'\n\n// Below the Call \"Phone / link\" field: when a linked contact has a primary\n// phone and the field is still empty, offer it as a one-click suggestion chip\n// showing the actual number (#3552). Companies/staff have no phone and never\n// appear. The chips vanish once the field is filled.\nfunction PhoneSuggestions({\n contactIds,\n onPick,\n}: {\n contactIds: string[]\n onPick(phone: string): void\n}) {\n const t = useT()\n const [contacts, setContacts] = React.useState<ContactPhone[]>([])\n const idsKey = contactIds.join(',')\n\n React.useEffect(() => {\n if (contactIds.length === 0) {\n setContacts([])\n return\n }\n const controller = new AbortController()\n let cancelled = false\n fetchPeoplePhones(contactIds, controller.signal).then((found) => {\n if (!cancelled) setContacts(found)\n })\n return () => {\n cancelled = true\n controller.abort()\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps -- idsKey captures the ids\n }, [idsKey])\n\n if (contacts.length === 0) return null\n return (\n <div className=\"flex flex-wrap items-center gap-1.5 pt-1.5\">\n {contacts.map((contact) => (\n <button\n key={contact.id}\n type=\"button\"\n onClick={() => onPick(contact.phone)}\n title={t('customers.calendar.editor.phoneSuggestion.use', 'Use {name}\u2019s number', { name: contact.name })}\n className=\"inline-flex max-w-full items-center gap-1.5 rounded-md border border-border bg-background px-2 py-1 text-xs text-muted-foreground transition-colors hover:bg-muted hover:text-foreground\"\n >\n <Plus aria-hidden className=\"size-3 shrink-0\" />\n <span className=\"shrink-0\">{t('customers.calendar.editor.phoneSuggestion.add', 'Add')}</span>\n <span className=\"truncate\">{contact.name}</span>\n <span className=\"shrink-0 tabular-nums text-foreground\">{contact.phone}</span>\n </button>\n ))}\n </div>\n )\n}\n\nexport function LocationField({\n variant,\n value,\n onChange,\n phoneContactIds,\n}: {\n variant: 'location' | 'phoneLink'\n value: string\n onChange(next: string): void\n /** Person ids whose phone can be suggested (Call variant only). */\n phoneContactIds?: string[]\n}) {\n const t = useT()\n const label = variant === 'phoneLink'\n ? t('customers.calendar.editor.phoneLink', 'Phone / link')\n : t('customers.calendar.editor.location', 'Location')\n const placeholder = variant === 'phoneLink'\n ? t('customers.calendar.editor.phoneLinkPlaceholder', 'Add a phone number or link\u2026')\n : t('customers.calendar.editor.locationPlaceholder', 'Add a location or link\u2026')\n // Suggestions only help while the field is empty \u2014 once filled they'd be noise.\n const showSuggestions = variant === 'phoneLink' && value.trim().length === 0\n return (\n <Field label={label}>\n <Input\n type=\"text\"\n value={value}\n onChange={(event) => onChange(event.target.value)}\n placeholder={placeholder}\n aria-label={label}\n leftIcon={variant === 'phoneLink' ? <Phone /> : <MapPin />}\n />\n {showSuggestions ? (\n <PhoneSuggestions contactIds={phoneContactIds ?? []} onPick={(phone) => onChange(phone)} />\n ) : null}\n </Field>\n )\n}\n"],
5
+ "mappings": ";AA6CQ,SAOE,KAPF;AA3CR,YAAY,WAAW;AACvB,SAAS,QAAQ,OAAO,YAAY;AACpC,SAAS,YAAY;AACrB,SAAS,aAAa;AACtB,SAAS,aAAa;AACtB,SAAS,yBAA4C;AAMrD,SAAS,iBAAiB;AAAA,EACxB;AAAA,EACA;AACF,GAGG;AACD,QAAM,IAAI,KAAK;AACf,QAAM,CAAC,UAAU,WAAW,IAAI,MAAM,SAAyB,CAAC,CAAC;AACjE,QAAM,SAAS,WAAW,KAAK,GAAG;AAElC,QAAM,UAAU,MAAM;AACpB,QAAI,WAAW,WAAW,GAAG;AAC3B,kBAAY,CAAC,CAAC;AACd;AAAA,IACF;AACA,UAAM,aAAa,IAAI,gBAAgB;AACvC,QAAI,YAAY;AAChB,sBAAkB,YAAY,WAAW,MAAM,EAAE,KAAK,CAAC,UAAU;AAC/D,UAAI,CAAC,UAAW,aAAY,KAAK;AAAA,IACnC,CAAC;AACD,WAAO,MAAM;AACX,kBAAY;AACZ,iBAAW,MAAM;AAAA,IACnB;AAAA,EAEF,GAAG,CAAC,MAAM,CAAC;AAEX,MAAI,SAAS,WAAW,EAAG,QAAO;AAClC,SACE,oBAAC,SAAI,WAAU,8CACZ,mBAAS,IAAI,CAAC,YACb;AAAA,IAAC;AAAA;AAAA,MAEC,MAAK;AAAA,MACL,SAAS,MAAM,OAAO,QAAQ,KAAK;AAAA,MACnC,OAAO,EAAE,iDAAiD,4BAAuB,EAAE,MAAM,QAAQ,KAAK,CAAC;AAAA,MACvG,WAAU;AAAA,MAEV;AAAA,4BAAC,QAAK,eAAW,MAAC,WAAU,mBAAkB;AAAA,QAC9C,oBAAC,UAAK,WAAU,YAAY,YAAE,iDAAiD,KAAK,GAAE;AAAA,QACtF,oBAAC,UAAK,WAAU,YAAY,kBAAQ,MAAK;AAAA,QACzC,oBAAC,UAAK,WAAU,yCAAyC,kBAAQ,OAAM;AAAA;AAAA;AAAA,IATlE,QAAQ;AAAA,EAUf,CACD,GACH;AAEJ;AAEO,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMG;AACD,QAAM,IAAI,KAAK;AACf,QAAM,QAAQ,YAAY,cACtB,EAAE,uCAAuC,cAAc,IACvD,EAAE,sCAAsC,UAAU;AACtD,QAAM,cAAc,YAAY,cAC5B,EAAE,kDAAkD,kCAA6B,IACjF,EAAE,iDAAiD,8BAAyB;AAEhF,QAAM,kBAAkB,YAAY,eAAe,MAAM,KAAK,EAAE,WAAW;AAC3E,SACE,qBAAC,SAAM,OACL;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL;AAAA,QACA,UAAU,CAAC,UAAU,SAAS,MAAM,OAAO,KAAK;AAAA,QAChD;AAAA,QACA,cAAY;AAAA,QACZ,UAAU,YAAY,cAAc,oBAAC,SAAM,IAAK,oBAAC,UAAO;AAAA;AAAA,IAC1D;AAAA,IACC,kBACC,oBAAC,oBAAiB,YAAY,mBAAmB,CAAC,GAAG,QAAQ,CAAC,UAAU,SAAS,KAAK,GAAG,IACvF;AAAA,KACN;AAEJ;",
6
6
  "names": []
7
7
  }
@@ -8,20 +8,23 @@ import { Button } from "@open-mercato/ui/primitives/button";
8
8
  import { Input } from "@open-mercato/ui/primitives/input";
9
9
  import { composeAccessibleName } from "../../../lib/calendar/labels.js";
10
10
  import { searchPeopleOptions } from "./lookups.js";
11
- import { CONTROL_BORDER, DROPDOWN_PANEL_CLASS, PersonChip, UppercaseBadge } from "./inputs.js";
11
+ import { CONTROL_BORDER, DROPDOWN_PANEL_CLASS, PersonChip, UppercaseBadge, useDropdownDismiss } from "./inputs.js";
12
12
  function PeopleField({
13
13
  mode,
14
14
  placeholder,
15
15
  ariaLabel,
16
16
  value,
17
17
  onChange,
18
- includeCustomers
18
+ includeCustomers,
19
+ includeStaff = true
19
20
  }) {
20
21
  const t = useT();
21
22
  const [query, setQuery] = React.useState("");
22
23
  const [open, setOpen] = React.useState(false);
23
24
  const [options, setOptions] = React.useState([]);
24
25
  const [loading, setLoading] = React.useState(false);
26
+ const close = React.useCallback(() => setOpen(false), []);
27
+ const rootRef = useDropdownDismiss(open, close);
25
28
  React.useEffect(() => {
26
29
  if (!open) return;
27
30
  const controller = new AbortController();
@@ -29,7 +32,7 @@ function PeopleField({
29
32
  const timer = window.setTimeout(async () => {
30
33
  setLoading(true);
31
34
  try {
32
- const results = await searchPeopleOptions(query.trim(), { includeCustomers, signal: controller.signal });
35
+ const results = await searchPeopleOptions(query.trim(), { includeCustomers, includeStaff, signal: controller.signal });
33
36
  if (cancelled) return;
34
37
  setOptions(results);
35
38
  } catch {
@@ -43,13 +46,14 @@ function PeopleField({
43
46
  controller.abort();
44
47
  window.clearTimeout(timer);
45
48
  };
46
- }, [open, query, includeCustomers]);
49
+ }, [open, query, includeCustomers, includeStaff]);
47
50
  const selectedIds = new Set(value.map((participant) => participant.userId));
48
51
  const visibleOptions = options.filter((option) => !selectedIds.has(option.userId));
49
52
  const customerBadge = /* @__PURE__ */ jsx(UppercaseBadge, { className: "bg-status-info-bg text-status-info-text", children: t("customers.calendar.editor.customerBadge", "Customer") });
50
53
  return /* @__PURE__ */ jsxs(
51
54
  "div",
52
55
  {
56
+ ref: rootRef,
53
57
  className: "relative w-full",
54
58
  onBlur: (event) => {
55
59
  if (!event.currentTarget.contains(event.relatedTarget)) setOpen(false);
@@ -60,7 +64,7 @@ function PeopleField({
60
64
  {
61
65
  className: cn(
62
66
  "flex w-full flex-wrap content-center items-center gap-2 rounded-md bg-background px-2.5 py-2",
63
- mode === "multi" ? "min-h-24" : "min-h-14",
67
+ "min-h-14",
64
68
  CONTROL_BORDER
65
69
  ),
66
70
  children: [
@@ -107,6 +111,7 @@ function PeopleField({
107
111
  option.email,
108
112
  option.isCustomer ? t("customers.calendar.editor.customerBadge", "Customer") : null
109
113
  ]),
114
+ title: composeAccessibleName([option.name, option.email]),
110
115
  onClick: () => {
111
116
  const participant = {
112
117
  userId: option.userId,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/customers/components/calendar/editor/PeopleField.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Avatar } from '@open-mercato/ui/primitives/avatar'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport type { EditorParticipant } from '../../../lib/calendar/editorPayload'\nimport { composeAccessibleName } from '../../../lib/calendar/labels'\nimport { searchPeopleOptions, type PersonOption } from './lookups'\nimport { CONTROL_BORDER, DROPDOWN_PANEL_CLASS, PersonChip, UppercaseBadge } from './inputs'\n\nexport function PeopleField({\n mode,\n placeholder,\n ariaLabel,\n value,\n onChange,\n includeCustomers,\n}: {\n mode: 'multi' | 'single'\n placeholder: string\n ariaLabel: string\n value: EditorParticipant[]\n onChange(next: EditorParticipant[]): void\n includeCustomers: boolean\n}) {\n const t = useT()\n const [query, setQuery] = React.useState('')\n const [open, setOpen] = React.useState(false)\n const [options, setOptions] = React.useState<PersonOption[]>([])\n const [loading, setLoading] = React.useState(false)\n\n React.useEffect(() => {\n if (!open) return\n const controller = new AbortController()\n let cancelled = false\n const timer = window.setTimeout(async () => {\n setLoading(true)\n try {\n const results = await searchPeopleOptions(query.trim(), { includeCustomers, signal: controller.signal })\n if (cancelled) return\n setOptions(results)\n } catch {\n if (!cancelled) setOptions([])\n } finally {\n if (!cancelled) setLoading(false)\n }\n }, 250)\n return () => {\n cancelled = true\n controller.abort()\n window.clearTimeout(timer)\n }\n }, [open, query, includeCustomers])\n\n const selectedIds = new Set(value.map((participant) => participant.userId))\n const visibleOptions = options.filter((option) => !selectedIds.has(option.userId))\n\n const customerBadge = (\n <UppercaseBadge className=\"bg-status-info-bg text-status-info-text\">\n {t('customers.calendar.editor.customerBadge', 'Customer')}\n </UppercaseBadge>\n )\n\n return (\n <div\n className=\"relative w-full\"\n onBlur={(event) => {\n if (!event.currentTarget.contains(event.relatedTarget as Node | null)) setOpen(false)\n }}\n >\n <div\n className={cn(\n 'flex w-full flex-wrap content-center items-center gap-2 rounded-md bg-background px-2.5 py-2',\n mode === 'multi' ? 'min-h-24' : 'min-h-14',\n CONTROL_BORDER,\n )}\n >\n {value.map((participant) => (\n <PersonChip\n key={participant.userId}\n name={participant.name}\n badge={participant.isCustomer ? customerBadge : undefined}\n onRemove={() => onChange(value.filter((entry) => entry.userId !== participant.userId))}\n removeLabel={t('customers.calendar.editor.removePerson', 'Remove {name}', { name: participant.name })}\n />\n ))}\n <Input\n type=\"text\"\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n onFocus={() => setOpen(true)}\n placeholder={placeholder}\n aria-label={ariaLabel}\n role=\"combobox\"\n aria-expanded={open}\n className=\"min-w-36 flex-1 border-0 bg-transparent px-0 shadow-none hover:bg-transparent focus-within:border-transparent focus-within:shadow-none\"\n inputClassName=\"text-sm text-foreground placeholder:text-muted-foreground\"\n />\n </div>\n {open ? (\n <div role=\"listbox\" aria-label={ariaLabel} className={DROPDOWN_PANEL_CLASS}>\n {loading ? (\n <p className=\"px-2 py-3 text-center text-xs text-muted-foreground\">\n {t('customers.calendar.editor.searching', 'Searching\u2026')}\n </p>\n ) : null}\n {!loading && visibleOptions.length === 0 ? (\n <p className=\"px-2 py-3 text-center text-xs text-muted-foreground\">\n {t('customers.calendar.editor.noResults', 'No results')}\n </p>\n ) : null}\n {!loading\n ? visibleOptions.map((option) => (\n <Button\n key={`${option.isCustomer ? 'customer' : 'staff'}:${option.userId}`}\n type=\"button\"\n variant=\"ghost\"\n role=\"option\"\n aria-selected={false}\n aria-label={composeAccessibleName([\n option.name,\n option.email,\n option.isCustomer ? t('customers.calendar.editor.customerBadge', 'Customer') : null,\n ])}\n onClick={() => {\n const participant: EditorParticipant = {\n userId: option.userId,\n name: option.name,\n email: option.email ?? undefined,\n isCustomer: option.isCustomer,\n }\n onChange(mode === 'single' ? [participant] : [...value, participant])\n setQuery('')\n if (mode === 'single') setOpen(false)\n }}\n className=\"h-auto w-full justify-start gap-2 whitespace-normal px-2 py-1.5 text-left text-sm font-normal text-foreground\"\n >\n <Avatar size=\"xs\" label={option.name} />\n <span className=\"min-w-0 flex-1 truncate\">\n {option.name}\n {option.email ? <span className=\"ml-1.5 text-xs text-muted-foreground\">{option.email}</span> : null}\n </span>\n {option.isCustomer ? customerBadge : null}\n </Button>\n ))\n : null}\n </div>\n ) : null}\n </div>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Avatar } from '@open-mercato/ui/primitives/avatar'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport type { EditorParticipant } from '../../../lib/calendar/editorPayload'\nimport { composeAccessibleName } from '../../../lib/calendar/labels'\nimport { searchPeopleOptions, type PersonOption } from './lookups'\nimport { CONTROL_BORDER, DROPDOWN_PANEL_CLASS, PersonChip, UppercaseBadge, useDropdownDismiss } from './inputs'\n\nexport function PeopleField({\n mode,\n placeholder,\n ariaLabel,\n value,\n onChange,\n includeCustomers,\n includeStaff = true,\n}: {\n mode: 'multi' | 'single'\n placeholder: string\n ariaLabel: string\n value: EditorParticipant[]\n onChange(next: EditorParticipant[]): void\n includeCustomers: boolean\n /** Pass false when the staff module is not loaded \u2014 customer-only options. */\n includeStaff?: boolean\n}) {\n const t = useT()\n const [query, setQuery] = React.useState('')\n const [open, setOpen] = React.useState(false)\n const [options, setOptions] = React.useState<PersonOption[]>([])\n const [loading, setLoading] = React.useState(false)\n const close = React.useCallback(() => setOpen(false), [])\n const rootRef = useDropdownDismiss(open, close)\n\n React.useEffect(() => {\n if (!open) return\n const controller = new AbortController()\n let cancelled = false\n const timer = window.setTimeout(async () => {\n setLoading(true)\n try {\n const results = await searchPeopleOptions(query.trim(), { includeCustomers, includeStaff, signal: controller.signal })\n if (cancelled) return\n setOptions(results)\n } catch {\n if (!cancelled) setOptions([])\n } finally {\n if (!cancelled) setLoading(false)\n }\n }, 250)\n return () => {\n cancelled = true\n controller.abort()\n window.clearTimeout(timer)\n }\n }, [open, query, includeCustomers, includeStaff])\n\n const selectedIds = new Set(value.map((participant) => participant.userId))\n const visibleOptions = options.filter((option) => !selectedIds.has(option.userId))\n\n const customerBadge = (\n <UppercaseBadge className=\"bg-status-info-bg text-status-info-text\">\n {t('customers.calendar.editor.customerBadge', 'Customer')}\n </UppercaseBadge>\n )\n\n return (\n <div\n ref={rootRef}\n className=\"relative w-full\"\n onBlur={(event) => {\n if (!event.currentTarget.contains(event.relatedTarget as Node | null)) setOpen(false)\n }}\n >\n <div\n className={cn(\n 'flex w-full flex-wrap content-center items-center gap-2 rounded-md bg-background px-2.5 py-2',\n 'min-h-14',\n CONTROL_BORDER,\n )}\n >\n {value.map((participant) => (\n <PersonChip\n key={participant.userId}\n name={participant.name}\n badge={participant.isCustomer ? customerBadge : undefined}\n onRemove={() => onChange(value.filter((entry) => entry.userId !== participant.userId))}\n removeLabel={t('customers.calendar.editor.removePerson', 'Remove {name}', { name: participant.name })}\n />\n ))}\n <Input\n type=\"text\"\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n onFocus={() => setOpen(true)}\n placeholder={placeholder}\n aria-label={ariaLabel}\n role=\"combobox\"\n aria-expanded={open}\n className=\"min-w-36 flex-1 border-0 bg-transparent px-0 shadow-none hover:bg-transparent focus-within:border-transparent focus-within:shadow-none\"\n inputClassName=\"text-sm text-foreground placeholder:text-muted-foreground\"\n />\n </div>\n {open ? (\n <div role=\"listbox\" aria-label={ariaLabel} className={DROPDOWN_PANEL_CLASS}>\n {loading ? (\n <p className=\"px-2 py-3 text-center text-xs text-muted-foreground\">\n {t('customers.calendar.editor.searching', 'Searching\u2026')}\n </p>\n ) : null}\n {!loading && visibleOptions.length === 0 ? (\n <p className=\"px-2 py-3 text-center text-xs text-muted-foreground\">\n {t('customers.calendar.editor.noResults', 'No results')}\n </p>\n ) : null}\n {!loading\n ? visibleOptions.map((option) => (\n <Button\n key={`${option.isCustomer ? 'customer' : 'staff'}:${option.userId}`}\n type=\"button\"\n variant=\"ghost\"\n role=\"option\"\n aria-selected={false}\n aria-label={composeAccessibleName([\n option.name,\n option.email,\n option.isCustomer ? t('customers.calendar.editor.customerBadge', 'Customer') : null,\n ])}\n title={composeAccessibleName([option.name, option.email])}\n onClick={() => {\n const participant: EditorParticipant = {\n userId: option.userId,\n name: option.name,\n email: option.email ?? undefined,\n isCustomer: option.isCustomer,\n }\n onChange(mode === 'single' ? [participant] : [...value, participant])\n setQuery('')\n if (mode === 'single') setOpen(false)\n }}\n className=\"h-auto w-full justify-start gap-2 whitespace-normal px-2 py-1.5 text-left text-sm font-normal text-foreground\"\n >\n <Avatar size=\"xs\" label={option.name} />\n <span className=\"min-w-0 flex-1 truncate\">\n {option.name}\n {option.email ? <span className=\"ml-1.5 text-xs text-muted-foreground\">{option.email}</span> : null}\n </span>\n {option.isCustomer ? customerBadge : null}\n </Button>\n ))\n : null}\n </div>\n ) : null}\n </div>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,85 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import { Check, ChevronDown, ChevronsDown, ChevronsUp, Equal } from "lucide-react";
5
+ import { cn } from "@open-mercato/shared/lib/utils";
6
+ import { Button } from "@open-mercato/ui/primitives/button";
7
+ import { CONTROL_BORDER, DROPDOWN_PANEL_CLASS, useDropdownDismiss } from "./inputs.js";
8
+ const PRIORITY_META = {
9
+ low: { Icon: ChevronsDown, color: "text-status-info-text" },
10
+ medium: { Icon: Equal, color: "text-muted-foreground" },
11
+ high: { Icon: ChevronsUp, color: "text-status-error-text" }
12
+ };
13
+ const PRIORITY_ORDER = ["high", "medium", "low"];
14
+ function PriorityField({
15
+ value,
16
+ labels,
17
+ ariaLabel,
18
+ onChange
19
+ }) {
20
+ const [open, setOpen] = React.useState(false);
21
+ const close = React.useCallback(() => setOpen(false), []);
22
+ const rootRef = useDropdownDismiss(open, close);
23
+ const selected = PRIORITY_META[value];
24
+ const SelectedIcon = selected.Icon;
25
+ return /* @__PURE__ */ jsxs(
26
+ "div",
27
+ {
28
+ ref: rootRef,
29
+ className: "relative w-full",
30
+ onBlur: (event) => {
31
+ if (!event.currentTarget.contains(event.relatedTarget)) setOpen(false);
32
+ },
33
+ children: [
34
+ /* @__PURE__ */ jsxs(
35
+ Button,
36
+ {
37
+ type: "button",
38
+ variant: "outline",
39
+ "aria-haspopup": "listbox",
40
+ "aria-expanded": open,
41
+ "aria-label": ariaLabel,
42
+ onClick: () => setOpen((previous) => !previous),
43
+ className: cn("h-9 w-full justify-between bg-background px-3 font-normal shadow-none", CONTROL_BORDER),
44
+ children: [
45
+ /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 items-center gap-2", children: [
46
+ /* @__PURE__ */ jsx(SelectedIcon, { "aria-hidden": true, className: cn("size-4 shrink-0", selected.color) }),
47
+ /* @__PURE__ */ jsx("span", { className: "truncate text-sm text-foreground", children: labels[value] })
48
+ ] }),
49
+ /* @__PURE__ */ jsx(ChevronDown, { "aria-hidden": true, className: "size-4 shrink-0 opacity-60" })
50
+ ]
51
+ }
52
+ ),
53
+ open ? /* @__PURE__ */ jsx("div", { role: "listbox", "aria-label": ariaLabel, className: DROPDOWN_PANEL_CLASS, children: PRIORITY_ORDER.map((priority) => {
54
+ const meta = PRIORITY_META[priority];
55
+ const Icon = meta.Icon;
56
+ const active = priority === value;
57
+ return /* @__PURE__ */ jsxs(
58
+ Button,
59
+ {
60
+ type: "button",
61
+ variant: "ghost",
62
+ role: "option",
63
+ "aria-selected": active,
64
+ onClick: () => {
65
+ onChange(priority);
66
+ setOpen(false);
67
+ },
68
+ className: cn("h-auto w-full justify-start gap-2 px-2 py-1.5 text-left text-sm font-normal", active && "bg-muted"),
69
+ children: [
70
+ /* @__PURE__ */ jsx(Icon, { "aria-hidden": true, className: cn("size-4 shrink-0", meta.color) }),
71
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-foreground", children: labels[priority] }),
72
+ /* @__PURE__ */ jsx(Check, { "aria-hidden": true, className: cn("size-4 shrink-0", active ? "opacity-100" : "opacity-0") })
73
+ ]
74
+ },
75
+ priority
76
+ );
77
+ }) }) : null
78
+ ]
79
+ }
80
+ );
81
+ }
82
+ export {
83
+ PriorityField
84
+ };
85
+ //# sourceMappingURL=PriorityField.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../src/modules/customers/components/calendar/editor/PriorityField.tsx"],
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Check, ChevronDown, ChevronsDown, ChevronsUp, Equal } from 'lucide-react'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport type { EditorPriority } from '../../../lib/calendar/editorPayload'\nimport { CONTROL_BORDER, DROPDOWN_PANEL_CLASS, useDropdownDismiss } from './inputs'\n\n// Jira/Linear-style priority glyphs: filled double chevrons for the extremes,\n// an equals bar for the middle. Colours stay on DS status tokens (no amber):\n// blue = low urgency, muted = medium, red = high.\nconst PRIORITY_META: Record<EditorPriority, { Icon: React.ComponentType<{ className?: string }>; color: string }> = {\n low: { Icon: ChevronsDown, color: 'text-status-info-text' },\n medium: { Icon: Equal, color: 'text-muted-foreground' },\n high: { Icon: ChevronsUp, color: 'text-status-error-text' },\n}\n\nconst PRIORITY_ORDER: EditorPriority[] = ['high', 'medium', 'low']\n\nexport function PriorityField({\n value,\n labels,\n ariaLabel,\n onChange,\n}: {\n value: EditorPriority\n labels: Record<EditorPriority, string>\n ariaLabel: string\n onChange(next: EditorPriority): void\n}) {\n const [open, setOpen] = React.useState(false)\n const close = React.useCallback(() => setOpen(false), [])\n const rootRef = useDropdownDismiss(open, close)\n const selected = PRIORITY_META[value]\n const SelectedIcon = selected.Icon\n\n return (\n <div\n ref={rootRef}\n className=\"relative w-full\"\n onBlur={(event) => {\n if (!event.currentTarget.contains(event.relatedTarget as Node | null)) setOpen(false)\n }}\n >\n <Button\n type=\"button\"\n variant=\"outline\"\n aria-haspopup=\"listbox\"\n aria-expanded={open}\n aria-label={ariaLabel}\n onClick={() => setOpen((previous) => !previous)}\n className={cn('h-9 w-full justify-between bg-background px-3 font-normal shadow-none', CONTROL_BORDER)}\n >\n <span className=\"flex min-w-0 items-center gap-2\">\n <SelectedIcon aria-hidden className={cn('size-4 shrink-0', selected.color)} />\n <span className=\"truncate text-sm text-foreground\">{labels[value]}</span>\n </span>\n <ChevronDown aria-hidden className=\"size-4 shrink-0 opacity-60\" />\n </Button>\n {open ? (\n <div role=\"listbox\" aria-label={ariaLabel} className={DROPDOWN_PANEL_CLASS}>\n {PRIORITY_ORDER.map((priority) => {\n const meta = PRIORITY_META[priority]\n const Icon = meta.Icon\n const active = priority === value\n return (\n <Button\n key={priority}\n type=\"button\"\n variant=\"ghost\"\n role=\"option\"\n aria-selected={active}\n onClick={() => {\n onChange(priority)\n setOpen(false)\n }}\n className={cn('h-auto w-full justify-start gap-2 px-2 py-1.5 text-left text-sm font-normal', active && 'bg-muted')}\n >\n <Icon aria-hidden className={cn('size-4 shrink-0', meta.color)} />\n <span className=\"min-w-0 flex-1 truncate text-foreground\">{labels[priority]}</span>\n <Check aria-hidden className={cn('size-4 shrink-0', active ? 'opacity-100' : 'opacity-0')} />\n </Button>\n )\n })}\n </div>\n ) : null}\n </div>\n )\n}\n"],
5
+ "mappings": ";AAsDQ,SACE,KADF;AApDR,YAAY,WAAW;AACvB,SAAS,OAAO,aAAa,cAAc,YAAY,aAAa;AACpE,SAAS,UAAU;AACnB,SAAS,cAAc;AAEvB,SAAS,gBAAgB,sBAAsB,0BAA0B;AAKzE,MAAM,gBAA8G;AAAA,EAClH,KAAK,EAAE,MAAM,cAAc,OAAO,wBAAwB;AAAA,EAC1D,QAAQ,EAAE,MAAM,OAAO,OAAO,wBAAwB;AAAA,EACtD,MAAM,EAAE,MAAM,YAAY,OAAO,yBAAyB;AAC5D;AAEA,MAAM,iBAAmC,CAAC,QAAQ,UAAU,KAAK;AAE1D,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,QAAM,CAAC,MAAM,OAAO,IAAI,MAAM,SAAS,KAAK;AAC5C,QAAM,QAAQ,MAAM,YAAY,MAAM,QAAQ,KAAK,GAAG,CAAC,CAAC;AACxD,QAAM,UAAU,mBAAmB,MAAM,KAAK;AAC9C,QAAM,WAAW,cAAc,KAAK;AACpC,QAAM,eAAe,SAAS;AAE9B,SACE;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL,WAAU;AAAA,MACV,QAAQ,CAAC,UAAU;AACjB,YAAI,CAAC,MAAM,cAAc,SAAS,MAAM,aAA4B,EAAG,SAAQ,KAAK;AAAA,MACtF;AAAA,MAEA;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,SAAQ;AAAA,YACR,iBAAc;AAAA,YACd,iBAAe;AAAA,YACf,cAAY;AAAA,YACZ,SAAS,MAAM,QAAQ,CAAC,aAAa,CAAC,QAAQ;AAAA,YAC9C,WAAW,GAAG,yEAAyE,cAAc;AAAA,YAErG;AAAA,mCAAC,UAAK,WAAU,mCACd;AAAA,oCAAC,gBAAa,eAAW,MAAC,WAAW,GAAG,mBAAmB,SAAS,KAAK,GAAG;AAAA,gBAC5E,oBAAC,UAAK,WAAU,oCAAoC,iBAAO,KAAK,GAAE;AAAA,iBACpE;AAAA,cACA,oBAAC,eAAY,eAAW,MAAC,WAAU,8BAA6B;AAAA;AAAA;AAAA,QAClE;AAAA,QACC,OACC,oBAAC,SAAI,MAAK,WAAU,cAAY,WAAW,WAAW,sBACnD,yBAAe,IAAI,CAAC,aAAa;AAChC,gBAAM,OAAO,cAAc,QAAQ;AACnC,gBAAM,OAAO,KAAK;AAClB,gBAAM,SAAS,aAAa;AAC5B,iBACE;AAAA,YAAC;AAAA;AAAA,cAEC,MAAK;AAAA,cACL,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,iBAAe;AAAA,cACf,SAAS,MAAM;AACb,yBAAS,QAAQ;AACjB,wBAAQ,KAAK;AAAA,cACf;AAAA,cACA,WAAW,GAAG,+EAA+E,UAAU,UAAU;AAAA,cAEjH;AAAA,oCAAC,QAAK,eAAW,MAAC,WAAW,GAAG,mBAAmB,KAAK,KAAK,GAAG;AAAA,gBAChE,oBAAC,UAAK,WAAU,2CAA2C,iBAAO,QAAQ,GAAE;AAAA,gBAC5E,oBAAC,SAAM,eAAW,MAAC,WAAW,GAAG,mBAAmB,SAAS,gBAAgB,WAAW,GAAG;AAAA;AAAA;AAAA,YAbtF;AAAA,UAcP;AAAA,QAEJ,CAAC,GACH,IACE;AAAA;AAAA;AAAA,EACN;AAEJ;",
6
+ "names": []
7
+ }
@@ -12,7 +12,7 @@ import {
12
12
  fetchDealsForEntity,
13
13
  searchRelatedEntities
14
14
  } from "./lookups.js";
15
- import { CONTROL_BORDER, DROPDOWN_PANEL_CLASS, PersonChip, UppercaseBadge } from "./inputs.js";
15
+ import { CONTROL_BORDER, DROPDOWN_PANEL_CLASS, PersonChip, UppercaseBadge, useDropdownDismiss } from "./inputs.js";
16
16
  const OPTION_ROW_CLASS = "h-auto w-full justify-start gap-2 whitespace-normal px-2 py-1.5 text-left text-sm font-normal text-foreground";
17
17
  function RelatedToField({
18
18
  label,
@@ -24,6 +24,8 @@ function RelatedToField({
24
24
  }) {
25
25
  const t = useT();
26
26
  const [open, setOpen] = React.useState(false);
27
+ const closeDropdown = React.useCallback(() => setOpen(false), []);
28
+ const rootRef = useDropdownDismiss(open, closeDropdown);
27
29
  const [query, setQuery] = React.useState("");
28
30
  const [options, setOptions] = React.useState([]);
29
31
  const [deals, setDeals] = React.useState([]);
@@ -75,6 +77,7 @@ function RelatedToField({
75
77
  return /* @__PURE__ */ jsxs(
76
78
  "div",
77
79
  {
80
+ ref: rootRef,
78
81
  className: "relative w-full",
79
82
  onBlur: (event) => {
80
83
  if (!event.currentTarget.contains(event.relatedTarget)) setOpen(false);
@@ -84,7 +87,7 @@ function RelatedToField({
84
87
  "div",
85
88
  {
86
89
  className: cn(
87
- "flex h-10 w-full items-center rounded-md bg-background pl-2.5 pr-3",
90
+ "flex h-10 w-full items-center rounded-md bg-background pl-2.5 pr-3 transition-colors hover:bg-accent/50",
88
91
  error ? "border border-status-error-border" : CONTROL_BORDER
89
92
  ),
90
93
  children: [
@@ -97,7 +100,7 @@ function RelatedToField({
97
100
  "aria-expanded": open,
98
101
  "aria-label": label,
99
102
  onClick: () => setOpen((previous) => !previous),
100
- className: "h-full min-w-0 flex-1 justify-between rounded-none bg-transparent p-0 text-left shadow-none hover:bg-transparent",
103
+ className: "h-full min-w-0 flex-1 justify-between rounded-none bg-transparent p-0 text-left shadow-none hover:bg-transparent dark:hover:bg-transparent",
101
104
  children: [
102
105
  /* @__PURE__ */ jsx("span", { className: "flex min-w-0 items-center gap-2", children: value ? /* @__PURE__ */ jsx(
103
106
  PersonChip,
@@ -155,6 +158,7 @@ function RelatedToField({
155
158
  role: "option",
156
159
  "aria-selected": value?.id === option.id,
157
160
  "aria-label": composeAccessibleName([option.label, option.subtitle, kindLabel(option.kind)]),
161
+ title: composeAccessibleName([option.label, option.subtitle]),
158
162
  onClick: () => {
159
163
  onChange({ id: option.id, kind: option.kind, label: option.label });
160
164
  if (value?.id !== option.id) onDealChange(null);
@@ -196,6 +200,7 @@ function RelatedToField({
196
200
  variant: "ghost",
197
201
  role: "option",
198
202
  "aria-selected": deal?.id === option.id,
203
+ title: option.label,
199
204
  onClick: () => {
200
205
  onDealChange(option);
201
206
  setOpen(false);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/customers/components/calendar/editor/RelatedToField.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Building2, ChevronDown, User, X } from 'lucide-react'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { IconButton } from '@open-mercato/ui/primitives/icon-button'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport type { EditorRelatedTo } from '../../../lib/calendar/editorPayload'\nimport { composeAccessibleName } from '../../../lib/calendar/labels'\nimport {\n fetchDealsForEntity,\n searchRelatedEntities,\n type DealOption,\n type RelatedEntityOption,\n} from './lookups'\nimport { CONTROL_BORDER, DROPDOWN_PANEL_CLASS, PersonChip, UppercaseBadge } from './inputs'\n\nconst OPTION_ROW_CLASS =\n 'h-auto w-full justify-start gap-2 whitespace-normal px-2 py-1.5 text-left text-sm font-normal text-foreground'\n\nexport function RelatedToField({\n label,\n value,\n deal,\n onChange,\n onDealChange,\n error,\n}: {\n label: string\n value: EditorRelatedTo | null\n deal: DealOption | null\n onChange(next: EditorRelatedTo | null): void\n onDealChange(next: DealOption | null): void\n error?: string | null\n}) {\n const t = useT()\n const [open, setOpen] = React.useState(false)\n const [query, setQuery] = React.useState('')\n const [options, setOptions] = React.useState<RelatedEntityOption[]>([])\n const [deals, setDeals] = React.useState<DealOption[]>([])\n const [loading, setLoading] = React.useState(false)\n\n React.useEffect(() => {\n if (!open) return\n const controller = new AbortController()\n let cancelled = false\n const timer = window.setTimeout(async () => {\n setLoading(true)\n try {\n const trimmed = query.trim()\n const [people, companies] = await Promise.all([\n searchRelatedEntities('person', trimmed, controller.signal),\n searchRelatedEntities('company', trimmed, controller.signal),\n ])\n if (cancelled) return\n setOptions([...people, ...companies])\n } catch {\n if (!cancelled) setOptions([])\n } finally {\n if (!cancelled) setLoading(false)\n }\n }, 200)\n return () => {\n cancelled = true\n controller.abort()\n window.clearTimeout(timer)\n }\n }, [open, query])\n\n React.useEffect(() => {\n if (!open || !value || value.kind === 'unknown') {\n setDeals([])\n return\n }\n const controller = new AbortController()\n let cancelled = false\n fetchDealsForEntity({ id: value.id, kind: value.kind }, controller.signal)\n .then((items) => { if (!cancelled) setDeals(items) })\n .catch(() => { if (!cancelled) setDeals([]) })\n return () => {\n cancelled = true\n controller.abort()\n }\n }, [open, value])\n\n const kindLabel = (kind: RelatedEntityOption['kind']) =>\n kind === 'person'\n ? t('customers.deals.detail.tabs.peopleSingular', 'Person')\n : t('customers.deals.detail.tabs.companySingular', 'Company')\n\n return (\n <div\n className=\"relative w-full\"\n onBlur={(event) => {\n if (!event.currentTarget.contains(event.relatedTarget as Node | null)) setOpen(false)\n }}\n >\n <div\n className={cn(\n 'flex h-10 w-full items-center rounded-md bg-background pl-2.5 pr-3',\n error ? 'border border-status-error-border' : CONTROL_BORDER,\n )}\n >\n <Button\n type=\"button\"\n variant=\"ghost\"\n aria-haspopup=\"listbox\"\n aria-expanded={open}\n aria-label={label}\n onClick={() => setOpen((previous) => !previous)}\n className=\"h-full min-w-0 flex-1 justify-between rounded-none bg-transparent p-0 text-left shadow-none hover:bg-transparent\"\n >\n <span className=\"flex min-w-0 items-center gap-2\">\n {value ? (\n <PersonChip\n compact\n name={value.label || value.id}\n />\n ) : (\n <span className=\"truncate text-sm text-muted-foreground\">\n {t('customers.calendar.editor.relatedToPlaceholder', 'Search people or companies\u2026')}\n </span>\n )}\n </span>\n <span className=\"flex shrink-0 items-center\">\n {deal ? (\n <UppercaseBadge className=\"h-7 bg-status-info-bg text-status-info-text\">\n {t('customers.calendar.editor.dealBadge', '{name} \u00B7 Deal', { name: deal.label })}\n </UppercaseBadge>\n ) : null}\n <span aria-hidden className=\"h-px w-2\" />\n <ChevronDown aria-hidden className=\"size-4 opacity-60\" />\n </span>\n </Button>\n {value ? (\n <IconButton\n variant=\"ghost\"\n size=\"xs\"\n onClick={() => {\n onChange(null)\n onDealChange(null)\n }}\n aria-label={t('customers.calendar.editor.removeRelated', 'Clear related record')}\n className=\"ms-1 shrink-0 text-muted-foreground\"\n >\n <X aria-hidden className=\"size-3.5\" />\n </IconButton>\n ) : null}\n </div>\n {open ? (\n <div role=\"listbox\" aria-label={label} className={DROPDOWN_PANEL_CLASS}>\n <Input\n type=\"text\"\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n placeholder={t('customers.calendar.editor.relatedToPlaceholder', 'Search people or companies\u2026')}\n aria-label={t('customers.calendar.editor.relatedToPlaceholder', 'Search people or companies\u2026')}\n autoFocus\n size=\"sm\"\n className=\"mb-1\"\n />\n {loading ? (\n <p className=\"px-2 py-3 text-center text-xs text-muted-foreground\">\n {t('customers.calendar.editor.searching', 'Searching\u2026')}\n </p>\n ) : null}\n {!loading && options.length === 0 ? (\n <p className=\"px-2 py-3 text-center text-xs text-muted-foreground\">\n {t('customers.calendar.editor.noResults', 'No results')}\n </p>\n ) : null}\n {!loading\n ? options.map((option) => (\n <Button\n key={`${option.kind}:${option.id}`}\n type=\"button\"\n variant=\"ghost\"\n role=\"option\"\n aria-selected={value?.id === option.id}\n aria-label={composeAccessibleName([option.label, option.subtitle, kindLabel(option.kind)])}\n onClick={() => {\n onChange({ id: option.id, kind: option.kind, label: option.label })\n if (value?.id !== option.id) onDealChange(null)\n setQuery('')\n }}\n className={OPTION_ROW_CLASS}\n >\n {option.kind === 'company'\n ? <Building2 aria-hidden className=\"size-3.5 shrink-0 text-muted-foreground\" />\n : <User aria-hidden className=\"size-3.5 shrink-0 text-muted-foreground\" />}\n <span className=\"min-w-0 flex-1 truncate\">\n {option.label}\n {option.subtitle ? <span className=\"ml-1.5 text-xs text-muted-foreground\">{option.subtitle}</span> : null}\n </span>\n <span className=\"shrink-0 text-xs text-muted-foreground\">{kindLabel(option.kind)}</span>\n </Button>\n ))\n : null}\n {value && deals.length > 0 ? (\n <>\n <p className=\"px-2 pb-1 pt-2 text-overline font-medium uppercase text-muted-foreground\">\n {t('customers.calendar.editor.dealsSection', 'Deals')}\n </p>\n <Button\n type=\"button\"\n variant=\"ghost\"\n role=\"option\"\n aria-selected={deal === null}\n onClick={() => {\n onDealChange(null)\n setOpen(false)\n }}\n className={OPTION_ROW_CLASS}\n >\n {t('customers.calendar.editor.dealNone', 'No deal')}\n </Button>\n {deals.map((option) => (\n <Button\n key={option.id}\n type=\"button\"\n variant=\"ghost\"\n role=\"option\"\n aria-selected={deal?.id === option.id}\n onClick={() => {\n onDealChange(option)\n setOpen(false)\n }}\n className={OPTION_ROW_CLASS}\n >\n <span className=\"min-w-0 flex-1 truncate\">{option.label}</span>\n <UppercaseBadge className=\"bg-status-info-bg text-status-info-text\">\n {t('customers.calendar.editor.dealBadgeSuffix', 'Deal')}\n </UppercaseBadge>\n </Button>\n ))}\n </>\n ) : null}\n </div>\n ) : null}\n </div>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Building2, ChevronDown, User, X } from 'lucide-react'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { IconButton } from '@open-mercato/ui/primitives/icon-button'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport type { EditorRelatedTo } from '../../../lib/calendar/editorPayload'\nimport { composeAccessibleName } from '../../../lib/calendar/labels'\nimport {\n fetchDealsForEntity,\n searchRelatedEntities,\n type DealOption,\n type RelatedEntityOption,\n} from './lookups'\nimport { CONTROL_BORDER, DROPDOWN_PANEL_CLASS, PersonChip, UppercaseBadge, useDropdownDismiss } from './inputs'\n\nconst OPTION_ROW_CLASS =\n 'h-auto w-full justify-start gap-2 whitespace-normal px-2 py-1.5 text-left text-sm font-normal text-foreground'\n\nexport function RelatedToField({\n label,\n value,\n deal,\n onChange,\n onDealChange,\n error,\n}: {\n label: string\n value: EditorRelatedTo | null\n deal: DealOption | null\n onChange(next: EditorRelatedTo | null): void\n onDealChange(next: DealOption | null): void\n error?: string | null\n}) {\n const t = useT()\n const [open, setOpen] = React.useState(false)\n const closeDropdown = React.useCallback(() => setOpen(false), [])\n const rootRef = useDropdownDismiss(open, closeDropdown)\n const [query, setQuery] = React.useState('')\n const [options, setOptions] = React.useState<RelatedEntityOption[]>([])\n const [deals, setDeals] = React.useState<DealOption[]>([])\n const [loading, setLoading] = React.useState(false)\n\n React.useEffect(() => {\n if (!open) return\n const controller = new AbortController()\n let cancelled = false\n const timer = window.setTimeout(async () => {\n setLoading(true)\n try {\n const trimmed = query.trim()\n const [people, companies] = await Promise.all([\n searchRelatedEntities('person', trimmed, controller.signal),\n searchRelatedEntities('company', trimmed, controller.signal),\n ])\n if (cancelled) return\n setOptions([...people, ...companies])\n } catch {\n if (!cancelled) setOptions([])\n } finally {\n if (!cancelled) setLoading(false)\n }\n }, 200)\n return () => {\n cancelled = true\n controller.abort()\n window.clearTimeout(timer)\n }\n }, [open, query])\n\n React.useEffect(() => {\n if (!open || !value || value.kind === 'unknown') {\n setDeals([])\n return\n }\n const controller = new AbortController()\n let cancelled = false\n fetchDealsForEntity({ id: value.id, kind: value.kind }, controller.signal)\n .then((items) => { if (!cancelled) setDeals(items) })\n .catch(() => { if (!cancelled) setDeals([]) })\n return () => {\n cancelled = true\n controller.abort()\n }\n }, [open, value])\n\n const kindLabel = (kind: RelatedEntityOption['kind']) =>\n kind === 'person'\n ? t('customers.deals.detail.tabs.peopleSingular', 'Person')\n : t('customers.deals.detail.tabs.companySingular', 'Company')\n\n return (\n <div\n ref={rootRef}\n className=\"relative w-full\"\n onBlur={(event) => {\n if (!event.currentTarget.contains(event.relatedTarget as Node | null)) setOpen(false)\n }}\n >\n <div\n className={cn(\n 'flex h-10 w-full items-center rounded-md bg-background pl-2.5 pr-3 transition-colors hover:bg-accent/50',\n error ? 'border border-status-error-border' : CONTROL_BORDER,\n )}\n >\n <Button\n type=\"button\"\n variant=\"ghost\"\n aria-haspopup=\"listbox\"\n aria-expanded={open}\n aria-label={label}\n onClick={() => setOpen((previous) => !previous)}\n className=\"h-full min-w-0 flex-1 justify-between rounded-none bg-transparent p-0 text-left shadow-none hover:bg-transparent dark:hover:bg-transparent\"\n >\n <span className=\"flex min-w-0 items-center gap-2\">\n {value ? (\n <PersonChip\n compact\n name={value.label || value.id}\n />\n ) : (\n <span className=\"truncate text-sm text-muted-foreground\">\n {t('customers.calendar.editor.relatedToPlaceholder', 'Search people or companies\u2026')}\n </span>\n )}\n </span>\n <span className=\"flex shrink-0 items-center\">\n {deal ? (\n <UppercaseBadge className=\"h-7 bg-status-info-bg text-status-info-text\">\n {t('customers.calendar.editor.dealBadge', '{name} \u00B7 Deal', { name: deal.label })}\n </UppercaseBadge>\n ) : null}\n <span aria-hidden className=\"h-px w-2\" />\n <ChevronDown aria-hidden className=\"size-4 opacity-60\" />\n </span>\n </Button>\n {value ? (\n <IconButton\n variant=\"ghost\"\n size=\"xs\"\n onClick={() => {\n onChange(null)\n onDealChange(null)\n }}\n aria-label={t('customers.calendar.editor.removeRelated', 'Clear related record')}\n className=\"ms-1 shrink-0 text-muted-foreground\"\n >\n <X aria-hidden className=\"size-3.5\" />\n </IconButton>\n ) : null}\n </div>\n {open ? (\n <div role=\"listbox\" aria-label={label} className={DROPDOWN_PANEL_CLASS}>\n <Input\n type=\"text\"\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n placeholder={t('customers.calendar.editor.relatedToPlaceholder', 'Search people or companies\u2026')}\n aria-label={t('customers.calendar.editor.relatedToPlaceholder', 'Search people or companies\u2026')}\n autoFocus\n size=\"sm\"\n className=\"mb-1\"\n />\n {loading ? (\n <p className=\"px-2 py-3 text-center text-xs text-muted-foreground\">\n {t('customers.calendar.editor.searching', 'Searching\u2026')}\n </p>\n ) : null}\n {!loading && options.length === 0 ? (\n <p className=\"px-2 py-3 text-center text-xs text-muted-foreground\">\n {t('customers.calendar.editor.noResults', 'No results')}\n </p>\n ) : null}\n {!loading\n ? options.map((option) => (\n <Button\n key={`${option.kind}:${option.id}`}\n type=\"button\"\n variant=\"ghost\"\n role=\"option\"\n aria-selected={value?.id === option.id}\n aria-label={composeAccessibleName([option.label, option.subtitle, kindLabel(option.kind)])}\n title={composeAccessibleName([option.label, option.subtitle])}\n onClick={() => {\n onChange({ id: option.id, kind: option.kind, label: option.label })\n if (value?.id !== option.id) onDealChange(null)\n setQuery('')\n }}\n className={OPTION_ROW_CLASS}\n >\n {option.kind === 'company'\n ? <Building2 aria-hidden className=\"size-3.5 shrink-0 text-muted-foreground\" />\n : <User aria-hidden className=\"size-3.5 shrink-0 text-muted-foreground\" />}\n <span className=\"min-w-0 flex-1 truncate\">\n {option.label}\n {option.subtitle ? <span className=\"ml-1.5 text-xs text-muted-foreground\">{option.subtitle}</span> : null}\n </span>\n <span className=\"shrink-0 text-xs text-muted-foreground\">{kindLabel(option.kind)}</span>\n </Button>\n ))\n : null}\n {value && deals.length > 0 ? (\n <>\n <p className=\"px-2 pb-1 pt-2 text-overline font-medium uppercase text-muted-foreground\">\n {t('customers.calendar.editor.dealsSection', 'Deals')}\n </p>\n <Button\n type=\"button\"\n variant=\"ghost\"\n role=\"option\"\n aria-selected={deal === null}\n onClick={() => {\n onDealChange(null)\n setOpen(false)\n }}\n className={OPTION_ROW_CLASS}\n >\n {t('customers.calendar.editor.dealNone', 'No deal')}\n </Button>\n {deals.map((option) => (\n <Button\n key={option.id}\n type=\"button\"\n variant=\"ghost\"\n role=\"option\"\n aria-selected={deal?.id === option.id}\n title={option.label}\n onClick={() => {\n onDealChange(option)\n setOpen(false)\n }}\n className={OPTION_ROW_CLASS}\n >\n <span className=\"min-w-0 flex-1 truncate\">{option.label}</span>\n <UppercaseBadge className=\"bg-status-info-bg text-status-info-text\">\n {t('customers.calendar.editor.dealBadgeSuffix', 'Deal')}\n </UppercaseBadge>\n </Button>\n ))}\n </>\n ) : null}\n </div>\n ) : null}\n </div>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }