Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch premium plan #284

Merged
merged 6 commits into from
Jan 1, 2025
Merged

Switch premium plan #284

merged 6 commits into from
Jan 1, 2025

Conversation

elie222
Copy link
Owner

@elie222 elie222 commented Jan 1, 2025

Also handling cancellation of a different plan better

Summary by CodeRabbit

  • New Features

    • Enhanced premium plan switching functionality with user feedback during plan changes.
    • Introduced new event handling for subscription plan changes.
    • Added functions for managing premium tiers based on variant IDs.
  • Bug Fixes

    • Simplified premium tier determination logic.
    • Improved error handling for subscription events.
  • Improvements

    • Added logging for Lemon Squeezy API interactions.
    • Updated webhook handling for subscription changes.
    • Improved user experience with clearer subscription status messaging.

Copy link

vercel bot commented Jan 1, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Updated (UTC)
inbox-zero ✅ Ready (Inspect) Visit Preview Jan 1, 2025 11:26am

Copy link
Contributor

coderabbitai bot commented Jan 1, 2025

Warning

Rate limit exceeded

@elie222 has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 1 minutes and 53 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between cc9fa0d and 1ac6d36.

📒 Files selected for processing (2)
  • apps/web/app/(app)/premium/config.ts (2 hunks)
  • apps/web/utils/actions/ai-rule.ts (1 hunks)

Walkthrough

This pull request introduces comprehensive changes to the premium subscription management system across multiple files. The modifications enhance the user experience for switching premium plans, improve logging and error handling, and add new functionality for tracking subscription changes. The changes span the web application's frontend, backend API, and utility functions, focusing on seamless premium tier transitions and better user feedback.

Changes

File Change Summary
apps/web/app/(app)/premium/Pricing.tsx Added toast notifications, improved plan switching logic, updated anchor element behavior
apps/web/app/(app)/premium/config.ts Added variantIdToTier and tierToVariantId mappings, introduced getSubscriptionTier and getVariantId functions
apps/web/app/api/lemon-squeezy/api.ts Added switchPremiumPlan function, enhanced logging for subscription updates
apps/web/app/api/lemon-squeezy/webhook/route.ts Added subscriptionPlanChanged handler, updated existing webhook functions, refactored subscription creation logic
apps/web/app/api/lemon-squeezy/webhook/types.ts Added "subscription_plan_changed" to EventName type
apps/web/utils/actions/premium.ts Added switchPremiumPlanAction for plan switching
apps/web/utils/premium/server.ts Updated cancelPremium function with enhanced parameter handling
packages/loops/src/loops.ts Added switchedPremiumPlan event tracking function

Sequence Diagram

sequenceDiagram
    participant User
    participant Pricing
    participant PremiumAction
    participant LemonSqueezyAPI
    participant Webhook

    User->>Pricing: Click Switch Plan
    Pricing->>PremiumAction: switchPremiumPlanAction
    PremiumAction->>LemonSqueezyAPI: switchPremiumPlan
    LemonSqueezyAPI-->>Webhook: Trigger subscription_plan_changed
    Webhook->>Webhook: Process subscription change
    Pricing->>User: Show Toast Notification
Loading

Possibly related PRs

Poem

🐰 A Rabbit's Ode to Premium Plans 🎉

Switching tiers with just a click,
Sonner toasts that do the trick,
Lemon Squeezy dances light,
Premium paths now shining bright!
Hop along, upgrade with glee! 🚀


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (4)
apps/web/app/api/lemon-squeezy/webhook/route.ts (2)

153-188: Refactored subscription creation workflow
Delegating the core creation logic to handleSubscriptionCreated streamlines the code. Consider checking and logging Promise.allSettled partial rejections for better observability.


190-226: New subscriptionPlanChanged function
This is similar in structure to subscriptionCreated. If there is significant overlap, consider extracting common logic to reduce duplication.

apps/web/app/(app)/premium/config.ts (1)

192-218: Consider a lookup table or consistent type checks, plus improved error handling.

The switch-case is straightforward. You could also leverage a lookup table (or dictionary) keyed by environment variable to reduce duplication. Additionally, ensure that the thrown error is caught or handled in upstream calls to avoid unhandled promise rejections.

apps/web/app/(app)/premium/Pricing.tsx (1)

260-284: Handle plan switching with user feedback.

Using toast.promise is an elegant approach to surface loading, success, and error states. Consider adding a fallback or additional error context if switchPremiumPlanAction rejects unexpectedly (such as network/time-out issues).

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bd0ec3d and b9dadb6.

