import SwiftUI /// Ported from `src/components/dashboard/StatusBadge.tsx` — the web /// dashboard's "3-tier status badges" (see `PROJECT.md`'s feature #12). /// Keep this resolver logic in sync with `resolveReceiptStatusTier` / /// `receiptNeedsAttention` (`src/lib/ai/recalculate.ts`) on the web side. enum ReceiptStatusTier { case scanned case pendingReview case confirmed /// Mirrors `resolveReceiptStatusTier`: a manual confirmation always wins, /// then math/confidence problems route to "needs review", and everything /// else that at least parsed successfully is "scanned". static func resolve(_ receipt: Receipt) -> ReceiptStatusTier { let validation = receipt.validation if validation.userConfirmed == true { return .confirmed } if validation.needsUserReview || !validation.isMathValid { return .pendingReview } if receipt.status == .needsReview { return .pendingReview } return .scanned } var label: String { switch self { case .scanned: return "Erfasst" case .pendingReview: return "Prüfung erforderlich" case .confirmed: return "Bestätigt" } } var systemImage: String { switch self { case .scanned: return "checkmark.circle.fill" case .pendingReview: return "exclamationmark.triangle.fill" case .confirmed: return "person.fill.checkmark" } } var background: Color { switch self { case .scanned: return .zenithScannedBg case .pendingReview: return .zenithPendingBg case .confirmed: return .zenithConfirmedBg } } var foreground: Color { switch self { case .scanned: return .zenithScannedText case .pendingReview: return .zenithPendingText case .confirmed: return .zenithConfirmedText } } var border: Color { switch self { case .scanned: return .zenithScannedBorder case .pendingReview: return .zenithPendingBorder case .confirmed: return .zenithConfirmedBorder } } var dot: Color { switch self { case .scanned: return .zenithScannedDot case .pendingReview: return .zenithPendingDot case .confirmed: return .zenithConfirmedDot } } } /// The badge itself — small rectangular (0-radius), bordered, dot + icon + /// label, exactly the shape `StatusBadge.tsx` renders on the web. struct ZenithStatusBadge: View { let tier: ReceiptStatusTier var showIcon = true var showDot = true init(_ receipt: Receipt, showIcon: Bool = true, showDot: Bool = true) { self.tier = .resolve(receipt) self.showIcon = showIcon self.showDot = showDot } init(tier: ReceiptStatusTier, showIcon: Bool = true, showDot: Bool = true) { self.tier = tier self.showIcon = showIcon self.showDot = showDot } var body: some View { HStack(spacing: 6) { if showDot { Circle().fill(tier.dot).frame(width: 6, height: 6) } if showIcon { Image(systemName: tier.systemImage) .font(.system(size: 10, weight: .semibold)) } Text(tier.label) .lineLimit(1) } .font(.zenithLabelSm) .foregroundStyle(tier.foreground) .padding(.horizontal, 8) .padding(.vertical, 3) .background(tier.background) .overlay(Rectangle().strokeBorder(tier.border, lineWidth: 1)) } } /// A generic (non-status) rectangular chip — `DESIGN (1).md` → Components → /// Chips/Tags: "`label-md` typography, small rectangular boxes with #F5F7F9 /// fills and no borders." Use for categories, payment methods, etc. struct ZenithChip: View { let text: String var body: some View { Text(text) .zenithLabelMdStyle(color: .zenithMuted) .padding(.horizontal, 8) .padding(.vertical, 3) .background(Color.zenithLow) } }