Files
coder/site/contexts/UserContext.tsx
T
Bryan 69d88b4a6d feat: Add Sign-out functionality (#46)
#37 implemented the Sign-_in_ flow, but there wasn't a Sign-_out_ flow as part of that PR (aside from letting the cookie expire... or manually deleting the cookie...), which is obviously not ideal.

This PR implements a basic sign-out flow, along with a very simple user dropdown:
![2022-01-21 18 09 14](https://user-images.githubusercontent.com/88213859/150620847-94e4d22f-1dcf-451e-8b4a-cec24702ea6c.gif)

Bringing in a few pruned down components for the `<UserDropdown />` to integrate into the `<NavBar />`.

In addition, this also implements a simple back-end API for `/logout` which just clears the session token.
2022-01-24 17:09:39 -08:00

75 lines
1.7 KiB
TypeScript

import { useRouter } from "next/router"
import React, { useContext, useEffect } from "react"
import useSWR from "swr"
import * as API from "../api"
export interface User {
readonly id: string
readonly username: string
readonly email: string
readonly created_at: string
}
export interface UserContext {
readonly error?: Error
readonly me?: User
readonly signOut: () => Promise<void>
}
const UserContext = React.createContext<UserContext>({
signOut: () => {
return Promise.reject("Sign out API not available")
},
})
export const useUser = (redirectOnError = false): UserContext => {
const ctx = useContext(UserContext)
const router = useRouter()
const requestError = ctx.error
useEffect(() => {
if (redirectOnError && requestError) {
// 'void' means we are ignoring handling the promise returned
// from router.push (and lets the linter know we're OK with that!)
void router.push({
pathname: "/login",
query: {
redirect: router.asPath,
},
})
}
}, [redirectOnError, requestError])
return ctx
}
export const UserProvider: React.FC = (props) => {
const router = useRouter()
const { data, error, mutate } = useSWR("/api/v2/users/me")
const signOut = async () => {
await API.logout()
// Tell SWR to invalidate the cache for the user endpoint
await mutate("/api/v2/users/me")
await router.push({
pathname: "/login",
query: {
redirect: router.asPath,
},
})
}
return (
<UserContext.Provider
value={{
error: error,
me: data,
signOut: signOut,
}}
>
{props.children}
</UserContext.Provider>
)
}