| 1 |
{% extends "base.html" %} |
| 2 |
|
| 3 |
{% block title %}Import Data - Makenot.work{% endblock %} |
| 4 |
{% block body_attrs %} class="padded-page import-page"{% endblock %} |
| 5 |
|
| 6 |
{% block content %} |
| 7 |
{% include "partials/site_header.html" %} |
| 8 |
|
| 9 |
<div class="container"> |
| 10 |
<a href="/dashboard" class="back-link">← Back to Dashboard</a> |
| 11 |
|
| 12 |
<header> |
| 13 |
<h1 class="page-title">Import Data</h1> |
| 14 |
<p class="subtitle">Import subscribers, items, and transaction history from other platforms.</p> |
| 15 |
</header> |
| 16 |
|
| 17 |
<div class="import-form"> |
| 18 |
<div class="form-group"> |
| 19 |
<label for="import-project">Project</label> |
| 20 |
<select id="import-project"> |
| 21 |
{% for p in projects %} |
| 22 |
<option value="{{ p.id }}">{{ p.title }}</option> |
| 23 |
{% endfor %} |
| 24 |
</select> |
| 25 |
</div> |
| 26 |
|
| 27 |
<div class="form-group"> |
| 28 |
<label for="import-file">CSV File</label> |
| 29 |
<input type="file" id="import-file" accept=".csv,text/csv"> |
| 30 |
</div> |
| 31 |
|
| 32 |
<div class="csv-preview hidden" id="csv-preview"> |
| 33 |
<p class="import-preview-label">Preview (first 3 rows):</p> |
| 34 |
<table id="preview-table"></table> |
| 35 |
</div> |
| 36 |
|
| 37 |
<div class="column-mapping hidden" id="column-mapping"> |
| 38 |
<p class="import-mapping-label">Map CSV columns to fields:</p> |
| 39 |
<div class="mapping-row"> |
| 40 |
<label>Email</label> |
| 41 |
<select id="map-email"><option value="">-- skip --</option></select> |
| 42 |
</div> |
| 43 |
<div class="mapping-row"> |
| 44 |
<label>Name</label> |
| 45 |
<select id="map-name"><option value="">-- skip --</option></select> |
| 46 |
</div> |
| 47 |
<div class="mapping-row"> |
| 48 |
<label>Amount</label> |
| 49 |
<select id="map-amount"><option value="">-- skip --</option></select> |
| 50 |
</div> |
| 51 |
<div class="mapping-row"> |
| 52 |
<label>Date</label> |
| 53 |
<select id="map-date"><option value="">-- skip --</option></select> |
| 54 |
</div> |
| 55 |
<div class="mapping-row"> |
| 56 |
<label>Item Title</label> |
| 57 |
<select id="map-item-title"><option value="">-- skip --</option></select> |
| 58 |
</div> |
| 59 |
<div class="mapping-row"> |
| 60 |
<label>Tier</label> |
| 61 |
<select id="map-tier"><option value="">-- skip --</option></select> |
| 62 |
</div> |
| 63 |
<div class="mapping-row"> |
| 64 |
<label>Status</label> |
| 65 |
<select id="map-status"><option value="">-- skip --</option></select> |
| 66 |
</div> |
| 67 |
|
| 68 |
<button id="start-import-btn" class="import-start-btn">Start Import</button> |
| 69 |
</div> |
| 70 |
</div> |
| 71 |
|
| 72 |
<div class="import-progress hidden" id="import-progress"> |
| 73 |
<p class="import-progress-label">Importing...</p> |
| 74 |
<div class="progress-bar-container my-4"> |
| 75 |
<div class="progress-bar progress-bar--highlight" id="progress-bar"></div> |
| 76 |
</div> |
| 77 |
<div class="progress-stats"> |
| 78 |
<span>Processed: <span class="stat-value" id="stat-processed">0</span></span> |
| 79 |
<span>Created: <span class="stat-value" id="stat-created">0</span></span> |
| 80 |
<span>Skipped: <span class="stat-value" id="stat-skipped">0</span></span> |
| 81 |
</div> |
| 82 |
</div> |
| 83 |
|
| 84 |
<div class="import-result hidden" id="import-result"></div> |
| 85 |
|
| 86 |
{% if !jobs.is_empty() %} |
| 87 |
<div class="import-history"> |
| 88 |
<h2 class="import-history-heading">Import History</h2> |
| 89 |
<table class="history-table"> |
| 90 |
<thead> |
| 91 |
<tr> |
| 92 |
<th>Source</th> |
| 93 |
<th>Status</th> |
| 94 |
<th>Rows</th> |
| 95 |
<th>Created</th> |
| 96 |
<th>Date</th> |
| 97 |
</tr> |
| 98 |
</thead> |
| 99 |
<tbody> |
| 100 |
{% for j in jobs %} |
| 101 |
<tr> |
| 102 |
<td>{{ j.source }}</td> |
| 103 |
<td><span class="status-badge {{ j.status }}">{{ j.status }}</span></td> |
| 104 |
<td>{{ j.total_rows }}</td> |
| 105 |
<td>{{ j.created_rows }}</td> |
| 106 |
<td>{{ j.created_at.format("%Y-%m-%d %H:%M") }}</td> |
| 107 |
</tr> |
| 108 |
{% endfor %} |
| 109 |
</tbody> |
| 110 |
</table> |
| 111 |
</div> |
| 112 |
{% endif %} |
| 113 |
|
| 114 |
<div class="import-note"> |
| 115 |
<h3>Supported Formats</h3> |
| 116 |
<p>Currently supports generic CSV files. Upload a CSV with subscriber emails, transaction amounts, or item data, then map columns to the right fields. Coming soon: direct Substack, Ghost, Gumroad, Bandcamp, and Patreon imports.</p> |
| 117 |
</div> |
| 118 |
</div> |
| 119 |
|
| 120 |
<div id="dashboard-import-inline-cfg" hidden data-csrf-token="{{ csrf_token.as_deref().unwrap_or_default() }}"></div> |
| 121 |
<script src="/static/dashboard-import-inline.js?v=0623" defer></script> |
| 122 |
{% endblock %} |
| 123 |
|