Skip to content

Commit 7e868e3

Browse files
committed
fix: sessions, vercel PoC
1 parent 5304a52 commit 7e868e3

File tree

9 files changed

+2111
-130
lines changed

9 files changed

+2111
-130
lines changed

apps/dashboard/app/(main)/settings/_components/sessions-form.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export function SessionsForm() {
3737

3838
useEffect(() => {
3939
fetchSessions();
40-
}, [fetchSessions]);
40+
}, []);
4141

4242
const fetchSessions = async () => {
4343
setIsLoading(true);

apps/dashboard/app/(main)/settings/integrations/page.tsx

Lines changed: 137 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,29 @@
11
'use client';
22

3-
import { CheckCircleIcon, LinkIcon, PlusIcon, WarningIcon } from '@phosphor-icons/react';
3+
import {
4+
CheckCircleIcon,
5+
LinkIcon,
6+
PlusIcon,
7+
WarningIcon,
8+
} from '@phosphor-icons/react';
49
import Image from 'next/image';
510
import { useSearchParams } from 'next/navigation';
611
import { useEffect, useState } from 'react';
7-
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
8-
import { Button } from '@/components/ui/button';
912
import { Badge } from '@/components/ui/badge';
13+
import { Button } from '@/components/ui/button';
14+
import {
15+
Card,
16+
CardContent,
17+
CardDescription,
18+
CardHeader,
19+
CardTitle,
20+
} from '@/components/ui/card';
1021
import { Skeleton } from '@/components/ui/skeleton';
11-
import { useIntegrations, useDisconnectIntegration, type Integration } from '@/hooks/use-integrations';
22+
import {
23+
type Integration,
24+
useDisconnectIntegration,
25+
useIntegrations,
26+
} from '@/hooks/use-integrations';
1227

1328
const categoryLabels = {
1429
deployment: 'Deployment',
@@ -31,7 +46,7 @@ function LoadingSkeleton() {
3146
</div>
3247
<div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
3348
{[1, 2, 3, 4].map((num) => (
34-
<Card key={num} className="animate-pulse border-0 shadow-sm">
49+
<Card className="animate-pulse border-0 shadow-sm" key={num}>
3550
<CardContent className="p-6">
3651
<div className="space-y-4">
3752
<div className="flex items-start justify-between">
@@ -65,7 +80,7 @@ function ErrorState({ onRetry }: { onRetry: () => void }) {
6580
<p className="mt-1 text-muted-foreground text-sm">
6681
There was an issue loading your integrations. Please try again.
6782
</p>
68-
<Button onClick={onRetry} variant="outline" className="mt-4">
83+
<Button className="mt-4" onClick={onRetry} variant="outline">
6984
Try Again
7085
</Button>
7186
</div>
@@ -75,7 +90,9 @@ function ErrorState({ onRetry }: { onRetry: () => void }) {
7590

7691
export default function IntegrationsPage() {
7792
const searchParams = useSearchParams();
78-
const [connectingProvider, setConnectingProvider] = useState<string | null>(null);
93+
const [connectingProvider, setConnectingProvider] = useState<string | null>(
94+
null
95+
);
7996
const [showSuccessMessage, setShowSuccessMessage] = useState(false);
8097
const { integrations, isLoading, isError, refetch } = useIntegrations();
8198
const disconnectMutation = useDisconnectIntegration();
@@ -85,17 +102,17 @@ export default function IntegrationsPage() {
85102
if (searchParams.get('vercel_integrated') === 'true') {
86103
setShowSuccessMessage(true);
87104
refetch(); // Refresh integrations to show the new connection
88-
105+
89106
// Remove the query parameter from URL
90107
const url = new URL(window.location.href);
91108
url.searchParams.delete('vercel_integrated');
92109
window.history.replaceState({}, '', url.toString());
93-
110+
94111
// Hide success message after 5 seconds
95112
const timer = setTimeout(() => {
96113
setShowSuccessMessage(false);
97114
}, 5000);
98-
115+
99116
return () => clearTimeout(timer);
100117
}
101118
}, [searchParams, refetch]);
@@ -125,127 +142,143 @@ export default function IntegrationsPage() {
125142
return <ErrorState onRetry={refetch} />;
126143
}
127144

128-
const groupedIntegrations = integrations.reduce((acc, integration) => {
129-
if (!acc[integration.category]) {
130-
acc[integration.category] = [];
131-
}
132-
acc[integration.category].push(integration);
133-
return acc;
134-
}, {} as Record<string, Integration[]>);
145+
const groupedIntegrations = integrations.reduce(
146+
(acc, integration) => {
147+
if (!acc[integration.category]) {
148+
acc[integration.category] = [];
149+
}
150+
acc[integration.category].push(integration);
151+
return acc;
152+
},
153+
{} as Record<string, Integration[]>
154+
);
135155

136156
return (
137157
<div className="space-y-8">
138158
{showSuccessMessage && (
139159
<div className="rounded-xl border border-green-200 bg-green-50 p-4 dark:border-green-800 dark:bg-green-950/50">
140160
<div className="flex items-start gap-3">
141-
<CheckCircleIcon className="h-5 w-5 text-green-600 dark:text-green-400 mt-0.5" />
161+
<CheckCircleIcon className="mt-0.5 h-5 w-5 text-green-600 dark:text-green-400" />
142162
<div className="flex-1">
143163
<h3 className="font-semibold text-green-900 dark:text-green-100">
144164
Integration Connected Successfully
145165
</h3>
146-
<p className="text-green-700 text-sm dark:text-green-300 mt-1">
147-
Vercel has been connected to your account. You can now manage your deployments.
166+
<p className="mt-1 text-green-700 text-sm dark:text-green-300">
167+
Vercel has been connected to your account. You can now manage
168+
your deployments.
148169
</p>
149170
</div>
150171
<Button
151-
variant="ghost"
152-
size="sm"
172+
className="-mt-1 text-green-600 hover:text-green-800 dark:text-green-400 dark:hover:text-green-200"
153173
onClick={() => setShowSuccessMessage(false)}
154-
className="text-green-600 hover:text-green-800 dark:text-green-400 dark:hover:text-green-200 -mt-1"
174+
size="sm"
175+
variant="ghost"
155176
>
156177
×
157178
</Button>
158179
</div>
159180
</div>
160181
)}
161-
162-
{Object.entries(groupedIntegrations).map(([category, categoryIntegrations]) => (
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">
169-
{categoryIntegrations.length}
182+
183+
{Object.entries(groupedIntegrations).map(
184+
([category, categoryIntegrations]) => (
185+
<div className="space-y-6" key={category}>
186+
<div className="flex items-center gap-3">
187+
<h2 className="font-semibold text-foreground text-xl">
188+
{categoryLabels[category as keyof typeof categoryLabels]}
189+
</h2>
190+
<div className="flex h-6 w-6 items-center justify-center rounded-full bg-muted font-medium text-muted-foreground text-xs">
191+
{categoryIntegrations.length}
192+
</div>
170193
</div>
171-
</div>
172194

173-
<div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
174-
{categoryIntegrations.map((integration) => (
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 dark:bg-gray-800">
180-
<Image
181-
src={integration.logo}
182-
alt={`${integration.name} logo`}
183-
width={28}
184-
height={28}
185-
className="h-7 w-7 brightness-0 dark:brightness-100"
186-
/>
187-
</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-
)}
193-
</div>
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
195+
<div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
196+
{categoryIntegrations.map((integration) => (
197+
<Card
198+
className="group relative border-0 shadow-sm transition-all duration-200 hover:shadow-black/5 hover:shadow-md"
199+
key={integration.id}
200+
>
201+
<CardContent className="p-6">
202+
<div className="space-y-4">
203+
<div className="flex items-start justify-between">
204+
<div className="flex h-12 w-12 items-center justify-center rounded-lg border bg-white shadow-sm dark:bg-gray-800">
205+
<Image
206+
alt={`${integration.name} logo`}
207+
className="h-7 w-7 brightness-0 dark:brightness-100"
208+
height={28}
209+
src={integration.logo}
210+
width={28}
211+
/>
212+
</div>
213+
{integration.connected && (
214+
<Badge
215+
className="bg-green-100 text-green-800 hover:bg-green-100 dark:bg-green-900 dark:text-green-100"
216+
variant="default"
212217
>
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}
218+
Connected
219+
</Badge>
220+
)}
221+
</div>
222+
223+
<div className="space-y-2">
224+
<h3 className="font-semibold text-lg leading-none tracking-tight">
225+
{integration.name}
226+
</h3>
227+
<p className="text-muted-foreground text-sm leading-relaxed">
228+
{integration.description}
229+
</p>
230+
</div>
231+
232+
<div className="pt-2">
233+
{integration.connected ? (
234+
<div className="flex gap-2">
235+
<Button
236+
className="flex-1"
237+
onClick={() =>
238+
(window.location.href = `/settings/integrations/${integration.id}`)
239+
}
240+
size="sm"
241+
variant="outline"
242+
>
243+
Configure
244+
</Button>
245+
<Button
246+
className="text-destructive hover:bg-destructive/10 hover:text-destructive"
247+
disabled={disconnectMutation.isPending}
248+
onClick={() => handleDisconnect(integration)}
249+
size="sm"
250+
variant="ghost"
251+
>
252+
{disconnectMutation.isPending
253+
? 'Disconnecting...'
254+
: 'Disconnect'}
255+
</Button>
256+
</div>
257+
) : (
258+
<Button
259+
className="w-full font-medium"
260+
disabled={connectingProvider === integration.id}
261+
onClick={() => handleConnect(integration)}
221262
>
222-
{disconnectMutation.isPending ? 'Disconnecting...' : 'Disconnect'}
263+
{connectingProvider === integration.id ? (
264+
'Connecting...'
265+
) : (
266+
<>
267+
<PlusIcon className="mr-2 h-4 w-4" />
268+
Connect
269+
</>
270+
)}
223271
</Button>
224-
</div>
225-
) : (
226-
<Button
227-
onClick={() => handleConnect(integration)}
228-
className="w-full font-medium"
229-
disabled={connectingProvider === integration.id}
230-
>
231-
{connectingProvider === integration.id ? (
232-
'Connecting...'
233-
) : (
234-
<>
235-
<PlusIcon className="mr-2 h-4 w-4" />
236-
Connect
237-
</>
238-
)}
239-
</Button>
240-
)}
272+
)}
273+
</div>
241274
</div>
242-
</div>
243-
</CardContent>
244-
</Card>
245-
))}
275+
</CardContent>
276+
</Card>
277+
))}
278+
</div>
246279
</div>
247-
</div>
248-
))}
280+
)
281+
)}
249282

250283
{integrations.length === 0 && (
251284
<div className="flex h-64 items-center justify-center">

0 commit comments

Comments
 (0)