Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions client/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ yarn.lock
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.env*
1,106 changes: 1,104 additions & 2 deletions client/package-lock.json

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
"@types/node": "^12.0.0",
"@types/qs": "^6.9.6",
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
"@types/react-router-dom": "^5.1.7",
"@types/react-router-dom": "^5.1.8",
"@types/react-table": "^7.7.1",
"axios": "^0.21.1",
"d3": "^6.7.0",
"firebase": "^8.8.1",
"match-sorter": "^6.3.0",
"qs": "^6.10.1",
"react": "^17.0.2",
Expand Down Expand Up @@ -47,6 +47,7 @@
]
},
"devDependencies": {
"@types/react-dom": "^17.0.9",
"@typescript-eslint/eslint-plugin": "^4.28.5",
"@typescript-eslint/parser": "^4.28.5",
"eslint": "^7.32.0",
Expand Down
35 changes: 24 additions & 11 deletions client/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import React from "react";
import { BrowserRouter as Router, Route } from "react-router-dom";
import { AuthProvider } from "./context/AuthContext";
import { AlertProvider } from "./context/AlertContext";
import Home from "./pages/Home";
import Alert from "./components/Alert";
import NavBar from "./components/NavBar";
import SampleView from "./pages/RLoop";
import SearchPage from "./pages/SearchPage";
Expand All @@ -9,20 +12,30 @@ import ApiReference from "./pages/ApiReference";
import Downloads from "./pages/Downloads";
import Help from "./pages/Help";
import Upload from "./pages/Upload";
import Signup from "./pages/Signup";
import Login from "./pages/Login";
import ProtectedRoute from "./components/ProtectedRoute";

function App() {
return (
<Router>
<Route path="/" component={NavBar} />
<Route exact path="/" component={Home} />
<Route exact path="/search/:type" component={SearchPage} />
<Route exact path="/explorer" component={SampleView} />
<Route exact path="/about" component={About} />
<Route exact path="/api-reference" component={ApiReference} />
<Route exact path="/downloads" component={Downloads} />
<Route exact path="/upload" component={Upload} />
<Route exact path="/help" component={Help} />
</Router>
<AlertProvider>
<AuthProvider>
<Route path="/" component={NavBar} />
<Router>
<Route path="/" component={Alert} />
<Route exact path="/" component={Home} />
<Route exact path="/search/:type" component={SearchPage} />
<Route exact path="/explorer" component={SampleView} />
<Route exact path="/about" component={About} />
<Route exact path="/api-reference" component={ApiReference} />
<Route exact path="/downloads" component={Downloads} />
<ProtectedRoute path="/upload" component={Upload} />
<Route exact path="/help" component={Help} />
<Route exact path="/signup" component={Signup} />
<Route exact path="/login" component={Login} />
</Router>
</AuthProvider>
</AlertProvider>
);
}

Expand Down
Binary file added client/src/assets/GithubLogo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added client/src/assets/GoogleLogo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 changes: 29 additions & 0 deletions client/src/components/Alert/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React, { useEffect } from "react";
import { useAlert } from "../../context/AlertContext";
import { useAuth } from "../../context/AuthContext";

export default function Alert() {
const { alert, setAlert } = useAlert();
const { currentUser, isVerified } = useAuth();

useEffect(() => {
if (currentUser && !isVerified()) {
setAlert({
type: "info",
message: "Your account is unverified. Check your email for a verification link.",
});
} else {
setAlert(null);
}
}, [currentUser]);

if (alert) {
return (
<div className={`container mt-2 alert alert-${alert.type}`} role="alert">
<p className="m-0 text-center">{alert.message}</p>
</div>
);
}

return null;
}
120 changes: 83 additions & 37 deletions client/src/components/NavBar/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,25 @@
import React from "react";
import { Link } from "react-router-dom";
import { Link, useHistory } from "react-router-dom";
import { useAuth } from "../../context/AuthContext";
import { useAlert } from "../../context/AlertContext";

const NavBar = () => {
const { currentUser, isVerified, logout } = useAuth();
const { setAlert } = useAlert();

const history = useHistory();

async function handleLogout(e: React.FormEvent) {
e.preventDefault();
try {
await logout();
setAlert(null);
history.push("/");
} catch (err) {
setAlert({ type: "danger", message: "Failed to sign out. Please try again." });
}
}

return (
<nav className="navbar navbar-expand-lg navbar-dark bg-dark">
<button
Expand All @@ -16,42 +34,70 @@ const NavBar = () => {
<span className="navbar-toggler-icon" />
</button>
<div className="collapse navbar-collapse" id="navbarNav">
<ul className="navbar-nav">
<li className="nav-item">
<Link to="/" className="nav-link">
RMapDB
</Link>
</li>
<li className="nav-item">
<Link to="/about" className="nav-link">
About
</Link>
</li>
<li className="nav-item">
<Link to="/search/sample" className="nav-link">
Samples
</Link>
</li>
<li className="nav-item">
<Link to="/downloads" className="nav-link">
Download
</Link>
</li>
<li className="nav-item">
<Link to="/upload" className="nav-link">
Upload
</Link>
</li>
<li className="nav-item">
<Link to="/api-reference" className="nav-link">
API Reference
</Link>
</li>
<li className="nav-item">
<Link to="/help" className="nav-link">
Help
</Link>
</li>
<ul className="container navbar-nav d-flex justify-content-between">
<span className="d-flex">
<li className="nav-item me-1">
<Link to="/" className="nav-link">
RMapDB
</Link>
</li>
<li className="nav-item me-1">
<Link to="/about" className="nav-link">
About
</Link>
</li>
<li className="nav-item me-1">
<Link to="/search/sample" className="nav-link">
Samples
</Link>
</li>
<li className="nav-item me-1">
<Link to="/downloads" className="nav-link">
Download
</Link>
</li>
{isVerified() && (
<li className="nav-item me-1">
<Link to="/upload" className="nav-link">
Upload
</Link>
</li>
)}
<li className="nav-item me-1">
<Link to="/api-reference" className="nav-link">
API Reference
</Link>
</li>
<li className="nav-item">
<Link to="/help" className="nav-link">
Help
</Link>
</li>
</span>
{currentUser ? (
<li className="nav-item">
<button
type="button"
className="nav-link btn btn-dark border border-light rounded"
onClick={handleLogout}
>
Log Out
</button>
</li>
) : (
<span className="d-flex">
<li className="nav-item me-1">
<Link to="/login" className="nav-link">
Log In
</Link>
</li>
<li className="nav-item">
<Link to="/signup" className="nav-link border border-light rounded">
Sign Up
</Link>
</li>
</span>
)}
</ul>
</div>
</nav>
Expand Down
15 changes: 15 additions & 0 deletions client/src/components/ProtectedRoute/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from "react";
import { Route, Redirect } from "react-router-dom";
import { useAuth } from "../../context/AuthContext";

export default function ProtectedRoute({
path,
component: Component,
}: {
path: string;
component: React.FC;
}): JSX.Element {
const { currentUser } = useAuth();

return <Route path={path}>{!currentUser ? <Redirect to="/" /> : <Component />}</Route>;
}
15 changes: 15 additions & 0 deletions client/src/components/SigninButton/index.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.signInButton {
padding: 0.5em;
display: flex;
align-items: center;
justify-content: center;
}

.signInButton:hover {
background-image: linear-gradient(white, #f8f9fa)
}

.signInLogo {
height: 1.5em;
padding-right: 0.5em;
}
43 changes: 43 additions & 0 deletions client/src/components/SigninButton/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from "react";
import { useHistory } from "react-router-dom";
import firebase from "firebase";
import styles from "./index.module.css";

export default function SignInButton({
provider,
logo,
handleSignIn,
setError,
}: {
provider: string;
logo: string;
handleSignIn: () => Promise<firebase.auth.UserCredential>;
setError: (error: string) => void;
}): JSX.Element {
const history = useHistory();

const handleSigninWithProvider = async (
e: React.FormEvent,
signInFunction: () => Promise<firebase.auth.UserCredential>
) => {
e.preventDefault();
try {
setError("");
await signInFunction();
history.push("/");
} catch (err) {
setError(err.message);
}
};

return (
<button
type="button"
className={`btn border border-secondary mb-3 ${styles.signInButton}`}
onClick={(e) => handleSigninWithProvider(e, handleSignIn)}
>
<img src={logo} alt={provider} className={styles.signInLogo} />
Sign in with {provider}
</button>
);
}
27 changes: 27 additions & 0 deletions client/src/context/AlertContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React, { useContext, useState } from "react";

interface Alert {
message: string;
type: "success" | "danger" | "info"; // matches bootstrap alert types
}
interface AlertContextInterface {
alert: Alert | null;
setAlert: (alert: Alert | null) => void;
}

const AlertContext = React.createContext<AlertContextInterface>({} as AlertContextInterface);

export function useAlert(): AlertContextInterface {
return useContext(AlertContext);
}

export function AlertProvider({ children }: { children: JSX.Element }): JSX.Element {
const [alert, setAlert] = useState<Alert | null>(null);

const value: AlertContextInterface = {
alert,
setAlert,
};

return <AlertContext.Provider value={value}>{children}</AlertContext.Provider>;
}
Loading