Files
challenge-admin-pl/CLAUDE.MD

5.3 KiB
Raw Permalink Blame History

Overview

This document summarizes the recent changes around submissions/users pages and records guardrails to avoid similar issues in the future.

We:

  • Reworked submissions and user stats UIs to use real routes/pages instead of modals.
  • Added compact progress overview for participants.
  • Introduced deep-linked details pages for submissions and users.
  • Fixed Chakra UI dialog misuse and type/translation issues.

Routing & Page Structure

Do

  • Define all routes centrally in src/__data__/urls.ts and src/dashboard.ts:
    • Add both the URL builder (e.g. submissionDetails(userId, submissionId)) and the :param path.
    • Wrap pages in PageWrapper in dashboard.tsx.
  • Use real pages for complex views (details, stats) instead of large modals:
    • Submissions details: SubmissionDetailsPage with URL /submissions/:userId/:submissionId.
    • User stats: UserStatsPage with URL /users/:userId.
  • Pass IDs via URL, not only component state:
    • Use route params for userId, submissionId, etc.
    • For “return and keep selection”, encode it as a query param (e.g. ?userId=...) and read it on the list page.

Dont

  • Dont hardcode paths in components (e.g. '/submissions/...'); always use URLs.* helpers.
  • Dont rely solely on local React state for deep links:
    • If a view must be shareable/bookmarkable or restorable on reload, it must be addressable by URL.

Chakra UI Dialogs & Layout

Do

  • Use dialog subcomponents only inside a dialog root:
    • If you use DialogBody, DialogContent, etc., they must be wrapped in <DialogRoot>.
  • For standalone pages, use plain layout components:
    • Box, Heading, VStack, Grid, Progress, etc.
    • No Dialog* components on normal routed pages.

Dont

  • Dont import or use DialogBody, DialogContent, DialogHeader, etc. on regular pages:
    • This causes useDialogStyles returned 'undefined' runtime errors.
  • Dont mix modal patterns and page patterns:
    • Either a true modal (DialogRoot + DialogContent) over an existing page,
    • Or a full page route with normal layout — not both at the same time.

Data Safety & Types

Do

  • Assume backend fields can be either object or ID string, per ChallengeSubmission types:
    • Example safe access in submissions:
      • Guard before reading user.nickname or task.title.
    • Derive strings like:
      • const nickname = typeof rawUser === 'object' && 'nickname' in rawUser ? rawUser.nickname ?? '' : typeof rawUser === 'string' ? rawUser : ''.
  • Normalize strings before calling .toLowerCase():
    • const normalized = (value ?? '').toLowerCase().
  • When filtering/searching, never call string methods on possibly undefined or non-object values.

Dont

  • Dont cast blindly (as ChallengeUser) and then access .nickname or .title without guards.
  • Dont call .toLowerCase() directly on untrusted values from API or union-typed fields.

“Back” Navigation & State Restoration

Do

  • For details pages that should restore list state:
    • Encode the necessary selection into the URL when navigating to details.
    • Example: SubmissionDetailsPage returns to URLs.submissions with ?userId=..., and SubmissionsPage reads userId from useSearchParams to preselect the user.
  • Prefer semantic back actions over bare navigate(-1) when the previous page/state is known:
    • Use navigate(URLs.submissions + '?userId=...') or navigate(URLs.users) when appropriate.

Dont

  • Dont rely on navigate(-1) when:
    • The previous page might not be the canonical list page,
    • You need a specific state (e.g. selected user) restored.

i18n / Locales

Do

  • Keep ru.json and en.json in sync for any new keys:
    • When adding a key under challenge.admin.* in one file, add the corresponding entry in the other.
  • For status enums, ensure all possible values have translations:
    • challenge.admin.users.stats.status.* must cover all values of taskStat.status.
    • challenge.admin.submissions.status.* must cover all submission statuses.
  • Use consistent key naming patterns:
    • Example: challenge.admin.users.stats.status.accepted, ...status.needs_revision, etc.

Dont

  • Dont introduce new t('...') keys in code without adding them to both locale files.
  • Dont reuse unrelated keys just to avoid adding translations — create clear, specific keys.

UI Patterns for High-Density Overviews

Do

  • For high-density screens (e.g. 100 participants at once):
    • Use compact cards or rows with:
      • Truncated names (truncate),
      • Thin Progress bars,
      • Minimal text (percentage + small counters).
    • Sort by progress to surface lagging participants.

Dont

  • Dont use wide tables when many rows must fit on one screen; prefer grids or narrow rows with fixed-width text columns and flexible progress area.

When Adding New Features

Before merging:

  • Check routing:
    • New URL added to URLs.
    • Route wired in dashboard.tsx.
  • Check data safety:
    • No unchecked property access on union/nullable types.
  • Check i18n:
    • New keys exist in both ru.json and en.json.
  • Check Chakra usage:
    • No Dialog* components outside a proper <DialogRoot> or on standalone pages.