155 lines
5.4 KiB
TypeScript
155 lines
5.4 KiB
TypeScript
"use client"
|
||
|
||
import type React from "react"
|
||
import { useState } from "react"
|
||
import { IonCard, IonCardContent, IonButton, IonIcon, IonBadge } from "@ionic/react"
|
||
import { playOutline, videocamOutline, closeCircleOutline } from "ionicons/icons" // Добавлен videocamOutline и closeCircleOutline
|
||
|
||
interface Exercise {
|
||
id: number
|
||
name: string
|
||
duration: number // в секундах
|
||
description: string
|
||
difficulty: "easy" | "medium" | "hard"
|
||
completed: boolean
|
||
videoUrl?: string // Добавлено поле для URL видео
|
||
}
|
||
|
||
interface ExerciseItemProps {
|
||
exercise: Exercise
|
||
onStart: (exercise: Exercise) => void
|
||
isCurrent: boolean
|
||
isDisabled: boolean
|
||
onVideoPlayToggle: (isPlaying: boolean) => void // Добавлено для уведомления родителя
|
||
}
|
||
|
||
const ExerciseItem: React.FC<ExerciseItemProps> = ({ exercise, onStart, isCurrent, isDisabled, onVideoPlayToggle }) => {
|
||
const [showVideo, setShowVideo] = useState(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 getDifficultyColor = (difficulty: string) => {
|
||
switch (difficulty) {
|
||
case "easy":
|
||
return "text-emerald-400"
|
||
case "medium":
|
||
return "text-yellow-400"
|
||
case "hard":
|
||
return "text-red-400"
|
||
default:
|
||
return "text-slate-400"
|
||
}
|
||
}
|
||
|
||
const getDifficultyBg = (difficulty: string) => {
|
||
switch (difficulty) {
|
||
case "easy":
|
||
return "bg-emerald-500/20 border-emerald-500/30"
|
||
case "medium":
|
||
return "bg-yellow-500/20 border-yellow-500/30"
|
||
case "hard":
|
||
return "bg-red-500/20 border-red-500/30"
|
||
default:
|
||
return "bg-slate-500/20 border-slate-500/30"
|
||
}
|
||
}
|
||
|
||
const handleVideoToggle = () => {
|
||
setShowVideo((prev) => {
|
||
onVideoPlayToggle(!prev) // Уведомляем родителя об изменении состояния видео
|
||
return !prev
|
||
})
|
||
}
|
||
|
||
return (
|
||
<IonCard
|
||
className={`${exercise.completed ? "bg-emerald-50/80" : "bg-white/80"} backdrop-blur-sm border border-teal-200/50 shadow-md`}
|
||
>
|
||
<IonCardContent>
|
||
<div className="flex justify-between items-start mb-3">
|
||
<div className="flex-1">
|
||
<h3 className={`font-semibold ${exercise.completed ? "text-emerald-700" : "text-slate-800"}`}>
|
||
{exercise.name}
|
||
</h3>
|
||
<p className="text-sm text-slate-600 mt-1">{exercise.description}</p>
|
||
</div>
|
||
{exercise.completed && (
|
||
<IonBadge color="success" className="ml-2">
|
||
Выполнено
|
||
</IonBadge>
|
||
)}
|
||
</div>
|
||
|
||
{showVideo && exercise.videoUrl && (
|
||
<div className="mb-4 relative">
|
||
<video
|
||
src={exercise.videoUrl}
|
||
controls
|
||
poster={`/placeholder.svg?height=200&width=300&query=${encodeURIComponent(exercise.name)}`}
|
||
className="w-full rounded-lg"
|
||
>
|
||
Ваш браузер не поддерживает видео тег.
|
||
</video>
|
||
<IonButton
|
||
fill="clear"
|
||
size="small"
|
||
onClick={handleVideoToggle}
|
||
className="absolute top-2 right-2 text-white bg-black/50 rounded-full"
|
||
>
|
||
<IonIcon icon={closeCircleOutline} />
|
||
</IonButton>
|
||
</div>
|
||
)}
|
||
|
||
<div className="flex justify-between items-center">
|
||
<div className="flex items-center gap-3">
|
||
<span className="text-sm text-slate-500">{formatTime(exercise.duration)}</span>
|
||
<IonBadge
|
||
className={`${getDifficultyBg(exercise.difficulty)} ${getDifficultyColor(exercise.difficulty)} border`}
|
||
>
|
||
{exercise.difficulty === "easy" ? "Легко" : exercise.difficulty === "medium" ? "Средне" : "Сложно"}
|
||
</IonBadge>
|
||
</div>
|
||
|
||
<div className="flex gap-2">
|
||
{exercise.videoUrl && (
|
||
<IonButton
|
||
size="small"
|
||
onClick={handleVideoToggle}
|
||
className="bg-gradient-to-r from-blue-500 to-indigo-500"
|
||
disabled={isCurrent} // Отключаем кнопку видео, если упражнение активно
|
||
>
|
||
<IonIcon icon={videocamOutline} slot="start" />
|
||
{showVideo ? "Скрыть" : "Видео"}
|
||
</IonButton>
|
||
)}
|
||
|
||
{!exercise.completed && !isCurrent && (
|
||
<IonButton
|
||
size="small"
|
||
onClick={() => onStart(exercise)}
|
||
className="bg-gradient-to-r from-teal-500 to-cyan-500"
|
||
disabled={isDisabled || showVideo} // Отключаем кнопку, если другое упражнение активно или видео проигрывается
|
||
>
|
||
<IonIcon icon={playOutline} slot="start" />
|
||
Начать
|
||
</IonButton>
|
||
)}
|
||
{isCurrent && (
|
||
<IonBadge color="primary" className="ml-2 animate-pulse">
|
||
Активно
|
||
</IonBadge>
|
||
)}
|
||
</div>
|
||
</div>
|
||
</IonCardContent>
|
||
</IonCard>
|
||
)
|
||
}
|
||
|
||
export default ExerciseItem
|