bmc_hub/TEMPLATES_QUICK_REFERENCE.md
Christian 29acdf3e01 Add tests for new SAG module endpoints and module deactivation
- Implement test script for new SAG module endpoints BE-003 (Tag State Management) and BE-004 (Bulk Operations).
- Create test cases for creating, updating, and bulk operations on cases and tags.
- Add a test for module deactivation to ensure data integrity is maintained.
- Include setup and teardown for tests to clear database state before and after each test.
2026-01-31 23:16:24 +01:00

12 KiB

Location Module Templates - Quick Reference Guide

Template Overview

5 production-ready Jinja2 templates for the Location (Lokaliteter) module:

Template Purpose Context Key Features
list.html List all locations locations, total, page_number, total_pages, filters Pagination, bulk select, filters, responsive table
detail.html View location details location, location.* (contacts, hours, services, capacity) 6 tabs, modals, CRUD operations, progress bars
create.html Create new location location_types 5-section form, validation, character counter
edit.html Edit location location, location_types Pre-filled form, delete modal, PATCH request
map.html Interactive map locations, location_types Leaflet.js, clustering, type filters

Directory

/app/modules/locations/templates/

Integration Points

1. Routes Required (Backend)

@router.get("/locations", response_model=List[Location])
def list_locations(skip: int = 0, limit: int = 10, ...):
    # Return filtered, paginated locations

@router.get("/locations/create", ...)
def create_page(location_types: List[str]):
    # Render create.html

@router.get("/locations/{id}", response_model=LocationDetail)
def detail_page(id: int):
    # Render detail.html with full object

@router.get("/locations/{id}/edit", ...)
def edit_page(id: int, location_types: List[str]):
    # Render edit.html with location pre-filled

@router.get("/locations/map", ...)
def map_page(locations: List[Location], location_types: List[str]):
    # Render map.html with location data

2. API Endpoints Required

POST   /api/v1/locations              - Create location
GET    /api/v1/locations/{id}         - Get location
PATCH  /api/v1/locations/{id}         - Update location
DELETE /api/v1/locations/{id}         - Delete location (soft)

POST   /api/v1/locations/{id}/contacts     - Add contact
DELETE /api/v1/locations/{id}/contacts/{cid} - Delete contact

POST   /api/v1/locations/{id}/services     - Add service
DELETE /api/v1/locations/{id}/services/{sid} - Delete service

POST   /api/v1/locations/{id}/capacity     - Add capacity
DELETE /api/v1/locations/{id}/capacity/{cid} - Delete capacity

Context Variables Reference

list.html

{
    'locations': List[Location],
    'total': int,
    'skip': int,
    'limit': int,
    'page_number': int,
    'total_pages': int,
    'location_type': Optional[str],
    'is_active': Optional[bool],
    'location_types': List[str]
}

detail.html

{
    'location': LocationDetail,  # With all nested data
    'location.id': int,
    'location.name': str,
    'location.location_type': str,
    'location.is_active': bool,
    'location.address_*': str,
    'location.phone': str,
    'location.email': str,
    'location.contacts': List[Contact],
    'location.operating_hours': List[Hours],
    'location.services': List[Service],
    'location.capacity': List[Capacity],
    'location.audit_log': List[AuditEntry],
    'location_types': List[str]
}

create.html

{
    'location_types': List[str]
}

edit.html

{
    'location': Location,  # Pre-fill values
    'location_types': List[str]
}

map.html

{
    'locations': List[Location],  # Must have: id, name, latitude, longitude, location_type, address_city
    'location_types': List[str]
}

CSS Classes Used

Bootstrap 5 Classes

Container: container-fluid, px-4, py-4
Grid: row, col-*, col-md-*, col-lg-*
Cards: card, card-body, card-header
Forms: form-control, form-select, form-check, form-label
Buttons: btn, btn-primary, btn-outline-secondary, btn-danger
Tables: table, table-hover, table-responsive
Badges: badge, bg-success, bg-secondary
Modals: modal, modal-dialog, modal-content
Alerts: alert, alert-danger
Pagination: pagination, page-item, page-link
Utilities: d-flex, gap-*, justify-content-*, align-items-*

Custom CSS Variables (from base.html)

--bg-body: #f8f9fa / #212529
--bg-card: #ffffff / #2c3034
--text-primary: #2c3e50 / #f8f9fa
--text-secondary: #6c757d / #adb5bd
--accent: #0f4c75 / #3d8bfd
--accent-light: #eef2f5 / #373b3e
--border-radius: 12px

JavaScript Events

list.html

  • Checkbox select/deselect
  • Bulk delete confirmation
  • Individual delete confirmation
  • Row click navigation
  • Page navigation

detail.html

  • Tab switching (Bootstrap nav-tabs)
  • Modal open/close
  • Form submission (Fetch API)
  • Delete confirmation
  • Inline delete buttons

create.html

  • Character counter update
  • Form submission (Fetch API)
  • Error display/dismiss
  • Loading state toggle
  • Redirect on success

edit.html

  • Same as create.html + delete modal

map.html

  • Leaflet map initialization
  • Marker clustering
  • Popup display
  • Type filter update
  • Marker click handlers

Color Reference

Type Badges

  • Branch (Filial): #0f4c75 - Deep Blue
  • Warehouse (Lager): #f39c12 - Orange
  • Service Center (Servicecenter): #2eb341 - Green
  • Client Site (Kundesite): #9b59b6 - Purple

