@wealthx/shadcn 1.5.22 → 1.5.24
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 +58 -58
- package/CHANGELOG.md +12 -0
- package/dist/{chunk-NEMWMXGL.mjs → chunk-3HFOSFOM.mjs} +76 -48
- package/dist/{chunk-F3MIRXRF.mjs → chunk-ONYADWSO.mjs} +7 -1
- package/dist/{chunk-K4GJTP6N.mjs → chunk-RYGZRDP6.mjs} +24 -1
- package/dist/{chunk-SET6GFGL.mjs → chunk-ZSMQZ3VN.mjs} +96 -73
- package/dist/components/ui/ai-conversations.js +24 -1
- package/dist/components/ui/ai-conversations.mjs +1 -1
- 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 +204 -124
- package/dist/index.mjs +4 -4
- package/package.json +1 -1
- package/src/components/ui/ai-conversations.tsx +58 -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
|
@@ -520,6 +520,7 @@ function ChatComposer({
|
|
|
520
520
|
mode,
|
|
521
521
|
channel: channelProp = "chat",
|
|
522
522
|
onChannelChange,
|
|
523
|
+
channelType = "chat",
|
|
523
524
|
isEmailIntegrated = false,
|
|
524
525
|
contactEmail = "",
|
|
525
526
|
inputValue = "",
|
|
@@ -530,8 +531,10 @@ function ChatComposer({
|
|
|
530
531
|
onLetAiHandle,
|
|
531
532
|
className
|
|
532
533
|
}) {
|
|
534
|
+
const showIntegrateEmailPrompt = channelType === "email" && !isEmailIntegrated;
|
|
535
|
+
const initialChannel = channelType === "email" && isEmailIntegrated ? "email" : channelProp;
|
|
533
536
|
const [channel, setChannel] = React.useState(
|
|
534
|
-
isEmailIntegrated ?
|
|
537
|
+
isEmailIntegrated ? initialChannel : "chat"
|
|
535
538
|
);
|
|
536
539
|
const [emailTo, setEmailTo] = React.useState(contactEmail);
|
|
537
540
|
const [emailCc, setEmailCc] = React.useState("");
|
|
@@ -556,6 +559,22 @@ function ChatComposer({
|
|
|
556
559
|
setChannel(c);
|
|
557
560
|
onChannelChange == null ? void 0 : onChannelChange(c);
|
|
558
561
|
};
|
|
562
|
+
if (showIntegrateEmailPrompt) {
|
|
563
|
+
return /* @__PURE__ */ jsxs(
|
|
564
|
+
"div",
|
|
565
|
+
{
|
|
566
|
+
className: cn(
|
|
567
|
+
"flex flex-col items-center justify-center gap-2 border-t border-border bg-muted/30 px-6 py-8 text-center",
|
|
568
|
+
className
|
|
569
|
+
),
|
|
570
|
+
children: [
|
|
571
|
+
/* @__PURE__ */ jsx(Mail, { className: "h-8 w-8 text-muted-foreground" }),
|
|
572
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-foreground", children: "Email integration required" }),
|
|
573
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Please integrate your email to reply to this conversation." })
|
|
574
|
+
]
|
|
575
|
+
}
|
|
576
|
+
);
|
|
577
|
+
}
|
|
559
578
|
return /* @__PURE__ */ jsxs(
|
|
560
579
|
"div",
|
|
561
580
|
{
|
|
@@ -755,6 +774,7 @@ function ChatThread({
|
|
|
755
774
|
isAiTyping = false,
|
|
756
775
|
channel,
|
|
757
776
|
onChannelChange,
|
|
777
|
+
channelType,
|
|
758
778
|
isEmailIntegrated,
|
|
759
779
|
inputValue,
|
|
760
780
|
onInputChange,
|
|
@@ -946,6 +966,7 @@ function ChatThread({
|
|
|
946
966
|
mode,
|
|
947
967
|
channel,
|
|
948
968
|
onChannelChange,
|
|
969
|
+
channelType,
|
|
949
970
|
isEmailIntegrated,
|
|
950
971
|
contactEmail: contact.email,
|
|
951
972
|
inputValue,
|
|
@@ -1334,6 +1355,7 @@ function ConversationsPage({
|
|
|
1334
1355
|
onChannelFilterChange,
|
|
1335
1356
|
channel,
|
|
1336
1357
|
onChannelChange,
|
|
1358
|
+
channelType,
|
|
1337
1359
|
isEmailIntegrated,
|
|
1338
1360
|
inputValue,
|
|
1339
1361
|
internalNotes,
|
|
@@ -1420,6 +1442,7 @@ function ConversationsPage({
|
|
|
1420
1442
|
isAiTyping,
|
|
1421
1443
|
channel,
|
|
1422
1444
|
onChannelChange,
|
|
1445
|
+
channelType,
|
|
1423
1446
|
isEmailIntegrated,
|
|
1424
1447
|
inputValue,
|
|
1425
1448
|
onInputChange,
|
|
@@ -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" }),
|
|
@@ -1381,6 +1381,7 @@ function ChatComposer({
|
|
|
1381
1381
|
mode,
|
|
1382
1382
|
channel: channelProp = "chat",
|
|
1383
1383
|
onChannelChange,
|
|
1384
|
+
channelType = "chat",
|
|
1384
1385
|
isEmailIntegrated = false,
|
|
1385
1386
|
contactEmail = "",
|
|
1386
1387
|
inputValue = "",
|
|
@@ -1391,8 +1392,10 @@ function ChatComposer({
|
|
|
1391
1392
|
onLetAiHandle,
|
|
1392
1393
|
className
|
|
1393
1394
|
}) {
|
|
1395
|
+
const showIntegrateEmailPrompt = channelType === "email" && !isEmailIntegrated;
|
|
1396
|
+
const initialChannel = channelType === "email" && isEmailIntegrated ? "email" : channelProp;
|
|
1394
1397
|
const [channel, setChannel] = import_react3.default.useState(
|
|
1395
|
-
isEmailIntegrated ?
|
|
1398
|
+
isEmailIntegrated ? initialChannel : "chat"
|
|
1396
1399
|
);
|
|
1397
1400
|
const [emailTo, setEmailTo] = import_react3.default.useState(contactEmail);
|
|
1398
1401
|
const [emailCc, setEmailCc] = import_react3.default.useState("");
|
|
@@ -1417,6 +1420,22 @@ function ChatComposer({
|
|
|
1417
1420
|
setChannel(c);
|
|
1418
1421
|
onChannelChange == null ? void 0 : onChannelChange(c);
|
|
1419
1422
|
};
|
|
1423
|
+
if (showIntegrateEmailPrompt) {
|
|
1424
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
1425
|
+
"div",
|
|
1426
|
+
{
|
|
1427
|
+
className: cn(
|
|
1428
|
+
"flex flex-col items-center justify-center gap-2 border-t border-border bg-muted/30 px-6 py-8 text-center",
|
|
1429
|
+
className
|
|
1430
|
+
),
|
|
1431
|
+
children: [
|
|
1432
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react4.Mail, { className: "h-8 w-8 text-muted-foreground" }),
|
|
1433
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-sm font-medium text-foreground", children: "Email integration required" }),
|
|
1434
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-xs text-muted-foreground", children: "Please integrate your email to reply to this conversation." })
|
|
1435
|
+
]
|
|
1436
|
+
}
|
|
1437
|
+
);
|
|
1438
|
+
}
|
|
1420
1439
|
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
1421
1440
|
"div",
|
|
1422
1441
|
{
|
|
@@ -1616,6 +1635,7 @@ function ChatThread({
|
|
|
1616
1635
|
isAiTyping = false,
|
|
1617
1636
|
channel,
|
|
1618
1637
|
onChannelChange,
|
|
1638
|
+
channelType,
|
|
1619
1639
|
isEmailIntegrated,
|
|
1620
1640
|
inputValue,
|
|
1621
1641
|
onInputChange,
|
|
@@ -1807,6 +1827,7 @@ function ChatThread({
|
|
|
1807
1827
|
mode,
|
|
1808
1828
|
channel,
|
|
1809
1829
|
onChannelChange,
|
|
1830
|
+
channelType,
|
|
1810
1831
|
isEmailIntegrated,
|
|
1811
1832
|
contactEmail: contact.email,
|
|
1812
1833
|
inputValue,
|
|
@@ -2195,6 +2216,7 @@ function ConversationsPage({
|
|
|
2195
2216
|
onChannelFilterChange,
|
|
2196
2217
|
channel,
|
|
2197
2218
|
onChannelChange,
|
|
2219
|
+
channelType,
|
|
2198
2220
|
isEmailIntegrated,
|
|
2199
2221
|
inputValue,
|
|
2200
2222
|
internalNotes,
|
|
@@ -2281,6 +2303,7 @@ function ConversationsPage({
|
|
|
2281
2303
|
isAiTyping,
|
|
2282
2304
|
channel,
|
|
2283
2305
|
onChannelChange,
|
|
2306
|
+
channelType,
|
|
2284
2307
|
isEmailIntegrated,
|
|
2285
2308
|
inputValue,
|
|
2286
2309
|
onInputChange,
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
ConversationStatusChip,
|
|
10
10
|
ConversationsPage,
|
|
11
11
|
LeadInfoPanel
|
|
12
|
-
} from "../../chunk-
|
|
12
|
+
} from "../../chunk-RYGZRDP6.mjs";
|
|
13
13
|
import "../../chunk-3S6KVFF5.mjs";
|
|
14
14
|
import "../../chunk-WE4YKBDE.mjs";
|
|
15
15
|
import "../../chunk-H5DTKPJ2.mjs";
|
|
@@ -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" }),
|