From 44bc7751f2dfb7838d099d282516e6d05fad03d5 Mon Sep 17 00:00:00 2001 From: Divyank Shah Date: Sun, 5 Nov 2023 16:44:50 -0800 Subject: [PATCH 1/3] merge 2 calendars --- .../dynamic/admin/services/calendar/Event.jsx | 22 ++++++---- .../admin/services/calendar/Events.jsx | 44 ++++++++++++------- src/data/dynamic/admin/Calendar.js | 14 +++--- 3 files changed, 48 insertions(+), 32 deletions(-) diff --git a/src/components/dynamic/admin/services/calendar/Event.jsx b/src/components/dynamic/admin/services/calendar/Event.jsx index 8a6a88a6c..deee1b4b0 100644 --- a/src/components/dynamic/admin/services/calendar/Event.jsx +++ b/src/components/dynamic/admin/services/calendar/Event.jsx @@ -1,13 +1,19 @@ -const Event = ({ event }) => { +const Event = ({ event, view }) => { + console.log(event); + return ( -
-

+

+

{event.summary} -
- {new Date(event.start).toLocaleTimeString(navigator.language, { - hour: "2-digit", - minute: "2-digit", - })} + {view === "month" && ( + <> + {" - "} + {new Date(event.start).toLocaleTimeString(navigator.language, { + hour: "2-digit", + minute: "2-digit", + })} + + )}

); diff --git a/src/components/dynamic/admin/services/calendar/Events.jsx b/src/components/dynamic/admin/services/calendar/Events.jsx index 18325c409..535e5f567 100644 --- a/src/components/dynamic/admin/services/calendar/Events.jsx +++ b/src/components/dynamic/admin/services/calendar/Events.jsx @@ -29,24 +29,33 @@ const CalendarEvents = () => { }; useEffect(() => { - axios - .get( - `https://www.googleapis.com/calendar/v3/calendars/${process.env.NEXT_PUBLIC_GOOGLE_CALENDAR_EMAIL}/events?key=${process.env.NEXT_PUBLIC_GOOGLE_CALENDAR_API_KEY}&singleEvents=true&orderBy=startTime` - ) - .then((response) => { - const items = response.data.items.map((item) => { - item.start = new Date(item.start.dateTime); - item.end = new Date(item.end.dateTime); - item.color = - LABELS[ - item.description.split("\n")[1].split(": ")[1].toLowerCase() - ].background; - item.hidden = false; + const hackathon = axios.get( + `https://www.googleapis.com/calendar/v3/calendars/${process.env.NEXT_PUBLIC_GOOGLE_CALENDAR}/events?key=${process.env.NEXT_PUBLIC_GOOGLE_CALENDAR_API_KEY}&singleEvents=true&orderBy=startTime` + ); - return item; - }); - setEvents(items); + const leads = axios.get( + `https://www.googleapis.com/calendar/v3/calendars/${process.env.NEXT_PUBLIC_GOOGLE_CALENDAR_LEADS}/events?key=${process.env.NEXT_PUBLIC_GOOGLE_CALENDAR_API_KEY}&singleEvents=true&orderBy=startTime` + ); + + Promise.all([hackathon, leads]).then(([hackathonData, leadsData]) => { + const hackathon = hackathonData.data.items; + const leads = leadsData.data.items; + + const rawEvents = [...hackathon, ...leads]; + + rawEvents.forEach((item) => { + item.start = new Date(item.start.dateTime); + item.end = new Date(item.end.dateTime); + item.color = + LABELS[ + item.description.split("\n")[1].split(": ")[1].toLowerCase() + ].background; + item.hidden = false; }); + + setEvents(rawEvents); + }); + document.addEventListener("keydown", handleShortcuts); return () => document.removeEventListener("keydown", handleShortcuts); }, []); @@ -59,6 +68,7 @@ const CalendarEvents = () => { date={date} view={view} className="py-4" + step={15} events={events.filter((event) => !event.hidden)} localizer={mLocalizer} defaultView="month" @@ -66,7 +76,7 @@ const CalendarEvents = () => { onNavigate={(newDate) => setDate(newDate)} onView={(newView) => setView(newView)} components={{ - event: Event, + event: (props) => , toolbar: (props) => ( ), diff --git a/src/data/dynamic/admin/Calendar.js b/src/data/dynamic/admin/Calendar.js index fac9f506c..11c0ec63a 100644 --- a/src/data/dynamic/admin/Calendar.js +++ b/src/data/dynamic/admin/Calendar.js @@ -3,7 +3,7 @@ export const LABELS = { color: "gray", background: "!bg-hackathon-tags-gray-text", }, - director: { + directors: { color: "red", background: "!bg-hackathon-tags-red-text", }, @@ -27,20 +27,20 @@ export const LABELS = { color: "teal", background: "!bg-hackathon-tags-teal-text", }, - UIUX: { + uiux: { color: "lightgreen", background: "!bg-hackathon-tags-lightgreen-text", }, - activities: { - color: "pink", - background: "!bg-hackathon-tags-pink-text", - }, workshop: { color: "grayblue", background: "!bg-hackathon-tags-grayblue-text", }, - general: { + leads: { color: "red", background: "!bg-hackathon-tags-red-text", }, + hackathon: { + color: "pink", + background: "!bg-hackathon-tags-pink-text", + }, }; From e491ca213f17281f14462481542dcdb92c8dc745 Mon Sep 17 00:00:00 2001 From: Divyank Shah Date: Sun, 5 Nov 2023 16:48:13 -0800 Subject: [PATCH 2/3] update checkin calendar --- src/components/dynamic/admin/services/checkin/CheckIn.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/dynamic/admin/services/checkin/CheckIn.jsx b/src/components/dynamic/admin/services/checkin/CheckIn.jsx index 7b4bc9ff2..21af6f892 100644 --- a/src/components/dynamic/admin/services/checkin/CheckIn.jsx +++ b/src/components/dynamic/admin/services/checkin/CheckIn.jsx @@ -15,7 +15,7 @@ const CheckIn = () => { useEffect(() => { axios .get( - `https://www.googleapis.com/calendar/v3/calendars/${process.env.NEXT_PUBLIC_GOOGLE_CALENDAR_EMAIL}/events?key=${process.env.NEXT_PUBLIC_GOOGLE_CALENDAR_API_KEY}&singleEvents=true&orderBy=startTime` + `https://www.googleapis.com/calendar/v3/calendars/${process.env.NEXT_PUBLIC_GOOGLE_CALENDAR}/events?key=${process.env.NEXT_PUBLIC_GOOGLE_CALENDAR_API_KEY}&singleEvents=true&orderBy=startTime` ) .then((response) => { setEvents( From c0eaee2b004cd17e11a50bfa7f68309016e6dbcb Mon Sep 17 00:00:00 2001 From: Divyank Shah Date: Sun, 5 Nov 2023 17:38:12 -0800 Subject: [PATCH 3/3] event attendance --- src/app/api/checkin/route.js | 27 ++++++++++++++++--- src/app/api/statistics/route.js | 17 ++++++++++-- .../admin/services/checkin/CheckIn.jsx | 3 ++- .../admin/services/statistics/Statistics.jsx | 13 +++++---- .../admin/services/statistics/Tabs.jsx | 19 ++++++++----- src/data/dynamic/Navigation.js | 4 +-- 6 files changed, 64 insertions(+), 19 deletions(-) diff --git a/src/app/api/checkin/route.js b/src/app/api/checkin/route.js index c63719917..6484e7701 100644 --- a/src/app/api/checkin/route.js +++ b/src/app/api/checkin/route.js @@ -1,6 +1,13 @@ import { NextResponse } from "next/server"; import { db } from "../../../../firebase"; -import { doc, getDoc, updateDoc, arrayUnion } from "firebase/firestore"; +import { + doc, + getDoc, + updateDoc, + arrayUnion, + increment, + setDoc, +} from "firebase/firestore"; import { authenticate } from "@/utils/auth"; export async function GET(req) { @@ -20,7 +27,8 @@ export async function GET(req) { try { const docSnap = await getDoc(doc(db, "users", uid)); - const data = docSnap.data().events; + const data = docSnap.data().events || []; + console.log(data); return res.json({ message: "OK", items: data }, { status: 200 }); } catch (err) { return res.json( @@ -43,12 +51,25 @@ export async function PUT(req) { ); } - const { uid, event } = await req.json(); + const { uid, event, name } = await req.json(); try { await updateDoc(doc(db, "users", uid), { events: arrayUnion(event), }); + + const data = await getDoc(doc(db, "events", event)); + if (data.exists()) { + await updateDoc(doc(db, "events", event), { + attendance: increment(1), + }); + } else { + await setDoc(doc(db, "events", event), { + attendance: 1, + name: name, + }); + } + return res.json({ message: "OK" }, { status: 200 }); } catch (err) { return res.json( diff --git a/src/app/api/statistics/route.js b/src/app/api/statistics/route.js index 1046bb51d..ef754d537 100644 --- a/src/app/api/statistics/route.js +++ b/src/app/api/statistics/route.js @@ -5,6 +5,7 @@ import { query, collection, getCountFromServer, + getDocs, } from "firebase/firestore"; import { authenticate } from "@/utils/auth"; @@ -71,7 +72,16 @@ export async function GET() { ) ).data().count; - const items = { + const events = await getDocs(collection(db, "events")); + + const eventAttendees = {}; + + events.forEach((doc) => { + const { name, attendance } = doc.data(); + eventAttendees[name] = attendance; + }); + + const users = { participants, teams, judges, @@ -81,7 +91,10 @@ export async function GET() { admins, }; - return res.json({ items: items }, { status: 200 }); + return res.json( + { items: { users, events: eventAttendees } }, + { status: 200 } + ); } catch (err) { return res.json( { message: `Internal Server Error: ${err}` }, diff --git a/src/components/dynamic/admin/services/checkin/CheckIn.jsx b/src/components/dynamic/admin/services/checkin/CheckIn.jsx index 21af6f892..45227f020 100644 --- a/src/components/dynamic/admin/services/checkin/CheckIn.jsx +++ b/src/components/dynamic/admin/services/checkin/CheckIn.jsx @@ -48,6 +48,7 @@ const CheckIn = () => { // TODO: CHANGE TO 5 SECONDS ONCE DEPLOYED if (delta < 5000) { const response = await axios.get(`/api/checkin?uid=${user}`); + console.log(response.data); if (response.data.items.includes(event.id)) { toast("❌ Already Checked In!"); @@ -55,7 +56,7 @@ const CheckIn = () => { } axios - .put("/api/checkin", { uid: user, event: event.id }) + .put("/api/checkin", { uid: user, event: event.id, name: event.name }) .then(() => toast(`✅ Checked in for ${event.name}`)); } else { toast("❌ Expired QR code!"); diff --git a/src/components/dynamic/admin/services/statistics/Statistics.jsx b/src/components/dynamic/admin/services/statistics/Statistics.jsx index 410897b3e..d2d5f768c 100644 --- a/src/components/dynamic/admin/services/statistics/Statistics.jsx +++ b/src/components/dynamic/admin/services/statistics/Statistics.jsx @@ -5,18 +5,21 @@ import Tabs from "./Tabs"; import axios from "axios"; const Statistics = () => { - const [counts, setCounts] = useState({}); + const [counts, setCounts] = useState({ + users: {}, + events: {}, + }); useEffect(() => { - axios - .get("/api/statistics") - .then((response) => setCounts(response.data.items)); + axios.get("/api/statistics").then((response) => { + setCounts(response.data.items); + }); }, []); return (
- <Tabs counts={counts} /> + <Tabs counts={counts.users} events={counts.events} /> </div> ); }; diff --git a/src/components/dynamic/admin/services/statistics/Tabs.jsx b/src/components/dynamic/admin/services/statistics/Tabs.jsx index 7143a7556..b9cf81579 100644 --- a/src/components/dynamic/admin/services/statistics/Tabs.jsx +++ b/src/components/dynamic/admin/services/statistics/Tabs.jsx @@ -1,12 +1,19 @@ import Tab from "./Tab"; -const Tabs = ({ counts }) => { +const Tabs = ({ counts, events }) => { return ( - <div className="w-full mt-3 grid grid-cols-7"> - {Object.entries(counts).map(([title, count], index) => ( - <Tab key={index} title={title} value={count} /> - ))} - </div> + <> + <div className="w-full mt-3 grid grid-cols-7"> + {Object.entries(counts).map(([title, count], index) => ( + <Tab key={index} title={title} value={count} /> + ))} + </div> + <div className="w-full mt-3 grid grid-cols-4"> + {Object.entries(events).map(([title, count], index) => ( + <Tab key={index} title={title} value={count} /> + ))} + </div> + </> ); }; diff --git a/src/data/dynamic/Navigation.js b/src/data/dynamic/Navigation.js index 2ab1880c9..9cdc943fb 100644 --- a/src/data/dynamic/Navigation.js +++ b/src/data/dynamic/Navigation.js @@ -130,12 +130,12 @@ export const TABS = { tabs: [ { name: "dashboard", - link: "/users/dashboard", + link: "/user/dashboard", icon: <BsFillPersonFill className={iconStyle} />, }, { name: "checkin", - link: "/users/checkin", + link: "/user/checkin", icon: <AiOutlineQrcode className={iconStyle} />, }, {