Feat: expands project reservation system.

-Reservation list view
-expandable project cards
This commit is contained in:
2026-03-15 05:25:23 +00:00
parent e4d1f0d684
commit 0e3f512203
3 changed files with 71 additions and 48 deletions

View File

@@ -6,12 +6,13 @@
{% set card_id = "res-card-" ~ res.id %}
{% set detail_id = "res-detail-" ~ res.id %}
<div class="rounded-lg border border-gray-200 dark:border-gray-700 overflow-hidden"
<div class="rounded-lg border border-gray-200 dark:border-gray-700"
style="border-left: 4px solid {{ res.color }};">
<!-- Header row (always visible, clickable) -->
<div class="res-card-header flex items-center justify-between p-4 cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-700/50 transition-colors select-none"
data-res-id="{{ res.id }}">
data-res-id="{{ res.id }}"
onclick="toggleResCard('{{ res.id }}')">
<div class="flex-1 min-w-0">
<div class="flex items-center gap-2 flex-wrap">
@@ -59,30 +60,30 @@
</div>
<!-- Action buttons (stop propagation so clicks don't toggle card) -->
<div class="flex items-center gap-1 flex-shrink-0" onclick="event.stopPropagation(); event.preventDefault();">
<button onclick="openPlanner('{{ res.id }}')"
<div class="flex items-center gap-1 flex-shrink-0">
<button onclick="event.stopPropagation(); openPlanner('{{ res.id }}')"
class="p-2 text-gray-400 hover:text-green-600 dark:hover:text-green-400 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700"
title="Plan units">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-3 7h3m-3 4h3m-6-4h.01M9 16h.01"/>
</svg>
</button>
<button onclick="editReservation('{{ res.id }}')"
<button onclick="event.stopPropagation(); editReservation('{{ res.id }}')"
class="p-2 text-gray-400 hover:text-blue-600 dark:hover:text-blue-400 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700"
title="Edit">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"/>
</svg>
</button>
<button onclick="deleteReservation('{{ res.id }}', '{{ res.name }}')"
<button onclick="event.stopPropagation(); deleteReservation('{{ res.id }}', '{{ res.name }}')"
class="p-2 text-gray-400 hover:text-red-600 dark:hover:text-red-400 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700"
title="Delete">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/>
</svg>
</button>
<!-- Chevron -->
<svg id="chevron-{{ res.id }}" class="w-4 h-4 text-gray-400 transition-transform duration-200 ml-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<!-- Chevron (not in stopPropagation zone so clicking it still toggles the card) -->
<svg id="chevron-{{ res.id }}" class="w-4 h-4 text-gray-400 transition-transform duration-200 ml-1 pointer-events-none" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
</svg>
</div>
@@ -116,23 +117,28 @@
<p class="text-xs font-semibold uppercase tracking-wide text-gray-400 dark:text-gray-500 mb-2">Monitoring Locations</p>
<div class="flex flex-col gap-1">
{% for u in item.assigned_units %}
<div class="flex items-center gap-3 px-3 py-1.5 rounded bg-white dark:bg-slate-700 border border-gray-100 dark:border-gray-600 text-sm">
<span class="text-gray-400 dark:text-gray-500 text-xs w-12 flex-shrink-0">Loc. {{ loop.index }}</span>
<button onclick="openUnitDetailModal('{{ u.id }}')"
class="font-medium text-blue-600 dark:text-blue-400 hover:underline">{{ u.id }}</button>
<span class="flex-1"></span>
{% if u.power_type == 'ac' %}
<span class="text-xs px-1.5 py-0.5 bg-blue-50 dark:bg-blue-900/20 text-blue-600 dark:text-blue-400 rounded">A/C</span>
{% elif u.power_type == 'solar' %}
<span class="text-xs px-1.5 py-0.5 bg-yellow-50 dark:bg-yellow-900/20 text-yellow-600 dark:text-yellow-400 rounded">Solar</span>
{% endif %}
{% if u.deployed %}
<span class="text-xs px-1.5 py-0.5 bg-green-50 dark:bg-green-900/20 text-green-600 dark:text-green-400 rounded">Deployed</span>
{% else %}
<span class="text-xs px-1.5 py-0.5 bg-gray-100 dark:bg-gray-600 text-gray-500 dark:text-gray-400 rounded">Benched</span>
{% endif %}
{% if u.last_calibrated %}
<span class="text-xs text-gray-400 dark:text-gray-500">Cal: {{ u.last_calibrated.strftime('%b %d, %Y') }}</span>
<div class="rounded bg-white dark:bg-slate-700 border border-gray-100 dark:border-gray-600 text-sm">
<div class="flex items-center gap-3 px-3 py-1.5">
<span class="text-gray-400 dark:text-gray-500 text-xs w-12 flex-shrink-0">Loc. {{ loop.index }}</span>
<button onclick="openUnitDetailModal('{{ u.id }}')"
class="font-medium text-blue-600 dark:text-blue-400 hover:underline">{{ u.id }}</button>
<span class="flex-1"></span>
{% if u.power_type == 'ac' %}
<span class="text-xs px-1.5 py-0.5 bg-blue-50 dark:bg-blue-900/20 text-blue-600 dark:text-blue-400 rounded">A/C</span>
{% elif u.power_type == 'solar' %}
<span class="text-xs px-1.5 py-0.5 bg-yellow-50 dark:bg-yellow-900/20 text-yellow-600 dark:text-yellow-400 rounded">Solar</span>
{% endif %}
{% if u.deployed %}
<span class="text-xs px-1.5 py-0.5 bg-green-50 dark:bg-green-900/20 text-green-600 dark:text-green-400 rounded">Deployed</span>
{% else %}
<span class="text-xs px-1.5 py-0.5 bg-gray-100 dark:bg-gray-600 text-gray-500 dark:text-gray-400 rounded">Benched</span>
{% endif %}
{% if u.last_calibrated %}
<span class="text-xs text-gray-400 dark:text-gray-500">Cal: {{ u.last_calibrated.strftime('%b %d, %Y') }}</span>
{% endif %}
</div>
{% if u.notes %}
<p class="px-3 pb-1.5 text-xs text-gray-400 dark:text-gray-500 italic">{{ u.notes }}</p>
{% endif %}
</div>
{% endfor %}