@wealthx/shadcn 1.5.11 → 1.5.13
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 +88 -88
- package/CHANGELOG.md +12 -0
- package/dist/{chunk-O5CP6VP6.mjs → chunk-BF5FKUF6.mjs} +104 -63
- package/dist/{chunk-ZMTCMP2G.mjs → chunk-EB626HVW.mjs} +70 -3
- package/dist/chunk-KICT4VQL.mjs +508 -0
- package/dist/chunk-V23CBULF.mjs +432 -0
- package/dist/components/ui/ai-conversations.js +70 -3
- package/dist/components/ui/ai-conversations.mjs +1 -1
- package/dist/components/ui/appointment-calendar-view.js +177 -176
- package/dist/components/ui/appointment-calendar-view.mjs +1 -1
- package/dist/components/ui/bank-statement-generate-dialog.js +209 -107
- package/dist/components/ui/bank-statement-generate-dialog.mjs +2 -1
- package/dist/components/ui/resource-center/index.js +1030 -0
- package/dist/components/ui/resource-center/index.mjs +29 -0
- package/dist/index.js +661 -403
- package/dist/index.mjs +16 -14
- package/dist/styles.css +1 -1
- package/package.json +4 -4
- package/src/components/index.tsx +2 -0
- package/src/components/ui/ai-conversations.tsx +157 -23
- package/src/components/ui/appointment-calendar-view.tsx +211 -199
- package/src/components/ui/bank-statement-generate-dialog.tsx +147 -96
- package/src/components/ui/resource-center/index.tsx +35 -0
- package/src/components/ui/resource-center/resource-cards.tsx +218 -0
- package/src/components/ui/resource-center/resource-carousel.tsx +122 -0
- package/src/components/ui/resource-center/resource-center-header.tsx +95 -0
- package/src/components/ui/resource-center/resource-email-editor-dialog.tsx +131 -0
- package/src/components/ui/resource-center/resource-modal.tsx +76 -0
- package/src/components/ui/resource-center/types.ts +81 -0
- package/src/styles/styles-css.ts +1 -1
- package/tsup.config.ts +1 -1
- package/dist/chunk-IODGRCQG.mjs +0 -438
- package/dist/chunk-XYWEGBAA.mjs +0 -348
- package/dist/components/ui/resource-center.js +0 -748
- package/dist/components/ui/resource-center.mjs +0 -24
- package/src/components/ui/resource-center.tsx +0 -539
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Tabs,
|
|
3
|
+
TabsContent,
|
|
4
|
+
TabsList,
|
|
5
|
+
TabsTrigger
|
|
6
|
+
} from "./chunk-WE4YKBDE.mjs";
|
|
7
|
+
import {
|
|
8
|
+
Separator
|
|
9
|
+
} from "./chunk-2GIYVERS.mjs";
|
|
10
|
+
import {
|
|
11
|
+
Avatar,
|
|
12
|
+
AvatarFallback
|
|
13
|
+
} from "./chunk-H6NQTIF4.mjs";
|
|
14
|
+
import {
|
|
15
|
+
Badge
|
|
16
|
+
} from "./chunk-X6RC5UWB.mjs";
|
|
17
|
+
import {
|
|
18
|
+
formatWeekdayShort
|
|
19
|
+
} from "./chunk-LHWJQNLG.mjs";
|
|
20
|
+
import {
|
|
21
|
+
Button
|
|
22
|
+
} from "./chunk-NOOEKOWY.mjs";
|
|
23
|
+
|
|
24
|
+
// src/components/ui/appointment-calendar-view.tsx
|
|
25
|
+
import { ChevronLeft, ChevronRight } from "lucide-react";
|
|
26
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
27
|
+
var STATUS = {
|
|
28
|
+
pending: {
|
|
29
|
+
card: "border-l-warning bg-warning/[0.06]",
|
|
30
|
+
badge: "warning",
|
|
31
|
+
label: "Pending"
|
|
32
|
+
},
|
|
33
|
+
confirmed: {
|
|
34
|
+
card: "border-l-success bg-success/[0.06]",
|
|
35
|
+
badge: "success",
|
|
36
|
+
label: "Confirmed"
|
|
37
|
+
},
|
|
38
|
+
cancelled: {
|
|
39
|
+
card: "border-l-destructive bg-destructive/[0.06]",
|
|
40
|
+
badge: "destructive",
|
|
41
|
+
label: "Cancelled"
|
|
42
|
+
},
|
|
43
|
+
rescheduled: {
|
|
44
|
+
card: "border-l-info bg-info/[0.06]",
|
|
45
|
+
badge: "info",
|
|
46
|
+
label: "Rescheduled"
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
function formatHour(h) {
|
|
50
|
+
if (h === 12) return "12 PM";
|
|
51
|
+
return h < 12 ? `${h} AM` : `${h - 12} PM`;
|
|
52
|
+
}
|
|
53
|
+
function getHourFromTime(time) {
|
|
54
|
+
const match = time.match(/^(\d+):/);
|
|
55
|
+
if (!match) return 0;
|
|
56
|
+
const h = parseInt(match[1], 10);
|
|
57
|
+
return time.includes("PM") && h !== 12 ? h + 12 : h;
|
|
58
|
+
}
|
|
59
|
+
var DEFAULT_HOURS = [9, 10, 11, 12, 13, 14, 15, 16, 17];
|
|
60
|
+
function TimeGutter({ hour }) {
|
|
61
|
+
return /* @__PURE__ */ jsx("div", { className: "flex w-16 shrink-0 items-start justify-end border-r border-border pr-3 pt-2", children: /* @__PURE__ */ jsx("span", { className: "text-caption text-muted-foreground", children: formatHour(hour) }) });
|
|
62
|
+
}
|
|
63
|
+
function DayCard({
|
|
64
|
+
apt,
|
|
65
|
+
onSelect
|
|
66
|
+
}) {
|
|
67
|
+
return /* @__PURE__ */ jsxs(
|
|
68
|
+
Button,
|
|
69
|
+
{
|
|
70
|
+
type: "button",
|
|
71
|
+
variant: "ghost",
|
|
72
|
+
onClick: () => onSelect == null ? void 0 : onSelect(apt),
|
|
73
|
+
className: `h-auto w-full justify-start gap-3 border-l-2 px-3 py-3 text-left hover:opacity-80 ${STATUS[apt.status].card}`,
|
|
74
|
+
children: [
|
|
75
|
+
/* @__PURE__ */ jsx(Avatar, { className: "h-8 w-8 shrink-0", children: /* @__PURE__ */ jsx(AvatarFallback, { className: "text-caption", children: apt.clientAvatarInitials }) }),
|
|
76
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [
|
|
77
|
+
/* @__PURE__ */ jsx("span", { className: "text-body-small font-semibold", children: apt.clientName }),
|
|
78
|
+
/* @__PURE__ */ jsxs("span", { className: "text-caption text-muted-foreground", children: [
|
|
79
|
+
apt.timeStart,
|
|
80
|
+
" \u2013 ",
|
|
81
|
+
apt.timeEnd
|
|
82
|
+
] })
|
|
83
|
+
] }),
|
|
84
|
+
/* @__PURE__ */ jsx(Badge, { variant: STATUS[apt.status].badge, children: STATUS[apt.status].label })
|
|
85
|
+
]
|
|
86
|
+
}
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
function AptChip({
|
|
90
|
+
apt,
|
|
91
|
+
onSelect,
|
|
92
|
+
className
|
|
93
|
+
}) {
|
|
94
|
+
return /* @__PURE__ */ jsx(
|
|
95
|
+
Button,
|
|
96
|
+
{
|
|
97
|
+
type: "button",
|
|
98
|
+
variant: "ghost",
|
|
99
|
+
onClick: () => onSelect == null ? void 0 : onSelect(apt),
|
|
100
|
+
className: `h-auto w-full justify-start truncate border-l-2 text-left hover:opacity-80 ${STATUS[apt.status].card} ${className != null ? className : ""}`,
|
|
101
|
+
children: /* @__PURE__ */ jsxs("span", { className: "truncate text-caption font-medium", children: [
|
|
102
|
+
apt.timeStart,
|
|
103
|
+
" ",
|
|
104
|
+
apt.clientName
|
|
105
|
+
] })
|
|
106
|
+
}
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
function DayView({
|
|
110
|
+
appointments,
|
|
111
|
+
date,
|
|
112
|
+
today,
|
|
113
|
+
hours,
|
|
114
|
+
onSelectAppointment
|
|
115
|
+
}) {
|
|
116
|
+
const d = /* @__PURE__ */ new Date(date + "T00:00:00");
|
|
117
|
+
const isToday = date === today;
|
|
118
|
+
const dayApts = appointments.filter((a) => a.date === date);
|
|
119
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col", children: [
|
|
120
|
+
/* @__PURE__ */ jsxs("div", { className: "flex shrink-0 border-b border-border", children: [
|
|
121
|
+
/* @__PURE__ */ jsx("div", { className: "w-16 shrink-0 border-r border-border" }),
|
|
122
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col items-center gap-1 py-4", children: [
|
|
123
|
+
/* @__PURE__ */ jsx(
|
|
124
|
+
"span",
|
|
125
|
+
{
|
|
126
|
+
className: `text-caption tracking-wide ${isToday ? "font-semibold text-primary" : "text-muted-foreground"}`,
|
|
127
|
+
children: formatWeekdayShort(d)
|
|
128
|
+
}
|
|
129
|
+
),
|
|
130
|
+
/* @__PURE__ */ jsx(
|
|
131
|
+
"span",
|
|
132
|
+
{
|
|
133
|
+
className: `flex h-10 w-10 items-center justify-center text-xl font-semibold ${isToday ? "text-primary" : ""}`,
|
|
134
|
+
children: d.getDate()
|
|
135
|
+
}
|
|
136
|
+
)
|
|
137
|
+
] })
|
|
138
|
+
] }),
|
|
139
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-1 flex-col", children: hours.map((hour) => {
|
|
140
|
+
const aptsAtHour = dayApts.filter(
|
|
141
|
+
(a) => getHourFromTime(a.timeStart) === hour
|
|
142
|
+
);
|
|
143
|
+
return /* @__PURE__ */ jsxs(
|
|
144
|
+
"div",
|
|
145
|
+
{
|
|
146
|
+
className: "flex flex-1 border-b border-border/40 last:border-b-0",
|
|
147
|
+
children: [
|
|
148
|
+
/* @__PURE__ */ jsx(TimeGutter, { hour }),
|
|
149
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-1 flex-col gap-2 p-2", children: aptsAtHour.map((apt) => /* @__PURE__ */ jsx(
|
|
150
|
+
DayCard,
|
|
151
|
+
{
|
|
152
|
+
apt,
|
|
153
|
+
onSelect: onSelectAppointment
|
|
154
|
+
},
|
|
155
|
+
apt.id
|
|
156
|
+
)) })
|
|
157
|
+
]
|
|
158
|
+
},
|
|
159
|
+
hour
|
|
160
|
+
);
|
|
161
|
+
}) })
|
|
162
|
+
] });
|
|
163
|
+
}
|
|
164
|
+
function WeekView({
|
|
165
|
+
appointments,
|
|
166
|
+
weekDays,
|
|
167
|
+
today,
|
|
168
|
+
hours,
|
|
169
|
+
onSelectAppointment
|
|
170
|
+
}) {
|
|
171
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col overflow-x-auto", children: [
|
|
172
|
+
/* @__PURE__ */ jsxs("div", { className: "flex shrink-0 border-b border-border", children: [
|
|
173
|
+
/* @__PURE__ */ jsx("div", { className: "w-16 shrink-0 border-r border-border" }),
|
|
174
|
+
weekDays.map((day) => /* @__PURE__ */ jsxs(
|
|
175
|
+
"div",
|
|
176
|
+
{
|
|
177
|
+
className: "flex flex-1 flex-col items-center border-r border-border py-3 last:border-r-0",
|
|
178
|
+
children: [
|
|
179
|
+
/* @__PURE__ */ jsx(
|
|
180
|
+
"span",
|
|
181
|
+
{
|
|
182
|
+
className: `text-caption ${day.date === today ? "font-semibold text-primary" : "text-muted-foreground"}`,
|
|
183
|
+
children: day.label
|
|
184
|
+
}
|
|
185
|
+
),
|
|
186
|
+
/* @__PURE__ */ jsx(
|
|
187
|
+
"span",
|
|
188
|
+
{
|
|
189
|
+
className: `text-body-small font-semibold ${day.date === today ? "text-primary" : ""}`,
|
|
190
|
+
children: day.short
|
|
191
|
+
}
|
|
192
|
+
)
|
|
193
|
+
]
|
|
194
|
+
},
|
|
195
|
+
day.date
|
|
196
|
+
))
|
|
197
|
+
] }),
|
|
198
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-1 flex-col", children: hours.map((hour) => /* @__PURE__ */ jsxs(
|
|
199
|
+
"div",
|
|
200
|
+
{
|
|
201
|
+
className: "flex flex-1 border-b border-border/40 last:border-b-0",
|
|
202
|
+
children: [
|
|
203
|
+
/* @__PURE__ */ jsx(TimeGutter, { hour }),
|
|
204
|
+
weekDays.map((day) => {
|
|
205
|
+
const aptsAtCell = appointments.filter(
|
|
206
|
+
(a) => a.date === day.date && getHourFromTime(a.timeStart) === hour
|
|
207
|
+
);
|
|
208
|
+
return /* @__PURE__ */ jsx(
|
|
209
|
+
"div",
|
|
210
|
+
{
|
|
211
|
+
className: "flex flex-1 flex-col overflow-hidden border-r border-border/40 p-1 last:border-r-0",
|
|
212
|
+
children: aptsAtCell.map((apt) => /* @__PURE__ */ jsx(
|
|
213
|
+
AptChip,
|
|
214
|
+
{
|
|
215
|
+
apt,
|
|
216
|
+
onSelect: onSelectAppointment,
|
|
217
|
+
className: "px-2 py-1.5"
|
|
218
|
+
},
|
|
219
|
+
apt.id
|
|
220
|
+
))
|
|
221
|
+
},
|
|
222
|
+
day.date
|
|
223
|
+
);
|
|
224
|
+
})
|
|
225
|
+
]
|
|
226
|
+
},
|
|
227
|
+
hour
|
|
228
|
+
)) })
|
|
229
|
+
] });
|
|
230
|
+
}
|
|
231
|
+
var MONTH_DAY_HEADERS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
232
|
+
function generateMonthGrid(year, month) {
|
|
233
|
+
const firstDay = new Date(year, month, 1);
|
|
234
|
+
const lastDay = new Date(year, month + 1, 0);
|
|
235
|
+
const startDow = firstDay.getDay();
|
|
236
|
+
const grid = [];
|
|
237
|
+
let week = Array.from({ length: startDow }, () => null);
|
|
238
|
+
for (let day = 1; day <= lastDay.getDate(); day++) {
|
|
239
|
+
week.push(new Date(year, month, day));
|
|
240
|
+
if (week.length === 7) {
|
|
241
|
+
grid.push(week);
|
|
242
|
+
week = [];
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
if (week.length > 0) {
|
|
246
|
+
while (week.length < 7) week.push(null);
|
|
247
|
+
grid.push(week);
|
|
248
|
+
}
|
|
249
|
+
return grid;
|
|
250
|
+
}
|
|
251
|
+
function MonthView({
|
|
252
|
+
appointments,
|
|
253
|
+
viewDate,
|
|
254
|
+
today,
|
|
255
|
+
onSelectAppointment
|
|
256
|
+
}) {
|
|
257
|
+
const vd = /* @__PURE__ */ new Date(viewDate + "T00:00:00");
|
|
258
|
+
const grid = generateMonthGrid(vd.getFullYear(), vd.getMonth());
|
|
259
|
+
const toIso = (d) => `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
|
|
260
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col", children: [
|
|
261
|
+
/* @__PURE__ */ jsx("div", { className: "grid shrink-0 grid-cols-7 border-b border-border", children: MONTH_DAY_HEADERS.map((d) => /* @__PURE__ */ jsx(
|
|
262
|
+
"div",
|
|
263
|
+
{
|
|
264
|
+
className: "flex items-center justify-center border-r border-border/40 py-2 last:border-r-0",
|
|
265
|
+
children: /* @__PURE__ */ jsx("span", { className: "text-caption font-medium text-muted-foreground", children: d })
|
|
266
|
+
},
|
|
267
|
+
d
|
|
268
|
+
)) }),
|
|
269
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-1 flex-col", children: grid.map((week, wi) => /* @__PURE__ */ jsx(
|
|
270
|
+
"div",
|
|
271
|
+
{
|
|
272
|
+
className: "flex flex-1 border-b border-border last:border-b-0",
|
|
273
|
+
children: week.map((day, di) => {
|
|
274
|
+
const iso = day ? toIso(day) : null;
|
|
275
|
+
const dayApts = iso ? appointments.filter((a) => a.date === iso) : [];
|
|
276
|
+
const isToday = iso === today;
|
|
277
|
+
return /* @__PURE__ */ jsx(
|
|
278
|
+
"div",
|
|
279
|
+
{
|
|
280
|
+
className: `min-w-0 flex-1 border-r border-border/40 p-1.5 last:border-r-0 ${!day ? "bg-muted/20" : ""}`,
|
|
281
|
+
children: day && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
282
|
+
/* @__PURE__ */ jsx(
|
|
283
|
+
"div",
|
|
284
|
+
{
|
|
285
|
+
className: `mb-1 flex h-6 w-6 items-center justify-center text-xs font-semibold ${isToday ? "text-primary" : "text-foreground"}`,
|
|
286
|
+
children: day.getDate()
|
|
287
|
+
}
|
|
288
|
+
),
|
|
289
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
|
|
290
|
+
dayApts.slice(0, 2).map((apt) => /* @__PURE__ */ jsx(
|
|
291
|
+
AptChip,
|
|
292
|
+
{
|
|
293
|
+
apt,
|
|
294
|
+
onSelect: onSelectAppointment,
|
|
295
|
+
className: "px-1.5 py-1"
|
|
296
|
+
},
|
|
297
|
+
apt.id
|
|
298
|
+
)),
|
|
299
|
+
dayApts.length > 2 && /* @__PURE__ */ jsxs("p", { className: "px-1 text-caption text-muted-foreground", children: [
|
|
300
|
+
"+",
|
|
301
|
+
dayApts.length - 2,
|
|
302
|
+
" more"
|
|
303
|
+
] })
|
|
304
|
+
] })
|
|
305
|
+
] })
|
|
306
|
+
},
|
|
307
|
+
di
|
|
308
|
+
);
|
|
309
|
+
})
|
|
310
|
+
},
|
|
311
|
+
wi
|
|
312
|
+
)) })
|
|
313
|
+
] });
|
|
314
|
+
}
|
|
315
|
+
function AppointmentCalendarView({
|
|
316
|
+
appointments,
|
|
317
|
+
today,
|
|
318
|
+
periodLabel,
|
|
319
|
+
weekDays,
|
|
320
|
+
hours = DEFAULT_HOURS,
|
|
321
|
+
viewDate,
|
|
322
|
+
dayViewDate,
|
|
323
|
+
defaultView = "week",
|
|
324
|
+
onPrev,
|
|
325
|
+
onNext,
|
|
326
|
+
onToday,
|
|
327
|
+
onViewChange,
|
|
328
|
+
onSelectAppointment,
|
|
329
|
+
toolbarActions
|
|
330
|
+
}) {
|
|
331
|
+
var _a;
|
|
332
|
+
const effectiveViewDate = (_a = viewDate != null ? viewDate : dayViewDate) != null ? _a : today;
|
|
333
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col min-h-0 border border-border bg-card", children: [
|
|
334
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-4 px-4 py-3", children: [
|
|
335
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
336
|
+
/* @__PURE__ */ jsx(
|
|
337
|
+
Button,
|
|
338
|
+
{
|
|
339
|
+
variant: "outline",
|
|
340
|
+
size: "sm",
|
|
341
|
+
className: "gap-1",
|
|
342
|
+
onClick: onPrev,
|
|
343
|
+
children: /* @__PURE__ */ jsx(ChevronLeft, { className: "h-3.5 w-3.5" })
|
|
344
|
+
}
|
|
345
|
+
),
|
|
346
|
+
/* @__PURE__ */ jsx("p", { className: "text-label-medium", children: periodLabel }),
|
|
347
|
+
/* @__PURE__ */ jsx(
|
|
348
|
+
Button,
|
|
349
|
+
{
|
|
350
|
+
variant: "outline",
|
|
351
|
+
size: "sm",
|
|
352
|
+
className: "gap-1",
|
|
353
|
+
onClick: onNext,
|
|
354
|
+
children: /* @__PURE__ */ jsx(ChevronRight, { className: "h-3.5 w-3.5" })
|
|
355
|
+
}
|
|
356
|
+
),
|
|
357
|
+
/* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: onToday, children: "Today" })
|
|
358
|
+
] }),
|
|
359
|
+
toolbarActions && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: toolbarActions })
|
|
360
|
+
] }),
|
|
361
|
+
/* @__PURE__ */ jsx(Separator, {}),
|
|
362
|
+
/* @__PURE__ */ jsxs(
|
|
363
|
+
Tabs,
|
|
364
|
+
{
|
|
365
|
+
defaultValue: defaultView,
|
|
366
|
+
onValueChange: (v) => onViewChange == null ? void 0 : onViewChange(v),
|
|
367
|
+
className: "flex flex-col flex-1 min-h-0",
|
|
368
|
+
children: [
|
|
369
|
+
/* @__PURE__ */ jsx("div", { className: "px-4 pt-3", children: /* @__PURE__ */ jsxs(TabsList, { children: [
|
|
370
|
+
/* @__PURE__ */ jsx(TabsTrigger, { value: "day", children: "Day" }),
|
|
371
|
+
/* @__PURE__ */ jsx(TabsTrigger, { value: "week", children: "Week" }),
|
|
372
|
+
/* @__PURE__ */ jsx(TabsTrigger, { value: "month", children: "Month" })
|
|
373
|
+
] }) }),
|
|
374
|
+
/* @__PURE__ */ jsx(
|
|
375
|
+
TabsContent,
|
|
376
|
+
{
|
|
377
|
+
value: "day",
|
|
378
|
+
className: "mt-0 min-h-0 flex-1 flex flex-col overflow-y-auto",
|
|
379
|
+
children: /* @__PURE__ */ jsx(
|
|
380
|
+
DayView,
|
|
381
|
+
{
|
|
382
|
+
appointments,
|
|
383
|
+
date: effectiveViewDate,
|
|
384
|
+
today,
|
|
385
|
+
hours,
|
|
386
|
+
onSelectAppointment
|
|
387
|
+
}
|
|
388
|
+
)
|
|
389
|
+
}
|
|
390
|
+
),
|
|
391
|
+
/* @__PURE__ */ jsx(
|
|
392
|
+
TabsContent,
|
|
393
|
+
{
|
|
394
|
+
value: "week",
|
|
395
|
+
className: "mt-0 min-h-0 flex-1 flex flex-col overflow-y-auto",
|
|
396
|
+
children: /* @__PURE__ */ jsx(
|
|
397
|
+
WeekView,
|
|
398
|
+
{
|
|
399
|
+
appointments,
|
|
400
|
+
weekDays,
|
|
401
|
+
today,
|
|
402
|
+
hours,
|
|
403
|
+
onSelectAppointment
|
|
404
|
+
}
|
|
405
|
+
)
|
|
406
|
+
}
|
|
407
|
+
),
|
|
408
|
+
/* @__PURE__ */ jsx(
|
|
409
|
+
TabsContent,
|
|
410
|
+
{
|
|
411
|
+
value: "month",
|
|
412
|
+
className: "mt-0 min-h-0 flex-1 flex flex-col overflow-y-auto",
|
|
413
|
+
children: /* @__PURE__ */ jsx(
|
|
414
|
+
MonthView,
|
|
415
|
+
{
|
|
416
|
+
appointments,
|
|
417
|
+
viewDate: effectiveViewDate,
|
|
418
|
+
today,
|
|
419
|
+
onSelectAppointment
|
|
420
|
+
}
|
|
421
|
+
)
|
|
422
|
+
}
|
|
423
|
+
)
|
|
424
|
+
]
|
|
425
|
+
}
|
|
426
|
+
)
|
|
427
|
+
] });
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
export {
|
|
431
|
+
AppointmentCalendarView
|
|
432
|
+
};
|
|
@@ -1244,15 +1244,19 @@ function ChatComposer({
|
|
|
1244
1244
|
mode,
|
|
1245
1245
|
channel: channelProp = "chat",
|
|
1246
1246
|
onChannelChange,
|
|
1247
|
+
isEmailIntegrated = false,
|
|
1247
1248
|
contactEmail = "",
|
|
1248
1249
|
inputValue = "",
|
|
1249
1250
|
onInputChange,
|
|
1250
1251
|
onSend,
|
|
1252
|
+
onSendEmail,
|
|
1251
1253
|
onTakeOver,
|
|
1252
1254
|
onLetAiHandle,
|
|
1253
1255
|
className
|
|
1254
1256
|
}) {
|
|
1255
|
-
const [channel, setChannel] = import_react3.default.useState(
|
|
1257
|
+
const [channel, setChannel] = import_react3.default.useState(
|
|
1258
|
+
isEmailIntegrated ? channelProp : "chat"
|
|
1259
|
+
);
|
|
1256
1260
|
const [emailTo, setEmailTo] = import_react3.default.useState(contactEmail);
|
|
1257
1261
|
const [emailCc, setEmailCc] = import_react3.default.useState("");
|
|
1258
1262
|
const [showCc, setShowCc] = import_react3.default.useState(false);
|
|
@@ -1302,7 +1306,7 @@ function ChatComposer({
|
|
|
1302
1306
|
className
|
|
1303
1307
|
),
|
|
1304
1308
|
children: [
|
|
1305
|
-
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "border-b border-border px-3 py-2", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1309
|
+
isEmailIntegrated && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "border-b border-border px-3 py-2", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1306
1310
|
Tabs,
|
|
1307
1311
|
{
|
|
1308
1312
|
value: channel,
|
|
@@ -1437,7 +1441,12 @@ function ChatComposer({
|
|
|
1437
1441
|
Button,
|
|
1438
1442
|
{
|
|
1439
1443
|
size: "sm",
|
|
1440
|
-
onClick: () =>
|
|
1444
|
+
onClick: () => onSendEmail == null ? void 0 : onSendEmail({
|
|
1445
|
+
content: inputValue,
|
|
1446
|
+
to: emailTo,
|
|
1447
|
+
cc: emailCc,
|
|
1448
|
+
subject: emailSubject
|
|
1449
|
+
}),
|
|
1441
1450
|
disabled: !inputValue.trim() || !emailTo.trim(),
|
|
1442
1451
|
children: [
|
|
1443
1452
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react4.Send, { className: "mr-1.5 size-3.5" }),
|
|
@@ -1492,9 +1501,11 @@ function ChatThread({
|
|
|
1492
1501
|
isAiTyping = false,
|
|
1493
1502
|
channel,
|
|
1494
1503
|
onChannelChange,
|
|
1504
|
+
isEmailIntegrated,
|
|
1495
1505
|
inputValue,
|
|
1496
1506
|
onInputChange,
|
|
1497
1507
|
onSend,
|
|
1508
|
+
onSendEmail,
|
|
1498
1509
|
onTakeOver,
|
|
1499
1510
|
onLetAiHandle,
|
|
1500
1511
|
onReopen,
|
|
@@ -1502,12 +1513,53 @@ function ChatThread({
|
|
|
1502
1513
|
onUnmarkUrgent,
|
|
1503
1514
|
onArchive,
|
|
1504
1515
|
onAssignToAdvisor,
|
|
1516
|
+
hasMoreMessages,
|
|
1517
|
+
isLoadingMoreMessages,
|
|
1518
|
+
onLoadMoreMessages,
|
|
1505
1519
|
onBack,
|
|
1506
1520
|
onShowLeadInfo,
|
|
1507
1521
|
className
|
|
1508
1522
|
}) {
|
|
1509
1523
|
const aiIsHandling = mode === "ai";
|
|
1510
1524
|
const isClosed = status === "closed";
|
|
1525
|
+
const scrollRef = import_react3.default.useRef(null);
|
|
1526
|
+
const preLoadScrollHeightRef = import_react3.default.useRef(null);
|
|
1527
|
+
const handleScroll = (e) => {
|
|
1528
|
+
if (!hasMoreMessages || isLoadingMoreMessages || !onLoadMoreMessages) {
|
|
1529
|
+
return;
|
|
1530
|
+
}
|
|
1531
|
+
if (e.currentTarget.scrollTop <= 80) {
|
|
1532
|
+
preLoadScrollHeightRef.current = e.currentTarget.scrollHeight;
|
|
1533
|
+
onLoadMoreMessages();
|
|
1534
|
+
}
|
|
1535
|
+
};
|
|
1536
|
+
const prevLastMessageIdRef = import_react3.default.useRef(void 0);
|
|
1537
|
+
const prevContactIdRef = import_react3.default.useRef(contact.id);
|
|
1538
|
+
import_react3.default.useLayoutEffect(() => {
|
|
1539
|
+
var _a, _b;
|
|
1540
|
+
const el = scrollRef.current;
|
|
1541
|
+
if (!el) return;
|
|
1542
|
+
if (preLoadScrollHeightRef.current !== null) {
|
|
1543
|
+
el.scrollTop = el.scrollHeight - preLoadScrollHeightRef.current;
|
|
1544
|
+
preLoadScrollHeightRef.current = null;
|
|
1545
|
+
prevLastMessageIdRef.current = (_a = messages[messages.length - 1]) == null ? void 0 : _a.id;
|
|
1546
|
+
prevContactIdRef.current = contact.id;
|
|
1547
|
+
return;
|
|
1548
|
+
}
|
|
1549
|
+
const currentLastId = (_b = messages[messages.length - 1]) == null ? void 0 : _b.id;
|
|
1550
|
+
const contactChanged = prevContactIdRef.current !== contact.id;
|
|
1551
|
+
const tailChanged = prevLastMessageIdRef.current !== currentLastId;
|
|
1552
|
+
if (contactChanged || tailChanged) {
|
|
1553
|
+
el.scrollTop = el.scrollHeight;
|
|
1554
|
+
}
|
|
1555
|
+
prevLastMessageIdRef.current = currentLastId;
|
|
1556
|
+
prevContactIdRef.current = contact.id;
|
|
1557
|
+
}, [contact.id, messages]);
|
|
1558
|
+
import_react3.default.useLayoutEffect(() => {
|
|
1559
|
+
if (!isAiTyping) return;
|
|
1560
|
+
const el = scrollRef.current;
|
|
1561
|
+
if (el) el.scrollTop = el.scrollHeight;
|
|
1562
|
+
}, [isAiTyping]);
|
|
1511
1563
|
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: cn("flex flex-col bg-background", className), children: [
|
|
1512
1564
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
1513
1565
|
"div",
|
|
@@ -1597,9 +1649,12 @@ function ChatThread({
|
|
|
1597
1649
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
1598
1650
|
"div",
|
|
1599
1651
|
{
|
|
1652
|
+
ref: scrollRef,
|
|
1653
|
+
onScroll: handleScroll,
|
|
1600
1654
|
className: "flex flex-1 flex-col gap-4 overflow-y-auto p-4",
|
|
1601
1655
|
tabIndex: 0,
|
|
1602
1656
|
children: [
|
|
1657
|
+
isLoadingMoreMessages && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "flex justify-center py-1 text-caption text-muted-foreground", children: "Loading older messages..." }),
|
|
1603
1658
|
messages.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-1 flex-col items-center justify-center gap-2 text-muted-foreground", children: [
|
|
1604
1659
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react4.MessageSquare, { className: "size-8 opacity-30" }),
|
|
1605
1660
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-sm", children: "No messages yet" })
|
|
@@ -1637,10 +1692,12 @@ function ChatThread({
|
|
|
1637
1692
|
mode,
|
|
1638
1693
|
channel,
|
|
1639
1694
|
onChannelChange,
|
|
1695
|
+
isEmailIntegrated,
|
|
1640
1696
|
contactEmail: contact.email,
|
|
1641
1697
|
inputValue,
|
|
1642
1698
|
onInputChange,
|
|
1643
1699
|
onSend,
|
|
1700
|
+
onSendEmail,
|
|
1644
1701
|
onTakeOver,
|
|
1645
1702
|
onLetAiHandle
|
|
1646
1703
|
}
|
|
@@ -1991,11 +2048,15 @@ function ConversationsPage({
|
|
|
1991
2048
|
onChannelFilterChange,
|
|
1992
2049
|
channel,
|
|
1993
2050
|
onChannelChange,
|
|
2051
|
+
isEmailIntegrated,
|
|
1994
2052
|
inputValue,
|
|
1995
2053
|
internalNotes,
|
|
1996
2054
|
showLeadPanel = true,
|
|
1997
2055
|
hasMore,
|
|
1998
2056
|
isLoadingMore,
|
|
2057
|
+
hasMoreMessages,
|
|
2058
|
+
isLoadingMoreMessages,
|
|
2059
|
+
onLoadMoreMessages,
|
|
1999
2060
|
isAiTyping,
|
|
2000
2061
|
notesSaveStatus,
|
|
2001
2062
|
onSelectConversation,
|
|
@@ -2004,6 +2065,7 @@ function ConversationsPage({
|
|
|
2004
2065
|
onFilterChange,
|
|
2005
2066
|
onInputChange,
|
|
2006
2067
|
onSend,
|
|
2068
|
+
onSendEmail,
|
|
2007
2069
|
onTakeOver,
|
|
2008
2070
|
onLetAiHandle,
|
|
2009
2071
|
onReopen,
|
|
@@ -2072,9 +2134,11 @@ function ConversationsPage({
|
|
|
2072
2134
|
isAiTyping,
|
|
2073
2135
|
channel,
|
|
2074
2136
|
onChannelChange,
|
|
2137
|
+
isEmailIntegrated,
|
|
2075
2138
|
inputValue,
|
|
2076
2139
|
onInputChange,
|
|
2077
2140
|
onSend,
|
|
2141
|
+
onSendEmail,
|
|
2078
2142
|
onTakeOver,
|
|
2079
2143
|
onLetAiHandle,
|
|
2080
2144
|
onReopen,
|
|
@@ -2082,6 +2146,9 @@ function ConversationsPage({
|
|
|
2082
2146
|
onUnmarkUrgent,
|
|
2083
2147
|
onArchive,
|
|
2084
2148
|
onAssignToAdvisor,
|
|
2149
|
+
hasMoreMessages,
|
|
2150
|
+
isLoadingMoreMessages,
|
|
2151
|
+
onLoadMoreMessages,
|
|
2085
2152
|
onBack: () => setMobilePanel("list"),
|
|
2086
2153
|
onShowLeadInfo: () => setMobilePanel("lead"),
|
|
2087
2154
|
className: cn(
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
ConversationStatusChip,
|
|
10
10
|
ConversationsPage,
|
|
11
11
|
LeadInfoPanel
|
|
12
|
-
} from "../../chunk-
|
|
12
|
+
} from "../../chunk-EB626HVW.mjs";
|
|
13
13
|
import "../../chunk-3S6KVFF5.mjs";
|
|
14
14
|
import "../../chunk-WE4YKBDE.mjs";
|
|
15
15
|
import "../../chunk-H5DTKPJ2.mjs";
|