@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
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { cn } from "@/lib/utils";
|
|
3
|
+
import { Button } from "@/components/ui/button";
|
|
4
|
+
import { formatCurrency } from "@/lib/format-currency";
|
|
5
|
+
|
|
6
|
+
export type ExpenseCategoryData = {
|
|
7
|
+
label: string;
|
|
8
|
+
color: string;
|
|
9
|
+
monthlyAmounts: number[];
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export type ApplicantExpensesSectionProps = {
|
|
13
|
+
applicantName: string;
|
|
14
|
+
/** Three states: loading, access granted, access not granted. */
|
|
15
|
+
state: "loading" | "connected" | "pending-access";
|
|
16
|
+
/** Last 12 month labels (e.g. "Jan", "Feb" …). Required when state = "connected". */
|
|
17
|
+
monthLabels?: string[];
|
|
18
|
+
/** Per-category breakdown. Required when state = "connected". */
|
|
19
|
+
categories?: ExpenseCategoryData[];
|
|
20
|
+
/** Total spend over the loaded period. */
|
|
21
|
+
totalAmount?: number;
|
|
22
|
+
onConnectMore?: () => void;
|
|
23
|
+
onAddManually?: () => void;
|
|
24
|
+
onSendRequest?: () => void;
|
|
25
|
+
className?: string;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export function ApplicantExpensesSection({
|
|
29
|
+
applicantName,
|
|
30
|
+
state,
|
|
31
|
+
monthLabels = [],
|
|
32
|
+
categories = [],
|
|
33
|
+
totalAmount = 0,
|
|
34
|
+
onConnectMore,
|
|
35
|
+
onAddManually,
|
|
36
|
+
onSendRequest,
|
|
37
|
+
className,
|
|
38
|
+
}: ApplicantExpensesSectionProps) {
|
|
39
|
+
return (
|
|
40
|
+
<div className={cn("flex flex-col gap-4 font-sans", className)}>
|
|
41
|
+
<h3 className="text-sm font-semibold text-foreground">
|
|
42
|
+
{applicantName}'s Expenses
|
|
43
|
+
</h3>
|
|
44
|
+
|
|
45
|
+
{state === "loading" && <LoadingState />}
|
|
46
|
+
|
|
47
|
+
{state === "connected" && (
|
|
48
|
+
<ConnectedState
|
|
49
|
+
monthLabels={monthLabels}
|
|
50
|
+
categories={categories}
|
|
51
|
+
totalAmount={totalAmount}
|
|
52
|
+
onConnectMore={onConnectMore}
|
|
53
|
+
onAddManually={onAddManually}
|
|
54
|
+
/>
|
|
55
|
+
)}
|
|
56
|
+
|
|
57
|
+
{state === "pending-access" && (
|
|
58
|
+
<PendingAccessState
|
|
59
|
+
applicantName={applicantName}
|
|
60
|
+
onSendRequest={onSendRequest}
|
|
61
|
+
/>
|
|
62
|
+
)}
|
|
63
|
+
</div>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// ─── Sub-states ───────────────────────────────────────────────────────────────
|
|
68
|
+
|
|
69
|
+
function LoadingState() {
|
|
70
|
+
return (
|
|
71
|
+
<div className="flex h-48 items-center justify-center border border-border bg-muted/30">
|
|
72
|
+
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
|
73
|
+
<SpinnerIcon className="size-4 animate-spin" />
|
|
74
|
+
Loading banking data…
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function ConnectedState({
|
|
81
|
+
monthLabels,
|
|
82
|
+
categories,
|
|
83
|
+
totalAmount,
|
|
84
|
+
onConnectMore,
|
|
85
|
+
onAddManually,
|
|
86
|
+
}: {
|
|
87
|
+
monthLabels: string[];
|
|
88
|
+
categories: ExpenseCategoryData[];
|
|
89
|
+
totalAmount: number;
|
|
90
|
+
onConnectMore?: () => void;
|
|
91
|
+
onAddManually?: () => void;
|
|
92
|
+
}) {
|
|
93
|
+
const maxValue = Math.max(
|
|
94
|
+
...monthLabels.map((_, mi) =>
|
|
95
|
+
categories.reduce((sum, cat) => sum + (cat.monthlyAmounts[mi] ?? 0), 0),
|
|
96
|
+
),
|
|
97
|
+
1,
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
return (
|
|
101
|
+
<div className="flex flex-col gap-4">
|
|
102
|
+
<div className="flex flex-wrap items-start justify-between gap-4">
|
|
103
|
+
<div className="flex flex-col gap-0.5">
|
|
104
|
+
<span className="text-title-medium font-semibold text-foreground">
|
|
105
|
+
{formatCurrency(totalAmount)}
|
|
106
|
+
</span>
|
|
107
|
+
<span className="text-xs text-muted-foreground">
|
|
108
|
+
Total latest 12 months
|
|
109
|
+
</span>
|
|
110
|
+
</div>
|
|
111
|
+
<div className="flex flex-col gap-2">
|
|
112
|
+
<Button size="sm" onClick={onConnectMore}>
|
|
113
|
+
Connect More Accounts
|
|
114
|
+
</Button>
|
|
115
|
+
{onAddManually && (
|
|
116
|
+
<Button size="sm" variant="outline" onClick={onAddManually}>
|
|
117
|
+
Add Manually
|
|
118
|
+
</Button>
|
|
119
|
+
)}
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
|
|
123
|
+
{/* Mini stacked bar chart */}
|
|
124
|
+
{monthLabels.length > 0 && categories.length > 0 && (
|
|
125
|
+
<div className="overflow-x-auto">
|
|
126
|
+
<div className="flex min-w-0 items-end gap-1">
|
|
127
|
+
{monthLabels.map((month, mi) => {
|
|
128
|
+
const colTotal = categories.reduce(
|
|
129
|
+
(sum, cat) => sum + (cat.monthlyAmounts[mi] ?? 0),
|
|
130
|
+
0,
|
|
131
|
+
);
|
|
132
|
+
const heightPct = (colTotal / maxValue) * 100;
|
|
133
|
+
return (
|
|
134
|
+
<div
|
|
135
|
+
key={month}
|
|
136
|
+
className="flex flex-1 flex-col items-center gap-1"
|
|
137
|
+
>
|
|
138
|
+
<div
|
|
139
|
+
className="flex w-full flex-col-reverse overflow-hidden"
|
|
140
|
+
style={{ height: 80 }}
|
|
141
|
+
title={`${month}: ${formatCurrency(colTotal)}`}
|
|
142
|
+
>
|
|
143
|
+
<div
|
|
144
|
+
className="flex w-full flex-col-reverse"
|
|
145
|
+
style={{ height: `${heightPct}%` }}
|
|
146
|
+
>
|
|
147
|
+
{categories.map((cat) => {
|
|
148
|
+
const segPct =
|
|
149
|
+
colTotal > 0
|
|
150
|
+
? ((cat.monthlyAmounts[mi] ?? 0) / colTotal) * 100
|
|
151
|
+
: 0;
|
|
152
|
+
return (
|
|
153
|
+
<div
|
|
154
|
+
key={cat.label}
|
|
155
|
+
style={{
|
|
156
|
+
height: `${segPct}%`,
|
|
157
|
+
backgroundColor: cat.color,
|
|
158
|
+
}}
|
|
159
|
+
/>
|
|
160
|
+
);
|
|
161
|
+
})}
|
|
162
|
+
</div>
|
|
163
|
+
</div>
|
|
164
|
+
<span className="text-[10px] text-muted-foreground">
|
|
165
|
+
{month}
|
|
166
|
+
</span>
|
|
167
|
+
</div>
|
|
168
|
+
);
|
|
169
|
+
})}
|
|
170
|
+
</div>
|
|
171
|
+
</div>
|
|
172
|
+
)}
|
|
173
|
+
|
|
174
|
+
{/* Legend */}
|
|
175
|
+
{categories.length > 0 && (
|
|
176
|
+
<div className="flex flex-wrap gap-3">
|
|
177
|
+
{categories.map((cat) => (
|
|
178
|
+
<div key={cat.label} className="flex items-center gap-1.5">
|
|
179
|
+
<div
|
|
180
|
+
className="size-2.5 shrink-0"
|
|
181
|
+
style={{ backgroundColor: cat.color }}
|
|
182
|
+
/>
|
|
183
|
+
<span className="text-xs text-muted-foreground">{cat.label}</span>
|
|
184
|
+
</div>
|
|
185
|
+
))}
|
|
186
|
+
</div>
|
|
187
|
+
)}
|
|
188
|
+
</div>
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function PendingAccessState({
|
|
193
|
+
applicantName,
|
|
194
|
+
onSendRequest,
|
|
195
|
+
}: {
|
|
196
|
+
applicantName: string;
|
|
197
|
+
onSendRequest?: () => void;
|
|
198
|
+
}) {
|
|
199
|
+
return (
|
|
200
|
+
<div className="flex flex-col items-center gap-4 border border-border py-10 text-center">
|
|
201
|
+
<LockIcon className="size-8 text-muted-foreground" />
|
|
202
|
+
<div className="flex flex-col gap-1">
|
|
203
|
+
<p className="text-sm font-medium text-foreground">
|
|
204
|
+
Requires access to banking data
|
|
205
|
+
</p>
|
|
206
|
+
<p className="text-xs text-muted-foreground">
|
|
207
|
+
Send {applicantName} an invitation to connect their bank accounts.
|
|
208
|
+
</p>
|
|
209
|
+
</div>
|
|
210
|
+
<Button onClick={onSendRequest}>Send request to {applicantName}</Button>
|
|
211
|
+
</div>
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// ─── Icons ────────────────────────────────────────────────────────────────────
|
|
216
|
+
|
|
217
|
+
function SpinnerIcon({ className }: { className?: string }) {
|
|
218
|
+
return (
|
|
219
|
+
<svg
|
|
220
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
221
|
+
fill="none"
|
|
222
|
+
viewBox="0 0 24 24"
|
|
223
|
+
className={className}
|
|
224
|
+
aria-hidden="true"
|
|
225
|
+
>
|
|
226
|
+
<circle
|
|
227
|
+
className="opacity-25"
|
|
228
|
+
cx="12"
|
|
229
|
+
cy="12"
|
|
230
|
+
r="10"
|
|
231
|
+
stroke="currentColor"
|
|
232
|
+
strokeWidth="4"
|
|
233
|
+
/>
|
|
234
|
+
<path
|
|
235
|
+
className="opacity-75"
|
|
236
|
+
fill="currentColor"
|
|
237
|
+
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"
|
|
238
|
+
/>
|
|
239
|
+
</svg>
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function LockIcon({ className }: { className?: string }) {
|
|
244
|
+
return (
|
|
245
|
+
<svg
|
|
246
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
247
|
+
viewBox="0 0 24 24"
|
|
248
|
+
fill="none"
|
|
249
|
+
stroke="currentColor"
|
|
250
|
+
strokeWidth={2}
|
|
251
|
+
strokeLinecap="round"
|
|
252
|
+
strokeLinejoin="round"
|
|
253
|
+
className={className}
|
|
254
|
+
aria-hidden="true"
|
|
255
|
+
>
|
|
256
|
+
<rect x="3" y="11" width="18" height="11" rx="0" />
|
|
257
|
+
<path d="M7 11V7a5 5 0 0 1 10 0v4" />
|
|
258
|
+
</svg>
|
|
259
|
+
);
|
|
260
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { cn } from "@/lib/utils";
|
|
3
|
+
import { Button } from "@/components/ui/button";
|
|
4
|
+
|
|
5
|
+
export type ApplicantNavigationBarApplicant = {
|
|
6
|
+
name: string;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export type ApplicantNavigationBarProps = {
|
|
10
|
+
applicants: ApplicantNavigationBarApplicant[];
|
|
11
|
+
currentIndex: number;
|
|
12
|
+
/** Ordered list of applicant indices to navigate between. */
|
|
13
|
+
displayOrder?: number[];
|
|
14
|
+
onPrev?: () => void;
|
|
15
|
+
onNext?: () => void;
|
|
16
|
+
/** Called when there is no next applicant (last in order). */
|
|
17
|
+
onSaveAndNext?: () => void;
|
|
18
|
+
saveLabel?: string;
|
|
19
|
+
className?: string;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export function ApplicantNavigationBar({
|
|
23
|
+
applicants,
|
|
24
|
+
currentIndex,
|
|
25
|
+
displayOrder,
|
|
26
|
+
onPrev,
|
|
27
|
+
onNext,
|
|
28
|
+
onSaveAndNext,
|
|
29
|
+
saveLabel = "Save & Next",
|
|
30
|
+
className,
|
|
31
|
+
}: ApplicantNavigationBarProps) {
|
|
32
|
+
const order = displayOrder ?? applicants.map((_, i) => i);
|
|
33
|
+
const position = order.indexOf(currentIndex);
|
|
34
|
+
const pos = position >= 0 ? position : 0;
|
|
35
|
+
const isFirst = pos === 0;
|
|
36
|
+
const isLast = pos === order.length - 1;
|
|
37
|
+
const hasMultiple = applicants.length > 1;
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<div
|
|
41
|
+
className={cn(
|
|
42
|
+
"flex items-center justify-between pt-6 font-sans",
|
|
43
|
+
className,
|
|
44
|
+
)}
|
|
45
|
+
>
|
|
46
|
+
{hasMultiple && !isFirst ? (
|
|
47
|
+
<Button variant="outline" onClick={onPrev}>
|
|
48
|
+
<ChevronLeftIcon className="mr-1 size-4" />
|
|
49
|
+
Previous
|
|
50
|
+
</Button>
|
|
51
|
+
) : (
|
|
52
|
+
<span />
|
|
53
|
+
)}
|
|
54
|
+
|
|
55
|
+
{hasMultiple && !isLast ? (
|
|
56
|
+
<Button variant="outline" onClick={onNext}>
|
|
57
|
+
Next
|
|
58
|
+
<ChevronRightIcon className="ml-1 size-4" />
|
|
59
|
+
</Button>
|
|
60
|
+
) : (
|
|
61
|
+
<Button onClick={onSaveAndNext}>
|
|
62
|
+
{saveLabel}
|
|
63
|
+
<ChevronRightIcon className="ml-1 size-4" />
|
|
64
|
+
</Button>
|
|
65
|
+
)}
|
|
66
|
+
</div>
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function ChevronLeftIcon({ className }: { className?: string }) {
|
|
71
|
+
return (
|
|
72
|
+
<svg
|
|
73
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
74
|
+
viewBox="0 0 24 24"
|
|
75
|
+
fill="none"
|
|
76
|
+
stroke="currentColor"
|
|
77
|
+
strokeWidth={2}
|
|
78
|
+
strokeLinecap="round"
|
|
79
|
+
strokeLinejoin="round"
|
|
80
|
+
className={className}
|
|
81
|
+
aria-hidden="true"
|
|
82
|
+
>
|
|
83
|
+
<path d="m15 18-6-6 6-6" />
|
|
84
|
+
</svg>
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function ChevronRightIcon({ className }: { className?: string }) {
|
|
89
|
+
return (
|
|
90
|
+
<svg
|
|
91
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
92
|
+
viewBox="0 0 24 24"
|
|
93
|
+
fill="none"
|
|
94
|
+
stroke="currentColor"
|
|
95
|
+
strokeWidth={2}
|
|
96
|
+
strokeLinecap="round"
|
|
97
|
+
strokeLinejoin="round"
|
|
98
|
+
className={className}
|
|
99
|
+
aria-hidden="true"
|
|
100
|
+
>
|
|
101
|
+
<path d="m9 18 6-6-6-6" />
|
|
102
|
+
</svg>
|
|
103
|
+
);
|
|
104
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { cn } from "@/lib/utils";
|
|
3
|
+
import { Button } from "@/components/ui/button";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Segmented toggle bar for switching between the main applicant and
|
|
7
|
+
* co-applicant(s) in the loan wizard. Returns null when fewer than 2
|
|
8
|
+
* applicants are present.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export type ApplicantSwitcherApplicant = {
|
|
12
|
+
name: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export type ApplicantSwitcherProps = {
|
|
16
|
+
applicants: ApplicantSwitcherApplicant[];
|
|
17
|
+
selectedIndex: number;
|
|
18
|
+
onSelect: (index: number) => void;
|
|
19
|
+
className?: string;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export function ApplicantSwitcher({
|
|
23
|
+
applicants,
|
|
24
|
+
selectedIndex,
|
|
25
|
+
onSelect,
|
|
26
|
+
className,
|
|
27
|
+
}: ApplicantSwitcherProps) {
|
|
28
|
+
if (!applicants || applicants.length <= 1) return null;
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<div
|
|
32
|
+
className={cn("flex w-fit items-center", className)}
|
|
33
|
+
role="group"
|
|
34
|
+
aria-label="Select applicant"
|
|
35
|
+
>
|
|
36
|
+
{applicants.map((applicant, index) => (
|
|
37
|
+
<Button
|
|
38
|
+
key={index}
|
|
39
|
+
type="button"
|
|
40
|
+
variant={selectedIndex === index ? "default" : "outline"}
|
|
41
|
+
onClick={() => onSelect(index)}
|
|
42
|
+
aria-pressed={selectedIndex === index}
|
|
43
|
+
className={cn(
|
|
44
|
+
"rounded-none",
|
|
45
|
+
// Remove left border on non-first items to create a joined look
|
|
46
|
+
index > 0 && "-ml-px",
|
|
47
|
+
)}
|
|
48
|
+
>
|
|
49
|
+
{applicant.name}
|
|
50
|
+
</Button>
|
|
51
|
+
))}
|
|
52
|
+
</div>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { cn } from "@/lib/utils";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Outer responsive shell for multi-step application flows (e.g. Loan Application).
|
|
6
|
+
*
|
|
7
|
+
* - Mobile (< md): full-screen, no extra padding — content fills the viewport.
|
|
8
|
+
* - Desktop (≥ md): wraps content in a centered max-width card so the flow
|
|
9
|
+
* doesn't stretch across a wide screen.
|
|
10
|
+
*
|
|
11
|
+
* Compose inside this wrapper, then place OnboardingLayout (or similar) as the child.
|
|
12
|
+
*/
|
|
13
|
+
export interface ApplicationMobileLayoutProps {
|
|
14
|
+
children: React.ReactNode;
|
|
15
|
+
className?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function ApplicationMobileLayout({
|
|
19
|
+
children,
|
|
20
|
+
className,
|
|
21
|
+
}: ApplicationMobileLayoutProps) {
|
|
22
|
+
return (
|
|
23
|
+
<div
|
|
24
|
+
className={cn(
|
|
25
|
+
"min-h-screen bg-background font-sans",
|
|
26
|
+
// On desktop, center and cap the width so it doesn't span the full screen
|
|
27
|
+
"md:flex md:items-start md:justify-center md:py-8",
|
|
28
|
+
className,
|
|
29
|
+
)}
|
|
30
|
+
>
|
|
31
|
+
<div className="w-full md:max-w-2xl">{children}</div>
|
|
32
|
+
</div>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
@@ -44,6 +44,11 @@ export interface AppointmentAvailabilityPrefs {
|
|
|
44
44
|
maxSlotsPerDay: string;
|
|
45
45
|
/** IANA timezone identifier — e.g. "Australia/Sydney" */
|
|
46
46
|
timezone: string;
|
|
47
|
+
/**
|
|
48
|
+
* Online meeting platform brokers require clients to use.
|
|
49
|
+
* "any" means the client can choose between Google Meet and Microsoft Teams.
|
|
50
|
+
*/
|
|
51
|
+
defaultMeetingPlatform?: "google-meet" | "microsoft-teams" | "any";
|
|
47
52
|
}
|
|
48
53
|
|
|
49
54
|
export interface AppointmentBlockedDate {
|
|
@@ -117,6 +122,44 @@ export const TIMEZONE_OPTIONS: { value: string; label: string }[] = [
|
|
|
117
122
|
{ value: "UTC", label: "UTC" },
|
|
118
123
|
];
|
|
119
124
|
|
|
125
|
+
export const MEETING_PLATFORM_OPTIONS: {
|
|
126
|
+
value: "google-meet" | "microsoft-teams" | "any";
|
|
127
|
+
label: string;
|
|
128
|
+
}[] = [
|
|
129
|
+
{ value: "google-meet", label: "Google Meet" },
|
|
130
|
+
{ value: "microsoft-teams", label: "Microsoft Teams" },
|
|
131
|
+
{ value: "any", label: "Let client choose" },
|
|
132
|
+
];
|
|
133
|
+
|
|
134
|
+
const MEETING_DURATION_OPTIONS: { value: string; label: string }[] = [
|
|
135
|
+
{ value: "15", label: "15 minutes" },
|
|
136
|
+
{ value: "30", label: "30 minutes" },
|
|
137
|
+
{ value: "45", label: "45 minutes" },
|
|
138
|
+
{ value: "60", label: "60 minutes" },
|
|
139
|
+
{ value: "90", label: "90 minutes" },
|
|
140
|
+
];
|
|
141
|
+
|
|
142
|
+
const SCHEDULING_BUFFER_OPTIONS: { value: string; label: string }[] = [
|
|
143
|
+
{ value: "0", label: "No buffer" },
|
|
144
|
+
{ value: "5", label: "5 minutes" },
|
|
145
|
+
{ value: "10", label: "10 minutes" },
|
|
146
|
+
{ value: "15", label: "15 minutes" },
|
|
147
|
+
{ value: "30", label: "30 minutes" },
|
|
148
|
+
];
|
|
149
|
+
|
|
150
|
+
const MAX_SLOTS_OPTIONS: { value: string; label: string }[] = [
|
|
151
|
+
{ value: "2", label: "2 per day" },
|
|
152
|
+
{ value: "4", label: "4 per day" },
|
|
153
|
+
{ value: "6", label: "6 per day" },
|
|
154
|
+
{ value: "8", label: "8 per day" },
|
|
155
|
+
{ value: "10", label: "10 per day" },
|
|
156
|
+
{ value: "unlimited", label: "Unlimited" },
|
|
157
|
+
];
|
|
158
|
+
|
|
159
|
+
/** Map a Base UI SelectValue `v` to its display label from an options array. */
|
|
160
|
+
const selectLabel = (opts: { value: string; label: string }[], v: unknown) =>
|
|
161
|
+
opts.find((o) => o.value === String(v))?.label ?? String(v ?? "");
|
|
162
|
+
|
|
120
163
|
// 30-min increments from 06:00 to 21:30
|
|
121
164
|
const TIME_OPTIONS: { value: string; label: string }[] = (() => {
|
|
122
165
|
const opts: { value: string; label: string }[] = [];
|
|
@@ -249,7 +292,7 @@ function AddTimeOffDialog({
|
|
|
249
292
|
|
|
250
293
|
return (
|
|
251
294
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
252
|
-
<DialogContent size="auto" minWidth="26rem"
|
|
295
|
+
<DialogContent size="auto" minWidth="26rem">
|
|
253
296
|
<DialogHeader>
|
|
254
297
|
<DialogTitle>Add time off</DialogTitle>
|
|
255
298
|
<DialogDescription>
|
|
@@ -349,6 +392,9 @@ export function AppointmentAvailabilitySettings({
|
|
|
349
392
|
const [timezone, setTimezone] = React.useState(
|
|
350
393
|
prefsProp?.timezone ?? "Australia/Sydney",
|
|
351
394
|
);
|
|
395
|
+
const [defaultMeetingPlatform, setDefaultMeetingPlatform] = React.useState<
|
|
396
|
+
"google-meet" | "microsoft-teams" | "any"
|
|
397
|
+
>(prefsProp?.defaultMeetingPlatform ?? "any");
|
|
352
398
|
|
|
353
399
|
const [timeOffEntries, setTimeOffEntries] = React.useState<TimeOffEntry[]>(
|
|
354
400
|
() => {
|
|
@@ -384,8 +430,20 @@ export function AppointmentAvailabilitySettings({
|
|
|
384
430
|
// ---------------------------------------------------------------------------
|
|
385
431
|
|
|
386
432
|
const currentPrefs = React.useMemo(
|
|
387
|
-
() => ({
|
|
388
|
-
|
|
433
|
+
() => ({
|
|
434
|
+
meetingDuration,
|
|
435
|
+
schedulingBuffer,
|
|
436
|
+
maxSlotsPerDay,
|
|
437
|
+
timezone,
|
|
438
|
+
defaultMeetingPlatform,
|
|
439
|
+
}),
|
|
440
|
+
[
|
|
441
|
+
meetingDuration,
|
|
442
|
+
schedulingBuffer,
|
|
443
|
+
maxSlotsPerDay,
|
|
444
|
+
timezone,
|
|
445
|
+
defaultMeetingPlatform,
|
|
446
|
+
],
|
|
389
447
|
);
|
|
390
448
|
|
|
391
449
|
const saveGuard = React.useRef(false);
|
|
@@ -535,14 +593,16 @@ export function AppointmentAvailabilitySettings({
|
|
|
535
593
|
onValueChange={(v) => setMeetingDuration(v as string)}
|
|
536
594
|
>
|
|
537
595
|
<SelectTrigger className="w-40">
|
|
538
|
-
<SelectValue
|
|
596
|
+
<SelectValue>
|
|
597
|
+
{(v) => selectLabel(MEETING_DURATION_OPTIONS, v)}
|
|
598
|
+
</SelectValue>
|
|
539
599
|
</SelectTrigger>
|
|
540
600
|
<SelectContent>
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
601
|
+
{MEETING_DURATION_OPTIONS.map((opt) => (
|
|
602
|
+
<SelectItem key={opt.value} value={opt.value}>
|
|
603
|
+
{opt.label}
|
|
604
|
+
</SelectItem>
|
|
605
|
+
))}
|
|
546
606
|
</SelectContent>
|
|
547
607
|
</Select>
|
|
548
608
|
</PrefRow>
|
|
@@ -556,14 +616,16 @@ export function AppointmentAvailabilitySettings({
|
|
|
556
616
|
onValueChange={(v) => setSchedulingBuffer(v as string)}
|
|
557
617
|
>
|
|
558
618
|
<SelectTrigger className="w-40">
|
|
559
|
-
<SelectValue
|
|
619
|
+
<SelectValue>
|
|
620
|
+
{(v) => selectLabel(SCHEDULING_BUFFER_OPTIONS, v)}
|
|
621
|
+
</SelectValue>
|
|
560
622
|
</SelectTrigger>
|
|
561
623
|
<SelectContent>
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
624
|
+
{SCHEDULING_BUFFER_OPTIONS.map((opt) => (
|
|
625
|
+
<SelectItem key={opt.value} value={opt.value}>
|
|
626
|
+
{opt.label}
|
|
627
|
+
</SelectItem>
|
|
628
|
+
))}
|
|
567
629
|
</SelectContent>
|
|
568
630
|
</Select>
|
|
569
631
|
</PrefRow>
|
|
@@ -577,15 +639,16 @@ export function AppointmentAvailabilitySettings({
|
|
|
577
639
|
onValueChange={(v) => setMaxSlotsPerDay(v as string)}
|
|
578
640
|
>
|
|
579
641
|
<SelectTrigger className="w-40">
|
|
580
|
-
<SelectValue
|
|
642
|
+
<SelectValue>
|
|
643
|
+
{(v) => selectLabel(MAX_SLOTS_OPTIONS, v)}
|
|
644
|
+
</SelectValue>
|
|
581
645
|
</SelectTrigger>
|
|
582
646
|
<SelectContent>
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
<SelectItem value="unlimited">Unlimited</SelectItem>
|
|
647
|
+
{MAX_SLOTS_OPTIONS.map((opt) => (
|
|
648
|
+
<SelectItem key={opt.value} value={opt.value}>
|
|
649
|
+
{opt.label}
|
|
650
|
+
</SelectItem>
|
|
651
|
+
))}
|
|
589
652
|
</SelectContent>
|
|
590
653
|
</Select>
|
|
591
654
|
</PrefRow>
|
|
@@ -599,7 +662,9 @@ export function AppointmentAvailabilitySettings({
|
|
|
599
662
|
onValueChange={(v) => setTimezone(v as string)}
|
|
600
663
|
>
|
|
601
664
|
<SelectTrigger className="w-56">
|
|
602
|
-
<SelectValue
|
|
665
|
+
<SelectValue>
|
|
666
|
+
{(v) => selectLabel(TIMEZONE_OPTIONS, v)}
|
|
667
|
+
</SelectValue>
|
|
603
668
|
</SelectTrigger>
|
|
604
669
|
<SelectContent>
|
|
605
670
|
{TIMEZONE_OPTIONS.map((opt) => (
|
|
@@ -610,6 +675,33 @@ export function AppointmentAvailabilitySettings({
|
|
|
610
675
|
</SelectContent>
|
|
611
676
|
</Select>
|
|
612
677
|
</PrefRow>
|
|
678
|
+
|
|
679
|
+
<PrefRow
|
|
680
|
+
label="Default Meeting Platform"
|
|
681
|
+
description="Online meeting platform clients must use when booking"
|
|
682
|
+
>
|
|
683
|
+
<Select
|
|
684
|
+
value={defaultMeetingPlatform}
|
|
685
|
+
onValueChange={(v) =>
|
|
686
|
+
setDefaultMeetingPlatform(
|
|
687
|
+
v as "google-meet" | "microsoft-teams" | "any",
|
|
688
|
+
)
|
|
689
|
+
}
|
|
690
|
+
>
|
|
691
|
+
<SelectTrigger className="w-48">
|
|
692
|
+
<SelectValue>
|
|
693
|
+
{(v) => selectLabel(MEETING_PLATFORM_OPTIONS, v)}
|
|
694
|
+
</SelectValue>
|
|
695
|
+
</SelectTrigger>
|
|
696
|
+
<SelectContent>
|
|
697
|
+
{MEETING_PLATFORM_OPTIONS.map((opt) => (
|
|
698
|
+
<SelectItem key={opt.value} value={opt.value}>
|
|
699
|
+
{opt.label}
|
|
700
|
+
</SelectItem>
|
|
701
|
+
))}
|
|
702
|
+
</SelectContent>
|
|
703
|
+
</Select>
|
|
704
|
+
</PrefRow>
|
|
613
705
|
</div>
|
|
614
706
|
</TabsContent>
|
|
615
707
|
|