feat(gift): 선물 상세 액션을 추가한다

This commit is contained in:
Yu Sung
2026-10-08 12:32:58 +09:00
parent 83b90b2fdb
commit d73a69297b
2 changed files with 175 additions and 0 deletions
@@ -0,0 +1,91 @@
import SwiftUI
struct GiftCancelCompleteView: View {
let model: SentGiftDetailDisplayModel
@State private var isNavigating = false
var body: some View {
VStack(alignment: .leading, spacing: SodaSpacing.s32) {
VStack(alignment: .leading, spacing: SodaSpacing.s14) {
Text("취소 완료")
.appFont(.caption2)
.foregroundColor(.white)
.padding(.horizontal, SodaSpacing.s8)
.padding(.vertical, SodaSpacing.s4)
.background(Color.gray700)
.clipShape(RoundedRectangle(cornerRadius: SodaRadius.r4))
Text("선물 신청이 취소되었어요")
.appFont(.heading2)
.foregroundColor(.white)
.accessibilityAddTraits(.isHeader)
Text(completionMessage)
.appFont(.body6)
.foregroundColor(.gray300)
}
.fixedSize(horizontal: false, vertical: true)
.frame(maxWidth: .infinity, alignment: .leading)
VStack(spacing: SodaSpacing.s12) {
GiftInfoSectionView(title: "취소 상세") {
if let creatorNickname {
GiftInfoRow(title: "크리에이터", value: creatorNickname)
}
GiftInfoRow(title: "선물 사이즈", value: model.sizeName)
GiftInfoRow(title: "카테고리", value: model.categoryName)
GiftInfoRow(title: "신청번호", value: model.applicationNo)
if let applicationDate = model.applicationDateText {
GiftInfoRow(title: "신청일", value: applicationDate)
}
if let canceledDate = model.canceledDateText {
GiftInfoRow(title: "취소일", value: canceledDate)
}
if let paidCan = model.paidCan {
GiftInfoRow(title: "환불 캔", value: String(paidCan))
}
}
inquiryButton
}
}
.frame(maxWidth: .infinity, alignment: .leading)
.onAppear {
isNavigating = false
}
}
private var inquiryButton: some View {
Button {
guard !isNavigating else { return }
isNavigating = true
AppState.shared.setAppStep(step: GiftConstants.inquiryStep)
} label: {
Text("문의하기")
.appFont(.body2)
.foregroundColor(isNavigating ? .gray500 : .white)
.multilineTextAlignment(.center)
.fixedSize(horizontal: false, vertical: true)
.padding(.horizontal, SodaSpacing.s16)
.padding(.vertical, SodaSpacing.s12)
.frame(maxWidth: .infinity, minHeight: SodaSpacing.s48)
.overlay(Capsule().strokeBorder(Color.gray800))
.contentShape(Capsule())
}
.buttonStyle(.plain)
.disabled(isNavigating)
}
private var creatorNickname: String? {
guard let nickname = model.recipientCreatorNickname?.trimmingCharacters(in: .whitespacesAndNewlines),
!nickname.isEmpty else { return nil }
return nickname
}
private var completionMessage: String {
let recipient = creatorNickname.map { "\($0)에게 보내는 " } ?? ""
let applicationNo = model.applicationNo.trimmingCharacters(in: .whitespacesAndNewlines)
let application = applicationNo.isEmpty ? "" : "(\(applicationNo))"
return "\(recipient)선물 신청\(application)이 취소되었습니다. 취소한 신청은 되돌릴 수 없으며, 다시 보내려면 새로 신청해 주세요."
}
}
@@ -0,0 +1,84 @@
import SwiftUI
struct GiftDetailActionBar: View {
let model: SentGiftDetailDisplayModel
var onCancel: (() -> Void)? = nil
let onPolicy: () -> Void
@State private var isNavigating = false
var body: some View {
if model.trackingRequired || model.status == .received || model.status == .undeliverable {
VStack(spacing: SodaSpacing.s8) {
if model.trackingRequired {
Button {
guard !isNavigating else { return }
isNavigating = true
AppState.shared.setAppStep(step: .giftTrackingRegistration(applicationNo: model.applicationNo))
} label: {
SelectedButtonView(
title: "운송장 작성하기",
isActive: !isNavigating,
isSelected: false,
bgDefaultColor: .button,
textDefaultColor: .white
)
.multilineTextAlignment(.center)
.fixedSize(horizontal: false, vertical: true)
.frame(minHeight: SodaSpacing.s48)
.contentShape(Rectangle())
}
.disabled(isNavigating)
}
if model.status == .received {
Button {
onCancel?()
} label: {
secondaryLabel("신청 취소", isEnabled: onCancel != nil)
}
.disabled(onCancel == nil)
.accessibilityHint(onCancel == nil ? "현재 신청 취소를 이용할 수 없습니다." : "")
}
if model.status == .undeliverable {
Button {
guard !isNavigating else { return }
isNavigating = true
AppState.shared.setAppStep(step: GiftConstants.inquiryStep)
} label: {
secondaryLabel("문의하기", isEnabled: !isNavigating)
}
.disabled(isNavigating)
Button {
onPolicy()
} label: {
secondaryLabel("선물 정책 확인")
}
}
}
.buttonStyle(.plain)
.padding(.horizontal, SodaSpacing.s14)
.padding(.vertical, SodaSpacing.s12)
.frame(maxWidth: .infinity)
.background(Color.black)
.onAppear {
isNavigating = false
}
}
}
private func secondaryLabel(_ title: String, isEnabled: Bool = true) -> some View {
Text(title)
.appFont(.body2)
.foregroundColor(isEnabled ? .white : .gray500)
.multilineTextAlignment(.center)
.fixedSize(horizontal: false, vertical: true)
.padding(.horizontal, SodaSpacing.s16)
.padding(.vertical, SodaSpacing.s12)
.frame(maxWidth: .infinity, minHeight: SodaSpacing.s48)
.background(Color.gray900)
.clipShape(RoundedRectangle(cornerRadius: SodaRadius.r8))
.contentShape(Rectangle())
}
}