6.15.1: Фикс race condition при смене доски желаний
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 1m25s

This commit is contained in:
poignatov
2026-03-13 14:52:07 +03:00
parent c8a47ff408
commit 6f76c4a25c
4 changed files with 52 additions and 36 deletions

View File

@@ -1 +1 @@
6.15.0 6.15.1

Binary file not shown.

View File

@@ -1,6 +1,6 @@
{ {
"name": "play-life-web", "name": "play-life-web",
"version": "6.15.0", "version": "6.15.1",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",

View File

@@ -51,9 +51,11 @@ function Wishlist({ onNavigate, refreshTrigger = 0, isActive = false, initialBoa
const fetchingCompletedRef = useRef(false) const fetchingCompletedRef = useRef(false)
const initialFetchDoneRef = useRef(false) const initialFetchDoneRef = useRef(false)
const prevIsActiveRef = useRef(isActive) const prevIsActiveRef = useRef(isActive)
const selectedBoardIdRef = useRef(getInitialBoardId())
// Обёртка для setSelectedBoardId с сохранением в localStorage // Обёртка для setSelectedBoardId с сохранением в localStorage
const setSelectedBoardId = (boardId) => { const setSelectedBoardId = (boardId) => {
selectedBoardIdRef.current = boardId
setSelectedBoardIdState(boardId) setSelectedBoardIdState(boardId)
try { try {
if (boardId) { if (boardId) {
@@ -171,20 +173,20 @@ function Wishlist({ onNavigate, refreshTrigger = 0, isActive = false, initialBoa
} }
// Загрузка желаний выбранной доски // Загрузка желаний выбранной доски
const fetchItems = async () => { const fetchItems = async (boardId) => {
if (!selectedBoardId || fetchingRef.current) return if (!boardId || fetchingRef.current) return
fetchingRef.current = true fetchingRef.current = true
try { try {
const hasDataInState = items.length > 0 || completedCount > 0 const hasDataInState = items.length > 0 || completedCount > 0
if (!hasDataInState) { if (!hasDataInState) {
const cacheLoaded = loadItemsFromCache(selectedBoardId) const cacheLoaded = loadItemsFromCache(boardId)
if (!cacheLoaded) { if (!cacheLoaded) {
setLoading(true) setLoading(true)
} }
} }
const response = await authFetch(`${API_URL}/boards/${selectedBoardId}/items`) const response = await authFetch(`${API_URL}/boards/${boardId}/items`)
if (!response.ok) { if (!response.ok) {
throw new Error('Ошибка при загрузке желаний') throw new Error('Ошибка при загрузке желаний')
@@ -194,31 +196,37 @@ function Wishlist({ onNavigate, refreshTrigger = 0, isActive = false, initialBoa
const allItems = [...(data.unlocked || []), ...(data.locked || [])] const allItems = [...(data.unlocked || []), ...(data.locked || [])]
const count = data.completed_count || 0 const count = data.completed_count || 0
// Проверяем, что пользователь не переключился на другую доску пока шёл запрос
if (selectedBoardIdRef.current !== boardId) return
setItems(allItems) setItems(allItems)
setCompletedCount(count) setCompletedCount(count)
saveItemsToCache(selectedBoardId, allItems, count) saveItemsToCache(boardId, allItems, count)
setError('') setError('')
} catch (err) { } catch (err) {
if (selectedBoardIdRef.current !== boardId) return
setError(err.message) setError(err.message)
if (!loadItemsFromCache(selectedBoardId)) { if (!loadItemsFromCache(boardId)) {
setItems([]) setItems([])
setCompletedCount(0) setCompletedCount(0)
} }
} finally { } finally {
if (selectedBoardIdRef.current === boardId) {
setLoading(false) setLoading(false)
}
fetchingRef.current = false fetchingRef.current = false
} }
} }
// Загрузка завершённых для текущей доски // Загрузка завершённых для текущей доски
const fetchCompleted = async () => { const fetchCompleted = async (boardId) => {
if (fetchingCompletedRef.current || !selectedBoardId) return if (fetchingCompletedRef.current || !boardId) return
fetchingCompletedRef.current = true fetchingCompletedRef.current = true
try { try {
setCompletedLoading(true) setCompletedLoading(true)
// Используем новый API для получения завершённых на доске // Используем новый API для получения завершённых на доске
const response = await authFetch(`${API_URL}/boards/${selectedBoardId}/completed`) const response = await authFetch(`${API_URL}/boards/${boardId}/completed`)
if (!response.ok) { if (!response.ok) {
const errText = await response.text() const errText = await response.text()
@@ -228,12 +236,20 @@ function Wishlist({ onNavigate, refreshTrigger = 0, isActive = false, initialBoa
const data = await response.json() const data = await response.json()
const completedData = Array.isArray(data) ? data : [] const completedData = Array.isArray(data) ? data : []
// Проверяем, что пользователь не переключился на другую доску пока шёл запрос
if (selectedBoardIdRef.current !== boardId) return
setCompleted(completedData) setCompleted(completedData)
} catch (err) { } catch (err) {
console.error('Error fetching completed items:', err) console.error('Error fetching completed items:', err)
if (selectedBoardIdRef.current === boardId) {
setCompleted([]) setCompleted([])
}
} finally { } finally {
if (selectedBoardIdRef.current === boardId) {
setCompletedLoading(false) setCompletedLoading(false)
}
fetchingCompletedRef.current = false fetchingCompletedRef.current = false
} }
} }
@@ -292,7 +308,7 @@ function Wishlist({ onNavigate, refreshTrigger = 0, isActive = false, initialBoa
} }
// Загружаем свежие данные // Загружаем свежие данные
fetchItems() fetchItems(selectedBoardId)
} }
}, [selectedBoardId]) }, [selectedBoardId])
@@ -306,7 +322,7 @@ function Wishlist({ onNavigate, refreshTrigger = 0, isActive = false, initialBoa
if (isActive && !wasActive) { if (isActive && !wasActive) {
fetchBoards() fetchBoards()
if (selectedBoardId) { if (selectedBoardId) {
fetchItems() fetchItems(selectedBoardId)
} }
} }
}, [isActive]) }, [isActive])
@@ -321,9 +337,9 @@ function Wishlist({ onNavigate, refreshTrigger = 0, isActive = false, initialBoa
console.error('Error clearing cache:', err) console.error('Error clearing cache:', err)
} }
fetchBoards() fetchBoards()
fetchItems() fetchItems(selectedBoardId)
if (completedExpanded && completedCount > 0) { if (completedExpanded && completedCount > 0) {
fetchCompleted() fetchCompleted(selectedBoardId)
} }
} }
}, [refreshTrigger, selectedBoardId]) }, [refreshTrigger, selectedBoardId])
@@ -421,7 +437,7 @@ function Wishlist({ onNavigate, refreshTrigger = 0, isActive = false, initialBoa
setCompletedExpanded(newExpanded) setCompletedExpanded(newExpanded)
if (newExpanded && completedCount > 0) { if (newExpanded && completedCount > 0) {
fetchCompleted() fetchCompleted(selectedBoardId)
} }
} }
@@ -465,9 +481,9 @@ function Wishlist({ onNavigate, refreshTrigger = 0, isActive = false, initialBoa
} }
setSelectedItem(null) setSelectedItem(null)
await fetchItems() await fetchItems(selectedBoardId)
if (completedExpanded) { if (completedExpanded) {
await fetchCompleted() await fetchCompleted(selectedBoardId)
} }
} catch (err) { } catch (err) {
setError(err.message) setError(err.message)
@@ -502,7 +518,7 @@ function Wishlist({ onNavigate, refreshTrigger = 0, isActive = false, initialBoa
} }
// Обновляем список // Обновляем список
await fetchItems() await fetchItems(selectedBoardId)
// Открываем форму редактирования для нового желания // Открываем форму редактирования для нового желания
onNavigate?.('wishlist-form', { wishlistId: newItem.id, boardId: selectedBoardId }) onNavigate?.('wishlist-form', { wishlistId: newItem.id, boardId: selectedBoardId })
@@ -682,7 +698,7 @@ function Wishlist({ onNavigate, refreshTrigger = 0, isActive = false, initialBoa
loading={boardsLoading} loading={boardsLoading}
showBoardAction={false} showBoardAction={false}
/> />
<LoadingError onRetry={() => fetchItems()} /> <LoadingError onRetry={() => fetchItems(selectedBoardId)} />
</div> </div>
) )
} }
@@ -794,9 +810,9 @@ function Wishlist({ onNavigate, refreshTrigger = 0, isActive = false, initialBoa
onNavigate={onNavigate} onNavigate={onNavigate}
boardId={selectedBoardId} boardId={selectedBoardId}
onRefresh={async () => { onRefresh={async () => {
await fetchItems() await fetchItems(selectedBoardId)
if (completedExpanded) { if (completedExpanded) {
await fetchCompleted() await fetchCompleted(selectedBoardId)
} }
}} }}
onClose={handleCloseDetail} onClose={handleCloseDetail}