Skip to content

Commit b4efa01

Browse files
committed
Merge branch 'dev' of https://github.com/CryptCollab/Client into dev
2 parents b9d06d9 + 2b569cb commit b4efa01

32 files changed

Lines changed: 1230 additions & 6818 deletions

package-lock.json

Lines changed: 584 additions & 6366 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
"dev": "vite",
88
"build": "tsc && vite build",
99
"preview": "vite preview",
10-
"lint": "eslint src/**/*.ts src/**/*.tsx"
10+
"lint": "eslint src/**/*.ts src/**/*.tsx",
11+
"fix": "eslint src/**/*.ts src/**/*.tsx --fix"
1112
},
1213
"dependencies": {
1314
"@emotion/react": "^11.10.6",
@@ -32,6 +33,9 @@
3233
"axios": "^1.3.3",
3334
"bootstrap": "^5.2.3",
3435
"buffer": "^6.0.3",
36+
"dayjs": "^1.11.7",
37+
"eslint-plugin-unused-imports": "^2.0.0",
38+
"formik": "^2.2.9",
3539
"html-react-parser": "^3.0.15",
3640
"js-base64": "^3.7.5",
3741
"localforage": "^1.10.0",
@@ -41,19 +45,19 @@
4145
"react-bootstrap": "^2.7.2",
4246
"react-bootstrap-typeahead": "^6.1.1",
4347
"react-dom": "^18.2.0",
48+
"react-loader-spinner": "^5.3.4",
4449
"react-icons": "^4.8.0",
4550
"react-moving-text": "^0.0.7",
46-
"react-redux": "^8.0.5",
4751
"react-router-dom": "^6.8.1",
4852
"react-router-loading": "^1.0.0",
4953
"react-top-loading-bar": "^2.3.1",
50-
"react-topbar-progress-indicator": "^4.1.1",
5154
"rollup-plugin-polyfill-node": "^0.12.0",
5255
"secure-webstore": "^1.3.6",
5356
"socket.io-client": "^4.6.1",
5457
"sodium-plus": "^0.9.0",
5558
"sort-by": "^1.2.0",
56-
"yjs": "^13.5.50"
59+
"yjs": "^13.5.50",
60+
"yup": "^1.1.1"
5761
},
5862
"devDependencies": {
5963
"@types/node": "^18.15.3",

src/App.tsx

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,52 +10,68 @@ import { CryptoUtils } from "./utils/crypto";
1010
import { socketHandlers } from "./utils/socket";
1111
import { Routes, Route } from "react-router-loading";
1212

13-
import './styles/app.css';
14-
import './styles/app.scss';
13+
import "./styles/app.css";
14+
import "./styles/app.scss";
1515
import Loader from "./components/Loader";
1616
import { useEffect, useState } from "react";
1717
import useRefreshToken from "./hooks/useRefreshToken";
18+
import { AuthContext } from "./contexts/AuthContext";
19+
import ErrorToastContainer from "./components/ErrorToastContainer";
20+
import ErrorHandlerContext from "./contexts/ErrorHandlerContext";
1821

1922
export const cryptoUtils = new CryptoUtils();
2023
export const socket = new socketHandlers(import.meta.env.VITE_SERVER_BASE_URL);
2124
export default function App() {
2225
const [loading, setLoading] = useState(true);
2326
const refresh = useRefreshToken();
27+
const [userData, setUserData] = useState<UserData | null>(null);
28+
const [errors, setErrors] = useState<string[]>([]);
2429

2530

2631
useEffect(() => {
2732
if (loading) {
28-
refresh().then(() => { setLoading(false) });
33+
refresh().then((fetchedUserData) => {
34+
setLoading(false);
35+
setUserData(fetchedUserData);
36+
});
2937
} else {
3038
setLoading(false);
3139
}
3240

33-
}, []);
41+
}, [userData]);
3442

35-
if (loading) return <Loader />
43+
if (loading) return <Loader />;
3644

