Skip to content

[Feat/#77] 기존캘린더부분api연결 및 MVI로 리팩토링 #77

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jul 12, 2025

Conversation

hooni0918
Copy link
Member

@hooni0918 hooni0918 commented Jul 12, 2025

🔗 연결된 이슈

📄 작업 내용

  • 삭제 API 연결
  • 등록Todo 갯수맞춰 빵과 매핑 (일단 매핑만 디테일 부분은 디자이너에게 질문후 재검수)
  • 기존 캘린더 뷰 코드가 너무 비대해져 MVI로 리팩토링
구현 내용 IPhone 15 pro IPhone SE
GIF

💻 주요 코드 설명

숨이 안쉬어질정도로 너무 바빠서 완전히 선생님들 코드랑 1:1로 맞춰서 MVI구조를 만든건 아니지만 기존에 제가 아는만큼의 MVI로 구현을 해보았습니다. 설명하자면,,

1. Intent (사용자 액션 정의)

public enum CalendarIntent {
    case viewDidAppear                          // 화면 나타남
    case toggleChanged(CalendarNavigationBar.ToggleOption)  // 주/월 토글
    case dateSelected(Date)                     // 날짜 선택
    case categorySelected(TaskCategory)         // 카테고리 선택
    case directInputTapped                      // 직접 입력
    case taskEditRequested(Int)                 // 할일 편집
    case taskDeleteRequested(Int)               // 할일 삭제
    case taskTitleChanged(Int, String)          // 할일 제목 변경
    case categorySelectionToggled               // 카테고리 선택 토글
    case scrollOffsetChanged(CGFloat, Bool)     // 스크롤 오프셋 변경
}
  • 모든 사용자 액션 enum 정의
  • 액션에 필요한 데이터를 연관값으로 전달

2. State (UI 상태 관리)

public struct CalendarState: Equatable {
    // 기본 데이터
    var selectedDate = Date()
    var selectedToggle: CalendarNavigationBar.ToggleOption = .week
    var dailySchedules: [DailySchedule] = []
    var todoItems: [DesignSystem.TodoItem] = []

    // UI 상태
    var showDatePicker = false
    var showTaskEditSheet = false
    var showCategorySelection = false
    var scrollOffset: CGFloat = 0
    var isScrolling = false

    // 선택/편집 상태
    var selectedTaskIndex: Int?
    var editingTaskIndex: Int?
    var isLoading = false

    // Computed Properties (파생 상태)
    var isFloatingButtonExpanded: Bool {
        scrollOffset == 0 && !isScrolling
    }

    var currentDateString: String {
        selectedDate.toString(format: "yyyy년 M월")
    }
}
  • Computed Properties로 파생 상태 계산

3. Effect

public enum CalendarEffect {
    case navigateToTaskCreate(Date)
    case navigateToTaskEdit(Int, String, String?, String?, Date)
    case showError(String)
}
  • 네비게이션, 알림 등 순수하지 않은 작업들
  • View에서 처리해야 할 부수 효과들
  • State 변경 외의 모든 Side Effect

4. Store (비즈니스 로직 처리)

public final class CalendarStore: ObservableObject {
    @Dependency private var calendarUseCase: CalendarUseCaseProtocol

    @Published public private(set) var state = CalendarState()
    private let effectSubject = PassthroughSubject<CalendarEffect, Never>()

    public var effect: AnyPublisher<CalendarEffect, Never> {
        effectSubject.eraseToAnyPublisher()
    }

    // Intent 처리
    public func send(_ intent: CalendarIntent) {
        Task { @MainActor in
            await handle(intent)
        }
    }

    // State 직접 변경 (내부용)
    @MainActor
    internal func updateState(_ update: (inout CalendarState) -> Void) {
        update(&state)
    }
}

5. Intent 처리 로직

@MainActor
private func handle(_ intent: CalendarIntent) async {
    switch intent {
    case .viewDidAppear:
        await handleViewDidAppear()
    case .toggleChanged(let toggle):
        await handleToggleChanged(toggle)
    case .dateSelected(let date):
        await handleDateSelected(date)
    // ... 나머지 케이스들
    }
}

@MainActor
func handleDateSelected(_ date: Date) async {
    state.selectedDate = date        // 1. 상태 업데이트
    await loadSchedules()           // 2. 비즈니스 로직 실행
    updateTodoItemsForSelectedDate() // 3. 파생 데이터 업데이트
}

처리 과정:

  1. Intent 수신
  2. 상태 변경
  3. 필요시 UseCase 호출
  4. 결과에 따른 추가 상태 업데이트
  5. 필요시 Effect 발생

6. View랑 연결

public struct CalendarView: View {
    @StateObject private var store = CalendarStore()

    var body: some View {
        // State 구독
        CalendarNavigationBar(
            dateText: store.state.currentDateString,
            onDateTapped: {
                // Intent 전송
                Task { @MainActor in
                    store.updateState { $0.showDatePicker = true }
                }
            },
            onToggleChanged: { toggle in
                store.send(.toggleChanged(toggle))
            }
        )

        // Effect 처리
        .onReceive(store.effect) { effect in
            handleEffect(effect)
        }
        .task {
            store.send(.viewDidAppear)
        }
    }
}

날짜선택할때 플로우

1. User: 날짜 버튼 탭
   ↓
2. View: store.send(.dateSelected(date))
   ↓
3. Store: handleDateSelected() 호출
   ↓
4. Store: state.selectedDate = date
   ↓
5. Store: loadSchedules() 실행
   ↓
6. Store: calendarUseCase.getSchedules() 호출
   ↓
7. Store: state.dailySchedules 업데이트
   ↓
8. Store: updateTodoItemsForSelectedDate() 실행
   ↓
9. Store: state.todoItems 업데이트
   ↓
10. View: @Published state 변경으로 자동 리렌더링

👀 기타 더 이야기해볼 점

수정하기 부분 API가 고장난것같아 일단 추후 작업으로 미루겟습니다
식빵 이미지 매핑도 디자이너에게 물어보고 수정하겟습니다.
위 두개 부분이랑 플로팅 버튼에서 추천받은 3가지 태그를 붙이는것만 하면 캘린더부분은 끝,,일걸요,,?
아 연차일경우 내일로 미루기 부분인데 이것도 디자이너랑 서버에게 물어보고 다시,,,할게요,,,,,,,,,,,

✔️ CI Completed

  • ✅ Lint: Completed
  • ✅ Build: Completed

@hooni0918 hooni0918 requested review from k-nh and SijongKim93 July 12, 2025 08:41
@hooni0918 hooni0918 self-assigned this Jul 12, 2025
@hooni0918 hooni0918 merged commit 826dc2b into develop Jul 12, 2025
1 check passed
@hooni0918 hooni0918 deleted the feat/#77-기존캘린더부분API연결 branch July 12, 2025 11:40
SijongKim93 pushed a commit that referenced this pull request Jul 13, 2025
SijongKim93 pushed a commit that referenced this pull request Jul 13, 2025
SijongKim93 pushed a commit that referenced this pull request Jul 13, 2025
body 내부 줄이기
SijongKim93 pushed a commit that referenced this pull request Jul 13, 2025
SijongKim93 pushed a commit that referenced this pull request Jul 13, 2025
SijongKim93 pushed a commit that referenced this pull request Jul 13, 2025
[Feat/#77] 기존캘린더부분api연결 및 MVI로 리팩토링
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant