The BAP Beta Tau frontend organises reusable UI into three directories:Documentation Index
Fetch the complete documentation index at: https://mintlify.com/asubap/website/llms.txt
Use this file to discover all available pages before exploring further.
src/components/common/ for generic utility components, src/components/network/ for directory-display components, src/components/event/ for event-specific components, and src/components/protectedRoute/ for route guards. This page documents the props, behavior, and usage patterns of each key shared component.
ProtectedRoute
Path:src/components/protectedRoute/ProtectedRoute.tsx
ProtectedRoute is a React Router wrapper that guards authenticated routes. It consumes useAuth() and renders the child <Outlet> only when the user passes both authentication and role-permission checks.
Behavior
Loading state
While
loading === true (auth check in progress), a full-screen LoadingSpinner is shown. This prevents content flash.Unauthenticated
If
session is null, the attempted URL is saved to localStorage.redirectAfterLogin and the user is redirected to /login.Permission check
hasPermission() maps the current path to required roles:/admin→ requires"e-board"role/sponsor→ requires"sponsor"role (string or{ type: "sponsor" }object)/member→ requires"general-member"role- All other protected paths → any authenticated role
Role mismatch
If the user is authenticated but lacks the required role, they are redirected to
/auth/Home.Usage in App.tsx
/auth/Home is intentionally excluded from the hasPermission check — a user can reach it even if role is null. This allows the error state (e.g., archived member) to be displayed before the session is fully cleared.NetworkList
Path:src/components/network/NetworkList.tsx
NetworkList renders a responsive card grid for any mix of MemberDetail and Sponsor entities. It is used on the Members, Alumni, E-board, and Sponsors Network pages.
Rendering Logic
Each card conditionally shows fields based onentity.type:
| Field | Member card | Sponsor card |
|---|---|---|
| Photo / logo | Round avatar | Round logo |
| Subtitle | entity.major | Tier badge (e.g., “Gold Sponsor”) |
| ✅ | ❌ | |
| Total hours | ✅ (hidden for alumni) | ❌ |
| First link | ✅ | ❌ |
| About (2-line clamp) | ✅ | ✅ |
| All links | ❌ | ✅ |
| Rank / Status | ✅ | ❌ |
MemberDetail→NetworkProfileModalSponsor→SponsorProfileModal
Grid Layout
Example
EventCard
Path:src/components/event/EventCard.tsx
EventCard renders a single event in a white card. Its visible actions and data fields change based on the current user’s role — members see RSVP and check-in buttons, while e-board members also see edit, delete, and participant management controls.
Role-Aware Actions
| Action | Roles | Condition |
|---|---|---|
| RSVP button | general-member, sponsor | !isPast && !hideRSVP && !isAlumni |
| Check-in button | general-member | !isPast && !isAlumni |
| Edit (⋯) button | e-board | onEdit prop provided |
| Announce (📣) button | e-board | onAnnounce prop + !isPast |
| Delete (🗑) button | e-board | onDelete prop provided |
| RSVPs & Attendees panel | e-board | Always visible, lazy-loaded |
E-Board Participant Panel
When the collapsible “RSVPs and Attendees” panel is opened, the card fetches detailed participant data fromGET /events/:eventId/participants. E-board members can also:
- Add RSVPs — search active members and bulk-RSVP them via
POST /events/rsvp/:eventId - Remove RSVPs — via
POST /events/unrsvp/:eventIdwith{ user_email } - Add Attendees — via
POST /events/add-member-attending - Remove Attendees — via
POST /events/delete-member-attending
Helper Export
YYYY-MM-DD date string and optional HH:MM:SS time string into a locale-aware human-readable string such as "Monday, January 20, 2025 at 6:00 PM".
Example
LoadingSpinner
Path:src/components/common/LoadingSpinner.tsx
A minimal animated spinner with optional text label. Used throughout the app for async loading states.
| Size | Spinner dimensions |
|---|---|
sm | 16 × 16 px (h-4 w-4) |
md | 20 × 20 px (h-5 w-5) |
lg | 32 × 32 px (h-8 w-8) |
animate-spin class and a text-gray-500 color. Both the circle and path use currentColor, so the spinner inherits its color from the surrounding text color.
ConfirmDialog
Path:src/components/common/ConfirmDialog.tsx
A portal-mounted modal dialog for confirmation prompts. Renders into document.body via createPortal, so it appears above all other content regardless of stacking context.
Modal UI component with size="sm" and zIndex="z-[10000]" to ensure it renders above other modals (such as ProfileEditModal).
ProfilePictureUpload
Path:src/components/common/ProfilePictureUpload.tsx
A reusable profile photo widget that handles upload preview, upload-in-progress overlay, and delete confirmation. Used inside ProfileEditModal for sponsor logos and potentially member profile photos.
Key Behaviors
- A
+button (bottom-right of image) opens the OS file picker. Onlyimage/*MIME types are accepted. - When a file is selected,
URL.createObjectURLgenerates a local preview immediately whileonFileSelectfires asynchronously. If upload fails, the preview is revoked. - A
🗑button (top-right) triggers the delete confirmation flow viashowDeleteConfirmationDialog(true). - The delete button is hidden when
currentProfileUrlequalsplaceholderImageUrl(no real photo to delete). - An upload overlay (semi-transparent black, animated spinner) covers the image while
uploading === true.
useToast Hook
Path:src/context/toast/ToastContext.tsx
Provides access to the global toast notification system defined in App.tsx.
Toast component in App.tsx and auto-dismisses after duration milliseconds.