Skip to content

인증샷 조회 API 수정 반영#84

Merged
chanho0908 merged 12 commits intodevelopfrom
feat/#83-phopolog-api-change
Feb 18, 2026
Merged

인증샷 조회 API 수정 반영#84
chanho0908 merged 12 commits intodevelopfrom
feat/#83-phopolog-api-change

Conversation

@chanho0908
Copy link
Member

@chanho0908 chanho0908 commented Feb 11, 2026

이슈 번호

#83

리뷰/머지 희망 기한 (선택)

작업내용

  • 사진 선택, 촬영시 키보드가 올라오지 않는 문제 수정
  • 날짜별 목표 인증 조회 기능 구현

결과물

default.mp4

리뷰어에게 추가로 요구하는 사항 (선택)

사진을 업로드하기까지 시간이 좀 걸려서 이 부분 개선이 필요해보여 🥲
사진 업로드 전에 뒤로가기를 하거나 화면을 이탈하면 인증 화면으로 돌아올 때 렌더링이 안되는데 이 부분은 추후 수정할게 !
목표를 상하로 스와이프 하는 기능은 아직 미구현이야 !

- `PhotologDetailUiModel` 삭제
- `GoalPhotologUiModel` 추가하여 목표별 인증 정보를 관리하도록 변경
- 날짜 기반으로 전체 목표 인증 현황을 가져오도록 API 호출 방식 수정
- UI Model 구조 변경에 따른 화면 및 ViewModel 로직 수정
@chanho0908 chanho0908 self-assigned this Feb 11, 2026
@chanho0908 chanho0908 added the Refactor Good for newcomers label Feb 11, 2026
@chanho0908 chanho0908 linked an issue Feb 11, 2026 that may be closed by this pull request
1 task
@coderabbitai
Copy link

coderabbitai bot commented Feb 11, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

포토로그 기능의 데이터 흐름과 네비게이션이 재구조화되었습니다. 네트워크 응답이 목표별 복수 포토로그를 반환하도록 PhotoLogsResponse와 GoalPhotologResponse가 추가되고 기존 PhotoLogResponse는 제거되었습니다. 도메인 모델은 GoalPhotolog과 PhotoLogs로 재정의되었고, PhotologDetail의 필드 타입과 반응(reaction) 처리가 추가되었습니다. 중간 UI 모델 계층(PhotologDetailUiModel, PhotoLogsUiModel)을 제거하고 도메인 모델을 UI에서 직접 사용하도록 변경했으며, TaskCertificationDetail 경로와 관련 네비게이션에 date 인자가 추가되어 targetDate 기반 조회로 전환되었습니다.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 가장 중요한 변경사항인 인증샷 조회 API 수정을 명확히 반영하고 있습니다.
Description check ✅ Passed PR 설명이 구체적인 작업 내용(키보드 문제 수정, 날짜별 목표 인증 조회 구현)을 포함하고 있습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/#83-phopolog-api-change

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In
`@core/network/src/main/java/com/twix/network/model/response/photolog/PhotologDetailResponse.kt`:
- Line 15: The PhotologDetailResponse data class declares
`@SerialName`("reaction") val reaction: String? without a default which can cause
kotlinx.serialization MissingFieldException when the server omits the key;
update the declaration for reaction in PhotologDetailResponse to provide a
default (e.g., reaction: String? = null) similar to the comment field so
deserialization is safe and consistent.

