캐릭터 코디/기본 정보 자동 새로고침
보스 수익 계산기/심볼 계산기에서 저장된 캐릭터의 character_image, level, 직업 정보를 페이지 로드마다 /api/character/search로 재조회해 반영. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
3829ada3cf
commit
791f4f8e35
3 changed files with 61 additions and 1 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
import { useState, useEffect } from 'react'
|
import { useState, useEffect } from 'react'
|
||||||
import { useQuery } from '@tanstack/react-query'
|
import { useQuery, useQueries } from '@tanstack/react-query'
|
||||||
import { api } from '../../api/client'
|
import { api } from '../../api/client'
|
||||||
import { useLayout } from '../../components/Layout'
|
import { useLayout } from '../../components/Layout'
|
||||||
import CharacterPanel from './user/CharacterPanel'
|
import CharacterPanel from './user/CharacterPanel'
|
||||||
|
|
@ -44,6 +44,34 @@ export default function BossCrystal() {
|
||||||
queryFn: () => api('/api/boss-crystal/bosses').catch(() => []),
|
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) => {
|
const handleAddCharacter = (char) => {
|
||||||
setCharacters((prev) => [...prev, char])
|
setCharacters((prev) => [...prev, char])
|
||||||
setSelectedChar(char.character_name)
|
setSelectedChar(char.character_name)
|
||||||
|
|
|
||||||
|
|
@ -377,12 +377,40 @@ export default function Symbol() {
|
||||||
const removeCharacter = useSymbolStore((s) => s.removeCharacter)
|
const removeCharacter = useSymbolStore((s) => s.removeCharacter)
|
||||||
const selectCharacter = useSymbolStore((s) => s.selectCharacter)
|
const selectCharacter = useSymbolStore((s) => s.selectCharacter)
|
||||||
const syncCharacterSymbols = useSymbolStore((s) => s.syncCharacterSymbols)
|
const syncCharacterSymbols = useSymbolStore((s) => s.syncCharacterSymbols)
|
||||||
|
const updateCharacter = useSymbolStore((s) => s.updateCharacter)
|
||||||
const storedTab = useSymbolStore((s) => s.selectedTabs?.[selectedCharId])
|
const storedTab = useSymbolStore((s) => s.selectedTabs?.[selectedCharId])
|
||||||
const setTabStore = useSymbolStore((s) => s.setTab)
|
const setTabStore = useSymbolStore((s) => s.setTab)
|
||||||
|
|
||||||
const tab = storedTab || tabs[0]?.key || null
|
const tab = storedTab || tabs[0]?.key || null
|
||||||
const setTab = (t) => { if (selectedCharId) setTabStore(selectedCharId, t) }
|
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 (새로고침마다 갱신)
|
// 각 캐릭터의 장착 심볼 fetch (새로고침마다 갱신)
|
||||||
const symbolQueries = useQueries({
|
const symbolQueries = useQueries({
|
||||||
queries: characters.map((c) => ({
|
queries: characters.map((c) => ({
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,10 @@ export const useSymbolStore = create(persist(
|
||||||
|
|
||||||
selectCharacter: (id) => set({ selectedCharId: id }),
|
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],
|
getSymbolState: (charId, symbolId) => get().progress?.[charId]?.[symbolId],
|
||||||
|
|
||||||
updateSymbol: (charId, symbolId, patch) => set((s) => {
|
updateSymbol: (charId, symbolId, patch) => set((s) => {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue