feat: add iOS support and harden receipt scanning
This commit is contained in:
72
app/ios/ScanReceipts/Features/Receipts/ReceiptRow.swift
Normal file
72
app/ios/ScanReceipts/Features/Receipts/ReceiptRow.swift
Normal file
@@ -0,0 +1,72 @@
|
||||
import SwiftUI
|
||||
|
||||
/// One row in `ReceiptsListView`: merchant, formatted business date and
|
||||
/// amount, category, and the shared `ZenithStatusBadge` (matching the web
|
||||
/// dashboard's `StatusBadge.tsx`).
|
||||
struct ReceiptRow: View {
|
||||
let receipt: Receipt
|
||||
|
||||
var body: some View {
|
||||
HStack(alignment: .top, spacing: ZenithSpacing.sm) {
|
||||
VStack(alignment: .leading, spacing: ZenithSpacing.unit) {
|
||||
Text(receipt.merchant.name.isEmpty ? "Unbekannter Händler" : receipt.merchant.name)
|
||||
.zenithBodyStyle()
|
||||
.fontWeight(.medium)
|
||||
.lineLimit(1)
|
||||
|
||||
HStack(spacing: 6) {
|
||||
Text(formattedDate)
|
||||
Text("·")
|
||||
Text(receipt.suggestedCategory.rawValue)
|
||||
}
|
||||
.zenithBodySmStyle()
|
||||
.lineLimit(1)
|
||||
}
|
||||
|
||||
Spacer(minLength: ZenithSpacing.xs)
|
||||
|
||||
VStack(alignment: .trailing, spacing: 6) {
|
||||
Text(formattedAmount)
|
||||
.zenithLabelMdStyle()
|
||||
.fontWeight(.medium)
|
||||
.multilineTextAlignment(.trailing)
|
||||
|
||||
ZenithStatusBadge(receipt)
|
||||
.accessibilityElement(children: .combine)
|
||||
}
|
||||
}
|
||||
.padding(.vertical, ZenithSpacing.xs)
|
||||
}
|
||||
|
||||
// `receipt.date.isoDate` is a plain "YYYY-MM-DD" string (no time/zone
|
||||
// component), so it deliberately does NOT go through ISO8601.parse
|
||||
// (which expects a full timestamp and would just return nil here).
|
||||
private var formattedDate: String {
|
||||
guard let date = Self.isoDateOnlyFormatter.date(from: receipt.date.isoDate) else {
|
||||
return receipt.date.isoDate
|
||||
}
|
||||
return Self.displayDateFormatter.string(from: date)
|
||||
}
|
||||
|
||||
private var formattedAmount: String {
|
||||
let code = receipt.currency.isEmpty ? "EUR" : receipt.currency
|
||||
return receipt.totalAmount.value.formatted(.currency(code: code))
|
||||
}
|
||||
|
||||
private static let isoDateOnlyFormatter: DateFormatter = {
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateFormat = "yyyy-MM-dd"
|
||||
formatter.locale = Locale(identifier: "en_US_POSIX")
|
||||
formatter.timeZone = TimeZone(identifier: "UTC")
|
||||
return formatter
|
||||
}()
|
||||
|
||||
private static let displayDateFormatter: DateFormatter = {
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateStyle = .medium
|
||||
formatter.timeStyle = .none
|
||||
formatter.locale = Locale(identifier: "de_DE")
|
||||
formatter.timeZone = TimeZone(identifier: "UTC")
|
||||
return formatter
|
||||
}()
|
||||
}
|
||||
Reference in New Issue
Block a user