3745
return (
38-
<Routes>
46+
<AuthContext.Provider value={{ userData, setUserData }}>
47+
<ErrorHandlerContext.Provider value={{ errors, setErrors }}>
48+
49+
<Routes>
3950
//Routes that do not require any authentication
40-
<Route path="/loading" element={<Loader />} />
41-
<Route path="*" element={<h1>404: Not Found</h1>} />
51+
<Route path="/loading" element={<Loader />} />
52+
<Route path="*" element={<h1>404: Not Found</h1>} />
4253

4354
//Routes that require authentication, to load parts of the page conditionally
44-
<Route path="/" element={<HomePage />} loadingScreen={<Loader />} />
55+
<Route path="/" element={<HomePage />} loadingScreen={<Loader />} />
4556

4657
//Routes that require user to NOT be logged in, to be loaded
47-
<Route element={<PrivateRoute requireUnAuthenticated />} >
48-
<Route path="/login" element={<LoginPage />} />
49-
<Route path="/register" element={<SignUpPage />} />
50-
</Route>
58+
<Route element={<PrivateRoute requireUnAuthenticated />} >
59+
<Route path="/login" element={<LoginPage />} />
60+
<Route path="/register" element={<SignUpPage />} />
61+
</Route>
5162
//Routes that require user to be logged in, to be loaded
52-
<Route element={<PrivateRoute />}>
53-
<Route path="/dashboard" element={<DashBoard />} loading />
54-
<Route path="/document" element={<Navigate to="/dashboard" replace />} loading />
55-
<Route path="/document/:id" element={<Document />} loading />
56-
</Route>
63+
<Route element={<PrivateRoute />}>
64+
<Route path="/dashboard" element={<DashBoard />} loading />
65+
<Route path="/document" element={<Navigate to="/dashboard" replace />} loading />
66+
<Route path="/document/:id" element={<Document />} loading />
67+
</Route>
68+
69+
</Routes>
70+
<ErrorToastContainer />
71+
72+
</ErrorHandlerContext.Provider >
73+
</AuthContext.Provider >
5774

58-
</Routes>
5975
);
6076
}
6177

src/app/store.ts

Lines changed: 0 additions & 12 deletions
This file was deleted.

