2026-01-31 23:16:24 +01:00
{% extends "shared/frontend/base.html" %}
{% block title %}{{ location.name }} - BMC Hub{% endblock %}
2026-05-06 07:01:43 +02:00
{% block extra_css %}
< style >
.locations-detail-page {
--loc-accent: var(--accent, #0f4c75);
}
.locations-detail-page .case-hero {
background: var(--bg-card, #fff);
border-radius: 16px;
overflow: visible;
box-shadow:
0 0 0 1px rgba(0,0,0,0.06),
0 4px 6px -1px rgba(0,0,0,0.05),
0 16px 32px -8px rgba(15,76,117,0.10);
}
.locations-detail-page .case-hero-identity {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0.75rem 1.25rem;
background: linear-gradient(135deg, rgba(15,76,117,0.05) 0%, rgba(15,76,117,0.01) 100%);
border-bottom: 1px solid rgba(0,0,0,0.06);
border-radius: 16px 16px 0 0;
flex-wrap: wrap;
gap: 0.5rem;
}
.locations-detail-page .case-id-chip {
display: inline-flex;
align-items: center;
font-size: 1rem;
font-weight: 900;
letter-spacing: -0.4px;
color: var(--loc-accent);
background: color-mix(in srgb, var(--loc-accent) 10%, transparent);
border: 1.5px solid color-mix(in srgb, var(--loc-accent) 30%, transparent);
border-radius: 8px;
padding: 0.2em 0.65em;
}
.locations-detail-page .case-type-chip {
display: inline-flex;
align-items: center;
gap: 0.35rem;
font-size: 0.73rem;
font-weight: 700;
letter-spacing: 0.05em;
text-transform: uppercase;
color: var(--loc-accent);
background: color-mix(in srgb, var(--loc-accent) 8%, transparent);
border: 1px solid color-mix(in srgb, var(--loc-accent) 25%, transparent);
border-radius: 999px;
padding: 0.32em 0.8em;
}
.locations-detail-page .case-status-chip {
display: inline-flex;
align-items: center;
gap: 0.4em;
font-size: 0.73rem;
font-weight: 700;
letter-spacing: 0.04em;
border-radius: 999px;
padding: 0.3em 0.85em;
border: 1px solid transparent;
}
.locations-detail-page .case-status-chip.open {
background: #dcfce7;
color: #15803d;
border-color: #86efac;
}
.locations-detail-page .case-status-chip.closed {
background: #f1f5f9;
color: #475569;
border-color: #cbd5e1;
}
.locations-detail-page .case-status-dot {
width: 7px;
height: 7px;
border-radius: 50%;
background: currentColor;
flex-shrink: 0;
}
.locations-detail-page .case-hero-meta {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 0.55rem;
padding: 0.75rem 1rem 0.95rem;
}
.locations-detail-page .case-meta-cell {
border: 1px solid rgba(0,0,0,0.06);
border-radius: 10px;
background: color-mix(in srgb, var(--loc-accent) 4%, var(--bg-card, #fff));
padding: 0.58rem 0.7rem;
}
.locations-detail-page .hero-meta-label {
font-size: 0.62rem;
text-transform: uppercase;
letter-spacing: 0.07em;
font-weight: 700;
color: var(--text-secondary);
opacity: 0.7;
margin-bottom: 3px;
}
.locations-detail-page .hero-meta-value {
font-size: 0.95rem;
font-weight: 700;
color: var(--text-primary);
}
.locations-detail-page #locationTabs {
border-bottom: none;
gap: 0.45rem;
}
.locations-detail-page #locationTabs .nav-link {
border: 1px solid rgba(0,0,0,0.1);
border-radius: 999px;
color: var(--text-secondary);
background: var(--bg-card, #fff);
font-weight: 600;
padding: 0.44rem 0.82rem;
transition: all 0.16s ease;
}
.locations-detail-page #locationTabs .nav-link:hover,
.locations-detail-page #locationTabs .nav-link:focus-visible {
border-color: color-mix(in srgb, var(--loc-accent) 45%, transparent);
color: var(--loc-accent);
}
.locations-detail-page #locationTabs .nav-link.active {
background: color-mix(in srgb, var(--loc-accent) 12%, var(--bg-card, #fff));
border-color: color-mix(in srgb, var(--loc-accent) 40%, transparent);
color: var(--loc-accent);
}
.locations-detail-page .location-tab-count-badge {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 1.2rem;
height: 1.2rem;
border-radius: 999px;
padding: 0 0.34rem;
font-size: 0.66rem;
font-weight: 800;
background: color-mix(in srgb, var(--loc-accent) 14%, transparent);
color: var(--loc-accent);
}
.locations-detail-page .card {
border-radius: 12px;
border: 1px solid rgba(0,0,0,0.08) !important;
box-shadow: 0 6px 18px rgba(15, 76, 117, 0.08);
}
.locations-detail-page .list-group-item {
border-radius: 0.8rem !important;
margin-bottom: 0.45rem;
border: 1px solid rgba(15, 76, 117, 0.1);
}
.locations-detail-page .timeline-item {
position: relative;
}
.locations-detail-page .timeline-item::before {
content: "";
position: absolute;
left: 6px;
top: 20px;
bottom: -14px;
width: 1px;
background: rgba(15, 76, 117, 0.2);
}
.locations-detail-page .timeline-item:last-child::before {
display: none;
}
@media (max-width: 767.98px) {
.locations-detail-page {
padding-left: 0.5rem;
padding-right: 0.5rem;
}
.locations-detail-page .case-hero-meta {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
< / style >
{% endblock %}
2026-01-31 23:16:24 +01:00
{% block content %}
2026-05-06 07:01:43 +02:00
< div class = "container-fluid px-4 py-4 locations-detail-page" >
2026-01-31 23:16:24 +01:00
<!-- Breadcrumb -->
< nav aria-label = "breadcrumb" class = "mb-4" >
< ol class = "breadcrumb" >
< li class = "breadcrumb-item" > < a href = "/" class = "text-decoration-none" > Hjem< / a > < / li >
< li class = "breadcrumb-item" > < a href = "/app/locations" class = "text-decoration-none" > Lokaliteter< / a > < / li >
< li class = "breadcrumb-item active" > {{ location.name }}< / li >
< / ol >
< / nav >
<!-- Header Section -->
< div class = "row mb-4" >
< div class = "col-12" >
2026-05-06 07:01:43 +02:00
< div class = "case-hero" >
< div class = "case-hero-identity" >
< div class = "d-flex flex-wrap align-items-center gap-2" >
< span class = "case-id-chip" > Lokation #{{ location.id }}< / span >
2026-01-31 23:16:24 +01:00
{% set type_label = {
'kompleks': 'Kompleks',
'bygning': 'Bygning',
'etage': 'Etage',
'rum': 'Rum',
2026-02-09 15:30:07 +01:00
'kantine': 'Kantine',
'moedelokale': 'Mødelokale',
2026-01-31 23:16:24 +01:00
'customer_site': 'Kundesite',
'vehicle': 'Køretøj'
}.get(location.location_type, location.location_type) %}
{% set type_color = {
'kompleks': '#0f4c75',
'bygning': '#1abc9c',
'etage': '#3498db',
'rum': '#e67e22',
2026-02-09 15:30:07 +01:00
'kantine': '#d35400',
'moedelokale': '#16a085',
2026-01-31 23:16:24 +01:00
'customer_site': '#9b59b6',
'vehicle': '#8e44ad'
}.get(location.location_type, '#6c757d') %}
2026-05-06 07:01:43 +02:00
< span class = "case-type-chip" style = "--tcolor: {{ type_color }};" >
2026-01-31 23:16:24 +01:00
{{ type_label }}
< / span >
{% if location.is_active %}
2026-05-06 07:01:43 +02:00
< span class = "case-status-chip open" >
< span class = "case-status-dot" > < / span > Aktiv
< / span >
2026-01-31 23:16:24 +01:00
{% else %}
2026-05-06 07:01:43 +02:00
< span class = "case-status-chip closed" >
< span class = "case-status-dot" > < / span > Inaktiv
< / span >
2026-01-31 23:16:24 +01:00
{% endif %}
< / div >
2026-05-06 07:01:43 +02:00
< div class = "d-flex gap-2" >
< a href = "/app/locations/{{ location.id }}/edit" class = "btn btn-primary btn-sm" >
< i class = "bi bi-pencil me-2" > < / i > Rediger
< / a >
< button type = "button" class = "btn btn-outline-danger btn-sm" data-bs-toggle = "modal" data-bs-target = "#deleteModal" >
< i class = "bi bi-trash me-2" > < / i > Slet
< / button >
< a href = "/app/locations" class = "btn btn-outline-secondary btn-sm" >
< i class = "bi bi-arrow-left me-2" > < / i > Tilbage
< / a >
< / div >
2026-01-31 23:16:24 +01:00
< / div >
2026-05-06 07:01:43 +02:00
< div class = "case-hero-meta" >
< div class = "case-meta-cell" >
< div class = "hero-meta-label" > Navn< / div >
< div class = "hero-meta-value" > {{ location.name }}< / div >
< / div >
< div class = "case-meta-cell" >
< div class = "hero-meta-label" > Overordnet< / div >
{% if location.parent_location_id and location.parent_location_name %}
< a href = "/app/locations/{{ location.parent_location_id }}" class = "hero-meta-value text-decoration-none" >
{{ location.parent_location_name }}
< / a >
{% else %}
< span class = "hero-meta-value text-muted" > Ingen< / span >
{% endif %}
< / div >
< div class = "case-meta-cell" >
< div class = "hero-meta-label" > Kontakter< / div >
< div class = "hero-meta-value" > {{ location.contacts|length if location.contacts else 0 }}< / div >
< / div >
< div class = "case-meta-cell" >
< div class = "hero-meta-label" > Tjenester< / div >
< div class = "hero-meta-value" > {{ location.services|length if location.services else 0 }}< / div >
< / div >
2026-01-31 23:16:24 +01:00
< / div >
< / div >
< / div >
< / div >
<!-- Tabs Navigation -->
2026-05-06 07:01:43 +02:00
< ul class = "nav nav-tabs mb-4" id = "locationTabs" role = "tablist" >
2026-01-31 23:16:24 +01:00
< li class = "nav-item" role = "presentation" >
< button class = "nav-link active" id = "infoTab" data-bs-toggle = "tab" data-bs-target = "#infoContent" type = "button" role = "tab" aria-controls = "infoContent" aria-selected = "true" >
< i class = "bi bi-info-circle me-2" > < / i > Oplysninger
< / button >
< / li >
< li class = "nav-item" role = "presentation" >
< button class = "nav-link" id = "contactsTab" data-bs-toggle = "tab" data-bs-target = "#contactsContent" type = "button" role = "tab" aria-controls = "contactsContent" aria-selected = "false" >
< i class = "bi bi-people me-2" > < / i > Kontakter
2026-05-06 07:01:43 +02:00
< span class = "location-tab-count-badge ms-1" > {{ location.contacts|length if location.contacts else 0 }}< / span >
2026-01-31 23:16:24 +01:00
< / button >
< / li >
< li class = "nav-item" role = "presentation" >
< button class = "nav-link" id = "hoursTab" data-bs-toggle = "tab" data-bs-target = "#hoursContent" type = "button" role = "tab" aria-controls = "hoursContent" aria-selected = "false" >
< i class = "bi bi-clock me-2" > < / i > Åbningstider
< / button >
< / li >
< li class = "nav-item" role = "presentation" >
< button class = "nav-link" id = "servicesTab" data-bs-toggle = "tab" data-bs-target = "#servicesContent" type = "button" role = "tab" aria-controls = "servicesContent" aria-selected = "false" >
< i class = "bi bi-tools me-2" > < / i > Tjenester
2026-05-06 07:01:43 +02:00
< span class = "location-tab-count-badge ms-1" > {{ location.services|length if location.services else 0 }}< / span >
2026-01-31 23:16:24 +01:00
< / button >
< / li >
< li class = "nav-item" role = "presentation" >
< button class = "nav-link" id = "capacityTab" data-bs-toggle = "tab" data-bs-target = "#capacityContent" type = "button" role = "tab" aria-controls = "capacityContent" aria-selected = "false" >
< i class = "bi bi-graph-up me-2" > < / i > Kapacitet
2026-05-06 07:01:43 +02:00
< span class = "location-tab-count-badge ms-1" > {{ location.capacity|length if location.capacity else 0 }}< / span >
2026-01-31 23:16:24 +01:00
< / button >
< / li >
< li class = "nav-item" role = "presentation" >
< button class = "nav-link" id = "relationsTab" data-bs-toggle = "tab" data-bs-target = "#relationsContent" type = "button" role = "tab" aria-controls = "relationsContent" aria-selected = "false" >
< i class = "bi bi-diagram-3 me-2" > < / i > Relationer
< / button >
< / li >
< li class = "nav-item" role = "presentation" >
< button class = "nav-link" id = "hardwareTab" data-bs-toggle = "tab" data-bs-target = "#hardwareContent" type = "button" role = "tab" aria-controls = "hardwareContent" aria-selected = "false" >
< i class = "bi bi-hdd-stack me-2" > < / i > Hardware på lokation
2026-05-06 07:01:43 +02:00
< span class = "location-tab-count-badge ms-1" > {{ location.hardware|length if location.hardware else 0 }}< / span >
2026-01-31 23:16:24 +01:00
< / button >
< / li >
< li class = "nav-item" role = "presentation" >
< button class = "nav-link" id = "historyTab" data-bs-toggle = "tab" data-bs-target = "#historyContent" type = "button" role = "tab" aria-controls = "historyContent" aria-selected = "false" >
< i class = "bi bi-clock-history me-2" > < / i > Historik
< / button >
< / li >
< / ul >
<!-- Tab Content -->
< div class = "tab-content" >
<!-- Tab 1: Information -->
< div class = "tab-pane fade show active" id = "infoContent" role = "tabpanel" aria-labelledby = "infoTab" >
< div class = "row" >
< div class = "col-lg-6" >
< div class = "card border-0 mb-4" >
< div class = "card-header bg-transparent border-bottom" >
< h5 class = "card-title mb-0" > Grundlæggende oplysninger< / h5 >
< / div >
< div class = "card-body" >
< div class = "mb-3" >
< label class = "form-label text-muted small" > Navn< / label >
< p class = "fw-500" > {{ location.name }}< / p >
< / div >
< div class = "mb-3" >
< label class = "form-label text-muted small" > Type< / label >
< p class = "fw-500" > {{ type_label }}< / p >
< / div >
< div class = "mb-3" >
< label class = "form-label text-muted small" > Kunde< / label >
< p class = "fw-500" >
{% if location.customer_id and location.customer_name %}
< a href = "/customers/{{ location.customer_id }}" class = "text-decoration-none" > {{ location.customer_name }}< / a >
{% else %}
< span class = "text-muted" > —< / span >
{% endif %}
< / p >
< / div >
< div class = "mb-3" >
< label class = "form-label text-muted small" > Status< / label >
< p class = "fw-500" > {% if location.is_active %}Aktiv{% else %}Inaktiv{% endif %}< / p >
< / div >
< div class = "mb-3" >
< label class = "form-label text-muted small" > Telefon< / label >
< p class = "fw-500" >
{% if location.phone %}
< a href = "tel:{{ location.phone }}" class = "text-decoration-none" > {{ location.phone }}< / a >
{% else %}
< span class = "text-muted" > —< / span >
{% endif %}
< / p >
< / div >
< div class = "mb-3" >
< label class = "form-label text-muted small" > Email< / label >
< p class = "fw-500" >
{% if location.email %}
< a href = "mailto:{{ location.email }}" class = "text-decoration-none" > {{ location.email }}< / a >
{% else %}
< span class = "text-muted" > —< / span >
{% endif %}
< / p >
< / div >
< / div >
< / div >
< / div >
< div class = "col-lg-6" >
< div class = "card border-0 mb-4" >
< div class = "card-header bg-transparent border-bottom" >
< h5 class = "card-title mb-0" > Adresse< / h5 >
< / div >
< div class = "card-body" >
< div class = "mb-3" >
< label class = "form-label text-muted small" > Vej< / label >
< p class = "fw-500" > {{ location.address_street | default('—') }}< / p >
< / div >
< div class = "mb-3" >
< label class = "form-label text-muted small" > By< / label >
< p class = "fw-500" > {{ location.address_city | default('—') }}< / p >
< / div >
< div class = "mb-3" >
< label class = "form-label text-muted small" > Postnummer< / label >
< p class = "fw-500" > {{ location.address_postal_code | default('—') }}< / p >
< / div >
< div class = "mb-3" >
< label class = "form-label text-muted small" > Land< / label >
< p class = "fw-500" > {{ location.address_country | default('DK') }}< / p >
< / div >
< / div >
< / div >
< / div >
< / div >
< div class = "card border-0 mb-4" >
< div class = "card-header bg-transparent border-bottom" >
< h5 class = "card-title mb-0" > Noter< / h5 >
< / div >
< div class = "card-body" >
< p class = "mb-0" > {{ location.notes | default('< span class = "text-muted" > —< / span > ') }}< / p >
< / div >
< / div >
< div class = "card border-0" >
< div class = "card-header bg-transparent border-bottom" >
< h5 class = "card-title mb-0" > Metadata< / h5 >
< / div >
< div class = "card-body" >
< div class = "row" >
< div class = "col-md-6" >
< label class = "form-label text-muted small" > Oprettet< / label >
< p class = "fw-500 small" > {{ location.created_at | default('—') }}< / p >
< / div >
< div class = "col-md-6" >
< label class = "form-label text-muted small" > Sidst opdateret< / label >
< p class = "fw-500 small" > {{ location.updated_at | default('—') }}< / p >
< / div >
< / div >
< / div >
< / div >
< div class = "card border-0" >
< div class = "card-header bg-transparent border-bottom" >
< h5 class = "card-title mb-0" > Hierarki (træ)< / h5 >
< / div >
< div class = "card-body" >
{% if location.hierarchy or location.children %}
< ul class = "list-unstyled mb-0" >
{% for node in location.hierarchy %}
< li class = "mb-1" >
< i class = "bi bi-diagram-3 me-2 text-muted" > < / i >
< a href = "/app/locations/{{ node.id }}" class = "text-decoration-none" >
{{ node.name }}{% if node.location_type %} ({{ node.location_type }}){% endif %}
< / a >
< / li >
{% endfor %}
< li class = "mb-1 fw-600" >
< i class = "bi bi-pin-map me-2" > < / i > {{ location.name }}
< / li >
{% if location.children %}
< li >
< ul class = "list-unstyled ms-4 mt-2" >
{% for child in location.children %}
< li class = "mb-1" >
< i class = "bi bi-arrow-return-right me-2 text-muted" > < / i >
< a href = "/app/locations/{{ child.id }}" class = "text-decoration-none" >
{{ child.name }}{% if child.location_type %} ({{ child.location_type }}){% endif %}
< / a >
< / li >
{% endfor %}
< / ul >
< / li >
{% endif %}
< / ul >
{% else %}
< span class = "text-muted" > Ingen relationer registreret< / span >
{% endif %}
< / div >
< / div >
< / div >
<!-- Tab 2: Contacts -->
< div class = "tab-pane fade" id = "contactsContent" role = "tabpanel" aria-labelledby = "contactsTab" >
< div class = "card border-0" >
< div class = "card-header bg-transparent border-bottom d-flex justify-content-between align-items-center" >
< h5 class = "card-title mb-0" > Kontaktpersoner< / h5 >
< button type = "button" class = "btn btn-sm btn-primary" data-bs-toggle = "modal" data-bs-target = "#addContactModal" >
< i class = "bi bi-plus-lg me-2" > < / i > Tilføj kontakt
< / button >
< / div >
< div class = "card-body" >
{% if location.contacts %}
< div class = "list-group" >
{% for contact in location.contacts %}
< div class = "list-group-item" >
< div class = "d-flex justify-content-between align-items-start" >
< div class = "flex-grow-1" >
2026-05-06 07:01:43 +02:00
< h6 class = "fw-600 mb-1" >
{% if contact.related_contact_id %}
< a href = "/contacts/{{ contact.related_contact_id }}" class = "text-decoration-none" > {{ contact.contact_name }}< / a >
{% else %}
{{ contact.contact_name }}
{% endif %}
< / h6 >
2026-01-31 23:16:24 +01:00
< p class = "small text-muted mb-2" >
{% if contact.role %}{{ contact.role }}{% endif %}
{% if contact.is_primary %}< span class = "badge bg-info ms-2" > Primær< / span > {% endif %}
< / p >
{% if contact.contact_email %}
< p class = "small mb-1" > < a href = "mailto:{{ contact.contact_email }}" class = "text-decoration-none" > {{ contact.contact_email }}< / a > < / p >
{% endif %}
{% if contact.contact_phone %}
< p class = "small mb-0" > < a href = "tel:{{ contact.contact_phone }}" class = "text-decoration-none" > {{ contact.contact_phone }}< / a > < / p >
{% endif %}
< / div >
< div class = "btn-group btn-group-sm ms-3" >
< button type = "button" class = "btn btn-outline-secondary edit-contact-btn" data-contact-id = "{{ contact.id }}" >
< i class = "bi bi-pencil" > < / i >
< / button >
< button type = "button" class = "btn btn-outline-danger delete-contact-btn" data-contact-id = "{{ contact.id }}" data-contact-name = "{{ contact.contact_name }}" >
< i class = "bi bi-trash" > < / i >
< / button >
< / div >
< / div >
< / div >
{% endfor %}
< / div >
{% else %}
< p class = "text-muted text-center py-4" > Ingen kontakter registreret< / p >
{% endif %}
< / div >
< / div >
< / div >
<!-- Tab 3: Operating Hours -->
< div class = "tab-pane fade" id = "hoursContent" role = "tabpanel" aria-labelledby = "hoursTab" >
< div class = "card border-0" >
< div class = "card-header bg-transparent border-bottom" >
< h5 class = "card-title mb-0" > Åbningstider< / h5 >
< / div >
< div class = "card-body" >
{% if location.operating_hours %}
< div class = "table-responsive" >
< table class = "table table-sm mb-0" >
< thead >
< tr >
< th > Dag< / th >
< th > Åbner< / th >
< th > Lukker< / th >
< th > Status< / th >
< th style = "width: 80px;" > Handlinger< / th >
< / tr >
< / thead >
< tbody >
{% for hours in location.operating_hours %}
< tr >
< td class = "fw-500" > {{ hours.day_name }}< / td >
< td > {{ hours.open_time | default('—') }}< / td >
< td > {{ hours.close_time | default('—') }}< / td >
< td >
{% if hours.is_open %}
< span class = "badge bg-success" > Åben< / span >
{% else %}
< span class = "badge bg-secondary" > Lukket< / span >
{% endif %}
< / td >
< td >
< button type = "button" class = "btn btn-sm btn-outline-secondary edit-hours-btn" data-hours-id = "{{ hours.id }}" >
< i class = "bi bi-pencil" > < / i >
< / button >
< / td >
< / tr >
{% endfor %}
< / tbody >
< / table >
< / div >
{% else %}
< p class = "text-muted text-center py-4" > Ingen åbningstider registreret< / p >
{% endif %}
< / div >
< / div >
< / div >
<!-- Tab 4: Services -->
< div class = "tab-pane fade" id = "servicesContent" role = "tabpanel" aria-labelledby = "servicesTab" >
< div class = "card border-0" >
< div class = "card-header bg-transparent border-bottom d-flex justify-content-between align-items-center" >
< h5 class = "card-title mb-0" > Tjenester< / h5 >
< button type = "button" class = "btn btn-sm btn-primary" data-bs-toggle = "modal" data-bs-target = "#addServiceModal" >
< i class = "bi bi-plus-lg me-2" > < / i > Tilføj tjeneste
< / button >
< / div >
< div class = "card-body" >
{% if location.services %}
< div class = "list-group" >
{% for service in location.services %}
< div class = "list-group-item d-flex justify-content-between align-items-center" >
< div >
< h6 class = "fw-600 mb-0" > {{ service.service_name }}< / h6 >
< / div >
< div >
< span class = "badge {% if service.is_available %}bg-success{% else %}bg-secondary{% endif %} me-2" >
{% if service.is_available %}Tilgængelig{% else %}Ikke tilgængelig{% endif %}
< / span >
< button type = "button" class = "btn btn-sm btn-outline-danger delete-service-btn" data-service-id = "{{ service.id }}" data-service-name = "{{ service.service_name }}" >
< i class = "bi bi-trash" > < / i >
< / button >
< / div >
< / div >
{% endfor %}
< / div >
{% else %}
< p class = "text-muted text-center py-4" > Ingen tjenester registreret< / p >
{% endif %}
< / div >
< / div >
< / div >
<!-- Tab 5: Capacity -->
< div class = "tab-pane fade" id = "capacityContent" role = "tabpanel" aria-labelledby = "capacityTab" >
< div class = "card border-0" >
< div class = "card-header bg-transparent border-bottom d-flex justify-content-between align-items-center" >
< h5 class = "card-title mb-0" > Kapacitetssporing< / h5 >
< button type = "button" class = "btn btn-sm btn-primary" data-bs-toggle = "modal" data-bs-target = "#addCapacityModal" >
< i class = "bi bi-plus-lg me-2" > < / i > Tilføj kapacitet
< / button >
< / div >
< div class = "card-body" >
{% if location.capacity %}
< div class = "list-group" >
{% for cap in location.capacity %}
{% set usage_pct = ((cap.used_capacity / cap.total_capacity) * 100) | int %}
< div class = "list-group-item" >
< div class = "d-flex justify-content-between align-items-start mb-2" >
< h6 class = "fw-600 mb-0" > {{ cap.capacity_type }}< / h6 >
< span class = "small text-muted" > {{ cap.used_capacity }} / {{ cap.total_capacity }}< / span >
< / div >
< div class = "progress mb-2" style = "height: 6px;" >
< div class = "progress-bar" role = "progressbar" style = "width: {{ usage_pct }}%" aria-valuenow = "{{ usage_pct }}" aria-valuemin = "0" aria-valuemax = "100" > < / div >
< / div >
< div class = "d-flex justify-content-between align-items-center" >
< small class = "text-muted" > {{ usage_pct }}% i brug< / small >
< button type = "button" class = "btn btn-sm btn-outline-danger delete-capacity-btn" data-capacity-id = "{{ cap.id }}" data-capacity-type = "{{ cap.capacity_type }}" >
< i class = "bi bi-trash" > < / i >
< / button >
< / div >
< / div >
{% endfor %}
< / div >
{% else %}
< p class = "text-muted text-center py-4" > Ingen kapacitetsdata registreret< / p >
{% endif %}
< / div >
< / div >
< / div >
<!-- Tab 6: Relations -->
< div class = "tab-pane fade" id = "relationsContent" role = "tabpanel" aria-labelledby = "relationsTab" >
< div class = "row" >
< div class = "col-lg-6" >
< div class = "card border-0 mb-4" >
< div class = "card-header bg-transparent border-bottom" >
< h5 class = "card-title mb-0" > Overordnet lokation< / h5 >
< / div >
< div class = "card-body" >
{% if location.parent_location_id and location.parent_location_name %}
< a href = "/app/locations/{{ location.parent_location_id }}" class = "text-decoration-none" >
{{ location.parent_location_name }}
< / a >
{% else %}
< span class = "text-muted" > Ingen (øverste niveau)< / span >
{% endif %}
< / div >
< / div >
< / div >
< div class = "col-lg-6" >
< div class = "card border-0 mb-4" >
< div class = "card-header bg-transparent border-bottom" >
< h5 class = "card-title mb-0" > Underlokationer< / h5 >
< / div >
< div class = "card-body" >
{% if location.children %}
< ul class = "list-unstyled mb-0" >
{% for child in location.children %}
< li class = "mb-2" >
< a href = "/app/locations/{{ child.id }}" class = "text-decoration-none" >
{{ child.name }}{% if child.location_type %} ({{ child.location_type }}){% endif %}
< / a >
< / li >
{% endfor %}
< / ul >
{% else %}
< span class = "text-muted" > Ingen underlokationer< / span >
{% endif %}
< / div >
< / div >
< div class = "card border-0" >
< div class = "card-header bg-transparent border-bottom" >
2026-07-17 01:58:02 +02:00
< div class = "d-flex justify-content-between align-items-center gap-2 flex-wrap" >
< h5 class = "card-title mb-0" > Tilføj underlokation< / h5 >
< a href = "/app/locations/create?parent_location_id={{ location.id }}{% if location.customer_id %}&customer_id={{ location.customer_id }}{% endif %}" class = "btn btn-outline-primary btn-sm" >
< i class = "bi bi-box-arrow-up-right me-1" > < / i > Fuld formular
< / a >
< / div >
2026-01-31 23:16:24 +01:00
< / div >
< div class = "card-body" >
2026-07-17 01:58:02 +02:00
< p class = "text-muted small mb-3" > Den hurtige formular opretter direkte under < strong > {{ location.name }}< / strong > . Brug fuld formular, hvis du også vil sætte adresse, noter eller GPS med det samme.< / p >
2026-01-31 23:16:24 +01:00
< form action = "/api/v1/locations" method = "post" class = "row g-2" >
< input type = "hidden" name = "parent_location_id" value = "{{ location.id }}" >
< input type = "hidden" name = "redirect_to" value = "/app/locations/{id}" >
< input type = "hidden" name = "is_active" value = "on" >
< div class = "col-12" >
< label class = "form-label small text-muted" for = "childName" > Navn *< / label >
< input type = "text" class = "form-control" id = "childName" name = "name" required maxlength = "255" placeholder = "f.eks. Bygning A, 1 sal, Møderum 1" >
< / div >
< div class = "col-12" >
< label class = "form-label small text-muted" for = "childType" > Type *< / label >
< select class = "form-select" id = "childType" name = "location_type" required >
< option value = "" > Vælg type< / option >
{% if location_types %}
{% for type_option in location_types %}
{% set option_value = type_option['value'] if type_option is mapping else type_option %}
{% set option_label = type_option['label'] if type_option is mapping else type_option %}
< option value = "{{ option_value }}" >
2026-02-09 15:30:07 +01:00
{% if option_value == 'kompleks' %}Kompleks{% elif option_value == 'bygning' %}Bygning{% elif option_value == 'etage' %}Etage{% elif option_value == 'customer_site' %}Kundesite{% elif option_value == 'rum' %}Rum{% elif option_value == 'kantine' %}Kantine{% elif option_value == 'moedelokale' %}Mødelokale{% elif option_value == 'vehicle' %}Køretøj{% else %}{{ option_label }}{% endif %}
2026-01-31 23:16:24 +01:00
< / option >
{% endfor %}
{% endif %}
< / select >
< / div >
< div class = "col-12" >
< label class = "form-label small text-muted" for = "childCustomer" > Kunde (valgfri)< / label >
< select class = "form-select" id = "childCustomer" name = "customer_id" >
< option value = "" > Ingen< / option >
{% if customers %}
{% for customer in customers %}
2026-07-17 01:58:02 +02:00
< option value = "{{ customer.id }}" { % if location . customer_id = = customer . id % } selected { % endif % } > {{ customer.name }}< / option >
2026-01-31 23:16:24 +01:00
{% endfor %}
{% endif %}
< / select >
< / div >
< div class = "col-12 d-flex justify-content-end" >
< button type = "submit" class = "btn btn-sm btn-primary" >
< i class = "bi bi-plus-lg me-1" > < / i > Opret
< / button >
< / div >
< / form >
< / div >
< / div >
< / div >
< / div >
< div class = "card border-0 mt-4" >
< div class = "card-header bg-transparent border-bottom" >
< h5 class = "card-title mb-0" > Hierarki (træ)< / h5 >
< / div >
< div class = "card-body" >
{% if location.hierarchy or location.children %}
< ul class = "list-unstyled mb-0" >
{% for node in location.hierarchy %}
< li class = "mb-1" >
< i class = "bi bi-diagram-3 me-2 text-muted" > < / i >
< a href = "/app/locations/{{ node.id }}" class = "text-decoration-none" >
{{ node.name }}{% if node.location_type %} ({{ node.location_type }}){% endif %}
< / a >
< / li >
{% endfor %}
< li class = "mb-1 fw-600" >
< i class = "bi bi-pin-map me-2" > < / i > {{ location.name }}
< / li >
{% if location.children %}
< li >
< ul class = "list-unstyled ms-4 mt-2" >
{% for child in location.children %}
< li class = "mb-1" >
< i class = "bi bi-arrow-return-right me-2 text-muted" > < / i >
< a href = "/app/locations/{{ child.id }}" class = "text-decoration-none" >
{{ child.name }}{% if child.location_type %} ({{ child.location_type }}){% endif %}
< / a >
< / li >
{% endfor %}
< / ul >
< / li >
{% endif %}
< / ul >
{% else %}
< span class = "text-muted" > Ingen relationer registreret< / span >
{% endif %}
< / div >
< / div >
< / div >
<!-- Tab 7: Hardware -->
< div class = "tab-pane fade" id = "hardwareContent" role = "tabpanel" aria-labelledby = "hardwareTab" >
< div class = "card border-0" >
< div class = "card-header bg-transparent border-bottom" >
< h5 class = "card-title mb-0" > Hardware på lokation< / h5 >
< / div >
< div class = "card-body" >
{% if location.hardware %}
< div class = "list-group" >
{% for hw in location.hardware %}
< div class = "list-group-item d-flex justify-content-between align-items-center" >
< div >
< div class = "fw-600" > {{ hw.brand }} {{ hw.model }}< / div >
< div class = "text-muted small" > {{ hw.asset_type }}{% if hw.serial_number %} · {{ hw.serial_number }}{% endif %}< / div >
< / div >
< span class = "badge bg-secondary" > {{ hw.status }}< / span >
< / div >
{% endfor %}
< / div >
{% else %}
< span class = "text-muted" > Ingen hardware registreret på denne lokation< / span >
{% endif %}
< / div >
< / div >
< / div >
<!-- Tab 8: History -->
< div class = "tab-pane fade" id = "historyContent" role = "tabpanel" aria-labelledby = "historyTab" >
< div class = "card border-0" >
< div class = "card-header bg-transparent border-bottom" >
< h5 class = "card-title mb-0" > Ændringshistorik< / h5 >
< / div >
< div class = "card-body" >
{% if location.audit_log %}
< div class = "timeline" >
{% for entry in location.audit_log | reverse %}
< div class = "timeline-item mb-3 pb-3 border-bottom" >
< div class = "d-flex gap-3" >
< div class = "timeline-marker" >
< i class = "bi bi-circle-fill small" style = "color: var(--accent);" > < / i >
< / div >
< div class = "flex-grow-1" >
< div class = "d-flex justify-content-between align-items-start" >
< div >
< h6 class = "fw-600 mb-1" > {{ entry.event_type }}< / h6 >
< p class = "small text-muted mb-1" > {{ entry.created_at }}< / p >
< / div >
{% if entry.user_id %}
< span class = "badge bg-light text-dark small" > {{ entry.user_id }}< / span >
{% endif %}
< / div >
{% if entry.changes %}
< p class = "small mb-0" > < code style = "font-size: 11px;" > {{ entry.changes }}< / code > < / p >
{% endif %}
< / div >
< / div >
< / div >
{% endfor %}
< / div >
{% else %}
< p class = "text-muted text-center py-4" > Ingen historik tilgængelig< / p >
{% endif %}
< / div >
< / div >
< / div >
< / div >
< / div >
<!-- Add Contact Modal -->
< div class = "modal fade" id = "addContactModal" tabindex = "-1" aria-hidden = "true" >
< div class = "modal-dialog" >
< div class = "modal-content" >
< div class = "modal-header border-bottom-0" >
< h5 class = "modal-title" > Tilføj kontaktperson< / h5 >
< button type = "button" class = "btn-close" data-bs-dismiss = "modal" aria-label = "Luk" > < / button >
< / div >
< form id = "addContactForm" >
< div class = "modal-body" >
< div class = "mb-3" >
2026-05-06 07:01:43 +02:00
< label for = "existingContactSearch" class = "form-label" > Søg eksisterende kontakt< / label >
< input type = "text" class = "form-control" id = "existingContactSearch" placeholder = "Skriv navn, email eller telefon..." >
< div class = "form-text" > Vælg en eksisterende kontakt for at udfylde felterne automatisk.< / div >
< div id = "existingContactResults" class = "list-group mt-2 d-none" style = "max-height: 220px; overflow-y: auto;" > < / div >
2026-01-31 23:16:24 +01:00
< / div >
2026-05-06 07:01:43 +02:00
< div id = "selectedExistingContact" class = "alert alert-info py-2 px-3 d-none" role = "alert" >
< div class = "d-flex justify-content-between align-items-center" >
< span id = "selectedExistingContactText" class = "small mb-0" > < / span >
< button type = "button" class = "btn btn-link btn-sm p-0" id = "clearExistingContactBtn" > Fjern< / button >
< / div >
2026-01-31 23:16:24 +01:00
< / div >
2026-05-06 07:01:43 +02:00
< input type = "hidden" id = "existingContactId" value = "" >
2026-01-31 23:16:24 +01:00
< div class = "mb-3" >
2026-05-06 07:01:43 +02:00
< label class = "form-label" > Kontaktoplysninger< / label >
< div class = "form-control-plaintext small text-muted" id = "selectedContactMeta" > Vælg en kontakt for at se email og telefon.< / div >
2026-01-31 23:16:24 +01:00
< / div >
< div class = "mb-3" >
< label for = "contactRole" class = "form-label" > Rolle< / label >
< input type = "text" class = "form-control" id = "contactRole" >
< / div >
< div class = "form-check" >
< input class = "form-check-input" type = "checkbox" id = "isPrimaryContact" >
< label class = "form-check-label" for = "isPrimaryContact" > Sæt som primær kontakt< / label >
< / div >
< / div >
< div class = "modal-footer border-top-0" >
< button type = "button" class = "btn btn-outline-secondary btn-sm" data-bs-dismiss = "modal" > Annuller< / button >
< button type = "submit" class = "btn btn-primary btn-sm" > Tilføj< / button >
< / div >
< / form >
< / div >
< / div >
< / div >
<!-- Add Service Modal -->
< div class = "modal fade" id = "addServiceModal" tabindex = "-1" aria-hidden = "true" >
< div class = "modal-dialog" >
< div class = "modal-content" >
< div class = "modal-header border-bottom-0" >
< h5 class = "modal-title" > Tilføj tjeneste< / h5 >
< button type = "button" class = "btn-close" data-bs-dismiss = "modal" aria-label = "Luk" > < / button >
< / div >
< form id = "addServiceForm" >
< div class = "modal-body" >
< div class = "mb-3" >
< label for = "serviceName" class = "form-label" > Tjeneste *< / label >
< input type = "text" class = "form-control" id = "serviceName" required >
< / div >
< div class = "form-check" >
< input class = "form-check-input" type = "checkbox" id = "serviceAvailable" checked >
< label class = "form-check-label" for = "serviceAvailable" > Tilgængelig< / label >
< / div >
< / div >
< div class = "modal-footer border-top-0" >
< button type = "button" class = "btn btn-outline-secondary btn-sm" data-bs-dismiss = "modal" > Annuller< / button >
< button type = "submit" class = "btn btn-primary btn-sm" > Tilføj< / button >
< / div >
< / form >
< / div >
< / div >
< / div >
<!-- Add Capacity Modal -->
< div class = "modal fade" id = "addCapacityModal" tabindex = "-1" aria-hidden = "true" >
< div class = "modal-dialog" >
< div class = "modal-content" >
< div class = "modal-header border-bottom-0" >
< h5 class = "modal-title" > Tilføj kapacitet< / h5 >
< button type = "button" class = "btn-close" data-bs-dismiss = "modal" aria-label = "Luk" > < / button >
< / div >
< form id = "addCapacityForm" >
< div class = "modal-body" >
< div class = "mb-3" >
< label for = "capacityType" class = "form-label" > Type *< / label >
< input type = "text" class = "form-control" id = "capacityType" required >
< / div >
< div class = "mb-3" >
< label for = "totalCapacity" class = "form-label" > Total kapacitet *< / label >
< input type = "number" class = "form-control" id = "totalCapacity" min = "1" required >
< / div >
< div class = "mb-3" >
< label for = "usedCapacity" class = "form-label" > Brugt kapacitet< / label >
< input type = "number" class = "form-control" id = "usedCapacity" min = "0" >
< / div >
< / div >
< div class = "modal-footer border-top-0" >
< button type = "button" class = "btn btn-outline-secondary btn-sm" data-bs-dismiss = "modal" > Annuller< / button >
< button type = "submit" class = "btn btn-primary btn-sm" > Tilføj< / button >
< / div >
< / form >
< / div >
< / div >
< / div >
<!-- Delete Confirmation Modal -->
< div class = "modal fade" id = "deleteModal" tabindex = "-1" aria-hidden = "true" >
< div class = "modal-dialog modal-dialog-centered" >
< div class = "modal-content" >
< div class = "modal-header border-bottom-0" >
< h5 class = "modal-title" > Slet lokation?< / h5 >
< button type = "button" class = "btn-close" data-bs-dismiss = "modal" aria-label = "Luk" > < / button >
< / div >
< div class = "modal-body" >
< p class = "mb-0" > Er du sikker på, at du vil slette < strong > {{ location.name }}< / strong > ?< / p >
< p class = "text-muted small mt-2" > Denne handling kan ikke fortrydes. Lokationen vil blive soft-deleted og kan gendannes af en administrator.< / p >
< / div >
< div class = "modal-footer border-top-0" >
< button type = "button" class = "btn btn-outline-secondary btn-sm" data-bs-dismiss = "modal" > Annuller< / button >
< button type = "button" class = "btn btn-danger btn-sm" id = "confirmDeleteBtn" >
< i class = "bi bi-trash me-2" > < / i > Slet
< / button >
< / div >
< / div >
< / div >
< / div >
{% endblock %}
{% block scripts %}
< script >
document.addEventListener('DOMContentLoaded', function() {
const deleteModal = new bootstrap.Modal(document.getElementById('deleteModal'));
const locationId = '{{ location.id }}';
2026-05-06 07:01:43 +02:00
const existingContactSearchInput = document.getElementById('existingContactSearch');
const existingContactResultsContainer = document.getElementById('existingContactResults');
const existingContactIdInput = document.getElementById('existingContactId');
const selectedExistingContactAlert = document.getElementById('selectedExistingContact');
const selectedExistingContactText = document.getElementById('selectedExistingContactText');
const selectedContactMeta = document.getElementById('selectedContactMeta');
const clearExistingContactBtn = document.getElementById('clearExistingContactBtn');
const contactRoleInput = document.getElementById('contactRole');
const addContactModalElement = document.getElementById('addContactModal');
const addContactForm = document.getElementById('addContactForm');
const addContactSubmitBtn = addContactForm?.querySelector('button[type="submit"]');
let existingContactResults = [];
let contactSearchDebounceTimer = null;
let isSavingContact = false;
function clearExistingContactSelection() {
existingContactIdInput.value = '';
selectedExistingContactText.textContent = '';
selectedExistingContactAlert.classList.add('d-none');
selectedContactMeta.textContent = 'Vælg en kontakt for at se email og telefon.';
}
function hideExistingContactResults() {
existingContactResults = [];
existingContactResultsContainer.innerHTML = '';
existingContactResultsContainer.classList.add('d-none');
}
function buildFullName(contact) {
const firstName = (contact.first_name || '').trim();
const lastName = (contact.last_name || '').trim();
return `${firstName} ${lastName}`.trim();
}
function selectExistingContact(contact) {
const fullName = buildFullName(contact);
const email = contact.email || '';
const phone = contact.mobile || contact.phone || '';
existingContactIdInput.value = String(contact.id || '');
selectedExistingContactText.textContent = `Valgt: ${fullName || 'Kontakt'} (ID: ${contact.id})`;
selectedExistingContactAlert.classList.remove('d-none');
selectedContactMeta.textContent = `${email || 'Ingen email'} • ${phone || 'Ingen telefon'}`;
hideExistingContactResults();
existingContactSearchInput.value = fullName;
}
function renderExistingContactResults(results) {
if (!results || !results.length) {
hideExistingContactResults();
return;
}
existingContactResults = results;
existingContactResultsContainer.innerHTML = results.map((contact, index) => {
const fullName = buildFullName(contact) || `Kontakt #${contact.id}`;
const secondaryInfo = [contact.email, contact.mobile || contact.phone, contact.user_company]
.filter(Boolean)
.join(' • ');
return `
< button type = "button" class = "list-group-item list-group-item-action existing-contact-result" data-index = "${index}" >
< div class = "fw-500" > ${fullName}< / div >
< div class = "small text-muted" > ${secondaryInfo || 'Ingen ekstra info'}< / div >
< / button >
`;
}).join('');
existingContactResultsContainer.classList.remove('d-none');
}
async function searchExistingContacts(term) {
if (!term || term.trim().length < 2 ) {
hideExistingContactResults();
return;
}
try {
const response = await fetch(`/api/v1/search/contacts?q=${encodeURIComponent(term.trim())}`);
if (!response.ok) {
hideExistingContactResults();
return;
}
const contacts = await response.json();
renderExistingContactResults(contacts || []);
} catch (error) {
console.error('Error searching contacts:', error);
hideExistingContactResults();
}
}
existingContactSearchInput.addEventListener('input', function(e) {
const term = e.target.value;
if (contactSearchDebounceTimer) {
clearTimeout(contactSearchDebounceTimer);
}
contactSearchDebounceTimer = setTimeout(() => {
searchExistingContacts(term);
}, 220);
});
existingContactResultsContainer.addEventListener('click', function(e) {
const button = e.target.closest('.existing-contact-result');
if (!button) return;
const index = Number(button.dataset.index);
const selectedContact = existingContactResults[index];
if (selectedContact) {
selectExistingContact(selectedContact);
}
});
clearExistingContactBtn.addEventListener('click', function() {
clearExistingContactSelection();
existingContactSearchInput.value = '';
hideExistingContactResults();
});
addContactModalElement.addEventListener('hidden.bs.modal', function() {
hideExistingContactResults();
clearExistingContactSelection();
existingContactSearchInput.value = '';
});
2026-01-31 23:16:24 +01:00
// Delete location
document.getElementById('confirmDeleteBtn').addEventListener('click', function() {
fetch(`/api/v1/locations/${locationId}`, {
method: 'DELETE',
headers: { 'Content-Type': 'application/json' }
})
.then(response => {
if (response.ok) {
deleteModal.hide();
setTimeout(() => window.location.href = '/app/locations', 300);
} else {
alert('Fejl ved sletning af lokation');
}
})
.catch(error => {
console.error('Error:', error);
alert('Fejl ved sletning af lokation');
});
});
// Add contact form
2026-05-06 07:01:43 +02:00
addContactForm.addEventListener('submit', function(e) {
2026-01-31 23:16:24 +01:00
e.preventDefault();
2026-05-06 07:01:43 +02:00
if (isSavingContact) {
return;
}
if (!existingContactIdInput.value) {
alert('Vælg en eksisterende kontakt fra søgningen før du gemmer.');
return;
}
isSavingContact = true;
if (addContactSubmitBtn) {
addContactSubmitBtn.disabled = true;
addContactSubmitBtn.textContent = 'Gemmer...';
}
2026-01-31 23:16:24 +01:00
const contactData = {
location_id: locationId,
2026-05-06 07:01:43 +02:00
role: contactRoleInput.value,
existing_contact_id: existingContactIdInput.value ? parseInt(existingContactIdInput.value, 10) : null,
2026-01-31 23:16:24 +01:00
is_primary: document.getElementById('isPrimaryContact').checked
};
fetch(`/api/v1/locations/${locationId}/contacts`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(contactData)
})
2026-05-06 07:01:43 +02:00
.then(async response => {
2026-01-31 23:16:24 +01:00
if (response.ok) {
bootstrap.Modal.getInstance(document.getElementById('addContactModal')).hide();
setTimeout(() => location.reload(), 300);
2026-05-06 07:01:43 +02:00
return;
}
let detail = 'Fejl ved gem af kontaktlink';
try {
const payload = await response.json();
if (payload & & payload.detail) {
detail = String(payload.detail);
}
} catch (e) {
// ignore parse errors and keep default message
2026-01-31 23:16:24 +01:00
}
2026-05-06 07:01:43 +02:00
alert(detail);
2026-01-31 23:16:24 +01:00
})
2026-05-06 07:01:43 +02:00
.catch(error => {
console.error('Error:', error);
alert('Netværksfejl ved gem af kontaktlink');
})
.finally(() => {
isSavingContact = false;
if (addContactSubmitBtn) {
addContactSubmitBtn.disabled = false;
addContactSubmitBtn.textContent = 'Tilføj';
}
});
2026-01-31 23:16:24 +01:00
});
// Add service form
document.getElementById('addServiceForm').addEventListener('submit', function(e) {
e.preventDefault();
const serviceData = {
location_id: locationId,
service_name: document.getElementById('serviceName').value,
is_available: document.getElementById('serviceAvailable').checked
};
fetch(`/api/v1/locations/${locationId}/services`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(serviceData)
})
.then(response => {
if (response.ok) {
bootstrap.Modal.getInstance(document.getElementById('addServiceModal')).hide();
setTimeout(() => location.reload(), 300);
}
})
.catch(error => console.error('Error:', error));
});
// Add capacity form
document.getElementById('addCapacityForm').addEventListener('submit', function(e) {
e.preventDefault();
const capacityData = {
location_id: locationId,
capacity_type: document.getElementById('capacityType').value,
total_capacity: parseInt(document.getElementById('totalCapacity').value),
used_capacity: parseInt(document.getElementById('usedCapacity').value) || 0
};
fetch(`/api/v1/locations/${locationId}/capacity`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(capacityData)
})
.then(response => {
if (response.ok) {
bootstrap.Modal.getInstance(document.getElementById('addCapacityModal')).hide();
setTimeout(() => location.reload(), 300);
}
})
.catch(error => console.error('Error:', error));
});
// Delete buttons
document.querySelectorAll('.delete-contact-btn').forEach(btn => {
btn.addEventListener('click', function() {
const contactId = this.dataset.contactId;
const contactName = this.dataset.contactName;
if (confirm(`Slet kontakt: ${contactName}?`)) {
fetch(`/api/v1/locations/${locationId}/contacts/${contactId}`, { method: 'DELETE' })
.then(response => {
if (response.ok) location.reload();
});
}
});
});
document.querySelectorAll('.delete-service-btn').forEach(btn => {
btn.addEventListener('click', function() {
const serviceId = this.dataset.serviceId;
const serviceName = this.dataset.serviceName;
if (confirm(`Slet tjeneste: ${serviceName}?`)) {
fetch(`/api/v1/locations/${locationId}/services/${serviceId}`, { method: 'DELETE' })
.then(response => {
if (response.ok) location.reload();
});
}
});
});
document.querySelectorAll('.delete-capacity-btn').forEach(btn => {
btn.addEventListener('click', function() {
const capacityId = this.dataset.capacityId;
const capacityType = this.dataset.capacityType;
if (confirm(`Slet kapacitet: ${capacityType}?`)) {
fetch(`/api/v1/locations/${locationId}/capacity/${capacityId}`, { method: 'DELETE' })
.then(response => {
if (response.ok) location.reload();
});
}
});
});
});
< / script >
{% endblock %}