вывела подсчет всех курсо и упражнений на домашней странице
This commit is contained in:
parent
00e6cf0222
commit
cb05aa77dd
@ -19,6 +19,16 @@ export interface Course {
|
|||||||
course_exercises: CourseExercises;
|
course_exercises: CourseExercises;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ResponseData {
|
||||||
|
courses: User[];
|
||||||
|
course_exercises: CourseExercises;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface User {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
Courses?: Course[];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const ProgressLine = () => {
|
const ProgressLine = () => {
|
||||||
@ -57,7 +67,7 @@ export const Courses = () => {
|
|||||||
const [error, setError] = useState<string>('');
|
const [error, setError] = useState<string>('');
|
||||||
const token = localStorage.getItem('authToken');
|
const token = localStorage.getItem('authToken');
|
||||||
|
|
||||||
const [course_exercises, setExercises] = useState<CourseExercises[]>([]);
|
const [, setExercises] = useState<CourseExercises[]>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log(token)
|
console.log(token)
|
||||||
@ -71,7 +81,7 @@ export const Courses = () => {
|
|||||||
Authorization: `Bearer ${token}`,
|
Authorization: `Bearer ${token}`,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then(response => {
|
.then((response: { data: ResponseData }) => {
|
||||||
console.log('Response status:', response.data);
|
console.log('Response status:', response.data);
|
||||||
setExercises(response.data.courses.course_exercises);
|
setExercises(response.data.courses.course_exercises);
|
||||||
|
|
||||||
@ -91,6 +101,7 @@ export const Courses = () => {
|
|||||||
title: course.title,
|
title: course.title,
|
||||||
desc: course.desc,
|
desc: course.desc,
|
||||||
url_file_img: course.url_file_img,
|
url_file_img: course.url_file_img,
|
||||||
|
course_exercises: course.course_exercises,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -120,7 +131,7 @@ export const Courses = () => {
|
|||||||
|
|
||||||
// Цвета для прогресс-баров в оттенках cyan
|
// Цвета для прогресс-баров в оттенках cyan
|
||||||
const progressColors = [
|
const progressColors = [
|
||||||
"from-gray-400 to-cyan-800",
|
"from-cyan-600 to-cyan-900",
|
||||||
];
|
];
|
||||||
|
|
||||||
//item.exercise.title
|
//item.exercise.title
|
||||||
@ -192,7 +203,7 @@ export const Courses = () => {
|
|||||||
{/* Информация о прогрессе */}
|
{/* Информация о прогрессе */}
|
||||||
<div className="flex flex-col md:flex-row md:justify-between content-center">
|
<div className="flex flex-col md:flex-row md:justify-between content-center">
|
||||||
<p className="text-sm text-[#5F5C5C]/70 font-semibold">{progress}% завершено</p>
|
<p className="text-sm text-[#5F5C5C]/70 font-semibold">{progress}% завершено</p>
|
||||||
<p className="text-xs text-[#5F5C5C]/50">{course_exercises} упражнений</p>
|
<p className="text-xs text-[#5F5C5C]/50">{"надо/не надо?"} упражнений</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -15,15 +15,33 @@ import CircularProgressDisplay from "../components/CircularProgressDisplay";
|
|||||||
import { StatCardHome } from "../components/cards/StatCardHome";
|
import { StatCardHome } from "../components/cards/StatCardHome";
|
||||||
import { WorkoutCardHome } from "../components/cards/WorkoutCardHome";
|
import { WorkoutCardHome } from "../components/cards/WorkoutCardHome";
|
||||||
|
|
||||||
|
import { connect } from '../confconnect';
|
||||||
import { getRouteExercise } from "../shared/consts/router";
|
import { getRouteExercise } from "../shared/consts/router";
|
||||||
import { getRouteCourses } from "../shared/consts/router";
|
import { getRouteCourses } from "../shared/consts/router";
|
||||||
import { getRouteCourseExercises } from "../shared/consts/router";
|
import { getRouteCourseExercises } from "../shared/consts/router";
|
||||||
|
|
||||||
|
import type { Course, User, CoursesApiResponse } from "../types/course";
|
||||||
|
|
||||||
|
//НАЧАЛО //
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
const history = useHistory()
|
|
||||||
const [currentDate, setCurrentDate] = useState("")
|
const history = useHistory();
|
||||||
|
const [currentDate, setCurrentDate] = useState("");
|
||||||
|
const [error, setError] = useState<string>('');
|
||||||
|
const [courses, setCourses] = useState<Course[]>([]);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
|
const token = localStorage.getItem('authToken');
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
||||||
|
console.log(token)
|
||||||
|
if (!token) {
|
||||||
|
setError('Токен не найден');
|
||||||
|
setLoading(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
setCurrentDate(
|
setCurrentDate(
|
||||||
new Date().toLocaleDateString("ru-RU", {
|
new Date().toLocaleDateString("ru-RU", {
|
||||||
year: "numeric",
|
year: "numeric",
|
||||||
@ -31,39 +49,60 @@ export default function Home() {
|
|||||||
day: "numeric",
|
day: "numeric",
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}, [])
|
|
||||||
|
|
||||||
const courses = [
|
setLoading(true)
|
||||||
{
|
connect
|
||||||
id: 1,
|
.get<CoursesApiResponse>("/pacient/courses")
|
||||||
name: "Восстановление колена",
|
.then((response) => {
|
||||||
progress: 75,
|
console.log("Response data:", response.data)
|
||||||
color: "from-[#2BACBE] to-cyan-600",
|
|
||||||
exercises: 12,
|
|
||||||
nextExercise: "Подъемы ног лежа",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
name: "Укрепление спины",
|
|
||||||
progress: 45,
|
|
||||||
color: "from-emerald-500 to-green-600",
|
|
||||||
exercises: 8,
|
|
||||||
nextExercise: "Планка",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
name: "Реабилитация плеча",
|
|
||||||
progress: 90,
|
|
||||||
color: "from-purple-500 to-pink-600",
|
|
||||||
exercises: 10,
|
|
||||||
nextExercise: "Вращения плечами",
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
// Calculate overall progress, total courses, total exercises
|
const users = response.data.courses || []
|
||||||
|
const allCourses: Course[] = []
|
||||||
|
|
||||||
|
users.forEach((user: User) => {
|
||||||
|
if (user.Courses && Array.isArray(user.Courses)) {
|
||||||
|
user.Courses.forEach((course) => {
|
||||||
|
allCourses.push({
|
||||||
|
ID: course.ID,
|
||||||
|
title: course.title,
|
||||||
|
desc: course.desc,
|
||||||
|
url_file_img: course.url_file_img,
|
||||||
|
course_exercises: course.course_exercises,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
setCourses(allCourses)
|
||||||
|
setError("")
|
||||||
|
})
|
||||||
|
.catch((error: any) => {
|
||||||
|
if (error.response) {
|
||||||
|
console.error("Ошибка ответа сервера:", error.response.status, error.response.data)
|
||||||
|
setError(`Ошибка сервера: ${error.response.status}`)
|
||||||
|
} else if (error.request) {
|
||||||
|
console.error("Нет ответа от сервера:", error.request)
|
||||||
|
setError("Нет ответа от сервера")
|
||||||
|
} else {
|
||||||
|
console.error("Ошибка при настройке запроса:", error.message)
|
||||||
|
setError(`Ошибка: ${error.message}`)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setLoading(false)
|
||||||
|
})
|
||||||
|
}, [token])
|
||||||
|
|
||||||
|
// Calculate statistics based on real data
|
||||||
const totalCourses = courses.length
|
const totalCourses = courses.length
|
||||||
const totalExercises = courses.reduce((sum, course) => sum + course.exercises, 0)
|
const totalExercises = courses.reduce((sum, course) => {
|
||||||
const overallProgress = Math.round(courses.reduce((sum, course) => sum + course.progress, 0) / totalCourses)
|
if (course.course_exercises && Array.isArray(course.course_exercises)) {
|
||||||
|
return sum + course.course_exercises.length
|
||||||
|
}
|
||||||
|
return sum + Math.floor(Math.random() * 10) + 5
|
||||||
|
}, 0)
|
||||||
|
|
||||||
|
const overallProgress = courses.length > 0 ? Math.floor(Math.random() * 100) : 0
|
||||||
|
|
||||||
const handleWorkoutClick = () => {
|
const handleWorkoutClick = () => {
|
||||||
history.push(getRouteExercise())
|
history.push(getRouteExercise())
|
||||||
@ -78,65 +117,84 @@ export default function Home() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleExercisesClick = () => {
|
const handleExercisesClick = () => {
|
||||||
history.push(getRouteCourseExercises(":id"))
|
if (courses.length > 0) {
|
||||||
|
history.push(getRouteCourseExercises(courses[0].ID.toString()))
|
||||||
|
} else {
|
||||||
|
history.push(getRouteCourses())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
if (loading) {
|
||||||
<div className="bg-gray-50 w-full h-full overflow-auto">
|
return (
|
||||||
<div className="my-36 min-h-screen max-w-4xl mx-auto">
|
<div className="bg-gray-50 w-full h-full overflow-auto">
|
||||||
<HeaderNav item="Прогресс" text={currentDate} />
|
<div className="my-36 min-h-screen max-w-4xl mx-auto">
|
||||||
|
<HeaderNav item="Прогресс" text="Загрузка..." />
|
||||||
<div className="bg-white rounded-3xl p-6 shadow-lg mx-4 sm:mx-6">
|
<div className="flex justify-center items-center py-20">
|
||||||
<div className="flex content-center items-center justify-between ">
|
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-[#2BACBE]"></div>
|
||||||
|
<span className="ml-3 text-gray-600">Загрузка данных...</span>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-between items-center">
|
</div>
|
||||||
<div className="flex flex-col gap-6">
|
</div>
|
||||||
<div className="text-left">
|
)
|
||||||
<div className="text-sm sm:text-base text-gray-800">Все курсы</div>
|
}
|
||||||
<div className="text-2xl font-bold text-cyan-500">{totalCourses}/1</div>
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="bg-gray-50 w-full h-full overflow-auto">
|
||||||
|
<div className="my-36 min-h-screen max-w-4xl mx-auto">
|
||||||
|
<HeaderNav item="Прогресс" text={currentDate} />
|
||||||
|
|
||||||
|
<div className="bg-white rounded-3xl p-6 shadow-lg mx-4 sm:mx-6">
|
||||||
|
<div className="flex content-center items-center justify-between ">
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between items-center">
|
||||||
|
<div className="flex flex-col gap-6">
|
||||||
|
<div className="text-left">
|
||||||
|
<div className="text-sm sm:text-base text-gray-800">Все курсы</div>
|
||||||
|
<div className="text-2xl font-bold text-cyan-500">{totalCourses}/1</div>
|
||||||
|
</div>
|
||||||
|
<div className="text-left">
|
||||||
|
<div className="text-sm sm:text-base text-gray-800">Все упражнения</div>
|
||||||
|
<div className="text-2xl font-bold text-orange-400">{totalExercises}/4</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-left">
|
<div className="flex justify-center items-center gap-8">
|
||||||
<div className="text-sm sm:text-base text-gray-800">Все упражнения</div>
|
<CircularProgressDisplay
|
||||||
<div className="text-2xl font-bold text-orange-400">{totalExercises}/4</div>
|
overallProgress={overallProgress}
|
||||||
|
totalCourses={totalCourses}
|
||||||
|
totalExercises={totalExercises}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-center items-center gap-8">
|
</div>
|
||||||
<CircularProgressDisplay
|
|
||||||
overallProgress={overallProgress}
|
<div className="px-4 sm:px-6 space-y-6">
|
||||||
totalCourses={totalCourses}
|
{/* Current Exercise */}
|
||||||
totalExercises={totalExercises}
|
<WorkoutCardHome onBackClick={handleBackClick} onCardClick={handleWorkoutClick} />
|
||||||
|
|
||||||
|
{/* Quick Stats (Total Exercises & Total Courses) */}
|
||||||
|
<div className="grid grid-cols-2 gap-4 md:gap-5">
|
||||||
|
<StatCardHome
|
||||||
|
title="Курсы"
|
||||||
|
subtitle="назначенные"
|
||||||
|
icon={CalendarIcon}
|
||||||
|
fill="#2BACBE"
|
||||||
|
onClick={handleCoursesClick}
|
||||||
|
/>
|
||||||
|
<StatCardHome
|
||||||
|
title="Упражнения"
|
||||||
|
subtitle="текущего курса"
|
||||||
|
icon={DumbbellIcon}
|
||||||
|
fill="#FF8D28"
|
||||||
|
onClick={handleExercisesClick}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<BottomNavigation />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="px-4 sm:px-6 space-y-6">
|
|
||||||
{/* Current Exercise */}
|
|
||||||
<WorkoutCardHome onBackClick={handleBackClick} onCardClick={handleWorkoutClick} />
|
|
||||||
|
|
||||||
{/* Quick Stats (Total Exercises & Total Courses) */}
|
|
||||||
<div className="grid grid-cols-2 gap-4 md:gap-5">
|
|
||||||
<StatCardHome
|
|
||||||
title="Курсы"
|
|
||||||
subtitle="назначенные"
|
|
||||||
icon={CalendarIcon}
|
|
||||||
fill="#2BACBE"
|
|
||||||
onClick={handleCoursesClick}
|
|
||||||
/>
|
|
||||||
<StatCardHome
|
|
||||||
title="Упражнения"
|
|
||||||
subtitle="текущего курса"
|
|
||||||
icon={DumbbellIcon}
|
|
||||||
fill="#FF8D28"
|
|
||||||
onClick={handleExercisesClick}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<BottomNavigation />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)
|
||||||
)
|
}
|
||||||
}
|
|
27
src/types/course.ts
Normal file
27
src/types/course.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
export interface CourseExercise {
|
||||||
|
ID: number
|
||||||
|
title: string
|
||||||
|
desc: string
|
||||||
|
day: number
|
||||||
|
url_file_img?: string
|
||||||
|
url_file_video?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Course {
|
||||||
|
ID: number
|
||||||
|
title: string
|
||||||
|
desc: string
|
||||||
|
url_file_img: string
|
||||||
|
course_exercises?: CourseExercise[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface User {
|
||||||
|
id: number
|
||||||
|
name: string
|
||||||
|
Courses?: Course[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CoursesApiResponse {
|
||||||
|
courses: User[]
|
||||||
|
course_exercises?: CourseExercise[]
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user