fix(creator): 팬Talk 액션 팝업을 정리한다

This commit is contained in:
Yu Sung
2026-07-07 15:44:45 +09:00
parent 75aa99768e
commit f2d589eca2
8 changed files with 170 additions and 78 deletions

View File

@@ -3608,6 +3608,14 @@ If you block this user, the following features will be restricted.
pick(ko: "수정", en: "Edit", ja: "編集")
}
static var editAction: String {
pick(ko: "수정하기", en: "Edit", ja: "編集する")
}
static var deleteAction: String {
pick(ko: "삭제하기", en: "Delete", ja: "削除する")
}
static var report: String {
pick(ko: "신고", en: "Report", ja: "通報")
}

View File

@@ -156,6 +156,10 @@ struct CreatorChannelView: View {
authConfirmDialog
}
if viewModel.selectedTab == .fanTalk && fanTalkViewModel.isShowDeleteDialog {
fanTalkDeleteDialog
}
if isShowChannelDonationDialog {
LiveRoomDonationDialogView(
isShowing: $isShowChannelDonationDialog,
@@ -338,6 +342,30 @@ struct CreatorChannelView: View {
)
}
private var fanTalkDeleteDialog: some View {
SodaV2ActionModal(
title: I18n.MemberChannel.cheersDeleteTitle,
message: I18n.Common.confirmDeleteQuestion,
button1: SodaV2ActionModalButton(
label: I18n.Common.delete,
action: {
fanTalkViewModel.isShowDeleteDialog = false
fanTalkViewModel.deleteSelectedFanTalk(creatorId: creatorId)
}
),
button2: SodaV2ActionModalButton(
label: I18n.Common.cancel,
action: dismissFanTalkDeleteDialog
),
onDimmedTap: dismissFanTalkDeleteDialog
)
}
private func dismissFanTalkDeleteDialog() {
fanTalkViewModel.isShowDeleteDialog = false
fanTalkViewModel.selectedFanTalkId = 0
}
private var authView: some View {
BootpayUI(payload: payload, requestType: BootpayRequest.TYPE_AUTHENTICATION)
.onConfirm { _ in true }

View File

@@ -1,19 +1,21 @@
import SwiftUI
struct CreatorChannelFanTalkActionPopup: View {
let isMine: Bool
let isOwnCreatorChannel: Bool
struct CreatorChannelActionPopup: View {
let canEdit: Bool
let canDelete: Bool
let onTapEdit: () -> Void
let onTapDelete: () -> Void
var editTitle = I18n.Explorer.editAction
var deleteTitle = I18n.Explorer.deleteAction
var body: some View {
VStack(alignment: .leading, spacing: 0) {
if isMine {
actionButton(title: "수정하기", action: onTapEdit)
if canEdit {
actionButton(title: editTitle, action: onTapEdit)
}
if isMine || isOwnCreatorChannel {
actionButton(title: "삭제하기", action: onTapDelete)
if canDelete {
actionButton(title: deleteTitle, action: onTapDelete)
}
}
.background(Color.gray900)
@@ -37,3 +39,19 @@ struct CreatorChannelFanTalkActionPopup: View {
.buttonStyle(.plain)
}
}
struct CreatorChannelFanTalkActionPopup: View {
let isMine: Bool
let isOwnCreatorChannel: Bool
let onTapEdit: () -> Void
let onTapDelete: () -> Void
var body: some View {
CreatorChannelActionPopup(
canEdit: isMine,
canDelete: isMine || isOwnCreatorChannel,
onTapEdit: onTapEdit,
onTapDelete: onTapDelete
)
}
}

View File

@@ -30,7 +30,6 @@ struct CreatorChannelFanTalkTabView: View {
}
.sodaToast(isPresented: $viewModel.isShowPopup, message: viewModel.errorMessage, autohideIn: 1)
.overlay(reportDialog)
.overlay(deleteDialog)
}
private var content: some View {
@@ -100,9 +99,9 @@ struct CreatorChannelFanTalkTabView: View {
let itemFrame = fanTalkItemFrames[fanTalk.fanTalkId] {
let isMine = fanTalk.writerId == UserDefaults.int(forKey: .userId)
CreatorChannelFanTalkActionPopup(
isMine: isMine,
isOwnCreatorChannel: isOwnCreatorChannel,
CreatorChannelActionPopup(
canEdit: isMine,
canDelete: isMine || isOwnCreatorChannel,
onTapEdit: {
actionPopupFanTalk = nil
onTapEdit(fanTalk)
@@ -110,7 +109,9 @@ struct CreatorChannelFanTalkTabView: View {
onTapDelete: {
actionPopupFanTalk = nil
viewModel.presentDeleteDialog(fanTalkId: fanTalk.fanTalkId)
}
},
editTitle: I18n.Explorer.editAction,
deleteTitle: I18n.Explorer.deleteAction
)
.padding(.top, itemFrame.minY + 44)
.padding(.trailing, SodaSpacing.s14)
@@ -134,26 +135,6 @@ struct CreatorChannelFanTalkTabView: View {
}
}
@ViewBuilder
private var deleteDialog: some View {
if viewModel.isShowDeleteDialog {
SodaDialog(
title: I18n.MemberChannel.cheersDeleteTitle,
desc: I18n.Common.confirmDeleteQuestion,
confirmButtonTitle: I18n.Common.delete,
confirmButtonAction: {
viewModel.isShowDeleteDialog = false
viewModel.deleteSelectedFanTalk(creatorId: creatorId)
},
cancelButtonTitle: I18n.Common.cancel,
cancelButtonAction: {
viewModel.isShowDeleteDialog = false
viewModel.selectedFanTalkId = 0
},
textAlignment: .center
)
}
}
private static let coordinateSpaceName = "CreatorChannelFanTalkTabView"
}

View File

@@ -7,33 +7,13 @@ struct CreatorChannelReplyDetailActionPopup: View {
let onTapDelete: () -> Void
var body: some View {
VStack(alignment: .leading, spacing: 0) {
if canEdit {
actionButton(title: I18n.Explorer.edit, action: onTapEdit)
}
if canDelete {
actionButton(title: I18n.Common.delete, action: onTapDelete)
}
}
.background(Color.gray900)
.cornerRadius(14)
.overlay(
RoundedRectangle(cornerRadius: 14, style: .continuous)
.stroke(Color.gray700, lineWidth: 1)
CreatorChannelActionPopup(
canEdit: canEdit,
canDelete: canDelete,
onTapEdit: onTapEdit,
onTapDelete: onTapDelete,
editTitle: I18n.Explorer.editAction,
deleteTitle: I18n.Explorer.deleteAction
)
}
private func actionButton(title: String, action: @escaping () -> Void) -> some View {
Button(action: action) {
Text(title)
.appFont(size: 14, weight: .medium)
.foregroundColor(.white)
.lineLimit(1)
.frame(minWidth: 80, alignment: .leading)
.padding(.horizontal, SodaSpacing.s12)
.padding(.vertical, SodaSpacing.s8)
}
.buttonStyle(.plain)
}
}

View File

@@ -45,17 +45,18 @@ struct CreatorChannelReplyDetailView: View {
}
if viewModel.isShowDeleteDialog {
SodaDialog(
SodaV2ActionModal(
title: I18n.Common.commentDeleteTitle,
desc: I18n.Common.confirmDeleteQuestion,
confirmButtonTitle: I18n.Common.delete,
confirmButtonAction: viewModel.confirmDelete,
cancelButtonTitle: I18n.Common.cancel,
cancelButtonAction: {
viewModel.isShowDeleteDialog = false
viewModel.deletingItem = nil
},
textAlignment: .center
message: I18n.Common.confirmDeleteQuestion,
button1: SodaV2ActionModalButton(
label: I18n.Common.delete,
action: viewModel.confirmDelete
),
button2: SodaV2ActionModalButton(
label: I18n.Common.cancel,
action: dismissDeleteDialog
),
onDimmedTap: dismissDeleteDialog
)
}
}
@@ -65,4 +66,9 @@ struct CreatorChannelReplyDetailView: View {
}
.sodaToast(isPresented: $viewModel.isShowPopup, message: viewModel.errorMessage, autohideIn: 1)
}
private func dismissDeleteDialog() {
viewModel.isShowDeleteDialog = false
viewModel.deletingItem = nil
}
}

View File

@@ -362,6 +362,59 @@
- 기대 결과: `BUILD SUCCEEDED`.
- workspace 인식 실패 등 환경 문제가 있으면 `xcodebuild -project "SodaLive.xcodeproj" -scheme "SodaLive-dev" -configuration Debug build`를 대체 검증으로 실행하고 실패 원인을 검증 기록에 남긴다.
### Phase 10: 팬Talk 팝업 위치와 문구 통일
- [x] **Task 10.1: 삭제 확인 모달 표시 위치 상위 이동**
- 대상 파일:
- 수정: `SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift`
- 수정: `SodaLive/Sources/V2/CreatorChannel/FanTalk/CreatorChannelFanTalkTabView.swift`
- 작업 내용:
- 팬Talk row 더보기의 `삭제` 선택 시 기존 선택 상태와 삭제 API 흐름은 유지한다.
- 삭제 확인 모달 렌더링은 팬Talk 탭 내부 overlay에서 제거하고 `CreatorChannelView`의 상위 `ZStack`에서 표시한다.
- 삭제 확인 모달은 기존 `SodaDialog` 대신 `SodaV2ActionModal`을 사용한다.
- 신고 사유 선택 UI인 `CheersReportDialogView`는 기존 신고 플로우 재사용 범위로 유지하고 이번 확인형 V2 popup dialog 전환 대상에서 제외한다.
- 검증 기준:
- 실행 명령: `rg "fanTalkDeleteDialog|SodaV2ActionModal|isShowDeleteDialog|deleteSelectedFanTalk|overlay\(deleteDialog\)|private var deleteDialog" SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift SodaLive/Sources/V2/CreatorChannel/FanTalk/CreatorChannelFanTalkTabView.swift`
- 기대 결과: `CreatorChannelView``fanTalkDeleteDialog``SodaV2ActionModal`이 있고, `CreatorChannelFanTalkTabView`에는 삭제 dialog overlay가 남지 않는다.
- [x] **Task 10.2: 팬Talk 리스트/상세 anchored context popup 공용화**
- 대상 파일:
- 수정: `SodaLive/Sources/V2/CreatorChannel/FanTalk/Components/CreatorChannelFanTalkActionPopup.swift`
- 수정: `SodaLive/Sources/V2/CreatorChannel/ReplyDetail/Components/CreatorChannelReplyDetailActionPopup.swift`
- 확인: `SodaLive/Sources/V2/CreatorChannel/FanTalk/CreatorChannelFanTalkTabView.swift`
- 확인: `SodaLive/Sources/V2/CreatorChannel/ReplyDetail/Components/CreatorChannelReplyDetailFeedView.swift`
- 작업 내용:
- 공용 `CreatorChannelActionPopup`을 사용해 리스트와 상세의 anchored context popup UI와 문구를 통일한다.
- 팬Talk 목록 row의 사용자 노출 문구는 `I18n.Explorer.editAction`, `I18n.Explorer.deleteAction`을 사용해 `수정하기`, `삭제하기`로 표시한다.
- 검증 기준:
- 실행 명령: `rg "CreatorChannelActionPopup|I18n\.Explorer\.editAction|I18n\.Explorer\.deleteAction|수정하기|삭제하기" SodaLive/Sources/V2/CreatorChannel/FanTalk/Components/CreatorChannelFanTalkActionPopup.swift SodaLive/Sources/V2/CreatorChannel/FanTalk/CreatorChannelFanTalkTabView.swift SodaLive/Sources/I18n/I18n.swift`
- 기대 결과: 팬Talk 목록 row가 공용 popup에 action 문구를 주입하고, `수정하기`/`삭제하기` 문구는 I18n 키에서 확인된다.
- [x] **Task 10.3: 팬Talk 상세 삭제 dialog V2 모달 적용**
- 대상 파일:
- 수정: `SodaLive/Sources/V2/CreatorChannel/ReplyDetail/CreatorChannelReplyDetailView.swift`
- 작업 내용:
- 팬Talk 상세/답글 화면의 삭제 확인 dialog도 `SodaV2ActionModal`로 교체한다.
- 확인, 취소, dimmed tap에서 기존 삭제/닫기 상태 흐름을 유지한다.
- 검증 기준:
- 실행 명령: `rg "SodaV2ActionModal|dismissDeleteDialog|confirmDelete|SodaDialog" SodaLive/Sources/V2/CreatorChannel/ReplyDetail/CreatorChannelReplyDetailView.swift`
- 기대 결과: 상세 삭제 확인 dialog가 `SodaV2ActionModal`을 사용하고 `SodaDialog`는 남지 않는다.
- [x] **Task 10.4: 정적/빌드 검증**
- 대상 파일:
- 확인: `docs/20260704_크리에이터_채널_팬Talk_탭/prd.md`
- 확인: `docs/20260704_크리에이터_채널_팬Talk_탭/plan-task.md`
- 확인: `SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift`
- 확인: `SodaLive/Sources/V2/CreatorChannel/FanTalk/CreatorChannelFanTalkTabView.swift`
- 확인: `SodaLive/Sources/V2/CreatorChannel/FanTalk/Components/CreatorChannelFanTalkActionPopup.swift`
- 확인: `SodaLive/Sources/V2/CreatorChannel/ReplyDetail/CreatorChannelReplyDetailView.swift`
- 확인: `SodaLive/Sources/V2/CreatorChannel/ReplyDetail/Components/CreatorChannelReplyDetailActionPopup.swift`
- 검증 기준:
- 실행 명령: `git diff --check -- docs/20260704_크리에이터_채널_팬Talk_탭 SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift SodaLive/Sources/V2/CreatorChannel/FanTalk/CreatorChannelFanTalkTabView.swift SodaLive/Sources/V2/CreatorChannel/FanTalk/Components/CreatorChannelFanTalkActionPopup.swift SodaLive/Sources/V2/CreatorChannel/ReplyDetail/CreatorChannelReplyDetailView.swift SodaLive/Sources/V2/CreatorChannel/ReplyDetail/Components/CreatorChannelReplyDetailActionPopup.swift`
- 기대 결과: 공백 오류 없이 성공한다.
- 실행 명령: `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build`
- 기대 결과: `BUILD SUCCEEDED`.
## 검증 기록
- 2026-07-04: Figma `get_design_context``get_screenshot`으로 `290:9139`, `290:9145`, `290:9147`, `666:36114`, `290:9001`을 확인했다.
@@ -389,3 +442,10 @@
- 2026-07-06: `plutil -lint SodaLive.xcodeproj/project.pbxproj` 결과 `OK`를 확인했다.
- 2026-07-06: `git diff --check -- docs/20260704_크리에이터_채널_팬Talk_탭 SodaLive/Sources/V2/Component/Modal SodaLive/Sources/V2/CreatorChannel/FanTalk/Write SodaLive/Sources/App/AppStep.swift SodaLive/Sources/ContentView.swift SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift SodaLive/Sources/V2/CreatorChannel/FanTalk/CreatorChannelFanTalkTabView.swift SodaLive/Sources/I18n/I18n.swift SodaLive.xcodeproj/project.pbxproj` 실행 결과 출력 없이 종료되어 공백 오류가 없음을 확인했다.
- 2026-07-06: `xcodebuild -workspace "SodaLive.xcworkspace" -scheme "SodaLive-dev" -configuration Debug build` 결과 `BUILD SUCCEEDED`를 확인했다. 빌드 중 `Alamofire` dependency scan warning이 출력되었으나 빌드는 성공했다.
- 2026-07-07: `rg "fanTalkDeleteDialog|SodaV2ActionModal|isShowDeleteDialog|deleteSelectedFanTalk|overlay\(deleteDialog\)|private var deleteDialog" SodaLive/Sources/V2/CreatorChannel/CreatorChannelView.swift SodaLive/Sources/V2/CreatorChannel/FanTalk/CreatorChannelFanTalkTabView.swift`로 팬Talk 삭제 모달이 상위 `CreatorChannelView`에서 `SodaV2ActionModal`로 표시되고, 팬Talk 탭 내부 삭제 dialog overlay가 제거된 것을 확인했다.
- 2026-07-07: `rg "CreatorChannelActionPopup|I18n\.Explorer\.edit|I18n\.Common\.delete|수정하기|삭제하기" SodaLive/Sources/V2/CreatorChannel/FanTalk/Components/CreatorChannelFanTalkActionPopup.swift SodaLive/Sources/V2/CreatorChannel/ReplyDetail/Components/CreatorChannelReplyDetailActionPopup.swift SodaLive/Sources/V2/CreatorChannel/FanTalk/CreatorChannelFanTalkTabView.swift SodaLive/Sources/V2/CreatorChannel/ReplyDetail/Components/CreatorChannelReplyDetailFeedView.swift`로 리스트와 상세 anchored context popup이 공용 컴포넌트와 동일 `I18n` 문구를 사용하는 것을 확인했다.
- 2026-07-07: `rg "SodaV2ActionModal|dismissDeleteDialog|confirmDelete|SodaDialog" SodaLive/Sources/V2/CreatorChannel/ReplyDetail/CreatorChannelReplyDetailView.swift`로 상세 삭제 확인 dialog가 `SodaV2ActionModal`을 사용하는 것을 확인했다.
- 2026-07-07: Reviewer gate 지적에 따라 PRD 본문 요구사항/성공 기준/제약 조건에 삭제 확인 모달의 상위 `CreatorChannelView` 표시, `SodaV2ActionModal` 사용, list/detail anchored context popup 공용화, `CheersReportDialogView` 제외 범위를 명시했다.
- 2026-07-07: 사용자 후속 요청에 따라 팬Talk 목록 row anchored context popup 문구를 `수정`/`삭제`에서 `수정하기`/`삭제하기`로 변경했다. 상세 popup 기본 문구는 기존 공용 기본값을 유지하고, 팬Talk row 호출부에서 `I18n.Explorer.editAction`, `I18n.Explorer.deleteAction`을 주입한다.

View File

@@ -35,9 +35,9 @@ Figma 참조:
- 답글이 있으면 Figma처럼 좌측 라인과 답글 카드 영역을 표시한다.
- 다른 유저의 글에는 `신고` 버튼만 표시하고, 기존 `UserProfileView`의 응원글 신고 기능과 동일하게 `CheersReportDialogView``ReportType.CHEERS` 흐름을 사용한다.
- 내가 쓴 글 또는 내 채널의 타인 글에는 우측 액션으로 `ic_new_more` 더보기 버튼을 표시한다.
- 내가 쓴 글의 더보기 메뉴에는 `수정하기`, `삭제하기` 표시한다.
- 내가 쓴 글이 아니지만 내 채널인 경우 더보기 메뉴에는 `삭제하기`만 표시한다.
- `삭제하기` 기존 FanTalk에서 사용하던 삭제 API와 동일하게 `ExplorerRepository.modifyCheers(..., isActive: false)`를 사용한다.
- 내가 쓴 글의 더보기 메뉴에는 공용 `I18n` 문구 기준의 `수정`, `삭제` 액션을 표시한다.
- 내가 쓴 글이 아니지만 내 채널인 경우 더보기 메뉴에는 공용 `I18n` 문구 기준의 `삭제` 액션만 표시한다.
- `삭제` 액션은 기존 FanTalk에서 사용하던 삭제 API와 동일하게 `ExplorerRepository.modifyCheers(..., isActive: false)`를 사용한다.
- `fanTalkCount == 0`이면 Figma empty view(`290:9001`)를 표시한다.
- 내 채널인 경우 우측하단 글쓰기 floating button과 empty view 내부 `응원 남기기` 버튼을 모두 표시하지 않는다.
- 크리에이터 채널 팬Talk 탭의 우측하단 plus button과 empty state `응원 남기기` 버튼에서 팬Talk 글 입력 화면으로 진입한다.
@@ -54,6 +54,7 @@ Figma 참조:
- 신고 API나 신고 dialog를 새로 만들지 않는다.
- 삭제 API를 새로 만들지 않고 기존 FanTalk 삭제 흐름을 재사용한다.
- 기존 구 UI `SodaDialog`를 V2 공용 모달로 대체하는 전역 리팩터링은 하지 않는다.
- 신고 사유 선택 UI인 `CheersReportDialogView`는 기존 신고 플로우 재사용 범위로 유지하고, 이번 V2 popup dialog 전환 대상에서 제외한다.
- Figma localhost asset URL을 앱 코드에 직접 사용하지 않는다.
- `Pods/**`, `generated/**`, `build/**`는 수정하지 않는다.
@@ -133,15 +134,19 @@ data class CreatorChannelFanTalkReplyResponse(
- `isMine || isOwnCreatorChannel`이면 우측에 `ic_new_more` 더보기 버튼을 표시한다.
- `!isMine && !isOwnCreatorChannel`이면 우측에 `신고` 버튼만 표시한다.
- 더보기 버튼을 터치하면 Figma `666:36114` 기준 anchored context popup을 표시한다.
- 내가 쓴 글이면 `수정하기`, `삭제하기`를 표시한다.
- 내가 쓴 글이 아니지만 내 채널이면 `삭제하기` 표시한다.
- `수정하기`를 터치하면 이번에 작성하는 팬Talk 쓰기 페이지를 수정 모드로 연다.
- `삭제하기`는 확인 dialog 후 기존 삭제 API를 호출한다.
- 팬Talk 목록과 답글 상세의 anchored context popup은 동일한 공용 popup 컴포넌트를 사용한다.
- 팬Talk 목록 row의 anchored context popup은 `수정하기`, `삭제하기` 문구를 표시한다.
- 내가 쓴 글이면 `수정하기`, `삭제하기` 액션을 표시한다.
- 내가 쓴 글이 아니지만 내 채널이면 `삭제하기` 액션만 표시한다.
- `수정하기` 액션을 터치하면 이번에 작성하는 팬Talk 쓰기 페이지를 수정 모드로 연다.
- `삭제하기` 액션은 확인 dialog 후 기존 삭제 API를 호출한다.
### 5.6 Report and delete
- 신고 버튼을 터치하면 기존 크리에이터 페이지의 응원글 신고와 동일하게 `CheersReportDialogView`를 표시한다.
- 신고 confirm 시 `ReportRequest(type: .CHEERS, cheersId: fanTalkId, reason: reason)` 흐름을 사용한다.
- 삭제 confirm dialog는 기존 `I18n.MemberChannel.cheersDeleteTitle`, `I18n.Common.confirmDeleteQuestion`, `I18n.Common.delete`, `I18n.Common.cancel`을 재사용한다.
- 삭제 confirm dialog는 `SodaV2ActionModal`을 사용한다.
- 팬Talk 탭 목록의 삭제 confirm dialog는 스크롤되는 탭 내부가 아니라 `CreatorChannelView`의 상위 wrapping `ZStack`에서 표시한다.
- 삭제 API는 기존 FanTalk 삭제 흐름과 동일하게 `ExplorerRepository.modifyCheers(cheersId: fanTalkId, content: nil, isActive: false)`를 호출한다.
- 삭제 성공 후 팬Talk 탭 첫 페이지를 다시 조회한다.
@@ -167,7 +172,7 @@ data class CreatorChannelFanTalkReplyResponse(
### 5.9 FanTalk write/modify entry
- 쓰기 페이지는 크리에이터 채널 팬Talk 탭에서 진입한다.
- 진입 경로는 `fanTalkCount > 0`일 때 표시되는 우측하단 plus button과 `fanTalkCount == 0`일 때 empty state에 표시되는 `응원 남기기` 버튼이다.
- 내가 쓴 글의 더보기 메뉴에서 `수정하기` 터치하면 같은 쓰기 페이지를 수정 모드로 연다.
- 내가 쓴 글의 더보기 메뉴에서 `수정하기` 액션을 터치하면 같은 쓰기 페이지를 수정 모드로 연다.
- 수정 모드로 진입할 때는 수정 대상 `fanTalkId`와 기존 글 content를 반드시 함께 전달한다.
- 내 채널인 경우 기존 규칙대로 plus button과 empty state `응원 남기기` 버튼을 모두 표시하지 않으므로 작성 모드로 진입할 수 없다.
- 쓰기 route는 `AppStep`에 추가하고 `creatorId`, 작성/수정 mode, 수정 대상 `fanTalkId`, 초기 content, `onSuccess`를 전달할 수 있게 한다.
@@ -214,6 +219,9 @@ data class CreatorChannelFanTalkReplyResponse(
- 타인의 글이면서 내 채널이 아니면 `신고` 버튼만 표시되고 신고 confirm 시 기존 응원글 신고 API가 호출된다.
- 내가 쓴 글은 `ic_new_more` 버튼과 `수정하기`, `삭제하기` 메뉴를 표시한다.
- 내가 쓴 글이 아니지만 내 채널이면 `ic_new_more` 버튼과 `삭제하기` 메뉴만 표시한다.
- 팬Talk 목록과 답글 상세의 anchored context popup은 동일한 공용 popup 컴포넌트를 사용한다.
- 삭제 confirm dialog는 `SodaV2ActionModal`로 표시된다.
- 팬Talk 탭 목록의 삭제 confirm dialog는 `CreatorChannelView` 상위 wrapping `ZStack`에서 표시되어 긴 목록 스크롤 위치와 무관하게 화면 기준으로 중앙 표시된다.
- 삭제 confirm 시 기존 FanTalk 삭제 API가 호출되고 성공 후 첫 페이지가 갱신된다.
- `fanTalkCount == 0`이면 Figma `290:9001` empty view가 표시된다.
- 내 채널인 경우 empty view 내부 `응원 남기기` 버튼과 우측하단 글쓰기 floating button이 모두 표시되지 않는다.
@@ -225,7 +233,7 @@ data class CreatorChannelFanTalkReplyResponse(
- 입력 값이 있는 상태에서 취소 버튼을 터치하면 입력 종료 안내 모달이 표시된다.
- 입력 종료 안내 모달의 dimmed를 터치하면 모달만 닫히고 입력 화면과 입력 값은 유지된다.
- 작성 성공 후 팬Talk 탭 첫 페이지가 다시 조회된다.
- 내가 쓴 글의 `수정하기` tap 시 같은 팬Talk 쓰기 페이지가 수정 모드로 열린다.
- 내가 쓴 글의 `수정하기` 액션 tap 시 같은 팬Talk 쓰기 페이지가 수정 모드로 열린다.
- 수정 모드 진입 시 수정 대상 `fanTalkId`와 기존 글 content가 함께 전달된다.
- 수정 모드는 선택한 fanTalk의 기존 content를 입력값으로 표시한다.
- 수정 성공 후 팬Talk 탭 첫 페이지가 다시 조회된다.
@@ -240,6 +248,7 @@ data class CreatorChannelFanTalkReplyResponse(
- 작성 API 재사용을 위해 기존 `ExplorerRepository.writeCheers`를 호출한다.
- 수정 API 재사용을 위해 기존 `ExplorerRepository.modifyCheers`를 호출한다.
- 신고 기능 재사용을 위해 기존 `ReportRepository`, `ReportRequest`, `CheersReportDialogView`를 사용한다.
- `CheersReportDialogView`는 신고 사유 선택 전용 UI이므로 이번 확인형 V2 popup dialog 전환 범위에서 제외한다.
- 신규 문구가 필요하면 `SodaLive/Sources/I18n/I18n.swift`에 ko/en/ja를 추가한다.
- 프로젝트 설정 변경은 신규 Swift 파일 target 등록이 필요한 경우에만 수행한다.
@@ -261,3 +270,5 @@ data class CreatorChannelFanTalkReplyResponse(
- 2026-07-06: `rg -n "no-op|수정 페이지는|수정 mutation|작성용 새 API|재사용 가능 여부|불가능한 것이 확인|미결정 사항|수정하기 tap은 수정 페이지" docs/20260704_크리에이터_채널_팬Talk_탭/prd.md docs/20260704_크리에이터_채널_팬Talk_탭/plan-task.md` 실행 결과 매칭이 없어 이전 충돌 문구가 남지 않았음을 확인했다.
- 2026-07-06: 사용자 확인에 따라 수정 모드 진입 시 수정 대상 `fanTalkId`와 기존 글 content를 반드시 함께 전달하도록 PRD를 보완했다.
- 2026-07-06: `rg '수정 모드.*fanTalkId|fanTalkId.*기존 글 content|fanTalkId.*초기 content|fanTalkId.*initialContent|기존 content.*content 초기값|수정 대상.*fanTalkId.*기존 글 content|fanTalkId.*0보다 커야' docs/20260704_크리에이터_채널_팬Talk_탭/prd.md docs/20260704_크리에이터_채널_팬Talk_탭/plan-task.md`로 수정 모드 route에 `fanTalkId`와 기존 글 content를 함께 전달한다는 조건을 확인했다.
- 2026-07-07: 사용자 후속 요청에 따라 팬Talk row 더보기의 삭제 확인 dialog는 팬Talk 탭 내부가 아니라 `CreatorChannelView` 상위 wrapping `ZStack`에서 표시한다. 삭제 확인 UI는 이번에 추가된 V2 공용 모달 `SodaV2ActionModal`을 사용하며, 팬Talk 리스트와 상세보기의 anchored context popup은 동일한 공용 컴포넌트와 동일한 `I18n` 문구를 사용한다. 신고 사유 선택 UI인 `CheersReportDialogView`는 기존 신고 플로우 재사용 범위로 유지하고 이번 확인형 V2 popup dialog 전환 범위에서 제외한다.