- 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.
12 KiB
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 filledtype="email"- Email format validationtype="tel"- Phone formattype="number"- Numeric inputmin="-90" max="90"- Range validationmaxlength="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
- Bootstrap 5 Documentation
- Leaflet.js Documentation
- Jinja2 Template Documentation
- MDN Web Docs - HTML
- MDN Web Docs - CSS
- MDN Web Docs - JavaScript
Template Files
All files located in: /app/modules/locations/templates/
Ready for production deployment ✅
Last updated: 31 January 2026