Add modal for network errors

This commit is contained in:
Justin Edmund 2023-01-27 21:59:56 -08:00
parent 6da5a4f320
commit ab928f4429
6 changed files with 104 additions and 17 deletions

View file

@ -23,7 +23,11 @@ const Alert = (props: Props) => {
<AlertDialog.Overlay className="Overlay" onClick={props.cancelAction} />
<div className="AlertWrapper">
<AlertDialog.Content className="Alert">
{props.title ? <AlertDialog.Title>Error</AlertDialog.Title> : ''}
{props.title ? (
<AlertDialog.Title>{props.title}</AlertDialog.Title>
) : (
''
)}
<AlertDialog.Description className="description">
{props.message}
</AlertDialog.Description>

View file

@ -2,8 +2,9 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react'
import { getCookie } from 'cookies-next'
import { useSnapshot } from 'valtio'
import { useTranslation } from 'next-i18next'
import { AxiosResponse } from 'axios'
import { AxiosError, AxiosResponse } from 'axios'
import debounce from 'lodash.debounce'
import Alert from '~components/Alert'
@ -31,12 +32,19 @@ const CharacterGrid = (props: Props) => {
// Constants
const numCharacters: number = 5
// Localization
const { t } = useTranslation('common')
// Cookies
const cookie = getCookie('account')
const accountData: AccountCookie = cookie
? JSON.parse(cookie as string)
: null
// Set up state for error handling
const [axiosError, setAxiosError] = useState<AxiosResponse>()
const [errorAlertOpen, setErrorAlertOpen] = useState(false)
// Set up state for view management
const { party, grid } = useSnapshot(appState)
const [slug, setSlug] = useState()
@ -111,7 +119,15 @@ const CharacterGrid = (props: Props) => {
if (party.editable)
saveCharacter(party.id, character, position)
.then((response) => handleCharacterResponse(response.data))
.catch((error) => console.error(error))
.catch((error) => {
const axiosError = error as AxiosError
const response = axiosError.response
if (response) {
setErrorAlertOpen(true)
setAxiosError(response)
}
})
}
}
@ -482,6 +498,19 @@ const CharacterGrid = (props: Props) => {
}
// Render: JSX components
const errorAlert = () => {
console.log(axiosError?.status)
return (
<Alert
open={errorAlertOpen}
title={axiosError ? `${axiosError.status}` : 'Error'}
message={t(`errors.${axiosError?.statusText.toLowerCase()}`)}
cancelAction={() => setErrorAlertOpen(false)}
cancelActionText={t('buttons.confirm')}
/>
)
}
return (
<div>
<Alert
@ -526,6 +555,7 @@ const CharacterGrid = (props: Props) => {
})}
</ul>
</div>
{errorAlert()}
</div>
)
}

View file

