feat(appeals): Task #126 Phase 2 — Trinity Appeals form on policy page

Replaces the mailto: section on /cancellation-refund with a real form
that POSTs to https://discord-bot.firefrostgaming.com/api/appeals/submit.

Form fields: discord_username, email, circumstances, requested_outcome
Client-side: disables button during submit, shows result inline
Success: displays confirmation + appeal reference ID
Failure: shows error + falls back to support@ mailto

Backend was deployed earlier in this session — this closes the full
Phase 2 user-facing flow. End-to-end tested via curl; browser test
still needed post-deploy.

Preserves the mailto: line as a fallback below the form in case the
API endpoint is unreachable.
This commit is contained in:
Claude
2026-04-12 00:08:07 +00:00
parent c0dcd9ab02
commit 8f4823b6dd

View File

@@ -40,15 +40,73 @@ description: Firefrost Gaming Cancellation and Refund Policy — We Don't Kick P
<h2 style="color: #4ecdc4; font-size: 2rem; margin-top: 40px; margin-bottom: 20px;">The Trinity Appeal Process</h2>
<p>We believe in second chances. If your access has been removed — whether due to a refund, chargeback, or other action — you have the right to appeal directly to the Trinity (Michael, Meg, and Holly, the co-founders of Firefrost Gaming).</p>
<p>To submit an appeal, please email <a href="mailto:support@firefrostgaming.com?subject=Trinity%20Appeal" style="color: #FFD700;">support@firefrostgaming.com</a> with the subject line <strong>"Trinity Appeal"</strong> and include:</p>
<ul style="margin-left: 20px; margin-bottom: 20px;">
<li style="margin-bottom: 10px;">Your Discord username</li>
<li style="margin-bottom: 10px;">The email address used for your subscription</li>
<li style="margin-bottom: 10px;">A brief explanation of the circumstances</li>
<li style="margin-bottom: 10px;">What outcome you are requesting</li>
</ul>
<p>The Trinity reviews every appeal personally. We will respond within 7 days. Decisions are made with compassion and context — we understand that mistakes happen, billing systems can be confusing, and life is complicated.</p>
<p style="color: #6b7280; font-style: italic; margin-top: 20px;">A dedicated appeals submission form with case tracking will be available in a future update. For now, email remains the primary channel.</p>
<p>To submit an appeal, please fill out the form below. The Trinity reviews every submission personally and responds within 7 days. Decisions are made with compassion and context — we understand that mistakes happen, billing systems can be confusing, and life is complicated.</p>
<form id="appealForm" style="margin-top: 30px; padding: 30px; background: rgba(168, 85, 247, 0.08); border: 1px solid rgba(168, 85, 247, 0.3); border-radius: 12px;">
<div style="margin-bottom: 20px;">
<label for="discord_username" style="display: block; color: #FFD700; font-weight: 600; margin-bottom: 8px;">Discord Username</label>
<input type="text" id="discord_username" name="discord_username" required maxlength="100" style="width: 100%; padding: 12px; background: #1a1a2e; border: 1px solid rgba(78, 205, 196, 0.3); border-radius: 6px; color: #e8f4f8; font-size: 1rem;" />
</div>
<div style="margin-bottom: 20px;">
<label for="email" style="display: block; color: #FFD700; font-weight: 600; margin-bottom: 8px;">Email (used for your subscription)</label>
<input type="email" id="email" name="email" required maxlength="255" style="width: 100%; padding: 12px; background: #1a1a2e; border: 1px solid rgba(78, 205, 196, 0.3); border-radius: 6px; color: #e8f4f8; font-size: 1rem;" />
</div>
<div style="margin-bottom: 20px;">
<label for="circumstances" style="display: block; color: #FFD700; font-weight: 600; margin-bottom: 8px;">What happened? (circumstances of the ban or concern)</label>
<textarea id="circumstances" name="circumstances" required maxlength="5000" rows="6" style="width: 100%; padding: 12px; background: #1a1a2e; border: 1px solid rgba(78, 205, 196, 0.3); border-radius: 6px; color: #e8f4f8; font-size: 1rem; resize: vertical;"></textarea>
</div>
<div style="margin-bottom: 20px;">
<label for="requested_outcome" style="display: block; color: #FFD700; font-weight: 600; margin-bottom: 8px;">What outcome are you requesting?</label>
<textarea id="requested_outcome" name="requested_outcome" required maxlength="2000" rows="3" style="width: 100%; padding: 12px; background: #1a1a2e; border: 1px solid rgba(78, 205, 196, 0.3); border-radius: 6px; color: #e8f4f8; font-size: 1rem; resize: vertical;"></textarea>
</div>
<button type="submit" id="appealSubmit" style="padding: 14px 40px; background: linear-gradient(135deg, #a855f7 0%, #4ecdc4 100%); color: white; border: none; border-radius: 8px; font-size: 1.1rem; font-weight: 700; cursor: pointer;">Submit Appeal to the Trinity</button>
<div id="appealResult" style="margin-top: 20px; padding: 15px; border-radius: 8px; display: none;"></div>
</form>
<script>
document.getElementById('appealForm').addEventListener('submit', async (e) => {
e.preventDefault();
const btn = document.getElementById('appealSubmit');
const result = document.getElementById('appealResult');
btn.disabled = true;
btn.textContent = 'Submitting...';
result.style.display = 'none';
try {
const res = await fetch('https://discord-bot.firefrostgaming.com/api/appeals/submit', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
discord_username: document.getElementById('discord_username').value,
email: document.getElementById('email').value,
circumstances: document.getElementById('circumstances').value,
requested_outcome: document.getElementById('requested_outcome').value
})
});
const data = await res.json();
if (res.ok) {
result.style.display = 'block';
result.style.background = 'rgba(78, 205, 196, 0.15)';
result.style.border = '1px solid #4ecdc4';
result.style.color = '#4ecdc4';
result.innerHTML = '<strong>✓ ' + data.message + '</strong><br>Appeal reference: #' + data.appeal_id;
document.getElementById('appealForm').reset();
btn.textContent = 'Appeal Submitted';
} else {
throw new Error(data.error || 'Submission failed');
}
} catch (err) {
result.style.display = 'block';
result.style.background = 'rgba(255, 107, 53, 0.15)';
result.style.border = '1px solid #ff6b35';
result.style.color = '#ff6b35';
result.innerHTML = '<strong>Submission failed:</strong> ' + err.message + '<br>Please email <a href="mailto:support@firefrostgaming.com" style="color: #FFD700;">support@firefrostgaming.com</a> directly.';
btn.disabled = false;
btn.textContent = 'Submit Appeal to the Trinity';
}
});
</script>
<p style="color: #6b7280; font-style: italic; margin-top: 20px;">Alternatively, you may email <a href="mailto:support@firefrostgaming.com?subject=Trinity%20Appeal" style="color: #a8dadc;">support@firefrostgaming.com</a> with the subject "Trinity Appeal" if the form is unavailable.</p>
<h2 style="color: #4ecdc4; font-size: 2rem; margin-top: 40px; margin-bottom: 20px;">Hard Bans</h2>
<p>We only remove all Firefrost Gaming access — including Awakened — in two circumstances:</p>