Files
WearPartTracker/lib/utils.ts
Denis Urs Rudolph de193bc783 Initial commit: Fahrrad Verschleißteile Tracker
- Next.js SPA mit Bun Runtime
- Prisma mit SQLite Datenbank
- Vollständige CRUD-Operationen für Fahrräder, Verschleißteile und Wartungshistorie
- Warnsystem für bevorstehende Wartungen
- Statistik-Features (Gesamtkosten, durchschnittliche Lebensdauer)
- Zod-Validierung für alle API-Requests
- Umfassende Test-Suite (41 Tests)
2025-12-05 22:17:50 +01:00

86 lines
2.4 KiB
TypeScript

import { WearPart, MaintenanceHistory } from '@prisma/client'
export function calculateServiceStatus(
part: WearPart & { maintenanceHistory: MaintenanceHistory[] }
): {
status: 'OK' | 'WARNING' | 'CRITICAL'
remainingKm: number
percentageUsed: number
} {
const latestMaintenance = part.maintenanceHistory[0]
const currentMileage = latestMaintenance?.mileage ?? part.installMileage
const kmSinceInstall = currentMileage - part.installMileage
const remainingKm = part.serviceInterval - kmSinceInstall
const percentageUsed = (kmSinceInstall / part.serviceInterval) * 100
let status: 'OK' | 'WARNING' | 'CRITICAL' = 'OK'
if (percentageUsed >= 90) {
status = 'CRITICAL'
} else if (percentageUsed >= 75) {
status = 'WARNING'
}
return {
status,
remainingKm: Math.max(0, remainingKm),
percentageUsed: Math.min(100, percentageUsed),
}
}
export function calculateTotalCosts(
parts: (WearPart & { maintenanceHistory: MaintenanceHistory[] })[]
): number {
return parts.reduce((total, part) => {
const partCost = part.cost ?? 0
const maintenanceCost = part.maintenanceHistory.reduce(
(sum, m) => sum + (m.cost ?? 0),
0
)
return total + partCost + maintenanceCost
}, 0)
}
export function calculateAverageLifespan(
parts: (WearPart & { maintenanceHistory: MaintenanceHistory[] })[]
): number | null {
const replacedParts = parts.filter(
(p) => p.status === 'REPLACED' && p.maintenanceHistory.length > 0
)
if (replacedParts.length === 0) return null
const totalKm = replacedParts.reduce((sum, part) => {
const installHistory = part.maintenanceHistory.find(
(h) => h.action === 'INSTALL'
)
const replaceHistory = part.maintenanceHistory.find(
(h) => h.action === 'REPLACE'
)
if (installHistory && replaceHistory) {
return sum + (replaceHistory.mileage - installHistory.mileage)
}
return sum
}, 0)
return totalKm / replacedParts.length
}
export function formatDate(date: Date | string): string {
const d = typeof date === 'string' ? new Date(date) : date
return d.toLocaleDateString('de-DE', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
})
}
export function formatCurrency(amount: number | null | undefined): string {
if (amount === null || amount === undefined) return '0,00 €'
return new Intl.NumberFormat('de-DE', {
style: 'currency',
currency: 'EUR',
}).format(amount)
}