📒 Files selected for processing (8)
  • apps/web/app/(app)/premium/Pricing.tsx (5 hunks)
  • apps/web/app/(app)/premium/config.ts (2 hunks)
  • apps/web/app/api/lemon-squeezy/api.ts (3 hunks)
  • apps/web/app/api/lemon-squeezy/webhook/route.ts (6 hunks)
  • apps/web/app/api/lemon-squeezy/webhook/types.ts (1 hunks)
  • apps/web/utils/actions/premium.ts (2 hunks)
  • apps/web/utils/premium/server.ts (1 hunks)
  • packages/loops/src/loops.ts (1 hunks)
🔇 Additional comments (22)
apps/web/app/api/lemon-squeezy/webhook/route.ts (7)

15-19: New import of switchedPremiumPlan
These imports from @inboxzero/loops provide additional event functionality.


21-23: Important imports for tier resolution and logging
You now have getSubscriptionTier and a scoped logger, ensuring clearer subscription tier handling and better traceability.


84-94: Added handling for subscription_plan_changed
This block correctly checks for userId, logs the error if missing, and delegates processing to subscriptionPlanChanged.


102-102: Forwarding variantId in subscriptionCancelled
Passing variantId helps in accurately identifying the plan variant for cancellation.


112-112: Consistent variantId usage on payment failure
Including variantId for payment failures ensures uniform cancellation logic.


Line range hint 228-255: Centralized handleSubscriptionCreated
Good approach: centralizing the upgrade logic and automatically deriving the tier using getSubscriptionTier.


360-374: Enhanced subscriptionCancelled
Introducing variantId and skipping cancellation when the database record is absent properly handles changed-plan scenarios.

apps/web/app/api/lemon-squeezy/api.ts (6)

9-9: Imported updateSubscription
Enables the ability to update subscription plans.


11-11: Added createScopedLogger import
Maintains a custom logger context for “Lemon Squeezy” operations.


13-13: Initializing scoped logger
Tracks API calls under a coherent “Lemon Squeezy” label.


29-29: Logging in updateSubscriptionItemQuantity
Improves traceability for subscription item changes.


46-46: Logging license key activation
Provides a clearer audit trail for license activation events.


50-57: New switchPremiumPlan function
Updates a subscription with a given variant, enabling plan switching.

packages/loops/src/loops.ts (1)

58-71: Added switchedPremiumPlan
Allows tracking plan switches within Loops to maintain robust analytics and event history.

apps/web/app/api/lemon-squeezy/webhook/types.ts (1)

18-19: Included subscription_plan_changed in EventName
Ensures strongly typed event handling for plan-change scenarios.

apps/web/utils/premium/server.ts (1)

74-97: Extended cancelPremium to accept variantId
Checks for a matching premium record before proceeding, which gracefully handles the case when the user switches plans.

apps/web/app/(app)/premium/config.ts (1)

45-54: Ensure environment variables are defined and correctly typed.

These new mappings retrieve numeric IDs from environment variables. If any of these are missing or not valid integers, the app might behave unpredictably. Consider validating these variables, or at least logging a warning if they’re missing.

✅ Verification successful

Let me check the environment variable definitions in the codebase.


Environment variables are properly validated with default values

The environment variables used in tierToVariantId are properly validated using @t3-oss/env-nextjs with Zod schema validation. Looking at apps/web/env.ts, all variant IDs are:

  • Coerced to numbers using z.coerce.number()
  • Have a default value of 0 using .default(0)

This means:

  • Type safety is enforced through Zod validation
  • Missing values will default to 0 instead of undefined
  • The app won't crash due to missing environment variables
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Validate presence of environment variables used in tierToVariantId
# Checking that they are set and numeric.

vars=(
  "NEXT_PUBLIC_BASIC_MONTHLY_VARIANT_ID"
  "NEXT_PUBLIC_BASIC_ANNUALLY_VARIANT_ID"
  "NEXT_PUBLIC_PRO_MONTHLY_VARIANT_ID"
  "NEXT_PUBLIC_PRO_ANNUALLY_VARIANT_ID"
  "NEXT_PUBLIC_BUSINESS_MONTHLY_VARIANT_ID"
  "NEXT_PUBLIC_BUSINESS_ANNUALLY_VARIANT_ID"
  "NEXT_PUBLIC_COPILOT_MONTHLY_VARIANT_ID"
  "NEXT_PUBLIC_LIFETIME_VARIANT_ID"
)

