6.15.6: Открытие редактирования задачи из статистики
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 1m6s

This commit is contained in:
poignatov
2026-03-13 15:49:09 +03:00
parent 06b7c614ed
commit 193b4138d9
3 changed files with 70 additions and 61 deletions

View File

@@ -1 +1 @@
6.15.5 6.15.6

View File

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

View File

@@ -1,6 +1,7 @@
import React, { useState } from 'react' import React, { useState, useEffect, useRef } from 'react'
import LoadingError from './LoadingError' import LoadingError from './LoadingError'
import { useAuth } from './auth/AuthContext' import { useAuth } from './auth/AuthContext'
import TaskDetail from './TaskDetail'
// Функция для форматирования скорa (аналогично formatScore из TaskDetail) // Функция для форматирования скорa (аналогично formatScore из TaskDetail)
const formatScore = (num) => { const formatScore = (num) => {
@@ -134,7 +135,56 @@ const formatEntryText = (text, nodes) => {
function TodayEntriesList({ data, loading, error, onRetry, onDelete }) { function TodayEntriesList({ data, loading, error, onRetry, onDelete }) {
const { authFetch } = useAuth() const { authFetch } = useAuth()
const [deletingIds, setDeletingIds] = useState(new Set()) const [deletingIds, setDeletingIds] = useState(new Set())
const [clearingAutoCompleteIds, setClearingAutoCompleteIds] = useState(new Set()) const [selectedTaskId, setSelectedTaskId] = useState(null)
const selectedTaskIdRef = useRef(null)
const historyPushedRef = useRef(false)
// Обновляем ref при изменении selectedTaskId
useEffect(() => {
selectedTaskIdRef.current = selectedTaskId
}, [selectedTaskId])
// Управление историей браузера при открытии/закрытии TaskDetail
useEffect(() => {
if (selectedTaskId && !historyPushedRef.current) {
window.history.pushState({ modalOpen: true, type: 'task-detail-statistics' }, '', window.location.href)
historyPushedRef.current = true
} else if (!selectedTaskId) {
historyPushedRef.current = false
}
if (!selectedTaskId) return
const handlePopState = () => {
if (selectedTaskIdRef.current) {
setSelectedTaskId(null)
historyPushedRef.current = false
}
}
window.addEventListener('popstate', handlePopState)
return () => {
window.removeEventListener('popstate', handlePopState)
}
}, [selectedTaskId])
const handleOpenTaskDetail = (taskId) => {
setSelectedTaskId(taskId)
}
const handleCloseTaskDetail = () => {
if (historyPushedRef.current) {
window.history.back()
} else {
setSelectedTaskId(null)
}
}
const handleTaskSaved = () => {
if (onDelete) {
onDelete()
}
}
const handleDelete = async (entryId) => { const handleDelete = async (entryId) => {
if (deletingIds.has(entryId)) return if (deletingIds.has(entryId)) return
@@ -175,45 +225,6 @@ function TodayEntriesList({ data, loading, error, onRetry, onDelete }) {
} }
} }
const handleClearAutoComplete = async (taskId) => {
if (clearingAutoCompleteIds.has(taskId)) return
if (!window.confirm('Снять автовыполнение в конце дня? Задача не будет выполнена автоматически.')) {
return
}
setClearingAutoCompleteIds(prev => new Set(prev).add(taskId))
try {
const response = await authFetch(`/api/tasks/${taskId}/draft`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ auto_complete: false }),
})
if (!response.ok) {
const errorText = await response.text()
console.error('Clear auto_complete error:', response.status, errorText)
throw new Error(`Ошибка: ${response.status}`)
}
if (onDelete) {
onDelete()
}
} catch (err) {
console.error('Clear auto_complete failed:', err)
alert(err.message || 'Не удалось снять автовыполнение')
} finally {
setClearingAutoCompleteIds(prev => {
const next = new Set(prev)
next.delete(taskId)
return next
})
}
}
if (loading) { if (loading) {
return ( return (
<div className="flex justify-center items-center py-8"> <div className="flex justify-center items-center py-8">
@@ -235,6 +246,7 @@ function TodayEntriesList({ data, loading, error, onRetry, onDelete }) {
} }
return ( return (
<>
<div className="mt-2 mb-6"> <div className="mt-2 mb-6">
<div className="space-y-3"> <div className="space-y-3">
{data.map((entry) => { {data.map((entry) => {
@@ -248,9 +260,8 @@ function TodayEntriesList({ data, loading, error, onRetry, onDelete }) {
> >
{isDraft ? ( {isDraft ? (
<button <button
onClick={() => handleClearAutoComplete(entry.task_id)} onClick={() => handleOpenTaskDetail(entry.task_id)}
disabled={clearingAutoCompleteIds.has(entry.task_id)} className="absolute top-4 right-4"
className="absolute top-4 right-4 disabled:opacity-50 disabled:cursor-not-allowed"
style={{ style={{
color: '#3b82f6', color: '#3b82f6',
background: 'none', background: 'none',
@@ -264,29 +275,19 @@ function TodayEntriesList({ data, loading, error, onRetry, onDelete }) {
width: '24px', width: '24px',
height: '24px', height: '24px',
transition: 'all 0.2s', transition: 'all 0.2s',
opacity: clearingAutoCompleteIds.has(entry.task_id) ? 0.5 : 1,
zIndex: 10 zIndex: 10
}} }}
onMouseEnter={(e) => { onMouseEnter={(e) => {
if (!clearingAutoCompleteIds.has(entry.task_id)) { e.currentTarget.style.backgroundColor = '#eff6ff'
e.currentTarget.style.backgroundColor = '#eff6ff'
}
}} }}
onMouseLeave={(e) => { onMouseLeave={(e) => {
e.currentTarget.style.backgroundColor = 'transparent' e.currentTarget.style.backgroundColor = 'transparent'
}} }}
title="Снять автовыполнение в конце дня" title="Редактировать задачу"
> >
{clearingAutoCompleteIds.has(entry.task_id) ? ( <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" title="Автовыполнение в конце дня">
<svg className="w-5 h-5 animate-spin" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"> <path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"></path>
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle> </svg>
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
) : (
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" title="Автовыполнение в конце дня">
<path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"></path>
</svg>
)}
</button> </button>
) : ( ) : (
<button <button
@@ -353,6 +354,14 @@ function TodayEntriesList({ data, loading, error, onRetry, onDelete }) {
})} })}
</div> </div>
</div> </div>
{selectedTaskId && (
<TaskDetail
taskId={selectedTaskId}
onClose={handleCloseTaskDetail}
onRefresh={handleTaskSaved}
/>
)}
</>
) )
} }