diff --git a/components/AccountModal/index.tsx b/components/AccountModal/index.tsx index 9dc64075..6b081b20 100644 --- a/components/AccountModal/index.tsx +++ b/components/AccountModal/index.tsx @@ -1,211 +1,255 @@ -import React, { useEffect, useState } from 'react' -import { useCookies } from 'react-cookie' -import { useRouter } from 'next/router' -import { useSnapshot } from 'valtio' -import { useTranslation } from 'next-i18next' +import React, { useEffect, useState } from "react" +import { getCookie } 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 * as Dialog from "@radix-ui/react-dialog" +import * as Switch from "@radix-ui/react-switch" -import api from '~utils/api' -import { accountState } from '~utils/accountState' -import { pictureData } from '~utils/pictureData' +import api from "~utils/api" +import { accountState } from "~utils/accountState" +import { pictureData } from "~utils/pictureData" -import Button from '~components/Button' +import Button from "~components/Button" -import CrossIcon from '~public/icons/Cross.svg' -import './index.scss' +import CrossIcon from "~public/icons/Cross.svg" +import "./index.scss" const AccountModal = () => { - const { account } = useSnapshot(accountState) + const { account } = useSnapshot(accountState) - const router = useRouter() - const { t } = useTranslation('common') - const locale = (router.locale && ['en', 'ja'].includes(router.locale)) ? router.locale : 'en' + const router = useRouter() + const { t } = useTranslation("common") + const locale = + router.locale && ["en", "ja"].includes(router.locale) ? router.locale : "en" - // Cookies - const [cookies, setCookies] = useCookies() + // Cookies + const cookie = getCookie("account") - const headers = (cookies.account != null) ? { - headers: { - 'Authorization': `Bearer ${cookies.account.access_token}` - } - } : {} - - // 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 headers = {} + // cookies.account != null + // ? { + // headers: { + // Authorization: `Bearer ${cookies.account.access_token}`, + // }, + // } + // : {} - // Refs - const pictureSelect = React.createRef() - const languageSelect = React.createRef() - const genderSelect = React.createRef() - const privateSelect = React.createRef() + // State + const [open, setOpen] = useState(false) + const [picture, setPicture] = useState("") + const [language, setLanguage] = useState("") + const [gender, setGender] = useState(0) + 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]) + // Refs + const pictureSelect = React.createRef() + const languageSelect = React.createRef() + const genderSelect = React.createRef() + const privateSelect = React.createRef() - const pictureOptions = ( - pictureData.sort((a, b) => (a.name.en > b.name.en) ? 1 : -1).map((item, i) => { - return ( - - ) - }) - ) + // useEffect(() => { + // if (cookies.user) setPicture(cookies.user.picture) + // if (cookies.user) setLanguage(cookies.user.language) + // if (cookies.user) setGender(cookies.user.gender) + // }, [cookies]) - function handlePictureChange(event: React.ChangeEvent) { - if (pictureSelect.current) - setPicture(pictureSelect.current.value) + const pictureOptions = pictureData + .sort((a, b) => (a.name.en > b.name.en ? 1 : -1)) + .map((item, i) => { + return ( + + ) + }) + + function handlePictureChange(event: React.ChangeEvent) { + if (pictureSelect.current) setPicture(pictureSelect.current.value) + } + + function handleLanguageChange(event: React.ChangeEvent) { + if (languageSelect.current) setLanguage(languageSelect.current.value) + } + + function handleGenderChange(event: React.ChangeEvent) { + if (genderSelect.current) setGender(parseInt(genderSelect.current.value)) + } + + function handlePrivateChange(checked: boolean) { + setPrivateProfile(checked) + } + + function update(event: React.FormEvent) { + event.preventDefault() + + const object = { + user: { + picture: picture, + element: pictureData.find((i) => i.filename === picture)?.element, + language: language, + gender: gender, + private: privateProfile, + }, } - function handleLanguageChange(event: React.ChangeEvent) { - if (languageSelect.current) - setLanguage(languageSelect.current.value) - } + // api.endpoints.users + // .update(cookies.account.user_id, object, headers) + // .then((response) => { + // const user = response.data.user - function handleGenderChange(event: React.ChangeEvent) { - if (genderSelect.current) - setGender(parseInt(genderSelect.current.value)) - } + // const cookieObj = { + // picture: user.picture.picture, + // element: user.picture.element, + // gender: user.gender, + // language: user.language, + // } - function handlePrivateChange(checked: boolean) { - setPrivateProfile(checked) - } + // setCookies("user", cookieObj, { path: "/" }) - function update(event: React.FormEvent) { - event.preventDefault() + // accountState.account.user = { + // id: user.id, + // username: user.username, + // picture: user.picture.picture, + // element: user.picture.element, + // gender: user.gender, + // } - const object = { - user: { - picture: picture, - element: pictureData.find(i => i.filename === picture)?.element, - language: language, - gender: gender, - private: privateProfile - } - } + // setOpen(false) + // changeLanguage(user.language) + // }) + } - api.endpoints.users.update(cookies.account.user_id, object, headers) - .then(response => { - const user = response.data.user + function changeLanguage(newLanguage: string) { + // if (newLanguage !== router.locale) { + // setCookies("NEXT_LOCALE", newLanguage, { path: "/" }) + // router.push(router.asPath, undefined, { locale: newLanguage }) + // } + } - const cookieObj = { - picture: user.picture.picture, - element: user.picture.element, - gender: user.gender, - language: user.language - } - - setCookies('user', cookieObj, { path: '/'}) + function openChange(open: boolean) { + setOpen(open) + } - accountState.account.user = { - id: user.id, - username: user.username, - picture: user.picture.picture, - element: user.picture.element, - gender: user.gender - } + return ( + + +
  • + {t("menu.settings")} +
  • +
    + + event.preventDefault()} + > +
    +
    + + {t("modals.settings.title")} + + + @{account.user?.username} + +
    + + + + + +
    - setOpen(false) - changeLanguage(user.language) - }) - } +
    +
    +
    + +
    - function changeLanguage(newLanguage: string) { - if (newLanguage !== router.locale) { - setCookies('NEXT_LOCALE', newLanguage, { path: '/'}) - router.push(router.asPath, undefined, { locale: newLanguage }) - } - } - - function openChange(open: boolean) { - setOpen(open) - } - - return ( - - -
  • - {t('menu.settings')} -
  • -
    - - event.preventDefault() }> -
    -
    - {t('modals.settings.title')} - @{account.user?.username} -
    - - - - - -
    - - -
    -
    - -
    - -
    i.filename === picture)?.element}`}> - Profile preview i.filename === picture)?.element + }`} + > + Profile preview -
    + src={`/profile/${picture}.png`} + /> +
    - -
    -
    -
    - -
    + +
    +
    +
    + +
    - -
    -
    -
    - -
    + +
    +
    +
    + +
    - -
    -
    -
    - -

    {t('modals.settings.descriptions.private')}

    -
    + +
    +
    +
    + +

    + {t("modals.settings.descriptions.private")} +

    +
    - - - -
    + + + + - -
    -
    - -
    -
    - ) + + + + + + + ) } export default AccountModal diff --git a/components/GridRep/index.tsx b/components/GridRep/index.tsx index 8f07209b..b43380bb 100644 --- a/components/GridRep/index.tsx +++ b/components/GridRep/index.tsx @@ -1,187 +1,201 @@ +import React, { useEffect, useState } from "react" +import { useRouter } from "next/router" +import { useSnapshot } from "valtio" +import { useTranslation } from "next-i18next" +import classNames from "classnames" -import React, { useEffect, useState } from 'react' -import { useRouter } from 'next/router' -import { useSnapshot } from 'valtio' -import { useTranslation } from 'next-i18next' -import classNames from 'classnames' +import { accountState } from "~utils/accountState" +import { formatTimeAgo } from "~utils/timeAgo" -import { accountState } from '~utils/accountState' -import { formatTimeAgo } from '~utils/timeAgo' +import Button from "~components/Button" +import { ButtonType } from "~utils/enums" -import Button from '~components/Button' -import { ButtonType } from '~utils/enums' - -import './index.scss' +import "./index.scss" interface Props { - shortcode: string - id: string - name: string - raid: Raid - grid: GridWeapon[] - user?: User - favorited: boolean - createdAt: Date - displayUser?: boolean | false - onClick: (shortcode: string) => void - onSave?: (partyId: string, favorited: boolean) => void + shortcode: string + id: string + name: string + raid: Raid + grid: GridWeapon[] + user?: User + favorited: boolean + createdAt: Date + displayUser?: boolean | false + onClick: (shortcode: string) => void + onSave?: (partyId: string, favorited: boolean) => void } const GridRep = (props: Props) => { - const numWeapons: number = 9 + const numWeapons: number = 9 - const { account } = useSnapshot(accountState) + const { account } = useSnapshot(accountState) - const router = useRouter() - const { t } = useTranslation('common') - const locale = (router.locale && ['en', 'ja'].includes(router.locale)) ? router.locale : 'en' + const router = useRouter() + const { t } = useTranslation("common") + const locale = + router.locale && ["en", "ja"].includes(router.locale) ? router.locale : "en" - const [mainhand, setMainhand] = useState() - const [weapons, setWeapons] = useState>({}) + const [mainhand, setMainhand] = useState() + const [weapons, setWeapons] = useState>({}) - const titleClass = classNames({ - 'empty': !props.name - }) + const titleClass = classNames({ + empty: !props.name, + }) - const raidClass = classNames({ - 'raid': true, - 'empty': !props.raid - }) + const raidClass = classNames({ + raid: true, + empty: !props.raid, + }) - const userClass = classNames({ - 'user': true, - 'empty': !props.user - }) + const userClass = classNames({ + user: true, + empty: !props.user, + }) - useEffect(() => { - const newWeapons = Array(numWeapons) + useEffect(() => { + const newWeapons = Array(numWeapons) - for (const [key, value] of Object.entries(props.grid)) { - if (value.position == -1) - setMainhand(value.object) - else if (!value.mainhand && value.position != null) - newWeapons[value.position] = value.object - } - - setWeapons(newWeapons) - }, [props.grid]) - - function navigate() { - props.onClick(props.shortcode) + for (const [key, value] of Object.entries(props.grid)) { + if (value.position == -1) setMainhand(value.object) + else if (!value.mainhand && value.position != null) + newWeapons[value.position] = value.object } - function generateMainhandImage() { - let url = '' + setWeapons(newWeapons) + }, [props.grid]) - if (mainhand) { - if (mainhand.element == 0 && props.grid[0].element) { - url = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/weapon-main/${mainhand.granblue_id}_${props.grid[0].element}.jpg` - } else { - url = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/weapon-main/${mainhand.granblue_id}.jpg` - } - } + function navigate() { + props.onClick(props.shortcode) + } - return (mainhand) ? - {mainhand.name[locale]} : '' + function generateMainhandImage() { + let url = "" + + if (mainhand) { + if (mainhand.element == 0 && props.grid[0].element) { + url = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/weapon-main/${mainhand.granblue_id}_${props.grid[0].element}.jpg` + } else { + url = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/weapon-main/${mainhand.granblue_id}.jpg` + } } - function generateGridImage(position: number) { - let url = '' + return mainhand && props.grid[0] ? ( + {mainhand.name[locale]} + ) : ( + "" + ) + } - if (weapons[position]) { - if (weapons[position].element == 0 && props.grid[position].element) { - url = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/weapon-grid/${weapons[position]?.granblue_id}_${props.grid[position].element}.jpg` - } else { - url = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/weapon-grid/${weapons[position]?.granblue_id}.jpg` - } - } + function generateGridImage(position: number) { + let url = "" - return (weapons[position]) ? - {weapons[position].name[locale]} : '' + if (weapons[position]) { + if (weapons[position].element == 0 && props.grid[position].element) { + url = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/weapon-grid/${weapons[position]?.granblue_id}_${props.grid[position].element}.jpg` + } else { + url = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/weapon-grid/${weapons[position]?.granblue_id}.jpg` + } } - function sendSaveData() { - if (props.onSave) - props.onSave(props.id, props.favorited) - } + return weapons[position] ? ( + {weapons[position].name[locale]} + ) : ( + "" + ) + } - const userImage = () => { - if (props.user) - return ( - {props.user.picture.picture} { + if (props.user) + return ( + {props.user.picture.picture} + src={`/profile/${props.user.picture.picture}.png`} + /> + ) + else return
    + } + + const details = ( +
    +

    + {props.name ? props.name : t("no_title")} +

    +
    +
    + {props.raid ? props.raid.name[locale] : t("no_raid")} +
    + +
    +
    + ) + + const detailsWithUsername = ( +
    +
    +
    +

    + {props.name ? props.name : t("no_title")} +

    +
    + {props.raid ? props.raid.name[locale] : t("no_raid")} +
    +
    + {account.authorized && + ((props.user && account.user && account.user.id !== props.user.id) || + !props.user) ? ( +
    +
    +
    + {userImage()} + {props.user ? props.user.username : t("no_user")} +
    + +
    +
    + ) + + return ( +
    + {props.displayUser ? detailsWithUsername : details} +
    +
    {generateMainhandImage()}
    + +
      + {Array.from(Array(numWeapons)).map((x, i) => { + return ( +
    • + {generateGridImage(i)} +
    • ) - else - return (
      ) - } - - const details = ( -
      -

      { (props.name) ? props.name : t('no_title') }

      -
      -
      { (props.raid) ? props.raid.name[locale] : t('no_raid') }
      - -
      -
      - ) - - const detailsWithUsername = ( -
      -
      -
      -

      { (props.name) ? props.name : t('no_title') }

      -
      { (props.raid) ? props.raid.name[locale] : t('no_raid') }
      -
      - { - (account.authorized && ( - (props.user && account.user && account.user.id !== props.user.id) - || (!props.user) - )) ? -
      -
      -
      - { userImage() } - { (props.user) ? props.user.username : t('no_user') } -
      - -
      -
      - ) - - return ( -
      - { (props.displayUser) ? detailsWithUsername : details} -
      -
      - {generateMainhandImage()} -
      - -
        - { - Array.from(Array(numWeapons)).map((x, i) => { - return ( -
      • - {generateGridImage(i)} -
      • - ) - }) - } -
      -
      -
      - ) + })} +
    +
    +
    + ) } export default GridRep diff --git a/components/GridRepCollection/index.scss b/components/GridRepCollection/index.scss index f2752274..1f0a2db3 100644 --- a/components/GridRepCollection/index.scss +++ b/components/GridRepCollection/index.scss @@ -1,15 +1,10 @@ .GridRepCollection { - display: grid; - grid-template-columns: auto auto auto; - margin: 0 auto; - opacity: 0; - padding: 0; - width: fit-content; - transition: opacity 0.14s ease-in-out; - // width: fit-content; - max-width: 996px; - - &.visible { - opacity: 1; - } -} \ No newline at end of file + display: grid; + grid-template-columns: auto auto auto; + margin: 0 auto; + padding: 0; + width: fit-content; + transition: opacity 0.14s ease-in-out; + // width: fit-content; + max-width: 996px; +} diff --git a/components/GridRepCollection/index.tsx b/components/GridRepCollection/index.tsx index 041fad4b..77592ffd 100644 --- a/components/GridRepCollection/index.tsx +++ b/components/GridRepCollection/index.tsx @@ -1,24 +1,18 @@ -import classNames from 'classnames' -import React from 'react' +import classNames from "classnames" +import React from "react" -import './index.scss' +import "./index.scss" interface Props { - loading: boolean - children: React.ReactNode + children: React.ReactNode } const GridRepCollection = (props: Props) => { - const classes = classNames({ - 'GridRepCollection': true, - 'visible': !props.loading - }) - - return ( -
    - {props.children} -
    - ) + const classes = classNames({ + GridRepCollection: true, + }) + + return
    {props.children}
    } export default GridRepCollection diff --git a/components/LoginModal/index.tsx b/components/LoginModal/index.tsx index 8d83ec13..de5f5443 100644 --- a/components/LoginModal/index.tsx +++ b/components/LoginModal/index.tsx @@ -1,213 +1,216 @@ -import React, { useState } from 'react' -import { useCookies } from 'react-cookie' -import Router, { useRouter } from 'next/router' -import { useTranslation } from 'react-i18next' -import { AxiosResponse } from 'axios' +import React, { useState } from "react" +import { setCookie } from "cookies-next" +import Router, { useRouter } from "next/router" +import { useTranslation } from "react-i18next" +import { AxiosResponse } from "axios" -import * as Dialog from '@radix-ui/react-dialog' +import * as Dialog from "@radix-ui/react-dialog" -import api from '~utils/api' -import { accountState } from '~utils/accountState' +import api from "~utils/api" +import { accountState } from "~utils/accountState" -import Button from '~components/Button' -import Fieldset from '~components/Fieldset' +import Button from "~components/Button" +import Fieldset from "~components/Fieldset" -import CrossIcon from '~public/icons/Cross.svg' -import './index.scss' +import CrossIcon from "~public/icons/Cross.svg" +import "./index.scss" interface Props {} interface ErrorMap { - [index: string]: string - email: string - password: string + [index: string]: string + email: string + password: string } -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 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 router = useRouter() - const { t } = useTranslation('common') + const router = useRouter() + const { t } = useTranslation("common") - // Set up form states and error handling - const [formValid, setFormValid] = useState(false) - const [errors, setErrors] = useState({ - email: '', - password: '' - }) + // Set up form states and error handling + const [formValid, setFormValid] = useState(false) + const [errors, setErrors] = useState({ + email: "", + password: "", + }) - // Cookies - const [cookies, setCookies] = useCookies() + // States + const [open, setOpen] = useState(false) - // States - const [open, setOpen] = useState(false) + // Set up form refs + const emailInput: React.RefObject = React.createRef() + const passwordInput: React.RefObject = React.createRef() + const form: React.RefObject[] = [emailInput, passwordInput] - // Set up form refs - const emailInput: React.RefObject = React.createRef() - const passwordInput: React.RefObject = React.createRef() - const form: React.RefObject[] = [emailInput, passwordInput] + function handleChange(event: React.ChangeEvent) { + const { name, value } = event.target + let newErrors = { ...errors } - function handleChange(event: React.ChangeEvent) { - const { name, value } = event.target - let newErrors = {...errors} + switch (name) { + case "email": + if (value.length == 0) + newErrors.email = t("modals.login.errors.empty_email") + else if (!emailRegex.test(value)) + newErrors.email = t("modals.login.errors.invalid_email") + else newErrors.email = "" + break - switch(name) { - case 'email': - if (value.length == 0) - newErrors.email = t('modals.login.errors.empty_email') - else if (!emailRegex.test(value)) - newErrors.email = t('modals.login.errors.invalid_email') - else - newErrors.email = '' - break + case "password": + newErrors.password = + value.length == 0 ? t("modals.login.errors.empty_password") : "" + break - case 'password': - newErrors.password = value.length == 0 - ? t('modals.login.errors.empty_password') - : '' - break - - default: - break - } - - setErrors(newErrors) - setFormValid(validateForm(newErrors)) + default: + break } - function validateForm(errors: ErrorMap) { - let valid = true + setErrors(newErrors) + setFormValid(validateForm(newErrors)) + } - Object.values(form).forEach( - (input) => input.current?.value.length == 0 && (valid = false) - ) + function validateForm(errors: ErrorMap) { + let valid = true - Object.values(errors).forEach( - (error) => error.length > 0 && (valid = false) - ) - - return valid - } - - function login(event: React.FormEvent) { - event.preventDefault() - - const body = { - email: emailInput.current?.value, - password: passwordInput.current?.value, - grant_type: 'password' - } - - if (formValid) { - api.login(body) - .then(response => { - storeCookieInfo(response) - return response.data.user.id - }) - .then(id => fetchUserInfo(id)) - .then(infoResponse => storeUserInfo(infoResponse)) - } - } - - function fetchUserInfo(id: string) { - return api.userInfo(id) - } - - function storeCookieInfo(response: AxiosResponse) { - const user = response.data.user - - const cookieObj = { - user_id: user.id, - username: user.username, - access_token: response.data.access_token - } - - setCookies('account', cookieObj, { path: '/' }) - } - - function storeUserInfo(response: AxiosResponse) { - const user = response.data.user - - const cookieObj = { - picture: user.picture.picture, - element: user.picture.element, - language: user.language, - gender: user.gender - } - - setCookies('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.authorized = true - - setOpen(false) - changeLanguage(user.language) - } - - function changeLanguage(newLanguage: string) { - if (newLanguage !== router.locale) { - setCookies('NEXT_LOCALE', newLanguage, { path: '/'}) - router.push(router.asPath, undefined, { locale: newLanguage }) - } - } - - function openChange(open: boolean) { - setOpen(open) - setErrors({ - email: '', - password: '' - }) - } - - return ( - - -
  • - {t('menu.login')} -
  • -
    - - event.preventDefault() }> -
    - {t('modals.login.title')} - - - - - -
    - -
    -
    - -
    - - - - - - - + Object.values(form).forEach( + (input) => input.current?.value.length == 0 && (valid = false) ) + + Object.values(errors).forEach( + (error) => error.length > 0 && (valid = false) + ) + + return valid + } + + function login(event: React.FormEvent) { + event.preventDefault() + + const body = { + email: emailInput.current?.value, + password: passwordInput.current?.value, + grant_type: "password", + } + + if (formValid) { + api + .login(body) + .then((response) => { + storeCookieInfo(response) + return response.data.user.id + }) + .then((id) => fetchUserInfo(id)) + .then((infoResponse) => storeUserInfo(infoResponse)) + } + } + + function fetchUserInfo(id: string) { + return api.userInfo(id) + } + + function storeCookieInfo(response: AxiosResponse) { + const user = response.data.user + + const cookieObj: AccountCookie = { + userId: user.id, + username: user.username, + token: response.data.access_token, + } + + setCookie("account", cookieObj, { path: "/" }) + } + + function storeUserInfo(response: AxiosResponse) { + const user = response.data.user + + const cookieObj: UserCookie = { + picture: user.picture.picture, + element: user.picture.element, + language: user.language, + gender: user.gender, + } + + setCookie("user", cookieObj, { path: "/" }) + + accountState.account.user = { + id: user.id, + username: user.username, + picture: user.picture.picture, + element: user.picture.element, + gender: user.gender, + } + + 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 }) + } + } + + function openChange(open: boolean) { + setOpen(open) + setErrors({ + email: "", + password: "", + }) + } + + return ( + + +
  • + {t("menu.login")} +
  • +
    + + event.preventDefault()} + > +
    + + {t("modals.login.title")} + + + + + + +
    + +
    +
    + +
    + + + + + + + + ) } -export default LoginModal \ No newline at end of file +export default LoginModal diff --git a/components/SearchModal/index.tsx b/components/SearchModal/index.tsx index 1e8aa954..88a0e340 100644 --- a/components/SearchModal/index.tsx +++ b/components/SearchModal/index.tsx @@ -1,311 +1,348 @@ -import React, { useEffect, useRef, useState } from 'react' -import { useCookies } from 'react-cookie' -import { useRouter } from 'next/router' -import { useSnapshot } from 'valtio' -import { useTranslation } from 'react-i18next' -import InfiniteScroll from 'react-infinite-scroll-component' +import React, { useEffect, useRef, useState } from "react" +import { getCookie, setCookie } from "cookies-next" +import { useRouter } from "next/router" +import { useSnapshot } from "valtio" +import { useTranslation } from "react-i18next" +import InfiniteScroll from "react-infinite-scroll-component" -import { appState } from '~utils/appState' -import api from '~utils/api' +import { appState } from "~utils/appState" +import api from "~utils/api" -import * as Dialog from '@radix-ui/react-dialog' +import * as Dialog from "@radix-ui/react-dialog" -import CharacterSearchFilterBar from '~components/CharacterSearchFilterBar' -import WeaponSearchFilterBar from '~components/WeaponSearchFilterBar' -import SummonSearchFilterBar from '~components/SummonSearchFilterBar' +import CharacterSearchFilterBar from "~components/CharacterSearchFilterBar" +import WeaponSearchFilterBar from "~components/WeaponSearchFilterBar" +import SummonSearchFilterBar from "~components/SummonSearchFilterBar" -import CharacterResult from '~components/CharacterResult' -import WeaponResult from '~components/WeaponResult' -import SummonResult from '~components/SummonResult' +import CharacterResult from "~components/CharacterResult" +import WeaponResult from "~components/WeaponResult" +import SummonResult from "~components/SummonResult" -import './index.scss' -import CrossIcon from '~public/icons/Cross.svg' -import cloneDeep from 'lodash.clonedeep' +import "./index.scss" +import CrossIcon from "~public/icons/Cross.svg" +import cloneDeep from "lodash.clonedeep" interface Props { - send: (object: Character | Weapon | Summon, position: number) => any - placeholderText: string - fromPosition: number - object: 'weapons' | 'characters' | 'summons', - children: React.ReactNode + send: (object: Character | Weapon | Summon, position: number) => any + placeholderText: string + fromPosition: number + object: "weapons" | "characters" | "summons" + children: React.ReactNode } const SearchModal = (props: Props) => { - // Set up snapshot of app state - let { grid, search } = useSnapshot(appState) + // Set up snapshot of app state + let { grid, search } = useSnapshot(appState) - // Set up router - const router = useRouter() - const locale = router.locale + // Set up router + const router = useRouter() + const locale = router.locale - // Set up translation - const { t } = useTranslation('common') + // Set up translation + const { t } = useTranslation("common") - // Set up cookies - const [cookies, setCookies] = useCookies() + let searchInput = React.createRef() + let scrollContainer = React.createRef() - let searchInput = React.createRef() - let scrollContainer = React.createRef() + const [firstLoad, setFirstLoad] = useState(true) + const [objects, setObjects] = useState<{ + [id: number]: GridCharacter | GridWeapon | GridSummon + }>() + const [filters, setFilters] = useState<{ [key: string]: number[] }>() + const [open, setOpen] = useState(false) + const [query, setQuery] = useState("") + const [results, setResults] = useState<(Weapon | Summon | Character)[]>([]) - const [firstLoad, setFirstLoad] = useState(true) - const [objects, setObjects] = useState<{[id: number]: GridCharacter | GridWeapon | GridSummon}>() - const [filters, setFilters] = useState<{ [key: string]: number[] }>() - const [open, setOpen] = useState(false) - const [query, setQuery] = useState('') - const [results, setResults] = useState<(Weapon | Summon | Character)[]>([]) + // Pagination states + const [recordCount, setRecordCount] = useState(0) + const [currentPage, setCurrentPage] = useState(1) + const [totalPages, setTotalPages] = useState(1) - // Pagination states - const [recordCount, setRecordCount] = useState(0) - const [currentPage, setCurrentPage] = useState(1) - const [totalPages, setTotalPages] = useState(1) + useEffect(() => { + setObjects(grid[props.object]) + }, [grid, props.object]) - useEffect(() => { - setObjects(grid[props.object]) - }, [grid, props.object]) + useEffect(() => { + if (searchInput.current) searchInput.current.focus() + }, [searchInput]) - useEffect(() => { - if (searchInput.current) - searchInput.current.focus() - }, [searchInput]) + function inputChanged(event: React.ChangeEvent) { + const text = event.target.value + if (text.length) { + setQuery(text) + } else { + setQuery("") + } + } - function inputChanged(event: React.ChangeEvent) { - const text = event.target.value - if (text.length) { - setQuery(text) + function fetchResults({ replace = false }: { replace?: boolean }) { + api + .search({ + object: props.object, + query: query, + filters: filters, + locale: locale, + page: currentPage, + }) + .then((response) => { + setTotalPages(response.data.total_pages) + setRecordCount(response.data.count) + + if (replace) { + replaceResults(response.data.count, response.data.results) } else { - setQuery('') + appendResults(response.data.results) } - } - - function fetchResults({ replace = false }: { replace?: boolean }) { - api.search({ - object: props.object, - query: query, - filters: filters, - locale: locale, - page: currentPage - }).then(response => { - setTotalPages(response.data.total_pages) - setRecordCount(response.data.count) + }) + .catch((error) => { + console.error(error) + }) + } - if (replace) { - replaceResults(response.data.count, response.data.results) - } else { - appendResults(response.data.results) - } - }).catch(error => { - console.error(error) - }) + function replaceResults( + count: number, + list: Weapon[] | Summon[] | Character[] + ) { + if (count > 0) { + setResults(list) + } else { + setResults([]) + } + } + + function appendResults(list: Weapon[] | Summon[] | Character[]) { + setResults([...results, ...list]) + } + + function storeRecentResult(result: Character | Weapon | Summon) { + const key = `recent_${props.object}` + const cookie = getCookie(key) + const cookieObj: Character[] | Weapon[] | Summon[] = cookie + ? JSON.parse(cookie as string) + : [] + let recents: Character[] | Weapon[] | Summon[] = [] + + if (props.object === "weapons") { + recents = cloneDeep(cookieObj as Weapon[]) || [] + if (!recents.find((item) => item.granblue_id === result.granblue_id)) { + recents.unshift(result as Weapon) + } + } else if (props.object === "summons") { + recents = cloneDeep(cookieObj as Summon[]) || [] + if (!recents.find((item) => item.granblue_id === result.granblue_id)) { + recents.unshift(result as Summon) + } } - function replaceResults(count: number, list: Weapon[] | Summon[] | Character[]) { - if (count > 0) { - setResults(list) - } else { - setResults([]) - } + if (recents && recents.length > 5) recents.pop() + setCookie(`recent_${props.object}`, recents, { path: "/" }) + sendData(result) + } + + function sendData(result: Character | Weapon | Summon) { + props.send(result, props.fromPosition) + openChange() + } + + function receiveFilters(filters: { [key: string]: number[] }) { + setCurrentPage(1) + setResults([]) + setFilters(filters) + } + + useEffect(() => { + // Current page changed + if (open && currentPage > 1) { + fetchResults({ replace: false }) + } else if (open && currentPage == 1) { + fetchResults({ replace: true }) } + }, [currentPage]) - function appendResults(list: Weapon[] | Summon[] | Character[]) { - setResults([...results, ...list]) - } + useEffect(() => { + // Filters changed + const key = `recent_${props.object}` + const cookie = getCookie(key) + const cookieObj: Weapon[] | Summon[] | Character[] = cookie + ? JSON.parse(cookie as string) + : [] - function storeRecentResult(result: Character | Weapon | Summon) { - const key = `recent_${props.object}` - let recents: Character[] | Weapon[] | Summon[] = [] - - if (props.object === "weapons") { - recents = cloneDeep(cookies[key] as Weapon[]) || [] - if (!recents.find(item => item.granblue_id === result.granblue_id)) { - recents.unshift(result as Weapon) - } - } else if (props.object === "summons") { - recents = cloneDeep(cookies[key] as Summon[]) || [] - if (!recents.find(item => item.granblue_id === result.granblue_id)) { - recents.unshift(result as Summon) - } - } - - if (recents && recents.length > 5) recents.pop() - setCookies(`recent_${props.object}`, recents, { path: '/' }) - sendData(result) - } - - function sendData(result: Character | Weapon | Summon) { - props.send(result, props.fromPosition) - openChange() - } - - function receiveFilters(filters: { [key: string]: number[] }) { + if (open) { + if (firstLoad && cookieObj && cookieObj.length > 0) { + setResults(cookieObj) + setRecordCount(cookieObj.length) + setFirstLoad(false) + } else { setCurrentPage(1) - setResults([]) - setFilters(filters) + fetchResults({ replace: true }) + } } + }, [filters]) - useEffect(() => { - // Current page changed - if (open && currentPage > 1) { - fetchResults({ replace: false }) - } else if (open && currentPage == 1) { - fetchResults({ replace: true }) - } - }, [currentPage]) - - useEffect(() => { - // Filters changed - const key = `recent_${props.object}` - - if (open) { - if (firstLoad && cookies[key] && cookies[key].length > 0) { - setResults(cookies[key]) - setRecordCount(cookies[key].length) - setFirstLoad(false) - } else { - setCurrentPage(1) - fetchResults({ replace: true }) - } - } - }, [filters]) - - useEffect(() => { - // Query changed - if (open && query.length != 1) { - setCurrentPage(1) - fetchResults({ replace: true }) - } - }, [query]) - - function renderResults() { - let jsx - - switch(props.object) { - case 'weapons': - jsx = renderWeaponSearchResults() - break - case 'summons': - jsx = renderSummonSearchResults(results) - break - case 'characters': - jsx = renderCharacterSearchResults(results) - break - } - - return ( - 0) ? results.length : 0} - next={ () => setCurrentPage(currentPage + 1) } - hasMore={totalPages > currentPage} - scrollableTarget="Results" - loader={
    Loading...
    }> - {jsx} -
    - ) + useEffect(() => { + // Query changed + if (open && query.length != 1) { + setCurrentPage(1) + fetchResults({ replace: true }) } + }, [query]) - function renderWeaponSearchResults() { - let jsx: React.ReactNode - - const castResults: Weapon[] = results as Weapon[] - if (castResults && Object.keys(castResults).length > 0) { - jsx = castResults.map((result: Weapon) => { - return { storeRecentResult(result) }} - /> - }) - } + function renderResults() { + let jsx - return jsx - } - - function renderSummonSearchResults(results: { [key: string]: any }) { - let jsx: React.ReactNode - - const castResults: Summon[] = results as Summon[] - if (castResults && Object.keys(castResults).length > 0) { - jsx = castResults.map((result: Summon) => { - return { storeRecentResult(result) }} - /> - }) - } - - return jsx - } - - function renderCharacterSearchResults(results: { [key: string]: any }) { - let jsx: React.ReactNode - - const castResults: Character[] = results as Character[] - if (castResults && Object.keys(castResults).length > 0) { - jsx = castResults.map((result: Character) => { - return { storeRecentResult(result) }} - /> - }) - } - - return jsx - } - - function openChange() { - if (open) { - setQuery('') - setFirstLoad(true) - setResults([]) - setRecordCount(0) - setCurrentPage(1) - setOpen(false) - } else { - setOpen(true) - } + switch (props.object) { + case "weapons": + jsx = renderWeaponSearchResults() + break + case "summons": + jsx = renderSummonSearchResults(results) + break + case "characters": + jsx = renderCharacterSearchResults(results) + break } return ( - - - {props.children} - - - - - -
    -
    {t('search.result_count', { "record_count": recordCount })}
    - { (open) ? renderResults() : ''} -
    -
    - -
    -
    + 0 ? results.length : 0} + next={() => setCurrentPage(currentPage + 1)} + hasMore={totalPages > currentPage} + scrollableTarget="Results" + loader={
    Loading...
    } + > + {jsx} +
    ) + } + + function renderWeaponSearchResults() { + let jsx: React.ReactNode + + const castResults: Weapon[] = results as Weapon[] + if (castResults && Object.keys(castResults).length > 0) { + jsx = castResults.map((result: Weapon) => { + return ( + { + storeRecentResult(result) + }} + /> + ) + }) + } + + return jsx + } + + function renderSummonSearchResults(results: { [key: string]: any }) { + let jsx: React.ReactNode + + const castResults: Summon[] = results as Summon[] + if (castResults && Object.keys(castResults).length > 0) { + jsx = castResults.map((result: Summon) => { + return ( + { + storeRecentResult(result) + }} + /> + ) + }) + } + + return jsx + } + + function renderCharacterSearchResults(results: { [key: string]: any }) { + let jsx: React.ReactNode + + const castResults: Character[] = results as Character[] + if (castResults && Object.keys(castResults).length > 0) { + jsx = castResults.map((result: Character) => { + return ( + { + storeRecentResult(result) + }} + /> + ) + }) + } + + return jsx + } + + function openChange() { + if (open) { + setQuery("") + setFirstLoad(true) + setResults([]) + setRecordCount(0) + setCurrentPage(1) + setOpen(false) + } else { + setOpen(true) + } + } + + return ( + + {props.children} + + + + +
    +
    + {t("search.result_count", { record_count: recordCount })} +
    + {open ? renderResults() : ""} +
    +
    + +
    +
    + ) } -export default SearchModal \ No newline at end of file +export default SearchModal diff --git a/components/SignupModal/index.tsx b/components/SignupModal/index.tsx index 516c6900..c27ffa79 100644 --- a/components/SignupModal/index.tsx +++ b/components/SignupModal/index.tsx @@ -1,306 +1,324 @@ -import React, { useEffect, useState } from 'react' -import Link from 'next/link' -import { useCookies } from 'react-cookie' -import { useRouter } from 'next/router' -import { Trans, useTranslation } from 'next-i18next' -import { AxiosResponse } from 'axios' +import React, { useEffect, useState } from "react" +import Link from "next/link" +import { setCookie } from "cookies-next" +import { useRouter } from "next/router" +import { Trans, useTranslation } from "next-i18next" +import { AxiosResponse } from "axios" -import * as Dialog from '@radix-ui/react-dialog' +import * as Dialog from "@radix-ui/react-dialog" -import api from '~utils/api' -import { accountState } from '~utils/accountState' +import api from "~utils/api" +import { accountState } from "~utils/accountState" -import Button from '~components/Button' -import Fieldset from '~components/Fieldset' +import Button from "~components/Button" +import Fieldset from "~components/Fieldset" -import CrossIcon from '~public/icons/Cross.svg' -import './index.scss' +import CrossIcon from "~public/icons/Cross.svg" +import "./index.scss" interface Props {} interface ErrorMap { - [index: string]: string - username: string - email: string - password: string - passwordConfirmation: string + [index: string]: string + username: string + email: string + password: string + passwordConfirmation: string } -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 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 router = useRouter() - const { t } = useTranslation('common') - - // Set up form states and error handling - const [formValid, setFormValid] = useState(false) - const [errors, setErrors] = useState({ - username: '', - email: '', - password: '', - passwordConfirmation: '' - }) + const router = useRouter() + const { t } = useTranslation("common") - // Cookies - const [cookies, setCookies] = useCookies() + // Set up form states and error handling + const [formValid, setFormValid] = useState(false) + const [errors, setErrors] = useState({ + username: "", + email: "", + password: "", + passwordConfirmation: "", + }) - // States - const [open, setOpen] = useState(false) - - // Set up form refs - const usernameInput = React.createRef() - const emailInput = React.createRef() - const passwordInput = React.createRef() - const passwordConfirmationInput = React.createRef() - const form = [usernameInput, emailInput, passwordInput, passwordConfirmationInput] + // States + const [open, setOpen] = useState(false) - function register(event: React.FormEvent) { - event.preventDefault() + // Set up form refs + const usernameInput = React.createRef() + const emailInput = React.createRef() + const passwordInput = React.createRef() + const passwordConfirmationInput = React.createRef() + const form = [ + usernameInput, + emailInput, + passwordInput, + passwordConfirmationInput, + ] - const body = { - user: { - username: usernameInput.current?.value, - email: emailInput.current?.value, - password: passwordInput.current?.value, - password_confirmation: passwordConfirmationInput.current?.value, - language: router.locale - } - } + function register(event: React.FormEvent) { + event.preventDefault() - if (formValid) - api.endpoints.users.create(body) - .then(response => { - storeCookieInfo(response) - return response.data.user.user_id - }) - .then(id => fetchUserInfo(id)) - .then(infoResponse => storeUserInfo(infoResponse)) + const body = { + user: { + username: usernameInput.current?.value, + email: emailInput.current?.value, + password: passwordInput.current?.value, + password_confirmation: passwordConfirmationInput.current?.value, + language: router.locale, + }, } - function storeCookieInfo(response: AxiosResponse) { - const user = response.data.user - - const cookieObj = { - user_id: user.user_id, - username: user.username, - access_token: user.token - } - - setCookies('account', cookieObj, { path: '/'}) - } - - function fetchUserInfo(id: string) { - return api.userInfo(id) - } - - function storeUserInfo(response: AxiosResponse) { - const user = response.data.user - - const cookieObj = { - picture: user.picture.picture, - element: user.picture.element, - language: user.language, - gender: user.gender - } - - // TODO: Set language - setCookies('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.authorized = true - setOpen(false) - } - - function handleNameChange(event: React.ChangeEvent) { - event.preventDefault() - - const fieldName = event.target.name - const value = event.target.value - - if (value.length >= 3) { - api.check(fieldName, value) - .then((response) => { - processNameCheck(fieldName, value, response.data.available) - }, (error) => { - console.error(error) - }) - } else { - validateName(fieldName, value) - } - } - - function processNameCheck(fieldName: string, value: string, available: boolean) { - const newErrors = {...errors} - - if (available) { - // Continue checking for errors - newErrors[fieldName] = '' - setErrors(newErrors) - setFormValid(true) - - validateName(fieldName, value) - } else { - newErrors[fieldName] = t('modals.signup.errors.field_in_use', { field: fieldName}) - setErrors(newErrors) - setFormValid(false) - } - } - - function validateName(fieldName: string, value: string) { - let newErrors = {...errors} - - switch(fieldName) { - case 'username': - if (value.length < 3) - newErrors.username = t('modals.signup.errors.username_too_short') - else if (value.length > 20) - newErrors.username = t('modals.signup.errors.username_too_long') - else - newErrors.username = '' - - break - - case 'email': - newErrors.email = emailRegex.test(value) - ? '' - : t('modals.signup.errors.invalid_email') - break - - default: - break - } - - setFormValid(validateForm(newErrors)) - } - - function handlePasswordChange(event: React.ChangeEvent) { - event.preventDefault() - - const { name, value } = event.target - let newErrors = {...errors} - - switch(name) { - case 'password': - newErrors.password = passwordInput.current?.value.includes(usernameInput.current?.value!) - ? t('modals.signup.errors.password_contains_username') - : '' - break - - case 'password': - newErrors.password = value.length < 8 - ? t('modals.signup.errors.password_too_short') - : '' - break - - case 'confirm_password': - newErrors.passwordConfirmation = passwordInput.current?.value === passwordConfirmationInput.current?.value - ? '' - : t('modals.signup.errors.passwords_dont_match') - break - - default: - break - } - - setFormValid(validateForm(newErrors)) - } - - function validateForm(errors: ErrorMap) { - let valid = true - - Object.values(form).forEach( - (input) => input.current?.value.length == 0 && (valid = false) - ) - - Object.values(errors).forEach( - (error) => error.length > 0 && (valid = false) - ) - - return valid - } - - function openChange(open: boolean) { - setOpen(open) - setErrors({ - username: '', - email: '', - password: '', - passwordConfirmation: '' + if (formValid) + api.endpoints.users + .create(body) + .then((response) => { + storeCookieInfo(response) + return response.data.user.user_id }) + .then((id) => fetchUserInfo(id)) + .then((infoResponse) => storeUserInfo(infoResponse)) + } + + function storeCookieInfo(response: AxiosResponse) { + const user = response.data.user + + const cookieObj: AccountCookie = { + userId: user.user_id, + username: user.username, + token: user.token, } - return ( - - -
  • - {t('menu.signup')} -
  • -
    - - event.preventDefault() }> -
    - {t('modals.signup.title')} - - - - - -
    + setCookie("account", cookieObj, { path: "/" }) + } -
    -
    + function fetchUserInfo(id: string) { + return api.userInfo(id) + } -
    + function storeUserInfo(response: AxiosResponse) { + const user = response.data.user -
    + const cookieObj: UserCookie = { + picture: user.picture.picture, + element: user.picture.element, + language: user.language, + gender: user.gender, + } -
    + // TODO: Set language + 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.authorized = true + setOpen(false) + } + + function handleNameChange(event: React.ChangeEvent) { + event.preventDefault() + + const fieldName = event.target.name + const value = event.target.value + + if (value.length >= 3) { + api.check(fieldName, value).then( + (response) => { + processNameCheck(fieldName, value, response.data.available) + }, + (error) => { + console.error(error) + } + ) + } else { + validateName(fieldName, value) + } + } + + function processNameCheck( + fieldName: string, + value: string, + available: boolean + ) { + const newErrors = { ...errors } + + if (available) { + // Continue checking for errors + newErrors[fieldName] = "" + setErrors(newErrors) + setFormValid(true) + + validateName(fieldName, value) + } else { + newErrors[fieldName] = t("modals.signup.errors.field_in_use", { + field: fieldName, + }) + setErrors(newErrors) + setFormValid(false) + } + } + + function validateName(fieldName: string, value: string) { + let newErrors = { ...errors } + + switch (fieldName) { + case "username": + if (value.length < 3) + newErrors.username = t("modals.signup.errors.username_too_short") + else if (value.length > 20) + newErrors.username = t("modals.signup.errors.username_too_long") + else newErrors.username = "" + + break + + case "email": + newErrors.email = emailRegex.test(value) + ? "" + : t("modals.signup.errors.invalid_email") + break + + default: + break + } + + setFormValid(validateForm(newErrors)) + } + + function handlePasswordChange(event: React.ChangeEvent) { + event.preventDefault() + + const { name, value } = event.target + let newErrors = { ...errors } + + switch (name) { + case "password": + newErrors.password = passwordInput.current?.value.includes( + usernameInput.current?.value! + ) + ? t("modals.signup.errors.password_contains_username") + : "" + break + + case "password": + newErrors.password = + value.length < 8 ? t("modals.signup.errors.password_too_short") : "" + break + + case "confirm_password": + newErrors.passwordConfirmation = + passwordInput.current?.value === + passwordConfirmationInput.current?.value + ? "" + : t("modals.signup.errors.passwords_dont_match") + break + + default: + break + } + + setFormValid(validateForm(newErrors)) + } + + function validateForm(errors: ErrorMap) { + let valid = true + + Object.values(form).forEach( + (input) => input.current?.value.length == 0 && (valid = false) + ) + + Object.values(errors).forEach( + (error) => error.length > 0 && (valid = false) + ) + + return valid + } + + function openChange(open: boolean) { + setOpen(open) + setErrors({ + username: "", + email: "", + password: "", + passwordConfirmation: "", + }) + } + + return ( + + +
  • + {t("menu.signup")} +
  • +
    + + event.preventDefault()} + > +
    + + {t("modals.signup.title")} + + + + + + +
    + + +
    + +
    + +
    + +
    + + + + + {/* By signing up, I agree to the Privacy PolicyUsage Guidelines. */} - - - - - - - ) + + + + + + + ) } - -export default SignupModal \ No newline at end of file +export default SignupModal diff --git a/components/WeaponModal/index.tsx b/components/WeaponModal/index.tsx index 1f8a684c..26df35a9 100644 --- a/components/WeaponModal/index.tsx +++ b/components/WeaponModal/index.tsx @@ -1,223 +1,263 @@ -import React, { useState } from 'react' -import { useCookies } from 'react-cookie' -import { useRouter } from 'next/router' -import { useTranslation } from 'next-i18next' -import { AxiosResponse } from 'axios' +import React, { useState } from "react" +// import { useCookies } from 'react-cookie' +import { useRouter } from "next/router" +import { useTranslation } from "next-i18next" +import { AxiosResponse } from "axios" -import * as Dialog from '@radix-ui/react-dialog' +import * as Dialog from "@radix-ui/react-dialog" -import AXSelect from '~components/AxSelect' -import ElementToggle from '~components/ElementToggle' -import WeaponKeyDropdown from '~components/WeaponKeyDropdown' -import Button from '~components/Button' +import AXSelect from "~components/AxSelect" +import ElementToggle from "~components/ElementToggle" +import WeaponKeyDropdown from "~components/WeaponKeyDropdown" +import Button from "~components/Button" -import api from '~utils/api' -import { appState } from '~utils/appState' +import api from "~utils/api" +import { appState } from "~utils/appState" -import CrossIcon from '~public/icons/Cross.svg' -import './index.scss' +import CrossIcon from "~public/icons/Cross.svg" +import "./index.scss" interface GridWeaponObject { - weapon: { - element?: number - weapon_key1_id?: string - weapon_key2_id?: string - weapon_key3_id?: string - ax_modifier1?: number - ax_modifier2?: number - ax_strength1?: number - ax_strength2?: number - } + weapon: { + element?: number + weapon_key1_id?: string + weapon_key2_id?: string + weapon_key3_id?: string + ax_modifier1?: number + ax_modifier2?: number + ax_strength1?: number + ax_strength2?: number + } } interface Props { - gridWeapon: GridWeapon - children: React.ReactNode + gridWeapon: GridWeapon + children: React.ReactNode } const WeaponModal = (props: Props) => { - const router = useRouter() - const locale = (router.locale && ['en', 'ja'].includes(router.locale)) ? router.locale : 'en' - const { t } = useTranslation('common') - - // Cookies - const [cookies] = useCookies(['account']) - const headers = (cookies.account != null) ? { - headers: { - 'Authorization': `Bearer ${cookies.account.access_token}` + const router = useRouter() + const locale = + router.locale && ["en", "ja"].includes(router.locale) ? router.locale : "en" + const { t } = useTranslation("common") + + // Cookies + const [cookies] = useCookies(["account"]) + const headers = + cookies.account != null + ? { + headers: { + Authorization: `Bearer ${cookies.account.access_token}`, + }, } - } : {} - - // Refs - const weaponKey1Select = React.createRef() - const weaponKey2Select = React.createRef() - const weaponKey3Select = React.createRef() + : {} - // State - const [open, setOpen] = useState(false) - const [formValid, setFormValid] = useState(false) + // Refs + const weaponKey1Select = React.createRef() + const weaponKey2Select = React.createRef() + const weaponKey3Select = React.createRef() - const [element, setElement] = useState(-1) - const [primaryAxModifier, setPrimaryAxModifier] = useState(-1) - const [secondaryAxModifier, setSecondaryAxModifier] = useState(-1) - const [primaryAxValue, setPrimaryAxValue] = useState(0.0) - const [secondaryAxValue, setSecondaryAxValue] = useState(0.0) - - function receiveAxValues(primaryAxModifier: number, primaryAxValue: number, secondaryAxModifier: number, secondaryAxValue: number) { - setPrimaryAxModifier(primaryAxModifier) - setSecondaryAxModifier(secondaryAxModifier) + // State + const [open, setOpen] = useState(false) + const [formValid, setFormValid] = useState(false) - setPrimaryAxValue(primaryAxValue) - setSecondaryAxValue(secondaryAxValue) + const [element, setElement] = useState(-1) + const [primaryAxModifier, setPrimaryAxModifier] = useState(-1) + const [secondaryAxModifier, setSecondaryAxModifier] = useState(-1) + const [primaryAxValue, setPrimaryAxValue] = useState(0.0) + const [secondaryAxValue, setSecondaryAxValue] = useState(0.0) + + function receiveAxValues( + primaryAxModifier: number, + primaryAxValue: number, + secondaryAxModifier: number, + secondaryAxValue: number + ) { + setPrimaryAxModifier(primaryAxModifier) + setSecondaryAxModifier(secondaryAxModifier) + + setPrimaryAxValue(primaryAxValue) + setSecondaryAxValue(secondaryAxValue) + } + + function receiveAxValidity(isValid: boolean) { + setFormValid(isValid) + } + + function receiveElementValue(element: string) { + setElement(parseInt(element)) + } + + function prepareObject() { + let object: GridWeaponObject = { weapon: {} } + + if (props.gridWeapon.object.element == 0) object.weapon.element = element + + if ([2, 3, 17, 24].includes(props.gridWeapon.object.series)) + object.weapon.weapon_key1_id = weaponKey1Select.current?.value + + if ([2, 3, 17].includes(props.gridWeapon.object.series)) + object.weapon.weapon_key2_id = weaponKey2Select.current?.value + + if (props.gridWeapon.object.series == 17) + object.weapon.weapon_key3_id = weaponKey3Select.current?.value + + if (props.gridWeapon.object.ax > 0) { + object.weapon.ax_modifier1 = primaryAxModifier + object.weapon.ax_modifier2 = secondaryAxModifier + object.weapon.ax_strength1 = primaryAxValue + object.weapon.ax_strength2 = secondaryAxValue } - function receiveAxValidity(isValid: boolean) { - setFormValid(isValid) - } + return object + } - function receiveElementValue(element: string) { - setElement(parseInt(element)) - } + async function updateWeapon() { + const updateObject = prepareObject() + return await api.endpoints.grid_weapons + .update(props.gridWeapon.id, updateObject, headers) + .then((response) => processResult(response)) + .catch((error) => processError(error)) + } - function prepareObject() { - let object: GridWeaponObject = { weapon: {} } + function processResult(response: AxiosResponse) { + const gridWeapon: GridWeapon = response.data.grid_weapon - if (props.gridWeapon.object.element == 0) - object.weapon.element = element + if (gridWeapon.mainhand) appState.grid.weapons.mainWeapon = gridWeapon + else appState.grid.weapons.allWeapons[gridWeapon.position] = gridWeapon - if ([2, 3, 17, 24].includes(props.gridWeapon.object.series)) - object.weapon.weapon_key1_id = weaponKey1Select.current?.value + setOpen(false) + } - if ([2, 3, 17].includes(props.gridWeapon.object.series)) - object.weapon.weapon_key2_id = weaponKey2Select.current?.value + function processError(error: any) { + console.error(error) + } - if (props.gridWeapon.object.series == 17) - object.weapon.weapon_key3_id = weaponKey3Select.current?.value - - if (props.gridWeapon.object.ax > 0) { - object.weapon.ax_modifier1 = primaryAxModifier - object.weapon.ax_modifier2 = secondaryAxModifier - object.weapon.ax_strength1 = primaryAxValue - object.weapon.ax_strength2 = secondaryAxValue - } - - return object - } - - async function updateWeapon() { - const updateObject = prepareObject() - return await api.endpoints.grid_weapons.update(props.gridWeapon.id, updateObject, headers) - .then(response => processResult(response)) - .catch(error => processError(error)) - } - - function processResult(response: AxiosResponse) { - const gridWeapon: GridWeapon = response.data.grid_weapon - - if (gridWeapon.mainhand) - appState.grid.weapons.mainWeapon = gridWeapon - else - appState.grid.weapons.allWeapons[gridWeapon.position] = gridWeapon - - setOpen(false) - } - - function processError(error: any) { - console.error(error) - } - - const elementSelect = () => { - return ( -
    -

    {t('modals.weapon.subtitles.element')}

    - -
    - ) - } - - const keySelect = () => { - return ( -
    -

    {t('modals.weapon.subtitles.weapon_keys')}

    - { ([2, 3, 17, 22].includes(props.gridWeapon.object.series)) ? - - : ''} - - { ([2, 3, 17].includes(props.gridWeapon.object.series)) ? - - : ''} - - { (props.gridWeapon.object.series == 17) ? - - : ''} -
    - ) - } - - const axSelect = () => { - return ( -
    -

    {t('modals.weapon.subtitles.ax_skills')}

    - -
    - ) - } - - function openChange(open: boolean) { - setFormValid(false) - setOpen(open) - } - + const elementSelect = () => { return ( - - - { props.children } - - - event.preventDefault() }> -
    -
    - {t('modals.weapon.title')} - {props.gridWeapon.object.name[locale]} -
    - - - - - -
    - -
    - { (props.gridWeapon.object.element == 0) ? elementSelect() : '' } - { ([2, 3, 17, 24].includes(props.gridWeapon.object.series)) ? keySelect() : '' } - { (props.gridWeapon.object.ax > 0) ? axSelect() : '' } - -
    -
    - -
    -
    +
    +

    {t("modals.weapon.subtitles.element")}

    + +
    ) + } + + const keySelect = () => { + return ( +
    +

    {t("modals.weapon.subtitles.weapon_keys")}

    + {[2, 3, 17, 22].includes(props.gridWeapon.object.series) ? ( + + ) : ( + "" + )} + + {[2, 3, 17].includes(props.gridWeapon.object.series) ? ( + + ) : ( + "" + )} + + {props.gridWeapon.object.series == 17 ? ( + + ) : ( + "" + )} +
    + ) + } + + const axSelect = () => { + return ( +
    +

    {t("modals.weapon.subtitles.ax_skills")}

    + +
    + ) + } + + function openChange(open: boolean) { + setFormValid(false) + setOpen(open) + } + + return ( + + {props.children} + + event.preventDefault()} + > +
    +
    + + {t("modals.weapon.title")} + + + {props.gridWeapon.object.name[locale]} + +
    + + + + + +
    + +
    + {props.gridWeapon.object.element == 0 ? elementSelect() : ""} + {[2, 3, 17, 24].includes(props.gridWeapon.object.series) + ? keySelect() + : ""} + {props.gridWeapon.object.ax > 0 ? axSelect() : ""} + +
    +
    + +
    +
    + ) } -export default WeaponModal \ No newline at end of file +export default WeaponModal