Skip to content

Commit bf6e6b6

Browse files
authored
Update landing page, Navbar, blog page
Update landing page, Navbar, blog page
2 parents 1e9cf1a + db7f78e commit bf6e6b6

File tree

20 files changed

+1618
-515
lines changed

20 files changed

+1618
-515
lines changed

apps/api/src/billing/billing.controller.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,6 @@ export class BillingController {
4343
);
4444
}
4545

46-
@Post('sync')
47-
@UseGuards(SupabaseAuthGuard)
48-
syncSubscription(@Req() req: AuthRequest) {
49-
const userId = req.user?.id;
50-
if (!userId) throw new UnauthorizedException();
51-
return this.billingService.syncSubscription(userId);
52-
}
53-
5446
@Post('checkout')
5547
@UseGuards(SupabaseAuthGuard)
5648
createCheckoutSession(

apps/api/src/billing/billing.service.ts

Lines changed: 3 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import {
1010
lemonSqueezySetup,
1111
createCheckout,
1212
getSubscription,
13-
listSubscriptions,
1413
type NewCheckout,
1514
} from '@lemonsqueezy/lemonsqueezy.js';
1615
import * as crypto from 'crypto';
@@ -207,121 +206,6 @@ export class BillingService {
207206
};
208207
}
209208

210-
// --- Direct sync with LemonSqueezy API (fallback when webhook is delayed) ---
211-
212-
async syncSubscription(userId: string): Promise<{ synced: boolean }> {
213-
this.initLemonSqueezy();
214-
const supabase = this.supabaseService.getClient();
215-
const storeId = this.configService.get<string>('LEMONSQUEEZY_STORE_ID');
216-
if (!storeId) return { synced: false };
217-
218-
const { data: existingSub } = await supabase
219-
.from('subscriptions')
220-
.select('ls_subscription_id')
221-
.eq('user_id', userId)
222-
.in('status', ['active', 'on_trial'])
223-
.order('created_at', { ascending: false })
224-
.limit(1)
225-
.maybeSingle();
226-
227-
if (existingSub?.ls_subscription_id) {
228-
return { synced: true };
229-
}
230-
231-
const { data: profile } = await supabase
232-
.from('profiles')
233-
.select('email')
234-
.eq('user_id', userId)
235-
.single();
236-
237-
if (!profile?.email) return { synced: false };
238-
239-
try {
240-
const { data: subs } = await listSubscriptions({
241-
filter: { storeId, status: 'active' },
242-
});
243-
244-
const items = subs?.data ?? [];
245-
const match = items.find((sub) => {
246-
const customData = (sub.attributes as Record<string, unknown>)
247-
.first_order_item as Record<string, unknown> | undefined;
248-
const meta = (sub as Record<string, unknown>).meta as
249-
| { custom_data?: { user_id?: string } }
250-
| undefined;
251-
252-
if (meta?.custom_data?.user_id === userId) return true;
253-
254-
const email = (sub.attributes as Record<string, unknown>)
255-
.user_email as string | undefined;
256-
return email === profile.email;
257-
});
258-
259-
if (!match) return { synced: false };
260-
261-
const attrs = match.attributes as Record<string, unknown>;
262-
const lsSubId = match.id;
263-
264-
const { data: alreadyExists } = await supabase
265-
.from('subscriptions')
266-
.select('id')
267-
.eq('ls_subscription_id', lsSubId)
268-
.maybeSingle();
269-
270-
if (alreadyExists) return { synced: true };
271-
272-
const variantId = String(attrs.variant_id ?? '');
273-
const { data: plan } = await supabase
274-
.from('plans')
275-
.select('id, credits_monthly')
276-
.eq('ls_variant_id', variantId)
277-
.maybeSingle();
278-
279-
if (!plan) {
280-
this.logger.warn(`Sync: No plan found for variant ${variantId}`);
281-
return { synced: false };
282-
}
283-
284-
await supabase
285-
.from('subscriptions')
286-
.update({ status: 'canceled' })
287-
.eq('user_id', userId)
288-
.in('status', ['active', 'on_trial', 'past_due']);
289-
290-
const { error: insertError } = await supabase
291-
.from('subscriptions')
292-
.insert({
293-
user_id: userId,
294-
plan_id: plan.id,
295-
ls_subscription_id: lsSubId,
296-
ls_customer_id: String(attrs.customer_id ?? ''),
297-
ls_order_id: String(attrs.order_id ?? ''),
298-
status: this.mapLsStatus(String(attrs.status ?? 'active')),
299-
current_period_start: attrs.created_at
300-
? new Date(attrs.created_at as string).toISOString()
301-
: null,
302-
current_period_end: attrs.renews_at
303-
? new Date(attrs.renews_at as string).toISOString()
304-
: null,
305-
});
306-
307-
if (insertError) {
308-
this.logger.error(`Sync insert failed: ${JSON.stringify(insertError)}`);
309-
return { synced: false };
310-
}
311-
312-
await supabase
313-
.from('profiles')
314-
.update({ credits: plan.credits_monthly })
315-
.eq('user_id', userId);
316-
317-
this.logger.log(`Subscription synced for user ${userId} via API`);
318-
return { synced: true };
319-
} catch (err) {
320-
this.logger.error(`Sync failed: ${err}`);
321-
return { synced: false };
322-
}
323-
}
324-
325209
// --- Webhook handlers ---
326210

