운동 루틴 등록 API 구현
import { createClient } from '@/supabase/server';
import { NextRequest, NextResponse } from 'next/server';
export const POST = async (request: NextRequest) => {
try {
const supabase = createClient();
// 사용자 인증 확인
const {
data: { user },
error: authError,
} = await supabase.auth.getUser();
if (authError || !user) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
const userId = user.id;
// request body에서 데이터 추출
const { exerciseData, routineData } = await request.json();
const { isRoutine } = exerciseData;
if (!isRoutine || !routineData) {
return NextResponse.json({ message: '루틴이 아니거나 루틴 데이터가 없습니다.' }, { status: 204 });
}
const { endDate, days } = routineData;
// 필수 필드 검증
if (!endDate || !days) {
return NextResponse.json({ error: '필수 필드가 누락되었습니다' }, { status: 400 });
}
// Supabase에 데이터 삽입
const { data, error } = await supabase.from('exerciseRoutines').insert({
userId,
endDate,
days,
exerciseId: 7,
});
if (error) return NextResponse.json({ error: error.message }, { status: 400 });
return NextResponse.json({ message: '루틴이 성공적으로 등록되었습니다', data }, { status: 200 });
} catch (e) {
console.error('루틴 등록 오류:', e);
return NextResponse.json({ error: '루틴 등록에 실패했습니다' }, { status: 500 });
}
};
설명:
- Supabase 클라이언트를 사용하여 사용자 인증을 확인
- exerciseData와 routineData를 요청 본문에서 추출하고, exerciseData의 isRoutine 값을 확인하여 루틴 여부를 판별
- routineData에서 필수 필드(endDate, days)를 검증하고, 필수 필드가 누락된 경우 적절한 응답을 반환
- 데이터를 exerciseRoutines 테이블에 삽입하고, 오류 발생 시 적절한 오류 메시지를 반환
운동 데이터 등록 UI 구현
'use client';
import Button from '@/components/Button';
import axios from 'axios';
import dayjs from 'dayjs';
import { useEffect, useState } from 'react';
import 'swiper/css';
import TestMonthCalendar from './TestMonthCalendar';
import TestWeekCalendar from './TestWeekCalendar';
const TestCalendar = () => {
const [isMonthView, setIsMonthView] = useState(false);
const [selectedDate, setSelectedDate] = useState<Date>(new Date());
const [selectedDays, setSelectedDays] = useState<number[]>([]);
const [currentDisplayDate, setCurrentDisplayDate] = useState<Date>(new Date());
const toggleView = () => {
setIsMonthView(!isMonthView);
};
const handleDateSelect = (date: Date) => {
const today = dayjs().startOf('day');
const selectedDate = dayjs(date);
if (selectedDate.isAfter(today) || selectedDate.isSame(today, 'day')) {
setSelectedDate(date);
console.log('Selected date:', selectedDate.format('YYYY-MM-DD'));
} else {
console.log('마감일은 과거 선택이 불가능합니다.');
}
};
const handleDayClick = (dayIndex: number) => {
setSelectedDays((prev) => {
const newSelectedDays = prev.includes(dayIndex) ? prev.filter((d) => d !== dayIndex) : [...prev, dayIndex];
return [...newSelectedDays].sort((a, b) => a - b);
});
};
useEffect(() => {
console.log(selectedDays);
}, [selectedDays]);
const getMonthYear = (date: Date | null): string => {
if (!date) return '';
return date.toLocaleDateString('ko-KR', { year: 'numeric', month: 'long' });
};
const handleSubmit = async () => {
const exerciseData = {
isRoutine: selectedDays.length > 0, // 선택된 요일이 있으면 루틴으로 간주
};
const routineData =
selectedDays.length > 0
? {
endDate: dayjs(selectedDate).format('YYYY-MM-DD'),
days: selectedDays,
}
: null;
try {
const response = await axios.post('/api/exercises/routines', {
exerciseData,
routineData,
});
console.log('운동 및 루틴 등록 성공:', response.data);
// 성공 처리 (예: 메시지 표시, 상태 초기화 등)
} catch (error) {
console.error('운동 및 루틴 등록 실패:', error);
// 오류 처리 (예: 오류 메시지 표시)
}
};
return (
<div className="w-full p-2">
<header className="flex flex-col gap-2 items-center bg-gray-100 py-2 px-4">
<button onClick={toggleView} className="bg-blue-500 text-white px-4 py-2 rounded">
{isMonthView ? '주별 보기' : '월별 보기'}
</button>
<h2 className="font-bold">{getMonthYear(currentDisplayDate)}</h2>
</header>
{isMonthView ? (
<TestMonthCalendar
selectedDate={selectedDate}
onSelectDate={handleDateSelect}
onChangeMonth={setCurrentDisplayDate}
selectedDays={selectedDays}
onDayClick={handleDayClick}
/>
) : (
<TestWeekCalendar
selectedDate={selectedDate}
onSelectDate={handleDateSelect}
onChangeWeek={setCurrentDisplayDate}
selectedDays={selectedDays}
onDayClick={handleDayClick}
/>
)}
<Button onClick={handleSubmit}>운동 등록</Button>
</div>
);
};
export default TestCalendar;
설명:
- React 컴포넌트에서 TestCalendar UI를 구현하였으며, 사용자가 날짜를 선택하고 루틴을 설정할 수 있는 기능 추가
- 사용자가 날짜를 선택하면 selectedDate와 selectedDays 상태 업데이트
- handleSubmit 함수는 선택된 날짜와 요일을 포함하여 운동 루틴을 등록하는 API 호출
- 날짜 선택 및 캘린더 뷰 전환 기능 구현
추가 사항:
- 현재의 exerciseId는 하드코딩된 값으로 설정되어 있으며, 향후 다른 route와 통합할 때 동적으로 처리
- 현재는 운동 기록과 루틴 등록이 별도로 구현되어 있으며, exerciseId 통합을 고려하여 구조를 사전 설계
'TIL' 카테고리의 다른 글
TIL - 공통 컴포넌트 input에 커스텀 date 넣기 (0) | 2024.08.02 |
---|---|
TIL - input 공용 컴포넌트 이벤트 처리 기능 추가 (0) | 2024.08.01 |
TIL - 드롭다운 구현 select에서 커스텀 button+ul로의 전환 (0) | 2024.07.30 |
TIL - border bottom 그라데이션 구현하기 (0) | 2024.07.29 |
TIL - 하단 네비게이션 바 구현 (0) | 2024.07.26 |