Update tabs for with-nextjs.mdx

This commit is contained in:
Joshen Lim committed 2022-11-01 23:35:44 +07:00
1 parent a7b5876c71
commit 98277bce3d
9 files changed
+178 -86

No files matched your search

@@ -1,4 +1,4 @@
import { getAnchor, removeAnchor } from './CustomMDX.utils'
import { getAnchor, removeAnchor } from './CustomHTMLElements.utils'
const H3 = ({ children }) => {
const anchor = getAnchor(children)
@@ -1,4 +1,4 @@
import { getAnchor, removeAnchor } from './CustomMDX.utils'
import { getAnchor, removeAnchor } from './CustomHTMLElements.utils'
const H4 = ({ children }) => {
const anchor = getAnchor(children)
@@ -0,0 +1,55 @@
import UserManagementSQLTemplate from './user_management_quickstart_sql_template.mdx'
## Project set up
Before we start building we're going to set up our Database and API. This is as simple as starting a new Project in Supabase
and then creating a "schema" inside the database.
### Create a project
1. Go to [app.supabase.com](https://app.supabase.com).
1. Click on "New Project".
1. Enter your project details.
1. Wait for the new database to launch.
### Set up the database schema
Now we are going to set up the database schema. We can use the "User Management Starter" quickstart in the SQL Editor,
or you can just copy/paste the SQL from below and run it yourself.
<Tabs
scrollable
size="small"
type="underlined"
defaultActiveId="dashboard"
>
<TabPanel id="dashboard" label="Dashboard">
1. Go to the [SQL Editor](https://app.supabase.com/project/_/sql) page in the Dashboard.
2. Click **User Management Starter**.
3. Click **Run**.
<video width="99%" muted playsInline controls="true">
<source src="/docs/videos/sql-user-management-starter.mp4" type="video/mp4" muted playsInline />
</video>
</TabPanel>
<TabPanel id="sql" label="SQL">
<UserManagementSQLTemplate />
</TabPanel>
</Tabs>
### Get the API Keys
Now that you've created some database tables, you are ready to insert data using the auto-generated API.
We just need to get the URL and `anon` key from the API settings.
1. Go to the [Settings](https://app.supabase.com/project/_/settings) page in the Dashboard.
2. Click **API** in the sidebar.
3. Find your API `URL`, `anon`, and `service_role` keys on this page.
<video width="99%" muted playsInline controls="true">
<source src="/docs/videos/api/api-url-and-key.mp4" type="video/mp4" muted playsInline />
</video>
@@ -0,0 +1,11 @@
## Intro
This example provides the steps to build a basic user management app. It includes:
- Supabase [Database](/docs/guides/database): a Postgres database for storing your user data.
- Supabase [Auth](/docs/guides/auth): users can sign in with magic links (no passwords, only email).
- Supabase [Storage](/docs/guides/storage): users can upload a photo.
- [Row Level Security](/docs/guides/auth#row-level-security): data is protected so that individuals can only access their own data.
- Instant [APIs](/docs/guides/api): APIs will be automatically generated when you create your database tables.
By the end of this guide you'll have an app which allows users to login and update some basic profile details:
@@ -0,0 +1,55 @@
```sql
-- Create a table for public profiles
create table profiles (
id uuid references auth.users not null primary key,
updated_at timestamp with time zone,
username text unique,
full_name text,
avatar_url text,
website text,
constraint username_length check (char_length(username) >= 3)
);
-- Set up Row Level Security (RLS)
-- See https://supabase.com/docs/guides/auth/row-level-security for more details.
alter table profiles
enable row level security;
create policy "Public profiles are viewable by everyone." on profiles
for select using (true);
create policy "Users can insert their own profile." on profiles
for insert with check (auth.uid() = id);
create policy "Users can update own profile." on profiles
for update using (auth.uid() = id);
-- This trigger automatically creates a profile entry when a new user signs up via Supabase Auth.
-- See https://supabase.com/docs/guides/auth/managing-user-data#using-triggers for more details.
create function public.handle_new_user()
returns trigger as $$
begin
insert into public.profiles (id, full_name, avatar_url)
values (new.id, new.raw_user_meta_data->>'full_name', new.raw_user_meta_data->>'avatar_url');
return new;
end;
$$ language plpgsql security definer;
create trigger on_auth_user_created
after insert on auth.users
for each row execute procedure public.handle_new_user();
-- Set up Storage!
insert into storage.buckets (id, name)
values ('avatars', 'avatars');
-- Set up access controls for storage.
-- See https://supabase.com/docs/guides/storage#policy-examples for more details.
create policy "Avatar images are publicly accessible." on storage.objects
for select using (bucket_id = 'avatars');
create policy "Anyone can upload an avatar." on storage.objects
for insert with check (bucket_id = 'avatars');
create policy "Anyone can update their own avatar." on storage.objects
for update using (auth.uid() = owner) with check (bucket_id = 'avatars');
```
+8 -2
View File
@@ -4,15 +4,21 @@ import CodeBlock from './CodeBlock/CodeBlock'
import ButtonCard from './ButtonCard'
import Frameworks from './Frameworks'
import AuthProviders from './AuthProviders'
import { H3, H4 } from './CustomMDX'
import { H3, H4 } from './CustomHTMLElements'
import QuickstartIntro from './MDX/quickstart_intro.mdx'
import ProjectSetup from './MDX/project_setup.mdx'
const components = {
Alert,
ButtonCard,
CodeBlock,
Frameworks,
AuthProviders,
QuickstartIntro,
ProjectSetup,
Alert,
Tabs,
TabPanel: (props: any) => <Tabs.Panel {...props}>{props.children}</Tabs.Panel>,
+47 -82
View File
@@ -7,12 +7,11 @@ sidebar_label: 'Next.js'
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
import QuickstartIntro from './_partials/quickstart_intro.md'
import ProjectSetup from './_partials/project_setup.mdx'
<QuickstartIntro />
![Supabase User Management example](/img/user-management-demo.png)
![Supabase User Management example](/docs/img/user-management-demo.png)
### Video Guide
@@ -41,28 +40,27 @@ We can use [`create-next-app`](https://nextjs.org/docs/getting-started) to initi
an app called `supabase-nextjs`:
<Tabs
groupId="language"
defaultValue="js"
values={[
{label: 'JavaScript', value: 'js'},
{label: 'TypeScript', value: 'ts'},
]}>
<TabItem value="js">
scrollable
size="small"
type="underlined"
defaultActiveId="js"
>
<TabPanel id="js" label="JavaScript">
```bash
npx create-next-app@latest --use-npm supabase-nextjs
cd supabase-nextjs
```
</TabItem>
<TabItem value="ts">
</TabPanel>
<TabPanel id="ts" label="TypeScript">
```bash
npx create-next-app@latest --ts --use-npm supabase-nextjs
cd supabase-nextjs
```
</TabItem>
</TabPanel>
</Tabs>
Then install the Supabase client library: [supabase-js](https://github.com/supabase/supabase-js)
@@ -97,13 +95,12 @@ npm install @supabase/auth-helpers-react @supabase/auth-helpers-nextjs
```
<Tabs
groupId="language"
defaultValue="js"
values={[
{label: 'JavaScript', value: 'js'},
{label: 'TypeScript', value: 'ts'},
]}>
<TabItem value="js">
scrollable
size="small"
type="underlined"
defaultActiveId="js"
>
<TabPanel id="js" label="JavaScript">
Wrap your `pages/_app.js` component with the `SessionContextProvider` component:
@@ -127,8 +124,8 @@ function MyApp({ Component, pageProps }) {
export default MyApp
```
</TabItem>
<TabItem value="ts">
</TabPanel>
<TabPanel id="ts" label="TypeScript">
Wrap your `pages/_app.tsx` component with the `SessionContextProvider` component:
@@ -160,7 +157,7 @@ export default MyApp
See the [Auth Helpers docs](/docs/guides/auth/auth-helpers/nextjs#usage-with-typescript) for more details on usage with TypeScript.
</TabItem>
</TabPanel>
</Tabs>
#### Supabase Auth UI
@@ -186,11 +183,7 @@ const Home = () => {
return (
<div className="container" style={{ padding: '50px 0 100px 0' }}>
{!session ? (
<Auth
supabaseClient={supabase}
appearance={{ theme: ThemeSupa }}
theme="dark"
/>
<Auth supabaseClient={supabase} appearance={{ theme: ThemeSupa }} theme="dark" />
) : (
<p>Account page will go here.</p>
)}
@@ -206,13 +199,12 @@ export default Home
After a user is signed in we can allow them to edit their profile details and manage their account.
<Tabs
groupId="language"
defaultValue="js"
values={[
{label: 'JavaScript', value: 'js'},
{label: 'TypeScript', value: 'ts'},
]}>
<TabItem value="js">
scrollable
size="small"
type="underlined"
defaultActiveId="js"
>
<TabPanel id="js" label="JavaScript">
Let's create a new component for that called `Account.js` within a `components` folder.
@@ -318,10 +310,7 @@ export default function Account({ session }) {
</div>
<div>
<button
className="button block"
onClick={() => supabase.auth.signOut()}
>
<button className="button block" onClick={() => supabase.auth.signOut()}>
Sign Out
</button>
</div>
@@ -330,18 +319,14 @@ export default function Account({ session }) {
}
```
</TabItem>
<TabItem value="ts">
</TabPanel>
<TabPanel id="ts" label="TypeScript">
Let's create a new component for that called `Account.tsx` within a `components` folder.
```tsx title="components/Account.tsx"
import { useState, useEffect } from 'react'
import {
useUser,
useSupabaseClient,
Session,
} from '@supabase/auth-helpers-react'
import { useUser, useSupabaseClient, Session } from '@supabase/auth-helpers-react'
import { Database } from '../utils/database.types'
type Profiles = Database['public']['Tables']['profiles']['Row']
@@ -453,10 +438,7 @@ export default function Account({ session }: { session: Session }) {
</div>
<div>
<button
className="button block"
onClick={() => supabase.auth.signOut()}
>
<button className="button block" onClick={() => supabase.auth.signOut()}>
Sign Out
</button>
</div>
@@ -465,7 +447,7 @@ export default function Account({ session }: { session: Session }) {
}
```
</TabItem>
</TabPanel>
</Tabs>
### Launch!
@@ -485,11 +467,7 @@ const Home = () => {
return (
<div className="container" style={{ padding: '50px 0 100px 0' }}>
{!session ? (
<Auth
supabaseClient={supabase}
appearance={{ theme: ThemeSupa }}
theme="dark"
/>
<Auth supabaseClient={supabase} appearance={{ theme: ThemeSupa }} theme="dark" />
) : (
// highlight-next-line
<Account session={session} />
@@ -519,13 +497,12 @@ photos and videos.
Let's create an avatar widget for the user so that they can upload a profile photo. We can start by creating a new component:
<Tabs
groupId="language"
defaultValue="js"
values={[
{label: 'JavaScript', value: 'js'},
{label: 'TypeScript', value: 'ts'},
]}>
<TabItem value="js">
scrollable
size="small"
type="underlined"
defaultActiveId="js"
>
<TabPanel id="js" label="JavaScript">
```jsx title="components/Avatar.js"
import React, { useEffect, useState } from 'react'
@@ -542,9 +519,7 @@ export default function Avatar({ uid, url, size, onUpload }) {
async function downloadImage(path) {
try {
const { data, error } = await supabase.storage
.from('avatars')
.download(path)
const { data, error } = await supabase.storage.from('avatars').download(path)
if (error) {
throw error
}
@@ -595,10 +570,7 @@ export default function Avatar({ uid, url, size, onUpload }) {
style={{ height: size, width: size }}
/>
) : (
<div
className="avatar no-image"
style={{ height: size, width: size }}
/>
<div className="avatar no-image" style={{ height: size, width: size }} />
)}
<div style={{ width: size }}>
<label className="button primary block" htmlFor="single">
@@ -621,8 +593,8 @@ export default function Avatar({ uid, url, size, onUpload }) {
}
```
</TabItem>
<TabItem value="ts">
</TabPanel>
<TabPanel id="ts" label="TypeScript">
```tsx title="components/Avatar.tsx"
import React, { useEffect, useState } from 'react'
@@ -651,9 +623,7 @@ export default function Avatar({
async function downloadImage(path: string) {
try {
const { data, error } = await supabase.storage
.from('avatars')
.download(path)
const { data, error } = await supabase.storage.from('avatars').download(path)
if (error) {
throw error
}
@@ -664,9 +634,7 @@ export default function Avatar({
}
}
const uploadAvatar: React.ChangeEventHandler<HTMLInputElement> = async (
event
) => {
const uploadAvatar: React.ChangeEventHandler<HTMLInputElement> = async (event) => {
try {
setUploading(true)
@@ -706,10 +674,7 @@ export default function Avatar({
style={{ height: size, width: size }}
/>
) : (
<div
className="avatar no-image"
style={{ height: size, width: size }}
/>
<div className="avatar no-image" style={{ height: size, width: size }} />
)}
<div style={{ width: size }}>
<label className="button primary block" htmlFor="single">
@@ -732,7 +697,7 @@ export default function Avatar({
}
```
</TabItem>
</TabPanel>
</Tabs>
### Add the new widget