운동관리 - todayExercise 등록

Project Diary/Next.js + Prisma + MariaDB (KiloFlow)

이 글에서는 사용자가 오늘의 운동을 등록하는 기능을 구현합니다.


 

데이터베이스

 

users 테이블

model users {
  user_id                Int              @id @default(autoincrement())
  email                  String           @unique
  password               String
  nickname               String
  profile_image          String           @default("default_image_url")
  isInitialSetupComplete Boolean          @default(false)
  created_at             DateTime         @default(now())
  userProfile            UserProfile?

  recommends             recommend[]
  userFoodList           userFoodList[]
  todayFood              todayFood[]
  todayExercise          todayExercise[] // 추가된 부분

  @@index([user_id])
}

 

todayExercise 테이블

model todayExercise {
  id          Int           @id @default(autoincrement())
  user_id     Int
  exercise_id Int
  duration    Int
  calories    Float
  added_at    DateTime      @default(now())

  user        users         @relation(fields: [user_id], references: [user_id], onDelete: Cascade)

  @@index([user_id])
}

 


 

프론트엔드

 

ExerciseDetail 컴포넌트

 

1. 운동 시간 변경 핸들러

// 운동 시간 변경 핸들러
const changeMin = (e: React.ChangeEvent<HTMLInputElement>) => {
  setMin(parseInt(e.target.value));  // 입력된 운동 시간을 상태에 저장
};
  • setMin(parseInt(e.target.value)) : 입력된 운동 시간을 정수로 변환하여 상태에 저장합니다.

2. 오늘의 운동 추가 함수

// 오늘의 운동 추가 함수
const addTodayExercise = async () => {
  const calories = (MET * 3.5 * userWeight * min) / 200;  // 운동 시간에 따른 소모 칼로리 계산

  try {
    const res = await fetch('/api/exercise/todayExercise', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        user_id: currentUserID,  // 현재 사용자 ID
        exercise_id: id,  // 운동 ID
        duration: min,  // 운동 시간
        calories: calories,  // 계산된 소모 칼로리
      }),
    });

    if (res.ok) {
      const rec = await res.json();
      const newExerciseData = [...exerciseData, { calories }];
      setExerciseData(newExerciseData);  // 새로운 운동 데이터를 상태에 추가

      const newAchievement = achievement;
      try {
        const res = await fetch(
          `/api/achievement/get?user_id=${currentUserID}&date=${new Date().toISOString().split('T')[0]}`,
          {
            method: 'GET',
          }
        );

        if (res.ok) {
          await fetch('/api/achievement/update', {
            method: 'POST',
            headers: {
              'Content-Type': 'application/json',
            },
            body: JSON.stringify({
              user_id: currentUserID,
              date: new Date().toISOString().split('T')[0],
              achievement: newAchievement,
            }),
          });
          router.back();
        } else {
          await fetch('/api/achievement/create', {
            method: 'POST',
            headers: {
              'Content-Type': 'application/json',
            },
            body: JSON.stringify({
              user_id: currentUserID,
              date: new Date().toISOString().split('T')[0],
              achievement: newAchievement,
            }),
          });
          router.back();
        }
      } catch (error) {
        console.error('Failed to update or create achievement:', error);
      }

      alert(`${name} ${rec.message}`);
      router.back();
    } else {
      alert('추가에 실패했습니다.');
    }
  } catch (err) {
    alert('추가에 실패했습니다.');
  }
};
  • const calories = (MET * 3.5 * userWeight * min) / 200
    동 시간에 따른 소모 칼로리를 계산합니다.
  • const res = await fetch('/api/exercise/todayExercise', {...}) :
    todayExercise API에 POST 요청을 보냅니다.
  • body: JSON.stringify({ user_id: currentUserID, exercise_id: id, duration: min, calories: calories })
    현재 사용자 ID, 운동 ID, 운동 시간, 계산된 소모 칼로리를 JSON 형식으로 요청 본문에 포함합니다.
  • const newExerciseData = [...exerciseData, { calories }]
    새로운 운동 데이터를 기존 운동 데이터 배열에 추가합니다.

 

백엔드

 

todayExercise API엔드포인트

import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "../../../lib/prisma";

// todayExercise 등록을 처리하는 API 핸들러 함수
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  if (req.method === "POST") {  // POST 요청 처리
    try {
      const { user_id, exercise_id, duration, calories } = req.body; // 요청 본문에서 필요한 데이터 추출

      // todayExercise 테이블에 새로운 레코드 생성
      await prisma.todayExercise.create({
        data: {
          user_id: Number(user_id),  // 사용자 ID
          exercise_id: exercise_id,  // 운동 ID
          duration: duration,  // 운동 시간
          calories: calories,  // 소모 칼로리
        },
      });

      // 성공 메시지 반환
      return res.status(200).json({ message: "추가가 완료되었습니다." });
    } catch (error: any) {
      // 에러 처리
      console.log("서버에러", error);
      return res.status(500).json({
        error: "서버에서 오류가 발생했습니다.",
        details: error.message,
      });
    }
  } else {
    return res.status(405).json({ error: `Method ${req.method} Not Allowed` });
  }
}