import { useCallback, useState } from 'react'
import { Link } from 'react-router-dom'
import { Loading, ErrorState } from '../../components/PageState.jsx'
import { useAsync } from '../../lib/useAsync.js'
import { ago, dateTime } from '../../lib/format.js'
import { api } from '../../api/client.js'
// Player-facing appeals: eligible sanctions the player can appeal, plus the
// status of appeals they've already submitted. Mirrors PlayerAccount's
// Section layout.
const STATUS_STYLE = {
pending: { color: '#e0b070', background: 'rgba(224,176,112,0.12)', border: '1px solid rgba(224,176,112,0.4)' },
under_review: { color: '#7fa8d0', background: 'rgba(127,168,208,0.14)', border: '1px solid rgba(127,168,208,0.4)' },
approved: { color: '#7fd0a4', background: 'rgba(95,185,138,0.16)', border: '1px solid rgba(95,185,138,0.4)' },
denied: { color: '#d98b84', background: 'rgba(217,139,132,0.16)', border: '1px solid rgba(217,139,132,0.4)' },
withdrawn: { color: '#9fb0c6', background: 'rgba(127,153,189,0.14)', border: '1px solid var(--line)' },
}
const STATUS_LABEL = {
pending: 'Pending',
under_review: 'Under review',
approved: 'Approved',
denied: 'Denied',
withdrawn: 'Withdrawn',
}
function fmtDuration(seconds) {
if (!seconds) return null
if (seconds % 86400 === 0) return `${seconds / 86400}d`
if (seconds % 3600 === 0) return `${seconds / 3600}h`
if (seconds % 60 === 0) return `${seconds / 60}m`
return `${seconds}s`
}
function Section({ title, children }) {
return (
{title}
{children}
{item.reason || 'No reason given.'}
{!open ? ({error}
}You have no sanctions available to appeal right now.
If you were sanctioned on Discord, link your Discord account on the{' '} Account page to appeal.
{appeal.submitted_text}
{appeal.staff_response && ({appeal.staff_response}
{error}
} {canWithdraw && (You haven't submitted any appeals yet.
} return (Appeal a Discord ban or mute, or check the status of an appeal you've already submitted.