Skip to content

Commit

Permalink
Refactor Auth components to use React Router hooks and actions
Browse files Browse the repository at this point in the history
  • Loading branch information
TheRealBill91 committed Sep 29, 2023
1 parent f47c630 commit 819238c
Show file tree
Hide file tree
Showing 16 changed files with 1,087 additions and 5,055 deletions.
5,685 changes: 884 additions & 4,801 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.16.0",
"react-toastify": "^9.1.3",
"sonner": "^1.0.3"
},
"workspaces": {
Expand Down
9 changes: 5 additions & 4 deletions src/components/AuthButton.jsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
export function AuthButton({ name, status }) {

export function AuthButton({ name, submitting }) {
return (
<button
aria-disabled={status}
aria-disabled={submitting}
className="inline-flex w-[140px] items-center justify-evenly self-center rounded-lg border-[1px] border-solid border-gray-700 bg-white p-2 text-lg text-gray-700 shadow-sm shadow-gray-100 transition-all hover:border-[1px] hover:border-solid hover:border-gray-900 hover:text-gray-900 aria-disabled:border-gray-300 aria-disabled:text-gray-300 dark:text-slate-800 dark:aria-disabled:text-gray-300"
type="submit"
>
{name}
{status === "SUBMITTING" ? (
{submitting ? (
<svg
className=" mr-3 h-5 w-5 animate-spin bg-white"
className=" mr-3 h-5 w-5 animate-spin bg-white text-gray-600"
viewBox="0 0 24 24"
>
<circle
Expand Down
24 changes: 24 additions & 0 deletions src/components/GoogleSignIn.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Icon } from "./Icon";

export function GoogleSignIn() {
return (
<>
{/* line pass through effect inspired by The
Odin Project Sign In form */}
<div className="relative my-6">
<div className="absolute inset-0 flex items-center">
<div className="w-full border-t border-gray-400"></div>
</div>
<div className="relative flex justify-center text-sm capitalize">
<p className=" bg-gray-200 px-3 text-gray-700">or sigin with</p>
</div>
</div>
<div className="mt-4 flex items-center justify-center">
<button className="flex w-[140px] items-center gap-4 rounded-lg border border-gray-600 bg-white p-2 px-3 text-lg shadow-sm">
<Icon id="Google" className="h-6 w-6 text-gray-700" />
Sign In
</button>
</div>
</>
);
}
5 changes: 2 additions & 3 deletions src/components/Header.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { ToastContext } from "../contexts/ToastContext";
import { NavBar } from "./NavBar/NavBar";
import { motion } from "framer-motion";
import { useNavigate } from "react-router-dom";
import { AuthContext } from "../contexts/AuthContext";

const Path = (props) => (
<motion.path fill="grey" strokeWidth="3.3" strokeLinecap="round" {...props} />
Expand All @@ -18,12 +19,11 @@ export function Header(props) {
toggleTheme,
theme,
onBlogPage,
auth,
setAuth,
} = props;

const navigate = useNavigate();
const { addToast } = useContext(ToastContext);
const { setAuth } = useContext(AuthContext);

const signOut = async () => {
toggleMobileMenu();
Expand Down Expand Up @@ -52,7 +52,6 @@ export function Header(props) {
<MobileMenu
onBlogPage={onBlogPage}
toggleMobileMenu={toggleMobileMenu}
auth={auth}
signOut={signOut}
/>
) : null}
Expand Down
8 changes: 2 additions & 6 deletions src/components/MainLayout.jsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
import { Header } from "./Header";
import "../main.css";
import { useState, useContext } from "react";
import { useState } from "react";
import { useDarkMode } from "../hooks/useDarkMode";
import { Outlet, useLocation, useNavigation } from "react-router";
import { MotionConfig } from "framer-motion";
import { LoadingAnimation } from "../components/portfolio/LoadingAnimation";
import { ToastProvider } from "../contexts/ToastContext";
import { BounceAnimation } from "./BounceAnimation";
import { AuthContext } from "../contexts/AuthContext";

export function MainLayout() {
const [theme, setTheme] = useDarkMode();
const [mobileMenuVisible, setMobileMenuVisible] = useState(false);
const [loadAnimationStatus, setLoadAnimationStatus] = useState(true);
const { auth, setAuth } = useContext(AuthContext);

const loadHomePage = () => {
setLoadAnimationStatus(false);
Expand Down Expand Up @@ -53,13 +51,11 @@ export function MainLayout() {
toggleTheme={toggleTheme}
theme={theme}
onBlogPage={onBlogPage}
auth={auth}
setAuth={setAuth}
/>
{navigation.state === "loading" ? (
<BounceAnimation />
) : (
<Outlet context={[auth, setAuth, onBlogPage, theme]} />
<Outlet context={[onBlogPage, theme]} />
)}
</ToastProvider>
</div>
Expand Down
5 changes: 4 additions & 1 deletion src/components/mobilemenus/BlogMenu.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ import { Link } from "react-router-dom";
import { motion, AnimatePresence } from "framer-motion";
import { blogLinkObjects } from "../../utils/blogLinkObjects";
import { itemVariants } from "../../utils/FramerVariants/MobileMenuVariants";
import { useContext } from "react";
import { AuthContext } from "../../contexts/AuthContext";

export function BlogMenu({ toggleMobileMenu, auth, signOut }) {
export function BlogMenu({ toggleMobileMenu, signOut }) {
let updatedblogLinkObjects;
const { auth } = useContext(AuthContext);
// If user is authenticated, remove the sign in blog link object
// otherwise, remove the sign out blog link object
if (auth === true) {
Expand Down
8 changes: 2 additions & 6 deletions src/components/mobilemenus/MobileMenu.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { AnimatePresence } from "framer-motion";
import { PortfolioMenu } from "./PortfolioMenu";
import { BlogMenu } from "./BlogMenu";

export function MobileMenu({ toggleMobileMenu, onBlogPage, auth, signOut }) {
export function MobileMenu({ toggleMobileMenu, onBlogPage, signOut }) {
return (
<>
<AnimatePresence>
Expand All @@ -11,11 +11,7 @@ export function MobileMenu({ toggleMobileMenu, onBlogPage, auth, signOut }) {
{!onBlogPage ? (
<PortfolioMenu toggleMobileMenu={toggleMobileMenu} />
) : (
<BlogMenu
toggleMobileMenu={toggleMobileMenu}
signOut={signOut}
auth={auth}
/>
<BlogMenu toggleMobileMenu={toggleMobileMenu} signOut={signOut} />
)}
</ul>
</div>
Expand Down
1 change: 1 addition & 0 deletions src/contexts/AuthContext.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export function AuthProvider({ children }) {
const [auth, setAuth] = useState(false);
const [authStatusError, setAuthStatusError] = useState(null);


useEffect(() => {
async function checkAuthStatus() {
try {
Expand Down
92 changes: 14 additions & 78 deletions src/pages/Auth/SignIn/SignIn.jsx
Original file line number Diff line number Diff line change
@@ -1,74 +1,28 @@
import { Icon } from "../../../components/Icon";
import { Footer } from "../../../components/Footer";
import { useContext, useState } from "react";
import { useNavigate } from "react-router-dom";
import { useContext } from "react";
import { Form, useActionData, useNavigation, Navigate } from "react-router-dom";
import { AuthButton } from "../../../components/AuthButton";
import { ToastContext } from "../../../contexts/ToastContext";
import { AuthContext } from "../../../contexts/AuthContext";
import { STATUS } from "../../../utils/enums/formStatus";

export function SignIn() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState({ loginError: "" });
const { setAuth } = useContext(AuthContext);
const { addToast } = useContext(ToastContext);
const [status, setStatus] = useState(STATUS.IDLE);
const { auth } = useContext(AuthContext);

const navigate = useNavigate();
const navigation = useNavigation();
const submitting = navigation.state === "submitting";

const handleInputChange = (evt) => {
const { name, value } = evt.target;
if (name === "email") {
setEmail(value);
} else if (name === "password") {
setPassword(value);
}
};
const serverError = useActionData();

const handleSubmit = async (event) => {
event.preventDefault();
let userIsAuth;

setStatus(STATUS.SUBMITTING);
try {
const response = await fetch("http://localhost:3000/client/auth/login", {
mode: "cors",
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email, password }),
credentials: "include",
});

if (response.ok) {
addToast("Logged in successfully");
setStatus(STATUS.COMPLETED);
userIsAuth = true;
setAuth(userIsAuth);
} else {
setStatus(STATUS.SUBMITTED);
setPassword("");
setAuth(false);
throw await response.json();
}
} catch (error) {
setError({ loginError: error.message });
} finally {
if (userIsAuth === true) {
navigate("/bloghome");
}
}
};

return (
<>
{auth === true && <Navigate to={"/bloghome"} />}
<main className=" flex min-h-screen flex-1 flex-col items-center justify-start bg-white px-7 py-8 dark:bg-gray-800">
<div className="mt-10">
<h1 className="mb-4 text-center text-2xl font-bold text-gray-800 dark:text-slate-100">
Sign in with your account
</h1>
<div className="flex-col rounded-xl bg-gray-200 px-10 py-6 shadow-md shadow-gray-200 md:min-w-[400px] md:max-w-[550px] md:justify-center md:self-center">
<form onSubmit={handleSubmit}>
<Form method="POST" action="/bloghome/signin">
<div className="mb-3 flex flex-col gap-4">
<div className="mx-2 flex flex-col gap-2 text-gray-700">
<label
Expand All @@ -80,8 +34,7 @@ export function SignIn() {
<input
className="peer w-full rounded-md p-2 [&:not(:focus)]:[&:not(:placeholder-shown)]:invalid:border [&:not(:focus)]:[&:not(:placeholder-shown)]:invalid:border-solid [&:not(:focus)]:[&:not(:placeholder-shown)]:invalid:border-red-700"
name="email"
value={email}
onChange={handleInputChange}

placeholder="[email protected]"
type="email"
required
Expand All @@ -101,8 +54,7 @@ export function SignIn() {
<input
className=" peer w-full rounded-md p-2 [&:not(:focus)]:[&:not(:placeholder-shown)]:invalid:border [&:not(:focus)]:[&:not(:placeholder-shown)]:invalid:border-solid [&:not(:focus)]:[&:not(:placeholder-shown)]:invalid:border-red-700 "
name="password"
value={password}
onChange={handleInputChange}

id="password"
type="password"
placeholder=""
Expand All @@ -113,30 +65,14 @@ export function SignIn() {
Please enter your password
</span>
</div>
{error.loginError && (
{serverError && (
<span className="px-1 pb-3 text-center text-red-700">
{error.loginError}
{serverError.message}
</span>
)}
<AuthButton status={status} name={"Sign in"} />
</div>
</form>
{/* line pass through effect inspired by The
Odin Project Sign In form */}
<div className="relative my-6">
<div className="absolute inset-0 flex items-center">
<div className="w-full border-t border-gray-400"></div>
</div>
<div className="relative flex justify-center text-sm capitalize">
<p className=" bg-gray-200 px-3 text-gray-700">or sigin with</p>
<AuthButton submitting={submitting} name={"Sign in"} />
</div>
</div>
<div className="mt-4 flex items-center justify-center">
<button className="flex w-[140px] items-center gap-4 rounded-lg border border-gray-600 bg-white p-2 px-3 text-lg shadow-sm">
<Icon id="Google" className="h-6 w-6 text-gray-700" />
Sign In
</button>
</div>
</Form>
</div>
</div>
</main>
Expand Down
Loading

0 comments on commit 819238c

Please sign in to comment.