Merge pull request #4 from CPSC319-Winter-term-2/contacts-page
Contacts page
This commit is contained in:
commit
6865a55672
7
package-lock.json
generated
7
package-lock.json
generated
@ -4552,6 +4552,7 @@
|
||||
"dependencies": {
|
||||
"anymatch": "~3.1.2",
|
||||
"braces": "~3.0.2",
|
||||
"fsevents": "~2.3.2",
|
||||
"glob-parent": "~5.1.2",
|
||||
"is-binary-path": "~2.1.0",
|
||||
"is-glob": "~4.0.1",
|
||||
@ -7707,6 +7708,12 @@
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"imagemin": "^7.0.1",
|
||||
"imagemin-gifsicle": "^7.0.0",
|
||||
"imagemin-mozjpeg": "^9.0.0",
|
||||
"imagemin-optipng": "^8.0.0",
|
||||
"imagemin-pngquant": "^9.0.2",
|
||||
"imagemin-svgo": "^9.0.0",
|
||||
"imagemin-webp": "^7.0.0",
|
||||
"loader-utils": "^2.0.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"schema-utils": "^2.7.1"
|
||||
|
||||
28
src/components/contacts/Body.tsx
Normal file
28
src/components/contacts/Body.tsx
Normal file
@ -0,0 +1,28 @@
|
||||
import { Box, Toolbar } from "@mui/material";
|
||||
import React from "react";
|
||||
import UpperBody from "./UpperBody";
|
||||
import LowerBody from "./LowerBody";
|
||||
import ContactInfo from "./ContactInfo";
|
||||
|
||||
interface Props {
|
||||
contactSelected: ContactInfo;
|
||||
}
|
||||
|
||||
const Body: React.FC<Props> = (props) => {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
}}
|
||||
>
|
||||
<Toolbar />
|
||||
<UpperBody contactInfo={props.contactSelected} />
|
||||
<LowerBody contactInfo={props.contactSelected} />
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default Body;
|
||||
8
src/components/contacts/ContactInfo.tsx
Normal file
8
src/components/contacts/ContactInfo.tsx
Normal file
@ -0,0 +1,8 @@
|
||||
import Status from "./Status";
|
||||
|
||||
interface ContactInfo {
|
||||
name: string;
|
||||
status: Status;
|
||||
}
|
||||
|
||||
export default ContactInfo;
|
||||
33
src/components/contacts/ContactItem.tsx
Normal file
33
src/components/contacts/ContactItem.tsx
Normal file
@ -0,0 +1,33 @@
|
||||
import { ListItemButton, ListItemIcon, ListItemText } from "@mui/material";
|
||||
import React from "react";
|
||||
import PersonOutlineIcon from "@mui/icons-material/PersonOutline";
|
||||
import CircleIcon from "@mui/icons-material/Circle";
|
||||
import ContactInfo from "./ContactInfo";
|
||||
import { returnStatusColor } from "./Utils";
|
||||
|
||||
interface Props {
|
||||
contactInfo: ContactInfo;
|
||||
setContactSelected: (contactInfo: ContactInfo) => void;
|
||||
}
|
||||
|
||||
const ContactItem: React.FC<Props> = (props) => {
|
||||
return (
|
||||
<ListItemButton
|
||||
onClick={() => {
|
||||
props.setContactSelected(props.contactInfo);
|
||||
}}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<PersonOutlineIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary={props.contactInfo.name}
|
||||
secondary={props.contactInfo.status}
|
||||
sx={{ flexGrow: 1 }}
|
||||
/>
|
||||
<CircleIcon color={returnStatusColor(props.contactInfo.status)} />
|
||||
</ListItemButton>
|
||||
);
|
||||
};
|
||||
|
||||
export default ContactItem;
|
||||
@ -1,5 +1,22 @@
|
||||
import { Box } from "@mui/material";
|
||||
import React from "react";
|
||||
import Body from "./Body";
|
||||
|
||||
import ContactInfo from "./ContactInfo";
|
||||
import Sidebar from "./Sidebar";
|
||||
|
||||
const Contacts: React.FC = () => {
|
||||
return <span>Contacts</span>;
|
||||
const [contactSelected, setContactSelected] =
|
||||
React.useState<ContactInfo | null>(null);
|
||||
|
||||
return (
|
||||
<Box sx={{ display: "flex", height: "100%" }}>
|
||||
<Sidebar setContactSelected={setContactSelected} />
|
||||
{contactSelected !== null ? (
|
||||
<Body contactSelected={contactSelected} />
|
||||
) : null}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default Contacts;
|
||||
|
||||
55
src/components/contacts/LowerBody.tsx
Normal file
55
src/components/contacts/LowerBody.tsx
Normal file
@ -0,0 +1,55 @@
|
||||
import { Box, List, Typography } from "@mui/material";
|
||||
import React from "react";
|
||||
import ContactInfo from "./ContactInfo";
|
||||
|
||||
const meetings: { name: string; duration: string }[] = [
|
||||
{ name: "Kanban Meeting", duration: "10:45 am - 11:45 am" },
|
||||
{ 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" },
|
||||
];
|
||||
|
||||
interface Props {
|
||||
contactInfo: ContactInfo;
|
||||
}
|
||||
|
||||
const LowerBody: React.FC<Props> = () => {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
border: 1,
|
||||
borderRadius: 2,
|
||||
width: "70%",
|
||||
height: "70%",
|
||||
alignSelf: "center",
|
||||
}}
|
||||
>
|
||||
<Typography variant="h4" textAlign="center">
|
||||
Upcoming meetings
|
||||
</Typography>
|
||||
<List sx={{ maxHeight: "100%", overflow: "auto" }}>
|
||||
{meetings.map((meeting, i) => (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
height: "50px",
|
||||
px: "10px",
|
||||
borderTop: 1,
|
||||
borderBottom: i === meetings.length - 1 ? 1 : 0,
|
||||
}}
|
||||
key={i}
|
||||
>
|
||||
<Typography sx={{ pt: "12px" }}>{meeting.name}</Typography>
|
||||
<Typography sx={{ pt: "12px" }}>{meeting.duration}</Typography>
|
||||
</Box>
|
||||
))}
|
||||
</List>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default LowerBody;
|
||||
86
src/components/contacts/Sidebar.tsx
Normal file
86
src/components/contacts/Sidebar.tsx
Normal file
@ -0,0 +1,86 @@
|
||||
import {
|
||||
Collapse,
|
||||
Divider,
|
||||
Drawer,
|
||||
List,
|
||||
ListItemButton,
|
||||
ListItemText,
|
||||
Toolbar,
|
||||
} from "@mui/material";
|
||||
import React from "react";
|
||||
import { ExpandLess, ExpandMore } from "@mui/icons-material";
|
||||
import ContactInfo from "./ContactInfo";
|
||||
import Status from "./Status";
|
||||
import ContactItem from "./ContactItem";
|
||||
|
||||
const contacts: ContactInfo[] = [
|
||||
{ name: "Taehee ...", status: Status.Online },
|
||||
{ name: "Jincheng ...", status: Status.Offline },
|
||||
{ name: "Mathew ...", status: Status.InMeeting },
|
||||
{ name: "Esteban ...", status: Status.Away },
|
||||
];
|
||||
|
||||
interface Props {
|
||||
setContactSelected: (contactInfo: ContactInfo) => void;
|
||||
}
|
||||
|
||||
const sidebarWidth = 240;
|
||||
|
||||
const Sidebar: React.FC<Props> = (props) => {
|
||||
const [favoritesOpen, setFavoritesOpen] = React.useState<boolean>(true);
|
||||
const [teamOpen, setTeamOpen] = React.useState<boolean>(false);
|
||||
|
||||
return (
|
||||
<Drawer
|
||||
variant="permanent"
|
||||
sx={{
|
||||
width: sidebarWidth,
|
||||
["& .MuiDrawer-paper"]: { width: sidebarWidth },
|
||||
}}
|
||||
>
|
||||
<Toolbar />
|
||||
<List>
|
||||
<ListItemText
|
||||
primary="Contacts"
|
||||
primaryTypographyProps={{ variant: "h6" }}
|
||||
sx={{ textAlign: "center" }}
|
||||
/>
|
||||
<Divider />
|
||||
<ListItemButton onClick={() => setFavoritesOpen(!favoritesOpen)}>
|
||||
{favoritesOpen ? <ExpandLess /> : <ExpandMore />}
|
||||
<ListItemText primary="Favorites" sx={{ textAlign: "center" }} />
|
||||
<ListItemText primary="10" sx={{ textAlign: "right" }} />
|
||||
</ListItemButton>
|
||||
<Collapse in={favoritesOpen} timeout="auto" unmountOnExit>
|
||||
<List disablePadding>
|
||||
{contacts.map((contact, i) => (
|
||||
<ContactItem
|
||||
contactInfo={contact}
|
||||
key={i}
|
||||
setContactSelected={props.setContactSelected}
|
||||
/>
|
||||
))}
|
||||
</List>
|
||||
</Collapse>
|
||||
<ListItemButton onClick={() => setTeamOpen(!teamOpen)}>
|
||||
{teamOpen ? <ExpandLess /> : <ExpandMore />}
|
||||
<ListItemText primary="Team" sx={{ textAlign: "center" }} />
|
||||
<ListItemText primary="10" sx={{ textAlign: "right" }} />
|
||||
</ListItemButton>
|
||||
<Collapse in={teamOpen} timeout="auto" unmountOnExit>
|
||||
<List disablePadding>
|
||||
{contacts.map((contact, i) => (
|
||||
<ContactItem
|
||||
contactInfo={contact}
|
||||
key={i}
|
||||
setContactSelected={props.setContactSelected}
|
||||
/>
|
||||
))}
|
||||
</List>
|
||||
</Collapse>
|
||||
</List>
|
||||
</Drawer>
|
||||
);
|
||||
};
|
||||
|
||||
export default Sidebar;
|
||||
8
src/components/contacts/Status.tsx
Normal file
8
src/components/contacts/Status.tsx
Normal file
@ -0,0 +1,8 @@
|
||||
enum Status {
|
||||
Online = "Online",
|
||||
Offline = "Offline",
|
||||
Away = "Away",
|
||||
InMeeting = "In Meeting",
|
||||
}
|
||||
|
||||
export default Status;
|
||||
70
src/components/contacts/UpperBody.tsx
Normal file
70
src/components/contacts/UpperBody.tsx
Normal file
@ -0,0 +1,70 @@
|
||||
import { Box, Button, IconButton, Typography } from "@mui/material";
|
||||
import React from "react";
|
||||
import PhoneIcon from "@mui/icons-material/Phone";
|
||||
import VideocamIcon from "@mui/icons-material/Videocam";
|
||||
import GroupsIcon from "@mui/icons-material/Groups";
|
||||
import ContactInfo from "./ContactInfo";
|
||||
|
||||
interface Props {
|
||||
contactInfo: ContactInfo;
|
||||
}
|
||||
|
||||
const UpperBody: React.FC<Props> = (props) => {
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
border: 1,
|
||||
borderRadius: 2,
|
||||
width: "70%",
|
||||
alignSelf: "center",
|
||||
mb: 2,
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-evenly",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<Typography variant="h3">{props.contactInfo.name}</Typography>
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
my: 2,
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
ml: "5%",
|
||||
}}
|
||||
>
|
||||
<IconButton sx={{ border: 1, mr: 1 }} size="large">
|
||||
<PhoneIcon fontSize="large" />
|
||||
</IconButton>
|
||||
<IconButton sx={{ border: 1, mr: 1 }} size="large">
|
||||
<VideocamIcon fontSize="large" />
|
||||
</IconButton>
|
||||
<IconButton sx={{ border: 1, mr: 1 }} size="large">
|
||||
<GroupsIcon fontSize="large" />
|
||||
</IconButton>
|
||||
<Button variant="outlined" color="success">
|
||||
Add to favorites
|
||||
</Button>
|
||||
</Box>
|
||||
<Box sx={{ display: "flex", flexDirection: "column", ml: "10%" }}>
|
||||
<Typography>{props.contactInfo.status}</Typography>
|
||||
<Typography>MeetingName-1372</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default UpperBody;
|
||||
18
src/components/contacts/Utils.tsx
Normal file
18
src/components/contacts/Utils.tsx
Normal file
@ -0,0 +1,18 @@
|
||||
import Status from "./Status";
|
||||
|
||||
const returnStatusColor = (
|
||||
status: Status
|
||||
): "success" | "disabled" | "warning" | "error" => {
|
||||
switch (status) {
|
||||
case Status.Online:
|
||||
return "success";
|
||||
case Status.Offline:
|
||||
return "disabled";
|
||||
case Status.Away:
|
||||
return "warning";
|
||||
case Status.InMeeting:
|
||||
return "error";
|
||||
}
|
||||
};
|
||||
|
||||
export { returnStatusColor };
|
||||
@ -3,7 +3,7 @@ import { AppBar, Box, IconButton, Toolbar, Typography } from "@mui/material";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
import Clock from "./Clock";
|
||||
import pngLogo from "../../assets/logo-png.png";
|
||||
import hsbcLogo from "../../assets/logo-png.png";
|
||||
import { Page } from "./Page";
|
||||
|
||||
const pages: Page[] = [
|
||||
@ -14,15 +14,18 @@ const pages: Page[] = [
|
||||
|
||||
const Navbar: React.FC = () => {
|
||||
return (
|
||||
<AppBar position="static">
|
||||
<Toolbar variant="dense" disableGutters>
|
||||
<AppBar
|
||||
position="fixed"
|
||||
sx={{ zIndex: (theme) => theme.zIndex.drawer + 1 }}
|
||||
>
|
||||
<Toolbar>
|
||||
<IconButton disableRipple sx={{ mr: 2 }}>
|
||||
<img src={pngLogo} alt="Kitty Katty!" style={{ maxWidth: 130 }} />
|
||||
<img src={hsbcLogo} alt="HSBC Logo" style={{ maxWidth: 130 }} />
|
||||
</IconButton>
|
||||
{pages.map((page, i) => (
|
||||
<Box flexGrow={i == pages.length - 1 ? 1 : 0} sx={{ mr: 3 }} key={i}>
|
||||
<Box flexGrow={i == pages.length - 1 ? 1 : 0} sx={{ mr: 4 }} key={i}>
|
||||
<Typography
|
||||
variant="h6"
|
||||
variant="h5"
|
||||
color="inherit"
|
||||
component={Link}
|
||||
to={page.url}
|
||||
|
||||
Reference in New Issue
Block a user