@wealthx/shadcn 1.2.2 → 1.3.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 +200 -156
- package/CHANGELOG.md +22 -0
- package/dist/{chunk-4Y6R4WEC.mjs → chunk-2A5RRQGG.mjs} +9 -22
- package/dist/{chunk-TS2ZX2VS.mjs → chunk-2UM72RJ7.mjs} +11 -15
- package/dist/{chunk-A56YQQHG.mjs → chunk-3NCUZIFP.mjs} +2 -2
- package/dist/chunk-3OYFOX3X.mjs +79 -0
- package/dist/{chunk-RP3SQYA3.mjs → chunk-3TTACBDP.mjs} +9 -4
- package/dist/chunk-4GAWMKMI.mjs +710 -0
- package/dist/{chunk-VGSESELX.mjs → chunk-5FQIKDKP.mjs} +5 -5
- package/dist/{chunk-K3JYD4IU.mjs → chunk-5IS7G74I.mjs} +11 -4
- package/dist/chunk-6AW4KJHE.mjs +235 -0
- package/dist/chunk-6CR5N2JW.mjs +302 -0
- package/dist/{chunk-XIRTEFKH.mjs → chunk-6DZEXFNB.mjs} +36 -8
- package/dist/chunk-6O6KD7CE.mjs +271 -0
- package/dist/chunk-7PV3IWCN.mjs +33 -0
- package/dist/{chunk-SPJ5KXW7.mjs → chunk-7S5AESZO.mjs} +5 -5
- package/dist/{chunk-RYCLWMZ7.mjs → chunk-ABFDMHOR.mjs} +9 -7
- package/dist/{chunk-SWGT756Z.mjs → chunk-AMQZRHEZ.mjs} +10 -4
- package/dist/{chunk-WAZD7NFU.mjs → chunk-BKNFWEH2.mjs} +6 -6
- package/dist/{chunk-CLIN5525.mjs → chunk-C7CQJNMR.mjs} +1 -1
- package/dist/{chunk-D4ILTPOG.mjs → chunk-CFMQP5QS.mjs} +5 -4
- package/dist/{chunk-VPBN3WOO.mjs → chunk-DGHAXJBN.mjs} +9 -7
- package/dist/chunk-DOEO3CDL.mjs +27 -0
- package/dist/{chunk-5MEWU56Z.mjs → chunk-DUJTAXMH.mjs} +11 -6
- package/dist/{chunk-GGM2UYGG.mjs → chunk-EBXQWIYG.mjs} +10 -4
- package/dist/chunk-EWRB4PAD.mjs +468 -0
- package/dist/{chunk-ZSHYDDRB.mjs → chunk-FAKPBKLT.mjs} +6 -2
- package/dist/chunk-FNQXOAYJ.mjs +169 -0
- package/dist/{chunk-A6AAWBPF.mjs → chunk-GHC7LLUX.mjs} +13 -4
- package/dist/chunk-HBZLGDIN.mjs +507 -0
- package/dist/{chunk-SIZMLSRU.mjs → chunk-HISNT2MG.mjs} +8 -6
- package/dist/{chunk-CGH4DRNG.mjs → chunk-HVY6KCCF.mjs} +10 -7
- package/dist/chunk-I3RZS7V2.mjs +136 -0
- package/dist/chunk-IAE3F7DR.mjs +1962 -0
- package/dist/{chunk-UT4KJR7V.mjs → chunk-IHMFS7NZ.mjs} +35 -74
- package/dist/{chunk-PCPLO5HT.mjs → chunk-IOJRDS6V.mjs} +96 -14
- package/dist/{chunk-LHYCMLVA.mjs → chunk-JKGDCQTZ.mjs} +11 -4
- package/dist/{chunk-H45TKD34.mjs → chunk-JMHR3YGZ.mjs} +1 -1
- package/dist/{chunk-4MN6UQHG.mjs → chunk-K5A5L6T2.mjs} +17 -39
- package/dist/chunk-LV35NGVG.mjs +272 -0
- package/dist/{chunk-FZIXGLMV.mjs → chunk-M3FV7LOK.mjs} +5 -12
- package/dist/{chunk-FMAXJ2SI.mjs → chunk-MBON7YRJ.mjs} +1 -1
- package/dist/chunk-MIZQHHUO.mjs +441 -0
- package/dist/chunk-MN5NYQCL.mjs +29 -0
- package/dist/chunk-NL3ZO62D.mjs +31 -0
- package/dist/{chunk-Q76O3RIQ.mjs → chunk-NMOI6CQD.mjs} +1 -1
- package/dist/{chunk-P6AM5V7O.mjs → chunk-OODBHKG7.mjs} +1 -1
- package/dist/chunk-PBL4OQV2.mjs +283 -0
- package/dist/{chunk-Y4QFWRNR.mjs → chunk-PU4YZQXV.mjs} +17 -18
- package/dist/chunk-QMY3AZJH.mjs +80 -0
- package/dist/{chunk-BL3DXM2X.mjs → chunk-QZ4RE6NA.mjs} +11 -4
- package/dist/{chunk-VACKZOMY.mjs → chunk-R3VSPKNP.mjs} +3 -3
- package/dist/{chunk-OPNQAVVH.mjs → chunk-RJI6GKVF.mjs} +8 -6
- package/dist/{chunk-WG6JGJXB.mjs → chunk-T4BJLT57.mjs} +1 -1
- package/dist/chunk-UMTOX62O.mjs +415 -0
- package/dist/{chunk-7MMXNK3C.mjs → chunk-VLARHE5V.mjs} +8 -6
- package/dist/{chunk-2I5S2AMY.mjs → chunk-XREGSKX3.mjs} +2 -2
- package/dist/{chunk-JNQORUPP.mjs → chunk-YJG55G2H.mjs} +14 -11
- package/dist/{chunk-ZRSDX6OW.mjs → chunk-ZC45IGZO.mjs} +33 -30
- package/dist/components/ui/add-column-modal.js +42 -14
- package/dist/components/ui/add-column-modal.mjs +5 -5
- package/dist/components/ui/add-lead-modal.js +42 -11
- package/dist/components/ui/add-lead-modal.mjs +3 -3
- package/dist/components/ui/advisor-card.js +497 -0
- package/dist/components/ui/advisor-card.mjs +13 -0
- package/dist/components/ui/ai-assistant-drawer.js +11 -10
- package/dist/components/ui/ai-assistant-drawer.mjs +3 -3
- package/dist/components/ui/alert-dialog.js +2 -2
- package/dist/components/ui/alert-dialog.mjs +2 -2
- package/dist/components/ui/appointment-action-dialogs.js +1160 -0
- package/dist/components/ui/appointment-action-dialogs.mjs +23 -0
- package/dist/components/ui/appointment-availability-settings.js +1590 -0
- package/dist/components/ui/appointment-availability-settings.mjs +23 -0
- package/dist/components/ui/appointment-book-dialog.js +1744 -0
- package/dist/components/ui/appointment-book-dialog.mjs +27 -0
- package/dist/components/ui/appointment-calendar-view.js +833 -0
- package/dist/components/ui/appointment-calendar-view.mjs +14 -0
- package/dist/components/ui/appointment-detail-sheet.js +1517 -0
- package/dist/components/ui/appointment-detail-sheet.mjs +24 -0
- package/dist/components/ui/appointment-gmail-connect.js +467 -0
- package/dist/components/ui/appointment-gmail-connect.mjs +14 -0
- package/dist/components/ui/appointment-mini-card.js +345 -0
- package/dist/components/ui/appointment-mini-card.mjs +11 -0
- package/dist/components/ui/appointment-time-slot-picker.js +311 -0
- package/dist/components/ui/appointment-time-slot-picker.mjs +13 -0
- package/dist/components/ui/appointment-upcoming-card.js +1268 -0
- package/dist/components/ui/appointment-upcoming-card.mjs +21 -0
- package/dist/components/ui/backoffice-alert-history-chart.js +11 -5
- package/dist/components/ui/backoffice-alert-history-chart.mjs +5 -4
- package/dist/components/ui/backoffice-alerts-chart.js +786 -0
- package/dist/components/ui/backoffice-alerts-chart.mjs +19 -0
- package/dist/components/ui/backoffice-connections-chart.js +817 -0
- package/dist/components/ui/backoffice-connections-chart.mjs +19 -0
- package/dist/components/ui/backoffice-contact-history-chart.js +11 -5
- package/dist/components/ui/backoffice-contact-history-chart.mjs +5 -4
- package/dist/components/ui/badge.js +6 -6
- package/dist/components/ui/badge.mjs +1 -1
- package/dist/components/ui/borrowing-capacity-line-chart.js +30 -21
- package/dist/components/ui/borrowing-capacity-line-chart.mjs +5 -4
- package/dist/components/ui/button.js +2 -2
- package/dist/components/ui/button.mjs +1 -1
- package/dist/components/ui/calendar.js +2 -2
- package/dist/components/ui/calendar.mjs +2 -2
- package/dist/components/ui/card.js +1 -1
- package/dist/components/ui/card.mjs +1 -1
- package/dist/components/ui/cash-balance-line-chart.js +31 -23
- package/dist/components/ui/cash-balance-line-chart.mjs +5 -4
- package/dist/components/ui/cashflow-bar-chart.js +12 -5
- package/dist/components/ui/cashflow-bar-chart.mjs +5 -4
- package/dist/components/ui/chip.js +97 -18
- package/dist/components/ui/chip.mjs +3 -2
- package/dist/components/ui/color-picker.js +158 -28
- package/dist/components/ui/color-picker.mjs +3 -1
- package/dist/components/ui/data-table.js +140 -119
- package/dist/components/ui/data-table.mjs +3 -2
- package/dist/components/ui/date-picker.js +48 -27
- package/dist/components/ui/date-picker.mjs +4 -3
- package/dist/components/ui/dialog.js +37 -9
- package/dist/components/ui/dialog.mjs +2 -2
- package/dist/components/ui/expense-bar-chart.js +12 -5
- package/dist/components/ui/expense-bar-chart.mjs +5 -4
- package/dist/components/ui/field.mjs +2 -2
- package/dist/components/ui/financial-cards.js +322 -155
- package/dist/components/ui/financial-cards.mjs +5 -3
- package/dist/components/ui/financial-drawers.js +2 -2
- package/dist/components/ui/financial-drawers.mjs +3 -3
- package/dist/components/ui/financial-sections.js +14 -10
- package/dist/components/ui/financial-sections.mjs +6 -5
- package/dist/components/ui/income-bar-chart.js +12 -5
- package/dist/components/ui/income-bar-chart.mjs +5 -4
- package/dist/components/ui/input-group.js +2 -2
- package/dist/components/ui/input-group.mjs +2 -2
- package/dist/components/ui/kanban-column.js +52 -44
- package/dist/components/ui/kanban-column.mjs +7 -5
- package/dist/components/ui/opportunity-card.js +52 -44
- package/dist/components/ui/opportunity-card.mjs +6 -4
- package/dist/components/ui/opportunity-edit-modals.js +1367 -1263
- package/dist/components/ui/opportunity-edit-modals.mjs +8 -8
- package/dist/components/ui/opportunity-summary-tab.js +2744 -2157
- package/dist/components/ui/opportunity-summary-tab.mjs +14 -14
- package/dist/components/ui/page-header.js +92 -0
- package/dist/components/ui/page-header.mjs +8 -0
- package/dist/components/ui/page-top-bar.js +88 -0
- package/dist/components/ui/page-top-bar.mjs +8 -0
- package/dist/components/ui/pagination.js +303 -19
- package/dist/components/ui/pagination.mjs +11 -4
- package/dist/components/ui/pipeline-board.js +205 -191
- package/dist/components/ui/pipeline-board.mjs +9 -7
- package/dist/components/ui/pipeline-dialogs.js +114 -65
- package/dist/components/ui/pipeline-dialogs.mjs +7 -6
- package/dist/components/ui/pipeline-primitives.js +6 -6
- package/dist/components/ui/pipeline-primitives.mjs +2 -2
- package/dist/components/ui/property-cashflow-doughnut-chart.js +14 -12
- package/dist/components/ui/property-cashflow-doughnut-chart.mjs +5 -4
- package/dist/components/ui/property-debt-equity-doughnut-chart.js +14 -12
- package/dist/components/ui/property-debt-equity-doughnut-chart.mjs +5 -4
- package/dist/components/ui/property-mobile-estimate-line-chart.js +16 -14
- package/dist/components/ui/property-mobile-estimate-line-chart.mjs +5 -4
- package/dist/components/ui/sidebar-nav.js +234 -95
- package/dist/components/ui/sidebar-nav.mjs +4 -1
- package/dist/components/ui/stage-timeline.js +6 -6
- package/dist/components/ui/stage-timeline.mjs +3 -3
- package/dist/components/ui/transactions-expense-categories-doughnut-chart.js +18 -16
- package/dist/components/ui/transactions-expense-categories-doughnut-chart.mjs +5 -4
- package/dist/components/ui/transactions-income-expense-bar-chart.js +28 -12
- package/dist/components/ui/transactions-income-expense-bar-chart.mjs +5 -4
- package/dist/components/ui/transactions-liabilities-breakdown-doughnut-chart.js +18 -16
- package/dist/components/ui/transactions-liabilities-breakdown-doughnut-chart.mjs +5 -4
- package/dist/index.js +12899 -9343
- package/dist/index.mjs +256 -190
- package/dist/styles.css +1 -1
- package/package.json +71 -1
- package/src/components/index.tsx +114 -9
- package/src/components/ui/add-column-modal.tsx +7 -7
- package/src/components/ui/add-lead-modal.tsx +6 -3
- package/src/components/ui/advisor-card.tsx +227 -0
- package/src/components/ui/ai-assistant-drawer.tsx +4 -3
- package/src/components/ui/appointment-action-dialogs.tsx +297 -0
- package/src/components/ui/appointment-availability-settings.tsx +645 -0
- package/src/components/ui/appointment-book-dialog.tsx +618 -0
- package/src/components/ui/appointment-calendar-view.tsx +510 -0
- package/src/components/ui/appointment-detail-sheet.tsx +415 -0
- package/src/components/ui/appointment-gmail-connect.tsx +188 -0
- package/src/components/ui/appointment-mini-card.tsx +104 -0
- package/src/components/ui/appointment-time-slot-picker.tsx +123 -0
- package/src/components/ui/appointment-upcoming-card.tsx +635 -0
- package/src/components/ui/backoffice-alert-history-chart.tsx +10 -2
- package/src/components/ui/backoffice-alerts-chart.tsx +312 -0
- package/src/components/ui/backoffice-connections-chart.tsx +339 -0
- package/src/components/ui/backoffice-contact-history-chart.tsx +10 -2
- package/src/components/ui/badge.tsx +12 -6
- package/src/components/ui/borrowing-capacity-line-chart.tsx +4 -11
- package/src/components/ui/button.tsx +2 -2
- package/src/components/ui/card.tsx +1 -1
- package/src/components/ui/cash-balance-line-chart.tsx +4 -23
- package/src/components/ui/cashflow-bar-chart.tsx +9 -2
- package/src/components/ui/chart-shared.tsx +4 -11
- package/src/components/ui/chip.tsx +23 -19
- package/src/components/ui/color-picker.tsx +4 -2
- package/src/components/ui/data-table.tsx +28 -74
- package/src/components/ui/date-picker.tsx +42 -37
- package/src/components/ui/dialog.tsx +72 -6
- package/src/components/ui/expense-bar-chart.tsx +11 -2
- package/src/components/ui/financial-cards.tsx +99 -10
- package/src/components/ui/income-bar-chart.tsx +11 -2
- package/src/components/ui/opportunity-card.tsx +10 -39
- package/src/components/ui/opportunity-edit-modals.tsx +98 -36
- package/src/components/ui/opportunity-summary-tab.tsx +548 -232
- package/src/components/ui/page-header.tsx +57 -0
- package/src/components/ui/page-top-bar.tsx +48 -0
- package/src/components/ui/pagination.tsx +171 -22
- package/src/components/ui/pipeline-board.tsx +12 -5
- package/src/components/ui/property-cashflow-doughnut-chart.tsx +3 -1
- package/src/components/ui/property-debt-equity-doughnut-chart.tsx +3 -1
- package/src/components/ui/property-mobile-estimate-line-chart.tsx +3 -1
- package/src/components/ui/sidebar-nav.tsx +36 -37
- package/src/components/ui/transactions-expense-categories-doughnut-chart.tsx +3 -1
- package/src/components/ui/transactions-income-expense-bar-chart.tsx +12 -9
- package/src/components/ui/transactions-liabilities-breakdown-doughnut-chart.tsx +3 -1
- package/src/lib/format-currency.ts +44 -0
- package/src/lib/format-date.ts +50 -0
- package/src/lib/opportunity-constants.ts +12 -0
- package/src/styles/globals.css +17 -15
- package/src/styles/styles-css.ts +1 -1
- package/tsup.config.ts +14 -0
- package/dist/chunk-S4QRUQNW.mjs +0 -475
- package/dist/chunk-URGMJAE3.mjs +0 -1885
- package/dist/chunk-WNGWBVLV.mjs +0 -148
- package/dist/{chunk-LLVQKSU3.mjs → chunk-GD4BJDJR.mjs} +3 -3
|
@@ -68,10 +68,55 @@ function DialogOverlay({
|
|
|
68
68
|
);
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
/**
|
|
72
|
+
* Maps the `size` prop to an exact CSS max-width value.
|
|
73
|
+
* Applied via inline style — bypasses Tailwind v4 class scanning entirely.
|
|
74
|
+
*/
|
|
75
|
+
const DIALOG_MAX_WIDTHS: Record<string, string> = {
|
|
76
|
+
sm: "24rem",
|
|
77
|
+
md: "28rem",
|
|
78
|
+
lg: "32rem",
|
|
79
|
+
xl: "36rem",
|
|
80
|
+
"2xl": "42rem",
|
|
81
|
+
"3xl": "48rem",
|
|
82
|
+
"4xl": "56rem",
|
|
83
|
+
full: "100%",
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Default minimum width for size="auto" dialogs.
|
|
88
|
+
* Prevents the dialog from collapsing too narrow when hugging content.
|
|
89
|
+
* Override per-instance via the `minWidth` prop.
|
|
90
|
+
*/
|
|
91
|
+
const DIALOG_AUTO_MIN_WIDTH = "20rem"; // 320px
|
|
92
|
+
|
|
71
93
|
export type DialogContentProps = React.ComponentProps<
|
|
72
94
|
typeof DialogPrimitive.Popup
|
|
73
95
|
> & {
|
|
74
96
|
showCloseButton?: boolean;
|
|
97
|
+
/**
|
|
98
|
+
* Optional container element to render the Dialog portal into.
|
|
99
|
+
* Pass a ref'd element to scope the overlay inside a parent (e.g. a Sheet drawer)
|
|
100
|
+
* instead of appending to document.body.
|
|
101
|
+
*/
|
|
102
|
+
container?: HTMLElement | null;
|
|
103
|
+
/** Vertical alignment of the dialog. "top" anchors to top-4; "center" (default) vertically centers. */
|
|
104
|
+
align?: "center" | "top";
|
|
105
|
+
/**
|
|
106
|
+
* Width behaviour of the dialog panel.
|
|
107
|
+
* - Fixed sizes ("sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl" | "full"):
|
|
108
|
+
* dialog fills width up to that maximum (applied via inline style — reliable in Tailwind v4).
|
|
109
|
+
* - "auto": dialog shrinks to fit its content (hug-content). Has a built-in minimum
|
|
110
|
+
* width of `DIALOG_AUTO_MIN_WIDTH` (20rem / 320px) to avoid collapsing too narrow.
|
|
111
|
+
* Defaults to "lg".
|
|
112
|
+
*/
|
|
113
|
+
size?: "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl" | "full" | "auto";
|
|
114
|
+
/**
|
|
115
|
+
* Override the minimum width for `size="auto"` dialogs.
|
|
116
|
+
* Accepts any valid CSS length value (e.g. "24rem", "400px").
|
|
117
|
+
* Ignored when using a fixed size.
|
|
118
|
+
*/
|
|
119
|
+
minWidth?: string;
|
|
75
120
|
};
|
|
76
121
|
|
|
77
122
|
function DialogContent({
|
|
@@ -79,28 +124,47 @@ function DialogContent({
|
|
|
79
124
|
children,
|
|
80
125
|
showCloseButton = true,
|
|
81
126
|
style,
|
|
127
|
+
container,
|
|
128
|
+
align = "center",
|
|
129
|
+
size = "lg",
|
|
130
|
+
minWidth,
|
|
82
131
|
...props
|
|
83
132
|
}: DialogContentProps): ReactElement {
|
|
84
133
|
const themeVars = useThemeVars();
|
|
134
|
+
const isAuto = size === "auto";
|
|
135
|
+
|
|
136
|
+
const sizeStyle = isAuto
|
|
137
|
+
? { minWidth: minWidth ?? DIALOG_AUTO_MIN_WIDTH }
|
|
138
|
+
: { maxWidth: DIALOG_MAX_WIDTHS[size] };
|
|
139
|
+
|
|
85
140
|
return (
|
|
86
|
-
<DialogPortal>
|
|
141
|
+
<DialogPortal container={container ?? undefined}>
|
|
87
142
|
<DialogOverlay style={themeVars as React.CSSProperties} />
|
|
88
143
|
<DialogPrimitive.Popup
|
|
89
144
|
className={cn(
|
|
90
|
-
// WealthX: removed rounded-lg (sharp corners), shadow-lg (flat panels)
|
|
91
|
-
|
|
145
|
+
// WealthX: removed rounded-lg (sharp corners), shadow-lg (flat panels)
|
|
146
|
+
// max-w-[calc(100%-2rem)] acts as a viewport-edge guard on all sizes.
|
|
147
|
+
// Fixed max-width is applied via inline style (sizeStyle) to avoid
|
|
148
|
+
// Tailwind v4 class-scanning gaps with dynamic class lookups.
|
|
149
|
+
"fixed left-[50%] z-50 grid max-w-[calc(100%-2rem)] translate-x-[-50%] gap-4 border bg-background p-6 duration-200 outline-none data-ending-style:animate-out data-ending-style:fade-out-0 data-ending-style:zoom-out-95 data-ending-style:fill-mode-forwards data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95",
|
|
150
|
+
// "auto" → hug content (with min-width floor); fixed sizes → fill to max-width
|
|
151
|
+
isAuto ? "w-auto" : "w-full",
|
|
152
|
+
align === "center"
|
|
153
|
+
? "top-[50%] translate-y-[-50%]"
|
|
154
|
+
: "top-4 translate-y-0",
|
|
92
155
|
className,
|
|
93
156
|
)}
|
|
94
157
|
data-slot="dialog-content"
|
|
95
|
-
style={{ ...themeVars, ...style } as React.CSSProperties}
|
|
158
|
+
style={{ ...themeVars, ...sizeStyle, ...style } as React.CSSProperties}
|
|
96
159
|
{...props}
|
|
97
160
|
>
|
|
98
161
|
{children}
|
|
99
162
|
{showCloseButton ? (
|
|
100
163
|
<DialogPrimitive.Close
|
|
101
|
-
className="absolute top-4 right-4 transition-colors hover:bg-foreground/5 focus:outline-hidden focus:ring-2 focus:ring-border focus:ring-offset-0 disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
|
|
164
|
+
className="absolute top-4 right-4 inline-flex size-7 items-center justify-center transition-colors hover:bg-foreground/5 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-border focus-visible:ring-offset-0 disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
|
|
102
165
|
// WealthX: removed rounded-xs (sharp), replaced opacity fade with hover:bg-foreground/5,
|
|
103
|
-
// focus ring uses border color (subtle, matches Figma DialogClose focus state)
|
|
166
|
+
// focus ring uses border color (subtle, matches Figma DialogClose focus state).
|
|
167
|
+
// size-7 = 28px hit area (icon is size-4=16px, centered via inline-flex).
|
|
104
168
|
data-slot="dialog-close"
|
|
105
169
|
>
|
|
106
170
|
<XIcon />
|
|
@@ -152,6 +216,8 @@ function DialogFooter({
|
|
|
152
216
|
{showCloseButton ? (
|
|
153
217
|
<DialogPrimitive.Close
|
|
154
218
|
className={cn(buttonVariants({ variant: "outline" }))}
|
|
219
|
+
// type="button" prevents accidental form submission inside Dialog forms
|
|
220
|
+
type="button"
|
|
155
221
|
>
|
|
156
222
|
Close
|
|
157
223
|
</DialogPrimitive.Close>
|
|
@@ -30,7 +30,14 @@ import {
|
|
|
30
30
|
type ChartGranularity,
|
|
31
31
|
} from "./chart-shared";
|
|
32
32
|
|
|
33
|
-
ChartJS.register(
|
|
33
|
+
ChartJS.register(
|
|
34
|
+
CategoryScale,
|
|
35
|
+
LinearScale,
|
|
36
|
+
BarController,
|
|
37
|
+
BarElement,
|
|
38
|
+
Tooltip,
|
|
39
|
+
Legend,
|
|
40
|
+
);
|
|
34
41
|
|
|
35
42
|
// ---------------------------------------------------------------------------
|
|
36
43
|
// Types
|
|
@@ -234,7 +241,9 @@ export function ExpenseBarChart({
|
|
|
234
241
|
style={{ maxWidth: width, fontFamily }}
|
|
235
242
|
>
|
|
236
243
|
<CardHeader className="px-3 sm:px-6">
|
|
237
|
-
<CardTitle className="text-
|
|
244
|
+
<CardTitle className="text-xs font-semibold uppercase tracking-wide">
|
|
245
|
+
{title}
|
|
246
|
+
</CardTitle>
|
|
238
247
|
<CardAction>
|
|
239
248
|
<div className="flex gap-0.5 sm:gap-1">
|
|
240
249
|
{periods.map((p) => (
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
} from "lucide-react";
|
|
21
21
|
import type { LucideIcon } from "lucide-react";
|
|
22
22
|
import { cn } from "@/lib/utils";
|
|
23
|
+
import { formatDateShort } from "@/lib/format-date";
|
|
23
24
|
import { Badge } from "./badge";
|
|
24
25
|
import { RadioGroup, RadioGroupItem } from "./radio-group";
|
|
25
26
|
import {
|
|
@@ -30,6 +31,7 @@ import {
|
|
|
30
31
|
FinancialSubtotalBlock,
|
|
31
32
|
FinancialSubtotalFrame,
|
|
32
33
|
} from "./financial-primitives";
|
|
34
|
+
import { Button } from "./button";
|
|
33
35
|
|
|
34
36
|
/**
|
|
35
37
|
* Financial card molecules — WealthX DS (Level 3)
|
|
@@ -122,11 +124,12 @@ export function PropertyCard({
|
|
|
122
124
|
>
|
|
123
125
|
{/* Header row */}
|
|
124
126
|
{isLinkedToBank ? (
|
|
125
|
-
<
|
|
127
|
+
<Button
|
|
126
128
|
type="button"
|
|
129
|
+
variant="ghost"
|
|
127
130
|
aria-expanded={expanded}
|
|
128
131
|
onClick={() => setExpanded((prev) => !prev)}
|
|
129
|
-
className="
|
|
132
|
+
className="h-auto w-full justify-start gap-1.5 px-5 py-3 text-left"
|
|
130
133
|
>
|
|
131
134
|
<span className="text-label-medium text-foreground">{address}</span>
|
|
132
135
|
{type && <Badge variant="outline">{type}</Badge>}
|
|
@@ -137,7 +140,7 @@ export function PropertyCard({
|
|
|
137
140
|
expanded && "rotate-180",
|
|
138
141
|
)}
|
|
139
142
|
/>
|
|
140
|
-
</
|
|
143
|
+
</Button>
|
|
141
144
|
) : (
|
|
142
145
|
<div className="flex items-center gap-1.5 px-5 py-3">
|
|
143
146
|
<span className="text-label-medium text-foreground">{address}</span>
|
|
@@ -615,9 +618,17 @@ export interface AboutCardProps {
|
|
|
615
618
|
lastName?: string;
|
|
616
619
|
phone?: string;
|
|
617
620
|
email?: string;
|
|
621
|
+
dob?: string;
|
|
618
622
|
gender?: string;
|
|
619
623
|
maritalStatus?: string;
|
|
624
|
+
numDependants?: string;
|
|
620
625
|
citizenStatus?: string;
|
|
626
|
+
residentialAddress?: string;
|
|
627
|
+
residentialStatus?: string;
|
|
628
|
+
timeAtAddressYears?: string;
|
|
629
|
+
timeAtAddressMonths?: string;
|
|
630
|
+
driversLicence?: string;
|
|
631
|
+
passport?: string;
|
|
621
632
|
propertyInTrust?: string;
|
|
622
633
|
companyOwnership?: string;
|
|
623
634
|
}
|
|
@@ -632,19 +643,38 @@ export function AboutCard({
|
|
|
632
643
|
lastName,
|
|
633
644
|
phone,
|
|
634
645
|
email,
|
|
646
|
+
dob,
|
|
635
647
|
gender,
|
|
636
648
|
maritalStatus,
|
|
649
|
+
numDependants,
|
|
637
650
|
citizenStatus,
|
|
651
|
+
residentialAddress,
|
|
652
|
+
residentialStatus,
|
|
653
|
+
timeAtAddressYears,
|
|
654
|
+
timeAtAddressMonths,
|
|
655
|
+
driversLicence,
|
|
656
|
+
passport,
|
|
638
657
|
propertyInTrust,
|
|
639
658
|
companyOwnership,
|
|
640
659
|
}: AboutCardProps) {
|
|
641
660
|
const fullName =
|
|
642
661
|
[title, firstName, lastName].filter(Boolean).join(" ") || "—";
|
|
643
662
|
|
|
663
|
+
const timeAtAddress =
|
|
664
|
+
timeAtAddressYears || timeAtAddressMonths
|
|
665
|
+
? [
|
|
666
|
+
timeAtAddressYears && `${timeAtAddressYears}yr`,
|
|
667
|
+
timeAtAddressMonths && `${timeAtAddressMonths}mo`,
|
|
668
|
+
]
|
|
669
|
+
.filter(Boolean)
|
|
670
|
+
.join(" ")
|
|
671
|
+
: undefined;
|
|
672
|
+
|
|
644
673
|
return (
|
|
645
674
|
<div className="border border-border overflow-hidden">
|
|
646
675
|
<div className="grid grid-cols-2 gap-x-8 gap-y-4 px-5 py-4">
|
|
647
676
|
<FinancialDetailField label="Full Name" value={fullName} />
|
|
677
|
+
<FinancialDetailField label="Date of Birth" value={dob || "—"} />
|
|
648
678
|
<FinancialDetailField label="Gender" value={gender || "—"} />
|
|
649
679
|
<FinancialDetailField label="Phone" value={phone || "—"} />
|
|
650
680
|
<FinancialDetailField label="Email" value={email || "—"} />
|
|
@@ -652,10 +682,30 @@ export function AboutCard({
|
|
|
652
682
|
label="Marital Status"
|
|
653
683
|
value={maritalStatus || "—"}
|
|
654
684
|
/>
|
|
685
|
+
<FinancialDetailField
|
|
686
|
+
label="No. of Dependants"
|
|
687
|
+
value={numDependants ?? "—"}
|
|
688
|
+
/>
|
|
655
689
|
<FinancialDetailField
|
|
656
690
|
label="Citizenship"
|
|
657
691
|
value={citizenStatus || "—"}
|
|
658
692
|
/>
|
|
693
|
+
<FinancialDetailField
|
|
694
|
+
label="Residential Address"
|
|
695
|
+
value={residentialAddress || "—"}
|
|
696
|
+
/>
|
|
697
|
+
<FinancialDetailField
|
|
698
|
+
label="Residential Status"
|
|
699
|
+
value={residentialStatus || "—"}
|
|
700
|
+
/>
|
|
701
|
+
{timeAtAddress && (
|
|
702
|
+
<FinancialDetailField label="Time at Address" value={timeAtAddress} />
|
|
703
|
+
)}
|
|
704
|
+
<FinancialDetailField
|
|
705
|
+
label="Driver's Licence"
|
|
706
|
+
value={driversLicence || "—"}
|
|
707
|
+
/>
|
|
708
|
+
<FinancialDetailField label="Passport" value={passport || "—"} />
|
|
659
709
|
<FinancialDetailField
|
|
660
710
|
label="Property in Trust"
|
|
661
711
|
value={propertyInTrust || "—"}
|
|
@@ -677,6 +727,11 @@ export interface IncomeCardItem {
|
|
|
677
727
|
incomeType: string;
|
|
678
728
|
jobTitle?: string;
|
|
679
729
|
companyName?: string;
|
|
730
|
+
companyAddress?: string;
|
|
731
|
+
startDate?: string;
|
|
732
|
+
stillInPosition?: boolean;
|
|
733
|
+
endDate?: string;
|
|
734
|
+
companyType?: string;
|
|
680
735
|
/** Pre-formatted amount + frequency e.g. "$9,500 / Monthly" */
|
|
681
736
|
amountLabel: string;
|
|
682
737
|
}
|
|
@@ -687,6 +742,7 @@ export interface IncomeCardProps {
|
|
|
687
742
|
totalMonthly?: string;
|
|
688
743
|
}
|
|
689
744
|
|
|
745
|
+
|
|
690
746
|
/**
|
|
691
747
|
* Display card for applicant income items.
|
|
692
748
|
* Each income source renders as a bordered row with type, company, and amount.
|
|
@@ -706,16 +762,49 @@ export function IncomeCard({ items, totalMonthly }: IncomeCardProps) {
|
|
|
706
762
|
<div
|
|
707
763
|
key={i}
|
|
708
764
|
className={cn(
|
|
709
|
-
"
|
|
765
|
+
"flex flex-col gap-3 px-5 py-[15px]",
|
|
710
766
|
i < items.length - 1 && "border-b border-border",
|
|
711
767
|
)}
|
|
712
768
|
>
|
|
713
|
-
|
|
714
|
-
<
|
|
715
|
-
label="
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
769
|
+
{/* Primary row: Type | Job Title | Amount */}
|
|
770
|
+
<div className="grid grid-cols-3 gap-x-6">
|
|
771
|
+
<FinancialDetailField label="Type" value={item.incomeType || "—"} />
|
|
772
|
+
<FinancialDetailField
|
|
773
|
+
label="Job Title"
|
|
774
|
+
value={item.jobTitle || "—"}
|
|
775
|
+
/>
|
|
776
|
+
<FinancialDetailField label="Amount" value={item.amountLabel} />
|
|
777
|
+
</div>
|
|
778
|
+
{/* Secondary row: Company | Start Date | Status */}
|
|
779
|
+
<div className="grid grid-cols-3 gap-x-6">
|
|
780
|
+
<FinancialDetailField
|
|
781
|
+
label="Company"
|
|
782
|
+
value={item.companyName || "—"}
|
|
783
|
+
/>
|
|
784
|
+
<FinancialDetailField
|
|
785
|
+
label="Start Date"
|
|
786
|
+
value={formatDateShort(item.startDate)}
|
|
787
|
+
/>
|
|
788
|
+
<FinancialDetailField
|
|
789
|
+
label="Status"
|
|
790
|
+
value={
|
|
791
|
+
item.stillInPosition === undefined
|
|
792
|
+
? "—"
|
|
793
|
+
: item.stillInPosition
|
|
794
|
+
? "Still in position"
|
|
795
|
+
: item.endDate
|
|
796
|
+
? `Ended ${formatDateShort(item.endDate)}`
|
|
797
|
+
: "No longer in position"
|
|
798
|
+
}
|
|
799
|
+
/>
|
|
800
|
+
</div>
|
|
801
|
+
{/* Company address — full width if present */}
|
|
802
|
+
{item.companyAddress && (
|
|
803
|
+
<FinancialDetailField
|
|
804
|
+
label="Company Address"
|
|
805
|
+
value={item.companyAddress}
|
|
806
|
+
/>
|
|
807
|
+
)}
|
|
719
808
|
</div>
|
|
720
809
|
))}
|
|
721
810
|
{totalMonthly && (
|
|
@@ -30,7 +30,14 @@ import {
|
|
|
30
30
|
type ChartGranularity,
|
|
31
31
|
} from "./chart-shared";
|
|
32
32
|
|
|
33
|
-
ChartJS.register(
|
|
33
|
+
ChartJS.register(
|
|
34
|
+
CategoryScale,
|
|
35
|
+
LinearScale,
|
|
36
|
+
BarController,
|
|
37
|
+
BarElement,
|
|
38
|
+
Tooltip,
|
|
39
|
+
Legend,
|
|
40
|
+
);
|
|
34
41
|
|
|
35
42
|
// ---------------------------------------------------------------------------
|
|
36
43
|
// Types
|
|
@@ -235,7 +242,9 @@ export function IncomeBarChart({
|
|
|
235
242
|
style={{ maxWidth: width, fontFamily }}
|
|
236
243
|
>
|
|
237
244
|
<CardHeader className="px-3 sm:px-6">
|
|
238
|
-
<CardTitle className="text-
|
|
245
|
+
<CardTitle className="text-xs font-semibold uppercase tracking-wide">
|
|
246
|
+
{title}
|
|
247
|
+
</CardTitle>
|
|
239
248
|
<CardAction>
|
|
240
249
|
<div className="flex gap-0.5 sm:gap-1">
|
|
241
250
|
{periods.map((p) => (
|
|
@@ -10,6 +10,8 @@ import {
|
|
|
10
10
|
Bot,
|
|
11
11
|
} from "lucide-react";
|
|
12
12
|
import { cn } from "@/lib/utils";
|
|
13
|
+
import { formatCurrency } from "@/lib/format-currency";
|
|
14
|
+
import { formatDateShort, formatDateDayMonth } from "@/lib/format-date";
|
|
13
15
|
import { Badge } from "@/components/ui/badge";
|
|
14
16
|
import { Button, buttonVariants } from "@/components/ui/button";
|
|
15
17
|
import { Separator } from "@/components/ui/separator";
|
|
@@ -149,36 +151,6 @@ function resolvePriority(
|
|
|
149
151
|
return priority;
|
|
150
152
|
}
|
|
151
153
|
|
|
152
|
-
function formatAmount(amount: number): string {
|
|
153
|
-
return new Intl.NumberFormat("en-AU", {
|
|
154
|
-
style: "currency",
|
|
155
|
-
currency: "AUD",
|
|
156
|
-
maximumFractionDigits: 0,
|
|
157
|
-
}).format(amount);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
function formatDate(iso: string): string {
|
|
161
|
-
try {
|
|
162
|
-
return new Date(iso).toLocaleDateString("en-AU", {
|
|
163
|
-
day: "2-digit",
|
|
164
|
-
month: "short",
|
|
165
|
-
year: "numeric",
|
|
166
|
-
});
|
|
167
|
-
} catch {
|
|
168
|
-
return iso;
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
function formatHoldDate(iso: string): string {
|
|
173
|
-
try {
|
|
174
|
-
return new Date(iso).toLocaleDateString("en-AU", {
|
|
175
|
-
day: "2-digit",
|
|
176
|
-
month: "short",
|
|
177
|
-
});
|
|
178
|
-
} catch {
|
|
179
|
-
return iso;
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
154
|
|
|
183
155
|
function formatLoanType(type: string): string {
|
|
184
156
|
return type
|
|
@@ -249,7 +221,7 @@ export function OpportunityCard({
|
|
|
249
221
|
style={{ color: "var(--color-warning-text)" }}
|
|
250
222
|
>
|
|
251
223
|
<Clock className="size-3 shrink-0" />
|
|
252
|
-
On hold until {
|
|
224
|
+
On hold until {formatDateDayMonth(onHoldTo)}
|
|
253
225
|
</div>
|
|
254
226
|
)}
|
|
255
227
|
|
|
@@ -272,24 +244,23 @@ export function OpportunityCard({
|
|
|
272
244
|
</Badge>
|
|
273
245
|
)}
|
|
274
246
|
<span className="text-base font-bold tabular-nums text-foreground">
|
|
275
|
-
{
|
|
247
|
+
{formatCurrency(amount)}
|
|
276
248
|
</span>
|
|
277
249
|
</div>
|
|
278
250
|
|
|
279
251
|
<div className="flex items-center gap-1 -mr-1 -mt-1">
|
|
280
252
|
{onLaunchAssistant && (
|
|
281
|
-
<
|
|
253
|
+
<Button
|
|
282
254
|
type="button"
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
)}
|
|
255
|
+
variant="ghost"
|
|
256
|
+
size="icon"
|
|
257
|
+
className="size-7 shrink-0"
|
|
287
258
|
onClick={onLaunchAssistant}
|
|
288
259
|
aria-label="Launch AI Assistant"
|
|
289
260
|
title="Launch AI Assistant"
|
|
290
261
|
>
|
|
291
262
|
<Bot className="size-4" />
|
|
292
|
-
</
|
|
263
|
+
</Button>
|
|
293
264
|
)}
|
|
294
265
|
{hasMenu && (
|
|
295
266
|
<DropdownMenu>
|
|
@@ -372,7 +343,7 @@ export function OpportunityCard({
|
|
|
372
343
|
<div className="flex items-center justify-between">
|
|
373
344
|
<span className="flex items-center gap-1.5 text-xs text-muted-foreground">
|
|
374
345
|
<Calendar className="size-3 shrink-0" aria-hidden="true" />
|
|
375
|
-
{
|
|
346
|
+
{formatDateShort(date)}
|
|
376
347
|
</span>
|
|
377
348
|
|
|
378
349
|
<span className="flex items-center gap-1.5">
|