for var in "${vars[@]}"; do
  val=$(printenv "$var")
  if [[ -z "$val" ]]; then
    echo "Missing: $var"
  elif ! [[ "$val" =~ ^[0-9]+$ ]]; then
    echo "Not numeric: $var=$val"
  fi
done

Length of output: 2704


Script:

#!/bin/bash
# Check for environment variable definitions in common configuration files
fd -t f "env|.env" -x cat {} \; 2>/dev/null

# Also check if there's any validation logic for these variables
rg -l "NEXT_PUBLIC.*VARIANT_ID"

Length of output: 10879

apps/web/utils/actions/premium.ts (1)

14-21: Imports appear correct.

These import statements cleanly bring in dependencies, and the references align with the new code changes. No further actions needed.

apps/web/app/(app)/premium/Pricing.tsx (4)

4-4: Toast import successfully integrated for better UX feedback.

Import of toast from "sonner" is a nice addition to give visible feedback to users during plan changes.


27-28: Imports are consistent with newly introduced actions.

Bringing switchPremiumPlanAction and isActionError aligns with the new premium plan switching logic. Looks good.


177-177: Clarity in comparing current vs. selected plan.

const isCurrentPlan = tier.tiers[frequency.value] === premiumTier; succinctly checks if the user’s plan matches. This is straightforward and readable.


293-297: Excellent user-friendly plan status messaging.

Differentiating text based on whether it’s the current plan or a switch action helps users understand their subscription state more clearly.

Comment on lines 179 to 202
export const switchPremiumPlanAction = withActionInstrumentation(
"switchPremiumPlan",
async (premiumTier: PremiumTier) => {
const session = await auth();
if (!session?.user.id) return { error: "Not logged in" };

const user = await prisma.user.findUnique({
where: { id: session.user.id },
select: {
premium: {
select: { lemonSqueezySubscriptionId: true },
},
},
});

if (!user) return { error: "User not found" };
if (!user.premium?.lemonSqueezySubscriptionId)
return { error: "You do not have a premium subscription" };

const variantId = tierToVariantId[premiumTier];

await switchPremiumPlan(user.premium.lemonSqueezySubscriptionId, variantId);
},
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Validate subscription ID and handle switch errors gracefully.

This new switchPremiumPlanAction function checks if the user is premium, retrieves the subscription, and calls switchPremiumPlan. Consider:

  1. Handling any thrown error from switchPremiumPlan.
  2. Verifying that variantId is valid to avoid runtime issues.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
apps/web/app/(app)/premium/config.ts (1)

202-216: Enhance utility functions with better error handling and type safety

The utility functions could benefit from improved error handling and type safety:

  1. Error messages could be more descriptive by including available options.
  2. Input validation could prevent runtime errors.
  3. TypeScript types could be more strict.

Apply this diff to enhance the functions:

+type GetSubscriptionTierParams = {
+  variantId: number | undefined | null;
+};
+
 export function getSubscriptionTier({
   variantId,
-}: {
-  variantId: number;
-}): PremiumTier {
+}: GetSubscriptionTierParams): PremiumTier {
+  if (!variantId) {
+    throw new Error('Variant ID is required');
+  }
   const tier = variantIdToTier[variantId];
-  if (!tier) throw new Error(`Unknown variant id: ${variantId}`);
+  if (!tier) {
+    const availableIds = Object.keys(variantIdToTier).join(', ');
+    throw new Error(
+      `Unknown variant id: ${variantId}. Available ids: ${availableIds}`
+    );
+  }
   return tier;
 }

