ui кнопок на странице упражнения
This commit is contained in:
parent
ef64080882
commit
c756041321
@ -31,7 +31,7 @@ const AppRoutes = () => (
|
|||||||
<Route path={getRouteForgotPassword()} component={ForgotPasword} />
|
<Route path={getRouteForgotPassword()} component={ForgotPasword} />
|
||||||
<Route exact path={getRouteCourses()} component={Courses} />
|
<Route exact path={getRouteCourses()} component={Courses} />
|
||||||
<Route exact path="/course/:id" component={CourseExercises} />
|
<Route exact path="/course/:id" component={CourseExercises} />
|
||||||
<Route exact path="/course/:courseId/exercise/:exerciseId" component={Exercise} />
|
<Route exact path="/course/:courseId/:exerciseId" component={Exercise} />
|
||||||
<Route path={getRouteSettings()} component={Settings} />
|
<Route path={getRouteSettings()} component={Settings} />
|
||||||
<Route path={getRouteCourseComplete()} component={CourseComplete} />
|
<Route path={getRouteCourseComplete()} component={CourseComplete} />
|
||||||
</Switch>
|
</Switch>
|
||||||
|
27
src/components/icons/CheckIcon.tsx
Normal file
27
src/components/icons/CheckIcon.tsx
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
interface IconProps {
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export const CheckIcon: React.FC<IconProps> = ({ className }) => {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
className={className}
|
||||||
|
>
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={3} d="M5 13l4 4L19 7" />
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
27
src/components/icons/RefreshIcon.tsx
Normal file
27
src/components/icons/RefreshIcon.tsx
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
interface IconProps {
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const RefreshIcon: React.FC<IconProps> = ({ className }) => {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="20"
|
||||||
|
height="20"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
stroke="#6F6F6F"
|
||||||
|
strokeWidth="3"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
className={className} // Передача пропса сюда
|
||||||
|
>
|
||||||
|
<path d="M2.5 2v6h6" />
|
||||||
|
<path d="M21.5 22v-6h-6" />
|
||||||
|
<path d="M22 11.5A10 10 0 0 0 3.2 7.2" />
|
||||||
|
<path d="M2 12.5a10 10 0 0 0 18.8 4.2" />
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
@ -63,3 +63,8 @@
|
|||||||
transform: translateX(100%);
|
transform: translateX(100%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.rotate-360 {
|
||||||
|
transform: rotate(160deg);
|
||||||
|
}
|
@ -110,7 +110,7 @@ const history = useHistory();
|
|||||||
|
|
||||||
{/* Кнопки выбора дня */}
|
{/* Кнопки выбора дня */}
|
||||||
{days.length > 1 && (
|
{days.length > 1 && (
|
||||||
<div className="px-4 sm:px-6 mb-6">
|
<div className="mb-6">
|
||||||
<div className="flex space-x-2 overflow-x-auto pb-2">
|
<div className="flex space-x-2 overflow-x-auto pb-2">
|
||||||
{days.map((day) => (
|
{days.map((day) => (
|
||||||
<button
|
<button
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
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 BottomNavigation from "../components/BottomNavigation"
|
import BottomNavigation from "../components/BottomNavigation"
|
||||||
import { getRouteCourseComplete } from "../shared/consts/router"
|
import { getRouteCourseComplete } from "../shared/consts/router"
|
||||||
import HeaderNav from "../components/HeaderNav"
|
import HeaderNav from "../components/HeaderNav"
|
||||||
@ -38,7 +40,9 @@ export const Exercise = () => {
|
|||||||
const [currentTime, setCurrentTime] = useState(0)
|
const [currentTime, setCurrentTime] = useState(0)
|
||||||
const [totalTime, setTotalTime] = useState(900) // Default 15 minutes
|
const [totalTime, setTotalTime] = useState(900) // Default 15 minutes
|
||||||
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)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log("Course ID:", courseId)
|
console.log("Course ID:", courseId)
|
||||||
@ -123,6 +127,15 @@ export const Exercise = () => {
|
|||||||
}
|
}
|
||||||
}, [isPlaying, totalTime, history])
|
}, [isPlaying, totalTime, history])
|
||||||
|
|
||||||
|
|
||||||
|
const handleClick = () => {
|
||||||
|
setIsRotating(true);
|
||||||
|
}
|
||||||
|
const handleTransitionEnd = () => {
|
||||||
|
setIsRotating(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// Функция для отправки прогресса на сервер
|
// Функция для отправки прогресса на сервер
|
||||||
const submitProgress = async () => {
|
const submitProgress = async () => {
|
||||||
if (!courseId || !exerciseId) return
|
if (!courseId || !exerciseId) return
|
||||||
@ -160,28 +173,7 @@ export const Exercise = () => {
|
|||||||
</svg>
|
</svg>
|
||||||
)
|
)
|
||||||
|
|
||||||
const RefreshIcon = () => (
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
width="20"
|
|
||||||
height="20"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="none"
|
|
||||||
stroke="#6F6F6F"
|
|
||||||
strokeWidth="3"
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
>
|
|
||||||
<path d="M2.5 2v6h6M21.5 22v-6h-6" />
|
|
||||||
<path d="M22 11.5A10 10 0 0 0 3.2 7.2M2 12.5a10 10 0 0 0 18.8 4.2" />
|
|
||||||
</svg>
|
|
||||||
)
|
|
||||||
|
|
||||||
const CheckIcon = () => (
|
|
||||||
<svg className="w-6 h-6 text-cyan-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={3} d="M5 13l4 4L19 7" />
|
|
||||||
</svg>
|
|
||||||
)
|
|
||||||
|
|
||||||
// Генерируем инструкции на основе реальных данных упражнения
|
// Генерируем инструкции на основе реальных данных упражнения
|
||||||
const exerciseSteps = [
|
const exerciseSteps = [
|
||||||
@ -318,7 +310,7 @@ export const Exercise = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Fixed Timer at Bottom */}
|
{/* Fixed Timer at Bottom */}
|
||||||
<div className="fixed bottom-36 left-0 right-0 bg-white opacity-95 border-t border-white/20 px-4 sm:px-6 py-4 shadow-2xl z-30">
|
<div className="fixed bottom-36 left-0 right-0 bg-white opacity-85 border-t border-white/20 px-4 sm:px-6 py-4 shadow-2xl 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">
|
||||||
@ -340,8 +332,7 @@ export const Exercise = () => {
|
|||||||
<div className="flex space-x-3">
|
<div className="flex space-x-3">
|
||||||
<button
|
<button
|
||||||
onClick={() => setIsPlaying(!isPlaying)}
|
onClick={() => setIsPlaying(!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 ${
|
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-gray-400 text-white shadow-lg"
|
? "bg-gray-400 text-white shadow-lg"
|
||||||
: "bg-[#2BACBE] hover:bg-[#2099A8] text-white shadow-lg"
|
: "bg-[#2BACBE] hover:bg-[#2099A8] text-white shadow-lg"
|
||||||
}`}
|
}`}
|
||||||
@ -360,20 +351,50 @@ export const Exercise = () => {
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
setCurrentTime(0)
|
setCurrentTime(0)
|
||||||
setIsPlaying(false)
|
setIsPlaying(false)
|
||||||
|
handleClick()
|
||||||
}}
|
}}
|
||||||
className="px-6 py-3 bg-white text-gray-800 font-bold rounded-xl transition-all duration-300 hover:shadow-lg border border-gray-200 flex items-center justify-center"
|
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"
|
||||||
|
|
||||||
>
|
>
|
||||||
<RefreshIcon />
|
|
||||||
|
<div
|
||||||
|
onTransitionEnd={handleTransitionEnd}
|
||||||
|
className="inline-block">
|
||||||
|
<RefreshIcon
|
||||||
|
className={`transition-transform duration-400 ease-in-out ${isRotating ? 'rotate-360' : ''}`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setCurrentSet((prev) => Math.min(prev + 1, totalSets))
|
|
||||||
submitProgress()
|
const newSet = Math.min(currentSet + 1, totalSets);
|
||||||
|
setCurrentSet(newSet);
|
||||||
}}
|
}}
|
||||||
className="px-6 py-3 bg-white text-gray-800 font-bold rounded-xl transition-all duration-300 hover:shadow-lg border border-gray-200 flex items-center justify-center"
|
|
||||||
|
onMouseDown={() => setIsActive(true)}
|
||||||
|
onMouseUp={() => setIsActive(false)}
|
||||||
|
onMouseLeave={() => setIsActive(false)}
|
||||||
|
|
||||||
|
onTouchStart={() => setIsActive(true)}
|
||||||
|
onTouchEnd={() => setIsActive(false)}
|
||||||
|
|
||||||
|
className={`cursor-pointer px-6 py-3 font-bold rounded-xl transition-all duration-500 hover:scale-105 hover:shadow-lg border border-gray-200 flex items-center justify-center ${!isActive ? "bg-white text-cyan-500" : "bg-orange-400 text-white"}`}
|
||||||
>
|
>
|
||||||
<CheckIcon />
|
|
||||||
|
|
||||||
|
|
||||||
|
<CheckIcon
|
||||||
|
className="w-6 h-6"
|
||||||
|
|
||||||
|
/>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -5,6 +5,6 @@ export const getRouteForgotPassword = () => `/forgot-password`
|
|||||||
export const getRouteCourses = () => `/courses`
|
export const getRouteCourses = () => `/courses`
|
||||||
export const getRouteCourseExercises = (id: number | string) => `/course/${id}`
|
export const getRouteCourseExercises = (id: number | string) => `/course/${id}`
|
||||||
export const getRouteExercise = (courseId: number | string, exerciseId: number | string) =>
|
export const getRouteExercise = (courseId: number | string, exerciseId: number | string) =>
|
||||||
`/course/${courseId}/exercise/${exerciseId}`
|
`/course/${courseId}/${exerciseId}`
|
||||||
export const getRouteSettings = () => `/settings`
|
export const getRouteSettings = () => `/settings`
|
||||||
export const getRouteCourseComplete = () => `/course-complete`
|
export const getRouteCourseComplete = () => `/course-complete`
|
||||||
|
Loading…
x
Reference in New Issue
Block a user