commit
10e010c642
@ -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
12
src/ProtectedRoute.tsx
Normal 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
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
1
src/assets/zoom.svg
Normal 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 |
@ -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>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
15
src/context/AuthProvider.tsx
Normal file
15
src/context/AuthProvider.tsx
Normal 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
8
src/hooks/useAuth.tsx
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { useContext } from "react";
|
||||||
|
import AuthContext from "../context/AuthProvider";
|
||||||
|
|
||||||
|
const useAuth = () => {
|
||||||
|
return useContext(AuthContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useAuth;
|
||||||
@ -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"));
|
||||||
|
|||||||
@ -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 */
|
||||||
@ -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",
|
||||||
|
|||||||
@ -44,3 +44,7 @@
|
|||||||
|
|
||||||
.full-width
|
.full-width
|
||||||
width: 100%
|
width: 100%
|
||||||
|
|
||||||
|
a
|
||||||
|
text-decoration: none
|
||||||
|
|
||||||
@ -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%
|
||||||
Reference in New Issue
Block a user