Skip to content

Commit 83f07a1

Browse files
committed
feat(donations): add "Resend receipt" action to the donations list
Shows a resend button on rows that have a valid donor email and a successful payment. It calls /logs/resend_receipt and surfaces the result as an inline toast — no page reload.
1 parent 008d760 commit 83f07a1

1 file changed

Lines changed: 59 additions & 1 deletion

File tree

‎donations.php‎

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,14 @@
108108
<?php endif; ?>
109109
</td>
110110
<td style="padding-right:20px;text-align:center;white-space:nowrap;">
111+
<?php if (filter_var($row['mail'] ?? '', FILTER_VALIDATE_EMAIL) && $row['payment_status']==1): ?>
112+
<button type="button" class="btn btn-gradient-success btn-xs me-1 js-resend-receipt"
113+
data-rid="<?= (int)$row['id'] ?>"
114+
data-mail="<?= htmlspecialchars($row['mail']) ?>"
115+
title="Resend receipt email to <?= htmlspecialchars($row['mail']) ?>">
116+
<i class="mdi mdi-email-outline"></i>
117+
</button>
118+
<?php endif; ?>
111119
<a href="manage_donations?rid=<?= $row['id'] ?>" class="btn btn-gradient-info btn-xs me-1">
112120
<i class="mdi mdi-pencil"></i>
113121
</a>
@@ -145,4 +153,54 @@
145153

146154
</div>
147155
<?php include 'includes/footer.php'; ?>
148-
</div>
156+
</div>
157+
158+
<!-- ── Resend receipt (inline, no page reload) ─────────────────────────── -->
159+
<script>
160+
(function () {
161+
"use strict";
162+
const API_BASE = "<?= rtrim($api_url, '/') ?>";
163+
164+
function toast(message, ok) {
165+
const t = document.createElement('div');
166+
t.textContent = message;
167+
t.style.cssText =
168+
'position:fixed;z-index:3000;right:20px;bottom:20px;max-width:340px;' +
169+
'padding:12px 16px;border-radius:10px;color:#fff;font-size:.86rem;' +
170+
'box-shadow:0 6px 20px rgba(0,0,0,.18);' +
171+
(ok ? 'background:#2a7d4f;' : 'background:#c0392b;');
172+
document.body.appendChild(t);
173+
setTimeout(function () {
174+
t.style.transition = 'opacity .4s';
175+
t.style.opacity = '0';
176+
setTimeout(function () { t.remove(); }, 400);
177+
}, 3400);
178+
}
179+
180+
document.querySelectorAll('.js-resend-receipt').forEach(function (btn) {
181+
btn.addEventListener('click', function () {
182+
const rid = btn.getAttribute('data-rid');
183+
const mail = btn.getAttribute('data-mail') || 'this donor';
184+
if (!rid) return;
185+
if (!confirm('Resend the donation receipt to ' + mail + '?')) return;
186+
187+
const icon = btn.querySelector('i');
188+
const prev = icon ? icon.className : '';
189+
if (icon) icon.className = 'mdi mdi-loading mdi-spin';
190+
btn.disabled = true;
191+
192+
fetch(API_BASE + '/logs/resend_receipt?rid=' + encodeURIComponent(rid))
193+
.then(function (r) { return r.json(); })
194+
.then(function (j) {
195+
toast(j.message || (j.status === 'success' ? 'Receipt sent.' : 'Could not send receipt.'),
196+
j.status === 'success');
197+
})
198+
.catch(function () { toast('Network error. Please try again.', false); })
199+
.finally(function () {
200+
if (icon) icon.className = prev;
201+
btn.disabled = false;
202+
});
203+
});
204+
});
205+
})();
206+
</script>

0 commit comments

Comments
 (0)