src/components/ErrorToast.tsx

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { useEffect, useState } from "react";
2+
import Toast from "react-bootstrap/Toast";
3+
import relativeTime from "dayjs/plugin/relativeTime";
4+
import dayjs from "dayjs";
5+
6+
dayjs.extend(relativeTime);
7+
type ErrorToastProps = {
8+
error: string,
9+
index: number,
10+
closeHandler: (index: number) => void
11+
}
12+
13+
export default function ErrorToast(props: ErrorToastProps) {
14+
const [show, setShow] = useState(true);
15+
const [currentTime] = useState(Date.now());
16+
const [relativeTime, setRelativeTime] = useState(dayjs(Date.now()).fromNow());
17+
18+
//this timer is used to update the relative time every minute
19+
const [timer] = useState(
20+
setInterval(() => {
21+
setRelativeTime(dayjs(currentTime).fromNow());
22+
}, 30 * 1000)
23+
);
24+
25+
const handleClose = () => {
26+
setShow(false);
27+
props.closeHandler(props.index);
28+
};
29+
useEffect(() => {
30+
return () => {
31+
clearInterval(timer);
32+
};
33+
}, []);
34+
35+
36+
return (
37+
<Toast show={show} onClose={handleClose} >
38+
<Toast.Header>
39+
<strong className="me-auto">⚠️ Error!</strong>
40+
<small>{relativeTime}</small>
41+
</Toast.Header>
42+
<Toast.Body>{props.error}</Toast.Body>
43+
</Toast>
44+
);
45+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import ToastContainer from "react-bootstrap/ToastContainer";
2+
import styles from "../styles/error-toast.module.css";
3+
import useErrorHandler from "../hooks/useErrorHandler";
4+
import ErrorToast from "./ErrorToast";
5+
6+
7+
8+
export default function ErrorToastContainer() {
9+
const handler = useErrorHandler();
10+
const closeHandler = (index: number) => {
11+
//FIXME multiple are being removed
12+
handler.errors.splice(index, 1);
13+
//Copying array to mutate the state
14+
handler.setErrors([...handler.errors]);
15+
console.log(handler.errors);
16+
};
17+
18+
return (
19+
<ToastContainer position="bottom-start" className={styles.container}>
20+
{handler.errors.map((error, index) =>
21+
<ErrorToast error={error} key={index} index={index} closeHandler={closeHandler} />
22+
)}
23+
</ToastContainer >
24+
);
25+
}

src/components/Loader.tsx

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
import { useEffect, useRef } from "react";
2-
import styles from "../styles/loader.module.css"
3-
import { LoadingBarRef } from 'react-top-loading-bar'
2+
import styles from "../styles/loader.module.css";
3+
import { LoadingBarRef } from "react-top-loading-bar";
44
export default function Loader() {
5-
const ref: React.Ref<LoadingBarRef> = useRef(null)
6-
useEffect(() => {
7-
ref.current?.continuousStart();
8-
return () => {
9-
ref.current?.complete();
10-
}
11-
}, [])
5+
const ref: React.Ref<LoadingBarRef> = useRef(null);
6+
useEffect(() => {
7+
ref.current?.continuousStart();
8+
return () => {
9+
ref.current?.complete();
10+
};
11+
}, []);
1212

1313

14-
return (
15-
<div className={styles.root}>
16-
<object data="loader.svg" type="image/svg+xml" />
17-
</div>
18-
)
14+
return (
15+
<div className={styles.root}>
16+
<object data="loader.svg" type="image/svg+xml" />
17+
</div>
18+
);
1919

2020
}

src/components/Navigationbar.tsx

Lines changed: 47 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,20 @@ import { useNavigate } from "react-router-dom";
22
import useAuth from "../hooks/useAuth";
33
import useAxios from "../hooks/useAxios";
44
import { Link } from "react-router-dom";
5-
import Container from 'react-bootstrap/Container';
6-
import Nav from 'react-bootstrap/Nav';
7-
import Navbar from 'react-bootstrap/Navbar';
8-
import Button from 'react-bootstrap/Button';
5+
import Container from "react-bootstrap/Container";
6+
import Nav from "react-bootstrap/Nav";
7+
import Navbar from "react-bootstrap/Navbar";
8+
import Button from "react-bootstrap/Button";
99

1010

1111
export default function Navigationbar() {
12-
const user = useAuth();
12+
const auth = useAuth();
1313
const navigate = useNavigate();
1414
const axios = useAxios();
1515
const handleLogout = async () => {
1616
try {
1717
await axios.get("/api/logout");
18-
user.logoutUser();
18+
auth.logoutUser();
1919
navigate("/");
2020
}
2121
catch (error) {
@@ -25,61 +25,63 @@ export default function Navigationbar() {
2525
};
2626

2727
const linkStyle = {
28-
margin: "1rem",
29-
textDecoration: "none",
30-
color: 'white'
28+
margin: "1rem",
29+
textDecoration: "none",
30+
color: "white"
3131
};
3232

33-
if (user.isUserLoggedIn()) {
34-
return (
33+
if (auth.isUserLoggedIn()) {
34+
return (
3535
<Navbar bg="dark" variant="dark" expand="lg">
36-
<Container>
37-
<Navbar.Brand href="#home">
38-
<img style={{objectFit:"contain"}}
39-
src="/logo_50_dark.png"
40-
width="auto"
41-
height="auto"
42-
/>{' '}
36+
<Container>
37+
<Navbar.Brand href="#home">
38+
<img style={{ objectFit: "contain" }}
39+
src="/logo_50_dark.png"
40+
width="auto"
41+
height="auto"
42+
/>{" "}
4343
CryptCollab
4444
</Navbar.Brand>
4545
<Navbar.Toggle aria-controls="basic-navbar-nav" />
46-
<Navbar.Collapse id="basic-navbar-nav">
47-
<Nav className="ms-auto">
48-
<Link to="/dashboard" style={linkStyle}>Dashboard</Link>
49-
<Link to="/document" style={linkStyle}>Document</Link>
50-
<Button onClick={handleLogout} variant="link"
51-
style={{textDecoration: "none",
52-
color: 'white'}}>
53-
Logout
46+
<Navbar.Collapse id="basic-navbar-nav">
47+
<Nav className="ms-auto">
48+
<Link to="/dashboard" style={linkStyle}>Dashboard</Link>
49+
<Link to="/document" style={linkStyle}>Document</Link>
50+
<Button onClick={handleLogout} variant="link"
51+
style={{
52+
textDecoration: "none",
53+
color: "white"
54+
}}>
55+
Logout
5456
</Button>
55-
</Nav>
57+
</Nav>
5658
</Navbar.Collapse>
57-
</Container>
58-
</Navbar>
59+
</Container>
60+
</Navbar>
5961
);
6062
}
6163
else {
62-
return (
64+
return (
6365
<Navbar bg="dark" variant="dark" expand="lg">
64-
<Container>
65-
<Navbar.Brand href="#home">
66-
<img style={{objectFit:"contain"}}
67-
src="/logo_50_dark.png"
68-
width="auto"
69-
height="40"
70-
71-
/>{' '}
66+
<Container>
67+
<Navbar.Brand href="#home">
68+
<img style={{ objectFit: "contain" }}
69+
src="/logo_50_dark.png"
70+
width="auto"
71+
height="40"
72+
73+
/>{" "}
7274
CryptCollab
7375
</Navbar.Brand>
7476
<Navbar.Toggle aria-controls="basic-navbar-nav" />
75-
<Navbar.Collapse id="basic-navbar-nav">
76-
<Nav className="ms-auto">
77-
<Link to="/login" style={linkStyle}>Login</Link>
78-
<Link to="/register" style={linkStyle}>Register</Link>
79-
</Nav>
77+
<Navbar.Collapse id="basic-navbar-nav">
78+
<Nav className="ms-auto">
79+
<Link to="/login" style={linkStyle}>Login</Link>
80+
<Link to="/register" style={linkStyle}>Register</Link>
81+
</Nav>
8082
</Navbar.Collapse>
81-
</Container>
82-
</Navbar>
83+
</Container>
84+
</Navbar>
8385
);
8486
}
8587

src/components/PrivateRoute.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ const PrivateRoute: React.FC<PrivateRouteProps> = ({ requireUnAuthenticated })
2222

2323
return (outletLogic)
2424
? <Outlet />
25-
: <Navigate to={(auth.isUserLoggedIn()) ? "/dashboard" : "/login"} state={{ redirectURL: location.pathname }} replace />
25+
: <Navigate to={(auth.isUserLoggedIn()) ? "/dashboard" : "/login"} state={{ redirectURL: location.pathname }} replace />;
2626

2727

2828
};

0 commit comments

Comments
 (0)