Jul 28 - Update the demo request button, and add demo registration page

This commit is contained in:
2026-07-28 14:18:22 -04:00
parent 6b904aead9
commit ea9458395d
17 changed files with 905 additions and 13 deletions
+1 -1
View File
@@ -17,7 +17,7 @@
href="{{ url_for('admin.audit', action=val, entity=entity) }}">{{ label }}</a>
{% endfor %}
<span class="filters__sep">·</span>
{% set entities = [('', 'All types'), ('section','section'), ('topic','topic')] %}
{% set entities = [('', 'All types'), ('section','section'), ('topic','topic'), ('demo','demo')] %}
{% for val, label in entities %}
<a class="filter-chip {{ 'is-active' if entity == val }}"
href="{{ url_for('admin.audit', action=action, entity=val) }}">{{ label }}</a>
+2
View File
@@ -16,6 +16,8 @@
<nav class="anav">
<a class="anav__brand" href="{{ url_for('admin.dashboard') }}">JQC<span>admin</span></a>
<div class="anav__right">
<a class="anav__link" href="{{ url_for('admin.demos') }}">Demo requests{% if pending_demos %}<span
class="anav__count">{{ pending_demos }}</span>{% endif %}</a>
<a class="anav__link" href="{{ url_for('admin.audit') }}">Audit</a>
<a class="anav__link" href="{{ url_for('index') }}" target="_blank" rel="noopener">View site ↗</a>
<span class="anav__user">{{ session.get('admin') }}</span>
+91
View File
@@ -0,0 +1,91 @@
{% extends "admin/base.html" %}
{% block title %}Demo requests{% endblock %}
{% block content %}
<header class="page-head">
<div>
<h1>Demo requests</h1>
<p class="muted">Appointments booked from the public page, soonest first.</p>
</div>
<a class="btn btn--ghost" href="{{ url_for('admin.dashboard') }}">← Dashboard</a>
</header>
<div class="filters">
<span class="filters__label">Show</span>
{% set views = [('', 'Open'), ('new','new'), ('scheduled','scheduled'), ('done','done'), ('cancelled','cancelled')] %}
{% for val, label in views %}
<a class="filter-chip {{ 'is-active' if status == val }}"
href="{{ url_for('admin.demos', status=val) }}">{{ label }}</a>
{% endfor %}
{% if new_count %}<span class="filters__sep">·</span><span class="muted">{{ new_count }} new</span>{% endif %}
</div>
{% if requests %}
<div class="table-wrap">
<table class="audit-table">
<thead>
<tr>
<th>Requested for</th>
<th>Contact</th>
<th>Company</th>
<th>Message</th>
<th>Received (UTC)</th>
<th>Status</th>
<th></th>
</tr>
</thead>
<tbody>
{% for r in requests %}
<tr>
<td class="mono nowrap">{{ r.preferred_date.strftime('%Y-%m-%d') }} {{ r.preferred_time }}</td>
<td>
<strong>{{ r.name }}</strong><br>
<a href="mailto:{{ r.email }}">{{ r.email }}</a>
{% if r.phone %}<br><span class="mono">{{ r.phone }}</span>{% endif %}
</td>
<td>{{ r.company or '—' }}</td>
<td>{{ r.message or '' }}</td>
<td class="mono nowrap">{{ r.created_at.strftime('%Y-%m-%d %H:%M') if r.created_at else '—' }}</td>
<td><span class="badge badge--{{ 'create' if r.status == 'new' else ('update' if r.status == 'scheduled' else 'delete') }}">{{ r.status }}</span></td>
<td class="nowrap">
<form method="post" action="{{ url_for('admin.demo_status', req_id=r.id) }}" class="inline-form">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<input type="hidden" name="back_status" value="{{ status }}">
<select name="status" class="mini-select">
{% for s in statuses %}
<option value="{{ s }}" {{ 'selected' if r.status == s }}>{{ s }}</option>
{% endfor %}
</select>
<button class="btn btn--ghost btn--sm" type="submit">Set</button>
</form>
<form method="post" action="{{ url_for('admin.demo_delete', req_id=r.id) }}" class="inline-form"
onsubmit="return confirm('Delete the request from {{ r.name }}?');">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<button class="btn btn--danger btn--sm" type="submit">Delete</button>
</form>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% if pagination.pages > 1 %}
<nav class="pager">
{% if pagination.has_prev %}
<a class="btn btn--ghost btn--sm" href="{{ url_for('admin.demos', page=pagination.prev_num, status=status) }}">← Previous</a>
{% else %}
<span class="btn btn--ghost btn--sm is-disabled">← Previous</span>
{% endif %}
<span class="pager__info">Page {{ pagination.page }} of {{ pagination.pages }}</span>
{% if pagination.has_next %}
<a class="btn btn--ghost btn--sm" href="{{ url_for('admin.demos', page=pagination.next_num, status=status) }}">Next →</a>
{% else %}
<span class="btn btn--ghost btn--sm is-disabled">Next →</span>
{% endif %}
</nav>
{% endif %}
{% else %}
<div class="empty">No demo requests{{ ' with this status' if status }}.</div>
{% endif %}
{% endblock %}
+113
View File
@@ -0,0 +1,113 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Request a demo — JQC · LT Services</title>
<meta name="description" content="Book a live demonstration of LT Services' JQC quality control platform.">
<meta name="robots" content="noindex">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link
href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,500;12..96,700;12..96,800&family=IBM+Plex+Mono:wght@400;500;600&family=IBM+Plex+Sans:wght@400;500;600&display=swap"
rel="stylesheet">
<link rel="stylesheet" href="{{ asset_url('css/style.css') }}">
</head>
<body>
<div class="grain" aria-hidden="true"></div>
<main class="book">
<a class="book__back" href="{{ url_for('index') }}">← Back to JQC features</a>
<header class="book__head">
<p class="book__kicker">Live demonstration</p>
<h1 class="book__title">Book a demo</h1>
<p class="book__lede">
Pick a day and time that suits you and we'll walk you through JQC — inspections, issue tracking, SLA alerts
and reporting — on your own facilities' terms. Monday to Friday, {{ tz_label }}.
</p>
</header>
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
<div class="book__alerts" role="alert">
{% for cat, msg in messages %}
<p class="book__alert book__alert--{{ cat }}">{{ msg }}</p>
{% endfor %}
</div>
{% endif %}
{% endwith %}
<form class="book__form" method="post" action="{{ url_for('demo') }}" novalidate>
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<!-- honeypot: hidden from people, irresistible to bots -->
<div class="book__hp" aria-hidden="true">
<label>Website<input type="text" name="website" tabindex="-1" autocomplete="off"></label>
</div>
<div class="field">
<label for="name">Your name <span class="req">*</span></label>
<input id="name" name="name" type="text" maxlength="120" required autocomplete="name"
value="{{ form.name or '' }}">
</div>
<div class="field-row">
<div class="field">
<label for="company">Company / facility</label>
<input id="company" name="company" type="text" maxlength="160" autocomplete="organization"
value="{{ form.company or '' }}">
</div>
<div class="field">
<label for="phone">Phone</label>
<input id="phone" name="phone" type="tel" maxlength="40" autocomplete="tel"
value="{{ form.phone or '' }}">
</div>
</div>
<div class="field">
<label for="email">Email <span class="req">*</span></label>
<input id="email" name="email" type="email" maxlength="200" required autocomplete="email"
value="{{ form.email or '' }}">
<p class="hint">We'll send a confirmation here.</p>
</div>
<div class="field-row">
<div class="field">
<label for="preferred_date">Preferred date <span class="req">*</span></label>
<input id="preferred_date" name="preferred_date" type="date" required
min="{{ min_date }}" max="{{ max_date }}" value="{{ form.preferred_date or '' }}">
<p class="hint">Weekdays only.</p>
</div>
<div class="field">
<label for="preferred_time">Preferred time <span class="req">*</span></label>
<select id="preferred_time" name="preferred_time" required>
<option value="">Select a time…</option>
{% for slot in slots %}
<option value="{{ slot }}" {{ 'selected' if form.preferred_time == slot }}>{{ slot }}</option>
{% endfor %}
</select>
<p class="hint">{{ tz_label }}.</p>
</div>
</div>
<div class="field">
<label for="message">Anything we should prepare?</label>
<textarea id="message" name="message" rows="4" maxlength="2000"
placeholder="Number of sites, current QC process, people who'll join…">{{ form.message or '' }}</textarea>
</div>
<button class="book__submit" type="submit">Request this appointment</button>
<p class="book__fallback">
Prefer email? <a href="{{ demo_url }}">Contact us directly</a>.
</p>
</form>
</main>
<footer class="cta cta--slim">
<p class="cta__legal">© LT Services Inc. · JQC Quality Control Program</p>
</footer>
</body>
</html>
+43
View File
@@ -0,0 +1,43 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Request received — JQC · LT Services</title>
<meta name="robots" content="noindex">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link
href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,500;12..96,700;12..96,800&family=IBM+Plex+Mono:wght@400;500;600&family=IBM+Plex+Sans:wght@400;500;600&display=swap"
rel="stylesheet">
<link rel="stylesheet" href="{{ asset_url('css/style.css') }}">
</head>
<body>
<div class="grain" aria-hidden="true"></div>
<main class="book book--done">
<div class="book__stamp" aria-hidden="true">
<svg viewBox="0 0 24 24">
<polyline points="4 12 10 18 20 6" />
</svg>
</div>
<h1 class="book__title">Request received</h1>
<p class="book__lede">
Thank you — your appointment request is with us. We've emailed you a copy, and someone from LT Services
will confirm the time shortly.
</p>
<p class="book__fallback">
Need to change something? <a href="{{ demo_url }}">Email us</a> or
<a href="{{ url_for('demo') }}">submit another time</a>.
</p>
<a class="book__back" href="{{ url_for('index') }}">← Back to JQC features</a>
</main>
<footer class="cta cta--slim">
<p class="cta__legal">© LT Services Inc. · JQC Quality Control Program</p>
</footer>
</body>
</html>
+2 -1
View File
@@ -110,7 +110,8 @@
<div class="cta__inner">
<p class="cta__kicker">Paperless · Maintenance-free · No subscription</p>
<h2 class="cta__title">LT would be glad to run a live demonstration.</h2>
<a class="cta__btn" href="{{ demo_url }}">Request a demo</a>
<a class="cta__btn" href="{{ url_for('demo') }}">Request a demo</a>
<p class="cta__alt">Pick a day and time — or <a href="{{ demo_url }}">email us directly</a>.</p>
</div>
<p class="cta__legal">© LT Services Inc. · JQC Quality Control Program</p>
</footer>