Merge pull request #12 from CPSC319-Winter-term-2/cochrane

Cochrane
This commit is contained in:
Jincheng Lu 2022-03-11 12:37:55 -08:00 committed by GitHub
commit 10e010c642
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 195 additions and 13 deletions

View File

@ -2,11 +2,13 @@ import React, { useState } from "react";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import "./styles.css"; import "./styles.css";
import Login from "./components/login/Login";
import Home from "./components/home/Home"; import Home from "./components/home/Home";
import Contacts from "./components/contacts/Contacts"; import Contacts from "./components/contacts/Contacts";
import Calendar from "./components/calendar/Calendar"; import Calendar from "./components/calendar/Calendar";
import Navbar from "./components/navbar/Navbar"; import Navbar from "./components/navbar/Navbar";
import { ThemeProvider } from "@emotion/react"; import { ThemeProvider } from "@emotion/react";
import ProtectedRoute from "./ProtectedRoute";
import Theme from "./Theme"; import Theme from "./Theme";
@ -54,12 +56,15 @@ const App: React.FC = () => {
<Box id="drawer-container" sx={{ display: "flex", height: "100%" }}> <Box id="drawer-container" sx={{ display: "flex", height: "100%" }}>
<Box sx={{ flexGrow: 1 }}> <Box sx={{ flexGrow: 1 }}>
<Routes> <Routes>
<Route path="/login" element={<Login />} />
<Route element={<ProtectedRoute />}>
<Route path="/" element={<Home />} /> <Route path="/" element={<Home />} />
<Route <Route
path="/contacts" path="/contacts"
element={<Contacts setMeetingInfoOpen={setMeetingInfoOpen} />} element={<Contacts setMeetingInfoOpen={setMeetingInfoOpen} />}
/> />
<Route path="/calendar" element={<Calendar />} /> <Route path="/calendar" element={<Calendar />} />
</Route>
</Routes> </Routes>
</Box> </Box>
<Box> <Box>

12
src/ProtectedRoute.tsx Normal file
View File

@ -0,0 +1,12 @@
import { useLocation, Outlet, Navigate } from "react-router-dom";
import useAuth from "./hooks/useAuth";
const ProtectedRoute = () => {
const { auth }: any = useAuth();
const location = useLocation();
return (
auth?.isLoggedIn ? <Outlet /> : <Navigate to="/login" state={{ from: location }} replace />
);
}
export default ProtectedRoute;

BIN
src/assets/zoom.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

1
src/assets/zoom.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1329.08 1329.08" shape-rendering="geometricPrecision" text-rendering="geometricPrecision" image-rendering="optimizeQuality" fill-rule="evenodd" clip-rule="evenodd"><defs><style>.fil1{fill:#fff;fill-rule:nonzero}</style></defs><g id="Layer_x0020_1"><g id="_2116467169744"><path d="M664.54 0c367.02 0 664.54 297.52 664.54 664.54s-297.52 664.54-664.54 664.54S0 1031.56 0 664.54 297.52 0 664.54 0z" fill="#e5e5e4" fill-rule="nonzero"/><path class="fil1" d="M664.54 12.94c359.87 0 651.6 291.73 651.6 651.6s-291.73 651.6-651.6 651.6-651.6-291.73-651.6-651.6 291.74-651.6 651.6-651.6z"/><path d="M664.54 65.21c331 0 599.33 268.33 599.33 599.33 0 331-268.33 599.33-599.33 599.33-331 0-599.33-268.33-599.33-599.33 0-331 268.33-599.33 599.33-599.33z" fill="#4a8cff" fill-rule="nonzero"/><path class="fil1" d="M273.53 476.77v281.65c.25 63.69 52.27 114.95 115.71 114.69h410.55c11.67 0 21.06-9.39 21.06-20.81V570.65c-.25-63.69-52.27-114.95-115.7-114.69H294.6c-11.67 0-21.06 9.39-21.06 20.81zm573.45 109.87l169.5-123.82c14.72-12.18 26.13-9.14 26.13 12.94v377.56c0 25.12-13.96 22.08-26.13 12.94l-169.5-123.57V586.64z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1,6 +1,7 @@
interface Props { interface Props {
meetingName: string; meetingName: string;
meetingTime: string; meetingTime: string;
meetingMembers: string
} }
function Meeting(props: Props) { function Meeting(props: Props) {
@ -13,6 +14,9 @@ function Meeting(props: Props) {
<div className="row"> <div className="row">
<label>{props.meetingTime}</label> <label>{props.meetingTime}</label>
</div> </div>
<div className="row">
<label>{props.meetingMembers}</label>
</div>
</div> </div>
</div> </div>
); );

View File

@ -10,8 +10,8 @@ const MeetingsPanel: React.FC = () => {
<label>Sunday, 03 Feb 2022</label> <label>Sunday, 03 Feb 2022</label>
</div> </div>
<Meeting meetingName="first meeting" meetingTime="time" /> <Meeting meetingName="meeting" meetingTime="0800-1200" meetingMembers="" />
<Meeting meetingName="second meeting" meetingTime="time" /> <Meeting meetingName="meeting" meetingTime="0830-1100" meetingMembers="" />
</div> </div>
); );
}; };

