fix(creator): 팬Talk 답글 수정을 확인한다

This commit is contained in:
Yu Sung
2026-07-09 02:54:20 +09:00
parent d96001e213
commit bc9f4ed370
5 changed files with 68 additions and 7 deletions

View File

@@ -3475,6 +3475,18 @@ If you block this user, the following features will be restricted.
static var replyPlaceholder: String {
pick(ko: "답글을 입력하세요", en: "Enter a reply", ja: "返信を入力してください")
}
static var replaceReplyTitle: String {
pick(ko: "답글을 수정할까요?", en: "Replace your reply?", ja: "返信を修正しますか?")
}
static var replaceReplyMessage: String {
pick(ko: "이미 작성한 답글이 있어요. 확인을 누르면 기존 답글이 새 내용으로 수정됩니다.", en: "You already have a reply. If you continue, the existing reply will be updated with the new content.", ja: "すでに返信があります。確認すると既存の返信が新しい内容に修正されます。")
}
static var replaceReplyConfirm: String {
pick(ko: "수정하기", en: "Update", ja: "修正する")
}
}
enum CreatorChannelFanTalk {

View File

@@ -20,7 +20,7 @@ struct CreatorChannelFanTalkListItem: View {
.frame(maxWidth: .infinity, alignment: .leading)
.padding(.leading, 50)
.background(alignment: .topLeading) {
if fanTalk.creatorReplies.isEmpty == false {
if fanTalk.latestCreatorReply != nil {
GeometryReader { proxy in
CreatorChannelFanTalkReplyConnector()
.stroke(Color.gray800, style: StrokeStyle(lineWidth: 2, lineCap: .round, lineJoin: .round))
@@ -29,7 +29,7 @@ struct CreatorChannelFanTalkListItem: View {
}
}
if fanTalk.creatorReplies.isEmpty == false {
if fanTalk.latestCreatorReply != nil {
replies
.padding(.leading, 50)
}
@@ -95,7 +95,7 @@ struct CreatorChannelFanTalkListItem: View {
private var replies: some View {
VStack(alignment: .leading, spacing: SodaSpacing.s8) {
ForEach(fanTalk.creatorReplies) { reply in
if let reply = fanTalk.latestCreatorReply {
replyCard(reply)
}
}

View File

@@ -18,6 +18,21 @@ struct CreatorChannelFanTalkItemResponse: Decodable, Identifiable {
let creatorReplies: [CreatorChannelFanTalkReplyResponse]
var id: Int { fanTalkId }
var latestCreatorReply: CreatorChannelFanTalkReplyResponse? {
creatorReplies.max { lhs, rhs in
switch (DateParser.parse(lhs.createdAtUtc), DateParser.parse(rhs.createdAtUtc)) {
case let (lhsDate?, rhsDate?):
return lhsDate < rhsDate
case (nil, _?):
return true
case (_?, nil):
return false
case (nil, nil):
return lhs.createdAtUtc < rhs.createdAtUtc
}
}
}
}
struct CreatorChannelFanTalkReplyResponse: Decodable, Identifiable {

View File

@@ -60,6 +60,22 @@ struct CreatorChannelReplyDetailView: View {
onDimmedTap: dismissDeleteDialog
)
}
if viewModel.isShowReplaceReplyDialog {
SodaV2ActionModal(
title: I18n.CreatorChannelReplyDetail.replaceReplyTitle,
message: I18n.CreatorChannelReplyDetail.replaceReplyMessage,
button1: SodaV2ActionModalButton(
label: I18n.CreatorChannelReplyDetail.replaceReplyConfirm,
action: viewModel.confirmReplaceReply
),
button2: SodaV2ActionModalButton(
label: I18n.Common.cancel,
action: viewModel.dismissReplaceReplyDialog
),
onDimmedTap: viewModel.dismissReplaceReplyDialog
)
}
}
.navigationBarBackButtonHidden(true)
.onAppear {

View File

@@ -28,6 +28,7 @@ final class CreatorChannelReplyDetailViewModel: ObservableObject {
@Published var editingItem: CreatorChannelReplyDetailDisplayItem?
@Published var deletingItem: CreatorChannelReplyDetailDisplayItem?
@Published var isShowDeleteDialog = false
@Published var isShowReplaceReplyDialog = false
var isSendEnabled: Bool {
replyText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty == false
@@ -53,9 +54,9 @@ final class CreatorChannelReplyDetailViewModel: ObservableObject {
fetchCommunityReplies(reset: true)
case .fanTalk(let creatorId, let parentFanTalk):
parentItem = CreatorChannelReplyDetailDisplayItem(fanTalk: parentFanTalk)
replies = parentFanTalk.creatorReplies.map {
replies = parentFanTalk.latestCreatorReply.map {
CreatorChannelReplyDetailDisplayItem(fanTalkReply: $0, creatorId: creatorId)
}
}.map { [$0] } ?? []
}
}
@@ -118,11 +119,23 @@ final class CreatorChannelReplyDetailViewModel: ObservableObject {
if let editingItem {
modify(item: editingItem)
} else if existingFanTalkCreatorReply != nil {
isShowReplaceReplyDialog = true
} else {
createReply()
}
}
func dismissReplaceReplyDialog() {
isShowReplaceReplyDialog = false
}
func confirmReplaceReply() {
guard let existingFanTalkCreatorReply, isLoading == false else { return }
isShowReplaceReplyDialog = false
modify(item: existingFanTalkCreatorReply)
}
func confirmDelete() {
guard let deletingItem, isLoading == false else { return }
isShowDeleteDialog = false
@@ -328,9 +341,9 @@ final class CreatorChannelReplyDetailViewModel: ObservableObject {
if let data = decoded.data, decoded.success {
if let fanTalk = data.fanTalks.first(where: { $0.fanTalkId == parentFanTalk.fanTalkId }) {
self.isLoading = false
self.replies = fanTalk.creatorReplies.map {
self.replies = fanTalk.latestCreatorReply.map {
CreatorChannelReplyDetailDisplayItem(fanTalkReply: $0, creatorId: creatorId)
}
}.map { [$0] } ?? []
} else if data.hasNext {
self.fetchFanTalkReplies(page: page + 1)
} else {
@@ -435,6 +448,11 @@ final class CreatorChannelReplyDetailViewModel: ObservableObject {
return false
}
private var existingFanTalkCreatorReply: CreatorChannelReplyDetailDisplayItem? {
guard case .fanTalk = context else { return nil }
return replies.first { $0.isCreatorReply }
}
private func communityRepliesPublisher(page: Int) -> AnyPublisher<Response, MoyaError> {
switch context {
case .community(_, _, let parentComment):