откат / не работает

This commit is contained in:
Tatyana 2025-09-05 16:01:22 +03:00
parent f8b33ddbd5
commit 5d75167fe8

View File

@ -41,6 +41,7 @@ export const Exercise = () => {
const { courseId, exerciseId, exerciseIndex } = useParams<RouteParams>() const { courseId, exerciseId, exerciseIndex } = useParams<RouteParams>()
const location = useLocation() const location = useLocation()
const [course_exercises, setCourseExercises] = useState<CourseExercises[]>([]) const [course_exercises, setCourseExercises] = useState<CourseExercises[]>([])
const [actualExerciseId, setActualExerciseId] = useState<string>("") const [actualExerciseId, setActualExerciseId] = useState<string>("")
const [currentDay, setCurrentDay] = useState<number | null>(null) const [currentDay, setCurrentDay] = useState<number | null>(null)
@ -70,10 +71,6 @@ export const Exercise = () => {
const [totalRestTime] = useState(60) const [totalRestTime] = useState(60)
const [isRestPaused, setIsRestPaused] = useState(false) const [isRestPaused, setIsRestPaused] = useState(false)
// ========== НОВЫЕ СОСТОЯНИЯ ДЛЯ ЗАВЕРШЕНИЯ ДНЯ ==========
const [completedExercisesInDay, setCompletedExercisesInDay] = useState(0) // Сколько упражнений уже завершено в текущем дне
const [totalExercisesInDay, setTotalExercisesInDay] = useState(0) // Общее количество упражнений в текущем дне
useEffect(() => { useEffect(() => {
const loadCourseExercises = async () => { const loadCourseExercises = async () => {
if (!courseId) return if (!courseId) return
@ -120,26 +117,6 @@ export const Exercise = () => {
setLoading(false) setLoading(false)
return 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) { } catch (error) {
console.error("Ошибка при загрузке упражнений курса:", error) console.error("Ошибка при загрузке упражнений курса:", error)
setError("Ошибка при загрузке упражнений") setError("Ошибка при загрузке упражнений")
@ -150,6 +127,7 @@ export const Exercise = () => {
loadCourseExercises() loadCourseExercises()
}, [courseId, exerciseId, exerciseIndex, location.search]) }, [courseId, exerciseId, exerciseIndex, location.search])
// ========== ЗАГРУЗКА ДАННЫХ УПРАЖНЕНИЯ С СЕРВЕРА ==========
useEffect(() => { useEffect(() => {
if (!actualExerciseId || !courseId) return if (!actualExerciseId || !courseId) return
@ -206,6 +184,7 @@ export const Exercise = () => {
}) })
}, [courseId, actualExerciseId]) }, [courseId, actualExerciseId])
// ========== ФУНКЦИЯ ЗАГРУЗКИ ПРОГРЕССА С СЕРВЕРА ==========
const loadProgressFromServer = async () => { const loadProgressFromServer = async () => {
try { try {
console.log(`Загружаем прогресс для курса ${courseId}, упражнения ${actualExerciseId}, день ${currentDay}`) console.log(`Загружаем прогресс для курса ${courseId}, упражнения ${actualExerciseId}, день ${currentDay}`)
@ -219,6 +198,7 @@ export const Exercise = () => {
}, },
}) })
console.log("Ответ сервера с прогрессом:", response.data) console.log("Ответ сервера с прогрессом:", response.data)
if ( if (
@ -297,6 +277,7 @@ export const Exercise = () => {
} }
} }
// ========== ФУНКЦИЯ КОНВЕРТАЦИИ ВРЕМЕНИ ИЗ MM:SS В СЕКУНДЫ ==========
const convertTimeToSeconds = (timeString: string): number => { const convertTimeToSeconds = (timeString: string): number => {
try { try {
const parts = timeString.split(":") const parts = timeString.split(":")
@ -318,6 +299,7 @@ export const Exercise = () => {
} }
} }
// ========== ФУНКЦИЯ СОХРАНЕНИЯ ПРОГРЕССА ПОДХОДА НА СЕРВЕР ==========
const saveSetProgress = async (setNumber: number, timeString: string, status: number) => { const saveSetProgress = async (setNumber: number, timeString: string, status: number) => {
try { try {
const dayToSave = currentDay || 1 const dayToSave = currentDay || 1
@ -347,9 +329,19 @@ export const Exercise = () => {
console.log("TEST DAY COMPLETE", course_exercises)
console.log("Всего упражнений в курсе", course_exercises.length)
// ========== ФУНКЦИЯ перехода к след упражнению ==========
const goToNextExercise = () => { const goToNextExercise = () => {
console.log("Переходим к следующему упражнению") console.log("Переходим к следующему упражнению")
if (exerciseIndex !== undefined) { if (exerciseIndex !== undefined) {
const currentIndex = Number.parseInt(exerciseIndex) const currentIndex = Number.parseInt(exerciseIndex)
const nextIndex = currentIndex + 1 const nextIndex = currentIndex + 1
@ -357,6 +349,8 @@ export const Exercise = () => {
const dayParam = selectedDay ? `?day=${selectedDay}` : "" const dayParam = selectedDay ? `?day=${selectedDay}` : ""
history.push(`/course/${courseId}/exercise/${nextIndex}${dayParam}`) history.push(`/course/${courseId}/exercise/${nextIndex}${dayParam}`)
} else { } else {
const currentExerciseNum = Number.parseInt(actualExerciseId) const currentExerciseNum = Number.parseInt(actualExerciseId)
const nextExerciseId = currentExerciseNum + 1 const nextExerciseId = currentExerciseNum + 1
@ -364,6 +358,7 @@ export const Exercise = () => {
} }
} }
// ========== ФУНКЦИЯ ЗАВЕРШЕНИЯ ТЕКУЩЕГО ПОДХОДА ==========
const handleCompleteSet = async () => { const handleCompleteSet = async () => {
console.log("Пользователь завершает подход", currentSet, "из", totalSets) console.log("Пользователь завершает подход", currentSet, "из", totalSets)
@ -388,6 +383,7 @@ export const Exercise = () => {
} }
} }
// ========== ФУНКЦИЯ ПОЛНОГО ЗАВЕРШЕНИЯ УПРАЖНЕНИЯ ==========
const handleComplete = async (completedSetsArray = completedSets) => { const handleComplete = async (completedSetsArray = completedSets) => {
console.log("УПРАЖНЕНИЕ ПОЛНОСТЬЮ ЗАВЕРШЕНО! Все подходы выполнены.") console.log("УПРАЖНЕНИЕ ПОЛНОСТЬЮ ЗАВЕРШЕНО! Все подходы выполнены.")
@ -403,15 +399,13 @@ export const Exercise = () => {
day: currentDay, day: currentDay,
position: totalTime, position: totalTime,
set: totalSets, set: totalSets,
status: 1, // 1 = полностью завершено status: 1,
totalTime: totalTime, totalTime: totalTime,
completedSets: completedSetsArray, completedSets: completedSetsArray,
completedAt: new Date().toISOString(), completedAt: new Date().toISOString(),
}), }),
) )
setCompletedExercisesInDay((prev) => prev + 1)
setIsCompleted(true) setIsCompleted(true)
setCurrentTime(totalTime) setCurrentTime(totalTime)
setIsPlaying(false) setIsPlaying(false)
@ -421,6 +415,7 @@ export const Exercise = () => {
setCompletedSets(completedSetsArray) setCompletedSets(completedSetsArray)
} }
// ========== ФУНКЦИЯ ПАУЗЫ И СОХРАНЕНИЯ ПРОГРЕССА ==========
const handlePause = async ( const handlePause = async (
completedSetsArray = completedSets, completedSetsArray = completedSets,
setNumber = currentSet, setNumber = currentSet,
@ -455,6 +450,7 @@ export const Exercise = () => {
setHasSavedProgress(true) setHasSavedProgress(true)
} }
// ========== ВОССТАНОВЛЕНИЕ ПРОГРЕССА ПРИ ЗАГРУЗКЕ СТРАНИЦЫ ==========
useEffect(() => { useEffect(() => {
const loadProgress = async () => { const loadProgress = async () => {
if (!actualExerciseId) return if (!actualExerciseId) return
@ -507,6 +503,7 @@ export const Exercise = () => {
loadProgress() loadProgress()
}, [courseId, actualExerciseId, currentDay, totalTime, totalSets]) }, [courseId, actualExerciseId, currentDay, totalTime, totalSets])
// ========== ОСНОВНОЙ ТАЙМЕР ДЛЯ УПРАЖНЕНИЯ ==========
useEffect(() => { useEffect(() => {
let interval: NodeJS.Timeout | undefined let interval: NodeJS.Timeout | undefined
@ -540,6 +537,7 @@ export const Exercise = () => {
} }
}, [isPlaying, totalTime, isCompleted, isResting, currentSet, completedSets]) }, [isPlaying, totalTime, isCompleted, isResting, currentSet, completedSets])
// ========== ТАЙМЕР ДЛЯ ОТДЫХА МЕЖДУ ПОДХОДАМИ ==========
useEffect(() => { useEffect(() => {
let restInterval: NodeJS.Timeout | undefined let restInterval: NodeJS.Timeout | undefined
@ -573,6 +571,7 @@ export const Exercise = () => {
} }
}, [isResting, restTime, isRestPaused, currentSet]) }, [isResting, restTime, isRestPaused, currentSet])
// ========== ФУНКЦИИ ДЛЯ АНИМАЦИИ КНОПКИ СБРОСА ==========
const handleClick = () => { const handleClick = () => {
console.log("Запускаем анимацию кнопки сброса") console.log("Запускаем анимацию кнопки сброса")
setIsRotating(true) setIsRotating(true)
@ -583,14 +582,17 @@ export const Exercise = () => {
setIsRotating(false) setIsRotating(false)
} }
// ========== ФУНКЦИЯ ФОРМАТИРОВАНИЯ ВРЕМЕНИ ==========
const formatTime = (seconds: number) => { const formatTime = (seconds: number) => {
const mins = Math.floor(seconds / 60) const mins = Math.floor(seconds / 60)
const secs = seconds % 60 const secs = seconds % 60
return `${mins.toString().padStart(2, "0")}:${secs.toString().padStart(2, "0")}` return `${mins.toString().padStart(2, "0")}:${secs.toString().padStart(2, "0")}`
} }
// ========== РАСЧЕТ ПРОГРЕССА ДЛЯ ПОЛОСКИ ==========
const progress = isResting ? ((totalRestTime - restTime) / totalRestTime) * 100 : (currentTime / totalTime) * 100 const progress = isResting ? ((totalRestTime - restTime) / totalRestTime) * 100 : (currentTime / totalTime) * 100
// ========== ИКОНКИ ДЛЯ КНОПОК ==========
const PlayIcon = () => ( const PlayIcon = () => (
<svg className="w-10 h-10 text-white" fill="currentColor" viewBox="0 0 24 24"> <svg className="w-10 h-10 text-white" fill="currentColor" viewBox="0 0 24 24">
<path d="M8 5v14l11-7z" /> <path d="M8 5v14l11-7z" />
@ -618,6 +620,7 @@ export const Exercise = () => {
</svg> </svg>
) )
// ========== ИНФОРМАЦИЯ ОБ УПРАЖНЕНИИ ДЛЯ ОТОБРАЖЕНИЯ ==========
const exerciseSteps = [ const exerciseSteps = [
{ {
title: "Описание упражнения", title: "Описание упражнения",
@ -641,7 +644,7 @@ export const Exercise = () => {
}, },
] ]
// ========== ЭКРАНЫ ЗАГРУЗКИ И ОШИБОК ==========
if (loading) { if (loading) {
return ( return (
<div className="bg-gray-50 w-full h-full overflow-auto"> <div className="bg-gray-50 w-full h-full overflow-auto">
@ -697,6 +700,7 @@ export const Exercise = () => {
) )
} }
// ========== ОСНОВНОЙ ИНТЕРФЕЙС УПРАЖНЕНИЯ ==========
return ( return (
<div className="bg-gray-50 w-full h-full overflow-auto"> <div className="bg-gray-50 w-full h-full overflow-auto">
<div className="mt-36 mb-90 min-h-screen max-w-4xl mx-auto"> <div className="mt-36 mb-90 min-h-screen max-w-4xl mx-auto">
@ -729,7 +733,8 @@ export const Exercise = () => {
<button <button
onClick={() => !isCompleted && !isResting && setIsPlaying(!isPlaying)} onClick={() => !isCompleted && !isResting && setIsPlaying(!isPlaying)}
disabled={isCompleted || isResting} disabled={isCompleted || isResting}
className={`w-20 h-20 rounded-full flex items-center justify-center shadow-2xl transition-all duration-300 transform hover:scale-110 ${isPlaying className={`w-20 h-20 rounded-full flex items-center justify-center shadow-2xl transition-all duration-300 transform hover:scale-110 ${
isPlaying
? "bg-white/20 backdrop-blur-xl border border-white/30" ? "bg-white/20 backdrop-blur-xl border border-white/30"
: "bg-white/30 backdrop-blur-xl border border-white/50" : "bg-white/30 backdrop-blur-xl border border-white/50"
} ${isCompleted || isResting ? "opacity-50 cursor-not-allowed" : ""}`} } ${isCompleted || isResting ? "opacity-50 cursor-not-allowed" : ""}`}
@ -787,7 +792,8 @@ export const Exercise = () => {
return ( return (
<div key={setNumber} className="flex-1 text-center"> <div key={setNumber} className="flex-1 text-center">
<div <div
className={`h-3 rounded-full transition-all duration-300 ${isSetCompleted ? "bg-cyan-500" : isCurrent ? "bg-cyan-500" : "bg-gray-200" className={`h-3 rounded-full transition-all duration-300 ${
isSetCompleted ? "bg-cyan-500" : isCurrent ? "bg-cyan-500" : "bg-gray-200"
}`} }`}
/> />
<div className="text-xs font-bold mt-1 text-gray-600">{setNumber}</div> <div className="text-xs font-bold mt-1 text-gray-600">{setNumber}</div>
@ -823,7 +829,8 @@ export const Exercise = () => {
<div className="flex items-center justify-between mb-3"> <div className="flex items-center justify-between mb-3">
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
<div <div
className={`w-2 h-2 rounded-full ${isCompleted className={`w-2 h-2 rounded-full ${
isCompleted
? "bg-cyan-400" ? "bg-cyan-400"
: isResting : isResting
? `bg-cyan-400 ${!isRestPaused ? "animate-pulse" : ""}` ? `bg-cyan-400 ${!isRestPaused ? "animate-pulse" : ""}`
@ -845,7 +852,8 @@ export const Exercise = () => {
<div className="bg-gray-200 rounded-full h-2 mb-4 overflow-hidden"> <div className="bg-gray-200 rounded-full h-2 mb-4 overflow-hidden">
<div <div
className={`h-2 rounded-full transition-all duration-1000 shadow-sm ${isCompleted className={`h-2 rounded-full transition-all duration-1000 shadow-sm ${
isCompleted
? "bg-gradient-to-r from-cyan-400 via-cyan-500 to-cyan-600" ? "bg-gradient-to-r from-cyan-400 via-cyan-500 to-cyan-600"
: isResting : isResting
? "bg-gradient-to-r from-cyan-400 via-cyan-500 to-cyan-600" ? "bg-gradient-to-r from-cyan-400 via-cyan-500 to-cyan-600"
@ -858,24 +866,13 @@ export const Exercise = () => {
<div className="flex space-x-3"> <div className="flex space-x-3">
{isCompleted ? ( {isCompleted ? (
<> <>
{completedExercisesInDay + 1 >= totalExercisesInDay ? (
<button
className="flex-1 font-bold py-3 px-4 rounded-xl bg-green-500 hover:bg-green-600 text-white flex items-center justify-center space-x-2 transition-all duration-300 hover:scale-105"
>
<CheckIcon />
<span>🎉 День завершен!</span>
</button>
) : (
<button <button
onClick={goToNextExercise} onClick={goToNextExercise}
className="flex-1 font-bold py-3 px-4 rounded-xl bg-orange-400 hover:bg-yellow-500 hover:scale-105 text-white flex items-center justify-center space-x-2 transition-all duration-300" className="flex-1 font-bold py-3 px-4 rounded-xl bg-orange-400 hover:bg-yellow-500 hover:scale-105 text-white flex items-center justify-center space-x-2 transition-all duration-300"
> >
<span>Следующее упражнение</span> <span>Следующее упражнение</span>
<span className="text-xs">
({completedExercisesInDay + 1}/{totalExercisesInDay})
</span>
</button> </button>
)}
<div className="px-4 py-3 bg-cyan-500 text-white font-bold rounded-xl flex items-center justify-center space-x-2"> <div className="px-4 py-3 bg-cyan-500 text-white font-bold rounded-xl flex items-center justify-center space-x-2">
<CheckIcon /> <CheckIcon />
@ -889,7 +886,8 @@ export const Exercise = () => {
setIsRestPaused(!isRestPaused) setIsRestPaused(!isRestPaused)
handlePause(completedSets, currentSet, true, restTime, !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-yellow-500 hover:bg-yellow-600 text-white"
: "bg-[#2BACBE] hover:bg-[#2099A8] text-white" : "bg-[#2BACBE] hover:bg-[#2099A8] text-white"
}`} }`}
@ -932,7 +930,8 @@ export const Exercise = () => {
setIsPlaying(false) 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-yellow-500 hover:bg-yellow-600 text-white shadow-lg"
: "bg-[#2BACBE] hover:bg-[#2099A8] text-white shadow-lg" : "bg-[#2BACBE] hover:bg-[#2099A8] text-white shadow-lg"
}`} }`}