View File

@ -1,9 +1,64 @@
import { useRef, useState, useEffect, useContext } from "react";
import { useLocation, Link, useNavigate } from "react-router-dom";
import { Stack } from "@mui/material";
import Container from "@mui/material/Container"; import Container from "@mui/material/Container";
import TextField from "@mui/material/TextField";
import Button from "@mui/material/Button";
import hsbcLogo from "../../assets/logo-png.png";
import zoomLogo from "../../assets/zoom.png";
import LoginIcon from "@mui/icons-material/Login";
import useAuth from "../../hooks/useAuth";
const Login: React.FC = () => { const Login: React.FC = () => {
const { setAuth }: any = useAuth();
const navigate = useNavigate();
const location: any = useLocation();
const from = location.state?.from?.pathname || "/";
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
// const [errMsg, setErrMsg] = useState('');
// const userRef = useRef();
// const errRef = useRef();
// useEffect(() => {
// userRef.current.focus();
// }, [])
// useEffect(() => {
// setErrMsg('');
// }, [user, pwd])
const handleLogin = () => {
if (username === "" && password === "") {
setAuth({username: username, isLoggedIn: true});
navigate(from, {replace: true});
}
setUsername("");
setPassword("");
};
return ( return (
<Container className="login"> <Container className="login">
Login <Stack className="grid-container" spacing={2}>
<img className="login-logo" src={hsbcLogo} alt="HSBC Logo"/>
{/* <p ref={errRef} className={errMsg ? "errmsg" : "offscreen"} aria-live="assertive">{errMsg}</p> */}
<TextField className="username-input" id="outlined-basic" label="Username" variant="outlined" placeholder="Username" onChange={(event) => {setUsername(event.target.value)}}/>
<TextField className="password-input" id="outlined-basic" label="Password" variant="outlined" placeholder="Password" type="password" onChange={(event) => {setPassword(event.target.value)}}/>
<Stack direction="row" justifyContent="space-between" spacing={2}>
<a className="register-btn" href="#">Forgotten Your Password?</a>
<Button endIcon={<LoginIcon />} className="login-btn" variant="contained" type="submit" onClick={handleLogin}>Login</Button>
</Stack>
<Stack direction="row" justifyContent="space-between" spacing={2}>
<label>Login with</label>
<a className="zoom-logo" href="#">
<img src={zoomLogo} alt="Zoom Logo"/>
</a>
</Stack>
</Stack>
</Container> </Container>
); );
}; };

View File

@ -0,0 +1,15 @@
import { createContext, useState } from "react";
const AuthContext = createContext({});
export const AuthProvider = ({ children }: {children: any}) => {
const [auth, setAuth] = useState({});
return (
<AuthContext.Provider value={{ auth, setAuth }}>
{children}
</AuthContext.Provider>
)
}
export default AuthContext;

8
src/hooks/useAuth.tsx Normal file
View File

@ -0,0 +1,8 @@
import { useContext } from "react";
import AuthContext from "../context/AuthProvider";
const useAuth = () => {
return useContext(AuthContext);
}
export default useAuth;

View File

@ -1,8 +1,14 @@
import ReactDOM from "react-dom"; import ReactDOM from "react-dom";
import App from "./App"; import App from "./App";
import "./style/App.css";
import { AuthProvider } from './context/AuthProvider';
const Index:React.FC = () => { const Index:React.FC = () => {
return <App />; return (
<AuthProvider>
<App />
</AuthProvider>
);
}; };
ReactDOM.render(<Index />, document.getElementById("root")); ReactDOM.render(<Index />, document.getElementById("root"));

View File

