@wealthx/shadcn 1.4.1 → 1.5.1

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 +356 -176
  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 +367 -3
  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,111 @@
1
+ import React, { useEffect, useState } from "react";
2
+ import { cn } from "@/lib/utils";
3
+ import {
4
+ InputGroup,
5
+ InputGroupAddon,
6
+ InputGroupInput,
7
+ } from "@/components/ui/input-group";
8
+
9
+ /**
10
+ * Numeric input for interest rates with a "%" suffix.
11
+ * Accepts 0–max with one decimal place. Strips the slider from the app's
12
+ * InterestRateInput — use this wherever just the rate field is needed.
13
+ *
14
+ * Consumers should wrap in <Field> + <FieldLabel> / <FieldError> for label/error display.
15
+ */
16
+
17
+ export type InterestRateInputProps = {
18
+ /** Current rate value (e.g. 5.5 for 5.5%) */
19
+ value: number;
20
+ /** Called on blur with the parsed, validated value */
21
+ onChange: (value: number) => void;
22
+ /** HTML id forwarded to the inner <input> */
23
+ id?: string;
24
+ /** Minimum allowed value (default: 0) */
25
+ min?: number;
26
+ /** Maximum allowed value (default: 10) */
27
+ max?: number;
28
+ disabled?: boolean;
29
+ /** When true, renders the InputGroup in its error visual state */
30
+ error?: boolean;
31
+ className?: string;
32
+ };
33
+
34
+ /** Allow one decimal place: 0–max (e.g. "5", "5.", "5.5", "10.0") */
35
+ function buildValidationRegex(max: number): RegExp {
36
+ const intMax = Math.floor(max);
37
+ // Matches: integer part 0–max, optional single decimal digit
38
+ return new RegExp(`^(${intMax}(\\.\\d?)?|[0-9](\\.[0-9]?)?)$`);
39
+ }
40
+
41
+ function clamp(n: number, min: number, max: number): number {
42
+ return Math.min(max, Math.max(min, n));
43
+ }
44
+
45
+ export function InterestRateInput({
46
+ value,
47
+ onChange,
48
+ id,
49
+ min = 0,
50
+ max = 10,
51
+ disabled = false,
52
+ error = false,
53
+ className,
54
+ }: InterestRateInputProps) {
55
+ const [displayValue, setDisplayValue] = useState(() =>
56
+ value > 0 ? String(value) : "",
57
+ );
58
+ const [focused, setFocused] = useState(false);
59
+
60
+ const validationRegex = buildValidationRegex(max);
61
+
62
+ // Sync when value changes externally
63
+ useEffect(() => {
64
+ if (!focused) {
65
+ setDisplayValue(value > 0 ? String(value) : "");
66
+ }
67
+ }, [value, focused]);
68
+
69
+ function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
70
+ const raw = e.target.value;
71
+ // Allow empty string or values matching the pattern
72
+ if (raw === "" || validationRegex.test(raw)) {
73
+ setDisplayValue(raw);
74
+ }
75
+ }
76
+
77
+ function handleFocus() {
78
+ setFocused(true);
79
+ }
80
+
81
+ function handleBlur() {
82
+ setFocused(false);
83
+ // Strip trailing decimal point, then parse + clamp
84
+ const cleaned = displayValue.replace(/\.$/, "");
85
+ const parsed = parseFloat(cleaned);
86
+ const final = isNaN(parsed) ? min : clamp(parsed, min, max);
87
+ onChange(final);
88
+ setDisplayValue(final > 0 ? String(final) : "");
89
+ }
90
+
91
+ return (
92
+ <InputGroup
93
+ className={cn(className)}
94
+ data-disabled={disabled ? "true" : undefined}
95
+ >
96
+ <InputGroupInput
97
+ id={id}
98
+ type="text"
99
+ inputMode="decimal"
100
+ value={displayValue}
101
+ onChange={handleChange}
102
+ onFocus={handleFocus}
103
+ onBlur={handleBlur}
104
+ placeholder="0"
105
+ disabled={disabled}
106
+ aria-invalid={error ? "true" : undefined}
107
+ />
108
+ <InputGroupAddon align="inline-end">%</InputGroupAddon>
109
+ </InputGroup>
110
+ );
111
+ }
@@ -0,0 +1,158 @@
1
+ import React, { useState } from "react";
2
+ import { cn } from "@/lib/utils";
3
+ import { formatCurrency, formatCurrencyAbbrev } from "@/lib/format-currency";
4
+ import { Button } from "./button";
5
+ import { Skeleton } from "./skeleton";
6
+
7
+ /**
8
+ * Organism — full lender comparison table for the Borrowing Capacity page.
9
+ *
10
+ * Renders an optional title, a sticky column-header row, and a paginated list
11
+ * of lender rows. Each row shows: Lender, Interest Rate, Comparison Rate,
12
+ * Monthly Repayments, Total Cost, and Max Buying Power.
13
+ *
14
+ * Values are pre-formatted / typed — business logic stays in the app layer.
15
+ * Pass `isLoading` to render a skeleton table in place of real rows.
16
+ */
17
+
18
+ export interface InterestRateItem {
19
+ /** Lender display name (e.g. "ANZ") */
20
+ lender: string;
21
+ /** Interest rate percentage (e.g. 5.5 → displayed as "5.50%") */
22
+ interestRate: number;
23
+ /** Comparison rate percentage (e.g. 5.75 → displayed as "5.75%") */
24
+ comparisonRate: number;
25
+ /** Pre-formatted monthly repayment string (e.g. "$2,800" or "$2,800 – $3,100") */
26
+ monthlyRepayment: string;
27
+ /** Total cost in AUD cents */
28
+ totalCost: number;
29
+ /** Maximum buying power in AUD cents */
30
+ maxBuyingPower: number;
31
+ }
32
+
33
+ export interface InterestRateSectionProps {
34
+ /**
35
+ * Section heading shown above the table, e.g.
36
+ * "Lender Options for cash towards $150,000"
37
+ */
38
+ title?: string;
39
+ /** Lender rows to display */
40
+ items?: InterestRateItem[];
41
+ /** Number of rows shown per page (default: 5) */
42
+ pageSize?: number;
43
+ /** Replace rows with a skeleton loading state */
44
+ isLoading?: boolean;
45
+ className?: string;
46
+ }
47
+
48
+ const COLUMN_HEADERS = [
49
+ "Lender",
50
+ "Interest Rate",
51
+ "Comparison Rate",
52
+ "Monthly Repayments",
53
+ "Total Cost",
54
+ "Real Buying Power",
55
+ ] as const;
56
+
57
+ export function InterestRateSection({
58
+ title,
59
+ items = [],
60
+ pageSize = 5,
61
+ isLoading = false,
62
+ className,
63
+ }: InterestRateSectionProps) {
64
+ const [visibleCount, setVisibleCount] = useState(pageSize);
65
+ const visibleItems = items.slice(0, visibleCount);
66
+ const hasMore = visibleCount < items.length;
67
+
68
+ const handleLoadMore = () => setVisibleCount((n) => n + pageSize);
69
+
70
+ return (
71
+ <div className={cn("flex flex-col gap-3", className)}>
72
+ {title && (
73
+ <p className="text-sm font-semibold text-foreground">{title}</p>
74
+ )}
75
+
76
+ {/* Column headers */}
77
+ <div className="grid grid-cols-6 border-b border-border pb-2">
78
+ {COLUMN_HEADERS.map((col) => (
79
+ <span
80
+ key={col}
81
+ className="text-xs font-medium uppercase tracking-wide text-muted-foreground"
82
+ >
83
+ {col}
84
+ </span>
85
+ ))}
86
+ </div>
87
+
88
+ {/* Rows */}
89
+ <div className="flex flex-col divide-y divide-border">
90
+ {isLoading
91
+ ? Array.from({ length: pageSize }).map((_, i) => (
92
+ <div key={i} className="grid grid-cols-6 gap-2 py-3">
93
+ {Array.from({ length: 6 }).map((__, j) => (
94
+ <Skeleton key={j} className="h-4 w-full" />
95
+ ))}
96
+ </div>
97
+ ))
98
+ : visibleItems.length > 0
99
+ ? visibleItems.map((item, i) => (
100
+ <div
101
+ key={`${item.lender}-${i}`}
102
+ className="grid grid-cols-6 items-center py-3"
103
+ >
104
+ {/* Lender */}
105
+ <div className="flex items-center gap-2">
106
+ <span
107
+ className="h-2 w-2 shrink-0 rounded-full bg-primary"
108
+ aria-hidden
109
+ />
110
+ <span className="truncate text-sm font-medium text-foreground">
111
+ {item.lender}
112
+ </span>
113
+ </div>
114
+
115
+ {/* Interest Rate */}
116
+ <span className="text-sm tabular-nums text-foreground">
117
+ {item.interestRate.toFixed(2)}%
118
+ </span>
119
+
120
+ {/* Comparison Rate */}
121
+ <span className="text-sm tabular-nums text-foreground">
122
+ {item.comparisonRate.toFixed(2)}%
123
+ </span>
124
+
125
+ {/* Monthly Repayments */}
126
+ <span className="text-sm text-foreground">
127
+ {item.monthlyRepayment}
128
+ </span>
129
+
130
+ {/* Total Cost */}
131
+ <span className="text-sm tabular-nums text-foreground">
132
+ {formatCurrencyAbbrev(item.totalCost)}
133
+ </span>
134
+
135
+ {/* Max Buying Power */}
136
+ <span className="text-sm font-semibold tabular-nums text-foreground">
137
+ {formatCurrency(item.maxBuyingPower)}
138
+ </span>
139
+ </div>
140
+ ))
141
+ : !isLoading && (
142
+ <p className="py-6 text-center text-sm text-muted-foreground">
143
+ No lender options available for this scenario.
144
+ </p>
145
+ )}
146
+ </div>
147
+
148
+ {/* Load more */}
149
+ {!isLoading && hasMore && (
150
+ <div className="flex justify-center pt-1">
151
+ <Button variant="outline" size="sm" onClick={handleLoadMore}>
152
+ Load More
153
+ </Button>
154
+ </div>
155
+ )}
156
+ </div>
157
+ );
158
+ }
@@ -0,0 +1,82 @@
1
+ import React from "react";
2
+ import { cn } from "@/lib/utils";
3
+ import { Slider } from "./slider";
4
+
5
+ /**
6
+ * Right-sidebar organism for the Borrowing Capacity page.
7
+ *
8
+ * Shows the current interest rate used in the calculation along with the
9
+ * resulting buying power and estimated repayments. The slider lets the user
10
+ * explore how different rates affect their borrowing capacity.
11
+ *
12
+ * This is a **controlled** component — the consumer owns `rate` and
13
+ * `onRateChange`; no internal state is held.
14
+ */
15
+
16
+ export interface InterestRateUsedProps {
17
+ /** Current interest rate (%) — drives the slider position */
18
+ rate: number;
19
+ /** Called when the slider is moved */
20
+ onRateChange: (rate: number) => void;
21
+ /** Pre-formatted buying power string, e.g. "$957.53K" */
22
+ buyingPowerFormatted: string;
23
+ /** Pre-formatted repayments string, e.g. "$2.66K" */
24
+ repaymentsFormatted: string;
25
+ /** Minimum rate (default: 0) */
26
+ minRate?: number;
27
+ /** Maximum rate (default: 13) */
28
+ maxRate?: number;
29
+ /** Slider step (default: 0.01) */
30
+ rateStep?: number;
31
+ className?: string;
32
+ }
33
+
34
+ export function InterestRateUsed({
35
+ rate,
36
+ onRateChange,
37
+ buyingPowerFormatted,
38
+ repaymentsFormatted,
39
+ minRate = 0,
40
+ maxRate = 13,
41
+ rateStep = 0.01,
42
+ className,
43
+ }: InterestRateUsedProps) {
44
+ return (
45
+ <div
46
+ className={cn(
47
+ "flex flex-col items-center gap-3 border-b border-border px-4 py-4 text-center",
48
+ className,
49
+ )}
50
+ >
51
+ <p className="text-base font-bold text-foreground">Interest Rate Used</p>
52
+
53
+ <div className="flex w-full justify-around gap-4">
54
+ <div className="flex flex-col gap-0.5">
55
+ <p className="text-sm text-muted-foreground">Current Buying Power</p>
56
+ <p className="text-lg font-bold text-foreground">
57
+ {buyingPowerFormatted}
58
+ </p>
59
+ </div>
60
+ <div className="flex flex-col gap-0.5">
61
+ <p className="text-sm text-muted-foreground">Repayments</p>
62
+ <p className="text-lg font-bold text-foreground">
63
+ {repaymentsFormatted}
64
+ </p>
65
+ </div>
66
+ </div>
67
+
68
+ <div className="flex w-full flex-col gap-2">
69
+ <p className="text-sm font-semibold text-foreground">
70
+ {rate.toFixed(2)}%
71
+ </p>
72
+ <Slider
73
+ value={rate}
74
+ min={minRate}
75
+ max={maxRate}
76
+ step={rateStep}
77
+ onValueChange={onRateChange}
78
+ />
79
+ </div>
80
+ </div>
81
+ );
82
+ }
@@ -97,11 +97,15 @@ export interface KanbanColumnProps {
97
97
  onMarkAsDone?: (opportunityId: string) => void;
98
98
  onMoveToNextStage?: (opportunityId: string) => void;
99
99
  onSendLoanApplication?: (opportunityId: string) => void;
100
+ /** Fires when clicking the non-interactive card body. */
101
+ onCardClick?: (opportunityId: string) => void;
100
102
  onViewDetails?: (opportunityId: string) => void;
101
103
  onChangePriority?: (opportunityId: string) => void;
102
104
  onLaunchAssistant?: (opportunityId: string) => void;
103
105
  onPutOnHold?: (opportunityId: string) => void;
104
106
  onDeleteOpportunity?: (opportunityId: string) => void;
107
+ /** Fires when a card is dropped onto this column (HTML5 DnD). */
108
+ onCardDrop?: (cardId: string) => void;
105
109
  /** Opportunity ID currently being submitted — disables that card's actions. */
106
110
  submittingOpportunityId?: string | null;
107
111
 
@@ -143,11 +147,13 @@ export function KanbanColumn({
143
147
  onMarkAsDone,
144
148
  onMoveToNextStage,
145
149
  onSendLoanApplication,
150
+ onCardClick,
146
151
  onViewDetails,
147
152
  onChangePriority,
148
153
  onLaunchAssistant,
149
154
  onPutOnHold,
150
155
  onDeleteOpportunity,
156
+ onCardDrop,
151
157
  submittingOpportunityId,
152
158
  className,
153
159
  }: KanbanColumnProps) {
@@ -155,6 +161,31 @@ export function KanbanColumn({
155
161
  const accentColor = stage.accentColor ?? "var(--color-border)";
156
162
  const hasMenu = onEditColumn || (!isDefault && onDeleteColumn);
157
163
 
164
+ // ── HTML5 drag-and-drop drop-zone state ──────────────────────
165
+ const [isDragOver, setIsDragOver] = React.useState(false);
166
+
167
+ function handleDragOver(e: React.DragEvent<HTMLDivElement>) {
168
+ if (!onCardDrop) return;
169
+ e.preventDefault();
170
+ e.dataTransfer.dropEffect = "move";
171
+ setIsDragOver(true);
172
+ }
173
+
174
+ function handleDragLeave(e: React.DragEvent<HTMLDivElement>) {
175
+ // Only clear when leaving the column entirely (not entering a child)
176
+ if (!e.currentTarget.contains(e.relatedTarget as Node)) {
177
+ setIsDragOver(false);
178
+ }
179
+ }
180
+
181
+ function handleDrop(e: React.DragEvent<HTMLDivElement>) {
182
+ if (!onCardDrop) return;
183
+ e.preventDefault();
184
+ setIsDragOver(false);
185
+ const cardId = e.dataTransfer.getData("text/plain");
186
+ if (cardId) onCardDrop(cardId);
187
+ }
188
+
158
189
  return (
159
190
  <div
160
191
  className={cn(
@@ -231,9 +262,17 @@ export function KanbanColumn({
231
262
  </div>
232
263
 
233
264
  {/* ── Body ── */}
234
- <div className="flex flex-1 flex-col gap-2 overflow-y-auto p-2">
265
+ <div
266
+ className={cn(
267
+ "flex flex-1 flex-col gap-2 overflow-y-auto p-2",
268
+ isDragOver && "ring-2 ring-primary ring-inset bg-primary/5",
269
+ )}
270
+ onDragOver={handleDragOver}
271
+ onDragLeave={handleDragLeave}
272
+ onDrop={handleDrop}
273
+ >
235
274
  {/* Drop target hint — shown at top when a card is dragged over */}
236
- {isDropTarget && (
275
+ {(isDropTarget || isDragOver) && (
237
276
  <div className="border border-dashed border-primary/40 bg-primary/5 px-3 py-2 text-center text-xs text-primary">
238
277
  Drop here → {stage.name}
239
278
  </div>
@@ -272,6 +311,18 @@ export function KanbanColumn({
272
311
  <OpportunityCard
273
312
  key={opp.id}
274
313
  {...opp}
314
+ draggable={!!onCardDrop}
315
+ onDragStart={
316
+ onCardDrop
317
+ ? (e) => {
318
+ e.dataTransfer.setData("text/plain", opp.id);
319
+ e.dataTransfer.effectAllowed = "move";
320
+ }
321
+ : undefined
322
+ }
323
+ onCardClick={
324
+ onCardClick ? () => onCardClick(opp.id) : undefined
325
+ }
275
326
  onTaskToggle={
276
327
  onTaskToggle
277
328
  ? (taskId) => onTaskToggle(opp.id, taskId)
@@ -0,0 +1,64 @@
1
+ import React from "react";
2
+ import { cn } from "@/lib/utils";
3
+ import { Badge } from "./badge";
4
+ import { Button } from "./button";
5
+ import { Card } from "./card";
6
+ import { Pencil } from "lucide-react";
7
+
8
+ export type ApplicantStatus = "active" | "waiting";
9
+
10
+ export interface LoanApplicantInformationProps {
11
+ name: string;
12
+ phone: string;
13
+ email: string;
14
+ /** "waiting" shows a badge next to the name */
15
+ status?: ApplicantStatus;
16
+ /** When provided, shows an edit button in the top-right corner */
17
+ onEdit?: () => void;
18
+ className?: string;
19
+ }
20
+
21
+ export function LoanApplicantInformation({
22
+ name,
23
+ phone,
24
+ email,
25
+ status = "active",
26
+ onEdit,
27
+ className,
28
+ }: LoanApplicantInformationProps) {
29
+ return (
30
+ <Card className={cn("relative flex flex-col gap-3 p-4", className)}>
31
+ {onEdit && (
32
+ <Button
33
+ variant="ghost"
34
+ size="icon"
35
+ onClick={onEdit}
36
+ className="absolute top-2 right-2 h-7 w-7 text-muted-foreground"
37
+ aria-label="Edit applicant"
38
+ >
39
+ <Pencil className="h-3.5 w-3.5" />
40
+ </Button>
41
+ )}
42
+
43
+ <div className="flex items-center gap-2">
44
+ <span className="text-sm font-semibold text-foreground">{name}</span>
45
+ {status === "waiting" && (
46
+ <Badge variant="warning" className="text-xs">
47
+ Waiting
48
+ </Badge>
49
+ )}
50
+ </div>
51
+
52
+ <div className="flex flex-col gap-1.5">
53
+ <p className="text-sm text-foreground">
54
+ <span className="font-medium">{phone}</span>{" "}
55
+ <span className="text-muted-foreground">contact number</span>
56
+ </p>
57
+ <p className="text-sm text-foreground">
58
+ <span className="font-medium">{email}</span>{" "}
59
+ <span className="text-muted-foreground">contact email</span>
60
+ </p>
61
+ </div>
62
+ </Card>
63
+ );
64
+ }
@@ -0,0 +1,67 @@
1
+ import React, { useState } from "react";
2
+ import { cn } from "@/lib/utils";
3
+ import { Button } from "./button";
4
+ import { Card } from "./card";
5
+ import { Input } from "./input";
6
+ import { SendHorizontal } from "lucide-react";
7
+
8
+ const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
9
+
10
+ export interface LoanApplicantInviteProps {
11
+ /** Called when the user submits a valid email */
12
+ onInvite?: (email: string) => void;
13
+ loading?: boolean;
14
+ className?: string;
15
+ }
16
+
17
+ export function LoanApplicantInvite({
18
+ onInvite,
19
+ loading = false,
20
+ className,
21
+ }: LoanApplicantInviteProps) {
22
+ const [email, setEmail] = useState("");
23
+ const isValid = EMAIL_RE.test(email);
24
+
25
+ const handleSend = () => {
26
+ if (!isValid) return;
27
+ onInvite?.(email);
28
+ setEmail("");
29
+ };
30
+
31
+ const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
32
+ if (e.key === "Enter") handleSend();
33
+ };
34
+
35
+ return (
36
+ <Card className={cn("flex flex-col gap-3 p-4", className)}>
37
+ <p className="text-sm font-medium text-foreground">
38
+ Create Joint Application
39
+ </p>
40
+
41
+ <div className="flex">
42
+ <Input
43
+ type="email"
44
+ value={email}
45
+ onChange={(e) => setEmail(e.target.value)}
46
+ onKeyDown={handleKeyDown}
47
+ placeholder="Co-applicant email"
48
+ className="flex-1 border-r-0 focus-visible:ring-0 focus-visible:ring-offset-0"
49
+ aria-label="Co-applicant email"
50
+ />
51
+ <Button
52
+ onClick={handleSend}
53
+ disabled={!isValid || loading}
54
+ size="icon"
55
+ className="shrink-0"
56
+ aria-label="Send invite"
57
+ >
58
+ <SendHorizontal className="h-4 w-4" />
59
+ </Button>
60
+ </div>
61
+
62
+ {email && !isValid && (
63
+ <p className="text-xs text-destructive">Invalid email address</p>
64
+ )}
65
+ </Card>
66
+ );
67
+ }
@@ -0,0 +1,70 @@
1
+ import React from "react";
2
+ import { CheckIcon } from "lucide-react";
3
+
4
+ import { cn } from "../../lib/utils";
5
+ import { Badge } from "./badge";
6
+
7
+ // ---------------------------------------------------------------------------
8
+ // Types
9
+ // ---------------------------------------------------------------------------
10
+
11
+ /** The three lifecycle states of a loan application in the contact CRM. */
12
+ export type LoanApplicationBadgeStatus = "SENT" | "IN_PROGRESS" | "COMPLETED";
13
+
14
+ export interface LoanApplicationBadgeProps {
15
+ /** Loan application lifecycle status. */
16
+ status: LoanApplicationBadgeStatus;
17
+ /** Optional extra class names applied to the Badge element. */
18
+ className?: string;
19
+ }
20
+
21
+ // ---------------------------------------------------------------------------
22
+ // Status config
23
+ // ---------------------------------------------------------------------------
24
+
25
+ const STATUS_CONFIG: Record<
26
+ LoanApplicationBadgeStatus,
27
+ { label: string; statusClassName: string; showCheck: boolean }
28
+ > = {
29
+ SENT: {
30
+ label: "Sent Application",
31
+ statusClassName: "border-info/40 bg-info/10 text-info-text",
32
+ showCheck: false,
33
+ },
34
+ IN_PROGRESS: {
35
+ label: "Application In Progress",
36
+ statusClassName: "border-warning/40 bg-warning/10 text-warning-text",
37
+ showCheck: false,
38
+ },
39
+ COMPLETED: {
40
+ label: "Loan Application",
41
+ statusClassName: "border-success/40 bg-success/10 text-success-text",
42
+ showCheck: true,
43
+ },
44
+ };
45
+
46
+ // ---------------------------------------------------------------------------
47
+ // Component
48
+ // ---------------------------------------------------------------------------
49
+
50
+ /**
51
+ * Inline badge showing the lifecycle state of a loan application.
52
+ *
53
+ * Used in the Backoffice Contact CRM table `Name` cell to surface which
54
+ * contacts have an active loan application and where they are in the process.
55
+ */
56
+ export function LoanApplicationBadge({
57
+ status,
58
+ className,
59
+ }: LoanApplicationBadgeProps) {
60
+ const { label, statusClassName, showCheck } = STATUS_CONFIG[status];
61
+ return (
62
+ <Badge
63
+ variant="outline"
64
+ className={cn("w-fit text-xs gap-1", statusClassName, className)}
65
+ >
66
+ {showCheck && <CheckIcon aria-hidden="true" className="size-3" />}
67
+ {label}
68
+ </Badge>
69
+ );
70
+ }