Real-time queue management for badminton courts with Firebase-backed Google sign-in, persistent state, and live synchronization across all users.
npm install
npm startThe app runs at http://localhost:3000 with hot reload and built-in ESLint checks. npm test launches Jest in watch mode, and npm run build produces a production bundle in build/.
- Create a Firebase project
- Visit the Firebase console, create a new project, and add a web app.
- Enable Google sign-in
- In Authentication → Sign-in method, enable Google and set your OAuth consent screen details.
- Create a Firestore database
- In Firestore Database, start in production or test mode (your choice) and select the desired region.
- Configure Firestore Security Rules
- Navigate to Firestore Database → Rules tab
- Copy the rules from
FIRESTORE_RULES.mdand publish them - Important: Update the admin email list in the rules to match your
REACT_APP_ADMIN_EMAILS
- Configure web credentials
- Copy the web app configuration snippet from Project settings → General.
- Duplicate
.env.exampleto.env.local(ignored by git) and fill in the values:REACT_APP_FIREBASE_API_KEY=... REACT_APP_FIREBASE_AUTH_DOMAIN=... REACT_APP_FIREBASE_PROJECT_ID=... REACT_APP_FIREBASE_STORAGE_BUCKET=... REACT_APP_FIREBASE_MESSAGING_SENDER_ID=... REACT_APP_FIREBASE_APP_ID=... REACT_APP_FIREBASE_MEASUREMENT_ID=... # optional – enables Firebase Analytics REACT_APP_ADMIN_EMAILS=alice@example.com,bob@example.com # comma-separated admin allow list - Restart
npm startso Create React App picks up the new environment variables.
All court updates sync instantly across all connected users via Firestore's onSnapshot listeners. When anyone adds, removes, or edits a player, everyone sees the change in real-time.
-
Regular Users:
- Must sign in to view courts
- Can add themselves to any court (one entry per court maximum)
- Can edit/remove only their own entries (both in "playing" and "waiting" states)
- Click on their name to edit inline (no popup)
-
Admins (emails in
REACT_APP_ADMIN_EMAILS):- Can edit/remove any entry
- Can advance courts (move waiting players to playing)
- See "Advance" button on courts
- Click the "Edit" button or click your name directly to edit
- Press Enter to save, Escape to cancel
- Changes sync in real-time to all users
Users can only have one entry per court at a time. If you try to add a second entry, you'll receive a message asking you to edit or remove your existing entry first.
The auth layer lives in src/context/AuthContext.js. It exposes the current user, loading/error state, and signIn/signOut helpers. The top-level AppBar consumes this context and renders the Google sign-in button or the active user profile.
Court state is managed in Firestore via src/firebase/courtRepository.js, which provides:
- Real-time subscriptions using
onSnapshot - Atomic updates using Firestore transactions
- Validation for duplicate entries and ownership
Authenticated users are mirrored into the Firestore collection users/{uid} with basic profile metadata (display name, email, avatar, provider IDs, timestamps) on first login and subsequent visits. Admin-only actions can be gated by checking isAdminEmail from src/config/adminConfig.js, which compares the signed-in email against the configured allow list.
src/components/AppBar/– reusable app bar with Google sign-in/out controls.src/context/AuthContext.js– shared auth provider and hook for Firebase Auth state.src/firebase/firebaseClient.js– Firebase initialisation and exports (auth,firestore,analytics, Google provider helpers).src/firebase/courtRepository.js– Firestore operations for court management with real-time sync.src/firebase/userRepository.js– helper to upsert signed-in users into theuserscollection.src/config/adminConfig.js– parsesREACT_APP_ADMIN_EMAILSand exposes anisAdminEmailhelper.src/App.js– courts UI with real-time Firestore integration, wrapped by the auth provider insrc/index.js.src/Court.js– individual court component with inline editing support.FIRESTORE_RULES.md– security rules to apply in Firebase Console.
Keep new domain-specific features colocated within src/, alongside their tests (*.test.js) and styles, following the existing patterns.
To verify real-time synchronization is working:
- Open two browser tabs with the app (or use different browsers)
- Sign in on both tabs with different Google accounts
- Add a player on Tab 1 - it should appear instantly on Tab 2
- Edit a player on Tab 1 - the change should appear instantly on Tab 2
- Remove a player on Tab 1 - it should disappear instantly on Tab 2
- Sign in as admin and click "Advance" - both tabs should update
The sync happens in real-time with typical latency under 100ms on good connections.