Fix typings and output with remixes

This commit is contained in:
Justin Edmund 2023-07-07 14:32:03 -07:00
parent d0535d6031
commit 973e7f34da
22 changed files with 246 additions and 207 deletions

View file

@ -20,12 +20,12 @@ interface Props {
shortcode: string
id: string
name: string
raid?: Raid
raid: Raid | null
weapons: {
mainWeapon?: GridWeapon
allWeapons: GridArray<GridWeapon>
}
user?: User
mainWeapon: GridWeapon | null
allWeapons: GridArray<GridWeapon> | null
} | null
user: User | null
fullAuto: boolean
autoGuard: boolean
favorited: boolean

View file

@ -16,6 +16,8 @@ import type { DetailsObject, JobSkillObject, SearchableObject } from '~types'
import api from '~utils/api'
import { appState } from '~utils/appState'
import * as CharacterTransformer from '~transformers/CharacterTransformer'
import * as GridCharacterTransformer from '~transformers/GridCharacterTransformer'
import styles from './index.module.scss'
@ -121,8 +123,10 @@ const CharacterGrid = (props: Props) => {
async function handleCharacterResponse(data: any) {
if (data.hasOwnProperty('conflicts')) {
setIncoming(data.incoming)
setConflicts(data.conflicts)
setIncoming(CharacterTransformer.toObject(data.incoming))
setConflicts(
data.conflicts.map((c: any) => GridCharacterTransformer.toObject(c))
)
setPosition(data.position)
setModalOpen(true)
} else {
@ -145,7 +149,8 @@ const CharacterGrid = (props: Props) => {
})
}
function storeGridCharacter(gridCharacter: GridCharacter) {
function storeGridCharacter(data: any) {
const gridCharacter = GridCharacterTransformer.toObject(data)
appState.party.grid.characters[gridCharacter.position] = gridCharacter
}
@ -164,7 +169,7 @@ const CharacterGrid = (props: Props) => {
// Remove conflicting characters from state
conflicts.forEach(
(c) => (appState.party.grid.characters[c.position] = undefined)
(c) => (appState.party.grid.characters[c.position] = null)
)
// Reset conflict
@ -186,7 +191,7 @@ const CharacterGrid = (props: Props) => {
async function removeCharacter(id: string) {
try {
const response = await api.endpoints.grid_characters.destroy({ id: id })
appState.party.grid.characters[response.data.position] = undefined
appState.party.grid.characters[response.data.position] = null
} catch (error) {
console.error(error)
}

View file

@ -40,6 +40,7 @@ const CharacterResult = (props: Props) => {
flb={character.uncap.flb}
ulb={character.uncap.ulb}
special={character.special}
transcendenceStage={character.uncap.ulb ? 5 : 0}
/>
<div className={styles.tags}>
<WeaponLabelIcon labelType={character.element.slug} />

View file

@ -22,6 +22,7 @@ import UncapIndicator from '~components/uncap/UncapIndicator'
import api from '~utils/api'
import { appState } from '~utils/appState'
import { ElementMap } from '~utils/elements'
import * as GridCharacterTransformer from '~transformers/GridCharacterTransformer'
import PlusIcon from '~public/icons/Add.svg'
import SettingsIcon from '~public/icons/Settings.svg'
@ -37,7 +38,7 @@ import type {
import styles from './index.module.scss'
interface Props {
gridCharacter?: GridCharacter
gridCharacter: GridCharacter | null
position: number
editable: boolean
removeCharacter: (id: string) => void
@ -145,7 +146,9 @@ const CharacterUnit = ({
// Save the server's response to state
function processResult(response: AxiosResponse) {
const gridCharacter: GridCharacter = response.data
const gridCharacter: GridCharacter = GridCharacterTransformer.toObject(
response.data
)
let character = cloneDeep(gridCharacter)
if (character.mastery.overMastery) {
@ -159,7 +162,7 @@ const CharacterUnit = ({
character.mastery.overMastery = overMastery
}
appState.grid.characters[gridCharacter.position] = character
appState.party.grid.characters[gridCharacter.position] = character
}
function processError(error: any) {
@ -188,7 +191,11 @@ const CharacterUnit = ({
// Change the image based on the uncap level
let suffix = '01'
if (gridCharacter.transcendenceStep > 0) suffix = '04'
if (
gridCharacter.transcendenceStep &&
gridCharacter.transcendenceStep > 0
)
suffix = '04'
else if (gridCharacter.uncapLevel >= 5) suffix = '03'
else if (gridCharacter.uncapLevel > 2) suffix = '02'

View file

@ -18,6 +18,7 @@ import { accountState } from '~utils/accountState'
import { appState, initialAppState } from '~utils/appState'
import { getLocalId } from '~utils/localId'
import { GridType } from '~utils/enums'
import * as PartyTransformer from '~transformers/PartyTransformer'
import { retrieveCookies } from '~utils/retrieveCookies'
import { setEditKey, storeEditKey, unsetEditKey } from '~utils/userToken'
@ -220,11 +221,11 @@ const Party = (props: Props) => {
api
.remix({ shortcode: props.party.shortcode, body: body })
.then((response) => {
const remix = response.data.party
const remix = PartyTransformer.toObject(response.data.party)
// Store the edit key in local storage
if (remix.edit_key) {
storeEditKey(remix.id, remix.edit_key)
if (remix.editKey) {
storeEditKey(remix.id, remix.editKey)
setEditKey(remix.id, remix.user)
}
@ -275,30 +276,31 @@ const Party = (props: Props) => {
appState.party.protagonist.ultimateMastery =
team.protagonist.ultimate_mastery
appState.party.details.chargeAttack = team.charge_attack
appState.party.details.fullAuto = team.full_auto
appState.party.details.autoGuard = team.auto_guard
appState.party.details.autoSummon = team.auto_summon
appState.party.details.clearTime = team.clear_time
appState.party.details.fullAuto = team.details.full_auto
appState.party.details.autoGuard = team.details.auto_guard
appState.party.details.autoSummon = team.details.auto_summon
appState.party.details.clearTime = team.details.clear_time
appState.party.details.buttonCount =
team.button_count !== null ? team.button_count : undefined
team.details.button_count !== null ? team.details.button_count : undefined
appState.party.details.chainCount =
team.chain_count !== null ? team.chain_count : undefined
team.details.chain_count !== null ? team.details.chain_count : undefined
appState.party.details.turnCount =
team.turn_count !== null ? team.turn_count : undefined
team.details.turn_count !== null ? team.details.turn_count : undefined
appState.party.id = team.id
appState.party.shortcode = team.shortcode
appState.party.details.extra = team.extra
appState.party.details.extra = team.details.extra
appState.party.guidebooks = team.guidebooks
appState.party.user = team.user
appState.party.social.favorited = team.favorited
appState.party.social.remix = team.remix
appState.party.social.remixes = team.remixes
appState.party.social.sourceParty = team.source_party
appState.party.social.favorited = team.social.favorited
appState.party.social.remix = team.social.remix
appState.party.social.remixes = team.social.remixes
appState.party.social.sourceParty = team.social.sourceParty
appState.party.timestamps.createdAt = team.created_at
appState.party.timestamps.updatedAt = team.updated_at
appState.party.grid = team.grid
console.log(team.grid)
// Store the edit key in local storage
if (team.edit_key) {

View file

@ -16,7 +16,6 @@ import EditPartyModal from '../EditPartyModal'
import api from '~utils/api'
import { appState } from '~utils/appState'
import { youtube } from '~utils/youtube'
import type { DetailsObject } from 'types'
@ -39,10 +38,7 @@ const PartyFooter = (props: Props) => {
const { t } = useTranslation('common')
const router = useRouter()
const { party: partySnapshot } = useSnapshot(appState)
const youtubeUrlRegex =
/(?:https:\/\/www\.youtube\.com\/watch\?v=|https:\/\/youtu\.be\/)([\w-]+)/g
const { party } = useSnapshot(appState)
// State: Component
const [currentSegment, setCurrentSegment] = useState(0)
@ -55,69 +51,19 @@ const PartyFooter = (props: Props) => {
const [sanitizedDescription, setSanitizedDescription] = useState('')
useEffect(() => {
if (partySnapshot.description) {
const purified = DOMPurify.sanitize(partySnapshot.description)
if (party.description) {
const purified = DOMPurify.sanitize(party.description)
setSanitizedDescription(purified)
} else {
setSanitizedDescription('')
}
}, [partySnapshot.description])
// Extract the video IDs from the description
// const videoIds = extractYoutubeVideoIds(partySnapshot.description)
// Fetch the video titles for each ID
// const fetchPromises = videoIds.map(({ id }) => fetchYoutubeData(id))
// // Wait for all the video titles to be fetched
// Promise.all(fetchPromises).then((videoTitles) => {
// // Replace the video URLs in the description with LiteYoutubeEmbed elements
// const newDescription = reactStringReplace(
// partySnapshot.description,
// youtubeUrlRegex,
// (match, i) => (
// <LiteYouTubeEmbed
// key={`${match}-${i}`}
// id={match}
// title={videoTitles[i]}
// wrapperClass={styles.youtube}
// playerClass={styles.playerButton}
// />
// )
// )
// Update the state with the new description
async function fetchYoutubeData(videoId: string) {
return await youtube
.getVideoById(videoId, { maxResults: 1 })
.then((data) => data.items[0].snippet.localized.title)
}
}, [party.description])
// Methods: Navigation
function goTo(shortcode?: string) {
if (shortcode) router.push(`/p/${shortcode}`)
}
function extractYoutubeVideoIds(text: string) {
// Initialize an array to store the video IDs
const videoIds = []
// Use the regular expression to find all the Youtube URLs in the text
let match
while ((match = youtubeUrlRegex.exec(text)) !== null) {
// Extract the video ID from the URL
const videoId = match[1]
// Add the video ID to the array, along with the character position of the URL
videoIds.push({
id: videoId,
url: match[0],
position: match.index,
})
}
// Return the array of video IDs
return videoIds
}
// Methods: Favorites
function toggleFavorite(teamId: string, favorited: boolean) {
if (favorited) unsaveFavorite(teamId)
@ -202,7 +148,7 @@ const PartyFooter = (props: Props) => {
onClick={() => setCurrentSegment(1)}
>
{t('footer.remixes.label', {
count: partySnapshot?.social.remixes?.length,
count: party?.social.remixes?.length ?? 0,
})}
</Segment>
</SegmentedControl>
@ -218,7 +164,7 @@ const PartyFooter = (props: Props) => {
key={props.party?.shortcode}
/>
)}
{(!partySnapshot || !partySnapshot.description) && (
{(!party || !party.description) && (
<section className={styles.noDescription}>
<h3>{t('footer.description.empty')}</h3>
{props.editable && (
@ -242,10 +188,10 @@ const PartyFooter = (props: Props) => {
const remixesSection = (
<section className={styles.remixes}>
{partySnapshot?.social.remixes?.length > 0 && (
{party?.social.remixes?.length > 0 && (
<GridRepCollection>{renderRemixes()}</GridRepCollection>
)}
{partySnapshot?.social.remixes?.length === 0 && (
{party?.social.remixes?.length === 0 && (
<div className={styles.noRemixes}>
<h3>{t('footer.remixes.empty')}</h3>
<Button
@ -259,7 +205,7 @@ const PartyFooter = (props: Props) => {
)
function renderRemixes() {
return partySnapshot?.social.remixes.map((party, i) => {
return party?.social.remixes.map((party, i) => {
return (
<GridRep
id={party.id}
@ -290,7 +236,7 @@ const PartyFooter = (props: Props) => {
<RemixTeamAlert
creator={props.editable}
name={partySnapshot.name ? partySnapshot.name : t('no_title')}
name={party.name ? party.name : t('no_title')}
open={remixAlertOpen}
onOpenChange={handleRemixTeamAlertChange}
remixCallback={remixTeamCallback}

View file

@ -15,6 +15,12 @@ import WeaponSearchFilterBar from '~components/weapon/WeaponSearchFilterBar'
import SummonSearchFilterBar from '~components/summon/SummonSearchFilterBar'
import JobSkillSearchFilterBar from '~components/job/JobSkillSearchFilterBar'
import * as WeaponTransformer from '~transformers/WeaponTransformer'
import * as SummonTransformer from '~transformers/SummonTransformer'
import * as CharacterTransformer from '~transformers/CharacterTransformer'
import * as JobSkillTransformer from '~transformers/JobSkillTransformer'
import * as GuidebookTransformer from '~transformers/GuidebookTransformer'
import CharacterResult from '~components/character/CharacterResult'
import WeaponResult from '~components/weapon/WeaponResult'
import SummonResult from '~components/summon/SummonResult'
@ -270,13 +276,14 @@ const SearchModal = (props: Props) => {
const castResults: Weapon[] = results as Weapon[]
if (castResults && Object.keys(castResults).length > 0) {
jsx = castResults.map((result: Weapon) => {
jsx = castResults.map((result: any) => {
const weapon = WeaponTransformer.toObject(result)
return (
<WeaponResult
key={result.id}
data={result}
key={weapon.id}
data={weapon}
onClick={() => {
storeRecentResult(result)
storeRecentResult(weapon)
}}
/>
)
@ -291,13 +298,14 @@ const SearchModal = (props: Props) => {
const castResults: Summon[] = results as Summon[]
if (castResults && Object.keys(castResults).length > 0) {
jsx = castResults.map((result: Summon) => {
jsx = castResults.map((result: any) => {
const summon = SummonTransformer.toObject(result)
return (
<SummonResult
key={result.id}
data={result}
key={summon.id}
data={summon}
onClick={() => {
storeRecentResult(result)
storeRecentResult(summon)
}}
/>
)
@ -312,13 +320,14 @@ const SearchModal = (props: Props) => {
const castResults: Character[] = results as Character[]
if (castResults && Object.keys(castResults).length > 0) {
jsx = castResults.map((result: Character) => {
jsx = castResults.map((result: any) => {
const character = CharacterTransformer.toObject(result)
return (
<CharacterResult
key={result.id}
data={result}
key={character.id}
data={character}
onClick={() => {
storeRecentResult(result)
storeRecentResult(character)
}}
/>
)
@ -334,12 +343,13 @@ const SearchModal = (props: Props) => {
const castResults: JobSkill[] = results as JobSkill[]
if (castResults && Object.keys(castResults).length > 0) {
jsx = castResults.map((result: JobSkill) => {
const jobSkill = JobSkillTransformer.toObject(result)
return (
<JobSkillResult
key={result.id}
data={result}
key={jobSkill.id}
data={jobSkill}
onClick={() => {
storeRecentResult(result)
storeRecentResult(jobSkill)
}}
/>
)
@ -355,12 +365,13 @@ const SearchModal = (props: Props) => {
const castResults: Guidebook[] = results as Guidebook[]
if (castResults && Object.keys(castResults).length > 0) {
jsx = castResults.map((result: Guidebook) => {
const guidebook = GuidebookTransformer.toObject(result)
return (
<GuidebookResult
key={result.id}
data={result}
key={guidebook.id}
data={guidebook}
onClick={() => {
storeRecentResult(result)
storeRecentResult(guidebook)
}}
/>
)

View file

@ -14,6 +14,7 @@ import ExtraSummonsGrid from '~components/extra/ExtraSummonsGrid'
import api from '~utils/api'
import { appState } from '~utils/appState'
import * as GridSummonTransformer from '~transformers/GridSummonTransformer'
import type { DetailsObject, SearchableObject } from '~types'
import styles from './index.module.scss'
@ -119,11 +120,11 @@ const SummonGrid = (props: Props) => {
const position = data.meta['replaced']
if (position == -1) {
appState.party.grid.summons.mainSummon = undefined
appState.party.grid.summons.mainSummon = null
} else if (position == 6) {
appState.party.grid.summons.friendSummon = undefined
appState.party.grid.summons.friendSummon = null
} else {
appState.party.grid.summons.allSummons[position] = undefined
appState.party.grid.summons.allSummons[position] = null
}
}
}
@ -146,7 +147,9 @@ const SummonGrid = (props: Props) => {
})
}
function storeGridSummon(gridSummon: GridSummon) {
function storeGridSummon(data: GridSummon) {
const gridSummon = GridSummonTransformer.toObject(data)
if (gridSummon.position == -1)
appState.party.grid.summons.mainSummon = gridSummon
else if (gridSummon.position == 6)
@ -360,12 +363,11 @@ const SummonGrid = (props: Props) => {
const data = response.data
if (data.position === -1) {
appState.party.grid.summons.mainSummon = undefined
appState.party.grid.summons.mainSummon = null
} else if (data.position === 6) {
appState.party.grid.summons.friendSummon = undefined
appState.party.grid.summons.friendSummon = null
} else {
appState.party.grid.summons.allSummons[response.data.position] =
undefined
appState.party.grid.summons.allSummons[response.data.position] = null
}
} catch (error) {
console.error(error)

View file

@ -28,8 +28,11 @@ const SummonResult = (props: Props) => {
<h5>{summon.name[locale]}</h5>
<UncapIndicator
type="summon"
flb={summon.uncap.flb}
ulb={summon.uncap.ulb}
ulb={summon.uncap.ulb || false}
flb={summon.uncap.flb || false}
xlb={summon.uncap.xlb || false}
uncapLevel={6}
transcendenceStage={5}
special={false}
/>
<div className={styles.tags}>

View file

@ -6,6 +6,7 @@ import classNames from 'classnames'
import api from '~utils/api'
import { appState } from '~utils/appState'
import * as GridSummonTransformer from '~transformers/GridSummonTransformer'
import Alert from '~components/common/Alert'
import Button from '~components/common/Button'
@ -26,7 +27,7 @@ import SettingsIcon from '~public/icons/Settings.svg'
import styles from './index.module.scss'
interface Props {
gridSummon: GridSummon | undefined
gridSummon: GridSummon | null
unitType: 0 | 1 | 2
position: number
editable: boolean
@ -125,13 +126,23 @@ const SummonUnit = ({
// If a user sets a quick summon while one is already set,
// the previous one will be unset.
const gridSummons: GridSummon[] = response.data.summons
const mainSummon = gridSummons.find((summon) =>
GridSummonTransformer.toObject(summon)
)
const friendSummon = gridSummons.find((summon) =>
GridSummonTransformer.toObject(summon)
)
for (const gridSummon of gridSummons) {
if (gridSummon.main) {
appState.grid.summons.mainSummon = gridSummon
appState.grid.summons.mainSummon = mainSummon
} else if (gridSummon.friend) {
appState.grid.summons.friendSummon = gridSummon
appState.grid.summons.friendSummon = friendSummon
} else {
appState.grid.summons.allSummons[gridSummon.position] = gridSummon
appState.party.grid.summons.allSummons[gridSummon.position] = gridSummon
? GridSummonTransformer.toObject(gridSummon)
: null
}
}
}
@ -157,8 +168,7 @@ const SummonUnit = ({
function generateImageUrl() {
let imgSrc = ''
if (gridSummon) {
const summon = gridSummon.object!
const summon = gridSummon.object
const upgradedSummons = [
'2040094000',
'2040100000',
@ -179,6 +189,7 @@ const SummonUnit = ({
let suffix = ''
if (gridSummon.object.uncap.xlb && gridSummon.uncapLevel == 6) {
if (
gridSummon.transcendenceStep &&
gridSummon.transcendenceStep >= 1 &&
gridSummon.transcendenceStep < 5
) {
@ -187,7 +198,7 @@ const SummonUnit = ({
suffix = '_04'
}
} else if (
upgradedSummons.indexOf(summon.granblueId.toString()) != -1 &&
upgradedSummons.indexOf(summon.granblueId) != -1 &&
gridSummon.uncapLevel == 5
) {
suffix = '_02'

View file

@ -38,7 +38,7 @@ const TranscendenceStar = ({
const starClasses = classnames({
[styles.star]: true,
[styles.immutable]: immutable,
[styles.empty]: stage === 0,
[styles.empty]: true,
[styles.stage1]: stage === 1,
[styles.stage2]: stage === 2,
[styles.stage3]: stage === 3,

View file

@ -1,4 +1,4 @@
import React, { useState } from 'react'
import React, { useEffect, useState } from 'react'
import UncapStar from '~components/uncap/UncapStar'
import TranscendencePopover from '~components/uncap/TranscendencePopover'
import TranscendenceStar from '~components/uncap/TranscendenceStar'
@ -82,7 +82,11 @@ const UncapIndicator = (props: Props) => {
return props.type === 'character' || props.type === 'summon' ? (
<TranscendencePopover
open={popoverOpen}
stage={props.transcendenceStage ? props.transcendenceStage : 0}
stage={
props.transcendenceStage && props.transcendenceStage !== null
? props.transcendenceStage
: 0
}
type={props.type}
onOpenChange={togglePopover}
sendValue={sendTranscendenceStage}

View file

@ -18,6 +18,7 @@ import WeaponConflictModal from '~components/weapon/WeaponConflictModal'
import api from '~utils/api'
import { appState } from '~utils/appState'
import * as GridWeaponTransformer from '~transformers/GridWeaponTransformer'
import type { DetailsObject, SearchableObject } from '~types'
@ -58,7 +59,7 @@ const WeaponGrid = (props: Props) => {
const [showIncompatibleAlert, setShowIncompatibleAlert] = useState(false)
// Set up state for view management
const { party, grid } = useSnapshot(appState)
const { party } = useSnapshot(appState)
const [modalOpen, setModalOpen] = useState(false)
// Set up state for conflict management
@ -150,10 +151,10 @@ const WeaponGrid = (props: Props) => {
const position = data.meta['replaced']
if (position == -1) {
appState.party.grid.weapons.mainWeapon = undefined
appState.party.grid.weapons.mainWeapon = null
appState.party.element = ElementMap.null
} else {
appState.party.grid.weapons.allWeapons[position] = undefined
appState.party.grid.weapons.allWeapons[position] = null
}
}
}
@ -195,7 +196,8 @@ const WeaponGrid = (props: Props) => {
}
}
function storeGridWeapon(gridWeapon: GridWeapon) {
function storeGridWeapon(data: GridWeapon) {
const gridWeapon = GridWeaponTransformer.toObject(data)
if (gridWeapon.position === -1) {
appState.party.grid.weapons.mainWeapon = gridWeapon
appState.party.element = gridWeapon.object.element
@ -220,10 +222,10 @@ const WeaponGrid = (props: Props) => {
if (
appState.party.grid.weapons.mainWeapon?.object.id === c.object.id
) {
appState.party.grid.weapons.mainWeapon = undefined
appState.party.grid.weapons.mainWeapon = null
appState.party.element = ElementMap.null
} else {
appState.party.grid.weapons.allWeapons[c.position] = undefined
appState.party.grid.weapons.allWeapons[c.position] = null
}
})
@ -251,10 +253,9 @@ const WeaponGrid = (props: Props) => {
const data = response.data
if (data.position === -1) {
appState.party.grid.weapons.mainWeapon = undefined
appState.party.grid.weapons.mainWeapon = null
} else {
appState.party.grid.weapons.allWeapons[response.data.position] =
undefined
appState.party.grid.weapons.allWeapons[response.data.position] = null
}
} catch (error) {
console.error(error)
@ -376,7 +377,7 @@ const WeaponGrid = (props: Props) => {
return (
<li className={itemClasses} key={`grid_unit_${i}`}>
<WeaponUnit
gridWeapon={appState.party.grid.weapons.allWeapons[i]}
gridWeapon={party.grid.weapons.allWeapons[i]}
editable={props.editable}
position={i}
unitType={1}

View file

@ -31,7 +31,7 @@ import SettingsIcon from '~public/icons/Settings.svg'
import styles from './index.module.scss'
interface Props {
gridWeapon: GridWeapon | undefined
gridWeapon: GridWeapon | null
unitType: 0 | 1
position: number
editable: boolean

View file

@ -193,8 +193,12 @@ export const getServerSideProps = async ({ req, res, locale, query }: { req: Nex
const party: Party | undefined = await api.endpoints.parties.getOne({
id: query.party,
}).then((response) => PartyTransformer.toObject(response.data.party))
}).then((response) =>
PartyTransformer.toObject(response.data.party)
)
console.log(party)
// Consolidate data into context object
const context: PageContextObj = {
party: party,

View file

@ -4,29 +4,61 @@ import * as GridCharacter from '~transformers/GridCharacterTransformer'
// Transforms API response to Party object
export function toObject(data: any): Grid {
const mainSummon = data.summons.find((summon: any) => summon.main === true)
const friendSummon = data.summons.find(
(summon: any) => summon.friend === true
)
const mainWeapon = data.weapons.find(
(weapon: any) => weapon.mainhand === true
)
console.log('----- GridTransformer.tsx -----')
console.log(data.summons, data.characters)
console.log('----- End GridTransformer.tsx -----')
const mainSummon = data.summons
? data.summons.find((summon: any) => summon.main === true)
: null
const friendSummon = data.summons
? data.summons.find((summon: any) => summon.friend === true)
: null
const allSummons = data.summons
? removeItem(data.summons, [mainSummon, friendSummon])
: null
const mainWeapon = data.weapons
? data.weapons.find((weapon: any) => weapon.mainhand === true)
: null
return {
characters: data.characters.map((character: any) =>
GridCharacter.toObject(character)
),
characters: data.characters
? mapToGridArray(data.characters, GridCharacter.toObject)
: null,
summons: {
mainSummon: mainSummon ? GridSummon.toObject(mainSummon) : null,
friendSummon: friendSummon ? GridSummon.toObject(friendSummon) : null,
allSummons: data.summons.map((summon: any) => {
if (!summon.main && !summon.friend) return GridSummon.toObject(summon)
}),
allSummons: allSummons
? mapToGridArray(allSummons, GridSummon.toObject)
: null,
},
weapons: {
mainWeapon: mainWeapon ? GridWeapon.toObject(mainWeapon) : null,
allWeapons: data.weapons.map((weapon: any) => {
if (!weapon.mainhand) return GridWeapon.toObject(weapon)
}),
allWeapons: data.weapons
? mapToGridArray(data.weapons, GridWeapon.toObject)
: null,
},
}
}
function removeItem<T>(arr: Array<T>, values: T[]): Array<T> {
values.forEach((value) => {
const index = arr.indexOf(value)
if (index > -1) {
arr.splice(index, 1)
}
})
return arr
}
function mapToGridArray<T>(
arr: any[],
transformer: (data: any) => T
): GridArray<T> {
return arr.reduce(
(gridArray, item) => ({ ...gridArray, [item.position]: transformer(item) }),
{} as GridArray<T>
)
}

View file

@ -12,12 +12,16 @@ export function toObject(data: any): GridWeapon {
mainhand: data.mainhand,
uncapLevel: data.uncap_level,
element: Element.toObject(data.element),
weaponKeys: data.weapon_keys.map((key: any) => WeaponKey.toObject(key)),
ax: data.ax,
awakening: {
type: Awakening.toObject(data.awakening.type),
level: data.awakening.awakening_level,
},
weaponKeys: data.weapon_keys
? data.weapon_keys.map((key: any) => WeaponKey.toObject(key))
: null,
ax: data.ax ? data.ax : null,
awakening: data.awakening
? {
type: Awakening.toObject(data.awakening.type),
level: data.awakening.awakening_level,
}
: null,
}
}

View file

@ -10,11 +10,12 @@ import * as User from './UserTransformer'
export function toObject(data: any): Party {
return {
id: data.id,
localId: data.local_id,
localId: data.local_id ? data.local_id : null,
editKey: data.edit_key ? data.edit_key : null,
name: data.name,
description: data.description,
description: data.description ? data.description : null,
shortcode: data.shortcode,
user: User.toObject(data.user),
user: data.user ? User.toObject(data.user) : null,
editable: data.editable ?? false,
grid: Grid.toObject({
characters: data.characters,
@ -26,35 +27,39 @@ export function toObject(data: any): Party {
fullAuto: data.full_auto,
autoGuard: data.auto_guard,
autoSummon: data.auto_summon,
chargeAttack: data.charge_attack,
clearTime: data.clear_time,
buttonCount: data.button_count,
turnCount: data.turn_count,
chainCount: data.chain_count,
chargeAttack: data.charge_attack ? data.charge_attack : null,
clearTime: data.clear_time ? data.clear_time : null,
buttonCount: data.button_count ? data.button_count : null,
turnCount: data.turn_count ? data.turn_count : null,
chainCount: data.chain_count ? data.chain_count : null,
},
protagonist: {
job: data.job && Job.toObject(data.job),
skills: {
0: data.job_skills[0] && JobSkill.toObject(data.job_skills[0]),
1: data.job_skills[1] && JobSkill.toObject(data.job_skills[1]),
2: data.job_skills[2] && JobSkill.toObject(data.job_skills[2]),
3: data.job_skills[3] && JobSkill.toObject(data.job_skills[3]),
},
masterLevel: data.master_level,
ultimateMastery: data.ultimate_mastery,
accessory: data.accessory && JobAccessory.toObject(data.accessory),
skills: data.job_skills
? {
0: data.job_skills[0] && JobSkill.toObject(data.job_skills[0]),
1: data.job_skills[1] && JobSkill.toObject(data.job_skills[1]),
2: data.job_skills[2] && JobSkill.toObject(data.job_skills[2]),
3: data.job_skills[3] && JobSkill.toObject(data.job_skills[3]),
}
: null,
masterLevel: data.master_level ? data.master_level : null,
ultimateMastery: data.ultimate_mastery ? data.ultimate_mastery : null,
accessory: data.accessory ? JobAccessory.toObject(data.accessory) : null,
},
social: {
favorited: data.favorited,
remix: data.remix,
remixes: data.remixes.map((remix: any) => toObject(remix)),
sourceParty: data.source_party && toObject(data.source_party),
remixes: data.remixes
? data.remixes.map((remix: any) => toObject(remix))
: [],
sourceParty: data.source_party ? toObject(data.source_party) : null,
},
timestamps: {
createdAt: data.created_at,
updatedAt: data.updated_at,
},
raid: data.raid && Raid.toObject(data.raid),
raid: data.raid ? Raid.toObject(data.raid) : null,
guidebooks: {
0: data.guidebooks[1] && Guidebook.toObject(data.guidebooks[1]),
1: data.guidebooks[2] && Guidebook.toObject(data.guidebooks[2]),

12
types/Grid.d.ts vendored
View file

@ -1,12 +1,12 @@
interface Grid {
weapons: {
mainWeapon?: GridWeapon | undefined
allWeapons: GridArray<GridWeapon>
mainWeapon: GridWeapon | null
allWeapons: GridArray<GridWeapon> | null
}
summons: {
mainSummon?: GridSummon | undefined
friendSummon?: GridSummon | undefined
allSummons: GridArray<GridSummon>
mainSummon: GridSummon | null
friendSummon: GridSummon | null
allSummons: GridArray<GridSummon> | null
}
characters: GridArray<GridCharacter>
characters: GridArray<GridCharacter> | null
}

View file

@ -1 +1 @@
type GridArray<T> = { [key: number]: T | undefined }
type GridArray<T> = { [key: number]: T | null }

View file

@ -7,8 +7,8 @@ interface GridWeapon {
element: GranblueElement
weaponKeys?: WeaponKey[]
ax?: SimpleAxSkill[]
awakening?: {
awakening: {
type: Awakening
level: number
}
} | null
}

27
types/Party.d.ts vendored
View file

@ -15,11 +15,12 @@ type GuidebookList = {
interface Party {
id: string
localId?: string
localId: string | null
editKey: string | null
name: string
description: string
shortcode: string
user?: User
user: User | null
editable: boolean
element?: GranblueElement
grid: Grid
@ -28,26 +29,26 @@ interface Party {
fullAuto: boolean
autoGuard: boolean
autoSummon: boolean
chargeAttack: boolean
clearTime: number
buttonCount?: number
turnCount?: number
chainCount?: number
chargeAttack: boolean | null
clearTime: number | null
buttonCount: number | null
turnCount: number | null
chainCount: number | null
}
protagonist: {
job?: Job
skills: JobSkillList
masterLevel?: number
ultimateMastery?: number
accessory?: JobAccessory
skills: JobSkillList | null
masterLevel: number | null
ultimateMastery: number | null
accessory: JobAccessory | null
}
social: {
favorited: boolean
sourceParty?: Party
sourceParty: Party | null
remix: boolean
remixes: Party[]
}
raid?: Raid
raid: Raid | null
guidebooks: GuidebookList
timestamps: {
createdAt: string