ui: convert admin request page to two-column layout

This commit is contained in:
Troll (Hermes Agent) 2026-08-02 22:24:54 +00:00
parent 3e25c3638b
commit 3cb63a6480

View file

@ -6,15 +6,11 @@
<title>Request #{{ req.id }} — Admin</title> <title>Request #{{ req.id }} — Admin</title>
<style> <style>
/* /*
Single-request admin detail page. Two-column admin detail page.
Sections: Left column: customer context + workflow.
1. Customer info (with revisions note if any) Right column: operator tools + delivery.
2. Operator notes (internal, operator-only)
3. Generate and save Suno prompt
4. Upload Version A and Version B MP3s
5. Send preview email with private player link
6. Mark paid and deliver selected MP3(s)
*/ */
*{box-sizing:border-box;}
body{ body{
font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif; font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;
background:#111827; background:#111827;
@ -23,8 +19,8 @@
padding:1rem; padding:1rem;
line-height:1.5; line-height:1.5;
} }
.container{max-width:900px;margin:0 auto;} .container{max-width:1200px;margin:0 auto;}
h1,h2{color:#60a5fa;} h1,h2{color:#60a5fa;margin-top:0;}
a{color:#93c5fd;} a{color:#93c5fd;}
.section{ .section{
background:#1f2937; background:#1f2937;
@ -43,7 +39,7 @@
box-sizing:border-box; box-sizing:border-box;
font:inherit; font:inherit;
} }
textarea{min-height:120px;} textarea{min-height:100px;}
button{ button{
padding:.7rem 1rem; padding:.7rem 1rem;
border:none; border:none;
@ -66,13 +62,6 @@
margin-bottom:1rem; margin-bottom:1rem;
} }
.flash.error{background:#450a0a;} .flash.error{background:#450a0a;}
.info-grid{display:grid;grid-template-columns:1fr 1fr;gap:1rem;}
.info-grid div{
background:#111827;
padding:.6rem;
border-radius:.5rem;
}
.approved-box{font-size:1.2rem;font-weight:bold;color:#fbbf24;}
.status-badge{ .status-badge{
display:inline-block; display:inline-block;
padding:.25rem .6rem; padding:.25rem .6rem;
@ -118,6 +107,17 @@
color:#9ca3af; color:#9ca3af;
margin-left:1.8rem; margin-left:1.8rem;
} }
.approved-box{font-size:1.2rem;font-weight:bold;color:#fbbf24;}
/* Two-column layout */
.two-col{
display:grid;
grid-template-columns:1fr 1fr;
gap:1rem;
}
@media(max-width:900px){
.two-col{grid-template-columns:1fr;}
}
</style> </style>
</head> </head>
<body> <body>
@ -131,7 +131,10 @@
{% endfor %} {% endfor %}
{% endwith %} {% endwith %}
<!-- Section 1: Customer info summary --> <div class="two-col">
<!-- LEFT COLUMN -->
<div class="left">
<!-- Customer Info -->
<div class="section"> <div class="section">
<h2>Customer Info</h2> <h2>Customer Info</h2>
<p class="copy-hint">Operators can correct the customer's email address here.</p> <p class="copy-hint">Operators can correct the customer's email address here.</p>
@ -144,10 +147,8 @@
</div> </div>
</form> </form>
<div class="info-grid" style="margin-top:1rem"> <p style="margin-top:1rem"><strong>Request #:</strong> {{ req.id }}</p>
<div><strong>Request #:</strong> {{ req.id }}</div> <p><strong>Status:</strong> <span class="status-badge">{{ statuses[req.status] }}</span></p>
<div><strong>Status:</strong> {{ statuses[req.status] }}</div>
</div>
<p><strong>Hobbies:</strong><br>{{ req.hobbies or '-' }}</p> <p><strong>Hobbies:</strong><br>{{ req.hobbies or '-' }}</p>
<p><strong>Notable facts:</strong><br>{{ req.notable_facts or '-' }}</p> <p><strong>Notable facts:</strong><br>{{ req.notable_facts or '-' }}</p>
<p><strong>Style / genre:</strong><br>{{ req.style_genre or '-' }}</p> <p><strong>Style / genre:</strong><br>{{ req.style_genre or '-' }}</p>
@ -155,7 +156,6 @@
<p><strong>Extra requests:</strong><br>{{ req.extra_requests or '-' }}</p> <p><strong>Extra requests:</strong><br>{{ req.extra_requests or '-' }}</p>
{% if req.revision_note %} {% if req.revision_note %}
<!-- Revisions requested by the customer -->
<div class="revision-note"> <div class="revision-note">
<h3>📝 Revisions Requested{% if req.revision_count %}<span style="float:right">Revision #{{ req.revision_count }}</span>{% endif %}</h3> <h3>📝 Revisions Requested{% if req.revision_count %}<span style="float:right">Revision #{{ req.revision_count }}</span>{% endif %}</h3>
<p>{{ req.revision_note }}</p> <p>{{ req.revision_note }}</p>
@ -163,7 +163,7 @@
{% endif %} {% endif %}
</div> </div>
<!-- Section 2: Operator notes --> <!-- Operator Notes -->
<div class="section"> <div class="section">
<h2>Operator Notes</h2> <h2>Operator Notes</h2>
<p class="copy-hint">Internal notes for the booth team. Customers cannot see this.</p> <p class="copy-hint">Internal notes for the booth team. Customers cannot see this.</p>
@ -176,26 +176,24 @@
</div> </div>
</form> </form>
</div> </div>
</div>
<!-- Section 3: Generate Suno prompt --> <!-- RIGHT COLUMN -->
<div class="right">
<!-- Generate Suno Prompt -->
<div class="section"> <div class="section">
<h2>1. Generate &amp; Save Suno Prompt</h2> <h2>1. Generate &amp; Save Suno Prompt</h2>
<button type="button" onclick="copyPromptForHermes()">Copy customer info for Hermes</button> <button type="button" onclick="copyPromptForHermes()">Copy customer info for Hermes</button>
<p class="copy-hint">Paste Hermes' Title, Style, and Lyrics directly into the fields below, then save.</p> <p class="copy-hint">Paste Hermes' Title, Style, and Lyrics directly into the fields below, then save.</p>
<form method="POST"> <form method="POST">
<input type="hidden" name="action" value="save_prompt"> <input type="hidden" name="action" value="save_prompt">
<label for="suno_title">Title</label> <label for="suno_title">Title</label>
<input type="text" id="suno_title" name="suno_title" value="{{ req.suno_title or '' }}"> <input type="text" id="suno_title" name="suno_title" value="{{ req.suno_title or '' }}">
<label for="suno_style">Style</label> <label for="suno_style">Style</label>
<textarea id="suno_style" name="suno_style">{{ req.suno_style or '' }}</textarea> <textarea id="suno_style" name="suno_style">{{ req.suno_style or '' }}</textarea>
<label for="suno_lyrics">Lyrics (with metatags)</label> <label for="suno_lyrics">Lyrics (with metatags)</label>
<textarea id="suno_lyrics" name="suno_lyrics" rows="12">{{ req.suno_lyrics or '' }}</textarea> <textarea id="suno_lyrics" name="suno_lyrics" rows="10">{{ req.suno_lyrics or '' }}</textarea>
<div class="actions"> <div class="actions">
<button type="button" class="secondary" onclick="copyToClipboard('suno_title', 'Title')">Copy Title</button> <button type="button" class="secondary" onclick="copyToClipboard('suno_title', 'Title')">Copy Title</button>
<button type="button" class="secondary" onclick="copyToClipboard('suno_style', 'Style')">Copy Style</button> <button type="button" class="secondary" onclick="copyToClipboard('suno_style', 'Style')">Copy Style</button>
@ -205,7 +203,7 @@
</form> </form>
</div> </div>
<!-- Section 4: Upload songs --> <!-- Upload Songs -->
<div class="section"> <div class="section">
<h2>2. Upload Songs</h2> <h2>2. Upload Songs</h2>
<p> <p>
@ -237,10 +235,9 @@
</form> </form>
</div> </div>
<!-- Section 5: Notify customer --> <!-- Notify Customer -->
<div class="section"> <div class="section">
<h2>3. Notify Customer</h2> <h2>3. Notify Customer</h2>
<p> <p>
Preview email: Preview email:
{% if req.preview_sent_at %} {% if req.preview_sent_at %}
@ -263,7 +260,7 @@
{% endif %} {% endif %}
</div> </div>
<!-- Section 6: Payment &amp; delivery --> <!-- Payment & Delivery -->
<div class="section"> <div class="section">
<h2>4. Payment &amp; Delivery</h2> <h2>4. Payment &amp; Delivery</h2>
<p> <p>
@ -286,7 +283,6 @@
<input type="hidden" name="action" value="mark_paid_deliver"> <input type="hidden" name="action" value="mark_paid_deliver">
<p style="color:#93c5fd;font-weight:600">Select files to deliver:</p> <p style="color:#93c5fd;font-weight:600">Select files to deliver:</p>
{% set all_files = [] %} {% set all_files = [] %}
{% if req.song_a_path and file_exists(req.song_a_path) %} {% if req.song_a_path and file_exists(req.song_a_path) %}
{% set _ = all_files.append(req.song_a_path) %} {% set _ = all_files.append(req.song_a_path) %}
@ -295,7 +291,6 @@
{% set _ = all_files.append(req.song_b_path) %} {% set _ = all_files.append(req.song_b_path) %}
{% endif %} {% endif %}
<!-- List all MP3 files in the request's upload folder (includes revisions) -->
{% set files_to_show = all_files + extra_files %} {% set files_to_show = all_files + extra_files %}
{% for fpath in files_to_show %} {% for fpath in files_to_show %}
<div class="file-select"> <div class="file-select">
@ -317,14 +312,10 @@
</div> </div>
</form> </form>
</div> </div>
</div>
</div>
<script> <script>
/*
Client-side helpers for the admin detail page.
- copyPromptForHermes(): builds a plain-text prompt and copies it.
- copyToClipboard(): copies a field to the clipboard for pasting into Suno.
*/
function copyPromptForHermes() { function copyPromptForHermes() {
const data = { const data = {
name: {{ req.name | tojson }}, name: {{ req.name | tojson }},