Add interactive uncap indicators for summons

This commit is contained in:
Justin Edmund 2022-02-01 15:50:06 -08:00
parent 36ddc6e506
commit 44966fe8fe
6 changed files with 85 additions and 50 deletions

View file

@ -12,12 +12,13 @@ export enum GridType {
// Props // Props
interface Props { interface Props {
grid: GridArray<Summon> grid: GridArray<GridSummon>
editable: boolean editable: boolean
exists: boolean exists: boolean
found?: boolean found?: boolean
offset: number offset: number
onClick: (position: number) => void onClick: (position: number) => void
updateUncap: (id: string, uncap: number) => void
} }
const ExtraSummons = (props: Props) => { const ExtraSummons = (props: Props) => {
@ -32,11 +33,12 @@ const ExtraSummons = (props: Props) => {
return ( return (
<li key={`grid_unit_${i}`} > <li key={`grid_unit_${i}`} >
<SummonUnit <SummonUnit
onClick={() => { props.onClick(props.offset + i) }}
editable={props.editable} editable={props.editable}
position={props.offset + i} position={props.offset + i}
unitType={1} unitType={1}
summon={props.grid[props.offset + i]} gridSummon={props.grid[props.offset + i]}
onClick={() => { props.onClick(props.offset + i) }}
updateUncap={props.updateUncap}
/> />
</li> </li>
) )

View file

@ -24,11 +24,11 @@ import './index.scss'
interface Props { interface Props {
partyId?: string partyId?: string
mainWeapon?: GridWeapon mainWeapon?: GridWeapon
mainSummon?: Summon mainSummon?: GridSummon
friendSummon?: Summon friendSummon?: GridSummon
characters?: GridArray<Character> characters?: GridArray<Character>
weapons?: GridArray<GridWeapon> weapons?: GridArray<GridWeapon>
summons?: GridArray<Summon> summons?: GridArray<GridSummon>
extra: boolean extra: boolean
editable: boolean editable: boolean
exists: boolean exists: boolean
@ -47,11 +47,11 @@ const Party = (props: Props) => {
// Grid data // Grid data
const [characters, setCharacters] = useState<GridArray<Character>>({}) const [characters, setCharacters] = useState<GridArray<Character>>({})
const [weapons, setWeapons] = useState<GridArray<GridWeapon>>({}) const [weapons, setWeapons] = useState<GridArray<GridWeapon>>({})
const [summons, setSummons] = useState<GridArray<Summon>>({}) const [summons, setSummons] = useState<GridArray<GridSummon>>({})
const [mainWeapon, setMainWeapon] = useState<GridWeapon>() const [mainWeapon, setMainWeapon] = useState<GridWeapon>()
const [mainSummon, setMainSummon] = useState<Summon>() const [mainSummon, setMainSummon] = useState<GridSummon>()
const [friendSummon, setFriendSummon] = useState<Summon>() const [friendSummon, setFriendSummon] = useState<GridSummon>()
const [extra, setExtra] = useState<boolean>(false) const [extra, setExtra] = useState<boolean>(false)
@ -185,8 +185,8 @@ const Party = (props: Props) => {
case GridType.Summon: case GridType.Summon:
const summon = item as Summon const summon = item as Summon
saveSummon(summon, position, partyId) saveSummon(summon, position, partyId)
.then(() => { .then((response) => {
storeSummon(summon, position) storeSummon(response.data.grid_summon, position)
}) })
break break
} }
@ -224,7 +224,7 @@ const Party = (props: Props) => {
} }
// Summons // Summons
function storeSummon(summon: Summon, position: number) { function storeSummon(summon: GridSummon, position: number) {
if (position == -1) { if (position == -1) {
setMainSummon(summon) setMainSummon(summon)
} else if (position == 6) { } else if (position == 6) {
@ -238,7 +238,7 @@ const Party = (props: Props) => {
} }
async function saveSummon(summon: Summon, position: number, party: string) { async function saveSummon(summon: Summon, position: number, party: string) {
await api.endpoints.summons.create({ return await api.endpoints.summons.create({
'summon': { 'summon': {
'party_id': party, 'party_id': party,
'summon_id': summon.id, 'summon_id': summon.id,

View file

@ -1,10 +1,13 @@
import React, { useState } from 'react' import React, { useCallback, useState } from 'react'
import { useModal as useModal } from '~utils/useModal' import { useModal as useModal } from '~utils/useModal'
import SearchModal from '~components/SearchModal' import debounce from 'lodash.debounce'
import ExtraSummons from '~components/ExtraSummons'
import SummonUnit from '~components/SummonUnit'
import SearchModal from '~components/SearchModal'
import SummonUnit from '~components/SummonUnit'
import ExtraSummons from '~components/ExtraSummons'
import api from '~utils/api'
import './index.scss' import './index.scss'
// GridType // GridType
@ -19,9 +22,9 @@ export enum GridType {
interface Props { interface Props {
userId?: string userId?: string
partyId?: string partyId?: string
main?: Summon | undefined main?: GridSummon | undefined
friend?: Summon | undefined friend?: GridSummon | undefined
grid: GridArray<Summon> grid: GridArray<GridSummon>
editable: boolean editable: boolean
exists: boolean exists: boolean
found?: boolean found?: boolean
@ -33,11 +36,7 @@ const SummonGrid = (props: Props) => {
const [searchPosition, setSearchPosition] = useState(0) const [searchPosition, setSearchPosition] = useState(0)
const numSummons: number = 4 const numSummons: number = 4
const searchGrid: GridArray<Summon> = Object.values(props.grid).map((o) => o.summon)
function openSearchModal(position: number) {
setSearchPosition(position)
openModal()
}
function receiveSummon(summon: Summon, position: number) { function receiveSummon(summon: Summon, position: number) {
props.onSelect(GridType.Summon, summon, position) props.onSelect(GridType.Summon, summon, position)
@ -54,30 +53,54 @@ const SummonGrid = (props: Props) => {
return (object as Summon).granblue_id !== undefined return (object as Summon).granblue_id !== undefined
} }
function openSearchModal(position: number) {
setSearchPosition(position)
openModal()
}
async function updateUncap(id: string, level: number) {
await api.updateUncap('summon', id, level)
.catch(error => {
console.error(error)
})
}
const initiateUncapUpdate = (id: string, uncapLevel: number) => {
debouncedAction(id, uncapLevel)
}
const debouncedAction = useCallback(
() => debounce((id, number) => {
updateUncap(id, number)
}, 1000), []
)()
return ( return (
<div> <div>
<div className="SummonGrid"> <div className="SummonGrid">
<div className="LabeledUnit"> <div className="LabeledUnit">
<div className="Label">Main Summon</div> <div className="Label">Main Summon</div>
<SummonUnit <SummonUnit
onClick={() => { openSearchModal(0) }}
editable={props.editable} editable={props.editable}
key="grid_main_summon" key="grid_main_summon"
position={-1} position={-1}
unitType={0} unitType={0}
summon={props.main} gridSummon={props.main}
onClick={() => { openSearchModal(-1) }}
updateUncap={initiateUncapUpdate}
/> />
</div> </div>
<div className="LabeledUnit"> <div className="LabeledUnit">
<div className="Label">Friend Summon</div> <div className="Label">Friend Summon</div>
<SummonUnit <SummonUnit
onClick={() => { openSearchModal(6) }}
editable={props.editable} editable={props.editable}
key="grid_friend_summon" key="grid_friend_summon"
position={6} position={6}
unitType={2} unitType={2}
summon={props.friend} gridSummon={props.friend}
onClick={() => { openSearchModal(6) }}
updateUncap={initiateUncapUpdate}
/> />
</div> </div>
@ -89,11 +112,12 @@ const SummonGrid = (props: Props) => {
return ( return (
<li key={`grid_unit_${i}`} > <li key={`grid_unit_${i}`} >
<SummonUnit <SummonUnit
onClick={() => { openSearchModal(i) }}
editable={props.editable} editable={props.editable}
position={i} position={i}
unitType={1} unitType={1}
summon={props.grid[i]} gridSummon={props.grid[i]}
onClick={() => { openSearchModal(i) }}
updateUncap={initiateUncapUpdate}
/> />
</li> </li>
) )
@ -104,16 +128,17 @@ const SummonGrid = (props: Props) => {
</div> </div>
<ExtraSummons <ExtraSummons
onClick={openSearchModal}
grid={props.grid} grid={props.grid}
editable={props.editable} editable={props.editable}
exists={false} exists={false}
offset={numSummons} offset={numSummons}
onClick={openSearchModal}
updateUncap={initiateUncapUpdate}
/> />
{open ? ( {open ? (
<SearchModal <SearchModal
grid={props.grid} grid={searchGrid}
close={closeModal} close={closeModal}
send={sendData} send={sendData}
fromPosition={searchPosition} fromPosition={searchPosition}

View file

@ -1,16 +1,15 @@
import React, { useEffect, useState } from 'react' import React, { useEffect, useState } from 'react'
import classnames from 'classnames' import classnames from 'classnames'
import UncapIndicator from '~components/UncapIndicator' import UncapIndicator from '~components/UncapIndicator'
import PlusIcon from '~public/icons/plus.svg' import PlusIcon from '~public/icons/plus.svg'
import './index.scss' import './index.scss'
interface Props { interface Props {
onClick: () => void onClick: () => void
summon: Summon | undefined updateUncap: (id: string, uncap: number) => void
gridSummon: GridSummon | undefined
position: number position: number
editable: boolean editable: boolean
unitType: 0 | 1 | 2 unitType: 0 | 1 | 2
@ -25,10 +24,11 @@ const SummonUnit = (props: Props) => {
'grid': props.unitType == 1, 'grid': props.unitType == 1,
'friend': props.unitType == 2, 'friend': props.unitType == 2,
'editable': props.editable, 'editable': props.editable,
'filled': (props.summon !== undefined) 'filled': (props.gridSummon !== undefined)
}) })
const summon = props.summon const gridSummon = props.gridSummon
const summon = gridSummon?.summon
useEffect(() => { useEffect(() => {
generateImageUrl() generateImageUrl()
@ -36,8 +36,8 @@ const SummonUnit = (props: Props) => {
function generateImageUrl() { function generateImageUrl() {
let imgSrc = "" let imgSrc = ""
if (props.summon) { if (props.gridSummon) {
const summon = props.summon! const summon = props.gridSummon.summon!
// Generate the correct source for the summon // Generate the correct source for the summon
if (props.unitType == 0 || props.unitType == 2) if (props.unitType == 0 || props.unitType == 2)
@ -49,6 +49,11 @@ const SummonUnit = (props: Props) => {
setImageUrl(imgSrc) setImageUrl(imgSrc)
} }
function passUncapData(uncap: number) {
if (props.gridSummon)
props.updateUncap(props.gridSummon.id, uncap)
}
return ( return (
<div> <div>
<div className={classes}> <div className={classes}>
@ -56,12 +61,14 @@ const SummonUnit = (props: Props) => {
<img alt={summon?.name.en} className="grid_image" src={imageUrl} /> <img alt={summon?.name.en} className="grid_image" src={imageUrl} />
{ (props.editable) ? <span className='icon'><PlusIcon /></span> : '' } { (props.editable) ? <span className='icon'><PlusIcon /></span> : '' }
</div> </div>
{ (gridSummon) ?
<UncapIndicator <UncapIndicator
type="summon" type="summon"
ulb={summon?.uncap.ulb || false} ulb={summon?.uncap.ulb || false}
flb={summon?.uncap.flb || false} flb={summon?.uncap.flb || false}
uncapLevel={3} uncapLevel={gridSummon?.uncap_level}
/> updateUncap={passUncapData}
/> : '' }
<h3 className="SummonName">{summon?.name.en}</h3> <h3 className="SummonName">{summon?.name.en}</h3>
</div> </div>
</div> </div>

View file

@ -24,11 +24,11 @@ const PartyRoute: React.FC = () => {
const [characters, setCharacters] = useState<GridArray<Character>>({}) const [characters, setCharacters] = useState<GridArray<Character>>({})
const [weapons, setWeapons] = useState<GridArray<GridWeapon>>({}) const [weapons, setWeapons] = useState<GridArray<GridWeapon>>({})
const [summons, setSummons] = useState<GridArray<Summon>>({}) const [summons, setSummons] = useState<GridArray<GridSummon>>({})
const [mainWeapon, setMainWeapon] = useState<GridWeapon>() const [mainWeapon, setMainWeapon] = useState<GridWeapon>()
const [mainSummon, setMainSummon] = useState<Summon>() const [mainSummon, setMainSummon] = useState<GridSummon>()
const [friendSummon, setFriendSummon] = useState<Summon>() const [friendSummon, setFriendSummon] = useState<GridSummon>()
const [partyId, setPartyId] = useState('') const [partyId, setPartyId] = useState('')
const [extra, setExtra] = useState<boolean>(false) const [extra, setExtra] = useState<boolean>(false)
@ -97,15 +97,15 @@ const PartyRoute: React.FC = () => {
} }
function populateSummons(list: [GridSummon]) { function populateSummons(list: [GridSummon]) {
let summons: GridArray<Summon> = {} let summons: GridArray<GridSummon> = {}
list.forEach((object: GridSummon) => { list.forEach((object: GridSummon) => {
if (object.main) if (object.main)
setMainSummon(object.summon) setMainSummon(object)
else if (object.friend) else if (object.friend)
setFriendSummon(object.summon) setFriendSummon(object)
else if (!object.main && !object.friend && object.position != null) else if (!object.main && !object.friend && object.position != null)
summons[object.position] = object.summon summons[object.position] = object
}) })
return summons return summons

View file

@ -4,4 +4,5 @@ interface GridSummon {
friend: boolean friend: boolean
position: number | null position: number | null
summon: Summon summon: Summon
uncap_level: number
} }