In
`@feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetailViewModel.kt`:
- Line 87: The constant TARGET_DATE_NOT_FOUND contains an extra "Id" from a copy
of GOAL_ID_NOT_FOUND; update the string value of TARGET_DATE_NOT_FOUND (in
TaskCertificationDetailViewModel) to remove "Id" so it reads "Target Date
Argument Not Found" (ensure the constant name TARGET_DATE_NOT_FOUND is
unchanged).
- Around line 69-75: 요약: TaskCertificationDetailIntent.Sting가 TODO("찌르기 API
연동")로 남아 있어 NotImplementedError로 크래시를 발생시킵니다; handleIntent에서 이를 안전한 처리를 하도록
교체하세요. 수정 방법: TaskCertificationDetailViewModel의 handleIntent에서
TaskCertificationDetailIntent.Sting 분기를 TODO로 남기지 말고 삭제하고, 대신 크래시를 유발하지 않는 동작으로
바꿉니다 — 예: 기존 효과/이벤트 채널이 있으면 _effect.tryEmit(UIEffect.ShowToast("준비 중")) 또는
viewState 이벤트(예: emitEvent/showToast)로 "준비 중" 토스트를 발행하거나, 간단한 no-op 핸들러
handleStingPlaceholder()를 추가해 호출하도록 변경하세요; 관련 심볼: handleIntent,
TaskCertificationDetailIntent.Sting, reduceReaction, reduceShownCard, (또는 사용 중인
이벤트 채널 이름)_effect/_events를 찾아 적용하세요.
🧹 Nitpick comments (9)
feature/task-certification/src/main/java/com/twix/task_certification/detail/component/CertificatedCard.kt (1)

37-37: 더 관용적인 null/empty 체크 사용을 권장합니다

comment?.isNotEmpty() == true는 동작상 문제는 없지만, Kotlin에서는 !comment.isNullOrEmpty()가 더 관용적이고 가독성이 좋습니다.

♻️ 제안하는 변경
-        if (comment?.isNotEmpty() == true) {
+        if (!comment.isNullOrEmpty()) {
feature/task-certification/src/main/java/com/twix/task_certification/detail/model/GoalPhotologUiModel.kt (1)

24-28: computed property의 재계산에 대해 — 현재는 괜찮습니다

myUpdatedDatepartnerUpdatedDateget()으로 매 접근 시 RelativeTimeFormatter.format()을 호출합니다. 현재는 가벼운 연산이라 문제없지만, 만약 RelativeTimeFormatter.format()이 무거워지거나 Compose recomposition이 빈번해진다면 캐싱을 고려해볼 수 있습니다.

core/network/src/main/java/com/twix/network/service/PhotoLogService.kt (1)

22-25: 파라미터 이름 request가 의미를 전달하지 못합니다.

@Query("targetDate")의 값으로 날짜 문자열을 전달하는데, 파라미터명이 request로 되어 있어 실제 의미와 괴리가 있습니다. 다른 메서드(getUploadUrl)에서는 goalId처럼 의미 있는 이름을 사용하고 있으므로, 일관성을 위해서도 targetDate로 변경하는 것이 좋겠습니다.

♻️ 제안하는 변경
     `@GET`("api/v1/photologs")
     suspend fun fetchPhotoLogs(
-        `@Query`("targetDate") request: String,
+        `@Query`("targetDate") targetDate: String,
     ): PhotoLogsResponse
domain/src/main/java/com/twix/domain/repository/PhotoLogRepository.kt (1)

19-19: targetDate의 타입으로 String 대신 LocalDate 사용을 고려해 보세요.

현재 HomeScreen에서는 LocalDate로 날짜를 관리하고, 네비게이션을 통해 String으로 변환된 후 도메인 레이어까지 String으로 전달됩니다. 도메인 레이어는 외부 포맷에 의존하지 않는 것이 이상적이므로, targetDateLocalDate로 정의하고 Data 레이어(Repository 구현체)에서 String으로 변환하면 다음과 같은 이점이 있습니다:

  1. 타입 안전성: 잘못된 날짜 형식의 문자열이 전달되는 것을 컴파일 타임에 방지
  2. 도메인 순수성: 도메인 모델이 API의 날짜 포맷(예: "yyyy-MM-dd")에 결합되지 않음

다만 java.time 의존성을 도메인에 두는 것이 프로젝트 방침에 맞는지 확인이 필요합니다. 이미 다른 곳에서 LocalDate를 사용하고 있다면 일관성 있게 적용하는 것이 좋겠습니다.

feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetail.kt (1)

213-217: 주석 처리된 ReactionSection 코드에 대해 — TODO 추적이 필요합니다.

ViewModel에서 Sting에 대한 TODO가 있고, 여기서 ReactionSection이 주석 처리되어 있는데, 이 코드가 추후 복원될 예정이라면 관련 이슈 번호를 주석에 함께 남겨두면 추적이 용이합니다. 만약 제거 대상이라면 완전히 삭제하는 것이 코드 가독성 측면에서 더 좋습니다.

// TODO(`#이슈번호`): ReactionSection 복원 - 찌르기 API 연동 후 활성화
domain/src/main/java/com/twix/domain/model/photolog/PhotologDetail.kt (1)

5-18: Non-null 전환과 불변 업데이트 패턴이 잘 적용되었습니다.

핵심 필드들(photologId, imageUrl)의 nullable 제거는 도메인 계층에서의 null 안전성을 높이고, updateReaction()updateComment()copy()를 활용하여 불변성을 유지하는 점이 좋습니다. isMine 필드 제거도 새로운 GoalPhotolog 구조에서 my/partner를 구조적으로 분리한 것과 잘 맞습니다.

한 가지 향후 개선 포인트로, verificationDate, uploadedAt 등 날짜/시간 필드가 String으로 되어 있는데, 도메인 레벨에서 LocalDate/LocalDateTime 같은 타입을 사용하면 비즈니스 로직에서 날짜 비교나 포맷팅이 더 안전해질 수 있습니다. 현재 구조에서 급한 사항은 아니지만, 참고해 주세요.

feature/task-certification/src/main/java/com/twix/task_certification/detail/model/TaskCertificationDetailUiState.kt (2)

14-43: computed property들이 매 접근마다 goalCache Map을 재생성하는 구조입니다.

currentGoalphotoLogs[currentGoalId]를 호출하고, 이는 내부적으로 goalPhotolog.associateBy { it.goalId }로 Map을 매번 새로 생성합니다. 한 번의 recomposition에서 isDisplayedGoalCertificated, displayedGoalUpdateAt, displayedGoalImageUrl, displayedGoalComment, canModify, canReaction 등이 각각 currentGoal에 접근하므로, Map이 여러 번 불필요하게 재생성됩니다.

현재 goal 수가 적다면 실질적 성능 영향은 크지 않겠지만, PhotoLogsUiModelgoalCache를 lazy 초기화하거나 currentGoal을 state 필드로 직접 관리하면 더 효율적입니다. 이 부분은 PhotoLogsUiModel 리뷰에서 더 자세히 다루겠습니다.


9-10: currentGoalId의 기본값 -1L에 대해 — sentinel value 사용의 안전성을 확인해 주세요.

currentGoalId = -1L은 초기 상태에서 photoLogs[-1L]이 호출되면 빈 GoalPhotologUiModel()을 반환하여 크래시는 방지됩니다. 다만, reduceGoalId()가 호출되기 전에 UI가 렌더링되면 빈 데이터가 잠시 표시될 수 있습니다. init 블록에서 reduceGoalId()가 먼저 호출되므로 현재 구조에서는 문제가 없지만, 의도를 명확히 하기 위해 상수로 분리하는 것도 고려해 볼 수 있습니다.

feature/task-certification/src/main/java/com/twix/task_certification/detail/model/PhotoLogsUiModel.kt (1)

14-17: goalCache가 getter로 정의되어 접근할 때마다 Map이 재생성됩니다.

goalCacheget() = goalPhotolog.associateBy { ... }로 정의되어 있어, operator fun get(goalId)가 호출될 때마다 전체 리스트를 순회하여 새로운 Map을 생성합니다. TaskCertificationDetailUiState의 computed property들이 currentGoal을 반복적으로 참조하므로, 한 번의 recomposition에서 Map이 여러 차례 불필요하게 생성됩니다.

goal 수가 적으므로, Map을 생성하지 않고 find로 직접 검색하는 것이 더 간결하고 효율적입니다.

♻️ 개선 제안
-    private val goalCache: Map<Long, GoalPhotologUiModel>
-        get() = goalPhotolog.associateBy { it.goalId }
-
-    operator fun get(goalId: Long): GoalPhotologUiModel = goalCache[goalId] ?: GoalPhotologUiModel()
+    operator fun get(goalId: Long): GoalPhotologUiModel =
+        goalPhotolog.find { it.goalId == goalId } ?: GoalPhotologUiModel()

@SerialName("verificationDate") val verificationDate: String,
@SerialName("uploaderName") val uploaderName: String,
@SerialName("uploadedAt") val uploadedAt: String,
@SerialName("reaction") val reaction: String?,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

reaction 필드에 기본값 누락 — 역직렬화 실패 위험

commentString? = null로 기본값이 있지만, reactionString?만 선언되어 기본값이 없습니다. 서버 응답에서 "reaction" 키가 아예 없는 경우, kotlinx.serialization은 MissingFieldException을 발생시킵니다.

서버가 항상 이 필드를 포함한다면 괜찮지만, comment과의 일관성 및 방어적 코딩 관점에서 기본값 추가를 권장합니다.

🛡️ 제안하는 변경
-    `@SerialName`("reaction") val reaction: String?,
+    `@SerialName`("reaction") val reaction: String? = null,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@SerialName("reaction") val reaction: String?,
`@SerialName`("reaction") val reaction: String? = null,
🤖 Prompt for AI Agents
In
`@core/network/src/main/java/com/twix/network/model/response/photolog/PhotologDetailResponse.kt`
at line 15, The PhotologDetailResponse data class declares
`@SerialName`("reaction") val reaction: String? without a default which can cause
kotlinx.serialization MissingFieldException when the server omits the key;
update the declaration for reaction in PhotologDetailResponse to provide a
default (e.g., reaction: String? = null) similar to the comment field so
deserialization is safe and consistent.

Copy link
Member

@dogmania dogmania left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

상태 업데이트하는 로직이 UiModel, UiState 여기저기 퍼져있는 것만 뷰모델로 통합하면 좋을 것 같은데 다른 의견 있으시면 말씀해주세요!

Comment on lines 14 to 15
private val goalCache: Map<Long, GoalPhotologUiModel>
get() = goalPhotolog.associateBy { it.goalId }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

캐시를 활용하려고 하신 거 같은데 되게 좋은 거 같아요! 그런데 지금 형태는 매번 associateBy가 실행될 수도 있을 거 같아서 의도치 않게 반복 생성될 수 있어요. 그래서 차라리 goalCache를 PhotoLogUiModel의 생성자 필드로 옮겨서 copy할 때 같이 갱신하도록 하고 toUiModel에서 추가해주는 건 어떨까요


operator fun get(goalId: Long): GoalPhotologUiModel = goalCache[goalId] ?: GoalPhotologUiModel()

fun updatePartnerReaction(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

실제 상태 업데이트하는 로직은 뷰모델로 옮겨주세요! 지금 UiState, UiModel이 여러개로 분산되어 있고 update도 퍼져 있어서 유지보수 과정에서 어려움이 있을 거 같아요

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

다른 리뷰도 비슷한 내용이라 요기에 한번에 답변 남길게 👍

현수가 말한 것 처럼 상태 업데이트 로직이 분산되어 있는건 맞아 ㅇㅅㅇ,,,
다만 이렇게 구현했던 이유는 내가 일전에 ViewModel에 모든 상태 변환을 두니까
ViewModel이 너~~~무 비대해져서 이걸 리팩터링 하는데 너무 힘들었던 경험이 있어서 UiState내에 위치 시키고
ViewModel은 이 함수들을 사용해서 상태를 업데이트하면 ViewModel 다이어트가 가능하더라구

다만 이렇게 하니까 단순히 값 하나만 바꿔도 함수를 만들어야 하더라구 ...

그래서 이 상태 업데이트 로직을 만드는 기준이 되게 애매해지는걸 나도 코드 짜면서 느꼈어
근데 다시 고민해보니 이것도 결국에 ViewModel에서 함수를 잘 분리하면 해결되는 것 같네?

이번 리뷰를 반영하면서 PhotoLogsUiModel, GoalPhotologUiModel 등 복잡하게 나누어진 UiState, UiModel 들을 TaskCertificationDetailUiState 하나로 통일 하는 방향으로 리팩터링 했어

이유는 UiModel과 UiState에 있는 상태 업데이트를 ViewModel로 옮기니까 이란 괴랄한 코드가 나오더라구.. 😓

private fun reduceReaction(reaction: GoalReactionType) {
    reduce {
        currentState.copy(
            photoLogs = currentState.photoLogs.copy(
                goalPhotolog = currentState.photoLogs.goalPhotolog.copy(
                    partnerPhotolog = currentState.photoLogs.goalPhotolog.myPhotolog?.copy(
                        reaction = reaction,
                    ),
                )
            )
        )
    }
}

이걸 보니 지금 UiState가 너무 과하게 분리되었단 생각이 들어서 하나의 UiState로 통일했어 !

리뷰 반영 커밋

TODO

내가 다른 코드들도 다 이렇게 짜놔서 어제 이야기한 컨벤션 내용에 추가해서 나중에 한번에 리팩터링할게 !

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

굿굿 좋아요!

get() = partnerPhotolog?.uploadedAt?.let { RelativeTimeFormatter.format(it) } ?: ""

fun updatePartnerReaction(reaction: GoalReactionType): GoalPhotologUiModel =
copy(partnerPhotolog = partnerPhotolog?.updateReaction(reaction))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

상태를 업데이트하는 로직은 뷰모델로 옮겨주세요!

photoLogs.partnerPhotologs.isCertificated
currentShow == BetweenUs.PARTNER && currentGoal.isPartnerCertificated

fun toggleBetweenUs() =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UiModel이나 UiState에서는 파생 상태 정도만 관리하는 걸로 하고 상태 업데이트 로직은 다 뷰모델로 옮겨주세요

}

private fun reduceReaction(reaction: GoalReactionType) {
reduce { updatePartnerReaction(reaction) }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

서버랑 통신하는 로직이 빠져있는 것 같은데 아직 구현이 안된 건가요??

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요건 이거 바로 다음 PR에 적용 되어있어 !

굳이 PR을 나눈 이유는 추후 PR을 찾아보고 싶을 때 내가 구현했던 핵심적인 코드들을 찾아보기 쉬워서야 !

예를 들면 이번 리액션 API를 적용하면서 디바운싱을 적용했는데 나중에 이 내용만 찾아보고 싶으면 바로 필터링 해서 찾기 편하더라구 🙂

Comment on lines 29 to 33
?: error(GOAL_ID_NOT_FOUND)

private val targetDate: String =
savedStateHandle[NavRoutes.TaskCertificationDetailRoute.ARG_DATE]
?: error(TARGET_DATE_NOT_FOUND)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 이런식으로 네비게이션 파라미터 값을 꺼낼 수 있다는 건 처음 알았어요 신기하네요

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

savedStateHandle을 사용하면 Navigation BackStackEntry에서 값을 꺼내서
UI → ViewModel로 전달하는 과정을 줄일 수 있어서 편한 것 같더라!

무엇보다 savedStateHandle은 프로세스가 죽어도 재생성 시 자동으로 상태를 복원해줘서 안정성 면에서도 좋은 것 같아 👍

coderabbitai[bot]

This comment was marked as resolved.

@YAPP-Github YAPP-Github deleted a comment from coderabbitai bot Feb 18, 2026
@YAPP-Github YAPP-Github deleted a comment from coderabbitai bot Feb 18, 2026
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
feature/task-certification/src/main/java/com/twix/task_certification/detail/model/TaskCertificationDetailUiState.kt (1)

22-64: 표시 대상 선택 로직 중복을 줄이면 일관성 관리가 쉬워집니다.
현재 currentShow 기준 분기가 여러 프로퍼티에 반복되어, 추후 분기 로직 변경 시 누락 위험이 있습니다. 공통 선택 결과를 하나의 프로퍼티로 묶어 재사용하면 유지보수가 쉬워집니다.

♻️ 제안 리팩터링
 data class TaskCertificationDetailUiState(
     val goalId: Long = -1L,
     val currentShow: BetweenUs = BetweenUs.PARTNER,
@@
     val partnerPhotolog: PhotologDetail? = null,
 ) : State {
+    private val displayedPhotolog: PhotologDetail?
+        get() = when (currentShow) {
+            BetweenUs.ME -> myPhotolog
+            BetweenUs.PARTNER -> partnerPhotolog
+        }
+
     val isDisplayedGoalCertificated: Boolean
         get() =
             when (currentShow) {
                 BetweenUs.ME -> myPhotolog != null
                 BetweenUs.PARTNER -> partnerPhotolog != null
             }
@@
     val displayedGoalUpdateAt: String
         get() =
-            when (currentShow) {
-                BetweenUs.ME ->
-                    myPhotolog?.uploadedAt?.let {
-                        RelativeTimeFormatter.format(it)
-                    } ?: ""
-
-                BetweenUs.PARTNER ->
-                    partnerPhotolog?.uploadedAt?.let {
-                        RelativeTimeFormatter.format(
-                            it,
-                        )
-                    } ?: ""
-            }
+            displayedPhotolog?.uploadedAt?.let { RelativeTimeFormatter.format(it) } ?: ""
@@
     val displayedGoalImageUrl: String?
-        get() =
-            when (currentShow) {
-                BetweenUs.ME -> myPhotolog?.imageUrl
-                BetweenUs.PARTNER -> partnerPhotolog?.imageUrl
-            }
+        get() = displayedPhotolog?.imageUrl
@@
     val displayedGoalComment: String?
-        get() =
-            when (currentShow) {
-                BetweenUs.ME -> myPhotolog?.comment
-                BetweenUs.PARTNER -> partnerPhotolog?.comment
-            }
+        get() = displayedPhotolog?.comment
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@feature/task-certification/src/main/java/com/twix/task_certification/detail/model/TaskCertificationDetailUiState.kt`
around lines 22 - 64, Multiple properties duplicate the same when(currentShow)
branching (BetweenUs.ME / BetweenUs.PARTNER) causing maintenance risk; introduce
one or two shared computed properties (e.g., selectedPhotolog: Photolog? and
selectedNickname: String) that return myPhotolog/partnerPhotolog and
myNickname/partnerNickname based on currentShow, then rewrite
displayedGoalCertificated, displayedGoalUpdateAt, displayedGoalImageUrl,
displayedGoalComment, and displayedNickname to read from
selectedPhotolog/selectedNickname (use RelativeTimeFormatter.format on
selectedPhotolog?.uploadedAt where needed) so branching is centralized in the
selected* accessors (keep current property names intact for external callers).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@feature/task-certification/src/main/java/com/twix/task_certification/detail/model/TaskCertificationDetailUiState.kt`:
- Around line 75-89: The current PhotoLogs.toUiState(goalId: Long) returns a
default TaskCertificationDetailUiState() when the goal isn't found, which drops
the requested goalId; change the fallback to preserve the requested id (e.g.,
return TaskCertificationDetailUiState(goalId = goalId)) or return an explicit
error state field on TaskCertificationDetailUiState if you prefer signalling
failure; update the toUiState function to return
TaskCertificationDetailUiState(goalId = goalId, /* optionally isError = true */)
instead of the parameterless constructor so downstream actions/navigation can
still identify the requested goal.

---

Nitpick comments:
In
`@feature/task-certification/src/main/java/com/twix/task_certification/detail/model/TaskCertificationDetailUiState.kt`:
- Around line 22-64: Multiple properties duplicate the same when(currentShow)
branching (BetweenUs.ME / BetweenUs.PARTNER) causing maintenance risk; introduce
one or two shared computed properties (e.g., selectedPhotolog: Photolog? and
selectedNickname: String) that return myPhotolog/partnerPhotolog and
myNickname/partnerNickname based on currentShow, then rewrite
displayedGoalCertificated, displayedGoalUpdateAt, displayedGoalImageUrl,
displayedGoalComment, and displayedNickname to read from
selectedPhotolog/selectedNickname (use RelativeTimeFormatter.format on
selectedPhotolog?.uploadedAt where needed) so branching is centralized in the
selected* accessors (keep current property names intact for external callers).

chanho0908 added a commit that referenced this pull request Feb 18, 2026
…fication-update

# Conflicts:
#	data/src/main/java/com/twix/data/repository/DefaultPhotoLogRepository.kt
#	feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetail.kt
#	feature/task-certification/src/main/java/com/twix/task_certification/detail/TaskCertificationDetailViewModel.kt
#	feature/task-certification/src/main/java/com/twix/task_certification/detail/model/TaskCertificationDetailUiState.kt
#	feature/task-certification/src/main/res/values/strings.xml
@chanho0908 chanho0908 requested a review from dogmania February 18, 2026 08:35
Copy link
Member

@dogmania dogmania left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고생하셨습니다~~!

@chanho0908 chanho0908 merged commit 9bcf6d8 into develop Feb 18, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Refactor Good for newcomers

Projects

None yet

Development

Successfully merging this pull request may close these issues.

인증샷 조회 API 수정 반영

2 participants

Comments