import React, { useEffect, useState } from 'react' import Link from 'next/link' import { useRouter } from 'next/router' import { useSnapshot } from 'valtio' import { useTranslation } from 'next-i18next' import classNames from 'classnames' import 'fix-date' import { accountState } from '~utils/accountState' import { formatTimeAgo } from '~utils/timeAgo' import Button from '~components/common/Button' import Tooltip from '~components/common/Tooltip' import SaveIcon from '~public/icons/Save.svg' import PrivateIcon from '~public/icons/Private.svg' import UnlistedIcon from '~public/icons/Unlisted.svg' import ShieldIcon from '~public/icons/Shield.svg' import styles from './index.module.scss' interface Props { party: Party loading: boolean onClick: (shortcode: string) => void onSave?: (partyId: string, favorited: boolean) => void } const GridRep = ({ party, loading, onClick, onSave }: Props) => { const numWeapons: number = 9 const numSummons: number = 6 const { account } = useSnapshot(accountState) const router = useRouter() const { t } = useTranslation('common') const locale = router.locale && ['en', 'ja'].includes(router.locale) ? router.locale : 'en' const [visible, setVisible] = useState(false) const [currentView, setCurrentView] = useState< 'characters' | 'weapons' | 'summons' >('weapons') const [mainhand, setMainhand] = useState() const [weapons, setWeapons] = useState>({}) const [weaponGrid, setWeaponGrid] = useState>({}) const [characters, setCharacters] = useState>({}) const [characterGrid, setCharacterGrid] = useState>( {} ) const [mainSummon, setMainSummon] = useState() const [friendSummon, setFriendSummon] = useState() const [summons, setSummons] = useState>({}) const [summonGrid, setSummonGrid] = useState>({}) // Style construction const gridRepClasses = classNames({ [styles.gridRep]: true, [styles.visible]: visible, [styles.hidden]: !visible, }) const titleClass = classNames({ empty: !party.name, }) const raidClass = classNames({ [styles.raid]: true, [styles.empty]: !party.raid, }) const userClass = classNames({ [styles.user]: true, [styles.empty]: !party.user, }) const mainhandClasses = classNames({ [styles.weapon]: true, [styles.mainhand]: true, }) const weaponClasses = classNames({ [styles.weapon]: true, [styles.grid]: true, }) const protagonistClasses = classNames({ [styles.protagonist]: true, [styles.grid]: true, [styles[`${numberToElement()}`]]: true, [styles.empty]: !party.job || party.job.id === '-1', }) const characterClasses = classNames({ [styles.character]: true, [styles.grid]: true, }) // Hooks useEffect(() => { if (loading) { setVisible(false) } else { const timeout = setTimeout(() => { setVisible(true) }, 150) return () => clearTimeout(timeout) } }, [loading]) useEffect(() => { setVisible(false) // Trigger fade out const timeout = setTimeout(() => { setVisible(true) // Trigger fade in }, 300) // You can adjust the timing based on your preference return () => clearTimeout(timeout) }, []) useEffect(() => { const newWeapons = Array(numWeapons) const gridWeapons = Array(numWeapons) let foundMainhand = false for (const [key, value] of Object.entries(party.weapons)) { if (value.position == -1) { setMainhand(value.object) foundMainhand = true } else if (!value.mainhand && value.position != null) { newWeapons[value.position] = value.object gridWeapons[value.position] = value } } if (!foundMainhand) { setMainhand(undefined) } setWeapons(newWeapons) setWeaponGrid(gridWeapons) }, [party]) useEffect(() => { const newCharacters = Array(3) const gridCharacters = Array(3) if (party.characters) { for (const [key, value] of Object.entries(party.characters)) { if (value.position != null) { newCharacters[value.position] = value.object gridCharacters[value.position] = value } } setCharacters(newCharacters) setCharacterGrid(gridCharacters) } }, [party]) useEffect(() => { const newSummons = Array(numSummons) const gridSummons = Array(numSummons) if (party.summons) { for (const [key, value] of Object.entries(party.summons)) { if (value.main) { setMainSummon(value) } else if (value.friend) { setFriendSummon(value) } else if (!value.main && !value.friend && value.position != null) { newSummons[value.position] = value.object gridSummons[value.position] = value } } setSummons(newSummons) setSummonGrid(gridSummons) } }, [party]) // Convert element to string function numberToElement() { switch (mainhand?.element || weaponGrid[0]?.element) { case 1: return 'wind' case 2: return 'fire' case 3: return 'water' case 4: return 'earth' case 5: return 'dark' case 6: return 'light' default: return '' } } // Methods: Image generation function generateMainhandImage() { let url = '' if (mainhand) { const weapon = Object.values(party.weapons).find( (w) => w && w.object.id === mainhand.id ) let suffix = '' if ( weapon && weapon.object.uncap.transcendence && weapon.uncap_level == 6 ) { if (weapon.transcendence_step >= 1 && weapon.transcendence_step < 5) { suffix = '_02' } else if (weapon.transcendence_step === 5) { suffix = '_03' } } if (mainhand.element == 0 && weapon && weapon.element) { url = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/weapon-main/${mainhand.granblue_id}_${weapon.element}.jpg` } else { url = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/weapon-main/${mainhand.granblue_id}${suffix}.jpg` } } return mainhand && party.weapons[0] ? ( {mainhand.name[locale]} ) : ( '' ) } function generateWeaponGridImage(position: number) { let url = '' const weapon = weapons[position] const gridWeapon = weaponGrid[position] if (weapon && gridWeapon) { let suffix = '' if (weapon.uncap.transcendence && gridWeapon.uncap_level == 6) { if ( gridWeapon.transcendence_step >= 1 && gridWeapon.transcendence_step < 5 ) { suffix = '_02' } else if (gridWeapon.transcendence_step === 5) { suffix = '_03' } } if (weapon.element == 0 && gridWeapon.element) { url = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/weapon-grid/${weapon.granblue_id}_${gridWeapon.element}.jpg` } else { url = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/weapon-grid/${weapon.granblue_id}${suffix}.jpg` } } return weapons[position] ? ( {weapons[position]?.name[locale]} ) : ( '' ) } function generateMCImage() { let source = '' if (party.job) { const slug = party.job.name.en.replaceAll(' ', '-').toLowerCase() const gender = party.user?.gender == 1 ? 'b' : 'a' source = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/job-portraits/${slug}_${gender}.png` } return ( party.job && party.job.id !== '-1' && ( {party.job ) ) } function generateCharacterGridImage(position: number) { let url = '' const gridCharacter = characterGrid[position] const character = characters[position] if (character && gridCharacter) { // Change the image based on the uncap level let suffix = '01' if (gridCharacter.transcendence_step > 0) suffix = '04' else if (gridCharacter.uncap_level >= 5) suffix = '03' else if (gridCharacter.uncap_level > 2) suffix = '02' if (gridCharacter.object.granblue_id === '3030182000') { let element = 1 if (mainhand && mainhand.element) { element = mainhand.element } suffix = `${suffix}_0${element}` } const url = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/character-main/${character.granblue_id}_${suffix}.jpg` return ( characters[position] && ( {characters[position]?.name[locale]} ) ) } } function generateMainSummonImage(position: 'main' | 'friend') { let url = '' const upgradedSummons = [ '2040094000', '2040100000', '2040080000', '2040098000', '2040090000', '2040084000', '2040003000', '2040056000', '2040020000', '2040034000', '2040028000', '2040027000', '2040046000', '2040047000', ] const summon = position === 'main' ? mainSummon : friendSummon if (summon) { // Change the image based on the uncap level let suffix = '' if (summon.object.uncap.transcendence && summon.uncap_level == 6) { if (summon.transcendence_step >= 1 && summon.transcendence_step < 5) { suffix = '_03' } else if (summon.transcendence_step === 5) { suffix = '_04' } } else if ( upgradedSummons.indexOf(summon.object.granblue_id.toString()) != -1 && summon.uncap_level == 5 ) { suffix = '_02' } url = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/summon-main/${summon.object.granblue_id}${suffix}.jpg` } return summon && {summon.object.name[locale]} } function generateSummonGridImage(position: number) { let url = '' const gridSummon = summonGrid[position] const summon = gridSummon?.object const upgradedSummons = [ '2040094000', '2040100000', '2040080000', '2040098000', '2040090000', '2040084000', '2040003000', '2040056000', '2040020000', '2040034000', '2040028000', '2040027000', '2040046000', '2040047000', ] if (summon && gridSummon) { // Change the image based on the uncap level let suffix = '' if (gridSummon.transcendence_step >= 1 && gridSummon.uncap_level == 6) { if ( gridSummon.transcendence_step >= 1 && gridSummon.transcendence_step < 5 ) { suffix = '_03' } else if (gridSummon.transcendence_step === 5) { suffix = '_04' } } else if ( upgradedSummons.indexOf(summon.granblue_id.toString()) != -1 && gridSummon.uncap_level == 5 ) { suffix = '_02' } url = `${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/summon-grid/${summon.granblue_id}${suffix}.jpg` } return ( summons[position] && ( {summons[position]?.name[locale]} ) ) } function sendSaveData() { if (onSave) onSave(party.id, party.favorited) } const userImage = () => { if (party.user && party.user.avatar) { return ( {party.user.avatar.picture} ) } else return ( {t('no_user')} ) } const attribution = () => ( {userImage()} {party.user ? party.user.username : t('no_user')} ) const renderWeaponGrid = (
{generateMainhandImage()}
    {Array.from(Array(numWeapons)).map((x, i) => { return (
  • {generateWeaponGridImage(i)}
  • ) })}
) const renderCharacterGrid = (
{generateMCImage()}
{Array.from(Array(3)).map((x, i) => { return (
  • {generateCharacterGridImage(i)}
  • ) })}
    ) const renderSummonGrid = (
    {generateMainSummonImage('main')}
      {Array.from(Array(numSummons)).map((x, i) => { return (
    • {generateSummonGridImage(i)}
    • ) })}
    {generateMainSummonImage('friend')}
    ) const favoriteButton = (