2026-01-31 23:16:24 +01:00
|
|
|
{% extends "shared/frontend/base.html" %}
|
|
|
|
|
|
|
|
|
|
{% block title %}{{ location.name }} - BMC Hub{% endblock %}
|
|
|
|
|
|
|
|
|
|
{% block content %}
|
|
|
|
|
<div class="container-fluid px-4 py-4">
|
|
|
|
|
<!-- 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">
|
|
|
|
|
<div class="d-flex justify-content-between align-items-start mb-3">
|
|
|
|
|
<div>
|
|
|
|
|
<h1 class="h2 fw-700 mb-2">{{ location.name }}</h1>
|
|
|
|
|
{% if location.hierarchy %}
|
|
|
|
|
<nav aria-label="breadcrumb" class="mb-2">
|
|
|
|
|
<ol class="breadcrumb mb-0">
|
|
|
|
|
{% for node in location.hierarchy %}
|
|
|
|
|
<li class="breadcrumb-item">
|
|
|
|
|
<a href="/app/locations/{{ node.id }}" class="text-decoration-none">
|
|
|
|
|
{{ node.name }}
|
|
|
|
|
</a>
|
|
|
|
|
</li>
|
|
|
|
|
{% endfor %}
|
|
|
|
|
<li class="breadcrumb-item active" aria-current="page">{{ location.name }}</li>
|
|
|
|
|
</ol>
|
|
|
|
|
</nav>
|
|
|
|
|
{% endif %}
|
|
|
|
|
<div class="d-flex gap-2 align-items-center">
|
|
|
|
|
{% 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') %}
|
|
|
|
|
|
|
|
|
|
<span class="badge" style="background-color: {{ type_color }}; color: white;">
|
|
|
|
|
{{ type_label }}
|
|
|
|
|
</span>
|
|
|
|
|
{% if location.parent_location_id and location.parent_location_name %}
|
|
|
|
|
<span class="text-muted small">
|
|
|
|
|
<i class="bi bi-diagram-3 me-1"></i>
|
|
|
|
|
<a href="/app/locations/{{ location.parent_location_id }}" class="text-decoration-none">
|
|
|
|
|
{{ location.parent_location_name }}
|
|
|
|
|
</a>
|
|
|
|
|
</span>
|
|
|
|
|
{% endif %}
|
|
|
|
|
{% if location.is_active %}
|
|
|
|
|
<span class="badge bg-success">Aktiv</span>
|
|
|
|
|
{% else %}
|
|
|
|
|
<span class="badge bg-secondary">Inaktiv</span>
|
|
|
|
|
{% endif %}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<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>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Tabs Navigation -->
|
|
|
|
|
<ul class="nav nav-tabs mb-4" role="tablist">
|
|
|
|
|
<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
|
|
|
|
|
</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
|
|
|
|
|
</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
|
|
|
|
|
</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
|
|
|
|
|
</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">
|
|
|
|
|
<h6 class="fw-600 mb-1">{{ contact.contact_name }}</h6>
|
|
|
|
|
<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">
|
|
|
|
|
<h5 class="card-title mb-0">Tilføj underlokation</h5>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="card-body">
|
|
|
|
|
<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 %}
|
|
|
|
|
<option value="{{ customer.id }}">{{ customer.name }}</option>
|
|
|
|
|
{% 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">
|
|
|
|
|
<label for="contactName" class="form-label">Navn *</label>
|
|
|
|
|
<input type="text" class="form-control" id="contactName" required>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="mb-3">
|
|
|
|
|
<label for="contactEmail" class="form-label">Email</label>
|
|
|
|
|
<input type="email" class="form-control" id="contactEmail">
|
|
|
|
|
</div>
|
|
|
|
|
<div class="mb-3">
|
|
|
|
|
<label for="contactPhone" class="form-label">Telefon</label>
|
|
|
|
|
<input type="tel" class="form-control" id="contactPhone">
|
|
|
|
|
</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 }}';
|
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
document.getElementById('addContactForm').addEventListener('submit', function(e) {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
const contactData = {
|
|
|
|
|
location_id: locationId,
|
|
|
|
|
contact_name: document.getElementById('contactName').value,
|
|
|
|
|
contact_email: document.getElementById('contactEmail').value,
|
|
|
|
|
contact_phone: document.getElementById('contactPhone').value,
|
|
|
|
|
role: document.getElementById('contactRole').value,
|
|
|
|
|
is_primary: document.getElementById('isPrimaryContact').checked
|
|
|
|
|
};
|
|
|
|
|
fetch(`/api/v1/locations/${locationId}/contacts`, {
|
|
|
|
|
method: 'POST',
|
|
|
|
|
headers: { 'Content-Type': 'application/json' },
|
|
|
|
|
body: JSON.stringify(contactData)
|
|
|
|
|
})
|
|
|
|
|
.then(response => {
|
|
|
|
|
if (response.ok) {
|
|
|
|
|
bootstrap.Modal.getInstance(document.getElementById('addContactModal')).hide();
|
|
|
|
|
setTimeout(() => location.reload(), 300);
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.catch(error => console.error('Error:', error));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 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 %}
|