Files
2025-07-07 01:44:12 +02:00

380 lines
13 KiB
Plaintext

package pages
import (
"fmt"
"tankstopp/internal/models"
"tankstopp/internal/views/components"
)
templ VehiclesPage(user *models.User, username string, vehicles []models.Vehicle) {
@components.BaseLayout("Vehicles", user, username) {
@components.PageHeader("Manage your vehicles", "Vehicles")
<div class="page-body">
<div class="container-xl">
<!-- Quick Actions -->
<div class="row mb-4">
<div class="col-12">
<div class="d-flex justify-content-between align-items-center">
<div>
<h3 class="mb-0">Your Vehicles</h3>
<p class="text-muted">Manage and track your vehicles</p>
</div>
<div>
<a href="/vehicles/add" class="btn btn-primary">
@components.Icon("plus", 24)
Add Vehicle
</a>
</div>
</div>
</div>
</div>
<!-- Vehicles Grid -->
<div class="row">
if len(vehicles) > 0 {
for _, vehicle := range vehicles {
<div class="col-md-6 col-lg-4 mb-4">
@VehicleCard(vehicle)
</div>
}
} else {
<div class="col-12">
@components.EmptyState("car", "No vehicles found", "Add your first vehicle to start tracking fuel expenses.", "Add Vehicle", "/vehicles/add")
</div>
}
</div>
<!-- Statistics Cards -->
if len(vehicles) > 0 {
<div class="row mt-4">
<div class="col-12">
<h4 class="mb-3">Vehicle Statistics</h4>
</div>
<div class="col-sm-6 col-lg-3">
@components.Card("Total Vehicles", "car") {
<div class="h2 mb-2">{ fmt.Sprintf("%d", len(vehicles)) }</div>
<div class="text-muted">Registered vehicles</div>
}
</div>
<div class="col-sm-6 col-lg-3">
@components.Card("Active Vehicles", "status") {
<div class="h2 mb-2">{ fmt.Sprintf("%d", countActiveVehicles(vehicles)) }</div>
<div class="text-muted">Currently active</div>
}
</div>
<div class="col-sm-6 col-lg-3">
@components.Card("Brands", "brand") {
<div class="h2 mb-2">{ fmt.Sprintf("%d", countUniqueBrands(vehicles)) }</div>
<div class="text-muted">Different brands</div>
}
</div>
<div class="col-sm-6 col-lg-3">
@components.Card("Fuel Types", "fuel") {
<div class="h2 mb-2">{ fmt.Sprintf("%d", countUniqueFuelTypes(vehicles)) }</div>
<div class="text-muted">Different fuel types</div>
}
</div>
</div>
}
</div>
</div>
}
}
templ VehicleCard(vehicle models.Vehicle) {
<div class="card">
<div class="card-body">
<div class="d-flex justify-content-between align-items-start mb-3">
<div class="flex-fill">
<h4 class="card-title mb-1">{ vehicle.Name }</h4>
<div class="text-muted small">
{ vehicle.Make } { vehicle.Model }
</div>
</div>
<div class="dropdown">
<button class="btn btn-sm btn-ghost-secondary" type="button" data-bs-toggle="dropdown">
@components.Icon("dots-vertical", 24)
</button>
<div class="dropdown-menu dropdown-menu-end">
<a class="dropdown-item" href={ templ.SafeURL(fmt.Sprintf("/vehicles/edit/%d", vehicle.ID)) }>
@components.Icon("edit", 24)
Edit
</a>
<div class="dropdown-divider"></div>
<form method="POST" action={ fmt.Sprintf("/vehicles/delete/%d", vehicle.ID) } style="display: inline;" onsubmit="return confirmDelete(this)" data-item={ vehicle.Name }>
<button type="submit" class="dropdown-item text-danger">
@components.Icon("trash", 24)
Delete
</button>
</form>
</div>
</div>
</div>
<div class="row">
<div class="col-6">
<div class="d-flex align-items-center mb-2">
@components.Icon("license-plate", 24)
<span class="ms-2 small">
if vehicle.LicensePlate != "" {
{ vehicle.LicensePlate }
} else {
<span class="text-muted">No plate</span>
}
</span>
</div>
</div>
<div class="col-6">
<div class="d-flex align-items-center mb-2">
@components.Icon("fuel", 24)
<span class="ms-2 small">{ vehicle.FuelType }</span>
</div>
</div>
</div>
<div class="row">
<div class="col-6">
<div class="d-flex align-items-center mb-2">
@components.Icon("calendar", 24)
<span class="ms-2 small">{ fmt.Sprintf("%d", vehicle.Year) }</span>
</div>
</div>
<div class="col-6">
<div class="d-flex align-items-center mb-2">
if vehicle.IsActive {
<span class="badge bg-success">Active</span>
} else {
<span class="badge bg-secondary">Inactive</span>
}
</div>
</div>
</div>
if vehicle.Notes != "" {
<div class="mt-3 pt-3 border-top">
<small class="text-muted">{ vehicle.Notes }</small>
</div>
}
</div>
</div>
}
templ AddVehiclePage(user *models.User, username string) {
@components.BaseLayout("Add Vehicle", user, username) {
@components.PageHeader("Add a new vehicle", "Add Vehicle")
<div class="page-body">
<div class="container-xl">
<div class="row justify-content-center">
<div class="col-12 col-lg-8">
@components.Card("Vehicle Information", "car") {
@components.Form("post", "/vehicles/add") {
<div class="row">
<div class="col-md-6">
@components.FormGroup("Vehicle Name", "A friendly name for your vehicle") {
@components.Input("name", "text", "e.g., My Car, Work Van", "", true)
}
</div>
<div class="col-md-6">
@components.FormGroup("License Plate", "Vehicle registration number") {
@components.Input("license_plate", "text", "e.g., ABC-123", "", false)
}
</div>
</div>
<div class="row">
<div class="col-md-6">
@components.FormGroup("Make", "Vehicle manufacturer") {
@VehicleBrandSelect("make", "")
}
</div>
<div class="col-md-6">
@components.FormGroup("Model", "Vehicle model") {
@components.Input("model", "text", "e.g., Corolla, Golf", "", true)
}
</div>
</div>
<div class="row">
<div class="col-md-6">
@components.FormGroup("Year", "Manufacturing year") {
@components.NumberInput("year", "2024", 0, "1", 1900, true)
}
</div>
<div class="col-md-6">
@components.FormGroup("Fuel Type", "Primary fuel type") {
@components.FuelTypeSelect("fuel_type", "", true)
}
</div>
</div>
<div class="row">
<div class="col-md-6">
@components.FormGroup("Active", "Vehicle status") {
@components.Switch("is_active", "Vehicle is active", true)
}
</div>
</div>
<div class="row">
<div class="col-12">
@components.FormGroup("Notes", "Additional information (optional)") {
@components.TextArea("notes", "Add any additional notes about this vehicle...", "", 3)
}
</div>
</div>
@components.FormButtons("/vehicles", "Add Vehicle", "save")
}
}
</div>
</div>
</div>
</div>
}
}
templ EditVehiclePage(user *models.User, username string, vehicle *models.Vehicle) {
@components.BaseLayout("Edit Vehicle", user, username) {
@components.PageHeader("Update vehicle information", "Edit Vehicle")
<div class="page-body">
<div class="container-xl">
<div class="row justify-content-center">
<div class="col-12 col-lg-8">
@components.Card("Vehicle Information", "car") {
@components.Form("post", fmt.Sprintf("/vehicles/edit/%d", vehicle.ID)) {
<div class="row">
<div class="col-md-6">
@components.FormGroup("Vehicle Name", "A friendly name for your vehicle") {
@components.Input("name", "text", "e.g., My Car, Work Van", vehicle.Name, true)
}
</div>
<div class="col-md-6">
@components.FormGroup("License Plate", "Vehicle registration number") {
@components.Input("license_plate", "text", "e.g., ABC-123", vehicle.LicensePlate, false)
}
</div>
</div>
<div class="row">
<div class="col-md-6">
@components.FormGroup("Make", "Vehicle manufacturer") {
@VehicleBrandSelect("make", vehicle.Make)
}
</div>
<div class="col-md-6">
@components.FormGroup("Model", "Vehicle model") {
@components.Input("model", "text", "e.g., Corolla, Golf", vehicle.Model, true)
}
</div>
</div>
<div class="row">
<div class="col-md-6">
@components.FormGroup("Year", "Manufacturing year") {
@components.NumberInput("year", "2024", float64(vehicle.Year), "1", 1900, true)
}
</div>
<div class="col-md-6">
@components.FormGroup("Fuel Type", "Primary fuel type") {
@components.FuelTypeSelect("fuel_type", vehicle.FuelType, true)
}
</div>
</div>
<div class="row">
<div class="col-md-6">
@components.FormGroup("Active", "Vehicle status") {
@components.Switch("is_active", "Vehicle is active", vehicle.IsActive)
}
</div>
</div>
<div class="row">
<div class="col-12">
@components.FormGroup("Notes", "Additional information (optional)") {
@components.TextArea("notes", "Add any additional notes about this vehicle...", vehicle.Notes, 3)
}
</div>
</div>
@components.FormButtons("/vehicles", "Update Vehicle", "save")
}
}
</div>
</div>
</div>
</div>
}
}
templ VehicleBrandSelect(name, selectedMake string) {
@components.Select(name, true) {
@components.Option("", "Select make...", selectedMake == "")
@components.Option("Audi", "Audi", selectedMake == "Audi")
@components.Option("BMW", "BMW", selectedMake == "BMW")
@components.Option("Mercedes-Benz", "Mercedes-Benz", selectedMake == "Mercedes-Benz")
@components.Option("Volkswagen", "Volkswagen", selectedMake == "Volkswagen")
@components.Option("Ford", "Ford", selectedMake == "Ford")
@components.Option("Toyota", "Toyota", selectedMake == "Toyota")
@components.Option("Honda", "Honda", selectedMake == "Honda")
@components.Option("Nissan", "Nissan", selectedMake == "Nissan")
@components.Option("Hyundai", "Hyundai", selectedMake == "Hyundai")
@components.Option("Kia", "Kia", selectedMake == "Kia")
@components.Option("Mazda", "Mazda", selectedMake == "Mazda")
@components.Option("Subaru", "Subaru", selectedMake == "Subaru")
@components.Option("Volvo", "Volvo", selectedMake == "Volvo")
@components.Option("Peugeot", "Peugeot", selectedMake == "Peugeot")
@components.Option("Renault", "Renault", selectedMake == "Renault")
@components.Option("Citroen", "Citroen", selectedMake == "Citroen")
@components.Option("Fiat", "Fiat", selectedMake == "Fiat")
@components.Option("Opel", "Opel", selectedMake == "Opel")
@components.Option("Skoda", "Skoda", selectedMake == "Skoda")
@components.Option("SEAT", "SEAT", selectedMake == "SEAT")
@components.Option("Chevrolet", "Chevrolet", selectedMake == "Chevrolet")
@components.Option("Jeep", "Jeep", selectedMake == "Jeep")
@components.Option("Land Rover", "Land Rover", selectedMake == "Land Rover")
@components.Option("Jaguar", "Jaguar", selectedMake == "Jaguar")
@components.Option("Porsche", "Porsche", selectedMake == "Porsche")
@components.Option("Tesla", "Tesla", selectedMake == "Tesla")
@components.Option("Other", "Other", selectedMake == "Other")
}
}
// Helper functions for statistics
func countActiveVehicles(vehicles []models.Vehicle) int {
count := 0
for _, vehicle := range vehicles {
if vehicle.IsActive {
count++
}
}
return count
}
func countUniqueBrands(vehicles []models.Vehicle) int {
brands := make(map[string]bool)
for _, vehicle := range vehicles {
if vehicle.Make != "" {
brands[vehicle.Make] = true
}
}
return len(brands)
}
func countUniqueFuelTypes(vehicles []models.Vehicle) int {
fuelTypes := make(map[string]bool)
for _, vehicle := range vehicles {
if vehicle.FuelType != "" {
fuelTypes[vehicle.FuelType] = true
}
}
return len(fuelTypes)
}
script VehicleScript() {
function confirmDelete(form) {
const vehicleName = form.dataset.item;
return confirm(`Are you sure you want to delete the vehicle "${vehicleName}"? This action cannot be undone and will also delete all associated fuel stops.`);
}
// Initialize tooltips and dropdowns
document.addEventListener('DOMContentLoaded', function() {
// Initialize Bootstrap tooltips
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl);
});
// Set current year as default
const yearInput = document.querySelector('input[name="year"]');
if (yearInput && !yearInput.value) {
yearInput.value = new Date().getFullYear();
}
});
}