feat(gift): 선물 표시 정책을 추가한다
This commit is contained in:
@@ -0,0 +1,105 @@
|
|||||||
|
import Foundation
|
||||||
|
|
||||||
|
enum GiftDirection: String, Decodable {
|
||||||
|
case sent = "SENT"
|
||||||
|
case received = "RECEIVED"
|
||||||
|
}
|
||||||
|
|
||||||
|
enum GiftStatus: String, Decodable, CaseIterable {
|
||||||
|
case received = "RECEIVED"
|
||||||
|
case trackingRegistered = "TRACKING_REGISTERED"
|
||||||
|
case arrivedAtMailbox = "ARRIVED_AT_MAILBOX"
|
||||||
|
case inspectionCompleted = "INSPECTION_COMPLETED"
|
||||||
|
case delivered = "DELIVERED"
|
||||||
|
case undeliverable = "UNDELIVERABLE"
|
||||||
|
case canceled = "CANCELED"
|
||||||
|
}
|
||||||
|
|
||||||
|
enum GiftProgressStep: String, CaseIterable {
|
||||||
|
case received = "RECEIVED"
|
||||||
|
case trackingRegistered = "TRACKING_REGISTERED"
|
||||||
|
case arrivedAtMailbox = "ARRIVED_AT_MAILBOX"
|
||||||
|
case inspectionCompleted = "INSPECTION_COMPLETED"
|
||||||
|
case delivered = "DELIVERED"
|
||||||
|
|
||||||
|
var title: String {
|
||||||
|
switch self {
|
||||||
|
case .received:
|
||||||
|
return "신청 접수"
|
||||||
|
case .trackingRegistered:
|
||||||
|
return "발송 확인"
|
||||||
|
case .arrivedAtMailbox:
|
||||||
|
return "사서함 도착"
|
||||||
|
case .inspectionCompleted:
|
||||||
|
return "검수 완료"
|
||||||
|
case .delivered:
|
||||||
|
return "전달 완료"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum GiftSize: String, Decodable {
|
||||||
|
case small = "SMALL"
|
||||||
|
case medium = "MEDIUM"
|
||||||
|
case large = "LARGE"
|
||||||
|
}
|
||||||
|
|
||||||
|
struct GiftListStatusDisplayModel {
|
||||||
|
let title: String
|
||||||
|
let subtitle: String?
|
||||||
|
}
|
||||||
|
|
||||||
|
struct GiftListCardDisplayModel {
|
||||||
|
let applicationNo: String
|
||||||
|
let direction: GiftDirection
|
||||||
|
let status: GiftStatus
|
||||||
|
let counterpartNickname: String
|
||||||
|
let counterpartProfileImageUrl: String?
|
||||||
|
let categoryName: String
|
||||||
|
let sizeName: String
|
||||||
|
let createdDateText: String?
|
||||||
|
let statusDisplay: GiftListStatusDisplayModel
|
||||||
|
}
|
||||||
|
|
||||||
|
struct GiftProgressDisplayModel {
|
||||||
|
let step: GiftProgressStep
|
||||||
|
let occurredDateText: String?
|
||||||
|
}
|
||||||
|
|
||||||
|
struct GiftAddressDisplayModel {
|
||||||
|
let name: String
|
||||||
|
let phoneNumber: String
|
||||||
|
let address: String
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SentGiftDetailDisplayModel {
|
||||||
|
let status: GiftStatus
|
||||||
|
let statusName: String
|
||||||
|
let undeliverableReason: String?
|
||||||
|
let recipientCreatorNickname: String?
|
||||||
|
let sizeName: String
|
||||||
|
let categoryName: String
|
||||||
|
let applicationNo: String
|
||||||
|
let paidCan: Int?
|
||||||
|
let tracking: String?
|
||||||
|
let shippingRequestedDateText: String?
|
||||||
|
let applicationDateText: String?
|
||||||
|
let canceledDateText: String?
|
||||||
|
let senderInfo: GiftAddressDisplayModel?
|
||||||
|
let mailbox: GiftAddressDisplayModel?
|
||||||
|
let trackingRequired: Bool
|
||||||
|
let progress: [GiftProgressDisplayModel]
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ReceivedGiftDetailDisplayModel {
|
||||||
|
let status: GiftStatus
|
||||||
|
let statusName: String
|
||||||
|
let undeliverableReason: String?
|
||||||
|
let senderNickname: String?
|
||||||
|
let sizeName: String
|
||||||
|
let categoryName: String
|
||||||
|
let shippingRequestedDateText: String?
|
||||||
|
let recipientAddressRequired: Bool
|
||||||
|
let recipientAddress: GiftAddressDisplayModel?
|
||||||
|
let progress: [GiftProgressDisplayModel]
|
||||||
|
}
|
||||||
@@ -0,0 +1,164 @@
|
|||||||
|
import Foundation
|
||||||
|
|
||||||
|
enum GiftDateFormatter {
|
||||||
|
static func yyyyMMdd(fromUTC text: String?) -> String? {
|
||||||
|
format(text, format: "yyyy.MM.dd")
|
||||||
|
}
|
||||||
|
|
||||||
|
static func mmDD(fromUTC text: String?) -> String? {
|
||||||
|
format(text, format: "MM.dd")
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func format(_ text: String?, format: String) -> String? {
|
||||||
|
guard let text, let date = DateParser.parse(text) else { return nil }
|
||||||
|
|
||||||
|
let formatter = DateFormatter()
|
||||||
|
formatter.locale = Locale(identifier: "en_US_POSIX")
|
||||||
|
formatter.timeZone = .autoupdatingCurrent
|
||||||
|
formatter.dateFormat = format
|
||||||
|
return formatter.string(from: date)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum GiftDisplayPolicy {
|
||||||
|
static func listCard(from item: GiftListItemResponse) -> GiftListCardDisplayModel? {
|
||||||
|
guard let direction = GiftDirection(rawValue: item.direction),
|
||||||
|
let status = GiftStatus(rawValue: item.status) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return GiftListCardDisplayModel(
|
||||||
|
applicationNo: item.applicationNo,
|
||||||
|
direction: direction,
|
||||||
|
status: status,
|
||||||
|
counterpartNickname: item.counterpartNickname,
|
||||||
|
counterpartProfileImageUrl: item.counterpartProfileImageUrl,
|
||||||
|
categoryName: item.categoryName,
|
||||||
|
sizeName: item.sizeName,
|
||||||
|
createdDateText: GiftDateFormatter.yyyyMMdd(fromUTC: item.createdAt),
|
||||||
|
statusDisplay: listStatus(direction: direction, status: status, statusName: item.statusName)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
static func sentDetail(from detail: GiftDetailResponse) -> SentGiftDetailDisplayModel? {
|
||||||
|
guard let status = status(from: detail, expectedDirection: .sent) else { return nil }
|
||||||
|
|
||||||
|
return SentGiftDetailDisplayModel(
|
||||||
|
status: status,
|
||||||
|
statusName: detail.statusName,
|
||||||
|
undeliverableReason: detail.delivery.undeliverableReason,
|
||||||
|
recipientCreatorNickname: detail.giftInfo.recipientCreatorNickname,
|
||||||
|
sizeName: detail.giftInfo.sizeName,
|
||||||
|
categoryName: detail.giftInfo.categoryName,
|
||||||
|
applicationNo: detail.applicationNo,
|
||||||
|
paidCan: detail.giftInfo.paidCan,
|
||||||
|
tracking: detail.giftInfo.tracking,
|
||||||
|
shippingRequestedDateText: GiftDateFormatter.yyyyMMdd(fromUTC: detail.giftInfo.shippingRequestedAt),
|
||||||
|
applicationDateText: GiftDateFormatter.yyyyMMdd(
|
||||||
|
fromUTC: detail.statusTimeline.first { $0.status == GiftStatus.received.rawValue }?.occurredAt
|
||||||
|
),
|
||||||
|
canceledDateText: GiftDateFormatter.yyyyMMdd(fromUTC: detail.delivery.canceledAt),
|
||||||
|
senderInfo: detail.senderInfo.map(GiftAddressDisplayModel.init),
|
||||||
|
mailbox: detail.mailbox.map(GiftAddressDisplayModel.init),
|
||||||
|
trackingRequired: detail.trackingRequired,
|
||||||
|
progress: progress(from: detail.statusTimeline)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
static func receivedDetail(from detail: GiftDetailResponse) -> ReceivedGiftDetailDisplayModel? {
|
||||||
|
guard let status = status(from: detail, expectedDirection: .received) else { return nil }
|
||||||
|
|
||||||
|
return ReceivedGiftDetailDisplayModel(
|
||||||
|
status: status,
|
||||||
|
statusName: detail.statusName,
|
||||||
|
undeliverableReason: detail.delivery.undeliverableReason,
|
||||||
|
senderNickname: detail.giftInfo.senderNickname,
|
||||||
|
sizeName: detail.giftInfo.sizeName,
|
||||||
|
categoryName: detail.giftInfo.categoryName,
|
||||||
|
shippingRequestedDateText: GiftDateFormatter.yyyyMMdd(fromUTC: detail.giftInfo.shippingRequestedAt),
|
||||||
|
recipientAddressRequired: status == .undeliverable ? false : detail.recipientAddressRequired,
|
||||||
|
recipientAddress: status == .undeliverable ? nil : detail.recipientAddress.map(GiftAddressDisplayModel.init),
|
||||||
|
progress: progress(from: detail.statusTimeline)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
static func sizeDescription(for sizeCode: String) -> String? {
|
||||||
|
guard let size = GiftSize(rawValue: sizeCode) else { return nil }
|
||||||
|
|
||||||
|
switch size {
|
||||||
|
case .small:
|
||||||
|
return "세 변의 합 100cm 이하 · 5kg 이하"
|
||||||
|
case .medium:
|
||||||
|
return "세 변의 합 120cm 이하 · 15kg 이하"
|
||||||
|
case .large:
|
||||||
|
return "세 변의 합 160cm 이하 · 20kg 이하"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func listStatus(
|
||||||
|
direction: GiftDirection,
|
||||||
|
status: GiftStatus,
|
||||||
|
statusName: String
|
||||||
|
) -> GiftListStatusDisplayModel {
|
||||||
|
switch (direction, status) {
|
||||||
|
case (.sent, .received):
|
||||||
|
return GiftListStatusDisplayModel(title: "운송장 등록 필요", subtitle: nil)
|
||||||
|
case (.sent, .trackingRegistered):
|
||||||
|
return GiftListStatusDisplayModel(title: "발송 확인", subtitle: nil)
|
||||||
|
case (.sent, .arrivedAtMailbox):
|
||||||
|
return GiftListStatusDisplayModel(title: "사서함 도착", subtitle: nil)
|
||||||
|
case (.sent, .inspectionCompleted):
|
||||||
|
return GiftListStatusDisplayModel(title: "선물 검수 완료", subtitle: nil)
|
||||||
|
case (.sent, .delivered):
|
||||||
|
return GiftListStatusDisplayModel(title: "전달 완료", subtitle: nil)
|
||||||
|
case (.sent, .undeliverable):
|
||||||
|
return GiftListStatusDisplayModel(title: "전달 불가", subtitle: nil)
|
||||||
|
case (.sent, .canceled):
|
||||||
|
return GiftListStatusDisplayModel(title: "신청 취소", subtitle: nil)
|
||||||
|
case (.received, .trackingRegistered):
|
||||||
|
return GiftListStatusDisplayModel(title: "배송지 입력 필요", subtitle: "전달 예정")
|
||||||
|
case (.received, .arrivedAtMailbox):
|
||||||
|
return GiftListStatusDisplayModel(title: "선물 검수", subtitle: "선물 확인 중")
|
||||||
|
case (.received, .inspectionCompleted):
|
||||||
|
return GiftListStatusDisplayModel(title: "선물 검수 완료", subtitle: "배송 중")
|
||||||
|
case (.received, .delivered):
|
||||||
|
return GiftListStatusDisplayModel(title: "전달 완료", subtitle: nil)
|
||||||
|
case (.received, .undeliverable):
|
||||||
|
return GiftListStatusDisplayModel(title: "전달 불가", subtitle: nil)
|
||||||
|
default:
|
||||||
|
return GiftListStatusDisplayModel(title: statusName, subtitle: nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func status(
|
||||||
|
from detail: GiftDetailResponse,
|
||||||
|
expectedDirection: GiftDirection
|
||||||
|
) -> GiftStatus? {
|
||||||
|
guard GiftDirection(rawValue: detail.direction) == expectedDirection else { return nil }
|
||||||
|
return GiftStatus(rawValue: detail.status)
|
||||||
|
}
|
||||||
|
|
||||||
|
private static func progress(from timeline: [GiftStatusTimelineResponse]) -> [GiftProgressDisplayModel] {
|
||||||
|
GiftProgressStep.allCases.map { step in
|
||||||
|
let occurredAt = timeline.first { $0.status == step.rawValue }?.occurredAt
|
||||||
|
return GiftProgressDisplayModel(
|
||||||
|
step: step,
|
||||||
|
occurredDateText: GiftDateFormatter.mmDD(fromUTC: occurredAt)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension GiftAddressDisplayModel {
|
||||||
|
init(_ senderInfo: GiftSenderInfoResponse) {
|
||||||
|
self.init(name: senderInfo.name, phoneNumber: senderInfo.phoneNumber, address: senderInfo.address)
|
||||||
|
}
|
||||||
|
|
||||||
|
init(_ recipientAddress: GiftRecipientAddressResponse) {
|
||||||
|
self.init(name: recipientAddress.name, phoneNumber: recipientAddress.phoneNumber, address: recipientAddress.address)
|
||||||
|
}
|
||||||
|
|
||||||
|
init(_ mailbox: GiftMailboxResponse) {
|
||||||
|
self.init(name: mailbox.name, phoneNumber: mailbox.phoneNumber, address: mailbox.address)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user