Skip to content

Robust Tab Visibility & Gating #403

Description

@Benjtalkshow

Robust Tab Visibility & Gating

Objective

Ensure that tabs not explicitly enabled in enabledTabs are completely hidden from every navigation surface in the UI and are entirely unreachable — whether through normal navigation, direct URL entry, browser history, or stale deep links. A disabled tab must leave no visible trace in the interface and must never cause a layout break or unexpected visual shift if accessed directly.


Technical Implementation

Target File

  • app/(landing)/hackathons/[slug]/page.tsx

Logic Mapping

Navigation Filtering — hackathonTabs useMemo

  • Refactor the hackathonTabs useMemo to filter the tabs array against currentHackathon.enabledTabs before returning
  • Only tabs whose identifier exists in the enabledTabs array should be included in the memoized result — the filtered array becomes the single source of truth for all navigation rendering
  • The filter must be data-driven and dynamic — if an organizer enables or disables a tab mid-session, the memoized value should recompute and all navigation surfaces should update accordingly without a hard page reload
  • The memo's dependency array must include currentHackathon.enabledTabs to ensure it recalculates when the configuration changes

Component Guard — Tab Content Section

  • In the "Tab Content" section of the page, wrap the rendering of each tab component — including HackathonResources, AnnouncementsTab, SubmissionTab, and any others — in a conditional check against currentHackathon.enabledTabs
  • A tab component must not render at all if its identifier is not present in enabledTabs — not even partially, not even as a loading skeleton
  • This guard operates as a secondary layer of protection beneath the navigation filtering, ensuring that even if a user reaches a disabled tab via a direct URL or stale link, the component is never instantiated

Deep Linking Gating

  • If the activeTab resolved from the URL query parameter does not exist in the filtered hackathonTabs array, immediately call setActiveTab('overview') to default to the overview tab
  • This must be applied before any tab content renders — the default should be set early enough that the user never sees a flash of an incorrect or empty tab state
  • If the overview tab is itself disabled (an edge case), handle this gracefully rather than triggering an infinite loop — surface an appropriate fallback rather than repeatedly resetting the active tab

Component Consistency

Mobile Navigation

  • The mobile bottom bar and/or mobile drawer menu must apply the same enabledTabs filtering as the desktop navigation — disabled tabs must not appear in any mobile navigation surface
  • Mobile and desktop navigation must remain fully in sync — a tab hidden on desktop must also be hidden on mobile at all times
  • Both surfaces should derive their visible tabs from the same filtered hackathonTabs memoized value to guarantee consistency and avoid duplicating the filter logic

⚠️ Caution

This is a production environment — not a sandbox.

  • Code must be performant, accessible, and clean
  • No dummy data — all gating logic must operate on real enabledTabs values from currentHackathon
  • AI-generated code will be scrutinized; poorly structured or "hallucinated" code will result in immediate issue closure
  • Follow the existing design system: shadcn/ui, Tailwind, Framer Motion

Testing & Verification

Automated Tests

npm run lint    # Ensure code quality
npm run build   # Verify no breaking changes in routing or types

Manual Verification

  • Confirm the hackathonTabs useMemo correctly filters out tabs not present in enabledTabs and that the filtered result drives all navigation rendering
  • Verify that currentHackathon.enabledTabs is included in the memo's dependency array — confirm tabs update dynamically when the configuration changes
  • Confirm that HackathonResources, AnnouncementsTab, SubmissionTab, and other tab components do not render at all when their identifier is absent from enabledTabs
  • Directly navigate to a disabled tab via URL — confirm setActiveTab('overview') is called and the overview tab is shown without any flash of the disabled tab's content
  • Verify the default to 'overview' occurs before any tab content renders — no partial render of the disabled tab should be visible
  • Simulate an organizer enabling a new tab mid-session — confirm all navigation surfaces update without a hard reload
  • Simulate an organizer disabling an active tab mid-session — confirm the tab disappears from all navigation surfaces immediately and direct URL access defaults to overview
  • Confirm the mobile bottom bar and drawer menu hide disabled tabs and remain fully in sync with the desktop navigation
  • Test with a malformed or unrecognized tab query value in the URL — confirm it falls through to the 'overview' default correctly
  • Test the edge case where 'overview' itself is disabled — confirm no infinite loop occurs and an appropriate fallback is shown
  • Provide video evidence

Activity

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions