feat: Implement NotificationsView component for Lendair iOS
- Create NotificationsView.swift with SwiftUI List and pull-to-refresh - Create NotificationRowView.swift for individual notification items - Create NotificationsViewModel.swift with MVVM pattern - Implement empty state view for no notifications - Add mark-as-read and mark-all-as-read functionality - Support notification types: loan approved/rejected, payment received/due, new lender, system updates - Add toolbar action for marking all notifications as read - Include README.md with architecture documentation and integration guide Next: Connect tRPC notifications router for data fetching
This commit is contained in:
89
Lendair/Views/NotificationRowView.swift
Normal file
89
Lendair/Views/NotificationRowView.swift
Normal file
@@ -0,0 +1,89 @@
|
||||
import SwiftUI
|
||||
|
||||
struct NotificationRowView: View {
|
||||
let notification: NotificationItem
|
||||
|
||||
var body: some View {
|
||||
HStack(spacing: 12) {
|
||||
// Notification icon
|
||||
Image(systemName: notification.type.icon)
|
||||
.font(.system(size: 24))
|
||||
.foregroundColor(notification.type.color)
|
||||
.accessibilityLabel(notification.type.rawValue)
|
||||
|
||||
// Notification content
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text(notification.title)
|
||||
.font(.headline)
|
||||
.foregroundColor(.primary)
|
||||
|
||||
Text(notification.message)
|
||||
.font(.subheadline)
|
||||
.foregroundColor(.secondary)
|
||||
.lineLimit(2)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
// Timestamp and read indicator
|
||||
VStack(alignment: .trailing, spacing: 4) {
|
||||
if !notification.isRead {
|
||||
Image(systemName: "circle.fill")
|
||||
.font(.system(size: 8))
|
||||
.foregroundColor(.blue)
|
||||
}
|
||||
|
||||
Text(formatTimestamp(notification.createdAt))
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
}
|
||||
.padding(.vertical, 8)
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
|
||||
private func formatTimestamp(_ date: Date) -> String {
|
||||
let formatter = RelativeDateTimeFormatter()
|
||||
formatter.unitsStyle = .abbreviated
|
||||
return formatter.localizedString(for: date, relativeTo: Date())
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
List {
|
||||
NotificationRowView(
|
||||
notification: NotificationItem(
|
||||
id: "1",
|
||||
type: .loanApproved,
|
||||
title: "Loan Approved",
|
||||
message: "Your loan application for $500 has been approved by Sarah Johnson.",
|
||||
createdAt: Date().addingTimeInterval(-3600),
|
||||
isRead: false
|
||||
)
|
||||
)
|
||||
|
||||
NotificationRowView(
|
||||
notification: NotificationItem(
|
||||
id: "2",
|
||||
type: .paymentDue,
|
||||
title: "Payment Due Soon",
|
||||
message: "Your payment of $150 is due in 3 days.",
|
||||
createdAt: Date().addingTimeInterval(-86400 * 2),
|
||||
isRead: true
|
||||
)
|
||||
)
|
||||
|
||||
NotificationRowView(
|
||||
notification: NotificationItem(
|
||||
id: "3",
|
||||
type: .paymentReceived,
|
||||
title: "Payment Received",
|
||||
message: "You received a payment of $75 from Michael Chen.",
|
||||
createdAt: Date().addingTimeInterval(-86400 * 5),
|
||||
isRead: false
|
||||
)
|
||||
)
|
||||
}
|
||||
.listStyle(.insetGrouped)
|
||||
.previewDisplayName("Notification Row Preview")
|
||||
}
|
||||
Reference in New Issue
Block a user