Initial commit: Purrse personal finance app
Self-hosted, plugin-extensible personal finance manager built with ASP.NET Core 9.0, Vue 3 + Vuetify 3, and PostgreSQL 17. Backend (8 .NET projects): - Core: 19 domain models, 6 enums, 14 DTOs, 12 service interfaces - Data: EF Core DbContext, 16 entity configurations, category seeder - API: 14 controllers, 15 services, JWT auth, SignalR, middleware - Plugins: Abstractions + OFX/CSV/QIF file parsers - Tests: 28 xUnit tests (fingerprinting, duplicate detection, parsers) Frontend (Vue 3 + Vuetify 3 + TypeScript): - 13 views, Pinia stores, Axios API services with JWT interceptors - Dashboard, accounts, transactions, categories, imports, and more Deployment: - Docker Compose (PostgreSQL 17 + .NET API + nginx frontend) - Auto-migration on startup Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
import { format, parseISO } from 'date-fns'
|
||||
|
||||
export function formatCurrency(amount: number): string {
|
||||
return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(amount)
|
||||
}
|
||||
|
||||
export function formatDate(date: string): string {
|
||||
return format(parseISO(date), 'MM/dd/yyyy')
|
||||
}
|
||||
|
||||
export function formatDateTime(date: string): string {
|
||||
return format(parseISO(date), 'MM/dd/yyyy h:mm a')
|
||||
}
|
||||
|
||||
export function formatPercent(value: number): string {
|
||||
return `${value >= 0 ? '+' : ''}${value.toFixed(1)}%`
|
||||
}
|
||||
|
||||
export function accountTypeLabel(type: string): string {
|
||||
const labels: Record<string, string> = {
|
||||
Checking: 'Checking',
|
||||
Savings: 'Savings',
|
||||
CreditCard: 'Credit Card',
|
||||
AutoLoan: 'Auto Loan',
|
||||
PersonalLoan: 'Personal Loan',
|
||||
Mortgage: 'Mortgage',
|
||||
LineOfCredit: 'Line of Credit',
|
||||
Retirement401k: '401(k)',
|
||||
IRA: 'IRA',
|
||||
Brokerage: 'Brokerage',
|
||||
Cash: 'Cash',
|
||||
}
|
||||
return labels[type] || type
|
||||
}
|
||||
|
||||
export function accountTypeIcon(type: string): string {
|
||||
const icons: Record<string, string> = {
|
||||
Checking: 'mdi-bank',
|
||||
Savings: 'mdi-piggy-bank',
|
||||
CreditCard: 'mdi-credit-card',
|
||||
AutoLoan: 'mdi-car',
|
||||
PersonalLoan: 'mdi-cash-multiple',
|
||||
Mortgage: 'mdi-home',
|
||||
LineOfCredit: 'mdi-credit-card-outline',
|
||||
Retirement401k: 'mdi-chart-line',
|
||||
IRA: 'mdi-chart-areaspline',
|
||||
Brokerage: 'mdi-finance',
|
||||
Cash: 'mdi-cash',
|
||||
}
|
||||
return icons[type] || 'mdi-bank'
|
||||
}
|
||||
Reference in New Issue
Block a user