Merge pull request #51 from jedmund/user-settings

Refactor user settings
This commit is contained in:
Justin Edmund 2022-12-25 20:17:07 -08:00 committed by GitHub
commit d64e9824c0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 589 additions and 363 deletions

View file

@ -2,7 +2,7 @@
display: flex;
flex-direction: column;
gap: $unit * 2;
width: $unit * 60;
width: $unit * 64;
form {
display: flex;
@ -45,89 +45,6 @@
transform: translateX(21px);
}
}
.field {
align-items: center;
display: flex;
flex-direction: row;
gap: $unit * 2;
select {
background: no-repeat url('/icons/ArrowDark.svg'), $grey-90;
background-position-y: center;
background-position-x: 95%;
margin: 0;
width: 240px;
}
.left {
display: flex;
flex-direction: column;
flex-grow: 1;
gap: calc($unit / 2);
label {
color: var(--text-secondary);
font-size: $font-regular;
}
p {
color: var(--text-secondary);
font-size: $font-small;
line-height: 1.1;
max-width: 300px;
&.jp {
max-width: 270px;
}
}
}
.preview {
$diameter: 48px;
background-color: $grey-90;
border-radius: 999px;
height: $diameter;
width: $diameter;
img {
height: $diameter;
width: $diameter;
}
&.fire {
background: $fire-bg-20;
}
&.water {
background: $water-bg-20;
}
&.wind {
background: $wind-bg-20;
}
&.earth {
background: $earth-bg-20;
}
&.dark {
background: $dark-bg-10;
}
&.light {
background: $light-bg-20;
}
}
}
section {
margin-bottom: $unit;
h2 {
margin-bottom: $unit * 3;
}
}
}
.DialogDescription {

View file

@ -1,74 +1,123 @@
import React, { useEffect, useState } from 'react'
import { getCookie } from 'cookies-next'
import { getCookie, setCookie } from 'cookies-next'
import { useRouter } from 'next/router'
import { useSnapshot } from 'valtio'
import { useTranslation } from 'next-i18next'
import * as Dialog from '@radix-ui/react-dialog'
import * as Switch from '@radix-ui/react-switch'
import {
Dialog,
DialogClose,
DialogContent,
DialogTitle,
DialogTrigger,
} from '~components/Dialog'
import Button from '~components/Button'
import SelectItem from '~components/SelectItem'
import PictureSelectItem from '~components/PictureSelectItem'
import SelectTableField from '~components/SelectTableField'
// import * as Switch from '@radix-ui/react-switch'
import api from '~utils/api'
import changeLanguage from 'utils/changeLanguage'
import { accountState } from '~utils/accountState'
import { pictureData } from '~utils/pictureData'
import Button from '~components/Button'
import CrossIcon from '~public/icons/Cross.svg'
import './index.scss'
import { useTheme } from 'next-themes'
const AccountModal = () => {
const { account } = useSnapshot(accountState)
type StateVariables = {
[key: string]: boolean
picture: boolean
gender: boolean
language: boolean
theme: boolean
}
const router = useRouter()
interface Props {
username?: string
picture?: string
gender?: number
language?: string
theme?: string
private?: boolean
}
const AccountModal = (props: Props) => {
// Localization
const { t } = useTranslation('common')
const router = useRouter()
const locale =
router.locale && ['en', 'ja'].includes(router.locale) ? router.locale : 'en'
// State
// useEffect only runs on the client, so now we can safely show the UI
const [mounted, setMounted] = useState(false)
const { theme: appTheme, setTheme: setAppTheme } = useTheme()
// Cookies
const accountCookie = getCookie('account')
const userCookie = getCookie('user')
const cookieData = {
account: accountCookie ? JSON.parse(accountCookie as string) : undefined,
user: userCookie ? JSON.parse(userCookie as string) : undefined,
}
// UI State
const [open, setOpen] = useState(false)
const [picture, setPicture] = useState('')
const [language, setLanguage] = useState('')
const [gender, setGender] = useState(0)
const [privateProfile, setPrivateProfile] = useState(false)
const [selectOpenState, setSelectOpenState] = useState<StateVariables>({
picture: false,
gender: false,
language: false,
theme: false,
})
// Refs
const pictureSelect = React.createRef<HTMLSelectElement>()
const languageSelect = React.createRef<HTMLSelectElement>()
const genderSelect = React.createRef<HTMLSelectElement>()
const privateSelect = React.createRef<HTMLInputElement>()
// Values
const [username, setUsername] = useState(props.username || '')
const [picture, setPicture] = useState(props.picture || '')
const [language, setLanguage] = useState(props.language || '')
const [gender, setGender] = useState(props.gender || 0)
const [theme, setTheme] = useState(props.theme || 'system')
// const [privateProfile, setPrivateProfile] = useState(false)
// useEffect(() => {
// if (cookies.user) setPicture(cookies.user.picture)
// if (cookies.user) setLanguage(cookies.user.language)
// if (cookies.user) setGender(cookies.user.gender)
// }, [cookies])
// Setup
const pictureOptions = pictureData
.sort((a, b) => (a.name.en > b.name.en ? 1 : -1))
.map((item, i) => {
return (
<option key={`picture-${i}`} value={item.filename}>
{item.name[locale]}
</option>
)
// UI management
function openChange(open: boolean) {
setOpen(open)
}
function openSelect(name: 'picture' | 'gender' | 'language' | 'theme') {
const stateVars = selectOpenState
Object.keys(stateVars).forEach((key) => {
if (key === name) {
stateVars[name] = true
} else {
stateVars[key] = false
}
})
function handlePictureChange(event: React.ChangeEvent<HTMLSelectElement>) {
if (pictureSelect.current) setPicture(pictureSelect.current.value)
setSelectOpenState(stateVars)
}
function handleLanguageChange(event: React.ChangeEvent<HTMLSelectElement>) {
if (languageSelect.current) setLanguage(languageSelect.current.value)
// Event handlers
function handlePictureChange(value: string) {
setPicture(value)
}
function handleGenderChange(event: React.ChangeEvent<HTMLSelectElement>) {
if (genderSelect.current) setGender(parseInt(genderSelect.current.value))
function handleLanguageChange(value: string) {
setLanguage(value)
}
function handlePrivateChange(checked: boolean) {
setPrivateProfile(checked)
function handleGenderChange(value: string) {
setGender(parseInt(value))
}
function handleThemeChange(value: string) {
setTheme(value)
setAppTheme(value)
}
// API calls
function update(event: React.FormEvent<HTMLFormElement>) {
event.preventDefault()
@ -78,172 +127,180 @@ const AccountModal = () => {
element: pictureData.find((i) => i.filename === picture)?.element,
language: language,
gender: gender,
private: privateProfile,
theme: theme,
// private: privateProfile,
},
}
// api.endpoints.users
// .update(cookies.account.user_id, object, headers)
// .then((response) => {
// const user = response.data.user
if (accountState.account.user) {
api.endpoints.users
.update(accountState.account.user?.id, object)
.then((response) => {
const user = response.data
// const cookieObj = {
// picture: user.picture.picture,
// element: user.picture.element,
// gender: user.gender,
// language: user.language,
// }
const cookieObj = {
picture: user.avatar.picture,
element: user.avatar.element,
gender: user.gender,
language: user.language,
theme: user.theme,
}
// setCookies("user", cookieObj, { path: "/" })
setCookie('user', cookieObj, { path: '/' })
// accountState.account.user = {
// id: user.id,
// username: user.username,
// picture: user.picture.picture,
// element: user.picture.element,
// gender: user.gender,
// }
accountState.account.user = {
id: user.id,
username: user.username,
picture: user.avatar.picture,
element: user.avatar.element,
language: user.language,
theme: user.theme,
gender: user.gender,
}
// setOpen(false)
// changeLanguage(user.language)
// })
setOpen(false)
changeLanguage(router, user.language)
})
}
}
function changeLanguage(newLanguage: string) {
// if (newLanguage !== router.locale) {
// setCookies("NEXT_LOCALE", newLanguage, { path: "/" })
// router.push(router.asPath, undefined, { locale: newLanguage })
// }
}
// Views
const pictureOptions = pictureData
.sort((a, b) => (a.name.en > b.name.en ? 1 : -1))
.map((item, i) => {
return (
<PictureSelectItem
key={`picture-${i}`}
element={item.element}
src={[
`/profile/${item.filename}.png`,
`/profile/${item.filename}@2x.png 2x`,
]}
value={item.filename}
>
{item.name[locale]}
</PictureSelectItem>
)
})
function openChange(open: boolean) {
setOpen(open)
const pictureField = () => (
<SelectTableField
name="picture"
description={t('modals.settings.descriptions.picture')}
className="Image"
label={t('modals.settings.labels.picture')}
open={selectOpenState.picture}
onClick={() => openSelect('picture')}
onChange={handlePictureChange}
imageAlt={t('modals.settings.labels.image_alt')}
imageClass={pictureData.find((i) => i.filename === picture)?.element}
imageSrc={[`/profile/${picture}.png`, `/profile/${picture}@2x.png 2x`]}
value={picture}
>
{pictureOptions}
</SelectTableField>
)
const genderField = () => (
<SelectTableField
name="gender"
description={t('modals.settings.descriptions.gender')}
label={t('modals.settings.labels.gender')}
open={selectOpenState.gender}
onClick={() => openSelect('gender')}
onChange={handleGenderChange}
value={`${gender}`}
>
<SelectItem key="gran" value="0">
{t('modals.settings.gender.gran')}
</SelectItem>
<SelectItem key="djeeta" value="1">
{t('modals.settings.gender.djeeta')}
</SelectItem>
</SelectTableField>
)
const languageField = () => (
<SelectTableField
name="language"
label={t('modals.settings.labels.language')}
open={selectOpenState.language}
onClick={() => openSelect('language')}
onChange={handleLanguageChange}
value={language}
>
<SelectItem key="en" value="en">
{t('modals.settings.language.english')}
</SelectItem>
<SelectItem key="ja" value="ja">
{t('modals.settings.language.japanese')}
</SelectItem>
</SelectTableField>
)
const themeField = () => (
<SelectTableField
name="theme"
label={t('modals.settings.labels.theme')}
open={selectOpenState.theme}
onClick={() => openSelect('theme')}
onChange={handleThemeChange}
value={theme}
>
<SelectItem key="system" value="system">
{t('modals.settings.theme.system')}
</SelectItem>
<SelectItem key="light" value="light">
{t('modals.settings.theme.light')}
</SelectItem>
<SelectItem key="dark" value="dark">
{t('modals.settings.theme.dark')}
</SelectItem>
</SelectTableField>
)
useEffect(() => {
setMounted(true)
}, [])
if (!mounted) {
return null
}
return (
<Dialog.Root open={open} onOpenChange={openChange}>
<Dialog.Trigger asChild>
<Dialog open={open} onOpenChange={openChange}>
<DialogTrigger asChild>
<li className="MenuItem">
<span>{t('menu.settings')}</span>
</li>
</Dialog.Trigger>
<Dialog.Portal>
<Dialog.Content
className="Account Dialog"
onOpenAutoFocus={(event) => event.preventDefault()}
>
<div className="DialogHeader">
<div className="DialogTop">
<Dialog.Title className="SubTitle">
{t('modals.settings.title')}
</Dialog.Title>
<Dialog.Title className="DialogTitle">
@{account.user?.username}
</Dialog.Title>
</div>
<Dialog.Close className="DialogClose" asChild>
<span>
<CrossIcon />
</span>
</Dialog.Close>
</DialogTrigger>
<DialogContent className="Account Dialog">
<div className="DialogHeader">
<div className="DialogTop">
<DialogTitle className="SubTitle">
{t('modals.settings.title')}
</DialogTitle>
<DialogTitle className="DialogTitle">@{username}</DialogTitle>
</div>
<DialogClose className="DialogClose" asChild>
<span>
<CrossIcon />
</span>
</DialogClose>
</div>
<form onSubmit={update}>
<div className="field">
<div className="left">
<label>{t('modals.settings.labels.picture')}</label>
</div>
<div
className={`preview ${
pictureData.find((i) => i.filename === picture)?.element
}`}
>
{picture ? (
<img
alt="Profile preview"
srcSet={`/profile/${picture}.png,
/profile/${picture}@2x.png 2x`}
src={`/profile/${picture}.png`}
/>
) : (
''
)}
</div>
<select
name="picture"
onChange={handlePictureChange}
value={picture}
ref={pictureSelect}
>
{pictureOptions}
</select>
</div>
<div className="field">
<div className="left">
<label>{t('modals.settings.labels.gender')}</label>
</div>
<select
name="gender"
onChange={handleGenderChange}
value={gender}
ref={genderSelect}
>
<option key="gran" value="0">
{t('modals.settings.gender.gran')}
</option>
<option key="djeeta" value="1">
{t('modals.settings.gender.djeeta')}
</option>
</select>
</div>
<div className="field">
<div className="left">
<label>{t('modals.settings.labels.language')}</label>
</div>
<select
name="language"
onChange={handleLanguageChange}
value={language}
ref={languageSelect}
>
<option key="en" value="en">
{t('modals.settings.language.english')}
</option>
<option key="jp" value="ja">
{t('modals.settings.language.japanese')}
</option>
</select>
</div>
<div className="field">
<div className="left">
<label>{t('modals.settings.labels.private')}</label>
<p className={locale}>
{t('modals.settings.descriptions.private')}
</p>
</div>
<Switch.Root
className="Switch"
onCheckedChange={handlePrivateChange}
checked={privateProfile}
>
<Switch.Thumb className="Thumb" />
</Switch.Root>
</div>
<Button
contained={true}
text={t('modals.settings.buttons.confirm')}
/>
</form>
</Dialog.Content>
<Dialog.Overlay className="Overlay" />
</Dialog.Portal>
</Dialog.Root>
<form onSubmit={update}>
{pictureField()}
{genderField()}
{languageField()}
{themeField()}
<Button
contained={true}
text={t('modals.settings.buttons.confirm')}
/>
</form>
</DialogContent>
</Dialog>
)
}

View file

@ -107,13 +107,6 @@ const AXSelect = (props: Props) => {
}, [props.currentSkills, setSecondaryAxModifier])
useEffect(() => {
console.log(
primaryAxModifier,
primaryAxValue,
secondaryAxModifier,
secondaryAxValue
)
let noErrors = false
if (errors.axValue1 === '' && errors.axValue2 === '') {
@ -132,13 +125,6 @@ const AXSelect = (props: Props) => {
secondaryAxValue > 0
)
noErrors = true
else
console.log(
primaryAxModifier >= 0,
primaryAxValue > 0,
secondaryAxModifier >= 0,
secondaryAxValue > 0
)
}
props.sendValidity(noErrors)

View file

@ -35,5 +35,6 @@ export const DialogContent = React.forwardRef<HTMLDivElement, Props>(
)
export const Dialog = DialogPrimitive.Root
export const DialogTitle = DialogPrimitive.Title
export const DialogTrigger = DialogPrimitive.Trigger
export const DialogClose = DialogPrimitive.Close

View file

@ -4,7 +4,7 @@
display: none;
min-width: 220px;
position: absolute;
top: $unit * 5; // This shouldn't be hardcoded. How to calculate it?
top: $unit * 5.75; // This shouldn't be hardcoded. How to calculate it?
// Also, add space that doesn't make the menu disappear if you move your mouse slowly
z-index: 10;
}

View file

@ -12,6 +12,7 @@ import LoginModal from '~components/LoginModal'
import SignupModal from '~components/SignupModal'
import './index.scss'
import { accountState } from '~utils/accountState'
interface Props {
authenticated: boolean
@ -59,8 +60,8 @@ const HeaderMenu = (props: Props) => {
<span>{accountData.username}</span>
<img
alt={userData.picture}
className={`profile ${userData.element}`}
srcSet={`/profile/${userData.picture}.png,
className={`profile ${accountState.account.user?.element}`}
srcSet={`/profile/${accountState.account.user?.picture}.png,
/profile/${userData.picture}@2x.png 2x`}
src={`/profile/${userData.picture}.png`}
/>
@ -85,7 +86,13 @@ const HeaderMenu = (props: Props) => {
</div>
<div className="MenuGroup">
<AboutModal />
<AccountModal />
<AccountModal
username={accountState.account.user?.username}
picture={accountState.account.user?.picture}
gender={accountState.account.user?.gender}
language={accountState.account.user?.language}
theme={accountState.account.user?.theme}
/>
<li className="MenuItem" onClick={props.logout}>
<span>{t('menu.logout')}</span>
</li>

View file

@ -16,6 +16,8 @@ import {
DialogClose,
} from '~components/Dialog'
import changeLanguage from '~utils/changeLanguage'
import CrossIcon from '~public/icons/Cross.svg'
import './index.scss'
@ -127,37 +129,38 @@ const LoginModal = (props: Props) => {
}
function storeUserInfo(response: AxiosResponse) {
// Extract the user
const user = response.data
const cookieObj: UserCookie = {
picture: user.avatar.picture,
element: user.avatar.element,
language: user.language,
gender: user.gender,
}
setCookie('user', cookieObj, { path: '/' })
// Set user data in the user cookie
setCookie(
'user',
{
picture: user.avatar.picture,
element: user.avatar.element,
language: user.language,
gender: user.gender,
theme: user.theme,
},
{ path: '/' }
)
// Set the user data in the account state
accountState.account.user = {
id: user.id,
username: user.username,
picture: user.avatar.picture,
element: user.avatar.element,
gender: user.gender,
language: user.language,
theme: user.theme,
}
console.log('Authorizing account...')
accountState.account.authorized = true
setOpen(false)
changeLanguage(user.language)
}
function changeLanguage(newLanguage: string) {
if (newLanguage !== router.locale) {
setCookie('NEXT_LOCALE', newLanguage, { path: '/' })
router.push(router.asPath, undefined, { locale: newLanguage })
}
changeLanguage(router, user.language)
}
function openChange(open: boolean) {

View file

@ -0,0 +1,42 @@
.SelectItem.Picture {
display: flex;
flex-direction: row;
gap: $unit;
align-items: center;
.preview {
$diameter: $unit-4x;
border-radius: $unit-2x;
width: $diameter;
height: $diameter;
img {
width: $diameter;
height: auto;
}
&.fire {
background: $fire-bg-20;
}
&.water {
background: $water-bg-20;
}
&.wind {
background: $wind-bg-20;
}
&.earth {
background: $earth-bg-20;
}
&.dark {
background: $dark-bg-10;
}
&.light {
background: $light-bg-20;
}
}
}

View file

@ -0,0 +1,35 @@
import React, { ComponentProps } from 'react'
import * as Select from '@radix-ui/react-select'
import './index.scss'
import classNames from 'classnames'
interface Props extends ComponentProps<'div'> {
src: string[]
element: string
value: string
}
const PictureSelectItem = React.forwardRef<HTMLDivElement, Props>(
function selectItem({ children, ...props }, forwardedRef) {
return (
<Select.Item
className={classNames('SelectItem Picture', props.className)}
{...props}
ref={forwardedRef}
value={`${props.value}`}
>
<div className={`preview ${props.element}`}>
<img
alt={`${props.value}`}
src={props.src[0]}
srcSet={props.src.join(', ')}
/>
</div>
<Select.ItemText>{children}</Select.ItemText>
</Select.Item>
)
}
)
export default PictureSelectItem

View file

@ -43,6 +43,10 @@
}
}
&.Table {
min-width: $unit * 30;
}
.SelectIcon {
display: flex;
align-items: center;

View file

@ -0,0 +1,69 @@
.TableField {
align-items: center;
display: grid;
gap: $unit * 2;
grid-template-columns: 1fr auto;
&.Image {
grid-template-columns: 1fr auto 1fr;
}
.Left {
display: flex;
flex-direction: column;
gap: calc($unit / 2);
label {
color: var(--text-tertiary);
font-size: $font-regular;
}
p {
color: var(--text-secondary);
font-size: $font-small;
line-height: 1.1;
max-width: 300px;
&.jp {
max-width: 270px;
}
}
}
.preview {
$diameter: $unit * 6;
background-color: $grey-90;
border-radius: 999px;
height: $diameter;
width: $diameter;
img {
height: $diameter;
width: $diameter;
}
&.fire {
background: $fire-bg-20;
}
&.water {
background: $water-bg-20;
}
&.wind {
background: $wind-bg-20;
}
&.earth {
background: $earth-bg-20;
}
&.dark {
background: $dark-bg-10;
}
&.light {
background: $light-bg-20;
}
}
}

View file

@ -0,0 +1,68 @@
import classNames from 'classnames'
import { useEffect, useState } from 'react'
import Select from '~components/Select'
import './index.scss'
interface Props {
name: string
label: string
description?: string
open: boolean
value?: string
className?: string
imageAlt?: string
imageClass?: string
imageSrc?: string[]
children: React.ReactNode
onClick: () => void
onChange: (value: string) => void
}
const SelectTableField = (props: Props) => {
const [value, setValue] = useState('')
useEffect(() => {
if (props.value) setValue(props.value)
}, [props.value])
const image = () => {
return props.imageSrc && props.imageSrc.length > 0 ? (
<div className={`preview ${props.imageClass}`}>
<img
alt={props.imageAlt}
srcSet={props.imageSrc.join(', ')}
src={props.imageSrc[0]}
/>
</div>
) : (
''
)
}
return (
<div className={classNames({ TableField: true }, props.className)}>
<div className="Left">
<h3>{props.label}</h3>
<p>{props.description}</p>
</div>
{image()}
<div className="Right">
<Select
name={props.name}
open={props.open}
onClick={props.onClick}
onValueChange={props.onChange}
triggerClass={classNames({ Bound: true, Table: true })}
value={value}
>
{props.children}
</Select>
</div>
</div>
)
}
export default SelectTableField

View file

@ -102,27 +102,36 @@ const SignupModal = (props: Props) => {
}
function storeUserInfo(response: AxiosResponse) {
// Extract the user
const user = response.data
const cookieObj: UserCookie = {
picture: user.avatar.picture,
element: user.avatar.element,
language: user.language,
gender: user.gender,
}
// TODO: Set language
setCookie('user', cookieObj, { path: '/' })
// Set user data in the user cookie
setCookie(
'user',
{
picture: user.avatar.picture,
element: user.avatar.element,
language: user.language,
gender: user.gender,
theme: user.theme,
},
{ path: '/' }
)
// Set the user data in the account state
accountState.account.user = {
id: user.id,
username: user.username,
picture: user.avatar.picture,
element: user.avatar.element,
gender: user.gender,
language: user.language,
theme: user.theme,
}
console.log('Authorizing account...')
accountState.account.authorized = true
setOpen(false)
}

View file

@ -106,12 +106,8 @@ const WeaponGrid = (props: Props) => {
.catch((error) => {
const code = error.response.status
const data = error.response.data
console.log(error.response)
console.log(data, code)
if (code === 422) {
if (data.code === 'incompatible_weapon_for_position') {
console.log('Here')
setShowIncompatibleAlert(true)
}
}
@ -339,7 +335,6 @@ const WeaponGrid = (props: Props) => {
}
const incompatibleAlert = () => {
console.log(t('alert.incompatible_weapon'))
return showIncompatibleAlert ? (
<Alert
open={showIncompatibleAlert}

View file

@ -1,7 +1,7 @@
import { useEffect } from 'react'
import { getCookie } from 'cookies-next'
import { useEffect, useState } from 'react'
import { getCookie, getCookies } from 'cookies-next'
import { appWithTranslation } from 'next-i18next'
import { ThemeProvider } from 'next-themes'
import { ThemeProvider, useTheme } from 'next-themes'
import type { AppProps } from 'next/app'
import Layout from '~components/Layout'
@ -12,27 +12,34 @@ import setUserToken from '~utils/setUserToken'
import '../styles/globals.scss'
function MyApp({ Component, pageProps }: AppProps) {
const cookie = getCookie('account')
const cookieData: AccountCookie = cookie ? JSON.parse(cookie as string) : null
const accountCookie = getCookie('account')
const userCookie = getCookie('user')
const cookieData = {
account: accountCookie ? JSON.parse(accountCookie as string) : undefined,
user: userCookie ? JSON.parse(userCookie as string) : undefined,
}
useEffect(() => {
setUserToken()
if (cookie) {
console.log(`Logged in as user "${cookieData.username}"`)
if (accountCookie) {
console.log(`Logged in as user "${cookieData.account.username}"`)
accountState.account.authorized = true
accountState.account.user = {
id: cookieData.userId,
username: cookieData.username,
picture: '',
element: '',
gender: 0,
id: cookieData.account.userId,
username: cookieData.account.username,
picture: cookieData.user.picture,
element: cookieData.user.element,
gender: cookieData.user.gender,
language: cookieData.user.language,
theme: cookieData.user.theme,
}
} else {
console.log(`You are not currently logged in.`)
}
}, [cookie, cookieData])
}, [])
return (
<ThemeProvider>

View file

@ -7,6 +7,7 @@ import Party from '~components/Party'
import { appState } from '~utils/appState'
import { groupWeaponKeys } from '~utils/groupWeaponKeys'
import organizeRaids from '~utils/organizeRaids'
import setUserToken from '~utils/setUserToken'
import api from '~utils/api'
import type { NextApiRequest, NextApiResponse } from 'next'
@ -48,38 +49,35 @@ export const getServerSidePaths = async () => {
// prettier-ignore
export const getServerSideProps = async ({ req, res, locale, query }: { req: NextApiRequest, res: NextApiResponse, locale: string, query: { [index: string]: string } }) => {
// Cookies
const cookie = getCookie("account", { req, res })
const accountData: AccountCookie = cookie
? JSON.parse(cookie as string)
: null
const headers = accountData
? { headers: { Authorization: `Bearer ${accountData.token}` } }
: {}
// Set headers for server-side requests
setUserToken(req, res)
let { raids, sortedRaids } = await api.endpoints.raids
.getAll()
.then((response) => organizeRaids(response.data))
let jobs = await api.endpoints.jobs
.getAll({ params: headers })
.getAll()
.then((response) => {
return response.data
})
let jobSkills = await api.allJobSkills(headers).then((response) => response.data)
let jobSkills = await api
.allJobSkills()
.then((response) => response.data)
let weaponKeys = await api.endpoints.weapon_keys
.getAll()
.then((response) => groupWeaponKeys(response.data))
let party: Party | null = null
if (query.party) {
let response = await api.endpoints.parties.getOne({ id: query.party, params: headers })
let response = await api.endpoints.parties.getOne({
id: query.party
})
party = response.data.party
} else {
console.log("No party code")
console.log('No party code')
}
return {
@ -90,7 +88,7 @@ export const getServerSideProps = async ({ req, res, locale, query }: { req: Nex
raids: raids,
sortedRaids: sortedRaids,
weaponKeys: weaponKeys,
...(await serverSideTranslations(locale, ["common"])),
...(await serverSideTranslations(locale, ['common'])),
// Will be passed to the page component as props
},
}

View file

@ -170,9 +170,12 @@
"picture": "Picture",
"language": "Language",
"gender": "Main Character",
"private": "Private"
"private": "Private",
"theme": "Theme"
},
"descriptions": {
"picture": "Displayed next to your name",
"gender": "The character shown on your teams",
"private": "Hide your profile and prevent your grids from showing up in collections"
},
"gender": {
@ -183,6 +186,11 @@
"english": "English",
"japanese": "Japanese"
},
"theme": {
"light": "Light",
"dark": "Dark",
"system": "Follow system"
},
"buttons": {
"confirm": "Save settings"
}

View file

@ -170,9 +170,12 @@
"picture": "プロフィール画像",
"language": "言語",
"gender": "主人公",
"private": "プライベート"
"private": "プライベート",
"theme": "表示"
},
"descriptions": {
"picture": "名前の隣に表示する",
"gender": "編成で表示するキャラクター",
"private": "プロフィールを隠し、編成をコレクションに表示されないようにします"
},
"gender": {
@ -183,6 +186,11 @@
"english": "英語",
"japanese": "日本語"
},
"theme": {
"light": "ライト",
"dark": "ダーク",
"system": "システム"
},
"buttons": {
"confirm": "設定を保存する"
}

View file

@ -126,7 +126,7 @@ $menu--text--light: $grey-90;
$menu--text--dark: $grey-50;
$menu--separator--light: $grey-90;
$menu--separator--dark: $grey-05;
$menu--item--bg--light--hover: $grey-90;
$menu--item--bg--light--hover: $grey-85;
$menu--item--bg--dark--hover: $grey-00;
$menu--text--light--hover: $grey-100;
$menu--text--dark--hover: $grey-15;

View file

@ -3,4 +3,5 @@ interface UserCookie {
element: string
language: string
gender: number
theme: string
}

View file

@ -1,19 +1,21 @@
import { proxy } from 'valtio'
export type UserState = {
id: string
username: string
picture: string
element: string
gender: number
language: string
theme: string
}
interface AccountState {
[key: string]: any
account: {
authorized: boolean
user:
| {
id: string
username: string
picture: string
element: string
gender: number
}
| undefined
user: UserState | undefined
}
}

12
utils/changeLanguage.tsx Normal file
View file

@ -0,0 +1,12 @@
import { setCookie } from 'cookies-next'
import { NextRouter } from 'next/router'
export default function changeLanguage(
router: NextRouter,
newLanguage: string
) {
if (newLanguage !== router.locale) {
setCookie('NEXT_LOCALE', newLanguage, { path: '/' })
router.push(router.asPath, undefined, { locale: newLanguage })
}
}

View file

@ -10,7 +10,6 @@ export type GroupedWeaponKeys = {
}
export function groupWeaponKeys(keys: WeaponKey[]) {
console.log(keys)
const numGroups = Math.max.apply(
Math,
keys.map((key) => key.group)
@ -28,7 +27,5 @@ export function groupWeaponKeys(keys: WeaponKey[]) {
groupedKeys[weaponKeyGroups[i].slug] = keys.filter((key) => key.group == i)
}
console.log(groupedKeys)
return groupedKeys
}