in progress: establishing auth context in new client side app
This commit is contained in:
848
client/package-lock.json
generated
848
client/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -9,8 +9,11 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"react": "^18.2.0",
|
"@supabase/supabase-js": "^1.35.7",
|
||||||
"react-dom": "^18.2.0"
|
"react": "^18.0.0",
|
||||||
|
"react-dom": "^18.0.0",
|
||||||
|
"react-router-dom": "^6.3.0",
|
||||||
|
"sass": "^1.52.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/react": "^18.0.17",
|
"@types/react": "^18.0.17",
|
||||||
|
|||||||
@@ -1,33 +1,18 @@
|
|||||||
import { useState } from 'react'
|
import { BrowserRouter, Route, Routes } from 'react-router-dom'
|
||||||
import reactLogo from './assets/react.svg'
|
import Home from './components/Home/Home'
|
||||||
|
import Register from './components/User/Register'
|
||||||
import './App.css'
|
import './App.css'
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [count, setCount] = useState(0)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="App">
|
<BrowserRouter>
|
||||||
<div>
|
<div className="App">
|
||||||
<a href="https://vitejs.dev" target="_blank">
|
<Routes>
|
||||||
<img src="/vite.svg" className="logo" alt="Vite logo" />
|
<Route path="/" element={<Home />} />
|
||||||
</a>
|
<Route path="/register" element={<Register />} />
|
||||||
<a href="https://reactjs.org" target="_blank">
|
</Routes>
|
||||||
<img src={reactLogo} className="logo react" alt="React logo" />
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
<h1>Vite + React</h1>
|
</BrowserRouter>
|
||||||
<div className="card">
|
|
||||||
<button onClick={() => setCount((count) => count + 1)}>
|
|
||||||
count is {count}
|
|
||||||
</button>
|
|
||||||
<p>
|
|
||||||
Edit <code>src/App.tsx</code> and save to test HMR
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<p className="read-the-docs">
|
|
||||||
Click on the Vite and React logos to learn more
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
9
client/src/components/Home/Home.tsx
Normal file
9
client/src/components/Home/Home.tsx
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
export default function Home() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>Vite + React + Supabase</h1>
|
||||||
|
<p>Check out the user stuff below:</p>
|
||||||
|
<a href="/register">User stuff</a>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
40
client/src/components/User/Register.tsx
Normal file
40
client/src/components/User/Register.tsx
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
import { createClient } from "@supabase/supabase-js";
|
||||||
|
import { useAuth } from "../../supabase/SupabaseContext";
|
||||||
|
|
||||||
|
const url = import.meta.env.VITE_SUPABASE_URL;
|
||||||
|
const key = import.meta.env.VITE_SUPABASE_KEY;
|
||||||
|
|
||||||
|
interface FormInput {
|
||||||
|
email: string
|
||||||
|
password: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Register() {
|
||||||
|
const [input, setInput] = useState<FormInput>({email: "", password: ""});
|
||||||
|
const { handleRegister, setUserData, setUserSession } = useAuth();
|
||||||
|
|
||||||
|
const handleClick = () => {
|
||||||
|
const { email, password } = input;
|
||||||
|
if (email && password) handleRegister(email, password, { setUserData, setUserSession });
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section>
|
||||||
|
<h1>Register</h1>
|
||||||
|
|
||||||
|
<form>
|
||||||
|
<div>
|
||||||
|
<label>Email:</label>
|
||||||
|
<input required type="text" onChange={(e) => setInput({...input, email: e.target.value})} />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label>Password:</label>
|
||||||
|
<input required type="text" onChange={(e) => setInput({...input, password: e.target.value})} />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<button onClick={handleClick}>Register</button>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
57
client/src/supabase/SupabaseContext.tsx
Normal file
57
client/src/supabase/SupabaseContext.tsx
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import { FunctionComponent, ReactPortal, createContext, useState, useContext, Dispatch, SetStateAction } from "react";
|
||||||
|
import { handleRegister, handleEmailLogin } from "./authHelpers";
|
||||||
|
import { createClient, SupabaseClient } from "@supabase/supabase-js";
|
||||||
|
|
||||||
|
const supabase = createClient(import.meta.env.VITE_SUPABASE_URL, import.meta.env.VITE_SUPABASE_KEY);
|
||||||
|
|
||||||
|
interface SupabaseContextData {
|
||||||
|
supabase: SupabaseClient
|
||||||
|
userSession?: any
|
||||||
|
setUserSession?: Dispatch<SetStateAction<any>>
|
||||||
|
userData?: any
|
||||||
|
setUserData?: Dispatch<SetStateAction<any>>
|
||||||
|
handleRegister: (email: string, password: string, authData: ReactAuthData) => Promise<AuthData>
|
||||||
|
handleEmailLogin: (email: string, password: string, authData: ReactAuthData) => Promise<AuthData>
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AuthData {
|
||||||
|
user?: any
|
||||||
|
session?: any
|
||||||
|
error?: any
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ReactAuthData {
|
||||||
|
userSession: any
|
||||||
|
setUserSession: Dispatch<SetStateAction<any>>
|
||||||
|
userData: any
|
||||||
|
setUserData: Dispatch<SetStateAction<any>>
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialState: SupabaseContextData = {
|
||||||
|
supabase: supabase,
|
||||||
|
userSession: undefined,
|
||||||
|
userData: undefined,
|
||||||
|
handleRegister: handleRegister,
|
||||||
|
handleEmailLogin: handleEmailLogin
|
||||||
|
}
|
||||||
|
|
||||||
|
const SupabaseContext = createContext<SupabaseContextData>(initialState);
|
||||||
|
|
||||||
|
export const SupabaseProvider: FunctionComponent<ReactPortal> = ({ children }) => {
|
||||||
|
const [userData, setUserData] = useState<any>();
|
||||||
|
const [userSession, setUserSession] = useState<any>();
|
||||||
|
|
||||||
|
const store = {
|
||||||
|
supabase, userData, setUserData, userSession, setUserSession, handleRegister, handleEmailLogin
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SupabaseContext.Provider value={store}>
|
||||||
|
{ children }
|
||||||
|
</SupabaseContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useAuth = () => {
|
||||||
|
return useContext(SupabaseContext);
|
||||||
|
}
|
||||||
1
client/src/supabase/SupabaseTypes.ts
Normal file
1
client/src/supabase/SupabaseTypes.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export default {}
|
||||||
54
client/src/supabase/authHelpers.ts
Normal file
54
client/src/supabase/authHelpers.ts
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import { SupabaseClient } from "@supabase/supabase-js";
|
||||||
|
import { ReactAuthData, useAuth } from "./SupabaseContext";
|
||||||
|
|
||||||
|
export const handleRegister = async (email: string, password: string, authData: ReactAuthData) => {
|
||||||
|
const { setUserData } = authData;
|
||||||
|
const { supabase } = useAuth();
|
||||||
|
|
||||||
|
const { user, session, error } = await supabase.auth.signUp({ email, password });
|
||||||
|
if (error) throw error;
|
||||||
|
if (user) setUserData(user);
|
||||||
|
|
||||||
|
return { user, session, error }
|
||||||
|
// SEE USER RETURN TYPE BELOW
|
||||||
|
/**
|
||||||
|
* object {
|
||||||
|
* app_metadata: {
|
||||||
|
* provider: string
|
||||||
|
* providers: string[]
|
||||||
|
* }
|
||||||
|
* aud: string
|
||||||
|
* confirmation_sent_at: string
|
||||||
|
* created_at: string
|
||||||
|
* email: string
|
||||||
|
* id: string
|
||||||
|
* identities: Identity[] // to define below
|
||||||
|
* phone: string?
|
||||||
|
* role: string
|
||||||
|
* updated_at: string
|
||||||
|
* user_metadata: object?
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* Identity = {
|
||||||
|
* created_at,
|
||||||
|
* id,
|
||||||
|
* identity_data: { sub: string },
|
||||||
|
* last_sign_in_at: string
|
||||||
|
* provider: email
|
||||||
|
* updated_at: string
|
||||||
|
* user_id: string
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
export const handleEmailLogin = async (email: string, password: string, authData: ReactAuthData) => {
|
||||||
|
const { setUserData, setUserSession } = authData;
|
||||||
|
const { supabase } = useAuth();
|
||||||
|
|
||||||
|
const { user, session, error } = await supabase.auth.signIn({ email, password });
|
||||||
|
if (error) throw error;
|
||||||
|
if (user) setUserData(user);
|
||||||
|
if (session) setUserSession(session);
|
||||||
|
|
||||||
|
return { user, session, error };
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user