Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions client/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,6 @@
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# cache
.eslintcache
24 changes: 24 additions & 0 deletions client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"react": "^18.1.0",
"react-bootstrap": "^2.4.0",
"react-dom": "^18.1.0",
"react-error-boundary": "^3.1.4",
"react-photoswipe-gallery": "^2.2.1",
"react-router-dom": "^6.3.0",
"react-scripts": "5.0.1",
Expand Down
36 changes: 22 additions & 14 deletions client/src/App.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,32 @@
import { lazy, Suspense } from "react";
import { BrowserRouter, Navigate, Route, Routes } from "react-router-dom";
import Homepage from "./pages/home/Homepage";
import Activity from "./pages/activity/Activity";
import Events from "./pages/events/Events";
import Projects from "./pages/projects/Projects";
import Resources from "./pages/resources/Resources";
import { ErrorBoundary } from "react-error-boundary";
import NavigationBar from "./components/navbar/NavigationBar";

import { ErrorState, LoadingState } from "./components/states";

const Homepage = lazy(() => import("./pages/home/Homepage"));
const Activity = lazy(() => import("./pages/activity/Activity"));
const Events = lazy(() => import("./pages/events/Events"));
const Projects = lazy(() => import("./pages/projects/Projects"));
const Resources = lazy(() => import("./pages/resources/Resources"));

function App() {
return (
<BrowserRouter>
<NavigationBar />
<h1 className="text-occ_color font-bold text-2xl">CS Club</h1>
<Routes>
<Route path="/homepage" element={<Homepage />} />
<Route path="/activity" element={<Activity />} />
<Route path="/activity/events" element={<Events />} />
<Route path="/activity/projects" element={<Projects />} />
<Route path="/resources" element={<Resources />} />
<Route path="*" element={<Navigate to="/homepage" replace />} />
</Routes>
<ErrorBoundary FallbackComponent={ErrorState}>
<Suspense fallback={<LoadingState />}>
<Routes>
<Route path="/homepage" element={<Homepage />} />
<Route path="/activity" element={<Activity />} />
<Route path="/activity/events" element={<Events />} />
<Route path="/activity/projects" element={<Projects />} />
<Route path="/resources" element={<Resources />} />
<Route path="*" element={<Navigate to="/homepage" replace />} />
</Routes>
</Suspense>
</ErrorBoundary>
{/* Add Footer */}
</BrowserRouter>
);
Expand Down
28 changes: 28 additions & 0 deletions client/src/components/states/error.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import PropTypes from "prop-types";

function ErrorState({ error, resetErrorBoundary }) {
return (
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2">
<div className="m-auto flex flex-col">
<p className="text-white text-semibold text-xl mb-1">
Something went wrong:
</p>
<pre className="text-slate-50 text-md mb-2">{error.message}</pre>
<button
className="bg-occ_color text-white font-semibold rounded-md px-4 py-2 mt-4i hover:bg-amber-600 active:bg-amber-700 focus:outline-none focus:ring focus:ring-amber-600"
type="button"
onClick={resetErrorBoundary}
>
Try again
</button>
</div>
</div>
);
}

export default ErrorState;

ErrorState.propTypes = {
error: PropTypes.shape({ message: PropTypes.string.isRequired }).isRequired,
resetErrorBoundary: PropTypes.func.isRequired,
};
2 changes: 2 additions & 0 deletions client/src/components/states/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as LoadingState } from "./loading";
export { default as ErrorState } from "./error";
33 changes: 33 additions & 0 deletions client/src/components/states/loading.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import PropTypes from "prop-types";

function LoadingState({ message, animateOnly }) {
const dotCommonClasses = `h-2.5 w-2.5 bg-occ_color rounded-full`;
return (
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2">
<div className="m-auto">
<div className="flex justify-center space-x-3 mb-2">
<div className={`${dotCommonClasses} mr-1 animate-bounce`} />
<div className={`${dotCommonClasses} mr-1 animate-bounce200`} />
<div className={`${dotCommonClasses} animate-bounce400`} />
</div>
{animateOnly ? null : (
<p className="text-center text-lg text-white font-semibold">
{message}
</p>
)}
</div>
</div>
);
}

export default LoadingState;

LoadingState.defaultProps = {
message: "Loading...",
animateOnly: false,
};

LoadingState.propTypes = {
message: PropTypes.string,
animateOnly: PropTypes.bool,
};
11 changes: 8 additions & 3 deletions client/tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@
module.exports = {
content: ["./src/**/*.{js,jsx,ts,tsx}"],
theme: {
colors: {
occ_color: "#b26910",
extend: {
colors: {
occ_color: "#b26910",
},
animation: {
bounce200: "bounce 1s infinite 200ms",
bounce400: "bounce 1s infinite 400ms",
},
},
extend: {},
},
plugins: [],
};