@wealthx/shadcn 1.5.25 → 1.5.27
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 +165 -165
- package/CHANGELOG.md +12 -0
- package/dist/{chunk-7JVKSZ4O.mjs → chunk-2CHH5QOA.mjs} +1 -1
- package/dist/{chunk-5ST6BK7R.mjs → chunk-36IN7YRM.mjs} +1 -1
- package/dist/{chunk-RGHKARAK.mjs → chunk-7PTRHNUV.mjs} +1 -1
- package/dist/{chunk-QM7LU2BR.mjs → chunk-AAZSLTER.mjs} +7 -7
- package/dist/{chunk-OFQFD2E2.mjs → chunk-C35JMOII.mjs} +1 -1
- package/dist/{chunk-4FJC64FV.mjs → chunk-CE2WONIY.mjs} +15 -14
- package/dist/{chunk-YV7XF32X.mjs → chunk-DSVKEVX6.mjs} +1 -1
- package/dist/{chunk-EY5YPFKX.mjs → chunk-EVUY67CY.mjs} +4 -4
- package/dist/{chunk-5G2M45CA.mjs → chunk-FYZBGWYR.mjs} +1 -1
- package/dist/{chunk-RVDBYV2B.mjs → chunk-HONTZFLO.mjs} +1 -1
- package/dist/chunk-HSL23TOM.mjs +443 -0
- package/dist/{chunk-VNB5E7SI.mjs → chunk-HSXMTFIM.mjs} +4 -4
- package/dist/{chunk-ABVCQWDY.mjs → chunk-KGVVK6OS.mjs} +5 -5
- package/dist/{chunk-IG7DEIWU.mjs → chunk-KI57CBJR.mjs} +7 -7
- package/dist/{chunk-IT3QJF3D.mjs → chunk-LBXIYS34.mjs} +4 -4
- package/dist/{chunk-K35TFQUB.mjs → chunk-LSSIWLYU.mjs} +1 -1
- package/dist/{chunk-UMR3HVZF.mjs → chunk-M32QNCD3.mjs} +7 -7
- package/dist/{chunk-ECC2LLZM.mjs → chunk-MD66TGX7.mjs} +7 -7
- package/dist/{chunk-ZSMQZ3VN.mjs → chunk-NGKTJRFN.mjs} +7 -7
- package/dist/{chunk-2PWTXE66.mjs → chunk-OG2VM34K.mjs} +1 -1
- package/dist/{chunk-SQ54W3JH.mjs → chunk-OKIWXOJL.mjs} +4 -4
- package/dist/{chunk-WIDZVCH3.mjs → chunk-S7SBLNX4.mjs} +7 -7
- package/dist/{chunk-PX2B3Q3A.mjs → chunk-SYJ6LVJ6.mjs} +1 -1
- package/dist/{chunk-OIETBBXQ.mjs → chunk-T5FRVEJQ.mjs} +1 -1
- package/dist/{chunk-Z5QI7CW2.mjs → chunk-T5HU4S4X.mjs} +1 -1
- package/dist/{chunk-KENLXFJ7.mjs → chunk-ULQ53FRJ.mjs} +4 -4
- package/dist/{chunk-NTIFG5A7.mjs → chunk-USIRKDYQ.mjs} +4 -4
- package/dist/{chunk-QJ3RSZF4.mjs → chunk-VVURVETY.mjs} +4 -4
- package/dist/components/ui/add-column-modal.js +1 -1
- package/dist/components/ui/add-column-modal.mjs +2 -2
- package/dist/components/ui/add-lead-modal.js +1 -1
- package/dist/components/ui/add-lead-modal.mjs +2 -2
- package/dist/components/ui/advisor-card.mjs +2 -2
- package/dist/components/ui/{ai-builder.js → ai-builder/index.js} +288 -187
- package/dist/components/ui/ai-builder/index.mjs +26 -0
- package/dist/components/ui/ai-conversations/index.js +4 -3
- package/dist/components/ui/ai-conversations/index.mjs +3 -3
- package/dist/components/ui/appointment-action-dialogs.js +1 -1
- package/dist/components/ui/appointment-action-dialogs.mjs +2 -2
- package/dist/components/ui/appointment-availability-settings.js +1 -1
- package/dist/components/ui/appointment-availability-settings.mjs +3 -3
- package/dist/components/ui/appointment-book-dialog.js +1 -1
- package/dist/components/ui/appointment-book-dialog.mjs +3 -3
- package/dist/components/ui/appointment-calendar-view.mjs +2 -2
- package/dist/components/ui/appointment-detail-sheet.js +1 -1
- package/dist/components/ui/appointment-detail-sheet.mjs +4 -4
- package/dist/components/ui/appointment-upcoming-card.js +1 -1
- package/dist/components/ui/appointment-upcoming-card.mjs +3 -3
- package/dist/components/ui/bank-statement-generate-dialog.js +1 -1
- package/dist/components/ui/bank-statement-generate-dialog.mjs +2 -2
- package/dist/components/ui/bank-statement-pdf-viewer.mjs +2 -2
- package/dist/components/ui/cash-balance-line-chart.mjs +2 -2
- package/dist/components/ui/category-edit-dialog.js +1 -1
- package/dist/components/ui/category-edit-dialog.mjs +2 -2
- package/dist/components/ui/chat-widget.mjs +1 -1
- package/dist/components/ui/contact-alert-dialog/index.js +1 -1
- package/dist/components/ui/contact-alert-dialog/index.mjs +2 -2
- package/dist/components/ui/create-contact-modal.js +1 -1
- package/dist/components/ui/create-contact-modal.mjs +2 -2
- package/dist/components/ui/csv-import-modal.js +1 -1
- package/dist/components/ui/csv-import-modal.mjs +2 -2
- package/dist/components/ui/dashboard-expense-categories.mjs +3 -3
- package/dist/components/ui/dashboard-transactions-table.js +1 -1
- package/dist/components/ui/dashboard-transactions-table.mjs +5 -5
- package/dist/components/ui/dialog.js +1 -1
- package/dist/components/ui/dialog.mjs +1 -1
- package/dist/components/ui/document-checklist-template.mjs +2 -2
- package/dist/components/ui/expense-detail-item.mjs +2 -2
- package/dist/components/ui/expense-work-details.mjs +8 -8
- package/dist/components/ui/file-preview-dialog.js +1 -1
- package/dist/components/ui/file-preview-dialog.mjs +2 -2
- package/dist/components/ui/income-sources-card.mjs +3 -3
- package/dist/components/ui/income-work-details.mjs +2 -2
- package/dist/components/ui/kanban-column.mjs +4 -4
- package/dist/components/ui/opportunity-card.mjs +3 -3
- package/dist/components/ui/opportunity-edit-modals.js +1 -1
- package/dist/components/ui/opportunity-edit-modals.mjs +2 -2
- package/dist/components/ui/opportunity-summary-tab.js +1 -1
- package/dist/components/ui/opportunity-summary-tab.mjs +4 -4
- package/dist/components/ui/pipeline-board.mjs +5 -5
- package/dist/components/ui/pipeline-dialogs.js +1 -1
- package/dist/components/ui/pipeline-dialogs.mjs +2 -2
- package/dist/components/ui/pipeline-primitives.mjs +2 -2
- package/dist/components/ui/property-report-dialog.js +1 -1
- package/dist/components/ui/property-report-dialog.mjs +2 -2
- package/dist/components/ui/resource-center/index.js +1 -1
- package/dist/components/ui/resource-center/index.mjs +2 -2
- package/dist/components/ui/review-alerts-dialog.js +1 -1
- package/dist/components/ui/review-alerts-dialog.mjs +2 -2
- package/dist/components/ui/savings-goal-modal.js +1 -1
- package/dist/components/ui/savings-goal-modal.mjs +1 -1
- package/dist/components/ui/share-details-dialog.js +1 -1
- package/dist/components/ui/share-details-dialog.mjs +2 -2
- package/dist/components/ui/stage-timeline.mjs +3 -3
- package/dist/components/ui/transactions-income-expense-bar-chart.mjs +2 -2
- package/dist/index.js +4302 -4241
- package/dist/index.mjs +114 -114
- package/package.json +4 -4
- package/src/components/index.tsx +1 -0
- package/src/components/ui/ai-builder/agent-card.tsx +181 -0
- package/src/components/ui/ai-builder/index.tsx +21 -0
- package/src/components/ui/ai-builder/integration-card.tsx +144 -0
- package/src/components/ui/ai-builder/service-config-modal.tsx +283 -0
- package/src/components/ui/ai-builder/types.ts +34 -0
- package/src/components/ui/ai-conversations/thread.tsx +14 -9
- package/src/components/ui/dialog.tsx +1 -1
- package/tsup.config.ts +1 -1
- package/dist/chunk-INGYBZGU.mjs +0 -394
- package/dist/components/ui/ai-builder.mjs +0 -25
- package/src/components/ui/ai-builder.tsx +0 -558
- package/dist/{chunk-G2W754UJ.mjs → chunk-6UKOJLXO.mjs} +3 -3
- package/dist/{chunk-S6AYZJYO.mjs → chunk-CZ6IEOM5.mjs} +3 -3
- package/dist/{chunk-K2KX3NX7.mjs → chunk-I433SC7S.mjs} +3 -3
- package/dist/{chunk-57QES5LX.mjs → chunk-JHS2T6JZ.mjs} +3 -3
- package/dist/{chunk-EXI64H46.mjs → chunk-L6LE4OIM.mjs} +3 -3
- package/dist/{chunk-DCKT635J.mjs → chunk-LHQACMZY.mjs} +3 -3
- package/dist/{chunk-V23CBULF.mjs → chunk-SZLAPJKD.mjs} +3 -3
- package/dist/{chunk-KGBLORCQ.mjs → chunk-ZA37ZWZW.mjs} +4 -4
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import { Check, CheckCircle2, Copy, Settings, User } from "lucide-react";
|
|
3
|
+
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
|
|
4
|
+
import { Badge } from "@/components/ui/badge";
|
|
5
|
+
import { Button } from "@/components/ui/button";
|
|
6
|
+
import { Card } from "@/components/ui/card";
|
|
7
|
+
import { cn } from "@/lib/utils";
|
|
8
|
+
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// IntegrationServiceCard
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
|
|
13
|
+
export type IntegrationServiceCardProps = {
|
|
14
|
+
title: string;
|
|
15
|
+
imageUrl?: string;
|
|
16
|
+
iconNode?: React.ReactNode;
|
|
17
|
+
description: string;
|
|
18
|
+
isConnected: boolean;
|
|
19
|
+
onCardClick: () => void;
|
|
20
|
+
onSettingsClick: () => void;
|
|
21
|
+
className?: string;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export function IntegrationServiceCard({
|
|
25
|
+
title,
|
|
26
|
+
imageUrl,
|
|
27
|
+
iconNode,
|
|
28
|
+
description,
|
|
29
|
+
isConnected,
|
|
30
|
+
onCardClick,
|
|
31
|
+
onSettingsClick,
|
|
32
|
+
className,
|
|
33
|
+
}: IntegrationServiceCardProps) {
|
|
34
|
+
return (
|
|
35
|
+
<Card
|
|
36
|
+
className={cn(
|
|
37
|
+
"flex flex-col gap-3 p-4",
|
|
38
|
+
!isConnected && "cursor-pointer transition-colors hover:bg-accent/50",
|
|
39
|
+
className,
|
|
40
|
+
)}
|
|
41
|
+
onClick={!isConnected ? onCardClick : undefined}
|
|
42
|
+
>
|
|
43
|
+
<div className="flex items-start gap-3">
|
|
44
|
+
<Avatar className="h-10 w-10 shrink-0">
|
|
45
|
+
{imageUrl && <AvatarImage src={imageUrl} alt={title} />}
|
|
46
|
+
<AvatarFallback className={iconNode ? "bg-transparent p-0.5" : ""}>
|
|
47
|
+
{iconNode ?? <User className="h-5 w-5" />}
|
|
48
|
+
</AvatarFallback>
|
|
49
|
+
</Avatar>
|
|
50
|
+
|
|
51
|
+
<div className="flex min-w-0 flex-1 flex-col gap-0.5">
|
|
52
|
+
<div className="flex items-center gap-2">
|
|
53
|
+
<span className="text-base font-semibold">{title}</span>
|
|
54
|
+
{isConnected && (
|
|
55
|
+
<Badge variant="success" className="gap-1 text-xs">
|
|
56
|
+
<CheckCircle2 className="h-3 w-3" />
|
|
57
|
+
Connected
|
|
58
|
+
</Badge>
|
|
59
|
+
)}
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
|
|
63
|
+
{isConnected && (
|
|
64
|
+
<Button
|
|
65
|
+
variant="ghost"
|
|
66
|
+
size="icon"
|
|
67
|
+
className="h-7 w-7 shrink-0"
|
|
68
|
+
onClick={(e) => {
|
|
69
|
+
e.stopPropagation();
|
|
70
|
+
onSettingsClick();
|
|
71
|
+
}}
|
|
72
|
+
aria-label={`Settings for ${title}`}
|
|
73
|
+
>
|
|
74
|
+
<Settings className="h-4 w-4" />
|
|
75
|
+
</Button>
|
|
76
|
+
)}
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
<p className="text-sm leading-relaxed text-muted-foreground">
|
|
80
|
+
{description}
|
|
81
|
+
</p>
|
|
82
|
+
</Card>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// ---------------------------------------------------------------------------
|
|
87
|
+
// IntegrationInstructionCard
|
|
88
|
+
// ---------------------------------------------------------------------------
|
|
89
|
+
|
|
90
|
+
export type IntegrationInstructionCardProps = {
|
|
91
|
+
title: string;
|
|
92
|
+
codeBlock: string;
|
|
93
|
+
onCopy?: () => void;
|
|
94
|
+
className?: string;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export function IntegrationInstructionCard({
|
|
98
|
+
title,
|
|
99
|
+
codeBlock,
|
|
100
|
+
onCopy,
|
|
101
|
+
className,
|
|
102
|
+
}: IntegrationInstructionCardProps) {
|
|
103
|
+
const [copied, setCopied] = useState(false);
|
|
104
|
+
|
|
105
|
+
const handleCopy = async () => {
|
|
106
|
+
try {
|
|
107
|
+
await navigator.clipboard.writeText(codeBlock);
|
|
108
|
+
setCopied(true);
|
|
109
|
+
onCopy?.();
|
|
110
|
+
setTimeout(() => setCopied(false), 2000);
|
|
111
|
+
} catch {
|
|
112
|
+
// clipboard unavailable (non-HTTPS or permissions denied)
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
return (
|
|
117
|
+
<Card className={cn("flex flex-col gap-3 p-4", className)}>
|
|
118
|
+
<div className="flex items-center justify-between gap-2">
|
|
119
|
+
<h3 className="text-sm font-semibold">{title}</h3>
|
|
120
|
+
<Button
|
|
121
|
+
variant="outline"
|
|
122
|
+
size="sm"
|
|
123
|
+
className="h-7 gap-1.5 text-xs"
|
|
124
|
+
onClick={handleCopy}
|
|
125
|
+
>
|
|
126
|
+
{copied ? (
|
|
127
|
+
<>
|
|
128
|
+
<Check className="h-3 w-3" />
|
|
129
|
+
Copied
|
|
130
|
+
</>
|
|
131
|
+
) : (
|
|
132
|
+
<>
|
|
133
|
+
<Copy className="h-3 w-3" />
|
|
134
|
+
Copy
|
|
135
|
+
</>
|
|
136
|
+
)}
|
|
137
|
+
</Button>
|
|
138
|
+
</div>
|
|
139
|
+
<pre className="bg-muted overflow-x-auto p-3 text-xs leading-relaxed">
|
|
140
|
+
<code>{codeBlock}</code>
|
|
141
|
+
</pre>
|
|
142
|
+
</Card>
|
|
143
|
+
);
|
|
144
|
+
}
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Check, CheckCircle2, Clock, Mail, Shield, User } from "lucide-react";
|
|
3
|
+
import { Button } from "@/components/ui/button";
|
|
4
|
+
import { Card, CardContent } from "@/components/ui/card";
|
|
5
|
+
import { Checkbox } from "@/components/ui/checkbox";
|
|
6
|
+
import {
|
|
7
|
+
Dialog,
|
|
8
|
+
DialogContent,
|
|
9
|
+
DialogDescription,
|
|
10
|
+
DialogFooter,
|
|
11
|
+
DialogHeader,
|
|
12
|
+
DialogTitle,
|
|
13
|
+
} from "@/components/ui/dialog";
|
|
14
|
+
import { Switch } from "@/components/ui/switch";
|
|
15
|
+
import type { AiBuilderServiceData } from "./types";
|
|
16
|
+
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
// ServiceConfigurationModal
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
|
|
21
|
+
export type ServiceConfigurationModalProps = {
|
|
22
|
+
open: boolean;
|
|
23
|
+
onOpenChange: (open: boolean) => void;
|
|
24
|
+
serviceTitle: string;
|
|
25
|
+
isConnected: boolean;
|
|
26
|
+
serviceData?: AiBuilderServiceData;
|
|
27
|
+
/** Brand icon node shown in the not-connected centered layout */
|
|
28
|
+
iconNode?: React.ReactNode;
|
|
29
|
+
/** Permissions shown in the not-connected state */
|
|
30
|
+
connectPermissions?: string[];
|
|
31
|
+
/** Subtitle shown below the service name in the not-connected state */
|
|
32
|
+
connectDescription?: string;
|
|
33
|
+
onConnect: () => void;
|
|
34
|
+
onDisconnect: () => void;
|
|
35
|
+
onReconnect: () => void;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export function ServiceConfigurationModal({
|
|
39
|
+
open,
|
|
40
|
+
onOpenChange,
|
|
41
|
+
serviceTitle,
|
|
42
|
+
isConnected,
|
|
43
|
+
serviceData,
|
|
44
|
+
iconNode,
|
|
45
|
+
connectPermissions,
|
|
46
|
+
connectDescription = "Link your account to enable automated workflows with WealthX.",
|
|
47
|
+
onConnect,
|
|
48
|
+
onDisconnect,
|
|
49
|
+
onReconnect,
|
|
50
|
+
}: ServiceConfigurationModalProps) {
|
|
51
|
+
return (
|
|
52
|
+
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
53
|
+
<DialogContent className="max-w-md">
|
|
54
|
+
{isConnected ? (
|
|
55
|
+
<>
|
|
56
|
+
<DialogHeader>
|
|
57
|
+
<DialogTitle>{serviceTitle}</DialogTitle>
|
|
58
|
+
<DialogDescription>
|
|
59
|
+
Manage your integration settings.
|
|
60
|
+
</DialogDescription>
|
|
61
|
+
</DialogHeader>
|
|
62
|
+
|
|
63
|
+
<div className="flex flex-col gap-4 py-2">
|
|
64
|
+
<div className="flex items-center gap-2 px-3 py-2 text-xs font-medium bg-success/10 text-success">
|
|
65
|
+
<CheckCircle2 className="h-3.5 w-3.5 shrink-0" />
|
|
66
|
+
Active — integration is running
|
|
67
|
+
</div>
|
|
68
|
+
|
|
69
|
+
{serviceData && (
|
|
70
|
+
<>
|
|
71
|
+
<div className="flex flex-col gap-2">
|
|
72
|
+
<p className="text-overline text-muted-foreground">
|
|
73
|
+
Account Information
|
|
74
|
+
</p>
|
|
75
|
+
<Card className="py-0">
|
|
76
|
+
<CardContent className="flex flex-col gap-3 p-3">
|
|
77
|
+
<div className="flex items-center gap-2 text-sm">
|
|
78
|
+
<User className="text-muted-foreground h-4 w-4 shrink-0" />
|
|
79
|
+
<span className="text-muted-foreground">
|
|
80
|
+
{serviceData.accountIdentifierLabel}:
|
|
81
|
+
</span>
|
|
82
|
+
<span className="font-medium">
|
|
83
|
+
{serviceData.accountIdentifier}
|
|
84
|
+
</span>
|
|
85
|
+
</div>
|
|
86
|
+
<div className="flex items-center gap-2 text-sm">
|
|
87
|
+
<Clock className="text-muted-foreground h-4 w-4 shrink-0" />
|
|
88
|
+
<span className="text-muted-foreground">
|
|
89
|
+
Connected on:
|
|
90
|
+
</span>
|
|
91
|
+
<span className="font-medium">
|
|
92
|
+
{serviceData.connectedOn}
|
|
93
|
+
</span>
|
|
94
|
+
</div>
|
|
95
|
+
<div className="flex items-center gap-2 text-sm">
|
|
96
|
+
<Clock className="text-muted-foreground h-4 w-4 shrink-0" />
|
|
97
|
+
<span className="text-muted-foreground">
|
|
98
|
+
Last synced:
|
|
99
|
+
</span>
|
|
100
|
+
<span className="font-medium">
|
|
101
|
+
{serviceData.lastSynced}
|
|
102
|
+
</span>
|
|
103
|
+
</div>
|
|
104
|
+
</CardContent>
|
|
105
|
+
</Card>
|
|
106
|
+
</div>
|
|
107
|
+
|
|
108
|
+
<div className="flex flex-col gap-2">
|
|
109
|
+
<p className="text-overline text-muted-foreground">
|
|
110
|
+
Granted Permissions
|
|
111
|
+
</p>
|
|
112
|
+
<Card className="py-0">
|
|
113
|
+
<CardContent className="flex flex-col gap-2 p-3">
|
|
114
|
+
{serviceData.permissions.map((permission) => (
|
|
115
|
+
<div
|
|
116
|
+
key={permission}
|
|
117
|
+
className="flex items-center gap-2 text-sm"
|
|
118
|
+
>
|
|
119
|
+
<Shield className="text-success h-4 w-4 shrink-0" />
|
|
120
|
+
<span>{permission}</span>
|
|
121
|
+
</div>
|
|
122
|
+
))}
|
|
123
|
+
</CardContent>
|
|
124
|
+
</Card>
|
|
125
|
+
</div>
|
|
126
|
+
|
|
127
|
+
<div className="flex flex-col gap-2">
|
|
128
|
+
<p className="text-overline text-muted-foreground">
|
|
129
|
+
Sync Settings
|
|
130
|
+
</p>
|
|
131
|
+
<Card className="py-0">
|
|
132
|
+
<CardContent className="flex items-center justify-between gap-3 p-3">
|
|
133
|
+
<div className="flex flex-col gap-0.5">
|
|
134
|
+
<p className="text-sm font-medium">
|
|
135
|
+
{serviceData.syncLabel}
|
|
136
|
+
</p>
|
|
137
|
+
<p className="text-muted-foreground text-sm">
|
|
138
|
+
{serviceData.syncDescription}
|
|
139
|
+
</p>
|
|
140
|
+
</div>
|
|
141
|
+
<Switch
|
|
142
|
+
checked={serviceData.syncEnabled}
|
|
143
|
+
onCheckedChange={serviceData.onSyncToggle}
|
|
144
|
+
aria-label={serviceData.syncLabel}
|
|
145
|
+
/>
|
|
146
|
+
</CardContent>
|
|
147
|
+
</Card>
|
|
148
|
+
</div>
|
|
149
|
+
|
|
150
|
+
{serviceData.emailCategories && (
|
|
151
|
+
<div className="flex flex-col gap-2">
|
|
152
|
+
<div>
|
|
153
|
+
<p className="text-overline text-muted-foreground">
|
|
154
|
+
Email Filters
|
|
155
|
+
</p>
|
|
156
|
+
<p className="text-muted-foreground text-sm mt-0.5">
|
|
157
|
+
Choose which inbox categories to sync into WealthX.
|
|
158
|
+
</p>
|
|
159
|
+
</div>
|
|
160
|
+
<Card className="py-0">
|
|
161
|
+
<CardContent className="flex flex-col gap-3 p-3">
|
|
162
|
+
{serviceData.emailCategories.available.map(
|
|
163
|
+
(category) => {
|
|
164
|
+
const checked =
|
|
165
|
+
serviceData.emailCategories!.selected.includes(
|
|
166
|
+
category,
|
|
167
|
+
);
|
|
168
|
+
return (
|
|
169
|
+
<div
|
|
170
|
+
key={category}
|
|
171
|
+
className="flex items-center gap-2"
|
|
172
|
+
>
|
|
173
|
+
<Checkbox
|
|
174
|
+
id={`email-cat-${category}`}
|
|
175
|
+
checked={checked}
|
|
176
|
+
onCheckedChange={(v) => {
|
|
177
|
+
const next = v
|
|
178
|
+
? [
|
|
179
|
+
...serviceData.emailCategories!
|
|
180
|
+
.selected,
|
|
181
|
+
category,
|
|
182
|
+
]
|
|
183
|
+
: serviceData.emailCategories!.selected.filter(
|
|
184
|
+
(c) => c !== category,
|
|
185
|
+
);
|
|
186
|
+
serviceData.emailCategories!.onChange(
|
|
187
|
+
next,
|
|
188
|
+
);
|
|
189
|
+
}}
|
|
190
|
+
/>
|
|
191
|
+
<label
|
|
192
|
+
htmlFor={`email-cat-${category}`}
|
|
193
|
+
className="text-sm cursor-pointer select-none"
|
|
194
|
+
>
|
|
195
|
+
{category}
|
|
196
|
+
</label>
|
|
197
|
+
</div>
|
|
198
|
+
);
|
|
199
|
+
},
|
|
200
|
+
)}
|
|
201
|
+
</CardContent>
|
|
202
|
+
</Card>
|
|
203
|
+
</div>
|
|
204
|
+
)}
|
|
205
|
+
</>
|
|
206
|
+
)}
|
|
207
|
+
</div>
|
|
208
|
+
|
|
209
|
+
<DialogFooter>
|
|
210
|
+
<Button
|
|
211
|
+
variant="destructive"
|
|
212
|
+
size="sm"
|
|
213
|
+
onClick={onDisconnect}
|
|
214
|
+
className="mr-auto"
|
|
215
|
+
>
|
|
216
|
+
Disconnect
|
|
217
|
+
</Button>
|
|
218
|
+
<Button
|
|
219
|
+
variant="outline-secondary"
|
|
220
|
+
size="sm"
|
|
221
|
+
onClick={() => onOpenChange(false)}
|
|
222
|
+
>
|
|
223
|
+
Cancel
|
|
224
|
+
</Button>
|
|
225
|
+
<Button size="sm" onClick={onReconnect}>
|
|
226
|
+
Reconnect
|
|
227
|
+
</Button>
|
|
228
|
+
</DialogFooter>
|
|
229
|
+
</>
|
|
230
|
+
) : (
|
|
231
|
+
<>
|
|
232
|
+
<div className="flex flex-col gap-4 py-2">
|
|
233
|
+
<div className="flex items-center gap-3">
|
|
234
|
+
<div className="flex h-10 w-10 shrink-0 items-center justify-center bg-muted">
|
|
235
|
+
{iconNode ?? (
|
|
236
|
+
<Mail className="h-5 w-5 text-muted-foreground" />
|
|
237
|
+
)}
|
|
238
|
+
</div>
|
|
239
|
+
<div className="flex flex-col gap-0.5">
|
|
240
|
+
<p className="text-sm font-semibold">
|
|
241
|
+
Connect {serviceTitle}
|
|
242
|
+
</p>
|
|
243
|
+
<p className="text-muted-foreground text-xs">
|
|
244
|
+
{connectDescription}
|
|
245
|
+
</p>
|
|
246
|
+
</div>
|
|
247
|
+
</div>
|
|
248
|
+
|
|
249
|
+
{connectPermissions && connectPermissions.length > 0 && (
|
|
250
|
+
<div className="flex flex-col gap-2 border border-border px-4 py-3">
|
|
251
|
+
<p className="text-overline text-muted-foreground">
|
|
252
|
+
Permissions requested
|
|
253
|
+
</p>
|
|
254
|
+
{connectPermissions.map((perm) => (
|
|
255
|
+
<div key={perm} className="flex items-center gap-2">
|
|
256
|
+
<Check className="h-3.5 w-3.5 shrink-0 text-success" />
|
|
257
|
+
<span className="text-sm text-muted-foreground">
|
|
258
|
+
{perm}
|
|
259
|
+
</span>
|
|
260
|
+
</div>
|
|
261
|
+
))}
|
|
262
|
+
</div>
|
|
263
|
+
)}
|
|
264
|
+
</div>
|
|
265
|
+
|
|
266
|
+
<DialogFooter>
|
|
267
|
+
<Button
|
|
268
|
+
variant="outline-secondary"
|
|
269
|
+
size="sm"
|
|
270
|
+
onClick={() => onOpenChange(false)}
|
|
271
|
+
>
|
|
272
|
+
Cancel
|
|
273
|
+
</Button>
|
|
274
|
+
<Button size="sm" onClick={onConnect}>
|
|
275
|
+
Connect
|
|
276
|
+
</Button>
|
|
277
|
+
</DialogFooter>
|
|
278
|
+
</>
|
|
279
|
+
)}
|
|
280
|
+
</DialogContent>
|
|
281
|
+
</Dialog>
|
|
282
|
+
);
|
|
283
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export type AiBuilderAgentItem = {
|
|
2
|
+
id: string;
|
|
3
|
+
title: string;
|
|
4
|
+
description: string;
|
|
5
|
+
tags: string[];
|
|
6
|
+
isEnabled: boolean;
|
|
7
|
+
slug?: string;
|
|
8
|
+
infoBadge?: string;
|
|
9
|
+
isComingSoon?: boolean;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export type AiBuilderServiceType = "email" | "app";
|
|
13
|
+
|
|
14
|
+
export type AiBuilderEmailCategories = {
|
|
15
|
+
/** All available categories for this provider. */
|
|
16
|
+
available: string[];
|
|
17
|
+
/** Currently selected categories. */
|
|
18
|
+
selected: string[];
|
|
19
|
+
onChange: (categories: string[]) => void;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type AiBuilderServiceData = {
|
|
23
|
+
accountIdentifier: string;
|
|
24
|
+
accountIdentifierLabel: string;
|
|
25
|
+
connectedOn: string;
|
|
26
|
+
lastSynced: string;
|
|
27
|
+
permissions: string[];
|
|
28
|
+
syncLabel: string;
|
|
29
|
+
syncDescription: string;
|
|
30
|
+
syncEnabled: boolean;
|
|
31
|
+
onSyncToggle: (enabled: boolean) => void;
|
|
32
|
+
/** When set, renders an "Email Filters" section with per-category checkboxes. */
|
|
33
|
+
emailCategories?: AiBuilderEmailCategories;
|
|
34
|
+
};
|
|
@@ -216,6 +216,8 @@ export interface AiConvEmailPayload {
|
|
|
216
216
|
to: string;
|
|
217
217
|
cc: string;
|
|
218
218
|
subject: string;
|
|
219
|
+
/** `true` when composing a reply; `false` when composing a new email. */
|
|
220
|
+
isReply: boolean;
|
|
219
221
|
}
|
|
220
222
|
|
|
221
223
|
export interface ChatComposerProps {
|
|
@@ -497,15 +499,17 @@ export function ChatComposer({
|
|
|
497
499
|
/>
|
|
498
500
|
</ComposerEmailFieldRow>
|
|
499
501
|
)}
|
|
500
|
-
|
|
501
|
-
<
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
502
|
+
{emailMode !== "reply" && (
|
|
503
|
+
<ComposerEmailFieldRow label="Subject">
|
|
504
|
+
<input
|
|
505
|
+
type="text"
|
|
506
|
+
value={emailSubject}
|
|
507
|
+
onChange={(e) => setEmailSubject(e.target.value)}
|
|
508
|
+
placeholder="Email subject"
|
|
509
|
+
className="min-w-0 flex-1 bg-transparent text-base text-foreground outline-none placeholder:text-muted-foreground"
|
|
510
|
+
/>
|
|
511
|
+
</ComposerEmailFieldRow>
|
|
512
|
+
)}
|
|
509
513
|
<EditorContent editor={editor} />
|
|
510
514
|
<div className="flex items-center justify-between border-t border-border px-3 py-2">
|
|
511
515
|
<div className="flex items-center gap-0.5">
|
|
@@ -569,6 +573,7 @@ export function ChatComposer({
|
|
|
569
573
|
to: emailTo,
|
|
570
574
|
cc: emailCc,
|
|
571
575
|
subject: emailSubject,
|
|
576
|
+
isReply: emailMode === "reply",
|
|
572
577
|
});
|
|
573
578
|
editor?.commands.clearContent();
|
|
574
579
|
}}
|
|
@@ -235,7 +235,7 @@ export type DialogTitleProps = React.ComponentProps<
|
|
|
235
235
|
function DialogTitle({ className, ...props }: DialogTitleProps): ReactElement {
|
|
236
236
|
return (
|
|
237
237
|
<DialogPrimitive.Title
|
|
238
|
-
className={cn("text-h5
|
|
238
|
+
className={cn("text-h5", className)}
|
|
239
239
|
data-slot="dialog-title"
|
|
240
240
|
{...props}
|
|
241
241
|
/>
|
package/tsup.config.ts
CHANGED
|
@@ -43,7 +43,7 @@ export default defineConfig((options) => ({
|
|
|
43
43
|
"src/components/ui/drawer.tsx",
|
|
44
44
|
"src/components/ui/sheet.tsx",
|
|
45
45
|
"src/components/ui/accordion.tsx",
|
|
46
|
-
"src/components/ui/ai-builder.tsx",
|
|
46
|
+
"src/components/ui/ai-builder/index.tsx",
|
|
47
47
|
"src/components/ui/alert-dialog.tsx",
|
|
48
48
|
"src/components/ui/chip.tsx",
|
|
49
49
|
"src/components/ui/color-picker.tsx",
|