@ -2,6 +2,10 @@
width: 100%; width: 100%;
} }
a {
text-decoration: none;
}
.main-home { .main-home {
max-width: 85% !important; max-width: 85% !important;
} }
@ -69,4 +73,46 @@
width: 70%; width: 70%;
height: 70%; height: 70%;
} }
.login .grid-container {
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
margin: auto;
margin-top: 20%;
max-width: 40% !important;
}
.login .grid-container > * {
width: 98%;
margin: 0.5% 0;
}
.login .grid-container .login-logo {
display: inline-block;
text-align: center;
margin: 5% 0;
}
.login .grid-container .login-btn {
margin: 5% 0;
width: 40%;
background-color: #ed7f88;
}
.login .grid-container .register-btn {
display: inline-block;
text-align: left;
margin: 5% 0;
padding-top: 1rem;
}
.login .grid-container .zoom-logo {
width: 40px;
height: 40px;
}
.login .grid-container .zoom-logo * {
width: 100%;
}
/*# sourceMappingURL=App.css.map */ /*# sourceMappingURL=App.css.map */

View File

@ -1,6 +1,6 @@
{ {
"version": 3, "version": 3,
"mappings": "AG4CA,AAAA,WAAW,CAAC;EACR,KAAK,EAAE,IAAI;CAAG;;AK7ClB,AAAA,UAAU,CAAC;EAGP,SAAS,EAAE,cAAc;CA6CO;;AAhDpC,AAII,UAJM,CAIN,eAAe,CAAC;EACZ,MAAM,EAAE,IAAI;EACZ,UAAU,EAAE,IAAI;EAChB,YAAY,EAAE,KAAK;EACnB,YAAY,EPRS,OAAO;EOS5B,YAAY,EAAE,GAAG;EACjB,aAAa,EAAE,IAAI;EACnB,KAAK,EAAE,GAAG;EACV,MAAM,EAAE,IAAI;EACZ,QAAQ,EAAE,MAAM;CAgBO;;AA7B/B,AAcQ,UAdE,CAIN,eAAe,CAUX,IAAI,CAAC;EACD,KAAK,EAAE,IAAI;CAAG;;AAf1B,AAgBQ,UAhBE,CAIN,eAAe,CAYX,aAAa,CAAC;EACV,UAAU,EAAE,MAAM;EAClB,gBAAgB,EAAE,IAAI;EACtB,WAAW,EAAE,EAAE;EACf,cAAc,EAAE,EAAE;CAAG;;AApBjC,AAqBQ,UArBE,CAIN,eAAe,CAiBX,aAAa,CAAC;EACV,UAAU,EAAE,MAAM;EAClB,gBAAgB,EAAE,IAAI;EACtB,cAAc,EAAE,EAAE;CAAG;;AAxBjC,AAyBQ,UAzBE,CAIN,eAAe,CAqBX,QAAQ,CAAC;EACL,gBAAgB,EP1BC,OAAO;EO2BxB,UAAU,EAAE,MAAM;EAClB,UAAU,EAAE,IAAI;EAChB,WAAW,EAAE,CAAC;CAAG;;AA7B7B,AA+BQ,UA/BE,CA8BN,WAAW,CACP,MAAM,CAAC;EACH,UAAU,EAAE,IAAI;CAAG;;AAhC/B,AAiCQ,UAjCE,CA8BN,WAAW,CAGP,MAAM,CAAC;EACH,UAAU,EAAE,GAAG;CAAG;;AAlC9B,AAmCQ,UAnCE,CA8BN,WAAW,CAKP,KAAK,CAAC;EACF,OAAO,EAAE,YAAY;EACrB,KAAK,EAAE,KAAK;EACZ,UAAU,EAAE,MAAM;CAAG;;AAtCjC,AAuCQ,UAvCE,CA8BN,WAAW,CASP,KAAK,CAAC;EACF,YAAY,EAAE,IAAI;EAClB,gBAAgB,EPzCC,OAAO;EO0CxB,KAAK,EAAE,KAAK;EACZ,MAAM,EAAE,KAAK;EACb,aAAa,EAAE,IAAI;CAIC;;AAhDhC,AA6CY,UA7CF,CA8BN,WAAW,CASP,KAAK,CAMD,KAAK,CAAC;EACF,KAAK,EAAE,KAAK;EACZ,KAAK,EAAE,GAAG;EACV,MAAM,EAAE,GAAG;CAAG", "mappings": "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",
"sources": [ "sources": [
"App.sass", "App.sass",
"_variables.sass", "_variables.sass",

View File

@ -44,3 +44,7 @@
.full-width .full-width
width: 100% width: 100%
a
text-decoration: none

View File

@ -1 +1,27 @@
.login .login
.grid-container
align-items: center
margin: auto
margin-top: 20%
max-width: 40% !important
> *
width: 98%
margin: 0.5% 0
.login-logo
display: inline-block
text-align: center
margin: 5% 0
.login-btn,
margin: 5% 0
width: 40%
background-color: #ed7f88
.register-btn
display: inline-block
text-align: left
margin: 5% 0
padding-top: 1rem
.zoom-logo
width: 40px
height: 40px
*
width: 100%