@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,415 @@
1
+ import {
2
+ Tabs,
3
+ TabsContent,
4
+ TabsList,
5
+ TabsTrigger
6
+ } from "./chunk-JHJHG4GO.mjs";
7
+ import {
8
+ Avatar,
9
+ AvatarFallback
10
+ } from "./chunk-24FUO7TD.mjs";
11
+ import {
12
+ Badge
13
+ } from "./chunk-BKNFWEH2.mjs";
14
+ import {
15
+ Separator
16
+ } from "./chunk-FH6QVUVZ.mjs";
17
+ import {
18
+ Button
19
+ } from "./chunk-XREGSKX3.mjs";
20
+
21
+ // src/components/ui/appointment-calendar-view.tsx
22
+ import {
23
+ Check,
24
+ ChevronLeft,
25
+ ChevronRight,
26
+ RefreshCw,
27
+ X,
28
+ CalendarClock
29
+ } from "lucide-react";
30
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
31
+ var STATUS_COLORS = {
32
+ pending: "border-l-warning bg-warning/5",
33
+ confirmed: "border-l-success bg-success/5",
34
+ cancelled: "border-l-destructive bg-destructive/5",
35
+ rescheduled: "border-l-info bg-info/5"
36
+ };
37
+ var STATUS_CONFIG = {
38
+ pending: {
39
+ variant: "warning",
40
+ label: "Pending",
41
+ icon: /* @__PURE__ */ jsx(CalendarClock, { size: 12 })
42
+ },
43
+ confirmed: {
44
+ variant: "success",
45
+ label: "Confirmed",
46
+ icon: /* @__PURE__ */ jsx(Check, { size: 12 })
47
+ },
48
+ cancelled: {
49
+ variant: "destructive",
50
+ label: "Cancelled",
51
+ icon: /* @__PURE__ */ jsx(X, { size: 12 })
52
+ },
53
+ rescheduled: {
54
+ variant: "info",
55
+ label: "Rescheduled",
56
+ icon: /* @__PURE__ */ jsx(RefreshCw, { size: 12 })
57
+ }
58
+ };
59
+ function formatHour(h) {
60
+ if (h === 12) return "12 PM";
61
+ return h < 12 ? `${h} AM` : `${h - 12} PM`;
62
+ }
63
+ function getHourFromTime(time) {
64
+ const match = time.match(/^(\d+):/);
65
+ if (!match) return 0;
66
+ const h = parseInt(match[1], 10);
67
+ return time.includes("PM") && h !== 12 ? h + 12 : h;
68
+ }
69
+ var DEFAULT_HOURS = [9, 10, 11, 12, 13, 14, 15, 16, 17];
70
+ function DayView({
71
+ appointments,
72
+ date,
73
+ today,
74
+ hours,
75
+ onSelectAppointment
76
+ }) {
77
+ const d = /* @__PURE__ */ new Date(date + "T00:00:00");
78
+ const dayLabel = d.toLocaleDateString("en-AU", { weekday: "short" }).toUpperCase();
79
+ const dayShort = d.getDate();
80
+ const isToday = date === today;
81
+ const dayApts = appointments.filter((a) => a.date === date);
82
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
83
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[48px_1fr] border-b border-border", children: [
84
+ /* @__PURE__ */ jsx("div", { className: "border-r border-border" }),
85
+ /* @__PURE__ */ jsxs(
86
+ "div",
87
+ {
88
+ className: `flex flex-col items-center gap-1 py-3 ${isToday ? "bg-primary/5" : ""}`,
89
+ children: [
90
+ /* @__PURE__ */ jsx(
91
+ "span",
92
+ {
93
+ className: `text-xs font-medium tracking-wide ${isToday ? "font-semibold text-primary" : "text-muted-foreground"}`,
94
+ children: dayLabel
95
+ }
96
+ ),
97
+ /* @__PURE__ */ jsx(
98
+ "span",
99
+ {
100
+ className: `flex h-10 w-10 items-center justify-center text-xl font-semibold ${isToday ? "bg-primary text-primary-foreground" : ""}`,
101
+ children: dayShort
102
+ }
103
+ )
104
+ ]
105
+ }
106
+ )
107
+ ] }),
108
+ hours.map((hour) => {
109
+ const aptsAtHour = dayApts.filter(
110
+ (a) => getHourFromTime(a.timeStart) === hour
111
+ );
112
+ return /* @__PURE__ */ jsxs(
113
+ "div",
114
+ {
115
+ className: "grid min-h-[60px] grid-cols-[48px_1fr] border-b border-border/40 last:border-b-0",
116
+ children: [
117
+ /* @__PURE__ */ jsx(
118
+ "div",
119
+ {
120
+ className: `flex items-start justify-end border-r border-border pr-2 pt-1 ${isToday ? "bg-primary/5" : ""}`,
121
+ children: /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground", children: formatHour(hour) })
122
+ }
123
+ ),
124
+ /* @__PURE__ */ jsx(
125
+ "div",
126
+ {
127
+ className: `flex flex-col gap-1.5 p-1.5 ${isToday ? "bg-primary/5" : ""}`,
128
+ children: aptsAtHour.map((apt) => /* @__PURE__ */ jsxs(
129
+ Button,
130
+ {
131
+ type: "button",
132
+ variant: "ghost",
133
+ onClick: () => onSelectAppointment == null ? void 0 : onSelectAppointment(apt),
134
+ className: `h-auto w-full justify-start gap-3 border-l-2 px-3 py-2 text-left hover:opacity-80 ${STATUS_COLORS[apt.status]}`,
135
+ children: [
136
+ /* @__PURE__ */ jsx(Avatar, { className: "h-7 w-7 shrink-0", children: /* @__PURE__ */ jsx(AvatarFallback, { className: "text-xs", children: apt.clientAvatarInitials }) }),
137
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col", children: [
138
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold", children: apt.clientName }),
139
+ /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", children: [
140
+ apt.timeStart,
141
+ " \u2013 ",
142
+ apt.timeEnd
143
+ ] })
144
+ ] }),
145
+ /* @__PURE__ */ jsx(Badge, { variant: STATUS_CONFIG[apt.status].variant, children: STATUS_CONFIG[apt.status].label })
146
+ ]
147
+ },
148
+ apt.id
149
+ ))
150
+ }
151
+ )
152
+ ]
153
+ },
154
+ hour
155
+ );
156
+ })
157
+ ] });
158
+ }
159
+ function WeekView({
160
+ appointments,
161
+ weekDays,
162
+ today,
163
+ hours,
164
+ onSelectAppointment
165
+ }) {
166
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col overflow-x-auto", children: [
167
+ /* @__PURE__ */ jsxs(
168
+ "div",
169
+ {
170
+ className: "grid border-b border-border",
171
+ style: { gridTemplateColumns: `48px repeat(${weekDays.length}, 1fr)` },
172
+ children: [
173
+ /* @__PURE__ */ jsx("div", { className: "border-r border-border" }),
174
+ weekDays.map((day) => /* @__PURE__ */ jsxs(
175
+ "div",
176
+ {
177
+ className: `flex flex-col items-center border-r border-border py-2 last:border-r-0 ${day.date === today ? "bg-primary/5" : ""}`,
178
+ children: [
179
+ /* @__PURE__ */ jsx(
180
+ "span",
181
+ {
182
+ className: `text-xs font-medium ${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-sm font-semibold ${day.date === today ? "text-primary" : ""}`,
190
+ children: day.short
191
+ }
192
+ )
193
+ ]
194
+ },
195
+ day.date
196
+ ))
197
+ ]
198
+ }
199
+ ),
200
+ hours.map((hour) => /* @__PURE__ */ jsxs(
201
+ "div",
202
+ {
203
+ className: "grid border-b border-border/40 last:border-b-0",
204
+ style: {
205
+ gridTemplateColumns: `48px repeat(${weekDays.length}, 1fr)`
206
+ },
207
+ children: [
208
+ /* @__PURE__ */ jsx("div", { className: "flex items-start justify-end border-r border-border pr-2 pt-1", children: /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground", children: formatHour(hour) }) }),
209
+ weekDays.map((day) => {
210
+ const aptsAtCell = appointments.filter(
211
+ (a) => a.date === day.date && getHourFromTime(a.timeStart) === hour
212
+ );
213
+ return /* @__PURE__ */ jsx(
214
+ "div",
215
+ {
216
+ className: `min-h-[44px] overflow-hidden border-r border-border/40 p-0.5 last:border-r-0 ${day.date === today ? "bg-primary/5" : ""}`,
217
+ children: aptsAtCell.map((apt) => /* @__PURE__ */ jsxs(
218
+ Button,
219
+ {
220
+ type: "button",
221
+ variant: "ghost",
222
+ className: `h-auto w-full justify-start truncate border-l-2 px-1 py-1 text-left text-xs font-medium hover:opacity-80 ${STATUS_COLORS[apt.status]}`,
223
+ onClick: () => onSelectAppointment == null ? void 0 : onSelectAppointment(apt),
224
+ children: [
225
+ apt.timeStart,
226
+ " ",
227
+ apt.clientName
228
+ ]
229
+ },
230
+ apt.id
231
+ ))
232
+ },
233
+ day.date
234
+ );
235
+ })
236
+ ]
237
+ },
238
+ hour
239
+ ))
240
+ ] });
241
+ }
242
+ var MONTH_DAY_HEADERS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
243
+ function generateMonthGrid(year, month) {
244
+ const firstDay = new Date(year, month, 1);
245
+ const lastDay = new Date(year, month + 1, 0);
246
+ const startDow = firstDay.getDay();
247
+ const grid = [];
248
+ let week = Array.from({ length: startDow }, () => null);
249
+ for (let day = 1; day <= lastDay.getDate(); day++) {
250
+ week.push(new Date(year, month, day));
251
+ if (week.length === 7) {
252
+ grid.push(week);
253
+ week = [];
254
+ }
255
+ }
256
+ if (week.length > 0) {
257
+ while (week.length < 7) week.push(null);
258
+ grid.push(week);
259
+ }
260
+ return grid;
261
+ }
262
+ function MonthView({
263
+ appointments,
264
+ today,
265
+ onSelectAppointment
266
+ }) {
267
+ const todayDate = /* @__PURE__ */ new Date(today + "T00:00:00");
268
+ const grid = generateMonthGrid(todayDate.getFullYear(), todayDate.getMonth());
269
+ const toIso = (d) => d.toISOString().slice(0, 10);
270
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
271
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-7 border-b border-border", children: MONTH_DAY_HEADERS.map((d) => /* @__PURE__ */ jsx(
272
+ "div",
273
+ {
274
+ className: "flex items-center justify-center border-r border-border/40 py-2 last:border-r-0",
275
+ children: /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: d })
276
+ },
277
+ d
278
+ )) }),
279
+ grid.map((week, wi) => /* @__PURE__ */ jsx(
280
+ "div",
281
+ {
282
+ className: "grid grid-cols-7 border-b border-border last:border-b-0",
283
+ children: week.map((day, di) => {
284
+ const iso = day ? toIso(day) : null;
285
+ const dayApts = iso ? appointments.filter((a) => a.date === iso) : [];
286
+ const isToday = iso === today;
287
+ return /* @__PURE__ */ jsx(
288
+ "div",
289
+ {
290
+ className: `min-h-[80px] border-r border-border/40 p-1 last:border-r-0 ${!day ? "bg-muted/20" : ""} ${isToday ? "bg-primary/5" : ""}`,
291
+ children: day && /* @__PURE__ */ jsxs(Fragment, { children: [
292
+ /* @__PURE__ */ jsx(
293
+ "div",
294
+ {
295
+ className: `mb-1 flex h-6 w-6 items-center justify-center text-xs font-semibold ${isToday ? "bg-primary text-primary-foreground" : "text-foreground"}`,
296
+ children: day.getDate()
297
+ }
298
+ ),
299
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
300
+ dayApts.slice(0, 2).map((apt) => /* @__PURE__ */ jsxs(
301
+ Button,
302
+ {
303
+ type: "button",
304
+ variant: "ghost",
305
+ onClick: () => onSelectAppointment == null ? void 0 : onSelectAppointment(apt),
306
+ className: `h-auto w-full justify-start truncate border-l-2 px-1 py-0.5 text-left text-[10px] font-medium hover:opacity-80 ${STATUS_COLORS[apt.status]}`,
307
+ children: [
308
+ apt.timeStart,
309
+ " ",
310
+ apt.clientName
311
+ ]
312
+ },
313
+ apt.id
314
+ )),
315
+ dayApts.length > 2 && /* @__PURE__ */ jsxs("p", { className: "px-1 text-[10px] text-muted-foreground", children: [
316
+ "+",
317
+ dayApts.length - 2,
318
+ " more"
319
+ ] })
320
+ ] })
321
+ ] })
322
+ },
323
+ di
324
+ );
325
+ })
326
+ },
327
+ wi
328
+ ))
329
+ ] });
330
+ }
331
+ function AppointmentCalendarView({
332
+ appointments,
333
+ today,
334
+ periodLabel,
335
+ weekDays,
336
+ hours = DEFAULT_HOURS,
337
+ dayViewDate,
338
+ defaultView = "week",
339
+ onPrev,
340
+ onNext,
341
+ onToday,
342
+ onSelectAppointment,
343
+ toolbarActions
344
+ }) {
345
+ const dayDate = dayViewDate != null ? dayViewDate : today;
346
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col border border-border bg-card", children: [
347
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-4 px-4 py-3", children: [
348
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
349
+ /* @__PURE__ */ jsx(
350
+ Button,
351
+ {
352
+ variant: "outline",
353
+ size: "sm",
354
+ className: "gap-1",
355
+ onClick: onPrev,
356
+ children: /* @__PURE__ */ jsx(ChevronLeft, { className: "h-3.5 w-3.5" })
357
+ }
358
+ ),
359
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: periodLabel }),
360
+ /* @__PURE__ */ jsx(
361
+ Button,
362
+ {
363
+ variant: "outline",
364
+ size: "sm",
365
+ className: "gap-1",
366
+ onClick: onNext,
367
+ children: /* @__PURE__ */ jsx(ChevronRight, { className: "h-3.5 w-3.5" })
368
+ }
369
+ ),
370
+ /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: onToday, children: "Today" })
371
+ ] }),
372
+ toolbarActions && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: toolbarActions })
373
+ ] }),
374
+ /* @__PURE__ */ jsx(Separator, {}),
375
+ /* @__PURE__ */ jsxs(Tabs, { defaultValue: defaultView, className: "flex flex-col", children: [
376
+ /* @__PURE__ */ jsx("div", { className: "px-4 pt-3", children: /* @__PURE__ */ jsxs(TabsList, { children: [
377
+ /* @__PURE__ */ jsx(TabsTrigger, { value: "day", children: "Day" }),
378
+ /* @__PURE__ */ jsx(TabsTrigger, { value: "week", children: "Week" }),
379
+ /* @__PURE__ */ jsx(TabsTrigger, { value: "month", children: "Month" })
380
+ ] }) }),
381
+ /* @__PURE__ */ jsx(TabsContent, { value: "day", className: "mt-0", children: /* @__PURE__ */ jsx(
382
+ DayView,
383
+ {
384
+ appointments,
385
+ date: dayDate,
386
+ today,
387
+ hours,
388
+ onSelectAppointment
389
+ }
390
+ ) }),
391
+ /* @__PURE__ */ jsx(TabsContent, { value: "week", className: "mt-0", children: /* @__PURE__ */ jsx(
392
+ WeekView,
393
+ {
394
+ appointments,
395
+ weekDays,
396
+ today,
397
+ hours,
398
+ onSelectAppointment
399
+ }
400
+ ) }),
401
+ /* @__PURE__ */ jsx(TabsContent, { value: "month", className: "mt-0", children: /* @__PURE__ */ jsx(
402
+ MonthView,
403
+ {
404
+ appointments,
405
+ today,
406
+ onSelectAppointment
407
+ }
408
+ ) })
409
+ ] })
410
+ ] });
411
+ }
412
+
413
+ export {
414
+ AppointmentCalendarView
415
+ };
@@ -8,10 +8,12 @@ import {
8
8
  FALLBACK_PRIMARY,
9
9
  FALLBACK_SECONDARY,
10
10
  FALLBACK_TICK,
11
- formatAbbrev,
12
11
  formatMonthLabel,
13
12
  formatTooltipDate
14
- } from "./chunk-FZIXGLMV.mjs";
13
+ } from "./chunk-M3FV7LOK.mjs";
14
+ import {
15
+ formatCurrencyAbbrev
16
+ } from "./chunk-MN5NYQCL.mjs";
15
17
  import {
16
18
  Empty,
17
19
  EmptyDescription
@@ -22,7 +24,7 @@ import {
22
24
  CardContent,
23
25
  CardHeader,
24
26
  CardTitle
25
- } from "./chunk-CLIN5525.mjs";
27
+ } from "./chunk-C7CQJNMR.mjs";
26
28
  import {
27
29
  useThemeVars
28
30
  } from "./chunk-FEZKMUCF.mjs";
