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