327211
async handleSubscriptionCreated(event: LsWebhookEvent) {
@@ -330,32 +214,19 @@ export class BillingService {
330214
const planId = event.meta.custom_data?.plan_id;
331215

332216
if (!userId || !planId) {
333-
this.logger.warn(
334-
`Missing custom_data in subscription_created. meta: ${JSON.stringify(event.meta)}`,
335-
);
217+
this.logger.warn('Missing custom_data in subscription_created');
336218
return;
337219
}
338220

339221
const supabase = this.supabaseService.getClient();
340222

341-
const { data: alreadyExists } = await supabase
342-
.from('subscriptions')
343-
.select('id')
344-
.eq('ls_subscription_id', String(event.data.id))
345-
.maybeSingle();
346-
347-
if (alreadyExists) {
348-
this.logger.log(`Subscription ${event.data.id} already exists, skipping duplicate`);
349-
return;
350-
}
351-
352223
await supabase
353224
.from('subscriptions')
354225
.update({ status: 'canceled' })
355226
.eq('user_id', userId)
356227
.in('status', ['active', 'on_trial', 'past_due']);
357228

358-
const { error: insertError } = await supabase.from('subscriptions').insert({
229+
await supabase.from('subscriptions').insert({
359230
user_id: userId,
360231
plan_id: planId,
361232
ls_subscription_id: String(event.data.id),
@@ -370,13 +241,6 @@ export class BillingService {
370241
: null,
371242
});
372243

373-
if (insertError) {
374-
this.logger.error(
375-
`Failed to insert subscription for user ${userId}: ${JSON.stringify(insertError)}`,
376-
);
377-
throw new Error(`Subscription insert failed: ${insertError.message}`);
378-
}
379-
380244
const { data: plan } = await supabase
381245
.from('plans')
382246
.select('credits_monthly')
@@ -388,12 +252,9 @@ export class BillingService {
388252
.from('profiles')
389253
.update({ credits: plan.credits_monthly })
390254
.eq('user_id', userId);
391-
this.logger.log(
392-
`Credits updated to ${plan.credits_monthly} for user ${userId}`,
393-
);
394255
}
395256

396-
this.logger.log(`Subscription created for user ${userId}, plan ${planId}`);
257+
this.logger.log(`Subscription created for user ${userId}`);
397258
}
398259

399260
async handleSubscriptionUpdated(event: LsWebhookEvent) {

apps/api/src/billing/lemonsqueezy-webhook.controller.ts

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,10 @@ export class LemonSqueezyWebhookController {
4848
const eventName = req.headers['x-event-name'] as string;
4949
const event: LsWebhookEvent = req.body;
5050

51-
this.logger.log(
52-
`Webhook received: ${eventName} | subscription_id=${event?.data?.id} | custom_data=${JSON.stringify(event?.meta?.custom_data ?? {})}`,
53-
);
54-
5551
try {
5652
switch (eventName) {
5753
case 'subscription_created':
5854
await this.billingService.handleSubscriptionCreated(event);
59-
this.logger.log(`subscription_created processed for user ${event?.meta?.custom_data?.user_id}`);
6055
break;
6156
case 'subscription_updated':
6257
await this.billingService.handleSubscriptionUpdated(event);
@@ -71,12 +66,10 @@ export class LemonSqueezyWebhookController {
7166
await this.billingService.handleSubscriptionPaymentSuccess(event);
7267
break;
7368
default:
74-
this.logger.warn(`Unhandled webhook event: ${eventName}`);
69+
this.logger.log(`Unhandled event: ${eventName}`);
7570
}
7671
} catch (err) {
77-
this.logger.error(
78-
`Webhook handler error for ${eventName}: ${err instanceof Error ? err.message : err}`,
79-
);
72+
this.logger.error(`Webhook handler error: ${err}`);
8073
return res
8174
.status(HttpStatus.INTERNAL_SERVER_ERROR)
8275
.json({ error: 'Handler failed' });

apps/web/app/blog/[id]/page.tsx

Whitespace-only changes.

0 commit comments

Comments
 (0)