feat: добавлен раздел 'Бесконечные' для задач с периодичностью 0
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 45s
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 45s
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "play-life-web",
|
"name": "play-life-web",
|
||||||
"version": "2.9.0",
|
"version": "2.10.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -15,6 +15,15 @@ function TaskList({ onNavigate, data, loading, backgroundLoading, onRefresh }) {
|
|||||||
const [selectedTaskForDetail, setSelectedTaskForDetail] = useState(null)
|
const [selectedTaskForDetail, setSelectedTaskForDetail] = useState(null)
|
||||||
const [isCompleting, setIsCompleting] = useState(false)
|
const [isCompleting, setIsCompleting] = useState(false)
|
||||||
const [expandedCompleted, setExpandedCompleted] = useState({})
|
const [expandedCompleted, setExpandedCompleted] = useState({})
|
||||||
|
// Загружаем состояние раскрытия "Бесконечные" из localStorage (по умолчанию true)
|
||||||
|
const [expandedInfinite, setExpandedInfinite] = useState(() => {
|
||||||
|
try {
|
||||||
|
const saved = localStorage.getItem('taskList_expandedInfinite')
|
||||||
|
return saved ? JSON.parse(saved) : {}
|
||||||
|
} catch {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
})
|
||||||
const [toast, setToast] = useState(null)
|
const [toast, setToast] = useState(null)
|
||||||
|
|
||||||
// Для отслеживания изменений в списке задач (чтобы не перезагружать детали без необходимости)
|
// Для отслеживания изменений в списке задач (чтобы не перезагружать детали без необходимости)
|
||||||
@@ -149,6 +158,22 @@ function TaskList({ onNavigate, data, loading, backgroundLoading, onRefresh }) {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const toggleInfiniteExpanded = (projectName) => {
|
||||||
|
setExpandedInfinite(prev => {
|
||||||
|
const newState = {
|
||||||
|
...prev,
|
||||||
|
[projectName]: !prev[projectName]
|
||||||
|
}
|
||||||
|
// Сохраняем в localStorage
|
||||||
|
try {
|
||||||
|
localStorage.setItem('taskList_expandedInfinite', JSON.stringify(newState))
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error saving expandedInfinite to localStorage:', err)
|
||||||
|
}
|
||||||
|
return newState
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Получаем все проекты из наград задачи и подзадач
|
// Получаем все проекты из наград задачи и подзадач
|
||||||
const getTaskProjects = (task) => {
|
const getTaskProjects = (task) => {
|
||||||
const projects = new Set()
|
const projects = new Set()
|
||||||
@@ -256,9 +281,11 @@ function TaskList({ onNavigate, data, loading, backgroundLoading, onRefresh }) {
|
|||||||
|
|
||||||
// Определяем, в какую группу попадает задача
|
// Определяем, в какую группу попадает задача
|
||||||
let isCompleted = false
|
let isCompleted = false
|
||||||
|
let isInfinite = false
|
||||||
|
|
||||||
// Если у задачи период повторения = 0, она всегда в невыполненных
|
// Если у задачи период повторения = 0, она в бесконечных
|
||||||
if (task.repetition_period && isZeroPeriod(task.repetition_period)) {
|
if (task.repetition_period && isZeroPeriod(task.repetition_period)) {
|
||||||
|
isInfinite = true
|
||||||
isCompleted = false
|
isCompleted = false
|
||||||
} else if (task.repetition_period) {
|
} else if (task.repetition_period) {
|
||||||
// Если есть repetition_period (и он не 0), проверяем логику повторения
|
// Если есть repetition_period (и он не 0), проверяем логику повторения
|
||||||
@@ -297,11 +324,14 @@ function TaskList({ onNavigate, data, loading, backgroundLoading, onRefresh }) {
|
|||||||
if (!groups[projectName]) {
|
if (!groups[projectName]) {
|
||||||
groups[projectName] = {
|
groups[projectName] = {
|
||||||
notCompleted: [],
|
notCompleted: [],
|
||||||
completed: []
|
completed: [],
|
||||||
|
infinite: []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isCompleted) {
|
if (isInfinite) {
|
||||||
|
groups[projectName].infinite.push(task)
|
||||||
|
} else if (isCompleted) {
|
||||||
groups[projectName].completed.push(task)
|
groups[projectName].completed.push(task)
|
||||||
} else {
|
} else {
|
||||||
groups[projectName].notCompleted.push(task)
|
groups[projectName].notCompleted.push(task)
|
||||||
@@ -391,7 +421,12 @@ function TaskList({ onNavigate, data, loading, backgroundLoading, onRefresh }) {
|
|||||||
{projectNames.map(projectName => {
|
{projectNames.map(projectName => {
|
||||||
const group = groupedTasks[projectName]
|
const group = groupedTasks[projectName]
|
||||||
const hasCompleted = group.completed.length > 0
|
const hasCompleted = group.completed.length > 0
|
||||||
const isExpanded = expandedCompleted[projectName]
|
const hasInfinite = group.infinite.length > 0
|
||||||
|
const isCompletedExpanded = expandedCompleted[projectName]
|
||||||
|
// По умолчанию бесконечные раскрыты (true), если не сохранено иное
|
||||||
|
const isInfiniteExpanded = expandedInfinite[projectName] !== undefined
|
||||||
|
? expandedInfinite[projectName]
|
||||||
|
: true
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={projectName} className="project-group">
|
<div key={projectName} className="project-group">
|
||||||
@@ -405,6 +440,25 @@ function TaskList({ onNavigate, data, loading, backgroundLoading, onRefresh }) {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{hasInfinite && (
|
||||||
|
<div className="completed-section">
|
||||||
|
<button
|
||||||
|
className="completed-toggle"
|
||||||
|
onClick={() => toggleInfiniteExpanded(projectName)}
|
||||||
|
>
|
||||||
|
<span className="completed-toggle-icon">
|
||||||
|
{isInfiniteExpanded ? '▼' : '▶'}
|
||||||
|
</span>
|
||||||
|
<span>Бесконечные ({group.infinite.length})</span>
|
||||||
|
</button>
|
||||||
|
{isInfiniteExpanded && (
|
||||||
|
<div className="task-group completed-tasks">
|
||||||
|
{group.infinite.map(renderTaskItem)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{hasCompleted && (
|
{hasCompleted && (
|
||||||
<div className="completed-section">
|
<div className="completed-section">
|
||||||
<button
|
<button
|
||||||
@@ -412,11 +466,11 @@ function TaskList({ onNavigate, data, loading, backgroundLoading, onRefresh }) {
|
|||||||
onClick={() => toggleCompletedExpanded(projectName)}
|
onClick={() => toggleCompletedExpanded(projectName)}
|
||||||
>
|
>
|
||||||
<span className="completed-toggle-icon">
|
<span className="completed-toggle-icon">
|
||||||
{isExpanded ? '▼' : '▶'}
|
{isCompletedExpanded ? '▼' : '▶'}
|
||||||
</span>
|
</span>
|
||||||
<span>Выполненные ({group.completed.length})</span>
|
<span>Выполненные ({group.completed.length})</span>
|
||||||
</button>
|
</button>
|
||||||
{isExpanded && (
|
{isCompletedExpanded && (
|
||||||
<div className="task-group completed-tasks">
|
<div className="task-group completed-tasks">
|
||||||
{group.completed.map(renderTaskItem)}
|
{group.completed.map(renderTaskItem)}
|
||||||
</div>
|
</div>
|
||||||
@@ -424,7 +478,7 @@ function TaskList({ onNavigate, data, loading, backgroundLoading, onRefresh }) {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{group.notCompleted.length === 0 && !hasCompleted && (
|
{group.notCompleted.length === 0 && !hasCompleted && !hasInfinite && (
|
||||||
<div className="empty-group">Нет задач в этой группе</div>
|
<div className="empty-group">Нет задач в этой группе</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user