@wealthx/shadcn 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +360 -180
- package/CHANGELOG.md +12 -0
- package/dist/chunk-2A53WPEC.mjs +182 -0
- package/dist/{chunk-SIVYAI3M.mjs → chunk-2LLFNGJZ.mjs} +15 -15
- package/dist/chunk-2QNOPXMQ.mjs +360 -0
- package/dist/{chunk-K5QV4TT6.mjs → chunk-2WCIORP7.mjs} +29 -4
- package/dist/{chunk-5NF6T2RS.mjs → chunk-3AREQTZU.mjs} +8 -8
- package/dist/{chunk-2EM2FRU6.mjs → chunk-3WGFIFP6.mjs} +5 -5
- package/dist/{chunk-K4KOD3KR.mjs → chunk-42NEC57Y.mjs} +44 -25
- package/dist/{chunk-FL6DZFJK.mjs → chunk-46Q4335I.mjs} +121 -39
- package/dist/chunk-4DO3WM7V.mjs +48 -0
- package/dist/chunk-5FHBC6DY.mjs +68 -0
- package/dist/chunk-5SAYZ4CI.mjs +40 -0
- package/dist/chunk-5WMFKQZ6.mjs +180 -0
- package/dist/chunk-623YVI5O.mjs +43 -0
- package/dist/{chunk-SFH2NJEJ.mjs → chunk-6OSULDEO.mjs} +3 -3
- package/dist/{chunk-UALR6JGV.mjs → chunk-6SR4K5T5.mjs} +1 -1
- package/dist/{chunk-D2NSIIXG.mjs → chunk-7KT5HPYM.mjs} +11 -11
- package/dist/chunk-A6ER36CW.mjs +456 -0
- package/dist/{chunk-QX7IFQSF.mjs → chunk-AHKHVBWR.mjs} +4 -4
- package/dist/chunk-AHSCWXYJ.mjs +113 -0
- package/dist/{chunk-7GWRPXHD.mjs → chunk-AL6GOL2Y.mjs} +1 -1
- package/dist/{chunk-OIKBW2QD.mjs → chunk-AUEUTZIC.mjs} +13 -13
- package/dist/{chunk-FYPSTTEJ.mjs → chunk-B7DD3ODQ.mjs} +1 -1
- package/dist/{chunk-TLAWKTSA.mjs → chunk-BD3DWDT4.mjs} +3 -3
- package/dist/{chunk-S2FKV4M5.mjs → chunk-BDESHD25.mjs} +4 -4
- package/dist/{chunk-OKTJFDPN.mjs → chunk-BFB3UH7V.mjs} +2 -2
- package/dist/{chunk-DGNHGNYH.mjs → chunk-C6SWS7OW.mjs} +1 -1
- package/dist/chunk-CDVG7SFT.mjs +271 -0
- package/dist/chunk-CUSHAIUL.mjs +109 -0
- package/dist/{chunk-QXKGOMUX.mjs → chunk-CW32WTZU.mjs} +4 -4
- package/dist/{chunk-SET2ANTY.mjs → chunk-D447W45Z.mjs} +3 -3
- package/dist/{chunk-RCAOCHWA.mjs → chunk-DFL5CV75.mjs} +18 -18
- package/dist/chunk-DYSVJ473.mjs +162 -0
- package/dist/chunk-E3PQDBYI.mjs +288 -0
- package/dist/chunk-EMYBNPIA.mjs +83 -0
- package/dist/chunk-EUYPMDQG.mjs +348 -0
- package/dist/{chunk-XYPW2XA5.mjs → chunk-EW72FINW.mjs} +11 -11
- package/dist/chunk-F24U4QQQ.mjs +234 -0
- package/dist/{chunk-VB5M6OZQ.mjs → chunk-F4O2YPXJ.mjs} +1 -1
- package/dist/chunk-FFXTQTB4.mjs +84 -0
- package/dist/{chunk-ZOWL2L5J.mjs → chunk-FYUSF5KO.mjs} +5 -1
- package/dist/{chunk-FTPBQVQ6.mjs → chunk-GNER6MCO.mjs} +1 -1
- package/dist/{chunk-2D3HQPFN.mjs → chunk-HF4FUBCY.mjs} +5 -5
- package/dist/{chunk-RSUIPKGX.mjs → chunk-HNDTLT5X.mjs} +1 -1
- package/dist/{chunk-N6Q5IPKT.mjs → chunk-HO6S3ECM.mjs} +46 -18
- package/dist/{chunk-L4NSRQ3T.mjs → chunk-HROG643K.mjs} +1 -1
- package/dist/chunk-I2EKKSEF.mjs +148 -0
- package/dist/{chunk-QTRSCVQ3.mjs → chunk-I3UDLWQ7.mjs} +1 -1
- package/dist/{chunk-AE7MASLF.mjs → chunk-IQGKOT7A.mjs} +9 -6
- package/dist/chunk-IXR4BQSQ.mjs +290 -0
- package/dist/{chunk-4MM7LHM5.mjs → chunk-J5NW5NCT.mjs} +1 -1
- package/dist/{chunk-OLKMCXAR.mjs → chunk-JTG5R5YV.mjs} +24 -24
- package/dist/chunk-JUBUN65Q.mjs +106 -0
- package/dist/chunk-K7TWMLLW.mjs +520 -0
- package/dist/{chunk-BOW7U26Y.mjs → chunk-K7WSRWOU.mjs} +4 -4
- package/dist/{chunk-NTYQWVLI.mjs → chunk-KAD26MCC.mjs} +1 -1
- package/dist/{chunk-KCWNDYPZ.mjs → chunk-KB7MZMED.mjs} +4 -4
- package/dist/chunk-KCKYGQVQ.mjs +61 -0
- package/dist/{chunk-VY5NEUP7.mjs → chunk-KLJLDNCA.mjs} +1 -1
- package/dist/chunk-LLAGF6BA.mjs +49 -0
- package/dist/{chunk-G27TSQLQ.mjs → chunk-M4LTX3MH.mjs} +1 -1
- package/dist/{chunk-YIZHS72Z.mjs → chunk-MHHA7QGO.mjs} +94 -54
- package/dist/{chunk-P2N2PEFY.mjs → chunk-NCUH54IZ.mjs} +4 -4
- package/dist/{chunk-PNRUH7JY.mjs → chunk-OECGKCVF.mjs} +5 -5
- package/dist/{chunk-YE67AALL.mjs → chunk-OL65UQHQ.mjs} +10 -10
- package/dist/{chunk-LQULK2E3.mjs → chunk-OYBIUEGE.mjs} +1 -1
- package/dist/{chunk-LR6LHDP3.mjs → chunk-PGR53HMH.mjs} +7 -7
- package/dist/chunk-PUJ42INK.mjs +141 -0
- package/dist/{chunk-M4VYX2PV.mjs → chunk-PV3Y7QGK.mjs} +2 -2
- package/dist/{chunk-UJZ4UHWI.mjs → chunk-PV7PNA6K.mjs} +4 -4
- package/dist/{chunk-6HIOM2HL.mjs → chunk-Q35PNFJ7.mjs} +1 -1
- package/dist/{chunk-JZY6TNIS.mjs → chunk-Q5SGEIJV.mjs} +27 -27
- package/dist/{chunk-ZFCDYW6N.mjs → chunk-QAX6HCUH.mjs} +1 -1
- package/dist/chunk-QHJDGB54.mjs +135 -0
- package/dist/chunk-QQSOZQOC.mjs +27 -0
- package/dist/chunk-RUX3OLVZ.mjs +59 -0
- package/dist/{chunk-QOJ2DQD6.mjs → chunk-S4CTM3UE.mjs} +5 -0
- package/dist/{chunk-ZEDMKQK2.mjs → chunk-TAX3KL66.mjs} +1 -1
- package/dist/chunk-TC43SMIN.mjs +133 -0
- package/dist/chunk-TGVXRD53.mjs +174 -0
- package/dist/{chunk-K5VHK7CM.mjs → chunk-TLYSVRSK.mjs} +12 -12
- package/dist/{chunk-YCWLFG27.mjs → chunk-TOIVHWNC.mjs} +1 -1
- package/dist/chunk-TXUBGKB7.mjs +160 -0
- package/dist/chunk-UEREFDAE.mjs +75 -0
- package/dist/chunk-UTCQN6XU.mjs +123 -0
- package/dist/{chunk-37AE3OM5.mjs → chunk-V4CUTCHS.mjs} +4 -4
- package/dist/{chunk-THVO2N47.mjs → chunk-VFH632TB.mjs} +9 -9
- package/dist/{chunk-3ERBUVHC.mjs → chunk-VJ3GC7W3.mjs} +95 -49
- package/dist/{chunk-V6XGXYCJ.mjs → chunk-VLELWBEW.mjs} +4 -4
- package/dist/{chunk-FEZKMUCF.mjs → chunk-WDTXHLYM.mjs} +1 -1
- package/dist/chunk-WUA546RX.mjs +129 -0
- package/dist/chunk-XHGISOX5.mjs +257 -0
- package/dist/chunk-XIY5DJXI.mjs +168 -0
- package/dist/{chunk-TOWTPLRC.mjs → chunk-XN37434W.mjs} +8 -8
- package/dist/{chunk-KLTACJ2G.mjs → chunk-XTWAJWCQ.mjs} +1 -1
- package/dist/chunk-Y24TXIFJ.mjs +518 -0
- package/dist/{chunk-DMXYRCHM.mjs → chunk-Y6UM3VTN.mjs} +4 -4
- package/dist/components/ui/about-you-form.js +1120 -0
- package/dist/components/ui/about-you-form.mjs +323 -0
- package/dist/components/ui/account-list-carousel.js +304 -0
- package/dist/components/ui/account-list-carousel.mjs +11 -0
- package/dist/components/ui/add-column-modal.js +1 -1
- package/dist/components/ui/add-column-modal.mjs +6 -6
- package/dist/components/ui/add-lead-modal.js +2 -2
- package/dist/components/ui/add-lead-modal.mjs +6 -6
- package/dist/components/ui/advisor-card.mjs +2 -2
- package/dist/components/ui/agent-evaluation-toast.js +299 -0
- package/dist/components/ui/agent-evaluation-toast.mjs +12 -0
- package/dist/components/ui/ai-assistant-drawer.mjs +5 -5
- package/dist/components/ui/ai-builder.js +3 -3
- package/dist/components/ui/ai-builder.mjs +5 -5
- package/dist/components/ui/ai-conversations.js +2 -2
- package/dist/components/ui/ai-conversations.mjs +11 -11
- package/dist/components/ui/alert-dialog.mjs +3 -3
- package/dist/components/ui/applicant-document-checklist.js +346 -0
- package/dist/components/ui/applicant-document-checklist.mjs +10 -0
- package/dist/components/ui/applicant-expenses-section.js +455 -0
- package/dist/components/ui/applicant-expenses-section.mjs +220 -0
- package/dist/components/ui/applicant-navigation-bar.js +309 -0
- package/dist/components/ui/applicant-navigation-bar.mjs +87 -0
- package/dist/components/ui/applicant-switcher.js +268 -0
- package/dist/components/ui/applicant-switcher.mjs +46 -0
- package/dist/components/ui/application-mobile-layout.js +88 -0
- package/dist/components/ui/application-mobile-layout.mjs +8 -0
- package/dist/components/ui/appointment-action-dialogs.js +1 -1
- package/dist/components/ui/appointment-action-dialogs.mjs +10 -10
- package/dist/components/ui/appointment-availability-settings.js +78 -31
- package/dist/components/ui/appointment-availability-settings.mjs +12 -10
- package/dist/components/ui/appointment-book-dialog.js +137 -58
- package/dist/components/ui/appointment-book-dialog.mjs +14 -14
- package/dist/components/ui/appointment-calendar-view.js +1 -1
- package/dist/components/ui/appointment-calendar-view.mjs +4 -4
- package/dist/components/ui/appointment-detail-sheet.js +38 -11
- package/dist/components/ui/appointment-detail-sheet.mjs +13 -13
- package/dist/components/ui/appointment-gmail-connect.mjs +2 -2
- package/dist/components/ui/appointment-time-slot-picker.mjs +2 -2
- package/dist/components/ui/appointment-upcoming-card.js +1 -1
- package/dist/components/ui/appointment-upcoming-card.mjs +10 -10
- package/dist/components/ui/asset-accordion.js +506 -0
- package/dist/components/ui/asset-accordion.mjs +202 -0
- package/dist/components/ui/assets-liabilities-side-card.js +328 -0
- package/dist/components/ui/assets-liabilities-side-card.mjs +127 -0
- package/dist/components/ui/auth-page-layout.js +3 -3
- package/dist/components/ui/auth-page-layout.mjs +1 -1
- package/dist/components/ui/backoffice-alert-history-chart.mjs +4 -4
- package/dist/components/ui/backoffice-alert-matching-chart.js +786 -0
- package/dist/components/ui/backoffice-alert-matching-chart.mjs +19 -0
- package/dist/components/ui/backoffice-alerts-chart.mjs +4 -4
- package/dist/components/ui/backoffice-connections-chart.mjs +4 -4
- package/dist/components/ui/backoffice-contact-history-chart.mjs +4 -4
- package/dist/components/ui/backoffice-contact-matching-chart.js +803 -0
- package/dist/components/ui/backoffice-contact-matching-chart.mjs +19 -0
- package/dist/components/ui/backoffice-signup-steps.js +1673 -0
- package/dist/components/ui/backoffice-signup-steps.mjs +36 -0
- package/dist/components/ui/bank-statement-document-table.js +467 -0
- package/dist/components/ui/bank-statement-document-table.mjs +12 -0
- package/dist/components/ui/bank-statement-generate-dialog.js +1517 -0
- package/dist/components/ui/bank-statement-generate-dialog.mjs +27 -0
- package/dist/components/ui/bank-statement-pdf-viewer.js +525 -0
- package/dist/components/ui/bank-statement-pdf-viewer.mjs +14 -0
- package/dist/components/ui/banking-accounts-connect.js +336 -0
- package/dist/components/ui/banking-accounts-connect.mjs +114 -0
- package/dist/components/ui/borrowing-capacity-atoms.js +382 -0
- package/dist/components/ui/borrowing-capacity-atoms.mjs +17 -0
- package/dist/components/ui/borrowing-capacity-card.js +835 -0
- package/dist/components/ui/borrowing-capacity-card.mjs +89 -0
- package/dist/components/ui/borrowing-capacity-line-chart.mjs +4 -4
- package/dist/components/ui/broker-info-panel.js +281 -0
- package/dist/components/ui/broker-info-panel.mjs +59 -0
- package/dist/components/ui/calculator-input-item.js +101 -0
- package/dist/components/ui/calculator-input-item.mjs +8 -0
- package/dist/components/ui/calculator-section.js +743 -0
- package/dist/components/ui/calculator-section.mjs +220 -0
- package/dist/components/ui/calendar.mjs +2 -2
- package/dist/components/ui/cash-balance-line-chart.mjs +5 -5
- package/dist/components/ui/cashflow-bar-chart.mjs +4 -4
- package/dist/components/ui/category-edit-dialog.js +737 -0
- package/dist/components/ui/category-edit-dialog.mjs +16 -0
- package/dist/components/ui/chat-widget.mjs +3 -3
- package/dist/components/ui/color-picker.mjs +4 -4
- package/dist/components/ui/connect-bank-step.js +511 -0
- package/dist/components/ui/connect-bank-step.mjs +287 -0
- package/dist/components/ui/contact-alert-dialog.js +1405 -0
- package/dist/components/ui/contact-alert-dialog.mjs +27 -0
- package/dist/components/ui/create-contact-modal.js +1028 -0
- package/dist/components/ui/create-contact-modal.mjs +21 -0
- package/dist/components/ui/csv-import-modal.js +583 -0
- package/dist/components/ui/csv-import-modal.mjs +14 -0
- package/dist/components/ui/currency-input.js +439 -0
- package/dist/components/ui/currency-input.mjs +13 -0
- package/dist/components/ui/dashboard-expense-categories.js +355 -0
- package/dist/components/ui/dashboard-expense-categories.mjs +186 -0
- package/dist/components/ui/dashboard-transactions-table.js +1083 -0
- package/dist/components/ui/dashboard-transactions-table.mjs +177 -0
- package/dist/components/ui/data-table.mjs +6 -6
- package/dist/components/ui/date-picker.mjs +6 -6
- package/dist/components/ui/debt-accordion.js +523 -0
- package/dist/components/ui/debt-accordion.mjs +219 -0
- package/dist/components/ui/delete-contact-component.js +479 -0
- package/dist/components/ui/delete-contact-component.mjs +14 -0
- package/dist/components/ui/dialog.js +1 -1
- package/dist/components/ui/dialog.mjs +3 -3
- package/dist/components/ui/document-checklist-template.mjs +4 -4
- package/dist/components/ui/drawer.mjs +3 -3
- package/dist/components/ui/dropdown-menu.mjs +3 -3
- package/dist/components/ui/dynamic-tabs.js +274 -0
- package/dist/components/ui/dynamic-tabs.mjs +116 -0
- package/dist/components/ui/editable-money-item.js +306 -0
- package/dist/components/ui/editable-money-item.mjs +12 -0
- package/dist/components/ui/expense-bar-chart.mjs +4 -4
- package/dist/components/ui/expense-detail-item.js +506 -0
- package/dist/components/ui/expense-detail-item.mjs +15 -0
- package/dist/components/ui/expense-work-details.js +1259 -0
- package/dist/components/ui/expense-work-details.mjs +175 -0
- package/dist/components/ui/field.mjs +2 -2
- package/dist/components/ui/file-preview-dialog.js +704 -0
- package/dist/components/ui/file-preview-dialog.mjs +17 -0
- package/dist/components/ui/financial-cards.mjs +2 -2
- package/dist/components/ui/financial-drawers.js +1 -1
- package/dist/components/ui/financial-drawers.mjs +5 -5
- package/dist/components/ui/financial-sections.mjs +4 -4
- package/dist/components/ui/form-primitives.mjs +2 -2
- package/dist/components/ui/frontend-signup-steps.js +1239 -0
- package/dist/components/ui/frontend-signup-steps.mjs +38 -0
- package/dist/components/ui/income-bar-chart.mjs +4 -4
- package/dist/components/ui/income-sources-card.js +269 -0
- package/dist/components/ui/income-sources-card.mjs +100 -0
- package/dist/components/ui/income-summary-component.js +361 -0
- package/dist/components/ui/income-summary-component.mjs +84 -0
- package/dist/components/ui/income-work-details.js +1663 -0
- package/dist/components/ui/income-work-details.mjs +28 -0
- package/dist/components/ui/incoming-outgoings-card.js +218 -0
- package/dist/components/ui/incoming-outgoings-card.mjs +82 -0
- package/dist/components/ui/interest-rate-input.js +442 -0
- package/dist/components/ui/interest-rate-input.mjs +90 -0
- package/dist/components/ui/interest-rate-section.js +337 -0
- package/dist/components/ui/interest-rate-section.mjs +84 -0
- package/dist/components/ui/interest-rate-used.js +202 -0
- package/dist/components/ui/interest-rate-used.mjs +62 -0
- package/dist/components/ui/kanban-column.js +338 -160
- package/dist/components/ui/kanban-column.mjs +13 -11
- package/dist/components/ui/loan-applicant-information.js +336 -0
- package/dist/components/ui/loan-applicant-information.mjs +59 -0
- package/dist/components/ui/loan-applicant-invite.js +319 -0
- package/dist/components/ui/loan-applicant-invite.mjs +68 -0
- package/dist/components/ui/loan-application-badge.js +236 -0
- package/dist/components/ui/loan-application-badge.mjs +10 -0
- package/dist/components/ui/loan-application-cards.js +356 -0
- package/dist/components/ui/loan-application-cards.mjs +110 -0
- package/dist/components/ui/loan-entry-shell.js +104 -0
- package/dist/components/ui/loan-entry-shell.mjs +8 -0
- package/dist/components/ui/loan-financials.js +410 -0
- package/dist/components/ui/loan-financials.mjs +76 -0
- package/dist/components/ui/loan-option-card.js +102 -0
- package/dist/components/ui/loan-option-card.mjs +41 -0
- package/dist/components/ui/loan-option-group.js +288 -0
- package/dist/components/ui/loan-option-group.mjs +10 -0
- package/dist/components/ui/loan-steps.js +1121 -0
- package/dist/components/ui/loan-steps.mjs +509 -0
- package/dist/components/ui/loan-wizard-shell.js +452 -0
- package/dist/components/ui/loan-wizard-shell.mjs +11 -0
- package/dist/components/ui/money-input-with-slider.js +210 -0
- package/dist/components/ui/money-input-with-slider.mjs +10 -0
- package/dist/components/ui/money-item-with-color-indicator.js +314 -0
- package/dist/components/ui/money-item-with-color-indicator.mjs +20 -0
- package/dist/components/ui/opportunity-card.js +235 -97
- package/dist/components/ui/opportunity-card.mjs +11 -9
- package/dist/components/ui/opportunity-edit-modals.js +1 -1
- package/dist/components/ui/opportunity-edit-modals.mjs +15 -15
- package/dist/components/ui/opportunity-summary-tab.js +1 -1
- package/dist/components/ui/opportunity-summary-tab.mjs +19 -19
- package/dist/components/ui/pagination.mjs +4 -4
- package/dist/components/ui/password-strength-tooltip.mjs +4 -4
- package/dist/components/ui/pipeline-board.js +358 -176
- package/dist/components/ui/pipeline-board.mjs +16 -14
- package/dist/components/ui/pipeline-chart.mjs +3 -3
- package/dist/components/ui/pipeline-dialogs.js +1 -1
- package/dist/components/ui/pipeline-dialogs.mjs +9 -9
- package/dist/components/ui/pipeline-primitives.js +75 -8
- package/dist/components/ui/pipeline-primitives.mjs +3 -2
- package/dist/components/ui/popover.mjs +3 -3
- package/dist/components/ui/property-asset-card.js +428 -0
- package/dist/components/ui/property-asset-card.mjs +156 -0
- package/dist/components/ui/property-cashflow-doughnut-chart.mjs +4 -4
- package/dist/components/ui/property-debt-equity-doughnut-chart.mjs +4 -4
- package/dist/components/ui/property-list-carousel.js +295 -0
- package/dist/components/ui/property-list-carousel.mjs +11 -0
- package/dist/components/ui/property-mobile-estimate-line-chart.mjs +4 -4
- package/dist/components/ui/property-report-dialog.js +1148 -0
- package/dist/components/ui/property-report-dialog.mjs +25 -0
- package/dist/components/ui/resource-center.js +748 -0
- package/dist/components/ui/resource-center.mjs +24 -0
- package/dist/components/ui/review-alerts-dialog.js +569 -0
- package/dist/components/ui/review-alerts-dialog.mjs +15 -0
- package/dist/components/ui/savings-goal-modal.js +1148 -0
- package/dist/components/ui/savings-goal-modal.mjs +160 -0
- package/dist/components/ui/scenario-drawer.js +791 -0
- package/dist/components/ui/scenario-drawer.mjs +294 -0
- package/dist/components/ui/scenario-item.js +256 -0
- package/dist/components/ui/scenario-item.mjs +11 -0
- package/dist/components/ui/scenario-list.js +507 -0
- package/dist/components/ui/scenario-list.mjs +100 -0
- package/dist/components/ui/select.mjs +3 -3
- package/dist/components/ui/share-details-dialog.js +636 -0
- package/dist/components/ui/share-details-dialog.mjs +19 -0
- package/dist/components/ui/sheet.mjs +3 -3
- package/dist/components/ui/sidebar-nav.mjs +5 -5
- package/dist/components/ui/signup-form-primitives.js +770 -0
- package/dist/components/ui/signup-form-primitives.mjs +25 -0
- package/dist/components/ui/signup-shell.js +338 -0
- package/dist/components/ui/signup-shell.mjs +13 -0
- package/dist/components/ui/stage-timeline.js +103 -33
- package/dist/components/ui/stage-timeline.mjs +5 -4
- package/dist/components/ui/submission-confirmation-card.js +284 -0
- package/dist/components/ui/submission-confirmation-card.mjs +62 -0
- package/dist/components/ui/tooltip.mjs +3 -3
- package/dist/components/ui/top-three-product.js +374 -0
- package/dist/components/ui/top-three-product.mjs +129 -0
- package/dist/components/ui/transactions-expense-categories-doughnut-chart.mjs +4 -4
- package/dist/components/ui/transactions-income-expense-bar-chart.mjs +5 -5
- package/dist/components/ui/transactions-liabilities-breakdown-doughnut-chart.mjs +4 -4
- package/dist/components/ui/transactions-summary-block.js +95 -0
- package/dist/components/ui/transactions-summary-block.mjs +34 -0
- package/dist/components/ui/two-fa-setup-form.mjs +3 -3
- package/dist/index.js +9430 -4573
- package/dist/index.mjs +404 -251
- package/dist/lib/colors.js +6 -0
- package/dist/lib/colors.mjs +3 -1
- package/dist/lib/theme-provider.mjs +2 -2
- package/dist/styles.css +1 -1
- package/package.json +366 -2
- package/src/components/index.tsx +223 -0
- package/src/components/ui/about-you-form.tsx +397 -0
- package/src/components/ui/account-list-carousel.tsx +87 -0
- package/src/components/ui/add-lead-modal.tsx +1 -1
- package/src/components/ui/agent-evaluation-toast.tsx +191 -0
- package/src/components/ui/ai-builder.tsx +3 -5
- package/src/components/ui/ai-conversations.tsx +1 -1
- package/src/components/ui/applicant-document-checklist.tsx +175 -0
- package/src/components/ui/applicant-expenses-section.tsx +260 -0
- package/src/components/ui/applicant-navigation-bar.tsx +104 -0
- package/src/components/ui/applicant-switcher.tsx +54 -0
- package/src/components/ui/application-mobile-layout.tsx +34 -0
- package/src/components/ui/appointment-availability-settings.tsx +115 -23
- package/src/components/ui/appointment-book-dialog.tsx +406 -259
- package/src/components/ui/appointment-calendar-view.tsx +4 -1
- package/src/components/ui/appointment-detail-sheet.tsx +59 -24
- package/src/components/ui/appointment-time-slot-picker.tsx +5 -1
- package/src/components/ui/asset-accordion.tsx +241 -0
- package/src/components/ui/assets-liabilities-side-card.tsx +157 -0
- package/src/components/ui/auth-page-layout.tsx +3 -3
- package/src/components/ui/backoffice-alert-matching-chart.tsx +320 -0
- package/src/components/ui/backoffice-contact-matching-chart.tsx +341 -0
- package/src/components/ui/backoffice-signup-steps.tsx +615 -0
- package/src/components/ui/bank-statement-document-table.tsx +222 -0
- package/src/components/ui/bank-statement-generate-dialog.tsx +435 -0
- package/src/components/ui/bank-statement-pdf-viewer.tsx +241 -0
- package/src/components/ui/banking-accounts-connect.tsx +187 -0
- package/src/components/ui/borrowing-capacity-atoms.tsx +228 -0
- package/src/components/ui/borrowing-capacity-card.tsx +155 -0
- package/src/components/ui/broker-info-panel.tsx +94 -0
- package/src/components/ui/calculator-input-item.tsx +49 -0
- package/src/components/ui/calculator-section.tsx +275 -0
- package/src/components/ui/category-edit-dialog.tsx +300 -0
- package/src/components/ui/connect-bank-step.tsx +379 -0
- package/src/components/ui/contact-alert-dialog.tsx +710 -0
- package/src/components/ui/create-contact-modal.tsx +237 -0
- package/src/components/ui/csv-import-modal.tsx +153 -0
- package/src/components/ui/currency-input.tsx +104 -0
- package/src/components/ui/dashboard-expense-categories.tsx +262 -0
- package/src/components/ui/dashboard-transactions-table.tsx +241 -0
- package/src/components/ui/debt-accordion.tsx +254 -0
- package/src/components/ui/delete-contact-component.tsx +87 -0
- package/src/components/ui/dialog.tsx +2 -2
- package/src/components/ui/dynamic-tabs.tsx +149 -0
- package/src/components/ui/editable-money-item.tsx +176 -0
- package/src/components/ui/expense-detail-item.tsx +216 -0
- package/src/components/ui/expense-work-details.tsx +229 -0
- package/src/components/ui/file-preview-dialog.tsx +292 -0
- package/src/components/ui/financial-drawers.tsx +1 -1
- package/src/components/ui/frontend-signup-steps.tsx +548 -0
- package/src/components/ui/income-sources-card.tsx +143 -0
- package/src/components/ui/income-summary-component.tsx +120 -0
- package/src/components/ui/income-work-details.tsx +429 -0
- package/src/components/ui/incoming-outgoings-card.tsx +111 -0
- package/src/components/ui/interest-rate-input.tsx +111 -0
- package/src/components/ui/interest-rate-section.tsx +158 -0
- package/src/components/ui/interest-rate-used.tsx +82 -0
- package/src/components/ui/kanban-column.tsx +53 -2
- package/src/components/ui/loan-applicant-information.tsx +64 -0
- package/src/components/ui/loan-applicant-invite.tsx +67 -0
- package/src/components/ui/loan-application-badge.tsx +70 -0
- package/src/components/ui/loan-application-cards.tsx +152 -0
- package/src/components/ui/loan-entry-shell.tsx +86 -0
- package/src/components/ui/loan-financials.tsx +77 -0
- package/src/components/ui/loan-option-card.tsx +62 -0
- package/src/components/ui/loan-option-group.tsx +106 -0
- package/src/components/ui/loan-steps.tsx +630 -0
- package/src/components/ui/loan-wizard-shell.tsx +235 -0
- package/src/components/ui/money-input-with-slider.tsx +77 -0
- package/src/components/ui/money-item-with-color-indicator.tsx +30 -0
- package/src/components/ui/opportunity-card.tsx +46 -18
- package/src/components/ui/pipeline-board.tsx +13 -0
- package/src/components/ui/pipeline-primitives.tsx +28 -0
- package/src/components/ui/property-asset-card.tsx +221 -0
- package/src/components/ui/property-list-carousel.tsx +73 -0
- package/src/components/ui/property-report-dialog.tsx +355 -0
- package/src/components/ui/resource-center.tsx +539 -0
- package/src/components/ui/review-alerts-dialog.tsx +163 -0
- package/src/components/ui/savings-goal-modal.tsx +169 -0
- package/src/components/ui/scenario-drawer.tsx +358 -0
- package/src/components/ui/scenario-item.tsx +141 -0
- package/src/components/ui/scenario-list.tsx +150 -0
- package/src/components/ui/share-details-dialog.tsx +238 -0
- package/src/components/ui/signup-form-primitives.tsx +212 -0
- package/src/components/ui/signup-shell.tsx +180 -0
- package/src/components/ui/stage-timeline.tsx +11 -0
- package/src/components/ui/submission-confirmation-card.tsx +68 -0
- package/src/components/ui/top-three-product.tsx +207 -0
- package/src/components/ui/transactions-summary-block.tsx +59 -0
- package/src/lib/colors.ts +12 -0
- package/src/lib/format-date.ts +2 -2
- package/src/styles/styles-css.ts +1 -1
- package/tsup.config.ts +77 -1
- package/dist/{chunk-5VOTTIXF.mjs → chunk-FRT3S72S.mjs} +3 -3
- package/dist/{chunk-7BTFGCFC.mjs → chunk-MUV4EGDW.mjs} +3 -3
- package/dist/{chunk-57ZXILTS.mjs → chunk-MXP2RX2V.mjs} +3 -3
- package/dist/{chunk-ZKWXDQDG.mjs → chunk-VCDGLN25.mjs} +3 -3
- 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
|
-
{
|
|
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"
|
|
461
|
-
|
|
462
|
-
<
|
|
463
|
-
{
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
<
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
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
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
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
|
-
|
|
524
|
-
|
|
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
|
|
528
|
-
<
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
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
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
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="
|
|
549
|
-
|
|
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
|
-
<
|
|
555
|
-
id="
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
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
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
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
|
);
|