4.21.0: Исправление навигации и истории
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 1m15s

This commit is contained in:
poignatov
2026-02-05 13:52:13 +03:00
parent 22f6807eb2
commit 9a066c88ac
15 changed files with 67 additions and 25 deletions

View File

@@ -1 +1 @@
4.20.7 4.21.0

View File

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

View File

@@ -750,8 +750,33 @@ function AppContent() {
setTabParams(params) setTabParams(params)
// Обновляем URL только для глубоких табов // Обновляем URL только для глубоких табов
if (isNewTabDeep) { if (isNewTabDeep) {
// Сохраняем текущий таб как предыдущий при переходе на глубокий таб // Проверяем, была ли последняя запись в истории от модального окна
updateUrl(tab, params, activeTab) const currentState = window.history.state || {}
const isFromModal = currentState.modalOpen === true
const isNavigatingToForm = tab === 'task-form' || tab === 'wishlist-form'
if (isFromModal && isNavigatingToForm) {
// Заменяем запись модального окна на запись формы редактирования
// Используем replaceState вместо pushState, сохраняя activeTab как previousTab
const url = new URL(window.location)
url.searchParams.set('tab', tab)
// Удаляем старые параметры
const keysToRemove = []
url.searchParams.forEach((value, key) => {
if (key !== 'tab') keysToRemove.push(key)
})
keysToRemove.forEach(key => url.searchParams.delete(key))
// Добавляем новые параметры
Object.entries(params).forEach(([key, value]) => {
if (value !== undefined && value !== null) {
url.searchParams.set(key, typeof value === 'object' ? JSON.stringify(value) : value)
}
})
window.history.replaceState({ tab, params, previousTab: activeTab }, '', url)
} else {
// Сохраняем текущий таб как предыдущий при переходе на глубокий таб
updateUrl(tab, params, activeTab)
}
} else if (isNewTabMain && isCurrentTabDeep) { } else if (isNewTabMain && isCurrentTabDeep) {
// При переходе с глубокого таба на основной - очищаем URL и сохраняем таб в state // При переходе с глубокого таба на основной - очищаем URL и сохраняем таб в state
clearUrl(tab) clearUrl(tab)

View File

@@ -139,7 +139,7 @@ function AddWords({ onNavigate, dictionaryId, dictionaryName }) {
} }
const handleClose = () => { const handleClose = () => {
onNavigate?.('words', dictionaryId !== undefined && dictionaryId !== null ? { dictionaryId } : {}) window.history.back()
} }
// Show loading state while fetching dictionary name // Show loading state while fetching dictionary name

View File

@@ -156,7 +156,7 @@ function BoardForm({ boardId, onNavigate, onSaved }) {
} }
const handleClose = () => { const handleClose = () => {
onNavigate('wishlist') window.history.back()
} }
if (loadingBoard) { if (loadingBoard) {

View File

@@ -94,7 +94,7 @@ function DictionaryList({ onNavigate, refreshTrigger = 0 }) {
{/* Кнопка закрытия */} {/* Кнопка закрытия */}
<button <button
className="dictionary-close-button" className="dictionary-close-button"
onClick={() => onNavigate?.('profile')} onClick={() => window.history.back()}
title="Закрыть" title="Закрыть"
> >

View File

@@ -127,7 +127,7 @@ function FullStatistics({ selectedProject, onClearSelection, data, loading, erro
onClick={() => { onClick={() => {
// Сбрасываем выбор дня перед выходом с экрана // Сбрасываем выбор дня перед выходом с экрана
setSelectedDate(todayDateStr) setSelectedDate(todayDateStr)
onNavigate('current') window.history.back()
}} }}
className="close-x-button" className="close-x-button"
title="Закрыть" title="Закрыть"

View File

@@ -921,7 +921,7 @@ function ProjectPriorityManager({ allProjectsData, currentWeekData, shouldLoad,
<div className="max-w-2xl mx-auto flex flex-col h-full"> <div className="max-w-2xl mx-auto flex flex-col h-full">
{onNavigate && ( {onNavigate && (
<button <button
onClick={() => onNavigate('current')} onClick={() => window.history.back()}
className="close-x-button" className="close-x-button"
title="Закрыть" title="Закрыть"
> >

View File

@@ -735,7 +735,9 @@ function TaskDetail({ taskId, onClose, onRefresh, onTaskCompleted, onNavigate })
<h2 <h2
className="task-detail-title" className="task-detail-title"
onClick={taskDetail ? () => { onClick={taskDetail ? () => {
onClose?.() // Закрываем модальное окно БЕЗ history.back() (skipHistoryBack = true)
// handleTabChange заменит запись модального окна через replaceState
onClose?.(true)
onNavigate?.('task-form', { taskId: taskId }) onNavigate?.('task-form', { taskId: taskId })
} : undefined} } : undefined}
style={{ cursor: taskDetail ? 'pointer' : 'default' }} style={{ cursor: taskDetail ? 'pointer' : 'default' }}

View File

@@ -774,7 +774,7 @@ function TaskForm({ onNavigate, taskId, wishlistId, isTest: isTestFromProps = fa
const handleCancel = () => { const handleCancel = () => {
resetForm() resetForm()
onNavigate?.('tasks') window.history.back()
} }
const handleDelete = async () => { const handleDelete = async () => {

View File

@@ -71,8 +71,15 @@ function TaskList({ onNavigate, data, loading, backgroundLoading, error, onRetry
setSelectedTaskForDetail(task.id) setSelectedTaskForDetail(task.id)
} }
const handleCloseDetail = () => { const handleCloseDetail = (skipHistoryBack = false) => {
setSelectedTaskForDetail(null) // Если skipHistoryBack = true (например, при навигации на форму редактирования),
// просто закрываем модальное окно без history.back()
if (!skipHistoryBack && historyPushedForDetailRef.current) {
window.history.back()
} else {
historyPushedForDetailRef.current = false
setSelectedTaskForDetail(null)
}
} }
// Добавляем запись в историю при открытии модальных окон и обрабатываем "назад" // Добавляем запись в историю при открытии модальных окон и обрабатываем "назад"

View File

@@ -557,7 +557,7 @@ function TestWords({ onNavigate, wordCount: initialWordCount, configId: initialC
} }
const handleClose = () => { const handleClose = () => {
onNavigate?.('tasks') window.history.back()
} }
const handleStartTest = () => { const handleStartTest = () => {

View File

@@ -52,6 +52,9 @@ function WishlistDetail({ wishlistId, onNavigate, onRefresh, boardId, onClose, p
}, [wishlistId, fetchWishlistDetail]) }, [wishlistId, fetchWishlistDetail])
const handleEdit = () => { const handleEdit = () => {
// Сбрасываем флаг, чтобы handleClose не вызвал history.back()
// handleTabChange заменит запись модального окна через replaceState
historyPushedForWishlistRef.current = false
onClose?.() onClose?.()
onNavigate?.('wishlist-form', { wishlistId: wishlistId, boardId: boardId }) onNavigate?.('wishlist-form', { wishlistId: wishlistId, boardId: boardId })
} }
@@ -192,8 +195,15 @@ function WishlistDetail({ wishlistId, onNavigate, onRefresh, boardId, onClose, p
} }
} }
const handleCloseDetail = () => { const handleCloseDetail = (skipHistoryBack = false) => {
setSelectedTaskForDetail(null) // Если skipHistoryBack = true (например, при навигации на форму редактирования),
// просто закрываем модальное окно без history.back()
if (!skipHistoryBack && historyPushedForTaskRef.current) {
window.history.back()
} else {
historyPushedForTaskRef.current = false
setSelectedTaskForDetail(null)
}
} }
// Добавляем запись в историю при открытии модальных окон и обрабатываем "назад" // Добавляем запись в историю при открытии модальных окон и обрабатываем "назад"
@@ -278,8 +288,11 @@ function WishlistDetail({ wishlistId, onNavigate, onRefresh, boardId, onClose, p
}, [wishlistId, selectedTaskForDetail, onClose, onNavigate, previousTab, boardId]) }, [wishlistId, selectedTaskForDetail, onClose, onNavigate, previousTab, boardId])
const handleClose = () => { const handleClose = () => {
// Используем onClose если передан, иначе возвращаемся на wishlist // Если была добавлена запись в историю, удаляем её через history.back()
if (onClose) { // Обработчик popstate закроет модальное окно
if (historyPushedForWishlistRef.current) {
window.history.back()
} else if (onClose) {
onClose() onClose()
} else { } else {
// Возвращаемся на предыдущий таб, если он был сохранен, иначе на wishlist // Возвращаемся на предыдущий таб, если он был сохранен, иначе на wishlist

View File

@@ -666,12 +666,7 @@ function WishlistForm({ onNavigate, wishlistId, editConditionIndex, newTaskId, b
const handleCancel = () => { const handleCancel = () => {
resetForm() resetForm()
// Возвращаемся на доску, если она была указана window.history.back()
if (boardId) {
onNavigate?.('wishlist', { boardId })
} else {
onNavigate?.('wishlist')
}
} }
return ( return (

View File

@@ -176,7 +176,7 @@ function WordList({ onNavigate, dictionaryId, isNewDictionary, refreshTrigger =
return ( return (
<div className="word-list"> <div className="word-list">
<button <button
onClick={() => onNavigate?.('dictionaries')} onClick={() => window.history.back()}
className="close-x-button" className="close-x-button"
title="Закрыть" title="Закрыть"
> >