Skip to content

Conversation

@CH-JASWANTH-KUMAR
Copy link
Contributor

🍽️ Feature: Lunch & Dinner Scanner

What's Changed

  • Added Lunch and Dinner action types to the staff scanner
  • Users can now scan QR codes for meal distribution tracking
  • Duplicate prevention ensures each user only gets one lunch and one dinner

Features Added

  • 🍴 Lunch Scanner (Amber color) - Restaurant icon
  • 🍽️ Dinner Scanner (Blue color) - DinnerDining icon
  • ✅ Duplicate detection prevents multiple scans
  • 🔒 Requires check-in before meal access
  • 📊 All actions logged to checkins collection
  • 📱 Responsive 3-column grid (2 on mobile)

Technical Details

  • Updated ActionType to include "lunch" and "dinner"
  • Added Material-UI icons: Restaurant, DinnerDining
  • Firestore duplicate checking with timestamp alerts
  • Console logging for debugging

Testing

  • Lunch scan prevents duplicates
  • Dinner scan prevents duplicates
  • Check-in requirement enforced
  • Recent actions display correctly
  • Responsive layout works on mobile

Screenshots

Staff scanner now shows 6 action options:

  • Check-in (Green)
  • Check-out (Orange)
  • Swag (Purple)
  • Photobooth (Pink)
  • Lunch (Amber) ← NEW
  • Dinner (Blue) ← NEW

- Added lunch and dinner action types to scanner
- Added Restaurant and DinnerDining Material-UI icons
- Implemented duplicate prevention for lunch and dinner
- Lunch uses amber color scheme, dinner uses blue
- Required check-in before lunch/dinner access
- Updated action selector grid to 3 columns (2 on mobile)
- All actions now tracked in checkins collection
- Console logging for all scan events
Copilot AI review requested due to automatic review settings January 3, 2026 06:27
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to add lunch and dinner meal distribution tracking to the staff QR scanner, but includes numerous unrelated changes that should be in separate pull requests. The core feature adds two new action types with duplicate prevention, but the PR also contains leaderboard controls, admin enhancements, new milestone pages, printer improvements, and critically, exposes Firebase service account credentials.

Key Changes (as described in PR):

  • Added "lunch" and "dinner" action types to staff scanner with duplicate detection
  • Updated UI to 3-column grid layout on desktop (2 columns on mobile)
  • Required check-in before meal access

Additional Undocumented Changes:

  • Leaderboard visibility toggle system via new admin settings page
  • Five new milestone submission pages (milestones 5-10)
  • Admin team management enhancements (manual participant creation)
  • Printer client WiFi printer selection UI
  • Multiple seed scripts for database initialization
  • Field name change with typo: allottedClassroomallotedClassrooms
  • CRITICAL: Firebase service account private keys committed to repository

Reviewed changes

Copilot reviewed 22 out of 23 changed files in this pull request and generated 15 comments.

Show a summary per file
File Description
serviceAccountKey.json CRITICAL SECURITY ISSUE: Firebase private keys exposed in repository
src/app/staff/scanner/page.tsx Core feature: adds lunch/dinner actions with duplicate checking; missing payment verification; fragile timeout workaround
src/app/leaderboard/page.tsx Field name change introduces typo and inconsistency across codebase
src/app/admin/milestones/[id]/page.tsx Manual grading support and hardcoded deadline date
src/app/admin/teams/page.tsx Manual participant creation with weak UID generation
src/app/admin/settings/page.tsx New admin settings page for leaderboard visibility control
src/app/admin/page.tsx Added settings link to admin dashboard
src/app/printer/client/page.tsx Non-functional printer discovery using nonexistent Web API
src/app/hackathon/milestone_ten/page.tsx New final submission page
src/app/hackathon/milestone_[five-nine]/page.tsx Five new manual grading milestone pages
update-classrooms.ts New script for classroom seeding with spelling error in field name
toggle-leaderboard.ts CLI tool for leaderboard visibility control
seed-firestore.ts Modified to seed staff/admin and test teams instead of participants
reseed-staff-admin.ts New script for re-seeding staff and admin accounts
staff-admin-seed.csv, staff-admin-correct.csv, test-team-seed.csv Seed data files for testing and staff accounts
ADMIN_ROUTES.md New documentation for admin and staff routes
Comments suppressed due to low confidence (1)

serviceAccountKey.json:13

  • Critical security vulnerability: Firebase service account private keys are being committed to the repository. This file should never be committed to version control as it contains sensitive credentials that grant full administrative access to your Firebase project.

