운동 및 약물 계획 관리 화면 구현

계획 입력 및 관리 화면 개발

기능 개요

PlanManagementScreen은 사용자가 운동 계획과 약물 복용 계획을 입력하고 관리할 수 있는 화면입니다. 다음 두 종류의 계획을 지원합니다:

  • 운동 계획: 시작일과 종료일 + 일일 운동 시간(분 단위) + 세부 내용
  • 약물 계획: 시작일과 종료일 + 복용 용량(문자열) + 세부 내용

사용자가 입력한 계획은 로컬 AsyncStorage에 저장되어 영구적으로 보존되며, 메인 화면(Dashboard)에서 당일에 실행해야 할 계획을 표시합니다. 또한 계획 삭제 기능을 제공하여 사용자가 일정을 쉽게 업데이트할 수 있습니다.

사용 기술 및 의존성

  • React Native 프레임워크
  • useState 컴포넌트 상태 관리
  • useEffect 초기 데이터 로딩
  • AsyncStorage 로컬 데이터 저장
  • 서비스 모듈: planDataService.ts

컴포넌트 상태 변수 구조

const [workoutStartDate, setWorkoutStartDate] = useState('');
const [workoutEndDate, setWorkoutEndDate] = useState('');
const [workoutTime, setWorkoutTime] = useState('');
const [workoutDetails, setWorkoutDetails] = useState('');

사용자가 입력한 운동 정보를 관리하는 상태 변수들입니다.

const [medicationStartDate, setMedicationStartDate] = useState('');
const [medicationEndDate, setMedicationEndDate] = useState('');
const [dosageInfo, setDosageInfo] = useState('');
const [medicationDetails, setMedicationDetails] = useState('');

위 변수들은 약물 계획 입력 필드를 관리합니다.

const [savedWorkouts, setSavedWorkouts] = useState<WorkoutPlan[]>([]);
const [savedMedications, setSavedMedications] = useState<MedicationPlan[]>([]);

이 두 상태 변수는 화면에 표시되고 삭제할 수 있는 모든 저장된 계획을 보관합니다.

⏳ 초기 데이터 로딩 로직

useEffect(() => {
    const loadData = async () => {
        const workoutData = await fetchWorkoutPlans();
        const medicationData = await fetchMedicationPlans();
        setSavedWorkouts(workoutData);
        setSavedMedications(medicationData);
    };
    
    loadData();
}, []);

화면이 처음 로드될 때, planDataService.ts에 정의된 메서드를 통해 로컬 저장소에 보관된 운동 및 약물 계획을 JSON 배열 형태로 가져옵니다.

제출 및 로컬 저장 로직

const processFormSubmission = async () => {
    const updatedWorkouts = workoutDetails && workoutTime
        ? [...savedWorkouts, {
            startDate: workoutStartDate,
            endDate: workoutEndDate,
            duration: Number(workoutTime),
            content: workoutDetails
        }] : savedWorkouts;

    const updatedMedications = medicationDetails && dosageInfo
        ? [...savedMedications, {
            startDate: medicationStartDate,
            endDate: medicationEndDate,
            dosage: dosageInfo,
            content: medicationDetails
        }] : savedMedications;

    await persistWorkoutPlans(updatedWorkouts);
    await persistMedicationPlans(updatedMedications);
    ...
};

  • 제출 로직은 필수 입력값이 채워져 있을 경우에만 새 계획을 추가하도록 유효성 검사를 수행합니다.
  • 기존 배열에 새 계획을 추가하는 방식으로 저장됩니다.
  • 모든 저장 작업은 planDataService.tspersistWorkoutPlanspersistMedicationPlans 메서드를 호출합니다.

계획 항목 삭제 기능

const removePlanItem = async (planType: 'workout' | 'medication', itemIndex: number) => {
    const currentPlans = [...(planType === 'workout' ? savedWorkouts : savedMedications)];
    currentPlans.splice(itemIndex, 1);

    if (planType === 'workout') {
        setSavedWorkouts(currentPlans);
        await persistWorkoutPlans(currentPlans);
    } else {
        setSavedMedications(currentPlans);
        await persistMedicationPlans(currentPlans);
    }
};

"삭제" 버튼을 탭하면 해당 계획 항목이 즉시 삭제되고 로컬 저장소도 동기화됩니다.

입력 폼 표시 구조

화면 레이아웃은 ScrollView를 사용하며, 입력 필드는 TextInput 컴포넌트로 구현됩니다:

<TextInput placeholder="일일 운동 시간(분)" style={styles.input} keyboardType="numeric" value={workoutTime} onChangeText={setWorkoutTime} />

각 입력 필드는 해당 상태 변수와 연결되어 입력 시 상태가 업데이트됩니다. 하단에 제출 버튼이 배치됩니다.

저장된 계획 표시

{savedWorkouts.map((plan, index) => (
    <View key={index} style={styles.planCard}>
        <Text>{plan.startDate} ~ {plan.endDate} - 매일 {plan.duration}분 - {plan.content}</Text>
        <TouchableOpacity onPress={() => removePlanItem('workout', index)}>
            <Text style={styles.removeButton}>삭제</Text>
        </TouchableOpacity>
    </View>
))}

  • 각 계획 항목은 기간, 운동 시간/약물 용량, 세부 내용을 표시합니다.
  • 삭제 버튼은 빨간색 텍스트로 표시되며, 탭 시 removePlanItem 함수를 호출합니다.

스타일링 개요

planCard: {
    backgroundColor: '#f5f5f5',
    borderRadius: 8,
    padding: 12,
    marginVertical: 8,
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
},

리스트 항목은 연한 회색 배경과 둥근 모서리를 가진 카드 스타일로, 텍스트와 "삭제" 버튼이 좌우로 배치되어 깔끔하고 직관적인 디자인을 제공합니다.

태그: React Native AsyncStorage useState useEffect 모바일 앱 개발

7월 21일 07:27에 게시됨