Skip to content

Commit aeddb53

Browse files
committed
chore(dashboard): update VY and architectural improvements modals
1 parent 03a66c0 commit aeddb53

File tree

4 files changed

+159
-112
lines changed

4 files changed

+159
-112
lines changed

packages/apps/app-dashboard/src/components/user-dashboard/dashboard/PermittedAppsPage.tsx

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import { theme, fonts } from '@/components/user-dashboard/connect/ui/theme';
77
import { Package, ChevronDown, Check, Filter } from 'lucide-react';
88
import { AgentAppPermission } from '@/utils/user-dashboard/getAgentPkps';
99
import { PermittedAppCard } from './ui/PermittedAppCard';
10-
import { VincentYieldPromotionCard } from './ui/VincentYieldPromotionCard';
1110

1211
type FilterState = 'permitted' | 'unpermitted' | 'all';
1312

@@ -18,7 +17,6 @@ type PermittedAppsPageProps = {
1817
filterState: FilterState;
1918
setFilterState: (state: FilterState) => void;
2019
appVersionsMap: Record<string, AppVersion[]>;
21-
hasVincentYieldPKP: boolean;
2220
};
2321

2422
export function PermittedAppsPage({
@@ -28,7 +26,6 @@ export function PermittedAppsPage({
2826
unpermittedPkps,
2927
filterState,
3028
setFilterState,
31-
hasVincentYieldPKP,
3229
}: PermittedAppsPageProps) {
3330
const [showDropdown, setShowDropdown] = useState(false);
3431
const [showContent, setShowContent] = useState(false);
@@ -177,12 +174,7 @@ export function PermittedAppsPage({
177174
)}
178175
</div>
179176
</div>
180-
{apps.length === 0 && !hasVincentYieldPKP && filterState === 'permitted' ? (
181-
<div className="w-full grid grid-cols-1 md:grid-cols-2 lg:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4 gap-6">
182-
{/* Show only Vincent Yield card when no other apps and on permitted filter */}
183-
<VincentYieldPromotionCard index={0} />
184-
</div>
185-
) : apps.length === 0 ? (
177+
{apps.length === 0 ? (
186178
<div className="flex items-center justify-center min-h-[400px] w-full lg:mr-48">
187179
<div className="text-center max-w-md mx-auto px-6">
188180
<div
@@ -213,25 +205,18 @@ export function PermittedAppsPage({
213205
</div>
214206
) : (
215207
<div className="w-full grid grid-cols-1 md:grid-cols-2 lg:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4 gap-6">
216-
{/* Show Vincent Yield promotion card first if not permitted and on permitted filter */}
217-
{!hasVincentYieldPKP && filterState === 'permitted' && (
218-
<VincentYieldPromotionCard index={0} />
219-
)}
220208
{apps.map((app, index) => {
221209
const permittedPermission = permittedPkps.find((p) => p.appId === app.appId);
222210
const unpermittedPermission = unpermittedPkps.find((p) => p.appId === app.appId);
223211
const permission = permittedPermission || unpermittedPermission;
224212
const isUnpermitted = !!unpermittedPermission && !permittedPermission;
225-
// Adjust index for animation delay if Vincent Yield card is shown
226-
const cardIndex =
227-
!hasVincentYieldPKP && filterState === 'permitted' ? index + 1 : index;
228213
return (
229214
<PermittedAppCard
230215
key={app.appId}
231216
app={app}
232217
permission={permission}
233218
isUnpermitted={isUnpermitted}
234-
index={cardIndex}
219+
index={index}
235220
appVersionsMap={appVersionsMap}
236221
/>
237222
);

packages/apps/app-dashboard/src/components/user-dashboard/dashboard/PermittedAppsWrapper.tsx

Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import React, { useMemo, useState } from 'react';
1+
import { useMemo, useState, useEffect } from 'react';
22
import { PermittedAppsPage } from './PermittedAppsPage';
33
import { reactClient as vincentApiClient } from '@lit-protocol/vincent-registry-sdk';
44
import { useReadAuthInfo } from '@/hooks/user-dashboard/useAuthInfo';
55
import { AuthenticationErrorScreen } from '../connect/AuthenticationErrorScreen';
66
import { GeneralErrorScreen } from '@/components/user-dashboard/connect/GeneralErrorScreen';
7+
import { VincentYieldModal } from '../landing/VincentYieldModal';
78
import { ConnectToVincentYieldModal } from '../landing/ConnectToVincentYieldModal';
89
import { env } from '@/config/env';
910
import { useAllAgentApps } from '@/hooks/user-dashboard/useAllAgentApps';
@@ -17,7 +18,8 @@ export function PermittedAppsWrapper() {
1718
const { authInfo, sessionSigs, isProcessing, error } = readAuthInfo;
1819

1920
const userAddress = authInfo?.userPKP?.ethAddress || '';
20-
const [showConnectModal, setShowConnectModal] = useState(false);
21+
const [showVincentYieldModal, setShowVincentYieldModal] = useState(false);
22+
const [hasUserDismissedModal, setHasUserDismissedModal] = useState(false);
2123
const [filterState, setFilterState] = useState<FilterState>('permitted');
2224

2325
// Fetch all agent app permissions
@@ -67,26 +69,26 @@ export function PermittedAppsWrapper() {
6769

6870
const isUserAuthed = authInfo?.userPKP && sessionSigs;
6971

70-
// Find the agent PKP that's permitted for Vincent Yield
71-
const vincentYieldPKP = permittedPkps.find(
72-
(pkp) => pkp.appId === Number(env.VITE_VINCENT_YIELD_APPID),
73-
);
72+
// Check if Vincent Yield app is permitted or unpermitted (i.e., user has any connection to it)
73+
const vincentYieldAppId = Number(env.VITE_VINCENT_YIELD_APPID);
74+
const hasVincentYieldPerms =
75+
permittedPkps.some((p) => p.appId === vincentYieldAppId) ||
76+
unpermittedPkps.some((p) => p.appId === vincentYieldAppId);
7477

75-
// Find PKPs with appId = -1 (unconnected PKPs)
78+
// Find PKPs with appId = -1 (unconnected PKPs - for migration)
7679
const unconnectedPKP = permittedPkps.find((pkp) => pkp.appId === -1);
7780

78-
// Show connect modal for unconnected PKPs (but not when there are no PKPs at all)
79-
React.useEffect(() => {
80-
if (
81-
isUserAuthed &&
82-
!showConnectModal &&
83-
unconnectedPKP &&
84-
!vincentYieldPKP &&
85-
permittedPkps.length > 0
86-
) {
87-
setShowConnectModal(true);
81+
// Show Vincent Yield modal if user is authenticated but doesn't have permissions
82+
useEffect(() => {
83+
if (isUserAuthed && !hasUserDismissedModal) {
84+
if (!hasVincentYieldPerms && !showVincentYieldModal) {
85+
setShowVincentYieldModal(true);
86+
} else if (hasVincentYieldPerms && showVincentYieldModal) {
87+
// Close modal if Vincent Yield perms are now detected
88+
setShowVincentYieldModal(false);
89+
}
8890
}
89-
}, [isUserAuthed, showConnectModal, unconnectedPKP, vincentYieldPKP, permittedPkps.length]);
91+
}, [isUserAuthed, hasVincentYieldPerms, showVincentYieldModal, hasUserDismissedModal]);
9092

9193
// Show loading while auth is processing
9294
if (isProcessing) {
@@ -127,11 +129,23 @@ export function PermittedAppsWrapper() {
127129
filterState={filterState}
128130
setFilterState={setFilterState}
129131
appVersionsMap={appVersionsMap}
130-
hasVincentYieldPKP={!!vincentYieldPKP}
131132
/>
132-
{showConnectModal && unconnectedPKP && (
133-
<ConnectToVincentYieldModal agentPKP={unconnectedPKP.pkp} />
134-
)}
133+
{showVincentYieldModal && unconnectedPKP ? (
134+
<ConnectToVincentYieldModal
135+
agentPKP={unconnectedPKP.pkp}
136+
onClose={() => {
137+
setShowVincentYieldModal(false);
138+
setHasUserDismissedModal(true);
139+
}}
140+
/>
141+
) : showVincentYieldModal ? (
142+
<VincentYieldModal
143+
onClose={() => {
144+
setShowVincentYieldModal(false);
145+
setHasUserDismissedModal(true);
146+
}}
147+
/>
148+
) : null}
135149
</>
136150
);
137151
}

packages/apps/app-dashboard/src/components/user-dashboard/landing/ConnectToVincentYieldModal.tsx

Lines changed: 66 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ import {
77
DialogHeader,
88
DialogTitle,
99
} from '@/components/shared/ui/dialog';
10-
import { Button } from '@/components/shared/ui/button';
11-
import { theme } from '../connect/ui/theme';
12-
import { AlertCircle, ArrowRight } from 'lucide-react';
10+
import { theme, fonts } from '../connect/ui/theme';
11+
import { AlertCircle, ArrowRight, Sparkles } from 'lucide-react';
1312
import { env } from '@/config/env';
1413

1514
interface ConnectToVincentYieldModalProps {
1615
agentPKP: IRelayPKP;
16+
onClose?: () => void;
1717
}
1818

1919
export function ConnectToVincentYieldModal({ agentPKP }: ConnectToVincentYieldModalProps) {
@@ -34,31 +34,60 @@ export function ConnectToVincentYieldModal({ agentPKP }: ConnectToVincentYieldMo
3434
50% { opacity: 0.8; }
3535
}
3636
button[class*="absolute top-4 right-4"] {
37-
opacity: 0.15 !important;
38-
}
39-
button[class*="absolute top-4 right-4"]:hover {
40-
opacity: 0.4 !important;
37+
display: none !important;
4138
}
4239
`}</style>
4340
<DialogContent
44-
className={`w-[calc(100%-1rem)] max-w-md mx-auto ${theme.mainCard} border ${theme.mainCardBorder} rounded-2xl shadow-2xl overflow-hidden p-0 [&>button]:hidden`}
41+
className="w-[calc(100%-1rem)] max-w-md border-2 rounded-2xl shadow-2xl overflow-hidden p-0 backdrop-blur-xl"
42+
style={{
43+
borderColor: theme.brandOrange,
44+
background: `linear-gradient(135deg, ${theme.mainCard} 0%, rgba(224, 90, 26, 0.05) 100%)`,
45+
}}
4546
onPointerDownOutside={(e) => e.preventDefault()}
4647
onEscapeKeyDown={(e) => e.preventDefault()}
4748
>
48-
<DialogHeader className={`px-3 sm:px-6 pt-4 pb-3 border-b ${theme.cardBorder}`}>
49-
<div className="flex items-center justify-center mb-3">
49+
{/* NEW badge */}
50+
<div
51+
className="absolute top-4 right-4 px-2 py-1 rounded-md text-xs font-bold tracking-wide z-10"
52+
style={{
53+
backgroundColor: theme.brandOrange,
54+
color: 'white',
55+
...fonts.heading,
56+
}}
57+
>
58+
REQUIRED
59+
</div>
60+
61+
<DialogHeader className={`px-4 sm:px-6 pt-6 pb-4`}>
62+
{/* Logo and Title */}
63+
<div className="flex items-center gap-3 mb-4">
5064
<div
51-
className={`inline-flex items-center justify-center w-12 h-12 rounded-full bg-orange-100 dark:bg-orange-900/30`}
65+
className="w-16 h-16 rounded-lg flex items-center justify-center flex-shrink-0"
66+
style={{
67+
backgroundColor: theme.brandOrange,
68+
}}
5269
>
53-
<AlertCircle className="w-6 h-6 text-orange-500" />
70+
<Sparkles className="w-8 h-8 text-white" />
71+
</div>
72+
<div className="flex flex-col justify-center min-w-0 flex-1">
73+
<DialogTitle
74+
className={`text-base font-semibold leading-tight ${theme.text}`}
75+
style={fonts.heading}
76+
>
77+
Connect to Vincent Yield
78+
</DialogTitle>
79+
<span className={`text-sm leading-tight`} style={{ color: theme.brandOrange }}>
80+
Migration Required
81+
</span>
5482
</div>
5583
</div>
56-
<DialogTitle className={`text-lg font-semibold ${theme.text} text-center`}>
57-
Architectural Update Required
58-
</DialogTitle>
59-
<DialogDescription className={`${theme.textMuted} text-sm text-center mt-2`}>
60-
There's been an architectural change to Vincent Wallets. Your existing wallet needs to
61-
be connected to Vincent Yield to continue.
84+
85+
<DialogDescription
86+
className={`${theme.textMuted} text-xs leading-relaxed`}
87+
style={fonts.body}
88+
>
89+
Your existing Vincent Wallet needs to be connected to Vincent Yield due to architectural
90+
improvements.
6291
</DialogDescription>
6392
</DialogHeader>
6493

@@ -89,37 +118,36 @@ export function ConnectToVincentYieldModal({ agentPKP }: ConnectToVincentYieldMo
89118
</div>
90119
</div>
91120

92-
<div className="flex px-3 sm:px-6 pt-3 pb-4 sm:pb-6 border-t border-gray-200 dark:border-gray-700">
93-
<Button
121+
<div className="px-4 sm:px-6 pb-6">
122+
<button
94123
onClick={handleConnect}
95124
disabled={isRedirecting}
96-
className={`w-full font-normal tracking-wide transition-all duration-200 border text-white flex items-center justify-center gap-2 ${
97-
isRedirecting
98-
? 'bg-gray-100 dark:bg-gray-800 !text-gray-400 border-gray-200 dark:border-gray-700 cursor-not-allowed'
99-
: ''
100-
}`}
125+
className="w-full flex items-center justify-center gap-1.5 px-3 py-2 rounded-lg text-xs font-medium transition-colors text-white disabled:opacity-50 disabled:cursor-not-allowed"
101126
style={{
102-
borderRadius: '0.5rem',
103-
fontSize: 'clamp(0.75rem, 3vw, 0.875rem)',
104-
padding: 'clamp(0.5rem, 1vw, 0.75rem) clamp(1rem, 4vw, 1.5rem)',
105-
...(isRedirecting
106-
? {}
107-
: {
108-
backgroundColor: '#e55a1a',
109-
borderColor: '#e55a1a',
110-
animation: 'pulse 2s ease-in-out infinite',
111-
}),
127+
...fonts.heading,
128+
backgroundColor: isRedirecting ? theme.textMuted : theme.brandOrange,
129+
animation: isRedirecting ? 'none' : 'pulse 2s ease-in-out infinite',
130+
}}
131+
onMouseEnter={(e) => {
132+
if (!isRedirecting) {
133+
e.currentTarget.style.backgroundColor = theme.brandOrangeDarker;
134+
}
135+
}}
136+
onMouseLeave={(e) => {
137+
if (!isRedirecting) {
138+
e.currentTarget.style.backgroundColor = theme.brandOrange;
139+
}
112140
}}
113141
>
114142
{isRedirecting ? (
115143
'Redirecting...'
116144
) : (
117145
<>
118-
Connect to Vincent Yield
119-
<ArrowRight className="w-4 h-4" />
146+
<ArrowRight className="w-4 h-4 flex-shrink-0 -mt-px" />
147+
<span className="leading-none">Connect to Vincent Yield</span>
120148
</>
121149
)}
122-
</Button>
150+
</button>
123151
</div>
124152
</DialogContent>
125153
</Dialog>

0 commit comments

Comments
 (0)