redux updates
This commit is contained in:
parent
49aee79557
commit
9b5d8002a0
@ -1,4 +1,4 @@
|
|||||||
const people = [
|
const userLites = [
|
||||||
{
|
{
|
||||||
uuid: "0",
|
uuid: "0",
|
||||||
emailAddress: "cth0604@gmail.com",
|
emailAddress: "cth0604@gmail.com",
|
||||||
@ -58,7 +58,7 @@ const meetings = [
|
|||||||
meetingId: "1",
|
meetingId: "1",
|
||||||
liveParticipantIds: [],
|
liveParticipantIds: [],
|
||||||
registrantIds: ["0", "2", "4"],
|
registrantIds: ["0", "2", "4"],
|
||||||
start: "2022-03-13T17:30:00",
|
start: "2022-03-16T17:30:00",
|
||||||
duration: 30,
|
duration: 30,
|
||||||
timezone: "",
|
timezone: "",
|
||||||
joinUrl: "",
|
joinUrl: "",
|
||||||
@ -66,7 +66,7 @@ const meetings = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
meetingId: "2",
|
meetingId: "2",
|
||||||
liveParticipantIds: [],
|
liveParticipantIds: ["3", "5"],
|
||||||
registrantIds: ["3", "5", "6"],
|
registrantIds: ["3", "5", "6"],
|
||||||
start: "2022-03-13T17:30:00",
|
start: "2022-03-13T17:30:00",
|
||||||
duration: 30,
|
duration: 30,
|
||||||
@ -83,4 +83,6 @@ const team = {
|
|||||||
directReports: [],
|
directReports: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
export { people, meetings, team };
|
const favorites = ["2", "4"];
|
||||||
|
|
||||||
|
export { userLites, meetings, team, favorites };
|
||||||
|
|||||||
10
src/api-bodies/User.tsx
Normal file
10
src/api-bodies/User.tsx
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
interface User {
|
||||||
|
uuid: string;
|
||||||
|
emailAddress: string;
|
||||||
|
name: string;
|
||||||
|
role: string;
|
||||||
|
inMeeting: boolean;
|
||||||
|
meetingID: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default User;
|
||||||
7
src/api-bodies/UserStatus.tsx
Normal file
7
src/api-bodies/UserStatus.tsx
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
interface UserStatus {
|
||||||
|
uuid: string;
|
||||||
|
inMeeting: boolean;
|
||||||
|
meetingID: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UserStatus;
|
||||||
@ -16,10 +16,22 @@ const returnStatusColor = (
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getMeetingDuration = (meeting: DetailedMeeting) => {
|
const getUpcomingMeetingTime = (meeting: DetailedMeeting) => {
|
||||||
const startDate = new Date(meeting.start);
|
const startDate = new Date(meeting.start);
|
||||||
const endDate = new Date(startDate.getTime() + meeting.duration * 60000);
|
const endDate = new Date(startDate.getTime() + meeting.duration * 60000);
|
||||||
return `${startDate.toTimeString()} - ${endDate.toTimeString()}`;
|
const startTime = startDate
|
||||||
|
.toTimeString()
|
||||||
|
.split(" ")[0]
|
||||||
|
.split(":")
|
||||||
|
.slice(0, 2)
|
||||||
|
.join(":");
|
||||||
|
const endTime = endDate
|
||||||
|
.toTimeString()
|
||||||
|
.split(" ")[0]
|
||||||
|
.split(":")
|
||||||
|
.slice(0, 2)
|
||||||
|
.join(":");
|
||||||
|
return `${startTime} - ${endTime}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
export { returnStatusColor, getMeetingDuration };
|
export { returnStatusColor, getUpcomingMeetingTime };
|
||||||
|
|||||||
@ -16,6 +16,7 @@ const Body: React.FC<Props> = (props) => {
|
|||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
width: "100%",
|
width: "100%",
|
||||||
height: "100%",
|
height: "100%",
|
||||||
|
mt: 2,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Toolbar />
|
<Toolbar />
|
||||||
|
|||||||
@ -11,10 +11,7 @@ import React from "react";
|
|||||||
import { ExpandLess, ExpandMore } from "@mui/icons-material";
|
import { ExpandLess, ExpandMore } from "@mui/icons-material";
|
||||||
import ContactItem from "./sidebar-components/ContactItem";
|
import ContactItem from "./sidebar-components/ContactItem";
|
||||||
import { useAppSelector } from "../../../redux/hooks";
|
import { useAppSelector } from "../../../redux/hooks";
|
||||||
import {
|
import { selectUsers, selectTeam } from "../../../redux/slices/usersSlice";
|
||||||
selectFavoritesJSON,
|
|
||||||
selectTeamJSON,
|
|
||||||
} from "../../../redux/slices/peopleSlice";
|
|
||||||
import { selectFavorites } from "../../../redux/slices/favoritesSlice";
|
import { selectFavorites } from "../../../redux/slices/favoritesSlice";
|
||||||
import UserLite from "../../../api-bodies/UserLite";
|
import UserLite from "../../../api-bodies/UserLite";
|
||||||
|
|
||||||
@ -28,11 +25,11 @@ const Sidebar: React.FC<Props> = (props) => {
|
|||||||
const [favoritesOpen, setFavoritesOpen] = React.useState<boolean>(true);
|
const [favoritesOpen, setFavoritesOpen] = React.useState<boolean>(true);
|
||||||
const [teamOpen, setTeamOpen] = React.useState<boolean>(false);
|
const [teamOpen, setTeamOpen] = React.useState<boolean>(false);
|
||||||
|
|
||||||
const favorites = useAppSelector(selectFavorites);
|
const favoritesUuids = useAppSelector(selectFavorites);
|
||||||
const favoritesJSON = useAppSelector((state) =>
|
const favorites = useAppSelector((state) =>
|
||||||
selectFavoritesJSON(state, favorites)
|
selectUsers(state, favoritesUuids)
|
||||||
);
|
);
|
||||||
const teamJSON = useAppSelector(selectTeamJSON);
|
const team = useAppSelector(selectTeam);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Drawer
|
<Drawer
|
||||||
@ -54,13 +51,13 @@ const Sidebar: React.FC<Props> = (props) => {
|
|||||||
{favoritesOpen ? <ExpandLess /> : <ExpandMore />}
|
{favoritesOpen ? <ExpandLess /> : <ExpandMore />}
|
||||||
<ListItemText primary="Favorites" sx={{ textAlign: "center" }} />
|
<ListItemText primary="Favorites" sx={{ textAlign: "center" }} />
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={favoritesJSON.length}
|
primary={favorites.length}
|
||||||
sx={{ textAlign: "right" }}
|
sx={{ textAlign: "right" }}
|
||||||
/>
|
/>
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
<Collapse in={favoritesOpen} timeout="auto" unmountOnExit>
|
<Collapse in={favoritesOpen} timeout="auto" unmountOnExit>
|
||||||
<List disablePadding>
|
<List disablePadding>
|
||||||
{favoritesJSON.map((favorite, i) => (
|
{favorites.map((favorite, i) => (
|
||||||
<ContactItem
|
<ContactItem
|
||||||
contactInfo={favorite}
|
contactInfo={favorite}
|
||||||
key={i}
|
key={i}
|
||||||
@ -72,11 +69,11 @@ const Sidebar: React.FC<Props> = (props) => {
|
|||||||
<ListItemButton onClick={() => setTeamOpen(!teamOpen)}>
|
<ListItemButton onClick={() => setTeamOpen(!teamOpen)}>
|
||||||
{teamOpen ? <ExpandLess /> : <ExpandMore />}
|
{teamOpen ? <ExpandLess /> : <ExpandMore />}
|
||||||
<ListItemText primary="Team" sx={{ textAlign: "center" }} />
|
<ListItemText primary="Team" sx={{ textAlign: "center" }} />
|
||||||
<ListItemText primary={teamJSON.length} sx={{ textAlign: "right" }} />
|
<ListItemText primary={team.length} sx={{ textAlign: "right" }} />
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
<Collapse in={teamOpen} timeout="auto" unmountOnExit>
|
<Collapse in={teamOpen} timeout="auto" unmountOnExit>
|
||||||
<List disablePadding>
|
<List disablePadding>
|
||||||
{teamJSON.map((member, i) => (
|
{team.map((member, i) => (
|
||||||
<ContactItem
|
<ContactItem
|
||||||
contactInfo={member}
|
contactInfo={member}
|
||||||
key={i}
|
key={i}
|
||||||
|
|||||||
@ -3,8 +3,8 @@ import React from "react";
|
|||||||
import UserLite from "../../../../api-bodies/UserLite";
|
import UserLite from "../../../../api-bodies/UserLite";
|
||||||
import { useAppSelector, useAppDispatch } from "../../../../redux/hooks";
|
import { useAppSelector, useAppDispatch } from "../../../../redux/hooks";
|
||||||
import { open } from "../../../../redux/slices/meetingDetailsOpenSlice";
|
import { open } from "../../../../redux/slices/meetingDetailsOpenSlice";
|
||||||
import { selectUserUpcomingMeetings } from "../../../../redux/slices/meetingsSlice";
|
import { selectUserUpcomingMeetings } from "../../../../redux/slices/meetingsAndUserStatusSlice";
|
||||||
import { getMeetingDuration } from "../../Utils";
|
import { getUpcomingMeetingTime } from "../../Utils";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
contactInfo: UserLite;
|
contactInfo: UserLite;
|
||||||
@ -53,7 +53,7 @@ const LowerBody: React.FC<Props> = (props) => {
|
|||||||
{meeting.topic}
|
{meeting.topic}
|
||||||
</Button>
|
</Button>
|
||||||
<Typography sx={{ pt: 1.5 }}>
|
<Typography sx={{ pt: 1.5 }}>
|
||||||
{getMeetingDuration(meeting)}
|
{getUpcomingMeetingTime(meeting)}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@ -6,12 +6,34 @@ import GroupsIcon from "@mui/icons-material/Groups";
|
|||||||
import AddIcon from "@mui/icons-material/Add";
|
import AddIcon from "@mui/icons-material/Add";
|
||||||
import Status from "../../Status";
|
import Status from "../../Status";
|
||||||
import UserLite from "../../../../api-bodies/UserLite";
|
import UserLite from "../../../../api-bodies/UserLite";
|
||||||
|
import UserStatus from "../../../../api-bodies/UserStatus";
|
||||||
|
import { useAppSelector, useAppDispatch } from "../../../../redux/hooks";
|
||||||
|
import {
|
||||||
|
selectUserStatus,
|
||||||
|
selectMeeting,
|
||||||
|
} from "../../../../redux/slices/meetingsAndUserStatusSlice";
|
||||||
|
import {
|
||||||
|
selectFavorites,
|
||||||
|
addFavorite,
|
||||||
|
removeFavorite,
|
||||||
|
} from "../../../../redux/slices/favoritesSlice";
|
||||||
|
import RemoveIcon from "@mui/icons-material/Remove";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
contactInfo: UserLite;
|
contactInfo: UserLite;
|
||||||
}
|
}
|
||||||
|
|
||||||
const UpperBody: React.FC<Props> = (props) => {
|
const UpperBody: React.FC<Props> = (props) => {
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const userStatus: UserStatus | null = useAppSelector((state) =>
|
||||||
|
selectUserStatus(state, props.contactInfo.uuid)
|
||||||
|
);
|
||||||
|
const favoritesUuids = useAppSelector(selectFavorites);
|
||||||
|
const detailedMeeting = useAppSelector((state) =>
|
||||||
|
selectMeeting(state, userStatus.meetingID)
|
||||||
|
);
|
||||||
|
const status: Status =
|
||||||
|
userStatus && userStatus.inMeeting ? Status.Online : Status.Offline;
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
@ -34,9 +56,25 @@ const UpperBody: React.FC<Props> = (props) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography variant="h3">{props.contactInfo.name}</Typography>
|
<Typography variant="h3">{props.contactInfo.name}</Typography>
|
||||||
<Button variant="outlined" color="success" startIcon={<AddIcon />}>
|
{!favoritesUuids.includes(props.contactInfo.uuid) ? (
|
||||||
favorites
|
<Button
|
||||||
</Button>
|
variant="outlined"
|
||||||
|
color="success"
|
||||||
|
startIcon={<AddIcon />}
|
||||||
|
onClick={() => dispatch(addFavorite(props.contactInfo.uuid))}
|
||||||
|
>
|
||||||
|
favorites
|
||||||
|
</Button>
|
||||||
|
) : (
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
color="secondary"
|
||||||
|
startIcon={<RemoveIcon />}
|
||||||
|
onClick={() => dispatch(removeFavorite(props.contactInfo.uuid))}
|
||||||
|
>
|
||||||
|
favorites
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
@ -64,8 +102,10 @@ const UpperBody: React.FC<Props> = (props) => {
|
|||||||
</IconButton>
|
</IconButton>
|
||||||
</Box>
|
</Box>
|
||||||
<Box sx={{ display: "flex", flexDirection: "column" }}>
|
<Box sx={{ display: "flex", flexDirection: "column" }}>
|
||||||
<Typography sx={{ textAlign: "right" }}>{Status.Online}</Typography>
|
<Typography sx={{ textAlign: "right" }}>{status}</Typography>
|
||||||
<Typography>MeetingName-1372</Typography>
|
{detailedMeeting ? (
|
||||||
|
<Typography>{detailedMeeting.topic}</Typography>
|
||||||
|
) : null}
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@ -5,6 +5,9 @@ import CircleIcon from "@mui/icons-material/Circle";
|
|||||||
import { returnStatusColor } from "../../Utils";
|
import { returnStatusColor } from "../../Utils";
|
||||||
import UserLite from "../../../../api-bodies/UserLite";
|
import UserLite from "../../../../api-bodies/UserLite";
|
||||||
import Status from "../../Status";
|
import Status from "../../Status";
|
||||||
|
import { useAppSelector } from "../../../../redux/hooks";
|
||||||
|
import { selectUserStatus } from "../../../../redux/slices/meetingsAndUserStatusSlice";
|
||||||
|
import UserStatus from "../../../../api-bodies/UserStatus";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
contactInfo: UserLite;
|
contactInfo: UserLite;
|
||||||
@ -12,6 +15,11 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ContactItem: React.FC<Props> = (props) => {
|
const ContactItem: React.FC<Props> = (props) => {
|
||||||
|
const userStatus: UserStatus | null = useAppSelector((state) =>
|
||||||
|
selectUserStatus(state, props.contactInfo.uuid)
|
||||||
|
);
|
||||||
|
const status: Status =
|
||||||
|
userStatus && userStatus.inMeeting ? Status.Online : Status.Offline;
|
||||||
return (
|
return (
|
||||||
<ListItemButton
|
<ListItemButton
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@ -23,10 +31,10 @@ const ContactItem: React.FC<Props> = (props) => {
|
|||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={props.contactInfo.name}
|
primary={props.contactInfo.name}
|
||||||
secondary={Status.Online}
|
secondary={status}
|
||||||
sx={{ flexGrow: 1 }}
|
sx={{ flexGrow: 1 }}
|
||||||
/>
|
/>
|
||||||
<CircleIcon color={returnStatusColor(Status.Online)} />
|
<CircleIcon color={returnStatusColor(status)} />
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -12,7 +12,7 @@ const MeetingDetails: React.FC = () => {
|
|||||||
const meetingDetailsOpen = useAppSelector(selectMeetingDetailsOpen);
|
const meetingDetailsOpen = useAppSelector(selectMeetingDetailsOpen);
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
return (
|
return meetingDetailsOpen.meeting ? (
|
||||||
<Dialog
|
<Dialog
|
||||||
fullScreen
|
fullScreen
|
||||||
open={meetingDetailsOpen.open}
|
open={meetingDetailsOpen.open}
|
||||||
@ -21,7 +21,7 @@ const MeetingDetails: React.FC = () => {
|
|||||||
<Header meeting={meetingDetailsOpen.meeting} />
|
<Header meeting={meetingDetailsOpen.meeting} />
|
||||||
<Body meeting={meetingDetailsOpen.meeting} />
|
<Body meeting={meetingDetailsOpen.meeting} />
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
) : null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default MeetingDetails;
|
export default MeetingDetails;
|
||||||
|
|||||||
30
src/components/meeting-details/Utils.tsx
Normal file
30
src/components/meeting-details/Utils.tsx
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import DetailedMeeting from "../../api-bodies/DetailedMeeting";
|
||||||
|
|
||||||
|
const getMeetingStatus = (meeting: DetailedMeeting) => {
|
||||||
|
const startDate = new Date(meeting.start);
|
||||||
|
const endDate = new Date(startDate.getTime() + meeting.duration * 60000);
|
||||||
|
const currentDate = new Date();
|
||||||
|
if (currentDate > startDate && currentDate < endDate) return "Live";
|
||||||
|
else if (currentDate < startDate) return "Scheduled";
|
||||||
|
else return "Finished";
|
||||||
|
};
|
||||||
|
|
||||||
|
const getUpcomingMeetingTime = (meeting: DetailedMeeting) => {
|
||||||
|
const startDate = new Date(meeting.start);
|
||||||
|
const endDate = new Date(startDate.getTime() + meeting.duration * 60000);
|
||||||
|
const startTime = startDate
|
||||||
|
.toTimeString()
|
||||||
|
.split(" ")[0]
|
||||||
|
.split(":")
|
||||||
|
.slice(0, 2)
|
||||||
|
.join(":");
|
||||||
|
const endTime = endDate
|
||||||
|
.toTimeString()
|
||||||
|
.split(" ")[0]
|
||||||
|
.split(":")
|
||||||
|
.slice(0, 2)
|
||||||
|
.join(":");
|
||||||
|
return `${startTime} - ${endTime}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
export { getMeetingStatus, getUpcomingMeetingTime };
|
||||||
@ -9,12 +9,20 @@ import {
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import PersonOutlineIcon from "@mui/icons-material/PersonOutline";
|
import PersonOutlineIcon from "@mui/icons-material/PersonOutline";
|
||||||
import DetailedMeeting from "../../../api-bodies/DetailedMeeting";
|
import DetailedMeeting from "../../../api-bodies/DetailedMeeting";
|
||||||
|
import { useAppSelector } from "../../../redux/hooks";
|
||||||
|
import { selectUsers } from "../../../redux/slices/usersSlice";
|
||||||
|
import { getMeetingStatus } from "../Utils";
|
||||||
|
import UserLite from "../../../api-bodies/UserLite";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
meeting: DetailedMeeting | null;
|
meeting: DetailedMeeting;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Body: React.FC<Props> = () => {
|
const Body: React.FC<Props> = (props) => {
|
||||||
|
const registrants: UserLite[] = useAppSelector((state) =>
|
||||||
|
selectUsers(state, props.meeting.registrantIds)
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
@ -34,7 +42,7 @@ const Body: React.FC<Props> = () => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography>Feb 10, 2022 10:45 am - 11:00 am</Typography>
|
<Typography>Feb 10, 2022 10:45 am - 11:00 am</Typography>
|
||||||
<Typography>Status: Live</Typography>
|
<Typography>Status: {getMeetingStatus(props.meeting)}</Typography>
|
||||||
<Typography>
|
<Typography>
|
||||||
Topic: Lorem Ipsum is simply dummy text of the printing and
|
Topic: Lorem Ipsum is simply dummy text of the printing and
|
||||||
typesetting industry. Lorem Ipsum has been the industrys standard
|
typesetting industry. Lorem Ipsum has been the industrys standard
|
||||||
@ -56,20 +64,14 @@ const Body: React.FC<Props> = () => {
|
|||||||
<ListItem sx={{ borderBottom: 1 }}>
|
<ListItem sx={{ borderBottom: 1 }}>
|
||||||
<ListItemText primary="Invited" />
|
<ListItemText primary="Invited" />
|
||||||
</ListItem>
|
</ListItem>
|
||||||
<ListItem>
|
{registrants.map((registrant, i) => (
|
||||||
<ListItemIcon>
|
<ListItem key={i}>
|
||||||
<PersonOutlineIcon />
|
<ListItemIcon>
|
||||||
</ListItemIcon>
|
<PersonOutlineIcon />
|
||||||
<ListItemText primary="Taehee Choi" />
|
</ListItemIcon>
|
||||||
</ListItem>
|
<ListItemText primary={registrant.name} />
|
||||||
</List>
|
</ListItem>
|
||||||
<List>
|
))}
|
||||||
<ListItem>
|
|
||||||
<ListItemIcon>
|
|
||||||
<PersonOutlineIcon />
|
|
||||||
</ListItemIcon>
|
|
||||||
<ListItemText primary="Taehee Choi" />
|
|
||||||
</ListItem>
|
|
||||||
</List>
|
</List>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@ -5,14 +5,12 @@ import { AuthProvider } from "./context/AuthProvider";
|
|||||||
import { Provider } from "react-redux";
|
import { Provider } from "react-redux";
|
||||||
import { store } from "./redux/store";
|
import { store } from "./redux/store";
|
||||||
import { fetchFavorites } from "./redux/slices/favoritesSlice";
|
import { fetchFavorites } from "./redux/slices/favoritesSlice";
|
||||||
import { fetchTeam } from "./redux/slices/teamSlice";
|
import { fetchMeetings } from "./redux/slices/meetingsAndUserStatusSlice";
|
||||||
import { fetchMeetings } from "./redux/slices/meetingsSlice";
|
import { fetchUsers } from "./redux/slices/usersSlice";
|
||||||
import { fetchPeople } from "./redux/slices/peopleSlice";
|
|
||||||
|
|
||||||
store.dispatch(fetchPeople(""));
|
|
||||||
store.dispatch(fetchFavorites(""));
|
|
||||||
store.dispatch(fetchTeam(""));
|
|
||||||
store.dispatch(fetchMeetings(""));
|
store.dispatch(fetchMeetings(""));
|
||||||
|
store.dispatch(fetchUsers(""));
|
||||||
|
store.dispatch(fetchFavorites(""));
|
||||||
|
|
||||||
const Index: React.FC = () => {
|
const Index: React.FC = () => {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
|
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
|
||||||
import { RootState } from "../store";
|
import { RootState } from "../store";
|
||||||
|
import { favorites } from "../../api-bodies/MockData";
|
||||||
|
|
||||||
interface FavoritesState {
|
interface FavoritesState {
|
||||||
favorites: string[];
|
favorites: string[];
|
||||||
@ -34,7 +35,7 @@ export const fetchFavorites = createAsyncThunk(
|
|||||||
// const response = await client.post("/fakeApi/posts", initialPost);
|
// const response = await client.post("/fakeApi/posts", initialPost);
|
||||||
// !!!
|
// !!!
|
||||||
console.log(uuid);
|
console.log(uuid);
|
||||||
return ["2", "4"];
|
return favorites;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
export const addFavorite = createAsyncThunk(
|
export const addFavorite = createAsyncThunk(
|
||||||
|
|||||||
78
src/redux/slices/meetingsAndUserStatusSlice.tsx
Normal file
78
src/redux/slices/meetingsAndUserStatusSlice.tsx
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
|
||||||
|
import DetailedMeeting from "../../api-bodies/DetailedMeeting";
|
||||||
|
import { RootState } from "../store";
|
||||||
|
import { meetings } from "../../api-bodies/MockData";
|
||||||
|
import UserStatus from "../../api-bodies/UserStatus";
|
||||||
|
|
||||||
|
interface MeetingsAndUserStatusState {
|
||||||
|
meetings: DetailedMeeting[];
|
||||||
|
userStatuses: Record<string, UserStatus>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialState: MeetingsAndUserStatusState = {
|
||||||
|
meetings: [],
|
||||||
|
userStatuses: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const meetingsAndUserStatusSlice = createSlice({
|
||||||
|
name: "meetingsAndUserStatus",
|
||||||
|
initialState,
|
||||||
|
reducers: {},
|
||||||
|
extraReducers(builder) {
|
||||||
|
builder.addCase(fetchMeetings.fulfilled, (state, action) => {
|
||||||
|
state.meetings = action.payload.meetings;
|
||||||
|
state.userStatuses = action.payload.userStatuses;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const fetchMeetings = createAsyncThunk(
|
||||||
|
"meetingsAndUserStatus/fetchMeetings",
|
||||||
|
async (uuid: string) => {
|
||||||
|
// const response = await client.post("/fakeApi/posts", initialPost);
|
||||||
|
// !!!
|
||||||
|
console.log(uuid);
|
||||||
|
const userStatuses: Record<string, UserStatus> = {};
|
||||||
|
meetings.forEach((meeting) => {
|
||||||
|
meeting.liveParticipantIds.forEach((uuid) => {
|
||||||
|
userStatuses[uuid] = {
|
||||||
|
uuid: uuid,
|
||||||
|
inMeeting: true,
|
||||||
|
meetingID: meeting.meetingId,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return { userStatuses: userStatuses, meetings: meetings };
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const selectMeetings = (state: RootState) =>
|
||||||
|
state.meetingsAndUserStatuses.meetings;
|
||||||
|
export const selectMeeting = (state: RootState, meetingID: string | null) => {
|
||||||
|
return meetingID !== null
|
||||||
|
? state.meetingsAndUserStatuses.meetings.find(
|
||||||
|
(meeting) => meeting.meetingId === meetingID
|
||||||
|
)
|
||||||
|
: null;
|
||||||
|
};
|
||||||
|
export const selectUserUpcomingMeetings = (state: RootState, uuid: string) => {
|
||||||
|
return state.meetingsAndUserStatuses.meetings.filter((meeting) =>
|
||||||
|
meeting.registrantIds.includes(uuid)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export const selectUserStatus = (
|
||||||
|
state: RootState,
|
||||||
|
uuid: string
|
||||||
|
): UserStatus => {
|
||||||
|
const userStatus = state.meetingsAndUserStatuses.userStatuses[uuid];
|
||||||
|
if (userStatus) {
|
||||||
|
return userStatus;
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
uuid: uuid,
|
||||||
|
inMeeting: false,
|
||||||
|
meetingID: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
export default meetingsAndUserStatusSlice.reducer;
|
||||||
@ -1,41 +0,0 @@
|
|||||||
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
|
|
||||||
import DetailedMeeting from "../../api-bodies/DetailedMeeting";
|
|
||||||
import { RootState } from "../store";
|
|
||||||
import { meetings } from "../../api-bodies/MockData";
|
|
||||||
|
|
||||||
interface MeetingsState {
|
|
||||||
meetings: DetailedMeeting[];
|
|
||||||
}
|
|
||||||
|
|
||||||
const initialState: MeetingsState = {
|
|
||||||
meetings: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
export const meetingsSlice = createSlice({
|
|
||||||
name: "meetings",
|
|
||||||
initialState,
|
|
||||||
reducers: {},
|
|
||||||
extraReducers(builder) {
|
|
||||||
builder.addCase(fetchMeetings.fulfilled, (state, action) => {
|
|
||||||
return action.payload;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchMeetings = createAsyncThunk(
|
|
||||||
"meetings/fetchMeetings",
|
|
||||||
async (uuid: string) => {
|
|
||||||
// const response = await client.post("/fakeApi/posts", initialPost);
|
|
||||||
// !!!
|
|
||||||
console.log(uuid);
|
|
||||||
return { meetings: meetings };
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
export const selectMeetings = (state: RootState) => state.meetings.meetings;
|
|
||||||
export const selectUserUpcomingMeetings = (state: RootState, uuid: string) => {
|
|
||||||
return state.meetings.meetings.filter((meeting) =>
|
|
||||||
meeting.registrantIds.includes(uuid)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
export default meetingsSlice.reducer;
|
|
||||||
@ -1,40 +0,0 @@
|
|||||||
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
|
|
||||||
import UserLite from "../../api-bodies/UserLite";
|
|
||||||
import { RootState } from "../store";
|
|
||||||
import { people } from "../../api-bodies/MockData";
|
|
||||||
|
|
||||||
interface PeopleState {
|
|
||||||
people: UserLite[];
|
|
||||||
}
|
|
||||||
|
|
||||||
const initialState: PeopleState = {
|
|
||||||
people: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
export const peopleSlice = createSlice({
|
|
||||||
name: "people",
|
|
||||||
initialState,
|
|
||||||
reducers: {},
|
|
||||||
extraReducers(builder) {
|
|
||||||
builder.addCase(fetchPeople.fulfilled, (state, action) => {
|
|
||||||
console.log(action.payload);
|
|
||||||
state.people = action.payload;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchPeople = createAsyncThunk(
|
|
||||||
"people/fetchPeople",
|
|
||||||
async (uuid: string) => {
|
|
||||||
// const response = await client.post("/fakeApi/posts", initialPost);
|
|
||||||
// !!!
|
|
||||||
console.log(uuid);
|
|
||||||
return people;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
export const selectFavoritesJSON = (state: RootState, favorites: string[]) => {
|
|
||||||
return state.people.people.filter((p) => favorites.includes(p.uuid));
|
|
||||||
};
|
|
||||||
export const selectTeamJSON = (state: RootState) => state.people.people;
|
|
||||||
export default peopleSlice.reducer;
|
|
||||||
@ -1,41 +0,0 @@
|
|||||||
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
|
|
||||||
import { RootState } from "../store";
|
|
||||||
import { team } from "../../api-bodies/MockData";
|
|
||||||
|
|
||||||
interface TeamState {
|
|
||||||
user: string | null;
|
|
||||||
manager: string | null;
|
|
||||||
sameManager: string[];
|
|
||||||
directReports: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
const initialState: TeamState = {
|
|
||||||
user: null,
|
|
||||||
manager: null,
|
|
||||||
sameManager: [],
|
|
||||||
directReports: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
export const teamSlice = createSlice({
|
|
||||||
name: "team",
|
|
||||||
initialState,
|
|
||||||
reducers: {},
|
|
||||||
extraReducers(builder) {
|
|
||||||
builder.addCase(fetchTeam.fulfilled, (state, action) => {
|
|
||||||
return action.payload;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export const fetchTeam = createAsyncThunk(
|
|
||||||
"team/fetchTeam",
|
|
||||||
async (uuid: string) => {
|
|
||||||
// const response = await client.post("/fakeApi/posts", initialPost);
|
|
||||||
// !!!
|
|
||||||
console.log(uuid);
|
|
||||||
return team;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
export const selectTeam = (state: RootState) => state.team;
|
|
||||||
export default teamSlice.reducer;
|
|
||||||
66
src/redux/slices/usersSlice.tsx
Normal file
66
src/redux/slices/usersSlice.tsx
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
|
||||||
|
import { RootState } from "../store";
|
||||||
|
import { userLites, team } from "../../api-bodies/MockData";
|
||||||
|
import UserLite from "../../api-bodies/UserLite";
|
||||||
|
|
||||||
|
interface TeamState {
|
||||||
|
user: string | null;
|
||||||
|
manager: string | null;
|
||||||
|
sameManager: string[];
|
||||||
|
directReports: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UsersState {
|
||||||
|
users: Record<string, UserLite>;
|
||||||
|
team: TeamState;
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialState: UsersState = {
|
||||||
|
users: {},
|
||||||
|
team: { user: null, manager: null, sameManager: [], directReports: [] },
|
||||||
|
};
|
||||||
|
|
||||||
|
export const usersSlice = createSlice({
|
||||||
|
name: "users",
|
||||||
|
initialState,
|
||||||
|
reducers: {},
|
||||||
|
extraReducers(builder) {
|
||||||
|
builder.addCase(fetchUsers.fulfilled, (state, action) => {
|
||||||
|
state.users = action.payload.users;
|
||||||
|
state.team = action.payload.team;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const fetchUsers = createAsyncThunk(
|
||||||
|
"users/fetchUsers",
|
||||||
|
async (uuid: string) => {
|
||||||
|
// fetch userfull
|
||||||
|
// fetch managerfull
|
||||||
|
// now you have yourself, co-workers, manager, and direct reports (your team basically!)
|
||||||
|
// call setTeam reducer in teamSlice
|
||||||
|
console.log(uuid);
|
||||||
|
const users: Record<string, UserLite> = {};
|
||||||
|
userLites.forEach((userLite) => {
|
||||||
|
users[userLite.uuid] = userLite;
|
||||||
|
});
|
||||||
|
return { users: users, team: team };
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const selectUsers = (state: RootState, uuids: string[]): UserLite[] => {
|
||||||
|
const users: UserLite[] = [];
|
||||||
|
uuids.forEach((uuid) => users.push(state.users.users[uuid]));
|
||||||
|
return users;
|
||||||
|
};
|
||||||
|
export const selectTeam = (state: RootState) => {
|
||||||
|
const team: UserLite[] = [];
|
||||||
|
if (state.users.team.manager !== null)
|
||||||
|
team.push(state.users.users[state.users.team.manager]);
|
||||||
|
state.users.team.sameManager.forEach((u) => team.push(state.users.users[u]));
|
||||||
|
state.users.team.directReports.forEach((u) =>
|
||||||
|
team.push(state.users.users[u])
|
||||||
|
);
|
||||||
|
return team;
|
||||||
|
};
|
||||||
|
export default usersSlice.reducer;
|
||||||
@ -1,17 +1,15 @@
|
|||||||
import { configureStore } from "@reduxjs/toolkit";
|
import { configureStore } from "@reduxjs/toolkit";
|
||||||
import meetingDetailsOpenReducer from "./slices/meetingDetailsOpenSlice";
|
import meetingDetailsOpenReducer from "./slices/meetingDetailsOpenSlice";
|
||||||
import favoritesReducer from "./slices/favoritesSlice";
|
import favoritesReducer from "./slices/favoritesSlice";
|
||||||
import teamReducer from "./slices/teamSlice";
|
import meetingsAndUserStatusReducer from "./slices/meetingsAndUserStatusSlice";
|
||||||
import meetingsReducer from "./slices/meetingsSlice";
|
import usersReducer from "./slices/usersSlice";
|
||||||
import peopleReducer from "./slices/peopleSlice";
|
|
||||||
|
|
||||||
export const store = configureStore({
|
export const store = configureStore({
|
||||||
reducer: {
|
reducer: {
|
||||||
meetingDetailsOpen: meetingDetailsOpenReducer,
|
meetingDetailsOpen: meetingDetailsOpenReducer,
|
||||||
favorites: favoritesReducer,
|
favorites: favoritesReducer,
|
||||||
team: teamReducer,
|
meetingsAndUserStatuses: meetingsAndUserStatusReducer,
|
||||||
meetings: meetingsReducer,
|
users: usersReducer,
|
||||||
people: peopleReducer,
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -5,3 +5,8 @@ body,
|
|||||||
#app > div {
|
#app > div {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user