@wealthx/shadcn 1.2.2 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (229) hide show
  1. package/.turbo/turbo-build.log +200 -156
  2. package/CHANGELOG.md +22 -0
  3. package/dist/{chunk-4Y6R4WEC.mjs → chunk-2A5RRQGG.mjs} +9 -22
  4. package/dist/{chunk-TS2ZX2VS.mjs → chunk-2UM72RJ7.mjs} +11 -15
  5. package/dist/{chunk-A56YQQHG.mjs → chunk-3NCUZIFP.mjs} +2 -2
  6. package/dist/chunk-3OYFOX3X.mjs +79 -0
  7. package/dist/{chunk-RP3SQYA3.mjs → chunk-3TTACBDP.mjs} +9 -4
  8. package/dist/chunk-4GAWMKMI.mjs +710 -0
  9. package/dist/{chunk-VGSESELX.mjs → chunk-5FQIKDKP.mjs} +5 -5
  10. package/dist/{chunk-K3JYD4IU.mjs → chunk-5IS7G74I.mjs} +11 -4
  11. package/dist/chunk-6AW4KJHE.mjs +235 -0
  12. package/dist/chunk-6CR5N2JW.mjs +302 -0
  13. package/dist/{chunk-XIRTEFKH.mjs → chunk-6DZEXFNB.mjs} +36 -8
  14. package/dist/chunk-6O6KD7CE.mjs +271 -0
  15. package/dist/chunk-7PV3IWCN.mjs +33 -0
  16. package/dist/{chunk-SPJ5KXW7.mjs → chunk-7S5AESZO.mjs} +5 -5
  17. package/dist/{chunk-RYCLWMZ7.mjs → chunk-ABFDMHOR.mjs} +9 -7
  18. package/dist/{chunk-SWGT756Z.mjs → chunk-AMQZRHEZ.mjs} +10 -4
  19. package/dist/{chunk-WAZD7NFU.mjs → chunk-BKNFWEH2.mjs} +6 -6
  20. package/dist/{chunk-CLIN5525.mjs → chunk-C7CQJNMR.mjs} +1 -1
  21. package/dist/{chunk-D4ILTPOG.mjs → chunk-CFMQP5QS.mjs} +5 -4
  22. package/dist/{chunk-VPBN3WOO.mjs → chunk-DGHAXJBN.mjs} +9 -7
  23. package/dist/chunk-DOEO3CDL.mjs +27 -0
  24. package/dist/{chunk-5MEWU56Z.mjs → chunk-DUJTAXMH.mjs} +11 -6
  25. package/dist/{chunk-GGM2UYGG.mjs → chunk-EBXQWIYG.mjs} +10 -4
  26. package/dist/chunk-EWRB4PAD.mjs +468 -0
  27. package/dist/{chunk-ZSHYDDRB.mjs → chunk-FAKPBKLT.mjs} +6 -2
  28. package/dist/chunk-FNQXOAYJ.mjs +169 -0
  29. package/dist/{chunk-A6AAWBPF.mjs → chunk-GHC7LLUX.mjs} +13 -4
  30. package/dist/chunk-HBZLGDIN.mjs +507 -0
  31. package/dist/{chunk-SIZMLSRU.mjs → chunk-HISNT2MG.mjs} +8 -6
  32. package/dist/{chunk-CGH4DRNG.mjs → chunk-HVY6KCCF.mjs} +10 -7
  33. package/dist/chunk-I3RZS7V2.mjs +136 -0
  34. package/dist/chunk-IAE3F7DR.mjs +1962 -0
  35. package/dist/{chunk-UT4KJR7V.mjs → chunk-IHMFS7NZ.mjs} +35 -74
  36. package/dist/{chunk-PCPLO5HT.mjs → chunk-IOJRDS6V.mjs} +96 -14
  37. package/dist/{chunk-LHYCMLVA.mjs → chunk-JKGDCQTZ.mjs} +11 -4
  38. package/dist/{chunk-H45TKD34.mjs → chunk-JMHR3YGZ.mjs} +1 -1
  39. package/dist/{chunk-4MN6UQHG.mjs → chunk-K5A5L6T2.mjs} +17 -39
  40. package/dist/chunk-LV35NGVG.mjs +272 -0
  41. package/dist/{chunk-FZIXGLMV.mjs → chunk-M3FV7LOK.mjs} +5 -12
  42. package/dist/{chunk-FMAXJ2SI.mjs → chunk-MBON7YRJ.mjs} +1 -1
  43. package/dist/chunk-MIZQHHUO.mjs +441 -0
  44. package/dist/chunk-MN5NYQCL.mjs +29 -0
  45. package/dist/chunk-NL3ZO62D.mjs +31 -0
  46. package/dist/{chunk-Q76O3RIQ.mjs → chunk-NMOI6CQD.mjs} +1 -1
  47. package/dist/{chunk-P6AM5V7O.mjs → chunk-OODBHKG7.mjs} +1 -1
  48. package/dist/chunk-PBL4OQV2.mjs +283 -0
  49. package/dist/{chunk-Y4QFWRNR.mjs → chunk-PU4YZQXV.mjs} +17 -18
  50. package/dist/chunk-QMY3AZJH.mjs +80 -0
  51. package/dist/{chunk-BL3DXM2X.mjs → chunk-QZ4RE6NA.mjs} +11 -4
  52. package/dist/{chunk-VACKZOMY.mjs → chunk-R3VSPKNP.mjs} +3 -3
  53. package/dist/{chunk-OPNQAVVH.mjs → chunk-RJI6GKVF.mjs} +8 -6
  54. package/dist/{chunk-WG6JGJXB.mjs → chunk-T4BJLT57.mjs} +1 -1
  55. package/dist/chunk-UMTOX62O.mjs +415 -0
  56. package/dist/{chunk-7MMXNK3C.mjs → chunk-VLARHE5V.mjs} +8 -6
  57. package/dist/{chunk-2I5S2AMY.mjs → chunk-XREGSKX3.mjs} +2 -2
  58. package/dist/{chunk-JNQORUPP.mjs → chunk-YJG55G2H.mjs} +14 -11
  59. package/dist/{chunk-ZRSDX6OW.mjs → chunk-ZC45IGZO.mjs} +33 -30
  60. package/dist/components/ui/add-column-modal.js +42 -14
  61. package/dist/components/ui/add-column-modal.mjs +5 -5
  62. package/dist/components/ui/add-lead-modal.js +42 -11
  63. package/dist/components/ui/add-lead-modal.mjs +3 -3
  64. package/dist/components/ui/advisor-card.js +497 -0
  65. package/dist/components/ui/advisor-card.mjs +13 -0
  66. package/dist/components/ui/ai-assistant-drawer.js +11 -10
  67. package/dist/components/ui/ai-assistant-drawer.mjs +3 -3
  68. package/dist/components/ui/alert-dialog.js +2 -2
  69. package/dist/components/ui/alert-dialog.mjs +2 -2
  70. package/dist/components/ui/appointment-action-dialogs.js +1160 -0
  71. package/dist/components/ui/appointment-action-dialogs.mjs +23 -0
  72. package/dist/components/ui/appointment-availability-settings.js +1590 -0
  73. package/dist/components/ui/appointment-availability-settings.mjs +23 -0
  74. package/dist/components/ui/appointment-book-dialog.js +1744 -0
  75. package/dist/components/ui/appointment-book-dialog.mjs +27 -0
  76. package/dist/components/ui/appointment-calendar-view.js +833 -0
  77. package/dist/components/ui/appointment-calendar-view.mjs +14 -0
  78. package/dist/components/ui/appointment-detail-sheet.js +1517 -0
  79. package/dist/components/ui/appointment-detail-sheet.mjs +24 -0
  80. package/dist/components/ui/appointment-gmail-connect.js +467 -0
  81. package/dist/components/ui/appointment-gmail-connect.mjs +14 -0
  82. package/dist/components/ui/appointment-mini-card.js +345 -0
  83. package/dist/components/ui/appointment-mini-card.mjs +11 -0
  84. package/dist/components/ui/appointment-time-slot-picker.js +311 -0
  85. package/dist/components/ui/appointment-time-slot-picker.mjs +13 -0
  86. package/dist/components/ui/appointment-upcoming-card.js +1268 -0
  87. package/dist/components/ui/appointment-upcoming-card.mjs +21 -0
  88. package/dist/components/ui/backoffice-alert-history-chart.js +11 -5
  89. package/dist/components/ui/backoffice-alert-history-chart.mjs +5 -4
  90. package/dist/components/ui/backoffice-alerts-chart.js +786 -0
  91. package/dist/components/ui/backoffice-alerts-chart.mjs +19 -0
  92. package/dist/components/ui/backoffice-connections-chart.js +817 -0
  93. package/dist/components/ui/backoffice-connections-chart.mjs +19 -0
  94. package/dist/components/ui/backoffice-contact-history-chart.js +11 -5
  95. package/dist/components/ui/backoffice-contact-history-chart.mjs +5 -4
  96. package/dist/components/ui/badge.js +6 -6
  97. package/dist/components/ui/badge.mjs +1 -1
  98. package/dist/components/ui/borrowing-capacity-line-chart.js +30 -21
  99. package/dist/components/ui/borrowing-capacity-line-chart.mjs +5 -4
  100. package/dist/components/ui/button.js +2 -2
  101. package/dist/components/ui/button.mjs +1 -1
  102. package/dist/components/ui/calendar.js +2 -2
  103. package/dist/components/ui/calendar.mjs +2 -2
  104. package/dist/components/ui/card.js +1 -1
  105. package/dist/components/ui/card.mjs +1 -1
  106. package/dist/components/ui/cash-balance-line-chart.js +31 -23
  107. package/dist/components/ui/cash-balance-line-chart.mjs +5 -4
  108. package/dist/components/ui/cashflow-bar-chart.js +12 -5
  109. package/dist/components/ui/cashflow-bar-chart.mjs +5 -4
  110. package/dist/components/ui/chip.js +97 -18
  111. package/dist/components/ui/chip.mjs +3 -2
  112. package/dist/components/ui/color-picker.js +158 -28
  113. package/dist/components/ui/color-picker.mjs +3 -1
  114. package/dist/components/ui/data-table.js +140 -119
  115. package/dist/components/ui/data-table.mjs +3 -2
  116. package/dist/components/ui/date-picker.js +48 -27
  117. package/dist/components/ui/date-picker.mjs +4 -3
  118. package/dist/components/ui/dialog.js +37 -9
  119. package/dist/components/ui/dialog.mjs +2 -2
  120. package/dist/components/ui/expense-bar-chart.js +12 -5
  121. package/dist/components/ui/expense-bar-chart.mjs +5 -4
  122. package/dist/components/ui/field.mjs +2 -2
  123. package/dist/components/ui/financial-cards.js +322 -155
  124. package/dist/components/ui/financial-cards.mjs +5 -3
  125. package/dist/components/ui/financial-drawers.js +2 -2
  126. package/dist/components/ui/financial-drawers.mjs +3 -3
  127. package/dist/components/ui/financial-sections.js +14 -10
  128. package/dist/components/ui/financial-sections.mjs +6 -5
  129. package/dist/components/ui/income-bar-chart.js +12 -5
  130. package/dist/components/ui/income-bar-chart.mjs +5 -4
  131. package/dist/components/ui/input-group.js +2 -2
  132. package/dist/components/ui/input-group.mjs +2 -2
  133. package/dist/components/ui/kanban-column.js +52 -44
  134. package/dist/components/ui/kanban-column.mjs +7 -5
  135. package/dist/components/ui/opportunity-card.js +52 -44
  136. package/dist/components/ui/opportunity-card.mjs +6 -4
  137. package/dist/components/ui/opportunity-edit-modals.js +1367 -1263
  138. package/dist/components/ui/opportunity-edit-modals.mjs +8 -8
  139. package/dist/components/ui/opportunity-summary-tab.js +2744 -2157
  140. package/dist/components/ui/opportunity-summary-tab.mjs +14 -14
  141. package/dist/components/ui/page-header.js +92 -0
  142. package/dist/components/ui/page-header.mjs +8 -0
  143. package/dist/components/ui/page-top-bar.js +88 -0
  144. package/dist/components/ui/page-top-bar.mjs +8 -0
  145. package/dist/components/ui/pagination.js +303 -19
  146. package/dist/components/ui/pagination.mjs +11 -4
  147. package/dist/components/ui/pipeline-board.js +205 -191
  148. package/dist/components/ui/pipeline-board.mjs +9 -7
  149. package/dist/components/ui/pipeline-dialogs.js +114 -65
  150. package/dist/components/ui/pipeline-dialogs.mjs +7 -6
  151. package/dist/components/ui/pipeline-primitives.js +6 -6
  152. package/dist/components/ui/pipeline-primitives.mjs +2 -2
  153. package/dist/components/ui/property-cashflow-doughnut-chart.js +14 -12
  154. package/dist/components/ui/property-cashflow-doughnut-chart.mjs +5 -4
  155. package/dist/components/ui/property-debt-equity-doughnut-chart.js +14 -12
  156. package/dist/components/ui/property-debt-equity-doughnut-chart.mjs +5 -4
  157. package/dist/components/ui/property-mobile-estimate-line-chart.js +16 -14
  158. package/dist/components/ui/property-mobile-estimate-line-chart.mjs +5 -4
  159. package/dist/components/ui/sidebar-nav.js +234 -95
  160. package/dist/components/ui/sidebar-nav.mjs +4 -1
  161. package/dist/components/ui/stage-timeline.js +6 -6
  162. package/dist/components/ui/stage-timeline.mjs +3 -3
  163. package/dist/components/ui/transactions-expense-categories-doughnut-chart.js +18 -16
  164. package/dist/components/ui/transactions-expense-categories-doughnut-chart.mjs +5 -4
  165. package/dist/components/ui/transactions-income-expense-bar-chart.js +28 -12
  166. package/dist/components/ui/transactions-income-expense-bar-chart.mjs +5 -4
  167. package/dist/components/ui/transactions-liabilities-breakdown-doughnut-chart.js +18 -16
  168. package/dist/components/ui/transactions-liabilities-breakdown-doughnut-chart.mjs +5 -4
  169. package/dist/index.js +12899 -9343
  170. package/dist/index.mjs +256 -190
  171. package/dist/styles.css +1 -1
  172. package/package.json +71 -1
  173. package/src/components/index.tsx +114 -9
  174. package/src/components/ui/add-column-modal.tsx +7 -7
  175. package/src/components/ui/add-lead-modal.tsx +6 -3
  176. package/src/components/ui/advisor-card.tsx +227 -0
  177. package/src/components/ui/ai-assistant-drawer.tsx +4 -3
  178. package/src/components/ui/appointment-action-dialogs.tsx +297 -0
  179. package/src/components/ui/appointment-availability-settings.tsx +645 -0
  180. package/src/components/ui/appointment-book-dialog.tsx +618 -0
  181. package/src/components/ui/appointment-calendar-view.tsx +510 -0
  182. package/src/components/ui/appointment-detail-sheet.tsx +415 -0
  183. package/src/components/ui/appointment-gmail-connect.tsx +188 -0
  184. package/src/components/ui/appointment-mini-card.tsx +104 -0
  185. package/src/components/ui/appointment-time-slot-picker.tsx +123 -0
  186. package/src/components/ui/appointment-upcoming-card.tsx +635 -0
  187. package/src/components/ui/backoffice-alert-history-chart.tsx +10 -2
  188. package/src/components/ui/backoffice-alerts-chart.tsx +312 -0
  189. package/src/components/ui/backoffice-connections-chart.tsx +339 -0
  190. package/src/components/ui/backoffice-contact-history-chart.tsx +10 -2
  191. package/src/components/ui/badge.tsx +12 -6
  192. package/src/components/ui/borrowing-capacity-line-chart.tsx +4 -11
  193. package/src/components/ui/button.tsx +2 -2
  194. package/src/components/ui/card.tsx +1 -1
  195. package/src/components/ui/cash-balance-line-chart.tsx +4 -23
  196. package/src/components/ui/cashflow-bar-chart.tsx +9 -2
  197. package/src/components/ui/chart-shared.tsx +4 -11
  198. package/src/components/ui/chip.tsx +23 -19
  199. package/src/components/ui/color-picker.tsx +4 -2
  200. package/src/components/ui/data-table.tsx +28 -74
  201. package/src/components/ui/date-picker.tsx +42 -37
  202. package/src/components/ui/dialog.tsx +72 -6
  203. package/src/components/ui/expense-bar-chart.tsx +11 -2
  204. package/src/components/ui/financial-cards.tsx +99 -10
  205. package/src/components/ui/income-bar-chart.tsx +11 -2
  206. package/src/components/ui/opportunity-card.tsx +10 -39
  207. package/src/components/ui/opportunity-edit-modals.tsx +98 -36
  208. package/src/components/ui/opportunity-summary-tab.tsx +548 -232
  209. package/src/components/ui/page-header.tsx +57 -0
  210. package/src/components/ui/page-top-bar.tsx +48 -0
  211. package/src/components/ui/pagination.tsx +171 -22
  212. package/src/components/ui/pipeline-board.tsx +12 -5
  213. package/src/components/ui/property-cashflow-doughnut-chart.tsx +3 -1
  214. package/src/components/ui/property-debt-equity-doughnut-chart.tsx +3 -1
  215. package/src/components/ui/property-mobile-estimate-line-chart.tsx +3 -1
  216. package/src/components/ui/sidebar-nav.tsx +36 -37
  217. package/src/components/ui/transactions-expense-categories-doughnut-chart.tsx +3 -1
  218. package/src/components/ui/transactions-income-expense-bar-chart.tsx +12 -9
  219. package/src/components/ui/transactions-liabilities-breakdown-doughnut-chart.tsx +3 -1
  220. package/src/lib/format-currency.ts +44 -0
  221. package/src/lib/format-date.ts +50 -0
  222. package/src/lib/opportunity-constants.ts +12 -0
  223. package/src/styles/globals.css +17 -15
  224. package/src/styles/styles-css.ts +1 -1
  225. package/tsup.config.ts +14 -0
  226. package/dist/chunk-S4QRUQNW.mjs +0 -475
  227. package/dist/chunk-URGMJAE3.mjs +0 -1885
  228. package/dist/chunk-WNGWBVLV.mjs +0 -148
  229. package/dist/{chunk-LLVQKSU3.mjs → chunk-GD4BJDJR.mjs} +3 -3
