@wealthx/shadcn 1.4.1 → 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 +6 -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
@@ -26,7 +26,7 @@ import { Textarea } from "./textarea";
26
26
  import { Toggle } from "./toggle";
27
27
  import { Badge } from "./badge";
28
28
  import { Avatar, AvatarFallback } from "./avatar";
29
- import { MapPin, Phone, Video } from "lucide-react";
29
+ import { CalendarCheck, MapPin, Phone, Users, Video } from "lucide-react";
30
30
  import { formatDateLong } from "@/lib/format-date";
31
31
  import {
32
32
  AppointmentSlotSection,
@@ -124,6 +124,15 @@ export interface AppointmentBookDialogProps {
124
124
  * Used when rebooking from a cancelled appointment via `AppointmentDetailSheet`.
125
125
  */
126
126
  initialClientId?: string;
127
+ /**
128
+ * Pre-set meeting format from the advisor's availability settings.
129
+ * In **client mode**, when this is provided the meeting format picker is
130
+ * hidden — the client books using this format only.
131
+ * Has no effect in advisor mode (advisors always see the format picker).
132
+ *
133
+ * @remarks Mount-time initialiser only.
134
+ */
135
+ defaultMeetingFormat?: AppointmentMeetingFormat;
127
136
  /**
128
137
  * Guest identity for **client / public booking mode** only.
129
138
  * When all fields are provided the guest form is hidden; when any field is
@@ -238,6 +247,11 @@ const FORMAT_OPTIONS: {
238
247
  label: "Google Meet",
239
248
  icon: <Video className="h-4 w-4" />,
240
249
  },
250
+ {
251
+ value: "microsoft-teams",
252
+ label: "MS Teams",
253
+ icon: <Users className="h-4 w-4" />,
254
+ },
241
255
  {
242
256
  value: "offline",
243
257
  label: "Offline",
@@ -245,9 +259,16 @@ const FORMAT_OPTIONS: {
245
259
  },
246
260
  ];
247
261
 
262
+ // Pre-baked references — FORMAT_OPTIONS is a module constant so these are stable
263
+ const FORMAT_CALL = FORMAT_OPTIONS[0];
264
+ const FORMAT_OFFLINE = FORMAT_OPTIONS[3];
265
+ // Icon shared by the "Online Meeting" collapsed option in client mode
266
+ const ONLINE_MEETING_ICON = <Video className="h-4 w-4" />;
267
+
248
268
  function MeetingFormatSection({
249
269
  format,
250
270
  onFormatChange,
271
+ options = FORMAT_OPTIONS,
251
272
  offlineLocation,
252
273
  onOfflineLocationChange,
253
274
  customAddress,
@@ -258,6 +279,7 @@ function MeetingFormatSection({
258
279
  }: {
259
280
  format: AppointmentMeetingFormat;
260
281
  onFormatChange: (f: AppointmentMeetingFormat) => void;
282
+ options?: typeof FORMAT_OPTIONS;
261
283
  offlineLocation: AppointmentOfflineLocation;
262
284
  onOfflineLocationChange: (l: AppointmentOfflineLocation) => void;
263
285
  customAddress: string;
@@ -269,7 +291,7 @@ function MeetingFormatSection({
269
291
  return (
270
292
  <div className="flex flex-col gap-2">
271
293
  <div className="flex gap-2">
272
- {FORMAT_OPTIONS.map((opt) => (
294
+ {options.map((opt) => (
273
295
  <Toggle
274
296
  key={opt.value}
275
297
  variant="outline"
@@ -328,6 +350,80 @@ function MeetingFormatSection({
328
350
  );
329
351
  }
330
352
 
353
+ // ---------------------------------------------------------------------------
354
+ // Booking confirmation sub-component (client mode only)
355
+ // ---------------------------------------------------------------------------
356
+
357
+ interface SubmittedBooking {
358
+ advisorName?: string;
359
+ date: Date;
360
+ slotLabel: string;
361
+ }
362
+
363
+ function SummaryRow({
364
+ label,
365
+ value,
366
+ border = true,
367
+ }: {
368
+ label: string;
369
+ value: React.ReactNode;
370
+ border?: boolean;
371
+ }) {
372
+ return (
373
+ <div
374
+ className={`flex items-center justify-between px-4 py-3 ${border ? "border-b border-border" : ""}`}
375
+ >
376
+ <span className="text-xs text-muted-foreground">{label}</span>
377
+ {typeof value === "string" ? (
378
+ <span className="text-xs font-medium">{value}</span>
379
+ ) : (
380
+ value
381
+ )}
382
+ </div>
383
+ );
384
+ }
385
+
386
+ function BookingConfirmationScreen({
387
+ booking,
388
+ onDone,
389
+ }: {
390
+ booking: SubmittedBooking;
391
+ onDone: () => void;
392
+ }) {
393
+ return (
394
+ <div className="flex flex-col items-center gap-6 py-4 text-center">
395
+ <div className="flex h-16 w-16 items-center justify-center bg-success/10">
396
+ <CalendarCheck className="h-8 w-8 text-success" />
397
+ </div>
398
+
399
+ <div className="flex flex-col gap-1.5">
400
+ <h3 className="text-lg font-semibold">Booking request sent!</h3>
401
+ <p className="text-sm text-muted-foreground">
402
+ Your advisor will review and confirm the appointment. You'll receive a
403
+ notification once it's confirmed.
404
+ </p>
405
+ </div>
406
+
407
+ <div className="w-full border border-border bg-muted/30 text-left">
408
+ {booking.advisorName && (
409
+ <SummaryRow label="Advisor" value={booking.advisorName} />
410
+ )}
411
+ <SummaryRow label="Date" value={formatDateLong(booking.date)} />
412
+ <SummaryRow label="Time" value={booking.slotLabel} />
413
+ <SummaryRow
414
+ label="Status"
415
+ value={<Badge variant="warning">Pending confirmation</Badge>}
416
+ border={false}
417
+ />
418
+ </div>
419
+
420
+ <Button className="w-full" onClick={onDone}>
421
+ Done
422
+ </Button>
423
+ </div>
424
+ );
425
+ }
426
+
331
427
  // ---------------------------------------------------------------------------
332
428
  // Constants
333
429
  // ---------------------------------------------------------------------------
@@ -359,6 +455,7 @@ export function AppointmentBookDialog({
359
455
  clientHomeAddress,
360
456
  advisorInfo,
361
457
  initialClientId,
458
+ defaultMeetingFormat,
362
459
  guestInfo,
363
460
  onBook,
364
461
  }: AppointmentBookDialogProps) {
@@ -366,6 +463,22 @@ export function AppointmentBookDialog({
366
463
  // Guest form is shown in client mode when at least one identity field is missing.
367
464
  const showGuestForm = isClientMode && !(guestInfo?.name && guestInfo?.email);
368
465
 
466
+ // In client mode with a preset online platform, collapse Google Meet / MS Teams
467
+ // into a single "Online Meeting" option so the client sees 3 choices:
468
+ // Call | Online Meeting | Offline — without knowing the specific platform.
469
+ const visibleFormatOptions: typeof FORMAT_OPTIONS =
470
+ isClientMode && defaultMeetingFormat
471
+ ? [
472
+ FORMAT_CALL,
473
+ {
474
+ value: defaultMeetingFormat,
475
+ label: "Online Meeting",
476
+ icon: ONLINE_MEETING_ICON,
477
+ },
478
+ FORMAT_OFFLINE,
479
+ ]
480
+ : FORMAT_OPTIONS;
481
+
369
482
  const disabledDayOfWeek = React.useMemo(
370
483
  () =>
371
484
  schedule
@@ -375,16 +488,19 @@ export function AppointmentBookDialog({
375
488
  [schedule],
376
489
  );
377
490
 
491
+ // Stable "today" reference — avoids prop identity churn on CalendarPicker each render
492
+ const today = React.useMemo(() => new Date(), []);
493
+
378
494
  const [clientId, setClientId] = React.useState<string | undefined>(undefined);
379
495
  const [meetingType, setMeetingType] = React.useState("");
380
496
  const [meetingFormat, setMeetingFormat] =
381
- React.useState<AppointmentMeetingFormat>("call");
497
+ React.useState<AppointmentMeetingFormat>(defaultMeetingFormat ?? "call");
382
498
  const [offlineLocation, setOfflineLocation] =
383
499
  React.useState<AppointmentOfflineLocation>(
384
500
  advisorOfficeAddress ? "office" : "custom",
385
501
  );
386
502
  const [customAddress, setCustomAddress] = React.useState("");
387
- const [date, setDate] = React.useState<Date | undefined>(new Date());
503
+ const [date, setDate] = React.useState<Date | undefined>(() => new Date());
388
504
  const [selectedSlot, setSelectedSlot] = React.useState<
389
505
  AppointmentTimeSlot | undefined
390
506
  >(undefined);
@@ -398,6 +514,10 @@ export function AppointmentBookDialog({
398
514
  const [guestEmail, setGuestEmail] = React.useState(guestInfo?.email ?? "");
399
515
  const [guestPhone, setGuestPhone] = React.useState(guestInfo?.phone ?? "");
400
516
 
517
+ // null = form view; non-null = confirmation screen (client mode only)
518
+ const [submittedBooking, setSubmittedBooking] =
519
+ React.useState<SubmittedBooking | null>(null);
520
+
401
521
  const selectedClient = React.useMemo(
402
522
  () => clients.find((c) => c.id === clientId),
403
523
  [clients, clientId],
@@ -441,7 +561,7 @@ export function AppointmentBookDialog({
441
561
  if (!next) {
442
562
  setClientId(undefined);
443
563
  setMeetingType("");
444
- setMeetingFormat("call");
564
+ setMeetingFormat(defaultMeetingFormat ?? "call");
445
565
  setOfflineLocation(advisorOfficeAddress ? "office" : "custom");
446
566
  setCustomAddress("");
447
567
  setDate(new Date());
@@ -451,281 +571,308 @@ export function AppointmentBookDialog({
451
571
  setGuestName(guestInfo?.name ?? "");
452
572
  setGuestEmail(guestInfo?.email ?? "");
453
573
  setGuestPhone(guestInfo?.phone ?? "");
574
+ setSubmittedBooking(null);
454
575
  }
455
576
  onOpenChange(next);
456
577
  };
457
578
 
458
579
  return (
459
580
  <Dialog open={open} onOpenChange={handleOpenChange}>
460
- <DialogContent size="2xl" align="top">
461
- <DialogHeader>
462
- <DialogTitle>
463
- {isClientMode ? "Book an Appointment" : "New appointment"}
464
- </DialogTitle>
465
- <DialogDescription>
466
- {isClientMode
467
- ? "Request a meeting with your advisor. They will confirm once the appointment is reviewed."
468
- : "Book a meeting with a client. They will receive a confirmation email once the appointment is created."}
469
- </DialogDescription>
470
-
471
- {/* Advisor chip — client mode only */}
472
- {isClientMode && advisorInfo && (
473
- <div className="mt-3 flex items-center gap-3 border border-border bg-muted/30 px-3 py-2">
474
- <Avatar className="h-8 w-8 shrink-0">
475
- <AvatarFallback className="text-xs">
476
- {advisorInfo.initials}
477
- </AvatarFallback>
478
- </Avatar>
479
- <div className="flex flex-col gap-0.5">
480
- <p className="text-sm font-medium">{advisorInfo.name}</p>
481
- <p className="text-xs text-muted-foreground">
482
- {advisorInfo.role}
483
- </p>
484
- </div>
485
- </div>
486
- )}
487
- </DialogHeader>
488
-
489
- <Separator />
490
-
491
- <div className="flex flex-col gap-4">
492
- {!isClientMode && (
493
- <div className="flex flex-col gap-1.5">
494
- <Label>Client</Label>
495
- <ClientSearch
496
- clients={clients}
497
- value={clientId}
498
- onValueChange={setClientId}
499
- />
500
- </div>
501
- )}
581
+ <DialogContent size="2xl">
582
+ {submittedBooking ? (
583
+ <BookingConfirmationScreen
584
+ booking={submittedBooking}
585
+ onDone={() => handleOpenChange(false)}
586
+ />
587
+ ) : (
588
+ <>
589
+ <DialogHeader>
590
+ <DialogTitle>
591
+ {isClientMode ? "Book an Appointment" : "New appointment"}
592
+ </DialogTitle>
593
+ <DialogDescription>
594
+ {isClientMode
595
+ ? "Request a meeting with your advisor. They will confirm once the appointment is reviewed."
596
+ : "Book a meeting with a client. They will receive a confirmation email once the appointment is created."}
597
+ </DialogDescription>
598
+
599
+ {/* Advisor chip — client mode only */}
600
+ {isClientMode && advisorInfo && (
601
+ <div className="mt-3 flex items-center gap-3 border border-border bg-muted/30 px-3 py-2">
602
+ <Avatar className="h-8 w-8 shrink-0">
603
+ <AvatarFallback className="text-xs">
604
+ {advisorInfo.initials}
605
+ </AvatarFallback>
606
+ </Avatar>
607
+ <div className="flex flex-col gap-0.5">
608
+ <p className="text-sm font-medium">{advisorInfo.name}</p>
609
+ <p className="text-xs text-muted-foreground">
610
+ {advisorInfo.role}
611
+ </p>
612
+ </div>
613
+ </div>
614
+ )}
615
+ </DialogHeader>
616
+
617
+ <Separator />
618
+
619
+ <div className="flex flex-col gap-4">
620
+ {!isClientMode && (
621
+ <div className="flex flex-col gap-1.5">
622
+ <Label>Client</Label>
623
+ <ClientSearch
624
+ clients={clients}
625
+ value={clientId}
626
+ onValueChange={setClientId}
627
+ />
628
+ </div>
629
+ )}
502
630
 
503
- {meetingTypes.length > 0 && (
504
- <div className="flex flex-col gap-1.5">
505
- <Label htmlFor="book-apt-type">
506
- {isClientMode ? "Appointment type" : "Meeting type"}
507
- </Label>
508
- <Select onValueChange={(v) => setMeetingType(v as string)}>
509
- <SelectTrigger id="book-apt-type" className="w-full">
510
- <SelectValue placeholder="Select meeting type…" />
511
- </SelectTrigger>
512
- <SelectContent>
513
- {meetingTypes.map((t) => (
514
- <SelectItem key={t} value={t}>
515
- {t}
516
- </SelectItem>
517
- ))}
518
- </SelectContent>
519
- </Select>
520
- </div>
521
- )}
631
+ {meetingTypes.length > 0 && (
632
+ <div className="flex flex-col gap-1.5">
633
+ <Label htmlFor="book-apt-type">
634
+ {isClientMode ? "Appointment type" : "Meeting type"}
635
+ </Label>
636
+ <Select onValueChange={(v) => setMeetingType(v as string)}>
637
+ <SelectTrigger id="book-apt-type" className="w-full">
638
+ <SelectValue placeholder="Select meeting type…" />
639
+ </SelectTrigger>
640
+ <SelectContent>
641
+ {meetingTypes.map((t) => (
642
+ <SelectItem key={t} value={t}>
643
+ {t}
644
+ </SelectItem>
645
+ ))}
646
+ </SelectContent>
647
+ </Select>
648
+ </div>
649
+ )}
650
+
651
+ {/* Guest identity — public booking only */}
652
+ {showGuestForm && (
653
+ <>
654
+ <div className="flex flex-col gap-1.5">
655
+ <Label htmlFor="guest-name">Full name</Label>
656
+ <Input
657
+ id="guest-name"
658
+ placeholder="Your full name"
659
+ value={guestName}
660
+ onChange={(e) => setGuestName(e.target.value)}
661
+ autoComplete="name"
662
+ />
663
+ </div>
664
+ <div className="flex flex-col gap-1.5">
665
+ <Label htmlFor="guest-email">Email</Label>
666
+ <Input
667
+ id="guest-email"
668
+ type="email"
669
+ placeholder="your@email.com"
670
+ value={guestEmail}
671
+ onChange={(e) => setGuestEmail(e.target.value)}
672
+ autoComplete="email"
673
+ />
674
+ </div>
675
+ <div className="flex flex-col gap-1.5">
676
+ <Label htmlFor="guest-phone">
677
+ Phone{" "}
678
+ <span className="font-normal text-muted-foreground">
679
+ (optional)
680
+ </span>
681
+ </Label>
682
+ <Input
683
+ id="guest-phone"
684
+ type="tel"
685
+ placeholder="+61 4XX XXX XXX"
686
+ value={guestPhone}
687
+ onChange={(e) => setGuestPhone(e.target.value)}
688
+ autoComplete="tel"
689
+ />
690
+ </div>
691
+ </>
692
+ )}
522
693
 
523
- {/* Guest identity — public booking only */}
524
- {showGuestForm && (
525
- <>
694
+ {/* Format picker
695
+ - Advisor mode: all options (Call / Google Meet / MS Teams / Offline)
696
+ - Client mode, no preset: all options
697
+ - Client mode, preset online format: only [broker's platform, Offline]
698
+ so clients can still choose in-person while the online platform is locked */}
526
699
  <div className="flex flex-col gap-1.5">
527
- <Label htmlFor="guest-name">Full name</Label>
528
- <Input
529
- id="guest-name"
530
- placeholder="Your full name"
531
- value={guestName}
532
- onChange={(e) => setGuestName(e.target.value)}
533
- autoComplete="name"
700
+ <Label>Meeting format</Label>
701
+ <MeetingFormatSection
702
+ format={meetingFormat}
703
+ onFormatChange={setMeetingFormat}
704
+ options={visibleFormatOptions}
705
+ offlineLocation={offlineLocation}
706
+ onOfflineLocationChange={setOfflineLocation}
707
+ customAddress={customAddress}
708
+ onCustomAddressChange={setCustomAddress}
709
+ advisorOfficeAddress={advisorOfficeAddress}
710
+ clientHomeAddress={clientHomeAddress}
711
+ isClientMode={isClientMode}
534
712
  />
535
713
  </div>
536
- <div className="flex flex-col gap-1.5">
537
- <Label htmlFor="guest-email">Email</Label>
538
- <Input
539
- id="guest-email"
540
- type="email"
541
- placeholder="your@email.com"
542
- value={guestEmail}
543
- onChange={(e) => setGuestEmail(e.target.value)}
544
- autoComplete="email"
545
- />
714
+
715
+ {/* Phone selection — advisor mode, Call format, client has phones */}
716
+ {!isClientMode &&
717
+ meetingFormat === "call" &&
718
+ selectedClient?.phones &&
719
+ selectedClient.phones.length > 0 && (
720
+ <div className="flex flex-col gap-1.5">
721
+ <Label>
722
+ {selectedClient.accountType === "Joint"
723
+ ? "Select a contact number"
724
+ : "Phone number"}
725
+ </Label>
726
+ <RadioGroup
727
+ value={selectedPhone ?? ""}
728
+ onValueChange={(v) => setSelectedPhone(v as string)}
729
+ className="gap-1 border border-border p-3"
730
+ >
731
+ {selectedClient.phones.map((phone) => (
732
+ <div
733
+ key={phone}
734
+ className="flex items-center gap-3 p-2 hover:bg-muted/50"
735
+ >
736
+ <RadioGroupItem value={phone} id={`phone-${phone}`} />
737
+ <Label
738
+ htmlFor={`phone-${phone}`}
739
+ className="flex cursor-pointer items-center gap-2 font-normal"
740
+ >
741
+ <Phone className="h-4 w-4 text-muted-foreground" />
742
+ {phone}
743
+ </Label>
744
+ </div>
745
+ ))}
746
+ </RadioGroup>
747
+ </div>
748
+ )}
749
+
750
+ {/* Date + Time slot — side by side */}
751
+ <div className="grid grid-cols-[auto_1fr] items-start gap-5">
752
+ <div className="flex flex-col gap-1.5">
753
+ <Label>Date</Label>
754
+ <CalendarPicker
755
+ mode="single"
756
+ selected={date}
757
+ onSelect={(d) => {
758
+ setDate(d);
759
+ setSelectedSlot(undefined);
760
+ if (d) onDateChange?.(d);
761
+ }}
762
+ captionLayout="label"
763
+ fromDate={today}
764
+ disabled={
765
+ disabledDayOfWeek && disabledDayOfWeek.length > 0
766
+ ? [{ before: today }, { dayOfWeek: disabledDayOfWeek }]
767
+ : { before: today }
768
+ }
769
+ className="border border-border"
770
+ />
771
+ </div>
772
+ <div className="flex flex-col gap-1.5">
773
+ <Label>Time slot</Label>
774
+ {date ? (
775
+ <div className="flex flex-col gap-3">
776
+ <p className="text-xs text-muted-foreground">
777
+ {formatDateLong(date)}
778
+ </p>
779
+ <AppointmentSlotSection
780
+ label="Morning"
781
+ slots={amSlots}
782
+ selectedSlotId={selectedSlot?.id}
783
+ onSelect={setSelectedSlot}
784
+ />
785
+ <AppointmentSlotSection
786
+ label="Afternoon"
787
+ slots={pmSlots}
788
+ selectedSlotId={selectedSlot?.id}
789
+ onSelect={setSelectedSlot}
790
+ />
791
+ </div>
792
+ ) : (
793
+ <p className="text-sm text-muted-foreground">
794
+ Select a date to see available slots.
795
+ </p>
796
+ )}
797
+ </div>
546
798
  </div>
799
+
800
+ {/* Notes */}
547
801
  <div className="flex flex-col gap-1.5">
548
- <Label htmlFor="guest-phone">
549
- Phone{" "}
802
+ <Label htmlFor="book-apt-notes">
803
+ Notes{" "}
550
804
  <span className="font-normal text-muted-foreground">
551
805
  (optional)
552
806
  </span>
553
807
  </Label>
554
- <Input
555
- id="guest-phone"
556
- type="tel"
557
- placeholder="+61 4XX XXX XXX"
558
- value={guestPhone}
559
- onChange={(e) => setGuestPhone(e.target.value)}
560
- autoComplete="tel"
808
+ <Textarea
809
+ id="book-apt-notes"
810
+ placeholder={
811
+ isClientMode
812
+ ? "Let your advisor know what you'd like to discuss…"
813
+ : "e.g. Client wants to discuss refinancing their investment property…"
814
+ }
815
+ value={notes}
816
+ onChange={(e) => setNotes(e.target.value)}
817
+ className="w-full resize-none"
818
+ rows={2}
561
819
  />
562
820
  </div>
563
- </>
564
- )}
565
-
566
- <div className="flex flex-col gap-1.5">
567
- <Label>Meeting format</Label>
568
- <MeetingFormatSection
569
- format={meetingFormat}
570
- onFormatChange={setMeetingFormat}
571
- offlineLocation={offlineLocation}
572
- onOfflineLocationChange={setOfflineLocation}
573
- customAddress={customAddress}
574
- onCustomAddressChange={setCustomAddress}
575
- advisorOfficeAddress={advisorOfficeAddress}
576
- clientHomeAddress={clientHomeAddress}
577
- isClientMode={isClientMode}
578
- />
579
- </div>
580
-
581
- {/* Phone selection — advisor mode, Call format, client has phones */}
582
- {!isClientMode &&
583
- meetingFormat === "call" &&
584
- selectedClient?.phones &&
585
- selectedClient.phones.length > 0 && (
586
- <div className="flex flex-col gap-1.5">
587
- <Label>
588
- {selectedClient.accountType === "Joint"
589
- ? "Select a contact number"
590
- : "Phone number"}
591
- </Label>
592
- <RadioGroup
593
- value={selectedPhone ?? ""}
594
- onValueChange={(v) => setSelectedPhone(v as string)}
595
- className="gap-1 border border-border p-3"
596
- >
597
- {selectedClient.phones.map((phone) => (
598
- <div
599
- key={phone}
600
- className="flex items-center gap-3 p-2 hover:bg-muted/50"
601
- >
602
- <RadioGroupItem value={phone} id={`phone-${phone}`} />
603
- <Label
604
- htmlFor={`phone-${phone}`}
605
- className="flex cursor-pointer items-center gap-2 font-normal"
606
- >
607
- <Phone className="h-4 w-4 text-muted-foreground" />
608
- {phone}
609
- </Label>
610
- </div>
611
- ))}
612
- </RadioGroup>
613
- </div>
614
- )}
615
-
616
- {/* Date + Time slot — side by side */}
617
- <div className="grid grid-cols-[auto_1fr] items-start gap-5">
618
- <div className="flex flex-col gap-1.5">
619
- <Label>Date</Label>
620
- <CalendarPicker
621
- mode="single"
622
- selected={date}
623
- onSelect={(d) => {
624
- setDate(d);
625
- setSelectedSlot(undefined);
626
- if (d) onDateChange?.(d);
627
- }}
628
- captionLayout="label"
629
- fromDate={new Date()}
630
- disabled={
631
- disabledDayOfWeek && disabledDayOfWeek.length > 0
632
- ? [{ before: new Date() }, { dayOfWeek: disabledDayOfWeek }]
633
- : { before: new Date() }
634
- }
635
- className="border border-border"
636
- />
637
- </div>
638
- <div className="flex flex-col gap-1.5">
639
- <Label>Time slot</Label>
640
- {date ? (
641
- <div className="flex flex-col gap-3">
642
- <p className="text-xs text-muted-foreground">
643
- {formatDateLong(date)}
644
- </p>
645
- <AppointmentSlotSection
646
- label="Morning"
647
- slots={amSlots}
648
- selectedSlotId={selectedSlot?.id}
649
- onSelect={setSelectedSlot}
650
- />
651
- <AppointmentSlotSection
652
- label="Afternoon"
653
- slots={pmSlots}
654
- selectedSlotId={selectedSlot?.id}
655
- onSelect={setSelectedSlot}
656
- />
657
- </div>
658
- ) : (
659
- <p className="text-sm text-muted-foreground">
660
- Select a date to see available slots.
661
- </p>
662
- )}
663
821
  </div>
664
- </div>
665
-
666
- {/* Notes */}
667
- <div className="flex flex-col gap-1.5">
668
- <Label htmlFor="book-apt-notes">
669
- Notes{" "}
670
- <span className="font-normal text-muted-foreground">
671
- (optional)
672
- </span>
673
- </Label>
674
- <Textarea
675
- id="book-apt-notes"
676
- placeholder={
677
- isClientMode
678
- ? "Let your advisor know what you'd like to discuss…"
679
- : "e.g. Client wants to discuss refinancing their investment property…"
680
- }
681
- value={notes}
682
- onChange={(e) => setNotes(e.target.value)}
683
- className="w-full resize-none"
684
- rows={2}
685
- />
686
- </div>
687
- </div>
688
822
 
689
- <DialogFooter>
690
- <DialogClose render={<Button variant="outline" />}>
691
- Cancel
692
- </DialogClose>
693
- <Button
694
- disabled={!canSubmit}
695
- onClick={() => {
696
- if (canSubmit && date && selectedSlot) {
697
- onBook?.({
698
- clientId: clientId ?? "",
699
- meetingType,
700
- date,
701
- slot: selectedSlot,
702
- notes,
703
- meetingFormat,
704
- offlineLocation:
705
- meetingFormat === "offline" ? offlineLocation : undefined,
706
- customAddress:
707
- meetingFormat === "offline" && offlineLocation === "custom"
708
- ? customAddress
709
- : undefined,
710
- callPhone:
711
- meetingFormat === "call" ? selectedPhone : undefined,
712
- guestName: isClientMode
713
- ? guestName.trim() || undefined
714
- : undefined,
715
- guestEmail: isClientMode
716
- ? guestEmail.trim() || undefined
717
- : undefined,
718
- guestPhone: isClientMode
719
- ? guestPhone.trim() || undefined
720
- : undefined,
721
- });
722
- handleOpenChange(false);
723
- }
724
- }}
725
- >
726
- {isClientMode ? "Book Appointment" : "Create appointment"}
727
- </Button>
728
- </DialogFooter>
823
+ <DialogFooter>
824
+ <DialogClose render={<Button variant="outline" />}>
825
+ Cancel
826
+ </DialogClose>
827
+ <Button
828
+ disabled={!canSubmit}
829
+ onClick={() => {
830
+ if (canSubmit && date && selectedSlot) {
831
+ onBook?.({
832
+ clientId: clientId ?? "",
833
+ meetingType,
834
+ date,
835
+ slot: selectedSlot,
836
+ notes,
837
+ meetingFormat,
838
+ offlineLocation:
839
+ meetingFormat === "offline"
840
+ ? offlineLocation
841
+ : undefined,
842
+ customAddress:
843
+ meetingFormat === "offline" &&
844
+ offlineLocation === "custom"
845
+ ? customAddress
846
+ : undefined,
847
+ callPhone:
848
+ meetingFormat === "call" ? selectedPhone : undefined,
849
+ guestName: isClientMode
850
+ ? guestName.trim() || undefined
851
+ : undefined,
852
+ guestEmail: isClientMode
853
+ ? guestEmail.trim() || undefined
854
+ : undefined,
855
+ guestPhone: isClientMode
856
+ ? guestPhone.trim() || undefined
857
+ : undefined,
858
+ });
859
+ if (isClientMode) {
860
+ setSubmittedBooking({
861
+ advisorName: advisorInfo?.name,
862
+ date,
863
+ slotLabel: selectedSlot.label,
864
+ });
865
+ } else {
866
+ handleOpenChange(false);
867
+ }
868
+ }
869
+ }}
870
+ >
871
+ {isClientMode ? "Book Appointment" : "Create appointment"}
872
+ </Button>
873
+ </DialogFooter>
874
+ </>
875
+ )}
729
876
  </DialogContent>
730
877
  </Dialog>
731
878
  );