import SwiftUI struct CreatorChannelDonationCard: View { let donation: CreatorChannelDonationResponse var body: some View { VStack(alignment: .leading, spacing: SodaSpacing.s14) { header Text(donation.messageText) .appFont(size: 16, weight: .regular) .foregroundColor(.white) .lineLimit(2) .truncationMode(.tail) .frame(maxWidth: .infinity, alignment: .leading) .padding(.horizontal, SodaSpacing.s14) } .padding(.bottom, SodaSpacing.s14) .frame(maxWidth: .infinity, alignment: .leading) .background(Color.gray900) .clipShape(RoundedRectangle(cornerRadius: SodaSpacing.s14, style: .continuous)) } private var header: some View { HStack(alignment: .center, spacing: SodaSpacing.s8) { DownsampledKFImage( url: URL(string: donation.profileImageUrl), size: CGSize(width: 42, height: 42) ) .background(Color.white.opacity(0.6)) .clipShape(Circle()) VStack(alignment: .leading, spacing: 2) { Text(donation.nickname) .appFont(size: 14, weight: .medium) .foregroundColor(donation.nicknameColor) .lineLimit(1) .truncationMode(.tail) Text(donation.relativeTimeText()) .appFont(size: 14, weight: .regular) .foregroundColor(donation.relativeTimeColor) .lineLimit(1) } .frame(maxWidth: .infinity, alignment: .leading) canBadge } .padding(SodaSpacing.s14) .background(donation.tierColor) } private var canBadge: some View { HStack(spacing: 2) { Image("ic_bar_cash") .resizable() .scaledToFit() .frame(width: 18, height: 18) Text("\(donation.can)캔") .appFont(size: 14, weight: .regular) .foregroundColor(.white) .lineLimit(1) } .padding(.horizontal, SodaSpacing.s6) .padding(.vertical, SodaSpacing.s4) .background(Color.gray900) .clipShape(Capsule()) } } extension CreatorChannelDonationResponse { var messageText: String { let trimmedMessage = message.trimmingCharacters(in: .whitespacesAndNewlines) return trimmedMessage.isEmpty ? "\(can)캔을 후원하였습니다" : trimmedMessage } func relativeTimeText(now: Date = Date()) -> String { DateParser.relativeTimeText(fromUTC: createdAtUtc, fallback: createdAtUtc, now: now) } var tierColor: Color { switch can { case 1...50: return Color(hex: "E2E2E2") case 51...100: return Color(hex: "73EE01") case 101...500: return Color(hex: "00EAFF") default: return Color(hex: "FF4C3C") } } var nicknameColor: Color { can >= 501 ? .white : .black } var relativeTimeColor: Color { can >= 501 ? Color.gray100 : Color.gray700 } } struct CreatorChannelDonationCard_Previews: PreviewProvider { static var previews: some View { CreatorChannelDonationCard( donation: CreatorChannelDonationResponse( nickname: "팬 이름 501", profileImageUrl: "https://picsum.photos/120/120?4", can: 501, message: "501캔 이상 후원 컬러를 확인하는 Preview 샘플입니다.", createdAtUtc: "2026-07-03T03:41:00Z" ) ) .padding(SodaSpacing.s14) .background(Color.black) .previewLayout(.sizeThatFits) } }