@wealthx/shadcn 1.4.0 → 1.5.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 (430) hide show
  1. package/.turbo/turbo-build.log +360 -180
  2. package/CHANGELOG.md +12 -0
  3. package/dist/chunk-2A53WPEC.mjs +182 -0
  4. package/dist/{chunk-SIVYAI3M.mjs → chunk-2LLFNGJZ.mjs} +15 -15
  5. package/dist/chunk-2QNOPXMQ.mjs +360 -0
  6. package/dist/{chunk-K5QV4TT6.mjs → chunk-2WCIORP7.mjs} +29 -4
  7. package/dist/{chunk-5NF6T2RS.mjs → chunk-3AREQTZU.mjs} +8 -8
  8. package/dist/{chunk-2EM2FRU6.mjs → chunk-3WGFIFP6.mjs} +5 -5
  9. package/dist/{chunk-K4KOD3KR.mjs → chunk-42NEC57Y.mjs} +44 -25
  10. package/dist/{chunk-FL6DZFJK.mjs → chunk-46Q4335I.mjs} +121 -39
  11. package/dist/chunk-4DO3WM7V.mjs +48 -0
  12. package/dist/chunk-5FHBC6DY.mjs +68 -0
  13. package/dist/chunk-5SAYZ4CI.mjs +40 -0
  14. package/dist/chunk-5WMFKQZ6.mjs +180 -0
  15. package/dist/chunk-623YVI5O.mjs +43 -0
  16. package/dist/{chunk-SFH2NJEJ.mjs → chunk-6OSULDEO.mjs} +3 -3
  17. package/dist/{chunk-UALR6JGV.mjs → chunk-6SR4K5T5.mjs} +1 -1
  18. package/dist/{chunk-D2NSIIXG.mjs → chunk-7KT5HPYM.mjs} +11 -11
  19. package/dist/chunk-A6ER36CW.mjs +456 -0
  20. package/dist/{chunk-QX7IFQSF.mjs → chunk-AHKHVBWR.mjs} +4 -4
  21. package/dist/chunk-AHSCWXYJ.mjs +113 -0
  22. package/dist/{chunk-7GWRPXHD.mjs → chunk-AL6GOL2Y.mjs} +1 -1
  23. package/dist/{chunk-OIKBW2QD.mjs → chunk-AUEUTZIC.mjs} +13 -13
  24. package/dist/{chunk-FYPSTTEJ.mjs → chunk-B7DD3ODQ.mjs} +1 -1
  25. package/dist/{chunk-TLAWKTSA.mjs → chunk-BD3DWDT4.mjs} +3 -3
  26. package/dist/{chunk-S2FKV4M5.mjs → chunk-BDESHD25.mjs} +4 -4
  27. package/dist/{chunk-OKTJFDPN.mjs → chunk-BFB3UH7V.mjs} +2 -2
  28. package/dist/{chunk-DGNHGNYH.mjs → chunk-C6SWS7OW.mjs} +1 -1
  29. package/dist/chunk-CDVG7SFT.mjs +271 -0
  30. package/dist/chunk-CUSHAIUL.mjs +109 -0
  31. package/dist/{chunk-QXKGOMUX.mjs → chunk-CW32WTZU.mjs} +4 -4
  32. package/dist/{chunk-SET2ANTY.mjs → chunk-D447W45Z.mjs} +3 -3
  33. package/dist/{chunk-RCAOCHWA.mjs → chunk-DFL5CV75.mjs} +18 -18
  34. package/dist/chunk-DYSVJ473.mjs +162 -0
  35. package/dist/chunk-E3PQDBYI.mjs +288 -0
  36. package/dist/chunk-EMYBNPIA.mjs +83 -0
  37. package/dist/chunk-EUYPMDQG.mjs +348 -0
  38. package/dist/{chunk-XYPW2XA5.mjs → chunk-EW72FINW.mjs} +11 -11
  39. package/dist/chunk-F24U4QQQ.mjs +234 -0
  40. package/dist/{chunk-VB5M6OZQ.mjs → chunk-F4O2YPXJ.mjs} +1 -1
  41. package/dist/chunk-FFXTQTB4.mjs +84 -0
  42. package/dist/{chunk-ZOWL2L5J.mjs → chunk-FYUSF5KO.mjs} +5 -1
  43. package/dist/{chunk-FTPBQVQ6.mjs → chunk-GNER6MCO.mjs} +1 -1
  44. package/dist/{chunk-2D3HQPFN.mjs → chunk-HF4FUBCY.mjs} +5 -5
  45. package/dist/{chunk-RSUIPKGX.mjs → chunk-HNDTLT5X.mjs} +1 -1
  46. package/dist/{chunk-N6Q5IPKT.mjs → chunk-HO6S3ECM.mjs} +46 -18
  47. package/dist/{chunk-L4NSRQ3T.mjs → chunk-HROG643K.mjs} +1 -1
  48. package/dist/chunk-I2EKKSEF.mjs +148 -0
  49. package/dist/{chunk-QTRSCVQ3.mjs → chunk-I3UDLWQ7.mjs} +1 -1
  50. package/dist/{chunk-AE7MASLF.mjs → chunk-IQGKOT7A.mjs} +9 -6
  51. package/dist/chunk-IXR4BQSQ.mjs +290 -0
  52. package/dist/{chunk-4MM7LHM5.mjs → chunk-J5NW5NCT.mjs} +1 -1
  53. package/dist/{chunk-OLKMCXAR.mjs → chunk-JTG5R5YV.mjs} +24 -24
  54. package/dist/chunk-JUBUN65Q.mjs +106 -0
  55. package/dist/chunk-K7TWMLLW.mjs +520 -0
  56. package/dist/{chunk-BOW7U26Y.mjs → chunk-K7WSRWOU.mjs} +4 -4
  57. package/dist/{chunk-NTYQWVLI.mjs → chunk-KAD26MCC.mjs} +1 -1
  58. package/dist/{chunk-KCWNDYPZ.mjs → chunk-KB7MZMED.mjs} +4 -4
  59. package/dist/chunk-KCKYGQVQ.mjs +61 -0
  60. package/dist/{chunk-VY5NEUP7.mjs → chunk-KLJLDNCA.mjs} +1 -1
  61. package/dist/chunk-LLAGF6BA.mjs +49 -0
  62. package/dist/{chunk-G27TSQLQ.mjs → chunk-M4LTX3MH.mjs} +1 -1
  63. package/dist/{chunk-YIZHS72Z.mjs → chunk-MHHA7QGO.mjs} +94 -54
  64. package/dist/{chunk-P2N2PEFY.mjs → chunk-NCUH54IZ.mjs} +4 -4
  65. package/dist/{chunk-PNRUH7JY.mjs → chunk-OECGKCVF.mjs} +5 -5
  66. package/dist/{chunk-YE67AALL.mjs → chunk-OL65UQHQ.mjs} +10 -10
  67. package/dist/{chunk-LQULK2E3.mjs → chunk-OYBIUEGE.mjs} +1 -1
  68. package/dist/{chunk-LR6LHDP3.mjs → chunk-PGR53HMH.mjs} +7 -7
  69. package/dist/chunk-PUJ42INK.mjs +141 -0
  70. package/dist/{chunk-M4VYX2PV.mjs → chunk-PV3Y7QGK.mjs} +2 -2
  71. package/dist/{chunk-UJZ4UHWI.mjs → chunk-PV7PNA6K.mjs} +4 -4
  72. package/dist/{chunk-6HIOM2HL.mjs → chunk-Q35PNFJ7.mjs} +1 -1
  73. package/dist/{chunk-JZY6TNIS.mjs → chunk-Q5SGEIJV.mjs} +27 -27
  74. package/dist/{chunk-ZFCDYW6N.mjs → chunk-QAX6HCUH.mjs} +1 -1
  75. package/dist/chunk-QHJDGB54.mjs +135 -0
  76. package/dist/chunk-QQSOZQOC.mjs +27 -0
  77. package/dist/chunk-RUX3OLVZ.mjs +59 -0
  78. package/dist/{chunk-QOJ2DQD6.mjs → chunk-S4CTM3UE.mjs} +5 -0
  79. package/dist/{chunk-ZEDMKQK2.mjs → chunk-TAX3KL66.mjs} +1 -1
  80. package/dist/chunk-TC43SMIN.mjs +133 -0
  81. package/dist/chunk-TGVXRD53.mjs +174 -0
  82. package/dist/{chunk-K5VHK7CM.mjs → chunk-TLYSVRSK.mjs} +12 -12
  83. package/dist/{chunk-YCWLFG27.mjs → chunk-TOIVHWNC.mjs} +1 -1
  84. package/dist/chunk-TXUBGKB7.mjs +160 -0
  85. package/dist/chunk-UEREFDAE.mjs +75 -0
  86. package/dist/chunk-UTCQN6XU.mjs +123 -0
  87. package/dist/{chunk-37AE3OM5.mjs → chunk-V4CUTCHS.mjs} +4 -4
  88. package/dist/{chunk-THVO2N47.mjs → chunk-VFH632TB.mjs} +9 -9
  89. package/dist/{chunk-3ERBUVHC.mjs → chunk-VJ3GC7W3.mjs} +95 -49
  90. package/dist/{chunk-V6XGXYCJ.mjs → chunk-VLELWBEW.mjs} +4 -4
  91. package/dist/{chunk-FEZKMUCF.mjs → chunk-WDTXHLYM.mjs} +1 -1
  92. package/dist/chunk-WUA546RX.mjs +129 -0
  93. package/dist/chunk-XHGISOX5.mjs +257 -0
  94. package/dist/chunk-XIY5DJXI.mjs +168 -0
  95. package/dist/{chunk-TOWTPLRC.mjs → chunk-XN37434W.mjs} +8 -8
  96. package/dist/{chunk-KLTACJ2G.mjs → chunk-XTWAJWCQ.mjs} +1 -1
  97. package/dist/chunk-Y24TXIFJ.mjs +518 -0
  98. package/dist/{chunk-DMXYRCHM.mjs → chunk-Y6UM3VTN.mjs} +4 -4
  99. package/dist/components/ui/about-you-form.js +1120 -0
  100. package/dist/components/ui/about-you-form.mjs +323 -0
  101. package/dist/components/ui/account-list-carousel.js +304 -0
  102. package/dist/components/ui/account-list-carousel.mjs +11 -0
  103. package/dist/components/ui/add-column-modal.js +1 -1
  104. package/dist/components/ui/add-column-modal.mjs +6 -6
  105. package/dist/components/ui/add-lead-modal.js +2 -2
  106. package/dist/components/ui/add-lead-modal.mjs +6 -6
  107. package/dist/components/ui/advisor-card.mjs +2 -2
  108. package/dist/components/ui/agent-evaluation-toast.js +299 -0
  109. package/dist/components/ui/agent-evaluation-toast.mjs +12 -0
  110. package/dist/components/ui/ai-assistant-drawer.mjs +5 -5
  111. package/dist/components/ui/ai-builder.js +3 -3
  112. package/dist/components/ui/ai-builder.mjs +5 -5
  113. package/dist/components/ui/ai-conversations.js +2 -2
  114. package/dist/components/ui/ai-conversations.mjs +11 -11
  115. package/dist/components/ui/alert-dialog.mjs +3 -3
  116. package/dist/components/ui/applicant-document-checklist.js +346 -0
  117. package/dist/components/ui/applicant-document-checklist.mjs +10 -0
  118. package/dist/components/ui/applicant-expenses-section.js +455 -0
  119. package/dist/components/ui/applicant-expenses-section.mjs +220 -0
  120. package/dist/components/ui/applicant-navigation-bar.js +309 -0
  121. package/dist/components/ui/applicant-navigation-bar.mjs +87 -0
  122. package/dist/components/ui/applicant-switcher.js +268 -0
  123. package/dist/components/ui/applicant-switcher.mjs +46 -0
  124. package/dist/components/ui/application-mobile-layout.js +88 -0
  125. package/dist/components/ui/application-mobile-layout.mjs +8 -0
  126. package/dist/components/ui/appointment-action-dialogs.js +1 -1
  127. package/dist/components/ui/appointment-action-dialogs.mjs +10 -10
  128. package/dist/components/ui/appointment-availability-settings.js +78 -31
  129. package/dist/components/ui/appointment-availability-settings.mjs +12 -10
  130. package/dist/components/ui/appointment-book-dialog.js +137 -58
  131. package/dist/components/ui/appointment-book-dialog.mjs +14 -14
  132. package/dist/components/ui/appointment-calendar-view.js +1 -1
  133. package/dist/components/ui/appointment-calendar-view.mjs +4 -4
  134. package/dist/components/ui/appointment-detail-sheet.js +38 -11
  135. package/dist/components/ui/appointment-detail-sheet.mjs +13 -13
  136. package/dist/components/ui/appointment-gmail-connect.mjs +2 -2
  137. package/dist/components/ui/appointment-time-slot-picker.mjs +2 -2
  138. package/dist/components/ui/appointment-upcoming-card.js +1 -1
  139. package/dist/components/ui/appointment-upcoming-card.mjs +10 -10
  140. package/dist/components/ui/asset-accordion.js +506 -0
  141. package/dist/components/ui/asset-accordion.mjs +202 -0
  142. package/dist/components/ui/assets-liabilities-side-card.js +328 -0
  143. package/dist/components/ui/assets-liabilities-side-card.mjs +127 -0
  144. package/dist/components/ui/auth-page-layout.js +3 -3
  145. package/dist/components/ui/auth-page-layout.mjs +1 -1
  146. package/dist/components/ui/backoffice-alert-history-chart.mjs +4 -4
  147. package/dist/components/ui/backoffice-alert-matching-chart.js +786 -0
  148. package/dist/components/ui/backoffice-alert-matching-chart.mjs +19 -0
  149. package/dist/components/ui/backoffice-alerts-chart.mjs +4 -4
  150. package/dist/components/ui/backoffice-connections-chart.mjs +4 -4
  151. package/dist/components/ui/backoffice-contact-history-chart.mjs +4 -4
  152. package/dist/components/ui/backoffice-contact-matching-chart.js +803 -0
  153. package/dist/components/ui/backoffice-contact-matching-chart.mjs +19 -0
  154. package/dist/components/ui/backoffice-signup-steps.js +1673 -0
  155. package/dist/components/ui/backoffice-signup-steps.mjs +36 -0
  156. package/dist/components/ui/bank-statement-document-table.js +467 -0
  157. package/dist/components/ui/bank-statement-document-table.mjs +12 -0
  158. package/dist/components/ui/bank-statement-generate-dialog.js +1517 -0
  159. package/dist/components/ui/bank-statement-generate-dialog.mjs +27 -0
  160. package/dist/components/ui/bank-statement-pdf-viewer.js +525 -0
  161. package/dist/components/ui/bank-statement-pdf-viewer.mjs +14 -0
  162. package/dist/components/ui/banking-accounts-connect.js +336 -0
  163. package/dist/components/ui/banking-accounts-connect.mjs +114 -0
  164. package/dist/components/ui/borrowing-capacity-atoms.js +382 -0
  165. package/dist/components/ui/borrowing-capacity-atoms.mjs +17 -0
  166. package/dist/components/ui/borrowing-capacity-card.js +835 -0
  167. package/dist/components/ui/borrowing-capacity-card.mjs +89 -0
  168. package/dist/components/ui/borrowing-capacity-line-chart.mjs +4 -4
  169. package/dist/components/ui/broker-info-panel.js +281 -0
  170. package/dist/components/ui/broker-info-panel.mjs +59 -0
  171. package/dist/components/ui/calculator-input-item.js +101 -0
  172. package/dist/components/ui/calculator-input-item.mjs +8 -0
  173. package/dist/components/ui/calculator-section.js +743 -0
  174. package/dist/components/ui/calculator-section.mjs +220 -0
  175. package/dist/components/ui/calendar.mjs +2 -2
  176. package/dist/components/ui/cash-balance-line-chart.mjs +5 -5
  177. package/dist/components/ui/cashflow-bar-chart.mjs +4 -4
  178. package/dist/components/ui/category-edit-dialog.js +737 -0
  179. package/dist/components/ui/category-edit-dialog.mjs +16 -0
  180. package/dist/components/ui/chat-widget.mjs +3 -3
  181. package/dist/components/ui/color-picker.mjs +4 -4
  182. package/dist/components/ui/connect-bank-step.js +511 -0
  183. package/dist/components/ui/connect-bank-step.mjs +287 -0
  184. package/dist/components/ui/contact-alert-dialog.js +1405 -0
  185. package/dist/components/ui/contact-alert-dialog.mjs +27 -0
  186. package/dist/components/ui/create-contact-modal.js +1028 -0
  187. package/dist/components/ui/create-contact-modal.mjs +21 -0
  188. package/dist/components/ui/csv-import-modal.js +583 -0
  189. package/dist/components/ui/csv-import-modal.mjs +14 -0
  190. package/dist/components/ui/currency-input.js +439 -0
  191. package/dist/components/ui/currency-input.mjs +13 -0
  192. package/dist/components/ui/dashboard-expense-categories.js +355 -0
  193. package/dist/components/ui/dashboard-expense-categories.mjs +186 -0
  194. package/dist/components/ui/dashboard-transactions-table.js +1083 -0
  195. package/dist/components/ui/dashboard-transactions-table.mjs +177 -0
  196. package/dist/components/ui/data-table.mjs +6 -6
  197. package/dist/components/ui/date-picker.mjs +6 -6
  198. package/dist/components/ui/debt-accordion.js +523 -0
  199. package/dist/components/ui/debt-accordion.mjs +219 -0
  200. package/dist/components/ui/delete-contact-component.js +479 -0
  201. package/dist/components/ui/delete-contact-component.mjs +14 -0
  202. package/dist/components/ui/dialog.js +1 -1
  203. package/dist/components/ui/dialog.mjs +3 -3
  204. package/dist/components/ui/document-checklist-template.mjs +4 -4
  205. package/dist/components/ui/drawer.mjs +3 -3
  206. package/dist/components/ui/dropdown-menu.mjs +3 -3
  207. package/dist/components/ui/dynamic-tabs.js +274 -0
  208. package/dist/components/ui/dynamic-tabs.mjs +116 -0
  209. package/dist/components/ui/editable-money-item.js +306 -0
  210. package/dist/components/ui/editable-money-item.mjs +12 -0
  211. package/dist/components/ui/expense-bar-chart.mjs +4 -4
  212. package/dist/components/ui/expense-detail-item.js +506 -0
  213. package/dist/components/ui/expense-detail-item.mjs +15 -0
  214. package/dist/components/ui/expense-work-details.js +1259 -0
  215. package/dist/components/ui/expense-work-details.mjs +175 -0
  216. package/dist/components/ui/field.mjs +2 -2
  217. package/dist/components/ui/file-preview-dialog.js +704 -0
  218. package/dist/components/ui/file-preview-dialog.mjs +17 -0
  219. package/dist/components/ui/financial-cards.mjs +2 -2
  220. package/dist/components/ui/financial-drawers.js +1 -1
  221. package/dist/components/ui/financial-drawers.mjs +5 -5
  222. package/dist/components/ui/financial-sections.mjs +4 -4
  223. package/dist/components/ui/form-primitives.mjs +2 -2
  224. package/dist/components/ui/frontend-signup-steps.js +1239 -0
  225. package/dist/components/ui/frontend-signup-steps.mjs +38 -0
  226. package/dist/components/ui/income-bar-chart.mjs +4 -4
  227. package/dist/components/ui/income-sources-card.js +269 -0
  228. package/dist/components/ui/income-sources-card.mjs +100 -0
  229. package/dist/components/ui/income-summary-component.js +361 -0
  230. package/dist/components/ui/income-summary-component.mjs +84 -0
  231. package/dist/components/ui/income-work-details.js +1663 -0
  232. package/dist/components/ui/income-work-details.mjs +28 -0
  233. package/dist/components/ui/incoming-outgoings-card.js +218 -0
  234. package/dist/components/ui/incoming-outgoings-card.mjs +82 -0
  235. package/dist/components/ui/interest-rate-input.js +442 -0
  236. package/dist/components/ui/interest-rate-input.mjs +90 -0
  237. package/dist/components/ui/interest-rate-section.js +337 -0
  238. package/dist/components/ui/interest-rate-section.mjs +84 -0
  239. package/dist/components/ui/interest-rate-used.js +202 -0
  240. package/dist/components/ui/interest-rate-used.mjs +62 -0
  241. package/dist/components/ui/kanban-column.js +338 -160
  242. package/dist/components/ui/kanban-column.mjs +13 -11
  243. package/dist/components/ui/loan-applicant-information.js +336 -0
  244. package/dist/components/ui/loan-applicant-information.mjs +59 -0
  245. package/dist/components/ui/loan-applicant-invite.js +319 -0
  246. package/dist/components/ui/loan-applicant-invite.mjs +68 -0
  247. package/dist/components/ui/loan-application-badge.js +236 -0
  248. package/dist/components/ui/loan-application-badge.mjs +10 -0
  249. package/dist/components/ui/loan-application-cards.js +356 -0
  250. package/dist/components/ui/loan-application-cards.mjs +110 -0
  251. package/dist/components/ui/loan-entry-shell.js +104 -0
  252. package/dist/components/ui/loan-entry-shell.mjs +8 -0
  253. package/dist/components/ui/loan-financials.js +410 -0
  254. package/dist/components/ui/loan-financials.mjs +76 -0
  255. package/dist/components/ui/loan-option-card.js +102 -0
  256. package/dist/components/ui/loan-option-card.mjs +41 -0
  257. package/dist/components/ui/loan-option-group.js +288 -0
  258. package/dist/components/ui/loan-option-group.mjs +10 -0
  259. package/dist/components/ui/loan-steps.js +1121 -0
  260. package/dist/components/ui/loan-steps.mjs +509 -0
  261. package/dist/components/ui/loan-wizard-shell.js +452 -0
  262. package/dist/components/ui/loan-wizard-shell.mjs +11 -0
  263. package/dist/components/ui/money-input-with-slider.js +210 -0
  264. package/dist/components/ui/money-input-with-slider.mjs +10 -0
  265. package/dist/components/ui/money-item-with-color-indicator.js +314 -0
  266. package/dist/components/ui/money-item-with-color-indicator.mjs +20 -0
  267. package/dist/components/ui/opportunity-card.js +235 -97
  268. package/dist/components/ui/opportunity-card.mjs +11 -9
  269. package/dist/components/ui/opportunity-edit-modals.js +1 -1
  270. package/dist/components/ui/opportunity-edit-modals.mjs +15 -15
  271. package/dist/components/ui/opportunity-summary-tab.js +1 -1
  272. package/dist/components/ui/opportunity-summary-tab.mjs +19 -19
  273. package/dist/components/ui/pagination.mjs +4 -4
  274. package/dist/components/ui/password-strength-tooltip.mjs +4 -4
  275. package/dist/components/ui/pipeline-board.js +358 -176
  276. package/dist/components/ui/pipeline-board.mjs +16 -14
  277. package/dist/components/ui/pipeline-chart.mjs +3 -3
  278. package/dist/components/ui/pipeline-dialogs.js +1 -1
  279. package/dist/components/ui/pipeline-dialogs.mjs +9 -9
  280. package/dist/components/ui/pipeline-primitives.js +75 -8
  281. package/dist/components/ui/pipeline-primitives.mjs +3 -2
  282. package/dist/components/ui/popover.mjs +3 -3
  283. package/dist/components/ui/property-asset-card.js +428 -0
  284. package/dist/components/ui/property-asset-card.mjs +156 -0
  285. package/dist/components/ui/property-cashflow-doughnut-chart.mjs +4 -4
  286. package/dist/components/ui/property-debt-equity-doughnut-chart.mjs +4 -4
  287. package/dist/components/ui/property-list-carousel.js +295 -0
  288. package/dist/components/ui/property-list-carousel.mjs +11 -0
  289. package/dist/components/ui/property-mobile-estimate-line-chart.mjs +4 -4
  290. package/dist/components/ui/property-report-dialog.js +1148 -0
  291. package/dist/components/ui/property-report-dialog.mjs +25 -0
  292. package/dist/components/ui/resource-center.js +748 -0
  293. package/dist/components/ui/resource-center.mjs +24 -0
  294. package/dist/components/ui/review-alerts-dialog.js +569 -0
  295. package/dist/components/ui/review-alerts-dialog.mjs +15 -0
  296. package/dist/components/ui/savings-goal-modal.js +1148 -0
  297. package/dist/components/ui/savings-goal-modal.mjs +160 -0
  298. package/dist/components/ui/scenario-drawer.js +791 -0
  299. package/dist/components/ui/scenario-drawer.mjs +294 -0
  300. package/dist/components/ui/scenario-item.js +256 -0
  301. package/dist/components/ui/scenario-item.mjs +11 -0
  302. package/dist/components/ui/scenario-list.js +507 -0
  303. package/dist/components/ui/scenario-list.mjs +100 -0
  304. package/dist/components/ui/select.mjs +3 -3
  305. package/dist/components/ui/share-details-dialog.js +636 -0
  306. package/dist/components/ui/share-details-dialog.mjs +19 -0
  307. package/dist/components/ui/sheet.mjs +3 -3
  308. package/dist/components/ui/sidebar-nav.mjs +5 -5
  309. package/dist/components/ui/signup-form-primitives.js +770 -0
  310. package/dist/components/ui/signup-form-primitives.mjs +25 -0
  311. package/dist/components/ui/signup-shell.js +338 -0
  312. package/dist/components/ui/signup-shell.mjs +13 -0
  313. package/dist/components/ui/stage-timeline.js +103 -33
  314. package/dist/components/ui/stage-timeline.mjs +5 -4
  315. package/dist/components/ui/submission-confirmation-card.js +284 -0
  316. package/dist/components/ui/submission-confirmation-card.mjs +62 -0
  317. package/dist/components/ui/tooltip.mjs +3 -3
  318. package/dist/components/ui/top-three-product.js +374 -0
  319. package/dist/components/ui/top-three-product.mjs +129 -0
  320. package/dist/components/ui/transactions-expense-categories-doughnut-chart.mjs +4 -4
  321. package/dist/components/ui/transactions-income-expense-bar-chart.mjs +5 -5
  322. package/dist/components/ui/transactions-liabilities-breakdown-doughnut-chart.mjs +4 -4
  323. package/dist/components/ui/transactions-summary-block.js +95 -0
  324. package/dist/components/ui/transactions-summary-block.mjs +34 -0
  325. package/dist/components/ui/two-fa-setup-form.mjs +3 -3
  326. package/dist/index.js +9430 -4573
  327. package/dist/index.mjs +404 -251
  328. package/dist/lib/colors.js +6 -0
  329. package/dist/lib/colors.mjs +3 -1
  330. package/dist/lib/theme-provider.mjs +2 -2
  331. package/dist/styles.css +1 -1
  332. package/package.json +366 -2
  333. package/src/components/index.tsx +223 -0
  334. package/src/components/ui/about-you-form.tsx +397 -0
  335. package/src/components/ui/account-list-carousel.tsx +87 -0
  336. package/src/components/ui/add-lead-modal.tsx +1 -1
  337. package/src/components/ui/agent-evaluation-toast.tsx +191 -0
  338. package/src/components/ui/ai-builder.tsx +3 -5
  339. package/src/components/ui/ai-conversations.tsx +1 -1
  340. package/src/components/ui/applicant-document-checklist.tsx +175 -0
  341. package/src/components/ui/applicant-expenses-section.tsx +260 -0
  342. package/src/components/ui/applicant-navigation-bar.tsx +104 -0
  343. package/src/components/ui/applicant-switcher.tsx +54 -0
  344. package/src/components/ui/application-mobile-layout.tsx +34 -0
  345. package/src/components/ui/appointment-availability-settings.tsx +115 -23
  346. package/src/components/ui/appointment-book-dialog.tsx +406 -259
  347. package/src/components/ui/appointment-calendar-view.tsx +4 -1
  348. package/src/components/ui/appointment-detail-sheet.tsx +59 -24
  349. package/src/components/ui/appointment-time-slot-picker.tsx +5 -1
  350. package/src/components/ui/asset-accordion.tsx +241 -0
  351. package/src/components/ui/assets-liabilities-side-card.tsx +157 -0
  352. package/src/components/ui/auth-page-layout.tsx +3 -3
  353. package/src/components/ui/backoffice-alert-matching-chart.tsx +320 -0
  354. package/src/components/ui/backoffice-contact-matching-chart.tsx +341 -0
  355. package/src/components/ui/backoffice-signup-steps.tsx +615 -0
  356. package/src/components/ui/bank-statement-document-table.tsx +222 -0
  357. package/src/components/ui/bank-statement-generate-dialog.tsx +435 -0
  358. package/src/components/ui/bank-statement-pdf-viewer.tsx +241 -0
  359. package/src/components/ui/banking-accounts-connect.tsx +187 -0
  360. package/src/components/ui/borrowing-capacity-atoms.tsx +228 -0
  361. package/src/components/ui/borrowing-capacity-card.tsx +155 -0
  362. package/src/components/ui/broker-info-panel.tsx +94 -0
  363. package/src/components/ui/calculator-input-item.tsx +49 -0
  364. package/src/components/ui/calculator-section.tsx +275 -0
  365. package/src/components/ui/category-edit-dialog.tsx +300 -0
  366. package/src/components/ui/connect-bank-step.tsx +379 -0
  367. package/src/components/ui/contact-alert-dialog.tsx +710 -0
  368. package/src/components/ui/create-contact-modal.tsx +237 -0
  369. package/src/components/ui/csv-import-modal.tsx +153 -0
  370. package/src/components/ui/currency-input.tsx +104 -0
  371. package/src/components/ui/dashboard-expense-categories.tsx +262 -0
  372. package/src/components/ui/dashboard-transactions-table.tsx +241 -0
  373. package/src/components/ui/debt-accordion.tsx +254 -0
  374. package/src/components/ui/delete-contact-component.tsx +87 -0
  375. package/src/components/ui/dialog.tsx +2 -2
  376. package/src/components/ui/dynamic-tabs.tsx +149 -0
  377. package/src/components/ui/editable-money-item.tsx +176 -0
  378. package/src/components/ui/expense-detail-item.tsx +216 -0
  379. package/src/components/ui/expense-work-details.tsx +229 -0
  380. package/src/components/ui/file-preview-dialog.tsx +292 -0
  381. package/src/components/ui/financial-drawers.tsx +1 -1
  382. package/src/components/ui/frontend-signup-steps.tsx +548 -0
  383. package/src/components/ui/income-sources-card.tsx +143 -0
  384. package/src/components/ui/income-summary-component.tsx +120 -0
  385. package/src/components/ui/income-work-details.tsx +429 -0
  386. package/src/components/ui/incoming-outgoings-card.tsx +111 -0
  387. package/src/components/ui/interest-rate-input.tsx +111 -0
  388. package/src/components/ui/interest-rate-section.tsx +158 -0
  389. package/src/components/ui/interest-rate-used.tsx +82 -0
  390. package/src/components/ui/kanban-column.tsx +53 -2
  391. package/src/components/ui/loan-applicant-information.tsx +64 -0
  392. package/src/components/ui/loan-applicant-invite.tsx +67 -0
  393. package/src/components/ui/loan-application-badge.tsx +70 -0
  394. package/src/components/ui/loan-application-cards.tsx +152 -0
  395. package/src/components/ui/loan-entry-shell.tsx +86 -0
  396. package/src/components/ui/loan-financials.tsx +77 -0
  397. package/src/components/ui/loan-option-card.tsx +62 -0
  398. package/src/components/ui/loan-option-group.tsx +106 -0
  399. package/src/components/ui/loan-steps.tsx +630 -0
  400. package/src/components/ui/loan-wizard-shell.tsx +235 -0
  401. package/src/components/ui/money-input-with-slider.tsx +77 -0
  402. package/src/components/ui/money-item-with-color-indicator.tsx +30 -0
  403. package/src/components/ui/opportunity-card.tsx +46 -18
  404. package/src/components/ui/pipeline-board.tsx +13 -0
  405. package/src/components/ui/pipeline-primitives.tsx +28 -0
  406. package/src/components/ui/property-asset-card.tsx +221 -0
  407. package/src/components/ui/property-list-carousel.tsx +73 -0
  408. package/src/components/ui/property-report-dialog.tsx +355 -0
  409. package/src/components/ui/resource-center.tsx +539 -0
  410. package/src/components/ui/review-alerts-dialog.tsx +163 -0
  411. package/src/components/ui/savings-goal-modal.tsx +169 -0
  412. package/src/components/ui/scenario-drawer.tsx +358 -0
  413. package/src/components/ui/scenario-item.tsx +141 -0
  414. package/src/components/ui/scenario-list.tsx +150 -0
  415. package/src/components/ui/share-details-dialog.tsx +238 -0
  416. package/src/components/ui/signup-form-primitives.tsx +212 -0
  417. package/src/components/ui/signup-shell.tsx +180 -0
  418. package/src/components/ui/stage-timeline.tsx +11 -0
  419. package/src/components/ui/submission-confirmation-card.tsx +68 -0
  420. package/src/components/ui/top-three-product.tsx +207 -0
  421. package/src/components/ui/transactions-summary-block.tsx +59 -0
  422. package/src/lib/colors.ts +12 -0
  423. package/src/lib/format-date.ts +2 -2
  424. package/src/styles/styles-css.ts +1 -1
  425. package/tsup.config.ts +77 -1
  426. package/dist/{chunk-5VOTTIXF.mjs → chunk-FRT3S72S.mjs} +3 -3
  427. package/dist/{chunk-7BTFGCFC.mjs → chunk-MUV4EGDW.mjs} +3 -3
  428. package/dist/{chunk-57ZXILTS.mjs → chunk-MXP2RX2V.mjs} +3 -3
  429. package/dist/{chunk-ZKWXDQDG.mjs → chunk-VCDGLN25.mjs} +3 -3
  430. package/dist/{chunk-FLL633WS.mjs → chunk-ZXEUBBHJ.mjs} +3 -3
