bmc_hub/TEMPLATES_QUICK_REFERENCE.md

454 lines
12 KiB
Markdown
Raw Permalink Normal View History

# 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)
```python
@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
```python
{
'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
```python
{
'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
```python
{
'location_types': List[str]
}
```
### edit.html
```python
{
'location': Location, # Pre-fill values
'location_types': List[str]
}
```
### map.html
```python
{
'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)
```css
--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)
```html
<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:
```json
{
"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:
```json
{
"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
```html
<!-- 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
```html
<!-- 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
```javascript
const modal = new bootstrap.Modal(document.getElementById('deleteModal'));
modal.show();
modal.hide();
```
### Fetch API Call
```javascript
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
```javascript
document.getElementById('notes').addEventListener('input', function() {
document.getElementById('charCount').textContent = this.value.length;
});
```
### Bulk Delete
```javascript
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](https://getbootstrap.com/docs/5.0/)
- [Leaflet.js Documentation](https://leafletjs.com/)
- [Jinja2 Template Documentation](https://jinja.palletsprojects.com/)
- [MDN Web Docs - HTML](https://developer.mozilla.org/en-US/docs/Web/HTML)
- [MDN Web Docs - CSS](https://developer.mozilla.org/en-US/docs/Web/CSS)
- [MDN Web Docs - JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript)
---
## Template Files
All files located in: `/app/modules/locations/templates/`
**Ready for production deployment** ✅
Last updated: 31 January 2026