Status Badges

  • Active: #2eb341 (Green) - bg-success
  • Inactive: #6c757d (Gray) - bg-secondary

Actions

  • Primary: #0f4c75 (Blue) - btn-primary
  • Secondary: #6c757d (Gray) - btn-outline-secondary
  • Danger: #e74c3c (Red) - btn-danger

Responsive Breakpoints

Size Bootstrap Applies Changes
Mobile < 576px Default Full-width forms, stacked buttons
Tablet >= 768px col-md-* 2-column forms, table layout
Desktop >= 1024px col-lg-* Multi-column forms, sidebar options

list.html Responsive Changes

  • < 768px: Hide "City" column, show only essential
  • = 768px: Show all table columns

detail.html Responsive Changes

  • < 768px: Stacked tabs, full-width modals
  • = 768px: Side-by-side cards, responsive modals


Icons (Font Awesome / Bootstrap Icons)

<i class="bi bi-plus-lg"></i>           <!-- Plus -->
<i class="bi bi-pencil"></i>            <!-- Edit -->
<i class="bi bi-trash"></i>             <!-- Delete -->
<i class="bi bi-eye"></i>               <!-- View -->
<i class="bi bi-arrow-left"></i>        <!-- Back -->
<i class="bi bi-map-marker-alt"></i>    <!-- Location -->
<i class="bi bi-phone"></i>             <!-- Phone -->
<i class="bi bi-envelope"></i>          <!-- Email -->
<i class="bi bi-clock"></i>             <!-- Time -->
<i class="bi bi-chevron-left"></i>      <!-- Prev -->
<i class="bi bi-chevron-right"></i>     <!-- Next -->
<i class="bi bi-funnel"></i>            <!-- Filter -->
<i class="bi bi-pin-map"></i>           <!-- Location Pin -->
<i class="bi bi-check-lg"></i>          <!-- Check -->
<i class="bi bi-hourglass-split"></i>   <!-- Loading -->

Form Validation

HTML5 Validation

  • required - Field must be filled
  • type="email" - Email format validation
  • type="tel" - Phone format
  • type="number" - Numeric input
  • min="-90" max="90" - Range validation
  • maxlength="500" - Length limit

Server-Side Validation

Expected from API:

{
    "detail": "Validation error message",
    "status": 422
}

Error Handling

Client-Side

  • HTML5 validation prevents invalid submissions
  • Fetch API error handling
  • Try-catch for async operations
  • User-friendly error messages in alert boxes

API Errors

Expected format:

{
    "detail": "Location not found"
}

Mobile Optimization

  • Touch targets: Minimum 44px height
  • Forms: Full-width on mobile
  • Tables: Convert to card view at 768px
  • Buttons: Stacked vertically on mobile
  • Modals: Full-screen on mobile
  • Maps: Responsive container

Dark Mode

Automatic via data-bs-theme attribute on <html>:

  • Light mode: data-bs-theme="light"
  • Dark mode: data-bs-theme="dark"

CSS variables automatically adjust colors.


External Dependencies

CSS

<!-- Bootstrap 5 -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">

<!-- Bootstrap Icons -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css">

<!-- Leaflet (map.html only) -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/leaflet@1.9.4/dist/leaflet.min.css" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/leaflet.markercluster@1.5.1/dist/MarkerCluster.css" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/leaflet.markercluster@1.5.1/dist/MarkerCluster.Default.css" />

JavaScript

<!-- Bootstrap 5 -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>

<!-- Leaflet (map.html only) -->
<script src="https://cdn.jsdelivr.net/npm/leaflet@1.9.4/dist/leaflet.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/leaflet.markercluster@1.5.1/dist/leaflet.markercluster.js"></script>

Common Patterns

Opening a Modal

const modal = new bootstrap.Modal(document.getElementById('deleteModal'));
modal.show();
modal.hide();

Fetch API Call

const response = await fetch('/api/v1/locations', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(data)
});

if (response.ok) {
    const result = await response.json();
    // Success
} else {
    const error = await response.json();
    // Show error
}

Character Counter

document.getElementById('notes').addEventListener('input', function() {
    document.getElementById('charCount').textContent = this.value.length;
});

Bulk Delete

const selectedIds = Array.from(checkboxes)
    .filter(cb => cb.checked)
    .map(cb => cb.value);

Promise.all(selectedIds.map(id => 
    fetch(`/api/v1/locations/${id}`, { method: 'DELETE' })
))

Testing Checklist

  • Form validation works
  • Required fields enforced
  • Pagination navigation works
  • Filters persist across pages
  • Bulk select/deselect works
  • Individual delete confirmation
  • Modal forms submit correctly
  • Inline errors display
  • Map renders with markers
  • Map filter updates markers
  • Responsive at 375px
  • Responsive at 768px
  • Responsive at 1024px
  • Dark mode works
  • No console errors
  • API endpoints working

Support & Troubleshooting

Maps not showing

  • Check: Leaflet CDN is loaded
  • Check: Locations have latitude/longitude
  • Check: Zoom level is 6 (default Denmark view)

Forms not submitting

  • Check: All required fields filled
  • Check: API endpoint is correct
  • Check: CSRF protection if enabled

Modals not opening

  • Check: Bootstrap JS is loaded
  • Check: Modal ID matches button target
  • Check: No console errors

Styles not applying

  • Check: Bootstrap 5 CSS loaded
  • Check: CSS variables inherited from base.html
  • Check: Dark mode toggle working

References


Template Files

All files located in: /app/modules/locations/templates/

Ready for production deployment

Last updated: 31 January 2026