details for the admin

This commit is contained in:
Priec
2026-05-16 15:11:58 +02:00
parent 231b11b8b3
commit 40ee4cf398
4 changed files with 97 additions and 10 deletions

View File

@@ -52,3 +52,4 @@ theme-dark = Dark
settings = Settings settings = Settings
settings-language = Language settings-language = Language
settings-theme = Theme settings-theme = Theme
view-details = Details

View File

@@ -52,3 +52,4 @@ theme-dark = Tmavý
settings = Nastavenia settings = Nastavenia
settings-language = Jazyk settings-language = Jazyk
settings-theme = Téma settings-theme = Téma
view-details = Detaily

View File

@@ -2,6 +2,37 @@
{% block title %}{{ t(key="calendar-title", lang=lang) }}{% endblock title %} {% block title %}{{ t(key="calendar-title", lang=lang) }}{% endblock title %}
{% block head %}
{% if is_admin %}
<style>
/* Admin calendar — detailed-view toggle. The public calendar is unaffected. */
.cal-detail { display: none; }
#cal.cal--detailed .cal-chip {
position: static;
inset: auto;
margin: 0.25rem;
min-height: 3rem;
flex-direction: column;
align-items: stretch;
justify-content: center;
}
#cal.cal--detailed .cal-name {
white-space: normal;
font-weight: 600;
}
#cal.cal--detailed .cal-detail {
display: flex;
flex-direction: column;
gap: 1px;
margin-top: 2px;
font-weight: 400;
line-height: 1.25;
overflow-wrap: anywhere;
}
</style>
{% endif %}
{% endblock head %}
{% block content %} {% block content %}
<div class="mb-4 flex flex-wrap items-center justify-between gap-3"> <div class="mb-4 flex flex-wrap items-center justify-between gap-3">
<h1 class="text-2xl font-bold"> <h1 class="text-2xl font-bold">
@@ -22,19 +53,32 @@
{% if has_courts %} {% if has_courts %}
<div class="mb-3 flex flex-wrap items-center justify-between gap-2"> <div class="mb-3 flex flex-wrap items-center justify-between gap-2">
<div class="join"> <div class="flex flex-wrap items-center gap-2">
<a href="{{ base_path }}?court={{ court_id }}&week={{ prev_week }}" <div class="join">
class="btn btn-sm join-item">« {{ t(key="prev-week", lang=lang) }}</a> <a href="{{ base_path }}?court={{ court_id }}&week={{ prev_week }}"
<a href="{{ base_path }}?court={{ court_id }}&week={{ this_week }}" class="btn btn-sm join-item">« {{ t(key="prev-week", lang=lang) }}</a>
class="btn btn-sm join-item">{{ t(key="this-week", lang=lang) }}</a> <a href="{{ base_path }}?court={{ court_id }}&week={{ this_week }}"
<a href="{{ base_path }}?court={{ court_id }}&week={{ next_week }}" class="btn btn-sm join-item">{{ t(key="this-week", lang=lang) }}</a>
class="btn btn-sm join-item">{{ t(key="next-week", lang=lang) }} »</a> <a href="{{ base_path }}?court={{ court_id }}&week={{ next_week }}"
class="btn btn-sm join-item">{{ t(key="next-week", lang=lang) }} »</a>
</div>
{% if is_admin %}
<button type="button" id="cal-detail-toggle" class="btn btn-sm gap-1" aria-pressed="false"
title="{{ t(key='view-details', lang=lang) }}">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
stroke="currentColor" class="h-4 w-4">
<path stroke-linecap="round" stroke-linejoin="round"
d="M8.25 6.75h12M8.25 12h12m-12 5.25h12M3.75 6.75h.007v.008H3.75V6.75Zm.375 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0ZM3.75 12h.007v.008H3.75V12Zm.375 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Zm-.375 5.25h.007v.008H3.75v-.008Zm.375 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Z" />
</svg>
{{ t(key="view-details", lang=lang) }}
</button>
{% endif %}
</div> </div>
<div class="text-sm font-medium opacity-60">{{ court_name }} · {{ week_label }}</div> <div class="text-sm font-medium opacity-60">{{ court_name }} · {{ week_label }}</div>
</div> </div>
<div class="overflow-x-auto rounded-lg border border-base-300 bg-base-100 shadow-sm"> <div class="overflow-x-auto rounded-lg border border-base-300 bg-base-100 shadow-sm">
<table class="w-full border-collapse text-sm"> <table id="cal" class="w-full border-collapse text-sm">
<thead> <thead>
<tr class="bg-base-200"> <tr class="bg-base-200">
<th class="w-16 border border-base-300 p-2"></th> <th class="w-16 border border-base-300 p-2"></th>
@@ -55,9 +99,16 @@
{% if cell.booked %} {% if cell.booked %}
{% if is_admin %} {% if is_admin %}
<a href="/admin/booking/{{ cell.booking_id }}" <a href="/admin/booking/{{ cell.booking_id }}"
class="absolute inset-1 flex items-center overflow-hidden rounded px-1.5 text-xs font-medium text-white shadow-sm transition hover:opacity-90" class="cal-chip absolute inset-1 flex items-center overflow-hidden rounded px-1.5 text-xs font-medium text-white shadow-sm transition hover:opacity-90"
style="background-color: {{ cell.color }}"> style="background-color: {{ cell.color }}">
<span class="min-w-0 truncate">{{ cell.name }}</span> <span class="cal-name min-w-0 truncate">{{ cell.name }}</span>
{% if cell.title or cell.contact or cell.note %}
<span class="cal-detail">
{%- if cell.title %}<span class="truncate opacity-95">{{ cell.title }}</span>{% endif -%}
{%- if cell.contact %}<span class="truncate opacity-80">{{ cell.contact }}</span>{% endif -%}
{%- if cell.note %}<span class="opacity-80">{{ cell.note }}</span>{% endif -%}
</span>
{% endif %}
</a> </a>
{% else %} {% else %}
<div class="absolute inset-1 flex items-center overflow-hidden rounded px-1.5 text-xs font-medium text-white shadow-sm" <div class="absolute inset-1 flex items-center overflow-hidden rounded px-1.5 text-xs font-medium text-white shadow-sm"
@@ -88,3 +139,29 @@
</div> </div>
{% endif %} {% endif %}
{% endblock content %} {% endblock content %}
{% block js %}
{% if is_admin %}
<script>
// Detailed-view toggle for the admin calendar. The choice is remembered
// per browser; the public calendar never loads this script.
(function () {
var KEY = 'cal_detailed';
var tbl = document.getElementById('cal');
var btn = document.getElementById('cal-detail-toggle');
if (!tbl || !btn) return;
function apply(on) {
tbl.classList.toggle('cal--detailed', on);
btn.classList.toggle('btn-active', on);
btn.setAttribute('aria-pressed', on ? 'true' : 'false');
}
apply(localStorage.getItem(KEY) === '1');
btn.addEventListener('click', function () {
var on = !tbl.classList.contains('cal--detailed');
localStorage.setItem(KEY, on ? '1' : '0');
apply(on);
});
})();
</script>
{% endif %}
{% endblock js %}

View File

@@ -54,6 +54,10 @@ pub struct Cell {
pub name: String, pub name: String,
/// Public-facing label shown on the calendar when set. /// Public-facing label shown on the calendar when set.
pub title: String, pub title: String,
/// Private — admin only. Shown in the dashboard's detailed view.
pub contact: String,
/// Private — admin only. Shown in the dashboard's detailed view.
pub note: String,
} }
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
@@ -177,6 +181,8 @@ pub async fn build_calendar(
booking_id: b.id, booking_id: b.id,
name: b.name.clone(), name: b.name.clone(),
title: b.title.clone().unwrap_or_default(), title: b.title.clone().unwrap_or_default(),
contact: b.contact.clone().unwrap_or_default(),
note: b.note.clone().unwrap_or_default(),
}, },
None => Cell { None => Cell {
date: iso, date: iso,
@@ -186,6 +192,8 @@ pub async fn build_calendar(
booking_id: 0, booking_id: 0,
name: String::new(), name: String::new(),
title: String::new(), title: String::new(),
contact: String::new(),
note: String::new(),
}, },
} }
}) })