Merge branch 'main' into api-fetch

This commit is contained in:
cth0604 2022-03-25 13:18:34 -07:00 committed by GitHub
commit ff9f67222b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 269 additions and 227 deletions

View File

@ -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 = {

View File

@ -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 (
<>
<Toolbar />
<UserCalendar />
<FormControl variant="filled" fullWidth>
<InputLabel id="calendar-user-select-label">
<Typography color="black">User</Typography>
</InputLabel>
<Select
labelId="calendar-user-select-label"
id="calendar-user-select"
value={selectedUserUuid}
label="User"
onChange={handleUserChange}
>
<MenuItem value={CalendarTaskView.ViewAll}>
View all team member meetings
</MenuItem>
{currentUser ? (
<MenuItem value={currentUserUuid}>
{currentUser.name + " (Me)"}
</MenuItem>
) : null}
{team.map((user) => (
<MenuItem key={user.uuid} value={user.uuid}>
{user.name}
</MenuItem>
))}
</Select>
</FormControl>
<Divider sx={{ my: 1 }} />
<Calendar
events={getUserMeetings(selectedUserUuid)}
views={["month", "week", "day"]}
defaultView={Views.WEEK}
onSelectEvent={handleSelectEvent}
step={60}
showMultiDayTimes
localizer={momentLocalizer(moment)}
style={{ height: "83%" }}
/>
</>
);
};

View File

@ -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),
},
];

View File

@ -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 (
<Calendar
events={testEvents}
views={["month", "week", "day"]}
step={60}
showMultiDayTimes
localizer={localizer}
style={{ height: "80%" }}
/>
);
};
export default UserCalendar;

View File

@ -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 (
<div className="meetings-panel">
@ -24,9 +46,15 @@ const MeetingsPanel: React.FC = () => {
</div>
{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;

View File

@ -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,6 +41,10 @@ const Login: React.FC = () => {
// setErrMsg('');
// }, [user, pwd])
store.dispatch(fetchMeetings(logedInUser));
store.dispatch(fetchUsers(logedInUser));
store.dispatch(fetchFavorites(logedInUser));
const handleLogin = async(e: React.SyntheticEvent) => {
e.preventDefault();
@ -47,10 +52,6 @@ const Login: React.FC = () => {
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) {

View File

@ -13,7 +13,7 @@ const Clock: React.FC = () => {
const [date, setDate] = useState<Date>(new Date());
useEffect(() => {
setInterval(() => setDate(new Date()), 30000);
setInterval(() => setDate(new Date()), 1000);
}, []);
return (

View File

@ -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;