Diff -- /var/www/vhosts/3dshawn.com/crm.3dshawn.com/TEMPLATES/cf_admin_promotions.html

O Operator
Diff

/var/www/vhosts/3dshawn.com/crm.3dshawn.com/TEMPLATES/cf_admin_promotions.html

added on local at 2026-07-11 18:31:56

Added
+0
lines
Removed
-0
lines
Context
470
unchanged
Blobs
from 3ad49d98eb51
to 3ad49d98eb51
Restore this content →
Unified diff
Naive LCS-based line diff. Additions in emerald, deletions in rose. Both sides decompressed live from BLOB_STORE.
11<!-- =====================================================================
22 Admin Promotions -- platform-wide. ContactForge subscription
33 discounts (coupons, sales, flash sales) covering every customer.
44===================================================================== -->
55
66<div class="page-head">
77 <div>
88 <span class="page-eyebrow"><span class="dot"></span> Admin &middot; Catalogue</span>
99 <h1 class="page-title">Pricing &amp; Promotions</h1>
1010 <p class="page-subtitle">Coupons, sales, and discounts that apply across every ContactForge subscription. Use for new-customer acquisition, seasonal pushes, and limited-time marketing events.</p>
1111 </div>
1212 <div class="page-actions">
1313 [if:$is_list][if:$not_tutorial_mode]<a href="/admin_promotions.cgi?tutorial=1" class="btn btn-secondary"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>Sample Data View</a>[/if][/if]
1414 [if:$is_list][if:$tutorial_mode]<a href="/admin_promotions.cgi" class="btn btn-secondary"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>Exit sample view</a>[/if][/if]
1515 [if:$is_list]<a href="/admin_promotions.cgi?new=1" class="btn btn-primary"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>New platform promotion</a>[/if]
1616 [if:$is_new]<a href="/admin_promotions.cgi" class="btn btn-secondary">Cancel</a>[/if]
1717 [if:$is_edit]<a href="/admin_promotions.cgi" class="btn btn-secondary">Back to list</a>[/if]
1818 </div>
1919</div>
2020
2121<style>
2222 .pp-tabs { display:flex; gap:4px; padding:4px; background:var(--col-surface-2); border:1px solid var(--col-border); border-radius:10px; margin-bottom:22px; width:fit-content; }
2323 .pp-tab { padding:8px 18px; font-size:13px; font-weight:600; color:var(--col-text-2); border-radius:7px; text-decoration:none; transition:background 0.12s, color 0.12s; white-space:nowrap; }
2424 .pp-tab:hover { color:var(--col-text); }
2525 .pp-tab.is-active { background:var(--col-surface-3); color:#fff; box-shadow:inset 0 0 0 1px var(--col-border-2); }
2626 .pr-flash { padding:10px 14px; border-radius:8px; margin-bottom:14px; font-size:13px; }
2727 .pr-flash.ok { background:rgba(34,197,94,0.10); color:#86efac; border:1px solid rgba(34,197,94,0.30); }
2828 .pr-flash.err { background:rgba(239,68,68,0.10); color:#fca5a5; border:1px solid rgba(239,68,68,0.30); }
2929 .pr-kpis { display:grid; grid-template-columns:repeat(6,1fr); gap:12px; margin-bottom:22px; }
3030 .pr-kpi { background:var(--col-surface-1); border:1px solid var(--col-border); border-radius:10px; padding:14px 16px; }
3131 .pr-kpi .lbl { font-size:11px; text-transform:uppercase; letter-spacing:0.08em; color:var(--col-text-2); font-weight:600; }
3232 .pr-kpi .val { font-size:22px; font-weight:700; color:#fff; margin-top:4px; }
3333 .pr-kpi.is-active .val { color:#86efac; }
3434 .pr-kpi.is-scheduled .val { color:#7dd3fc; }
3535 .pr-kpi.is-paused .val { color:#fcd34d; }
3636 .pr-kpi.is-expired .val { color:#fca5a5; }
3737 .pr-table { width:100%; border-collapse:collapse; background:var(--col-surface-1); border:1px solid var(--col-border); border-radius:10px; overflow:hidden; }
3838 .pr-table th, .pr-table td { text-align:left; padding:12px 14px; border-bottom:1px solid var(--col-border); font-size:13px; vertical-align:top; }
3939 .pr-table th { background:var(--col-surface-2); color:var(--col-text-2); font-weight:600; font-size:11px; text-transform:uppercase; letter-spacing:0.06em; }
4040 .pr-table th.num, .pr-table td.num { text-align:right; }
4141 .pr-table tr:last-child td { border-bottom:none; }
4242 .pr-table .name { color:#fff; font-weight:600; }
4343 .pr-table .meta { color:var(--col-text-2); font-size:12px; margin-top:3px; }
4444 .pr-table .actions { white-space:nowrap; }
4545 .pr-table .actions a, .pr-table .actions button { background:none; border:none; color:var(--col-brand); font-size:13px; padding:0; cursor:pointer; }
4646 .pr-table .actions a:hover, .pr-table .actions button:hover { text-decoration:underline; }
4747 .pr-table .actions form { display:inline; }
4848 .pr-table .actions .sep { color:var(--col-text-2); padding:0 6px; }
4949 .pill { display:inline-block; padding:3px 8px; border-radius:99px; font-size:11px; font-weight:600; }
5050 .pill.kind { background:rgba(125,211,252,0.12); color:#7dd3fc; }
5151 .pill.kind.sale { background:rgba(252,211,77,0.12); color:#fcd34d; }
5252 .pill.kind.bundle { background:rgba(167,139,250,0.12); color:#a78bfa; }
5353 .pill.kind.flash { background:rgba(244,114,182,0.12); color:#f472b6; }
5454 .pill.active { background:rgba(34,197,94,0.12); color:#86efac; }
5555 .pill.paused { background:rgba(252,211,77,0.12); color:#fcd34d; }
5656 .pill.scheduled { background:rgba(125,211,252,0.12); color:#7dd3fc; }
5757 .pill.expired { background:rgba(239,68,68,0.12); color:#fca5a5; }
5858 .pill.draft { background:rgba(148,163,184,0.12); color:#94a3b8; }
5959 .pr-form { background:var(--col-surface-1); border:1px solid var(--col-border); border-radius:12px; padding:24px; }
6060 .pr-form-grid { display:grid; grid-template-columns:1fr 1fr; gap:18px 24px; }
6161 .pr-field { display:flex; flex-direction:column; gap:6px; }
6262 .pr-field.full { grid-column:1 / -1; }
6363 .pr-field label { font-size:12px; font-weight:600; color:var(--col-text-2); text-transform:uppercase; letter-spacing:0.05em; }
6464 .pr-field input[type=text], .pr-field input[type=number], .pr-field input[type=datetime-local], .pr-field textarea, .pr-field select { background:var(--col-surface-2); border:1px solid var(--col-border); color:#fff; padding:10px 12px; border-radius:8px; font-size:14px; font-family:inherit; }
6565 .pr-field textarea { min-height:70px; resize:vertical; }
6666 .pr-radio-row { display:flex; gap:8px; flex-wrap:wrap; }
6767 .pr-radio { display:inline-flex; align-items:center; gap:6px; padding:8px 14px; background:var(--col-surface-2); border:1px solid var(--col-border); border-radius:8px; font-size:13px; cursor:pointer; }
6868 .pr-radio.is-on { background:rgba(125,211,252,0.10); border-color:rgba(125,211,252,0.40); color:#7dd3fc; }
6969 .pr-radio input { accent-color:#7dd3fc; }
7070 .hint { font-size:12px; color:var(--col-text-2); }
7171 .pr-actions { display:flex; gap:10px; margin-top:22px; }
7272</style>
7373<nav class="pp-tabs">
7474 <a class="pp-tab" href="/admin_packages.cgi">Packages</a>
7575 <a class="pp-tab is-active" href="/admin_promotions.cgi">Promotions</a>
7676</nav>
7777
7878[if:$tutorial_mode][if:$is_list]
7979<div class="tutorial-banner">
8080 <div class="tutorial-banner-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg></div>
8181 <div class="tutorial-banner-body">
8282 <div class="tutorial-banner-title">Tutorial &middot; Sample data only</div>
8383 <div class="tutorial-banner-text">Three example platform promotions are shown: a new-customer coupon (active, no time limit), a summer sale (scheduled), and a Black Friday flash sale (scheduled with a 5000-redemption cap).</div>
8484 </div>
8585 <a href="/admin_promotions.cgi" class="btn btn-secondary btn-sm">Exit sample view</a>
8686</div>
8787[/if][/if]
8888
8989[if:$has_flash]
9090<div class="pr-flash $flash_kind">$flash_msg</div>
9191[/if]
9292
9393[if:$schema_missing]
9494<div class="an-banner" style="background:rgba(245,158,11,0.10);border-color:rgba(245,158,11,0.30)">
9595 <strong>Promotions schema not yet installed.</strong> Run the promotions migration against the database.
9696</div>
9797[/if]
9898
9999[if:$is_list][if:$schema_ready]
100100<div class="pr-kpis">
101101 <div class="pr-kpi is-active">
102102 <div class="lbl">Active</div>
103103 <div class="val">$cnt_active</div>
104104 </div>
105105 <div class="pr-kpi is-scheduled">
106106 <div class="lbl">Scheduled</div>
107107 <div class="val">$cnt_scheduled</div>
108108 </div>
109109 <div class="pr-kpi is-paused">
110110 <div class="lbl">Paused</div>
111111 <div class="val">$cnt_paused</div>
112112 </div>
113113 <div class="pr-kpi is-expired">
114114 <div class="lbl">Expired</div>
115115 <div class="val">$cnt_expired</div>
116116 </div>
117117 <div class="pr-kpi">
118118 <div class="lbl">Total redemptions</div>
119119 <div class="val">$sum_redemptions</div>
120120 </div>
121121 <div class="pr-kpi">
122122 <div class="lbl">Discount given</div>
123123 <div class="val">$sum_discount_display</div>
124124 </div>
125125</div>
126126
127127[if:$has_rows]
128128<table class="pr-table">
129129 <thead>
130130 <tr>
131131 <th>Promotion</th>
132132 <th>Kind</th>
133133 <th>Discount</th>
134134 <th>Window</th>
135135 <th>Usage</th>
136136 <th class="num">Discount given</th>
137137 <th>Status</th>
138138 <th>Actions</th>
139139 </tr>
140140 </thead>
141141 <tbody>
142142 [loop:@rows]
143143 <tr>
144144 <td>
145145 <div class="name">$loop1.name</div>
146146 <div class="meta">
147147 [if:$loop1.code_present]Code: <code>$loop1.code</code>[/if]
148148 [if:$loop1.slug_present][if:$loop1.code_present] &middot; [/if]Link: <code>/promo/$loop1.public_slug</code>[/if]
149149 [if:$loop1.new_customers_only] &middot; <span style="color:#86efac">New customers only</span>[/if]
150150 </div>
151151 </td>
152152 <td>
153153 [if:$loop1.is_coupon]<span class="pill kind">Coupon</span>[/if]
154154 [if:$loop1.is_sale]<span class="pill kind sale">Sale</span>[/if]
155155 [if:$loop1.is_bundle]<span class="pill kind bundle">Bundle</span>[/if]
156156 [if:$loop1.is_flash]<span class="pill kind flash">Flash sale</span>[/if]
157157 </td>
158158 <td>$loop1.discount_label</td>
159159 <td>
160160 [if:$loop1.has_window]
161161 <div class="meta" style="font-size:12px;color:var(--col-text-2)">
162162 <span class="ts" data-ts="$loop1.starts_epoch" data-fmt="date">$loop1.starts_at</span> <br>&rarr; <span class="ts" data-ts="$loop1.ends_epoch" data-fmt="date">$loop1.ends_at</span>
163163 </div>
164164 [/if]
165165 [if:!$loop1.has_window]<span class="text-xs text-dim">No time limit</span>[/if]
166166 </td>
167167 <td>$loop1.cap_label</td>
168168 <td class="num">$loop1.discount_given_display</td>
169169 <td>
170170 [if:$loop1.is_active]<span class="pill active">Active</span>[/if]
171171 [if:$loop1.is_paused]<span class="pill paused">Paused</span>[/if]
172172 [if:$loop1.is_scheduled]<span class="pill scheduled">Scheduled</span>[/if]
173173 [if:$loop1.is_expired]<span class="pill expired">Expired</span>[/if]
174174 [if:$loop1.is_draft]<span class="pill draft">Draft</span>[/if]
175175 </td>
176176 <td class="actions">
177177 <a href="$loop1.edit_url">Edit</a>
178178 [if:$loop1.is_active]
179179 <span class="sep">&middot;</span>
180180 <form method="POST" action="/admin_promotion_action.cgi">
181181 <input type="hidden" name="act" value="pause">
182182 <input type="hidden" name="id" value="$loop1.id">
183183 <button type="submit">Pause</button>
184184 </form>
185185 [/if]
186186 [if:$loop1.is_scheduled]
187187 <span class="sep">&middot;</span>
188188 <form method="POST" action="/admin_promotion_action.cgi">
189189 <input type="hidden" name="act" value="pause">
190190 <input type="hidden" name="id" value="$loop1.id">
191191 <button type="submit">Pause</button>
192192 </form>
193193 [/if]
194194 [if:$loop1.is_paused]
195195 <span class="sep">&middot;</span>
196196 <form method="POST" action="/admin_promotion_action.cgi">
197197 <input type="hidden" name="act" value="activate">
198198 <input type="hidden" name="id" value="$loop1.id">
199199 <button type="submit">Activate</button>
200200 </form>
201201 [/if]
202202 [if:$loop1.is_draft]
203203 <span class="sep">&middot;</span>
204204 <form method="POST" action="/admin_promotion_action.cgi">
205205 <input type="hidden" name="act" value="activate">
206206 <input type="hidden" name="id" value="$loop1.id">
207207 <button type="submit">Activate</button>
208208 </form>
209209 [/if]
210210 <span class="sep">&middot;</span>
211211 <form method="POST" action="/admin_promotion_action.cgi"
212212 onsubmit="return confirm('Delete this promotion permanently? Redemption history is also removed.');">
213213 <input type="hidden" name="act" value="delete">
214214 <input type="hidden" name="id" value="$loop1.id">
215215 <button type="submit" style="color:#fca5a5">Delete</button>
216216 </form>
217217 </td>
218218 </tr>
219219 [/loop]
220220 </tbody>
221221</table>
222222[/if]
223223
224224[if:!$has_rows]
225225<div style="text-align:center;padding:60px 24px;background:var(--col-surface-1);border:1px solid var(--col-border);border-radius:12px">
226226 <div class="text-sm fw-600" style="color:#fff;margin-bottom:6px">No platform promotions yet</div>
227227 <div class="text-xs text-dim" style="margin-bottom:14px;max-width:380px;margin-left:auto;margin-right:auto">Create coupons or sales to bring new customers onto the platform.</div>
228228 <a href="/admin_promotions.cgi?new=1" class="btn btn-primary btn-sm">Create your first platform promotion</a>
229229</div>
230230[/if]
231231[/if][/if]
232232
233233[if:$is_new][if:$schema_ready]
234234<form class="pr-form" method="POST" action="/admin_promotion_action.cgi">
235235 <input type="hidden" name="act" value="create">
236236 <div class="pr-form-grid">
237237 <div class="pr-field full">
238238 <label>Name</label>
239239 <input type="text" name="name" required maxlength="160" placeholder="e.g. New customer 20% off first month">
240240 </div>
241241
242242 <div class="pr-field full">
243243 <label>Description</label>
244244 <textarea name="description" maxlength="500"></textarea>
245245 </div>
246246
247247 <div class="pr-field full">
248248 <label>Kind</label>
249249 <div class="pr-radio-row">
250250 <label class="pr-radio is-on"><input type="radio" name="kind" value="coupon" checked> Coupon</label>
251251 <label class="pr-radio"><input type="radio" name="kind" value="sale"> Sale</label>
252252 <label class="pr-radio"><input type="radio" name="kind" value="flash_sale"> Flash sale</label>
253253 </div>
254254 </div>
255255
256256 <div class="pr-field full">
257257 <label>Applies to plans</label>
258258 <div class="pr-radio-row" data-applies-radio>
259259 <label class="pr-radio is-on"><input type="radio" name="plan_scope" value="all" checked data-plan-scope> All paid plans</label>
260260 <label class="pr-radio"><input type="radio" name="plan_scope" value="specific" data-plan-scope> Specific plan(s)</label>
261261 </div>
262262 <div class="hint" style="margin-top:6px">Platform promos always discount ContactForge subscriptions.</div>
263263 [if:$has_plan_options]
264264 <div data-plan-picker style="display:none;margin-top:10px;padding:10px 12px;border:1px solid var(--col-border);border-radius:8px;background:rgba(255,255,255,0.02)">
265265 <div class="hint" style="margin:0 0 8px">Check every plan this code should be redeemable on. Leave all unchecked to fall back to "All paid plans".</div>
266266 [loop:@plan_options]
267267 <label class="pr-radio" style="display:flex;align-items:center;gap:8px;margin-bottom:6px">
268268 <input type="checkbox" name="plan_ids" value="[$loop1.id]"> <strong>[$loop1.display_name]</strong> &mdash; [$loop1.price_display] / mo
269269 </label>
270270 [/loop]
271271 </div>
272272 [/if]
273273 </div>
274274
275275 <div class="pr-field">
276276 <label>Discount type</label>
277277 <select name="discount_type">
278278 <option value="percent">Percent off</option>
279279 <option value="fixed_amount">Fixed amount off</option>
280280 </select>
281281 </div>
282282
283283 <div class="pr-field">
284284 <label>Discount value</label>
285285 <div style="display:flex;gap:8px;align-items:center">
286286 <input type="number" name="discount_value_pct" min="0" max="100" step="1" placeholder="0" style="width:80px">
287287 <span class="hint">% off</span>
288288 <span class="hint">or</span>
289289 <input type="number" name="discount_value_amt" min="0" step="0.01" placeholder="0.00" style="width:100px">
290290 <span class="hint">\$ off</span>
291291 </div>
292292 </div>
293293
294294 <div class="pr-field">
295295 <label>Coupon code</label>
296296 <input type="text" name="code" maxlength="64" placeholder="NEWBIE20" style="text-transform:uppercase">
297297 </div>
298298
299299 <div class="pr-field">
300300 <label>Public slug</label>
301301 <input type="text" name="public_slug" maxlength="64" placeholder="newbie20" style="text-transform:lowercase">
302302 </div>
303303
304304 <div class="pr-field">
305305 <label>Starts at</label>
306306 <input type="datetime-local" name="starts_at_local">
307307 </div>
308308
309309 <div class="pr-field">
310310 <label>Ends at</label>
311311 <input type="datetime-local" name="ends_at_local">
312312 </div>
313313
314314 <div class="pr-field">
315315 <label>Max total redemptions</label>
316316 <input type="number" name="max_redemptions" min="0" placeholder="Unlimited">
317317 </div>
318318
319319 <div class="pr-field">
320320 <label>Max per customer</label>
321321 <input type="number" name="max_per_user" min="1" value="1">
322322 </div>
323323
324324 <div class="pr-field">
325325 <label>Minimum order total</label>
326326 <input type="number" name="minimum_order" min="0" step="0.01" placeholder="0.00">
327327 </div>
328328
329329 <div class="pr-field">
330330 <label>New customers only</label>
331331 <label class="pr-radio" style="display:inline-flex"><input type="checkbox" name="new_customers_only" value="1"> Only first-time subscribers</label>
332332 </div>
333333 </div>
334334
335335 <div class="pr-actions">
336336 <button type="submit" name="publish_now" value="1" class="btn btn-primary">Create &amp; activate</button>
337337 <button type="submit" class="btn btn-secondary">Save as draft</button>
338338 </div>
339339</form>
340340[/if][/if]
341341
342342[if:$is_edit][if:$schema_ready][if:$has_edit]
343343<form class="pr-form" method="POST" action="/admin_promotion_action.cgi">
344344 <input type="hidden" name="act" value="update">
345345 <input type="hidden" name="id" value="$edit.id">
346346 <div class="pr-form-grid">
347347 <div class="pr-field full">
348348 <label>Name</label>
349349 <input type="text" name="name" required maxlength="160" value="$edit.name">
350350 </div>
351351
352352 <div class="pr-field full">
353353 <label>Description</label>
354354 <textarea name="description" maxlength="500">$edit.description</textarea>
355355 </div>
356356
357357 <div class="pr-field full">
358358 <label>Kind</label>
359359 <div class="pr-radio-row">
360360 <label class="pr-radio[if:$edit.is_coupon] is-on[/if]"><input type="radio" name="kind" value="coupon"[if:$edit.is_coupon] checked[/if]> Coupon</label>
361361 <label class="pr-radio[if:$edit.is_sale] is-on[/if]"><input type="radio" name="kind" value="sale"[if:$edit.is_sale] checked[/if]> Sale</label>
362362 <label class="pr-radio[if:$edit.is_flash] is-on[/if]"><input type="radio" name="kind" value="flash_sale"[if:$edit.is_flash] checked[/if]> Flash sale</label>
363363 </div>
364364 </div>
365365
366366 <div class="pr-field full">
367367 <label>Applies to plans</label>
368368 <div class="pr-radio-row" data-applies-radio>
369369 <label class="pr-radio[if:$edit.applies_all_plans] is-on[/if]"><input type="radio" name="plan_scope" value="all"[if:$edit.applies_all_plans] checked[/if] data-plan-scope> All paid plans</label>
370370 <label class="pr-radio[if:$edit.applies_specific] is-on[/if]"><input type="radio" name="plan_scope" value="specific"[if:$edit.applies_specific] checked[/if] data-plan-scope> Specific plan(s)</label>
371371 </div>
372372 [if:$has_plan_options]
373373 <div data-plan-picker style="margin-top:10px;padding:10px 12px;border:1px solid var(--col-border);border-radius:8px;background:rgba(255,255,255,0.02)">
374374 <div class="hint" style="margin:0 0 8px">Check every plan this code should be redeemable on. Leave all unchecked to fall back to "All paid plans".</div>
375375 [loop:@plan_options]
376376 <label class="pr-radio" style="display:flex;align-items:center;gap:8px;margin-bottom:6px">
377377 <input type="checkbox" name="plan_ids" value="[$loop1.id]" [$loop1.checked]> <strong>[$loop1.display_name]</strong> &mdash; [$loop1.price_display] / mo
378378 </label>
379379 [/loop]
380380 </div>
381381 [/if]
382382 </div>
383383
384384 <div class="pr-field">
385385 <label>Discount type</label>
386386 <select name="discount_type">
387387 <option value="percent"[if:$edit.is_dtype_pct] selected[/if]>Percent off</option>
388388 <option value="fixed_amount"[if:$edit.is_dtype_amt] selected[/if]>Fixed amount off</option>
389389 </select>
390390 </div>
391391
392392 <div class="pr-field">
393393 <label>Discount value</label>
394394 <div style="display:flex;gap:8px;align-items:center">
395395 <input type="number" name="discount_value_pct" min="0" max="100" step="1" value="$edit.discount_value_pct" style="width:80px">
396396 <span class="hint">% off</span>
397397 <span class="hint">or</span>
398398 <input type="number" name="discount_value_amt" min="0" step="0.01" value="$edit.discount_value_amt" style="width:100px">
399399 <span class="hint">\$ off</span>
400400 </div>
401401 </div>
402402
403403 <div class="pr-field">
404404 <label>Coupon code</label>
405405 <input type="text" name="code" maxlength="64" value="$edit.code" style="text-transform:uppercase">
406406 </div>
407407
408408 <div class="pr-field">
409409 <label>Public slug</label>
410410 <input type="text" name="public_slug" maxlength="64" value="$edit.public_slug" style="text-transform:lowercase">
411411 </div>
412412
413413 <div class="pr-field">
414414 <label>Starts at</label>
415415 <input type="datetime-local" name="starts_at_local" value="$edit.starts_at_local">
416416 </div>
417417
418418 <div class="pr-field">
419419 <label>Ends at</label>
420420 <input type="datetime-local" name="ends_at_local" value="$edit.ends_at_local">
421421 </div>
422422
423423 <div class="pr-field">
424424 <label>Max total redemptions</label>
425425 <input type="number" name="max_redemptions" min="0" value="$edit.max_redemptions" placeholder="Unlimited">
426426 </div>
427427
428428 <div class="pr-field">
429429 <label>Max per customer</label>
430430 <input type="number" name="max_per_user" min="1" value="$edit.max_per_user">
431431 </div>
432432
433433 <div class="pr-field">
434434 <label>Minimum order total</label>
435435 <input type="number" name="minimum_order" min="0" step="0.01" value="$edit.minimum_order">
436436 </div>
437437
438438 <div class="pr-field">
439439 <label>New customers only</label>
440440 <label class="pr-radio" style="display:inline-flex"><input type="checkbox" name="new_customers_only" value="1"[if:$edit.new_customers_only] checked[/if]> Only first-time subscribers</label>
441441 </div>
442442 </div>
443443
444444 <div class="pr-actions">
445445 <button type="submit" class="btn btn-primary">Save changes</button>
446446 <a href="/admin_promotions.cgi" class="btn btn-secondary">Cancel</a>
447447 </div>
448448</form>
449449[/if][/if][/if]
450450
451451<script>
452452 (function () {
453453 document.querySelectorAll('form').forEach(function (form) {
454454 var radios = form.querySelectorAll('[data-plan-scope]');
455455 var picker = form.querySelector('[data-plan-picker]');
456456 if (!radios.length || !picker) return;
457457 function sync() {
458458 var sel = form.querySelector('[data-plan-scope]:checked');
459459 picker.style.display = (sel && sel.value === 'specific') ? '' : 'none';
460460 if (!sel || sel.value !== 'specific') {
461461 picker.querySelectorAll('input[type=checkbox]').forEach(function (cb) { cb.checked = false; });
462462 }
463463 }
464464 radios.forEach(function (r) { r.addEventListener('change', sync); });
465465 sync();
466466 });
467467 })();
468468</script>
469469
470470<div class="adm-foot-spacer" data-end="admin-promotions">&nbsp;</div>