From 08afce15b0a9ae506d38ebdf012e65b68efd2a38 Mon Sep 17 00:00:00 2001 From: isra el Date: Sat, 12 Jul 2025 18:04:11 +0300 Subject: [PATCH 1/3] chore(api): include usage details in get current subscription endpoint --- api/src/billing/billing.service.ts | 41 +++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/api/src/billing/billing.service.ts b/api/src/billing/billing.service.ts index 2c65abf..ac2c45b 100644 --- a/api/src/billing/billing.service.ts +++ b/api/src/billing/billing.service.ts @@ -53,8 +53,37 @@ export class BillingService { }) .populate('plan') + // Get user's devices and usage data + const userDevices = await this.deviceModel.find({ user: user._id }, '_id') + const deviceIds = userDevices.map(d => d._id) + + const processedSmsToday = await this.smsModel.countDocuments({ + device: { $in: deviceIds }, + createdAt: { $gte: new Date(new Date().setHours(0, 0, 0, 0)) }, + }) + + const processedSmsLastMonth = await this.smsModel.countDocuments({ + device: { $in: deviceIds }, + createdAt: { + $gte: new Date(new Date().setMonth(new Date().getMonth() - 1)), + }, + }) + if (subscription) { - return subscription + const plan = subscription.plan + return { + ...subscription.toObject(), + usage: { + processedSmsToday, + processedSmsLastMonth, + dailyLimit: plan.dailyLimit, + monthlyLimit: plan.monthlyLimit, + dailyRemaining: plan.dailyLimit === -1 ? -1 : plan.dailyLimit - processedSmsToday, + monthlyRemaining: plan.monthlyLimit === -1 ? -1 : plan.monthlyLimit - processedSmsLastMonth, + dailyUsagePercentage: plan.dailyLimit === -1 ? 0 : Math.round((processedSmsToday / plan.dailyLimit) * 100), + monthlyUsagePercentage: plan.monthlyLimit === -1 ? 0 : Math.round((processedSmsLastMonth / plan.monthlyLimit) * 100), + } + } } const plan = await this.planModel.findOne({ name: 'free' }) @@ -62,6 +91,16 @@ export class BillingService { return { plan, isActive: true, + usage: { + processedSmsToday, + processedSmsLastMonth, + dailyLimit: plan.dailyLimit, + monthlyLimit: plan.monthlyLimit, + dailyRemaining: plan.dailyLimit === -1 ? -1 : plan.dailyLimit - processedSmsToday, + monthlyRemaining: plan.monthlyLimit === -1 ? -1 : plan.monthlyLimit - processedSmsLastMonth, + dailyUsagePercentage: plan.dailyLimit === -1 ? 0 : Math.round((processedSmsToday / plan.dailyLimit) * 100), + monthlyUsagePercentage: plan.monthlyLimit === -1 ? 0 : Math.round((processedSmsLastMonth / plan.monthlyLimit) * 100), + } } } From 58b8eef92fcd268437bba35ecd754c0adff038b0 Mon Sep 17 00:00:00 2001 From: isra el Date: Sat, 12 Jul 2025 18:06:11 +0300 Subject: [PATCH 2/3] chore(web): fix api key and device list key issue --- web/app/(app)/dashboard/(components)/api-keys.tsx | 2 +- web/app/(app)/dashboard/(components)/device-list.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/web/app/(app)/dashboard/(components)/api-keys.tsx b/web/app/(app)/dashboard/(components)/api-keys.tsx index 3351426..536ddb9 100644 --- a/web/app/(app)/dashboard/(components)/api-keys.tsx +++ b/web/app/(app)/dashboard/(components)/api-keys.tsx @@ -169,7 +169,7 @@ export default function ApiKeys() { )} {apiKeys?.data?.map((apiKey) => ( - +
diff --git a/web/app/(app)/dashboard/(components)/device-list.tsx b/web/app/(app)/dashboard/(components)/device-list.tsx index 0dccb8e..321fdc6 100644 --- a/web/app/(app)/dashboard/(components)/device-list.tsx +++ b/web/app/(app)/dashboard/(components)/device-list.tsx @@ -77,7 +77,7 @@ export default function DeviceList() { )} {devices?.data?.map((device) => ( - +
From f9005e6063684abe6bd09a95f2eb947b42f3f128 Mon Sep 17 00:00:00 2001 From: isra el Date: Sat, 12 Jul 2025 18:07:25 +0300 Subject: [PATCH 3/3] chore(web): improve upgrade to pro dashboard cta --- .../(components)/upgrade-to-pro-alert.tsx | 110 +++++++++++------- 1 file changed, 70 insertions(+), 40 deletions(-) diff --git a/web/app/(app)/dashboard/(components)/upgrade-to-pro-alert.tsx b/web/app/(app)/dashboard/(components)/upgrade-to-pro-alert.tsx index a7c869d..3208750 100644 --- a/web/app/(app)/dashboard/(components)/upgrade-to-pro-alert.tsx +++ b/web/app/(app)/dashboard/(components)/upgrade-to-pro-alert.tsx @@ -19,33 +19,58 @@ export default function UpgradeToProAlert() { .then((res) => res.data), }) - const ctaMessages = useMemo(() => [ - "Upgrade to Pro for exclusive features and benefits!", - "Offer: You are eligible for a 30% discount when upgrading to Pro!", - "Unlock premium features with our Pro plan today!", - "Take your experience to the next level with Pro!", - "Pro users get priority support and advanced features!", - "Limited time offer: Upgrade to Pro and save 30%!", - ], []); + const monthlyUsagePercentage = currentSubscription?.usage?.monthlyUsagePercentage || 0 + const monthlyLimit = currentSubscription?.usage?.monthlyLimit || 0 + const processedSmsLastMonth = currentSubscription?.usage?.processedSmsLastMonth || 0 - const buttonTexts = useMemo(() => [ - "Get Pro Now!", - "Upgrade Today!", - "Go Pro!", - "Unlock Pro!", - "Claim Your Discount!", - "Upgrade & Save!", - ], []); - - const randomCta = useMemo(() => { - const randomIndex = Math.floor(Math.random() * ctaMessages.length); - return ctaMessages[randomIndex]; - }, [ctaMessages]); - - const randomButtonText = useMemo(() => { - const randomIndex = Math.floor(Math.random() * buttonTexts.length); - return buttonTexts[randomIndex]; - }, [buttonTexts]); + const alertConfig = useMemo(() => { + if (monthlyUsagePercentage >= 100 ) { + return { + bgColor: 'bg-gradient-to-r from-red-600 to-red-800', + message: "⚠️ Monthly limit exceeded! Your requests will be rejected until you upgrade.", + subMessage: `You've used ${processedSmsLastMonth} of ${monthlyLimit} SMS this month.`, + buttonText: "Upgrade Now!", + buttonColor: 'bg-white text-red-600 hover:bg-red-50 hover:text-red-700 border-red-600', + urgency: 'critical' + } + } else if (monthlyUsagePercentage >= 80) { + return { + bgColor: 'bg-gradient-to-r from-orange-500 to-red-500', + message: "⚠️ Approaching limit! Upgrade to Pro to avoid service interruption.", + subMessage: `You've used ${monthlyUsagePercentage}% of your monthly SMS limit (${processedSmsLastMonth}/${monthlyLimit}).`, + buttonText: "Upgrade Before Limit!", + buttonColor: 'bg-white text-orange-600 hover:bg-orange-50 hover:text-orange-700 border-orange-600', + urgency: 'warning' + } + } else { + const ctaMessages = [ + "Upgrade to Pro for exclusive features and benefits!", + "Offer: You are eligible for a 30% discount when upgrading to Pro!", + "Unlock premium features with our Pro plan today!", + "Take your experience to the next level with Pro!", + "Pro users get priority support and advanced features!", + "Limited time offer: Upgrade to Pro and save 30%!", + ] + const buttonTexts = [ + "Get Pro Now!", + "Upgrade Today!", + "Go Pro!", + "Unlock Pro!", + "Claim Your Discount!", + "Upgrade & Save!", + ] + const randomIndex = Math.floor(Math.random() * ctaMessages.length) + + return { + bgColor: 'bg-gradient-to-r from-purple-500 to-pink-500', + message: ctaMessages[randomIndex], + subMessage: `Use discount code SAVE30P at checkout for a 30% discount!`, + buttonText: buttonTexts[randomIndex], + buttonColor: 'bg-red-500 text-white hover:bg-red-600 border-red-500', + urgency: 'normal' + } + } + }, [monthlyUsagePercentage, monthlyLimit, processedSmsLastMonth]) if (isLoadingSubscription || !currentSubscription || subscriptionError) { return null @@ -56,32 +81,37 @@ export default function UpgradeToProAlert() { } return ( - + - {randomCta} + {alertConfig.message} - Use discount code SAVE30P at checkout for a 30% - discount! + {alertConfig.urgency === 'normal' ? ( + <>Use discount code SAVE30P at checkout for a 30% discount! + ) : ( + alertConfig.subMessage + )}
- + {alertConfig.urgency === 'normal' && ( + + )}