diff --git a/booking-app/app/api/db/addFields/route.ts b/booking-app/app/api/db/addFields/route.ts index d7352b64..c06bdb9c 100644 --- a/booking-app/app/api/db/addFields/route.ts +++ b/booking-app/app/api/db/addFields/route.ts @@ -4,16 +4,19 @@ import { serverUpdateInFirestore, } from "@/lib/firebase/server/adminDb"; +import { ApproverLevel } from "@/components/src/policy"; + export async function POST(request: NextRequest) { const { collection } = await request.json(); try { const rows = await serverFetchAllDataFromCollection(collection); - // await serverUpdateInFirestore(collection, rows[0].id, { level: 1 }); await Promise.all( rows.map(row => - serverUpdateInFirestore(collection, row.id, { level: 1 }), + serverUpdateInFirestore(collection, row.id, { + level: ApproverLevel.FIRST, + }), ), ); diff --git a/booking-app/components/src/client/routes/admin/components/Liaisons.tsx b/booking-app/components/src/client/routes/admin/components/Liaisons.tsx index f8529401..7ed7b2a8 100644 --- a/booking-app/components/src/client/routes/admin/components/Liaisons.tsx +++ b/booking-app/components/src/client/routes/admin/components/Liaisons.tsx @@ -46,7 +46,7 @@ const AddLiaisonForm = ({ liaisonEmails, reloadLiaisonEmails }) => { }; export const Liaisons = () => { - const { liaisonUsers, reloadLiaisonUsers } = useContext(DatabaseContext); + const { liaisonUsers, reloadApproverUsers } = useContext(DatabaseContext); const liaisonEmails = useMemo( () => liaisonUsers.map((user) => user.email), @@ -65,11 +65,11 @@ export const Liaisons = () => { tableName={TableNames.APPROVERS} columnNameToRemoveBy="email" rows={rows} - rowsRefresh={reloadLiaisonUsers} + rowsRefresh={reloadApproverUsers} topRow={ } columnFormatters={{ createdAt: formatDate }} diff --git a/booking-app/components/src/client/routes/admin/components/policySettings/FinalApprover.tsx b/booking-app/components/src/client/routes/admin/components/policySettings/FinalApprover.tsx index 5fa68679..e26861e3 100644 --- a/booking-app/components/src/client/routes/admin/components/policySettings/FinalApprover.tsx +++ b/booking-app/components/src/client/routes/admin/components/policySettings/FinalApprover.tsx @@ -10,10 +10,10 @@ import { import React, { useContext, useState } from "react"; import { DatabaseContext } from "../../../components/Provider"; -import { updatePolicySettingData } from "@/components/src/server/db"; +import { updateFinalApprover } from "@/components/src/server/db"; export default function FinalApprover() { - const { policySettings, reloadPolicySettings } = useContext(DatabaseContext); + const { policySettings, reloadApproverUsers } = useContext(DatabaseContext); const [editing, setEditing] = useState(false); const [finalApproverEmail, setFinalApproverEmail] = useState( policySettings.finalApproverEmail @@ -29,8 +29,8 @@ export default function FinalApprover() { const handleButtonClick = async () => { if (editing) { - await updatePolicySettingData({ finalApproverEmail }); - await reloadPolicySettings(); + await updateFinalApprover({ email: finalApproverEmail }); + await reloadApproverUsers(); } setEditing((prev) => !prev); }; diff --git a/booking-app/components/src/client/routes/components/Provider.tsx b/booking-app/components/src/client/routes/components/Provider.tsx index 7eba787e..1248881d 100644 --- a/booking-app/components/src/client/routes/components/Provider.tsx +++ b/booking-app/components/src/client/routes/components/Provider.tsx @@ -1,10 +1,10 @@ import { AdminUser, + Approver, Ban, Booking, BookingType, DepartmentType, - LiaisonType, PaUser, PagePermission, PolicySettings, @@ -12,9 +12,9 @@ import { SafetyTraining, Settings, } from "../../../types"; +import { ApproverLevel, TableNames } from "@/components/src/policy"; import React, { createContext, useEffect, useMemo, useState } from "react"; -import { TableNames } from "@/components/src/policy"; import { clientFetchAllDataFromCollection } from "@/lib/firebase/firebase"; import { fetchAllFutureBooking } from "@/components/src/server/db"; import { useAuth } from "@/components/src/client/routes/components/AuthProvider"; @@ -24,7 +24,7 @@ export interface DatabaseContextType { bannedUsers: Ban[]; bookings: Booking[]; bookingsLoading: boolean; - liaisonUsers: LiaisonType[]; + liaisonUsers: Approver[]; departmentNames: DepartmentType[]; pagePermission: PagePermission; paUsers: PaUser[]; @@ -34,12 +34,11 @@ export interface DatabaseContextType { settings: Settings; userEmail: string | undefined; reloadAdminUsers: () => Promise; + reloadApproverUsers: () => Promise; reloadBannedUsers: () => Promise; reloadBookings: () => Promise; - reloadLiaisonUsers: () => Promise; reloadDepartmentNames: () => Promise; reloadPaUsers: () => Promise; - reloadPolicySettings: () => Promise; reloadBookingTypes: () => Promise; reloadSafetyTrainedUsers: () => Promise; setUserEmail: (x: string) => void; @@ -60,12 +59,11 @@ export const DatabaseContext = createContext({ settings: { bookingTypes: [] }, userEmail: undefined, reloadAdminUsers: async () => {}, + reloadApproverUsers: async () => {}, reloadBannedUsers: async () => {}, reloadBookings: async () => {}, - reloadLiaisonUsers: async () => {}, reloadDepartmentNames: async () => {}, reloadPaUsers: async () => {}, - reloadPolicySettings: async () => {}, reloadBookingTypes: async () => {}, reloadSafetyTrainedUsers: async () => {}, setUserEmail: (x: string) => {}, @@ -80,7 +78,7 @@ export const DatabaseProvider = ({ const [bookings, setBookings] = useState([]); const [bookingsLoading, setBookingsLoading] = useState(true); const [adminUsers, setAdminUsers] = useState([]); - const [liaisonUsers, setLiaisonUsers] = useState([]); + const [liaisonUsers, setLiaisonUsers] = useState([]); const [departmentNames, setDepartmentName] = useState([]); const [paUsers, setPaUsers] = useState([]); const [policySettings, setPolicySettings] = useState({ @@ -110,7 +108,7 @@ export const DatabaseProvider = ({ if (!bookingsLoading) { fetchSafetyTrainedUsers(); fetchBannedUsers(); - fetchLiaisonUsers(); + fetchApproverUsers(); fetchDepartmentNames(); fetchSettings(); } else { @@ -295,19 +293,22 @@ export const DatabaseProvider = ({ .catch((error) => console.error("Error fetching data:", error)); }; - const fetchLiaisonUsers = async () => { + const fetchApproverUsers = async () => { clientFetchAllDataFromCollection(TableNames.APPROVERS) .then((fetchedData) => { - const filtered = fetchedData - .map((item: any) => ({ - id: item.id, - email: item.email, - department: item.department, - createdAt: item.createdAt, - level: Number(item.level), - })) - .filter((x) => x.level === 1); - setLiaisonUsers(filtered); + const all = fetchedData.map((item: any) => ({ + id: item.id, + email: item.email, + department: item.department, + createdAt: item.createdAt, + level: Number(item.level), + })); + const liaisons = all.filter((x) => x.level === ApproverLevel.FIRST); + const finalApprover = all.filter( + (x) => x.level === ApproverLevel.FINAL + )[0]; + setLiaisonUsers(liaisons); + setPolicySettings({ finalApproverEmail: finalApprover.email }); }) .catch((error) => console.error("Error fetching data:", error)); }; @@ -357,22 +358,21 @@ export const DatabaseProvider = ({ .catch((error) => console.error("Error fetching data:", error)); }; - const fetchPolicySettings = async () => { - clientFetchAllDataFromCollection(TableNames.POLICY) - .then((fetchedData) => { - const policy: PolicySettings = fetchedData.map((item: any) => ({ - finalApproverEmail: item.finalApproverEmail, - }))[0]; // should only be 1 document - setPolicySettings(policy); - }) - .catch((error) => - console.error("Error fetching policy settings data:", error) - ); - }; + // const fetchPolicySettings = async () => { + // clientFetchAllDataFromCollection(TableNames.POLICY) + // .then((fetchedData) => { + // const policy: PolicySettings = fetchedData.map((item: any) => ({ + // finalApproverEmail: item.finalApproverEmail, + // }))[0]; // should only be 1 document + // setPolicySettings(policy); + // }) + // .catch((error) => + // console.error("Error fetching policy settings data:", error) + // ); + // }; const fetchSettings = async () => { fetchBookingTypes(); - fetchPolicySettings(); }; return ( @@ -392,12 +392,11 @@ export const DatabaseProvider = ({ userEmail, bookingsLoading, reloadAdminUsers: fetchAdminUsers, + reloadApproverUsers: fetchApproverUsers, reloadBannedUsers: fetchBannedUsers, reloadBookings: fetchBookings, - reloadLiaisonUsers: fetchLiaisonUsers, reloadDepartmentNames: fetchDepartmentNames, reloadPaUsers: fetchPaUsers, - reloadPolicySettings: fetchPolicySettings, reloadBookingTypes: fetchBookingTypes, reloadSafetyTrainedUsers: fetchSafetyTrainedUsers, setUserEmail, diff --git a/booking-app/components/src/policy.ts b/booking-app/components/src/policy.ts index c3a0df16..d30ed9a0 100644 --- a/booking-app/components/src/policy.ts +++ b/booking-app/components/src/policy.ts @@ -14,12 +14,16 @@ export enum TableNames { BOOKING_TYPES = "bookingTypes", DEPARTMENTS = "departments", PAS = "usersPa", - POLICY = "policy", RESOURCES = "resources", SAFETY_TRAINING = "usersWhitelist", SETTINGS = "settings", } +export enum ApproverLevel { + FIRST = 1, + FINAL = 2, +} + /** Old safety training Google Sheet */ export const OLD_SAFETY_TRAINING_SHEET_ID = "1Debe5qF-2qXJhqP0AMy5etEvwAPd3mNFiTswytsbKxQ"; diff --git a/booking-app/components/src/server/db.ts b/booking-app/components/src/server/db.ts index d34e7e5c..ba619a38 100644 --- a/booking-app/components/src/server/db.ts +++ b/booking-app/components/src/server/db.ts @@ -1,9 +1,11 @@ import { + Approver, BookingFormDetails, BookingStatusLabel, PolicySettings, } from "../types"; import { + ApproverLevel, TableNames, clientGetFinalApproverEmail, getCancelCcEmail, @@ -137,21 +139,23 @@ export const cancel = async (id: string, email: string) => { ); }; -export const updatePolicySettingData = async (updatedData: object) => { - type PolicySettingsDoc = PolicySettings & { id: string }; - const policySettingsDocs = - await clientFetchAllDataFromCollection( - TableNames.POLICY - ); +export const updateFinalApprover = async (updatedData: object) => { + type ApproverDoc = Approver & { id: string }; + const approverDocs = await clientFetchAllDataFromCollection( + TableNames.APPROVERS + ); - if (policySettingsDocs.length > 0) { - const policySettings = policySettingsDocs[0]; // should only be 1 doc - const docId = policySettings.id; - await clientUpdateDataInFirestore(TableNames.POLICY, docId, updatedData); + if (approverDocs.length > 0) { + const finalApproverDoc = approverDocs.filter( + (doc) => doc.level === ApproverLevel.FINAL + )[0]; // assuming only 1 final approver + const docId = finalApproverDoc.id; + await clientUpdateDataInFirestore(TableNames.APPROVERS, docId, updatedData); } else { console.log("No policy settings docs found"); } }; + export const checkin = async (id: string, email: string) => { clientUpdateDataByCalendarEventId(TableNames.BOOKING, id, { checkedInAt: Timestamp.now(), diff --git a/booking-app/components/src/types.ts b/booking-app/components/src/types.ts index 3ccbc725..00a6267f 100644 --- a/booking-app/components/src/types.ts +++ b/booking-app/components/src/types.ts @@ -5,6 +5,13 @@ export type AdminUser = { createdAt: string; }; +export type Approver = { + email: string; + department: string; + createdAt: string; + level: number; +}; + export enum AttendeeAffiliation { NYU = "NYU Members with an active NYU ID", NON_NYU = "Non-NYU guests", @@ -143,13 +150,6 @@ export type Inputs = { chartFieldForRoomSetup: string; }; -export type LiaisonType = { - email: string; - department: string; - createdAt: string; - level: number; -}; - export type DepartmentType = { department: string; createdAt: string; diff --git a/booking-app/lib/firebase/firebase.ts b/booking-app/lib/firebase/firebase.ts index 2232c14b..34741c9f 100644 --- a/booking-app/lib/firebase/firebase.ts +++ b/booking-app/lib/firebase/firebase.ts @@ -1,3 +1,4 @@ +import { ApproverLevel, TableNames } from "@/components/src/policy"; // saveData.ts import { QueryConstraint, @@ -15,7 +16,6 @@ import { where, } from "@firebase/firestore"; -import { TableNames } from "@/components/src/policy"; import { getDb } from "./firebaseClient"; export type AdminUserData = { @@ -70,13 +70,17 @@ export const clientGetFinalApproverEmailFromDatabase = async (): Promise< > => { try { const db = getDb(); - const policyCollection = collection(db, TableNames.POLICY); - const q = query(policyCollection, limit(1)); + const approversCollection = collection(db, TableNames.APPROVERS); + const q = query( + approversCollection, + where("level", "==", ApproverLevel.FINAL) + ); const querySnapshot = await getDocs(q); if (!querySnapshot.empty) { - const doc = querySnapshot.docs[0]; - const finalApproverEmail = doc.data().finalApproverEmail; + const doc = querySnapshot.docs[0]; // assuming only one final approver + const finalApproverEmail = doc.data().email; if (finalApproverEmail) { + console.log("HERE", finalApproverEmail); return finalApproverEmail; } } diff --git a/booking-app/lib/firebase/server/adminDb.ts b/booking-app/lib/firebase/server/adminDb.ts index 7bce3abd..4cbfedad 100644 --- a/booking-app/lib/firebase/server/adminDb.ts +++ b/booking-app/lib/firebase/server/adminDb.ts @@ -1,3 +1,4 @@ +import { ApproverLevel, TableNames } from "@/components/src/policy"; import { CollectionReference, DocumentData, @@ -5,8 +6,8 @@ import { QuerySnapshot, WhereFilterOp, } from "firebase-admin/firestore"; + import admin from "./firebaseAdmin"; -import { TableNames } from "@/components/src/policy"; const db = admin.firestore(); @@ -116,11 +117,13 @@ export const serverGetFinalApproverEmailFromDatabase = async (): Promise< string | null > => { try { - const policyCollection = db.collection(TableNames.POLICY); - const querySnapshot = await policyCollection.limit(1).get(); + const policyCollection = db.collection(TableNames.APPROVERS); + const querySnapshot = await policyCollection + .where("level", "==", ApproverLevel.FINAL) + .get(); if (!querySnapshot.empty) { const doc = querySnapshot.docs[0]; - const finalApproverEmail = doc.data().finalApproverEmail; + const finalApproverEmail = doc.data().email; if (finalApproverEmail) { return finalApproverEmail; }