реализована логика и отображение прогресса подходов и отдыха

This commit is contained in:
Tatyana 2025-09-02 15:48:45 +03:00
parent 3d5cd3a4ac
commit 359fbb1731
2 changed files with 376 additions and 120 deletions

View File

@ -1,22 +1,14 @@
"use client" "use client"
//хуки import { useState, useEffect } from "react"
import { useState, useEffect } from "react"; import { useHistory, useParams } from "react-router-dom"
import { useHistory, useParams } from "react-router-dom";
// import { CheckIcon } from "../components/icons/CheckIcon"; import { RefreshIcon } from "../components/icons/RefreshIcon"
import { RefreshIcon } from "../components/icons/RefreshIcon";
import HeaderNav from "../components/HeaderNav"; import HeaderNav from "../components/HeaderNav"
import BottomNavigation from "../components/BottomNavigation"; import BottomNavigation from "../components/BottomNavigation"
// import { getRouteCourseComplete } from "../shared/consts/router";
import { connect } from "../confconnect";
import axios from "axios"
//В TypeScript ключевое слово interface используется для определения интерфейсов — это способ описать структуру объектов, то есть какие свойства и методы у них есть, и какие типы данных они содержат
import { connect } from "../confconnect"
export interface Exercise { export interface Exercise {
id: number id: number
@ -45,30 +37,43 @@ export const Exercise = () => {
const [error, setError] = useState<string>("") const [error, setError] = useState<string>("")
const [isPlaying, setIsPlaying] = useState(false) const [isPlaying, setIsPlaying] = useState(false)
const [currentTime, setCurrentTime] = useState(0) const [currentTime, setCurrentTime] = useState(0)
const [totalTime, setTotalTime] = useState(900) // Default 15 minutes const [totalTime, setTotalTime] = useState(900)
const [currentSet, setCurrentSet] = useState(1) const [currentSet, setCurrentSet] = useState(1)
const [isActive, setIsActive] = useState(false)
const [totalSets, setTotalSets] = useState(3) const [totalSets, setTotalSets] = useState(3)
const [isRotating, setIsRotating] = useState(false) const [isRotating, setIsRotating] = useState(false)
const [hasSavedProgress, setHasSavedProgress] = useState(false)
const [isCompleted, setIsCompleted] = useState(false)
const [completedSets, setCompletedSets] = useState<number[]>([])
// Новые состояния для отдыха
const [isResting, setIsResting] = useState(false)
//Можно реализовать полностью на клиенте. const [restTime, setRestTime] = useState(0)
// Ограничение — прогресс сохраняется только на устройстве пользователя. const [totalRestTime] = useState(60) // 60 секунд отдыха по умолчанию
// Если нужно синхронизировать между устройствами или сохранять историю, потребуется бэкенд.
//сохраняем прогресс
// Восстановление прогресса при загрузке // Восстановление прогресса при загрузке
useEffect(() => { useEffect(() => {
const savedProgress = localStorage.getItem('exerciseProgress'); const savedProgress = localStorage.getItem("exerciseProgress")
if (savedProgress) { if (savedProgress) {
const progress = JSON.parse(savedProgress); const progress = JSON.parse(savedProgress)
if (progress.exerciseId === exercise?.id) { if (progress.exerciseId === exercise?.id) {
setCurrentTime(progress.position); if (progress.status === 1) {
setCurrentSet(progress.set); setIsCompleted(true)
setCurrentTime(progress.totalTime || totalTime)
setCompletedSets(progress.completedSets || [])
setCurrentSet(progress.set || totalSets)
setHasSavedProgress(false)
} else {
setCurrentTime(progress.position)
setCurrentSet(progress.set)
setCompletedSets(progress.completedSets || [])
setIsResting(progress.isResting || false)
setRestTime(progress.restTime || 0)
setHasSavedProgress(true)
setIsCompleted(false)
} }
} }
}, [exercise]); }
}, [exercise, totalTime, totalSets])
useEffect(() => { useEffect(() => {
console.log("Course ID:", courseId) console.log("Course ID:", courseId)
@ -80,13 +85,9 @@ export const Exercise = () => {
return return
} }
// Получаем данные упражнения через API: GET /pacient/:course_id/:exercise_id
connect connect
.get(`pacient/${courseId}/${exerciseId}`) .get(`pacient/${courseId}/${exerciseId}`)
.then((response) => { .then((response) => {
// console.log("Response status:", response.status)
// console.log("Response data:", response.data)
const exerciseData = response.data const exerciseData = response.data
setExercise({ setExercise({
@ -103,9 +104,10 @@ export const Exercise = () => {
sessionname: exerciseData.sessionname, sessionname: exerciseData.sessionname,
}) })
// Устанавливаем время и подходы из данных упражнения
if (exerciseData.time) { if (exerciseData.time) {
setTotalTime(Number.parseInt(exerciseData.time) * 60) // Конвертируем минуты в секунды const timeInSeconds = Number.parseInt(exerciseData.time) * 60
setTotalTime(timeInSeconds)
console.log("Установлено время упражнения:", timeInSeconds, "секунд")
} }
if (exerciseData.count) { if (exerciseData.count) {
setTotalSets(exerciseData.count) setTotalSets(exerciseData.count)
@ -131,30 +133,104 @@ export const Exercise = () => {
}) })
}, [courseId, exerciseId]) }, [courseId, exerciseId])
// Функция для завершения текущего подхода
const handleCompleteSet = async () => {
console.log("Завершение подхода", currentSet, "из", totalSets)
const newCompletedSets = [...completedSets, currentSet]
setCompletedSets(newCompletedSets)
setIsPlaying(false)
// Проверяем, завершены ли все подходы
if (newCompletedSets.length >= totalSets) {
console.log("Все подходы завершены, завершаем упражнение")
// Все подходы завершены - завершаем упражнение
await handleComplete(newCompletedSets)
} else {
console.log("Начинаем отдых перед подходом", currentSet + 1)
// Начинаем отдых перед следующим подходом
setIsResting(true)
setRestTime(totalRestTime)
setCurrentTime(0)
const handlePause = async () => { // Сохраняем прогресс с отдыхом
// Формируем данные в том формате, который ожидает сервер await handlePause(newCompletedSets, currentSet, true, totalRestTime)
const progressData = { }
time_users: formatTime(currentTime), // Отправляем как строку в формате MM:SS }
status: currentSet, // Отправляем текущий подход как статус
// Функция для завершения упражнения
const handleComplete = async (completedSetsArray = completedSets) => {
console.log("Завершение упражнения")
const completionData = {
time_users: formatTime(totalTime),
status: 1,
}
localStorage.setItem(
"exerciseProgress",
JSON.stringify({
exerciseId: exercise?.id,
position: totalTime,
set: totalSets,
status: 1,
totalTime: totalTime,
completedSets: completedSetsArray,
completedAt: new Date().toISOString(),
}),
)
setIsCompleted(true)
setCurrentTime(totalTime)
setIsPlaying(false)
setIsResting(false)
setHasSavedProgress(false)
setCompletedSets(completedSetsArray)
try {
console.log("Отправляем данные о завершении:", completionData)
const response = await connect.post(`pacient/${courseId}/${exerciseId}`, completionData)
console.log("Ответ сервера при завершении:", response.status)
console.log("Упражнение успешно завершено")
} catch (error) {
console.error("Ошибка при отправке завершения:", error)
if (error.response) {
console.error("Ответ сервера:", error.response.status, error.response.data)
}
}
}
const handlePause = async (
completedSetsArray = completedSets,
setNumber = currentSet,
resting = isResting,
currentRestTime = restTime,
) => {
const progressData = {
time_users: formatTime(currentTime),
status: setNumber,
} }
// Сохраняем в localStorage
localStorage.setItem( localStorage.setItem(
"exerciseProgress", "exerciseProgress",
JSON.stringify({ JSON.stringify({
exerciseId: exercise?.id, exerciseId: exercise?.id,
position: currentTime, position: currentTime,
set: currentSet, set: setNumber,
status: 0,
completedSets: completedSetsArray,
isResting: resting,
restTime: currentRestTime,
}), }),
) )
setHasSavedProgress(true)
try { try {
console.log("Отправляем данные:", progressData) console.log("Отправляем данные:", progressData)
// Используем connect (axios) вместо прямого axios
const response = await connect.post(`pacient/${courseId}/${exerciseId}`, progressData) const response = await connect.post(`pacient/${courseId}/${exerciseId}`, progressData)
console.log("Ответ сервера при отправке прогресса:", response.status) console.log("Ответ сервера при отправке прогресса:", response.status)
@ -167,38 +243,67 @@ const handlePause = async () => {
} }
} }
// Основной таймер для упражнения
useEffect(() => { useEffect(() => {
let interval: NodeJS.Timeout | undefined let interval: NodeJS.Timeout | undefined
if (isPlaying) { if (isPlaying && !isCompleted && !isResting) {
interval = setInterval(() => { interval = setInterval(() => {
setCurrentTime((prev) => { setCurrentTime((prev) => {
if (prev >= totalTime) { const newTime = prev + 1
console.log(`Таймер: ${newTime}/${totalTime} секунд`)
// Проверяем, достигли ли мы конца времени для текущего подхода
if (newTime >= totalTime) {
console.log("Время подхода истекло, завершаем подход")
setIsPlaying(false) setIsPlaying(false)
// Отправляем результат на сервер при завершении // Используем setTimeout чтобы избежать проблем с состоянием в useEffect
// submitProgress() setTimeout(() => {
// Show completion animation handleCompleteSet()
// history.push(getRouteCourseComplete()) }, 100)
return totalTime return totalTime
} }
return prev + 1 return newTime
}) })
}, 1000) }, 1000)
} }
return () => { return () => {
if (interval) clearInterval(interval) if (interval) clearInterval(interval)
} }
}, [isPlaying, totalTime, history]) }, [isPlaying, totalTime, isCompleted, isResting, currentSet, completedSets])
// Таймер для отдыха
useEffect(() => {
let restInterval: NodeJS.Timeout | undefined
if (isResting && restTime > 0) {
restInterval = setInterval(() => {
setRestTime((prev) => {
const newRestTime = prev - 1
console.log(`Отдых: ${newRestTime} секунд осталось`)
if (newRestTime <= 0) {
console.log("Отдых закончен, переходим к следующему подходу")
// Отдых закончен, переходим к следующему подходу
setIsResting(false)
setCurrentSet(currentSet + 1)
setCurrentTime(0)
return 0
}
return newRestTime
})
}, 1000)
}
return () => {
if (restInterval) clearInterval(restInterval)
}
}, [isResting, restTime, currentSet])
const handleClick = () => { const handleClick = () => {
setIsRotating(true); setIsRotating(true)
} }
const handleTransitionEnd = () => { const handleTransitionEnd = () => {
setIsRotating(false); setIsRotating(false)
}; }
const formatTime = (seconds: number) => { const formatTime = (seconds: number) => {
const mins = Math.floor(seconds / 60) const mins = Math.floor(seconds / 60)
@ -206,7 +311,7 @@ const handlePause = async () => {
return `${mins.toString().padStart(2, "0")}:${secs.toString().padStart(2, "0")}` return `${mins.toString().padStart(2, "0")}:${secs.toString().padStart(2, "0")}`
} }
const progress = (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">
@ -220,9 +325,18 @@ const handlePause = async () => {
</svg> </svg>
) )
const CheckIcon = () => (
<svg className="w-10 h-10 text-white" fill="currentColor" viewBox="0 0 24 24">
<path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z" />
</svg>
)
const RestIcon = () => (
<svg className="w-10 h-10 text-white" fill="currentColor" viewBox="0 0 24 24">
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z" />
</svg>
)
// Генерируем инструкции на основе реальных данных упражнения
const exerciseSteps = [ const exerciseSteps = [
{ {
title: "Описание упражнения", title: "Описание упражнения",
@ -304,28 +418,72 @@ const handlePause = async () => {
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">
<HeaderNav item={exercise.title} text={`упражнение ${exercise.position}`} <HeaderNav item={exercise.title} text={`упражнение ${exercise.position}`} />
/>
<p className="bg-red-400 font-bold">Если упражнение меньше минуты, то скидывает сразу на отдых</p>
<div className="px-4 sm:px-6 mt-10 mb-6"> <div className="px-4 sm:px-6 mt-10 mb-6">
<div className="glass-morphism rounded-3xl overflow-hidden shadow-2xl border border-white/20 backdrop-blur-2xl"> <div className="glass-morphism rounded-3xl overflow-hidden shadow-2xl border border-white/20 backdrop-blur-2xl">
<div className="relative"> <div className="relative">
<img src={exercise.url_file_img || video} alt={exercise.title} className="w-full h-120 object-cover" /> <img
src={exercise.url_file_img || "/placeholder.svg?height=300&width=400&text=Упражнение"}
alt={exercise.title}
className="w-full h-64 object-cover"
onError={(e) => {
const target = e.target as HTMLImageElement
target.src = "/placeholder.svg?height=300&width=400&text=Упражнение"
}}
/>
<div className="absolute inset-0 bg-gradient-to-t from-black/30 via-transparent to-black/10"></div> <div className="absolute inset-0 bg-gradient-to-t from-black/30 via-transparent to-black/10"></div>
<div className="absolute inset-0 flex items-center justify-center"> <div className="absolute inset-0 flex items-center justify-center">
{isCompleted ? (
<div className="w-20 h-20 bg-green-500 rounded-full flex items-center justify-center shadow-2xl">
<CheckIcon />
</div>
) : isResting ? (
<div className="w-20 h-20 bg-cyan-500 opacity-80 rounded-full flex items-center justify-center shadow-2xl">
<svg width="40" height="40" viewBox="0 0 24 24" fill="ffffff80" xmlns="http://www.w3.org/2000/svg">
<path d="M12 2C17.523 2 22 6.477 22 12C22 17.523 17.523 22 12 22C6.477 22 2 17.523 2 12C2 6.477 6.477 2 12 2ZM12 6C11.7348 6 11.4804 6.10536 11.2929 6.29289C11.1054 6.48043 11 6.73478 11 7V12C11.0001 12.2652 11.1055 12.5195 11.293 12.707L14.293 15.707C14.4816 15.8892 14.7342 15.99 14.9964 15.9877C15.2586 15.9854 15.5094 15.8802 15.6948 15.6948C15.8802 15.5094 15.9854 15.2586 15.9877 14.9964C15.99 14.7342 15.8892 14.4816 15.707 14.293L13 11.586V7C13 6.73478 12.8946 6.48043 12.7071 6.29289C12.5196 6.10536 12.2652 6 12 6Z" fill="#ffffff80"/>
</svg>
</div>
) : (
<button <button
onClick={() => setIsPlaying(!isPlaying)} onClick={() => !isCompleted && !isResting && setIsPlaying(!isPlaying)}
className={ 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 isPlaying
? "w-20 h-20 bg-transparent backdrop-blur-xl rounded-full flex items-center justify-center shadow-2xl transition-all duration-300 transform hover:scale-110 border border-cyan-50 opacity-40" ? "bg-white/20 backdrop-blur-xl border border-white/30"
: "rounded-full w-20 h-20 flex items-center justify-center backdrop-blur-xl opacity-70" : "bg-white/30 backdrop-blur-xl border border-white/50"
} } ${isCompleted || isResting ? "opacity-50 cursor-not-allowed" : ""}`}
> >
{isPlaying ? <PauseIcon /> : <PlayIcon />} {isPlaying ? <PauseIcon /> : <PlayIcon />}
</button> </button>
)}
</div> </div>
{isPlaying && ( {/* Статус выполнения */}
{isCompleted && (
<div className="absolute top-4 left-4 flex items-center space-x-2">
<div className="w-3 h-3 bg-green-500 rounded-full"></div>
<span className="text-white text-sm font-bold bg-green-600/80 px-3 py-1 rounded-full backdrop-blur-sm">
Выполнено
</span>
</div>
)}
{isResting && (
<div className="absolute top-4 left-4 flex items-center space-x-2">
<div className="w-3 h-3 bg-cyan-500 rounded-full animate-pulse"></div>
<span className="text-white text-sm font-bold bg-cyan-600/80 px-3 py-1 rounded-full backdrop-blur-sm">
Отдых
</span>
</div>
)}
{isPlaying && !isCompleted && !isResting && (
<div className="absolute top-4 left-4 flex items-center space-x-2"> <div className="absolute top-4 left-4 flex items-center space-x-2">
<div className="w-3 h-3 bg-orange-500 rounded-full animate-pulse"></div> <div className="w-3 h-3 bg-orange-500 rounded-full animate-pulse"></div>
<span className="text-white text-sm font-bold bg-black/30 px-3 py-1 rounded-full backdrop-blur-sm"> <span className="text-white text-sm font-bold bg-black/30 px-3 py-1 rounded-full backdrop-blur-sm">
@ -335,12 +493,43 @@ const handlePause = async () => {
)} )}
<div className="absolute top-4 right-4 bg-cyan-50 backdrop-blur-sm px-3 py-1 rounded-xl"> <div className="absolute top-4 right-4 bg-cyan-50 backdrop-blur-sm px-3 py-1 rounded-xl">
<span className="text-gray-800 text-sm font-bold">{formatTime(currentTime)}</span> <span className="text-gray-800 text-sm font-bold">
{isResting ? formatTime(restTime) : formatTime(currentTime)}
</span>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
{/* Индикатор завершенных подходов */}
<div className="px-4 sm:px-6 mb-6">
<div className="bg-white rounded-2xl p-4 border border-gray-200 shadow-lg">
<h3 className="text-lg font-bold text-gray-800 mb-3">Прогресс подходов</h3>
<div className="flex space-x-2">
{Array.from({ length: totalSets }, (_, index) => {
const setNumber = index + 1
const isSetCompleted = completedSets.includes(setNumber)
const isCurrent = setNumber === currentSet && !isSetCompleted
return (
<div key={setNumber} className="flex-1 text-center">
<div
className={`h-3 rounded-full transition-all duration-300 ${
isSetCompleted ? "bg-green-500" : isCurrent ? "bg-cyan-500" : "bg-gray-200"
}`}
/>
<div className="text-xs font-bold mt-1 text-gray-600">{setNumber}</div>
</div>
)
})}
</div>
<div className="flex justify-between text-xs text-gray-600 mt-2">
<span>Завершено: {completedSets.length}</span>
<span>Всего: {totalSets}</span>
</div>
</div>
</div>
<div className="px-4 sm:px-6 space-y-4 mb-6"> <div className="px-4 sm:px-6 space-y-4 mb-6">
{exerciseSteps.map((step, index) => ( {exerciseSteps.map((step, index) => (
<div <div
@ -358,40 +547,69 @@ const handlePause = async () => {
</div> </div>
{/* Fixed Timer at Bottom */} {/* Fixed Timer at Bottom */}
<div className="fixed bottom-36 left-0 right-0 bg-white/5 backdrop-blur-sm rounded-2xl p-6 border border-gray-200/50 shadow-lg glass-morphism z-30"> <div className="fixed bottom-36 left-0 right-0 bg-white/95 backdrop-blur-sm border-t border-gray-200 px-4 sm:px-6 py-4 shadow-xl z-30">
<div className="max-w-md mx-auto"> <div className="max-w-md mx-auto">
<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 className="w-2 h-2 bg-green-400 rounded-full animate-pulse"></div> <div
className={`w-2 h-2 rounded-full ${
isCompleted
? "bg-green-400"
: isResting
? "bg-cyan-400 animate-pulse"
: "bg-green-400 animate-pulse"
}`}
></div>
<span className="text-sm font-bold text-gray-700"> <span className="text-sm font-bold text-gray-700">
Подход {currentSet} из {totalSets} {isCompleted
? `Завершено`
: isResting
? `Отдых перед подходом ${currentSet + 1}`
: `Подход ${currentSet} из ${totalSets}`}
</span> </span>
</div> </div>
<span className="text-sm font-black text-gray-700"> <span className="text-sm font-black text-gray-700">
{formatTime(currentTime)} / {formatTime(totalTime)} {isResting ? `${formatTime(restTime)} отдых` : `${formatTime(currentTime)} / ${formatTime(totalTime)}`}
</span> </span>
</div> </div>
<div className="bg-white/30 rounded-full h-3 mb-4 overflow-hidden"> <div className="bg-gray-200 rounded-full h-2 mb-4 overflow-hidden">
<div <div
className="bg-gradient-to-r from-[#2BACBE] via-cyan-500 to-cyan-700 h-3 rounded-full transition-all duration-1000 shadow-sm" className={`h-2 rounded-full transition-all duration-1000 shadow-sm ${
isCompleted
? "bg-gradient-to-r from-green-400 via-green-500 to-green-600"
: isResting
? "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>
<div className="flex space-x-3"> <div className="flex space-x-3">
{isCompleted ? (
<div className="flex-1 font-bold py-3 px-4 rounded-xl bg-green-500 text-white flex items-center justify-center space-x-2">
<CheckIcon />
<span>Упражнение выполнено</span>
</div>
) : isResting ? (
<div className="flex-1 font-bold py-3 px-4 rounded-xl bg-cyan-500 text-white flex items-center justify-center space-x-2">
<RestIcon />
<span>Отдых {formatTime(restTime)}</span>
</div>
) : (
<>
<button <button
onClick={() => { onClick={() => {
if (!isPlaying) { if (!isPlaying) {
setIsPlaying(true); setIsPlaying(true)
} else { } else {
handlePause(); handlePause()
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-gray-400 text-white shadow-lg" : "bg-[#2BACBE] hover:bg-[#2099A8] text-white shadow-lg"
: "bg-orange-400 text-white shadow-lg"
}`} }`}
> >
{isPlaying ? ( {isPlaying ? (
@ -400,32 +618,42 @@ const handlePause = async () => {
</> </>
) : ( ) : (
<> <>
<PlayIcon /> <span className="backdrop-blur-xl">Начать</span> <PlayIcon />
<span className="backdrop-blur-xl">{hasSavedProgress ? "Продолжить" : "Начать"}</span>
</> </>
)} )}
</button> </button>
<button
onClick={handleCompleteSet}
className="px-6 py-3 bg-green-500 hover:bg-green-600 hover:scale-110 text-white font-bold rounded-xl transition-all duration-300 flex items-center justify-center"
>
<CheckIcon />
</button>
</>
)}
<button <button
onClick={() => { onClick={() => {
setCurrentTime(0) setCurrentTime(0)
setIsPlaying(false) setIsPlaying(false)
setHasSavedProgress(false)
setIsCompleted(false)
setCompletedSets([])
setCurrentSet(1)
setIsResting(false)
setRestTime(0)
handleClick() handleClick()
localStorage.removeItem("exerciseProgress")
}} }}
className="cursor-pointer px-6 py-3 bg-white text-gray-800 font-bold rounded-xl transition-all duration-300 hover:scale-105 hover:shadow-lg border border-gray-200 flex items-center justify-center" className="cursor-pointer px-6 py-3 bg-gray-300 hover:bg-gray-200 text-white font-bold rounded-xl transition-all duration-300 hover:shadow-lg hover:scale-110 flex items-center justify-center"
> >
<div onTransitionEnd={handleTransitionEnd} className="inline-block">
<div
onTransitionEnd={handleTransitionEnd}
className="inline-block">
<RefreshIcon <RefreshIcon
className={`transition-transform duration-400 ease-in-out ${isRotating ? 'rotate-360' : ''}`} className={`transition-transform duration-400 ease-in-out ${isRotating ? "rotate-360" : ""}`}
/> />
</div> </div>
</button> </button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -27,12 +27,15 @@ export default function Home() {
const history = useHistory(); const history = useHistory();
const [currentDate, setCurrentDate] = useState(""); const [currentDate, setCurrentDate] = useState("");
const [error, setError] = useState<string>(''); const [, setError] = useState<string>('');
const [courses, setCourses] = useState<Course[]>([]); const [courses, setCourses] = useState<Course[]>([]);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const token = localStorage.getItem('authToken'); const token = localStorage.getItem('authToken');
const exerciseProgress = localStorage.getItem('exerciseProgress');
const currentProgress = localStorage.getItem('currentProgress')
useEffect(() => { useEffect(() => {
console.log(token) console.log(token)
@ -148,6 +151,8 @@ export default function Home() {
<div className="flex content-center items-center justify-between "> <div className="flex content-center items-center justify-between ">
</div> </div>
<div className="flex justify-between items-center"> <div className="flex justify-between items-center">
<div className="flex flex-col gap-6"> <div className="flex flex-col gap-6">
@ -171,8 +176,10 @@ export default function Home() {
</div> </div>
<div className="px-4 sm:px-6 space-y-6"> <div className="px-4 sm:px-6 space-y-6">
{/* Current Exercise */} {/* Текущее упражнение */}
<WorkoutCardHome onBackClick={handleBackClick} onCardClick={handleWorkoutClick} /> <WorkoutCardHome onBackClick={handleBackClick} onCardClick={handleWorkoutClick}
/>
{/* Quick Stats (Total Exercises & Total Courses) */} {/* Quick Stats (Total Exercises & Total Courses) */}
<div className="grid grid-cols-2 gap-4 md:gap-5"> <div className="grid grid-cols-2 gap-4 md:gap-5">
@ -191,6 +198,27 @@ export default function Home() {
onClick={handleExercisesClick} onClick={handleExercisesClick}
/> />
</div> </div>
<div className="bg-green-100">
<p className="font-bold ">Взяли из локального хранилища:</p>
надо считать прогресс исходя из выполненных/ вопрос: то есть, если выполнено, то как его исключить / как флаг проставлять?==
все курсы мы вяли из ручки курсов, назначенные по роутингу (пути в router.ts)
надо достать текущий курс. который не выполнен.
как узнать, что курс выполнен?==
мы берем данные для текущей тренировки, которые записываются с помощью post, --оттуда достаем данные для текущего упражнения, которое записано (1 строка в БД всегда),
а потом переходим на это упражнение.
и еще - мы считаем по индексу отображение, это же не повлияет на вывод итоговый на домашней странице, например?
<div className="bg-red-200">
<p>exerciseProgress:{exerciseProgress}</p>
<p>currentProgress{currentProgress}</p>
</div>
</div>
</div> </div>
<BottomNavigation /> <BottomNavigation />