@@ -0,0 +1,297 @@
1
+ import React from "react";
2
+ import {
3
+ AlertDialog,
4
+ AlertDialogAction,
5
+ AlertDialogCancel,
6
+ AlertDialogContent,
7
+ AlertDialogDescription,
8
+ AlertDialogFooter,
9
+ AlertDialogHeader,
10
+ AlertDialogTitle,
11
+ } from "./alert-dialog";
12
+ import { Button } from "./button";
13
+ import { Calendar as CalendarPicker } from "./calendar";
14
+ import {
15
+ Dialog,
16
+ DialogClose,
17
+ DialogContent,
18
+ DialogDescription,
19
+ DialogFooter,
20
+ DialogHeader,
21
+ DialogTitle,
22
+ } from "./dialog";
23
+ import { Label } from "./label";
24
+ import { Separator } from "./separator";
25
+ import { Textarea } from "./textarea";
26
+ import { Calendar as CalendarIcon, Clock } from "lucide-react";
27
+ import {
28
+ AppointmentSlotSection,
29
+ type AppointmentTimeSlot,
30
+ } from "./appointment-time-slot-picker";
31
+
32
+ // Re-export for consumers who import AppointmentTimeSlot from this module
33
+ export type { AppointmentTimeSlot } from "./appointment-time-slot-picker";
34
+
35
+ // ---------------------------------------------------------------------------
36
+ // AppointmentConfirmDialog
37
+ // ---------------------------------------------------------------------------
38
+
39
+ export type AppointmentConfirmAction = "accept" | "decline";
40
+
41
+ export interface AppointmentConfirmDialogProps {
42
+ open: boolean;
43
+ onOpenChange: (v: boolean) => void;
44
+ action: AppointmentConfirmAction;
45
+ clientName: string;
46
+ onConfirm: (reason?: string) => void;
47
+ }
48
+
49
+ export function AppointmentConfirmDialog({
50
+ open,
51
+ onOpenChange,
52
+ action,
53
+ clientName,
54
+ onConfirm,
55
+ }: AppointmentConfirmDialogProps) {
56
+ const isDecline = action === "decline";
57
+ const [cancelReason, setCancelReason] = React.useState("");
58
+
59
+ const handleOpenChange = (next: boolean) => {
60
+ if (!next) setCancelReason("");
61
+ onOpenChange(next);
62
+ };
63
+
64
+ return (
65
+ <AlertDialog open={open} onOpenChange={handleOpenChange}>
66
+ <AlertDialogContent>
67
+ <AlertDialogHeader>
68
+ <AlertDialogTitle>
69
+ {isDecline
70
+ ? "Decline this appointment?"
71
+ : "Accept this appointment?"}
72
+ </AlertDialogTitle>
73
+ <AlertDialogDescription>
74
+ {isDecline ? (
75
+ <>
76
+ This will cancel the appointment with{" "}
77
+ <strong>{clientName}</strong> and notify them by email. This
78
+ action cannot be undone.
79
+ </>
80
+ ) : (
81
+ <>
82
+ The appointment with <strong>{clientName}</strong> will be
83
+ confirmed and they will be notified by email.
84
+ </>
85
+ )}
86
+ </AlertDialogDescription>
87
+ </AlertDialogHeader>
88
+
89
+ {isDecline && (
90
+ <div className="flex flex-col gap-1.5">
91
+ <Label htmlFor="decline-reason">
92
+ Reason{" "}
93
+ <span className="font-normal text-muted-foreground">
94
+ (optional)
95
+ </span>
96
+ </Label>
97
+ <Textarea
98
+ id="decline-reason"
99
+ placeholder="e.g. Advisor is unavailable at this time…"
100
+ value={cancelReason}
101
+ onChange={(e) => setCancelReason(e.target.value)}
102
+ className="w-full resize-none"
103
+ rows={2}
104
+ />
105
+ </div>
106
+ )}
107
+
108
+ <AlertDialogFooter>
109
+ <AlertDialogCancel>
110
+ {isDecline ? "Keep appointment" : "Cancel"}
111
+ </AlertDialogCancel>
112
+ <AlertDialogAction
113
+ onClick={() => onConfirm(isDecline ? cancelReason : undefined)}
114
+ className={
115
+ isDecline
116
+ ? "bg-destructive text-destructive-foreground hover:bg-destructive/90"
117
+ : undefined
118
+ }
119
+ >
120
+ {isDecline ? "Decline appointment" : "Accept appointment"}
121
+ </AlertDialogAction>
122
+ </AlertDialogFooter>
123
+ </AlertDialogContent>
124
+ </AlertDialog>
125
+ );
126
+ }
127
+
128
+ // ---------------------------------------------------------------------------
129
+ // AppointmentRescheduleDialog
130
+ // ---------------------------------------------------------------------------
131
+
132
+ export interface AppointmentRescheduleDialogProps {
133
+ open: boolean;
134
+ onOpenChange: (v: boolean) => void;
135
+ amSlots: AppointmentTimeSlot[];
136
+ pmSlots: AppointmentTimeSlot[];
137
+ /** Current appointment date — shown as "Current booking" */
138
+ currentDate?: string;
139
+ currentTimeStart?: string;
140
+ currentTimeEnd?: string;
141
+ onReschedule: (date: Date, slot: AppointmentTimeSlot, note: string) => void;
142
+ }
143
+
144
+ export function AppointmentRescheduleDialog({
145
+ open,
146
+ onOpenChange,
147
+ amSlots,
148
+ pmSlots,
149
+ currentDate,
150
+ currentTimeStart,
151
+ currentTimeEnd,
152
+ onReschedule,
153
+ }: AppointmentRescheduleDialogProps) {
154
+ const [date, setDate] = React.useState<Date | undefined>(new Date());
155
+ const [slot, setSlot] = React.useState<AppointmentTimeSlot | undefined>();
156
+ const [note, setNote] = React.useState("");
157
+
158
+ const handleOpenChange = (next: boolean) => {
159
+ if (!next) {
160
+ setDate(new Date());
161
+ setSlot(undefined);
162
+ setNote("");
163
+ }
164
+ onOpenChange(next);
165
+ };
166
+
167
+ const totalAvailable = [...amSlots, ...pmSlots].filter(
168
+ (s) => s.available,
169
+ ).length;
170
+
171
+ return (
172
+ <Dialog open={open} onOpenChange={handleOpenChange}>
173
+ <DialogContent size="2xl">
174
+ <DialogHeader>
175
+ <DialogTitle>Propose New Time</DialogTitle>
176
+ <DialogDescription>
177
+ Select a new date and time slot. The client will be notified by
178
+ email.
179
+ </DialogDescription>
180
+ </DialogHeader>
181
+
182
+ <Separator />
183
+
184
+ {/* Current booking */}
185
+ {(currentDate || currentTimeStart) && (
186
+ <div className="flex flex-col gap-1.5">
187
+ <p className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
188
+ Current booking
189
+ </p>
190
+ <div className="flex items-center gap-4 border border-border bg-muted/30 px-3 py-2.5 text-sm text-muted-foreground">
191
+ {currentDate && (
192
+ <span className="flex items-center gap-1.5">
193
+ <CalendarIcon className="h-3.5 w-3.5 shrink-0" />
194
+ {currentDate}
195
+ </span>
196
+ )}
197
+ {currentTimeStart && (
198
+ <span className="flex items-center gap-1.5">
199
+ <Clock className="h-3.5 w-3.5 shrink-0" />
200
+ {currentTimeStart}
201
+ {currentTimeEnd ? ` – ${currentTimeEnd}` : ""}
202
+ </span>
203
+ )}
204
+ </div>
205
+ </div>
206
+ )}
207
+
208
+ <div className="grid grid-cols-[auto_1fr] items-start gap-5">
209
+ {/* Date picker */}
210
+ <div className="flex flex-col gap-1.5">
211
+ <Label>New date</Label>
212
+ <CalendarPicker
213
+ mode="single"
214
+ selected={date}
215
+ onSelect={(d) => {
216
+ setDate(d);
217
+ setSlot(undefined);
218
+ }}
219
+ captionLayout="label"
220
+ fromDate={new Date()}
221
+ disabled={{ before: new Date() }}
222
+ className="border border-border"
223
+ />
224
+ </div>
225
+
226
+ {/* Time slots */}
227
+ <div className="flex flex-col gap-5">
228
+ {date ? (
229
+ <>
230
+ <div className="flex items-center justify-between">
231
+ <p className="text-sm font-semibold">Select a time slot</p>
232
+ <span className="text-xs text-muted-foreground">
233
+ {totalAvailable} available
234
+ </span>
235
+ </div>
236
+ <AppointmentSlotSection
237
+ label="Morning"
238
+ slots={amSlots}
239
+ selectedSlotId={slot?.id}
240
+ onSelect={setSlot}
241
+ />
242
+ <AppointmentSlotSection
243
+ label="Afternoon"
244
+ slots={pmSlots}
245
+ selectedSlotId={slot?.id}
246
+ onSelect={setSlot}
247
+ />
248
+ </>
249
+ ) : (
250
+ <div className="flex h-full flex-col items-center justify-center gap-2 py-8 text-center">
251
+ <p className="text-sm font-semibold">Select a time slot</p>
252
+ <p className="text-xs text-muted-foreground">
253
+ Pick a date on the left to see available slots.
254
+ </p>
255
+ </div>
256
+ )}
257
+ </div>
258
+ </div>
259
+
260
+ {/* Note — full width */}
261
+ <div className="flex flex-col gap-1.5">
262
+ <Label htmlFor="reschedule-note">
263
+ Note{" "}
264
+ <span className="font-normal text-muted-foreground">
265
+ (optional)
266
+ </span>
267
+ </Label>
268
+ <Textarea
269
+ id="reschedule-note"
270
+ placeholder="e.g. Rescheduling due to an internal conflict — apologies for the inconvenience…"
271
+ value={note}
272
+ onChange={(e) => setNote(e.target.value)}
273
+ className="w-full resize-none"
274
+ rows={2}
275
+ />
276
+ </div>
277
+
278
+ <DialogFooter>
279
+ <DialogClose render={<Button variant="outline" />}>
280
+ Cancel
281
+ </DialogClose>
282
+ <Button
283
+ disabled={!date || !slot}
284
+ onClick={() => {
285
+ if (date && slot) {
286
+ onReschedule(date, slot, note);
287
+ handleOpenChange(false);
288
+ }
289
+ }}
290
+ >
291
+ Propose New Time
292
+ </Button>
293
+ </DialogFooter>
294
+ </DialogContent>
295
+ </Dialog>
296
+ );
297
+ }