Skip to content

Commit

Permalink
Merge pull request #6 from Fingertips18/development
Browse files Browse the repository at this point in the history
Refactor auth store to selectively persist properties and manage global loading state to actions
  • Loading branch information
Fingertips18 authored Sep 25, 2024
2 parents 988fb7c + 3b4a8c3 commit f7b3d8b
Show file tree
Hide file tree
Showing 19 changed files with 172 additions and 64 deletions.
2 changes: 1 addition & 1 deletion client/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "client",
"name": "go-react-auth-client",
"private": true,
"version": "1.0.0",
"type": "module",
Expand Down
2 changes: 0 additions & 2 deletions client/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { Route, Routes } from "react-router-dom";

import { ForgotPasswordPage } from "@/pages/forgot-password/page";
import { ResetPasswordPage } from "@/pages/reset-password/page";
import { ResendVerifyPage } from "@/pages/resend-verify/page";
import VerifyEmailPage from "@/pages/verify-email/page";
import PrivateGuard from "@/guards/private-guard";
import { AppRoutes } from "@/constants/routes";
Expand All @@ -22,7 +21,6 @@ function App() {
<Route path={AppRoutes.SignUp} element={<SignUpPage />} />
<Route path={AppRoutes.SignIn} element={<SignInPage />} />
<Route path={AppRoutes.VerifyEmail} element={<VerifyEmailPage />} />
<Route path={AppRoutes.ResendVerify} element={<ResendVerifyPage />} />
</Route>
<Route
path={AppRoutes.ForgotPassword}
Expand Down
8 changes: 6 additions & 2 deletions client/src/components/switch-auth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ interface SwitchAuthProps {
label?: string;
tag: string;
href: string;
disabled?: boolean;
}

const SwitchAuth = ({ label, tag, href }: SwitchAuthProps) => {
const SwitchAuth = ({ label, tag, href, disabled }: SwitchAuthProps) => {
return (
<div
className="p-4 w-full text-sm lg:text-base rounded-md border
Expand All @@ -15,7 +16,10 @@ const SwitchAuth = ({ label, tag, href }: SwitchAuthProps) => {
{label && <p className="font-medium">{label}</p>}
<Link
to={href}
className="font-bold underline-offset-4 hover:underline text-secondary transition-all hover:drop-shadow-secondary-glow"
replace
className={`font-bold underline-offset-4 hover:underline transition-all hover:drop-shadow-secondary-glow
${disabled} ? "text-secondary/50 pointer-events-none" : "text-secondary"
`}
>
{tag}
</Link>
Expand Down
36 changes: 23 additions & 13 deletions client/src/lib/stores/auth-store.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,34 @@
import { createJSONStorage, persist } from "zustand/middleware";
import { createJSONStorage, devtools, persist } from "zustand/middleware";
import { create } from "zustand";

interface AuthStoreState {
email: string;
setEmail: (email: string) => void;
authorized: boolean;
setAuthorized: (authorized: boolean) => void;
loading: boolean;
setLoading: (loading: boolean) => void;
}

export const useAuthStore = create(
persist<AuthStoreState>(
(set) => ({
email: "",
setEmail: (email: string) => set({ email }),
authorized: false,
setAuthorized: (authorized: boolean) => set({ authorized }),
}),
{
name: "email",
storage: createJSONStorage(() => sessionStorage),
}
export const useAuthStore = create<AuthStoreState>()(
devtools(
persist(
(set) => ({
email: "",
setEmail: (email: string) => set({ email }),
authorized: false,
setAuthorized: (authorized: boolean) => set({ authorized }),
loading: false,
setLoading: (loading: boolean) => set({ loading }),
}),
{
name: "go-react-auth",
partialize: (state) => ({
email: state.email,
authorized: state.authorized,
}),
storage: createJSONStorage(() => sessionStorage),
}
)
)
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { useAuthStore } from "@/lib/stores/auth-store";
import { SwitchAuth } from "@/components/switch-auth";
import { AppRoutes } from "@/constants/routes";

const ForgotPasswordBack = () => {
const { loading } = useAuthStore();

return <SwitchAuth href={AppRoutes.SignIn} tag="Back" disabled={loading} />;
};

export { ForgotPasswordBack };
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,28 @@ import { GenericResponse } from "@/lib/classes/generic-response-class";
import { ErrorResponse } from "@/lib/classes/error-response-class";
import { AuthService } from "@/lib/services/auth-service";
import { ValidateEmail } from "@/lib/utils/validations";
import { useAuthStore } from "@/lib/stores/auth-store";
import { FORGOTPASSWORDKEY } from "@/constants/keys";
import { Button } from "@/components/text-button";
import { Input } from "@/components/input";

const ForgotPasswordForm = () => {
const { setLoading: setGlobalLoading } = useAuthStore();
const [submitted, setSubmitted] = useState(false);
const [email, setEmail] = useState("");

const { mutate, isPending } = useMutation({
mutationKey: [FORGOTPASSWORDKEY],
mutationFn: AuthService.forgotPassword,
onSuccess: (res: GenericResponse) => {
toast.success(res.message);
setSubmitted(true);
setGlobalLoading(false);
},
onError: (error: ErrorResponse) => {
toast.error(error.message);
setGlobalLoading(false);
},
onError: (error: ErrorResponse) => toast.error(error.message),
});

const onSubmit = (e: FormEvent<HTMLFormElement>) => {
Expand All @@ -34,6 +41,7 @@ const ForgotPasswordForm = () => {
const emailData = forgotPasswordData["email"] as string;

setEmail(emailData);
setGlobalLoading(true);

mutate(emailData);
};
Expand Down
8 changes: 4 additions & 4 deletions client/src/pages/forgot-password/page.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { SwitchAuth } from "@/components/switch-auth";
import { ForgotPasswordForm } from "./_components/forgot-password-form";
import { AppRoutes } from "@/constants/routes";
import { AuthTitle } from "@/components/auth-title";

import { ForgotPasswordForm } from "./_components/forgot-password-form";
import { ForgotPasswordBack } from "./_components/forgot-password-back";

const ForgotPasswordPage = () => {
return (
<section className="px-4 lg:px-0 h-full flex-center flex-col gap-y-6 w-fit mx-auto">
Expand All @@ -13,7 +13,7 @@ const ForgotPasswordPage = () => {

<ForgotPasswordForm />

<SwitchAuth href={AppRoutes.Root} tag="Back" />
<ForgotPasswordBack />
</section>
);
};
Expand Down
11 changes: 0 additions & 11 deletions client/src/pages/resend-verify/page.tsx

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { useAuthStore } from "@/lib/stores/auth-store";
import { SwitchAuth } from "@/components/switch-auth";
import { AppRoutes } from "@/constants/routes";

const ResetPasswordBack = () => {
const { loading } = useAuthStore();

return <SwitchAuth href={AppRoutes.SignIn} tag="Back" disabled={loading} />;
};

export { ResetPasswordBack };
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,31 @@ import { GenericResponse } from "@/lib/classes/generic-response-class";
import { ErrorResponse } from "@/lib/classes/error-response-class";
import { RESET_PASSWORD_INPUTS } from "@/constants/collections";
import { AuthService } from "@/lib/services/auth-service";
import { useAuthStore } from "@/lib/stores/auth-store";
import { RESETPASSWORDKEY } from "@/constants/keys";
import { Button } from "@/components/text-button";
import { AppRoutes } from "@/constants/routes";
import { ResetDTO } from "@/lib/DTO/reset-dto";
import { Input } from "@/components/input";

const ResetPasswordForm = () => {
const { setLoading: setGlobalLoading } = useAuthStore();
const navigate = useNavigate();
const { token } = useParams();
const [confirmPassword, setConfirmPassword] = useState("");

const { mutate, isPending } = useMutation({
mutationKey: [RESETPASSWORDKEY],
mutationFn: AuthService.resetPassword,
onSuccess: (res: GenericResponse) => {
toast.success(res.message);
setGlobalLoading(false);
navigate(AppRoutes.SignIn);
},
onError: (error: ErrorResponse) => toast.error(error.message),
onError: (error: ErrorResponse) => {
toast.error(error.message);
setGlobalLoading(false);
},
});

const onSubmit = (e: FormEvent<HTMLFormElement>) => {
Expand All @@ -40,6 +47,8 @@ const ResetPasswordForm = () => {

resetPasswordData.token = token;

setGlobalLoading(true);

mutate(resetPasswordData);
};

Expand Down
5 changes: 2 additions & 3 deletions client/src/pages/reset-password/page.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { SwitchAuth } from "@/components/switch-auth";
import { AuthTitle } from "@/components/auth-title";
import { AppRoutes } from "@/constants/routes";

import { ResetPasswordForm } from "./_components/reset-password-form";
import { ResetPasswordBack } from "./_components/reset-password-back";

const ResetPasswordPage = () => {
return (
Expand All @@ -11,7 +10,7 @@ const ResetPasswordPage = () => {

<ResetPasswordForm />

<SwitchAuth href={AppRoutes.Root} tag="Back" />
<ResetPasswordBack />
</section>
);
};
Expand Down
18 changes: 18 additions & 0 deletions client/src/pages/sign-in/_components/no-account-yet.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useAuthStore } from "@/lib/stores/auth-store";
import { SwitchAuth } from "@/components/switch-auth";
import { AppRoutes } from "@/constants/routes";

const NoAccountYet = () => {
const { loading } = useAuthStore();

return (
<SwitchAuth
label="Don't have an account yet?"
tag="Sign Up"
href={AppRoutes.SignUp}
disabled={loading}
/>
);
};

export { NoAccountYet };
11 changes: 10 additions & 1 deletion client/src/pages/sign-in/_components/sign-in-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,29 @@ import { Input } from "@/components/input";

const SignInForm = () => {
const navigate = useNavigate();
const { setEmail, setAuthorized } = useAuthStore();
const {
setEmail,
setAuthorized,
setLoading: setGlobalLoading,
} = useAuthStore();

const { mutate, isPending } = useMutation({
mutationKey: [SIGNINKEY],
mutationFn: AuthService.signIn,
onSuccess: (res: GenericResponse) => {
toast.success(res.message);
setAuthorized(true);
setGlobalLoading(false);
},
onError: (error: ErrorResponse) => {
if (error.status == 403) {
toast.error("Please verify to sign in");
setGlobalLoading(false);
navigate(AppRoutes.VerifyEmail);
} else {
toast.error(error.message);
setAuthorized(false);
setGlobalLoading(false);
}
},
});
Expand All @@ -43,6 +51,7 @@ const SignInForm = () => {
const signInData = Object.fromEntries(formData.entries()) as SignInDTO;

setEmail(signInData.email);
setGlobalLoading(true);

mutate(signInData);
};
Expand Down
9 changes: 2 additions & 7 deletions client/src/pages/sign-in/page.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { SwitchAuth } from "@/components/switch-auth";
import { AuthTitle } from "@/components/auth-title";
import { AppRoutes } from "@/constants/routes";
import { Or } from "@/components/or";

import { NoAccountYet } from "./_components/no-account-yet";
import { SignInForm } from "./_components/sign-in-form";

const SignInPage = () => {
Expand All @@ -14,11 +13,7 @@ const SignInPage = () => {

<Or />

<SwitchAuth
label="Don't have an account yet?"
tag="Sign Up"
href={AppRoutes.SignUp}
/>
<NoAccountYet />
</section>
);
};
Expand Down
18 changes: 18 additions & 0 deletions client/src/pages/sign-up/_components/already-have-account.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useAuthStore } from "@/lib/stores/auth-store";
import { SwitchAuth } from "@/components/switch-auth";
import { AppRoutes } from "@/constants/routes";

const AlreadyHaveAccount = () => {
const { loading } = useAuthStore();

return (
<SwitchAuth
label="Already have an account?"
tag="Sign In"
href={AppRoutes.SignIn}
disabled={loading}
/>
);
};

export { AlreadyHaveAccount };
10 changes: 9 additions & 1 deletion client/src/pages/sign-up/_components/sign-up-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ import { toast } from "sonner";
import { ErrorResponse } from "@/lib/classes/error-response-class";
import { AuthService } from "@/lib/services/auth-service";
import { SIGNUP_INPUTS } from "@/constants/collections";
import { useAuthStore } from "@/lib/stores/auth-store";
import { SignUpDTO } from "@/lib/DTO/sign-up-dto";
import { Button } from "@/components/text-button";
import { AppRoutes } from "@/constants/routes";
import { SIGNUPKEY } from "@/constants/keys";
import { Input } from "@/components/input";

const SignUpForm = () => {
const { setLoading: setGlobalLoading } = useAuthStore();
const [confirmPassword, setConfirmPassword] = useState("");
const navigate = useNavigate();

Expand All @@ -21,9 +23,13 @@ const SignUpForm = () => {
mutationFn: AuthService.signUp,
onSuccess: () => {
toast.success("Registered successfully");
setGlobalLoading(false);
navigate(AppRoutes.SignIn);
},
onError: (error: ErrorResponse) => toast.error(error.message),
onError: (error: ErrorResponse) => {
toast.error(error.message);
setGlobalLoading(false);
},
});

const onSubmit = (e: FormEvent<HTMLFormElement>) => {
Expand All @@ -33,6 +39,8 @@ const SignUpForm = () => {

const signUpData = Object.fromEntries(formData.entries()) as SignUpDTO;

setGlobalLoading(true);

mutate(signUpData);
};

Expand Down
Loading

0 comments on commit f7b3d8b

Please sign in to comment.