From f8b33ddbd5f11be9104c32c82a3ff08bba2c3fbb Mon Sep 17 00:00:00 2001 From: Tatyana Date: Fri, 5 Sep 2025 15:50:38 +0300 Subject: [PATCH] =?UTF-8?q?=D0=B7=D0=B0=D0=B2=D0=B5=D1=80=D1=88=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D0=B4=D0=BD=D1=8F=20=D1=81=20=D1=83=D0=BF?= =?UTF-8?q?=D1=80=D0=B0=D0=B6=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F=D0=BC=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/CourseExercises.tsx | 9 ++- src/pages/Exercise.tsx | 111 ++++++++++++++++++++-------------- 2 files changed, 74 insertions(+), 46 deletions(-) diff --git a/src/pages/CourseExercises.tsx b/src/pages/CourseExercises.tsx index 196565a..e7b05d5 100644 --- a/src/pages/CourseExercises.tsx +++ b/src/pages/CourseExercises.tsx @@ -77,14 +77,21 @@ export const CourseExercises = () => { } }, [course_exercises]) - const uniqueDays = Array.from(new Set(course_exercises.map((ex) => ex.day))).sort((a, b) => a - b) + + + + + + const uniqueDays = Array.from(new Set(course_exercises.map((ex) => ex.day))).sort((a, b) => a - b) const dayMap: { [key: number]: number } = {} uniqueDays.forEach((day, index) => { dayMap[day] = index + 1 }) + console.log('Уникальные дни', uniqueDays) + const daysNav = uniqueDays.map((day) => dayMap[day]) const days = Array.from(new Set(course_exercises.map((ex) => ex.day))).sort((a, b) => a - b) diff --git a/src/pages/Exercise.tsx b/src/pages/Exercise.tsx index 4fb05db..44ae574 100644 --- a/src/pages/Exercise.tsx +++ b/src/pages/Exercise.tsx @@ -10,6 +10,8 @@ import { RefreshIcon } from "../components/icons/RefreshIcon" import HeaderNav from "../components/HeaderNav" import BottomNavigation from "../components/BottomNavigation" +import type { CourseExercises } from "./CourseExercises" + // Импортируем функцию для связи с сервером (бэкендом) import { connect } from "../confconnect" @@ -39,7 +41,7 @@ export const Exercise = () => { const { courseId, exerciseId, exerciseIndex } = useParams() const location = useLocation() - const [courseExercises, setCourseExercises] = useState([]) + const [course_exercises, setCourseExercises] = useState([]) const [actualExerciseId, setActualExerciseId] = useState("") const [currentDay, setCurrentDay] = useState(null) @@ -68,6 +70,10 @@ export const Exercise = () => { const [totalRestTime] = useState(60) const [isRestPaused, setIsRestPaused] = useState(false) + // ========== НОВЫЕ СОСТОЯНИЯ ДЛЯ ЗАВЕРШЕНИЯ ДНЯ ========== + const [completedExercisesInDay, setCompletedExercisesInDay] = useState(0) // Сколько упражнений уже завершено в текущем дне + const [totalExercisesInDay, setTotalExercisesInDay] = useState(0) // Общее количество упражнений в текущем дне + useEffect(() => { const loadCourseExercises = async () => { if (!courseId) return @@ -114,6 +120,26 @@ export const Exercise = () => { setLoading(false) return } + + const exercisesForCurrentDay = exercises.filter((ex: any) => ex.day === fixedDay) + setTotalExercisesInDay(exercisesForCurrentDay.length) + + // Подсчитываем завершенные упражнения из localStorage + let completedCount = 0 + exercisesForCurrentDay.forEach((ex: any) => { + const storageKey = `exerciseProgress_${courseId}_${ex.id_exercise}_day_${fixedDay}` + const savedProgress = localStorage.getItem(storageKey) + if (savedProgress) { + const progress = JSON.parse(savedProgress) + if (progress.status === 1) { + // 1 означает полностью завершено + completedCount++ + } + } + }) + setCompletedExercisesInDay(completedCount) + + console.log(`[v0] День ${fixedDay}: завершено ${completedCount} из ${exercisesForCurrentDay.length} упражнений`) } catch (error) { console.error("Ошибка при загрузке упражнений курса:", error) setError("Ошибка при загрузке упражнений") @@ -124,7 +150,6 @@ export const Exercise = () => { loadCourseExercises() }, [courseId, exerciseId, exerciseIndex, location.search]) - // ========== ЗАГРУЗКА ДАННЫХ УПРАЖНЕНИЯ С СЕРВЕРА ========== useEffect(() => { if (!actualExerciseId || !courseId) return @@ -181,7 +206,6 @@ export const Exercise = () => { }) }, [courseId, actualExerciseId]) - // ========== ФУНКЦИЯ ЗАГРУЗКИ ПРОГРЕССА С СЕРВЕРА ========== const loadProgressFromServer = async () => { try { console.log(`Загружаем прогресс для курса ${courseId}, упражнения ${actualExerciseId}, день ${currentDay}`) @@ -273,7 +297,6 @@ export const Exercise = () => { } } - // ========== ФУНКЦИЯ КОНВЕРТАЦИИ ВРЕМЕНИ ИЗ MM:SS В СЕКУНДЫ ========== const convertTimeToSeconds = (timeString: string): number => { try { const parts = timeString.split(":") @@ -295,7 +318,6 @@ export const Exercise = () => { } } - // ========== ФУНКЦИЯ СОХРАНЕНИЯ ПРОГРЕССА ПОДХОДА НА СЕРВЕР ========== const saveSetProgress = async (setNumber: number, timeString: string, status: number) => { try { const dayToSave = currentDay || 1 @@ -311,18 +333,20 @@ export const Exercise = () => { day: dayToSave, } - console.log("[v0] FINAL DATA TO SERVER:", progressData) + console.log("FINAL DATA TO SERVER:", progressData) const response = await connect.post(`pacient/${courseId}/${actualExerciseId}`, progressData) if (response.status === 200 || response.status === 201) { - console.log("[v0] SUCCESS: Progress saved to server for day", dayToSave) + console.log("SUCCESS: Progress saved to server for day", dayToSave) } } catch (error) { console.error("Ошибка при сохранении прогресса на сервер:", error) } } + + const goToNextExercise = () => { console.log("Переходим к следующему упражнению") @@ -340,7 +364,6 @@ export const Exercise = () => { } } - // ========== ФУНКЦИЯ ЗАВЕРШЕНИЯ ТЕКУЩЕГО ПОДХОДА ========== const handleCompleteSet = async () => { console.log("Пользователь завершает подход", currentSet, "из", totalSets) @@ -365,7 +388,6 @@ export const Exercise = () => { } } - // ========== ФУНКЦИЯ ПОЛНОГО ЗАВЕРШЕНИЯ УПРАЖНЕНИЯ ========== const handleComplete = async (completedSetsArray = completedSets) => { console.log("УПРАЖНЕНИЕ ПОЛНОСТЬЮ ЗАВЕРШЕНО! Все подходы выполнены.") @@ -381,13 +403,15 @@ export const Exercise = () => { day: currentDay, position: totalTime, set: totalSets, - status: 1, + status: 1, // 1 = полностью завершено totalTime: totalTime, completedSets: completedSetsArray, completedAt: new Date().toISOString(), }), ) + setCompletedExercisesInDay((prev) => prev + 1) + setIsCompleted(true) setCurrentTime(totalTime) setIsPlaying(false) @@ -397,7 +421,6 @@ export const Exercise = () => { setCompletedSets(completedSetsArray) } - // ========== ФУНКЦИЯ ПАУЗЫ И СОХРАНЕНИЯ ПРОГРЕССА ========== const handlePause = async ( completedSetsArray = completedSets, setNumber = currentSet, @@ -432,7 +455,6 @@ export const Exercise = () => { setHasSavedProgress(true) } - // ========== ВОССТАНОВЛЕНИЕ ПРОГРЕССА ПРИ ЗАГРУЗКЕ СТРАНИЦЫ ========== useEffect(() => { const loadProgress = async () => { if (!actualExerciseId) return @@ -485,7 +507,6 @@ export const Exercise = () => { loadProgress() }, [courseId, actualExerciseId, currentDay, totalTime, totalSets]) - // ========== ОСНОВНОЙ ТАЙМЕР ДЛЯ УПРАЖНЕНИЯ ========== useEffect(() => { let interval: NodeJS.Timeout | undefined @@ -519,7 +540,6 @@ export const Exercise = () => { } }, [isPlaying, totalTime, isCompleted, isResting, currentSet, completedSets]) - // ========== ТАЙМЕР ДЛЯ ОТДЫХА МЕЖДУ ПОДХОДАМИ ========== useEffect(() => { let restInterval: NodeJS.Timeout | undefined @@ -553,7 +573,6 @@ export const Exercise = () => { } }, [isResting, restTime, isRestPaused, currentSet]) - // ========== ФУНКЦИИ ДЛЯ АНИМАЦИИ КНОПКИ СБРОСА ========== const handleClick = () => { console.log("Запускаем анимацию кнопки сброса") setIsRotating(true) @@ -564,17 +583,14 @@ export const Exercise = () => { setIsRotating(false) } - // ========== ФУНКЦИЯ ФОРМАТИРОВАНИЯ ВРЕМЕНИ ========== const formatTime = (seconds: number) => { const mins = Math.floor(seconds / 60) const secs = seconds % 60 return `${mins.toString().padStart(2, "0")}:${secs.toString().padStart(2, "0")}` } - // ========== РАСЧЕТ ПРОГРЕССА ДЛЯ ПОЛОСКИ ========== const progress = isResting ? ((totalRestTime - restTime) / totalRestTime) * 100 : (currentTime / totalTime) * 100 - // ========== ИКОНКИ ДЛЯ КНОПОК ========== const PlayIcon = () => ( @@ -602,7 +618,6 @@ export const Exercise = () => { ) - // ========== ИНФОРМАЦИЯ ОБ УПРАЖНЕНИИ ДЛЯ ОТОБРАЖЕНИЯ ========== const exerciseSteps = [ { title: "Описание упражнения", @@ -626,7 +641,7 @@ export const Exercise = () => { }, ] - // ========== ЭКРАНЫ ЗАГРУЗКИ И ОШИБОК ========== + if (loading) { return (
@@ -682,7 +697,6 @@ export const Exercise = () => { ) } - // ========== ОСНОВНОЙ ИНТЕРФЕЙС УПРАЖНЕНИЯ ========== return (
@@ -715,11 +729,10 @@ export const Exercise = () => { @@ -774,9 +787,8 @@ export const Exercise = () => { return (
{setNumber}
@@ -811,13 +823,12 @@ export const Exercise = () => {
{isCompleted @@ -834,13 +845,12 @@ export const Exercise = () => {
@@ -848,12 +858,25 @@ export const Exercise = () => {
{isCompleted ? ( <> - + {completedExercisesInDay + 1 >= totalExercisesInDay ? ( + + ) : ( + + )} +
Завершено @@ -866,11 +889,10 @@ export const Exercise = () => { setIsRestPaused(!isRestPaused) handlePause(completedSets, currentSet, true, restTime, !isRestPaused) }} - className={`flex-1 font-bold py-3 px-4 rounded-xl transition-all duration-300 flex items-center justify-center space-x-2 ${ - isRestPaused + className={`flex-1 font-bold py-3 px-4 rounded-xl transition-all duration-300 flex items-center justify-center space-x-2 ${isRestPaused ? "bg-yellow-500 hover:bg-yellow-600 text-white" : "bg-[#2BACBE] hover:bg-[#2099A8] text-white" - }`} + }`} > {isRestPaused ? ( <> @@ -910,11 +932,10 @@ export const Exercise = () => { setIsPlaying(false) } }} - className={`flex-1 font-bold py-3 px-4 rounded-xl transition-all duration-300 transform hover:scale-105 flex items-center justify-center space-x-2 cursor-pointer ${ - isPlaying + className={`flex-1 font-bold py-3 px-4 rounded-xl transition-all duration-300 transform hover:scale-105 flex items-center justify-center space-x-2 cursor-pointer ${isPlaying ? "bg-yellow-500 hover:bg-yellow-600 text-white shadow-lg" : "bg-[#2BACBE] hover:bg-[#2099A8] text-white shadow-lg" - }`} + }`} > {isPlaying ? ( <>