diff --git a/front/src/pages/routine/List.jsx b/front/src/pages/routine/List.jsx index dd20552fcb86b74eaf411ba221d259063a7a7e63..aad379cf87c75e35280c86756c8aa789085e629b 100644 --- a/front/src/pages/routine/List.jsx +++ b/front/src/pages/routine/List.jsx @@ -1,211 +1,309 @@ -import React, { useState } from "react"; +import React, { useState, useEffect } from "react"; import "./List.css"; import truncateText from './truncateText'; +import { getUserRoutines, getRoutineVideos, deleteRoutine } from './api'; + +const initialRoutines = [ + { + id: 1, + name: "전신 루틴", + exercises: [ + { title: "전신 운동 1", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail1", link: "https://www.youtube.com/watch?v=example1", duration: 300, canceled: false }, + { title: "전신 운동 2", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail2", link: "https://www.youtube.com/watch?v=example2", duration: 420, canceled: false }, + { title: "전신 운동 3", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail3", link: "https://www.youtube.com/watch?v=example3", duration: 350, canceled: false }, + ], + }, + { + id: 2, + name: "상체 루틴", + exercises: [ + { title: "상체 운동 1", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail1", link: "https://www.youtube.com/watch?v=example11", duration: 360, canceled: false }, + { title: "상체 운동 2", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail2", link: "https://www.youtube.com/watch?v=example12", duration: 400, canceled: false }, + { title: "상체 운동 3", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail3", link: "https://www.youtube.com/watch?v=example13", duration: 330, canceled: false }, + { title: "상체 운동 4", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail4", link: "https://www.youtube.com/watch?v=example14", duration: 470, canceled: false }, + { title: "상체 운동 5", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail5", link: "https://www.youtube.com/watch?v=example15", duration: 380, canceled: false }, + { title: "상체 운동 6", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail6", link: "https://www.youtube.com/watch?v=example16", duration: 390, canceled: false }, + { title: "상체 운동 7", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail7", link: "https://www.youtube.com/watch?v=example17", duration: 420, canceled: false }, + { title: "상체 운동 8", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail8", link: "https://www.youtube.com/watch?v=example18", duration: 440, canceled: false }, + { title: "상체 운동 9", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail9", link: "https://www.youtube.com/watch?v=example19", duration: 350, canceled: false }, + { title: "상체 운동 10", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail10", link: "https://www.youtube.com/watch?v=example20", duration: 500, canceled: false }, + ], + }, + { + id: 3, + name: "하체 루틴", + exercises: [ + { title: "하체 운동 1", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail1", link: "https://www.youtube.com/watch?v=example21", duration: 350, canceled: false }, + { title: "하체 운동 2", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail2", link: "https://www.youtube.com/watch?v=example22", duration: 450, canceled: false }, + { title: "하체 운동 3", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail3", link: "https://www.youtube.com/watch?v=example23", duration: 400, canceled: false }, + { title: "하체 운동 4", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail4", link: "https://www.youtube.com/watch?v=example24", duration: 500, canceled: false }, + { title: "하체 운동 5", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail5", link: "https://www.youtube.com/watch?v=example25", duration: 480, canceled: false }, + { title: "하체 운동 6", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail6", link: "https://www.youtube.com/watch?v=example26", duration: 420, canceled: false }, + { title: "하체 운동 7", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail7", link: "https://www.youtube.com/watch?v=example27", duration: 430, canceled: false }, + { title: "하체 운동 8", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail8", link: "https://www.youtube.com/watch?v=example28", duration: 360, canceled: false }, + { title: "하체 운동 9", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail9", link: "https://www.youtube.com/watch?v=example29", duration: 490, canceled: false }, + { title: "하체 운동 10", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail10", link: "https://www.youtube.com/watch?v=example30", duration: 460, canceled: false }, + ], + }, + { + id: 4, + name: "복부 루틴", + exercises: [ + { title: "복부 운동 1", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail1", link: "https://www.youtube.com/watch?v=example31", duration: 400, canceled: false }, + { title: "복부 운동 2", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail2", link: "https://www.youtube.com/watch?v=example32", duration: 300, canceled: false }, + { title: "복부 운동 3", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail3", link: "https://www.youtube.com/watch?v=example33", duration: 350, canceled: false }, + { title: "복부 운동 4", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail4", link: "https://www.youtube.com/watch?v=example34", duration: 380, canceled: false }, + { title: "복부 운동 5", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail5", link: "https://www.youtube.com/watch?v=example35", duration: 320, canceled: false }, + { title: "복부 운동 6", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail6", link: "https://www.youtube.com/watch?v=example36", duration: 370, canceled: false }, + { title: "복부 운동 7", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail7", link: "https://www.youtube.com/watch?v=example37", duration: 390, canceled: false }, + { title: "복부 운동 8", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail8", link: "https://www.youtube.com/watch?v=example38", duration: 430, canceled: false }, + { title: "복부 운동 9", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail9", link: "https://www.youtube.com/watch?v=example39", duration: 480, canceled: false }, + { title: "복부 운동 10", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail10", link: "https://www.youtube.com/watch?v=example40", duration: 500, canceled: false }, + ], + }, + { + id: 5, + name: "유산소 루틴", + exercises: [ + { title: "유산소 운동 1", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail1", link: "https://www.youtube.com/watch?v=example41", duration: 600, canceled: false }, + { title: "유산소 운동 2", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail2", link: "https://www.youtube.com/watch?v=example42", duration: 500, canceled: false }, + { title: "유산소 운동 3", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail3", link: "https://www.youtube.com/watch?v=example43", duration: 550, canceled: false }, + { title: "유산소 운동 4", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail4", link: "https://www.youtube.com/watch?v=example44", duration: 510, canceled: false }, + { title: "유산소 운동 5", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail5", link: "https://www.youtube.com/watch?v=example45", duration: 560, canceled: false }, + { title: "유산소 운동 6", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail6", link: "https://www.youtube.com/watch?v=example46", duration: 530, canceled: false }, + { title: "유산소 운동 7", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail7", link: "https://www.youtube.com/watch?v=example47", duration: 480, canceled: false }, + { title: "유산소 운동 8", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail8", link: "https://www.youtube.com/watch?v=example48", duration: 540, canceled: false }, + { title: "유산소 운동 9", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail9", link: "https://www.youtube.com/watch?v=example49", duration: 490, canceled: false }, + { title: "유산소 운동 10", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail10", link: "https://www.youtube.com/watch?v=example50", duration: 520, canceled: false }, + ], + }, + { + id: 6, + name: "스트레칭 루틴", + exercises: [ + { title: "스트레칭 운동 1", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail1", link: "https://www.youtube.com/watch?v=example51", duration: 300, canceled: false }, + { title: "스트레칭 운동 2", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail2", link: "https://www.youtube.com/watch?v=example52", duration: 400, canceled: false }, + { title: "스트레칭 운동 3", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail3", link: "https://www.youtube.com/watch?v=example53", duration: 350, canceled: false }, + { title: "스트레칭 운동 4", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail4", link: "https://www.youtube.com/watch?v=example54", duration: 300, canceled: false }, + { title: "스트레칭 운동 5", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail5", link: "https://www.youtube.com/watch?v=example55", duration: 380, canceled: false }, + { title: "스트레칭 운동 6", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail6", link: "https://www.youtube.com/watch?v=example56", duration: 420, canceled: false }, + { title: "스트레칭 운동 7", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail7", link: "https://www.youtube.com/watch?v=example57", duration: 440, canceled: false }, + { title: "스트레칭 운동 8", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail8", link: "https://www.youtube.com/watch?v=example58", duration: 450, canceled: false }, + { title: "스트레칭 운동 9", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail9", link: "https://www.youtube.com/watch?v=example59", duration: 500, canceled: false }, + { title: "스트레칭 운동 10", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail10", link: "https://www.youtube.com/watch?v=example60", duration: 480, canceled: false }, + ], + }, + { + id: 7, + name: "등 루틴", + exercises: [ + { title: "업그레이드를 위한 새로운 등운동 [ BACK DAY ]", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail1", link: "https://www.youtube.com/watch?v=f7wFbp9BnFs", duration: 300, canceled: false }, + { title: "뚫고 나오는 등 만들고 싶으면 이거 봐", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail2", link: "https://www.youtube.com/watch?v=8SBBp65Sv3c", duration: 400, canceled: false }, + { title: "Try This Back Exercise | Back & Hamstrings Workout", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail3", link: "https://www.youtube.com/watch?v=nRzAV-CYndA", duration: 350, canceled: false }, + { title: "My Title Winning Back Training", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail4", link: "https://www.youtube.com/watch?v=5dp2FUN3mRQ", duration: 300, canceled: false }, + { title: "Back and Delts Workout", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail5", link: "https://www.youtube.com/watch?v=DjfnFj-50b4", duration: 380, canceled: false }, + { title: "INTENSE Back Workout | Mr. Olympia Derek Lunsford", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail6", link: "https://www.youtube.com/watch?v=HYngFKG5YbY&t=477s", duration: 420, canceled: false }, + { title: "Mr. Olympia BACK WORKOUT", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail7", link: "https://www.youtube.com/watch?v=HqZOWPRyck8&t=134s", duration: 440, canceled: false }, + { title: "등 운동 후 몽둥이질 당한 느낌이 나게 하는 방법들", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail8", link: "https://www.youtube.com/watch?v=OD1JMTLJp-A", duration: 450, canceled: false }, + { title: "등 운동 하는 날 반드시 시청해야 할 영상 ( feat.등 운동 루틴 풀버전 ) 등 운동 하는 날 반드시 시청해야 할 영상 ( feat.등 운동 루틴 풀버전 ) 등 운동 하는 날 반드시 시청해야 할 영상 ( feat.등 운동 루틴 풀버전 ) 등 운동 하는 날 반드시 시청해야 할 영상 ( feat.등 운동 루틴 풀버전 ) 등 운동 하는 날 반드시 시청해야 할 영상 ( feat.등 운동 루틴 풀버전 ) 등 운동 하는 날 반드시 시청해야 할 영상 ( feat.등 운동 루틴 풀버전 ) 등 운동 하는 날 반드시 시청해야 할 영상 ( feat.등 운동 루틴 풀버전 ) ", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail9", link: "https://www.youtube.com/watch?v=naxGvgl9pKg&t=1102s", duration: 500, canceled: false }, + { title: "요즘 유행하는 등 운동 루틴", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail10", link: "https://www.youtube.com/watch?v=XLCtwqECMrs&t=279s", duration: 480, canceled: false }, + ], + }, +]; function List({ onRoutineSelect, isActive }) { - const initialRoutines = [ - { - id: 1, - name: "전신 루틴", - exercises: [ - { title: "전신 운동 1", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail1", link: "https://www.youtube.com/watch?v=example1", duration: 300, canceled: false }, - { title: "전신 운동 2", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail2", link: "https://www.youtube.com/watch?v=example2", duration: 420, canceled: false }, - { title: "전신 운동 3", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail3", link: "https://www.youtube.com/watch?v=example3", duration: 350, canceled: false }, - ], - }, - { - id: 2, - name: "상체 루틴", - exercises: [ - { title: "상체 운동 1", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail1", link: "https://www.youtube.com/watch?v=example11", duration: 360, canceled: false }, - { title: "상체 운동 2", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail2", link: "https://www.youtube.com/watch?v=example12", duration: 400, canceled: false }, - { title: "상체 운동 3", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail3", link: "https://www.youtube.com/watch?v=example13", duration: 330, canceled: false }, - { title: "상체 운동 4", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail4", link: "https://www.youtube.com/watch?v=example14", duration: 470, canceled: false }, - { title: "상체 운동 5", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail5", link: "https://www.youtube.com/watch?v=example15", duration: 380, canceled: false }, - { title: "상체 운동 6", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail6", link: "https://www.youtube.com/watch?v=example16", duration: 390, canceled: false }, - { title: "상체 운동 7", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail7", link: "https://www.youtube.com/watch?v=example17", duration: 420, canceled: false }, - { title: "상체 운동 8", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail8", link: "https://www.youtube.com/watch?v=example18", duration: 440, canceled: false }, - { title: "상체 운동 9", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail9", link: "https://www.youtube.com/watch?v=example19", duration: 350, canceled: false }, - { title: "상체 운동 10", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail10", link: "https://www.youtube.com/watch?v=example20", duration: 500, canceled: false }, - ], - }, - { - id: 3, - name: "하체 루틴", - exercises: [ - { title: "하체 운동 1", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail1", link: "https://www.youtube.com/watch?v=example21", duration: 350, canceled: false }, - { title: "하체 운동 2", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail2", link: "https://www.youtube.com/watch?v=example22", duration: 450, canceled: false }, - { title: "하체 운동 3", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail3", link: "https://www.youtube.com/watch?v=example23", duration: 400, canceled: false }, - { title: "하체 운동 4", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail4", link: "https://www.youtube.com/watch?v=example24", duration: 500, canceled: false }, - { title: "하체 운동 5", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail5", link: "https://www.youtube.com/watch?v=example25", duration: 480, canceled: false }, - { title: "하체 운동 6", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail6", link: "https://www.youtube.com/watch?v=example26", duration: 420, canceled: false }, - { title: "하체 운동 7", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail7", link: "https://www.youtube.com/watch?v=example27", duration: 430, canceled: false }, - { title: "하체 운동 8", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail8", link: "https://www.youtube.com/watch?v=example28", duration: 360, canceled: false }, - { title: "하체 운동 9", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail9", link: "https://www.youtube.com/watch?v=example29", duration: 490, canceled: false }, - { title: "하체 운동 10", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail10", link: "https://www.youtube.com/watch?v=example30", duration: 460, canceled: false }, - ], - }, - { - id: 4, - name: "복부 루틴", - exercises: [ - { title: "복부 운동 1", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail1", link: "https://www.youtube.com/watch?v=example31", duration: 400, canceled: false }, - { title: "복부 운동 2", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail2", link: "https://www.youtube.com/watch?v=example32", duration: 300, canceled: false }, - { title: "복부 운동 3", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail3", link: "https://www.youtube.com/watch?v=example33", duration: 350, canceled: false }, - { title: "복부 운동 4", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail4", link: "https://www.youtube.com/watch?v=example34", duration: 380, canceled: false }, - { title: "복부 운동 5", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail5", link: "https://www.youtube.com/watch?v=example35", duration: 320, canceled: false }, - { title: "복부 운동 6", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail6", link: "https://www.youtube.com/watch?v=example36", duration: 370, canceled: false }, - { title: "복부 운동 7", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail7", link: "https://www.youtube.com/watch?v=example37", duration: 390, canceled: false }, - { title: "복부 운동 8", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail8", link: "https://www.youtube.com/watch?v=example38", duration: 430, canceled: false }, - { title: "복부 운동 9", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail9", link: "https://www.youtube.com/watch?v=example39", duration: 480, canceled: false }, - { title: "복부 운동 10", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail10", link: "https://www.youtube.com/watch?v=example40", duration: 500, canceled: false }, - ], - }, - { - id: 5, - name: "유산소 루틴", - exercises: [ - { title: "유산소 운동 1", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail1", link: "https://www.youtube.com/watch?v=example41", duration: 600, canceled: false }, - { title: "유산소 운동 2", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail2", link: "https://www.youtube.com/watch?v=example42", duration: 500, canceled: false }, - { title: "유산소 운동 3", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail3", link: "https://www.youtube.com/watch?v=example43", duration: 550, canceled: false }, - { title: "유산소 운동 4", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail4", link: "https://www.youtube.com/watch?v=example44", duration: 510, canceled: false }, - { title: "유산소 운동 5", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail5", link: "https://www.youtube.com/watch?v=example45", duration: 560, canceled: false }, - { title: "유산소 운동 6", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail6", link: "https://www.youtube.com/watch?v=example46", duration: 530, canceled: false }, - { title: "유산소 운동 7", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail7", link: "https://www.youtube.com/watch?v=example47", duration: 480, canceled: false }, - { title: "유산소 운동 8", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail8", link: "https://www.youtube.com/watch?v=example48", duration: 540, canceled: false }, - { title: "유산소 운동 9", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail9", link: "https://www.youtube.com/watch?v=example49", duration: 490, canceled: false }, - { title: "유산소 운동 10", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail10", link: "https://www.youtube.com/watch?v=example50", duration: 520, canceled: false }, - ], - }, - { - id: 6, - name: "스트레칭 루틴", - exercises: [ - { title: "스트레칭 운동 1", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail1", link: "https://www.youtube.com/watch?v=example51", duration: 300, canceled: false }, - { title: "스트레칭 운동 2", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail2", link: "https://www.youtube.com/watch?v=example52", duration: 400, canceled: false }, - { title: "스트레칭 운동 3", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail3", link: "https://www.youtube.com/watch?v=example53", duration: 350, canceled: false }, - { title: "스트레칭 운동 4", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail4", link: "https://www.youtube.com/watch?v=example54", duration: 300, canceled: false }, - { title: "스트레칭 운동 5", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail5", link: "https://www.youtube.com/watch?v=example55", duration: 380, canceled: false }, - { title: "스트레칭 운동 6", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail6", link: "https://www.youtube.com/watch?v=example56", duration: 420, canceled: false }, - { title: "스트레칭 운동 7", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail7", link: "https://www.youtube.com/watch?v=example57", duration: 440, canceled: false }, - { title: "스트레칭 운동 8", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail8", link: "https://www.youtube.com/watch?v=example58", duration: 450, canceled: false }, - { title: "스트레칭 운동 9", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail9", link: "https://www.youtube.com/watch?v=example59", duration: 500, canceled: false }, - { title: "스트레칭 운동 10", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail10", link: "https://www.youtube.com/watch?v=example60", duration: 480, canceled: false }, - ], - }, - { - id: 7, - name: "등 루틴", - exercises: [ - { title: "업그레이드를 위한 새로운 등운동 [ BACK DAY ]", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail1", link: "https://www.youtube.com/watch?v=f7wFbp9BnFs", duration: 300, canceled: false }, - { title: "뚫고 나오는 등 만들고 싶으면 이거 봐", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail2", link: "https://www.youtube.com/watch?v=8SBBp65Sv3c", duration: 400, canceled: false }, - { title: "Try This Back Exercise | Back & Hamstrings Workout", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail3", link: "https://www.youtube.com/watch?v=nRzAV-CYndA", duration: 350, canceled: false }, - { title: "My Title Winning Back Training", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail4", link: "https://www.youtube.com/watch?v=5dp2FUN3mRQ", duration: 300, canceled: false }, - { title: "Back and Delts Workout", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail5", link: "https://www.youtube.com/watch?v=DjfnFj-50b4", duration: 380, canceled: false }, - { title: "INTENSE Back Workout | Mr. Olympia Derek Lunsford", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail6", link: "https://www.youtube.com/watch?v=HYngFKG5YbY&t=477s", duration: 420, canceled: false }, - { title: "Mr. Olympia BACK WORKOUT", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail7", link: "https://www.youtube.com/watch?v=HqZOWPRyck8&t=134s", duration: 440, canceled: false }, - { title: "등 운동 후 몽둥이질 당한 느낌이 나게 하는 방법들", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail8", link: "https://www.youtube.com/watch?v=OD1JMTLJp-A", duration: 450, canceled: false }, - { title: "등 운동 하는 날 반드시 시청해야 할 영상 ( feat.등 운동 루틴 풀버전 ) 등 운동 하는 날 반드시 시청해야 할 영상 ( feat.등 운동 루틴 풀버전 ) 등 운동 하는 날 반드시 시청해야 할 영상 ( feat.등 운동 루틴 풀버전 ) 등 운동 하는 날 반드시 시청해야 할 영상 ( feat.등 운동 루틴 풀버전 ) 등 운동 하는 날 반드시 시청해야 할 영상 ( feat.등 운동 루틴 풀버전 ) 등 운동 하는 날 반드시 시청해야 할 영상 ( feat.등 운동 루틴 풀버전 ) 등 운동 하는 날 반드시 시청해야 할 영상 ( feat.등 운동 루틴 풀버전 ) ", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail9", link: "https://www.youtube.com/watch?v=naxGvgl9pKg&t=1102s", duration: 500, canceled: false }, - { title: "요즘 유행하는 등 운동 루틴", thumbnail: "https://via.placeholder.com/150x100.png?text=Thumbnail10", link: "https://www.youtube.com/watch?v=XLCtwqECMrs&t=279s", duration: 480, canceled: false }, - ], - }, - ]; - const [routines] = useState(initialRoutines); // 루틴 목록 + const [routines, setRoutines] = useState(initialRoutines); // 루틴 목록 const [selectedRoutine, setSelectedRoutine] = useState(null); // 선택한 루틴 + const [modify, setModify] = useState(false); + const [isModalOpen, setIsModalOpen] = useState(false); - /* - 루틴 목록에서 원하는 루틴 클릭 시 해당 루틴을 selectedRoutine으로 설정하여 - 해당 루틴 운동 목록화면으로 전환 - */ - const handleRoutineClick = (routine) => { - setSelectedRoutine(routine); + const modalStyle = { + position: 'fixed', + top: 0, + left: 0, + width: '100%', + height: '100%', + color: '#000000', + background: 'rgba(0, 0, 0, 0.1)', + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + zIndex: 9999, }; - - /* - 뒤로가기 클릭 시 selectedRoutine 값을 null로 설정하여 루틴 목록화면으로 전환 - */ - const handleBackClick = () => { - setSelectedRoutine(null); + + const modalContentStyle = { + background: 'white', + padding: '40px', + fontSize: '25px', + borderRadius: '10px', + textAlign: 'center', + boxShadow: '0 4px 10px rgba(0, 0, 0, 0.3)', + }; + + const buttonStyle = { + height: '60px', + width: '140px', + margin: '30px', + fontSize: '0.7em', + cursor: 'pointer', }; - /* - 토글 클릭 시 해당 운동의 루틴 제외 여부 설정 - */ - const toggleCancelExercise = (exercise) => { - const updatedExercises = selectedRoutine.exercises.map((ex) => - ex.title === exercise.title ? { ...ex, canceled: !ex.canceled } : ex +const fetchRoutines = async () => { + try { + const data = await getUserRoutines(); + fetchExercises(data); + } catch (err) { + alert(err); + } +}; + +const fetchExercises = async (routines) => { + try { + const updatedRoutines = await Promise.all( + routines.map(async (rt) => { + const data = await getRoutineVideos(rt.name); + const updatedExercises = data.map((exercise) => ({ + ...exercise, + canceled: false, + })); + return { ...rt, exercises: updatedExercises }; + }) ); - setSelectedRoutine({ ...selectedRoutine, exercises: updatedExercises }); - }; + setRoutines(updatedRoutines); + } catch (err) { + alert(err); + } +}; - return ( - <div id="list-container"> - {!selectedRoutine ? ( - <div className="list-head"> - {/*selectedRoutine이 null로 루틴 목록 화면 표시*/} - <div> - <span>routine</span> - <div className="division-line"></div> - </div> - <div id="list-content"> - <ul> - {routines.map((routine) => ( - <li key={routine.id} onClick={() => handleRoutineClick(routine)}> - <span>{truncateText(routine.name, 10)}</span> - </li> - ))} - </ul> - </div> +useEffect(() => { + fetchRoutines(); +}, []); + +/* + 루틴 목록에서 원하는 루틴 클릭 시 해당 루틴을 selectedRoutine으로 설정하여 + 해당 루틴 운동 목록화면으로 전환 +*/ +const handleRoutineClick = (routine) => { + if (!modify) setSelectedRoutine(routine); + +}; + +/* + 뒤로가기 클릭 시 selectedRoutine 값을 null로 설정하여 루틴 목록화면으로 전환 +*/ +const handleBackClick = () => { + setSelectedRoutine(null); +}; + +const handledelete = async (name) => { + try { + await deleteRoutine(name); + setIsModalOpen(false); + } catch (err) { + alert(err); + } +}; + +/* + 토글 클릭 시 해당 운동의 루틴 제외 여부 설정 +*/ +const toggleCancelExercise = (exercise) => { + const updatedExercises = selectedRoutine.exercises.map((ex) => + ex.title === exercise.title ? { ...ex, canceled: !ex.canceled } : ex + ); + setSelectedRoutine({ ...selectedRoutine, exercises: updatedExercises }); +}; + +return ( + <div id="list-container"> + {!selectedRoutine ? ( + <div className="list-head"> + {/*selectedRoutine이 null로 루틴 목록 화면 표시*/} + <div> + <span>routine</span> + <div className="division-line"></div> </div> - ) : ( - <div className="list-head"> - {/*selectedRoutine이 설정 되어 운동 목록 화면 표시*/} - <div> - <span>{selectedRoutine.name}</span> - <div className="division-line"></div> - </div> - <div id="list-content"> - <ul> - {selectedRoutine.exercises.map((exercise, index) => ( - <li key={index}> - <span - style={{ - textDecoration: exercise.canceled ? "line-through" : "none", - }} - > - {truncateText(exercise.title, 11)} - </span> - <button onClick={() => toggleCancelExercise(exercise)}> - {exercise.canceled ? "X" : "O"} - </button> - </li> - ))} - </ul> - <div className="list-foot"> - <button - className="pick" - onClick={() => { - if (!isActive) { - onRoutineSelect({ - ...selectedRoutine, - exercises: selectedRoutine.exercises.filter( - (exercise) => !exercise.canceled - ), - }); - } - }} - > - 선택 - </button> - <button onClick={handleBackClick}>뒤로가기</button> - </div> + <div id="list-content"> + <ul> + {routines.map((routine) => ( + <li key={routine.id} onClick={() => handleRoutineClick(routine)}> + <span>{truncateText(routine.name, 10)}</span> + {modify && ( + <button onClick={(e) => { + e.stopPropagation(); // 이벤트 전파 중단 + setIsModalOpen(true); + }}>X</button> + + )} + {isModalOpen && ( + <div style={modalStyle}> + <div style={modalContentStyle}> + <div> + 루틴을 삭제하겠습니까? + <div> + <button style={buttonStyle} onClick={() => handledelete(routine.title)}>삭제</button> + <button style={buttonStyle} onClick={() => setIsModalOpen(false)}>취소</button> + </div> + </div> + </div> + </div> + )} + </li> + ))} + </ul> + {!modify ? (<button className='back' onClick={() => setModify(true)}>수정</button> + ) : (<button className='back' onClick={() => setModify(false)}>뒤로가기</button>)} + </div> + </div> + ) : ( + <div className="list-head"> + {/*selectedRoutine이 설정 되어 운동 목록 화면 표시*/} + <div> + <span>{selectedRoutine.name}</span> + <div className="division-line"></div> + </div> + <div id="list-content"> + <ul> + {selectedRoutine.exercises.map((exercise, index) => ( + <li key={index}> + <span + style={{ + textDecoration: exercise.canceled ? "line-through" : "none", + }} + > + {truncateText(exercise.title, 11)} + </span> + <button onClick={() => toggleCancelExercise(exercise)}> + {exercise.canceled ? "X" : "O"} + </button> + </li> + ))} + </ul> + <div className="list-foot"> + <button + className="pick" + onClick={() => { + if (!isActive) { + onRoutineSelect({ + ...selectedRoutine, + exercises: selectedRoutine.exercises.filter( + (exercise) => !exercise.canceled + ), + }); + } + }} + > + 선택 + </button> + <button className='back' onClick={handleBackClick}>뒤로가기</button> </div> </div> - ) - } - </div > - ); + </div> + ) + } + </div > +); } export default List; diff --git a/front/src/pages/routine/Now.css b/front/src/pages/routine/Now.css index d2c42b224f457754b8e4dad08a518830a5251470..2514ef7accaa8c4c623d5f33de914750b00bd76c 100644 --- a/front/src/pages/routine/Now.css +++ b/front/src/pages/routine/Now.css @@ -33,12 +33,27 @@ /* 선택 사항: 그림자 추가 */ } -.underbar{ +.underbar { display: flex; + align-items: center; + justify-items: center; + width: 420px; + height: 60px; +} + +.underbar button { + width: 110px; + height: 45px; + margin-top: 0px; + border-radius: 7px; + cursor: pointer; } -.now-container button{ - width: 80px; - height: 30px; - margin: 20px; +.now-content { + display: flex; + align-items: center; + font-size: 22px; + font-weight: 600; + width: 420px; + height: 160px; } \ No newline at end of file diff --git a/front/src/pages/routine/Now.jsx b/front/src/pages/routine/Now.jsx index c848cacbe8e23f17f5e23bbeacdae848be8264fa..e11ddf1e8cf227b2c9bb4c98e0dc777000fe4602 100644 --- a/front/src/pages/routine/Now.jsx +++ b/front/src/pages/routine/Now.jsx @@ -11,7 +11,7 @@ function Now({ isActive, onPause, isPaused, - onAddTime, + onAddTime, endSignal }) { const [exerciseTime, setExerciseTime] = useState(0); // 현재 운동 타이머 @@ -20,6 +20,7 @@ function Now({ const [isTakingBreak, setIsTakingBreak] = useState(false); // 운동 중 휴식 상태 const [isModalOpen, setIsModalOpen] = useState(false); // 모달 여부 const [isFlag, setFlag] = useState(true); + const [oneRest, setoneRest] = useState(false); /* 운동 시작 전 설정한 휴식 시간으로 타이머 시간 설정 @@ -27,17 +28,16 @@ function Now({ useEffect(() => { if (!isActive) setRestTimeLeft(restSeconds); }, [restTimeLeft]); - + /* 마지막 운동에 대한 시간 전달 */ useEffect(() => { - if (endSignal&&!isFlag){ + if (endSignal) { onAddTime(`Exercise: ${exerciseTime}`); - setFlag(true); } - }, [exerciseTime]); - + }, [exerciseTime,endSignal]); + /* 운동 시간 타이머 */ @@ -63,7 +63,7 @@ function Now({ return () => clearInterval(timer); }, [isTakingBreak]); - + /* 쉬는 시간 타이머 4초 남을 시 모달 오픈 1초 남을 시 다음 운동으로 넘어감 @@ -75,6 +75,10 @@ function Now({ setRestTimeLeft((prev) => { if (prev <= 1) { onNext(); + if (!isRest && !isFlag && isActive) { + onAddTime(`Rest: ${restSeconds}`); + } else if (!isRest && isFlag && isActive) setFlag(false); + setoneRest(false); } if (prev <= 4) { setIsModalOpen(true); @@ -85,7 +89,7 @@ function Now({ return () => clearInterval(timer); }, [isRest, isPaused, isActive, isTakingBreak]); - + /* 다음 운동으로 넘어 갈 시 운동 시간 전달 휴식 종료시 쉬는 시간 전달 @@ -97,24 +101,28 @@ function Now({ onAddTime(`Exercise: ${exerciseTime}`); setExerciseTime(0); setRestTimeLeft(restSeconds); - } else if (!isRest && !isFlag && isActive) onAddTime(`Rest: ${restSeconds}`); - else if (!isRest && isFlag && isActive) setFlag(false); + } }, [currentVideo, isRest, isActive]); const handleRestStart = () => { - if (!isPaused && isActive) setIsTakingBreak(true); + if (!isPaused && isActive && !oneRest) { + setIsTakingBreak(true); + setoneRest(true); + } }; const handleRestStop = () => { - setIsTakingBreak(false); - onAddTime(`Rest: ${restTime}`); - setRestTime(0); + if (isTakingBreak) { + setIsTakingBreak(false); + onAddTime(`Rest: ${restTime}`); + setRestTime(0); + } }; /* 휴식 때 Next 클릭시 쉬는 시간 전달 및 쉬는 시간 4초로 변경 운동 시작 전이면 그냥 다음 영상으로 넘김 - */ + */ const handleRestNext = () => { if (isActive) { onAddTime(`Rest: ${restSeconds - restTimeLeft}`); @@ -124,26 +132,34 @@ function Now({ }; return ( - <div className={`now-container ${isRest ? "rest-highlight" : ""}`}> + <div className='now-container'> {isTakingBreak ? ( - <div className="now-break"> - <p>Taking a Break</p> - <h3>{formatTime(restTime)}</h3> - <button className="stop-rest-button" onClick={handleRestStop}> - Resume Exercise - </button> + <div> + <div className='now-content'> + <span>Taking a Break / </span> + <span> / {formatTime(restTime)}</span> + </div> + <div className="underbar"> + <button onClick={handleRestStop}> + Go back + </button> + </div> </div> ) : isRest ? ( - <div className="now-rest"> - <p>Rest Period</p> - {!isModalOpen ? ( - <h3>{formatTime(restTimeLeft)}</h3> - ) : ( - <h3>다음 운동으로</h3> - )} - <button className="next-button" onClick={handleRestNext}> - Next - </button> + <div> + <div className='now-content'> + <span>Rest Period / </span> + {!isModalOpen ? ( + <span>/ {formatTime(restTimeLeft)}</span> + ) : ( + <span>/ 다음 운동으로</span> + )} + </div> + <div className="underbar"> + <button className="next-button" onClick={handleRestNext}> + Next + </button> + </div> {isModalOpen && ( <div className="modal-backdrop"> <div className="modal"> @@ -155,26 +171,28 @@ function Now({ )} </div> ) : ( - <div className="now-container"> - {currentVideo?.thumbnail && ( - <div className="now-thumbnail"> - <img - src={currentVideo.thumbnail} - alt={currentVideo.title} - className="now-thumbnail" - /> - <p className="now-title">{truncateText(currentVideo.title, 20)}</p> - </div> - )} - <span>Exercise Timer: {formatTime(exerciseTime)}</span> + <div> + <div className='now-content'> + {currentVideo?.thumbnail && ( + <div className="now-thumbnail"> + <img + src={currentVideo.thumbnail} + alt={currentVideo.title} + className="now-thumbnail" + /> + <p className="now-title">{truncateText(currentVideo.title, 20)}</p> + </div> + )} + <p>Timer: {formatTime(exerciseTime)}</p> + </div> <div className="underbar"> - <button className="next-button" onClick={onNext}> + <button onClick={onNext}> Next </button> - <button className="pause-button" onClick={onPause}> + <button onClick={onPause}> {isPaused ? "Start" : "Pause"} </button> - <button className="rest-button" onClick={handleRestStart}> + <button onClick={handleRestStart}> Rest </button> </div> diff --git a/front/src/pages/routine/Routine.jsx b/front/src/pages/routine/Routine.jsx index 5c358e0e58347a5f7bf5f95e381ca7f23e89def9..eff847811d674aac6dfae54ede40fac751b20250 100644 --- a/front/src/pages/routine/Routine.jsx +++ b/front/src/pages/routine/Routine.jsx @@ -61,9 +61,10 @@ function Routine() { setCurrentIndex(currentIndex + 1); if (isActive) window.open(selectedRoutine.exercises[currentIndex + 1].link, "_blank", "noopener,noreferrer"); - } else { + } else if (isActive) { setEndSignal(true); setIsActive(false); + setCurrentIndex(currentIndex + 1); } }; @@ -94,6 +95,17 @@ function Routine() { setSelectedRoutine({ ...selectedRoutine, exercises: updatedExercises }); }; + useEffect(() => { + const handleBeforeUnload = (event) => { + event.preventDefault(); + }; + + window.addEventListener("beforeunload", handleBeforeUnload); + return () => { + window.removeEventListener("beforeunload", handleBeforeUnload); + }; + }, []); + return ( <div id="box"> <div id="left"> @@ -125,7 +137,14 @@ function Routine() { </div> <div id="down"> <div id="progress"> - <Progress times={progressTimes} endSignal={endSignal} onendClick={onendClick} /> + {selectedRoutine && ( + <Progress + currentVideo={selectedRoutine.exercises[currentIndex-1]} + times={progressTimes} + endSignal={endSignal} + onendClick={onendClick} + /> + )} </div> <div id="video"> {selectedRoutine && ( @@ -153,6 +172,7 @@ function Routine() { ButtonClick={ButtonClick} isActive={isActive} hasRoutine={selectedRoutine !== null} + endSignal={endSignal} /> </div> </div> diff --git a/front/src/pages/routine/Start.jsx b/front/src/pages/routine/Start.jsx index db6d43cf0aea03d5dee01ff9616219d20f49516e..8eb4fc6ea2e5596a2e5be00cce2aea254e0eb778 100644 --- a/front/src/pages/routine/Start.jsx +++ b/front/src/pages/routine/Start.jsx @@ -1,7 +1,7 @@ import React, { useState } from 'react'; import './Start.css'; -function Start({ ButtonClick, isActive, hasRoutine }) { +function Start({ ButtonClick, isActive, hasRoutine, endSignal }) { const [isModalOpen, setIsModalOpen] = useState(false); // 모달 여부 const [countdown, setCountdown] = useState(null); // 카운트다운 상태 @@ -31,7 +31,7 @@ function Start({ ButtonClick, isActive, hasRoutine }) { 운동 시작 전이면 모달 표시 */ const handleStartClick = () => { - if (!isActive) setIsModalOpen(true); + if (!isActive&&!endSignal) setIsModalOpen(true); }; /* @@ -57,7 +57,7 @@ function Start({ ButtonClick, isActive, hasRoutine }) { 취소 클릭 시 모달 종료 */ const handleCancel = () => { - setIsModalOpen(false); + setIsModalOpen(false); }; return ( diff --git a/front/src/pages/routine/Video.css b/front/src/pages/routine/Video.css index 9bfee7009eccec86684e0488b740e635d19fe60f..8381711ae05da17903ef3e37fa2229474a84e18d 100644 --- a/front/src/pages/routine/Video.css +++ b/front/src/pages/routine/Video.css @@ -67,6 +67,7 @@ height: 25.04px; background: #8C7DFF; + border: 2px solid #B87EED; border-radius: 14.389px; } diff --git a/front/src/pages/routine/api.js b/front/src/pages/routine/api.js new file mode 100644 index 0000000000000000000000000000000000000000..75b640f91ca465f969913bd9bfba12dc0e5c1fd8 --- /dev/null +++ b/front/src/pages/routine/api.js @@ -0,0 +1,52 @@ +async function fetchWithOptions(url, options) { + try { + const response = await fetch(url, options); + if (!response.ok) { + throw new Error(`HTTP 오류! 상태 코드: ${response.status}`); + } + return await response.json(); + } catch (error) { + console.error("API 요청 중 에러 발생:", error.message); + throw error; + } +} + +async function addExerciseRecord(record) { + return await fetchWithOptions('/routine/records', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(record), + }); +} + +async function getUserRoutines() { + return await fetchWithOptions('/routine', { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + }); +} + +async function getRoutineVideos(routineName) { + return await fetchWithOptions(`/routine/videos?routine_name=${routineName}`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + }); +} + +async function deleteRoutine(routineName) { + return await fetchWithOptions('/routine', { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ routine_name: routineName }), + }); +} + +export { addExerciseRecord, getUserRoutines, getRoutineVideos, deleteRoutine }; diff --git a/front/src/pages/routine/progress.jsx b/front/src/pages/routine/progress.jsx index 6f526294e73f310e6873440463bfb52b6043f4a0..0ead796075beefa4088d2265e5ed7e4d9e39495c 100644 --- a/front/src/pages/routine/progress.jsx +++ b/front/src/pages/routine/progress.jsx @@ -1,7 +1,8 @@ import React, { useState, useEffect } from "react"; -import "./progress.css"; +import "./Progress.css"; +import { addExerciseRecord } from './api'; -function Progress({ times, endSignal, onendClick }) { +function Progress({ currentVideo, times, endSignal, onendClick }) { const [restTimes, setRestTimes] = useState([]); const [exerciseTimes, setExerciseTimes] = useState([]); const [allTimes, setAllTimes] = useState([]); @@ -21,8 +22,19 @@ function Progress({ times, endSignal, onendClick }) { setRestTimes((prev) => [...prev, timeValue]); setAllTimes((prev) => [...prev, { type: "Rest", value: timeValue, color: randomColor, id: Date.now() }]); } else if (times.startsWith("Exercise:")) { - setExerciseTimes((prev) => [...prev, timeValue]); - setAllTimes((prev) => [...prev, { type: "Exercise", value: timeValue, color: randomColor, id: Date.now() }]); + const tmp = new Date(); + const { canceled, ...recordvideo } = { + ...currentVideo, + date: tmp.toISOString().split("T")[0], + }; + addExerciseRecord(recordvideo) + .then(() => { + setExerciseTimes((prev) => [...prev, timeValue]); + setAllTimes((prev) => [...prev, { type: "Exercise", value: timeValue, color: randomColor, id: Date.now() }]); + }) + .catch((err) => { + alert(err); + }); } } }, [times]); @@ -41,7 +53,7 @@ function Progress({ times, endSignal, onendClick }) { if (endSignal) setIsModalOpen(true); }, [endSignal]); - const calculateHeight = (value) => 5 * ((value + 60) / 60 + 1); + const calculateHeight = (value) => 2 * ((value + 60) / 60 + 1); return ( <div className="progress-container"> @@ -60,7 +72,7 @@ function Progress({ times, endSignal, onendClick }) { /> ); })} - {isModalOpen && ( + {(isModalOpen && endSignal) && ( <div className="modal-backdrop"> <div className="modal"> <div className="modal-content"> @@ -70,7 +82,7 @@ function Progress({ times, endSignal, onendClick }) { 동안 운동하셨고, 그 중 {`${Math.round((totals.exerciseTotal / totals.allTotal) * 100)}%`} 동안 운동하셨습니다! </p> - <button onClick={() => {setIsModalOpen(false); onendClick();} }>확인</button> + <button onClick={() => { setIsModalOpen(false); onendClick(); }}>확인</button> </div> </div> </div> diff --git a/front/src/pages/routine/video.jsx b/front/src/pages/routine/video.jsx index 411539f8efd58641e8578d38ee9fa21f9254800c..f818b285fbf9ff398f4003996b20dd8e8793196e 100644 --- a/front/src/pages/routine/video.jsx +++ b/front/src/pages/routine/video.jsx @@ -60,9 +60,9 @@ function Video({ */ const handleVideoClick = (exercise) => { window.open(exercise.link, "_blank", "noopener,noreferrer"); - onVideoClick(exercise); + if (!isActive) onVideoClick(exercise); }; - + return ( <DragDropContext onDragStart={handleDragStart} onDragEnd={handleDragEnd}> <Droppable droppableId="video-list">