The private key in this file can be used to:

  • Read/write all data in your Firestore database
  • Access Firebase Storage
  • Perform any administrative operation

Immediate actions required:

  1. Remove this file from the repository immediately
  2. Add serviceAccountKey.json to .gitignore
  3. Revoke this service account key in Firebase Console and generate a new one
  4. Store credentials securely using environment variables or secret management systems
  5. Review your Firebase security rules and audit logs for any unauthorized access

For CI/CD, use GitHub Secrets or similar secure secret management instead of committing credentials.

{
  "type": "service_account",
  "project_id": "techsprint-gitam",
  "private_key_id": "fe0c532876c7456432194af575556291e08f5fee",
  "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQD5Hv/O51kWbuoF\nOyLMZxb91d7So5V9eUomZarE7+gJ3Uz3g6T6cPTqgYrApPgiC+zvoSvkb15r2kMf\nUPVbqXSJd/ZkVCo3Q1ShSU4+rDGxDDeKx1ocE0wVZCEhLSKaHq2xIvhfLMEY9jh4\n0EyFR+uk3e/nWEY0+DkCczjSJz/0asfHAzY+p1JRR8P07bQsI+QM8xFUnRIgIuOB\nTxSvF1tNfRoa47ldlBZJTy0xgRlfzFk8KIdZrPWMIrfAUJnl5/LJvVlsA98Tv0sA\nhFtjfBMd1SM6sb83rmpmaH6DeeVyisfRRlxDILDhWFLL22Cwmwqn5pkCuG93MxYR\nA6FrkpQfAgMBAAECggEAb2p4URJx6xEO8+j3TsCabUs+HSnRPW1GBvc4UVzUg7jo\nZ9iGLAXh25G1OyRs31lDDgcgqMlQSt8yXuqn2WdnueWfmk50FQQ1cO7moiwEC2Fh\n49z1xZGx2O1PzdUwYQpwd0UjHPnYoK/aINpUJtW8I5+o4Gg/+ge8A4cBtiecuFQ5\ngVHUb3ty02ZqR7tPpfDhffhM3pOP6kZxTnzx2KfE3U1YlFe0seZAkmF5PpjOejFF\n+1O1dtSzvZpau2+6Mk/N45qvXYEm32LbSwCshoi3Vilfey6QVBsa/NFxBPMxsDpq\nrWLrkhy9m4uVA+HBeBszFqHlvMuIUktAB0xJipl3IQKBgQD91JqP3MnuVB2rLm1p\ndbf+KYTBbhtSSAX2jcz2EIPUxYpEAxZi2q1aL/UvK7O+n9iG4elcGxAnVfug+NuH\njJpl1yu+YK8g6bC6E9j9+tW9kgXqJtNlNczEBWZNJ5iKpcbcZBkVznYOiwlyCE97\nOCjVCwItDd55GrWw4Zcn99qqYQKBgQD7QBdPyR2a6zfbEWHEbsnqn6JuAgG0H952\nkfkDe1eOpPYZeYVRAycivH6u2iCCzMa2itiIRVT506qd5sK1Kikoh0HH5pqmwtFz\nxpfviWaAmPGU4GgybWuXNWHrbjYUDff2YXavenEAHMQyp6JmqEf6fk9fHZ2GovXG\nLlneLb7OfwKBgQCE+oLW55aq00qPyczsOQ3hi6LPK34Ix07IclV0fAZ0y+C57Nwn\ngeTboNBUnBKYxWlMkMIOzObTlMo09Osdwl2JCQcTv9c/6O37Lja6KFUd8YhDuX96\nQIs8DpAfz6Sszli2UYKK2BUlXVXfddcd+Lf7lL7ZF7D7xTB2sFjeSY03QQKBgFl7\nmRHccgPT1F/cT/Ky9ozub944Lr0lQIkAMizQR/3QuKmYAyg4ND8F3SSPIVcUcY1f\n5ACcmMglX7W/EweMzX3WtlHoypmr9wcB6ujwCaaxUhEQ32teVxxScd50sSPxWafR\nTIDw3cAJfsL/uzJOqtwHEmOw24KxFVGQ/obHyhYnAoGBAJi1ShoasGdYeKeukA99\n+64n9PshktE7jXIvaFxZi+P0j4qlqiQ+PZCJ9w7rht9SaYx+ZThwdvVATeGK6INR\nTFNq/HG6eVdV2WwEDL8qBN28raNKnVq9VCFjio2mvmcdK9r/kEI3F64W5ghvIiWw\n5Ulvs0fj/30VQih/i/rJ0ZKy\n-----END PRIVATE KEY-----\n",
  "client_email": "firebase-adminsdk-fbsvc@techsprint-gitam.iam.gserviceaccount.com",
  "client_id": "102465646528741241791",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-fbsvc%40techsprint-gitam.iam.gserviceaccount.com",
  "universe_domain": "googleapis.com"
}

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

