fix(creator): 팬Talk 답글 수정을 확인한다
This commit is contained in:
@@ -3475,6 +3475,18 @@ If you block this user, the following features will be restricted.
|
|||||||
static var replyPlaceholder: String {
|
static var replyPlaceholder: String {
|
||||||
pick(ko: "답글을 입력하세요", en: "Enter a reply", ja: "返信を入力してください")
|
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 {
|
enum CreatorChannelFanTalk {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ struct CreatorChannelFanTalkListItem: View {
|
|||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
.padding(.leading, 50)
|
.padding(.leading, 50)
|
||||||
.background(alignment: .topLeading) {
|
.background(alignment: .topLeading) {
|
||||||
if fanTalk.creatorReplies.isEmpty == false {
|
if fanTalk.latestCreatorReply != nil {
|
||||||
GeometryReader { proxy in
|
GeometryReader { proxy in
|
||||||
CreatorChannelFanTalkReplyConnector()
|
CreatorChannelFanTalkReplyConnector()
|
||||||
.stroke(Color.gray800, style: StrokeStyle(lineWidth: 2, lineCap: .round, lineJoin: .round))
|
.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
|
replies
|
||||||
.padding(.leading, 50)
|
.padding(.leading, 50)
|
||||||
}
|
}
|
||||||
@@ -95,7 +95,7 @@ struct CreatorChannelFanTalkListItem: View {
|
|||||||
|
|
||||||
private var replies: some View {
|
private var replies: some View {
|
||||||
VStack(alignment: .leading, spacing: SodaSpacing.s8) {
|
VStack(alignment: .leading, spacing: SodaSpacing.s8) {
|
||||||
ForEach(fanTalk.creatorReplies) { reply in
|
if let reply = fanTalk.latestCreatorReply {
|
||||||
replyCard(reply)
|
replyCard(reply)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,21 @@ struct CreatorChannelFanTalkItemResponse: Decodable, Identifiable {
|
|||||||
let creatorReplies: [CreatorChannelFanTalkReplyResponse]
|
let creatorReplies: [CreatorChannelFanTalkReplyResponse]
|
||||||
|
|
||||||
var id: Int { fanTalkId }
|
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 {
|
struct CreatorChannelFanTalkReplyResponse: Decodable, Identifiable {
|
||||||
|
|||||||
@@ -60,6 +60,22 @@ struct CreatorChannelReplyDetailView: View {
|
|||||||
onDimmedTap: dismissDeleteDialog
|
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)
|
.navigationBarBackButtonHidden(true)
|
||||||
.onAppear {
|
.onAppear {
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ final class CreatorChannelReplyDetailViewModel: ObservableObject {
|
|||||||
@Published var editingItem: CreatorChannelReplyDetailDisplayItem?
|
@Published var editingItem: CreatorChannelReplyDetailDisplayItem?
|
||||||
@Published var deletingItem: CreatorChannelReplyDetailDisplayItem?
|
@Published var deletingItem: CreatorChannelReplyDetailDisplayItem?
|
||||||
@Published var isShowDeleteDialog = false
|
@Published var isShowDeleteDialog = false
|
||||||
|
@Published var isShowReplaceReplyDialog = false
|
||||||
|
|
||||||
var isSendEnabled: Bool {
|
var isSendEnabled: Bool {
|
||||||
replyText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty == false
|
replyText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty == false
|
||||||
@@ -53,9 +54,9 @@ final class CreatorChannelReplyDetailViewModel: ObservableObject {
|
|||||||
fetchCommunityReplies(reset: true)
|
fetchCommunityReplies(reset: true)
|
||||||
case .fanTalk(let creatorId, let parentFanTalk):
|
case .fanTalk(let creatorId, let parentFanTalk):
|
||||||
parentItem = CreatorChannelReplyDetailDisplayItem(fanTalk: parentFanTalk)
|
parentItem = CreatorChannelReplyDetailDisplayItem(fanTalk: parentFanTalk)
|
||||||
replies = parentFanTalk.creatorReplies.map {
|
replies = parentFanTalk.latestCreatorReply.map {
|
||||||
CreatorChannelReplyDetailDisplayItem(fanTalkReply: $0, creatorId: creatorId)
|
CreatorChannelReplyDetailDisplayItem(fanTalkReply: $0, creatorId: creatorId)
|
||||||
}
|
}.map { [$0] } ?? []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,11 +119,23 @@ final class CreatorChannelReplyDetailViewModel: ObservableObject {
|
|||||||
|
|
||||||
if let editingItem {
|
if let editingItem {
|
||||||
modify(item: editingItem)
|
modify(item: editingItem)
|
||||||
|
} else if existingFanTalkCreatorReply != nil {
|
||||||
|
isShowReplaceReplyDialog = true
|
||||||
} else {
|
} else {
|
||||||
createReply()
|
createReply()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func dismissReplaceReplyDialog() {
|
||||||
|
isShowReplaceReplyDialog = false
|
||||||
|
}
|
||||||
|
|
||||||
|
func confirmReplaceReply() {
|
||||||
|
guard let existingFanTalkCreatorReply, isLoading == false else { return }
|
||||||
|
isShowReplaceReplyDialog = false
|
||||||
|
modify(item: existingFanTalkCreatorReply)
|
||||||
|
}
|
||||||
|
|
||||||
func confirmDelete() {
|
func confirmDelete() {
|
||||||
guard let deletingItem, isLoading == false else { return }
|
guard let deletingItem, isLoading == false else { return }
|
||||||
isShowDeleteDialog = false
|
isShowDeleteDialog = false
|
||||||
@@ -328,9 +341,9 @@ final class CreatorChannelReplyDetailViewModel: ObservableObject {
|
|||||||
if let data = decoded.data, decoded.success {
|
if let data = decoded.data, decoded.success {
|
||||||
if let fanTalk = data.fanTalks.first(where: { $0.fanTalkId == parentFanTalk.fanTalkId }) {
|
if let fanTalk = data.fanTalks.first(where: { $0.fanTalkId == parentFanTalk.fanTalkId }) {
|
||||||
self.isLoading = false
|
self.isLoading = false
|
||||||
self.replies = fanTalk.creatorReplies.map {
|
self.replies = fanTalk.latestCreatorReply.map {
|
||||||
CreatorChannelReplyDetailDisplayItem(fanTalkReply: $0, creatorId: creatorId)
|
CreatorChannelReplyDetailDisplayItem(fanTalkReply: $0, creatorId: creatorId)
|
||||||
}
|
}.map { [$0] } ?? []
|
||||||
} else if data.hasNext {
|
} else if data.hasNext {
|
||||||
self.fetchFanTalkReplies(page: page + 1)
|
self.fetchFanTalkReplies(page: page + 1)
|
||||||
} else {
|
} else {
|
||||||
@@ -435,6 +448,11 @@ final class CreatorChannelReplyDetailViewModel: ObservableObject {
|
|||||||
return false
|
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> {
|
private func communityRepliesPublisher(page: Int) -> AnyPublisher<Response, MoyaError> {
|
||||||
switch context {
|
switch context {
|
||||||
case .community(_, _, let parentComment):
|
case .community(_, _, let parentComment):
|
||||||
|
|||||||
Reference in New Issue
Block a user