Add type alias for searchable objects
This commit is contained in:
parent
322964d767
commit
73944becf4
5 changed files with 368 additions and 314 deletions
|
|
@ -1,41 +1,43 @@
|
|||
import React, { useEffect, useState } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useSnapshot } from 'valtio'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import classnames from 'classnames'
|
||||
import React, { useEffect, useState } from "react"
|
||||
import { useRouter } from "next/router"
|
||||
import { useSnapshot } from "valtio"
|
||||
import { useTranslation } from "next-i18next"
|
||||
import classnames from "classnames"
|
||||
|
||||
import { appState } from '~utils/appState'
|
||||
import { appState } from "~utils/appState"
|
||||
|
||||
import CharacterHovercard from '~components/CharacterHovercard'
|
||||
import SearchModal from '~components/SearchModal'
|
||||
import UncapIndicator from '~components/UncapIndicator'
|
||||
import PlusIcon from '~public/icons/Add.svg'
|
||||
import CharacterHovercard from "~components/CharacterHovercard"
|
||||
import SearchModal from "~components/SearchModal"
|
||||
import UncapIndicator from "~components/UncapIndicator"
|
||||
import PlusIcon from "~public/icons/Add.svg"
|
||||
|
||||
import './index.scss'
|
||||
import { getRedirectStatus } from 'next/dist/lib/load-custom-routes'
|
||||
import type { SearchableObject } from "~types"
|
||||
|
||||
import "./index.scss"
|
||||
|
||||
interface Props {
|
||||
gridCharacter: GridCharacter | undefined
|
||||
gridCharacter?: GridCharacter
|
||||
position: number
|
||||
editable: boolean
|
||||
updateObject: (object: Character | Weapon | Summon, position: number) => void
|
||||
updateObject: (object: SearchableObject, position: number) => void
|
||||
updateUncap: (id: string, position: number, uncap: number) => void
|
||||
}
|
||||
|
||||
const CharacterUnit = (props: Props) => {
|
||||
const { t } = useTranslation('common')
|
||||
const { t } = useTranslation("common")
|
||||
|
||||
const { party, grid } = useSnapshot(appState)
|
||||
|
||||
const router = useRouter()
|
||||
const locale = (router.locale && ['en', 'ja'].includes(router.locale)) ? router.locale : 'en'
|
||||
const locale =
|
||||
router.locale && ["en", "ja"].includes(router.locale) ? router.locale : "en"
|
||||
|
||||
const [imageUrl, setImageUrl] = useState('')
|
||||
const [imageUrl, setImageUrl] = useState("")
|
||||
|
||||
const classes = classnames({
|
||||
CharacterUnit: true,
|
||||
'editable': props.editable,
|
||||
'filled': (props.gridCharacter !== undefined)
|
||||
editable: props.editable,
|
||||
filled: props.gridCharacter !== undefined,
|
||||
})
|
||||
|
||||
const gridCharacter = props.gridCharacter
|
||||
|
|
@ -52,16 +54,13 @@ const CharacterUnit = (props: Props) => {
|
|||
const character = props.gridCharacter.object!
|
||||
|
||||
// Change the image based on the uncap level
|
||||
let suffix = '01'
|
||||
if (props.gridCharacter.uncap_level == 6)
|
||||
suffix = '04'
|
||||
else if (props.gridCharacter.uncap_level == 5)
|
||||
suffix = '03'
|
||||
else if (props.gridCharacter.uncap_level > 2)
|
||||
suffix = '02'
|
||||
let suffix = "01"
|
||||
if (props.gridCharacter.uncap_level == 6) suffix = "04"
|
||||
else if (props.gridCharacter.uncap_level == 5) suffix = "03"
|
||||
else if (props.gridCharacter.uncap_level > 2) suffix = "02"
|
||||
|
||||
// Special casing for Lyria (and Young Cat eventually)
|
||||
if (props.gridCharacter.object.granblue_id === '3030182000') {
|
||||
if (props.gridCharacter.object.granblue_id === "3030182000") {
|
||||
let element = 1
|
||||
if (grid.weapons.mainWeapon && grid.weapons.mainWeapon.element) {
|
||||
element = grid.weapons.mainWeapon.element
|
||||
|
|
@ -86,24 +85,31 @@ const CharacterUnit = (props: Props) => {
|
|||
const image = (
|
||||
<div className="CharacterImage">
|
||||
<img alt={character?.name.en} className="grid_image" src={imageUrl} />
|
||||
{ (props.editable) ? <span className='icon'><PlusIcon /></span> : '' }
|
||||
{props.editable ? (
|
||||
<span className="icon">
|
||||
<PlusIcon />
|
||||
</span>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
|
||||
const editableImage = (
|
||||
<SearchModal
|
||||
placeholderText={t('search.placeholders.character')}
|
||||
placeholderText={t("search.placeholders.character")}
|
||||
fromPosition={props.position}
|
||||
object="characters"
|
||||
send={props.updateObject}>
|
||||
send={props.updateObject}
|
||||
>
|
||||
{image}
|
||||
</SearchModal>
|
||||
)
|
||||
|
||||
const unitContent = (
|
||||
<div className={classes}>
|
||||
{ (props.editable) ? editableImage : image }
|
||||
{ (gridCharacter && character) ?
|
||||
{props.editable ? editableImage : image}
|
||||
{gridCharacter && character ? (
|
||||
<UncapIndicator
|
||||
type="character"
|
||||
flb={character.uncap.flb || false}
|
||||
|
|
@ -111,7 +117,10 @@ const CharacterUnit = (props: Props) => {
|
|||
uncapLevel={gridCharacter.uncap_level}
|
||||
updateUncap={passUncapData}
|
||||
special={character.special}
|
||||
/> : '' }
|
||||
/>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
<h3 className="CharacterName">{character?.name[locale]}</h3>
|
||||
</div>
|
||||
)
|
||||
|
|
@ -122,9 +131,7 @@ const CharacterUnit = (props: Props) => {
|
|||
</CharacterHovercard>
|
||||
)
|
||||
|
||||
return (
|
||||
(gridCharacter && !props.editable) ? withHovercard : unitContent
|
||||
)
|
||||
return gridCharacter && !props.editable ? withHovercard : unitContent
|
||||
}
|
||||
|
||||
export default CharacterUnit
|
||||
|
|
|
|||
|
|
@ -17,13 +17,14 @@ import SummonSearchFilterBar from "~components/SummonSearchFilterBar"
|
|||
import CharacterResult from "~components/CharacterResult"
|
||||
import WeaponResult from "~components/WeaponResult"
|
||||
import SummonResult from "~components/SummonResult"
|
||||
import type { SearchableObject, SearchableObjectArray } from "~types"
|
||||
|
||||
import "./index.scss"
|
||||
import CrossIcon from "~public/icons/Cross.svg"
|
||||
import cloneDeep from "lodash.clonedeep"
|
||||
|
||||
interface Props {
|
||||
send: (object: Character | Weapon | Summon, position: number) => any
|
||||
send: (object: SearchableObject, position: number) => any
|
||||
placeholderText: string
|
||||
fromPosition: number
|
||||
object: "weapons" | "characters" | "summons"
|
||||
|
|
@ -51,7 +52,7 @@ const SearchModal = (props: Props) => {
|
|||
const [filters, setFilters] = useState<{ [key: string]: number[] }>()
|
||||
const [open, setOpen] = useState(false)
|
||||
const [query, setQuery] = useState("")
|
||||
const [results, setResults] = useState<(Weapon | Summon | Character)[]>([])
|
||||
const [results, setResults] = useState<SearchableObjectArray>([])
|
||||
|
||||
// Pagination states
|
||||
const [recordCount, setRecordCount] = useState(0)
|
||||
|
|
@ -99,10 +100,7 @@ const SearchModal = (props: Props) => {
|
|||
})
|
||||
}
|
||||
|
||||
function replaceResults(
|
||||
count: number,
|
||||
list: Weapon[] | Summon[] | Character[]
|
||||
) {
|
||||
function replaceResults(count: number, list: SearchableObjectArray) {
|
||||
if (count > 0) {
|
||||
setResults(list)
|
||||
} else {
|
||||
|
|
@ -110,26 +108,36 @@ const SearchModal = (props: Props) => {
|
|||
}
|
||||
}
|
||||
|
||||
function appendResults(list: Weapon[] | Summon[] | Character[]) {
|
||||
function appendResults(list: SearchableObjectArray) {
|
||||
setResults([...results, ...list])
|
||||
}
|
||||
|
||||
function storeRecentResult(result: Character | Weapon | Summon) {
|
||||
function storeRecentResult(result: SearchableObject) {
|
||||
const key = `recent_${props.object}`
|
||||
const cookie = getCookie(key)
|
||||
const cookieObj: Character[] | Weapon[] | Summon[] = cookie
|
||||
const cookieObj: SearchableObjectArray = cookie
|
||||
? JSON.parse(cookie as string)
|
||||
: []
|
||||
let recents: Character[] | Weapon[] | Summon[] = []
|
||||
let recents: SearchableObjectArray = []
|
||||
|
||||
if (props.object === "weapons") {
|
||||
recents = cloneDeep(cookieObj as Weapon[]) || []
|
||||
if (!recents.find((item) => item.granblue_id === result.granblue_id)) {
|
||||
if (
|
||||
!recents.find(
|
||||
(item) =>
|
||||
(item as Weapon).granblue_id === (result as Weapon).granblue_id
|
||||
)
|
||||
) {
|
||||
recents.unshift(result as Weapon)
|
||||
}
|
||||
} else if (props.object === "summons") {
|
||||
recents = cloneDeep(cookieObj as Summon[]) || []
|
||||
if (!recents.find((item) => item.granblue_id === result.granblue_id)) {
|
||||
if (
|
||||
!recents.find(
|
||||
(item) =>
|
||||
(item as Summon).granblue_id === (result as Summon).granblue_id
|
||||
)
|
||||
) {
|
||||
recents.unshift(result as Summon)
|
||||
}
|
||||
}
|
||||
|
|
@ -139,7 +147,7 @@ const SearchModal = (props: Props) => {
|
|||
sendData(result)
|
||||
}
|
||||
|
||||
function sendData(result: Character | Weapon | Summon) {
|
||||
function sendData(result: SearchableObject) {
|
||||
props.send(result, props.fromPosition)
|
||||
openChange()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,39 +1,42 @@
|
|||
import React, { useEffect, useState } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import classnames from 'classnames'
|
||||
import React, { useEffect, useState } from "react"
|
||||
import { useRouter } from "next/router"
|
||||
import { useTranslation } from "next-i18next"
|
||||
import classnames from "classnames"
|
||||
|
||||
import SearchModal from '~components/SearchModal'
|
||||
import SummonHovercard from '~components/SummonHovercard'
|
||||
import UncapIndicator from '~components/UncapIndicator'
|
||||
import PlusIcon from '~public/icons/Add.svg'
|
||||
import SearchModal from "~components/SearchModal"
|
||||
import SummonHovercard from "~components/SummonHovercard"
|
||||
import UncapIndicator from "~components/UncapIndicator"
|
||||
import PlusIcon from "~public/icons/Add.svg"
|
||||
|
||||
import './index.scss'
|
||||
import type { SearchableObject } from "~types"
|
||||
|
||||
import "./index.scss"
|
||||
|
||||
interface Props {
|
||||
gridSummon: GridSummon | undefined
|
||||
unitType: 0 | 1 | 2
|
||||
position: number
|
||||
editable: boolean
|
||||
updateObject: (object: Character | Weapon | Summon, position: number) => void
|
||||
updateObject: (object: SearchableObject, position: number) => void
|
||||
updateUncap: (id: string, position: number, uncap: number) => void
|
||||
}
|
||||
|
||||
const SummonUnit = (props: Props) => {
|
||||
const { t } = useTranslation('common')
|
||||
const { t } = useTranslation("common")
|
||||
|
||||
const [imageUrl, setImageUrl] = useState('')
|
||||
const [imageUrl, setImageUrl] = useState("")
|
||||
|
||||
const router = useRouter()
|
||||
const locale = (router.locale && ['en', 'ja'].includes(router.locale)) ? router.locale : 'en'
|
||||
const locale =
|
||||
router.locale && ["en", "ja"].includes(router.locale) ? router.locale : "en"
|
||||
|
||||
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: props.unitType == 0,
|
||||
grid: props.unitType == 1,
|
||||
friend: props.unitType == 2,
|
||||
editable: props.editable,
|
||||
filled: props.gridSummon !== undefined,
|
||||
})
|
||||
|
||||
const gridSummon = props.gridSummon
|
||||
|
|
@ -49,15 +52,28 @@ const SummonUnit = (props: Props) => {
|
|||
const summon = props.gridSummon.object!
|
||||
|
||||
const upgradedSummons = [
|
||||
'2040094000', '2040100000', '2040080000', '2040098000',
|
||||
'2040090000', '2040084000', '2040003000', '2040056000',
|
||||
'2040020000', '2040034000', '2040028000', '2040027000',
|
||||
'2040046000', '2040047000'
|
||||
"2040094000",
|
||||
"2040100000",
|
||||
"2040080000",
|
||||
"2040098000",
|
||||
"2040090000",
|
||||
"2040084000",
|
||||
"2040003000",
|
||||
"2040056000",
|
||||
"2040020000",
|
||||
"2040034000",
|
||||
"2040028000",
|
||||
"2040027000",
|
||||
"2040046000",
|
||||
"2040047000",
|
||||
]
|
||||
|
||||
let suffix = ''
|
||||
if (upgradedSummons.indexOf(summon.granblue_id.toString()) != -1 && props.gridSummon.uncap_level == 5)
|
||||
suffix = '_02'
|
||||
let suffix = ""
|
||||
if (
|
||||
upgradedSummons.indexOf(summon.granblue_id.toString()) != -1 &&
|
||||
props.gridSummon.uncap_level == 5
|
||||
)
|
||||
suffix = "_02"
|
||||
|
||||
// Generate the correct source for the summon
|
||||
if (props.unitType == 0 || props.unitType == 2)
|
||||
|
|
@ -77,24 +93,31 @@ const SummonUnit = (props: Props) => {
|
|||
const image = (
|
||||
<div className="SummonImage">
|
||||
<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>
|
||||
)
|
||||
|
||||
const editableImage = (
|
||||
<SearchModal
|
||||
placeholderText={t('search.placeholders.summon')}
|
||||
placeholderText={t("search.placeholders.summon")}
|
||||
fromPosition={props.position}
|
||||
object="summons"
|
||||
send={props.updateObject}>
|
||||
send={props.updateObject}
|
||||
>
|
||||
{image}
|
||||
</SearchModal>
|
||||
)
|
||||
|
||||
const unitContent = (
|
||||
<div className={classes}>
|
||||
{ (props.editable) ? editableImage : image }
|
||||
{ (gridSummon) ?
|
||||
{props.editable ? editableImage : image}
|
||||
{gridSummon ? (
|
||||
<UncapIndicator
|
||||
type="summon"
|
||||
ulb={gridSummon.object.uncap.ulb || false}
|
||||
|
|
@ -102,19 +125,19 @@ const SummonUnit = (props: Props) => {
|
|||
uncapLevel={gridSummon.uncap_level}
|
||||
updateUncap={passUncapData}
|
||||
special={false}
|
||||
/> : ''
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
<h3 className="SummonName">{summon?.name[locale]}</h3>
|
||||
</div>
|
||||
)
|
||||
|
||||
const withHovercard = (
|
||||
<SummonHovercard gridSummon={gridSummon!}>
|
||||
{unitContent}
|
||||
</SummonHovercard>
|
||||
<SummonHovercard gridSummon={gridSummon!}>{unitContent}</SummonHovercard>
|
||||
)
|
||||
|
||||
return (gridSummon && !props.editable) ? withHovercard : unitContent
|
||||
return gridSummon && !props.editable ? withHovercard : unitContent
|
||||
}
|
||||
|
||||
export default SummonUnit
|
||||
|
|
|
|||
|
|
@ -1,42 +1,44 @@
|
|||
import React, { useEffect, useState } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import classnames from 'classnames'
|
||||
import React, { useEffect, useState } from "react"
|
||||
import { useRouter } from "next/router"
|
||||
import { useTranslation } from "next-i18next"
|
||||
import classnames from "classnames"
|
||||
|
||||
import SearchModal from '~components/SearchModal'
|
||||
import WeaponModal from '~components/WeaponModal'
|
||||
import WeaponHovercard from '~components/WeaponHovercard'
|
||||
import UncapIndicator from '~components/UncapIndicator'
|
||||
import Button from '~components/Button'
|
||||
import SearchModal from "~components/SearchModal"
|
||||
import WeaponModal from "~components/WeaponModal"
|
||||
import WeaponHovercard from "~components/WeaponHovercard"
|
||||
import UncapIndicator from "~components/UncapIndicator"
|
||||
import Button from "~components/Button"
|
||||
|
||||
import { ButtonType } from '~utils/enums'
|
||||
import { ButtonType } from "~utils/enums"
|
||||
import type { SearchableObject } from "~types"
|
||||
|
||||
import PlusIcon from '~public/icons/Add.svg'
|
||||
import './index.scss'
|
||||
import PlusIcon from "~public/icons/Add.svg"
|
||||
import "./index.scss"
|
||||
|
||||
interface Props {
|
||||
gridWeapon: GridWeapon | undefined
|
||||
unitType: 0 | 1
|
||||
position: number
|
||||
editable: boolean
|
||||
updateObject: (object: Character | Weapon | Summon, position: number) => void
|
||||
updateObject: (object: SearchableObject, position: number) => void
|
||||
updateUncap: (id: string, position: number, uncap: number) => void
|
||||
}
|
||||
|
||||
const WeaponUnit = (props: Props) => {
|
||||
const { t } = useTranslation('common')
|
||||
const { t } = useTranslation("common")
|
||||
|
||||
const [imageUrl, setImageUrl] = useState('')
|
||||
const [imageUrl, setImageUrl] = useState("")
|
||||
|
||||
const router = useRouter()
|
||||
const locale = (router.locale && ['en', 'ja'].includes(router.locale)) ? router.locale : 'en'
|
||||
const locale =
|
||||
router.locale && ["en", "ja"].includes(router.locale) ? router.locale : "en"
|
||||
|
||||
const classes = classnames({
|
||||
WeaponUnit: true,
|
||||
'mainhand': props.unitType == 0,
|
||||
'grid': props.unitType == 1,
|
||||
'editable': props.editable,
|
||||
'filled': (props.gridWeapon !== undefined)
|
||||
mainhand: props.unitType == 0,
|
||||
grid: props.unitType == 1,
|
||||
editable: props.editable,
|
||||
filled: props.gridWeapon !== undefined,
|
||||
})
|
||||
|
||||
const gridWeapon = props.gridWeapon
|
||||
|
|
@ -75,37 +77,49 @@ const WeaponUnit = (props: Props) => {
|
|||
function canBeModified(gridWeapon: GridWeapon) {
|
||||
const weapon = gridWeapon.object
|
||||
|
||||
return weapon.ax > 0 ||
|
||||
(weapon.series) && [2, 3, 17, 22, 24].includes(weapon.series)
|
||||
return (
|
||||
weapon.ax > 0 ||
|
||||
(weapon.series && [2, 3, 17, 22, 24].includes(weapon.series))
|
||||
)
|
||||
}
|
||||
|
||||
const image = (
|
||||
<div className="WeaponImage">
|
||||
<img alt={weapon?.name.en} className="grid_image" src={imageUrl} />
|
||||
{ (props.editable) ? <span className='icon'><PlusIcon /></span> : '' }
|
||||
{props.editable ? (
|
||||
<span className="icon">
|
||||
<PlusIcon />
|
||||
</span>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
|
||||
const editableImage = (
|
||||
<SearchModal
|
||||
placeholderText={t('search.placeholders.weapon')}
|
||||
placeholderText={t("search.placeholders.weapon")}
|
||||
fromPosition={props.position}
|
||||
object="weapons"
|
||||
send={props.updateObject}>
|
||||
send={props.updateObject}
|
||||
>
|
||||
{image}
|
||||
</SearchModal>
|
||||
)
|
||||
|
||||
const unitContent = (
|
||||
<div className={classes}>
|
||||
{ (props.editable && gridWeapon && canBeModified(gridWeapon)) ?
|
||||
{props.editable && gridWeapon && canBeModified(gridWeapon) ? (
|
||||
<WeaponModal gridWeapon={gridWeapon}>
|
||||
<div>
|
||||
<Button icon="settings" type={ButtonType.IconOnly} />
|
||||
</div>
|
||||
</WeaponModal>: '' }
|
||||
{ (props.editable) ? editableImage : image }
|
||||
{ (gridWeapon) ?
|
||||
</WeaponModal>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
{props.editable ? editableImage : image}
|
||||
{gridWeapon ? (
|
||||
<UncapIndicator
|
||||
type="weapon"
|
||||
ulb={gridWeapon.object.uncap.ulb || false}
|
||||
|
|
@ -113,19 +127,19 @@ const WeaponUnit = (props: Props) => {
|
|||
uncapLevel={gridWeapon.uncap_level}
|
||||
updateUncap={passUncapData}
|
||||
special={false}
|
||||
/> : ''
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
<h3 className="WeaponName">{weapon?.name[locale]}</h3>
|
||||
</div>
|
||||
)
|
||||
|
||||
const withHovercard = (
|
||||
<WeaponHovercard gridWeapon={gridWeapon!}>
|
||||
{unitContent}
|
||||
</WeaponHovercard>
|
||||
<WeaponHovercard gridWeapon={gridWeapon!}>{unitContent}</WeaponHovercard>
|
||||
)
|
||||
|
||||
return (gridWeapon && !props.editable) ? withHovercard : unitContent
|
||||
return gridWeapon && !props.editable ? withHovercard : unitContent
|
||||
}
|
||||
|
||||
export default WeaponUnit
|
||||
|
|
|
|||
2
types/index.d.ts
vendored
Normal file
2
types/index.d.ts
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
export type SearchableObject = Character | Weapon | Summon | JobSkill
|
||||
export type SearchableObjectArray = (Character | Weapon | Summon | JobSkill)[]
|
||||
Loading…
Reference in a new issue