diff --git a/SodaLive/Sources/V2/Gift/Detail/Components/ReceivedGiftDetailContentView.swift b/SodaLive/Sources/V2/Gift/Detail/Components/ReceivedGiftDetailContentView.swift new file mode 100644 index 00000000..295aa3b4 --- /dev/null +++ b/SodaLive/Sources/V2/Gift/Detail/Components/ReceivedGiftDetailContentView.swift @@ -0,0 +1,157 @@ +import SwiftUI + +struct ReceivedGiftDetailContentView: View { + let model: ReceivedGiftDetailDisplayModel + + var body: some View { + VStack(alignment: .leading, spacing: SodaSpacing.s32) { + hero + + if model.status == .undeliverable { + undeliverableReason + } else { + if model.status != .canceled { + GiftProgressView(progress: model.progress) + } + giftInfo + recipientAddress + } + } + .frame(maxWidth: .infinity, alignment: .leading) + } + + private var hero: some View { + VStack(alignment: .leading, spacing: SodaSpacing.s14) { + if let statusLabel { + Text(statusLabel) + .appFont(.caption2) + .foregroundColor(model.status == .undeliverable ? .red400 : .soda400) + .padding(.horizontal, SodaSpacing.s8) + .padding(.vertical, SodaSpacing.s4) + .background(Color.gray900) + .clipShape(RoundedRectangle(cornerRadius: SodaRadius.r4)) + } + + Text(heroTitle) + .appFont(.heading1) + .foregroundColor(.white) + .accessibilityAddTraits(.isHeader) + + if model.status == .undeliverable { + Text("보내주신 선물은 소다라이브 선물 정책에 따라 크리에이터에게 전달할 수 없는 품목으로 확인되었습니다.") + .appFont(.body6) + .foregroundColor(.gray500) + } + } + .fixedSize(horizontal: false, vertical: true) + .frame(maxWidth: .infinity, alignment: .leading) + } + + private var statusLabel: String? { + switch model.status { + case .trackingRegistered: return "배송지 입력 완료" + case .delivered: return "전달 완료" + case .undeliverable: return "전달 불가" + case .received, .arrivedAtMailbox, .inspectionCompleted, .canceled: return nil + } + } + + private var heroTitle: String { + switch model.status { + case .trackingRegistered: return "배송지 입력이 완료되었어요" + case .delivered: return "선물을 전달받았어요" + case .undeliverable: return "전달할 수 없는 품목입니다" + case .received, .arrivedAtMailbox, .inspectionCompleted, .canceled: return model.statusName + } + } + + private var giftInfo: some View { + GiftInfoSectionView(title: "선물 정보") { + if let nickname = model.senderNickname { + GiftInfoRow(title: "보낸 사람", value: nickname) + } + GiftInfoRow(title: "선물 사이즈", value: model.sizeName) + GiftInfoRow(title: "카테고리", value: model.categoryName) + } + } + + @ViewBuilder + private var recipientAddress: some View { + if let address = model.recipientAddress { + GiftInfoSectionView(title: "받는 주소") { + GiftInfoRow(title: "이름", value: address.name) + GiftInfoRow(title: "휴대폰 번호", value: address.phoneNumber) + GiftInfoRow(title: "주소", value: address.address) + } + } + } + + private var undeliverableReason: some View { + GiftInfoSectionView(title: "사유") { + if let reason = model.undeliverableReason?.trimmingCharacters(in: .whitespacesAndNewlines), + !reason.isEmpty { + Text(reason) + .appFont(.body6) + .foregroundColor(.white) + .fixedSize(horizontal: false, vertical: true) + .frame(maxWidth: .infinity, alignment: .leading) + + Divider() + .overlay(Color.gray800) + .accessibilityHidden(true) + } + + Text("해당 선물은 정책에 따라 폐기되며 반송되지 않습니다.") + .appFont(.body6) + .foregroundColor(.red400) + .fixedSize(horizontal: false, vertical: true) + .frame(maxWidth: .infinity, alignment: .leading) + } + } +} + +struct ReceivedGiftDetailActionBar: View { + let onPolicy: () -> Void + @State private var isNavigating = false + + var body: some View { + VStack(spacing: SodaSpacing.s8) { + 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()) + } +}