@wealthx/shadcn 1.3.2 → 1.3.4
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 +227 -191
- package/CHANGELOG.md +12 -0
- package/dist/{chunk-2UM72RJ7.mjs → chunk-2D3HQPFN.mjs} +12 -10
- package/dist/chunk-2EM2FRU6.mjs +613 -0
- package/dist/{chunk-FH6QVUVZ.mjs → chunk-2GIYVERS.mjs} +2 -2
- package/dist/chunk-2P7HP7LR.mjs +68 -0
- package/dist/{chunk-HISNT2MG.mjs → chunk-37AE3OM5.mjs} +5 -5
- package/dist/{chunk-HBZLGDIN.mjs → chunk-3ERBUVHC.mjs} +169 -110
- package/dist/{chunk-C7CQJNMR.mjs → chunk-3VDET466.mjs} +2 -2
- package/dist/{chunk-462HMNO4.mjs → chunk-4MM7LHM5.mjs} +2 -2
- package/dist/{chunk-QMY3AZJH.mjs → chunk-4Z66LMIQ.mjs} +2 -2
- package/dist/{chunk-U5X52X37.mjs → chunk-57ZXILTS.mjs} +6 -6
- package/dist/{chunk-2A5RRQGG.mjs → chunk-5NF6T2RS.mjs} +11 -20
- package/dist/{chunk-3OYFOX3X.mjs → chunk-5VOTTIXF.mjs} +2 -2
- package/dist/{chunk-LBMRIB3G.mjs → chunk-6AJUS7VX.mjs} +1 -1
- package/dist/{chunk-OODBHKG7.mjs → chunk-6HIOM2HL.mjs} +7 -4
- package/dist/{chunk-BDYZCBRT.mjs → chunk-6QAFGZC2.mjs} +2 -2
- package/dist/{chunk-U4NDAF2P.mjs → chunk-6TX73WG7.mjs} +1 -1
- package/dist/{chunk-GD4BJDJR.mjs → chunk-7BTFGCFC.mjs} +4 -4
- package/dist/{chunk-FAKPBKLT.mjs → chunk-7GWRPXHD.mjs} +4 -4
- package/dist/{chunk-NMOI6CQD.mjs → chunk-7YI3HEBH.mjs} +5 -5
- package/dist/{chunk-T4BJLT57.mjs → chunk-AE7MASLF.mjs} +5 -5
- package/dist/{chunk-VLQZANBF.mjs → chunk-AFML43VJ.mjs} +6 -1
- package/dist/chunk-BBXSNDS3.mjs +260 -0
- package/dist/chunk-BOW7U26Y.mjs +203 -0
- package/dist/{chunk-34NWQURD.mjs → chunk-BS75ICOO.mjs} +2 -2
- package/dist/chunk-D2NSIIXG.mjs +394 -0
- package/dist/{chunk-3GF7OVTP.mjs → chunk-DGNHGNYH.mjs} +2 -2
- package/dist/{chunk-VLARHE5V.mjs → chunk-DMXYRCHM.mjs} +6 -6
- package/dist/{chunk-OGOYQ7BG.mjs → chunk-DQB4EPIS.mjs} +1 -1
- package/dist/{chunk-MIZQHHUO.mjs → chunk-FL6DZFJK.mjs} +106 -38
- package/dist/{chunk-I3RZS7V2.mjs → chunk-FLL633WS.mjs} +19 -33
- package/dist/{chunk-PBL4OQV2.mjs → chunk-FTPBQVQ6.mjs} +4 -4
- package/dist/chunk-FYPSTTEJ.mjs +169 -0
- package/dist/{chunk-6O6KD7CE.mjs → chunk-G27TSQLQ.mjs} +6 -6
- package/dist/{chunk-66MI7Q4B.mjs → chunk-GT3RU6GA.mjs} +2 -2
- package/dist/{chunk-D6ID6M4V.mjs → chunk-GTAVSBDO.mjs} +2 -2
- package/dist/{chunk-24FUO7TD.mjs → chunk-H6NQTIF4.mjs} +2 -2
- package/dist/{chunk-7DHU4VGG.mjs → chunk-HK4HUQTV.mjs} +2 -2
- package/dist/chunk-I4KVSZCH.mjs +101 -0
- package/dist/{chunk-RGVKLTLH.mjs → chunk-IKXYTCSB.mjs} +2 -2
- package/dist/{chunk-Y6DWJSKZ.mjs → chunk-ISUA7DSB.mjs} +1 -1
- package/dist/{chunk-J5UICVJS.mjs → chunk-JPGL36WQ.mjs} +2 -2
- package/dist/{chunk-7XJHLGUV.mjs → chunk-JTK6VJXY.mjs} +2 -2
- package/dist/{chunk-7YAU5CY6.mjs → chunk-JVMXMFBB.mjs} +2 -2
- package/dist/{chunk-IAE3F7DR.mjs → chunk-JZY6TNIS.mjs} +21 -21
- package/dist/{chunk-K5A5L6T2.mjs → chunk-K4KOD3KR.mjs} +12 -12
- package/dist/{chunk-MBON7YRJ.mjs → chunk-K5QV4TT6.mjs} +3 -3
- package/dist/{chunk-IHMFS7NZ.mjs → chunk-K5VHK7CM.mjs} +21 -21
- package/dist/{chunk-RJI6GKVF.mjs → chunk-KCWNDYPZ.mjs} +5 -5
- package/dist/{chunk-UFYSFDER.mjs → chunk-KFH36NKF.mjs} +1 -1
- package/dist/{chunk-EBXQWIYG.mjs → chunk-KLTACJ2G.mjs} +5 -5
- package/dist/{chunk-3TTACBDP.mjs → chunk-KWD6GANL.mjs} +4 -4
- package/dist/{chunk-IOJRDS6V.mjs → chunk-L4NSRQ3T.mjs} +218 -147
- package/dist/{chunk-GYMYRIZP.mjs → chunk-LBTHZSBT.mjs} +2 -2
- package/dist/{chunk-AMQZRHEZ.mjs → chunk-LQULK2E3.mjs} +5 -5
- package/dist/{chunk-YJG55G2H.mjs → chunk-LR6LHDP3.mjs} +5 -5
- package/dist/{chunk-7PV3IWCN.mjs → chunk-M4VYX2PV.mjs} +19 -1
- package/dist/{chunk-P76HMUI6.mjs → chunk-MDUKXXIL.mjs} +2 -2
- package/dist/{chunk-LV35NGVG.mjs → chunk-N6Q5IPKT.mjs} +9 -9
- package/dist/{chunk-DOEO3CDL.mjs → chunk-NB3ZL36B.mjs} +1 -1
- package/dist/{chunk-XREGSKX3.mjs → chunk-NOOEKOWY.mjs} +5 -5
- package/dist/{chunk-NL3ZO62D.mjs → chunk-NT4FX27K.mjs} +1 -1
- package/dist/{chunk-QZ4RE6NA.mjs → chunk-NTYQWVLI.mjs} +6 -6
- package/dist/{chunk-ERGGHC2V.mjs → chunk-OEOOYMC2.mjs} +2 -2
- package/dist/{chunk-4GAWMKMI.mjs → chunk-OIKBW2QD.mjs} +291 -54
- package/dist/{chunk-DUJTAXMH.mjs → chunk-OKTJFDPN.mjs} +6 -6
- package/dist/chunk-OLKMCXAR.mjs +1219 -0
- package/dist/{chunk-EI5F6FMT.mjs → chunk-OWFQSXVD.mjs} +3 -3
- package/dist/{chunk-6DZEXFNB.mjs → chunk-P2N2PEFY.mjs} +3 -3
- package/dist/{chunk-NSLMILBT.mjs → chunk-P7CEBZM6.mjs} +2 -2
- package/dist/{chunk-7S5AESZO.mjs → chunk-PNRUH7JY.mjs} +6 -6
- package/dist/{chunk-ZU4NV6RG.mjs → chunk-PNSYFE3K.mjs} +2 -2
- package/dist/{chunk-JKGDCQTZ.mjs → chunk-QTRSCVQ3.mjs} +5 -5
- package/dist/{chunk-ABFDMHOR.mjs → chunk-QX7IFQSF.mjs} +5 -5
- package/dist/{chunk-CFMQP5QS.mjs → chunk-QXKGOMUX.mjs} +6 -6
- package/dist/{chunk-NQPOYKAQ.mjs → chunk-R2ON6CAN.mjs} +2 -2
- package/dist/{chunk-DBHJ5KC3.mjs → chunk-R4HCRDU5.mjs} +1 -1
- package/dist/{chunk-EWRB4PAD.mjs → chunk-RCAOCHWA.mjs} +14 -14
- package/dist/{chunk-EFRENWEJ.mjs → chunk-RSUIPKGX.mjs} +2 -2
- package/dist/{chunk-DGHAXJBN.mjs → chunk-S2FKV4M5.mjs} +5 -5
- package/dist/{chunk-RGU7HOEC.mjs → chunk-SET2ANTY.mjs} +5 -7
- package/dist/chunk-SFH2NJEJ.mjs +47 -0
- package/dist/{chunk-6AW4KJHE.mjs → chunk-SIVYAI3M.mjs} +12 -12
- package/dist/{chunk-5FQIKDKP.mjs → chunk-THVO2N47.mjs} +8 -8
- package/dist/{chunk-JMHR3YGZ.mjs → chunk-TLAWKTSA.mjs} +3 -3
- package/dist/{chunk-HVY6KCCF.mjs → chunk-TOWTPLRC.mjs} +68 -72
- package/dist/{chunk-6JQFUE5I.mjs → chunk-UALR6JGV.mjs} +2 -2
- package/dist/{chunk-N6TNTQL6.mjs → chunk-UJZ4UHWI.mjs} +9 -11
- package/dist/{chunk-MARPPFOJ.mjs → chunk-UNACI2YK.mjs} +2 -2
- package/dist/{chunk-3NCUZIFP.mjs → chunk-V6XGXYCJ.mjs} +7 -7
- package/dist/chunk-VB5M6OZQ.mjs +57 -0
- package/dist/{chunk-5IS7G74I.mjs → chunk-VY5NEUP7.mjs} +6 -6
- package/dist/{chunk-JHJHG4GO.mjs → chunk-WE4YKBDE.mjs} +2 -2
- package/dist/{chunk-BKNFWEH2.mjs → chunk-WL6WVV47.mjs} +3 -3
- package/dist/{chunk-FWCSY2DS.mjs → chunk-WNQUEZJF.mjs} +22 -1
- package/dist/{chunk-2Y7YJKPE.mjs → chunk-WZ6UJCBL.mjs} +1 -1
- package/dist/{chunk-UMTOX62O.mjs → chunk-XYPW2XA5.mjs} +13 -10
- package/dist/chunk-Y2MTAVAK.mjs +34 -0
- package/dist/{chunk-6CR5N2JW.mjs → chunk-YCWLFG27.mjs} +6 -6
- package/dist/{chunk-PU4YZQXV.mjs → chunk-YE67AALL.mjs} +12 -12
- package/dist/{chunk-M3FV7LOK.mjs → chunk-YEWNFK5S.mjs} +6 -1
- package/dist/{chunk-R3VSPKNP.mjs → chunk-YIZHS72Z.mjs} +11 -12
- package/dist/{chunk-7PYJD5JI.mjs → chunk-ZEDMKQK2.mjs} +2 -2
- package/dist/{chunk-N2PT566P.mjs → chunk-ZFCDYW6N.mjs} +4 -4
- package/dist/chunk-ZGQIVGIN.mjs +57 -0
- package/dist/{chunk-Q2BGOAMG.mjs → chunk-ZKWXDQDG.mjs} +4 -4
- package/dist/{chunk-GHC7LLUX.mjs → chunk-ZOWL2L5J.mjs} +5 -5
- package/dist/components/ui/accordion.mjs +3 -3
- package/dist/components/ui/add-column-modal.js +2 -2
- package/dist/components/ui/add-column-modal.mjs +10 -10
- package/dist/components/ui/add-lead-modal.js +424 -82
- package/dist/components/ui/add-lead-modal.mjs +12 -9
- package/dist/components/ui/advisor-card.js +2 -2
- package/dist/components/ui/advisor-card.mjs +8 -8
- package/dist/components/ui/ai-assistant-drawer.js +2 -2
- package/dist/components/ui/ai-assistant-drawer.mjs +9 -9
- package/dist/components/ui/ai-builder.js +958 -0
- package/dist/components/ui/ai-builder.mjs +25 -0
- package/dist/components/ui/ai-conversations.js +2045 -0
- package/dist/components/ui/ai-conversations.mjs +41 -0
- package/dist/components/ui/alert-dialog.js +2 -2
- package/dist/components/ui/alert-dialog.mjs +5 -5
- package/dist/components/ui/alert.mjs +3 -3
- package/dist/components/ui/appointment-action-dialogs.js +19 -3
- package/dist/components/ui/appointment-action-dialogs.mjs +15 -14
- package/dist/components/ui/appointment-availability-settings.js +181 -111
- package/dist/components/ui/appointment-availability-settings.mjs +20 -18
- package/dist/components/ui/appointment-book-dialog.js +113 -24
- package/dist/components/ui/appointment-book-dialog.mjs +21 -20
- package/dist/components/ui/appointment-calendar-view.js +19 -3
- package/dist/components/ui/appointment-calendar-view.mjs +10 -9
- package/dist/components/ui/appointment-detail-sheet.js +19 -3
- package/dist/components/ui/appointment-detail-sheet.mjs +18 -17
- package/dist/components/ui/appointment-gmail-connect.js +49 -89
- package/dist/components/ui/appointment-gmail-connect.mjs +8 -9
- package/dist/components/ui/appointment-mini-card.js +2 -2
- package/dist/components/ui/appointment-mini-card.mjs +6 -6
- package/dist/components/ui/appointment-time-slot-picker.mjs +6 -6
- package/dist/components/ui/appointment-upcoming-card.js +19 -3
- package/dist/components/ui/appointment-upcoming-card.mjs +15 -14
- package/dist/components/ui/auth-logo.js +95 -0
- package/dist/components/ui/auth-logo.mjs +8 -0
- package/dist/components/ui/auth-page-layout.js +108 -0
- package/dist/components/ui/auth-page-layout.mjs +8 -0
- package/dist/components/ui/avatar.mjs +3 -3
- package/dist/components/ui/backoffice-alert-history-chart.js +2 -2
- package/dist/components/ui/backoffice-alert-history-chart.mjs +9 -9
- package/dist/components/ui/backoffice-alerts-chart.js +2 -2
- package/dist/components/ui/backoffice-alerts-chart.mjs +11 -11
- package/dist/components/ui/backoffice-connections-chart.js +2 -2
- package/dist/components/ui/backoffice-connections-chart.mjs +11 -11
- package/dist/components/ui/backoffice-contact-history-chart.js +2 -2
- package/dist/components/ui/backoffice-contact-history-chart.mjs +9 -9
- package/dist/components/ui/badge.mjs +4 -4
- package/dist/components/ui/borrowing-capacity-line-chart.js +145 -132
- package/dist/components/ui/borrowing-capacity-line-chart.mjs +9 -9
- package/dist/components/ui/button.js +2 -2
- package/dist/components/ui/button.mjs +4 -4
- package/dist/components/ui/calendar.js +17 -3
- package/dist/components/ui/calendar.mjs +6 -5
- package/dist/components/ui/card.mjs +3 -3
- package/dist/components/ui/cash-balance-line-chart.js +158 -158
- package/dist/components/ui/cash-balance-line-chart.mjs +9 -9
- package/dist/components/ui/cashflow-bar-chart.js +2 -2
- package/dist/components/ui/cashflow-bar-chart.mjs +9 -9
- package/dist/components/ui/chat-widget-primitives.js +573 -0
- package/dist/components/ui/chat-widget-primitives.mjs +21 -0
- package/dist/components/ui/chat-widget.js +1268 -0
- package/dist/components/ui/chat-widget.mjs +29 -0
- package/dist/components/ui/checkbox.mjs +3 -3
- package/dist/components/ui/chip.js +2 -2
- package/dist/components/ui/chip.mjs +6 -6
- package/dist/components/ui/color-picker.js +2 -2
- package/dist/components/ui/color-picker.mjs +7 -7
- package/dist/components/ui/combobox.mjs +3 -3
- package/dist/components/ui/data-table.js +2 -2
- package/dist/components/ui/data-table.mjs +12 -12
- package/dist/components/ui/date-picker.js +22 -6
- package/dist/components/ui/date-picker.mjs +9 -8
- package/dist/components/ui/dialog.js +2 -2
- package/dist/components/ui/dialog.mjs +5 -5
- package/dist/components/ui/document-checklist-template.js +630 -0
- package/dist/components/ui/document-checklist-template.mjs +15 -0
- package/dist/components/ui/drawer.js +2 -2
- package/dist/components/ui/drawer.mjs +3 -3
- package/dist/components/ui/dropdown-menu.mjs +3 -3
- package/dist/components/ui/empty.mjs +3 -3
- package/dist/components/ui/expense-bar-chart.js +2 -2
- package/dist/components/ui/expense-bar-chart.mjs +9 -9
- package/dist/components/ui/field.mjs +5 -5
- package/dist/components/ui/financial-cards.js +431 -291
- package/dist/components/ui/financial-cards.mjs +10 -9
- package/dist/components/ui/financial-drawers.js +4 -4
- package/dist/components/ui/financial-drawers.mjs +8 -8
- package/dist/components/ui/financial-primitives.mjs +3 -3
- package/dist/components/ui/financial-sections.js +8 -9
- package/dist/components/ui/financial-sections.mjs +12 -12
- package/dist/components/ui/form-primitives.mjs +8 -8
- package/dist/components/ui/income-bar-chart.js +2 -2
- package/dist/components/ui/income-bar-chart.mjs +9 -9
- package/dist/components/ui/input-group.js +2 -2
- package/dist/components/ui/input-group.mjs +7 -7
- package/dist/components/ui/input-otp.mjs +3 -3
- package/dist/components/ui/input.mjs +3 -3
- package/dist/components/ui/kanban-column.js +19 -23
- package/dist/components/ui/kanban-column.mjs +14 -14
- package/dist/components/ui/label.mjs +3 -3
- package/dist/components/ui/onboarding-layout.js +476 -0
- package/dist/components/ui/onboarding-layout.mjs +11 -0
- package/dist/components/ui/opportunity-card.js +2 -2
- package/dist/components/ui/opportunity-card.mjs +12 -12
- package/dist/components/ui/opportunity-edit-modals.js +22 -6
- package/dist/components/ui/opportunity-edit-modals.mjs +21 -20
- package/dist/components/ui/opportunity-summary-tab.js +991 -674
- package/dist/components/ui/opportunity-summary-tab.mjs +26 -26
- package/dist/components/ui/page-header.mjs +3 -3
- package/dist/components/ui/page-top-bar.mjs +3 -3
- package/dist/components/ui/pagination.js +2 -2
- package/dist/components/ui/pagination.mjs +6 -6
- package/dist/components/ui/password-strength-tooltip.js +197 -0
- package/dist/components/ui/password-strength-tooltip.mjs +11 -0
- package/dist/components/ui/pipeline-alerts.mjs +3 -3
- package/dist/components/ui/pipeline-board.js +19 -23
- package/dist/components/ui/pipeline-board.mjs +18 -18
- package/dist/components/ui/pipeline-chart.js +12 -6
- package/dist/components/ui/pipeline-chart.mjs +4 -3
- package/dist/components/ui/pipeline-dialogs.js +28 -12
- package/dist/components/ui/pipeline-dialogs.mjs +14 -13
- package/dist/components/ui/pipeline-primitives.mjs +6 -6
- package/dist/components/ui/popover.mjs +3 -3
- package/dist/components/ui/progress.mjs +3 -3
- package/dist/components/ui/property-cashflow-doughnut-chart.js +2 -2
- package/dist/components/ui/property-cashflow-doughnut-chart.mjs +9 -9
- package/dist/components/ui/property-debt-equity-doughnut-chart.js +2 -2
- package/dist/components/ui/property-debt-equity-doughnut-chart.mjs +9 -9
- package/dist/components/ui/property-mobile-estimate-line-chart.js +2 -2
- package/dist/components/ui/property-mobile-estimate-line-chart.mjs +9 -9
- package/dist/components/ui/radio-group.mjs +3 -3
- package/dist/components/ui/select.mjs +3 -3
- package/dist/components/ui/separator.mjs +3 -3
- package/dist/components/ui/sheet.mjs +3 -3
- package/dist/components/ui/sidebar-nav.js +6 -5
- package/dist/components/ui/sidebar-nav.mjs +7 -7
- package/dist/components/ui/skeleton.mjs +3 -3
- package/dist/components/ui/slider.mjs +3 -3
- package/dist/components/ui/sonner.mjs +2 -2
- package/dist/components/ui/spinner.mjs +3 -3
- package/dist/components/ui/stage-timeline.mjs +10 -10
- package/dist/components/ui/stepper.mjs +3 -3
- package/dist/components/ui/switch.mjs +3 -3
- package/dist/components/ui/table.mjs +3 -3
- package/dist/components/ui/tabs.mjs +3 -3
- package/dist/components/ui/textarea.mjs +3 -3
- package/dist/components/ui/toggle-group.mjs +4 -4
- package/dist/components/ui/toggle.mjs +3 -3
- package/dist/components/ui/tooltip.mjs +3 -3
- package/dist/components/ui/transactions-expense-categories-doughnut-chart.js +2 -2
- package/dist/components/ui/transactions-expense-categories-doughnut-chart.mjs +9 -9
- package/dist/components/ui/transactions-income-expense-bar-chart.js +2 -2
- package/dist/components/ui/transactions-income-expense-bar-chart.mjs +9 -9
- package/dist/components/ui/transactions-liabilities-breakdown-doughnut-chart.js +2 -2
- package/dist/components/ui/transactions-liabilities-breakdown-doughnut-chart.mjs +9 -9
- package/dist/components/ui/two-fa-setup-form.js +612 -0
- package/dist/components/ui/two-fa-setup-form.mjs +16 -0
- package/dist/components/ui/upload-card.js +187 -0
- package/dist/components/ui/upload-card.mjs +10 -0
- package/dist/components/ui/video-background.js +118 -0
- package/dist/components/ui/video-background.mjs +8 -0
- package/dist/index.js +12674 -9311
- package/dist/index.mjs +341 -245
- package/dist/lib/colors.mjs +1 -1
- package/dist/lib/theme-provider.mjs +1 -1
- package/dist/lib/typography.mjs +2 -2
- package/dist/lib/utils.js +8 -2
- package/dist/lib/utils.mjs +6 -4
- package/dist/styles.css +1 -1
- package/package.json +61 -1
- package/src/components/index.tsx +126 -1
- package/src/components/ui/add-lead-modal.tsx +101 -142
- package/src/components/ui/ai-builder.tsx +560 -0
- package/src/components/ui/ai-conversations.tsx +1690 -0
- package/src/components/ui/appointment-availability-settings.tsx +152 -101
- package/src/components/ui/appointment-book-dialog.tsx +138 -24
- package/src/components/ui/appointment-calendar-view.tsx +2 -3
- package/src/components/ui/appointment-gmail-connect.tsx +23 -42
- package/src/components/ui/auth-logo.tsx +50 -0
- package/src/components/ui/auth-page-layout.tsx +59 -0
- package/src/components/ui/borrowing-capacity-line-chart.tsx +10 -8
- package/src/components/ui/button.tsx +2 -2
- package/src/components/ui/calendar.tsx +2 -1
- package/src/components/ui/cash-balance-line-chart.tsx +11 -20
- package/src/components/ui/chart-shared.tsx +10 -0
- package/src/components/ui/chat-widget-primitives.tsx +336 -0
- package/src/components/ui/chat-widget.tsx +822 -0
- package/src/components/ui/document-checklist-template.tsx +264 -0
- package/src/components/ui/drawer.tsx +2 -2
- package/src/components/ui/financial-cards.tsx +176 -78
- package/src/components/ui/financial-drawers.tsx +2 -2
- package/src/components/ui/financial-sections.tsx +1 -1
- package/src/components/ui/kanban-column.tsx +2 -5
- package/src/components/ui/onboarding-layout.tsx +109 -0
- package/src/components/ui/opportunity-summary-tab.tsx +469 -142
- package/src/components/ui/password-strength-tooltip.tsx +70 -0
- package/src/components/ui/pipeline-chart.tsx +2 -6
- package/src/components/ui/sidebar-nav.tsx +1 -11
- package/src/components/ui/two-fa-setup-form.tsx +229 -0
- package/src/components/ui/upload-card.tsx +98 -0
- package/src/components/ui/video-background.tsx +55 -0
- package/src/lib/format-date.ts +26 -0
- package/src/lib/utils.ts +11 -0
- package/src/styles/styles-css.ts +1 -1
- package/tsup.config.ts +13 -0
|
@@ -42,6 +42,8 @@ export interface AppointmentAvailabilityPrefs {
|
|
|
42
42
|
meetingDuration: string;
|
|
43
43
|
schedulingBuffer: string;
|
|
44
44
|
maxSlotsPerDay: string;
|
|
45
|
+
/** IANA timezone identifier — e.g. "Australia/Sydney" */
|
|
46
|
+
timezone: string;
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
export interface AppointmentBlockedDate {
|
|
@@ -56,8 +58,29 @@ export interface AppointmentBlockedDate {
|
|
|
56
58
|
}
|
|
57
59
|
|
|
58
60
|
export interface AppointmentAvailabilitySettingsProps {
|
|
61
|
+
/**
|
|
62
|
+
* Initial weekly schedule.
|
|
63
|
+
* @remarks Mount-time initialiser only — prop changes after mount are ignored.
|
|
64
|
+
* Use the `key` prop to reset the component when async data arrives.
|
|
65
|
+
*/
|
|
59
66
|
schedule: AppointmentDaySchedule[];
|
|
67
|
+
/**
|
|
68
|
+
* Saved booking preferences from DB — initialises the Booking Preferences tab.
|
|
69
|
+
* @remarks Mount-time initialiser only.
|
|
70
|
+
*/
|
|
71
|
+
prefs?: AppointmentAvailabilityPrefs;
|
|
72
|
+
/**
|
|
73
|
+
* Custom blocked dates added by the user (non-holiday).
|
|
74
|
+
* Merged with `publicHolidays` in the Time Off tab.
|
|
75
|
+
* @remarks Mount-time initialiser only.
|
|
76
|
+
*/
|
|
60
77
|
blockedDates?: AppointmentBlockedDate[];
|
|
78
|
+
/**
|
|
79
|
+
* Public holiday list from the DB/API.
|
|
80
|
+
* When provided, replaces the built-in `AU_PUBLIC_HOLIDAYS_2026` fallback.
|
|
81
|
+
* @remarks Mount-time initialiser only.
|
|
82
|
+
*/
|
|
83
|
+
publicHolidays?: AppointmentBlockedDate[];
|
|
61
84
|
onSave?: (
|
|
62
85
|
schedule: AppointmentDaySchedule[],
|
|
63
86
|
prefs: AppointmentAvailabilityPrefs,
|
|
@@ -66,9 +89,10 @@ export interface AppointmentAvailabilitySettingsProps {
|
|
|
66
89
|
}
|
|
67
90
|
|
|
68
91
|
// ---------------------------------------------------------------------------
|
|
69
|
-
//
|
|
92
|
+
// Constants
|
|
70
93
|
// ---------------------------------------------------------------------------
|
|
71
94
|
|
|
95
|
+
/** Fallback holiday list used when the `publicHolidays` prop is not provided. */
|
|
72
96
|
const AU_PUBLIC_HOLIDAYS_2026: AppointmentBlockedDate[] = [
|
|
73
97
|
{ date: "2026-01-01", label: "New Year's Day" },
|
|
74
98
|
{ date: "2026-01-26", label: "Australia Day" },
|
|
@@ -81,23 +105,19 @@ const AU_PUBLIC_HOLIDAYS_2026: AppointmentBlockedDate[] = [
|
|
|
81
105
|
{ date: "2026-12-26", label: "Boxing Day" },
|
|
82
106
|
];
|
|
83
107
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
label
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// ---------------------------------------------------------------------------
|
|
98
|
-
// Time options — 30-min increments from 6:00 to 21:30
|
|
99
|
-
// ---------------------------------------------------------------------------
|
|
108
|
+
export const TIMEZONE_OPTIONS: { value: string; label: string }[] = [
|
|
109
|
+
{ value: "Australia/Sydney", label: "Sydney / Melbourne (AEDT)" },
|
|
110
|
+
{ value: "Australia/Brisbane", label: "Brisbane (AEST, no DST)" },
|
|
111
|
+
{ value: "Australia/Adelaide", label: "Adelaide (ACDT)" },
|
|
112
|
+
{ value: "Australia/Perth", label: "Perth (AWST)" },
|
|
113
|
+
{ value: "Australia/Darwin", label: "Darwin (ACST, no DST)" },
|
|
114
|
+
{ value: "Australia/Hobart", label: "Hobart (AEDT)" },
|
|
115
|
+
{ value: "Asia/Ho_Chi_Minh", label: "Ho Chi Minh City (ICT)" },
|
|
116
|
+
{ value: "Asia/Singapore", label: "Singapore (SGT)" },
|
|
117
|
+
{ value: "UTC", label: "UTC" },
|
|
118
|
+
];
|
|
100
119
|
|
|
120
|
+
// 30-min increments from 06:00 to 21:30
|
|
101
121
|
const TIME_OPTIONS: { value: string; label: string }[] = (() => {
|
|
102
122
|
const opts: { value: string; label: string }[] = [];
|
|
103
123
|
for (let h = 6; h <= 21; h++) {
|
|
@@ -115,6 +135,23 @@ const TIME_OPTIONS: { value: string; label: string }[] = (() => {
|
|
|
115
135
|
const timeLabel = (v: string) =>
|
|
116
136
|
TIME_OPTIONS.find((o) => o.value === v)?.label ?? v;
|
|
117
137
|
|
|
138
|
+
// ---------------------------------------------------------------------------
|
|
139
|
+
// Internal type
|
|
140
|
+
// ---------------------------------------------------------------------------
|
|
141
|
+
|
|
142
|
+
interface TimeOffEntry {
|
|
143
|
+
date: string;
|
|
144
|
+
label?: string;
|
|
145
|
+
enabled: boolean;
|
|
146
|
+
isHoliday: boolean;
|
|
147
|
+
timeStart?: string;
|
|
148
|
+
timeEnd?: string;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// ---------------------------------------------------------------------------
|
|
152
|
+
// Sub-components
|
|
153
|
+
// ---------------------------------------------------------------------------
|
|
154
|
+
|
|
118
155
|
function TimeSelect({
|
|
119
156
|
value,
|
|
120
157
|
onChange,
|
|
@@ -144,10 +181,26 @@ function TimeSelect({
|
|
|
144
181
|
);
|
|
145
182
|
}
|
|
146
183
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
184
|
+
/** Shared row layout for the Booking Preferences tab. */
|
|
185
|
+
function PrefRow({
|
|
186
|
+
label,
|
|
187
|
+
description,
|
|
188
|
+
children,
|
|
189
|
+
}: {
|
|
190
|
+
label: string;
|
|
191
|
+
description: string;
|
|
192
|
+
children: React.ReactNode;
|
|
193
|
+
}) {
|
|
194
|
+
return (
|
|
195
|
+
<div className="flex min-h-[68px] items-center justify-between px-6 py-4">
|
|
196
|
+
<div className="flex flex-col gap-0.5">
|
|
197
|
+
<p className="text-sm font-medium">{label}</p>
|
|
198
|
+
<p className="text-xs text-muted-foreground">{description}</p>
|
|
199
|
+
</div>
|
|
200
|
+
{children}
|
|
201
|
+
</div>
|
|
202
|
+
);
|
|
203
|
+
}
|
|
151
204
|
|
|
152
205
|
function AddTimeOffDialog({
|
|
153
206
|
open,
|
|
@@ -156,12 +209,7 @@ function AddTimeOffDialog({
|
|
|
156
209
|
}: {
|
|
157
210
|
open: boolean;
|
|
158
211
|
onOpenChange: (v: boolean) => void;
|
|
159
|
-
onAdd: (entry:
|
|
160
|
-
date: string;
|
|
161
|
-
label?: string;
|
|
162
|
-
timeStart?: string;
|
|
163
|
-
timeEnd?: string;
|
|
164
|
-
}) => void;
|
|
212
|
+
onAdd: (entry: AppointmentBlockedDate) => void;
|
|
165
213
|
}) {
|
|
166
214
|
const [label, setLabel] = React.useState("");
|
|
167
215
|
const [date, setDate] = React.useState<Date | undefined>(undefined);
|
|
@@ -179,7 +227,6 @@ function AddTimeOffDialog({
|
|
|
179
227
|
|
|
180
228
|
const handleAdd = () => {
|
|
181
229
|
if (!date) return;
|
|
182
|
-
// Convert Date to ISO date string "YYYY-MM-DD"
|
|
183
230
|
const isoDate = [
|
|
184
231
|
date.getFullYear(),
|
|
185
232
|
String(date.getMonth() + 1).padStart(2, "0"),
|
|
@@ -212,7 +259,6 @@ function AddTimeOffDialog({
|
|
|
212
259
|
</DialogHeader>
|
|
213
260
|
|
|
214
261
|
<div className="flex flex-col gap-4 py-1">
|
|
215
|
-
{/* Label */}
|
|
216
262
|
<div className="flex flex-col gap-1.5">
|
|
217
263
|
<Label htmlFor="toff-label">
|
|
218
264
|
Name{" "}
|
|
@@ -228,7 +274,6 @@ function AddTimeOffDialog({
|
|
|
228
274
|
/>
|
|
229
275
|
</div>
|
|
230
276
|
|
|
231
|
-
{/* Date */}
|
|
232
277
|
<div className="flex flex-col gap-1.5">
|
|
233
278
|
<Label>Date</Label>
|
|
234
279
|
<DatePicker
|
|
@@ -239,7 +284,6 @@ function AddTimeOffDialog({
|
|
|
239
284
|
/>
|
|
240
285
|
</div>
|
|
241
286
|
|
|
242
|
-
{/* Add time switch */}
|
|
243
287
|
<div className="flex flex-col gap-3">
|
|
244
288
|
<div className="flex items-center gap-3">
|
|
245
289
|
<Switch
|
|
@@ -284,30 +328,33 @@ function AddTimeOffDialog({
|
|
|
284
328
|
|
|
285
329
|
export function AppointmentAvailabilitySettings({
|
|
286
330
|
schedule: initialSchedule,
|
|
331
|
+
prefs: prefsProp,
|
|
287
332
|
blockedDates: blockedDatesProp,
|
|
333
|
+
publicHolidays: publicHolidaysProp,
|
|
288
334
|
onSave,
|
|
289
335
|
onBlockedDatesChange,
|
|
290
336
|
}: AppointmentAvailabilitySettingsProps) {
|
|
291
|
-
// Track first render to skip auto-save on mount
|
|
292
|
-
const hasMounted = React.useRef(false);
|
|
293
|
-
React.useEffect(() => {
|
|
294
|
-
hasMounted.current = true;
|
|
295
|
-
}, []);
|
|
296
|
-
|
|
297
|
-
// --- Weekly Availability tab ---
|
|
298
337
|
const [schedule, setSchedule] =
|
|
299
338
|
React.useState<AppointmentDaySchedule[]>(initialSchedule);
|
|
300
339
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
const [
|
|
340
|
+
const [meetingDuration, setMeetingDuration] = React.useState(
|
|
341
|
+
prefsProp?.meetingDuration ?? "30",
|
|
342
|
+
);
|
|
343
|
+
const [schedulingBuffer, setSchedulingBuffer] = React.useState(
|
|
344
|
+
prefsProp?.schedulingBuffer ?? "0",
|
|
345
|
+
);
|
|
346
|
+
const [maxSlotsPerDay, setMaxSlotsPerDay] = React.useState(
|
|
347
|
+
prefsProp?.maxSlotsPerDay ?? "8",
|
|
348
|
+
);
|
|
349
|
+
const [timezone, setTimezone] = React.useState(
|
|
350
|
+
prefsProp?.timezone ?? "Australia/Sydney",
|
|
351
|
+
);
|
|
305
352
|
|
|
306
|
-
// --- Time Off tab ---
|
|
307
353
|
const [timeOffEntries, setTimeOffEntries] = React.useState<TimeOffEntry[]>(
|
|
308
354
|
() => {
|
|
309
|
-
const
|
|
310
|
-
const
|
|
355
|
+
const holidays = publicHolidaysProp ?? AU_PUBLIC_HOLIDAYS_2026;
|
|
356
|
+
const holidayDates = new Set(holidays.map((h) => h.date));
|
|
357
|
+
const entries: TimeOffEntry[] = holidays.map((h) => ({
|
|
311
358
|
...h,
|
|
312
359
|
enabled: true,
|
|
313
360
|
isHoliday: true,
|
|
@@ -328,28 +375,36 @@ export function AppointmentAvailabilitySettings({
|
|
|
328
375
|
const [addMoreOpen, setAddMoreOpen] = React.useState(false);
|
|
329
376
|
|
|
330
377
|
// ---------------------------------------------------------------------------
|
|
331
|
-
// Auto-save
|
|
378
|
+
// Auto-save effects
|
|
379
|
+
//
|
|
380
|
+
// Each effect uses its own mount-guard ref. A shared ref would break because
|
|
381
|
+
// React runs effects in declaration order within the same flush — the first
|
|
382
|
+
// effect would flip the ref to `true`, causing later effects to skip their
|
|
383
|
+
// own guard and fire onSave/onBlockedDatesChange on mount.
|
|
332
384
|
// ---------------------------------------------------------------------------
|
|
333
385
|
|
|
334
386
|
const currentPrefs = React.useMemo(
|
|
335
|
-
() => ({ meetingDuration, schedulingBuffer, maxSlotsPerDay }),
|
|
336
|
-
[meetingDuration, schedulingBuffer, maxSlotsPerDay],
|
|
387
|
+
() => ({ meetingDuration, schedulingBuffer, maxSlotsPerDay, timezone }),
|
|
388
|
+
[meetingDuration, schedulingBuffer, maxSlotsPerDay, timezone],
|
|
337
389
|
);
|
|
338
390
|
|
|
339
|
-
React.
|
|
340
|
-
|
|
341
|
-
onSave?.(schedule, currentPrefs);
|
|
342
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
343
|
-
}, [schedule]);
|
|
391
|
+
const saveGuard = React.useRef(false);
|
|
392
|
+
const timeOffGuard = React.useRef(false);
|
|
344
393
|
|
|
345
394
|
React.useEffect(() => {
|
|
346
|
-
if (!
|
|
395
|
+
if (!saveGuard.current) {
|
|
396
|
+
saveGuard.current = true;
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
347
399
|
onSave?.(schedule, currentPrefs);
|
|
348
400
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
349
|
-
}, [
|
|
401
|
+
}, [schedule, currentPrefs]);
|
|
350
402
|
|
|
351
403
|
React.useEffect(() => {
|
|
352
|
-
if (!
|
|
404
|
+
if (!timeOffGuard.current) {
|
|
405
|
+
timeOffGuard.current = true;
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
353
408
|
const blocked = timeOffEntries
|
|
354
409
|
.filter((e) => e.enabled)
|
|
355
410
|
.map(({ date, label, timeStart, timeEnd }) => ({
|
|
@@ -363,7 +418,7 @@ export function AppointmentAvailabilitySettings({
|
|
|
363
418
|
}, [timeOffEntries]);
|
|
364
419
|
|
|
365
420
|
// ---------------------------------------------------------------------------
|
|
366
|
-
// Weekly handlers
|
|
421
|
+
// Weekly schedule handlers
|
|
367
422
|
// ---------------------------------------------------------------------------
|
|
368
423
|
|
|
369
424
|
const toggleDay = (index: number) => {
|
|
@@ -396,12 +451,7 @@ export function AppointmentAvailabilitySettings({
|
|
|
396
451
|
setTimeOffEntries((prev) => prev.filter((e) => e.date !== date));
|
|
397
452
|
};
|
|
398
453
|
|
|
399
|
-
const handleAddMore = (entry: {
|
|
400
|
-
date: string;
|
|
401
|
-
label?: string;
|
|
402
|
-
timeStart?: string;
|
|
403
|
-
timeEnd?: string;
|
|
404
|
-
}) => {
|
|
454
|
+
const handleAddMore = (entry: AppointmentBlockedDate) => {
|
|
405
455
|
if (timeOffEntries.some((e) => e.date === entry.date)) return;
|
|
406
456
|
setTimeOffEntries((prev) =>
|
|
407
457
|
[
|
|
@@ -421,7 +471,6 @@ export function AppointmentAvailabilitySettings({
|
|
|
421
471
|
return (
|
|
422
472
|
<div className="border border-border bg-card">
|
|
423
473
|
<Tabs defaultValue="weekly" className="gap-0">
|
|
424
|
-
{/* Tab strip */}
|
|
425
474
|
<div className="border-b border-border p-1">
|
|
426
475
|
<TabsList variant="default" className="w-full">
|
|
427
476
|
<TabsTrigger value="weekly">Weekly Availability</TabsTrigger>
|
|
@@ -430,9 +479,7 @@ export function AppointmentAvailabilitySettings({
|
|
|
430
479
|
</TabsList>
|
|
431
480
|
</div>
|
|
432
481
|
|
|
433
|
-
{/*
|
|
434
|
-
{/* Tab 1: Weekly Availability */}
|
|
435
|
-
{/* ---------------------------------------------------------------- */}
|
|
482
|
+
{/* Tab 1: Weekly Availability */}
|
|
436
483
|
<TabsContent value="weekly">
|
|
437
484
|
<div className="flex flex-col divide-y divide-border">
|
|
438
485
|
{schedule.map((day, index) => (
|
|
@@ -476,18 +523,13 @@ export function AppointmentAvailabilitySettings({
|
|
|
476
523
|
</div>
|
|
477
524
|
</TabsContent>
|
|
478
525
|
|
|
479
|
-
{/*
|
|
480
|
-
{/* Tab 2: Booking Preferences */}
|
|
481
|
-
{/* ---------------------------------------------------------------- */}
|
|
526
|
+
{/* Tab 2: Booking Preferences */}
|
|
482
527
|
<TabsContent value="booking">
|
|
483
528
|
<div className="flex flex-col divide-y divide-border">
|
|
484
|
-
<
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
Length of each appointment slot
|
|
489
|
-
</p>
|
|
490
|
-
</div>
|
|
529
|
+
<PrefRow
|
|
530
|
+
label="Meeting Duration"
|
|
531
|
+
description="Length of each appointment slot"
|
|
532
|
+
>
|
|
491
533
|
<Select
|
|
492
534
|
value={meetingDuration}
|
|
493
535
|
onValueChange={(v) => setMeetingDuration(v as string)}
|
|
@@ -503,15 +545,12 @@ export function AppointmentAvailabilitySettings({
|
|
|
503
545
|
<SelectItem value="90">90 minutes</SelectItem>
|
|
504
546
|
</SelectContent>
|
|
505
547
|
</Select>
|
|
506
|
-
</
|
|
548
|
+
</PrefRow>
|
|
507
549
|
|
|
508
|
-
<
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
Gap between consecutive bookings
|
|
513
|
-
</p>
|
|
514
|
-
</div>
|
|
550
|
+
<PrefRow
|
|
551
|
+
label="Scheduling Buffer"
|
|
552
|
+
description="Gap between consecutive bookings"
|
|
553
|
+
>
|
|
515
554
|
<Select
|
|
516
555
|
value={schedulingBuffer}
|
|
517
556
|
onValueChange={(v) => setSchedulingBuffer(v as string)}
|
|
@@ -527,15 +566,12 @@ export function AppointmentAvailabilitySettings({
|
|
|
527
566
|
<SelectItem value="30">30 minutes</SelectItem>
|
|
528
567
|
</SelectContent>
|
|
529
568
|
</Select>
|
|
530
|
-
</
|
|
569
|
+
</PrefRow>
|
|
531
570
|
|
|
532
|
-
<
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
Maximum bookings accepted per day
|
|
537
|
-
</p>
|
|
538
|
-
</div>
|
|
571
|
+
<PrefRow
|
|
572
|
+
label="Daily Slot Limit"
|
|
573
|
+
description="Maximum bookings accepted per day"
|
|
574
|
+
>
|
|
539
575
|
<Select
|
|
540
576
|
value={maxSlotsPerDay}
|
|
541
577
|
onValueChange={(v) => setMaxSlotsPerDay(v as string)}
|
|
@@ -552,15 +588,33 @@ export function AppointmentAvailabilitySettings({
|
|
|
552
588
|
<SelectItem value="unlimited">Unlimited</SelectItem>
|
|
553
589
|
</SelectContent>
|
|
554
590
|
</Select>
|
|
555
|
-
</
|
|
591
|
+
</PrefRow>
|
|
592
|
+
|
|
593
|
+
<PrefRow
|
|
594
|
+
label="Meeting Timezone"
|
|
595
|
+
description="Timezone used for booking display and notifications"
|
|
596
|
+
>
|
|
597
|
+
<Select
|
|
598
|
+
value={timezone}
|
|
599
|
+
onValueChange={(v) => setTimezone(v as string)}
|
|
600
|
+
>
|
|
601
|
+
<SelectTrigger className="w-56">
|
|
602
|
+
<SelectValue />
|
|
603
|
+
</SelectTrigger>
|
|
604
|
+
<SelectContent>
|
|
605
|
+
{TIMEZONE_OPTIONS.map((opt) => (
|
|
606
|
+
<SelectItem key={opt.value} value={opt.value}>
|
|
607
|
+
{opt.label}
|
|
608
|
+
</SelectItem>
|
|
609
|
+
))}
|
|
610
|
+
</SelectContent>
|
|
611
|
+
</Select>
|
|
612
|
+
</PrefRow>
|
|
556
613
|
</div>
|
|
557
614
|
</TabsContent>
|
|
558
615
|
|
|
559
|
-
{/*
|
|
560
|
-
{/* Tab 3: Time Off */}
|
|
561
|
-
{/* ---------------------------------------------------------------- */}
|
|
616
|
+
{/* Tab 3: Time Off */}
|
|
562
617
|
<TabsContent value="time-off">
|
|
563
|
-
{/* Description + Add more button */}
|
|
564
618
|
<div className="flex items-center justify-between px-6 py-4">
|
|
565
619
|
<p className="text-sm text-muted-foreground">
|
|
566
620
|
Toggle dates when you are unavailable. Clients cannot book on
|
|
@@ -579,7 +633,6 @@ export function AppointmentAvailabilitySettings({
|
|
|
579
633
|
|
|
580
634
|
<Separator />
|
|
581
635
|
|
|
582
|
-
{/* Holiday + custom date rows */}
|
|
583
636
|
<div className="flex flex-col divide-y divide-border">
|
|
584
637
|
{timeOffEntries.map((entry) => {
|
|
585
638
|
const formattedDate = formatDateWithWeekday(entry.date);
|
|
@@ -615,7 +668,6 @@ export function AppointmentAvailabilitySettings({
|
|
|
615
668
|
)}
|
|
616
669
|
</p>
|
|
617
670
|
</div>
|
|
618
|
-
{/* Only custom (non-holiday) dates can be removed */}
|
|
619
671
|
{!entry.isHoliday && (
|
|
620
672
|
<Button
|
|
621
673
|
type="button"
|
|
@@ -634,7 +686,6 @@ export function AppointmentAvailabilitySettings({
|
|
|
634
686
|
</TabsContent>
|
|
635
687
|
</Tabs>
|
|
636
688
|
|
|
637
|
-
{/* Add More dialog */}
|
|
638
689
|
<AddTimeOffDialog
|
|
639
690
|
open={addMoreOpen}
|
|
640
691
|
onOpenChange={setAddMoreOpen}
|