HealthNote 🩺
나만의 인바디·운동 기록 대시보드 (React + Vite)
체성분(체중, 골격근량, 체지방률)과 운동 기록을 한 화면에서 관리하고, 최근 7일 요약과 그래프까지 보여주는 개인용 헬스 노트 웹 애플리케이션입니다. 모든 데이터는 브라우저 localStorage 에 저장되며, 별도 서버 없이 동작합니다.
- 프로젝트 소개
HealthNote는 다음 두 가지 정보를 중심으로 동작합니다.
체성분 기록 (InBody 형태)
날짜별로 체중(kg), 골격근량(kg), 체지방률(%) 기록
최근 기록 카드 / 인바디 스타일 그래프 / 목표와의 차이 확인
운동 기록
날짜별 운동 이름, 운동 시간(분), 칼로리(kcal) 기록
최근 7일 동안의 운동 횟수·평균 운동 시간·총 칼로리를 요약해서 표시
또한, 프로필 정보(나이, 키, 성별) 를 입력해두면 체성분 값에 대해 표준 / 표준 이상 / 표준 이하 를 계산해서 보여줍니다.
- 주요 기능 ✅ 2-1. 프로필 관리
나이, 키, 성별(남/여) 입력
첫 접속 시, 프로필이 비어있으면 자동으로 프로필 모달 표시
프로필 정보는 localStorage("healthnote_profile") 에 저장
프로필을 기반으로 인바디 카드에서 표준/이상/이하 상태 계산
사용 컴포넌트 / 훅:
ProfileModal.jsx
useHealthNoteData() – 프로필 상태 및 저장 로직 포함
✅ 2-2. 체성분 기록 관리
기록 항목
날짜
체중(kg)
골격근량(kg)
체지방률(%)
기능
새 기록 추가
기존 기록 선택 후 편집 / 수정
기록 삭제
날짜는 오늘보다 미래 날짜 선택 불가 (max={today})
사용 컴포넌트 / 훅:
BodyForm.jsx
useState, useEffect 를 활용한 편집 모드/추가 모드 전환
editingBody 값이 있을 때는 해당 데이터를 폼에 채워 넣고 수정
BodyTable.jsx
날짜 내림차순(최근 기록 먼저) 정렬
행 클릭 시 해당 기록을 폼으로 올려서 수정
삭제 버튼으로 개별 기록 삭제
BodyRecordModal.jsx
체성분 기록 입력 폼 + 최근 기록 테이블을 하나의 모달로 구성
오버레이 클릭 시 닫힘 처리
useHealthNoteData()
bodyRecords 상태 관리
addBody / updateBody / deleteBody 함수 제공
localStorage("bodyRecords")와 자동 동기화
✅ 2-3. 운동 기록 관리
기록 항목
날짜
운동명
시간(분)
칼로리(kcal)
기능
운동 기록 추가
최근 운동 기록을 날짜 기준으로 정렬해서 조회
기록 삭제
날짜 역시 오늘 이후로는 선택 불가 (max={today})
사용 컴포넌트 / 훅:
ExerciseForm.jsx
useState, useEffect 로 추가 모드와 편집 모드 모두 지원 가능하게 설계
운동명 공백 입력 방지 (trim() + 유효성 검사)
ExerciseTable.jsx
날짜 내림차순 + 같은 날짜에서는 최신 입력 먼저
삭제 버튼 클릭 시 삭제 콜백 호출
ExerciseRecordModal.jsx
상단: 운동 입력 폼
하단: “최근 기록” 리스트
배경 클릭 시 모달 닫기 / 카드 클릭 시 이벤트 전파 차단
useHealthNoteData()
exerciseRecords 상태 관리
addExercises / deleteExercise 함수 제공
localStorage("exerciseRecords")와 자동 동기화
✅ 2-4. 대시보드 & 요약
메인 대시보드는 크게 네 영역으로 구성됩니다.
최근 체성분 카드 (ActivityHeader)
가장 최근 체성분 기록 한 건을 카드 형태로 표시
체중 / 근육량 / 체지방률을 pill 카드로 배치
기록이 없을 때는 안내 메시지 + “기록 관리” 버튼만 표시
목표값 & 달성률 패널 (ActivityGoalPanel)
목표 체중(kg), 목표 근육량(kg) 입력
최근 기록과 비교해 다음 메시지 표시
예: “목표까지 2.1kg 감량 필요”, “목표를 초과했습니다” 등
내부 모달(GoalModal)에서 목표값 편집
목표는 localStorage("goals")에 저장
최근 7일 요약 (ActivitySummary)
최근 7일 동안
운동한 날 수 / 운동 횟수
평균 운동 시간
총 칼로리
운동한 날 수가 3일 이상이면 카드에 강조 배지 표시
체성분 변화 차트 (ActivityChart)
Recharts의 LineChart 사용
세 가지 지표 중 하나 선택해서 라인 차트로 표시
체중(kg), 골격근량(kg), 체지방률(%)
날짜별 데이터를 시계열로 정렬
선택된 측정값의 날짜와 수치를 상단에 표시
현재 선택 지점에 ReferenceLine(수직선) 표시
프로필 정보를 전달해 표준 / 표준 이상 / 표준 이하 상태 계산 (각 metric 별로 색상과 라벨 표현)
- 상태 관리 구조 useHealthNoteData() 커스텀 훅
src/hooks/useHealthNoteData.js에서 전체 화면에서 공통으로 사용하는 상태를 관리합니다.
초기 로딩 (useEffect)
localStorage에서 body / exercise / goals / profile 을 한 번에 읽어옴
프로필이 없거나 비어 있으면 자동으로 프로필 모달 오픈
공통 업데이트 헬퍼
updateBodyRecords(updateFn)
updateExerciseRecords(updateFn)
setState와 localStorage 저장을 한 곳에서 처리
체성분 관련
bodyRecords, editingBody, setEditingBody
addBody(record)
updateBody(updatedRecord)
deleteBody(id)
운동 관련
exerciseRecords
addExercises(newRecords[])
deleteExercise(id)
목표 / 프로필 관련
goals, saveGoals(newGoals)
profile, saveProfile(data)
모달 상태
isProfileOpen, isBodyModalOpen, isExerciseModalOpen
openProfileModal / closeProfileModal
openBodyModal / closeBodyModal
openExerciseModal / closeExerciseModal
이 훅을 App.jsx에서 호출해서 상태를 최상단에서 한 번만 관리하고, 필요한 컴포넌트에 props로 내려보내는 구조입니다. (→ “상태 끌어올리기(Lifting State Up)”와 “단방향 데이터 흐름”을 잘 보여줌)
- 기술 스택
React (함수형 컴포넌트 + Hooks)
useState, useEffect, useMemo, 커스텀 훅 사용
Vite
개발 서버 및 번들러
Tailwind CSS
유틸리티 클래스 기반의 스타일링
반응형 레이아웃, 그림자, 테두리, 색상 등 UI 디자인
Recharts
체성분 변화 LineChart 표현
localStorage
bodyRecords, exerciseRecords, goals, profile 데이터 영구 저장