@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,548 @@
1
+ import React, { useState, useEffect } from "react";
2
+ import { CheckIcon, HomeIcon, PlusIcon } from "lucide-react";
3
+ import { AddressAutocomplete } from "./form-primitives";
4
+ import { Button } from "./button";
5
+ import { Input } from "./input";
6
+ import { Slider } from "./slider";
7
+ import { Spinner } from "./spinner";
8
+ import { ToggleGroup, ToggleGroupItem } from "./toggle-group";
9
+ import {
10
+ InputOTP,
11
+ InputOTPGroup,
12
+ InputOTPSeparator,
13
+ InputOTPSlot,
14
+ } from "./input-otp";
15
+ import { FormField } from "./signup-form-primitives";
16
+
17
+ // ---------------------------------------------------------------------------
18
+ // Helpers
19
+ // ---------------------------------------------------------------------------
20
+
21
+ const fmt = (v: number) =>
22
+ new Intl.NumberFormat("en-AU", {
23
+ style: "currency",
24
+ currency: "AUD",
25
+ maximumFractionDigits: 0,
26
+ }).format(v);
27
+
28
+ const GOAL_MIN = 50_000;
29
+ const GOAL_MAX = 4_000_000;
30
+ const GOAL_STEP = 10_000;
31
+
32
+ // ---------------------------------------------------------------------------
33
+ // Step 2 — Phone Verification
34
+ // ---------------------------------------------------------------------------
35
+
36
+ export interface PhoneVerifyStepProps {
37
+ phone?: string;
38
+ countdown?: number;
39
+ error?: string;
40
+ isLoading?: boolean;
41
+ onVerify?: (code: string) => void;
42
+ onResend?: () => void;
43
+ }
44
+
45
+ export function PhoneVerifyStep({
46
+ phone = "+61 412 345 789",
47
+ countdown = 45,
48
+ error = "",
49
+ isLoading = false,
50
+ onVerify,
51
+ onResend,
52
+ }: PhoneVerifyStepProps) {
53
+ const [otp, setOtp] = useState("");
54
+ const [timer, setTimer] = useState(countdown);
55
+
56
+ useEffect(() => {
57
+ if (timer <= 0) return;
58
+ const id = setInterval(() => setTimer((t) => t - 1), 1000);
59
+ return () => clearInterval(id);
60
+ }, [timer]);
61
+
62
+ const handleChange = (value: string) => {
63
+ setOtp(value);
64
+ if (value.length === 6) onVerify?.(value);
65
+ };
66
+
67
+ const lastFour = phone.slice(-4);
68
+
69
+ return (
70
+ <div className="flex flex-col gap-6">
71
+ <div className="flex flex-col gap-1">
72
+ <p className="text-2xl font-bold text-foreground">
73
+ We sent you a text.
74
+ </p>
75
+ <p className="text-sm text-muted-foreground">
76
+ Number we have ends in •••• {lastFour}.
77
+ </p>
78
+ </div>
79
+
80
+ <div className="flex flex-col gap-3">
81
+ <InputOTP
82
+ maxLength={6}
83
+ value={otp}
84
+ onChange={handleChange}
85
+ disabled={isLoading}
86
+ aria-label="6-digit verification code"
87
+ >
88
+ <InputOTPGroup>
89
+ <InputOTPSlot index={0} aria-invalid={!!error || undefined} />
90
+ <InputOTPSlot index={1} aria-invalid={!!error || undefined} />
91
+ <InputOTPSlot index={2} aria-invalid={!!error || undefined} />
92
+ </InputOTPGroup>
93
+ <InputOTPSeparator />
94
+ <InputOTPGroup>
95
+ <InputOTPSlot index={3} aria-invalid={!!error || undefined} />
96
+ <InputOTPSlot index={4} aria-invalid={!!error || undefined} />
97
+ <InputOTPSlot index={5} aria-invalid={!!error || undefined} />
98
+ </InputOTPGroup>
99
+ </InputOTP>
100
+ {error && (
101
+ <p role="alert" className="text-sm text-destructive">
102
+ {error}
103
+ </p>
104
+ )}
105
+ </div>
106
+
107
+ {isLoading ? (
108
+ <div
109
+ role="status"
110
+ aria-label="Verifying code"
111
+ className="flex items-center gap-2 text-sm text-muted-foreground"
112
+ >
113
+ <span aria-hidden="true">
114
+ <Spinner className="size-4" />
115
+ </span>
116
+ Verifying…
117
+ </div>
118
+ ) : (
119
+ <p className="text-sm text-muted-foreground" aria-live="polite">
120
+ Didn&apos;t receive a code?{" "}
121
+ {timer > 0 ? (
122
+ <span>Resend it in {timer}s</span>
123
+ ) : (
124
+ <Button
125
+ variant="link"
126
+ size="sm"
127
+ className="h-auto p-0 text-sm"
128
+ onClick={() => {
129
+ setTimer(60);
130
+ onResend?.();
131
+ }}
132
+ >
133
+ Resend it
134
+ </Button>
135
+ )}
136
+ </p>
137
+ )}
138
+ </div>
139
+ );
140
+ }
141
+
142
+ // ---------------------------------------------------------------------------
143
+ // Step 3 — Request Broker Access
144
+ // ---------------------------------------------------------------------------
145
+
146
+ export interface BrokerFormValues {
147
+ firstName: string;
148
+ lastName: string;
149
+ email: string;
150
+ phone: string;
151
+ }
152
+
153
+ export interface BrokerRequestStepProps {
154
+ onValuesChange?: (values: BrokerFormValues) => void;
155
+ }
156
+
157
+ export function BrokerRequestStep({ onValuesChange }: BrokerRequestStepProps) {
158
+ const [values, setValues] = useState<BrokerFormValues>({
159
+ firstName: "",
160
+ lastName: "",
161
+ email: "",
162
+ phone: "",
163
+ });
164
+
165
+ const update = (field: keyof BrokerFormValues, value: string) => {
166
+ setValues((prev) => {
167
+ const next = { ...prev, [field]: value };
168
+ onValuesChange?.(next);
169
+ return next;
170
+ });
171
+ };
172
+
173
+ return (
174
+ <div className="flex flex-col gap-6">
175
+ <p className="text-sm text-muted-foreground">
176
+ You have access for the first 3 months covered by us. After this date
177
+ you will need to be connected with a mortgage broker or financial
178
+ planner to maintain access.
179
+ </p>
180
+
181
+ <div className="flex flex-col gap-4">
182
+ <div className="flex gap-4">
183
+ <FormField label="First Name">
184
+ <Input
185
+ id="broker-first-name"
186
+ autoComplete="given-name"
187
+ placeholder="First Name"
188
+ value={values.firstName}
189
+ onChange={(e) => update("firstName", e.target.value)}
190
+ />
191
+ </FormField>
192
+ <FormField label="Last Name">
193
+ <Input
194
+ id="broker-last-name"
195
+ autoComplete="family-name"
196
+ placeholder="Last Name"
197
+ value={values.lastName}
198
+ onChange={(e) => update("lastName", e.target.value)}
199
+ />
200
+ </FormField>
201
+ </div>
202
+ <FormField label="Email Address">
203
+ <Input
204
+ id="broker-email"
205
+ type="email"
206
+ autoComplete="email"
207
+ placeholder="Email Address"
208
+ value={values.email}
209
+ onChange={(e) => update("email", e.target.value)}
210
+ />
211
+ </FormField>
212
+ <FormField label="Phone Number">
213
+ <Input
214
+ id="broker-phone"
215
+ type="tel"
216
+ autoComplete="tel"
217
+ placeholder="Phone Number"
218
+ value={values.phone}
219
+ onChange={(e) => update("phone", e.target.value)}
220
+ />
221
+ </FormField>
222
+ </div>
223
+ </div>
224
+ );
225
+ }
226
+
227
+ // ---------------------------------------------------------------------------
228
+ // Step 4 — Connect Bank
229
+ // ---------------------------------------------------------------------------
230
+
231
+ const BANKS = ["CBA", "ANZ", "NAB", "WBC", "MAC", "BOQ"];
232
+
233
+ export interface ConnectBankStepProps {
234
+ onConnect?: () => void;
235
+ }
236
+
237
+ export function ConnectBankStep({ onConnect }: ConnectBankStepProps) {
238
+ return (
239
+ <div className="flex flex-col gap-6">
240
+ <button
241
+ type="button"
242
+ aria-label="Connect your bank account"
243
+ onClick={onConnect}
244
+ className="flex flex-col gap-4 border border-border p-6 text-left transition-colors hover:border-primary/60"
245
+ >
246
+ <div className="grid grid-cols-3 gap-3" aria-hidden="true">
247
+ {BANKS.map((abbr) => (
248
+ <div
249
+ key={abbr}
250
+ className="flex h-14 items-center justify-center border border-border bg-muted/30"
251
+ >
252
+ <span className="text-sm font-semibold text-foreground">
253
+ {abbr}
254
+ </span>
255
+ </div>
256
+ ))}
257
+ </div>
258
+ <div className="flex items-center justify-between">
259
+ <span className="text-sm font-semibold text-foreground">
260
+ Connect Bank
261
+ </span>
262
+ <div
263
+ aria-hidden="true"
264
+ className="flex h-7 w-7 items-center justify-center bg-primary text-primary-foreground"
265
+ >
266
+ <PlusIcon className="size-4" />
267
+ </div>
268
+ </div>
269
+ </button>
270
+ </div>
271
+ );
272
+ }
273
+
274
+ // ---------------------------------------------------------------------------
275
+ // Step 5 — Retrieve Bank Data (loading state)
276
+ // ---------------------------------------------------------------------------
277
+
278
+ export function RetrieveBankDataStep() {
279
+ return (
280
+ <div
281
+ role="status"
282
+ aria-label="Retrieving bank data"
283
+ className="flex flex-col items-center justify-center gap-4 py-16 text-center"
284
+ >
285
+ <span aria-hidden="true">
286
+ <Spinner className="size-10 text-primary" />
287
+ </span>
288
+ <div className="flex flex-col gap-1">
289
+ <p className="text-base font-semibold text-foreground">
290
+ Retrieving your bank data…
291
+ </p>
292
+ <p className="text-sm text-muted-foreground">
293
+ This may take a few seconds. Please don&apos;t close this window.
294
+ </p>
295
+ </div>
296
+ </div>
297
+ );
298
+ }
299
+
300
+ // ---------------------------------------------------------------------------
301
+ // Step 6 — Connect Property
302
+ // ---------------------------------------------------------------------------
303
+
304
+ interface PropertyItem {
305
+ id: string;
306
+ address: string;
307
+ suburb: string;
308
+ state: string;
309
+ }
310
+
311
+ export interface ConnectPropertyStepProps {
312
+ properties?: PropertyItem[];
313
+ onAddProperty?: (address: string) => void;
314
+ onCanProceedChange?: (can: boolean) => void;
315
+ onGoalChange?: (value: number) => void;
316
+ }
317
+
318
+ export function ConnectPropertyStep({
319
+ properties = [],
320
+ onAddProperty,
321
+ onCanProceedChange,
322
+ onGoalChange,
323
+ }: ConnectPropertyStepProps) {
324
+ const [hasProperty, setHasProperty] = useState<boolean | null>(null);
325
+ const [addressValue, setAddressValue] = useState("");
326
+ const [goalValue, setGoalValue] = useState(2_000_000);
327
+
328
+ const canProceed =
329
+ hasProperty === false || (hasProperty === true && properties.length > 0);
330
+
331
+ useEffect(() => {
332
+ onCanProceedChange?.(canProceed);
333
+ // eslint-disable-next-line react-hooks/exhaustive-deps
334
+ }, [canProceed]);
335
+
336
+ const handleGoalChange = (v: number) => {
337
+ setGoalValue(v);
338
+ onGoalChange?.(v);
339
+ };
340
+
341
+ return (
342
+ <div className="flex flex-col gap-6">
343
+ <ToggleGroup
344
+ type="single"
345
+ variant="outline"
346
+ aria-label="Do you own a property?"
347
+ value={
348
+ hasProperty === true ? ["yes"] : hasProperty === false ? ["no"] : []
349
+ }
350
+ onValueChange={(vals: readonly string[]) => {
351
+ const val = vals[0];
352
+ setHasProperty(val === "yes" ? true : val === "no" ? false : null);
353
+ }}
354
+ className="w-full"
355
+ >
356
+ <ToggleGroupItem value="yes" className="flex-1">
357
+ Yes, I have a property
358
+ </ToggleGroupItem>
359
+ <ToggleGroupItem value="no" className="flex-1">
360
+ No, I don&apos;t
361
+ </ToggleGroupItem>
362
+ </ToggleGroup>
363
+
364
+ {hasProperty === true && (
365
+ <>
366
+ <AddressAutocomplete
367
+ value={addressValue}
368
+ onValueChange={setAddressValue}
369
+ onSelect={(opt) => {
370
+ onAddProperty?.(opt.label);
371
+ setAddressValue("");
372
+ }}
373
+ />
374
+
375
+ {properties.length > 0 && (
376
+ <ul role="list" className="flex flex-col gap-2">
377
+ {properties.map((p) => (
378
+ <li
379
+ key={p.id}
380
+ className="flex items-center justify-between border border-border px-4 py-3"
381
+ >
382
+ <div className="flex items-center gap-3">
383
+ <HomeIcon
384
+ aria-hidden="true"
385
+ className="size-4 shrink-0 text-muted-foreground"
386
+ />
387
+ <div>
388
+ <p className="text-sm font-medium text-foreground">
389
+ {p.address}
390
+ </p>
391
+ <p className="text-xs text-muted-foreground">
392
+ {p.suburb}, {p.state}
393
+ </p>
394
+ </div>
395
+ </div>
396
+ <CheckIcon
397
+ aria-hidden="true"
398
+ className="size-4 text-success"
399
+ />
400
+ </li>
401
+ ))}
402
+ </ul>
403
+ )}
404
+ </>
405
+ )}
406
+
407
+ {hasProperty === false && (
408
+ <div className="flex flex-col gap-4 border border-border p-6">
409
+ <div className="flex flex-col gap-1">
410
+ <p className="text-sm font-medium text-foreground">
411
+ What&apos;s your property budget?
412
+ </p>
413
+ <p className="text-xs text-muted-foreground">
414
+ Set your estimated buying goal to help us tailor your experience.
415
+ </p>
416
+ </div>
417
+ <p
418
+ aria-live="polite"
419
+ className="tabular-nums text-3xl font-bold text-foreground"
420
+ >
421
+ {fmt(goalValue)}
422
+ </p>
423
+ <Slider
424
+ min={GOAL_MIN}
425
+ max={GOAL_MAX}
426
+ step={GOAL_STEP}
427
+ value={goalValue}
428
+ onValueChange={handleGoalChange}
429
+ aria-label="Property buying goal"
430
+ />
431
+ <div
432
+ aria-hidden="true"
433
+ className="flex justify-between text-xs text-muted-foreground"
434
+ >
435
+ <span>{fmt(GOAL_MIN)}</span>
436
+ <span>{fmt(GOAL_MAX)}</span>
437
+ </div>
438
+ </div>
439
+ )}
440
+ </div>
441
+ );
442
+ }
443
+
444
+ // ---------------------------------------------------------------------------
445
+ // BuyingGoalStep — standalone step (used in template stories)
446
+ // ---------------------------------------------------------------------------
447
+
448
+ export interface BuyingGoalStepProps {
449
+ initialValue?: number;
450
+ isLoading?: boolean;
451
+ onConfirm?: (value: number) => void;
452
+ }
453
+
454
+ export function BuyingGoalStep({
455
+ initialValue = 2_000_000,
456
+ isLoading = false,
457
+ onConfirm,
458
+ }: BuyingGoalStepProps) {
459
+ const [value, setValue] = useState(initialValue);
460
+
461
+ return (
462
+ <div className="flex flex-col gap-8">
463
+ <div className="flex flex-col gap-6 border border-border p-6">
464
+ <div className="flex items-center justify-between">
465
+ <p
466
+ aria-live="polite"
467
+ className="tabular-nums text-3xl font-bold text-foreground"
468
+ >
469
+ {fmt(value)}
470
+ </p>
471
+ <Button
472
+ variant="default"
473
+ onClick={() => onConfirm?.(value)}
474
+ disabled={isLoading}
475
+ >
476
+ {isLoading ? (
477
+ <>
478
+ <span aria-hidden="true">
479
+ <Spinner className="size-4" />
480
+ </span>
481
+ Adding…
482
+ </>
483
+ ) : (
484
+ "Confirm"
485
+ )}
486
+ </Button>
487
+ </div>
488
+
489
+ <Slider
490
+ min={GOAL_MIN}
491
+ max={GOAL_MAX}
492
+ step={GOAL_STEP}
493
+ value={value}
494
+ onValueChange={(v) => setValue(v)}
495
+ disabled={isLoading}
496
+ aria-label="Buying goal"
497
+ />
498
+
499
+ <div
500
+ aria-hidden="true"
501
+ className="flex justify-between text-xs text-muted-foreground"
502
+ >
503
+ <span>{fmt(GOAL_MIN)}</span>
504
+ <span>{fmt(GOAL_MAX)}</span>
505
+ </div>
506
+ </div>
507
+ </div>
508
+ );
509
+ }
510
+
511
+ // ---------------------------------------------------------------------------
512
+ // Step 7 — Success
513
+ // ---------------------------------------------------------------------------
514
+
515
+ export interface FrontendSuccessStepProps {
516
+ firstName?: string;
517
+ onGoToDashboard?: () => void;
518
+ }
519
+
520
+ export function FrontendSuccessStep({
521
+ firstName = "Alex",
522
+ onGoToDashboard,
523
+ }: FrontendSuccessStepProps) {
524
+ return (
525
+ <div className="flex min-h-full flex-col items-center justify-center gap-6 px-4 py-16 text-center">
526
+ <div
527
+ aria-hidden="true"
528
+ className="flex size-16 items-center justify-center bg-success/10"
529
+ >
530
+ <CheckIcon className="size-8 text-success" strokeWidth={2} />
531
+ </div>
532
+
533
+ <div className="flex flex-col gap-2">
534
+ <h2 className="text-2xl font-bold text-foreground">
535
+ You&apos;re all set, {firstName}!
536
+ </h2>
537
+ <p className="max-w-[360px] text-sm text-muted-foreground">
538
+ Your account is ready. Head to your dashboard to explore your
539
+ financial overview and next steps.
540
+ </p>
541
+ </div>
542
+
543
+ <Button variant="default" size="lg" onClick={onGoToDashboard}>
544
+ Go to Dashboard
545
+ </Button>
546
+ </div>
547
+ );
548
+ }
@@ -0,0 +1,143 @@
1
+ import React from "react";
2
+ import { Card, CardContent, CardHeader, CardTitle } from "./card";
3
+ import { Spinner } from "./spinner";
4
+ import { cn } from "@/lib/utils";
5
+ import { formatCurrency } from "@/lib/format-currency";
6
+
7
+ // ─── Types ───────────────────────────────────────────────────────────────────
8
+
9
+ export interface IncomeSource {
10
+ id: string;
11
+ label: string;
12
+ amount: number;
13
+ /** 0–100, percentage of total income */
14
+ percentage: number;
15
+ transactionCount?: number;
16
+ }
17
+
18
+ export interface IncomeSourcesCardProps {
19
+ sources: IncomeSource[];
20
+ totalIncome: number;
21
+ selectedSourceId?: string | null;
22
+ onSelectSource?: (id: string | null) => void;
23
+ /** Display label for the period, e.g. "30 Days" */
24
+ period?: string;
25
+ isLoading?: boolean;
26
+ className?: string;
27
+ }
28
+
29
+ // ─── Source row ───────────────────────────────────────────────────────────────
30
+
31
+ function SourceRow({
32
+ source,
33
+ isSelected,
34
+ onClick,
35
+ }: {
36
+ source: IncomeSource;
37
+ isSelected: boolean;
38
+ onClick: () => void;
39
+ }) {
40
+ return (
41
+ <button
42
+ type="button"
43
+ onClick={onClick}
44
+ aria-pressed={isSelected}
45
+ className={cn(
46
+ "flex w-full flex-col gap-1.5 border-b border-l-2 border-border py-3 pl-3 text-left transition-colors last:border-0",
47
+ isSelected
48
+ ? "border-l-primary bg-primary/5 hover:bg-primary/10"
49
+ : "border-l-transparent hover:bg-muted/50",
50
+ )}
51
+ >
52
+ <div className="flex items-baseline justify-between gap-3">
53
+ <span
54
+ className={cn(
55
+ "truncate text-sm font-medium",
56
+ isSelected ? "text-primary" : "text-foreground",
57
+ )}
58
+ >
59
+ {source.label}
60
+ </span>
61
+ <span className="shrink-0 text-sm font-semibold text-foreground">
62
+ {formatCurrency(source.amount)}
63
+ </span>
64
+ </div>
65
+
66
+ <div className="flex items-center justify-between gap-2">
67
+ <span className="text-xs text-muted-foreground">
68
+ {source.transactionCount != null
69
+ ? `${source.transactionCount} ${source.transactionCount === 1 ? "transaction" : "transactions"}`
70
+ : ""}
71
+ </span>
72
+ <span className="text-xs text-muted-foreground">
73
+ {source.percentage.toFixed(0)}%
74
+ </span>
75
+ </div>
76
+
77
+ <div className="h-1.5 w-full overflow-hidden bg-muted">
78
+ <div
79
+ className="h-full bg-primary transition-all"
80
+ style={{ width: `${Math.min(100, Math.max(0, source.percentage))}%` }}
81
+ aria-hidden="true"
82
+ />
83
+ </div>
84
+ </button>
85
+ );
86
+ }
87
+
88
+ // ─── Component ────────────────────────────────────────────────────────────────
89
+
90
+ export function IncomeSourcesCard({
91
+ sources,
92
+ totalIncome,
93
+ selectedSourceId,
94
+ onSelectSource,
95
+ period,
96
+ isLoading = false,
97
+ className,
98
+ }: IncomeSourcesCardProps) {
99
+ return (
100
+ <Card className={cn("flex flex-col", className)}>
101
+ <CardHeader className="pb-2">
102
+ <div className="flex items-start justify-between gap-2">
103
+ <CardTitle className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
104
+ Income Sources
105
+ </CardTitle>
106
+ <div className="flex shrink-0 flex-col items-end">
107
+ <span className="text-sm font-semibold text-foreground">
108
+ {formatCurrency(totalIncome)}
109
+ </span>
110
+ {period && (
111
+ <span className="text-xs text-muted-foreground">{period}</span>
112
+ )}
113
+ </div>
114
+ </div>
115
+ </CardHeader>
116
+
117
+ <CardContent className="flex flex-1 flex-col p-0 px-4 pb-2">
118
+ {isLoading ? (
119
+ <div className="flex flex-1 items-center justify-center py-8">
120
+ <Spinner size="default" />
121
+ </div>
122
+ ) : sources.length === 0 ? (
123
+ <p className="py-8 text-center text-sm text-muted-foreground">
124
+ No income sources available
125
+ </p>
126
+ ) : (
127
+ sources.map((source) => (
128
+ <SourceRow
129
+ key={source.id}
130
+ source={source}
131
+ isSelected={selectedSourceId === source.id}
132
+ onClick={() =>
133
+ onSelectSource?.(
134
+ selectedSourceId === source.id ? null : source.id,
135
+ )
136
+ }
137
+ />
138
+ ))
139
+ )}
140
+ </CardContent>
141
+ </Card>
142
+ );
143
+ }