"use client" import NextImage from "next/image" import useUserDataStore from "@/stores/userDataStore"; import { useTranslations } from "next-intl"; import { useMemo } from "react"; import { calcAffixBonus, calcBaseStatRaw, calcBonusStatRaw, calcMainAffixBonus, calcMainAffixBonusRaw, calcPromotion, calcSubAffixBonusRaw, getLocaleName, replaceByParam } from "@/helper"; import { mappingStats } from "@/constant/constant"; import QuickViewRelic from "./quickViewRelic"; import useLocaleStore from "@/stores/localeStore"; import useDetailDataStore from "@/stores/detailDataStore"; import useCurrentDataStore from "@/stores/currentDataStore"; import { useShallow } from "zustand/react/shallow"; export default function QuickView() { const { avatars } = useUserDataStore( useShallow((state) => ({ avatars: state.avatars })) ) const transI18n = useTranslations("DataPage") const { locale } = useLocaleStore( useShallow((state) => ({ locale: state.locale })) ) const { avatarSelected } = useCurrentDataStore( useShallow((state) => ({ avatarSelected: state.avatarSelected })) ) const { mainAffix, subAffix, mapRelicSet, mapLightCone, mapAvatar } = useDetailDataStore( useShallow((state) => ({ mainAffix: state.mainAffix, subAffix: state.subAffix, mapRelicSet: state.mapRelicSet, mapLightCone: state.mapLightCone, mapAvatar: state.mapAvatar, })) ) const avatarSkillTree = useMemo(() => { if (!avatarSelected || !avatars[avatarSelected?.ID?.toString()]) return {} if (avatars[avatarSelected?.ID?.toString()].enhanced) { return avatarSelected?.Enhanced?.[avatars[avatarSelected?.ID?.toString()].enhanced.toString()].SkillTrees || {} } return avatarSelected?.SkillTrees || {} }, [avatarSelected, avatars]) const avatarData = useMemo(() => { if (!avatarSelected) return return avatars[avatarSelected?.ID?.toString()] }, [avatarSelected, avatars]) const avatarProfile = useMemo(() => { if (!avatarSelected || !avatarData) return return avatarData?.profileList?.[avatarData?.profileSelect] ?? avatarData?.profileList?.[0] }, [avatarSelected, avatarData]) const relicEffects = useMemo(() => { const avatar = avatars[avatarSelected?.ID?.toString() || ""]; const relicCount: { [key: string]: number } = {}; const profile = avatar?.profileList?.[avatar?.profileSelect] ?? avatar?.profileList?.[0]; if (profile?.relics) { for (const relic of Object.values(profile.relics)) { if (relic && relic.relic_set_id) { relicCount[relic.relic_set_id] = (relicCount[relic.relic_set_id] || 0) + 1; } } } const listEffects: { key: string, count: number }[] = []; Object.entries(relicCount).forEach(([key, value]) => { if (value >= 2) { listEffects.push({ key: key, count: value }); } }); return listEffects; }, [avatars, avatarSelected]); const relicStats = useMemo(() => { if (!avatarSelected || !avatarProfile?.relics || !mainAffix || !subAffix) return return Object.entries(avatarProfile?.relics).map(([key, value]) => { const mainAffixMap = mainAffix["5" + key] const subAffixMap = subAffix["5"] if (!mainAffixMap || !subAffixMap) return return { img: `${process.env.CDN_URL}/spriteoutput/relicfigures/IconRelic_${value.relic_set_id}_${key}.png`, mainAffix: { property: mainAffixMap?.[value?.main_affix_id]?.Property, level: value?.level, valueAffix: calcMainAffixBonus(mainAffixMap?.[value?.main_affix_id], value?.level), detail: mappingStats?.[mainAffixMap?.[value?.main_affix_id]?.Property] }, subAffix: value?.sub_affixes?.map((subValue) => { return { property: subAffixMap?.[subValue?.sub_affix_id]?.Property, valueAffix: calcAffixBonus(subAffixMap?.[subValue?.sub_affix_id], subValue?.step, subValue?.count), detail: mappingStats?.[subAffixMap?.[subValue?.sub_affix_id]?.Property], step: subValue?.step, count: subValue?.count } }) } }) }, [avatarSelected, avatarProfile, mainAffix, subAffix]) const characterStats = useMemo(() => { if (!avatarSelected || !avatarData) return const charPromotion = calcPromotion(avatarData.level) const statsData: Record = { HP: { value: calcBaseStatRaw( mapAvatar?.[avatarSelected?.ID?.toString()]?.Stats[charPromotion]?.HPBase, mapAvatar?.[avatarSelected?.ID?.toString()]?.Stats[charPromotion]?.HPAdd, avatarData.level ), base: calcBaseStatRaw( mapAvatar?.[avatarSelected?.ID?.toString()]?.Stats[charPromotion]?.HPBase, mapAvatar?.[avatarSelected?.ID?.toString()]?.Stats[charPromotion]?.HPAdd, avatarData.level ), name: transI18n("hp"), icon: "spriteoutput/ui/avatar/icon/IconMaxHP.png", unit: "", round: 0 }, ATK: { value: calcBaseStatRaw( mapAvatar?.[avatarSelected?.ID?.toString()]?.Stats[charPromotion]?.AttackBase, mapAvatar?.[avatarSelected?.ID?.toString()]?.Stats[charPromotion]?.AttackAdd, avatarData.level ), base: calcBaseStatRaw( mapAvatar?.[avatarSelected?.ID?.toString()]?.Stats[charPromotion]?.AttackBase, mapAvatar?.[avatarSelected?.ID?.toString()]?.Stats[charPromotion]?.AttackAdd, avatarData.level ), name: transI18n("atk"), icon: "spriteoutput/ui/avatar/icon/IconAttack.png", unit: "", round: 0 }, DEF: { value: calcBaseStatRaw( mapAvatar?.[avatarSelected?.ID?.toString()]?.Stats[charPromotion]?.DefenceBase, mapAvatar?.[avatarSelected?.ID?.toString()]?.Stats[charPromotion]?.DefenceAdd, avatarData.level ), base: calcBaseStatRaw( mapAvatar?.[avatarSelected?.ID?.toString()]?.Stats[charPromotion]?.DefenceBase, mapAvatar?.[avatarSelected?.ID?.toString()]?.Stats[charPromotion]?.DefenceAdd, avatarData.level ), name: transI18n("def"), icon: "spriteoutput/ui/avatar/icon/IconDefence.png", unit: "", round: 0 }, SPD: { value: mapAvatar?.[avatarSelected?.ID?.toString()]?.Stats[charPromotion]?.SpeedBase || 0, base: mapAvatar?.[avatarSelected?.ID?.toString()]?.Stats[charPromotion]?.SpeedBase || 0, name: transI18n("speed"), icon: "spriteoutput/ui/avatar/icon/IconSpeed.png", unit: "", round: 1 }, CRITRate: { value: mapAvatar?.[avatarSelected?.ID?.toString()]?.Stats[charPromotion]?.CriticalChance || 0, base: mapAvatar?.[avatarSelected?.ID?.toString()]?.Stats[charPromotion]?.CriticalChance || 0, name: transI18n("critRate"), icon: "spriteoutput/ui/avatar/icon/IconCriticalChance.png", unit: "%", round: 1 }, CRITDmg: { value: mapAvatar?.[avatarSelected?.ID?.toString()]?.Stats[charPromotion]?.CriticalDamage || 0, base: mapAvatar?.[avatarSelected?.ID?.toString()]?.Stats[charPromotion]?.CriticalDamage || 0, name: transI18n("critDmg"), icon: "spriteoutput/ui/avatar/icon/IconCriticalDamage.png", unit: "%", round: 1 }, BreakEffect: { value: 0, base: 0, name: transI18n("breakEffect"), icon: "spriteoutput/ui/avatar/icon/IconBreakUp.png", unit: "%", round: 1 }, EffectRES: { value: 0, base: 0, name: transI18n("effectRes"), icon: "spriteoutput/ui/avatar/icon/IconStatusResistance.png", unit: "%", round: 1 }, EnergyRate: { value: 0, base: 0, name: transI18n("energyRegenerationRate"), icon: "spriteoutput/ui/avatar/icon/IconEnergyRecovery.png", unit: "%", round: 1 }, EffectHitRate: { value: 0, base: 0, name: transI18n("effectHitRate"), icon: "spriteoutput/ui/avatar/icon/IconStatusProbability.png", unit: "%", round: 1 }, HealBoost: { value: 0, base: 0, name: transI18n("outgoingHealingBoost"), icon: "spriteoutput/ui/avatar/icon/IconHealRatio.png", unit: "%", round: 1 }, PhysicalAdd: { value: 0, base: 0, name: transI18n("physicalDmgBoost"), icon: "spriteoutput/ui/avatar/icon/IconPhysicalAddedRatio.png", unit: "%", round: 1 }, FireAdd: { value: 0, base: 0, name: transI18n("fireDmgBoost"), icon: "spriteoutput/ui/avatar/icon/IconFireAddedRatio.png", unit: "%", round: 1 }, IceAdd: { value: 0, base: 0, name: transI18n("iceDmgBoost"), icon: "spriteoutput/ui/avatar/icon/IconIceAddedRatio.png", unit: "%", round: 1 }, ThunderAdd: { value: 0, base: 0, name: transI18n("thunderDmgBoost"), icon: "spriteoutput/ui/avatar/icon/IconThunderAddedRatio.png", unit: "%", round: 1 }, WindAdd: { value: 0, base: 0, name: transI18n("windDmgBoost"), icon: "spriteoutput/ui/avatar/icon/IconWindAddedRatio.png", unit: "%", round: 1 }, QuantumAdd: { value: 0, base: 0, name: transI18n("quantumDmgBoost"), icon: "spriteoutput/ui/avatar/icon/IconQuantumAddedRatio.png", unit: "%", round: 1 }, ImaginaryAdd: { value: 0, base: 0, name: transI18n("imaginaryDmgBoost"), icon: "spriteoutput/ui/avatar/icon/IconImaginaryAddedRatio.png", unit: "%", round: 1 }, ElationAdd: { value: 0, base: 0, name: transI18n("elation"), icon: "spriteoutput/ui/avatar/icon/IconJoy.png", unit: "%", round: 1 } } if (avatarProfile?.lightcone && mapLightCone[avatarProfile?.lightcone?.item_id]) { const lightconePromotion = calcPromotion(avatarProfile?.lightcone?.level) statsData.HP.value += calcBaseStatRaw( mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats?.[lightconePromotion]?.BaseHP, mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats[lightconePromotion]?.BaseHPAdd, avatarProfile?.lightcone?.level ) statsData.HP.base += calcBaseStatRaw( mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats?.[lightconePromotion]?.BaseHP, mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats[lightconePromotion]?.BaseHPAdd, avatarProfile?.lightcone?.level ) statsData.ATK.value += calcBaseStatRaw( mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats?.[lightconePromotion]?.BaseAttack, mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats?.[lightconePromotion]?.BaseAttackAdd, avatarProfile?.lightcone?.level ) statsData.ATK.base += calcBaseStatRaw( mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats?.[lightconePromotion]?.BaseAttack, mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats?.[lightconePromotion]?.BaseAttackAdd, avatarProfile?.lightcone?.level ) statsData.DEF.value += calcBaseStatRaw( mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats?.[lightconePromotion]?.BaseDefence, mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats?.[lightconePromotion]?.BaseDefenceAdd, avatarProfile?.lightcone?.level ) statsData.DEF.base += calcBaseStatRaw( mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats?.[lightconePromotion]?.BaseDefence, mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Stats?.[lightconePromotion]?.BaseDefenceAdd, avatarProfile?.lightcone?.level ) const bonusData = mapLightCone?.[avatarProfile?.lightcone?.item_id]?.Skills?.Level?.[avatarProfile?.lightcone.rank]?.Bonus if (bonusData && bonusData.length > 0) { const bonusSpd = bonusData.filter((bonus) => bonus.PropertyType === "BaseSpeed") const bonusOther = bonusData.filter((bonus) => bonus.PropertyType !== "BaseSpeed") bonusSpd.forEach((bonus) => { statsData.SPD.value += bonus.Value statsData.SPD.base += bonus.Value }) bonusOther.forEach((bonus) => { const statsBase = mappingStats?.[bonus.PropertyType]?.baseStat if (statsBase && statsData[statsBase]) { statsData[statsBase].value += calcBonusStatRaw(bonus.PropertyType, statsData[statsBase].base, bonus.Value) } }) } } if (avatarSkillTree) { Object.values(avatarSkillTree).forEach((value) => { if (value?.["1"] && value?.["1"]?.PointID && typeof avatarData?.data?.skills?.[value?.["1"]?.PointID] === "number" && avatarData?.data?.skills?.[value?.["1"]?.PointID] !== 0 && value?.["1"]?.StatusAddList && value?.["1"].StatusAddList.length > 0) { value?.["1"]?.StatusAddList.forEach((status) => { const statsBase = mappingStats?.[status?.PropertyType]?.baseStat if (statsBase && statsData[statsBase]) { statsData[statsBase].value += calcBonusStatRaw(status?.PropertyType, statsData[statsBase].base, status.Value) } }) } }) } if (avatarProfile?.relics && mainAffix && subAffix) { Object.entries(avatarProfile?.relics).forEach(([key, value]) => { const mainAffixMap = mainAffix["5" + key] const subAffixMap = subAffix["5"] if (!mainAffixMap || !subAffixMap) return const mainStats = mappingStats?.[mainAffixMap?.[value.main_affix_id]?.Property]?.baseStat if (mainStats && statsData[mainStats]) { statsData[mainStats].value += calcMainAffixBonusRaw(mainAffixMap?.[value.main_affix_id], value.level, statsData[mainStats].base) } value?.sub_affixes.forEach((subValue) => { const subStats = mappingStats?.[subAffixMap?.[subValue.sub_affix_id]?.Property]?.baseStat if (subStats && statsData[subStats]) { statsData[subStats].value += calcSubAffixBonusRaw(subAffixMap?.[subValue.sub_affix_id], subValue.step, subValue.count, statsData[subStats].base) } }) }) } if (relicEffects && relicEffects.length > 0) { relicEffects.forEach((relic) => { const dataBonus = mapRelicSet?.[relic.key]?.Skills if (!dataBonus || Object.keys(dataBonus).length === 0) return Object.entries(dataBonus || {}).forEach(([key, value]) => { if (relic.count < Number(key)) return value.Bonus.forEach((bonus) => { const statsBase = mappingStats?.[bonus.PropertyType]?.baseStat if (statsBase && statsData[statsBase]) { statsData[statsBase].value += calcBonusStatRaw(bonus.PropertyType, statsData[statsBase].base, bonus.Value) } }) }) }) } return statsData }, [ avatarSelected, avatarData, mapAvatar, avatarProfile?.lightcone, avatarProfile?.relics, mapLightCone, mainAffix, subAffix, relicEffects, mapRelicSet, avatarSkillTree ]) return (
{/* Stats Overview Column - Clean Minimal Grid, No Box-in-Box */}

{transI18n("character")}

{transI18n("level")} {avatarData?.level || 1}
{Object.entries(characterStats || {})?.map(([key, stat], index) => { if (!stat || (key.includes("Add") && stat.value === 0)) return null return (
{stat.name}
{stat.value ? stat.unit === "%" ? (stat.value * 100).toFixed(stat.round) : stat.value.toFixed(stat.round) : 0} {stat.unit}
) })}
{/* Set Effects - Flat Minimalist Row */} {relicEffects.length > 0 && (

{transI18n("relics")}

{relicEffects.map((setEffect, index) => { const relicInfo = mapRelicSet[setEffect.key]; if (!relicInfo) return null; return (
{setEffect.count} Pc
) })}
)}
{/* Relic Equipment Cards Column */}
{relicStats?.map((relic, index) => { if (!relic || !avatarSelected) return null return ( ) })} {(!relicStats || !relicStats?.length) && (
{transI18n("noRelicEquipped")}
)}
) }