This repository has been archived on 2026-09-04. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
theme-song-booth/templates/admin/request.html

277 lines
9.9 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Request #{{ req.id }} — Admin</title>
<style>
/*
Single-request admin detail page.
Sections:
1. Customer info (with revisions note if any)
2. Generate Suno prompt
3. Upload Songs
4. Notify Customer
5. Payment & Delivery
*/
body{
font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;
background:#111827;
color:#f3f4f6;
margin:0;
padding:1rem;
line-height:1.5;
}
.container{max-width:900px;margin:0 auto;}
h1,h2{color:#60a5fa;}
a{color:#93c5fd;}
.section{
background:#1f2937;
padding:1rem;
border-radius:.5rem;
margin-bottom:1rem;
}
label{display:block;margin-top:.8rem;font-weight:600;}
input,textarea{
width:100%;
padding:.6rem;
border-radius:.5rem;
border:1px solid #374151;
background:#111827;
color:#f3f4f6;
box-sizing:border-box;
font:inherit;
}
textarea{min-height:120px;}
button{
padding:.7rem 1rem;
border:none;
border-radius:.5rem;
background:#3b82f6;
color:#fff;
font-weight:700;
cursor:pointer;
margin-top:.5rem;
}
button.secondary{background:#4b5563;}
button.danger{background:#dc2626;}
button.success{background:#10b981;}
button:disabled{background:#374151;color:#9ca3af;cursor:not-allowed;}
.actions{display:flex;gap:.5rem;flex-wrap:wrap;margin-top:.5rem;}
.flash{
padding:.8rem;
background:#064e3b;
border-radius:.5rem;
margin-bottom:1rem;
}
.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{
display:inline-block;
padding:.25rem .6rem;
border-radius:9999px;
font-size:.8rem;
font-weight:600;
background:#374151;
color:#f3f4f6;
margin-right:.3rem;
}
.status-badge.ok{background:#10b981;color:#000;}
.status-badge.missing{background:#ef4444;color:#000;}
.status-badge.sent{background:#60a5fa;color:#000;}
.copy-hint{font-size:.85rem;color:#9ca3af;margin-top:.3rem;}
.revision-note{
margin-top:1rem;
background:#450a0a;
border:1px solid #7f1d1d;
border-radius:.5rem;
padding:1rem;
}
.revision-note h3{
margin-top:0;
color:#f87171;
}
</style>
</head>
<body>
<div class="container">
<p><a href="{{ url_for('admin_dashboard') }}">← Dashboard</a></p>
<h1>Request #{{ req.id }} — {{ req.name }}</h1>
{% with messages = get_flashed_messages(with_categories=true) %}
{% for category, message in messages %}
<div class="flash {{ category }}">{{ message }}</div>
{% endfor %}
{% endwith %}
<!-- Section 1: Customer info summary -->
<div class="section">
<h2>Customer Info</h2>
<div class="info-grid">
<div><strong>Email:</strong> {{ req.email }}</div>
<div><strong>Status:</strong> {{ statuses[req.status] }}</div>
</div>
<p><strong>Hobbies:</strong><br>{{ req.hobbies 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>Extra requests:</strong><br>{{ req.extra_requests or '-' }}</p>
{% if req.revision_note %}
<!-- Revisions requested by the customer -->
<div class="revision-note">
<h3>📝 Revisions Requested</h3>
<p>{{ req.revision_note }}</p>
</div>
{% endif %}
</div>
<!-- Section 2: Generate Suno prompt -->
<div class="section">
<h2>1. Generate Suno Prompt</h2>
<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>
<form method="POST">
<input type="hidden" name="action" value="save_prompt">
<label for="suno_title">Title</label>
<input type="text" id="suno_title" name="suno_title" value="{{ req.suno_title or '' }}">
<label for="suno_style">Style</label>
<textarea id="suno_style" name="suno_style">{{ req.suno_style or '' }}</textarea>
<label for="suno_lyrics">Lyrics (with metatags)</label>
<textarea id="suno_lyrics" name="suno_lyrics" rows="12">{{ req.suno_lyrics or '' }}</textarea>
<div class="actions">
<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_lyrics', 'Lyrics')">Copy Lyrics</button>
<button type="submit">Save Prompt</button>
</div>
</form>
</div>
<!-- Section 3: Upload songs -->
<div class="section">
<h2>2. Upload Songs</h2>
<p>
Version A:
{% if req.song_a_path and file_exists(req.song_a_path) %}
<span class="status-badge ok">✅ Uploaded</span> {{ basename(req.song_a_path) }}
{% else %}
<span class="status-badge missing">❌ Not uploaded</span>
{% endif %}
</p>
<p>
Version B:
{% if req.song_b_path and file_exists(req.song_b_path) %}
<span class="status-badge ok">✅ Uploaded</span> {{ basename(req.song_b_path) }}
{% else %}
<span class="status-badge missing">❌ Not uploaded</span>
{% endif %}
</p>
<form method="POST" enctype="multipart/form-data">
<input type="hidden" name="action" value="upload_songs">
<label for="song_a">Version A MP3</label>
<input type="file" id="song_a" name="song_a" accept="audio/mpeg,.mp3">
<label for="song_b">Version B MP3</label>
<input type="file" id="song_b" name="song_b" accept="audio/mpeg,.mp3">
<div class="actions">
<button type="submit">Upload Songs</button>
</div>
</form>
</div>
<!-- Section 4: Notify customer -->
<div class="section">
<h2>3. Notify Customer</h2>
<p>
Preview email:
{% if req.preview_sent_at %}
<span class="status-badge sent">✅ Sent</span> {{ req.preview_sent_at }}
{% else %}
<span class="status-badge missing">❌ Not sent yet</span>
{% endif %}
</p>
<p>Both songs must be uploaded first.</p>
<form method="POST">
<input type="hidden" name="action" value="notify_customer">
<button type="submit" {% if not (req.song_a_path and req.song_b_path) %}disabled{% endif %}>Send Preview Link</button>
</form>
{% if req.song_a_path and req.song_b_path %}
<p style="margin-top:.8rem">
Operator preview link:
<a href="{{ url_for('play', token=req.player_token) }}" target="_blank" rel="noopener noreferrer">Open customer player in new tab →</a>
</p>
{% endif %}
</div>
<!-- Section 5: Payment & delivery -->
<div class="section">
<h2>4. Payment & Delivery</h2>
<p>
Customer approved:
{% if req.customer_approved == 'none' %}
<span class="approved-box">Nothing yet</span>
{% else %}
<span class="approved-box">{{ req.customer_approved.upper() }}</span>
{% endif %}
</p>
<p>
Delivery email:
{% if req.delivery_sent_at %}
<span class="status-badge sent">✅ Sent</span> {{ req.delivery_sent_at }}
{% else %}
<span class="status-badge missing">❌ Not sent yet</span>
{% endif %}
</p>
<form method="POST">
<input type="hidden" name="action" value="mark_paid_deliver">
<label for="square_payment_ref">Square Payment Reference</label>
<input type="text" id="square_payment_ref" name="square_payment_ref" placeholder="e.g. sq0idp-... or receipt number">
<div class="actions">
<button type="submit" class="success" {% if req.customer_approved == 'none' %}disabled{% endif %}>Mark Paid & Deliver</button>
</div>
</form>
</div>
<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() {
const data = {
name: {{ req.name | tojson }},
hobbies: {{ req.hobbies | tojson }},
notable_facts: {{ req.notable_facts | tojson }},
style_genre: {{ req.style_genre | tojson }},
extra_requests: {{ req.extra_requests | tojson }}
};
const text = `Please write a Suno Custom Mode prompt for this customer. Suggest a song title too.\n\nCustomer data:\nName: ${data.name}\nHobbies: ${data.hobbies || '-'}\nNotable facts: ${data.notable_facts || '-'}\nStyle / genre: ${data.style_genre || '-'}\nExtra requests: ${data.extra_requests || '-'}\n\nReply with exactly this format:\n\nTitle: [suggested title]\n\nStyle:\n[the style description here]\n\nLyrics:\n[the lyrics here, with metatags]`;
navigator.clipboard.writeText(text).then(() => alert("Copied! Paste Hermes response into the Title, Style, and Lyrics fields."));
}
function copyToClipboard(elementId, label) {
const el = document.getElementById(elementId);
el.select();
el.setSelectionRange(0, 99999);
navigator.clipboard.writeText(el.value).then(() => alert(label + " copied!"));
}
</script>
</div>
</body>
</html>