Skip to content

Commit 4d4e4d1

Browse files
photo card improvement
1 parent f217ea0 commit 4d4e4d1

File tree

4 files changed

+183
-42
lines changed

4 files changed

+183
-42
lines changed

src/app/api/strava/[slug]/route.ts

+65-10
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,26 @@ export async function POST(
4040
props: { params: Promise<{ slug: string }> },
4141
) {
4242
const params = await props.params;
43-
console.log('Webhook received:', params.slug);
43+
console.log('Webhook POST received:', {
44+
slug: params.slug,
45+
method: req.method,
46+
headers: Object.fromEntries(req.headers.entries()),
47+
});
4448

4549
if (params.slug !== 'webhook')
4650
return new Response('Invalid endpoint', { status: 404 });
4751

4852
try {
4953
const data = (await req.json()) as WebhookRequest;
50-
console.log('Webhook data:', data);
54+
console.log('Webhook payload:', {
55+
object_type: data.object_type,
56+
object_id: data.object_id,
57+
aspect_type: data.aspect_type,
58+
owner_id: data.owner_id,
59+
subscription_id: data.subscription_id,
60+
event_time: new Date(data.event_time * 1000).toISOString(),
61+
updates: data.updates,
62+
});
5163

5264
// Verify that this is a valid subscription from our database
5365
const subscription = await db.query.webhooks.findFirst({
@@ -59,6 +71,19 @@ export async function POST(
5971
),
6072
});
6173

74+
console.log('Subscription check:', {
75+
received_id: data.subscription_id,
76+
found: !!subscription,
77+
subscription_details: subscription
78+
? {
79+
id: subscription.id,
80+
verified: subscription.verified,
81+
active: subscription.active,
82+
callback_url: subscription.callback_url,
83+
}
84+
: null,
85+
});
86+
6287
if (!subscription) {
6388
console.error('Invalid subscription ID:', {
6489
received: data.subscription_id,
@@ -68,39 +93,69 @@ export async function POST(
6893
}
6994

7095
if (data.object_type === 'athlete') {
96+
console.log('Received athlete webhook, skipping');
7197
return new Response('OK');
7298
}
7399

74100
if (data.aspect_type === 'delete') {
101+
console.log('Processing delete webhook:', {
102+
activity_id: data.object_id,
103+
athlete_id: data.owner_id,
104+
});
75105
await db.delete(activities).where(eq(activities.id, data.object_id));
76106
// Also delete associated photos
77107
await db.delete(photos).where(eq(photos.activity_id, data.object_id));
78108
return new Response(`Deleted activity ${data.object_id}`);
79109
}
80110

81111
if (data.aspect_type === 'create' || data.aspect_type === 'update') {
82-
const {
83-
activities: [activity],
84-
photos,
85-
} = await handleWebhookActivity({
112+
console.log('Processing create/update webhook:', {
113+
activity_id: data.object_id,
114+
athlete_id: data.owner_id,
115+
aspect_type: data.aspect_type,
116+
});
117+
118+
const result = await handleWebhookActivity({
86119
activityId: data.object_id,
87120
athleteId: data.owner_id,
88121
});
89122

90-
if (!activity) {
123+
console.log('Webhook activity processing result:', {
124+
activity_count: result.activities.length,
125+
photo_count: result.photos.length,
126+
first_activity: result.activities[0]
127+
? {
128+
id: result.activities[0].id,
129+
name: result.activities[0].name,
130+
is_complete: result.activities[0].is_complete,
131+
}
132+
: null,
133+
});
134+
135+
if (!result.activities[0]) {
91136
throw new Error('No activity returned from Strava');
92137
}
93138

94139
return new Response(
95140
`${data.aspect_type === 'create' ? 'Created' : 'Updated'} activity ${
96-
activity.id
97-
} with ${photos.length} photos`,
141+
result.activities[0].id
142+
} with ${result.photos.length} photos`,
98143
);
99144
}
100145

101146
return new Response('Invalid aspect type', { status: 400 });
102147
} catch (e) {
103-
console.error('Webhook request failed:', e);
148+
console.error('Webhook request failed:', {
149+
error:
150+
e instanceof Error
151+
? {
152+
message: e.message,
153+
name: e.name,
154+
stack: e.stack,
155+
}
156+
: e,
157+
timestamp: new Date().toISOString(),
158+
});
104159
return new Response(
105160
e instanceof Error ? e.message : 'Unknown error processing webhook',
106161
{ status: 500 },

src/components/list/card.tsx

+15-8
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ import {
99
Map,
1010
Info,
1111
Loader2,
12+
ArrowLeft,
13+
ArrowRight,
14+
X,
1215
} from 'lucide-react';
1316

1417
import { type Activity, type Photo } from '~/server/db/schema';
@@ -352,30 +355,34 @@ export function PhotoCard({
352355
className="h-full rounded-sm aspect-square object-cover"
353356
onClick={() => {
354357
api?.scrollTo(index);
355-
console.log(api);
356358
setOpen(true);
357359
}}
358360
/>
359361
</Button>
360362
))}
361363
</div>
362364
<Dialog open={open} onOpenChange={setOpen}>
363-
<DialogContent className="[&>button]:hidden p-0 max-w-2xl">
364-
<Carousel setApi={setApi}>
365-
<DialogTitle>{title}</DialogTitle>
365+
<DialogContent className="max-w-[90vw] max-h-[90vh] w-auto p-0 rounded-lg border-2 overflow-hidden">
366+
<DialogTitle className="p-6 hidden">{title}</DialogTitle>
367+
<Carousel setApi={setApi} className="w-full">
366368
<CarouselContent>
367369
{photos.map((photo) => (
368-
<CarouselItem key={photo.unique_id}>
370+
<CarouselItem
371+
key={photo.unique_id}
372+
className="flex items-center justify-center"
373+
>
369374
<img
370375
src={photo.urls ? Object.values(photo.urls).at(-1) : ''}
371376
alt={photo.caption ?? ''}
372-
className="h-full rounded-sm object-contain"
377+
className="object-contain max-w-full max-h-[80vh] w-auto h-auto"
373378
/>
374379
</CarouselItem>
375380
))}
376381
</CarouselContent>
377-
<CarouselPrevious />
378-
<CarouselNext />
382+
<div className="absolute bottom-4 left-0 right-0 flex justify-center gap-2">
383+
<CarouselPrevious />
384+
<CarouselNext />
385+
</div>
379386
</Carousel>
380387
</DialogContent>
381388
</Dialog>

src/env.js

-2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ export const env = createEnv({
2525
AUTH_SECRET: z.string(),
2626
AUTH_STRAVA_ID: z.string(),
2727
AUTH_STRAVA_SECRET: z.string(),
28-
AUTH_STRAVA_VERIFY_TOKEN: z.string(),
2928
PUBLIC_URL: z.string().url(),
3029
NODE_ENV: z
3130
.enum(["development", "test", "production"])
@@ -67,7 +66,6 @@ export const env = createEnv({
6766
AUTH_SECRET: process.env.AUTH_SECRET,
6867
AUTH_STRAVA_ID: process.env.AUTH_STRAVA_ID,
6968
AUTH_STRAVA_SECRET: process.env.AUTH_STRAVA_SECRET,
70-
AUTH_STRAVA_VERIFY_TOKEN: process.env.AUTH_STRAVA_VERIFY_TOKEN,
7169
PUBLIC_URL: process.env.PUBLIC_URL,
7270
NEXT_PUBLIC_MAPBOX_TOKEN:
7371
process.env.NEXT_PUBLIC_MAPBOX_TOKEN,

src/server/strava/actions.ts

+103-22
Original file line numberDiff line numberDiff line change
@@ -82,38 +82,66 @@ async function fetchStravaActivities({
8282
athleteId: number;
8383
shouldDeletePhotos?: boolean;
8484
}): Promise<{ activities: Activity[]; photos: Photo[] }> {
85-
console.log('Starting fetchStravaActivities with params:', {
86-
hasAccessToken: !!accessToken,
87-
before,
88-
activityIds,
89-
includePhotos,
90-
athleteId,
91-
shouldDeletePhotos,
85+
console.log('Starting fetchStravaActivities:', {
86+
has_access_token: !!accessToken,
87+
before: before ? new Date(before * 1000).toISOString() : undefined,
88+
activity_ids: activityIds,
89+
include_photos: includePhotos,
90+
athlete_id: athleteId,
91+
should_delete_photos: shouldDeletePhotos,
92+
timestamp: new Date().toISOString(),
9293
});
9394

9495
const client = new StravaClient(accessToken);
9596
const photos: Photo[] = [];
9697

9798
try {
98-
console.log('Fetching activities from Strava...');
9999
let stravaActivities: StravaActivity[];
100100

101101
if (activityIds) {
102-
// When fetching specific activities, get complete data
103-
console.log('Fetching complete activity data for IDs:', activityIds);
102+
console.log('Fetching complete activities by IDs:', {
103+
ids: activityIds,
104+
count: activityIds.length,
105+
});
104106
stravaActivities = await Promise.all(
105-
activityIds.map((id) => client.getActivity(id)),
107+
activityIds.map(async (id) => {
108+
try {
109+
const activity = await client.getActivity(id);
110+
console.log('Successfully fetched activity:', {
111+
id: activity.id,
112+
name: activity.name,
113+
type: activity.sport_type,
114+
has_polyline:
115+
!!activity.map.polyline || !!activity.map.summary_polyline,
116+
});
117+
return activity;
118+
} catch (error) {
119+
console.error('Failed to fetch individual activity:', {
120+
id,
121+
error: error instanceof Error ? error.message : error,
122+
});
123+
throw error;
124+
}
125+
}),
106126
);
107127
} else {
108-
// When fetching all activities, get summary data
109-
console.log('Fetching summary activity data');
128+
console.log('Fetching summary activities');
110129
stravaActivities = await client.getActivities({
111130
before,
112131
per_page: 200,
113132
});
114133
}
115134

116-
console.log(`Retrieved ${stravaActivities.length} activities from Strava`);
135+
console.log('Activity fetch completed:', {
136+
total_activities: stravaActivities.length,
137+
first_activity: stravaActivities[0]
138+
? {
139+
id: stravaActivities[0].id,
140+
name: stravaActivities[0].name,
141+
type: stravaActivities[0].sport_type,
142+
}
143+
: null,
144+
});
117145

118146
// Transform activities
119147
const activities = stravaActivities
@@ -381,30 +409,83 @@ export async function handleWebhookActivity({
381409
activityId: number;
382410
athleteId: number;
383411
}) {
384-
console.log('Handling webhook activity:', { activityId, athleteId });
412+
console.log('Starting webhook activity processing:', {
413+
activityId,
414+
athleteId,
415+
timestamp: new Date().toISOString(),
416+
});
385417

386418
// Get account directly using Strava athlete ID
387419
const account = await getAccount({
388420
providerAccountId: athleteId.toString(),
389421
});
390422

423+
console.log('Account lookup result:', {
424+
found: !!account,
425+
athlete_id: athleteId,
426+
has_access_token: account?.access_token ? true : false,
427+
token_expires_at: account?.expires_at
428+
? new Date(account.expires_at * 1000).toISOString()
429+
: null,
430+
});
431+
391432
// If no account found, this user hasn't connected their Strava account to our app
392433
if (!account) {
393434
console.log('No account found for athlete ID:', athleteId);
394435
return { activities: [], photos: [] };
395436
}
396437

397438
if (!account.access_token) {
439+
console.error('Account found but no access token present:', {
440+
athlete_id: athleteId,
441+
provider_account_id: account.providerAccountId,
442+
});
398443
throw new Error('No Strava access token found');
399444
}
400445

401-
return fetchStravaActivities({
402-
accessToken: account.access_token,
403-
activityIds: [activityId],
404-
includePhotos: true,
405-
athleteId,
406-
shouldDeletePhotos: true,
407-
});
446+
try {
447+
const result = await fetchStravaActivities({
448+
accessToken: account.access_token,
449+
activityIds: [activityId],
450+
includePhotos: true,
451+
athleteId,
452+
shouldDeletePhotos: true,
453+
});
454+
455+
console.log('Webhook activity processing completed:', {
456+
activityId,
457+
athleteId,
458+
activities_processed: result.activities.length,
459+
photos_processed: result.photos.length,
460+
first_activity: result.activities[0]
461+
? {
462+
id: result.activities[0].id,
463+
name: result.activities[0].name,
464+
is_complete: result.activities[0].is_complete,
465+
has_polyline:
466+
!!result.activities[0].map_polyline ||
467+
!!result.activities[0].map_summary_polyline,
468+
}
469+
: null,
470+
});
471+
472+
return result;
473+
} catch (error) {
474+
console.error('Error in handleWebhookActivity:', {
475+
error:
476+
error instanceof Error
477+
? {
478+
message: error.message,
479+
name: error.name,
480+
stack: error.stack,
481+
}
482+
: error,
483+
activityId,
484+
athleteId,
485+
timestamp: new Date().toISOString(),
486+
});
487+
throw error;
488+
}
408489
}
409490

410491
export async function checkWebhookStatus() {

0 commit comments

Comments
 (0)