@@ -219,6 +264,7 @@ const SummonGrid = (props: Props) => {
key="grid_main_summon"
position={-1}
unitType={0}
+ removeSummon={removeSummon}
updateObject={receiveSummonFromSearch}
updateUncap={initiateUncapUpdate}
/>
@@ -251,6 +297,7 @@ const SummonGrid = (props: Props) => {
editable={party.editable}
position={i}
unitType={1}
+ removeSummon={removeSummon}
updateObject={receiveSummonFromSearch}
updateUncap={initiateUncapUpdate}
/>
@@ -266,6 +313,7 @@ const SummonGrid = (props: Props) => {
editable={party.editable}
exists={false}
offset={numSummons}
+ removeSummon={removeSummon}
updateObject={receiveSummonFromSearch}
updateUncap={initiateUncapUpdate}
/>
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 (
+ <>
+
+
+ }
+ className={buttonClasses}
+ onClick={handleButtonClicked}
+ />
+
+
+
+ {t('context.remove')}
+
+
+
+ {removeAlert()}
+ >
+ )
+ }
}
+ const removeAlert = () => {
+ return (
+ setAlertOpen(false)}
+ cancelActionText={t('buttons.cancel')}
+ message={
+
+ Are you sure you want to remove{' '}
+ {{ weapon: gridSummon?.object.name[locale] }} from
+ your team?
+
+ }
+ />
+ )
+ }
+
+ const searchModal = () => {
+ return (
+
+ )
+ }
+
+ // Methods: Core element rendering
const image = (
-
+

- {props.editable ? (
+ {editable ? (
@@ -116,41 +233,34 @@ const SummonUnit = (props: Props) => {
)
- const editableImage = (
-
- {image}
-
- )
-
const unitContent = (
-
- {props.editable ? editableImage : image}
- {gridSummon ? (
-
- ) : (
- ''
- )}
-
{summon?.name[locale]}
-
+ <>
+
+ {contextMenu()}
+ {image}
+ {gridSummon ? (
+
+ ) : (
+ ''
+ )}
+
{summon?.name[locale]}
+
+ {searchModal()}
+ >
)
- const withHovercard = (
+ const unitContentWithHovercard = (
{unitContent}
)
- return gridSummon && !props.editable ? withHovercard : unitContent
+ return gridSummon && !editable ? unitContentWithHovercard : unitContent
}
export default SummonUnit
diff --git a/components/WeaponUnit/index.tsx b/components/WeaponUnit/index.tsx
index 2c18cf53..978c7710 100644
--- a/components/WeaponUnit/index.tsx
+++ b/components/WeaponUnit/index.tsx
@@ -520,7 +520,7 @@ const WeaponUnit = ({