Skip to content

Robust Tab Visibility & Gating #403

@Benjtalkshow

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions