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

examples: improve with-supabase example #51442

Merged
merged 21 commits into from
Jun 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
df1f8b3
opt examples out of routing
dijonmusters Jun 17, 2023
c580bf4
add init and seed sql
dijonmusters Jun 18, 2023
c40eea3
Add some new styles
saltcod Jun 20, 2023
5d5d842
move protected route to _examples folder
dijonmusters Jun 20, 2023
98bc967
Merge branch 'canary' into chore/opt-examples-out-of-routing
dijonmusters Jun 20, 2023
b4e47d3
final cleanup
dijonmusters Jun 20, 2023
c4fa1c7
refactor logout flow to use Client Component
dijonmusters Jun 20, 2023
55a7eef
Merge branch 'canary' into chore/opt-examples-out-of-routing
dijonmusters Jun 20, 2023
503abf5
Merge branch 'canary' into chore/opt-examples-out-of-routing
dijonmusters Jun 20, 2023
554e2b2
Merge branch 'canary' into chore/opt-examples-out-of-routing
dijonmusters Jun 20, 2023
113cdf8
Update examples/with-supabase/app/_examples/protected-route/page.tsx
dijonmusters Jun 20, 2023
3001afa
Update examples/with-supabase/app/_examples/protected-route/page.tsx
dijonmusters Jun 20, 2023
09bee8f
Update examples/with-supabase/app/page.tsx
dijonmusters Jun 20, 2023
7fc4397
Update examples/with-supabase/app/page.tsx
dijonmusters Jun 20, 2023
6f56964
Merge branch 'canary' into chore/opt-examples-out-of-routing
dijonmusters Jun 20, 2023
c8d6b5b
Merge branch 'canary' into chore/opt-examples-out-of-routing
dijonmusters Jun 20, 2023
766376a
Merge branch 'canary' into chore/opt-examples-out-of-routing
dijonmusters Jun 21, 2023
47575b1
Merge branch 'canary' into chore/opt-examples-out-of-routing
dijonmusters Jun 21, 2023
f53d54b
Merge branch 'canary' into chore/opt-examples-out-of-routing
leerob Jun 21, 2023
02a357d
Merge branch 'canary' into chore/opt-examples-out-of-routing
dijonmusters Jun 21, 2023
4ca212d
Merge branch 'canary' into chore/opt-examples-out-of-routing
dijonmusters Jun 21, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
32 changes: 15 additions & 17 deletions examples/with-supabase/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,32 +11,30 @@ The Vercel deployment will guide you through creating a Supabase account and pro
## How to use