for (const [teamCode, classroom] of Object.entries(TEAM_CLASSROOM_MAP)) {
try {
await db.collection('teams').doc(teamCode).update({
allotedClassrooms: classroom,
Copy link

Copilot AI Jan 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling error: "allotedClassrooms" should be "allottedClassrooms" (with double 't'). The correct spelling of the past tense of "allot" is "allotted", not "alloted".

This typo is being propagated into the database schema via this seed script, and then used inconsistently across the codebase (see related comment on leaderboard/page.tsx).

Copilot uses AI. Check for mistakes.
Comment on lines +210 to +241
// Check for lunch duplicate (STRICT - only once per user)
if (selectedAction === "lunch") {
const lunchQuery = query(
collection(db, "checkins"),
where("userId", "==", uid),
where("type", "==", "lunch")
);
const lunchSnapshot = await getDocs(lunchQuery);
if (!lunchSnapshot.empty) {
const lunchDate = lunchSnapshot.docs[0].data().timestamp?.toDate?.()?.toLocaleString();
alert(`⚠️ DUPLICATE BLOCKED!\n\nLunch already served to this user!\nServed at: ${lunchDate || "earlier"}`);
setProcessing(false);
return;
}
}

// Check for dinner duplicate (STRICT - only once per user)
if (selectedAction === "dinner") {
const dinnerQuery = query(
collection(db, "checkins"),
where("userId", "==", uid),
where("type", "==", "dinner")
);
const dinnerSnapshot = await getDocs(dinnerQuery);
if (!dinnerSnapshot.empty) {
const dinnerDate = dinnerSnapshot.docs[0].data().timestamp?.toDate?.()?.toLocaleString();
alert(`⚠️ DUPLICATE BLOCKED!\n\nDinner already served to this user!\nServed at: ${dinnerDate || "earlier"}`);
setProcessing(false);
return;
}
}

Copy link

Copilot AI Jan 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing payment verification for lunch and dinner: Unlike swag and photobooth (lines 171-176), lunch and dinner actions don't check payment_status. This means users who haven't paid can still receive meals, which may not be the intended behavior.

If meals should only be available to paying participants, add the same payment check:

if ((selectedAction === "lunch" || selectedAction === "dinner") && 
    userData.payment_status !== "captured") {
  alert("❌ Payment not confirmed. Cannot proceed with this action.");
  setProcessing(false);
  return;
}

If meals should be available to all checked-in participants regardless of payment status, this is acceptable but should be explicitly documented in comments to clarify the intentional difference from swag/photobooth.

Copilot uses AI. Check for mistakes.
import { Html5QrcodeScanner } from "html5-qrcode";

type ActionType = "check-in" | "check-out" | "swag" | "photobooth";
type ActionType = "check-in" | "check-out" | "swag" | "photobooth" | "lunch" | "dinner";
Copy link

Copilot AI Jan 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR includes many changes that are unrelated to the "Lunch & Dinner Scanner" feature described in the PR title and description. The PR contains:

Described in PR: Lunch and dinner action types for the staff scanner

NOT described in PR but included:

  • Leaderboard visibility toggle system (new admin settings page)
  • Multiple new milestone pages (5-10)
  • Admin team management enhancements (create participant feature)
  • Printer client WiFi printer selection
  • New seed scripts for staff/admin and classrooms
  • Documentation files (ADMIN_ROUTES.md)
  • Leaderboard field name change (allottedClassroom → allotedClassrooms)

These changes should be split into separate PRs:

  1. This PR: Lunch & Dinner scanner feature only
  2. Separate PR: Leaderboard visibility controls
  3. Separate PR: Milestone pages 5-10
  4. Separate PR: Admin enhancements
  5. Separate PR: Printer improvements
  6. Separate PR: Data seeding scripts

Mixing unrelated features makes code review difficult, increases merge conflict risk, and makes it harder to track which changes caused issues if problems arise.

Copilot uses AI. Check for mistakes.
Comment on lines +98 to +119

// Delay scanner initialization to ensure DOM element is rendered
setTimeout(() => {
const html5QrcodeScanner = new Html5QrcodeScanner(
"qr-reader",
{ fps: 10, qrbox: { width: 250, height: 250 } },
false
);

html5QrcodeScanner.render(
(decodedText) => {
handleScan(decodedText);
html5QrcodeScanner.clear();
setScanning(false);
},
(errorMessage) => {
// Ignore errors, just keep scanning
}
);
html5QrcodeScanner.render(
(decodedText) => {
handleScan(decodedText);
html5QrcodeScanner.clear();
setScanning(false);
},
(errorMessage) => {
// Ignore errors, just keep scanning
}
);

setScanner(html5QrcodeScanner);
setScanner(html5QrcodeScanner);
}, 100);
Copy link

Copilot AI Jan 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 100ms delay to ensure DOM element rendering is a fragile workaround that may fail on slower devices or under heavy load. Consider using a more robust approach:

  1. Use React's useEffect with proper dependency tracking
  2. Check for element existence before initializing: if (document.getElementById('qr-reader'))
  3. Use MutationObserver to wait for the element
  4. Or ensure the element is rendered before enabling the scan button

The current timeout approach can still fail if the device is slow or the browser is busy, leading to scanner initialization errors.

Copilot uses AI. Check for mistakes.
teamCode: data.teamCode || doc.id,
teamName: data.teamName || "Unknown Team",
classroom: data.allottedClassroom || "Not Assigned",
classroom: data.allotedClassrooms || "Not Assigned",
Copy link

Copilot AI Jan 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent field name change: This PR changes from allottedClassroom to allotedClassrooms (note the typo: "allotted" is misspelled as "alloted"). However, this change is not applied consistently across the codebase.

Files still using the old field name allottedClassroom:

  • src/app/admin/teams/page.tsx
  • src/app/hackathon/pitch-deck/page.tsx
  • src/app/leaderboard/live/page.tsx
  • src/app/photobooth/capture/page.tsx
  • src/app/photobooth/select/page.tsx
  • src/app/profile/page.tsx
  • src/app/staff/analytics/page.tsx

This inconsistency will cause bugs where classroom information fails to display correctly in some parts of the application. Additionally, if the intent was to fix the typo "allotted" → "alloted", this is actually introducing a new typo rather than fixing one.

Recommendations:

  1. Either revert this change or apply it consistently across ALL files
  2. If changing, use the correctly spelled "allottedClassroom" or "allottedClassrooms"
  3. Create a database migration to rename the field in Firestore if needed
Suggested change
classroom: data.allotedClassrooms || "Not Assigned",
classroom: data.allottedClassroom || data.allotedClassrooms || "Not Assigned",

Copilot uses AI. Check for mistakes.
const teamDetailsId = snapshot.docs[0].id;
setTeamDocId(teamDetailsId);
const dt = snapshot.docs[0].data()["milestone_ten_time"];
if (dt != undefined && dt != null) {
Copy link

Copilot AI Jan 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This guard always evaluates to true.

Suggested change
if (dt != undefined && dt != null) {
if (dt != null) {

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,54 @@
"use client";

import { useEffect } from "react";
Copy link

Copilot AI Jan 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused import useEffect.

Suggested change
import { useEffect } from "react";

Copilot uses AI. Check for mistakes.
Comment on lines +3 to +9
import { useEffect } from "react";
import { useRouter } from "next/navigation";
import { Info } from "@mui/icons-material";

export default function Page() {
const router = useRouter();

Copy link

Copilot AI Jan 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused variable router.

Suggested change
import { useEffect } from "react";
import { useRouter } from "next/navigation";
import { Info } from "@mui/icons-material";
export default function Page() {
const router = useRouter();
import { Info } from "@mui/icons-material";
export default function Page() {

Copilot uses AI. Check for mistakes.
"use client";
import { db } from "@/lib/firebase";
import { collection, getDocs, onSnapshot } from "firebase/firestore";
import { collection, getDocs, onSnapshot, doc } from "firebase/firestore";
Copy link

Copilot AI Jan 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused import getDocs.

Suggested change
import { collection, getDocs, onSnapshot, doc } from "firebase/firestore";
import { collection, onSnapshot, doc } from "firebase/firestore";

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,119 @@
import { initializeApp, cert, getApps } from 'firebase-admin/app';
import { getFirestore, Timestamp } from 'firebase-admin/firestore';
import * as fs from 'fs';
Copy link

Copilot AI Jan 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused import fs.

Suggested change
import * as fs from 'fs';

Copilot uses AI. Check for mistakes.
@ManasMalla ManasMalla merged commit 68d3151 into dsc-gitam:main Jan 3, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants