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

[bug] Subscribe a second time with a different plan causes "You are not currently subscribed to any plan." #366

Open
XiChenn opened this issue Aug 15, 2024 · 7 comments

Comments

@XiChenn
Copy link

XiChenn commented Aug 15, 2024

To reproduce:

  • Subscribe to "Hobby" plan
  • Subscribe to "Freelancer" plan
  • Click "Account", you will see "You are not currently subscribed to any plan."
  • Click "Pricing", buttons are "subscribe" instead of "manage"
@XiChenn XiChenn changed the title Subscribe a second time with a different plan causes "You are not currently subscribed to any plan." [bug] Subscribe a second time with a different plan causes "You are not currently subscribed to any plan." Aug 15, 2024
@k-thornton
Copy link
Contributor

k-thornton commented Aug 23, 2024

I also hit this early on in this template. It's due to the maybeSingle() in the query that gets the active subscriptions

export const getSubscription = cache(async (supabase: SupabaseClient) => {
const { data: subscription, error } = await supabase
.from('subscriptions')
.select('*, prices(*, products(*))')
.in('status', ['trialing', 'active'])
.maybeSingle();

0 subscriptions is ok, 1 subscription is ok, but >1 subscriptions throws an error and returns null. It's not terribly difficult to handle this by customizing the template, but I agree this was the biggest earliest roadblock I hit when using it too.

@Veeeetzzzz
Copy link

Veeeetzzzz commented Aug 31, 2024

+1 to having the same issue - it's what was said above but also, by default when a subscription ends it gets removed from your Stripe dashboard, but the subscriptions table doesn't delete the subscription record. It just changes the status to cancelled

image

I thought of two possible solutions and you can use either or both depending on your preference.

  • Modify utils/supabase/queries.ts with a new query that filters by user ID & then use it to determine if there's a valid sub.
  const { data: subscription, error } = await supabase
    .from('subscriptions')
    .select('*, prices(*, products(*))')
    .eq('user_id', user.id)  // Add this line to filter by user_id
    .in('status', ['trialing', 'active'])
    .maybeSingle();

  if (error) {
    console.error('Error fetching subscription:', error);
    throw error;
  }

  console.log('Fetched subscription:', subscription);
  return subscription;
});
  1. In Supabase set up a query to see all your cancelled subscriptions (i.e everyone who shouldn't have access)

SELECT
  *
FROM
  subscriptions
WHERE
  status NOT IN ('trialing', 'active');

Replace with the below to get rid of any cancelled subscriptions. Run manually or set up a job using pg_cron

DELETE FROM subscriptions
WHERE
  status NOT IN ('trialing', 'active');

@gbopola
Copy link

gbopola commented Sep 13, 2024

I think it's best to just create some logic that will cancel any current subscription and replace with the new one. That way you will always have just one subscription and this error won't persist.

@k-thornton
Copy link
Contributor

  • Modify utils/supabase/queries.ts with a new query that filters by user ID & then use it to determine if there's a valid sub.
  const { data: subscription, error } = await supabase
    .from('subscriptions')
    .select('*, prices(*, products(*))')
    .eq('user_id', user.id)  // Add this line to filter by user_id
    .in('status', ['trialing', 'active'])
    .maybeSingle();

  if (error) {
    console.error('Error fetching subscription:', error);
    throw error;
  }

  console.log('Fetched subscription:', subscription);
  return subscription;
});

This change actually shouldn't have any effect, because row-level security is set up on this table to only allow people to see their own entries, and no others. This means the .eq('user_id', user.id) is implicit and always happens.

Similarly, the record changing to "canceled" status will also remove it from the query (since it's filtered on ['trialing','active'], which means deletion should be unnecessary. The .maybeSingle() only cares about the outcome of the query, so as long as a given user doesn't have more than 1 subscription in 'trialing' or 'active' state, then it won't error out.

@k-thornton
Copy link
Contributor

I'd say the closest thing to a bug here is that there's no guard at all around allowing the user to trigger a Stripe checkout when they already have an active subscription.

Because the template breaks in a couple of places when this state occurs, some guard code should be put here to catch that state and return a getErrorRedirect instead

@k-thornton
Copy link
Contributor

posted a PR for how I'd fix this

@gbopola
Copy link

gbopola commented Sep 14, 2024

  • Modify utils/supabase/queries.ts with a new query that filters by user ID & then use it to determine if there's a valid sub.
  const { data: subscription, error } = await supabase
    .from('subscriptions')
    .select('*, prices(*, products(*))')
    .eq('user_id', user.id)  // Add this line to filter by user_id
    .in('status', ['trialing', 'active'])
    .maybeSingle();

  if (error) {
    console.error('Error fetching subscription:', error);
    throw error;
  }

  console.log('Fetched subscription:', subscription);
  return subscription;
});

This change actually shouldn't have any effect, because row-level security is set up on this table to only allow people to see their own entries, and no others. This means the .eq('user_id', user.id) is implicit and always happens.

Similarly, the record changing to "canceled" status will also remove it from the query (since it's filtered on ['trialing','active'], which means deletion should be unnecessary. The .maybeSingle() only cares about the outcome of the query, so as long as a given user doesn't have more than 1 subscription in 'trialing' or 'active' state, then it won't error out.

Oh I see what you mean. Makes more sense.

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

No branches or pull requests

4 participants