diff --git a/apps/www/src/client/App.tsx b/apps/www/src/client/App.tsx index 33a8e30..9df26bd 100644 --- a/apps/www/src/client/App.tsx +++ b/apps/www/src/client/App.tsx @@ -3306,7 +3306,19 @@ function Dashboard({ : []), // Narrower than the two above: the drop mints tokens, and www's route is developer-only. ...(isDeveloper() - ? [{ id: 'tokens', label: 'Token drop', render: () => }] + ? [ + { + id: 'tokens', + label: 'Token drop', + // Two audiences for one gift: whoever is online now, or whoever holds a Discord role. + render: () => ( + <> + + + + ), + }, + ] : []), ] const [active, setActive] = useState(sections[0].id) @@ -3682,6 +3694,97 @@ function TokenDropForm() { ) } +/** + * Developer-only: give every player whose Discord link holds a role the same number of + * tokens, in a gift box carrying the operator's message — the token drop's sibling, with a + * different audience. Offline is the point: the box waits for whoever isn't signed in. + * + * The audience is the roles the website recorded at each player's benefits claim and + * refreshes once a day, so it trails Discord by up to a day and never includes a member who + * hasn't claimed; the copy says so. Same cap as the online drop, repeated on the input. + */ +function RoleTokenDropForm() { + const [roleId, setRoleId] = useState('') + const [message, setMessage] = useState('') + const [tokens, setTokens] = useState('') + const { pending, error, done, run } = useAction() + + return ( +
+

Discord role drop

+

+ Give everyone holding a Discord role the same number of tokens, whether or not they are + online — a player who is signed out finds the gift box waiting. Only players who have + claimed benefits on this site are counted, and their roles are refreshed once a day, so a + role given or taken since then isn't seen yet. Up to {MAX_TOKEN_DROP.toLocaleString()}{' '} + tokens each. +

+
{ + e.preventDefault() + void run(async () => { + const amount = Number(tokens) + const role = roleId.trim() + const res = await call<{ paid: number[] }>( + `/api/staff/discord-roles/${encodeURIComponent(role)}/gift-tokens`, + { authed: true, json: { amount, message: message.trim() } } + ) + setTokens('') + setMessage('') + const n = res.paid.length + return `Sent ${amount.toLocaleString()} tokens to ${n} player${n === 1 ? '' : 's'} holding role ${role}.` + }) + }} + > + +