1. Create a [new Supabase project](https://database.new)
1. Run `npx create-next-app -e with-supabase myapp` to create a Next.js app using the Supabase Starter template
1. Run `cd myapp` to change into the app's directory
1. Run `npx create-next-app -e with-supabase` to create a Next.js app using the Supabase Starter template
1. Use `cd` to change into the app's directory
1. Run `npm install` to install dependencies
1. Rename `.env.local.example` to `.env.local` and update the values for `NEXT_PUBLIC_SUPABASE_URL` and `NEXT_PUBLIC_SUPABASE_ANON_KEY` from [your Supabase project's API settings](https://app.supabase.com/project/_/settings/api)
1. Run `npm run dev` to start the local development server

> Check out [the docs for Local Development](https://supabase.com/docs/guides/getting-started/local-development) to also run Supabase locally.

### Create Table and seed with data (optional)
### Create a Supabase client

Navigate to [your project's SQL Editor](https://app.supabase.com/project/_/sql), click `New query`, paste the following SQL 👇 and click `RUN`.
Check out the [`/app/_examples`](./app/_examples/) folder for an example of creating a Supabase client in:

```sql
create table if not exists todos (
id uuid default gen_random_uuid() primary key,
created_at timestamp with time zone default timezone('utc'::text, now()) not null,
title text,
is_complete boolean default false
);
- [Client Components](./app/_examples/client-component/page.tsx)
- [Server Components](./app/_examples/server-component/page.tsx)
- [Route Handlers](./app/_examples/route-handler/route.ts)
- [Server Actions](./app/_examples/server-action/page.tsx)

insert into todos(title)
values
('Create Supabase project'),
('Create Next.js app from Supabase Starter template'),
('Keeping building cool stuff!');
```
### Create `todo` table and seed with data (optional)

Navigate to [your project's SQL Editor](https://app.supabase.com/project/_/sql), click `New query`, paste the contents of the [init.sql](./supabase/migrations/20230618024722_init.sql) file and click `RUN`.

This will create a basic `todos` table, enable Row Level Security (RLS), and write RLS policies enabling `select` and `insert` actions for `authenticated` users.

To seed your `todos` table with some dummy data, run the contents of the [seed.sql](./supabase/seed.sql) file.

## Feedback and issues

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
'use client'

// TODO: Duplicate or move this file outside the `_examples` folder to make it a route

import { createClientComponentClient } from '@supabase/auth-helpers-nextjs'
import { useEffect, useState } from 'react'

Expand Down
81 changes: 81 additions & 0 deletions examples/with-supabase/app/_examples/protected-route/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// TODO: Duplicate or move this file outside the `_examples` folder to make it a route

import {
createServerActionClient,
createServerComponentClient,
} from '@supabase/auth-helpers-nextjs'
import { cookies } from 'next/headers'
import Image from 'next/image'
import { redirect } from 'next/navigation'

export default async function ProtectedRoute() {
const supabase = createServerComponentClient({ cookies })

const {
data: { user },
} = await supabase.auth.getUser()

if (!user) {
// This route can only be accessed by authenticated users.
// Unauthenticated users will be redirected to the `/login` route.
redirect('/login')
}

const signOut = async () => {
'use server'
const supabase = createServerActionClient({ cookies })
await supabase.auth.signOut()
redirect('/login')
}

return (
<div className="flex-1 flex flex-col max-w-3xl mt-24">
<h1 className="text-2xl mb-2 flex justify-between">
<span className="sr-only">Supabase and Next.js Starter Template</span>
</h1>

<div className="flex border-b py-3 text-sm text-neutral-100">
<div className="flex items-center justify-between w-full">
<code className="bg-neutral-700 px-3 py-1 rounded-lg text-sm">
Protected page
</code>
<span className="flex gap-4">
Hey, {user.email}! <span className="border-r"></span>{' '}
<form action={signOut}>
<button className="text-neutral-100">Logout</button>
</form>
</span>
</div>
</div>

<div className="flex gap-8 justify-center mt-12">
<Image
src="/supabase.svg"
alt="Supabase Logo"
width={225}
height={45}
priority
/>
<div className="border-l rotate-45 h-10"></div>
<Image
src="/next.svg"
alt="Vercel Logo"
width={150}
height={36}
priority
/>
</div>

<p className="text-3xl mx-auto max-w-2xl text-center mt-8 text-white">
The fastest way to get started building apps with{' '}
<strong>Supabase</strong> and <strong>Next.js</strong>
</p>

<div className="flex justify-center mt-12">
<span className="bg-neutral-100 py-3 px-6 rounded-lg font-mono text-sm text-neutral-900">
Get started by editing <strong>app/page.tsx</strong>
</span>
</div>
</div>
)
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// TODO: Duplicate or move this file outside the `_examples` folder to make it a route

import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs'
import { cookies } from 'next/headers'
import { NextResponse } from 'next/server'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// TODO: Duplicate or move this file outside the `_examples` folder to make it a route

import { createServerActionClient } from '@supabase/auth-helpers-nextjs'
import { revalidatePath } from 'next/cache'
import { cookies } from 'next/headers'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// TODO: Duplicate or move this file outside the `_examples` folder to make it a route

import { createServerComponentClient } from '@supabase/auth-helpers-nextjs'
import { cookies } from 'next/headers'

Expand Down
2 changes: 1 addition & 1 deletion examples/with-supabase/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export default function RootLayout({
return (
<html lang="en">
<body>
<main className="min-h-screen bg-gray-900 flex flex-col items-center">
<main className="min-h-screen bg-neutral-900 flex flex-col items-center">
{children}
</main>
</body>
Expand Down
21 changes: 10 additions & 11 deletions examples/with-supabase/app/login/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,17 @@ export default function Login() {

const handleSignIn = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault()
const { data, error } = await supabase.auth.signInWithPassword({
await supabase.auth.signInWithPassword({
email,
password,
})
console.log({ data, error })
router.push('/')
}

return (
<div className="flex-1 flex flex-col w-full max-w-sm justify-center gap-2">
{view === 'check-email' ? (
<p className="text-center text-gray-400">
<p className="text-center text-neutral-400">
Check <span className="font-bold text-white">{email}</span> to
continue signing up
</p>
Expand All @@ -45,21 +44,21 @@ export default function Login() {
className="flex-1 flex flex-col w-full max-w-sm justify-center gap-2"
onSubmit={view === 'sign-in' ? handleSignIn : handleSignUp}
>
<label className="text-md text-gray-400" htmlFor="email">
<label className="text-md text-neutral-400" htmlFor="email">
Email
</label>
<input
className="rounded-md px-4 py-2 bg-inherit border mb-6"
className="rounded-md px-4 py-2 bg-inherit border mb-6 text-neutral-100"
name="email"
onChange={(e) => setEmail(e.target.value)}
value={email}
placeholder="you@example.com"
/>
<label className="text-md text-gray-400" htmlFor="password">
<label className="text-md text-neutral-400" htmlFor="password">
Password
</label>
<input
className="rounded-md px-4 py-2 bg-inherit border mb-6"
className="rounded-md px-4 py-2 bg-inherit border mb-6 text-neutral-100"
type="password"
name="password"
onChange={(e) => setPassword(e.target.value)}
Expand All @@ -68,10 +67,10 @@ export default function Login() {
/>
{view === 'sign-in' ? (
<>
<button className="bg-green-700 rounded px-4 py-2 text-gray-200 mb-6">
<button className="bg-green-700 rounded px-4 py-2 text-neutral-200 mb-6">
Sign In
</button>
<p className="text-sm text-gray-500 text-center">
<p className="text-sm text-neutral-500 text-center">
Don't have an account?
<button
className="ml-1 text-white underline"
Expand All @@ -84,10 +83,10 @@ export default function Login() {
) : null}
{view === 'sign-up' ? (
<>
<button className="bg-green-700 rounded px-4 py-2 text-gray-200 mb-6">
<button className="bg-green-700 rounded px-4 py-2 text-neutral-200 mb-6">
Sign Up
</button>
<p className="text-sm text-gray-500 text-center">
<p className="text-sm text-neutral-500 text-center">
Already have an account?
<button
className="ml-1 text-white underline"
Expand Down
22 changes: 22 additions & 0 deletions examples/with-supabase/app/logout-button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
'use client'

import { createClientComponentClient } from '@supabase/auth-helpers-nextjs'
import { useRouter } from 'next/navigation'

export default function LogoutButton() {
const router = useRouter()

// Create a Supabase client configured to use cookies
const supabase = createClientComponentClient()

const signOut = async () => {
await supabase.auth.signOut()
router.push('/login')
}

return (
<button className="hover:underline" onClick={signOut}>
Logout
</button>
)
}