mirror of
https://github.com/coder/coder.git
synced 2026-10-24 01:26:25 +08:00
#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:  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.
75 lines
1.7 KiB
TypeScript
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>
|
|
)
|
|
}
|