@@ -9,7 +9,6 @@ import { Button } from '@/components/ui/button';
99import { Badge } from '@/components/ui/badge' ;
1010import { Skeleton } from '@/components/ui/skeleton' ;
1111import { useIntegrations , useDisconnectIntegration , type Integration } from '@/hooks/use-integrations' ;
12- import { trpc } from '@/lib/trpc' ;
1312
1413const categoryLabels = {
1514 deployment : 'Deployment' ,
@@ -21,29 +20,31 @@ const categoryLabels = {
2120function LoadingSkeleton ( ) {
2221 return (
2322 < div className = "space-y-8" >
24- < div className = "space-y-2 " >
25- < Skeleton className = "h-8 w-48 " />
26- < Skeleton className = "h-4 w-96" />
23+ < div className = "space-y-3 " >
24+ < Skeleton className = "h-9 w-64 " />
25+ < Skeleton className = "h-5 w-96" />
2726 </ div >
28- < div className = "space-y-4 " >
29- < div className = "flex items-center gap-2 " >
30- < Skeleton className = "h-6 w-24 " />
31- < Skeleton className = "h-5 w-8 " />
27+ < div className = "space-y-6 " >
28+ < div className = "flex items-center gap-3 " >
29+ < Skeleton className = "h-7 w-32 " />
30+ < Skeleton className = "h-6 w-6 rounded-full " />
3231 </ div >
33- < div className = "grid gap-4 sm:grid-cols-2 lg:grid-cols-3" >
34- { [ 1 , 2 , 3 ] . map ( ( num ) => (
35- < Card key = { num } className = "animate-pulse" >
36- < CardHeader className = "pb-3 " >
37- < div className = "flex items-center justify-between " >
38- < div className = "flex items-center gap-3 " >
39- < Skeleton className = "h-10 w-10 rounded" />
40- < Skeleton className = "h-5 w-20 " />
32+ < div className = "grid gap-6 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 " >
33+ { [ 1 , 2 , 3 , 4 ] . map ( ( num ) => (
34+ < Card key = { num } className = "animate-pulse border-0 shadow-sm " >
35+ < CardContent className = "p-6 " >
36+ < div className = "space-y-4 " >
37+ < div className = "flex items-start justify-between " >
38+ < Skeleton className = "h-12 w-12 rounded-lg " />
39+ < Skeleton className = "h-5 w-16 rounded-full " />
4140 </ div >
41+ < div className = "space-y-2" >
42+ < Skeleton className = "h-6 w-24" />
43+ < Skeleton className = "h-4 w-full" />
44+ < Skeleton className = "h-4 w-3/4" />
45+ </ div >
46+ < Skeleton className = "h-9 w-full rounded-lg" />
4247 </ div >
43- </ CardHeader >
44- < CardContent className = "space-y-4" >
45- < Skeleton className = "h-12 w-full" />
46- < Skeleton className = "h-9 w-full" />
4748 </ CardContent >
4849 </ Card >
4950 ) ) }
@@ -102,20 +103,7 @@ export default function IntegrationsPage() {
102103 const handleConnect = ( integration : Integration ) => {
103104 if ( integration . id === 'vercel' ) {
104105 setConnectingProvider ( integration . id ) ;
105-
106- // Redirect directly to Vercel OAuth
107- const clientId = process . env . NEXT_PUBLIC_VERCEL_CLIENT_ID ;
108- const redirectUri = `${ window . location . origin } /api/integrations/vercel/callback` ;
109- const state = encodeURIComponent ( window . location . href ) ;
110-
111- const vercelAuthUrl = new URL ( 'https://vercel.com/oauth/authorize' ) ;
112- vercelAuthUrl . searchParams . set ( 'client_id' , clientId || '' ) ;
113- vercelAuthUrl . searchParams . set ( 'redirect_uri' , redirectUri ) ;
114- vercelAuthUrl . searchParams . set ( 'response_type' , 'code' ) ;
115- vercelAuthUrl . searchParams . set ( 'scope' , 'user:read' ) ;
116- vercelAuthUrl . searchParams . set ( 'state' , state ) ;
117-
118- window . location . href = vercelAuthUrl . toString ( ) ;
106+ window . location . href = 'https://vercel.com/marketplace/databuddy' ;
119107 }
120108 } ;
121109
@@ -148,104 +136,109 @@ export default function IntegrationsPage() {
148136 return (
149137 < div className = "space-y-8" >
150138 { showSuccessMessage && (
151- < div className = "rounded-lg border border-green-200 bg-green-50 p-4 dark:border-green-800 dark:bg-green-950" >
152- < div className = "flex items-center gap-3" >
153- < CheckCircleIcon className = "h-5 w-5 text-green-600 dark:text-green-400" />
154- < div >
155- < h3 className = "font-medium text-green-800 dark:text-green-200 " >
139+ < div className = "rounded-xl border border-green-200 bg-green-50 p-4 dark:border-green-800 dark:bg-green-950/50 " >
140+ < div className = "flex items-start gap-3" >
141+ < CheckCircleIcon className = "h-5 w-5 text-green-600 dark:text-green-400 mt-0.5 " />
142+ < div className = "flex-1" >
143+ < h3 className = "font-semibold text-green-900 dark:text-green-100 " >
156144 Integration Connected Successfully
157145 </ h3 >
158- < p className = "text-green-700 text-sm dark:text-green-300" >
146+ < p className = "text-green-700 text-sm dark:text-green-300 mt-1 " >
159147 Vercel has been connected to your account. You can now manage your deployments.
160148 </ p >
161149 </ div >
162150 < Button
163151 variant = "ghost"
164152 size = "sm"
165153 onClick = { ( ) => setShowSuccessMessage ( false ) }
166- className = "ml-auto text-green-600 hover:text-green-800 dark:text-green-400 dark:hover:text-green-200"
154+ className = "text-green-600 hover:text-green-800 dark:text-green-400 dark:hover:text-green-200 -mt-1 "
167155 >
168156 ×
169157 </ Button >
170158 </ div >
171159 </ div >
172160 ) }
173-
174- < div className = "space-y-2" >
175- < h2 className = "font-semibold text-2xl tracking-tight" > Integrations</ h2 >
176- < p className = "text-muted-foreground" >
177- Connect your favorite tools and services to enhance your workflow.
178- </ p >
179- </ div >
180-
161+
181162 { Object . entries ( groupedIntegrations ) . map ( ( [ category , categoryIntegrations ] ) => (
182- < div key = { category } className = "space-y-4" >
183- < div className = "flex items-center gap-2" >
184- < h3 className = "font-medium text-lg" > { categoryLabels [ category as keyof typeof categoryLabels ] } </ h3 >
185- < Badge variant = "secondary" className = "text-xs" >
163+ < div key = { category } className = "space-y-6" >
164+ < div className = "flex items-center gap-3" >
165+ < h2 className = "font-semibold text-xl text-foreground" >
166+ { categoryLabels [ category as keyof typeof categoryLabels ] }
167+ </ h2 >
168+ < div className = "flex h-6 w-6 items-center justify-center rounded-full bg-muted text-muted-foreground text-xs font-medium" >
186169 { categoryIntegrations . length }
187- </ Badge >
170+ </ div >
188171 </ div >
189172
190- < div className = "grid gap-4 sm:grid-cols-2 lg:grid-cols-3" >
173+ < div className = "grid gap-6 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 " >
191174 { categoryIntegrations . map ( ( integration ) => (
192- < Card key = { integration . id } className = "relative shadow-sm transition-shadow hover:shadow-md" >
193- < CardHeader className = "pb-3 " >
194- < div className = "flex items-center justify-between " >
195- < div className = "flex items-center gap-3 " >
196- < div className = "flex h-10 w-10 items-center justify-center rounded border bg-background p-2 " >
175+ < Card key = { integration . id } className = "group relative border-0 shadow-sm transition-all duration-200 hover:shadow-md hover:shadow-black/5 " >
176+ < CardContent className = "p-6 " >
177+ < div className = "space-y-4 " >
178+ < div className = "flex items-start justify-between " >
179+ < div className = "flex h-12 w-12 items-center justify-center rounded-lg border bg-white shadow-sm " >
197180 < Image
198181 src = { integration . logo }
199182 alt = { `${ integration . name } logo` }
200- width = { 24 }
201- height = { 24 }
202- className = "h-6 w-6 "
183+ width = { 28 }
184+ height = { 28 }
185+ className = "h-7 w-7 not-dark:brightness-0 "
203186 />
204187 </ div >
205- < div >
206- < CardTitle className = "text-base" > { integration . name } </ CardTitle >
207- </ div >
188+ { integration . connected && (
189+ < Badge variant = "default" className = "bg-green-100 text-green-800 hover:bg-green-100 dark:bg-green-900 dark:text-green-100" >
190+ Connected
191+ </ Badge >
192+ ) }
208193 </ div >
209- { integration . connected && (
210- < Badge variant = "default" className = "text-xs" >
211- < LinkIcon className = "mr-1 h-3 w-3" />
212- Connected
213- </ Badge >
214- ) }
215- </ div >
216- </ CardHeader >
217- < CardContent className = "space-y-4" >
218- < CardDescription className = "text-sm leading-relaxed" >
219- { integration . description }
220- </ CardDescription >
221-
222- < div className = "flex items-center justify-between" >
223- { integration . connected ? (
224- < div className = "flex gap-2" >
225- < Button variant = "outline" size = "sm" disabled >
226- Configure
227- </ Button >
194+
195+ < div className = "space-y-2" >
196+ < h3 className = "font-semibold text-lg leading-none tracking-tight" >
197+ { integration . name }
198+ </ h3 >
199+ < p className = "text-muted-foreground text-sm leading-relaxed" >
200+ { integration . description }
201+ </ p >
202+ </ div >
203+
204+ < div className = "pt-2" >
205+ { integration . connected ? (
206+ < div className = "flex gap-2" >
207+ < Button
208+ variant = "outline"
209+ size = "sm"
210+ className = "flex-1"
211+ disabled
212+ >
213+ Configure
214+ </ Button >
215+ < Button
216+ variant = "ghost"
217+ size = "sm"
218+ className = "text-destructive hover:text-destructive hover:bg-destructive/10"
219+ onClick = { ( ) => handleDisconnect ( integration ) }
220+ disabled = { disconnectMutation . isPending }
221+ >
222+ { disconnectMutation . isPending ? 'Disconnecting...' : 'Disconnect' }
223+ </ Button >
224+ </ div >
225+ ) : (
228226 < Button
229- variant = "ghost"
230- size = "sm"
231- className = "text-destructive hover:text-destructive"
232- onClick = { ( ) => handleDisconnect ( integration ) }
233- disabled = { disconnectMutation . isPending }
227+ onClick = { ( ) => handleConnect ( integration ) }
228+ className = "w-full font-medium"
229+ disabled = { connectingProvider === integration . id }
234230 >
235- { disconnectMutation . isPending ? 'Disconnecting...' : 'Disconnect' }
231+ { connectingProvider === integration . id ? (
232+ 'Connecting...'
233+ ) : (
234+ < >
235+ < PlusIcon className = "mr-2 h-4 w-4" />
236+ Connect
237+ </ >
238+ ) }
236239 </ Button >
237- </ div >
238- ) : (
239- < Button
240- onClick = { ( ) => handleConnect ( integration ) }
241- size = "sm"
242- className = "w-full"
243- disabled = { connectingProvider === integration . id }
244- >
245- < PlusIcon className = "mr-2 h-4 w-4" />
246- { connectingProvider === integration . id ? 'Connecting...' : 'Connect' }
247- </ Button >
248- ) }
240+ ) }
241+ </ div >
249242 </ div >
250243 </ CardContent >
251244 </ Card >
0 commit comments