From 791f4f8e3525bbf546f3f19f423f1617eff86918 Mon Sep 17 00:00:00 2001 From: caadiq Date: Thu, 16 Apr 2026 13:48:03 +0900 Subject: [PATCH] =?UTF-8?q?=EC=BA=90=EB=A6=AD=ED=84=B0=20=EC=BD=94?= =?UTF-8?q?=EB=94=94/=EA=B8=B0=EB=B3=B8=20=EC=A0=95=EB=B3=B4=20=EC=9E=90?= =?UTF-8?q?=EB=8F=99=20=EC=83=88=EB=A1=9C=EA=B3=A0=EC=B9=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 보스 수익 계산기/심볼 계산기에서 저장된 캐릭터의 character_image, level, 직업 정보를 페이지 로드마다 /api/character/search로 재조회해 반영. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../src/features/boss-crystal/BossCrystal.jsx | 30 ++++++++++++++++++- frontend/src/features/symbol/Symbol.jsx | 28 +++++++++++++++++ frontend/src/features/symbol/store.js | 4 +++ 3 files changed, 61 insertions(+), 1 deletion(-) diff --git a/frontend/src/features/boss-crystal/BossCrystal.jsx b/frontend/src/features/boss-crystal/BossCrystal.jsx index cd6d7b7..4aed18e 100644 --- a/frontend/src/features/boss-crystal/BossCrystal.jsx +++ b/frontend/src/features/boss-crystal/BossCrystal.jsx @@ -1,5 +1,5 @@ import { useState, useEffect } from 'react' -import { useQuery } from '@tanstack/react-query' +import { useQuery, useQueries } from '@tanstack/react-query' import { api } from '../../api/client' import { useLayout } from '../../components/Layout' import CharacterPanel from './user/CharacterPanel' @@ -44,6 +44,34 @@ export default function BossCrystal() { queryFn: () => api('/api/boss-crystal/bosses').catch(() => []), }) + // 저장된 캐릭터의 기본 정보(코디 이미지 포함) 새로고침 + const charRefreshQueries = useQueries({ + queries: characters.map((c) => ({ + queryKey: ['character', 'basic', c.character_name], + queryFn: () => api(`/api/character/search?name=${encodeURIComponent(c.character_name)}`), + enabled: !!c.character_name, + refetchOnMount: 'always', + staleTime: 0, + retry: false, + })), + }) + + useEffect(() => { + if (!charRefreshQueries.length) return + let changed = false + const next = characters.map((c, i) => { + const d = charRefreshQueries[i]?.data + if (!d) return c + if (d.character_image !== c.character_image || d.character_level !== c.character_level || d.job_name !== c.job_name) { + changed = true + return { ...c, ...d } + } + return c + }) + if (changed) setCharacters(next) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [charRefreshQueries.map((q) => q.dataUpdatedAt).join(',')]) + const handleAddCharacter = (char) => { setCharacters((prev) => [...prev, char]) setSelectedChar(char.character_name) diff --git a/frontend/src/features/symbol/Symbol.jsx b/frontend/src/features/symbol/Symbol.jsx index a08a412..c3c0f2c 100644 --- a/frontend/src/features/symbol/Symbol.jsx +++ b/frontend/src/features/symbol/Symbol.jsx @@ -377,12 +377,40 @@ export default function Symbol() { const removeCharacter = useSymbolStore((s) => s.removeCharacter) const selectCharacter = useSymbolStore((s) => s.selectCharacter) const syncCharacterSymbols = useSymbolStore((s) => s.syncCharacterSymbols) + const updateCharacter = useSymbolStore((s) => s.updateCharacter) const storedTab = useSymbolStore((s) => s.selectedTabs?.[selectedCharId]) const setTabStore = useSymbolStore((s) => s.setTab) const tab = storedTab || tabs[0]?.key || null const setTab = (t) => { if (selectedCharId) setTabStore(selectedCharId, t) } + // 각 캐릭터 기본정보(코디 이미지) 새로고침 + const basicQueries = useQueries({ + queries: characters.map((c) => ({ + queryKey: ['character', 'basic', c.character_name], + queryFn: () => api(`/api/character/search?name=${encodeURIComponent(c.character_name)}`), + enabled: !!c.character_name, + refetchOnMount: 'always', + staleTime: 0, + retry: false, + })), + }) + useEffect(() => { + characters.forEach((c, idx) => { + const d = basicQueries[idx]?.data + if (!d) return + if (d.character_image !== c.character_image || d.character_level !== c.character_level || d.job_name !== c.job_name) { + updateCharacter(c.id, { + character_image: d.character_image, + character_level: d.character_level, + job_name: d.job_name, + world_name: d.world_name, + }) + } + }) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [basicQueries.map((q) => q.dataUpdatedAt).join(',')]) + // 각 캐릭터의 장착 심볼 fetch (새로고침마다 갱신) const symbolQueries = useQueries({ queries: characters.map((c) => ({ diff --git a/frontend/src/features/symbol/store.js b/frontend/src/features/symbol/store.js index 26504d6..6fa2eb7 100644 --- a/frontend/src/features/symbol/store.js +++ b/frontend/src/features/symbol/store.js @@ -54,6 +54,10 @@ export const useSymbolStore = create(persist( selectCharacter: (id) => set({ selectedCharId: id }), + updateCharacter: (id, patch) => set((s) => ({ + characters: s.characters.map((c) => (c.id === id ? { ...c, ...patch } : c)), + })), + getSymbolState: (charId, symbolId) => get().progress?.[charId]?.[symbolId], updateSymbol: (charId, symbolId, patch) => set((s) => {