From ddee38e37cca7452128d235d4297fac46e062f96 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sat, 21 Jan 2023 15:18:01 -0800 Subject: [PATCH 1/3] Refactor SummonUnit and add alert and contextmenu --- components/CharacterUnit/index.tsx | 6 +- components/SummonUnit/index.scss | 14 ++ components/SummonUnit/index.tsx | 216 ++++++++++++++++++++++------- components/WeaponUnit/index.tsx | 2 +- public/locales/en/common.json | 5 + public/locales/ja/common.json | 5 + 6 files changed, 193 insertions(+), 55 deletions(-) diff --git a/components/CharacterUnit/index.tsx b/components/CharacterUnit/index.tsx index 3e6ec5b0..d79a7b22 100644 --- a/components/CharacterUnit/index.tsx +++ b/components/CharacterUnit/index.tsx @@ -230,7 +230,11 @@ const CharacterUnit = ({ // Methods: Core element rendering const image = (
- {character?.name.en} + {character?.name[locale]} {editable ? ( diff --git a/components/SummonUnit/index.scss b/components/SummonUnit/index.scss index efc7f263..2124ed0b 100644 --- a/components/SummonUnit/index.scss +++ b/components/SummonUnit/index.scss @@ -2,6 +2,20 @@ display: flex; flex-direction: column; gap: 4px; + position: relative; + z-index: 0; + + .Button { + pointer-events: none; + opacity: 0; + z-index: 10; + } + + &:hover .Button, + .Button.Clicked { + pointer-events: initial; + opacity: 1; + } &.grid { // max-width: 148px; diff --git a/components/SummonUnit/index.tsx b/components/SummonUnit/index.tsx index 571f3dff..48847211 100644 --- a/components/SummonUnit/index.tsx +++ b/components/SummonUnit/index.tsx @@ -1,15 +1,24 @@ -import React, { useEffect, useState } from 'react' +import React, { MouseEvent, useEffect, useState } from 'react' import { useRouter } from 'next/router' -import { useTranslation } from 'next-i18next' +import { Trans, useTranslation } from 'next-i18next' import classNames from 'classnames' +import Alert from '~components/Alert' +import Button from '~components/Button' +import { + ContextMenu, + ContextMenuTrigger, + ContextMenuContent, +} from '~components/ContextMenu' +import ContextMenuItem from '~components/ContextMenuItem' import SearchModal from '~components/SearchModal' import SummonHovercard from '~components/SummonHovercard' import UncapIndicator from '~components/UncapIndicator' -import PlusIcon from '~public/icons/Add.svg' import type { SearchableObject } from '~types' +import PlusIcon from '~public/icons/Add.svg' +import SettingsIcon from '~public/icons/Settings.svg' import './index.scss' interface Props { @@ -17,39 +26,94 @@ interface Props { unitType: 0 | 1 | 2 position: number editable: boolean + removeSummon: (id: string) => void updateObject: (object: SearchableObject, position: number) => void updateUncap: (id: string, position: number, uncap: number) => void } -const SummonUnit = (props: Props) => { +const SummonUnit = ({ + gridSummon, + unitType, + position, + editable, + removeSummon: sendSummonToRemove, + updateObject, + updateUncap, +}: Props) => { + // Translations and locale const { t } = useTranslation('common') - - const [imageUrl, setImageUrl] = useState('') - const router = useRouter() const locale = router.locale && ['en', 'ja'].includes(router.locale) ? router.locale : 'en' + // State: UI + const [searchModalOpen, setSearchModalOpen] = useState(false) + const [contextMenuOpen, setContextMenuOpen] = useState(false) + const [alertOpen, setAlertOpen] = useState(false) + + // State: Other + const [imageUrl, setImageUrl] = useState('') + + // Classes const classes = classNames({ SummonUnit: true, - main: props.unitType == 0, - grid: props.unitType == 1, - friend: props.unitType == 2, - editable: props.editable, - filled: props.gridSummon !== undefined, + main: unitType == 0, + grid: unitType == 1, + friend: unitType == 2, + editable: editable, + filled: gridSummon !== undefined, }) - const gridSummon = props.gridSummon + const buttonClasses = classNames({ + Options: true, + Clicked: contextMenuOpen, + }) + + // Other const summon = gridSummon?.object + // Hooks useEffect(() => { generateImageUrl() }) + // Methods: Open layer + function openSearchModal(event: MouseEvent) { + if (editable) setSearchModalOpen(true) + } + + function openRemoveSummonAlert() { + setAlertOpen(true) + } + + // Methods: Handle button clicked + function handleButtonClicked() { + setContextMenuOpen(!contextMenuOpen) + } + + // Methods: Handle open change + function handleContextMenuOpenChange(open: boolean) { + if (!open) setContextMenuOpen(false) + } + + function handleSearchModalOpenChange(open: boolean) { + setSearchModalOpen(open) + } + + // Methods: Mutate data + function passUncapData(uncap: number) { + if (gridSummon) updateUncap(gridSummon.id, position, uncap) + } + + function removeSummon() { + if (gridSummon) sendSummonToRemove(gridSummon.id) + } + + // Methods: Image string generation function generateImageUrl() { let imgSrc = '' - if (props.gridSummon) { - const summon = props.gridSummon.object! + if (gridSummon) { + const summon = gridSummon.object! const upgradedSummons = [ '2040094000', @@ -71,12 +135,12 @@ const SummonUnit = (props: Props) => { let suffix = '' if ( upgradedSummons.indexOf(summon.granblue_id.toString()) != -1 && - props.gridSummon.uncap_level == 5 + gridSummon.uncap_level == 5 ) suffix = '_02' // Generate the correct source for the summon - if (props.unitType == 0 || props.unitType == 2) + if (unitType == 0 || unitType == 2) imgSrc = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/summon-main/${summon.granblue_id}${suffix}.jpg` else imgSrc = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/summon-grid/${summon.granblue_id}${suffix}.jpg` @@ -86,27 +150,80 @@ const SummonUnit = (props: Props) => { } function placeholderImageUrl() { - return props.unitType == 0 || props.unitType == 2 + return unitType == 0 || unitType == 2 ? '/images/placeholders/placeholder-summon-main.png' : '/images/placeholders/placeholder-summon-grid.png' } - function passUncapData(uncap: number) { - if (props.gridSummon) - props.updateUncap(props.gridSummon.id, props.position, uncap) + // Methods: Layer element rendering + const contextMenu = () => { + if (editable && gridSummon && gridSummon.id) { + return ( + <> + + +
{weapon?.name.en} Date: Sat, 21 Jan 2023 15:40:42 -0800 Subject: [PATCH 2/3] Implement deleting summons --- components/ExtraSummons/index.tsx | 2 ++ components/SummonGrid/index.tsx | 20 ++++++++++++++++++++ utils/api.tsx | 1 + 3 files changed, 23 insertions(+) diff --git a/components/ExtraSummons/index.tsx b/components/ExtraSummons/index.tsx index 4ef55272..ea3f7993 100644 --- a/components/ExtraSummons/index.tsx +++ b/components/ExtraSummons/index.tsx @@ -11,6 +11,7 @@ interface Props { exists: boolean found?: boolean offset: number + removeSummon: (id: string) => void updateObject: (object: SearchableObject, position: number) => void updateUncap: (id: string, position: number, uncap: number) => void } @@ -31,6 +32,7 @@ const ExtraSummons = (props: Props) => { editable={props.editable} position={props.offset + i} unitType={1} + removeSummon={props.removeSummon} gridSummon={props.grid[props.offset + i]} updateObject={props.updateObject} updateUncap={props.updateUncap} diff --git a/components/SummonGrid/index.tsx b/components/SummonGrid/index.tsx index de1847bb..23500bff 100644 --- a/components/SummonGrid/index.tsx +++ b/components/SummonGrid/index.tsx @@ -209,6 +209,23 @@ const SummonGrid = (props: Props) => { setPreviousUncapValues(newPreviousValues) } + async function removeSummon(id: string) { + try { + const response = await api.endpoints.grid_summons.destroy({ id: id }) + const data = response.data + + if (data.position === -1) { + appState.grid.summons.mainSummon = undefined + } else if (data.position === 6) { + appState.grid.summons.friendSummon = undefined + } else { + appState.grid.summons.allSummons[response.data.position] = undefined + } + } catch (error) { + console.error(error) + } + } + // Render: JSX components const mainSummonElement = (
@@ -219,6 +236,7 @@ const SummonGrid = (props: Props) => { key="grid_main_summon" position={-1} unitType={0} + removeSummon={removeSummon} updateObject={receiveSummonFromSearch} updateUncap={initiateUncapUpdate} /> @@ -251,6 +269,7 @@ const SummonGrid = (props: Props) => { editable={party.editable} position={i} unitType={1} + removeSummon={removeSummon} updateObject={receiveSummonFromSearch} updateUncap={initiateUncapUpdate} /> @@ -266,6 +285,7 @@ const SummonGrid = (props: Props) => { editable={party.editable} exists={false} offset={numSummons} + removeSummon={removeSummon} updateObject={receiveSummonFromSearch} updateUncap={initiateUncapUpdate} /> diff --git a/utils/api.tsx b/utils/api.tsx index 5fe6d589..0acb1d40 100644 --- a/utils/api.tsx +++ b/utils/api.tsx @@ -154,6 +154,7 @@ api.createEntity({ name: 'users' }) api.createEntity({ name: 'parties' }) api.createEntity({ name: 'grid_characters' }) api.createEntity({ name: 'grid_weapons' }) +api.createEntity({ name: 'grid_summons' }) api.createEntity({ name: 'characters' }) api.createEntity({ name: 'weapons' }) api.createEntity({ name: 'summons' }) From 3ce7145ec4886d577734e1bd812e1426e092eee4 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Sat, 21 Jan 2023 19:12:54 -0800 Subject: [PATCH 3/3] Add handleSummonResponse --- components/SummonGrid/index.tsx | 34 ++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/components/SummonGrid/index.tsx b/components/SummonGrid/index.tsx index 23500bff..0bf300e9 100644 --- a/components/SummonGrid/index.tsx +++ b/components/SummonGrid/index.tsx @@ -93,9 +93,37 @@ const SummonGrid = (props: Props) => { }) } else { if (party.editable) - saveSummon(party.id, summon, position).then((response) => - storeGridSummon(response.data) - ) + 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) + } + } + }) + } + } + + async function handleSummonResponse(data: any) { + if (data.hasOwnProperty('errors')) { + } else { + storeGridSummon(data.grid_summon) + + // If we replaced an existing weapon, remove it from the grid + if (data.hasOwnProperty('meta') && data.meta['replaced'] !== undefined) { + const position = data.meta['replaced'] + + if (position == -1) { + appState.grid.summons.mainSummon = undefined + } else if (position == 6) { + appState.grid.summons.friendSummon = undefined + } else { + appState.grid.summons.allSummons[position] = undefined + } + } } }