import SwiftUI struct MainHomeFollowingChatSection: View { let recentChats: [ChatRoomListItemResponse] let onTapTitle: () -> Void let onTapChatRoom: (Int, String) -> Void init( recentChats: [ChatRoomListItemResponse], onTapTitle: @escaping () -> Void = {}, onTapChatRoom: @escaping (Int, String) -> Void = { _, _ in } ) { self.recentChats = recentChats self.onTapTitle = onTapTitle self.onTapChatRoom = onTapChatRoom } var body: some View { if !recentChats.isEmpty { VStack(alignment: .leading, spacing: SodaSpacing.s14) { SectionTitle(title: I18n.HomeFollowing.recentChatTitle, action: onTapTitle) ScrollView(.horizontal, showsIndicators: false) { LazyHStack(alignment: .top, spacing: SodaSpacing.s8) { ForEach(recentChats) { chat in MainHomeFollowingChatItemView(chat: chat) { onTapChatRoom(chat.roomId, chat.chatType) } } } .padding(.leading, SodaSpacing.s14) } } } } } private struct MainHomeFollowingChatItemView: View { let chat: ChatRoomListItemResponse let action: () -> Void var body: some View { Button(action: action) { HStack(alignment: .center, spacing: SodaSpacing.s12) { DownsampledKFImage(url: URL(string: chat.targetImageUrl), size: CGSize(width: 64, height: 64)) .clipShape(Circle()) VStack(alignment: .leading, spacing: SodaSpacing.s4) { HStack(alignment: .top, spacing: SodaSpacing.s6) { if chat.isDirectMessage { DirectTagView() } Spacer(minLength: 0) Text(chat.relativeLastMessageAtText()) .appFont(size: 12, weight: .regular) .foregroundColor(Color.gray500) .lineLimit(1) } .frame(height: 19) Text(chat.targetName) .appFont(size: 14, weight: .bold) .foregroundColor(.white) .lineLimit(1) .truncationMode(.tail) Text(chat.lastMessage) .appFont(size: 14, weight: .regular) .foregroundColor(.white) .lineLimit(1) .truncationMode(.tail) } .frame(maxWidth: .infinity, alignment: .leading) } .padding(SodaSpacing.s14) .frame(width: 288, alignment: .leading) .background(Color.gray900) .cornerRadius(14) } .buttonStyle(.plain) } } private struct DirectTagView: View { var body: some View { Text(I18n.HomeFollowing.directTag) .appFont(size: 12, weight: .bold) .italic() .foregroundColor(.white) .padding(.horizontal, SodaSpacing.s4) .padding(.vertical, 2) .background(Color.soda400) .cornerRadius(4) } } private extension ChatRoomListItemResponse { var isDirectMessage: Bool { chatType == "DM" } func relativeLastMessageAtText(now: Date = Date()) -> String { DateParser.relativeTimeText(fromUTC: lastMessageAt, fallback: lastMessageAt, now: now) } } struct MainHomeFollowingChatSection_Previews: PreviewProvider { private static let previewImageUrl = "https://picsum.photos/500/500" static var previews: some View { MainHomeFollowingChatSection( recentChats: [ ChatRoomListItemResponse( roomId: 1, chatType: "DM", targetName: "크리에이터 이름", targetImageUrl: previewImageUrl, lastMessage: "마지막 대화 내용이 들어가는 부분 한줄만", lastMessageAt: "2026-07-01T01:30:00Z" ), ChatRoomListItemResponse( roomId: 2, chatType: "GROUP", targetName: "소다", targetImageUrl: previewImageUrl, lastMessage: "다음 대화 내용입니다", lastMessageAt: "2026-07-01T01:20:00Z" ) ] ) .padding(.vertical, SodaSpacing.s20) .background(Color.black) .previewLayout(.sizeThatFits) } }