@@ -225,7 +227,7 @@ function PropertyMobileEstimateLineChart({
225
227
  label: (ctx) => {
226
228
  const val = ctx.raw;
227
229
  if (val === 0) return;
228
- return ` ${ctx.dataset.label}: ${formatAbbrev(val)}`;
230
+ return ` ${ctx.dataset.label}: ${formatCurrencyAbbrev(val)}`;
229
231
  }
230
232
  }
231
233
  }
@@ -253,7 +255,7 @@ function PropertyMobileEstimateLineChart({
253
255
  maxTicksLimit: 5,
254
256
  color: FALLBACK_TICK,
255
257
  font: { size: 10 },
256
- callback: (v) => formatAbbrev(Number(v))
258
+ callback: (v) => formatCurrencyAbbrev(Number(v))
257
259
  }
258
260
  }
259
261
  }
@@ -267,7 +269,7 @@ function PropertyMobileEstimateLineChart({
267
269
  style: { maxWidth: width, fontFamily },
268
270
  children: [
269
271
  /* @__PURE__ */ jsxs(CardHeader, { className: "px-3 sm:px-6", children: [
270
- /* @__PURE__ */ jsx(CardTitle, { className: "text-sm sm:text-base", children: title }),
272
+ /* @__PURE__ */ jsx(CardTitle, { className: "text-xs font-semibold uppercase tracking-wide", children: title }),
271
273
  showPeriodSelector && /* @__PURE__ */ jsx(CardAction, { children: /* @__PURE__ */ jsx("div", { className: "flex gap-0.5 sm:gap-1", children: PROPERTY_PERIODS.map((p) => /* @__PURE__ */ jsx(
272
274
  ChartPeriodButton,
273
275
  {
@@ -23,10 +23,10 @@ var buttonVariants = cva(
23
23
  default: "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
24
24
  secondary: "bg-brand-secondary text-brand-secondary-foreground shadow-xs hover:bg-brand-secondary/80 focus-visible:ring-brand-secondary/30",
25
25
  destructive: "bg-destructive text-destructive-foreground shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40",
26
- outline: "border border-input bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
26
+ outline: "border border-input bg-background shadow-xs hover:bg-accent hover:text-accent-foreground focus-visible:ring-border/50 dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
27
27
  "outline-primary": "border border-primary text-foreground bg-transparent shadow-xs hover:bg-primary/5 focus-visible:ring-primary/50",
28
28
  "outline-secondary": "border border-brand-secondary text-brand-secondary bg-transparent shadow-xs hover:bg-brand-secondary/10 focus-visible:ring-brand-secondary/30",
29
- ghost: "hover:bg-accent hover:text-accent-foreground hover:shadow-xs dark:hover:bg-accent/50",
29
+ ghost: "hover:bg-accent hover:text-accent-foreground hover:shadow-xs focus-visible:ring-border/50 dark:hover:bg-accent/50",
30
30
  link: "text-primary underline-offset-4 hover:underline"
31
31
  },
32
32
  size: {
@@ -2,7 +2,10 @@ import {
2
2
  FALLBACK_PRIMARY,
3
3
  FALLBACK_SECONDARY,
4
4
  FALLBACK_TICK
5
- } from "./chunk-FZIXGLMV.mjs";
5
+ } from "./chunk-M3FV7LOK.mjs";
6
+ import {
7
+ formatCurrency
8
+ } from "./chunk-MN5NYQCL.mjs";
6
9
  import {
7
10
  Empty,
8
11
  EmptyDescription
@@ -12,7 +15,7 @@ import {
12
15
  CardContent,
13
16
  CardHeader,
14
17
  CardTitle
15
- } from "./chunk-CLIN5525.mjs";
18
+ } from "./chunk-C7CQJNMR.mjs";
16
19
  import {
17
20
  Spinner
18
21
  } from "./chunk-7YAU5CY6.mjs";
@@ -36,13 +39,13 @@ import {
36
39
  import ChartDataLabels from "chartjs-plugin-datalabels";
37
40
  import { Chart } from "react-chartjs-2";
38
41
  import { jsx, jsxs } from "react/jsx-runtime";
39
- ChartJS.register(CategoryScale, LinearScale, BarController, BarElement, Tooltip);
40
- function formatDollar(value) {
41
- return `$${value.toLocaleString(void 0, {
42
- minimumFractionDigits: 2,
43
- maximumFractionDigits: 2
44
- })}`;
45
- }
42
+ ChartJS.register(
43
+ CategoryScale,
44
+ LinearScale,
45
+ BarController,
46
+ BarElement,
47
+ Tooltip
48
+ );
46
49
  function TransactionsIncomeExpenseBarChart({
47
50
  totalIncome,
48
51
  totalExpense,
@@ -85,7 +88,7 @@ function TransactionsIncomeExpenseBarChart({
85
88
  color: FALLBACK_SECONDARY,
86
89
  textAlign: "left",
87
90
  // Returns array for multi-line: dollar value on line 1, blank on line 2
88
- formatter: (v) => [formatDollar(v), ""]
91
+ formatter: (v) => [formatCurrency(v, { decimals: 2 }), ""]
89
92
  },
90
93
  name: {
91
94
  anchor: "end",
@@ -149,7 +152,7 @@ function TransactionsIncomeExpenseBarChart({
149
152
  className: cn("w-full py-4 sm:py-6 gap-2", className),
150
153
  style: { maxWidth: width, fontFamily },
151
154
  children: [
152
- /* @__PURE__ */ jsx(CardHeader, { className: "px-3 sm:px-6", children: /* @__PURE__ */ jsx(CardTitle, { className: "text-sm sm:text-base", children: title }) }),
155
+ /* @__PURE__ */ jsx(CardHeader, { className: "px-3 sm:px-6", children: /* @__PURE__ */ jsx(CardTitle, { className: "text-xs font-semibold uppercase tracking-wide", children: title }) }),
153
156
  /* @__PURE__ */ jsx(CardContent, { className: "px-3 sm:px-6", children: isLoading ? /* @__PURE__ */ jsx(
154
157
  "div",
155
158
  {