разобралась с функцией загрузки прогресса с сервера
This commit is contained in:
parent
cf9803ef6f
commit
2b9c198e44
@ -41,12 +41,28 @@ export const Exercise = () => {
|
|||||||
|
|
||||||
// ========== ОСНОВНЫЕ СОСТОЯНИЯ КОМПОНЕНТА ==========
|
// ========== ОСНОВНЫЕ СОСТОЯНИЯ КОМПОНЕНТА ==========
|
||||||
// Состояние для хранения данных упражнения (null = данные еще не загружены)
|
// Состояние для хранения данных упражнения (null = данные еще не загружены)
|
||||||
|
// Мы говорим TypeScript, что переменная exercise может быть либо объектом типа Exercise, либо null. Это важно, потому что изначально у нас нет данных (например, мы их ещё не загрузили), и состояние пустое — null
|
||||||
|
|
||||||
|
|
||||||
|
// exercise — это переменная/ текущее значение состояния, которое может быть объектом Exercise или null.
|
||||||
|
// setExercise — функция, с помощью которой можно обновить exercise.
|
||||||
|
|
||||||
|
|
||||||
|
// useState<string>("") — это вызов функции useState с аргументом "" (пустая строка).
|
||||||
|
// Внутри угловых скобок <string> мы указываем тип состояния (TypeScript).
|
||||||
|
// В круглых скобках ("") — передаём начальное значение состояния.
|
||||||
|
|
||||||
const [exercise, setExercise] = useState<Exercise | null>(null)
|
const [exercise, setExercise] = useState<Exercise | null>(null)
|
||||||
|
// useState<Exercise | null>(null) — это вызов функции useState с начальным значением null
|
||||||
|
|
||||||
// Состояние загрузки (true = идет загрузка, false = загрузка завершена)
|
// Состояние загрузки (true = идет загрузка, false = загрузка завершена)
|
||||||
const [loading, setLoading] = useState(true)
|
const [loading, setLoading] = useState(true)
|
||||||
|
// если TypeScript может сам вывести тип из переданного начального значения, то указывать тип явно не обязательно
|
||||||
|
|
||||||
// Состояние ошибки (пустая строка = нет ошибки, текст = описание ошибки)
|
// Состояние ошибки (пустая строка = нет ошибки, текст = описание ошибки)
|
||||||
|
// С помощью ДЕСТРУКТУРИЗАЦИИ МАССИВА мы присваиваем первый элемент массива переменной error, а второй — функции setError
|
||||||
|
// Деструктуризация массива — это удобный синтаксис в JavaScript/TypeScript, который позволяет распаковать значения из массива в отдельные переменные
|
||||||
|
// Когда начальное значение — null или undefined, и TypeScript не может понять, какого типа будет состояние.
|
||||||
const [error, setError] = useState<string>("")
|
const [error, setError] = useState<string>("")
|
||||||
|
|
||||||
// ========== СОСТОЯНИЯ ТАЙМЕРУ УПРАЖНЕНИЯ ==========
|
// ========== СОСТОЯНИЯ ТАЙМЕРУ УПРАЖНЕНИЯ ==========
|
||||||
@ -98,6 +114,10 @@ export const Exercise = () => {
|
|||||||
const loadProgress = async () => {
|
const loadProgress = async () => {
|
||||||
const serverLoaded = await loadProgressFromServer()
|
const serverLoaded = await loadProgressFromServer()
|
||||||
|
|
||||||
|
// async — говорит, что функция работает асинхронно и возвращает промис.
|
||||||
|
// await — заставляет функцию ждать завершения промиса, не блокируя при этом весь поток выполнения.
|
||||||
|
|
||||||
|
|
||||||
if (!serverLoaded) {
|
if (!serverLoaded) {
|
||||||
// Fallback to localStorage if server loading failed
|
// Fallback to localStorage if server loading failed
|
||||||
console.log("Пытаемся загрузить прогресс из localStorage как резервный вариант")
|
console.log("Пытаемся загрузить прогресс из localStorage как резервный вариант")
|
||||||
@ -208,90 +228,98 @@ export const Exercise = () => {
|
|||||||
setLoading(false)
|
setLoading(false)
|
||||||
})
|
})
|
||||||
}, [courseId, exerciseId]) // Код выполняется при изменении ID курса или упражнения
|
}, [courseId, exerciseId]) // Код выполняется при изменении ID курса или упражнения
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ========== ФУНКЦИЯ ЗАГРУЗКИ ПРОГРЕССА С СЕРВЕРА ==========
|
// ========== ФУНКЦИЯ ЗАГРУЗКИ ПРОГРЕССА С СЕРВЕРА ==========
|
||||||
// Эта функция получает сохраненный прогресс упражнения с бэкенда
|
// Эта функция получает сохраненный прогресс упражнения с бэкенда
|
||||||
const loadProgressFromServer = async (): Promise<boolean> => {
|
const loadProgressFromServer = async () => {
|
||||||
try {
|
try {
|
||||||
console.log("Загружаем сохраненный прогресс с сервера для упражнения:", exerciseId, "в курсе:", courseId)
|
console.log(`Загружаем прогресс для курса ${courseId} и упражнения ${exerciseId}`);
|
||||||
|
|
||||||
const response = await connect.get(`pacient/${courseId}/${exerciseId}/progress?course_id=${courseId}`)
|
const token = localStorage.getItem('authToken');
|
||||||
|
|
||||||
if (response.data && response.data.length > 0) {
|
// Выполняем GET-запрос на сервер
|
||||||
console.log("Найден сохраненный прогресс на сервере для курса", courseId, ":", response.data)
|
const response = await connect.get(`pacient/${courseId}/${exerciseId}`, {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
// Получаем все записи прогресса для этого упражнения В ЭТОМ КУРСЕ
|
// Логируем ответ
|
||||||
const progressData = response.data
|
console.log("Ответ сервера с прогрессом:", response.data);
|
||||||
|
|
||||||
const filteredProgress = progressData.filter((record: any) => {
|
// Проверяем наличие user_progress
|
||||||
// Проверяем что запись относится к текущему курсу
|
if (
|
||||||
return record.course_id === Number.parseInt(courseId) || record.CourseId === Number.parseInt(courseId)
|
response.data &&
|
||||||
})
|
response.data.user_progress &&
|
||||||
|
Array.isArray(response.data.user_progress) &&
|
||||||
|
response.data.user_progress.length > 0
|
||||||
|
) {
|
||||||
|
const progressArray = response.data.user_progress;
|
||||||
|
|
||||||
console.log("Отфильтрованный прогресс для курса", courseId, ":", filteredProgress)
|
// Фильтруем прогресс по текущему курсу
|
||||||
|
const filteredProgress = progressArray.filter((record: any) => {
|
||||||
|
return record.course_id === Number.parseInt(courseId);
|
||||||
|
});
|
||||||
|
|
||||||
// Находим завершенные подходы (status = 1) и незавершенные (status = 0)
|
console.log("Отфильтрованный прогресс:", filteredProgress);
|
||||||
const completedSetsFromServer: number[] = []
|
|
||||||
let lastIncompleteSet = null
|
|
||||||
let lastSavedTime = "00:00"
|
|
||||||
|
|
||||||
// Обрабатываем каждую запись прогресса ТОЛЬКО ДЛЯ ТЕКУЩЕГО КУРСА
|
const completedSetsFromServer: number[] = [];
|
||||||
filteredProgress.forEach((record: any) => {
|
let lastIncompleteSet: any = null;
|
||||||
console.log(
|
let lastSavedTime = "00:00";
|
||||||
`Обрабатываем запись для курса ${courseId}: подход ${record.set}, статус ${record.status}, время ${record.time_users}`,
|
|
||||||
)
|
|
||||||
|
|
||||||
if (record.status === 1) {
|
// Обрабатываем каждый прогресс
|
||||||
// СТАТУС 1 = подход завершен
|
filteredProgress.forEach((record: any) => {
|
||||||
completedSetsFromServer.push(record.set)
|
console.log(`Подход ${record.set}, статус ${record.status}, время ${record.time_users}`);
|
||||||
console.log(`Подход ${record.set} завершен`)
|
|
||||||
} else if (record.status === 0) {
|
if (record.status === 1) {
|
||||||
// СТАТУС 0 = подход в процессе или на паузе
|
// Завершённый подход
|
||||||
lastIncompleteSet = record
|
completedSetsFromServer.push(record.set);
|
||||||
lastSavedTime = record.time_users || "00:00"
|
} else if (record.status === 0) {
|
||||||
console.log(`Подход ${record.set} в процессе, время: ${lastSavedTime}`)
|
// Незавершённый подход
|
||||||
|
if (!lastIncompleteSet || record.set > lastIncompleteSet.set) {
|
||||||
|
lastIncompleteSet = record;
|
||||||
|
lastSavedTime = record.time_users || "00:00";
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
// Восстанавливаем состояние на основе данных с сервера
|
|
||||||
if (completedSetsFromServer.length > 0) {
|
|
||||||
console.log("Восстанавливаем завершенные подходы:", completedSetsFromServer)
|
|
||||||
setCompletedSets(completedSetsFromServer)
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Если есть незавершенный подход, восстанавливаем его состояние
|
// Восстановление завершённых подходов
|
||||||
if (lastIncompleteSet) {
|
if (completedSetsFromServer.length > 0) {
|
||||||
console.log("Восстанавливаем незавершенный подход:", lastIncompleteSet.set)
|
setCompletedSets(completedSetsFromServer);
|
||||||
|
|
||||||
// Конвертируем время из формата MM:SS в секунды
|
|
||||||
const timeInSeconds = convertTimeToSeconds(lastSavedTime)
|
|
||||||
|
|
||||||
setCurrentSet(lastIncompleteSet.set) // Устанавливаем текущий подход
|
|
||||||
setCurrentTime(timeInSeconds) // Восстанавливаем время
|
|
||||||
setHasSavedProgress(true) // Помечаем что есть сохраненный прогресс
|
|
||||||
setIsCompleted(false) // Упражнение не завершено
|
|
||||||
|
|
||||||
console.log(`Восстановлено состояние: подход ${lastIncompleteSet.set}, время ${timeInSeconds} секунд`)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Проверяем, завершены ли все подходы
|
|
||||||
if (completedSetsFromServer.length >= totalSets) {
|
|
||||||
console.log("ВСЕ ПОДХОДЫ ЗАВЕРШЕНЫ согласно серверу!")
|
|
||||||
setIsCompleted(true) // Помечаем упражнение как завершенное
|
|
||||||
setCurrentTime(totalTime) // Устанавливаем время на максимум
|
|
||||||
setHasSavedProgress(false) // Сбрасываем флаг сохранения
|
|
||||||
}
|
|
||||||
|
|
||||||
return true // Successfully loaded from server
|
|
||||||
} else {
|
|
||||||
console.log("Прогресс на сервере не найден, начинаем с чистого листа")
|
|
||||||
return false // No progress found on server
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
|
||||||
console.error("Ошибка при загрузке прогресса с сервера:", error)
|
|
||||||
return false // Failed to load from server
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Восстановление незавершённого подхода
|
||||||
|
if (lastIncompleteSet) {
|
||||||
|
const timeInSeconds = convertTimeToSeconds(lastSavedTime);
|
||||||
|
|
||||||
|
setCurrentSet(lastIncompleteSet.set);
|
||||||
|
setCurrentTime(timeInSeconds);
|
||||||
|
setHasSavedProgress(true);
|
||||||
|
setIsCompleted(false);
|
||||||
|
|
||||||
|
console.log(`Восстановлен незавершённый подход ${lastIncompleteSet.set} с временем ${timeInSeconds} секунд`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Проверка, завершены ли все подходы
|
||||||
|
if (completedSetsFromServer.length >= totalSets) {
|
||||||
|
setIsCompleted(true);
|
||||||
|
setCurrentTime(totalTime);
|
||||||
|
setHasSavedProgress(false);
|
||||||
|
console.log("Все подходы завершены");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
console.log("Прогресс не найден, начинаем с чистого листа");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Ошибка при загрузке прогресса с сервера:", error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
// ========== ФУНКЦИЯ КОНВЕРТАЦИИ ВРЕМЕНИ ИЗ MM:SS В СЕКУНДЫ ==========
|
// ========== ФУНКЦИЯ КОНВЕРТАЦИИ ВРЕМЕНИ ИЗ MM:SS В СЕКУНДЫ ==========
|
||||||
// Преобразует время из формата "MM:SS" в секунды (например: "02:30" = 150 секунд)
|
// Преобразует время из формата "MM:SS" в секунды (например: "02:30" = 150 секунд)
|
||||||
const convertTimeToSeconds = (timeString: string): number => {
|
const convertTimeToSeconds = (timeString: string): number => {
|
||||||
@ -350,7 +378,7 @@ export const Exercise = () => {
|
|||||||
|
|
||||||
console.log(`!!!!Текущее упражнение: ${currentExerciseNum}, следующее: ${nextExerciseId}`)
|
console.log(`!!!!Текущее упражнение: ${currentExerciseNum}, следующее: ${nextExerciseId}`)
|
||||||
|
|
||||||
console.log({courseId}, {nextExerciseId})
|
console.log({ courseId }, { nextExerciseId })
|
||||||
// Переходим к следующему упражнению в том же курсе
|
// Переходим к следующему упражнению в том же курсе
|
||||||
history.push(`${courseId}/${nextExerciseId}`)
|
history.push(`${courseId}/${nextExerciseId}`)
|
||||||
}
|
}
|
||||||
@ -718,11 +746,10 @@ 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 ${
|
className={`w-20 h-20 rounded-full flex items-center justify-center shadow-2xl transition-all duration-300 transform hover:scale-110 ${isPlaying
|
||||||
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" : ""}`}
|
|
||||||
>
|
>
|
||||||
{isPlaying ? <PauseIcon /> : <PlayIcon />}
|
{isPlaying ? <PauseIcon /> : <PlayIcon />}
|
||||||
</button>
|
</button>
|
||||||
@ -782,9 +809,8 @@ export const Exercise = () => {
|
|||||||
<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 ${
|
className={`h-3 rounded-full transition-all duration-300 ${isSetCompleted ? "bg-cyan-500" : isCurrent ? "bg-cyan-500" : "bg-gray-200"
|
||||||
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>
|
||||||
@ -825,13 +851,12 @@ export const Exercise = () => {
|
|||||||
<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 ${
|
className={`w-2 h-2 rounded-full ${isCompleted
|
||||||
isCompleted
|
? "bg-cyan-400"
|
||||||
? "bg-cyan-400"
|
: isResting
|
||||||
: isResting
|
? `bg-cyan-400 ${!isRestPaused ? "animate-pulse" : ""}`
|
||||||
? `bg-cyan-400 ${!isRestPaused ? "animate-pulse" : ""}`
|
: "bg-cyan-400 animate-pulse"
|
||||||
: "bg-cyan-400 animate-pulse"
|
}`}
|
||||||
}`}
|
|
||||||
></div>
|
></div>
|
||||||
{/* Текст состояния */}
|
{/* Текст состояния */}
|
||||||
<span className="text-sm font-bold text-gray-700">
|
<span className="text-sm font-bold text-gray-700">
|
||||||
@ -851,13 +876,12 @@ 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 ${
|
className={`h-2 rounded-full transition-all duration-1000 shadow-sm ${isCompleted
|
||||||
isCompleted
|
? "bg-gradient-to-r from-cyan-400 via-cyan-500 to-cyan-600"
|
||||||
|
: 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"
|
||||||
: isResting
|
: "bg-gradient-to-r from-[#2BACBE] via-cyan-500 to-cyan-700"
|
||||||
? "bg-gradient-to-r from-cyan-400 via-cyan-500 to-cyan-600"
|
}`}
|
||||||
: "bg-gradient-to-r from-[#2BACBE] via-cyan-500 to-cyan-700"
|
|
||||||
}`}
|
|
||||||
style={{ width: `${progress}%` }}
|
style={{ width: `${progress}%` }}
|
||||||
></div>
|
></div>
|
||||||
</div>
|
</div>
|
||||||
@ -889,11 +913,10 @@ export const Exercise = () => {
|
|||||||
// Сохраняем состояние паузы
|
// Сохраняем состояние паузы
|
||||||
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 ${
|
className={`flex-1 font-bold py-3 px-4 rounded-xl transition-all duration-300 flex items-center justify-center space-x-2 ${isRestPaused
|
||||||
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"
|
}`}
|
||||||
}`}
|
|
||||||
>
|
>
|
||||||
{isRestPaused ? (
|
{isRestPaused ? (
|
||||||
<>
|
<>
|
||||||
@ -937,11 +960,10 @@ 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 ${
|
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
|
||||||
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"
|
}`}
|
||||||
}`}
|
|
||||||
>
|
>
|
||||||
{isPlaying ? (
|
{isPlaying ? (
|
||||||
<>
|
<>
|
||||||
|
1025
src/pages/ExerciseOld.tsx
Normal file
1025
src/pages/ExerciseOld.tsx
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user