This commit is contained in:
@@ -0,0 +1,189 @@
|
||||
{% extends "admin/layout.html" %}
|
||||
{% let active_page = "schedule" %}
|
||||
|
||||
{% block title %}{{ t.schedule_edit_title }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="page-head">
|
||||
<h1>{{ t.schedule_edit_title }}</h1>
|
||||
</div>
|
||||
|
||||
<div class="form-card">
|
||||
<form method="post" action="/admin/schedule/{{ visit.id }}/save">
|
||||
<!-- Client -->
|
||||
<div class="field">
|
||||
<label class="label">{{ t.schedule_client }}</label>
|
||||
<div class="control">
|
||||
<div class="select is-fullwidth">
|
||||
<select name="client_id" required>
|
||||
{% for c in &clients %}
|
||||
<option value="{{ c.id }}" {% if c.id.unwrap() == visit.client_id.primary_key().unwrap() %}selected{% endif %}>
|
||||
{{ c.name }}{% if let Some(p) = c.phone.as_deref() %} ({{ p }}){% endif %}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Admin -->
|
||||
<div class="field">
|
||||
<label class="label">{{ t.schedule_admin }}</label>
|
||||
<div class="control">
|
||||
<div class="select is-fullwidth">
|
||||
<select name="user_id">
|
||||
{% for u in &users %}
|
||||
<option value="{{ u.id }}" {% if u.id.unwrap() == visit.user_id.primary_key().unwrap() %}selected{% endif %}>
|
||||
{{ u.display_name.as_deref().unwrap_or(&u.login) }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Date -->
|
||||
<div class="field">
|
||||
<label class="label">{{ t.schedule_date }}</label>
|
||||
<div class="control">
|
||||
<input class="input" type="date" name="visit_date" value="{{ visit.visit_date }}" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Time -->
|
||||
<div class="field">
|
||||
<label class="label">{{ t.schedule_default_time }}</label>
|
||||
<div class="columns is-mobile" style="margin-bottom:0;">
|
||||
<div class="column">
|
||||
<div class="control">
|
||||
<input class="input" type="time" name="time_start" value="{{ visit.time_start }}" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column">
|
||||
<div class="control">
|
||||
<input class="input" type="time" name="time_end" value="{{ visit.time_end }}" required>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Status -->
|
||||
<div class="field">
|
||||
<label class="label">{{ t.schedule_status }}</label>
|
||||
<div class="control">
|
||||
<div class="select is-fullwidth">
|
||||
<select name="status">
|
||||
<option value="scheduled" {% if visit.status == "scheduled" %}selected{% endif %}>{{ t.visit_status_scheduled }}</option>
|
||||
<option value="completed" {% if visit.status == "completed" %}selected{% endif %}>{{ t.visit_status_completed }}</option>
|
||||
<option value="cancelled" {% if visit.status == "cancelled" %}selected{% endif %}>{{ t.visit_status_cancelled }}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Private Notes -->
|
||||
<div class="field">
|
||||
<label class="label">{{ t.schedule_notes }}</label>
|
||||
<div class="control">
|
||||
<textarea class="textarea" name="notes" rows="2">{{ visit.notes.as_deref().unwrap_or("") }}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Public Notes (visible to client) -->
|
||||
<div class="field">
|
||||
<label class="label">{{ t.schedule_public_notes }}</label>
|
||||
<div class="control">
|
||||
<textarea class="textarea" name="public_notes" rows="2">{{ visit.public_notes.as_deref().unwrap_or("") }}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="button is-primary is-fullwidth">{{ t.schedule_save }}</button>
|
||||
</form>
|
||||
|
||||
{% if let Some(fb) = visit.client_feedback.as_deref() %}
|
||||
<div style="margin-top:1rem;">
|
||||
<label class="label">{{ t.schedule_client_feedback }}</label>
|
||||
<div style="background:#f0f0ff;border-radius:8px;padding:0.6rem 0.85rem;font-size:0.9rem;color:#4a4570;">{{ fb }}</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<hr style="margin:1rem 0;">
|
||||
|
||||
<!-- Media -->
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:0.75rem;">
|
||||
<label class="label" style="margin:0;">{{ t.nav_media }}</label>
|
||||
<a href="/admin/media/{{ visit.id }}/upload?lang={{ lang.code() }}" class="button is-info is-small is-outlined">📷 {{ t.media_upload }}</a>
|
||||
</div>
|
||||
{% if media.is_empty() %}
|
||||
<p class="has-text-grey is-size-7" style="margin-bottom:1rem;">{{ t.media_empty }}</p>
|
||||
{% else %}
|
||||
<div class="visit-media-grid">
|
||||
{% for m in &media %}
|
||||
<div class="visit-media-item">
|
||||
{% if m.file_type == "photo" %}
|
||||
<a href="/admin/uploads/{{ m.id }}" data-lightbox="photo">
|
||||
<img src="/admin/uploads/{{ m.id }}" alt="" loading="lazy">
|
||||
</a>
|
||||
{% else %}
|
||||
<a href="/admin/uploads/{{ m.id }}" data-lightbox="video">
|
||||
<div class="video-thumb-sm">🎬</div>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if let Some(cap) = m.caption.as_deref() %}
|
||||
<div class="media-cap">{{ cap }}</div>
|
||||
{% endif %}
|
||||
<form method="post" action="/admin/media/{{ m.id }}/delete" onsubmit="return confirm('{{ t.media_delete_confirm }}');" style="text-align:center;">
|
||||
<button class="button is-danger is-outlined btn-sm" style="font-size:0.7rem;padding:0.15rem 0.4rem;">{{ t.media_delete }}</button>
|
||||
</form>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<hr style="margin:1rem 0;">
|
||||
<form method="post" action="/admin/schedule/{{ visit.id }}/delete" onsubmit="return confirm('{{ t.schedule_delete_confirm }}');">
|
||||
<button type="submit" class="button is-danger is-outlined is-fullwidth is-small">{{ t.schedule_delete }}</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.visit-media-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.visit-media-item {
|
||||
background: #fafafa;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #eee;
|
||||
overflow: hidden;
|
||||
}
|
||||
.visit-media-item img {
|
||||
width: 100%;
|
||||
height: 80px;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
}
|
||||
.visit-media-item .video-thumb-sm {
|
||||
width: 100%;
|
||||
height: 80px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 2rem;
|
||||
background: #f0f0f0;
|
||||
}
|
||||
.visit-media-item .media-cap {
|
||||
font-size: 0.7rem;
|
||||
color: #888;
|
||||
padding: 0.2rem 0.4rem;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.visit-media-item form {
|
||||
padding: 0.2rem;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user