-export function getVariantId({ tier }: { tier: PremiumTier }): number {
+type GetVariantIdParams = {
+  tier: PremiumTier | undefined | null;
+};
+
+export function getVariantId({ tier }: GetVariantIdParams): number {
+  if (!tier) {
+    throw new Error('Premium tier is required');
+  }
   const variantId = tierToVariantId[tier];
-  if (!variantId) throw new Error(`Unknown tier: ${tier}`);
+  if (!variantId) {
+    const availableTiers = Object.values(PremiumTier).join(', ');
+    throw new Error(
+      `Unknown tier: ${tier}. Available tiers: ${availableTiers}`
+    );
+  }
   return variantId;
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b9dadb6 and cc9fa0d.

📒 Files selected for processing (2)
  • apps/web/app/(app)/premium/config.ts (2 hunks)
  • apps/web/utils/actions/premium.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web/utils/actions/premium.ts
🔇 Additional comments (1)
apps/web/app/(app)/premium/config.ts (1)

Line range hint 45-216: Verify the usage of tier mapping functions

Since these functions are used across multiple files for premium plan switching, let's verify their usage and potential impact.

✅ Verification successful

The tier mapping implementation is consistent and properly handles all tiers

The verification shows that:

  1. The PremiumTier enum in the schema includes all tiers including LIFETIME
  2. The tierToVariantId mapping correctly includes the LIFETIME tier with its variant ID
  3. The tier mapping functions getSubscriptionTier and getVariantId are used consistently in:
    • Premium plan switching (premium.ts)
    • Webhook handling (webhook/route.ts)
  4. The tier ranking system in premium/index.ts properly includes all tiers with LIFETIME having the highest rank (8)

The implementation is complete and consistent across the codebase, with proper error handling for unknown tiers and variant IDs.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the usage of tier mapping functions and potential issues

# Check for usage of getSubscriptionTier and getVariantId
echo "Checking function usage..."
rg -A 2 "getSubscriptionTier|getVariantId" --type typescript

# Check for LIFETIME tier handling
echo "Checking LIFETIME tier handling..."
rg -A 2 "PremiumTier\.LIFETIME|\"LIFETIME\"" --type typescript

# Check for potential error handling of these functions
echo "Checking error handling..."
rg "try.*catch.*getSubscriptionTier|try.*catch.*getVariantId" --type typescript

Length of output: 517


Script:

#!/bin/bash
# Description: Verify the usage of tier mapping functions and potential issues

# Check for usage of getSubscriptionTier and getVariantId
echo "Checking function usage..."
rg "getSubscriptionTier|getVariantId"

# Check for LIFETIME tier handling
echo "Checking LIFETIME tier handling..."
rg "PremiumTier\.LIFETIME|\"LIFETIME\""

# Check for potential error handling of these functions
echo "Checking error handling..."
rg "try.*catch.*getSubscriptionTier|try.*catch.*getVariantId"

# Check for PremiumTier enum definition
echo "Checking PremiumTier enum..."
rg "enum PremiumTier"

Length of output: 2183


Script:

#!/bin/bash
# Let's check the PremiumTier enum definition and its values
echo "Checking PremiumTier enum definition..."
rg -A 10 "enum PremiumTier" apps/web/prisma/schema.prisma

# Let's also check the actual implementation of the premium tier logic
echo "Checking premium tier implementation..."
cat apps/web/utils/premium/index.ts

# Check if there are any other tier-to-variant mappings
echo "Checking for other tier mappings..."
rg "variantIdToTier|tierToVariantId"

Length of output: 3874

Comment on lines 45 to 64
const variantIdToTier: Record<number, PremiumTier> = {
[env.NEXT_PUBLIC_BASIC_MONTHLY_VARIANT_ID]: PremiumTier.BASIC_MONTHLY,
[env.NEXT_PUBLIC_BASIC_ANNUALLY_VARIANT_ID]: PremiumTier.BASIC_ANNUALLY,
[env.NEXT_PUBLIC_PRO_MONTHLY_VARIANT_ID]: PremiumTier.PRO_MONTHLY,
[env.NEXT_PUBLIC_PRO_ANNUALLY_VARIANT_ID]: PremiumTier.PRO_ANNUALLY,
[env.NEXT_PUBLIC_BUSINESS_MONTHLY_VARIANT_ID]: PremiumTier.BUSINESS_MONTHLY,
[env.NEXT_PUBLIC_BUSINESS_ANNUALLY_VARIANT_ID]: PremiumTier.BUSINESS_ANNUALLY,
[env.NEXT_PUBLIC_COPILOT_MONTHLY_VARIANT_ID]: PremiumTier.COPILOT_MONTHLY,
};

const tierToVariantId: Record<PremiumTier, number> = {
[PremiumTier.BASIC_MONTHLY]: env.NEXT_PUBLIC_BASIC_MONTHLY_VARIANT_ID,
[PremiumTier.BASIC_ANNUALLY]: env.NEXT_PUBLIC_BASIC_ANNUALLY_VARIANT_ID,
[PremiumTier.PRO_MONTHLY]: env.NEXT_PUBLIC_PRO_MONTHLY_VARIANT_ID,
[PremiumTier.PRO_ANNUALLY]: env.NEXT_PUBLIC_PRO_ANNUALLY_VARIANT_ID,
[PremiumTier.BUSINESS_MONTHLY]: env.NEXT_PUBLIC_BUSINESS_MONTHLY_VARIANT_ID,
[PremiumTier.BUSINESS_ANNUALLY]: env.NEXT_PUBLIC_BUSINESS_ANNUALLY_VARIANT_ID,
[PremiumTier.COPILOT_MONTHLY]: env.NEXT_PUBLIC_COPILOT_MONTHLY_VARIANT_ID,
[PremiumTier.LIFETIME]: env.NEXT_PUBLIC_LIFETIME_VARIANT_ID,
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Address inconsistencies in tier mappings

The mappings between variant IDs and tiers have several issues that need attention:

  1. The LIFETIME tier is missing in variantIdToTier but present in tierToVariantId, creating an asymmetric mapping.
  2. Environment variables lack type safety, which could lead to runtime errors if they're undefined.

Apply this diff to fix the issues:

 const variantIdToTier: Record<number, PremiumTier> = {
   [env.NEXT_PUBLIC_BASIC_MONTHLY_VARIANT_ID]: PremiumTier.BASIC_MONTHLY,
   [env.NEXT_PUBLIC_BASIC_ANNUALLY_VARIANT_ID]: PremiumTier.BASIC_ANNUALLY,
   [env.NEXT_PUBLIC_PRO_MONTHLY_VARIANT_ID]: PremiumTier.PRO_MONTHLY,
   [env.NEXT_PUBLIC_PRO_ANNUALLY_VARIANT_ID]: PremiumTier.PRO_ANNUALLY,
   [env.NEXT_PUBLIC_BUSINESS_MONTHLY_VARIANT_ID]: PremiumTier.BUSINESS_MONTHLY,
   [env.NEXT_PUBLIC_BUSINESS_ANNUALLY_VARIANT_ID]: PremiumTier.BUSINESS_ANNUALLY,
   [env.NEXT_PUBLIC_COPILOT_MONTHLY_VARIANT_ID]: PremiumTier.COPILOT_MONTHLY,
+  [env.NEXT_PUBLIC_LIFETIME_VARIANT_ID]: PremiumTier.LIFETIME,
 };

+// Ensure all variant IDs are defined
+const requiredVariantIds = [
+  env.NEXT_PUBLIC_BASIC_MONTHLY_VARIANT_ID,
+  env.NEXT_PUBLIC_BASIC_ANNUALLY_VARIANT_ID,
+  env.NEXT_PUBLIC_PRO_MONTHLY_VARIANT_ID,
+  env.NEXT_PUBLIC_PRO_ANNUALLY_VARIANT_ID,
+  env.NEXT_PUBLIC_BUSINESS_MONTHLY_VARIANT_ID,
+  env.NEXT_PUBLIC_BUSINESS_ANNUALLY_VARIANT_ID,
+  env.NEXT_PUBLIC_COPILOT_MONTHLY_VARIANT_ID,
+  env.NEXT_PUBLIC_LIFETIME_VARIANT_ID,
+] as const;
+
+if (requiredVariantIds.some(id => id === undefined)) {
+  throw new Error('Missing required variant IDs in environment variables');
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const variantIdToTier: Record<number, PremiumTier> = {
[env.NEXT_PUBLIC_BASIC_MONTHLY_VARIANT_ID]: PremiumTier.BASIC_MONTHLY,
[env.NEXT_PUBLIC_BASIC_ANNUALLY_VARIANT_ID]: PremiumTier.BASIC_ANNUALLY,
[env.NEXT_PUBLIC_PRO_MONTHLY_VARIANT_ID]: PremiumTier.PRO_MONTHLY,
[env.NEXT_PUBLIC_PRO_ANNUALLY_VARIANT_ID]: PremiumTier.PRO_ANNUALLY,
[env.NEXT_PUBLIC_BUSINESS_MONTHLY_VARIANT_ID]: PremiumTier.BUSINESS_MONTHLY,
[env.NEXT_PUBLIC_BUSINESS_ANNUALLY_VARIANT_ID]: PremiumTier.BUSINESS_ANNUALLY,
[env.NEXT_PUBLIC_COPILOT_MONTHLY_VARIANT_ID]: PremiumTier.COPILOT_MONTHLY,
};
const tierToVariantId: Record<PremiumTier, number> = {
[PremiumTier.BASIC_MONTHLY]: env.NEXT_PUBLIC_BASIC_MONTHLY_VARIANT_ID,
[PremiumTier.BASIC_ANNUALLY]: env.NEXT_PUBLIC_BASIC_ANNUALLY_VARIANT_ID,
[PremiumTier.PRO_MONTHLY]: env.NEXT_PUBLIC_PRO_MONTHLY_VARIANT_ID,
[PremiumTier.PRO_ANNUALLY]: env.NEXT_PUBLIC_PRO_ANNUALLY_VARIANT_ID,
[PremiumTier.BUSINESS_MONTHLY]: env.NEXT_PUBLIC_BUSINESS_MONTHLY_VARIANT_ID,
[PremiumTier.BUSINESS_ANNUALLY]: env.NEXT_PUBLIC_BUSINESS_ANNUALLY_VARIANT_ID,
[PremiumTier.COPILOT_MONTHLY]: env.NEXT_PUBLIC_COPILOT_MONTHLY_VARIANT_ID,
[PremiumTier.LIFETIME]: env.NEXT_PUBLIC_LIFETIME_VARIANT_ID,
};
const variantIdToTier: Record<number, PremiumTier> = {
[env.NEXT_PUBLIC_BASIC_MONTHLY_VARIANT_ID]: PremiumTier.BASIC_MONTHLY,
[env.NEXT_PUBLIC_BASIC_ANNUALLY_VARIANT_ID]: PremiumTier.BASIC_ANNUALLY,
[env.NEXT_PUBLIC_PRO_MONTHLY_VARIANT_ID]: PremiumTier.PRO_MONTHLY,
[env.NEXT_PUBLIC_PRO_ANNUALLY_VARIANT_ID]: PremiumTier.PRO_ANNUALLY,
[env.NEXT_PUBLIC_BUSINESS_MONTHLY_VARIANT_ID]: PremiumTier.BUSINESS_MONTHLY,
[env.NEXT_PUBLIC_BUSINESS_ANNUALLY_VARIANT_ID]: PremiumTier.BUSINESS_ANNUALLY,
[env.NEXT_PUBLIC_COPILOT_MONTHLY_VARIANT_ID]: PremiumTier.COPILOT_MONTHLY,
[env.NEXT_PUBLIC_LIFETIME_VARIANT_ID]: PremiumTier.LIFETIME,
};
// Ensure all variant IDs are defined
const requiredVariantIds = [
env.NEXT_PUBLIC_BASIC_MONTHLY_VARIANT_ID,
env.NEXT_PUBLIC_BASIC_ANNUALLY_VARIANT_ID,
env.NEXT_PUBLIC_PRO_MONTHLY_VARIANT_ID,
env.NEXT_PUBLIC_PRO_ANNUALLY_VARIANT_ID,
env.NEXT_PUBLIC_BUSINESS_MONTHLY_VARIANT_ID,
env.NEXT_PUBLIC_BUSINESS_ANNUALLY_VARIANT_ID,
env.NEXT_PUBLIC_COPILOT_MONTHLY_VARIANT_ID,
env.NEXT_PUBLIC_LIFETIME_VARIANT_ID,
] as const;
if (requiredVariantIds.some(id => id === undefined)) {
throw new Error('Missing required variant IDs in environment variables');
}
const tierToVariantId: Record<PremiumTier, number> = {
[PremiumTier.BASIC_MONTHLY]: env.NEXT_PUBLIC_BASIC_MONTHLY_VARIANT_ID,
[PremiumTier.BASIC_ANNUALLY]: env.NEXT_PUBLIC_BASIC_ANNUALLY_VARIANT_ID,
[PremiumTier.PRO_MONTHLY]: env.NEXT_PUBLIC_PRO_MONTHLY_VARIANT_ID,
[PremiumTier.PRO_ANNUALLY]: env.NEXT_PUBLIC_PRO_ANNUALLY_VARIANT_ID,
[PremiumTier.BUSINESS_MONTHLY]: env.NEXT_PUBLIC_BUSINESS_MONTHLY_VARIANT_ID,
[PremiumTier.BUSINESS_ANNUALLY]: env.NEXT_PUBLIC_BUSINESS_ANNUALLY_VARIANT_ID,
[PremiumTier.COPILOT_MONTHLY]: env.NEXT_PUBLIC_COPILOT_MONTHLY_VARIANT_ID,
[PremiumTier.LIFETIME]: env.NEXT_PUBLIC_LIFETIME_VARIANT_ID,
};

@elie222 elie222 merged commit 6724fbe into main Jan 1, 2025
2 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant