@wealthx/shadcn 1.5.22 → 1.5.23
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 +78 -78
- package/CHANGELOG.md +6 -0
- package/dist/{chunk-NEMWMXGL.mjs → chunk-3HFOSFOM.mjs} +76 -48
- package/dist/{chunk-F3MIRXRF.mjs → chunk-ONYADWSO.mjs} +7 -1
- package/dist/{chunk-SET6GFGL.mjs → chunk-ZSMQZ3VN.mjs} +96 -73
- package/dist/components/ui/appointment-action-dialogs.js +96 -73
- package/dist/components/ui/appointment-action-dialogs.mjs +1 -1
- package/dist/components/ui/appointment-book-dialog.js +76 -48
- package/dist/components/ui/appointment-book-dialog.mjs +1 -1
- package/dist/components/ui/appointment-detail-sheet.js +102 -73
- package/dist/components/ui/appointment-detail-sheet.mjs +2 -2
- package/dist/index.js +180 -123
- package/dist/index.mjs +3 -3
- package/package.json +1 -1
- package/src/components/ui/appointment-action-dialogs.tsx +67 -21
- package/src/components/ui/appointment-book-dialog.tsx +150 -53
- package/src/components/ui/appointment-detail-sheet.tsx +18 -0
|
@@ -64,12 +64,17 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
|
64
64
|
function ClientSearch({
|
|
65
65
|
clients,
|
|
66
66
|
value,
|
|
67
|
-
onValueChange
|
|
67
|
+
onValueChange,
|
|
68
|
+
onSearch,
|
|
69
|
+
isSearching,
|
|
70
|
+
hasMore,
|
|
71
|
+
onLoadMore,
|
|
72
|
+
isLoadingMore
|
|
68
73
|
}) {
|
|
69
74
|
const [query, setQuery] = React.useState("");
|
|
70
75
|
const [open, setOpen] = React.useState(false);
|
|
71
76
|
const selected = clients.find((c) => c.id === value);
|
|
72
|
-
const filtered = clients.filter((c) => {
|
|
77
|
+
const filtered = onSearch ? clients : clients.filter((c) => {
|
|
73
78
|
const q = query.toLowerCase();
|
|
74
79
|
return c.name.toLowerCase().includes(q) || c.email.toLowerCase().includes(q);
|
|
75
80
|
});
|
|
@@ -79,67 +84,79 @@ function ClientSearch({
|
|
|
79
84
|
{
|
|
80
85
|
value: selected ? selected.name : query,
|
|
81
86
|
onChange: (e) => {
|
|
82
|
-
|
|
87
|
+
const v = e.target.value;
|
|
88
|
+
setQuery(v);
|
|
83
89
|
if (selected) onValueChange(void 0);
|
|
84
|
-
setOpen(
|
|
90
|
+
setOpen(v.length > 0);
|
|
91
|
+
onSearch == null ? void 0 : onSearch(v);
|
|
85
92
|
},
|
|
86
93
|
onBlur: () => setTimeout(() => setOpen(false), 150),
|
|
87
94
|
placeholder: "Search by name or email\u2026",
|
|
88
95
|
autoComplete: "off"
|
|
89
96
|
}
|
|
90
97
|
),
|
|
91
|
-
open && (filtered.length > 0 || query.length > 0) && /* @__PURE__ */ jsx("div", { className: "absolute z-50 mt-1 w-full border border-border bg-popover shadow-md", children: filtered.length === 0 ? /* @__PURE__ */ jsx("p", { className: "px-3 py-6 text-center text-sm text-muted-foreground", children: "No clients found." }) :
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
98
|
+
open && (filtered.length > 0 || query.length > 0 || isSearching) && /* @__PURE__ */ jsx("div", { className: "absolute z-50 mt-1 max-h-64 w-full overflow-y-auto border border-border bg-popover shadow-md", children: isSearching ? /* @__PURE__ */ jsx("p", { className: "px-3 py-6 text-center text-sm text-muted-foreground", children: "Searching..." }) : filtered.length === 0 ? /* @__PURE__ */ jsx("p", { className: "px-3 py-6 text-center text-sm text-muted-foreground", children: "No clients found." }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
99
|
+
filtered.map((c) => /* @__PURE__ */ jsxs(
|
|
100
|
+
Button,
|
|
101
|
+
{
|
|
102
|
+
type: "button",
|
|
103
|
+
variant: "ghost",
|
|
104
|
+
className: "h-auto w-full flex-col items-start gap-0.5 px-3 py-2 text-left hover:bg-primary/5",
|
|
105
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
106
|
+
onClick: () => {
|
|
107
|
+
onValueChange(c.id);
|
|
108
|
+
setQuery("");
|
|
109
|
+
setOpen(false);
|
|
110
|
+
},
|
|
111
|
+
children: [
|
|
112
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: c.name }),
|
|
113
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: c.email })
|
|
114
|
+
]
|
|
102
115
|
},
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
116
|
+
c.id
|
|
117
|
+
)),
|
|
118
|
+
hasMore && onLoadMore && /* @__PURE__ */ jsx(
|
|
119
|
+
Button,
|
|
120
|
+
{
|
|
121
|
+
type: "button",
|
|
122
|
+
variant: "ghost",
|
|
123
|
+
size: "sm",
|
|
124
|
+
className: "w-full text-sm text-primary",
|
|
125
|
+
disabled: isLoadingMore,
|
|
126
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
127
|
+
onClick: onLoadMore,
|
|
128
|
+
children: isLoadingMore ? "Loading..." : "Load more"
|
|
129
|
+
}
|
|
130
|
+
)
|
|
131
|
+
] }) })
|
|
110
132
|
] });
|
|
111
133
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
134
|
+
function getFormatOptions(platform) {
|
|
135
|
+
const call = {
|
|
136
|
+
value: "call",
|
|
137
|
+
label: "Call",
|
|
138
|
+
icon: /* @__PURE__ */ jsx(Phone, { className: "h-4 w-4" })
|
|
139
|
+
};
|
|
140
|
+
const googleMeet = {
|
|
115
141
|
value: "google-meet",
|
|
116
142
|
label: "Google Meet",
|
|
117
143
|
icon: /* @__PURE__ */ jsx(Video, { className: "h-4 w-4" })
|
|
118
|
-
}
|
|
119
|
-
{
|
|
144
|
+
};
|
|
145
|
+
const msTeams = {
|
|
120
146
|
value: "microsoft-teams",
|
|
121
147
|
label: "MS Teams",
|
|
122
148
|
icon: /* @__PURE__ */ jsx(Users, { className: "h-4 w-4" })
|
|
123
|
-
}
|
|
124
|
-
{
|
|
125
|
-
value: "offline",
|
|
126
|
-
label: "Offline",
|
|
127
|
-
icon: /* @__PURE__ */ jsx(MapPin, { className: "h-4 w-4" })
|
|
128
|
-
}
|
|
129
|
-
];
|
|
130
|
-
var CLIENT_FORMAT_OPTIONS = [
|
|
131
|
-
{ value: "call", label: "Call", icon: /* @__PURE__ */ jsx(Phone, { className: "h-4 w-4" }) },
|
|
132
|
-
{
|
|
133
|
-
value: "online",
|
|
134
|
-
label: "Online Meeting",
|
|
135
|
-
icon: /* @__PURE__ */ jsx(Video, { className: "h-4 w-4" })
|
|
136
|
-
},
|
|
137
|
-
{
|
|
149
|
+
};
|
|
150
|
+
const offline = {
|
|
138
151
|
value: "offline",
|
|
139
152
|
label: "Offline Meeting",
|
|
140
153
|
icon: /* @__PURE__ */ jsx(MapPin, { className: "h-4 w-4" })
|
|
141
|
-
}
|
|
142
|
-
];
|
|
154
|
+
};
|
|
155
|
+
if (platform === "google-meet") return [call, googleMeet, offline];
|
|
156
|
+
if (platform === "microsoft-teams") return [call, msTeams, offline];
|
|
157
|
+
if (platform === "any") return [call, googleMeet, msTeams, offline];
|
|
158
|
+
return [call, offline];
|
|
159
|
+
}
|
|
143
160
|
function MeetingFormatSection({
|
|
144
161
|
format,
|
|
145
162
|
onFormatChange,
|
|
@@ -269,6 +286,11 @@ function AppointmentBookDialog({
|
|
|
269
286
|
open,
|
|
270
287
|
onOpenChange,
|
|
271
288
|
clients = [],
|
|
289
|
+
onSearchClients,
|
|
290
|
+
isSearchingClients,
|
|
291
|
+
hasMoreClients,
|
|
292
|
+
onLoadMoreClients,
|
|
293
|
+
isLoadingMoreClients,
|
|
272
294
|
meetingTypes = [],
|
|
273
295
|
amSlots,
|
|
274
296
|
pmSlots,
|
|
@@ -279,11 +301,12 @@ function AppointmentBookDialog({
|
|
|
279
301
|
advisorInfo,
|
|
280
302
|
initialClientId,
|
|
281
303
|
defaultMeetingFormat,
|
|
304
|
+
onlinePlatform,
|
|
282
305
|
guestInfo,
|
|
283
306
|
onBook
|
|
284
307
|
}) {
|
|
285
308
|
var _a, _b, _c;
|
|
286
|
-
const isClientMode = clients.length === 0;
|
|
309
|
+
const isClientMode = clients.length === 0 && !onSearchClients;
|
|
287
310
|
const showGuestForm = isClientMode && !((guestInfo == null ? void 0 : guestInfo.name) && (guestInfo == null ? void 0 : guestInfo.email));
|
|
288
311
|
const disabledDayOfWeek = React.useMemo(
|
|
289
312
|
() => schedule == null ? void 0 : schedule.filter((d) => !d.enabled).map((d) => DAY_MAP[d.day]).filter((n) => n !== void 0),
|
|
@@ -375,7 +398,12 @@ function AppointmentBookDialog({
|
|
|
375
398
|
{
|
|
376
399
|
clients,
|
|
377
400
|
value: clientId,
|
|
378
|
-
onValueChange: setClientId
|
|
401
|
+
onValueChange: setClientId,
|
|
402
|
+
onSearch: onSearchClients,
|
|
403
|
+
isSearching: isSearchingClients,
|
|
404
|
+
hasMore: hasMoreClients,
|
|
405
|
+
onLoadMore: onLoadMoreClients,
|
|
406
|
+
isLoadingMore: isLoadingMoreClients
|
|
379
407
|
}
|
|
380
408
|
)
|
|
381
409
|
] }),
|
|
@@ -433,7 +461,7 @@ function AppointmentBookDialog({
|
|
|
433
461
|
)
|
|
434
462
|
] })
|
|
435
463
|
] }),
|
|
436
|
-
|
|
464
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
437
465
|
/* @__PURE__ */ jsx(Label, { children: "Meeting format" }),
|
|
438
466
|
/* @__PURE__ */ jsx(
|
|
439
467
|
MeetingFormatSection,
|
|
@@ -447,7 +475,7 @@ function AppointmentBookDialog({
|
|
|
447
475
|
advisorOfficeAddress,
|
|
448
476
|
clientHomeAddress,
|
|
449
477
|
isClientMode,
|
|
450
|
-
formatOptions:
|
|
478
|
+
formatOptions: getFormatOptions(onlinePlatform)
|
|
451
479
|
}
|
|
452
480
|
)
|
|
453
481
|
] }),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AppointmentConfirmDialog,
|
|
3
3
|
AppointmentRescheduleDialog
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-ZSMQZ3VN.mjs";
|
|
5
5
|
import {
|
|
6
6
|
Sheet,
|
|
7
7
|
SheetContent
|
|
@@ -86,6 +86,9 @@ function AppointmentDetailSheet({
|
|
|
86
86
|
clientProfile,
|
|
87
87
|
amSlots,
|
|
88
88
|
pmSlots,
|
|
89
|
+
onDateChange,
|
|
90
|
+
schedule,
|
|
91
|
+
isLoadingSlots,
|
|
89
92
|
onAccept,
|
|
90
93
|
onDecline,
|
|
91
94
|
onReschedule,
|
|
@@ -286,6 +289,9 @@ function AppointmentDetailSheet({
|
|
|
286
289
|
currentDate: appointment.date,
|
|
287
290
|
currentTimeStart: appointment.timeStart,
|
|
288
291
|
currentTimeEnd: appointment.timeEnd,
|
|
292
|
+
onDateChange,
|
|
293
|
+
schedule,
|
|
294
|
+
isLoadingSlots,
|
|
289
295
|
onReschedule: (date, slot, note) => {
|
|
290
296
|
onReschedule == null ? void 0 : onReschedule(appointment.id, date, slot, note);
|
|
291
297
|
setRescheduleOpen(false);
|
|
@@ -98,6 +98,15 @@ function AppointmentConfirmDialog({
|
|
|
98
98
|
] })
|
|
99
99
|
] }) });
|
|
100
100
|
}
|
|
101
|
+
var DAY_MAP = {
|
|
102
|
+
Sun: 0,
|
|
103
|
+
Mon: 1,
|
|
104
|
+
Tue: 2,
|
|
105
|
+
Wed: 3,
|
|
106
|
+
Thu: 4,
|
|
107
|
+
Fri: 5,
|
|
108
|
+
Sat: 6
|
|
109
|
+
};
|
|
101
110
|
function AppointmentRescheduleDialog({
|
|
102
111
|
open,
|
|
103
112
|
onOpenChange,
|
|
@@ -106,11 +115,19 @@ function AppointmentRescheduleDialog({
|
|
|
106
115
|
currentDate,
|
|
107
116
|
currentTimeStart,
|
|
108
117
|
currentTimeEnd,
|
|
118
|
+
onDateChange,
|
|
119
|
+
schedule,
|
|
120
|
+
isLoadingSlots,
|
|
109
121
|
onReschedule
|
|
110
122
|
}) {
|
|
111
123
|
const [date, setDate] = React.useState(/* @__PURE__ */ new Date());
|
|
112
124
|
const [slot, setSlot] = React.useState();
|
|
113
125
|
const [note, setNote] = React.useState("");
|
|
126
|
+
const today = React.useMemo(() => /* @__PURE__ */ new Date(), []);
|
|
127
|
+
const disabledDayOfWeek = React.useMemo(
|
|
128
|
+
() => schedule == null ? void 0 : schedule.filter((d) => !d.enabled).map((d) => DAY_MAP[d.day]).filter((n) => n !== void 0),
|
|
129
|
+
[schedule]
|
|
130
|
+
);
|
|
114
131
|
const handleOpenChange = (next) => {
|
|
115
132
|
if (!next) {
|
|
116
133
|
setDate(/* @__PURE__ */ new Date());
|
|
@@ -128,87 +145,93 @@ function AppointmentRescheduleDialog({
|
|
|
128
145
|
/* @__PURE__ */ jsx(DialogDescription, { children: "Select a new date and time slot. The client will be notified by email." })
|
|
129
146
|
] }),
|
|
130
147
|
/* @__PURE__ */ jsx(Separator, {}),
|
|
131
|
-
|
|
132
|
-
/* @__PURE__ */
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
/* @__PURE__ */
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
/* @__PURE__ */
|
|
140
|
-
|
|
141
|
-
|
|
148
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4 overflow-y-auto max-h-[calc(90vh-200px)]", children: [
|
|
149
|
+
(currentDate || currentTimeStart) && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
150
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Current booking" }),
|
|
151
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4 border border-border bg-muted/30 px-3 py-2.5 text-sm text-muted-foreground", children: [
|
|
152
|
+
currentDate && /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1.5", children: [
|
|
153
|
+
/* @__PURE__ */ jsx(CalendarIcon, { className: "h-3.5 w-3.5 shrink-0" }),
|
|
154
|
+
currentDate
|
|
155
|
+
] }),
|
|
156
|
+
currentTimeStart && /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1.5", children: [
|
|
157
|
+
/* @__PURE__ */ jsx(Clock, { className: "h-3.5 w-3.5 shrink-0" }),
|
|
158
|
+
currentTimeStart,
|
|
159
|
+
currentTimeEnd ? ` \u2013 ${currentTimeEnd}` : ""
|
|
160
|
+
] })
|
|
142
161
|
] })
|
|
143
|
-
] })
|
|
144
|
-
] }),
|
|
145
|
-
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[auto_1fr] items-start gap-5", children: [
|
|
146
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
147
|
-
/* @__PURE__ */ jsx(Label, { children: "New date" }),
|
|
148
|
-
/* @__PURE__ */ jsx(
|
|
149
|
-
Calendar,
|
|
150
|
-
{
|
|
151
|
-
mode: "single",
|
|
152
|
-
selected: date,
|
|
153
|
-
onSelect: (d) => {
|
|
154
|
-
setDate(d);
|
|
155
|
-
setSlot(void 0);
|
|
156
|
-
},
|
|
157
|
-
captionLayout: "label",
|
|
158
|
-
fromDate: /* @__PURE__ */ new Date(),
|
|
159
|
-
disabled: { before: /* @__PURE__ */ new Date() },
|
|
160
|
-
className: "border border-border"
|
|
161
|
-
}
|
|
162
|
-
)
|
|
163
162
|
] }),
|
|
164
|
-
/* @__PURE__ */
|
|
165
|
-
/* @__PURE__ */ jsxs("div", { className: "flex
|
|
163
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[auto_1fr] items-start gap-5", children: [
|
|
164
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
165
|
+
/* @__PURE__ */ jsx(Label, { children: "New date" }),
|
|
166
|
+
/* @__PURE__ */ jsx(
|
|
167
|
+
Calendar,
|
|
168
|
+
{
|
|
169
|
+
mode: "single",
|
|
170
|
+
selected: date,
|
|
171
|
+
onSelect: (d) => {
|
|
172
|
+
setDate(d);
|
|
173
|
+
setSlot(void 0);
|
|
174
|
+
if (d) onDateChange == null ? void 0 : onDateChange(d);
|
|
175
|
+
},
|
|
176
|
+
captionLayout: "label",
|
|
177
|
+
fromDate: today,
|
|
178
|
+
disabled: disabledDayOfWeek && disabledDayOfWeek.length > 0 ? [{ before: today }, { dayOfWeek: disabledDayOfWeek }] : { before: today },
|
|
179
|
+
className: "border border-border"
|
|
180
|
+
}
|
|
181
|
+
)
|
|
182
|
+
] }),
|
|
183
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-col gap-5", children: date ? isLoadingSlots ? /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col items-center justify-center gap-2 py-8 text-center", children: [
|
|
184
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-semibold", children: "Loading slots\u2026" }),
|
|
185
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Fetching available times for the selected date." })
|
|
186
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
187
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
188
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-semibold", children: "Select a time slot" }),
|
|
189
|
+
/* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", children: [
|
|
190
|
+
totalAvailable,
|
|
191
|
+
" available"
|
|
192
|
+
] })
|
|
193
|
+
] }),
|
|
194
|
+
/* @__PURE__ */ jsx(
|
|
195
|
+
AppointmentSlotSection,
|
|
196
|
+
{
|
|
197
|
+
label: "Morning",
|
|
198
|
+
slots: amSlots,
|
|
199
|
+
selectedSlotId: slot == null ? void 0 : slot.id,
|
|
200
|
+
onSelect: setSlot
|
|
201
|
+
}
|
|
202
|
+
),
|
|
203
|
+
/* @__PURE__ */ jsx(
|
|
204
|
+
AppointmentSlotSection,
|
|
205
|
+
{
|
|
206
|
+
label: "Afternoon",
|
|
207
|
+
slots: pmSlots,
|
|
208
|
+
selectedSlotId: slot == null ? void 0 : slot.id,
|
|
209
|
+
onSelect: setSlot
|
|
210
|
+
}
|
|
211
|
+
)
|
|
212
|
+
] }) : /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col items-center justify-center gap-2 py-8 text-center", children: [
|
|
166
213
|
/* @__PURE__ */ jsx("p", { className: "text-sm font-semibold", children: "Select a time slot" }),
|
|
167
|
-
/* @__PURE__ */
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
214
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Pick a date on the left to see available slots." })
|
|
215
|
+
] }) })
|
|
216
|
+
] }),
|
|
217
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
218
|
+
/* @__PURE__ */ jsxs(Label, { htmlFor: "reschedule-note", children: [
|
|
219
|
+
"Note",
|
|
220
|
+
" ",
|
|
221
|
+
/* @__PURE__ */ jsx("span", { className: "font-normal text-muted-foreground", children: "(optional)" })
|
|
171
222
|
] }),
|
|
172
223
|
/* @__PURE__ */ jsx(
|
|
173
|
-
|
|
224
|
+
Textarea,
|
|
174
225
|
{
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
/* @__PURE__ */ jsx(
|
|
182
|
-
AppointmentSlotSection,
|
|
183
|
-
{
|
|
184
|
-
label: "Afternoon",
|
|
185
|
-
slots: pmSlots,
|
|
186
|
-
selectedSlotId: slot == null ? void 0 : slot.id,
|
|
187
|
-
onSelect: setSlot
|
|
226
|
+
id: "reschedule-note",
|
|
227
|
+
placeholder: "e.g. Rescheduling due to an internal conflict \u2014 apologies for the inconvenience\u2026",
|
|
228
|
+
value: note,
|
|
229
|
+
onChange: (e) => setNote(e.target.value),
|
|
230
|
+
className: "w-full resize-none",
|
|
231
|
+
rows: 2
|
|
188
232
|
}
|
|
189
233
|
)
|
|
190
|
-
] })
|
|
191
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm font-semibold", children: "Select a time slot" }),
|
|
192
|
-
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Pick a date on the left to see available slots." })
|
|
193
|
-
] }) })
|
|
194
|
-
] }),
|
|
195
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
196
|
-
/* @__PURE__ */ jsxs(Label, { htmlFor: "reschedule-note", children: [
|
|
197
|
-
"Note",
|
|
198
|
-
" ",
|
|
199
|
-
/* @__PURE__ */ jsx("span", { className: "font-normal text-muted-foreground", children: "(optional)" })
|
|
200
|
-
] }),
|
|
201
|
-
/* @__PURE__ */ jsx(
|
|
202
|
-
Textarea,
|
|
203
|
-
{
|
|
204
|
-
id: "reschedule-note",
|
|
205
|
-
placeholder: "e.g. Rescheduling due to an internal conflict \u2014 apologies for the inconvenience\u2026",
|
|
206
|
-
value: note,
|
|
207
|
-
onChange: (e) => setNote(e.target.value),
|
|
208
|
-
className: "w-full resize-none",
|
|
209
|
-
rows: 2
|
|
210
|
-
}
|
|
211
|
-
)
|
|
234
|
+
] })
|
|
212
235
|
] }),
|
|
213
236
|
/* @__PURE__ */ jsxs(DialogFooter, { children: [
|
|
214
237
|
/* @__PURE__ */ jsx(DialogClose, { render: /* @__PURE__ */ jsx(Button, { variant: "outline" }), children: "Cancel" }),
|
|
@@ -1054,6 +1054,15 @@ function AppointmentConfirmDialog({
|
|
|
1054
1054
|
] })
|
|
1055
1055
|
] }) });
|
|
1056
1056
|
}
|
|
1057
|
+
var DAY_MAP = {
|
|
1058
|
+
Sun: 0,
|
|
1059
|
+
Mon: 1,
|
|
1060
|
+
Tue: 2,
|
|
1061
|
+
Wed: 3,
|
|
1062
|
+
Thu: 4,
|
|
1063
|
+
Fri: 5,
|
|
1064
|
+
Sat: 6
|
|
1065
|
+
};
|
|
1057
1066
|
function AppointmentRescheduleDialog({
|
|
1058
1067
|
open,
|
|
1059
1068
|
onOpenChange,
|
|
@@ -1062,11 +1071,19 @@ function AppointmentRescheduleDialog({
|
|
|
1062
1071
|
currentDate,
|
|
1063
1072
|
currentTimeStart,
|
|
1064
1073
|
currentTimeEnd,
|
|
1074
|
+
onDateChange,
|
|
1075
|
+
schedule,
|
|
1076
|
+
isLoadingSlots,
|
|
1065
1077
|
onReschedule
|
|
1066
1078
|
}) {
|
|
1067
1079
|
const [date, setDate] = import_react3.default.useState(/* @__PURE__ */ new Date());
|
|
1068
1080
|
const [slot, setSlot] = import_react3.default.useState();
|
|
1069
1081
|
const [note, setNote] = import_react3.default.useState("");
|
|
1082
|
+
const today = import_react3.default.useMemo(() => /* @__PURE__ */ new Date(), []);
|
|
1083
|
+
const disabledDayOfWeek = import_react3.default.useMemo(
|
|
1084
|
+
() => schedule == null ? void 0 : schedule.filter((d) => !d.enabled).map((d) => DAY_MAP[d.day]).filter((n) => n !== void 0),
|
|
1085
|
+
[schedule]
|
|
1086
|
+
);
|
|
1070
1087
|
const handleOpenChange = (next) => {
|
|
1071
1088
|
if (!next) {
|
|
1072
1089
|
setDate(/* @__PURE__ */ new Date());
|
|
@@ -1084,87 +1101,93 @@ function AppointmentRescheduleDialog({
|
|
|
1084
1101
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(DialogDescription, { children: "Select a new date and time slot. The client will be notified by email." })
|
|
1085
1102
|
] }),
|
|
1086
1103
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Separator, {}),
|
|
1087
|
-
|
|
1088
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.
|
|
1096
|
-
|
|
1097
|
-
|
|
1104
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex flex-col gap-4 overflow-y-auto max-h-[calc(90vh-200px)]", children: [
|
|
1105
|
+
(currentDate || currentTimeStart) && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex flex-col gap-1.5", children: [
|
|
1106
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Current booking" }),
|
|
1107
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center gap-4 border border-border bg-muted/30 px-3 py-2.5 text-sm text-muted-foreground", children: [
|
|
1108
|
+
currentDate && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "flex items-center gap-1.5", children: [
|
|
1109
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react4.Calendar, { className: "h-3.5 w-3.5 shrink-0" }),
|
|
1110
|
+
currentDate
|
|
1111
|
+
] }),
|
|
1112
|
+
currentTimeStart && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "flex items-center gap-1.5", children: [
|
|
1113
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react4.Clock, { className: "h-3.5 w-3.5 shrink-0" }),
|
|
1114
|
+
currentTimeStart,
|
|
1115
|
+
currentTimeEnd ? ` \u2013 ${currentTimeEnd}` : ""
|
|
1116
|
+
] })
|
|
1098
1117
|
] })
|
|
1099
|
-
] })
|
|
1100
|
-
] }),
|
|
1101
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "grid grid-cols-[auto_1fr] items-start gap-5", children: [
|
|
1102
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex flex-col gap-1.5", children: [
|
|
1103
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Label, { children: "New date" }),
|
|
1104
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1105
|
-
Calendar,
|
|
1106
|
-
{
|
|
1107
|
-
mode: "single",
|
|
1108
|
-
selected: date,
|
|
1109
|
-
onSelect: (d) => {
|
|
1110
|
-
setDate(d);
|
|
1111
|
-
setSlot(void 0);
|
|
1112
|
-
},
|
|
1113
|
-
captionLayout: "label",
|
|
1114
|
-
fromDate: /* @__PURE__ */ new Date(),
|
|
1115
|
-
disabled: { before: /* @__PURE__ */ new Date() },
|
|
1116
|
-
className: "border border-border"
|
|
1117
|
-
}
|
|
1118
|
-
)
|
|
1119
1118
|
] }),
|
|
1120
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.
|
|
1121
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex
|
|
1119
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "grid grid-cols-[auto_1fr] items-start gap-5", children: [
|
|
1120
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex flex-col gap-1.5", children: [
|
|
1121
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Label, { children: "New date" }),
|
|
1122
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1123
|
+
Calendar,
|
|
1124
|
+
{
|
|
1125
|
+
mode: "single",
|
|
1126
|
+
selected: date,
|
|
1127
|
+
onSelect: (d) => {
|
|
1128
|
+
setDate(d);
|
|
1129
|
+
setSlot(void 0);
|
|
1130
|
+
if (d) onDateChange == null ? void 0 : onDateChange(d);
|
|
1131
|
+
},
|
|
1132
|
+
captionLayout: "label",
|
|
1133
|
+
fromDate: today,
|
|
1134
|
+
disabled: disabledDayOfWeek && disabledDayOfWeek.length > 0 ? [{ before: today }, { dayOfWeek: disabledDayOfWeek }] : { before: today },
|
|
1135
|
+
className: "border border-border"
|
|
1136
|
+
}
|
|
1137
|
+
)
|
|
1138
|
+
] }),
|
|
1139
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "flex flex-col gap-5", children: date ? isLoadingSlots ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex h-full flex-col items-center justify-center gap-2 py-8 text-center", children: [
|
|
1140
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-sm font-semibold", children: "Loading slots\u2026" }),
|
|
1141
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-xs text-muted-foreground", children: "Fetching available times for the selected date." })
|
|
1142
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
|
|
1143
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex items-center justify-between", children: [
|
|
1144
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-sm font-semibold", children: "Select a time slot" }),
|
|
1145
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "text-xs text-muted-foreground", children: [
|
|
1146
|
+
totalAvailable,
|
|
1147
|
+
" available"
|
|
1148
|
+
] })
|
|
1149
|
+
] }),
|
|
1150
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1151
|
+
AppointmentSlotSection,
|
|
1152
|
+
{
|
|
1153
|
+
label: "Morning",
|
|
1154
|
+
slots: amSlots,
|
|
1155
|
+
selectedSlotId: slot == null ? void 0 : slot.id,
|
|
1156
|
+
onSelect: setSlot
|
|
1157
|
+
}
|
|
1158
|
+
),
|
|
1159
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1160
|
+
AppointmentSlotSection,
|
|
1161
|
+
{
|
|
1162
|
+
label: "Afternoon",
|
|
1163
|
+
slots: pmSlots,
|
|
1164
|
+
selectedSlotId: slot == null ? void 0 : slot.id,
|
|
1165
|
+
onSelect: setSlot
|
|
1166
|
+
}
|
|
1167
|
+
)
|
|
1168
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex h-full flex-col items-center justify-center gap-2 py-8 text-center", children: [
|
|
1122
1169
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-sm font-semibold", children: "Select a time slot" }),
|
|
1123
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1170
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-xs text-muted-foreground", children: "Pick a date on the left to see available slots." })
|
|
1171
|
+
] }) })
|
|
1172
|
+
] }),
|
|
1173
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex flex-col gap-1.5", children: [
|
|
1174
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Label, { htmlFor: "reschedule-note", children: [
|
|
1175
|
+
"Note",
|
|
1176
|
+
" ",
|
|
1177
|
+
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "font-normal text-muted-foreground", children: "(optional)" })
|
|
1127
1178
|
] }),
|
|
1128
1179
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1129
|
-
|
|
1130
|
-
{
|
|
1131
|
-
label: "Morning",
|
|
1132
|
-
slots: amSlots,
|
|
1133
|
-
selectedSlotId: slot == null ? void 0 : slot.id,
|
|
1134
|
-
onSelect: setSlot
|
|
1135
|
-
}
|
|
1136
|
-
),
|
|
1137
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1138
|
-
AppointmentSlotSection,
|
|
1180
|
+
Textarea,
|
|
1139
1181
|
{
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1182
|
+
id: "reschedule-note",
|
|
1183
|
+
placeholder: "e.g. Rescheduling due to an internal conflict \u2014 apologies for the inconvenience\u2026",
|
|
1184
|
+
value: note,
|
|
1185
|
+
onChange: (e) => setNote(e.target.value),
|
|
1186
|
+
className: "w-full resize-none",
|
|
1187
|
+
rows: 2
|
|
1144
1188
|
}
|
|
1145
1189
|
)
|
|
1146
|
-
] })
|
|
1147
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-sm font-semibold", children: "Select a time slot" }),
|
|
1148
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-xs text-muted-foreground", children: "Pick a date on the left to see available slots." })
|
|
1149
|
-
] }) })
|
|
1150
|
-
] }),
|
|
1151
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "flex flex-col gap-1.5", children: [
|
|
1152
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Label, { htmlFor: "reschedule-note", children: [
|
|
1153
|
-
"Note",
|
|
1154
|
-
" ",
|
|
1155
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "font-normal text-muted-foreground", children: "(optional)" })
|
|
1156
|
-
] }),
|
|
1157
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1158
|
-
Textarea,
|
|
1159
|
-
{
|
|
1160
|
-
id: "reschedule-note",
|
|
1161
|
-
placeholder: "e.g. Rescheduling due to an internal conflict \u2014 apologies for the inconvenience\u2026",
|
|
1162
|
-
value: note,
|
|
1163
|
-
onChange: (e) => setNote(e.target.value),
|
|
1164
|
-
className: "w-full resize-none",
|
|
1165
|
-
rows: 2
|
|
1166
|
-
}
|
|
1167
|
-
)
|
|
1190
|
+
] })
|
|
1168
1191
|
] }),
|
|
1169
1192
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(DialogFooter, { children: [
|
|
1170
1193
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(DialogClose, { render: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Button, { variant: "outline" }), children: "Cancel" }),
|