@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.
- package/.turbo/turbo-build.log +1 -1
- package/dist/modules/customers/backend/calendar/page.js +9 -1
- package/dist/modules/customers/backend/calendar/page.js.map +2 -2
- package/dist/modules/customers/components/calendar/AgendaList.js +0 -11
- package/dist/modules/customers/components/calendar/AgendaList.js.map +2 -2
- package/dist/modules/customers/components/calendar/CalendarEventEditor.js +391 -235
- package/dist/modules/customers/components/calendar/CalendarEventEditor.js.map +2 -2
- package/dist/modules/customers/components/calendar/CalendarScreen.js +5 -5
- package/dist/modules/customers/components/calendar/CalendarScreen.js.map +2 -2
- package/dist/modules/customers/components/calendar/CalendarSettingsModal.js +2 -2
- package/dist/modules/customers/components/calendar/CalendarSettingsModal.js.map +2 -2
- package/dist/modules/customers/components/calendar/MonthGrid.js +1 -11
- package/dist/modules/customers/components/calendar/MonthGrid.js.map +2 -2
- package/dist/modules/customers/components/calendar/TimeGrid.js +162 -176
- package/dist/modules/customers/components/calendar/TimeGrid.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/LocationField.js +61 -14
- package/dist/modules/customers/components/calendar/editor/LocationField.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/PeopleField.js +10 -5
- package/dist/modules/customers/components/calendar/editor/PeopleField.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/PriorityField.js +85 -0
- package/dist/modules/customers/components/calendar/editor/PriorityField.js.map +7 -0
- package/dist/modules/customers/components/calendar/editor/RelatedToField.js +8 -3
- package/dist/modules/customers/components/calendar/editor/RelatedToField.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/ResourcesField.js +225 -0
- package/dist/modules/customers/components/calendar/editor/ResourcesField.js.map +7 -0
- package/dist/modules/customers/components/calendar/editor/SegmentGroup.js +12 -7
- package/dist/modules/customers/components/calendar/editor/SegmentGroup.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/inputs.js +68 -57
- package/dist/modules/customers/components/calendar/editor/inputs.js.map +2 -2
- package/dist/modules/customers/components/calendar/editor/lookups.js +82 -2
- package/dist/modules/customers/components/calendar/editor/lookups.js.map +2 -2
- package/dist/modules/customers/components/calendar/useCalendarItems.js +6 -1
- package/dist/modules/customers/components/calendar/useCalendarItems.js.map +2 -2
- package/dist/modules/customers/data/validators.js +3 -1
- package/dist/modules/customers/data/validators.js.map +2 -2
- package/dist/modules/customers/lib/calendar/editorPayload.js +53 -22
- package/dist/modules/customers/lib/calendar/editorPayload.js.map +2 -2
- package/dist/modules/entities/backend/entities/user/[entityId]/page.js +1 -1
- package/dist/modules/entities/backend/entities/user/[entityId]/page.js.map +2 -2
- package/package.json +7 -7
- package/src/modules/customers/backend/calendar/page.tsx +8 -1
- package/src/modules/customers/components/calendar/AgendaList.tsx +0 -10
- package/src/modules/customers/components/calendar/CalendarEventEditor.tsx +444 -261
- package/src/modules/customers/components/calendar/CalendarScreen.tsx +12 -5
- package/src/modules/customers/components/calendar/CalendarSettingsModal.tsx +6 -6
- package/src/modules/customers/components/calendar/MonthGrid.tsx +0 -11
- package/src/modules/customers/components/calendar/TimeGrid.tsx +1 -24
- package/src/modules/customers/components/calendar/editor/LocationField.tsx +64 -2
- package/src/modules/customers/components/calendar/editor/PeopleField.tsx +11 -4
- package/src/modules/customers/components/calendar/editor/PriorityField.tsx +90 -0
- package/src/modules/customers/components/calendar/editor/RelatedToField.tsx +8 -3
- package/src/modules/customers/components/calendar/editor/ResourcesField.tsx +264 -0
- package/src/modules/customers/components/calendar/editor/SegmentGroup.tsx +14 -6
- package/src/modules/customers/components/calendar/editor/inputs.tsx +91 -50
- package/src/modules/customers/components/calendar/editor/lookups.ts +115 -2
- package/src/modules/customers/components/calendar/useCalendarItems.ts +8 -1
- package/src/modules/customers/data/validators.ts +3 -1
- package/src/modules/customers/i18n/de.json +12 -2
- package/src/modules/customers/i18n/en.json +12 -2
- package/src/modules/customers/i18n/es.json +12 -2
- package/src/modules/customers/i18n/pl.json +12 -2
- package/src/modules/customers/lib/calendar/editorPayload.ts +94 -37
- package/src/modules/entities/backend/entities/user/[entityId]/page.tsx +1 -1
- package/src/modules/entities/i18n/de.json +120 -0
- package/src/modules/entities/i18n/en.json +120 -0
- package/src/modules/entities/i18n/es.json +120 -0
- package/src/modules/entities/i18n/pl.json +120 -0
- package/dist/modules/customers/components/calendar/editor/CategoryField.js +0 -75
- package/dist/modules/customers/components/calendar/editor/CategoryField.js.map +0 -7
- package/src/modules/customers/components/calendar/editor/CategoryField.tsx +0 -79
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { Box, Check, ChevronDown, Plus } from "lucide-react";
|
|
5
|
+
import { cn } from "@open-mercato/shared/lib/utils";
|
|
6
|
+
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
7
|
+
import { Button } from "@open-mercato/ui/primitives/button";
|
|
8
|
+
import { IconButton } from "@open-mercato/ui/primitives/icon-button";
|
|
9
|
+
import { Input } from "@open-mercato/ui/primitives/input";
|
|
10
|
+
import { fetchResourceTypes, searchResourceOptions } from "./lookups.js";
|
|
11
|
+
import { CONTROL_BORDER, DROPDOWN_PANEL_CLASS, useDropdownDismiss } from "./inputs.js";
|
|
12
|
+
const TYPE_SEARCH_THRESHOLD = 8;
|
|
13
|
+
function ResourcesField({
|
|
14
|
+
placeholder,
|
|
15
|
+
ariaLabel,
|
|
16
|
+
value,
|
|
17
|
+
onChange
|
|
18
|
+
}) {
|
|
19
|
+
const t = useT();
|
|
20
|
+
const [query, setQuery] = React.useState("");
|
|
21
|
+
const [open, setOpen] = React.useState(false);
|
|
22
|
+
const [options, setOptions] = React.useState([]);
|
|
23
|
+
const [total, setTotal] = React.useState(0);
|
|
24
|
+
const [loading, setLoading] = React.useState(false);
|
|
25
|
+
const [types, setTypes] = React.useState([]);
|
|
26
|
+
const [typeFilter, setTypeFilter] = React.useState(null);
|
|
27
|
+
const [typeMenuOpen, setTypeMenuOpen] = React.useState(false);
|
|
28
|
+
const [typeQuery, setTypeQuery] = React.useState("");
|
|
29
|
+
const close = React.useCallback(() => {
|
|
30
|
+
setOpen(false);
|
|
31
|
+
setTypeMenuOpen(false);
|
|
32
|
+
}, []);
|
|
33
|
+
const rootRef = useDropdownDismiss(open, close);
|
|
34
|
+
React.useEffect(() => {
|
|
35
|
+
if (!open || types.length > 0) return;
|
|
36
|
+
const controller = new AbortController();
|
|
37
|
+
let cancelled = false;
|
|
38
|
+
fetchResourceTypes(controller.signal).then((found) => {
|
|
39
|
+
if (!cancelled) setTypes(found);
|
|
40
|
+
});
|
|
41
|
+
return () => {
|
|
42
|
+
cancelled = true;
|
|
43
|
+
controller.abort();
|
|
44
|
+
};
|
|
45
|
+
}, [open, types.length]);
|
|
46
|
+
React.useEffect(() => {
|
|
47
|
+
if (!open) return;
|
|
48
|
+
const controller = new AbortController();
|
|
49
|
+
let cancelled = false;
|
|
50
|
+
const timer = window.setTimeout(async () => {
|
|
51
|
+
setLoading(true);
|
|
52
|
+
try {
|
|
53
|
+
const result = await searchResourceOptions({ query: query.trim(), resourceTypeId: typeFilter }, controller.signal);
|
|
54
|
+
if (cancelled) return;
|
|
55
|
+
setOptions(result.items);
|
|
56
|
+
setTotal(result.total);
|
|
57
|
+
} catch {
|
|
58
|
+
if (!cancelled) {
|
|
59
|
+
setOptions([]);
|
|
60
|
+
setTotal(0);
|
|
61
|
+
}
|
|
62
|
+
} finally {
|
|
63
|
+
if (!cancelled) setLoading(false);
|
|
64
|
+
}
|
|
65
|
+
}, 250);
|
|
66
|
+
return () => {
|
|
67
|
+
cancelled = true;
|
|
68
|
+
controller.abort();
|
|
69
|
+
window.clearTimeout(timer);
|
|
70
|
+
};
|
|
71
|
+
}, [open, query, typeFilter]);
|
|
72
|
+
const selectedIds = new Set(value.map((resource) => resource.id));
|
|
73
|
+
const visibleOptions = options.filter((option) => !selectedIds.has(option.id));
|
|
74
|
+
const hiddenCount = Math.max(0, total - options.length);
|
|
75
|
+
const activeType = typeFilter ? types.find((type) => type.id === typeFilter) ?? null : null;
|
|
76
|
+
const filteredTypes = typeQuery.trim().length ? types.filter((type) => type.name.toLowerCase().includes(typeQuery.trim().toLowerCase())) : types;
|
|
77
|
+
const selectType = (id) => {
|
|
78
|
+
setTypeFilter(id);
|
|
79
|
+
setTypeMenuOpen(false);
|
|
80
|
+
setTypeQuery("");
|
|
81
|
+
};
|
|
82
|
+
return /* @__PURE__ */ jsxs(
|
|
83
|
+
"div",
|
|
84
|
+
{
|
|
85
|
+
ref: rootRef,
|
|
86
|
+
className: "relative w-full",
|
|
87
|
+
onBlur: (event) => {
|
|
88
|
+
if (!event.currentTarget.contains(event.relatedTarget)) close();
|
|
89
|
+
},
|
|
90
|
+
children: [
|
|
91
|
+
/* @__PURE__ */ jsxs(
|
|
92
|
+
"div",
|
|
93
|
+
{
|
|
94
|
+
className: cn(
|
|
95
|
+
"flex min-h-14 w-full flex-wrap content-center items-center gap-2 rounded-md bg-background px-2.5 py-2",
|
|
96
|
+
CONTROL_BORDER
|
|
97
|
+
),
|
|
98
|
+
children: [
|
|
99
|
+
value.map((resource) => /* @__PURE__ */ jsxs("span", { className: "inline-flex shrink-0 items-center gap-1.5 rounded-full bg-muted py-1 pl-2 pr-2", children: [
|
|
100
|
+
/* @__PURE__ */ jsx(Box, { "aria-hidden": true, className: "size-3.5 text-muted-foreground" }),
|
|
101
|
+
/* @__PURE__ */ jsx("span", { className: "max-w-40 truncate text-xs font-medium text-foreground", children: resource.label }),
|
|
102
|
+
/* @__PURE__ */ jsx(
|
|
103
|
+
IconButton,
|
|
104
|
+
{
|
|
105
|
+
variant: "ghost",
|
|
106
|
+
size: "xs",
|
|
107
|
+
onClick: (event) => {
|
|
108
|
+
event.stopPropagation();
|
|
109
|
+
onChange(value.filter((entry) => entry.id !== resource.id));
|
|
110
|
+
},
|
|
111
|
+
"aria-label": t("customers.calendar.editor.removeResource", "Remove {name}", { name: resource.label }),
|
|
112
|
+
className: "size-5 shrink-0",
|
|
113
|
+
children: /* @__PURE__ */ jsx(Plus, { "aria-hidden": true, className: "size-3.5 rotate-45 opacity-50" })
|
|
114
|
+
}
|
|
115
|
+
)
|
|
116
|
+
] }, resource.id)),
|
|
117
|
+
/* @__PURE__ */ jsx(
|
|
118
|
+
Input,
|
|
119
|
+
{
|
|
120
|
+
type: "text",
|
|
121
|
+
value: query,
|
|
122
|
+
onChange: (event) => setQuery(event.target.value),
|
|
123
|
+
onFocus: () => setOpen(true),
|
|
124
|
+
placeholder: value.length > 0 ? "" : placeholder,
|
|
125
|
+
"aria-label": ariaLabel,
|
|
126
|
+
role: "combobox",
|
|
127
|
+
"aria-expanded": open,
|
|
128
|
+
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",
|
|
129
|
+
inputClassName: "text-sm text-foreground placeholder:text-muted-foreground"
|
|
130
|
+
}
|
|
131
|
+
)
|
|
132
|
+
]
|
|
133
|
+
}
|
|
134
|
+
),
|
|
135
|
+
open ? /* @__PURE__ */ jsxs("div", { className: cn(DROPDOWN_PANEL_CLASS, "flex max-h-none flex-col overflow-visible p-0"), children: [
|
|
136
|
+
types.length > 0 ? /* @__PURE__ */ jsx("div", { className: "border-b border-border p-1.5", children: /* @__PURE__ */ jsxs(
|
|
137
|
+
Button,
|
|
138
|
+
{
|
|
139
|
+
type: "button",
|
|
140
|
+
variant: "outline",
|
|
141
|
+
"aria-haspopup": "listbox",
|
|
142
|
+
"aria-expanded": typeMenuOpen,
|
|
143
|
+
onClick: () => setTypeMenuOpen((previous) => !previous),
|
|
144
|
+
className: cn("h-8 w-full justify-between bg-background px-2 text-sm font-normal shadow-none", CONTROL_BORDER),
|
|
145
|
+
children: [
|
|
146
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: activeType ? `${activeType.name} (${activeType.count})` : t("customers.calendar.editor.resourceTypes.all", "All types") }),
|
|
147
|
+
/* @__PURE__ */ jsx(ChevronDown, { "aria-hidden": true, className: "size-4 shrink-0 opacity-60" })
|
|
148
|
+
]
|
|
149
|
+
}
|
|
150
|
+
) }) : null,
|
|
151
|
+
typeMenuOpen ? /* @__PURE__ */ jsxs("div", { role: "listbox", "aria-label": t("customers.calendar.editor.resourceTypes.filterLabel", "Resource type"), className: "flex flex-col", children: [
|
|
152
|
+
types.length > TYPE_SEARCH_THRESHOLD ? /* @__PURE__ */ jsx("div", { className: "border-b border-border p-1.5", children: /* @__PURE__ */ jsx(
|
|
153
|
+
Input,
|
|
154
|
+
{
|
|
155
|
+
type: "text",
|
|
156
|
+
value: typeQuery,
|
|
157
|
+
onChange: (event) => setTypeQuery(event.target.value),
|
|
158
|
+
placeholder: t("customers.calendar.editor.resourceTypes.searchPlaceholder", "Search types\u2026"),
|
|
159
|
+
"aria-label": t("customers.calendar.editor.resourceTypes.searchPlaceholder", "Search types\u2026"),
|
|
160
|
+
autoFocus: true,
|
|
161
|
+
className: "h-8"
|
|
162
|
+
}
|
|
163
|
+
) }) : null,
|
|
164
|
+
/* @__PURE__ */ jsxs("div", { className: "max-h-56 overflow-y-auto p-1", children: [
|
|
165
|
+
/* @__PURE__ */ jsx(TypeRow, { label: t("customers.calendar.editor.resourceTypes.all", "All types"), active: typeFilter === null, onSelect: () => selectType(null) }),
|
|
166
|
+
filteredTypes.map((type) => /* @__PURE__ */ jsx(TypeRow, { label: type.name, count: type.count, active: typeFilter === type.id, onSelect: () => selectType(type.id) }, type.id)),
|
|
167
|
+
filteredTypes.length === 0 ? /* @__PURE__ */ jsx("p", { className: "px-2 py-3 text-center text-xs text-muted-foreground", children: t("customers.calendar.editor.noResults", "No results") }) : null
|
|
168
|
+
] })
|
|
169
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
170
|
+
/* @__PURE__ */ jsxs("div", { role: "listbox", "aria-label": ariaLabel, className: "max-h-56 overflow-y-auto p-1", children: [
|
|
171
|
+
loading ? /* @__PURE__ */ jsx("p", { className: "px-2 py-3 text-center text-xs text-muted-foreground", children: t("customers.calendar.editor.searching", "Searching\u2026") }) : null,
|
|
172
|
+
!loading && visibleOptions.length === 0 ? /* @__PURE__ */ jsx("p", { className: "px-2 py-3 text-center text-xs text-muted-foreground", children: t("customers.calendar.editor.noResults", "No results") }) : null,
|
|
173
|
+
!loading ? visibleOptions.map((option) => /* @__PURE__ */ jsxs(
|
|
174
|
+
Button,
|
|
175
|
+
{
|
|
176
|
+
type: "button",
|
|
177
|
+
variant: "ghost",
|
|
178
|
+
role: "option",
|
|
179
|
+
"aria-selected": false,
|
|
180
|
+
title: option.label,
|
|
181
|
+
onClick: () => {
|
|
182
|
+
onChange([...value, { id: option.id, label: option.label }]);
|
|
183
|
+
setQuery("");
|
|
184
|
+
},
|
|
185
|
+
className: "h-auto w-full justify-start gap-2 whitespace-normal px-2 py-1.5 text-left text-sm font-normal text-foreground",
|
|
186
|
+
children: [
|
|
187
|
+
/* @__PURE__ */ jsx(Box, { "aria-hidden": true, className: "size-4 text-muted-foreground" }),
|
|
188
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: option.label })
|
|
189
|
+
]
|
|
190
|
+
},
|
|
191
|
+
option.id
|
|
192
|
+
)) : null
|
|
193
|
+
] }),
|
|
194
|
+
!loading && hiddenCount > 0 ? /* @__PURE__ */ jsx("p", { className: "border-t border-border px-2 py-1.5 text-center text-xs text-muted-foreground", children: t("customers.calendar.editor.resourceTypes.moreHint", "Showing {shown} of {total} \u2014 keep typing to narrow", {
|
|
195
|
+
shown: options.length,
|
|
196
|
+
total
|
|
197
|
+
}) }) : null
|
|
198
|
+
] })
|
|
199
|
+
] }) : null
|
|
200
|
+
]
|
|
201
|
+
}
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
function TypeRow({ label, count, active, onSelect }) {
|
|
205
|
+
return /* @__PURE__ */ jsxs(
|
|
206
|
+
Button,
|
|
207
|
+
{
|
|
208
|
+
type: "button",
|
|
209
|
+
variant: "ghost",
|
|
210
|
+
role: "option",
|
|
211
|
+
"aria-selected": active,
|
|
212
|
+
onClick: onSelect,
|
|
213
|
+
className: cn("h-auto w-full justify-start gap-2 px-2 py-1.5 text-left text-sm font-normal", active ? "bg-muted text-foreground" : "text-foreground"),
|
|
214
|
+
children: [
|
|
215
|
+
/* @__PURE__ */ jsx(Check, { "aria-hidden": true, className: cn("size-4 shrink-0", active ? "opacity-100" : "opacity-0") }),
|
|
216
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: label }),
|
|
217
|
+
typeof count === "number" ? /* @__PURE__ */ jsx("span", { className: "shrink-0 tabular-nums text-xs text-muted-foreground", children: count }) : null
|
|
218
|
+
]
|
|
219
|
+
}
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
export {
|
|
223
|
+
ResourcesField
|
|
224
|
+
};
|
|
225
|
+
//# sourceMappingURL=ResourcesField.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/modules/customers/components/calendar/editor/ResourcesField.tsx"],
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Box, Check, ChevronDown, Plus } 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 { EditorResource } from '../../../lib/calendar/editorPayload'\nimport { fetchResourceTypes, searchResourceOptions, type ResourceOption, type ResourceType } from './lookups'\nimport { CONTROL_BORDER, DROPDOWN_PANEL_CLASS, useDropdownDismiss } from './inputs'\n\nconst TYPE_SEARCH_THRESHOLD = 8\n\n// Multi-select of bookable resources (rooms, cars, equipment) from the\n// resources module. Rendered only when that module is loaded \u2014 the calendar\n// consumes its public list API and stores FK-id + label snapshots in\n// `linkedEntities`, never resource entities (#3552). A potentially large\n// catalog (many resources AND many types) stays navigable with a collapsible\n// resource-type filter (searchable, with counts), server-side search and a\n// \"showing N of M\" hint.\nexport function ResourcesField({\n placeholder,\n ariaLabel,\n value,\n onChange,\n}: {\n placeholder: string\n ariaLabel: string\n value: EditorResource[]\n onChange(next: EditorResource[]): void\n}) {\n const t = useT()\n const [query, setQuery] = React.useState('')\n const [open, setOpen] = React.useState(false)\n const [options, setOptions] = React.useState<ResourceOption[]>([])\n const [total, setTotal] = React.useState(0)\n const [loading, setLoading] = React.useState(false)\n const [types, setTypes] = React.useState<ResourceType[]>([])\n const [typeFilter, setTypeFilter] = React.useState<string | null>(null)\n const [typeMenuOpen, setTypeMenuOpen] = React.useState(false)\n const [typeQuery, setTypeQuery] = React.useState('')\n const close = React.useCallback(() => {\n setOpen(false)\n setTypeMenuOpen(false)\n }, [])\n const rootRef = useDropdownDismiss(open, close)\n\n // Load the type filter once the dropdown first opens.\n React.useEffect(() => {\n if (!open || types.length > 0) return\n const controller = new AbortController()\n let cancelled = false\n fetchResourceTypes(controller.signal).then((found) => {\n if (!cancelled) setTypes(found)\n })\n return () => {\n cancelled = true\n controller.abort()\n }\n }, [open, types.length])\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 result = await searchResourceOptions({ query: query.trim(), resourceTypeId: typeFilter }, controller.signal)\n if (cancelled) return\n setOptions(result.items)\n setTotal(result.total)\n } catch {\n if (!cancelled) {\n setOptions([])\n setTotal(0)\n }\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, typeFilter])\n\n const selectedIds = new Set(value.map((resource) => resource.id))\n const visibleOptions = options.filter((option) => !selectedIds.has(option.id))\n const hiddenCount = Math.max(0, total - options.length)\n const activeType = typeFilter ? types.find((type) => type.id === typeFilter) ?? null : null\n const filteredTypes = typeQuery.trim().length\n ? types.filter((type) => type.name.toLowerCase().includes(typeQuery.trim().toLowerCase()))\n : types\n\n const selectType = (id: string | null) => {\n setTypeFilter(id)\n setTypeMenuOpen(false)\n setTypeQuery('')\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)) close()\n }}\n >\n <div\n className={cn(\n 'flex min-h-14 w-full flex-wrap content-center items-center gap-2 rounded-md bg-background px-2.5 py-2',\n CONTROL_BORDER,\n )}\n >\n {value.map((resource) => (\n <span key={resource.id} className=\"inline-flex shrink-0 items-center gap-1.5 rounded-full bg-muted py-1 pl-2 pr-2\">\n <Box aria-hidden className=\"size-3.5 text-muted-foreground\" />\n <span className=\"max-w-40 truncate text-xs font-medium text-foreground\">{resource.label}</span>\n <IconButton\n variant=\"ghost\"\n size=\"xs\"\n onClick={(event) => {\n event.stopPropagation()\n onChange(value.filter((entry) => entry.id !== resource.id))\n }}\n aria-label={t('customers.calendar.editor.removeResource', 'Remove {name}', { name: resource.label })}\n className=\"size-5 shrink-0\"\n >\n <Plus aria-hidden className=\"size-3.5 rotate-45 opacity-50\" />\n </IconButton>\n </span>\n ))}\n <Input\n type=\"text\"\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n onFocus={() => setOpen(true)}\n placeholder={value.length > 0 ? '' : 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 className={cn(DROPDOWN_PANEL_CLASS, 'flex max-h-none flex-col overflow-visible p-0')}>\n {types.length > 0 ? (\n <div className=\"border-b border-border p-1.5\">\n <Button\n type=\"button\"\n variant=\"outline\"\n aria-haspopup=\"listbox\"\n aria-expanded={typeMenuOpen}\n onClick={() => setTypeMenuOpen((previous) => !previous)}\n className={cn('h-8 w-full justify-between bg-background px-2 text-sm font-normal shadow-none', CONTROL_BORDER)}\n >\n <span className=\"truncate\">\n {activeType\n ? `${activeType.name} (${activeType.count})`\n : t('customers.calendar.editor.resourceTypes.all', 'All types')}\n </span>\n <ChevronDown aria-hidden className=\"size-4 shrink-0 opacity-60\" />\n </Button>\n </div>\n ) : null}\n\n {typeMenuOpen ? (\n <div role=\"listbox\" aria-label={t('customers.calendar.editor.resourceTypes.filterLabel', 'Resource type')} className=\"flex flex-col\">\n {types.length > TYPE_SEARCH_THRESHOLD ? (\n <div className=\"border-b border-border p-1.5\">\n <Input\n type=\"text\"\n value={typeQuery}\n onChange={(event) => setTypeQuery(event.target.value)}\n placeholder={t('customers.calendar.editor.resourceTypes.searchPlaceholder', 'Search types\u2026')}\n aria-label={t('customers.calendar.editor.resourceTypes.searchPlaceholder', 'Search types\u2026')}\n autoFocus\n className=\"h-8\"\n />\n </div>\n ) : null}\n <div className=\"max-h-56 overflow-y-auto p-1\">\n <TypeRow label={t('customers.calendar.editor.resourceTypes.all', 'All types')} active={typeFilter === null} onSelect={() => selectType(null)} />\n {filteredTypes.map((type) => (\n <TypeRow key={type.id} label={type.name} count={type.count} active={typeFilter === type.id} onSelect={() => selectType(type.id)} />\n ))}\n {filteredTypes.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 </div>\n </div>\n ) : (\n <>\n <div role=\"listbox\" aria-label={ariaLabel} className=\"max-h-56 overflow-y-auto p-1\">\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.id}\n type=\"button\"\n variant=\"ghost\"\n role=\"option\"\n aria-selected={false}\n title={option.label}\n onClick={() => {\n onChange([...value, { id: option.id, label: option.label }])\n setQuery('')\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 <Box aria-hidden className=\"size-4 text-muted-foreground\" />\n <span className=\"min-w-0 flex-1 truncate\">{option.label}</span>\n </Button>\n ))\n : null}\n </div>\n {!loading && hiddenCount > 0 ? (\n <p className=\"border-t border-border px-2 py-1.5 text-center text-xs text-muted-foreground\">\n {t('customers.calendar.editor.resourceTypes.moreHint', 'Showing {shown} of {total} \u2014 keep typing to narrow', {\n shown: options.length,\n total,\n })}\n </p>\n ) : null}\n </>\n )}\n </div>\n ) : null}\n </div>\n )\n}\n\nfunction TypeRow({ label, count, active, onSelect }: { label: string; count?: number; active: boolean; onSelect(): void }) {\n return (\n <Button\n type=\"button\"\n variant=\"ghost\"\n role=\"option\"\n aria-selected={active}\n onClick={onSelect}\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 text-foreground' : 'text-foreground')}\n >\n <Check aria-hidden className={cn('size-4 shrink-0', active ? 'opacity-100' : 'opacity-0')} />\n <span className=\"min-w-0 flex-1 truncate\">{label}</span>\n {typeof count === 'number' ? <span className=\"shrink-0 tabular-nums text-xs text-muted-foreground\">{count}</span> : null}\n </Button>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { cn } from "@open-mercato/shared/lib/utils";
|
|
4
4
|
import { Button } from "@open-mercato/ui/primitives/button";
|
|
5
5
|
function SegmentGroup({
|
|
@@ -14,23 +14,28 @@ function SegmentGroup({
|
|
|
14
14
|
{
|
|
15
15
|
role: "group",
|
|
16
16
|
"aria-label": ariaLabel,
|
|
17
|
-
className: "
|
|
17
|
+
className: "flex w-full items-stretch overflow-hidden rounded-md border border-border bg-background",
|
|
18
18
|
children: options.map((option, index) => {
|
|
19
19
|
const isActive = option.value === value;
|
|
20
|
-
return /* @__PURE__ */
|
|
20
|
+
return /* @__PURE__ */ jsxs(
|
|
21
21
|
Button,
|
|
22
22
|
{
|
|
23
23
|
type: "button",
|
|
24
24
|
variant: "ghost",
|
|
25
25
|
"aria-pressed": isActive,
|
|
26
26
|
onClick: () => onChange(option.value),
|
|
27
|
+
title: option.label,
|
|
28
|
+
"data-state": isActive ? "active" : "inactive",
|
|
27
29
|
className: cn(
|
|
28
|
-
"h-auto rounded-none border-0 text-sm font-medium leading-5 shadow-none",
|
|
29
|
-
size === "md" ? "
|
|
30
|
+
"h-auto min-w-0 flex-1 justify-center gap-1 rounded-none border-0 px-1.5 text-sm font-medium leading-5 shadow-none",
|
|
31
|
+
size === "md" ? "py-2" : "py-1.5",
|
|
30
32
|
index > 0 && "border-l border-border",
|
|
31
|
-
isActive ? "bg-
|
|
33
|
+
isActive ? "bg-accent-indigo font-semibold text-accent-indigo-foreground hover:bg-accent-indigo hover:text-accent-indigo-foreground dark:hover:bg-accent-indigo" : "bg-background text-muted-foreground hover:bg-muted hover:text-foreground"
|
|
32
34
|
),
|
|
33
|
-
children:
|
|
35
|
+
children: [
|
|
36
|
+
option.icon ? /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: cn("shrink-0", isActive ? "opacity-100" : "opacity-70"), children: option.icon }) : null,
|
|
37
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: option.label })
|
|
38
|
+
]
|
|
34
39
|
},
|
|
35
40
|
option.value
|
|
36
41
|
);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/customers/components/calendar/editor/SegmentGroup.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { Button } from '@open-mercato/ui/primitives/button'\n\nexport type SegmentOption<T extends string> = { value: T; label: string }\n\nexport function SegmentGroup<T extends string>({\n options,\n value,\n onChange,\n size = 'sm',\n ariaLabel,\n}: {\n options: Array<SegmentOption<T>>\n value: T\n onChange(next: T): void\n size?: 'sm' | 'md'\n ariaLabel: string\n}) {\n return (\n <div\n role=\"group\"\n aria-label={ariaLabel}\n className=\"
|
|
5
|
-
"mappings": ";AA8BU;AA3BV,SAAS,UAAU;AACnB,SAAS,cAAc;AAIhB,SAAS,aAA+B;AAAA,EAC7C;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP;AACF,GAMG;AACD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,cAAY;AAAA,MACZ,WAAU;AAAA,MAET,kBAAQ,IAAI,CAAC,QAAQ,UAAU;AAC9B,cAAM,WAAW,OAAO,UAAU;AAClC,eACE;AAAA,UAAC;AAAA;AAAA,YAEC,MAAK;AAAA,YACL,SAAQ;AAAA,YACR,gBAAc;AAAA,YACd,SAAS,MAAM,SAAS,OAAO,KAAK;AAAA,YACpC,WAAW;AAAA,cACT;AAAA,cACA,SAAS,OAAO,
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { Button } from '@open-mercato/ui/primitives/button'\n\nexport type SegmentOption<T extends string> = { value: T; label: string; icon?: React.ReactNode }\n\nexport function SegmentGroup<T extends string>({\n options,\n value,\n onChange,\n size = 'sm',\n ariaLabel,\n}: {\n options: Array<SegmentOption<T>>\n value: T\n onChange(next: T): void\n size?: 'sm' | 'md'\n ariaLabel: string\n}) {\n return (\n <div\n role=\"group\"\n aria-label={ariaLabel}\n className=\"flex w-full items-stretch overflow-hidden rounded-md border border-border bg-background\"\n >\n {options.map((option, index) => {\n const isActive = option.value === value\n return (\n <Button\n key={option.value}\n type=\"button\"\n variant=\"ghost\"\n aria-pressed={isActive}\n onClick={() => onChange(option.value)}\n title={option.label}\n data-state={isActive ? 'active' : 'inactive'}\n className={cn(\n 'h-auto min-w-0 flex-1 justify-center gap-1 rounded-none border-0 px-1.5 text-sm font-medium leading-5 shadow-none',\n size === 'md' ? 'py-2' : 'py-1.5',\n index > 0 && 'border-l border-border',\n isActive\n // Keep the indigo fill on hover in BOTH themes \u2014 the ghost Button\n // ships `dark:hover:bg-accent/50`, which would otherwise wash the\n // active segment out on hover in dark mode.\n ? 'bg-accent-indigo font-semibold text-accent-indigo-foreground hover:bg-accent-indigo hover:text-accent-indigo-foreground dark:hover:bg-accent-indigo'\n : 'bg-background text-muted-foreground hover:bg-muted hover:text-foreground',\n )}\n >\n {option.icon ? <span aria-hidden className={cn('shrink-0', isActive ? 'opacity-100' : 'opacity-70')}>{option.icon}</span> : null}\n <span className=\"truncate\">{option.label}</span>\n </Button>\n )\n })}\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": ";AA8BU,SAoBiB,KApBjB;AA3BV,SAAS,UAAU;AACnB,SAAS,cAAc;AAIhB,SAAS,aAA+B;AAAA,EAC7C;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP;AACF,GAMG;AACD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,cAAY;AAAA,MACZ,WAAU;AAAA,MAET,kBAAQ,IAAI,CAAC,QAAQ,UAAU;AAC9B,cAAM,WAAW,OAAO,UAAU;AAClC,eACE;AAAA,UAAC;AAAA;AAAA,YAEC,MAAK;AAAA,YACL,SAAQ;AAAA,YACR,gBAAc;AAAA,YACd,SAAS,MAAM,SAAS,OAAO,KAAK;AAAA,YACpC,OAAO,OAAO;AAAA,YACd,cAAY,WAAW,WAAW;AAAA,YAClC,WAAW;AAAA,cACT;AAAA,cACA,SAAS,OAAO,SAAS;AAAA,cACzB,QAAQ,KAAK;AAAA,cACb,WAII,wJACA;AAAA,YACN;AAAA,YAEC;AAAA,qBAAO,OAAO,oBAAC,UAAK,eAAW,MAAC,WAAW,GAAG,YAAY,WAAW,gBAAgB,YAAY,GAAI,iBAAO,MAAK,IAAU;AAAA,cAC5H,oBAAC,UAAK,WAAU,YAAY,iBAAO,OAAM;AAAA;AAAA;AAAA,UApBpC,OAAO;AAAA,QAqBd;AAAA,MAEJ,CAAC;AAAA;AAAA,EACH;AAEJ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,17 +1,41 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { Plus } from "lucide-react";
|
|
4
5
|
import { cn } from "@open-mercato/shared/lib/utils";
|
|
5
6
|
import { Avatar } from "@open-mercato/ui/primitives/avatar";
|
|
7
|
+
import { DatePicker } from "@open-mercato/ui/primitives/date-picker";
|
|
6
8
|
import { IconButton } from "@open-mercato/ui/primitives/icon-button";
|
|
7
|
-
import {
|
|
9
|
+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@open-mercato/ui/primitives/select";
|
|
8
10
|
import { Switch } from "@open-mercato/ui/primitives/switch";
|
|
9
11
|
const CONTROL_BORDER = "border border-input";
|
|
10
12
|
const CONTROL_TEXT = "text-sm text-foreground placeholder:text-muted-foreground";
|
|
11
13
|
const LABEL_CLASS = "text-xs font-medium text-muted-foreground";
|
|
12
14
|
const DROPDOWN_PANEL_CLASS = "absolute z-50 mt-1 max-h-56 w-full overflow-y-auto rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md";
|
|
13
|
-
function
|
|
14
|
-
|
|
15
|
+
function useDropdownDismiss(open, onClose) {
|
|
16
|
+
const rootRef = React.useRef(null);
|
|
17
|
+
React.useEffect(() => {
|
|
18
|
+
if (!open) return;
|
|
19
|
+
const handlePointerDown = (event) => {
|
|
20
|
+
if (rootRef.current && event.target instanceof Node && !rootRef.current.contains(event.target)) onClose();
|
|
21
|
+
};
|
|
22
|
+
const handleKeyDown = (event) => {
|
|
23
|
+
if (event.key === "Escape") {
|
|
24
|
+
event.stopPropagation();
|
|
25
|
+
onClose();
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
document.addEventListener("pointerdown", handlePointerDown, true);
|
|
29
|
+
document.addEventListener("keydown", handleKeyDown, true);
|
|
30
|
+
return () => {
|
|
31
|
+
document.removeEventListener("pointerdown", handlePointerDown, true);
|
|
32
|
+
document.removeEventListener("keydown", handleKeyDown, true);
|
|
33
|
+
};
|
|
34
|
+
}, [open, onClose]);
|
|
35
|
+
return rootRef;
|
|
36
|
+
}
|
|
37
|
+
function Field({ label, children, error, className }) {
|
|
38
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex w-full flex-col gap-1.5", className), children: [
|
|
15
39
|
/* @__PURE__ */ jsx("span", { className: LABEL_CLASS, children: label }),
|
|
16
40
|
children,
|
|
17
41
|
error ? /* @__PURE__ */ jsx("p", { className: "text-xs text-status-error-text", children: error }) : null
|
|
@@ -30,18 +54,6 @@ function UppercaseBadge({ style, className, children }) {
|
|
|
30
54
|
}
|
|
31
55
|
);
|
|
32
56
|
}
|
|
33
|
-
function categoryPillStyle(color) {
|
|
34
|
-
if (typeof color === "string" && /^#[0-9a-fA-F]{6}$/.test(color)) {
|
|
35
|
-
return { backgroundColor: `${color}59`, color: `color-mix(in srgb, ${color} 55%, black)` };
|
|
36
|
-
}
|
|
37
|
-
if (typeof color === "string" && color.length > 0) {
|
|
38
|
-
return {
|
|
39
|
-
backgroundColor: `color-mix(in srgb, ${color} 35%, white)`,
|
|
40
|
-
color: `color-mix(in srgb, ${color} 55%, black)`
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
return {};
|
|
44
|
-
}
|
|
45
57
|
function AllDayToggle({ checked, onCheckedChange, label }) {
|
|
46
58
|
return /* @__PURE__ */ jsx(
|
|
47
59
|
Switch,
|
|
@@ -53,61 +65,59 @@ function AllDayToggle({ checked, onCheckedChange, label }) {
|
|
|
53
65
|
}
|
|
54
66
|
);
|
|
55
67
|
}
|
|
56
|
-
function
|
|
68
|
+
function parseDateValue(value) {
|
|
69
|
+
if (!value) return null;
|
|
57
70
|
const parsed = /* @__PURE__ */ new Date(`${value}T00:00:00`);
|
|
58
|
-
|
|
59
|
-
|
|
71
|
+
return Number.isNaN(parsed.getTime()) ? null : parsed;
|
|
72
|
+
}
|
|
73
|
+
function formatDateValue(date) {
|
|
74
|
+
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
|
|
75
|
+
}
|
|
76
|
+
const EDITOR_SCROLL_EVENT = "om-calendar-editor-scroll";
|
|
77
|
+
function useCloseOnEditorScroll(setOpen) {
|
|
78
|
+
React.useEffect(() => {
|
|
79
|
+
const handler = () => setOpen(false);
|
|
80
|
+
document.addEventListener(EDITOR_SCROLL_EVENT, handler);
|
|
81
|
+
return () => document.removeEventListener(EDITOR_SCROLL_EVENT, handler);
|
|
82
|
+
}, [setOpen]);
|
|
60
83
|
}
|
|
61
84
|
function DateControl({
|
|
62
85
|
value,
|
|
63
86
|
onChange,
|
|
64
87
|
ariaLabel,
|
|
65
|
-
locale,
|
|
66
88
|
className
|
|
67
89
|
}) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
{
|
|
71
|
-
className: cn(
|
|
72
|
-
"relative flex h-9 w-full items-center justify-between rounded-md bg-background px-3",
|
|
73
|
-
CONTROL_BORDER,
|
|
74
|
-
className
|
|
75
|
-
),
|
|
76
|
-
children: [
|
|
77
|
-
/* @__PURE__ */ jsx("span", { className: "truncate text-sm text-foreground", children: formatDisplayDate(value, locale) }),
|
|
78
|
-
/* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "h-px w-2 shrink-0" }),
|
|
79
|
-
/* @__PURE__ */ jsx(ChevronDown, { "aria-hidden": true, className: "size-4 shrink-0 opacity-60" }),
|
|
80
|
-
/* @__PURE__ */ jsx(
|
|
81
|
-
Input,
|
|
82
|
-
{
|
|
83
|
-
type: "date",
|
|
84
|
-
value,
|
|
85
|
-
onChange: (event) => {
|
|
86
|
-
if (event.target.value) onChange(event.target.value);
|
|
87
|
-
},
|
|
88
|
-
"aria-label": ariaLabel,
|
|
89
|
-
className: "absolute inset-0 h-full w-full cursor-pointer border-0 bg-transparent p-0 opacity-0 shadow-none hover:bg-transparent",
|
|
90
|
-
inputClassName: "h-full cursor-pointer"
|
|
91
|
-
}
|
|
92
|
-
)
|
|
93
|
-
]
|
|
94
|
-
}
|
|
95
|
-
);
|
|
96
|
-
}
|
|
97
|
-
function TimeControl({ value, onChange, ariaLabel }) {
|
|
90
|
+
const [open, setOpen] = React.useState(false);
|
|
91
|
+
useCloseOnEditorScroll(setOpen);
|
|
98
92
|
return /* @__PURE__ */ jsx(
|
|
99
|
-
|
|
93
|
+
DatePicker,
|
|
100
94
|
{
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
if (event.target.value) onChange(event.target.value);
|
|
95
|
+
value: parseDateValue(value),
|
|
96
|
+
onChange: (date) => {
|
|
97
|
+
if (date) onChange(formatDateValue(date));
|
|
105
98
|
},
|
|
99
|
+
footer: "none",
|
|
100
|
+
open,
|
|
101
|
+
onOpenChange: setOpen,
|
|
106
102
|
"aria-label": ariaLabel,
|
|
107
|
-
className: "
|
|
103
|
+
className: cn("w-full", className)
|
|
108
104
|
}
|
|
109
105
|
);
|
|
110
106
|
}
|
|
107
|
+
const TIME_OPTIONS = Array.from({ length: 48 }, (_, index) => {
|
|
108
|
+
const hour = Math.floor(index / 2);
|
|
109
|
+
const minute = index % 2 === 0 ? "00" : "30";
|
|
110
|
+
return `${String(hour).padStart(2, "0")}:${minute}`;
|
|
111
|
+
});
|
|
112
|
+
function TimeControl({ value, onChange, ariaLabel }) {
|
|
113
|
+
const [open, setOpen] = React.useState(false);
|
|
114
|
+
useCloseOnEditorScroll(setOpen);
|
|
115
|
+
const options = value && !TIME_OPTIONS.includes(value) ? [value, ...TIME_OPTIONS] : TIME_OPTIONS;
|
|
116
|
+
return /* @__PURE__ */ jsxs(Select, { value, onValueChange: onChange, open, onOpenChange: setOpen, children: [
|
|
117
|
+
/* @__PURE__ */ jsx(SelectTrigger, { "aria-label": ariaLabel, className: "h-9 w-32 shrink-0", children: /* @__PURE__ */ jsx(SelectValue, {}) }),
|
|
118
|
+
/* @__PURE__ */ jsx(SelectContent, { className: "max-h-64", children: options.map((time) => /* @__PURE__ */ jsx(SelectItem, { value: time, children: time }, time)) })
|
|
119
|
+
] });
|
|
120
|
+
}
|
|
111
121
|
function PersonChip({
|
|
112
122
|
name,
|
|
113
123
|
badge,
|
|
@@ -150,11 +160,12 @@ export {
|
|
|
150
160
|
CONTROL_TEXT,
|
|
151
161
|
DROPDOWN_PANEL_CLASS,
|
|
152
162
|
DateControl,
|
|
163
|
+
EDITOR_SCROLL_EVENT,
|
|
153
164
|
Field,
|
|
154
165
|
LABEL_CLASS,
|
|
155
166
|
PersonChip,
|
|
156
167
|
TimeControl,
|
|
157
168
|
UppercaseBadge,
|
|
158
|
-
|
|
169
|
+
useDropdownDismiss
|
|
159
170
|
};
|
|
160
171
|
//# sourceMappingURL=inputs.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/customers/components/calendar/editor/inputs.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport {
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Plus } from 'lucide-react'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { Avatar } from '@open-mercato/ui/primitives/avatar'\nimport { DatePicker } from '@open-mercato/ui/primitives/date-picker'\nimport { IconButton } from '@open-mercato/ui/primitives/icon-button'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@open-mercato/ui/primitives/select'\nimport { Switch } from '@open-mercato/ui/primitives/switch'\n\nexport const CONTROL_BORDER = 'border border-input'\nexport const CONTROL_TEXT = 'text-sm text-foreground placeholder:text-muted-foreground'\nexport const LABEL_CLASS = 'text-xs font-medium text-muted-foreground'\nexport const DROPDOWN_PANEL_CLASS =\n 'absolute z-50 mt-1 max-h-56 w-full overflow-y-auto rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md'\n\n/**\n * Closes an editor dropdown on pointer-down outside the component or Escape.\n * Blur alone is unreliable inside the Radix dialog focus trap (#3552 feedback:\n * the Resources list stayed open), so dismissal listens on the document while\n * the dropdown is open. Returns the ref to attach to the component root.\n */\nexport function useDropdownDismiss(open: boolean, onClose: () => void): React.RefObject<HTMLDivElement | null> {\n const rootRef = React.useRef<HTMLDivElement | null>(null)\n React.useEffect(() => {\n if (!open) return\n const handlePointerDown = (event: PointerEvent) => {\n if (rootRef.current && event.target instanceof Node && !rootRef.current.contains(event.target)) onClose()\n }\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n // Swallow Escape so the dialog itself stays open.\n event.stopPropagation()\n onClose()\n }\n }\n document.addEventListener('pointerdown', handlePointerDown, true)\n document.addEventListener('keydown', handleKeyDown, true)\n return () => {\n document.removeEventListener('pointerdown', handlePointerDown, true)\n document.removeEventListener('keydown', handleKeyDown, true)\n }\n }, [open, onClose])\n return rootRef\n}\n\nexport function Field({ label, children, error, className }: { label: string; children: React.ReactNode; error?: string | null; className?: string }) {\n return (\n <div className={cn('flex w-full flex-col gap-1.5', className)}>\n <span className={LABEL_CLASS}>{label}</span>\n {children}\n {error ? <p className=\"text-xs text-status-error-text\">{error}</p> : null}\n </div>\n )\n}\n\nexport function UppercaseBadge({ style, className, children }: { style?: React.CSSProperties; className?: string; children: React.ReactNode }) {\n return (\n <span\n className={cn(\n 'inline-flex shrink-0 items-center justify-center rounded-full bg-muted px-2 py-0.5 text-overline font-medium uppercase text-muted-foreground',\n className,\n )}\n style={style}\n >\n {children}\n </span>\n )\n}\n\nexport function AllDayToggle({ checked, onCheckedChange, label }: { checked: boolean; onCheckedChange(next: boolean): void; label: string }) {\n return (\n <Switch\n checked={checked}\n aria-label={label}\n onCheckedChange={onCheckedChange}\n className=\"h-6 w-10\"\n />\n )\n}\n\nfunction parseDateValue(value: string): Date | null {\n if (!value) return null\n const parsed = new Date(`${value}T00:00:00`)\n return Number.isNaN(parsed.getTime()) ? null : parsed\n}\n\nfunction formatDateValue(date: Date): string {\n return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`\n}\n\n// Close the field's popover when the surrounding editor dialog scrolls, so a\n// portalled DS popover (DatePicker/Select) doesn't float over the form or drift\n// from its field (#3747 feedback). Radix ignores synthetic dismiss events, so\n// this drives the popover's controlled `open` state instead. The editor\n// dispatches `EDITOR_SCROLL_EVENT` on scroll.\nexport const EDITOR_SCROLL_EVENT = 'om-calendar-editor-scroll'\nfunction useCloseOnEditorScroll(setOpen: (open: boolean) => void) {\n React.useEffect(() => {\n const handler = () => setOpen(false)\n document.addEventListener(EDITOR_SCROLL_EVENT, handler)\n return () => document.removeEventListener(EDITOR_SCROLL_EVENT, handler)\n }, [setOpen])\n}\n\n// DS DatePicker (calendar popover) + DS Select (scrolling 30-min list) replace\n// the native `<input type=date|time>` overlays, which only opened via the\n// browser chevron and did not match the design system (#3747 feedback).\nexport function DateControl({\n value,\n onChange,\n ariaLabel,\n className,\n}: {\n value: string\n onChange(next: string): void\n ariaLabel: string\n locale: string\n className?: string\n}) {\n const [open, setOpen] = React.useState(false)\n useCloseOnEditorScroll(setOpen)\n return (\n <DatePicker\n value={parseDateValue(value)}\n onChange={(date) => { if (date) onChange(formatDateValue(date)) }}\n footer=\"none\"\n open={open}\n onOpenChange={setOpen}\n aria-label={ariaLabel}\n className={cn('w-full', className)}\n />\n )\n}\n\n// 24h times at 30-minute steps.\nconst TIME_OPTIONS: string[] = Array.from({ length: 48 }, (_, index) => {\n const hour = Math.floor(index / 2)\n const minute = index % 2 === 0 ? '00' : '30'\n return `${String(hour).padStart(2, '0')}:${minute}`\n})\n\nexport function TimeControl({ value, onChange, ariaLabel }: { value: string; onChange(next: string): void; ariaLabel: string }) {\n const [open, setOpen] = React.useState(false)\n useCloseOnEditorScroll(setOpen)\n // Keep an off-grid value (e.g. an imported 22:15) selectable.\n const options = value && !TIME_OPTIONS.includes(value) ? [value, ...TIME_OPTIONS] : TIME_OPTIONS\n return (\n <Select value={value} onValueChange={onChange} open={open} onOpenChange={setOpen}>\n <SelectTrigger aria-label={ariaLabel} className=\"h-9 w-32 shrink-0\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent className=\"max-h-64\">\n {options.map((time) => (\n <SelectItem key={time} value={time}>{time}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n )\n}\n\nexport function PersonChip({\n name,\n badge,\n compact,\n onRemove,\n removeLabel,\n}: {\n name: string\n badge?: React.ReactNode\n compact?: boolean\n onRemove?: () => void\n removeLabel?: string\n}) {\n return (\n <span\n className={cn(\n 'inline-flex shrink-0 items-center gap-1.5 rounded-full bg-muted pl-1 pr-2',\n compact ? 'py-0.5' : 'py-1',\n )}\n >\n <Avatar size=\"xs\" label={name} />\n <span className=\"max-w-40 truncate text-xs font-medium text-foreground\">{name}</span>\n {badge}\n {onRemove ? (\n <IconButton\n variant=\"ghost\"\n size=\"xs\"\n onClick={(event) => { event.stopPropagation(); onRemove() }}\n aria-label={removeLabel}\n className=\"size-5 shrink-0\"\n >\n <Plus aria-hidden className=\"size-3.5 rotate-45 opacity-50\" />\n </IconButton>\n ) : null}\n </span>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|