4.21.0: Исправление навигации и истории
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 1m15s
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 1m15s
This commit is contained in:
@@ -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",
|
||||||
|
|||||||
@@ -750,8 +750,33 @@ function AppContent() {
|
|||||||
setTabParams(params)
|
setTabParams(params)
|
||||||
// Обновляем URL только для глубоких табов
|
// Обновляем URL только для глубоких табов
|
||||||
if (isNewTabDeep) {
|
if (isNewTabDeep) {
|
||||||
|
// Проверяем, была ли последняя запись в истории от модального окна
|
||||||
|
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)
|
updateUrl(tab, params, activeTab)
|
||||||
|
}
|
||||||
} else if (isNewTabMain && isCurrentTabDeep) {
|
} else if (isNewTabMain && isCurrentTabDeep) {
|
||||||
// При переходе с глубокого таба на основной - очищаем URL и сохраняем таб в state
|
// При переходе с глубокого таба на основной - очищаем URL и сохраняем таб в state
|
||||||
clearUrl(tab)
|
clearUrl(tab)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ function BoardForm({ boardId, onNavigate, onSaved }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
onNavigate('wishlist')
|
window.history.back()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loadingBoard) {
|
if (loadingBoard) {
|
||||||
|
|||||||
@@ -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="Закрыть"
|
||||||
>
|
>
|
||||||
✕
|
✕
|
||||||
|
|||||||
@@ -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="Закрыть"
|
||||||
|
|||||||
@@ -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="Закрыть"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -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' }}
|
||||||
|
|||||||
@@ -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 () => {
|
||||||
|
|||||||
@@ -71,9 +71,16 @@ function TaskList({ onNavigate, data, loading, backgroundLoading, error, onRetry
|
|||||||
setSelectedTaskForDetail(task.id)
|
setSelectedTaskForDetail(task.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleCloseDetail = () => {
|
const handleCloseDetail = (skipHistoryBack = false) => {
|
||||||
|
// Если skipHistoryBack = true (например, при навигации на форму редактирования),
|
||||||
|
// просто закрываем модальное окно без history.back()
|
||||||
|
if (!skipHistoryBack && historyPushedForDetailRef.current) {
|
||||||
|
window.history.back()
|
||||||
|
} else {
|
||||||
|
historyPushedForDetailRef.current = false
|
||||||
setSelectedTaskForDetail(null)
|
setSelectedTaskForDetail(null)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Добавляем запись в историю при открытии модальных окон и обрабатываем "назад"
|
// Добавляем запись в историю при открытии модальных окон и обрабатываем "назад"
|
||||||
const historyPushedForDetailRef = useRef(false)
|
const historyPushedForDetailRef = useRef(false)
|
||||||
|
|||||||
@@ -557,7 +557,7 @@ function TestWords({ onNavigate, wordCount: initialWordCount, configId: initialC
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
onNavigate?.('tasks')
|
window.history.back()
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleStartTest = () => {
|
const handleStartTest = () => {
|
||||||
|
|||||||
@@ -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,9 +195,16 @@ function WishlistDetail({ wishlistId, onNavigate, onRefresh, boardId, onClose, p
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleCloseDetail = () => {
|
const handleCloseDetail = (skipHistoryBack = false) => {
|
||||||
|
// Если skipHistoryBack = true (например, при навигации на форму редактирования),
|
||||||
|
// просто закрываем модальное окно без history.back()
|
||||||
|
if (!skipHistoryBack && historyPushedForTaskRef.current) {
|
||||||
|
window.history.back()
|
||||||
|
} else {
|
||||||
|
historyPushedForTaskRef.current = false
|
||||||
setSelectedTaskForDetail(null)
|
setSelectedTaskForDetail(null)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Добавляем запись в историю при открытии модальных окон и обрабатываем "назад"
|
// Добавляем запись в историю при открытии модальных окон и обрабатываем "назад"
|
||||||
const historyPushedForWishlistRef = useRef(false)
|
const historyPushedForWishlistRef = useRef(false)
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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 (
|
||||||
|
|||||||
@@ -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="Закрыть"
|
||||||
>
|
>
|
||||||
|
|||||||
Reference in New Issue
Block a user