Skip to content

Frontend#96

Merged
BDonat05 merged 6 commits intotestfrom
frontend
Apr 15, 2026
Merged

Frontend#96
BDonat05 merged 6 commits intotestfrom
frontend

Conversation

@BDonat05
Copy link
Copy Markdown
Collaborator

fixes mostly

CsakEgyBago and others added 6 commits April 15, 2026 19:10
…localStorage

If the value stored under the "settings" key in localStorage is invalid JSON
(browser extension overwrite, storage corruption, manual DevTools edit, power-loss
mid-write), the previous unguarded JSON.parse threw a SyntaxError during the
SettingsProvider useState initializer. Because SettingsProvider sits at the root of
the component tree, this crashed the entire app with a blank screen and no recovery
path for the user.

Fixed by wrapping the JSON.parse call in a try/catch that falls back to null on
failure, matching the already-correct pattern used in useDebugSettings.ts.
The parsed value is cast as Partial<SettingsState> so TypeScript can still type-check
the individual property accesses and their ?? default fallbacks.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The constant GITHUB_STALE_TIME was set to 0 while the comment directly above it
read "staleTime of 10 minutes keeps well within the rate limit." The contradiction
meant React Query treated cached release data as always stale, firing a new GitHub
API request on every single mount of the Releases page plus every 5-minute polling
interval. GitHub's unauthenticated API is capped at 60 requests per hour per IP;
heavy page-switching or multiple users sharing a NAT IP could exhaust that budget
quickly, causing the page to show a fetch-error banner.

Changed to: const GITHUB_STALE_TIME = 10 * 60 * 1000 (10 minutes)
Updated the inline comment to match the value exactly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…eality

The AdminUserDTO interface declared `username: string` as a required field, but
the accompanying comment (and the optional-chaining already used when filtering
users in useAdminPageLogic.ts) made clear the backend never actually returns it.
This was a type lie: TypeScript believed username was always present, so it would
never warn if new code accessed it without a fallback — silently receiving
undefined at runtime.

Changed `username: string` to `username?: string` so the type honestly reflects
what the API sends. All existing call sites already have `|| email` guards or
optional-chaining, so no runtime behaviour changes. Future code that tries to use
.username directly without a guard will now get a compile-time error instead of a
silent runtime bug.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The news page had no empty-state UI. When a user unchecked all four category
filters the virtualiser rendered zero items and the content area went completely
blank — no message, no hint, just an unexplained void. The same blank behaviour
hit any future case where posts exist but nothing matched the current filter/search
state.

Added a conditional <p> block below the virtualised <ul> that renders only when
loading is done and visiblePosts.length is 0. It shows two different messages:
  • "Select at least one category to see posts." — when selectedCategories is empty
  • "No posts found." — when categories are selected but nothing matches
    (search query, or genuinely no posts in those categories)

Both strings are translated in locales/en/news.json and locales/hu/news.json
under the new "noCategories" key; "noResults" already existed and is reused for
the second case.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ge keys

userId in AuthContext is stored as bigint. Five places converted it to Number
before using it in localStorage key strings (selected_profile_<id>) or as a
React Query key. Number(bigint) silently loses precision for IDs larger than
2^53-1 (~9 quadrillion), which would produce the wrong key and potentially
share or delete the wrong profile entry for a different user.

Changes:
  - Navbar.tsx, AccountMenu.tsx, ProfileSelectorPage.tsx: template literals
    now use String(userId) instead of Number(userId) for the localStorage key.
  - ProfilesContext.tsx: profileStorageKey helper updated to accept string|number;
    all localStorage get/set/remove calls now pass String(userId) directly
    (bypassing numUserId which is only needed for API calls). The selectProfile
    useCallback dependency array cleaned up to [profiles, userId] after numUserId
    was removed from the callback body.
  - useItems.ts: Number(userId) kept for queryKeys.profiles.byUserId() since that
    API requires a number; a comment was added explaining the precision trade-off
    and when to revisit it.

For current sequential DB IDs, String(123n) and Number(123n) produce identical
key strings ("123"), so existing stored profiles are not affected by this change.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Errors.md documents the five client-side bugs found during the audit session,
their explanations, severity ratings, and fix prompts.

The three admin files (AdminPage.tsx, AdminPageContent.tsx, UserDetail.tsx) were
auto-formatted by Prettier during the test-client run that followed the username
type fix; those formatting changes are captured here rather than mixed into the
type-fix commit.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@BDonat05 BDonat05 merged commit b563244 into test Apr 15, 2026
5 checks passed
@BDonat05 BDonat05 deleted the frontend branch April 15, 2026 19:03
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