Skip to content

Commit

Permalink
automatic confirmation of mail by link
Browse files Browse the repository at this point in the history
  • Loading branch information
siarheidudko committed Jan 8, 2024
1 parent a1d28d6 commit ab2c17c
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 46 deletions.
32 changes: 29 additions & 3 deletions src/components/TopBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,51 @@ import { useAuthState } from "react-firebase-hooks/auth";
import LogoutIcon from "@mui/icons-material/Logout";
import LoginIcon from "@mui/icons-material/Login";
import "./TopBar.css";
import { UserModel } from "../models/database/User";
import { User } from "firebase/auth";

const menuItems: {
key: string;
path: string;
component: () => JSX.Element;
component: ({
authUser,
user,
isLoadingUser,
}: {
authUser: User | null | undefined;
user: UserModel | undefined;
isLoadingUser: boolean;
}) => JSX.Element;
label: string;
secure: boolean;
}[] = [
{
key: "page_main",
path: "/",
component: () => <MainRoute />,
component: ({ authUser }: { authUser: User | null | undefined }) => (
<MainRoute authUser={authUser} />
),
label: "Main Page",
secure: false,
},
{
key: "page_second",
path: "/second",
component: () => <SecondRoute />,
component: ({
authUser,
user,
isLoadingUser,
}: {
authUser: User | null | undefined;
user: UserModel | undefined;
isLoadingUser: boolean;
}) => (
<SecondRoute
authUser={authUser}
user={user}
isLoadingUser={isLoadingUser}
/>
),
label: "Second Page",
secure: true,
},
Expand Down
66 changes: 37 additions & 29 deletions src/components/auth/Action.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useState, FormEvent } from "react";
import { useState, FormEvent, useCallback, useEffect } from "react";
import Button from "@mui/material/Button";
import TextField from "@mui/material/TextField";
import Box from "@mui/material/Box";
Expand Down Expand Up @@ -32,7 +32,7 @@ export default function Action() {
)
? (searchParams.get("mode") as (typeof modes)[number])
: "resetEmail";
const oobCode = searchParams.get("oobCode");
let oobCode = searchParams.get("oobCode");
const navigate = useNavigate();
const { REACT_APP_404, REACT_APP_AUTH_SIGNIN } = process.env;

Expand Down Expand Up @@ -97,46 +97,54 @@ export default function Action() {
});
};

