import React, { useEffect, useState } from 'react' import { setCookie } from 'cookies-next' import { useRouter } from 'next/router' import { useTranslation } from 'react-i18next' import axios, { AxiosError, AxiosResponse } from 'axios' import api from '~utils/api' import { setHeaders } from '~utils/userToken' import { accountState } from '~utils/accountState' import Button from '~components/Button' import Input from '~components/Input' import { Dialog, DialogTrigger, DialogClose } from '~components/Dialog' import DialogContent from '~components/DialogContent' import changeLanguage from '~utils/changeLanguage' import CrossIcon from '~public/icons/Cross.svg' import './index.scss' interface ErrorMap { [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,}))$/ interface Props { open: boolean onOpenChange?: (open: boolean) => void } const LoginModal = (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({ email: '', password: '', }) // States const [open, setOpen] = useState(false) // Set up form refs const emailInput: React.RefObject = React.createRef() const passwordInput: React.RefObject = React.createRef() const footerRef: React.RefObject = React.createRef() const form: React.RefObject[] = [emailInput, passwordInput] useEffect(() => { setOpen(props.open) }, [props.open]) 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 case 'password': newErrors.password = value.length == 0 ? t('modals.login.errors.empty_password') : '' break default: break } setErrors(newErrors) 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 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)) .catch((error: Error | AxiosError) => { if (axios.isAxiosError(error)) { const response = error?.response if (response && response.data.error === 'invalid_grant') { const errors = { email: '', password: t('modals.login.errors.invalid_credentials'), } setErrors(errors) setFormValid(validateForm(errors)) } } }) } } function fetchUserInfo(id: string) { return api.userInfo(id) } function storeCookieInfo(response: AxiosResponse) { const resp = response.data const cookieObj: AccountCookie = { userId: resp.user.id, username: resp.user.username, token: resp.access_token, } const expiresAt = new Date() expiresAt.setDate(expiresAt.getDate() + 60) setCookie('account', cookieObj, { path: '/', expires: expiresAt }) // Set Axios default headers setHeaders() } function storeUserInfo(response: AxiosResponse) { // Extract the user const user = response.data // Set user data in the user cookie const expiresAt = new Date() expiresAt.setDate(expiresAt.getDate() + 60) setCookie( 'user', { avatar: { picture: user.avatar.picture, element: user.avatar.element, }, language: user.language, gender: user.gender, theme: user.theme, }, { path: '/', expires: expiresAt } ) // Set the user data in the account state accountState.account.user = { id: user.id, username: user.username, granblueId: '', avatar: { 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(router, user.language) } function openChange(open: boolean) { setOpen(open) setErrors({ email: '', password: '', }) setFormValid(false) if (props.onOpenChange) props.onOpenChange(open) } function onEscapeKeyDown(event: KeyboardEvent) { setOpen(false) } function onOpenAutoFocus(event: Event) { event.preventDefault() if (emailInput.current) emailInput.current.focus() } return (

{t('modals.login.title')}

) } export default LoginModal