95 lines
4.1 KiB
HTML
95 lines
4.1 KiB
HTML
{% extends "base_app.html" %}
|
|
{% set active_page = 'campaigns' %}
|
|
{% block title %}My Campaigns — TheNicheQuiz{% endblock %}
|
|
|
|
{% block body %}
|
|
<div class="app-page">
|
|
<div class="page-header" style="display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 16px;">
|
|
<div>
|
|
<h1 class="page-title">My Campaigns</h1>
|
|
<p class="page-subtitle">All your saved campaign sets in one place.</p>
|
|
</div>
|
|
<a href="/app/generate" class="btn btn-amber">
|
|
<svg style="width:16px;height:16px;" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"/></svg>
|
|
New Campaign
|
|
</a>
|
|
</div>
|
|
|
|
{% if campaigns %}
|
|
<div style="display: grid; grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); gap: 16px;">
|
|
{% for c in campaigns %}
|
|
<div class="card" style="position: relative;">
|
|
<div style="display: flex; align-items: start; justify-content: space-between; margin-bottom: 16px;">
|
|
<div>
|
|
<h3 style="font-size: 17px; font-weight: 700; margin-bottom: 6px;">{{ c.name }}</h3>
|
|
<div style="display: flex; flex-wrap: wrap; gap: 4px;">
|
|
{% if c.industry %}
|
|
<span class="badge badge-amber">{{ c.industry }}</span>
|
|
{% endif %}
|
|
{% if c.sub_niche %}
|
|
<span class="badge badge-purple">{{ c.sub_niche[:30] }}</span>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% if c.micro_niche %}
|
|
<div style="font-size: 13px; color: var(--text-secondary); margin-bottom: 12px;">
|
|
🎯 {{ c.micro_niche }}
|
|
</div>
|
|
{% endif %}
|
|
{% if c.campaign_data %}
|
|
{% set data = c.campaign_data if c.campaign_data is mapping else {} %}
|
|
{% set camp_count = data.get('campaigns', [])|length if data.get('campaigns') else 0 %}
|
|
{% if camp_count > 0 %}
|
|
<div style="font-size: 12px; color: var(--text-muted); margin-bottom: 12px;">
|
|
{{ camp_count }} campaign{{ 's' if camp_count != 1 else '' }} saved
|
|
</div>
|
|
{% endif %}
|
|
{% endif %}
|
|
<div style="display: flex; align-items: center; justify-content: space-between;">
|
|
<span style="font-size: 12px; color: var(--text-muted);">
|
|
{{ c.created_at.strftime('%b %d, %Y at %I:%M %p') if c.created_at else '' }}
|
|
</span>
|
|
<div style="display: flex; gap: 8px;">
|
|
<a href="/app/campaigns/{{ c.id }}" class="btn btn-outline btn-sm">View</a>
|
|
<button class="btn btn-red btn-sm" onclick="deleteCampaign({{ c.id }}, this)">Delete</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
{% else %}
|
|
<div class="card">
|
|
<div class="empty-state">
|
|
<div class="empty-icon">📦</div>
|
|
<div class="empty-title">No saved campaigns</div>
|
|
<div class="empty-desc">Generate campaigns with the quiz and save them here for later.</div>
|
|
<a href="/app/generate" class="btn btn-amber">Start Generating</a>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block scripts %}
|
|
<script>
|
|
async function deleteCampaign(id, btn) {
|
|
if (!confirm('Delete this campaign? This cannot be undone.')) return;
|
|
try {
|
|
const res = await fetch(`/api/delete-campaign/${id}`, { method: 'DELETE' });
|
|
const data = await res.json();
|
|
if (data.success) {
|
|
btn.closest('.card').style.opacity = '0';
|
|
btn.closest('.card').style.transform = 'scale(0.95)';
|
|
setTimeout(() => { btn.closest('.card').remove(); }, 300);
|
|
showToast('Campaign deleted');
|
|
} else {
|
|
showToast(data.error || 'Failed to delete', 'error');
|
|
}
|
|
} catch (e) {
|
|
showToast('Failed to delete campaign', 'error');
|
|
}
|
|
}
|
|
</script>
|
|
{% endblock %}
|