diff --git a/components/BottomHeader/index.tsx b/components/BottomHeader/index.tsx index 013b1f2a..ef9b4272 100644 --- a/components/BottomHeader/index.tsx +++ b/components/BottomHeader/index.tsx @@ -1,38 +1,55 @@ -import React, { MouseEventHandler, useContext, useEffect, useState } from 'react' -import { useCookies } from 'react-cookie' +import React from 'react' import { useRouter } from 'next/router' +import { useCookies } from 'react-cookie' +import { useSnapshot } from 'valtio' +import clonedeep from 'lodash.clonedeep' -import AppContext from '~context/AppContext' - -import * as AlertDialog from '@radix-ui/react-alert-dialog'; +import * as AlertDialog from '@radix-ui/react-alert-dialog' import Header from '~components/Header' import Button from '~components/Button' +import api from '~utils/api' +import { accountState } from '~utils/accountState' +import { appState, initialAppState } from '~utils/appState' + import { ButtonType } from '~utils/enums' import CrossIcon from '~public/icons/Cross.svg' - const BottomHeader = () => { - const { editable, setEditable, authenticated, setAuthenticated } = useContext(AppContext) - - const [username, setUsername] = useState(undefined) - const [cookies, _, removeCookie] = useCookies(['user']) + const account = useSnapshot(accountState) + const app = useSnapshot(appState) const router = useRouter() - useEffect(() => { - if (cookies.user) { - setAuthenticated(true) - setUsername(cookies.user.username) - } else { - setAuthenticated(false) + // Cookies + const [cookies] = useCookies(['user']) + const headers = (cookies.user != null) ? { + headers: { + 'Authorization': `Bearer ${cookies.user.access_token}` } - }, [cookies, setUsername, setAuthenticated]) + } : {} function deleteTeam(event: React.MouseEvent) { - // TODO: Implement deleting teams - console.log("Deleting team...") + if (appState.party.editable && appState.party.id) { + api.endpoints.parties.destroy(appState.party.id, headers) + .then(() => { + // Push to route + router.push('/') + + // Clean state + const resetState = clonedeep(initialAppState) + Object.keys(resetState).forEach((key) => { + appState[key] = resetState[key] + }) + + // Set party to be editable + appState.party.editable = true + }) + .catch((error) => { + console.error(error) + }) + } } const leftNav = () => { @@ -42,7 +59,7 @@ const BottomHeader = () => { } const rightNav = () => { - if (editable && router.route === '/p/[party]') { + if (app.party.editable && router.route === '/p/[party]') { return ( @@ -83,4 +100,4 @@ const BottomHeader = () => { ) } -export default BottomHeader \ No newline at end of file +export default BottomHeader diff --git a/components/CharacterGrid/index.tsx b/components/CharacterGrid/index.tsx index e1af247f..4a1eb463 100644 --- a/components/CharacterGrid/index.tsx +++ b/components/CharacterGrid/index.tsx @@ -1,5 +1,5 @@ /* eslint-disable react-hooks/exhaustive-deps */ -import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react' +import React, { useCallback, useEffect, useMemo, useState } from 'react' import { useCookies } from 'react-cookie' import { useSnapshot } from 'valtio' diff --git a/components/HeaderMenu/index.tsx b/components/HeaderMenu/index.tsx index c121d83f..389edfe0 100644 --- a/components/HeaderMenu/index.tsx +++ b/components/HeaderMenu/index.tsx @@ -1,6 +1,4 @@ -import './index.scss' - -import React, { useContext } from 'react' +import React from 'react' import Link from 'next/link' import LoginModal from '~components/LoginModal' @@ -12,6 +10,7 @@ import { useModal as useAboutModal } from '~utils/useModal' import AboutModal from '~components/AboutModal' +import './index.scss' interface Props { authenticated: boolean, diff --git a/components/LoginModal/index.tsx b/components/LoginModal/index.tsx index 79d7e7ab..a3c4763b 100644 --- a/components/LoginModal/index.tsx +++ b/components/LoginModal/index.tsx @@ -1,9 +1,9 @@ -import React, { useContext, useState } from 'react' +import React, { useState } from 'react' import { withCookies, Cookies } from 'react-cookie' import { createPortal } from 'react-dom' -import AppContext from '~context/AppContext' import api from '~utils/api' +import { accountState } from '~utils/accountState' import Button from '~components/Button' import Fieldset from '~components/Fieldset' @@ -12,8 +12,6 @@ import Overlay from '~components/Overlay' import './index.scss' -// import New from '../../../assets/new' - interface Props { cookies: Cookies close: () => void @@ -28,8 +26,6 @@ interface ErrorMap { const emailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ const LoginModal = (props: Props) => { - const { setAuthenticated } = useContext(AppContext) - const emailInput: React.RefObject = React.createRef() const passwordInput: React.RefObject = React.createRef() const form: React.RefObject[] = [emailInput, passwordInput] @@ -102,7 +98,11 @@ const LoginModal = (props: Props) => { } cookies.set('user', cookieObj, { path: '/'}) - setAuthenticated(true) + accountState.account.authorized = true + accountState.account.user = { + id: cookieObj.user_id, + username: cookieObj.username + } props.close() }, (error) => { diff --git a/components/PartySegmentedControl/index.tsx b/components/PartySegmentedControl/index.tsx index 29ff5ad4..18cc6c55 100644 --- a/components/PartySegmentedControl/index.tsx +++ b/components/PartySegmentedControl/index.tsx @@ -1,4 +1,4 @@ -import React, { useContext } from 'react' +import React from 'react' import './index.scss' import { appState } from '~utils/appState' diff --git a/components/SignupModal/index.tsx b/components/SignupModal/index.tsx index 82ba9a42..137217a8 100644 --- a/components/SignupModal/index.tsx +++ b/components/SignupModal/index.tsx @@ -1,9 +1,9 @@ -import React, { useContext, useState } from 'react' +import React, { useState } from 'react' import { withCookies, Cookies } from 'react-cookie' import { createPortal } from 'react-dom' -import AppContext from '~context/AppContext' import api from '~utils/api' +import { accountState } from '~utils/accountState' import Button from '~components/Button' import Fieldset from '~components/Fieldset' @@ -28,8 +28,6 @@ interface ErrorMap { const emailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ const SignupModal = (props: Props) => { - const { setAuthenticated } = useContext(AppContext) - const [formValid, setFormValid] = useState(false) const [errors, setErrors] = useState({ username: '', @@ -81,8 +79,12 @@ const SignupModal = (props: Props) => { .then((response) => { const cookies = props.cookies cookies.set('user', response.data.user, { path: '/'}) - - setAuthenticated(true) + + accountState.account.authorized = true + accountState.account.user = { + id: response.data.user.id, + username: response.data.user.username + } props.close() }, (error) => { diff --git a/components/SummonGrid/index.tsx b/components/SummonGrid/index.tsx index 9f9231ab..5f472e31 100644 --- a/components/SummonGrid/index.tsx +++ b/components/SummonGrid/index.tsx @@ -1,5 +1,5 @@ /* eslint-disable react-hooks/exhaustive-deps */ -import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react' +import React, { useCallback, useEffect, useMemo, useState } from 'react' import { useCookies } from 'react-cookie' import { useSnapshot } from 'valtio' diff --git a/components/TopHeader/index.tsx b/components/TopHeader/index.tsx index 4828f5b4..99bd9a54 100644 --- a/components/TopHeader/index.tsx +++ b/components/TopHeader/index.tsx @@ -1,35 +1,22 @@ -import React, { useContext, useEffect, useState } from 'react' +import React, { useEffect } from 'react' import { useCookies } from 'react-cookie' import { useRouter } from 'next/router' import clonedeep from 'lodash.clonedeep' +import { useSnapshot } from 'valtio' -import AppContext from '~context/AppContext' +import { accountState } from '~utils/accountState' import { appState, initialAppState } from '~utils/appState' import Header from '~components/Header' import Button from '~components/Button' import HeaderMenu from '~components/HeaderMenu' - const TopHeader = () => { - const { editable, setEditable, authenticated, setAuthenticated } = useContext(AppContext) - - const [username, setUsername] = useState(undefined) const [cookies, _, removeCookie] = useCookies(['user']) + const accountSnap = useSnapshot(accountState) const router = useRouter() - useEffect(() => { - if (cookies.user) { - setAuthenticated(true) - setUsername(cookies.user.username) - console.log(`Logged in as user "${cookies.user.username}"`) - } else { - setAuthenticated(false) - console.log('You are currently not logged in.') - } - }, [cookies, setUsername, setAuthenticated]) - function copyToClipboard() { const el = document.createElement('input') el.value = window.location.href @@ -58,8 +45,8 @@ const TopHeader = () => { function logout() { removeCookie('user') - setAuthenticated(false) - if (editable) setEditable(false) + accountState.authorized = false + appState.party.editable = false // TODO: How can we log out without navigating to root router.push('/') @@ -70,9 +57,9 @@ const TopHeader = () => { return (
- { (username) ? - : - + { (accountSnap.account.user) ? + : + }
) diff --git a/components/WeaponGrid/index.tsx b/components/WeaponGrid/index.tsx index 79893a0c..0be9798a 100644 --- a/components/WeaponGrid/index.tsx +++ b/components/WeaponGrid/index.tsx @@ -1,5 +1,5 @@ /* eslint-disable react-hooks/exhaustive-deps */ -import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react' +import React, { useCallback, useEffect, useMemo, useState } from 'react' import { useCookies } from 'react-cookie' import { useSnapshot } from 'valtio' diff --git a/context/AppContext.tsx b/context/AppContext.tsx deleted file mode 100644 index ab66c95c..00000000 --- a/context/AppContext.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { createContext } from 'react' - -const AppContext = createContext({ - authenticated: false, - editable: false, - setAuthenticated: (auth: boolean) => {}, - setEditable: (editable: boolean) => {} -}) - -export default AppContext \ No newline at end of file diff --git a/context/PartyContext.tsx b/context/PartyContext.tsx deleted file mode 100644 index 87599c19..00000000 --- a/context/PartyContext.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { createContext } from 'react' -import { TeamElement } from '~utils/enums' - -const PartyContext = createContext({ - id: '', - setId: (id: string) => {}, - slug: '', - setSlug: (slug: string) => {}, - element: TeamElement.Any, - setElement: (element: TeamElement) => {}, - editable: false, - setEditable: (editable: boolean) => {}, - hasExtra: false, - setHasExtra: (hasExtra: boolean) => {} -}) - -export default PartyContext \ No newline at end of file diff --git a/pages/_app.tsx b/pages/_app.tsx index 0ad5f753..81c1d965 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -1,24 +1,35 @@ -import '../styles/globals.scss' - -import { useState } from 'react' -import { CookiesProvider } from 'react-cookie' - -import Layout from '~components/Layout' -import AppContext from '~context/AppContext' +import { useEffect } from 'react' +import { useCookies, CookiesProvider } from 'react-cookie' import type { AppProps } from 'next/app' +import Layout from '~components/Layout' + +import { accountState } from '~utils/accountState' + +import '../styles/globals.scss' function MyApp({ Component, pageProps }: AppProps) { - const [authenticated, setAuthenticated] = useState(false) - const [editable, setEditable] = useState(false) + const [cookies] = useCookies(['user']) + + useEffect(() => { + if (cookies.user) { + console.log(`Logged in as user "${cookies.user.username}"`) + + accountState.account.authorized = true + accountState.account.user = { + id: cookies.user.user_id, + username: cookies.user.username + } + } else { + console.log(`You are not currently logged in.`) + } + }, [cookies.user]) return ( - - - - - + + + ) } diff --git a/pages/p/[party].tsx b/pages/p/[party].tsx index e43e2b07..1ac9a3d9 100644 --- a/pages/p/[party].tsx +++ b/pages/p/[party].tsx @@ -1,4 +1,4 @@ -import React, { useContext, useEffect, useState } from 'react' +import React from 'react' import { useRouter } from 'next/router' import Party from '~components/Party' diff --git a/utils/accountState.tsx b/utils/accountState.tsx index 3fdb86f4..46a917f6 100644 --- a/utils/accountState.tsx +++ b/utils/accountState.tsx @@ -5,14 +5,19 @@ interface AccountState { account: { authorized: boolean, - language: 'en' | 'jp' + language: 'en' | 'jp', + user: { + id: string, + username: string + } | undefined } } export const initialAccountState: AccountState = { account: { authorized: false, - language: 'en' + language: 'en', + user: undefined } } diff --git a/utils/api.tsx b/utils/api.tsx index f1cc9c85..e1d02c37 100644 --- a/utils/api.tsx +++ b/utils/api.tsx @@ -9,6 +9,7 @@ type IdEndpoint = ({ id }: { id: string }) => Promise> type IdWithObjectEndpoint = ({ id, object }: { id: string, object: string }) => Promise> type PostEndpoint = (object: {}, headers?: {}) => Promise> type PutEndpoint = (id: string, object: {}, headers?: {}) => Promise> +type DestroyEndpoint = (id: string, headers?: {}) => Promise> interface EndpointMap { getAll: CollectionEndpoint @@ -16,7 +17,7 @@ interface EndpointMap { getOneWithObject: IdWithObjectEndpoint create: PostEndpoint update: PutEndpoint - destroy: IdEndpoint + destroy: DestroyEndpoint } class Api { @@ -45,7 +46,7 @@ class Api { getOneWithObject: ({ id, object }: { id: string, object: string }) => axios.get(`${resourceUrl}/${id}/${object}`), create: (object: {}, headers?: {}) => axios.post(resourceUrl, object, headers), update: (id: string, object: {}, headers?: {}) => axios.put(`${resourceUrl}/${id}`, object, headers), - destroy: ({ id }: { id: string }) => axios.delete(`${resourceUrl}/${id}`) + destroy: (id: string, headers?: {}) => axios.delete(`${resourceUrl}/${id}`, headers) } as EndpointMap }