셀프 피드백 작성 화면 구현 #144
Conversation
- `feature:feedback` 모듈(api, impl) 추가 및 의존성 설정
- 셀프 피드백 작성을 위한 `FeedbackScreen`, `FeedbackViewModel` 구현
- `WriteSelfFeedbackUseCase` 및 관련 Repository, RemoteDataSource 로직 추가
- 홈 화면에서 피드백 작성 화면으로의 내비게이션 연결
- `POST recording/{presentationId}/review` API 엔드포인트 정의 및 `SelfFeedbackRequest` DTO 추가
- 피드백 작성 중 이탈 시 확인 다이얼로그 표시 로직 구현
- 피드백 저장 실패 시 스낵바 알림 표시 추가
- 피드백 작성 완료 시 이전 화면이 아닌 홈 화면으로 이동하도록 변경 - 분석 리포트에서 피드백 작성 화면으로 이동 시 발표 제목(`title`) 파라미터 추가 - `FeedbackUiEffect`에 `NavigateToHome` 상태 추가 - `feature:feedback:impl` 및 `feature:report:impl` 모듈의 의존성 업데이트 (`feature:home:api`, `feature:feedback:api`) - `FeedbackEntryBuilder` 및 `ReportEntryBuilder` 내 네비게이션 핸들러 구현 수정
- `PresentationSummaryResponse`의 `growthGraph` 필드에 null 허용 설정 및 매퍼 로직 수정 - `HomeScreenContent`의 `HorizontalPager`에서 인덱스 참조 시 발생할 수 있는 잠재적 오류 방지 로직 추가 - `PresentationHero`에서 사용하던 `PrezelChip`을 커스텀 `HomeCategoryChip`으로 교체하여 디자인 시스템 요구사항 반영
- `GetPresentationDetailResponse`에 `reviewContent` 필드 추가 - `PresentationRemoteDataSourceImpl`에서 상세 응답 데이터 변환 시 `reviewContent`를 우선적으로 매핑하도록 로직 개선 - `FeedbackEntryBuilder`에서 홈 화면 이동 시 기존 스택을 제거하고 루트를 교체하도록 변경 (`replaceRoot`) - `PresentationHero` 컴포넌트 프리뷰의 D-Day 표시 형식을 서비스 스펙에 맞게 수정 (`D-3`, `D+5`)
- `HomeScreen`에 발표 분석 페이지로 이동하는 `navigateToAnalyzePresentation` 콜백 추가 - 발표 목록 아이템 클릭 시 해당 발표의 ID와 과거 데이터 여부(`isPastPresentation`)를 전달하도록 구현 - `HomeEntryBuilder`에서 `AnalysisNavKey.ReRecording`을 사용하여 실제 내비게이션 로직 연결
- `FeedbackNavKey`에 `isPast`, `returnToReportOnSave` 파라미터 추가 - 피드백 저장 완료 시 홈 화면 또는 리포트 화면으로 이동하는 분기 로직 구현 - 피드백 작성 시 기존 저장된 내용을 불러오는 `fetchInitialContent` 로직 추가 - 변경 사항 여부를 판단하여 종료 다이얼로그 노출 로직 개선 - `AnalysisReport` 및 `Home` 화면에서 피드백 화면 이동 시 필요한 파라미터 전달 로직 수정 - `feature:feedback:impl` 모듈에 필요한 의존성 추가 (`coreModel`, `featureReportApi`)
|
Warning Review limit reached
More reviews will be available in 56 minutes and 50 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthrough네트워크 API·원격 데이터소스·도메인 레이어·유스케이스·UI(ViewModel/Composable)·네비게이션·빌드 설정을 통합해 발표의 자기 피드백 작성 흐름을 추가합니다. ChangesSelf Feedback 작성 기능 구현
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
Prezel/detekt-config.yml (1)
40-40: ⚡ Quick winDetekt 전역 완화 대신 범위 제한 적용을 권장합니다.
thresholdInInterfaces전역 상향은 unrelated 인터페이스까지 규칙 신호를 약화시킬 수 있습니다. 이 PR 목적이 특정 인터페이스 대응이라면 해당 지점에@Suppress("TooManyFunctions")또는 인터페이스 분리로 범위를 제한하는 쪽이 유지보수에 더 안전합니다.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Prezel/detekt-config.yml` at line 40, Revert the global raise of thresholdInInterfaces in detekt-config.yml and instead apply the suppression or refactor locally: identify the specific interface(s) that triggered the rule and either annotate that interface declaration with `@Suppress`("TooManyFunctions") or split the interface into smaller interfaces to reduce function count; ensure detekt-config.yml keeps the default thresholdInInterfaces and only use `@Suppress`("TooManyFunctions") on the precise interface(s) you changed (or perform the interface split) so the rule weakening is scoped rather than global.Prezel/feature/feedback/impl/src/main/java/com/team/prezel/feature/feedback/impl/FeedbackScreen.kt (1)
185-191: ⚡ Quick win글자 수 제한 상수가 중복됩니다.
maxLength = 200이 하드코딩되어 있는데,FeedbackViewModel의MAX_CONTENT_COUNT = 200과 동일한 값입니다. 한쪽만 변경되면 UI에 표시되는 카운트/제한과 ViewModel의 실제 truncate 길이가 어긋날 수 있습니다. 공용 상수로 추출해 단일 출처로 관리하는 것을 권장합니다.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Prezel/feature/feedback/impl/src/main/java/com/team/prezel/feature/feedback/impl/FeedbackScreen.kt` around lines 185 - 191, Hardcoded maxLength (200) in PrezelTextArea duplicates FeedbackViewModel's MAX_CONTENT_COUNT; extract a shared constant (e.g., FeedbackConstants.MAX_CONTENT_COUNT) and use it in both places so the UI and ViewModel stay in sync: create a common constant holder (object/class) and replace the literal in FeedbackScreen's PrezelTextArea (maxLength) and in FeedbackViewModel's MAX_CONTENT_COUNT reference to use that single constant.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@Prezel/feature/feedback/impl/src/main/java/com/team/prezel/feature/feedback/impl/FeedbackViewModel.kt`:
- Around line 45-61: fetchInitialContent uses fetchPresentationDetailUseCase but
lacks an onFailure branch so initialContent and the UI can be cleared on network
error; add an onFailure handler on the Result returned by
fetchPresentationDetailUseCase inside viewModelScope.launch that logs the error
and emits a user-facing event (or shows a toast/snackbar) via existing
state/events instead of setting initialContent to an empty string, and ensure
you only set initialContent and call updateState { copy(content = ...) } inside
the onSuccess path (do not overwrite currentState.content on failure). Use the
existing symbols: fetchInitialContent, fetchPresentationDetailUseCase,
initialContent, updateState, and viewModelScope.launch to locate where to add
the onFailure handling and UI/error emission.
---
Nitpick comments:
In `@Prezel/detekt-config.yml`:
- Line 40: Revert the global raise of thresholdInInterfaces in detekt-config.yml
and instead apply the suppression or refactor locally: identify the specific
interface(s) that triggered the rule and either annotate that interface
declaration with `@Suppress`("TooManyFunctions") or split the interface into
smaller interfaces to reduce function count; ensure detekt-config.yml keeps the
default thresholdInInterfaces and only use `@Suppress`("TooManyFunctions") on the
precise interface(s) you changed (or perform the interface split) so the rule
weakening is scoped rather than global.
In
`@Prezel/feature/feedback/impl/src/main/java/com/team/prezel/feature/feedback/impl/FeedbackScreen.kt`:
- Around line 185-191: Hardcoded maxLength (200) in PrezelTextArea duplicates
FeedbackViewModel's MAX_CONTENT_COUNT; extract a shared constant (e.g.,
FeedbackConstants.MAX_CONTENT_COUNT) and use it in both places so the UI and
ViewModel stay in sync: create a common constant holder (object/class) and
replace the literal in FeedbackScreen's PrezelTextArea (maxLength) and in
FeedbackViewModel's MAX_CONTENT_COUNT reference to use that single constant.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 1cfd6e0d-7aab-4e2f-85df-3e11e1c37aae
📒 Files selected for processing (39)
Prezel/app/build.gradle.ktsPrezel/core/data/src/main/java/com/team/prezel/core/data/mapper/PresentationMapper.ktPrezel/core/data/src/main/java/com/team/prezel/core/data/repository/PresentationRepositoryImpl.ktPrezel/core/domain/src/main/kotlin/com/team/prezel/core/domain/repository/presentation/PresentationRepository.ktPrezel/core/domain/src/main/kotlin/com/team/prezel/core/domain/usecase/presentation/WriteSelfFeedbackUseCase.ktPrezel/core/network/src/main/java/com/team/prezel/core/network/datasource/PresentationRemoteDataSource.ktPrezel/core/network/src/main/java/com/team/prezel/core/network/datasource/PresentationRemoteDataSourceImpl.ktPrezel/core/network/src/main/java/com/team/prezel/core/network/model/presentation/GetPresentationDetailResponse.ktPrezel/core/network/src/main/java/com/team/prezel/core/network/model/presentation/PresentationSummaryResponse.ktPrezel/core/network/src/main/java/com/team/prezel/core/network/model/presentation/review/SelfFeedbackRequest.ktPrezel/core/network/src/main/java/com/team/prezel/core/network/service/PresentationService.ktPrezel/detekt-config.ymlPrezel/feature/feedback/api/build.gradle.ktsPrezel/feature/feedback/api/consumer-rules.proPrezel/feature/feedback/api/proguard-rules.proPrezel/feature/feedback/api/src/main/java/com/team/prezel/feature/feedback/api/FeedbackNavKey.ktPrezel/feature/feedback/api/src/main/res/values/strings.xmlPrezel/feature/feedback/impl/build.gradle.ktsPrezel/feature/feedback/impl/consumer-rules.proPrezel/feature/feedback/impl/proguard-rules.proPrezel/feature/feedback/impl/src/main/java/com/team/prezel/feature/feedback/impl/FeedbackScreen.ktPrezel/feature/feedback/impl/src/main/java/com/team/prezel/feature/feedback/impl/FeedbackViewModel.ktPrezel/feature/feedback/impl/src/main/java/com/team/prezel/feature/feedback/impl/contract/FeedbackUiEffect.ktPrezel/feature/feedback/impl/src/main/java/com/team/prezel/feature/feedback/impl/contract/FeedbackUiIntent.ktPrezel/feature/feedback/impl/src/main/java/com/team/prezel/feature/feedback/impl/contract/FeedbackUiState.ktPrezel/feature/feedback/impl/src/main/java/com/team/prezel/feature/feedback/impl/model/FeedbackUiMessage.ktPrezel/feature/feedback/impl/src/main/java/com/team/prezel/feature/feedback/impl/navigation/FeedbackEntryBuilder.ktPrezel/feature/feedback/impl/src/main/res/values/strings.xmlPrezel/feature/home/impl/build.gradle.ktsPrezel/feature/home/impl/src/main/java/com/team/prezel/feature/home/impl/main/HomeScreen.ktPrezel/feature/home/impl/src/main/java/com/team/prezel/feature/home/impl/main/component/HomeScreenContent.ktPrezel/feature/home/impl/src/main/java/com/team/prezel/feature/home/impl/main/component/title/PresentationHero.ktPrezel/feature/home/impl/src/main/java/com/team/prezel/feature/home/impl/navigation/HomeEntryBuilder.ktPrezel/feature/report/impl/build.gradle.ktsPrezel/feature/report/impl/src/main/java/com/team/prezel/feature/report/impl/AnalysisReportScreen.ktPrezel/feature/report/impl/src/main/java/com/team/prezel/feature/report/impl/AnalysisReportViewModel.ktPrezel/feature/report/impl/src/main/java/com/team/prezel/feature/report/impl/contract/AnalysisReportUiEffect.ktPrezel/feature/report/impl/src/main/java/com/team/prezel/feature/report/impl/navigation/ReportEntryBuilder.ktPrezel/settings.gradle.kts
- `AnalysisReportUiIntent.FetchData` 인텐트를 추가하고 `LaunchedEffect`를 통해 데이터를 호출하도록 변경 - `ReportNavKey`와 `FeedbackNavKey`에서 불필요한 `refreshKey`, `returnToReportOnSave` 파라미터 제거 - 피드백 저장 완료 시 복잡한 화면 전환 로직을 `navigator.goBack()`으로 단순화 - `AnalysisReportViewModel`의 초기 데이터 로드 로직을 `init` 블록에서 `onIntent` 처리 방식으로 이전 - `feature:feedback:impl` 모듈의 불필요한 의존성(`feature:home:api`, `feature:report:api`) 제거
- 서버 에러 코드(`ServerErrorCode`) 및 앱 에러(`AppError`) 매핑 로직 추가
- `SELF_FEEDBACK_ALREADY_WRITTEN`, `PRESENTATION_REVIEW_NOT_FOUND`, `PRESENTATION_REVIEW_FORBIDDEN` 추가
- `FeedbackUiMessage` enum 클래스에 에러 케이스 추가
- `FETCH_FEEDBACK_FAILED`, `PRESENTATION_FORBIDDEN`, `PRESENTATION_NOT_FOUND`, `SELF_FEEDBACK_ALREADY_WRITTEN` 정의
- `FeedbackViewModel` 내 에러 핸들링 로직 개선
- 발표 상세 조회 및 피드백 저장 실패 시 `FeedbackUiMessage`로 변환하여 UI 에러 메시지 표시
- `AppException` 기반의 `toFeedbackUiMessage` 확장 함수 구현
- 피드백 화면(`FeedbackScreen`) 에러 메시지 스낵바 연동 및 다국어 리소스 추가
- `feature:feedback:impl` 모듈에 `coreCommon` 의존성 추가 및 최대 글자 수 상수명 변경(`FEEDBACK_CONTENT_MAX_LENGTH`)
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@Prezel/feature/feedback/impl/src/main/java/com/team/prezel/feature/feedback/impl/FeedbackViewModel.kt`:
- Around line 93-95: 성공 분기에서 isSaving 상태를 false로 복구하지 않아 저장 버튼이 비활성화된 상태로 남는 문제를
고치세요: FeedbackViewModel의 해당 비동기 호출의 onSuccess 블록(현재
sendEffect(FeedbackUiEffect.SaveComplete) 호출이 있는 위치)에서 isSaving 상태를 false로 설정하도록
상태 업데이트 로직(예: 상태 복사나 setState/updateState 호출)을 추가해 주세요 so that after
sendEffect(FeedbackUiEffect.SaveComplete) completes the viewModel restores
isSaving=false.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 5e13377d-49b6-4a17-8c83-d6453f901e0f
📒 Files selected for processing (16)
Prezel/app/build.gradle.ktsPrezel/core/data/src/main/java/com/team/prezel/core/data/error/AppErrorExt.ktPrezel/core/network/src/main/java/com/team/prezel/core/network/model/BaseResponse.ktPrezel/feature/analysis/impl/src/main/java/com/team/prezel/feature/analysis/impl/navigation/AnalysisEntryBuilder.ktPrezel/feature/feedback/api/src/main/java/com/team/prezel/feature/feedback/api/FeedbackNavKey.ktPrezel/feature/feedback/impl/build.gradle.ktsPrezel/feature/feedback/impl/src/main/java/com/team/prezel/feature/feedback/impl/FeedbackScreen.ktPrezel/feature/feedback/impl/src/main/java/com/team/prezel/feature/feedback/impl/FeedbackViewModel.ktPrezel/feature/feedback/impl/src/main/java/com/team/prezel/feature/feedback/impl/model/FeedbackUiMessage.ktPrezel/feature/feedback/impl/src/main/java/com/team/prezel/feature/feedback/impl/navigation/FeedbackEntryBuilder.ktPrezel/feature/feedback/impl/src/main/res/values/strings.xmlPrezel/feature/report/api/src/main/java/com/team/prezel/feature/report/api/ReportNavKey.ktPrezel/feature/report/impl/src/main/java/com/team/prezel/feature/report/impl/AnalysisReportScreen.ktPrezel/feature/report/impl/src/main/java/com/team/prezel/feature/report/impl/AnalysisReportViewModel.ktPrezel/feature/report/impl/src/main/java/com/team/prezel/feature/report/impl/contract/AnalysisReportUiIntent.ktPrezel/feature/report/impl/src/main/java/com/team/prezel/feature/report/impl/navigation/ReportEntryBuilder.kt
💤 Files with no reviewable changes (4)
- Prezel/feature/feedback/api/src/main/java/com/team/prezel/feature/feedback/api/FeedbackNavKey.kt
- Prezel/feature/report/impl/src/main/java/com/team/prezel/feature/report/impl/navigation/ReportEntryBuilder.kt
- Prezel/feature/report/api/src/main/java/com/team/prezel/feature/report/api/ReportNavKey.kt
- Prezel/feature/analysis/impl/src/main/java/com/team/prezel/feature/analysis/impl/navigation/AnalysisEntryBuilder.kt
✅ Files skipped from review due to trivial changes (2)
- Prezel/feature/report/impl/src/main/java/com/team/prezel/feature/report/impl/contract/AnalysisReportUiIntent.kt
- Prezel/feature/feedback/impl/src/main/res/values/strings.xml
🚧 Files skipped from review as they are similar to previous changes (3)
- Prezel/app/build.gradle.kts
- Prezel/feature/report/impl/src/main/java/com/team/prezel/feature/report/impl/AnalysisReportScreen.kt
- Prezel/feature/feedback/impl/src/main/java/com/team/prezel/feature/feedback/impl/FeedbackScreen.kt
- FeedbackViewModel에서 피드백 저장 성공(onSuccess) 시 isSaving 상태를 false로 변경하도록 수정하여 저장 중 상태를 해제함
- `when` 문 내 화살표(`->`) 앞의 불필요한 들여쓰기 제거
📌 작업 내용
셀프 피드백 작성 화면 신규 구현
셀프 피드백 저장 API 연동
홈 화면에서 셀프 피드백 작성 진입 연결
분석 리포트와 셀프 피드백 플로우 연결
🧩 관련 이슈
📸 스크린샷
Summary by CodeRabbit
New Features
Bug Fixes
Chores