From 5dba460acb2dfc82258217744f34e1b91298a1fa Mon Sep 17 00:00:00 2001 From: Arjun Patel Date: Fri, 14 Jan 2022 17:47:57 -0800 Subject: [PATCH] adding listeners for the team members --- components/Dashboard/TeamVoiceLine.tsx | 153 +++++++++++++++++-------- contexts/teamDashboardContext.tsx | 8 +- services/teamService.tsx | 8 +- services/userService.tsx | 56 ++++++--- 4 files changed, 157 insertions(+), 68 deletions(-) diff --git a/components/Dashboard/TeamVoiceLine.tsx b/components/Dashboard/TeamVoiceLine.tsx index a0fbef4..aa1f87c 100644 --- a/components/Dashboard/TeamVoiceLine.tsx +++ b/components/Dashboard/TeamVoiceLine.tsx @@ -3,19 +3,115 @@ import { FaPlus } from "react-icons/fa"; import { IoPulseOutline, IoRemoveOutline, IoTimer } from "react-icons/io5"; import { BsThreeDots } from "react-icons/bs"; import { useTeamDashboardContext } from "../../contexts/teamDashboardContext"; -import { UserStatus } from "../../models/user"; -import { useState } from "react"; +import { User, UserStatus } from "../../models/user"; +import { useEffect, useState } from "react"; import { toast } from "react-hot-toast"; import { TeamMemberRole } from "../../models/teamMember"; +import UserService from "../../services/userService"; +import { DocumentSnapshot, Unsubscribe } from "firebase/firestore"; + +const userService = new UserService(); + +function statusBubble(status: UserStatus) { + console.log(status); + + switch (status) { + case UserStatus.online: + return ( + + ); + case UserStatus.busy: + return ( + + ); + case UserStatus.offline: + return ( + + ); + default: + return ( + + ); + } +} + +function renderPulse(status: UserStatus) { + switch (status) { + case UserStatus.online: + return ( + + ); + case UserStatus.busy: + return ( + + ); + case UserStatus.offline: + return ( + + ); + default: + return ( + + ); + } +} export default function TeamVoiceLine() { const router = useRouter(); const { teamid } = router.query; - const { team, user, userTeamMember } = useTeamDashboardContext(); - const { teamMembers } = useTeamDashboardContext(); + const { team, user, userTeamMember, teamMembers } = useTeamDashboardContext(); const [loading, setLoading] = useState(true); - //listeners for all teammates' status + const [teamUsers, setTeamUsers] = useState([]); + const [count, setCount] = useState(0); + + useEffect(() => { + const unsubs: Unsubscribe[] = []; + + (async function () { + try { + // listeners for all teammates' status + if (teamMembers) { + teamMembers.forEach(async (tmember) => { + const unsub = await userService.getUserRealtime( + tmember.userId, + (doc: DocumentSnapshot) => { + // setTeamUsers((prevTeamUsers) => ({ + // ...prevTeamUsers, + // })); + + // updated user + const updatedUser = doc.data() as User; + + // update the teamUsers array in state + const newUsers: User[] = teamUsers.map((user, i) => { + if (user.id == updatedUser.id) { + return updatedUser; + } + + return user; + }); + + setTeamUsers(newUsers); + } + ); + + unsubs.push(unsub); + }); + } + } catch (error) { + console.log(error); + toast.error("Something went wrong"); + router.push("/teams/login"); + } + + setLoading(false); + })(); + + return () => { + unsubs.map((listener) => listener()); + }; + }, []); async function handleAdminRoute() { if (userTeamMember.role == TeamMemberRole.admin) { @@ -26,50 +122,6 @@ export default function TeamVoiceLine() { toast.error("You are not a team admin!"); } - function statusBubble(status: UserStatus) { - console.log(status); - - switch (status) { - case UserStatus.online: - return ( - - ); - case UserStatus.busy: - return ( - - ); - case UserStatus.offline: - return ( - - ); - default: - return ( - - ); - } - } - - function renderPulse(status: UserStatus) { - switch (status) { - case UserStatus.online: - return ( - - ); - case UserStatus.busy: - return ( - - ); - case UserStatus.offline: - return ( - - ); - default: - return ( - - ); - } - } - function renderTeamMemberList() { // show loading skeleton if not yet got friend info if (loading) { @@ -85,7 +137,8 @@ export default function TeamVoiceLine() { } // if not teammates, stale state message to tell admin to add people - if (!teamMembers.length) { + if (!teamUsers.length) { + return Please add team members.; } return teamMembers.map((tmember, i) => { diff --git a/contexts/teamDashboardContext.tsx b/contexts/teamDashboardContext.tsx index 8305ec5..6b1433f 100644 --- a/contexts/teamDashboardContext.tsx +++ b/contexts/teamDashboardContext.tsx @@ -119,10 +119,12 @@ export function TeamDashboardContextProvider({ children }) { } // SECTION: get all teammembers for team, will have listeners in other subcomponents - const teamMembers = await teamService.getTeamMembersByTeamId( - returnedTeam.id + const teamMembers = await teamService.getTeamMembersByTeamIdNotUser( + returnedTeam.id, + currUser.uid ); - setValue((prevValue) => ({ ...prevValue, teamMembers: teamMembers })); + + setValue((prevValue) => ({ ...prevValue, teamMembers })); } catch (error) { console.log(error); router.push("/teams/login"); diff --git a/services/teamService.tsx b/services/teamService.tsx index 16660b0..a4ba56b 100644 --- a/services/teamService.tsx +++ b/services/teamService.tsx @@ -158,10 +158,14 @@ export default class TeamService implements IService { return teamMembers; } - async getTeamMembersByTeamId(teamId: string): Promise { + async getTeamMembersByTeamIdNotUser( + teamId: string, + userId: string + ): Promise { const q = query( collection(this.db, Collections.teamMembers), - where("teamId", "==", teamId) + where("teamId", "==", teamId), + where("userId", "!=", userId) ); const querySnapshot = await getDocs(q); diff --git a/services/userService.tsx b/services/userService.tsx index ce2214f..69ac2c3 100644 --- a/services/userService.tsx +++ b/services/userService.tsx @@ -1,39 +1,69 @@ import { User as FirUser } from "firebase/auth"; -import { Firestore, getFirestore, doc, getDoc, setDoc, Timestamp, serverTimestamp } from "firebase/firestore"; -import { User } from '../models/user' +import { + Firestore, + getFirestore, + doc, + getDoc, + setDoc, + Timestamp, + serverTimestamp, + onSnapshot, + Unsubscribe, + DocumentSnapshot, +} from "firebase/firestore"; +import { User } from "../models/user"; import { Collections } from "./collections"; export default class UserService { - private db : Firestore = getFirestore() + private db: Firestore = getFirestore(); // give back the avatar based on the person's google account avatar getUserAvatar(displayName: string) { - return `https://ui-avatars.com/api/?name=${displayName}` + return `https://ui-avatars.com/api/?name=${displayName}`; } - async getUser(userId: string) : Promise { + async getUser(userId: string): Promise { const docRef = doc(this.db, Collections.users, userId); const docSnap = await getDoc(docRef); if (docSnap.exists()) { - console.log('got user data') - let user: User = docSnap.data() as User - return user + console.log("got user data"); + let user: User = docSnap.data() as User; + return user; } else { // doc.data() will be undefined in this case console.log("user not found!"); - - return null + + return null; } } + async getUserRealtime( + userId: string, + handleDataFetch: (doc: DocumentSnapshot) => void + ): Promise { + const docRef = doc(this.db, Collections.users, userId); + + const unsub = onSnapshot(docRef, handleDataFetch); + + return unsub; + } + async createUser(userId: string, emailAddress: string, avatarUrl: string) { const docRef = doc(this.db, Collections.users, userId); - await setDoc(docRef, { emailAddress, avatarUrl, createdDate: serverTimestamp() }, { merge: true }) + await setDoc( + docRef, + { emailAddress, avatarUrl, createdDate: serverTimestamp() }, + { merge: true } + ); } async updateUser(user: User) { const docRef = doc(this.db, Collections.users, user.id); - await setDoc(docRef, { ...user, lastUpdatedDate: serverTimestamp() }, { merge: true }) + await setDoc( + docRef, + { ...user, lastUpdatedDate: serverTimestamp() }, + { merge: true } + ); } -} \ No newline at end of file +}