From 2d22cf1f98b3ce13b54d72a2f2c4a99e3ec15b02 Mon Sep 17 00:00:00 2001 From: Jason Date: Fri, 16 Aug 2024 13:08:27 -0500 Subject: [PATCH 01/12] migrate qrcode scanner package and update ui --- app.json | 6 +- package.json | 2 +- src/screens/events/QRCodeManager.tsx | 11 ++-- src/screens/events/QRCodeScanningScreen.tsx | 69 ++++++++++++++++----- yarn.lock | 14 ++--- 5 files changed, 74 insertions(+), 28 deletions(-) diff --git a/app.json b/app.json index 2cc6a523..a98743da 100644 --- a/app.json +++ b/app.json @@ -34,9 +34,11 @@ } ], [ - "expo-barcode-scanner", + "expo-camera", { - "cameraPermission": "TAMU SHPE needs to access the camera to scan QR codes." + "cameraPermission": "TAMU SHPE needs access to your camera to scan QRCode", + "microphonePermission": "Allow TAMUSHPE to access your microphone", + "recordAudioAndroid": false } ] ], diff --git a/package.json b/package.json index 470cc492..7a97fa80 100644 --- a/package.json +++ b/package.json @@ -33,8 +33,8 @@ "expo": "~51.0.7", "expo-application": "~5.9.1", "expo-auth-session": "~5.5.2", - "expo-barcode-scanner": "~13.0.1", "expo-build-properties": "~0.12.1", + "expo-camera": "~15.0.14", "expo-clipboard": "~6.0.3", "expo-constants": "~16.0.1", "expo-crypto": "~13.0.2", diff --git a/src/screens/events/QRCodeManager.tsx b/src/screens/events/QRCodeManager.tsx index d966a0bd..4144f79f 100644 --- a/src/screens/events/QRCodeManager.tsx +++ b/src/screens/events/QRCodeManager.tsx @@ -86,12 +86,15 @@ const QRCodeManager: React.FC = ({ route, navigation }) = - {!event.signInPoints && !event.signOutPoints && ( + {!event.signInPoints && !event.signOutPoints && event.signInPoints !== 0 && event.signOutPoints !== 0 && ( - No QR Codes Available + + No QR Codes Available + )} - {event.signInPoints !== null && event.signInPoints !== undefined && event.signInPoints >= 0 && ( + + {event.signInPoints !== null && event.signInPoints !== undefined && ( = ({ route, navigation }) = )} - {event.signOutPoints !== null && event.signOutPoints !== undefined && event.signOutPoints >= 0 && ( + {event.signOutPoints !== null && event.signOutPoints !== undefined && ( ) => { const [hasCameraPermissions, setHasCameraPermissions] = useState(null); const [scanned, setScanned] = useState(false); + const pulseAnim = useRef(new Animated.Value(1)).current; useEffect(() => { const getBarCodeScannerPermissions = async () => { - const { status } = await BarCodeScanner.requestPermissionsAsync(); + const { status } = await Camera.requestCameraPermissionsAsync(); setHasCameraPermissions(status === 'granted'); }; getBarCodeScannerPermissions(); }, []); + useEffect(() => { + const pulse = () => { + Animated.sequence([ + Animated.timing(pulseAnim, { + toValue: 1.1, + duration: 800, + easing: Easing.inOut(Easing.ease), + useNativeDriver: true, + }), + Animated.timing(pulseAnim, { + toValue: 1, + duration: 800, + easing: Easing.inOut(Easing.ease), + useNativeDriver: true, + }), + ]).start(() => pulse()); + }; + + pulse(); + }, [pulseAnim]); + const handleBarCodeScanned = ({ type, data }: { type: string, data: string }) => { console.log('Data Received', `Bar code with type ${type} and data ${data} has been scanned!`); setScanned(true); @@ -51,22 +73,41 @@ const QRCodeScanningScreen = ({ navigation }: NativeStackScreenProps + {/* Header */} - + - Scan Event QR Code + Scanner navigation.goBack()} > - + - { } : handleBarCodeScanned} - /> - Scan a QR code to sign in/out of an event + + + {/* Pulsing Effect */} + + + + + + + + + + + + + + Using Scanner + Scan the QRCode provided by the event host. + ); }; diff --git a/yarn.lock b/yarn.lock index 934b3380..b9ddbf31 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5787,13 +5787,6 @@ expo-auth-session@~5.5.2: expo-web-browser "~13.0.0" invariant "^2.2.4" -expo-barcode-scanner@~13.0.1: - version "13.0.1" - resolved "https://registry.yarnpkg.com/expo-barcode-scanner/-/expo-barcode-scanner-13.0.1.tgz#c7218c78f9e3d27086473a9826756bbcacd7f117" - integrity sha512-xBGLT1An2gpAMIQRTLU3oHydKohX8r8F9/ait1Fk9Vgd0GraFZbP4IiT7nHMlaw4H6E7Muucf7vXpGV6u7d4HQ== - dependencies: - expo-image-loader "~4.7.0" - expo-build-properties@~0.12.1: version "0.12.1" resolved "https://registry.yarnpkg.com/expo-build-properties/-/expo-build-properties-0.12.1.tgz#8d11759b8f382e4654e2482ddcec4f9ad4530aad" @@ -5802,6 +5795,13 @@ expo-build-properties@~0.12.1: ajv "^8.11.0" semver "^7.6.0" +expo-camera@~15.0.14: + version "15.0.14" + resolved "https://registry.yarnpkg.com/expo-camera/-/expo-camera-15.0.14.tgz#1fec9c0e650cfa5b85d34ce8267ae8a9854eee4a" + integrity sha512-O4uvVywGsQ3a89d0BX4lq6mDuGYGukx1PYY4QrC9zw1yzD2W9BVTl8lanFRPC5h4PRniekfeWUVH1a0jJmkLIw== + dependencies: + invariant "^2.2.4" + expo-clipboard@~6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/expo-clipboard/-/expo-clipboard-6.0.3.tgz#dfea74d4a004dce59ecefd063d6fb9f1c356a03f" From 6c331aff9fa2249f96a8854e1960754ac14593ce Mon Sep 17 00:00:00 2001 From: Jason Date: Fri, 16 Aug 2024 13:08:48 -0500 Subject: [PATCH 02/12] update readme to include app store links --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b7c09bfb..030e1b9d 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,14 @@

- Your Famila, Our Mission. + + Download on the App Store + +   + + Get it on Google Play +

- ## Introduction The TAMU SHPE mobile application, designed for the Texas A&M University Chapter of the Society of Hispanic Professional Engineers, is a tool aimed at enhancing member interaction and engagement. This application brings together a host of features, each developed to streamline organizational processes and encourage community involvement. From 0885d2998f2d722b40e279c588424f3daf700bc8 Mon Sep 17 00:00:00 2001 From: Jason Date: Fri, 16 Aug 2024 13:15:09 -0500 Subject: [PATCH 03/12] update qrcode scan size --- src/screens/events/QRCodeScanningScreen.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/screens/events/QRCodeScanningScreen.tsx b/src/screens/events/QRCodeScanningScreen.tsx index ffcffe73..ff153ecc 100644 --- a/src/screens/events/QRCodeScanningScreen.tsx +++ b/src/screens/events/QRCodeScanningScreen.tsx @@ -94,7 +94,7 @@ const QRCodeScanningScreen = ({ navigation }: NativeStackScreenProps - + From 75c9dd9237b003ccbddd5485c93856d756008467 Mon Sep 17 00:00:00 2001 From: Jason Date: Fri, 16 Aug 2024 13:23:24 -0500 Subject: [PATCH 04/12] specify sign in or sign out message in event verification --- functions/src/types/events.ts | 11 ++++++----- shpe-app-web/app/types/events.ts | 11 ++++++----- src/screens/events/EventVerification.tsx | 2 +- src/types/events.ts | 8 ++++---- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/functions/src/types/events.ts b/functions/src/types/events.ts index fc097ab4..5b5d6d7b 100644 --- a/functions/src/types/events.ts +++ b/functions/src/types/events.ts @@ -406,15 +406,15 @@ export type UserEventData = { eventLog?: SHPEEventLog, } -export const getStatusMessage = (status: EventLogStatus): string => { +export const getStatusMessage = (status: EventLogStatus, mode?: "sign-in" | "sign-out"): string => { const statusMessages = { - [EventLogStatus.SUCCESS]: "Successfully signed in/out.", + [EventLogStatus.SUCCESS]: `Successfully ${mode === "sign-in" ? "signed in" : "signed out"}.`, [EventLogStatus.EVENT_OVER]: "The event is already over.", [EventLogStatus.EVENT_ONGOING]: "The event is ongoing.", - [EventLogStatus.EVENT_NOT_STARTED]: "The event has not started yet.", [EventLogStatus.EVENT_NOT_FOUND]: "The event was not found.", - [EventLogStatus.ALREADY_LOGGED]: "You have already signed in/out.", - [EventLogStatus.NOT_A_STUDENT]: "Only student can sign in/out of events..", + [EventLogStatus.ALREADY_LOGGED]: `You have already ${mode === "sign-in" ? "signed in" : "signed out"}.`, + [EventLogStatus.NOT_A_STUDENT]: "Only students can sign in/out of events.", + [EventLogStatus.EVENT_NOT_STARTED]: "The event has not started yet.", [EventLogStatus.OUT_OF_RANGE]: "You are not close enough to the event to sign in/out.", [EventLogStatus.ERROR]: "An internal error occurred. Please try again.", }; @@ -422,3 +422,4 @@ export const getStatusMessage = (status: EventLogStatus): string => { return statusMessages[status] || "An unknown error occurred."; }; + diff --git a/shpe-app-web/app/types/events.ts b/shpe-app-web/app/types/events.ts index 8ca86f81..3b773249 100644 --- a/shpe-app-web/app/types/events.ts +++ b/shpe-app-web/app/types/events.ts @@ -409,15 +409,15 @@ export type UserEventData = { eventLog?: SHPEEventLog, } -export const getStatusMessage = (status: EventLogStatus): string => { +export const getStatusMessage = (status: EventLogStatus, mode?: "sign-in" | "sign-out"): string => { const statusMessages = { - [EventLogStatus.SUCCESS]: "Successfully signed in/out.", + [EventLogStatus.SUCCESS]: `Successfully ${mode === "sign-in" ? "signed in" : "signed out"}.`, [EventLogStatus.EVENT_OVER]: "The event is already over.", [EventLogStatus.EVENT_ONGOING]: "The event is ongoing.", - [EventLogStatus.EVENT_NOT_STARTED]: "The event has not started yet.", [EventLogStatus.EVENT_NOT_FOUND]: "The event was not found.", - [EventLogStatus.ALREADY_LOGGED]: "You have already signed in/out.", - [EventLogStatus.NOT_A_STUDENT]: "Only student can sign in/out of events..", + [EventLogStatus.ALREADY_LOGGED]: `You have already ${mode === "sign-in" ? "signed in" : "signed out"}.`, + [EventLogStatus.NOT_A_STUDENT]: "Only students can sign in/out of events.", + [EventLogStatus.EVENT_NOT_STARTED]: "The event has not started yet.", [EventLogStatus.OUT_OF_RANGE]: "You are not close enough to the event to sign in/out.", [EventLogStatus.ERROR]: "An internal error occurred. Please try again.", }; @@ -425,3 +425,4 @@ export const getStatusMessage = (status: EventLogStatus): string => { return statusMessages[status] || "An unknown error occurred."; }; + diff --git a/src/screens/events/EventVerification.tsx b/src/screens/events/EventVerification.tsx index 4631b2dd..a5d9f3e0 100644 --- a/src/screens/events/EventVerification.tsx +++ b/src/screens/events/EventVerification.tsx @@ -126,7 +126,7 @@ const EventVerification: React.FC = ({ route, }; const { animation, haptic, bgColor } = statusComponents[logStatus]; - const message = getStatusMessage(logStatus); + const message = getStatusMessage(logStatus, mode); return ( diff --git a/src/types/events.ts b/src/types/events.ts index 46fd761e..a1a50c75 100644 --- a/src/types/events.ts +++ b/src/types/events.ts @@ -416,14 +416,14 @@ export type UserEventData = { eventLog?: SHPEEventLog, } -export const getStatusMessage = (status: EventLogStatus): string => { +export const getStatusMessage = (status: EventLogStatus, mode?: "sign-in" | "sign-out"): string => { const statusMessages = { - [EventLogStatus.SUCCESS]: "Successfully signed in/out.", + [EventLogStatus.SUCCESS]: `Successfully ${mode === "sign-in" ? "signed in" : "signed out"}.`, [EventLogStatus.EVENT_OVER]: "The event is already over.", [EventLogStatus.EVENT_ONGOING]: "The event is ongoing.", [EventLogStatus.EVENT_NOT_FOUND]: "The event was not found.", - [EventLogStatus.ALREADY_LOGGED]: "You have already signed in/out.", - [EventLogStatus.NOT_A_STUDENT]: "Only student can sign in/out of events..", + [EventLogStatus.ALREADY_LOGGED]: `You have already ${mode === "sign-in" ? "signed in" : "signed out"}.`, + [EventLogStatus.NOT_A_STUDENT]: "Only students can sign in/out of events.", [EventLogStatus.EVENT_NOT_STARTED]: "The event has not started yet.", [EventLogStatus.OUT_OF_RANGE]: "You are not close enough to the event to sign in/out.", [EventLogStatus.ERROR]: "An internal error occurred. Please try again.", From aebd888226ead8c63fc54a02c99c45dafce2b38c Mon Sep 17 00:00:00 2001 From: Jason Date: Fri, 16 Aug 2024 13:54:39 -0500 Subject: [PATCH 05/12] add resume downloader --- shpe-app-web/app/(main)/tools/page.tsx | 101 ++++++++++++++++++++++--- 1 file changed, 92 insertions(+), 9 deletions(-) diff --git a/shpe-app-web/app/(main)/tools/page.tsx b/shpe-app-web/app/(main)/tools/page.tsx index 9486a61e..9484ce49 100644 --- a/shpe-app-web/app/(main)/tools/page.tsx +++ b/shpe-app-web/app/(main)/tools/page.tsx @@ -4,10 +4,15 @@ import { useRouter } from "next/navigation"; import Header from "@/components/Header"; import { onAuthStateChanged } from "firebase/auth"; import { auth } from "@/config/firebaseConfig"; +import { getFunctions, httpsCallable } from "firebase/functions"; +import { doc, onSnapshot } from "firebase/firestore"; +import { db } from "@/config/firebaseConfig"; const Tools = () => { const router = useRouter(); const [loading, setLoading] = useState(true); + const [isGenerated, setIsGenerated] = useState(false); + const [resumeDownloadInfo, setResumeDownloadInfo] = useState(null); useEffect(() => { const unsubscribe = onAuthStateChanged(auth, (currentUser) => { @@ -22,19 +27,97 @@ const Tools = () => { return () => unsubscribe(); }, [router]); - if (loading) { - return ( -
- -
- ); - } + useEffect(() => { + const statusRef = doc(db, 'resumes/status'); + const dataRef = doc(db, 'resumes/data'); + + const unsubscribeStatus = onSnapshot(statusRef, (docSnapshot) => { + if (docSnapshot.exists()) { + const statusData = docSnapshot.data(); + setIsGenerated(statusData.isGenerated); + } else { + setIsGenerated(false); + } + }); + + const unsubscribeData = onSnapshot(dataRef, (docSnapshot) => { + if (docSnapshot.exists()) { + const downloadInfo = { + url: docSnapshot.data().url, + createdAt: docSnapshot.data().createdAt.toDate(), + expiresAt: docSnapshot.data().expiresAt.toDate(), + }; + setResumeDownloadInfo(downloadInfo); + } else { + setResumeDownloadInfo(null); + } + }); + + return () => { + unsubscribeStatus(); + unsubscribeData(); + }; + }, []); + + const zipResumes = async () => { + setIsGenerated(false); + const functions = getFunctions(); + const zipResumesFunction = httpsCallable(functions, 'zipResume'); + try { + await zipResumesFunction(); + } catch (error) { + console.error('Error:', error); + } + }; + + const handleDownloadResume = () => { + if (resumeDownloadInfo && resumeDownloadInfo.url) { + const link = document.createElement('a'); + link.href = resumeDownloadInfo.url; + link.setAttribute('download', `resume_${new Date().toISOString()}.zip`); + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + } + }; + + const isExpired = (expiresAt: Date) => { + const now = new Date(); + return now > expiresAt; + }; return (
-
+
+ +
+ + + {isGenerated && resumeDownloadInfo && !isExpired(resumeDownloadInfo.expiresAt) ? ( + + ) : ( +

Link is being generated.

+ )} +
); } -export default Tools; \ No newline at end of file +interface ResumeDownloadInfo { + url: string; + createdAt: Date; + expiresAt: Date; +} + + +export default Tools; From d57935eb40fe82ad0c88e81a81403a97d75e9707 Mon Sep 17 00:00:00 2001 From: Jason Date: Fri, 16 Aug 2024 14:00:59 -0500 Subject: [PATCH 06/12] delete user tab --- shpe-app-web/app/(main)/users/page.tsx | 25 ------------------------- shpe-app-web/app/components/Navbar.tsx | 22 +++------------------- 2 files changed, 3 insertions(+), 44 deletions(-) delete mode 100644 shpe-app-web/app/(main)/users/page.tsx diff --git a/shpe-app-web/app/(main)/users/page.tsx b/shpe-app-web/app/(main)/users/page.tsx deleted file mode 100644 index 6c122c97..00000000 --- a/shpe-app-web/app/(main)/users/page.tsx +++ /dev/null @@ -1,25 +0,0 @@ -'use client' -import Header from "@/components/Header"; -import { useRouter } from "next/navigation"; -import { useEffect, useState } from "react"; - -const Users = () => { - const router = useRouter(); - const [loading, setLoading] = useState(true); - - if (loading) { - return ( -
- -
- ); - } - - return ( -
-
-
- ); -} - -export default Users; \ No newline at end of file diff --git a/shpe-app-web/app/components/Navbar.tsx b/shpe-app-web/app/components/Navbar.tsx index d7ae4fdf..6ac98293 100644 --- a/shpe-app-web/app/components/Navbar.tsx +++ b/shpe-app-web/app/components/Navbar.tsx @@ -23,9 +23,9 @@ const Navbar = () => { {path == '/dashboard' ? - Dashboard - : '' + Dashboard + : '' } @@ -98,22 +98,6 @@ const Navbar = () => { - -
- Dashboard -
Users
-
- - { - - path == '/users' ? - Dashboard - : '' - - } - -
Dashboard From 51fe8b3f9ae2ac5c98ca6135eb573731b78b9d3f Mon Sep 17 00:00:00 2001 From: Jason Date: Fri, 16 Aug 2024 14:20:19 -0500 Subject: [PATCH 07/12] fix destroy event on home screen, fix navigation in home screen --- src/api/firebaseUtils.ts | 4 +++- src/navigation/EventsStack.tsx | 3 +++ src/screens/events/UpdateEvent.tsx | 13 ++++++++++--- src/screens/home/Home.tsx | 14 ++++++++++++-- src/types/navigation.ts | 1 + 5 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/api/firebaseUtils.ts b/src/api/firebaseUtils.ts index 75eb1c02..83862aa7 100644 --- a/src/api/firebaseUtils.ts +++ b/src/api/firebaseUtils.ts @@ -1291,7 +1291,9 @@ export const getMyEvents = async (committees: string[], interests: string[], max querySnapshots.forEach(querySnapshot => { querySnapshot.forEach(doc => { if (!allEvents.has(doc.id)) { - allEvents.set(doc.id, doc.data()); + const eventData = doc.data(); + eventData.id = doc.id; + allEvents.set(doc.id, eventData); } }); }); diff --git a/src/navigation/EventsStack.tsx b/src/navigation/EventsStack.tsx index 943bae1b..be994b35 100644 --- a/src/navigation/EventsStack.tsx +++ b/src/navigation/EventsStack.tsx @@ -13,6 +13,7 @@ import SetLocationEventDetails from "../screens/events/SetLocationEventDetails"; import EventVerification from "../screens/events/EventVerification"; import PublicProfileScreen from "../screens/userProfile/PublicProfile"; import PastEvents from "../screens/events/PastEvents"; +import Home from "../screens/home/Home"; const EventsStack = () => { const Stack = createNativeStackNavigator(); @@ -35,6 +36,8 @@ const EventsStack = () => { + + ); }; diff --git a/src/screens/events/UpdateEvent.tsx b/src/screens/events/UpdateEvent.tsx index 23875008..73d03b5f 100644 --- a/src/screens/events/UpdateEvent.tsx +++ b/src/screens/events/UpdateEvent.tsx @@ -1,7 +1,7 @@ import { View, Text, TouchableOpacity, TextInput, Image, Platform, TouchableHighlight, Modal, Alert, ActivityIndicator, useColorScheme } from 'react-native' import React, { useContext, useState } from 'react' import { EventProps, UpdateEventScreenRouteProp } from '../../types/navigation' -import { useRoute } from '@react-navigation/core'; +import { useNavigationState, useRoute } from '@react-navigation/core'; import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context'; import { Octicons, FontAwesome } from '@expo/vector-icons'; import { CommitteeMeeting, EventType, GeneralMeeting, IntramuralEvent, CustomEvent, SHPEEvent, SocialEvent, StudyHours, VolunteerEvent, Workshop } from '../../types/events'; @@ -26,9 +26,11 @@ import DismissibleModal from '../../components/DismissibleModal'; const UpdateEvent = ({ navigation }: EventProps) => { const route = useRoute(); const { event } = route.params; - const userContext = useContext(UserContext); const { userInfo } = userContext!; + const routes = useNavigationState(state => state.routes); + const isInHomeStack = routes.some(route => route.name === 'Home'); + const fixDarkMode = userInfo?.private?.privateInfo?.settings?.darkMode; const useSystemDefault = userInfo?.private?.privateInfo?.settings?.useSystemDefault; @@ -157,9 +159,14 @@ const UpdateEvent = ({ navigation }: EventProps) => { }; const handleDestroyEvent = async () => { + console.log("Destroying event with ID:", event.id); const isDeleted = await destroyEvent(event.id!); if (isDeleted) { - navigation.navigate("EventsScreen", {}) + if (isInHomeStack) { + navigation.navigate("Home") + } else { + navigation.navigate("EventsScreen", {}) + } } else { console.log("Failed to delete the event."); } diff --git a/src/screens/home/Home.tsx b/src/screens/home/Home.tsx index b7a11e65..db537a75 100644 --- a/src/screens/home/Home.tsx +++ b/src/screens/home/Home.tsx @@ -1,5 +1,5 @@ import { ActivityIndicator, Image, ScrollView, Text, TouchableOpacity, View, useColorScheme } from 'react-native'; -import React, { useContext, useEffect, useState } from 'react'; +import React, { useCallback, useContext, useEffect, useState } from 'react'; import { NativeStackScreenProps } from '@react-navigation/native-stack'; import { StatusBar } from 'expo-status-bar'; import { Octicons } from '@expo/vector-icons'; @@ -19,6 +19,7 @@ import { EventType, SHPEEvent } from '../../types/events'; import EventCard from '../events/EventCard'; import { reverseFormattedFirebaseName } from '../../types/committees'; import { doc, getDoc } from 'firebase/firestore'; +import { useFocusEffect } from '@react-navigation/core'; /** * Renders the home screen of the application. @@ -58,7 +59,7 @@ const Home = ({ navigation, route }: NativeStackScreenProps) => try { setIsLoading(true); - const events = await getMyEvents(userCommittees, userInterests, 3); + const events = await getMyEvents(userCommittees, userInterests, 4); events.sort((a, b) => (a.startTime?.toDate().getTime() || 0) - (b.startTime?.toDate().getTime() || 0)); setMyEvents(events); } catch (error) { @@ -134,6 +135,15 @@ const Home = ({ navigation, route }: NativeStackScreenProps) => } }, [currentUser]); + useFocusEffect( + useCallback(() => { + if (hasPrivileges) { + + fetchEvents(); + } + }, [hasPrivileges]) + ); + const isInterestChanged = () => { if (!userInfo?.publicInfo?.interests) { return userInterests.length > 0; diff --git a/src/types/navigation.ts b/src/types/navigation.ts index 9a662e25..81bc9dff 100644 --- a/src/types/navigation.ts +++ b/src/types/navigation.ts @@ -97,6 +97,7 @@ export type EventsStackParams = { EventVerificationScreen: { id: string; mode: "sign-in" | "sign-out"; }; PublicProfile: { uid: string; }; + Home: undefined; } export type CommitteesStackParams = { From ab4965052a51f6be27a24007dfd2cfb2f9cc3893 Mon Sep 17 00:00:00 2001 From: Jason Date: Fri, 16 Aug 2024 14:25:21 -0500 Subject: [PATCH 08/12] order request for committee --- src/screens/admin/CommitteeConfirm.tsx | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/screens/admin/CommitteeConfirm.tsx b/src/screens/admin/CommitteeConfirm.tsx index 96c98051..590ac9b2 100644 --- a/src/screens/admin/CommitteeConfirm.tsx +++ b/src/screens/admin/CommitteeConfirm.tsx @@ -47,10 +47,22 @@ const CommitteeConfirm = ({ navigation }: NativeStackScreenProps ({ - firebaseDocName: doc.id, - ...doc.data() as Committee - })) + + const committees = await Promise.all(snapshot.docs.map(async doc => { + const firebaseDocName = doc.id; + const requestSnapshot = await getDocs(collection(db, `committeeVerification/${firebaseDocName}/requests`)); + const requestCount = requestSnapshot.size; // Count the number of requests + + return { + firebaseDocName, + requestCount, // Include request count + ...doc.data() as Committee + }; + })); + + // Sort committees by request count in descending order + committees.sort((a, b) => b.requestCount - a.requestCount); + setCommittees(committees); } catch (err) { console.error("Error fetching open committees:", err); From e1edcdf3f548a524451c6066125c48243bf6f162 Mon Sep 17 00:00:00 2001 From: Jason Date: Fri, 16 Aug 2024 14:28:49 -0500 Subject: [PATCH 09/12] add committee count scheduler --- functions/src/committees.ts | 12 +++++++++--- functions/src/index.ts | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/functions/src/committees.ts b/functions/src/committees.ts index ebc9577e..2a6c15db 100644 --- a/functions/src/committees.ts +++ b/functions/src/committees.ts @@ -1,7 +1,7 @@ import * as functions from 'firebase-functions'; -import { db } from "./firebaseConfig" +import { db } from "./firebaseConfig"; -export const updateCommitteeCount = functions.https.onCall(async (data, context) => { +async function updateCommitteeCounts() { const committeesCount: CommitteeCounts = {}; const usersRef = db.collection('users'); @@ -24,10 +24,16 @@ export const updateCommitteeCount = functions.https.onCall(async (data, context) console.log('Committee counts updated:', committeesCount); return { message: 'Committee counts updated successfully', committeesCount }; +} + +export const updateCommitteeCount = functions.https.onCall(async (data, context) => { + return updateCommitteeCounts(); +}); +export const scheduleCommitteeCount = functions.pubsub.schedule('every 24 hours').onRun(async (context) => { + return updateCommitteeCounts(); }); interface CommitteeCounts { [key: string]: number; } - diff --git a/functions/src/index.ts b/functions/src/index.ts index 7087a736..5c691d8c 100644 --- a/functions/src/index.ts +++ b/functions/src/index.ts @@ -1,6 +1,6 @@ export { notifyUpcomingEvents, sendNotificationOfficeHours, sendNotificationMemberSHPE, sendNotificationCommitteeRequest, sendNotificationResumeConfirm } from "./pushNotification"; export { updateUserPoints, updateAllUserPoints, scheduledUpdateAllPoints } from "./pointSheet"; -export { updateCommitteeCount } from "./committees"; +export { updateCommitteeCount, scheduleCommitteeCount } from "./committees"; // export { resetOfficeScheduler } from "./officeReset"; export { resetOfficeOnCall } from "./officeReset"; export { zipResume } from "./resume"; From 050fd3241ed7e0e44a56af2b2d3b9556812c202e Mon Sep 17 00:00:00 2001 From: Jason Date: Fri, 16 Aug 2024 21:00:40 -0500 Subject: [PATCH 10/12] increase default image size --- src/helpers/validation.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helpers/validation.ts b/src/helpers/validation.ts index c3d89468..04178f46 100644 --- a/src/helpers/validation.ts +++ b/src/helpers/validation.ts @@ -135,7 +135,7 @@ export abstract class CommonMimeTypes { * console.log("Valid File"); * } */ -export const validateFileBlob = (file: Blob, allowedMimeTypes: Array, alertUser: boolean = false, maxSize: number = 8388608): boolean => { +export const validateFileBlob = (file: Blob, allowedMimeTypes: Array, alertUser: boolean = false, maxSize: number = 32000000): boolean => { const isValidMimeType = allowedMimeTypes.includes(file.type) const isValidSize = file.size < maxSize; const bytesInMegabyte = 1048576; From 3b070eaec25cd66efbc4a578736d8ff498a644ae Mon Sep 17 00:00:00 2001 From: Jason Date: Sat, 17 Aug 2024 13:18:28 -0500 Subject: [PATCH 11/12] fix motm card to fetch latest profile --- src/components/MOTMCard.tsx | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/components/MOTMCard.tsx b/src/components/MOTMCard.tsx index a989a3a5..4926d6c0 100644 --- a/src/components/MOTMCard.tsx +++ b/src/components/MOTMCard.tsx @@ -3,7 +3,7 @@ import React, { useCallback, useContext, useEffect, useState } from 'react' import { MemberCardProp } from '../types/navigation' import { Images } from '../../assets' import { PublicUserInfo } from '../types/user' -import { getMOTM } from '../api/firebaseUtils' +import { getMOTM, getPublicUserData } from '../api/firebaseUtils' import { useFocusEffect } from '@react-navigation/core' import { UserContext } from '../context/UserContext' import { truncateStringWithEllipsis } from '../helpers/stringUtils' @@ -11,7 +11,7 @@ import { auth } from '../config/firebaseConfig' const MOTMCard: React.FC = ({ navigation }) => { const userContext = useContext(UserContext); - const { userInfo, setUserInfo } = userContext!; + const { userInfo } = userContext!; const fixDarkMode = userInfo?.private?.privateInfo?.settings?.darkMode; const useSystemDefault = userInfo?.private?.privateInfo?.settings?.useSystemDefault; @@ -35,7 +35,10 @@ const MOTMCard: React.FC = ({ navigation }) => { const fetchMOTM = async () => { try { const fetchedMOTM = await getMOTM(); - setMOTM(fetchedMOTM); + if (fetchedMOTM?.uid) { + const motmData = await getPublicUserData(fetchedMOTM.uid); + setMOTM(motmData); + } } catch (error) { console.error('Error fetching member of the month:', error); } @@ -83,7 +86,7 @@ const MOTMCard: React.FC = ({ navigation }) => { }} > From 70e5cf37f860eb60174df71462dd5e81df4c42be Mon Sep 17 00:00:00 2001 From: Jason Date: Sat, 17 Aug 2024 13:20:02 -0500 Subject: [PATCH 12/12] version bump --- app.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app.json b/app.json index a98743da..08ab180a 100644 --- a/app.json +++ b/app.json @@ -2,7 +2,7 @@ "expo": { "name": "TAMU SHPE", "slug": "TAMU-SHPE", - "version": "1.0.2", + "version": "1.0.3", "owner": "tamu-shpe", "orientation": "portrait", "icon": "./assets/icon.png", @@ -59,8 +59,8 @@ }, "ios": { "bundleIdentifier": "com.tamu.shpe", - "buildNumber": "1", - "userInterfaceStyle": "automatic" + "userInterfaceStyle": "automatic", + "buildNumber": "2" }, "extra": { "eas": { diff --git a/package.json b/package.json index 7a97fa80..d3696dcb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "shpe-app", - "version": "1.0.2", + "version": "1.0.3", "scripts": { "start": "npx expo start --dev-client", "test": "jest --coverage=true --verbose --bail --config ./jest.config.ts",