@@ -0,0 +1,539 @@
1
+ import React, { useRef, useState } from "react";
2
+ import { ChevronLeft, ChevronRight, Download, Play } from "lucide-react";
3
+ import { cn } from "@/lib/utils";
4
+ import { Badge } from "@/components/ui/badge";
5
+ import { Button } from "@/components/ui/button";
6
+ import {
7
+ Dialog,
8
+ DialogContent,
9
+ DialogHeader,
10
+ DialogTitle,
11
+ } from "@/components/ui/dialog";
12
+
13
+ /**
14
+ * Resource Center — WealthX Backoffice
15
+ *
16
+ * Full-page resource hub with video cards, email template cards, document cards,
17
+ * a hero header, and a generic carousel container.
18
+ *
19
+ * Component hierarchy:
20
+ * Atom → (no separate atoms — primitives inlined per co-located pattern)
21
+ * Molecule → ResourceVideoCard, ResourceEmailTemplateCard, ResourceDocumentCard
22
+ * Organism → ResourceModal, ResourceCarousel, ResourceCenterHeader
23
+ * Template → (composed by consumers)
24
+ */
25
+
26
+ // ---------------------------------------------------------------------------
27
+ // ResourceModal
28
+ // ---------------------------------------------------------------------------
29
+
30
+ export interface ResourceModalAttachment {
31
+ name: string;
32
+ url: string;
33
+ type?: string;
34
+ }
35
+
36
+ export interface ResourceModalProps {
37
+ open: boolean;
38
+ onClose: () => void;
39
+ title: string;
40
+ videoUrl?: string;
41
+ tags?: string[];
42
+ attachments?: ResourceModalAttachment[];
43
+ }
44
+
45
+ export function ResourceModal({
46
+ open,
47
+ onClose,
48
+ title,
49
+ videoUrl,
50
+ tags,
51
+ attachments,
52
+ }: ResourceModalProps) {
53
+ return (
54
+ <Dialog open={open} onOpenChange={(v) => !v && onClose()}>
55
+ <DialogContent
56
+ size="2xl"
57
+ className="flex flex-col gap-4 p-0 overflow-hidden"
58
+ >
59
+ <DialogHeader className="px-6 pt-6 pb-0">
60
+ <DialogTitle className="text-lg font-semibold">{title}</DialogTitle>
61
+ {tags && tags.length > 0 && (
62
+ <div className="flex flex-wrap gap-1.5 pt-1">
63
+ {tags.map((tag) => (
64
+ <Badge key={tag} variant="secondary" className="text-xs">
65
+ {tag}
66
+ </Badge>
67
+ ))}
68
+ </div>
69
+ )}
70
+ </DialogHeader>
71
+
72
+ {videoUrl && (
73
+ <div className="aspect-video w-full bg-foreground">
74
+ <iframe
75
+ src={videoUrl}
76
+ title={title}
77
+ className="h-full w-full"
78
+ allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
79
+ allowFullScreen
80
+ />
81
+ </div>
82
+ )}
83
+
84
+ {attachments && attachments.length > 0 && (
85
+ <div className="flex flex-col gap-2 px-6 pb-6">
86
+ <p className="text-sm font-medium text-foreground">Attachments</p>
87
+ <div className="flex flex-col gap-1">
88
+ {attachments.map((attachment, i) => (
89
+ <a
90
+ key={i}
91
+ href={attachment.url}
92
+ download
93
+ className="flex items-center gap-2 text-sm text-primary hover:underline"
94
+ >
95
+ <Download className="size-3.5 shrink-0" />
96
+ {attachment.name}
97
+ </a>
98
+ ))}
99
+ </div>
100
+ </div>
101
+ )}
102
+
103
+ {(!attachments || attachments.length === 0) && <div className="pb-2" />}
104
+ </DialogContent>
105
+ </Dialog>
106
+ );
107
+ }
108
+
109
+ // ---------------------------------------------------------------------------
110
+ // ResourceVideoCard
111
+ // ---------------------------------------------------------------------------
112
+
113
+ export interface ResourceVideoItem {
114
+ id: string;
115
+ title: string;
116
+ thumbnailUrl?: string;
117
+ videoUrl?: string;
118
+ duration?: string;
119
+ tags?: string[];
120
+ attachments?: ResourceModalAttachment[];
121
+ }
122
+
123
+ export interface ResourceVideoCardProps {
124
+ video: ResourceVideoItem;
125
+ }
126
+
127
+ export function ResourceVideoCard({ video }: ResourceVideoCardProps) {
128
+ const [modalOpen, setModalOpen] = useState(false);
129
+
130
+ return (
131
+ <>
132
+ <button
133
+ type="button"
134
+ onClick={() => setModalOpen(true)}
135
+ className="group relative flex w-full flex-col gap-2 text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
136
+ >
137
+ {/* Thumbnail */}
138
+ <div className="relative w-full overflow-hidden bg-muted aspect-video">
139
+ {video.thumbnailUrl ? (
140
+ <img
141
+ src={video.thumbnailUrl}
142
+ alt={video.title}
143
+ className="h-full w-full object-cover transition-transform duration-200 group-hover:scale-105"
144
+ />
145
+ ) : (
146
+ <div className="flex h-full w-full items-center justify-center">
147
+ <Play className="size-10 text-muted-foreground opacity-40" />
148
+ </div>
149
+ )}
150
+
151
+ {/* Play overlay on hover */}
152
+ <div className="absolute inset-0 flex items-center justify-center bg-black/30 opacity-0 transition-opacity duration-200 group-hover:opacity-100">
153
+ <div className="flex size-12 items-center justify-center bg-background/90">
154
+ <Play className="size-5 text-foreground" />
155
+ </div>
156
+ </div>
157
+
158
+ {/* Duration badge */}
159
+ {video.duration && (
160
+ <span className="absolute bottom-2 right-2 bg-black/70 px-1.5 py-0.5 text-xs font-medium text-white">
161
+ {video.duration}
162
+ </span>
163
+ )}
164
+ </div>
165
+
166
+ {/* Title */}
167
+ <p className="text-sm font-medium text-foreground leading-snug line-clamp-2 group-hover:text-primary">
168
+ {video.title}
169
+ </p>
170
+ </button>
171
+
172
+ <ResourceModal
173
+ open={modalOpen}
174
+ onClose={() => setModalOpen(false)}
175
+ title={video.title}
176
+ videoUrl={video.videoUrl}
177
+ tags={video.tags}
178
+ attachments={video.attachments}
179
+ />
180
+ </>
181
+ );
182
+ }
183
+
184
+ // ---------------------------------------------------------------------------
185
+ // ResourceEmailTemplateCard
186
+ // ---------------------------------------------------------------------------
187
+
188
+ export interface ResourceEmailTemplateItem {
189
+ id: string;
190
+ title: string;
191
+ htmlContent?: string;
192
+ type?: "system" | "company";
193
+ isAddTemplate?: boolean;
194
+ }
195
+
196
+ export interface ResourceEmailTemplateCardProps {
197
+ template: ResourceEmailTemplateItem;
198
+ onClick?: () => void;
199
+ }
200
+
201
+ export function ResourceEmailTemplateCard({
202
+ template,
203
+ onClick,
204
+ }: ResourceEmailTemplateCardProps) {
205
+ if (template.isAddTemplate) {
206
+ return (
207
+ <button
208
+ type="button"
209
+ onClick={onClick}
210
+ className={cn(
211
+ "flex w-full flex-col items-center justify-center gap-3",
212
+ "border-2 border-dashed border-border bg-muted/40",
213
+ "aspect-[3/4] hover:border-primary hover:bg-muted/70 transition-colors",
214
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
215
+ )}
216
+ >
217
+ <div className="flex size-10 items-center justify-center border-2 border-dashed border-muted-foreground/40">
218
+ <span className="text-2xl text-muted-foreground/60">+</span>
219
+ </div>
220
+ <p className="text-sm font-medium text-muted-foreground">
221
+ Add Template
222
+ </p>
223
+ </button>
224
+ );
225
+ }
226
+
227
+ return (
228
+ <button
229
+ type="button"
230
+ onClick={onClick}
231
+ className="group relative flex w-full flex-col gap-2 text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
232
+ >
233
+ {/* Preview area */}
234
+ <div className="relative w-full overflow-hidden border border-border bg-background aspect-[3/4]">
235
+ {template.htmlContent ? (
236
+ <iframe
237
+ srcDoc={template.htmlContent}
238
+ title={template.title}
239
+ className="h-full w-full pointer-events-none"
240
+ style={{
241
+ transform: "scale(0.5)",
242
+ transformOrigin: "top left",
243
+ width: "200%",
244
+ height: "200%",
245
+ }}
246
+ sandbox="allow-same-origin"
247
+ />
248
+ ) : (
249
+ <div className="flex h-full w-full items-center justify-center bg-muted">
250
+ <p className="text-xs text-muted-foreground">
251
+ No preview available
252
+ </p>
253
+ </div>
254
+ )}
255
+
256
+ {/* Hover overlay */}
257
+ <div className="absolute inset-0 flex items-center justify-center bg-foreground/60 opacity-0 transition-opacity duration-200 group-hover:opacity-100">
258
+ <span className="text-sm font-medium text-white">Use Template</span>
259
+ </div>
260
+ </div>
261
+
262
+ {/* Meta */}
263
+ <div className="flex items-center justify-between gap-2">
264
+ <p className="text-sm font-medium text-foreground leading-snug line-clamp-1">
265
+ {template.title}
266
+ </p>
267
+ {template.type && (
268
+ <Badge variant="secondary" className="shrink-0 text-xs">
269
+ {template.type === "system" ? "System" : "Company"}
270
+ </Badge>
271
+ )}
272
+ </div>
273
+ </button>
274
+ );
275
+ }
276
+
277
+ // ---------------------------------------------------------------------------
278
+ // ResourceDocumentCard
279
+ // ---------------------------------------------------------------------------
280
+
281
+ export interface ResourceDocumentItem {
282
+ id: string;
283
+ title: string;
284
+ thumbnailUrl?: string;
285
+ tags?: string[];
286
+ downloadUrl?: string;
287
+ pdfUrl?: string;
288
+ }
289
+
290
+ export interface ResourceDocumentCardProps {
291
+ document: ResourceDocumentItem;
292
+ onClick?: () => void;
293
+ }
294
+
295
+ export function ResourceDocumentCard({
296
+ document,
297
+ onClick,
298
+ }: ResourceDocumentCardProps) {
299
+ return (
300
+ <div className="flex w-full flex-col gap-2">
301
+ {/* PDF preview */}
302
+ <button
303
+ type="button"
304
+ onClick={onClick}
305
+ className="group relative w-full overflow-hidden border border-border bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring aspect-[3/4]"
306
+ >
307
+ {document.pdfUrl ? (
308
+ <iframe
309
+ src={document.pdfUrl}
310
+ title={document.title}
311
+ className="h-full w-full pointer-events-none"
312
+ />
313
+ ) : document.thumbnailUrl ? (
314
+ <img
315
+ src={document.thumbnailUrl}
316
+ alt={document.title}
317
+ className="h-full w-full object-cover"
318
+ />
319
+ ) : (
320
+ <div className="flex h-full w-full flex-col items-center justify-center gap-2">
321
+ <div className="flex items-center justify-center bg-muted-foreground/10 p-4">
322
+ <Download className="size-8 text-muted-foreground opacity-50" />
323
+ </div>
324
+ <span className="text-xs text-muted-foreground">
325
+ {document.title}
326
+ </span>
327
+ </div>
328
+ )}
329
+
330
+ <div className="absolute inset-0 bg-foreground/40 opacity-0 transition-opacity duration-200 group-hover:opacity-100" />
331
+ </button>
332
+
333
+ {/* Footer: tags + download */}
334
+ <div className="flex items-center justify-between gap-2">
335
+ <div className="flex flex-col gap-1 min-w-0">
336
+ <p className="text-sm font-medium text-foreground leading-snug line-clamp-1">
337
+ {document.title}
338
+ </p>
339
+ {document.tags && document.tags.length > 0 && (
340
+ <div className="flex flex-wrap gap-1">
341
+ {document.tags.map((tag) => (
342
+ <Badge key={tag} variant="secondary" className="text-xs">
343
+ {tag}
344
+ </Badge>
345
+ ))}
346
+ </div>
347
+ )}
348
+ </div>
349
+ {document.downloadUrl && (
350
+ <a
351
+ href={document.downloadUrl}
352
+ download
353
+ onClick={(e) => e.stopPropagation()}
354
+ className="shrink-0"
355
+ aria-label={`Download ${document.title}`}
356
+ >
357
+ <Button variant="outline" size="icon" className="size-8">
358
+ <Download className="size-4" />
359
+ </Button>
360
+ </a>
361
+ )}
362
+ </div>
363
+ </div>
364
+ );
365
+ }
366
+
367
+ // ---------------------------------------------------------------------------
368
+ // ResourceCarousel
369
+ // ---------------------------------------------------------------------------
370
+
371
+ export interface ResourceCarouselProps {
372
+ title?: React.ReactNode;
373
+ items: React.ReactNode[];
374
+ headerAction?: React.ReactNode;
375
+ className?: string;
376
+ }
377
+
378
+ export function ResourceCarousel({
379
+ title,
380
+ items,
381
+ headerAction,
382
+ className,
383
+ }: ResourceCarouselProps) {
384
+ const scrollRef = useRef<HTMLDivElement>(null);
385
+
386
+ function scrollLeft() {
387
+ scrollRef.current?.scrollBy({ left: -300, behavior: "smooth" });
388
+ }
389
+
390
+ function scrollRight() {
391
+ scrollRef.current?.scrollBy({ left: 300, behavior: "smooth" });
392
+ }
393
+
394
+ return (
395
+ <div className={cn("flex flex-col gap-4", className)}>
396
+ {/* Header row */}
397
+ {(title || headerAction) && (
398
+ <div className="flex items-center justify-between gap-4">
399
+ {title && (
400
+ <h2 className="text-lg font-semibold text-foreground">{title}</h2>
401
+ )}
402
+ {headerAction && <div className="shrink-0">{headerAction}</div>}
403
+ </div>
404
+ )}
405
+
406
+ {/* Carousel track with hover-reveal arrows */}
407
+ {items.length === 0 ? (
408
+ <p className="py-8 text-center text-sm text-muted-foreground">
409
+ No items available
410
+ </p>
411
+ ) : (
412
+ <div className="group relative">
413
+ {/* Prev arrow */}
414
+ <button
415
+ type="button"
416
+ onClick={scrollLeft}
417
+ aria-label="Scroll left"
418
+ className={cn(
419
+ "absolute left-0 top-1/2 z-10 -translate-x-1/2 -translate-y-1/2",
420
+ "flex size-9 items-center justify-center",
421
+ "border border-border bg-background shadow-sm",
422
+ "opacity-0 transition-opacity duration-200 group-hover:opacity-100",
423
+ "hover:bg-muted focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
424
+ )}
425
+ >
426
+ <ChevronLeft className="size-4 text-foreground" />
427
+ </button>
428
+
429
+ {/* Scroll container */}
430
+ <div
431
+ ref={scrollRef}
432
+ className="flex gap-4 overflow-x-auto scroll-smooth pb-2"
433
+ style={{ scrollbarWidth: "none" }}
434
+ >
435
+ {items.map((item, i) => (
436
+ <div key={i} className="w-[220px] shrink-0">
437
+ {item}
438
+ </div>
439
+ ))}
440
+ </div>
441
+
442
+ {/* Next arrow */}
443
+ <button
444
+ type="button"
445
+ onClick={scrollRight}
446
+ aria-label="Scroll right"
447
+ className={cn(
448
+ "absolute right-0 top-1/2 z-10 translate-x-1/2 -translate-y-1/2",
449
+ "flex size-9 items-center justify-center",
450
+ "border border-border bg-background shadow-sm",
451
+ "opacity-0 transition-opacity duration-200 group-hover:opacity-100",
452
+ "hover:bg-muted focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
453
+ )}
454
+ >
455
+ <ChevronRight className="size-4 text-foreground" />
456
+ </button>
457
+ </div>
458
+ )}
459
+ </div>
460
+ );
461
+ }
462
+
463
+ // ---------------------------------------------------------------------------
464
+ // ResourceCenterHeader
465
+ // ---------------------------------------------------------------------------
466
+
467
+ export interface ResourceCenterHeaderProps {
468
+ title: string;
469
+ description: string;
470
+ backgroundVideoUrl?: string;
471
+ watchVideoUrl?: string;
472
+ }
473
+
474
+ export function ResourceCenterHeader({
475
+ title,
476
+ description,
477
+ backgroundVideoUrl,
478
+ watchVideoUrl,
479
+ }: ResourceCenterHeaderProps) {
480
+ const [watchModalOpen, setWatchModalOpen] = useState(false);
481
+
482
+ return (
483
+ <>
484
+ <div
485
+ className={cn(
486
+ "relative flex min-h-[400px] w-full items-center overflow-hidden bg-foreground",
487
+ )}
488
+ >
489
+ {/* Background video */}
490
+ {backgroundVideoUrl ? (
491
+ <video
492
+ className="absolute inset-0 h-full w-full object-cover opacity-60 z-[1]"
493
+ src={backgroundVideoUrl}
494
+ autoPlay
495
+ muted
496
+ loop
497
+ playsInline
498
+ />
499
+ ) : (
500
+ <div className="absolute inset-0 bg-foreground z-[1]" />
501
+ )}
502
+
503
+ {/* Overlay tint for legibility */}
504
+ <div className="absolute inset-0 bg-black/40 z-[1]" />
505
+
506
+ {/* Content */}
507
+ <div className="relative z-[2] flex flex-col gap-4 px-8 py-12 md:px-16 max-w-3xl">
508
+ <h1 className="text-3xl font-bold text-background md:text-4xl">
509
+ {title}
510
+ </h1>
511
+ <p className="text-base text-background/80 leading-relaxed">
512
+ {description}
513
+ </p>
514
+ {watchVideoUrl && (
515
+ <div className="pt-2">
516
+ <Button
517
+ variant="outline"
518
+ className="border-background text-background bg-transparent hover:bg-background/10 hover:text-background"
519
+ onClick={() => setWatchModalOpen(true)}
520
+ >
521
+ <Play className="mr-2 size-4" />
522
+ Watch Now
523
+ </Button>
524
+ </div>
525
+ )}
526
+ </div>
527
+ </div>
528
+
529
+ {watchVideoUrl && (
530
+ <ResourceModal
531
+ open={watchModalOpen}
532
+ onClose={() => setWatchModalOpen(false)}
533
+ title={title}
534
+ videoUrl={watchVideoUrl}
535
+ />
536
+ )}
537
+ </>
538
+ );
539
+ }
@@ -0,0 +1,163 @@
1
+ import * as React from "react";
2
+ import {
3
+ Dialog,
4
+ DialogContent,
5
+ DialogHeader,
6
+ DialogTitle,
7
+ DialogFooter,
8
+ } from "@/components/ui/dialog";
9
+ import { Button } from "@/components/ui/button";
10
+ import { Checkbox } from "@/components/ui/checkbox";
11
+ import { Label } from "@/components/ui/label";
12
+ import { cn } from "@/lib/utils";
13
+
14
+ // ---------------------------------------------------------------------------
15
+ // Types
16
+ // ---------------------------------------------------------------------------
17
+
18
+ export type AlertSeverity = "NEED_ACTION" | "WATCH" | "INSIGHT";
19
+
20
+ export interface ReviewableAlert {
21
+ id: string;
22
+ name: string;
23
+ severityCode: AlertSeverity;
24
+ snoozedUntil?: string;
25
+ dismissed?: boolean;
26
+ }
27
+
28
+ export interface ReviewAlertsDialogProps {
29
+ open: boolean;
30
+ onOpenChange: (open: boolean) => void;
31
+ alerts: ReviewableAlert[];
32
+ onSave: (
33
+ alertId: string,
34
+ action: { markDone: boolean; snooze: boolean },
35
+ ) => void;
36
+ className?: string;
37
+ }
38
+
39
+ // ---------------------------------------------------------------------------
40
+ // Severity config
41
+ // ---------------------------------------------------------------------------
42
+
43
+ const SEVERITY_CONFIG: Record<AlertSeverity, { dot: string; text: string }> = {
44
+ NEED_ACTION: { dot: "bg-destructive", text: "text-destructive" },
45
+ WATCH: { dot: "bg-warning", text: "text-warning" },
46
+ INSIGHT: { dot: "bg-success", text: "text-success" },
47
+ };
48
+
49
+ // ---------------------------------------------------------------------------
50
+ // ReviewAlertsDialog
51
+ // ---------------------------------------------------------------------------
52
+
53
+ export function ReviewAlertsDialog({
54
+ open,
55
+ onOpenChange,
56
+ alerts,
57
+ onSave,
58
+ className,
59
+ }: ReviewAlertsDialogProps) {
60
+ const [markDone, setMarkDone] = React.useState(false);
61
+ const [snooze, setSnooze] = React.useState(false);
62
+
63
+ const activeAlert = alerts.find((a) => !a.dismissed && !a.snoozedUntil);
64
+
65
+ React.useEffect(() => {
66
+ if (open) {
67
+ setMarkDone(false);
68
+ setSnooze(false);
69
+ }
70
+ }, [open, activeAlert?.id]);
71
+
72
+ const canSave = (markDone || snooze) && !!activeAlert;
73
+
74
+ return (
75
+ <Dialog open={open} onOpenChange={onOpenChange}>
76
+ <DialogContent size="sm" className={className}>
77
+ <DialogHeader>
78
+ <DialogTitle>Alerts</DialogTitle>
79
+ </DialogHeader>
80
+
81
+ {/* Alert list */}
82
+ <div className="flex flex-col gap-2">
83
+ {alerts.length === 0 ? (
84
+ <p className="text-sm text-muted-foreground">
85
+ No alerts for this contact.
86
+ </p>
87
+ ) : (
88
+ alerts.map((alert) => {
89
+ const { dot, text } = SEVERITY_CONFIG[alert.severityCode];
90
+ return (
91
+ <div
92
+ key={alert.id}
93
+ className={cn(
94
+ "flex items-center gap-2",
95
+ alert.id !== activeAlert?.id && "opacity-40",
96
+ )}
97
+ >
98
+ <span
99
+ aria-hidden
100
+ className={cn(
101
+ "inline-block size-2 shrink-0 rounded-full",
102
+ dot,
103
+ )}
104
+ />
105
+ <span className={cn("text-sm font-medium", text)}>
106
+ {alert.name}
107
+ </span>
108
+ </div>
109
+ );
110
+ })
111
+ )}
112
+ </div>
113
+
114
+ {/* Actions */}
115
+ {activeAlert && (
116
+ <div className="flex flex-col gap-3">
117
+ <p className="text-sm font-medium text-foreground">Actions</p>
118
+
119
+ <div className="flex items-center gap-2">
120
+ <Checkbox
121
+ id="alert-mark-done"
122
+ checked={markDone}
123
+ onCheckedChange={(v) => setMarkDone(!!v)}
124
+ />
125
+ <Label
126
+ htmlFor="alert-mark-done"
127
+ className="cursor-pointer font-normal"
128
+ >
129
+ Mark as done (will reset in 6 months)
130
+ </Label>
131
+ </div>
132
+
133
+ <div className="flex items-center gap-2">
134
+ <Checkbox
135
+ id="alert-snooze"
136
+ checked={snooze}
137
+ onCheckedChange={(v) => setSnooze(!!v)}
138
+ />
139
+ <Label
140
+ htmlFor="alert-snooze"
141
+ className="cursor-pointer font-normal"
142
+ >
143
+ Snooze for 30 days
144
+ </Label>
145
+ </div>
146
+ </div>
147
+ )}
148
+
149
+ <DialogFooter>
150
+ <Button variant="outline" onClick={() => onOpenChange(false)}>
151
+ Cancel
152
+ </Button>
153
+ <Button
154
+ disabled={!canSave}
155
+ onClick={() => onSave(activeAlert!.id, { markDone, snooze })}
156
+ >
157
+ Save
158
+ </Button>
159
+ </DialogFooter>
160
+ </DialogContent>
161
+ </Dialog>
162
+ );
163
+ }