mirror of
https://github.com/rowyio/rowy.git
synced 2025-12-29 00:16:39 +01:00
add auth redirect, public 404 page
This commit is contained in:
49
src/App.tsx
49
src/App.tsx
@@ -1,16 +1,14 @@
|
||||
import { lazy, Suspense } from "react";
|
||||
import { Route, Switch, Link, Redirect } from "react-router-dom";
|
||||
import { Route, Switch, Redirect } from "react-router-dom";
|
||||
import LocalizationProvider from "@mui/lab/LocalizationProvider";
|
||||
import AdapterDateFns from "@mui/lab/AdapterDateFns";
|
||||
|
||||
import { StyledEngineProvider } from "@mui/material/styles";
|
||||
import { Button } from "@mui/material";
|
||||
import "./space-grotesk.css";
|
||||
|
||||
import CustomBrowserRouter from "utils/CustomBrowserRouter";
|
||||
import PrivateRoute from "utils/PrivateRoute";
|
||||
import ErrorBoundary from "components/ErrorBoundary";
|
||||
import EmptyState from "components/EmptyState";
|
||||
import Loading from "components/Loading";
|
||||
import Navigation from "components/Navigation";
|
||||
import Logo from "assets/Logo";
|
||||
@@ -22,10 +20,11 @@ import { SnackbarProvider } from "contexts/SnackbarContext";
|
||||
import { SnackLogProvider } from "contexts/SnackLogContext";
|
||||
import routes from "constants/routes";
|
||||
|
||||
import AuthView from "pages/Auth";
|
||||
import SignOutView from "pages/Auth/SignOut";
|
||||
import TestView from "pages/Test";
|
||||
import RowyRunTestView from "pages/RowyRunTest";
|
||||
import AuthPage from "pages/Auth";
|
||||
import SignOutPage from "pages/Auth/SignOut";
|
||||
import TestPage from "pages/Test";
|
||||
import RowyRunTestPage from "pages/RowyRunTest";
|
||||
import PageNotFound from "pages/PageNotFound";
|
||||
|
||||
import Favicon from "assets/Favicon";
|
||||
import "analytics";
|
||||
@@ -67,7 +66,7 @@ export default function App() {
|
||||
<Route
|
||||
exact
|
||||
path={routes.auth}
|
||||
render={() => <AuthView />}
|
||||
render={() => <AuthPage />}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
@@ -82,7 +81,7 @@ export default function App() {
|
||||
<Route
|
||||
exact
|
||||
path={routes.signOut}
|
||||
render={() => <SignOutView />}
|
||||
render={() => <SignOutPage />}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
@@ -93,7 +92,7 @@ export default function App() {
|
||||
<Route
|
||||
exact
|
||||
path={"/test"}
|
||||
render={() => <TestView />}
|
||||
render={() => <TestPage />}
|
||||
/>
|
||||
|
||||
<PrivateRoute
|
||||
@@ -120,7 +119,7 @@ export default function App() {
|
||||
<Route
|
||||
exact
|
||||
path={routes.rowyRunTest}
|
||||
render={() => <RowyRunTestView />}
|
||||
render={() => <RowyRunTestPage />}
|
||||
/>
|
||||
<PrivateRoute
|
||||
exact
|
||||
@@ -189,30 +188,12 @@ export default function App() {
|
||||
)}
|
||||
/>
|
||||
|
||||
<PrivateRoute
|
||||
render={() => (
|
||||
<Navigation
|
||||
title="Page Not Found"
|
||||
titleComponent={<div />}
|
||||
>
|
||||
<EmptyState
|
||||
message="Page Not Found"
|
||||
description={
|
||||
<Button
|
||||
component={Link}
|
||||
to={routes.home}
|
||||
variant="outlined"
|
||||
style={{ marginTop: 8 }}
|
||||
>
|
||||
Go Home
|
||||
</Button>
|
||||
}
|
||||
fullScreen
|
||||
style={{ marginTop: -64 }}
|
||||
/>
|
||||
</Navigation>
|
||||
)}
|
||||
<Route
|
||||
exact
|
||||
path={routes.pageNotFound}
|
||||
render={() => <PageNotFound />}
|
||||
/>
|
||||
<Route render={() => <PageNotFound />} />
|
||||
</Switch>
|
||||
</Suspense>
|
||||
</CustomBrowserRouter>
|
||||
|
||||
@@ -6,6 +6,7 @@ export enum routes {
|
||||
signOut = "/signOut",
|
||||
authSetup = "/authSetup",
|
||||
setup = "/setup",
|
||||
pageNotFound = "/404",
|
||||
|
||||
table = "/table",
|
||||
tableWithId = "/table/:id",
|
||||
|
||||
@@ -24,6 +24,7 @@ export const projectId = process.env.REACT_APP_FIREBASE_PROJECT_ID!;
|
||||
export const WEBHOOK_URL = `https://${(functions as any).region_}-${
|
||||
appConfig.projectId
|
||||
}.cloudfunctions.net/webhook`;
|
||||
|
||||
export const googleProvider =
|
||||
new firebase.auth.GoogleAuthProvider().setCustomParameters({
|
||||
prompt: "select_account",
|
||||
|
||||
@@ -49,7 +49,7 @@ export default function ImpersonatorAuthPage() {
|
||||
return (
|
||||
<AuthLayout loading={loading}>
|
||||
<div>
|
||||
<Typography variant="h6" component="h2" gutterBottom>
|
||||
<Typography variant="h6" component="h1" gutterBottom>
|
||||
Admin Authentication
|
||||
</Typography>
|
||||
<Typography gutterBottom>
|
||||
|
||||
@@ -28,7 +28,7 @@ export default function JwtAuthPage() {
|
||||
|
||||
return (
|
||||
<AuthLayout loading={loading}>
|
||||
<Typography variant="h6" component="h2">
|
||||
<Typography variant="h6" component="h1">
|
||||
Test Authentication
|
||||
</Typography>
|
||||
|
||||
|
||||
@@ -18,13 +18,7 @@ export default function SignOutPage() {
|
||||
<EmptyState
|
||||
message="Signed Out"
|
||||
description={
|
||||
<Button
|
||||
component={Link}
|
||||
to="/auth"
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
style={{ marginTop: 24 }}
|
||||
>
|
||||
<Button component={Link} to="/auth" variant="outlined" sx={{ mt: 3 }}>
|
||||
Sign In Again
|
||||
</Button>
|
||||
}
|
||||
|
||||
@@ -1,10 +1,21 @@
|
||||
import { useLocation } from "react-router-dom";
|
||||
import queryString from "query-string";
|
||||
|
||||
import AuthLayout from "components/Auth/AuthLayout";
|
||||
import FirebaseUi from "components/Auth/FirebaseUi";
|
||||
|
||||
export default function AuthPage() {
|
||||
const { search } = useLocation();
|
||||
const parsed = queryString.parse(search);
|
||||
|
||||
const uiConfig: firebaseui.auth.Config = {};
|
||||
if (typeof parsed.redirect === "string" && parsed.redirect.length > 0) {
|
||||
uiConfig.signInSuccessUrl = parsed.redirect;
|
||||
}
|
||||
|
||||
return (
|
||||
<AuthLayout>
|
||||
<FirebaseUi />
|
||||
<FirebaseUi uiConfig={uiConfig} />
|
||||
</AuthLayout>
|
||||
);
|
||||
}
|
||||
|
||||
58
src/pages/PageNotFound.tsx
Normal file
58
src/pages/PageNotFound.tsx
Normal file
@@ -0,0 +1,58 @@
|
||||
import { Link } from "react-router-dom";
|
||||
import { Button } from "@mui/material";
|
||||
import GoIcon from "assets/icons/Go";
|
||||
import HomeIcon from "@mui/icons-material/HomeOutlined";
|
||||
|
||||
import AuthLayout from "components/Auth/AuthLayout";
|
||||
import Navigation, { APP_BAR_HEIGHT } from "components/Navigation";
|
||||
import EmptyState from "components/EmptyState";
|
||||
|
||||
import { homepage } from "@root/package.json";
|
||||
import { useAppContext } from "contexts/AppContext";
|
||||
import routes from "constants/routes";
|
||||
|
||||
export interface IPageNotFoundProps {}
|
||||
|
||||
export default function PageNotFound() {
|
||||
const { currentUser } = useAppContext();
|
||||
|
||||
if (!currentUser)
|
||||
return (
|
||||
<AuthLayout>
|
||||
<EmptyState
|
||||
message="Page Not Found"
|
||||
description={
|
||||
<Button
|
||||
variant="outlined"
|
||||
sx={{ mt: 3 }}
|
||||
href={homepage}
|
||||
endIcon={<GoIcon style={{ margin: "0 -0.33em" }} />}
|
||||
>
|
||||
{homepage.split("//")[1].replace(/\//g, "")}
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
</AuthLayout>
|
||||
);
|
||||
|
||||
return (
|
||||
<Navigation title="Page Not Found" titleComponent={<div />}>
|
||||
<EmptyState
|
||||
message="Page Not Found"
|
||||
description={
|
||||
<Button
|
||||
variant="outlined"
|
||||
sx={{ mt: 3 }}
|
||||
component={Link}
|
||||
to={routes.home}
|
||||
startIcon={<HomeIcon />}
|
||||
>
|
||||
Home
|
||||
</Button>
|
||||
}
|
||||
fullScreen
|
||||
style={{ marginTop: -APP_BAR_HEIGHT }}
|
||||
/>
|
||||
</Navigation>
|
||||
);
|
||||
}
|
||||
@@ -1,26 +1,35 @@
|
||||
import React, { useContext } from "react";
|
||||
import { Route, RouteProps, Redirect } from "react-router-dom";
|
||||
|
||||
import { AppContext } from "contexts/AppContext";
|
||||
import Loading from "../components/Loading";
|
||||
import { useAppContext } from "contexts/AppContext";
|
||||
import Loading from "components/Loading";
|
||||
import routes from "constants/routes";
|
||||
|
||||
interface IPrivateRouteProps extends RouteProps {
|
||||
render: NonNullable<RouteProps["render"]>;
|
||||
}
|
||||
|
||||
const PrivateRoute: React.FC<IPrivateRouteProps> = ({ render, ...rest }) => {
|
||||
const { currentUser } = useContext(AppContext);
|
||||
export default function PrivateRoute({ render, ...props }: IPrivateRouteProps) {
|
||||
const { currentUser } = useAppContext();
|
||||
|
||||
if (!!currentUser) return <Route {...rest} render={render} />;
|
||||
if (!!currentUser) return <Route {...props} render={render} />;
|
||||
|
||||
if (currentUser === null) return <Redirect to="/auth" />;
|
||||
const redirect =
|
||||
(props.location?.pathname ?? "") + (props.location?.search ?? "");
|
||||
|
||||
if (currentUser === null)
|
||||
return (
|
||||
<Redirect
|
||||
to={{
|
||||
pathname: routes.auth,
|
||||
search: redirect ? `?redirect=${encodeURIComponent(redirect)}` : "",
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<Route
|
||||
{...rest}
|
||||
{...props}
|
||||
render={() => <Loading message="Authenticating" fullScreen />}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default PrivateRoute;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user