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("해당 선물은 보관기간(입고일 포함 최대 7일) 내에 반송 등 필요한 조치가 완료되지 않을 경우, 사전에 동의한 약관 및 폐기 등의 내용에 따라 폐기될 수 있습니다. 자세한 내용은 고객센터로 문의해 주세요.") .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 ServiceCenterInquiry.openTalk() } 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()) } }