From 43df4d76ce6c5d379afe00973dcfcd996842b5f2 Mon Sep 17 00:00:00 2001 From: poignatov Date: Wed, 4 Feb 2026 14:09:48 +0300 Subject: [PATCH] =?UTF-8?q?4.13.3:=20=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=BE=D0=B1=D1=80=D0=B0=D0=B1=D0=BE?= =?UTF-8?q?=D1=82=D0=BA=D0=B0=20=D0=BA=D0=BD=D0=BE=D0=BF=D0=BA=D0=B8=20?= =?UTF-8?q?=D0=BD=D0=B0=D0=B7=D0=B0=D0=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- VERSION | 2 +- play-life-web/package.json | 2 +- play-life-web/src/App.jsx | 14 ++++ play-life-web/src/components/TaskList.jsx | 44 ++++++++++ .../src/components/WishlistDetail.jsx | 83 ++++++++++++++++++- 5 files changed, 142 insertions(+), 3 deletions(-) diff --git a/VERSION b/VERSION index 650edfe..89c318c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.13.2 +4.13.3 diff --git a/play-life-web/package.json b/play-life-web/package.json index 5e5612d..e576897 100644 --- a/play-life-web/package.json +++ b/play-life-web/package.json @@ -1,6 +1,6 @@ { "name": "play-life-web", - "version": "4.13.2", + "version": "4.13.3", "type": "module", "scripts": { "dev": "vite", diff --git a/play-life-web/src/App.jsx b/play-life-web/src/App.jsx index 5669258..f7d1d2f 100644 --- a/play-life-web/src/App.jsx +++ b/play-life-web/src/App.jsx @@ -591,6 +591,20 @@ function AppContent() { // Обработчик кнопки "назад" в браузере (только для глубоких табов) useEffect(() => { const handlePopState = (event) => { + // Проверяем, есть ли открытые модальные окна в DOM + const taskDetailModal = document.querySelector('.task-detail-modal-overlay') + const wishlistDetailModal = document.querySelector('.wishlist-detail-modal-overlay') + + // Если есть открытые модальные окна, не обрабатываем здесь - компоненты сами закроют их + if (taskDetailModal || wishlistDetailModal) { + return + } + + // Если это модальное окно, не обрабатываем здесь - компоненты сами закроют его + if (event.state && event.state.modalOpen) { + return + } + const validTabs = ['current', 'priorities', 'full', 'words', 'add-words', 'dictionaries', 'test', 'tasks', 'task-form', 'wishlist', 'wishlist-form', 'wishlist-detail', 'profile', 'todoist-integration', 'telegram-integration'] // Проверяем state текущей записи истории (куда мы вернулись) diff --git a/play-life-web/src/components/TaskList.jsx b/play-life-web/src/components/TaskList.jsx index 0d7a325..82d9ef9 100644 --- a/play-life-web/src/components/TaskList.jsx +++ b/play-life-web/src/components/TaskList.jsx @@ -72,6 +72,50 @@ function TaskList({ onNavigate, data, loading, backgroundLoading, error, onRetry setSelectedTaskForDetail(null) } + // Добавляем запись в историю при открытии модального окна и обрабатываем "назад" + const historyPushedRef = useRef(false) + const selectedTaskForDetailRef = useRef(selectedTaskForDetail) + + // Обновляем ref при изменении значения + useEffect(() => { + selectedTaskForDetailRef.current = selectedTaskForDetail + }, [selectedTaskForDetail]) + + useEffect(() => { + if (selectedTaskForDetail && !historyPushedRef.current) { + // Добавляем запись в историю при открытии модального окна + window.history.pushState({ modalOpen: true, type: 'task-detail' }, '', window.location.href) + historyPushedRef.current = true + } else if (!selectedTaskForDetail) { + historyPushedRef.current = false + } + + if (!selectedTaskForDetail) return + + const handlePopState = (event) => { + // Проверяем наличие модального окна в DOM + const taskDetailModal = document.querySelector('.task-detail-modal-overlay') + + // Используем ref для получения актуального состояния + const currentTaskDetail = selectedTaskForDetailRef.current + + // Проверяем, открыто ли модальное окно (по состоянию или в DOM) + if (currentTaskDetail || taskDetailModal) { + // Закрываем модальное окно + setSelectedTaskForDetail(null) + historyPushedRef.current = false + // Предотвращаем дальнейшую обработку в App.jsx + // Следующее нажатие "назад" обработается App.jsx нормально + return + } + } + + window.addEventListener('popstate', handlePopState) + return () => { + window.removeEventListener('popstate', handlePopState) + } + }, [selectedTaskForDetail]) + // Функция для вычисления следующей даты по repetition_date diff --git a/play-life-web/src/components/WishlistDetail.jsx b/play-life-web/src/components/WishlistDetail.jsx index 82f129e..e0ff084 100644 --- a/play-life-web/src/components/WishlistDetail.jsx +++ b/play-life-web/src/components/WishlistDetail.jsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect, useCallback } from 'react' +import React, { useState, useEffect, useCallback, useRef } from 'react' import { useAuth } from './auth/AuthContext' import TaskDetail from './TaskDetail' import LoadingError from './LoadingError' @@ -160,6 +160,87 @@ function WishlistDetail({ wishlistId, onNavigate, onRefresh, boardId, onClose, p setSelectedTaskForDetail(null) } + // Добавляем запись в историю при открытии модальных окон и обрабатываем "назад" + const historyPushedForWishlistRef = useRef(false) + const historyPushedForTaskRef = useRef(false) + const wishlistIdRef = useRef(wishlistId) + const selectedTaskForDetailRef = useRef(selectedTaskForDetail) + + // Обновляем refs при изменении значений + useEffect(() => { + wishlistIdRef.current = wishlistId + selectedTaskForDetailRef.current = selectedTaskForDetail + }, [wishlistId, selectedTaskForDetail]) + + useEffect(() => { + if (wishlistId && !historyPushedForWishlistRef.current) { + // Добавляем запись в историю при открытии модального окна WishlistDetail + window.history.pushState({ modalOpen: true, type: 'wishlist-detail' }, '', window.location.href) + historyPushedForWishlistRef.current = true + } else if (!wishlistId) { + historyPushedForWishlistRef.current = false + } + + if (selectedTaskForDetail && !historyPushedForTaskRef.current) { + // Добавляем запись в историю при открытии вложенного модального окна TaskDetail + window.history.pushState({ modalOpen: true, type: 'task-detail', nested: true }, '', window.location.href) + historyPushedForTaskRef.current = true + } else if (!selectedTaskForDetail) { + historyPushedForTaskRef.current = false + } + + if (!wishlistId && !selectedTaskForDetail) return + + const handlePopState = (event) => { + // Проверяем наличие модальных окон в DOM + const taskDetailModal = document.querySelector('.task-detail-modal-overlay') + const wishlistDetailModal = document.querySelector('.wishlist-detail-modal-overlay') + + // Используем refs для получения актуального состояния + const currentTaskDetail = selectedTaskForDetailRef.current + const currentWishlistId = wishlistIdRef.current + + // Сначала проверяем вложенное модальное окно TaskDetail + if (currentTaskDetail || taskDetailModal) { + setSelectedTaskForDetail(null) + historyPushedForTaskRef.current = false + // Возвращаем запись для WishlistDetail + if (currentWishlistId || wishlistDetailModal) { + window.history.pushState({ modalOpen: true, type: 'wishlist-detail' }, '', window.location.href) + } + return + } + + // Если открыто модальное окно WishlistDetail, закрываем его + if (currentWishlistId || wishlistDetailModal) { + if (onClose) { + onClose() + } else { + // Возвращаемся на предыдущий таб, если он был сохранен, иначе на wishlist + if (previousTab) { + if (boardId) { + onNavigate?.(previousTab, { boardId }) + } else { + onNavigate?.(previousTab) + } + } else if (boardId) { + onNavigate?.('wishlist', { boardId }) + } else { + onNavigate?.('wishlist') + } + } + historyPushedForWishlistRef.current = false + // Следующее нажатие "назад" обработается App.jsx нормально + return + } + } + + window.addEventListener('popstate', handlePopState) + return () => { + window.removeEventListener('popstate', handlePopState) + } + }, [wishlistId, selectedTaskForDetail, onClose, onNavigate, previousTab, boardId]) + const handleClose = () => { // Используем onClose если передан, иначе возвращаемся на wishlist if (onClose) {