diff --git a/src/api/firebaseUtils.ts b/src/api/firebaseUtils.ts index 18648bcf..21942aff 100644 --- a/src/api/firebaseUtils.ts +++ b/src/api/firebaseUtils.ts @@ -528,6 +528,29 @@ export const getUpcomingEvents = async () => { return events; }; +export const getWeekPastEvents = async (): Promise => { + const currentTime = new Date(); + const twoWeeksAgo = new Date(currentTime); + twoWeeksAgo.setDate(currentTime.getDate() - 8); + + const eventsRef = collection(db, "events"); + const q = query( + eventsRef, + where("endTime", "<", currentTime), + where("endTime", ">", twoWeeksAgo), + orderBy("endTime", "desc") + ); + + const querySnapshot = await getDocs(q); + const events: SHPEEvent[] = []; + + querySnapshot.forEach(doc => { + events.push({ id: doc.id, ...doc.data() } as SHPEEvent); + }); + + return events; +}; + export const getPastEvents = async (numLimit: number, startAfterDoc: any, setEndOfData?: (endOfData: boolean) => void) => { const currentTime = new Date(); const eventsRef = collection(db, "events"); diff --git a/src/components/MOTMCard.tsx b/src/components/MOTMCard.tsx index c9735e15..24314dcc 100644 --- a/src/components/MOTMCard.tsx +++ b/src/components/MOTMCard.tsx @@ -68,6 +68,9 @@ const MOTMCard: React.FC = ({ navigation }) => { }, [currentUser]) ); + if (!MOTM) { + return null; + } return ( diff --git a/src/screens/committees/CommitteeInfo.tsx b/src/screens/committees/CommitteeInfo.tsx index 6f3cec89..136b4d46 100644 --- a/src/screens/committees/CommitteeInfo.tsx +++ b/src/screens/committees/CommitteeInfo.tsx @@ -348,12 +348,6 @@ const CommitteeInfo: React.FC = ({ route, navigat Upcoming Events - navigation.getParent()?.navigate('EventsTab', { screen: 'EventsScreen', params: { filter: EventType.COMMITTEE_MEETING, committee: firebaseDocName } })} - > - View all - { const route = useRoute(); const userContext = useContext(UserContext); const { userInfo, setUserInfo } = userContext!; - const fixDarkMode = userInfo?.private?.privateInfo?.settings?.darkMode; const useSystemDefault = userInfo?.private?.privateInfo?.settings?.useSystemDefault; const colorScheme = useColorScheme(); const darkMode = useSystemDefault ? colorScheme === 'dark' : fixDarkMode; - const filterScrollViewRef = useRef(null); - const committeeScrollViewRef = useRef(null); - const [isLoading, setIsLoading] = useState(true); - const [todayEvents, setTodayEvents] = useState([]); - const [upcomingEvents, setUpcomingEvents] = useState([]); - const [pastEvents, setPastEvents] = useState([]); - const [selectedFilter, setSelectedFilter] = useState(route.params?.filter || null); - const [committees, setCommittees] = useState([]); - const [selectedCommittee, setSelectedCommittee] = useState(route.params?.committee || null); + const [mainEvents, setMainEvents] = useState({ today: [], upcoming: [], past: [] }); + const [intramuralEvents, setIntramuralEvents] = useState({ today: [], upcoming: [], past: [] }); + const [committeeEvents, setCommitteeEvents] = useState({ today: [], upcoming: [], past: [] }); const [infoVisible, setInfoVisible] = useState(false); + const [filter, setFilter] = useState<"main" | "intramural" | "committee">("main"); const hasPrivileges = (userInfo?.publicInfo?.roles?.admin?.valueOf() || userInfo?.publicInfo?.roles?.officer?.valueOf() || userInfo?.publicInfo?.roles?.developer?.valueOf() || userInfo?.publicInfo?.roles?.lead?.valueOf() || userInfo?.publicInfo?.roles?.representative?.valueOf()); + const selectedEvents = filter === "main" ? mainEvents : filter === "intramural" ? intramuralEvents : committeeEvents; + const fetchEvents = async () => { try { setIsLoading(true); const upcomingEventsData = await getUpcomingEvents(); - const pastEventsData = await getPastEvents(3, null); + const allPastEvents = await getWeekPastEvents(); const currentTime = new Date(); const today = new Date(currentTime.getFullYear(), currentTime.getMonth(), currentTime.getDate()); + const todayEvents = upcomingEventsData.filter(event => { const startTime = event.startTime ? event.startTime.toDate() : new Date(0); return startTime >= today && startTime < new Date(today.getTime() + 24 * 60 * 60 * 1000); @@ -62,9 +63,63 @@ const Events = ({ navigation }: EventsProps) => { return startTime >= new Date(today.getTime() + 24 * 60 * 60 * 1000); }); - setTodayEvents(todayEvents); - setUpcomingEvents(upcomingEvents); - setPastEvents(pastEventsData.events); + const mainEventsFiltered = upcomingEventsData.filter( + (event: SHPEEvent) => + (hasPrivileges || !event.hiddenEvent) && + event.eventType !== EventType.COMMITTEE_MEETING && + event.eventType !== EventType.INTRAMURAL_EVENT + ); + + const intramuralEventsFiltered = upcomingEventsData.filter( + (event: SHPEEvent) => + (hasPrivileges || !event.hiddenEvent) && + event.eventType === EventType.INTRAMURAL_EVENT + ); + + const committeeEventsFiltered = upcomingEventsData.filter( + (event: SHPEEvent) => + (hasPrivileges || !event.hiddenEvent) && + event.eventType === EventType.COMMITTEE_MEETING + ); + + const pastMainEvents = allPastEvents.filter( + (event: SHPEEvent) => + (hasPrivileges || !event.hiddenEvent) && + event.eventType !== EventType.COMMITTEE_MEETING && + event.eventType !== EventType.INTRAMURAL_EVENT + ); + + const pastIntramuralEvents = allPastEvents.filter( + (event: SHPEEvent) => + (hasPrivileges || !event.hiddenEvent) && + event.eventType === EventType.INTRAMURAL_EVENT + ); + + const pastCommitteeEvents = allPastEvents.filter( + (event: SHPEEvent) => + (hasPrivileges || !event.hiddenEvent) && + event.eventType === EventType.COMMITTEE_MEETING + ); + + + + setMainEvents({ + today: todayEvents.filter(event => mainEventsFiltered.includes(event)), + upcoming: upcomingEvents.filter(event => mainEventsFiltered.includes(event)), + past: pastMainEvents, + }); + + setIntramuralEvents({ + today: todayEvents.filter(event => intramuralEventsFiltered.includes(event)), + upcoming: upcomingEvents.filter(event => intramuralEventsFiltered.includes(event)), + past: pastIntramuralEvents, + }); + + setCommitteeEvents({ + today: todayEvents.filter(event => committeeEventsFiltered.includes(event)), + upcoming: upcomingEvents.filter(event => committeeEventsFiltered.includes(event)), + past: pastCommitteeEvents, + }); setIsLoading(false); } catch (error) { @@ -73,11 +128,6 @@ const Events = ({ navigation }: EventsProps) => { } }; - const fetchCommittees = async () => { - const committeeData = await getCommittees(); - setCommittees(committeeData); - }; - useEffect(() => { const fetchUserData = async () => { @@ -89,30 +139,8 @@ const Events = ({ navigation }: EventsProps) => { fetchEvents(); fetchUserData(); - fetchCommittees(); }, []) - useEffect(() => { - if (route.params?.filter !== undefined) { - setSelectedFilter(route.params.filter); - - const filterIndex = ["myEvents", "clubWide", ...Object.values(EventType)].indexOf(route.params.filter); - if (filterIndex !== -1 && filterScrollViewRef.current) { - const scrollPosition = filterIndex * 115; - filterScrollViewRef.current.scrollTo({ x: scrollPosition, animated: true }); - } - } - - if (route.params?.committee !== undefined) { - setSelectedCommittee(route.params.committee); - - const committeeIndex = committees.findIndex(committee => committee.firebaseDocName === route.params.committee); - if (committeeIndex !== -1 && committeeScrollViewRef.current) { - const scrollPosition = committeeIndex * 100; - committeeScrollViewRef.current.scrollTo({ x: scrollPosition, animated: true }); - } - } - }, [route.params, committees]); useFocusEffect( useCallback(() => { @@ -122,75 +150,6 @@ const Events = ({ navigation }: EventsProps) => { }, [hasPrivileges]) ); - const handleFilterSelect = (filter?: ExtendedEventType, committee?: string) => { - // Deselect committee when the same committee is selected - if (committee) { - if (selectedCommittee === committee) { - setSelectedCommittee(null); - if (!selectedFilter) { - setSelectedFilter(null); - } - } else { - setSelectedCommittee(committee); - if (selectedFilter !== EventType.COMMITTEE_MEETING) { - setSelectedFilter(EventType.COMMITTEE_MEETING); - } - } - return; - } - - // Deselect "Committee Meetings" when no committee is selected - if (filter === EventType.COMMITTEE_MEETING && selectedFilter === EventType.COMMITTEE_MEETING) { - setSelectedFilter(null); - setSelectedCommittee(null); - return; - } - - // Handle other filters - if (selectedFilter === filter) { - setSelectedFilter(null); - setSelectedCommittee(null); - } else { - setSelectedFilter(filter!); - setSelectedCommittee(null); - } - }; - - const filteredEvents = (events: SHPEEvent[]): SHPEEvent[] => { - // If no filter is selected, filter out hidden events and committee meetings - if (!selectedFilter) { - return events.filter(event => - (event.eventType !== EventType.COMMITTEE_MEETING || event.general) && - !event.hiddenEvent - ); - } - - if (selectedFilter === 'myEvents') { - return events.filter(event => - (userInfo?.publicInfo?.committees?.includes(event.committee || '') || - userInfo?.publicInfo?.interests?.includes(event.eventType || '')) && - !event.hiddenEvent - ); - } - - if (selectedFilter === 'clubWide') { - return events.filter(event => event.general && !event.hiddenEvent); - } - // Show hidden events for "Custom Event" filter - if (selectedFilter === 'Custom Event') { - return events.filter(event => event.eventType === selectedFilter); - } - - if (selectedFilter === EventType.COMMITTEE_MEETING) { - return events.filter(event => - event.eventType === EventType.COMMITTEE_MEETING && - (selectedCommittee ? event.committee === selectedCommittee : true) && - !event.hiddenEvent - ); - } - - return events.filter(event => event.eventType === selectedFilter && !event.hiddenEvent); - }; return ( @@ -205,99 +164,57 @@ const Events = ({ navigation }: EventsProps) => { {/* Filters */} - - - handleFilterSelect("myEvents")} + { + setFilter("main") + }} + > + - My Events - - - handleFilterSelect("clubWide")} + Main + + + + { + setFilter("intramural") + }} + > + - Club Wide - - - {Object.values(EventType).map((type) => ( - handleFilterSelect(type)} - > - {type} - - ))} - - - - {/* Additional Committee Filter */} - {selectedFilter === EventType.COMMITTEE_MEETING && ( - - - {committees.map(committee => ( - handleFilterSelect(undefined, committee.firebaseDocName)} - > - {committee.name} - - ))} - - - )} + Intramural + + + { + setFilter("committee") + }} + > + + Committee + + + {isLoading && @@ -307,100 +224,110 @@ const Events = ({ navigation }: EventsProps) => { {/* Event Listings */} {!isLoading && ( - - {filteredEvents(todayEvents).length === 0 && filteredEvents(upcomingEvents).length === 0 && filteredEvents(pastEvents).length === 0 ? ( - + + {selectedEvents.today.length === 0 && + selectedEvents.upcoming.length === 0 && + selectedEvents.past.length === 0 ? ( + No Events ) : ( {/* Today's Events */} - {filteredEvents(todayEvents).length !== 0 && ( - + {selectedEvents.today.length !== 0 && ( + Today's Events - {filteredEvents(todayEvents)?.map((event: SHPEEvent, index) => { - return ( - 0 && "mt-8"}`} - style={{ - shadowColor: "#000", - shadowOffset: { - width: 0, - height: 2, - }, - shadowOpacity: 0.25, - shadowRadius: 3.84, - - elevation: 5, - }} - onPress={() => { navigation.navigate("EventInfo", { event: event }) }} + {selectedEvents.today.map((event: SHPEEvent, index) => ( + 0 && "mt-8"}`} + style={{ + shadowColor: "#000", + shadowOffset: { width: 0, height: 2 }, + shadowOpacity: 0.25, + shadowRadius: 3.84, + elevation: 5, + }} + onPress={() => { + navigation.navigate("EventInfo", { event: event }); + }} + > + + - - + + {truncateStringWithEllipsis(event.name, 20)} + + {event.locationName ? ( + + {truncateStringWithEllipsis(event.locationName, 24)} + + ) : null} + + {formatTime(event.startTime?.toDate()!)} + + + + {hasPrivileges && ( + { + navigation.navigate("QRCode", { event: event }); + }} + className="absolute right-0 top-0 p-2 m-2 rounded-full" + style={{ backgroundColor: "rgba(0,0,0,0.7)" }} > - - {truncateStringWithEllipsis(event.name, 20)} - {event.locationName ? ( - {truncateStringWithEllipsis(event.locationName, 24)} - ) : null} - {formatTime(event.startTime?.toDate()!)} - - - {hasPrivileges && ( - { navigation.navigate("QRCode", { event: event }) }} - className='absolute right-0 top-0 p-2 m-2 rounded-full' - style={{ backgroundColor: 'rgba(0,0,0,0.7)' }} - > - - - )} - - ); - })} + + + )} + + ))} )} {/* Upcoming Events */} - {filteredEvents(upcomingEvents).length !== 0 && ( - - Upcoming Events - {filteredEvents(upcomingEvents)?.map((event: SHPEEvent, index) => { - return ( - 0 && "mt-8"}`}> - - - ); - })} + {selectedEvents.upcoming.length !== 0 && ( + + + Upcoming Events + + {selectedEvents.upcoming.map((event: SHPEEvent, index) => ( + 0 && "mt-8"}`}> + + + ))} )} {/* Past Events */} - {filteredEvents(pastEvents).length !== 0 && ( - - Past Events - {filteredEvents(pastEvents)?.map((event: SHPEEvent, index) => { - return ( - 0 && "mt-8"}`}> - - - ); - })} + {selectedEvents.past.length !== 0 && ( + + + Past Events + + {selectedEvents.past.map((event: SHPEEvent, index) => ( + 0 && "mt-8"}`}> + + + ))} )} - {!selectedFilter && ( - navigation.navigate("PastEvents")}> - View more - - )} + navigation.navigate("PastEvents")}> + View all past events + )} @@ -464,7 +391,7 @@ const Events = ({ navigation }: EventsProps) => { Event Location Check - The location check only happens during scans; we do not track you continuously. You are free to leave the area, but if a sign-out scan is required, you must be at the location to sign out. + The location check only happens during scans; we do not track you continuously. If a sign-out scan is required, you must be at the location to sign out. diff --git a/src/screens/home/Home.tsx b/src/screens/home/Home.tsx index 7f9ba2b7..a9379cd6 100644 --- a/src/screens/home/Home.tsx +++ b/src/screens/home/Home.tsx @@ -381,12 +381,6 @@ const Home = ({ navigation, route }: NativeStackScreenProps) => - navigation.getParent()?.navigate('EventsTab', { screen: 'EventsScreen', params: { filter: 'myEvents' } })} - > - View all -