diff --git a/src/api-bodies/MockData.tsx b/src/api-bodies/MockData.tsx index 8351c1b..d9132d0 100644 --- a/src/api-bodies/MockData.tsx +++ b/src/api-bodies/MockData.tsx @@ -74,6 +74,86 @@ const meetings = [ joinUrl: "", topic: "Back-end Meeting", }, + { + meetingId: "3", + liveParticipantIds: [], + registrantIds: ["0", "1"], + start: "2022-03-10T07:27:27", + duration: 727, + timezone: "", + joinUrl: "", + topic: "WHEN YOU", + }, + { + meetingId: "4", + liveParticipantIds: [], + registrantIds: ["0", "2", "3"], + start: "2022-03-10T12:30:00", + duration: 120, + timezone: "", + joinUrl: "", + topic: "Bathroom Break", + }, + { + meetingId: "5", + liveParticipantIds: ["0"], + registrantIds: ["0"], + start: "2022-03-24T23:11:11", + duration: 11, + timezone: "", + joinUrl: "", + topic: "Drink Coffee", + }, + { + meetingId: "6", + liveParticipantIds: ["0", "1"], + registrantIds: ["0", "1", "2", "3", "4", "5"], + start: "2022-03-25T09:00:00", + duration: 360, + timezone: "", + joinUrl: "", + topic: "Get grilled by Jerry", + }, + { + meetingId: "7", + liveParticipantIds: [], + registrantIds: ["0", "5"], + start: "2022-03-25T15:00:00", + duration: 150, + timezone: "", + joinUrl: "", + topic: "Get grilled by Arthur", + }, + { + meetingId: "8", + liveParticipantIds: ["2"], + registrantIds: ["0", "5", "2", "3"], + start: "2022-03-25T17:45:00", + duration: 60, + timezone: "", + joinUrl: "", + topic: "Jerry comes back for round 2", + }, + { + meetingId: "9", + liveParticipantIds: ["2", "5"], + registrantIds: ["0", "4"], + start: "2022-03-25T18:15:30", + duration: 75, + timezone: "", + joinUrl: "", + topic: "Tag team!", + }, + { + meetingId: "10", + liveParticipantIds: [], + registrantIds: ["0", "1", "2", "3", "4", "5", "6"], + start: "2022-04-04T18:30:00", + duration: 90, + timezone: "", + joinUrl: "", + topic: "MVP Deadline", + } ]; const team = { diff --git a/src/components/calendar/CalendarPage.tsx b/src/components/calendar/CalendarPage.tsx index 340e0fe..4e78494 100644 --- a/src/components/calendar/CalendarPage.tsx +++ b/src/components/calendar/CalendarPage.tsx @@ -1,12 +1,154 @@ -import { Toolbar } from "@mui/material"; -import UserCalendar from "./UserCalendar"; +import { Calendar, momentLocalizer, Views } from "react-big-calendar"; +import moment from "moment"; + +import "react-big-calendar/lib/css/react-big-calendar.css"; +import { + Divider, + FormControl, + InputLabel, + MenuItem, + Select, + SelectChangeEvent, + Toolbar, + Typography, +} from "@mui/material"; +import { selectMeetings } from "../../redux/slices/meetingsAndUserStatusSlice"; +import { useAppDispatch, useAppSelector } from "../../redux/hooks"; +import { + selectMe, + selectTeam, + selectUser, + selectUsers, +} from "../../redux/slices/usersSlice"; +import { open } from "../../redux/slices/meetingDetailsOpenSlice"; +import DetailedMeeting from "../../api-bodies/DetailedMeeting"; +import { useState } from "react"; +import UserLite from "../../api-bodies/UserLite"; + +// TODO: match the styles and themes + +// A superset of DetailedMeeting; contains fields required for the calendar to work +interface CalendarEvent { + meetingId: string; + liveParticipantIds: string[]; + registrantIds: string[]; + startIso: string; // names overlap here; this is equivalent to "start" in DetailedMeeting + duration: number; + timezone: string; + joinUrl: string; + topic: string; + title: string; + start: Date; + end: Date; +} + +enum CalendarTaskView { + ViewAll = "VIEWALL", +} const CalendarPage: React.FC = () => { + const dispatch = useAppDispatch(); + + const currentUserUuid: string = useAppSelector(selectMe); + const currentUser: UserLite | undefined = useAppSelector((state) => + selectUser(state, currentUserUuid) + ); + const teamUuids: string[] = useAppSelector(selectTeam); + const team: UserLite[] = useAppSelector((state) => + selectUsers(state, teamUuids) + ); + const meetings: CalendarEvent[] = useAppSelector((state) => + selectMeetings(state) + ).map((m) => ({ + meetingId: m.meetingId, + liveParticipantIds: m.liveParticipantIds, + registrantIds: m.registrantIds, + startIso: m.start, + duration: m.duration, + timezone: m.timezone, + joinUrl: m.joinUrl, + topic: m.topic, + // fields needed by calendar + title: m.topic, + start: new Date(Date.parse(m.start)), // Turns the ISO String into a date object + end: new Date(Date.parse(m.start) + m.duration * 60000), // result of Date.parse() is milliseconds, and m.duration is given in minutes + })); + + const [selectedUserUuid, setSelectedUserUuid] = useState(currentUserUuid); + + // turns calendar event back into DetailedMeeting then opens meeting view + const handleSelectEvent = (event: CalendarEvent) => { + const meeting: DetailedMeeting = { + meetingId: event.meetingId, + liveParticipantIds: event.liveParticipantIds, + registrantIds: event.registrantIds, + start: event.startIso, + duration: event.duration, + timezone: event.timezone, + joinUrl: event.joinUrl, + topic: event.topic, + }; + dispatch(open(meeting)); + }; + + // dropdown selection event + const handleUserChange = (event: SelectChangeEvent) => { + setSelectedUserUuid(event.target.value); + }; + + // filter the meetings based on the uuid + const getUserMeetings = (uuid: string): CalendarEvent[] => { + if (uuid == CalendarTaskView.ViewAll) { + // "View all team member meetings" option + return meetings; + } else { + return meetings.filter((meeting) => meeting.registrantIds.includes(uuid)); + } + }; return ( <> - + + + + User + + + + + + + ); }; diff --git a/src/components/calendar/Events.tsx b/src/components/calendar/Events.tsx deleted file mode 100644 index 6b62d47..0000000 --- a/src/components/calendar/Events.tsx +++ /dev/null @@ -1,185 +0,0 @@ -/* -Test data from -https://github.com/jquense/react-big-calendar/blob/master/examples/events.js -*/ - -const now = new Date(); - -export default [ - { - id: 0, - title: "All Day Event very long title", - allDay: true, - start: new Date(2022, 2, 0), - end: new Date(2022, 2, 1), - }, - { - id: 1, - title: "Long Event", - start: new Date(2022, 2, 7), - end: new Date(2022, 2, 10), - }, - - { - id: 2, - title: "DTS STARTS", - start: new Date(2022, 1, 13, 0, 0, 0), - end: new Date(2022, 1, 20, 0, 0, 0), - }, - - { - id: 3, - title: "DTS ENDS", - start: new Date(2022, 9, 6, 0, 0, 0), - end: new Date(2022, 9, 13, 0, 0, 0), - }, - - { - id: 4, - title: "Some Event", - start: new Date(2022, 2, 9, 0, 0, 0), - end: new Date(2022, 2, 10, 0, 0, 0), - }, - { - id: 5, - title: "Conference", - start: new Date(2022, 2, 11), - end: new Date(2022, 2, 13), - desc: "Big conference for important people", - }, - { - id: 6, - title: "Meeting", - start: new Date(2022, 2, 12, 10, 30, 0, 0), - end: new Date(2022, 2, 12, 12, 30, 0, 0), - desc: "Pre-meeting meeting, to prepare for the meeting", - }, - { - id: 7, - title: "Lunch", - start: new Date(2022, 2, 12, 12, 0, 0, 0), - end: new Date(2022, 2, 12, 13, 0, 0, 0), - desc: "Power lunch", - }, - { - id: 8, - title: "Meeting", - start: new Date(2022, 2, 12, 14, 0, 0, 0), - end: new Date(2022, 2, 12, 15, 0, 0, 0), - }, - { - id: 9, - title: "Happy Hour", - start: new Date(2022, 2, 12, 17, 0, 0, 0), - end: new Date(2022, 2, 12, 17, 30, 0, 0), - desc: "Most important meal of the day", - }, - { - id: 10, - title: "Dinner", - start: new Date(2022, 2, 12, 20, 0, 0, 0), - end: new Date(2022, 2, 12, 21, 0, 0, 0), - }, - { - id: 11, - title: "Planning Meeting with Paige", - start: new Date(2022, 2, 13, 8, 0, 0), - end: new Date(2022, 2, 13, 10, 30, 0), - }, - { - id: 11.1, - title: "Inconvenient multi-day Conference Call", - start: new Date(2022, 2, 13, 9, 30, 0), - end: new Date(2022, 2, 14, 1, 0, 0), - }, - { - id: 11.2, - title: "Project Kickoff - Lou's Shoes", - start: new Date(2022, 2, 13, 11, 30, 0), - end: new Date(2022, 2, 13, 14, 0, 0), - }, - { - id: 11.3, - title: "Quote Follow-up - Tea by Tina", - start: new Date(2022, 2, 13, 15, 30, 0), - end: new Date(2022, 2, 13, 16, 0, 0), - }, - { - id: 12, - title: "Late Night Event", - start: new Date(2022, 2, 17, 19, 30, 0), - end: new Date(2022, 2, 18, 2, 0, 0), - }, - { - id: 12.5, - title: "Late Same Night Event", - start: new Date(2022, 2, 17, 19, 30, 0), - end: new Date(2022, 2, 17, 23, 30, 0), - }, - { - id: 13, - title: "Multi-day Event", - start: new Date(2022, 2, 20, 19, 30, 0), - end: new Date(2022, 2, 22, 2, 0, 0), - }, - { - id: 14, - title: "Today", - start: new Date(new Date().setHours(new Date().getHours() - 3)), - end: new Date(new Date().setHours(new Date().getHours() + 3)), - }, - { - id: 15, - title: "Point in Time Event", - start: now, - end: now, - }, - { - id: 16, - title: "Video Record", - start: new Date(2022, 2, 14, 15, 30, 0), - end: new Date(2022, 2, 14, 19, 0, 0), - }, - { - id: 17, - title: "Dutch Song Producing", - start: new Date(2022, 2, 14, 16, 30, 0), - end: new Date(2022, 2, 14, 20, 0, 0), - }, - { - id: 18, - title: "Itaewon Halloween Meeting", - start: new Date(2022, 2, 14, 16, 30, 0), - end: new Date(2022, 2, 14, 17, 30, 0), - }, - { - id: 19, - title: "Online Coding Test", - start: new Date(2022, 2, 14, 17, 30, 0), - end: new Date(2022, 2, 14, 20, 30, 0), - }, - { - id: 20, - title: "An overlapped Event", - start: new Date(2022, 2, 14, 17, 0, 0), - end: new Date(2022, 2, 14, 18, 30, 0), - }, - { - id: 21, - title: "Phone Interview", - start: new Date(2022, 2, 14, 17, 0, 0), - end: new Date(2022, 2, 14, 18, 30, 0), - }, - { - id: 22, - title: "Cooking Class", - start: new Date(2022, 2, 14, 17, 30, 0), - end: new Date(2022, 2, 14, 19, 0, 0), - }, - { - id: 23, - title: "Go to the gym", - start: new Date(2022, 2, 14, 18, 30, 0), - end: new Date(2022, 2, 14, 20, 0, 0), - }, -]; \ No newline at end of file diff --git a/src/components/calendar/UserCalendar.tsx b/src/components/calendar/UserCalendar.tsx deleted file mode 100644 index d6a7797..0000000 --- a/src/components/calendar/UserCalendar.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { Calendar, momentLocalizer } from "react-big-calendar"; -import moment from "moment"; -import testEvents from "./Events"; - -import "react-big-calendar/lib/css/react-big-calendar.css"; - -const localizer = momentLocalizer(moment); - -const UserCalendar: React.FC = () => { - - return ( - - ); -}; - -export default UserCalendar; \ No newline at end of file diff --git a/src/components/home/MeetingsPanel.tsx b/src/components/home/MeetingsPanel.tsx index 5125a5e..0daadb7 100644 --- a/src/components/home/MeetingsPanel.tsx +++ b/src/components/home/MeetingsPanel.tsx @@ -5,9 +5,31 @@ import { useAppSelector } from "../../redux/hooks"; import { selectMeetings } from "../../redux/slices/meetingsAndUserStatusSlice"; import { selectUsers } from "../../redux/slices/usersSlice"; import { formatTimeFromDate } from "../../utils"; +import UserLite from "../../api-bodies/UserLite"; const MeetingsPanel: React.FC = () => { const meetings = useAppSelector(selectMeetings); + const uuids: string[] = []; + meetings.forEach((meeting) => { + meeting.liveParticipantIds.forEach((uuid) => { + if(!uuids.includes(uuid)) { + uuids.push(uuid); + } + }); + }); + + const participants = useAppSelector((state) => + selectUsers(state,uuids) + ); + + // const participants: (UserLite | undefined)[] = []; + // uuids.forEach((uuid) => { + // const userLite = useAppSelector((state) => + // selectUser(state,uuid) + // ); + // participants.push(userLite); + // }); + return (
@@ -24,9 +46,15 @@ const MeetingsPanel: React.FC = () => {
{meetings.map((meeting) => { - const meetingMembers = useAppSelector((state) => - selectUsers(state, meeting.liveParticipantIds) - ); + // const meetingMembers = useAppSelector((state) => + // selectUsers(state, meeting.liveParticipantIds) + // ); + const meetingMembers: UserLite[] = []; + participants.forEach((userLite) => { + if (userLite != undefined && meeting.liveParticipantIds.includes(userLite.uuid)) { + meetingMembers.push(userLite); + } + }); const startDate = new Date(meeting.start); const startDatemil = startDate.getTime(); const endDatemil = startDatemil + meeting.duration * 60000; diff --git a/src/components/login/Login.tsx b/src/components/login/Login.tsx index faf90b3..96fab47 100644 --- a/src/components/login/Login.tsx +++ b/src/components/login/Login.tsx @@ -27,6 +27,7 @@ const Login: React.FC = () => { const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); + const [logedInUser, setLogedInUser] = useState(""); // const [errMsg, setErrMsg] = useState(''); // const userRef = useRef(); @@ -40,17 +41,17 @@ const Login: React.FC = () => { // setErrMsg(''); // }, [user, pwd]) - const handleLogin = async (e: React.SyntheticEvent) => { + store.dispatch(fetchMeetings(logedInUser)); + store.dispatch(fetchUsers(logedInUser)); + store.dispatch(fetchFavorites(logedInUser)); + + const handleLogin = async(e: React.SyntheticEvent) => { e.preventDefault(); try { if (email === "" && password === "") { setAuth["email"] = email; setAuth["isLoggedIn"] = true; - - store.dispatch(fetchMeetings("")); - store.dispatch(fetchUsers("")); - store.dispatch(fetchFavorites("")); navigate(from, { replace: true }); } @@ -68,12 +69,9 @@ const Login: React.FC = () => { console.log(response?.data); if (logedInUserId != undefined) { - setAuth.email = email; - setAuth.isLoggedIn = true; - - store.dispatch(fetchMeetings(logedInUserId)); - store.dispatch(fetchUsers(logedInUserId)); - store.dispatch(fetchFavorites(logedInUserId)); + setAuth["email"] = email; + setAuth["isLoggedIn"] = true; + setLogedInUser(logedInUserId); navigate(from, { replace: true }); } } catch (error) { diff --git a/src/components/navbar/Clock.tsx b/src/components/navbar/Clock.tsx index 2de6a3b..d42da13 100644 --- a/src/components/navbar/Clock.tsx +++ b/src/components/navbar/Clock.tsx @@ -13,7 +13,7 @@ const Clock: React.FC = () => { const [date, setDate] = useState(new Date()); useEffect(() => { - setInterval(() => setDate(new Date()), 30000); + setInterval(() => setDate(new Date()), 1000); }, []); return ( diff --git a/src/redux/slices/usersSlice.tsx b/src/redux/slices/usersSlice.tsx index b3325da..c343ee1 100644 --- a/src/redux/slices/usersSlice.tsx +++ b/src/redux/slices/usersSlice.tsx @@ -91,9 +91,11 @@ export const selectUsers = (state: RootState, uuids: string[]): UserLite[] => { }; export const selectTeam = (state: RootState) => { const team: string[] = []; - if (state.users.team.manager !== null) team.push(state.users.team.manager); + if (state.users.team.manager) team.push(state.users.team.manager); state.users.team.sameManager.forEach((u) => team.push(u)); state.users.team.directReports.forEach((u) => team.push(u)); return team; }; +export const selectMe = (state: RootState) => state.users.team.user; + export default usersSlice.reducer;