Files
play-life/play-life-web/src/components/FullStatistics.jsx
poignatov e41abb2bff
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 1m4s
Перезагрузка списка записей при открытии экрана прогресса
2026-02-24 15:57:13 +03:00

203 lines
8.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React, { useState, useEffect, useCallback } from 'react'
import WeekProgressChart from './WeekProgressChart'
import LoadingError from './LoadingError'
import TodayEntriesList from './TodayEntriesList'
import { getAllProjectsSorted } from '../utils/projectUtils'
import './Integrations.css'
// Экспортируем для обратной совместимости (если используется в других местах)
export { getProjectColorByIndex } from '../utils/projectUtils'
// Функция для получения дат текущей недели (понедельник - воскресенье)
const getCurrentWeekDates = () => {
const now = new Date()
const day = now.getDay()
// Вычисляем разницу до понедельника (1 = понедельник, 0 = воскресенье)
const diff = day === 0 ? -6 : 1 - day
const monday = new Date(now)
monday.setDate(now.getDate() + diff)
const dates = []
for (let i = 0; i < 7; i++) {
const date = new Date(monday)
date.setDate(monday.getDate() + i)
dates.push(date)
}
return dates
}
// Функция для форматирования даты в YYYY-MM-DD
const formatDate = (date) => {
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`
}
// Названия дней недели
const dayNames = ['пн', 'вт', 'ср', 'чт', 'пт', 'сб', 'вс']
function FullStatistics({ selectedProject, onClearSelection, data, loading, error, onRetry, currentWeekData, onNavigate, todayEntries, todayEntriesLoading, todayEntriesError, onRetryTodayEntries, fetchTodayEntries, activeTab }) {
const [selectedDate, setSelectedDate] = useState(null)
const prevActiveTabRef = React.useRef(activeTab)
const componentJustOpenedRef = React.useRef(false)
// Получаем даты текущей недели
const weekDates = getCurrentWeekDates()
// Определяем текущий день (используем useMemo для стабильности)
const today = React.useMemo(() => {
const date = new Date()
date.setHours(0, 0, 0, 0)
return date
}, [])
// Получаем строковое представление сегодняшней даты
const todayDateStr = React.useMemo(() => formatDate(today), [today])
// Фильтруем только прошедшие дни (включая сегодня)
const pastDays = weekDates.filter((date) => {
const dateOnly = new Date(date)
dateOnly.setHours(0, 0, 0, 0)
return dateOnly <= today
})
// Отслеживаем выход с экрана и сбрасываем выбор дня
useEffect(() => {
// Если мы были на экране full и перешли на другой экран - сбрасываем выбор дня
if (prevActiveTabRef.current === 'full' && activeTab !== 'full') {
setSelectedDate(todayDateStr)
}
}, [activeTab, todayDateStr])
// Инициализируем выбранную дату текущим днем при первом рендере
// Также проверяем, что выбранная дата все еще в списке доступных дней
useEffect(() => {
const pastDaysDateStrs = pastDays.map(date => formatDate(date))
if (selectedDate === null) {
// Первая инициализация - устанавливаем текущий день
setSelectedDate(todayDateStr)
} else if (!pastDaysDateStrs.includes(selectedDate)) {
// Если выбранная дата больше не в списке доступных (например, прошла неделя)
// Сбрасываем на текущий день
setSelectedDate(todayDateStr)
}
}, [selectedDate, todayDateStr, pastDays])
// Отслеживаем открытие компонента
useEffect(() => {
// Когда компонент открывается (activeTab становится 'full'), помечаем это
if (activeTab === 'full' && prevActiveTabRef.current !== 'full') {
componentJustOpenedRef.current = true
}
prevActiveTabRef.current = activeTab
}, [activeTab])
// Загружаем данные при открытии экрана, при изменении selectedDate или selectedProject
useEffect(() => {
if (activeTab === 'full' && selectedDate && fetchTodayEntries) {
// Если компонент только что открылся - используем фоновую загрузку
if (componentJustOpenedRef.current) {
componentJustOpenedRef.current = false
fetchTodayEntries(true, selectedProject, selectedDate)
} else {
// При изменении даты или проекта - используем обычную загрузку (не фоновую)
fetchTodayEntries(false, selectedProject, selectedDate)
}
}
}, [activeTab, selectedDate, selectedProject, fetchTodayEntries])
// Обработчик выбора дня
const handleDaySelect = useCallback((date) => {
const dateStr = formatDate(date)
setSelectedDate(dateStr)
// Загрузка данных произойдет автоматически через useEffect выше
}, [])
if (error && (!data || data.length === 0) && !loading) {
return <LoadingError onRetry={onRetry} />
}
return (
<div className="max-w-2xl mx-auto">
{onNavigate && (
<button
onClick={() => {
// Сбрасываем выбор дня перед выходом с экрана
setSelectedDate(todayDateStr)
window.history.back()
}}
className="close-x-button"
title="Закрыть"
>
</button>
)}
{loading && (!data || data.length === 0) && (!todayEntries || (Array.isArray(todayEntries) && todayEntries.length === 0)) ? (
<div className="fixed inset-0 flex justify-center items-center">
<div className="flex flex-col items-center">
<div className="w-12 h-12 border-4 border-indigo-200 border-t-indigo-600 rounded-full animate-spin mb-4"></div>
<div className="text-gray-600 font-medium">Загрузка...</div>
</div>
</div>
) : (!data || data.length === 0) && !todayEntries ? (
<div className="flex justify-center items-center py-16">
<div className="text-gray-500 text-lg">Нет данных для отображения</div>
</div>
) : (
<>
<WeekProgressChart data={data} allProjectsSorted={getAllProjectsSorted(data)} currentWeekData={currentWeekData} selectedProject={selectedProject} />
{/* Чипсы дней недели */}
{pastDays.length > 0 && (
<div className="mt-3 mb-2">
<div className="flex flex-wrap gap-2.5">
{pastDays.map((date, index) => {
const dateStr = formatDate(date)
const dayOfWeek = index + 1 // 1 = понедельник
const isSelected = selectedDate === dateStr
const isToday = dateStr === todayDateStr
return (
<button
key={dateStr}
onClick={() => handleDaySelect(date)}
className={`
h-9 px-4 rounded-lg text-sm font-semibold
transition-all duration-200 ease-in-out
flex items-center justify-center
${
isSelected
? 'bg-white text-gray-900 shadow-sm border border-gray-200'
: 'bg-transparent text-gray-700 border border-gray-300 hover:border-gray-400'
}
${isToday && !isSelected ? 'ring-2 ring-indigo-200 border-indigo-300' : ''}
active:scale-95
`}
>
{dayNames[dayOfWeek - 1]}
</button>
)
})}
</div>
</div>
)}
<TodayEntriesList
data={todayEntries}
loading={todayEntriesLoading}
error={todayEntriesError}
onRetry={() => fetchTodayEntries && fetchTodayEntries(false, selectedProject, selectedDate)}
onDelete={() => fetchTodayEntries && fetchTodayEntries(false, selectedProject, selectedDate)}
/>
</>
)}
</div>
)
}
export default FullStatistics