@ -4,9 +4,10 @@ import { getCookie } from 'cookies-next'
import { useSnapshot } from 'valtio'
import { useTranslation } from 'next-i18next'
import { AxiosResponse } from 'axios'
import { AxiosError, AxiosResponse } from 'axios'
import debounce from 'lodash.debounce'
import Alert from '~components/Alert'
import SummonUnit from '~components/SummonUnit'
import ExtraSummons from '~components/ExtraSummons'
@ -38,6 +39,10 @@ const SummonGrid = (props: Props) => {
// Localization
const { t } = useTranslation('common')
// Set up state for error handling
const [axiosError, setAxiosError] = useState<AxiosResponse>()
const [errorAlertOpen, setErrorAlertOpen] = useState(false)
// Set up state for view management
const { party, grid } = useSnapshot(appState)
const [slug, setSlug] = useState()
@ -100,12 +105,12 @@ const SummonGrid = (props: Props) => {
saveSummon(party.id, summon, position)
.then((response) => handleSummonResponse(response.data))
.catch((error) => {
const code = error.response.status
const data = error.response.data
if (code === 422) {
if (data.code === 'incompatible_summon_for_position') {
// setShowIncompatibleAlert(true)
}
const axiosError = error as AxiosError
const response = axiosError.response
if (response) {
setErrorAlertOpen(true)
setAxiosError(response)
}
})
}
@ -380,6 +385,19 @@ const SummonGrid = (props: Props) => {
}
// Render: JSX components
const errorAlert = () => {
console.log(axiosError?.status)
return (
<Alert
open={errorAlertOpen}
title={axiosError ? `${axiosError.status}` : 'Error'}
message={t(`errors.${axiosError?.statusText.toLowerCase()}`)}
cancelAction={() => setErrorAlertOpen(false)}
cancelActionText={t('buttons.confirm')}
/>
)
}
const mainSummonElement = (
<div className="LabeledUnit">
<div className="Label">{t('summons.main')}</div>
@ -460,6 +478,7 @@ const SummonGrid = (props: Props) => {
</div>
{subAuraSummonElement}
{errorAlert()}
</div>
)
}

View file

@ -4,7 +4,7 @@ import { getCookie } from 'cookies-next'
import { useSnapshot } from 'valtio'
import { useTranslation } from 'next-i18next'
import { AxiosResponse } from 'axios'
import { AxiosError, AxiosResponse } from 'axios'
import debounce from 'lodash.debounce'
import Alert from '~components/Alert'
@ -41,11 +41,15 @@ const WeaponGrid = (props: Props) => {
? JSON.parse(cookie as string)
: null
// Set up state for error handling
const [axiosError, setAxiosError] = useState<AxiosResponse>()
const [errorAlertOpen, setErrorAlertOpen] = useState(false)
const [showIncompatibleAlert, setShowIncompatibleAlert] = useState(false)
// Set up state for view management
const { party, grid } = useSnapshot(appState)
const [slug, setSlug] = useState()
const [modalOpen, setModalOpen] = useState(false)
const [showIncompatibleAlert, setShowIncompatibleAlert] = useState(false)
// Set up state for conflict management
const [incoming, setIncoming] = useState<Weapon>()
@ -100,11 +104,21 @@ const WeaponGrid = (props: Props) => {
saveWeapon(party.id, weapon, position)
.then((response) => handleWeaponResponse(response.data))
.catch((error) => {
const code = error.response.status
const data = error.response.data
if (code === 422) {
if (data.code === 'incompatible_weapon_for_position') {
const axiosError = error as AxiosError
const response = axiosError.response
if (response) {
const code = response.status
const data = response.data
if (
code === 422 &&
data.code === 'incompatible_weapon_for_position'
) {
setShowIncompatibleAlert(true)
} else {
setErrorAlertOpen(true)
setAxiosError(response)
}
}
})
@ -362,16 +376,30 @@ const WeaponGrid = (props: Props) => {
cancelAction={() => setShowIncompatibleAlert(!showIncompatibleAlert)}
cancelActionText={t('buttons.confirm')}
message={t('alert.incompatible_weapon')}
></Alert>
/>
) : (
''
)
}
const errorAlert = () => {
console.log(axiosError?.status)
return (
<Alert
open={errorAlertOpen}
title={axiosError ? `${axiosError.status}` : 'Error'}
message={t(`errors.${axiosError?.statusText.toLowerCase()}`)}
cancelAction={() => setErrorAlertOpen(false)}
cancelActionText={t('buttons.confirm')}
/>
)
}
return (
<div id="WeaponGrid">
{conflicts ? conflictModal() : ''}
{incompatibleAlert()}
{errorAlert()}
<div id="MainGrid">
{mainhandElement}
<ul id="Weapons">{weaponGridElement}</ul>

View file

@ -51,6 +51,9 @@
},
"remove": "Remove from grid"
},
"errors": {
"unauthorized": "You don't have permission to perform that action"
},
"filters": {
"labels": {
"element": "Element",

View file

@ -59,6 +59,9 @@
"rarity": "レアリティ"
}
},
"errors": {
"unauthorized": "行ったアクションを実行する権限がありません"
},
"header": {
"anonymous": "無名",
"untitled_team": "{{username}}さんからの無題編成",