const handleVerifyEmail = (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
localStorage.removeItem("authorized");
const handleVerifyEmail = useCallback(async () => {
if (mode !== "verifyEmail") return;
if (!oobCode) {
setErrorMessage("You must follow the link from the email..");
setShowMsg({
type: "error",
message: "You must follow the link from the email.",
isShown: true,
});
return;
}
applyActionCode(FirebaseAuth, oobCode)
.then(() => signOut(FirebaseAuth))
await applyActionCode(FirebaseAuth, oobCode)
.then(() => {
setErrorMessage("");
navigate(REACT_APP_AUTH_SIGNIN || REACT_APP_404 || "/");
setShowMsg({
type: "info",
message: "The address has been confirmed, you need to log in again.",
isShown: true,
});
setTimeout(() => {
navigate("/");
window.location.reload();
}, 500);
})
.catch((err: FirebaseError) => {
if (errorMessagesMap[err.code]) {
setErrorMessage(errorMessagesMap[err.code]);
setShowMsg({
type: "error",
message: errorMessagesMap[err.code],
isShown: true,
});
} else {
setErrorMessage("Unknown error");
setShowMsg({
type: "error",
message: "Unknown error",
isShown: true,
});
}
});
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [mode, oobCode]);

useEffect(() => {
handleVerifyEmail();
}, [handleVerifyEmail]);

const inputBox = (): JSX.Element => {
const inputBox = (): JSX.Element | null => {
switch (mode) {
case "verifyEmail":
return (
<Box
component="form"
onSubmit={handleVerifyEmail}
noValidate
sx={{ mt: 1 }}
>
{errorMessage ? (
<Alert severity="error">{errorMessage}</Alert>
) : null}
<Button type="submit" fullWidth variant="contained" sx={{ mt: 3 }}>
Verify
</Button>
</Box>
);
return null;
case "resetPassword":
return (
<Box
Expand Down
1 change: 1 addition & 0 deletions src/components/auth/SignIn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export default function SignIn() {
})
.catch((err: FirebaseError) => {
switch (err.code) {
case "auth/invalid-login-credentials":
case "auth/user-not-found":
case "auth/wrong-password":
setErrorMessage("Invalid username or password");
Expand Down
11 changes: 10 additions & 1 deletion src/routes/MainRoute.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
import { Box, Typography } from "@mui/material";
import "./MainRoute.css";
import { User } from "firebase/auth";

function MainRoute() {
function MainRoute({ authUser }: { authUser: User | null | undefined }) {
return (
<div className="MainRoute">
{authUser?.emailVerified ? null : (
<Typography textAlign={"center"}>
{authUser
? "Confirm your email by clicking on the link from your email to see more."
: "Log in or register to see more."}
</Typography>
)}
<br />
<Typography align="center">The development is in progress...</Typography>
<Box sx={{ marginBottom: "10vmin" }} />
</div>
Expand Down
40 changes: 31 additions & 9 deletions src/routes/SecondRoute.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,39 @@
import { Box, Typography } from "@mui/material";
import { Box, Card, CardContent, Typography } from "@mui/material";
import "./SecondRoute.css";
import FirebaseAuth from "../services/FirebaseAuth";
import { useAuthState } from "react-firebase-hooks/auth";
import Loader from "../components/Loader";
import { User } from "firebase/auth";
import { UserModel } from "../models/database/User";

function SecondRoute() {
const [user] = useAuthState(FirebaseAuth);
return user?.emailVerified ? (
function SecondRoute({
authUser,
user,
isLoadingUser,
}: {
authUser: User | null | undefined;
user: UserModel | undefined;
isLoadingUser: boolean;
}) {
return authUser?.emailVerified || isLoadingUser ? (
<div className="SecondRoute">
<Card sx={{ maxWidth: 345 }}>
<CardContent>
<Typography
gutterBottom
variant="h5"
component="div"
fontWeight="bold"
overflow={"hidden"}
textOverflow={"ellipsis"}
>
{user?.id}
</Typography>
<Typography variant="body2" color="text.secondary">
{user?.email}
</Typography>
</CardContent>
</Card>
<br />
<Typography align="center">The development is in progress...</Typography>
<Typography align="left" style={{ whiteSpace: "pre-line" }}>
{JSON.stringify(user, undefined, "\u00A0\u00A0\u00A0\u00A0")}
</Typography>
<Box sx={{ marginBottom: "10vmin" }} />
</div>
) : (
Expand Down
28 changes: 24 additions & 4 deletions src/screens/BaseScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,15 @@ import "./BaseScreen.css";
import BottomBar from "../components/BottomBar";
import SignUp from "../components/auth/SignUp";
import Recovery from "../components/auth/Action";
import { useDocumentData } from "react-firebase-hooks/firestore";
import { doc } from "firebase/firestore";
import { UserModel } from "../models/database/User";

export default function BaseScreen() {
const [, loading] = useAuthState(FirebaseAuth);
const [authUser, isLoadingAuthUser] = useAuthState(FirebaseAuth);
const userRef = doc(UserModel.parent, `${FirebaseAuth.currentUser?.uid}`);
const [user, isLoadingUser] = useDocumentData(userRef);

const {
REACT_APP_AUTH_SIGNIN,
REACT_APP_AUTH_SIGNUP,
Expand All @@ -22,19 +28,33 @@ export default function BaseScreen() {
return (
<div className="App">
<TopBar />
{loading ? (
{isLoadingAuthUser ? (
<Loader />
) : (
<Routes>
<Route path="/" element={<Outlet />} key="page_main">
{menuItems.map((e, i) => {
if (i === 0) {
return <Route index element={e.component()} key={e.key} />;
return (
<Route
index
element={e.component({
authUser,
user,
isLoadingUser,
})}
key={e.key}
/>
);
}
return (
<Route
path={e.path.substring(1)}
element={e.component()}
element={e.component({
authUser,
user,
isLoadingUser,
})}
key={e.key}
/>
);
Expand Down

0 comments on commit ab2c17c

Please sign in to comment.