Skip to content

Commit e1faf14

Browse files
authored
feat: add new improved deploy button. (vercel#213)
* feat: add new improved deploy button. * fix: don't throw error when no subs. Closes vercel#212 * fix: only allow one subscription. * chore: delete duplicate styles. Closes vercel#206
1 parent ce74f66 commit e1faf14

File tree

8 files changed

+613
-739
lines changed

8 files changed

+613
-739
lines changed

README.md

+23-79
Original file line numberDiff line numberDiff line change
@@ -19,75 +19,42 @@ The all-in-one starter kit for high-performance SaaS applications.
1919

2020
![Architecture diagram](./public/architecture_diagram.svg)
2121

22-
## Step-by-step setup
22+
## Step-by-step setup
2323

2424
When deploying this template, the sequence of steps is important. Follow the steps below in order to get up and running.
2525

26-
The process is slightly different depending upon whether you start from Github or you start from Vercel, but it should work either way.
27-
28-
**Note:** We're working on our Stripe integration. We've documented the required steps below under "Configure Stripe" until the integration is ready.
29-
3026
### Initiate Deployment
3127

32-
#### Initiate Vercel Deployment
33-
34-
To get started from Github, click the "Deploy" button below. You may do this either from your own fork or from the [original template repo](https://github.com/vercel/nextjs-subscription-payments).
35-
36-
Vercel will prompt you to create a new Github repo. If you've used a fork, you may link your Vercel deployment to your existing fork by selecting "Import a different Git repository" from the left menu. If you've used the master template or started from the [Vercel website](https://vercel.com/new/promptly-technologies/templates/next.js/subscription-starter) instead of Github, you may allow Vercel to create a repo for you.
28+
- Redeploy
29+
- Create products and prices
3730

38-
#### Open a Codespace or clone the repo
31+
#### Vercel Deploy Button
3932

40-
Before proceeding with your Vercel deployment, you'll need to set up a [Supabase](https://supabase.com) project. For this step, it will be helpful to either open a Github codespace from your fork or clone the repo to your local machine. To clone the repo, use `git clone https://github.com/[your_username]/[your_repo_name]` and then `cd [your_repo_name]`.
33+
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fvercel%2Fnextjs-subscription-payments&env=NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY,STRIPE_SECRET_KEY&envDescription=Enter%20your%20Stripe%20API%20keys.&envLink=https%3A%2F%2Fdashboard.stripe.com%2Fapikeys&project-name=nextjs-subscription-payments&repository-name=nextjs-subscription-payments&integration-ids=oac_VqOgBHqhEoFTPzGkPd7L0iH6&external-id=https%3A%2F%2Fgithub.com%2Fvercel%2Fnextjs-subscription-payments%2Ftree%2Fmain)
4134

42-
### Set up Supabase
35+
The Vercel Deployment will create a new repository with this template on your GitHub account and guide your through a new Supabase project creation. The [Supabase Vercel Deploy Integration](https://vercel.com/integrations/supabase-v2) will set up the necessary Supabase environment variables and run the [SQL migrations](./supabase/migrations/20230530034630_init.sql) to set up the Database schema on your account. You can inspect the created tables in your project's [Table editor](https://app.supabase.com/project/_/editor).
4336

44-
#### Create a Supabase project
37+
Should the automatic setup fail, please [create a Supabase account](https://app.supabase.com/projects), and a new project if needed. In your project, navigate to the [SQL editor](https://app.supabase.com/project/_/sql) and select the "Stripe Subscriptions" starter template from the Quick start section.
4538

46-
On Supabase, create a Supabase account and create a project, with any name you like. Also generate an access token from https://app.supabase.com/account/tokens. You will need this later.
39+
### Configure Auth
4740

41+
In your Supabase project, navigate to [auth > URL configuration](https://app.supabase.com/project/_/auth/url-configuration) and set your main production URL (e.g. https://your-deployment-url.vercel.app) as the site url.
4842

49-
#### Run `schema.sql`
43+
Next, in your Vercel deployment settings, add a new **Production** environment variable called `NEXT_PUBLIC_SITE_URL` and set it to the same URL. Make sure to deselect preview and development environments to make sure that preview branches and local development work correctly.
5044

51-
From your Github fork, copy the code from `schema.sql`. In your Supabase project, navigate to the SQL editor, click `New Query`, paste the code, and run the code. This will create the necessary tables and RLS policies in your Supabase database.
45+
#### [Optional] - Set up redirect wildcards for deploy previews
5246

53-
#### Set up redirect wildcards for deploy previews
54-
55-
For auth redirects (magic links, OAuth providers) to work correctly in deploy previews, navigate to the auth settings (i.e. `https://app.supabase.com/project/:project-id/auth/url-configuration`) and add the following wildcard URL to "Redirect URLs": `https://**vercel.app/*/*`. (You can read more about redirect wildcard patterns in the [docs](https://supabase.com/docs/guides/auth#redirect-urls-and-wildcards).)
47+
For auth redirects (email confirmations, magic links, OAuth providers) to work correctly in deploy previews, navigate to the [auth settings](https://app.supabase.com/project/_/auth/url-configuration) and add the following wildcard URL to "Redirect URLs": `https://*-username.vercel.app/**`. You can read more about redirect wildcard patterns in the [docs](https://supabase.com/docs/guides/auth#redirect-urls-and-wildcards).
5648

5749
#### [Optional] - Set up OAuth providers
5850

59-
You can use third-party login providers like GitHub or Google. Refer to the [docs](https://supabase.io/docs/guides/auth#third-party-logins) to learn how to configure these. Once configured, you can add them to the `provider` array of the `Auth` component on the [`signin.tsx`](./pages/signin.tsx) page.
60-
61-
#### Generate types from your Supabase database
62-
63-
Now open a terminal in your codespace or cloned repo. You can use the [Supabase CLI](https://supabase.com/docs/reference/cli/usage#supabase-gen-types-typescript) to generate types from your Database by running:
64-
65-
1. To install Supabase cli
66-
67-
```bash
68-
npm install supabase --save-dev
69-
yarn add supabase --dev
70-
```
71-
72-
2. Connect to Supabase
73-
74-
```bash
75-
npx supabase login
76-
```
77-
78-
3. Enter the access token you created earlier. (As mentioned above, you can generate an access token from https://app.supabase.com/account/tokens.)
51+
You can use third-party login providers like GitHub or Google. Refer to the [docs](https://supabase.io/docs/guides/auth#third-party-logins) to learn how to configure these. Once configured, you can add them to the `provider` array of the [`Auth` component](./app/signin/AuthUI.tsx) page.
7952

80-
4. Generate types
53+
#### [Maybe Optional] - Set up Supabase environment variables (not needed if you installed via the Deploy Button)
8154

82-
```bash
83-
npx supabase gen types typescript --project-id [YOUR-PROJECT-REF] --schema public > types_db.ts
84-
```
85-
86-
#### Set up Supabase environment variables
87-
88-
Next, we need to set up environment variables for our Supabase project. We can copy these from `Supabase > Project Settings > API` and paste them into the Vercel deployment interface. Copy project API keys and paste into the `NEXT_PUBLIC_SUPABASE_ANON_KEY` and `SUPABASE_SERVICE_ROLE_KEY` fields, and copy the project URL and paste to Vercel as `NEXT_PUBLIC_SUPABASE_URL`.
55+
If you've deployed this template via the "Deploy to Vercel" button above, you can skip this step. Otherwise navigate to the [API settings](https://app.supabase.com/project/_/settings/api) and paste them into the Vercel deployment interface. Copy project API keys and paste into the `NEXT_PUBLIC_SUPABASE_ANON_KEY` and `SUPABASE_SERVICE_ROLE_KEY` fields, and copy the project URL and paste to Vercel as `NEXT_PUBLIC_SUPABASE_URL`.
8956

90-
This completes Supabase setup.
57+
Congrats, this completes the Supabase setup, almost there!
9158

9259
### Configure Stripe
9360

@@ -100,38 +67,15 @@ For the following steps, make sure you have the ["Test Mode" toggle](https://str
10067
We need to create a webhook in the `Developers` section of Stripe. Pictured in the architecture diagram above, this webhook is the piece that connects Stripe to your Vercel Serverless Functions.
10168

10269
1. Click the "Add Endpoint" button on the [test Endpoints page](https://dashboard.stripe.com/test/webhooks).
103-
1. Enter any placeholder text for the endpoint URL. (We will return later and change this to `https://your-deployment-url.vercel.app/api/webhooks` once we complete deployment to Vercel.)
70+
1. Enter your production deployment URL followed by `/api/webhooks` for the endpoint URL. (e.g. `https://your-deployment-url.vercel.app/api/webhooks`)
10471
1. Click `Select events` under the `Select events to listen to` heading.
10572
1. Click `Select all events` in the `Select events to send` section.
10673
1. Copy `Signing secret` as we'll need that in the next step.
74+
1. In addition to the `NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY` and the `STRIPE_SECRET_KEY` we've set earlier during deployment, we need to add the webhook secret as `STRIPE_WEBHOOK_SECRET` env var.
10775

108-
#### Set Stripe environment variables
109-
110-
To securely interact with Stripe, we need to add a few more [Environment Variables](https://vercel.com/docs/concepts/projects/environment-variables) in the Vercel deployment interface.
111-
112-
- `NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY`
113-
- `STRIPE_SECRET_KEY`
114-
- `STRIPE_WEBHOOK_SECRET_LIVE`
115-
116-
You can find the first two keys on the [API keys tab](https://dashboard.stripe.com/test/apikeys) in Stripe. The `STRIPE_WEBHOOK_SECRET_LIVE` is the `Signing secret` copied in the previous webhook configuration step.
117-
118-
### Complete deployment
119-
120-
#### Complete Vercel deployment
121-
122-
Once you've set your environment variables in the Vercel deployment interface, complete your deployment. Vercel may take a few minutes to build your application. It will then provide you with a domain URL for your deployment. Copy this URL and add it to .env.local:
123-
124-
```
125-
NEXT_PUBLIC_SITE_URL=https://your-deployment-url.vercel.app
126-
```
127-
128-
Keep the url on your clipboard, because you will also need it for the next step.
129-
130-
*NOTE:* Vercel assigns you a domain that is stable from deployment to redeployment (`https://your-deployment-url.vercel.app`) and a dynamic URL that changes every time you redploy (e.g., `https://your-deployment-url.vercel-12345678-your-organization.app`). You want to use the stable one, not the dynamic one!
131-
132-
#### Complete Stripe webhook configuration
76+
#### Redeploy with new env vars
13377

134-
Now that we have a deployment URL, we can complete our Stripe webhook configuration. Go back to the Stripe [test Webhooks page](https://dashboard.stripe.com/test/webhooks). Click your endpoint, and then click `... > Update Details`. In the `Endpoint URL` field, paste your deployment URL and add `/api/webhooks` to the end. For example, if your deployment URL is `https://your-deployment-url.vercel.app`, then your endpoint URL should be `https://your-deployment-url.vercel.app/api/webhooks`. Click `Update endpoint`.
78+
For the newly set environment variables to take effect and everything to work together correctly, we need to redeploy our app in Vercel. In your Vercel Dashboard, navigate to deployments, click the overflow menu button and select "Redeploy" (do NOT enable the "Use existing Build Cache" option). Once Vercel has rebuilt and redeployed your app, you're ready to set up your products and prices.
13579

13680
#### Create product and pricing information
13781

@@ -150,7 +94,7 @@ For example, you can create business models with different pricing tiers, e.g.:
15094

15195
Optionally, to speed up the setup, we have added a [fixtures file](fixtures/stripe-fixtures.json) to bootstrap test product and pricing data in your Stripe account. The [Stripe CLI](https://stripe.com/docs/stripe-cli#install) `fixtures` command executes a series of API requests defined in this JSON file. Simply run `stripe fixtures fixtures/stripe-fixtures.json`.
15296

153-
**Important:** Be sure webhook forwarding is active when you create your products, or the products created will not be imported into your database.
97+
**Important:** Make sure that you've configured your Stripe webhook correctly and redeployed with all needed environment variables.
15498

15599
#### Configure the Stripe customer portal
156100

@@ -164,7 +108,7 @@ Optionally, to speed up the setup, we have added a [fixtures file](fixtures/stri
164108

165109
### That's it
166110

167-
That's it. Now you're ready to earn recurring revenue from your customers. 🥳
111+
I know, that was quite a lot to get through, but it's worth it. You're now ready to earn recurring revenue from your customers. 🥳
168112

169113
## Develop locally
170114

@@ -227,7 +171,7 @@ To run the project in live mode and process payments with Stripe, switch Stripe
227171

228172
### Redeploy
229173

230-
Afterward, you will need to rebuild your production deployment for the changes to take effect. Within your project Dashboard, navigate to the "Deployments" tab, select the most recent deployment, click the overflow menu button (next to the "Visit" button) and select "Redeploy."
174+
Afterward, you will need to rebuild your production deployment for the changes to take effect. Within your project Dashboard, navigate to the "Deployments" tab, select the most recent deployment, click the overflow menu button (next to the "Visit" button) and select "Redeploy" (do NOT enable the "Use existing Build Cache" option).
231175

232176
To verify you are running in production mode, test checking out with the [Stripe test card](https://stripe.com/docs/testing). The test card should not work.
233177

app/api/webhooks/route.ts

+7-5
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@ const relevantEvents = new Set([
2121
export async function POST(req: Request) {
2222
const body = await req.text();
2323
const sig = headers().get('Stripe-Signature') as string;
24-
const webhookSecret =
25-
process.env.STRIPE_WEBHOOK_SECRET_LIVE ?? process.env.STRIPE_WEBHOOK_SECRET;
24+
const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET;
2625
let event: Stripe.Event;
2726

2827
try {
@@ -70,9 +69,12 @@ export async function POST(req: Request) {
7069
}
7170
} catch (error) {
7271
console.log(error);
73-
return new Response('Webhook handler failed. View logs.', {
74-
status: 400
75-
});
72+
return new Response(
73+
'Webhook handler failed. View your nextjs function logs.',
74+
{
75+
status: 400
76+
}
77+
);
7678
}
7779
}
7880
return new Response(JSON.stringify({ received: true }));

app/main.css

-52
This file was deleted.

app/supabase-provider.tsx

+5-6
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
'use client';
22

3-
import { createContext, useContext, useEffect, useState } from 'react';
3+
import type { Database } from '@/types_db';
44
import { createPagesBrowserClient } from '@supabase/auth-helpers-nextjs';
5-
import { useRouter } from 'next/navigation';
6-
75
import type { SupabaseClient } from '@supabase/auth-helpers-nextjs';
8-
import type { Database } from '@/types_db';
6+
import { useRouter } from 'next/navigation';
7+
import { createContext, useContext, useEffect, useState } from 'react';
98

109
type SupabaseContext = {
1110
supabase: SupabaseClient<Database>;
@@ -24,8 +23,8 @@ export default function SupabaseProvider({
2423
useEffect(() => {
2524
const {
2625
data: { subscription }
27-
} = supabase.auth.onAuthStateChange(() => {
28-
router.refresh();
26+
} = supabase.auth.onAuthStateChange((event) => {
27+
if (event === 'SIGNED_IN') router.refresh();
2928
});
3029

3130
return () => {

app/supabase-server.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export async function getSubscription() {
4141
.from('subscriptions')
4242
.select('*, prices(*, products(*))')
4343
.in('status', ['trialing', 'active'])
44-
.single()
44+
.maybeSingle()
4545
.throwOnError();
4646
return subscription;
4747
} catch (error) {

components/Pricing.tsx

+2-4
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ export default function Pricing({
5454
if (!user) {
5555
return router.push('/signin');
5656
}
57-
if (price.product_id === subscription?.prices?.products?.id) {
57+
if (subscription) {
5858
return router.push('/account');
5959
}
6060
try {
@@ -246,9 +246,7 @@ export default function Pricing({
246246
onClick={() => handleCheckout(price)}
247247
className="block w-full py-2 mt-8 text-sm font-semibold text-center text-white rounded-md hover:bg-zinc-900"
248248
>
249-
{product.name === subscription?.prices?.products?.name
250-
? 'Manage'
251-
: 'Subscribe'}
249+
{subscription ? 'Manage' : 'Subscribe'}
252250
</Button>
253251
</div>
254252
</div>

0 commit comments

Comments
 (0)