initial redux set up
This commit is contained in:
parent
52f76f8209
commit
20a4d5dabf
86
src/api-bodies/MockData.tsx
Normal file
86
src/api-bodies/MockData.tsx
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
const people = [
|
||||||
|
{
|
||||||
|
uuid: "0",
|
||||||
|
emailAddress: "cth0604@gmail.com",
|
||||||
|
name: "Taehee Choi",
|
||||||
|
role: "Front-end Dev",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
uuid: "1",
|
||||||
|
emailAddress: "cth0604@gmail.com",
|
||||||
|
name: "Arthur Marques",
|
||||||
|
role: "Team Lead",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
uuid: "2",
|
||||||
|
emailAddress: "cth0604@gmail.com",
|
||||||
|
name: "Mathew Balsdon",
|
||||||
|
role: "Front-end Dev",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
uuid: "3",
|
||||||
|
emailAddress: "cth0604@gmail.com",
|
||||||
|
name: "Benson Lin",
|
||||||
|
role: "Back-end Dev",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
uuid: "4",
|
||||||
|
emailAddress: "cth0604@gmail.com",
|
||||||
|
name: "Jincheng Lu",
|
||||||
|
role: "Front-end Dev",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
uuid: "5",
|
||||||
|
emailAddress: "cth0604@gmail.com",
|
||||||
|
name: "Esteban Margaron",
|
||||||
|
role: "Back-end Dev",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
uuid: "6",
|
||||||
|
emailAddress: "cth0604@gmail.com",
|
||||||
|
name: "Leanna Resurreccion",
|
||||||
|
role: "Back-end Dev",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const meetings = [
|
||||||
|
{
|
||||||
|
meetingId: "0",
|
||||||
|
liveParticipantIds: [],
|
||||||
|
registrantIds: ["0", "1", "2", "3", "4", "5", "6"],
|
||||||
|
start: "2022-03-13T17:00:00",
|
||||||
|
duration: 15,
|
||||||
|
timezone: "",
|
||||||
|
joinUrl: "",
|
||||||
|
topic: "Daily Scrum Meeting",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
meetingId: "1",
|
||||||
|
liveParticipantIds: [],
|
||||||
|
registrantIds: ["0", "2", "4"],
|
||||||
|
start: "2022-03-13T17:30:00",
|
||||||
|
duration: 30,
|
||||||
|
timezone: "",
|
||||||
|
joinUrl: "",
|
||||||
|
topic: "Front-end Meeting",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
meetingId: "2",
|
||||||
|
liveParticipantIds: [],
|
||||||
|
registrantIds: ["3", "5", "6"],
|
||||||
|
start: "2022-03-13T17:30:00",
|
||||||
|
duration: 30,
|
||||||
|
timezone: "",
|
||||||
|
joinUrl: "",
|
||||||
|
topic: "Back-end Meeting",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const team = {
|
||||||
|
user: "0",
|
||||||
|
manager: "1",
|
||||||
|
sameManager: ["2", "3", "4", "5", "6"],
|
||||||
|
directReports: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
export { people, meetings, team };
|
||||||
@ -1,8 +0,0 @@
|
|||||||
import Status from "./Status";
|
|
||||||
|
|
||||||
interface ContactInfo {
|
|
||||||
name: string;
|
|
||||||
status: Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ContactInfo;
|
|
||||||
@ -2,12 +2,13 @@ import { Box } from "@mui/material";
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Body from "./contacts-components/Body";
|
import Body from "./contacts-components/Body";
|
||||||
|
|
||||||
import ContactInfo from "./ContactInfo";
|
|
||||||
import Sidebar from "./contacts-components/Sidebar";
|
import Sidebar from "./contacts-components/Sidebar";
|
||||||
|
import UserLite from "../../api-bodies/UserLite";
|
||||||
|
|
||||||
const Contacts: React.FC = () => {
|
const Contacts: React.FC = () => {
|
||||||
const [contactSelected, setContactSelected] =
|
const [contactSelected, setContactSelected] = React.useState<UserLite | null>(
|
||||||
React.useState<ContactInfo | null>(null);
|
null
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{ display: "flex", height: "100%" }}>
|
<Box sx={{ display: "flex", height: "100%" }}>
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import DetailedMeeting from "../../api-bodies/DetailedMeeting";
|
||||||
import Status from "./Status";
|
import Status from "./Status";
|
||||||
|
|
||||||
const returnStatusColor = (
|
const returnStatusColor = (
|
||||||
@ -15,4 +16,10 @@ const returnStatusColor = (
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export { returnStatusColor };
|
const getMeetingDuration = (meeting: DetailedMeeting) => {
|
||||||
|
const startDate = new Date(meeting.start);
|
||||||
|
const endDate = new Date(startDate.getTime() + meeting.duration * 60000);
|
||||||
|
return `${startDate.toTimeString()} - ${endDate.toTimeString()}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
export { returnStatusColor, getMeetingDuration };
|
||||||
|
|||||||
@ -2,10 +2,10 @@ import { Box, Toolbar } from "@mui/material";
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import UpperBody from "./body-components/UpperBody";
|
import UpperBody from "./body-components/UpperBody";
|
||||||
import LowerBody from "./body-components/LowerBody";
|
import LowerBody from "./body-components/LowerBody";
|
||||||
import ContactInfo from "../ContactInfo";
|
import UserLite from "../../../api-bodies/UserLite";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
contactSelected: ContactInfo;
|
contactSelected: UserLite;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Body: React.FC<Props> = (props) => {
|
const Body: React.FC<Props> = (props) => {
|
||||||
@ -20,7 +20,7 @@ const Body: React.FC<Props> = (props) => {
|
|||||||
>
|
>
|
||||||
<Toolbar />
|
<Toolbar />
|
||||||
<UpperBody contactInfo={props.contactSelected} />
|
<UpperBody contactInfo={props.contactSelected} />
|
||||||
<LowerBody />
|
<LowerBody contactInfo={props.contactSelected} />
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -9,19 +9,17 @@ import {
|
|||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { ExpandLess, ExpandMore } from "@mui/icons-material";
|
import { ExpandLess, ExpandMore } from "@mui/icons-material";
|
||||||
import ContactInfo from "../ContactInfo";
|
|
||||||
import Status from "../Status";
|
|
||||||
import ContactItem from "./sidebar-components/ContactItem";
|
import ContactItem from "./sidebar-components/ContactItem";
|
||||||
|
import { useAppSelector } from "../../../redux/hooks";
|
||||||
const contacts: ContactInfo[] = [
|
import {
|
||||||
{ name: "Taehee ...", status: Status.Online },
|
selectFavoritesJSON,
|
||||||
{ name: "Jincheng ...", status: Status.Offline },
|
selectTeamJSON,
|
||||||
{ name: "Mathew ...", status: Status.InMeeting },
|
} from "../../../redux/slices/peopleSlice";
|
||||||
{ name: "Esteban ...", status: Status.Away },
|
import { selectFavorites } from "../../../redux/slices/favoritesSlice";
|
||||||
];
|
import UserLite from "../../../api-bodies/UserLite";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
setContactSelected: (contactInfo: ContactInfo) => void;
|
setContactSelected: (contactInfo: UserLite) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const sidebarWidth = 240;
|
const sidebarWidth = 240;
|
||||||
@ -30,6 +28,12 @@ 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 favoritesJSON = useAppSelector((state) =>
|
||||||
|
selectFavoritesJSON(state, favorites)
|
||||||
|
);
|
||||||
|
const teamJSON = useAppSelector(selectTeamJSON);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Drawer
|
<Drawer
|
||||||
variant="permanent"
|
variant="permanent"
|
||||||
@ -49,13 +53,16 @@ const Sidebar: React.FC<Props> = (props) => {
|
|||||||
<ListItemButton onClick={() => setFavoritesOpen(!favoritesOpen)}>
|
<ListItemButton onClick={() => setFavoritesOpen(!favoritesOpen)}>
|
||||||
{favoritesOpen ? <ExpandLess /> : <ExpandMore />}
|
{favoritesOpen ? <ExpandLess /> : <ExpandMore />}
|
||||||
<ListItemText primary="Favorites" sx={{ textAlign: "center" }} />
|
<ListItemText primary="Favorites" sx={{ textAlign: "center" }} />
|
||||||
<ListItemText primary="10" sx={{ textAlign: "right" }} />
|
<ListItemText
|
||||||
|
primary={favoritesJSON.length}
|
||||||
|
sx={{ textAlign: "right" }}
|
||||||
|
/>
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
<Collapse in={favoritesOpen} timeout="auto" unmountOnExit>
|
<Collapse in={favoritesOpen} timeout="auto" unmountOnExit>
|
||||||
<List disablePadding>
|
<List disablePadding>
|
||||||
{contacts.map((contact, i) => (
|
{favoritesJSON.map((favorite, i) => (
|
||||||
<ContactItem
|
<ContactItem
|
||||||
contactInfo={contact}
|
contactInfo={favorite}
|
||||||
key={i}
|
key={i}
|
||||||
setContactSelected={props.setContactSelected}
|
setContactSelected={props.setContactSelected}
|
||||||
/>
|
/>
|
||||||
@ -65,13 +72,13 @@ 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="10" sx={{ textAlign: "right" }} />
|
<ListItemText primary={teamJSON.length} sx={{ textAlign: "right" }} />
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
<Collapse in={teamOpen} timeout="auto" unmountOnExit>
|
<Collapse in={teamOpen} timeout="auto" unmountOnExit>
|
||||||
<List disablePadding>
|
<List disablePadding>
|
||||||
{contacts.map((contact, i) => (
|
{teamJSON.map((member, i) => (
|
||||||
<ContactItem
|
<ContactItem
|
||||||
contactInfo={contact}
|
contactInfo={member}
|
||||||
key={i}
|
key={i}
|
||||||
setContactSelected={props.setContactSelected}
|
setContactSelected={props.setContactSelected}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -1,18 +1,21 @@
|
|||||||
import { Box, Button, List, Typography } from "@mui/material";
|
import { Box, Button, List, Typography } from "@mui/material";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useDispatch } from "react-redux";
|
import UserLite from "../../../../api-bodies/UserLite";
|
||||||
|
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 { getMeetingDuration } from "../../Utils";
|
||||||
|
|
||||||
const meetings: { name: string; duration: string }[] = [
|
interface Props {
|
||||||
{ name: "Kanban Meeting", duration: "10:45 am - 11:45 am" },
|
contactInfo: UserLite;
|
||||||
{ name: "Design Meeting", duration: "10:45 am - 11:45 am" },
|
}
|
||||||
{ name: "Customer Meeting", duration: "10:45 am - 11:45 am" },
|
|
||||||
{ name: "Some kind of Meeting", duration: "10:45 am - 11:45 am" },
|
|
||||||
{ name: "Some kind of Meeting", duration: "10:45 am - 11:45 am" },
|
|
||||||
];
|
|
||||||
|
|
||||||
const LowerBody: React.FC = () => {
|
const LowerBody: React.FC<Props> = (props) => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
|
const meetings = useAppSelector((state) =>
|
||||||
|
selectUserUpcomingMeetings(state, props.contactInfo.uuid)
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
@ -45,11 +48,13 @@ const LowerBody: React.FC = () => {
|
|||||||
<Button
|
<Button
|
||||||
variant="text"
|
variant="text"
|
||||||
color="info"
|
color="info"
|
||||||
onClick={() => dispatch(open())}
|
onClick={() => dispatch(open(meeting))}
|
||||||
>
|
>
|
||||||
{meeting.name}
|
{meeting.topic}
|
||||||
</Button>
|
</Button>
|
||||||
<Typography sx={{ pt: 1.5 }}>{meeting.duration}</Typography>
|
<Typography sx={{ pt: 1.5 }}>
|
||||||
|
{getMeetingDuration(meeting)}
|
||||||
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
))}
|
))}
|
||||||
</List>
|
</List>
|
||||||
|
|||||||
@ -3,11 +3,12 @@ import React from "react";
|
|||||||
import PhoneIcon from "@mui/icons-material/Phone";
|
import PhoneIcon from "@mui/icons-material/Phone";
|
||||||
import VideocamIcon from "@mui/icons-material/Videocam";
|
import VideocamIcon from "@mui/icons-material/Videocam";
|
||||||
import GroupsIcon from "@mui/icons-material/Groups";
|
import GroupsIcon from "@mui/icons-material/Groups";
|
||||||
import ContactInfo from "../../ContactInfo";
|
|
||||||
import AddIcon from "@mui/icons-material/Add";
|
import AddIcon from "@mui/icons-material/Add";
|
||||||
|
import Status from "../../Status";
|
||||||
|
import UserLite from "../../../../api-bodies/UserLite";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
contactInfo: ContactInfo;
|
contactInfo: UserLite;
|
||||||
}
|
}
|
||||||
|
|
||||||
const UpperBody: React.FC<Props> = (props) => {
|
const UpperBody: React.FC<Props> = (props) => {
|
||||||
@ -63,9 +64,7 @@ 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" }}>
|
<Typography sx={{ textAlign: "right" }}>{Status.Online}</Typography>
|
||||||
{props.contactInfo.status}
|
|
||||||
</Typography>
|
|
||||||
<Typography>MeetingName-1372</Typography>
|
<Typography>MeetingName-1372</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@ -2,12 +2,13 @@ import { ListItemButton, ListItemIcon, ListItemText } from "@mui/material";
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import PersonOutlineIcon from "@mui/icons-material/PersonOutline";
|
import PersonOutlineIcon from "@mui/icons-material/PersonOutline";
|
||||||
import CircleIcon from "@mui/icons-material/Circle";
|
import CircleIcon from "@mui/icons-material/Circle";
|
||||||
import ContactInfo from "../../ContactInfo";
|
|
||||||
import { returnStatusColor } from "../../Utils";
|
import { returnStatusColor } from "../../Utils";
|
||||||
|
import UserLite from "../../../../api-bodies/UserLite";
|
||||||
|
import Status from "../../Status";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
contactInfo: ContactInfo;
|
contactInfo: UserLite;
|
||||||
setContactSelected: (contactInfo: ContactInfo) => void;
|
setContactSelected: (contactInfo: UserLite) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ContactItem: React.FC<Props> = (props) => {
|
const ContactItem: React.FC<Props> = (props) => {
|
||||||
@ -22,10 +23,10 @@ const ContactItem: React.FC<Props> = (props) => {
|
|||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
primary={props.contactInfo.name}
|
primary={props.contactInfo.name}
|
||||||
secondary={props.contactInfo.status}
|
secondary={Status.Online}
|
||||||
sx={{ flexGrow: 1 }}
|
sx={{ flexGrow: 1 }}
|
||||||
/>
|
/>
|
||||||
<CircleIcon color={returnStatusColor(props.contactInfo.status)} />
|
<CircleIcon color={returnStatusColor(Status.Online)} />
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -2,20 +2,24 @@ import { Dialog } from "@mui/material";
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Body from "./meeting-details-components/Body";
|
import Body from "./meeting-details-components/Body";
|
||||||
import Header from "./meeting-details-components/Header";
|
import Header from "./meeting-details-components/Header";
|
||||||
import { useSelector, useDispatch } from "react-redux";
|
import { useAppSelector, useAppDispatch } from "../../redux/hooks";
|
||||||
import {
|
import {
|
||||||
close,
|
close,
|
||||||
selectMeetingDetailsOpen,
|
selectMeetingDetailsOpen,
|
||||||
} from "../../redux/slices/meetingDetailsOpenSlice";
|
} from "../../redux/slices/meetingDetailsOpenSlice";
|
||||||
|
|
||||||
const MeetingDetails: React.FC = () => {
|
const MeetingDetails: React.FC = () => {
|
||||||
const open = useSelector(selectMeetingDetailsOpen);
|
const meetingDetailsOpen = useAppSelector(selectMeetingDetailsOpen);
|
||||||
const dispatch = useDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog fullScreen open={open} onClose={() => dispatch(close())}>
|
<Dialog
|
||||||
<Header />
|
fullScreen
|
||||||
<Body />
|
open={meetingDetailsOpen.open}
|
||||||
|
onClose={() => dispatch(close())}
|
||||||
|
>
|
||||||
|
<Header meeting={meetingDetailsOpen.meeting} />
|
||||||
|
<Body meeting={meetingDetailsOpen.meeting} />
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -8,8 +8,13 @@ import {
|
|||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
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";
|
||||||
|
|
||||||
const Body: React.FC = () => {
|
interface Props {
|
||||||
|
meeting: DetailedMeeting | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Body: React.FC<Props> = () => {
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
|
|||||||
@ -1,17 +1,22 @@
|
|||||||
import { AppBar, Button, IconButton, Toolbar, Typography } from "@mui/material";
|
import { AppBar, Button, IconButton, Toolbar, Typography } from "@mui/material";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import CloseIcon from "@mui/icons-material/Close";
|
import CloseIcon from "@mui/icons-material/Close";
|
||||||
import { useDispatch } from "react-redux";
|
import { useAppDispatch } from "../../../redux/hooks";
|
||||||
import { close } from "../../../redux/slices/meetingDetailsOpenSlice";
|
import { close } from "../../../redux/slices/meetingDetailsOpenSlice";
|
||||||
|
import DetailedMeeting from "../../../api-bodies/DetailedMeeting";
|
||||||
|
|
||||||
const Header: React.FC = () => {
|
interface Props {
|
||||||
const dispatch = useDispatch();
|
meeting: DetailedMeeting | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Header: React.FC<Props> = (props) => {
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppBar sx={{ position: "relative" }}>
|
<AppBar sx={{ position: "relative" }}>
|
||||||
<Toolbar>
|
<Toolbar>
|
||||||
<Typography variant="h6" sx={{ flexGrow: 1 }}>
|
<Typography variant="h6" sx={{ flexGrow: 1 }}>
|
||||||
Kanban Meeting
|
{props.meeting !== null ? props.meeting.topic : null}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Button variant="contained" color="secondary">
|
<Button variant="contained" color="secondary">
|
||||||
Join
|
Join
|
||||||
|
|||||||
@ -4,6 +4,15 @@ import "./style/App.css";
|
|||||||
import { AuthProvider } from "./context/AuthProvider";
|
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 { fetchTeam } from "./redux/slices/teamSlice";
|
||||||
|
import { fetchMeetings } from "./redux/slices/meetingsSlice";
|
||||||
|
import { fetchPeople } from "./redux/slices/peopleSlice";
|
||||||
|
|
||||||
|
store.dispatch(fetchPeople(""));
|
||||||
|
store.dispatch(fetchFavorites(""));
|
||||||
|
store.dispatch(fetchTeam(""));
|
||||||
|
store.dispatch(fetchMeetings(""));
|
||||||
|
|
||||||
const Index: React.FC = () => {
|
const Index: React.FC = () => {
|
||||||
return (
|
return (
|
||||||
|
|||||||
6
src/redux/hooks.tsx
Normal file
6
src/redux/hooks.tsx
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";
|
||||||
|
import type { RootState, AppDispatch } from "./store";
|
||||||
|
|
||||||
|
// Use throughout your app instead of plain `useDispatch` and `useSelector`
|
||||||
|
export const useAppDispatch = () => useDispatch<AppDispatch>();
|
||||||
|
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
|
||||||
55
src/redux/slices/favoritesSlice.tsx
Normal file
55
src/redux/slices/favoritesSlice.tsx
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
|
||||||
|
import { RootState } from "../store";
|
||||||
|
|
||||||
|
interface FavoritesState {
|
||||||
|
favorites: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialState: FavoritesState = {
|
||||||
|
favorites: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const favoritesSlice = createSlice({
|
||||||
|
name: "favorites",
|
||||||
|
initialState,
|
||||||
|
reducers: {},
|
||||||
|
extraReducers(builder) {
|
||||||
|
builder
|
||||||
|
.addCase(fetchFavorites.fulfilled, (state, action) => {
|
||||||
|
state.favorites = action.payload;
|
||||||
|
})
|
||||||
|
.addCase(addFavorite.fulfilled, (state, action) => {
|
||||||
|
state.favorites.push(action.payload);
|
||||||
|
})
|
||||||
|
.addCase(removeFavorite.fulfilled, (state, action) => {
|
||||||
|
const index = state.favorites.indexOf(action.payload);
|
||||||
|
state.favorites.splice(index, 1);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const fetchFavorites = createAsyncThunk(
|
||||||
|
"favorites/fetchFavorites",
|
||||||
|
async (uuid: string) => {
|
||||||
|
// const response = await client.post("/fakeApi/posts", initialPost);
|
||||||
|
// !!!
|
||||||
|
console.log(uuid);
|
||||||
|
return ["2", "4"];
|
||||||
|
}
|
||||||
|
);
|
||||||
|
export const addFavorite = createAsyncThunk(
|
||||||
|
"favorites/addFavorite",
|
||||||
|
async (uuid: string) => {
|
||||||
|
// const response = await client.post("/fakeApi/posts", initialPost);
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
export const removeFavorite = createAsyncThunk(
|
||||||
|
"favorites/removeFavorite",
|
||||||
|
async (uuid: string) => {
|
||||||
|
// const response = await client.post("/fakeApi/posts", initialPost);
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
export const selectFavorites = (state: RootState) => state.favorites.favorites;
|
||||||
|
export default favoritesSlice.reducer;
|
||||||
@ -1,28 +1,33 @@
|
|||||||
import { createSlice } from "@reduxjs/toolkit";
|
import { createSlice } from "@reduxjs/toolkit";
|
||||||
|
import DetailedMeeting from "../../api-bodies/DetailedMeeting";
|
||||||
import { RootState } from "../store";
|
import { RootState } from "../store";
|
||||||
|
|
||||||
interface MeetingDetailsOpenState {
|
interface MeetingDetailsOpenState {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
|
meeting: DetailedMeeting | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialState: MeetingDetailsOpenState = {
|
const initialState: MeetingDetailsOpenState = {
|
||||||
open: false,
|
open: false,
|
||||||
|
meeting: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const meetingDetailsOpenSlice = createSlice({
|
export const meetingDetailsOpenSlice = createSlice({
|
||||||
name: "meetingDetailsOpen",
|
name: "meetingDetailsOpen",
|
||||||
initialState,
|
initialState,
|
||||||
reducers: {
|
reducers: {
|
||||||
open: (state) => {
|
open: (state, action) => {
|
||||||
state.open = true;
|
state.open = true;
|
||||||
|
state.meeting = action.payload;
|
||||||
},
|
},
|
||||||
close: (state) => {
|
close: (state) => {
|
||||||
state.open = false;
|
state.open = false;
|
||||||
|
state.meeting = null;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const { open, close } = meetingDetailsOpenSlice.actions;
|
export const { open, close } = meetingDetailsOpenSlice.actions;
|
||||||
export const selectMeetingDetailsOpen = (state: RootState) =>
|
export const selectMeetingDetailsOpen = (state: RootState) =>
|
||||||
state.meetingDetailsOpen.open;
|
state.meetingDetailsOpen;
|
||||||
export default meetingDetailsOpenSlice.reducer;
|
export default meetingDetailsOpenSlice.reducer;
|
||||||
|
|||||||
41
src/redux/slices/meetingsSlice.tsx
Normal file
41
src/redux/slices/meetingsSlice.tsx
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
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;
|
||||||
40
src/redux/slices/peopleSlice.tsx
Normal file
40
src/redux/slices/peopleSlice.tsx
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
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;
|
||||||
41
src/redux/slices/teamSlice.tsx
Normal file
41
src/redux/slices/teamSlice.tsx
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
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;
|
||||||
@ -1,9 +1,17 @@
|
|||||||
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 teamReducer from "./slices/teamSlice";
|
||||||
|
import meetingsReducer from "./slices/meetingsSlice";
|
||||||
|
import peopleReducer from "./slices/peopleSlice";
|
||||||
|
|
||||||
export const store = configureStore({
|
export const store = configureStore({
|
||||||
reducer: {
|
reducer: {
|
||||||
meetingDetailsOpen: meetingDetailsOpenReducer,
|
meetingDetailsOpen: meetingDetailsOpenReducer,
|
||||||
|
favorites: favoritesReducer,
|
||||||
|
team: teamReducer,
|
||||||
|
meetings: meetingsReducer,
|
||||||
|
people: peopleReducer,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user