Skip to content

Add sponsorship requests form and admin system#3431

Merged
anoek merged 6 commits intomainfrom
prize-requests
Mar 10, 2026
Merged

Add sponsorship requests form and admin system#3431
anoek merged 6 commits intomainfrom
prize-requests

Conversation

@anoek
Copy link
Member

@anoek anoek commented Mar 9, 2026

No description provided.

@github-actions
Copy link

github-actions bot commented Mar 9, 2026

Code Review — Sponsorship Request feature

Bug: No date range validation in SponsorshipRequest.tsx

formValid checks that startDate and endDate are non-empty but never verifies that the end date falls on or after the start date. A request where the tournament ends before it starts can be submitted successfully. Adding endDate >= startDate (or equivalent comparison) to the formValid expression would prevent this.


Bug: Multiple components defined in SponsorshipRequestAdmin.tsx

SponsorshipRequestDetail and EditModal are both defined in the same file. The project requires one component per file for Vite HMR correctness (CLAUDE.md). EditModal should be extracted to its own EditModal.tsx / EditModal.css pair in the same directory.


Bug: Untranslated user-visible strings in PrizeBatchList.tsx

Several hardcoded English strings were added to the admin list view without translation wrappers, e.g.:

<h2>Pending Tournament Prize Requests</h2>
// ...
<span>Organizer: {req.name} | Players: {req.expected_players} | ...</span>
// ...
<h2>Past Tournament Prize Requests</h2>

Per project rules, all user-visible strings must go through _() / pgettext().

@github-actions
Copy link

Auth race condition in SponsorshipRequestAdmin.tsx: the useEffect reads user.is_superuser but user is not in the dependency array ([params.id]). If user data has not loaded when the component mounts, is_superuser is falsy and the component redirects immediately before the real auth state is confirmed. A superuser going directly to /sponsorship-requests/:id could be sent to / or see a perpetual loading screen. user or user.is_superuser should be added to the dependency array.

Untranslated strings in PrizeBatchList.tsx: the section headings Pending Tournament Prize Requests and Past Tournament Prize Requests, inline labels Organizer, Players, Review, View, and the raw req.status value rendered as brackets around req.status are not wrapped in translation functions, violating the project rule that all user-visible strings must be translated.

DURATION_OPTIONS labels cannot be translated in SponsorshipRequestTypes.ts: the label values such as 30 days and 60 days are plain strings defined at module load time. They cannot go through the translation system and are rendered directly in option elements in both SponsorshipRequest.tsx and EditModal.tsx. They need to be computed at render time to be translatable.

Missing user feedback on submission failure in SponsorshipRequest.tsx: when the POST in handleSubmit fails, only console.error is called and the button is re-enabled with no message shown to the user. A toast in the catch block would be consistent with how other actions in this PR handle errors.

@github-actions
Copy link

Code Review: Sponsorship Request Feature

Bug: getDurationLabel displays literal %s instead of the day count

In src/views/Prizes/SponsorshipRequestTypes.ts:

export function getDurationLabel(days: number): string {
    return ngettext("%s day", "%s days", days);
}

ngettext selects the correct singular/plural form but does not substitute %s. The duration dropdowns in both SponsorshipRequest.tsx and EditModal.tsx will display literally "%s days" instead of "30 days", "60 days", etc. It should use interpolate():

export function getDurationLabel(days: number): string {
    return interpolate(ngettext("%s day", "%s days", days), [days]);
}

Bug: No user-facing error feedback for approve/reject failures

In src/views/Prizes/SponsorshipRequestAdmin.tsx, both handleApprove and handleReject silently swallow errors — only logging to the console:

.catch((err: unknown) => {
    console.error("Error approving request:", err);
    setProcessing(false);
});

If the API call fails, the buttons just re-enable with no explanation. A toast(...) call is needed in the catch handler for both actions, consistent with how the success path already uses toast.


Untranslated user-visible strings in PrizeBatchList.tsx

Several hardcoded English strings skip the translation wrapper, violating the project's translation requirement:

<h2>Pending Tournament Prize Requests</h2>
<h2>Past Tournament Prize Requests</h2>

<span>Organizer: {req.name} | Players: {req.expected_players} | ...</span>
<span>Organizer: {req.name} | ...</span>

<Link ...>Review</Link>
<Link ...>View</Link>

Also, in SponsorshipRequestAdmin.tsx, the word "to" between the tournament dates and the raw request.status.toUpperCase() displayed in the status badge are not translated.

@github-actions
Copy link

Code Review

Bugs and issues found:


1. CI tests disabled (Critical)

Both .github/workflows/e2e_test.yml and .github/workflows/unit_test.yml have their push and pull_request triggers commented out, leaving only workflow_dispatch. If this lands as-is, CI will stop running automatically on all future PRs and pushes to main. This appears to be a leftover from local development.


2. Missing user in useEffect dependency array (SponsorshipRequestAdmin.tsx)

useEffect(() => {
    if (!user.is_superuser) {
        void navigate("/");
        return;
    }
    get(`prizes/sponsorship-requests/${params.id}`)...
}, [params.id]);  // user and navigate are missing

user and navigate are used inside the effect but are absent from the dependency array. The user object can be updated asynchronously via the user/update socket event — if that fires after mount, the stale closure will be used for the access check and the data fetch won't re-run. ESLint's exhaustive-deps rule should flag this.


3. Silent API failures on approve/reject (SponsorshipRequestAdmin.tsx)

The error handlers for handleApprove and handleReject only call console.error. If either POST fails, the admin sees no indication — the buttons re-enable but there is no toast, alert, or any visible feedback that the action failed. Compare with handleSaveEdit which has the same structure but this oversight still applies there. SponsorshipRequest.tsx correctly shows a toast on submission failure; the same pattern should be used here.


4. Pricing fetch failure leaves form permanently stuck (SponsorshipRequest.tsx and SponsorshipRequestAdmin.tsx)

get("prizes/pricing")
    .then((data: SupporterPricing) => setPricing(data))
    .catch((err: unknown) => console.error("Error fetching pricing:", err));

If the pricing fetch fails, pricing remains null forever and the component renders {_("Loading...")} indefinitely with no error message or retry option. Both components have this pattern. The user has no way to know why the page isn't loading or that they should refresh.

@anoek anoek merged commit 6cf5495 into main Mar 10, 2026
6 checks passed
@github-actions
Copy link

Untranslated user-visible strings

Several strings added in this PR are not wrapped in translation functions, which is required per project conventions (all user-visible strings must use pgettext/_/etc. from @/lib/translate).

In src/views/Prizes/PrizeBatchList.tsx, the new sponsorship request sections contain raw string literals: the headings 'Pending Tournament Prize Requests' and 'Past Tournament Prize Requests', the inline labels 'Organizer:' and 'Players:' in the list items, and the link text 'Review' and 'View' are all untranslated.

In src/views/Prizes/SponsorshipRequestAdmin.tsx, the word 'to' between the start and end dates is also untranslated:

<strong>{_("Dates")}:</strong> {request.tournament_start_date} to{" "}
{request.tournament_end_date}

These should be wrapped with _() or pgettext() (and interpolate() for the parameterized organizer/players strings).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants