{% extends "base.html" %}
{% block title %}Dashboard — AgentForms{% endblock %}
{% block content %}
<style nonce="{{ csp_nonce }}">
/* ── Dashboard Layout ─────────────────────────────────── */
.dashboard { padding: 32px 0 64px; }
.dashboard-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 32px;
flex-wrap: wrap;
gap: 16px;
}
.dashboard-header h1 {
font-size: 28px;
font-weight: 700;
color: var(--text);
margin: 0;
}
.dashboard-header .user-info {
display: flex;
align-items: center;
gap: 12px;
font-size: 14px;
color: var(--text-muted);
}
.tier-badge {
display: inline-flex;
align-items: center;
padding: 4px 12px;
border-radius: 999px;
font-size: 12px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.04em;
background: var(--accent-dim);
color: var(--accent-bright);
}
/* ── Stats Row ─────────────────────────────────────────── */
.stats-row {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 16px;
margin-bottom: 40px;
}
.stat-card {
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 10px;
padding: 24px;
}
.stat-card .stat-value {
font-size: 32px;
font-weight: 700;
color: var(--text);
line-height: 1.2;
}
.stat-card .stat-label {
font-size: 13px;
color: var(--text-muted);
margin-top: 4px;
}
.stat-card .stat-sub {
font-size: 12px;
color: var(--text-dim);
margin-top: 2px;
}
/* ── Section ───────────────────────────────────────────── */
.dash-section {
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 10px;
margin-bottom: 24px;
overflow: hidden;
}
.dash-section-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20px 24px;
border-bottom: 1px solid var(--border);
flex-wrap: wrap;
gap: 12px;
}
.dash-section-header h2 {
font-size: 17px;
font-weight: 600;
color: var(--text);
margin: 0;
}
.dash-section-actions {
display: flex;
gap: 8px;
flex-wrap: wrap;
}
.dash-section-actions .btn {
padding: 8px 16px;
font-size: 13px;
}
/* ── Table ─────────────────────────────────────────────── */
.dash-table-wrap {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
.dash-table {
width: 100%;
border-collapse: collapse;
table-layout: fixed;
}
.dash-table thead th {
padding: 12px 16px;
font-size: 12px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--text-muted);
background: var(--bg-elevated);
border-bottom: 1px solid var(--border);
text-align: left;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.dash-table tbody td {
padding: 14px 16px;
font-size: 14px;
color: var(--text);
border-bottom: 1px solid var(--border);
vertical-align: middle;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
line-height: 1.5;
}
.dash-table tbody tr:last-child td {
border-bottom: none;
}
.dash-table tbody tr:hover {
background: var(--bg-elevated);
}
/* Column widths — Your Forms */
.dash-table.forms-table {
/* col 0: Form name */
/* col 1: Token */
/* col 2: Owner */
/* col 3: Created */
/* col 4: Action */
}
.dash-table.forms-table thead th:nth-child(1),
.dash-table.forms-table tbody td:nth-child(1) { width: 25%; }
.dash-table.forms-table thead th:nth-child(2),
.dash-table.forms-table tbody td:nth-child(2) { width: 20%; }
.dash-table.forms-table thead th:nth-child(3),
.dash-table.forms-table tbody td:nth-child(3) { width: 25%; }
.dash-table.forms-table thead th:nth-child(4),
.dash-table.forms-table tbody td:nth-child(4) { width: 15%; }
.dash-table.forms-table thead th:nth-child(5),
.dash-table.forms-table tbody td:nth-child(5) { width: 15%; }
/* Column widths — Submissions */
.dash-table.submissions-table {
/* col 0: Form */
/* col 1: Customer */
/* col 2: Email */
/* col 3: Message */
/* col 4: When */
}
.dash-table.submissions-table thead th:nth-child(1),
.dash-table.submissions-table tbody td:nth-child(1) { width: 20%; }
.dash-table.submissions-table thead th:nth-child(2),
.dash-table.submissions-table tbody td:nth-child(2) { width: 15%; }
.dash-table.submissions-table thead th:nth-child(3),
.dash-table.submissions-table tbody td:nth-child(3) { width: 25%; }
.dash-table.submissions-table thead th:nth-child(4),
.dash-table.submissions-table tbody td:nth-child(4) { width: 30%; white-space: normal; }
.dash-table.submissions-table thead th:nth-child(5),
.dash-table.submissions-table tbody td:nth-child(5) { width: 10%; }
/* ── Table cells ───────────────────────────────────────── */
.cell-form-name {
font-weight: 500;
color: var(--text);
}
.cell-token {
display: flex;
align-items: center;
gap: 6px;
}
.cell-token .token {
font-family: var(--mono);
font-size: 12px;
background: var(--bg-elevated);
padding: 3px 8px;
border-radius: 4px;
color: var(--text-muted);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.cell-token .copy-btn {
background: none;
border: none;
cursor: pointer;
color: var(--text-dim);
padding: 2px;
font-size: 14px;
flex-shrink: 0;
line-height: 1;
}
.cell-token .copy-btn:hover { color: var(--accent); }
.cell-email {
color: var(--text-muted);
font-size: 13px;
}
.cell-date {
color: var(--text-muted);
font-size: 13px;
}
.cell-message {
color: var(--text);
}
.cell-message .expand-btn {
background: none;
border: none;
color: var(--accent);
cursor: pointer;
font-size: 12px;
padding: 0;
margin-left: 4px;
font-family: var(--font);
}
.cell-message .expand-btn:hover { text-decoration: underline; }
/* ── Empty state ───────────────────────────────────────── */
.empty-state {
padding: 48px 24px;
text-align: center;
color: var(--text-muted);
font-size: 14px;
}
/* ── Refer & Earn ──────────────────────────────────────── */
.referral-card {
background: linear-gradient(135deg, var(--accent-dim) 0%, rgba(16, 185, 129, 0.03) 100%);
border: 1px solid var(--border);
border-radius: 10px;
padding: 24px;
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 24px;
flex-wrap: wrap;
gap: 16px;
}
.referral-info {
display: flex;
align-items: center;
gap: 16px;
flex-wrap: wrap;
}
.referral-info .ref-icon {
width: 44px;
height: 44px;
border-radius: 10px;
background: var(--accent-dim);
display: flex;
align-items: center;
justify-content: center;
font-size: 20px;
flex-shrink: 0;
}
.referral-info .ref-text {
font-size: 14px;
color: var(--text);
line-height: 1.5;
}
.referral-info .ref-text strong {
color: var(--accent-bright);
}
.ref-code {
font-family: var(--mono);
font-size: 14px;
font-weight: 600;
background: var(--bg-elevated);
padding: 6px 14px;
border-radius: 6px;
border: 1px solid var(--border);
letter-spacing: 0.05em;
user-select: all;
}
/* ── API Keys ──────────────────────────────────────────── */
.api-keys-section {
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 10px;
padding: 24px;
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: 12px;
}
.api-keys-section h2 {
font-size: 17px;
font-weight: 600;
margin: 0;
}
/* ── Magic Link Banner ─────────────────────────────────── */
.magic-link-banner {
background: var(--bg-elevated);
border: 1px solid var(--border);
border-radius: 10px;
padding: 16px 24px;
margin-bottom: 24px;
display: flex;
align-items: center;
gap: 16px;
flex-wrap: wrap;
}
.magic-link-banner .banner-text {
flex: 1;
min-width: 200px;
}
.magic-link-banner .banner-text h3 {
font-size: 15px;
font-weight: 600;
margin: 0 0 4px;
color: var(--text);
}
.magic-link-banner .banner-text p {
font-size: 13px;
color: var(--text-muted);
margin: 0;
}
.magic-link-banner label {
display: inline-flex;
align-items: center;
gap: 8px;
font-size: 13px;
font-weight: 500;
color: var(--text);
cursor: pointer;
margin: 0;
}
/* ── Responsive ────────────────────────────────────────── */
@media (max-width: 768px) {
.dashboard { padding: 20px 0 48px; }
.dashboard-header { margin-bottom: 24px; }
.dashboard-header h1 { font-size: 22px; }
.stats-row { gap: 12px; }
.stat-card { padding: 18px; }
.stat-card .stat-value { font-size: 26px; }
.dash-section-header { padding: 16px; }
.dash-table thead th,
.dash-table tbody td { padding: 10px 12px; font-size: 13px; }
.referral-card { padding: 18px; }
}
</style>
<div class="dashboard">
<!-- Header -->
<div class="dashboard-header">
<h1>Dashboard</h1>
<div class="user-info">
<span>{{ user.name or user.email }}</span>
<span class="tier-badge">{{ usage.tier_name }}</span>
{% if user.tier == 'free' %}
<a href="/upgrade" class="btn btn-sm">Upgrade Plan</a>
{% endif %}
</div>
</div>
<!-- Stats -->
<div class="stats-row">
<div class="stat-card">
<div class="stat-value">{{ site_count }}</div>
<div class="stat-label">Active Forms</div>
{% if user.tier == 'free' %}
<div class="stat-sub">{{ site_count }} / {{ usage.max_sites }} limit</div>
{% else %}
<div class="stat-sub">Unlimited</div>
{% endif %}
</div>
<div class="stat-card">
<div class="stat-value">{{ usage.submissions }}</div>
<div class="stat-label">Submissions this month</div>
<div class="stat-sub">{{ usage.submissions }} / {{ usage.max_submissions }}</div>
</div>
<div class="stat-card">
<div class="stat-value">{{ recent_submissions | length }}</div>
<div class="stat-label">Recent Submissions</div>
<div class="stat-sub">All time</div>
</div>
</div>
<!-- Magic Link Banner -->
<div class="magic-link-banner">
<div class="banner-text">
<h3>Passwordless Login</h3>
<p>Magic link login via email — no password needed</p>
</div>
<label>
<input type="checkbox" checked> Enable
</label>
</div>
<!-- Refer & Earn -->
<div class="referral-card">
<div class="referral-info">
<div class="ref-icon">🎁</div>
<div class="ref-text">
<strong>Refer & Earn</strong><br>
Share your code <code class="ref-code">{{ referral_code }}</code> with friends. You earn <strong>50 credits</strong> per referral.
</div>
</div>
<a href="/referral" class="btn btn-outline btn-sm">View Details</a>
</div>
<!-- Your Forms -->
<div class="dash-section">
<div class="dash-section-header">
<h2>Your Forms</h2>
<div class="dash-section-actions">
<a href="/sites/new" class="btn btn-sm">+ New Form</a>
<a href="/sites/templates" class="btn btn-outline btn-sm">Browse Templates</a>
<a href="/sites" class="btn btn-outline btn-sm">Manage Forms</a>
</div>
</div>
{% if forms %}
<div class="dash-table-wrap">
<table class="dash-table forms-table">
<thead>
<tr>
<th>Form</th>
<th>Token</th>
<th>Owner Email</th>
<th>Created</th>
<th></th>
</tr>
</thead>
<tbody>
{% for form in forms %}
<tr>
<td class="cell-form-name">{{ form.name }}</td>
<td>
<div class="cell-token">
<span class="token" id="token-{{ loop.index }}">{{ form.form_token[:10] }}...{{ form.form_token[-4:] }}</span>
<button class="copy-btn" title="Copy token" onclick="navigator.clipboard.writeText('{{ form.form_token }}'); this.textContent='✓'; setTimeout(()=>this.textContent='📋', 1200);">📋</button>
</div>
</td>
<td class="cell-email">{{ form.owner_email }}</td>
<td class="cell-date">{{ form.created_at.strftime('%Y-%m-%d') }}</td>
<td>
<a href="/sites/{{ form.site_id }}/submissions" class="btn btn-outline btn-sm">View Submissions</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="empty-state">
No forms yet. <a href="/sites/new" style="color: var(--accent);">Create your first form</a> or <a href="/sites/templates" style="color: var(--accent);">browse templates</a>.
</div>
{% endif %}
</div>
<!-- Recent Submissions -->
<div class="dash-section">
<div class="dash-section-header">
<h2>Recent Submissions</h2>
<div class="dash-section-actions">
<a href="/sites" class="btn btn-outline btn-sm">View All</a>
</div>
</div>
{% if submissions %}
<div class="dash-table-wrap">
<table class="dash-table submissions-table">
<thead>
<tr>
<th>Form</th>
<th>Customer</th>
<th>Email</th>
<th>Message</th>
<th>When</th>
</tr>
</thead>
<tbody>
{% for sub in submissions %}
<tr>
<td class="cell-form-name">{{ sub.form_name }}</td>
<td>{{ sub.customer_name or '-' }}</td>
<td class="cell-email">{{ sub.customer_email or '-' }}</td>
<td class="cell-message">
{% if sub.message %}
{{ sub.message[:60] }}{% if sub.message|length > 60 %}... <button class="expand-btn" data-full="{{ sub.message }}">Expand</button>{% endif %}
{% else %}
-
{% endif %}
</td>
<td class="cell-date">{{ sub.submitted_at.strftime('%Y-%m-%d') }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="empty-state">
No submissions yet. They'll appear here once your forms start receiving responses.
</div>
{% endif %}
</div>
<!-- API Keys -->
<div class="api-keys-section">
<h2>API Keys</h2>
<a href="/settings/api-keys" class="btn btn-outline btn-sm">Manage Keys</a>
</div>
</div>
{% endblock %}
{% block scripts %}
<script src="/static/js/user-dashboard-inline.js"></script>
{% endblock %}