diff --git a/client/src/assets/wave.gif b/client/src/assets/wave.gif
new file mode 100644
index 0000000..acc50dd
Binary files /dev/null and b/client/src/assets/wave.gif differ
diff --git a/client/src/components/switch-auth.tsx b/client/src/components/switch-auth.tsx
index 0e2f8a2..4531b1f 100644
--- a/client/src/components/switch-auth.tsx
+++ b/client/src/components/switch-auth.tsx
@@ -18,7 +18,11 @@ const SwitchAuth = ({ label, tag, href, disabled }: SwitchAuthProps) => {
to={href}
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"
+ ${
+ disabled
+ ? "text-secondary/50 pointer-events-none"
+ : "text-secondary"
+ }
`}
>
{tag}
diff --git a/client/src/components/auth-title.tsx b/client/src/components/title.tsx
similarity index 86%
rename from client/src/components/auth-title.tsx
rename to client/src/components/title.tsx
index b11d078..0590b99 100644
--- a/client/src/components/auth-title.tsx
+++ b/client/src/components/title.tsx
@@ -1,9 +1,9 @@
-interface AuthTitleProps {
+interface TitleProps {
title: string;
body?: string;
}
-const AuthTitle = ({ title, body }: AuthTitleProps) => {
+const Title = ({ title, body }: TitleProps) => {
return (
{
);
};
-export { AuthTitle };
+export { Title };
diff --git a/client/src/constants/assets.ts b/client/src/constants/assets.ts
index 1581dc8..e860b58 100644
--- a/client/src/constants/assets.ts
+++ b/client/src/constants/assets.ts
@@ -1,3 +1,5 @@
+import wave from "@/assets/wave.gif";
import key from "@/assets/key.svg";
export const KEY = key;
+export const WAVE = wave;
diff --git a/client/src/constants/collections.ts b/client/src/constants/collections.ts
index 8acdbe3..27a6ab2 100644
--- a/client/src/constants/collections.ts
+++ b/client/src/constants/collections.ts
@@ -85,7 +85,7 @@ export const SIGNIN_INPUTS = [
export const RESET_PASSWORD_INPUTS = [
{
- name: "oldPassword",
+ name: "old-password",
label: "Old Password",
tooltip: "Enter your current password",
placeholder: "e.g. m#P52s@ap$V",
@@ -96,7 +96,7 @@ export const RESET_PASSWORD_INPUTS = [
maxLength: 128,
},
{
- name: "newPassword",
+ name: "new-password",
label: "New Password",
tooltip:
"Create a password with at least 8 characters, including uppercase, lowercase, numbers, and special characters for security",
diff --git a/client/src/lib/DTO/reset-dto.ts b/client/src/lib/DTO/reset-dto.ts
index 1edc94e..2f32021 100644
--- a/client/src/lib/DTO/reset-dto.ts
+++ b/client/src/lib/DTO/reset-dto.ts
@@ -1,5 +1,5 @@
export type ResetDTO = {
token: string;
- oldpassword: string;
- newpassword: string;
+ old_password: string;
+ new_password: string;
};
diff --git a/client/src/lib/services/auth-service.ts b/client/src/lib/services/auth-service.ts
index 1598787..8adcfba 100644
--- a/client/src/lib/services/auth-service.ts
+++ b/client/src/lib/services/auth-service.ts
@@ -4,7 +4,7 @@ import { UserResponse } from "@/lib/classes/user-response-class";
import { SignUpDTO } from "@/lib/DTO/sign-up-dto";
import { SignInDTO } from "@/lib/DTO/sign-in-dto";
import { AppRoutes } from "@/constants/routes";
-import { ResetDTO } from "../DTO/reset-dto";
+import { ResetDTO } from "@/lib/DTO/reset-dto";
const baseURL =
import.meta.env.VITE_ENV === "development"
@@ -28,9 +28,8 @@ export const AuthService = {
});
}
- return new UserResponse({
+ return new GenericResponse({
message: data.message,
- user: data.user,
});
},
signIn: async (signIn: SignInDTO) => {
@@ -52,8 +51,9 @@ export const AuthService = {
});
}
- return new GenericResponse({
+ return new UserResponse({
message: data.message,
+ user: data.user,
});
},
signOut: async () => {
@@ -172,8 +172,8 @@ export const AuthService = {
"Content-Type": "application/json",
},
body: JSON.stringify({
- old_password: reset.oldpassword,
- new_password: reset.newpassword,
+ old_password: reset.old_password,
+ new_password: reset.new_password,
}),
}
);
diff --git a/client/src/lib/stores/user-store.ts b/client/src/lib/stores/user-store.ts
new file mode 100644
index 0000000..bad3f9b
--- /dev/null
+++ b/client/src/lib/stores/user-store.ts
@@ -0,0 +1,24 @@
+import { createJSONStorage, devtools, persist } from "zustand/middleware";
+import { create } from "zustand";
+
+import { UserDTO } from "@/lib/DTO/user-dto";
+
+interface UserStoreState {
+ user?: UserDTO;
+ setUser: (user?: UserDTO) => void;
+}
+
+export const useUserStore = create()(
+ devtools(
+ persist(
+ (set) => ({
+ user: undefined,
+ setUser: (user?: UserDTO) => set({ user }),
+ }),
+ {
+ name: "go-react-user",
+ storage: createJSONStorage(() => sessionStorage),
+ }
+ )
+ )
+);
diff --git a/client/src/lib/utils/date.ts b/client/src/lib/utils/date.ts
new file mode 100644
index 0000000..971cb0c
--- /dev/null
+++ b/client/src/lib/utils/date.ts
@@ -0,0 +1,16 @@
+export const formatDate = (dateString: string) => {
+ const date = new Date(dateString);
+
+ if (isNaN(date.getTime())) {
+ return "Invalid Date";
+ }
+
+ return date.toLocaleString("en-US", {
+ year: "numeric",
+ month: "short",
+ day: "numeric",
+ hour: "2-digit",
+ minute: "2-digit",
+ hour12: true,
+ });
+};
diff --git a/client/src/pages/forgot-password/page.tsx b/client/src/pages/forgot-password/page.tsx
index ab82818..d726969 100644
--- a/client/src/pages/forgot-password/page.tsx
+++ b/client/src/pages/forgot-password/page.tsx
@@ -1,4 +1,4 @@
-import { AuthTitle } from "@/components/auth-title";
+import { Title } from "@/components/title";
import { ForgotPasswordForm } from "./_components/forgot-password-form";
import { ForgotPasswordBack } from "./_components/forgot-password-back";
@@ -6,7 +6,7 @@ import { ForgotPasswordBack } from "./_components/forgot-password-back";
const ForgotPasswordPage = () => {
return (
-
diff --git a/client/src/pages/reset-password/_components/reset-password-form.tsx b/client/src/pages/reset-password/_components/reset-password-form.tsx
index 2e121e2..2e33763 100644
--- a/client/src/pages/reset-password/_components/reset-password-form.tsx
+++ b/client/src/pages/reset-password/_components/reset-password-form.tsx
@@ -41,11 +41,13 @@ const ResetPasswordForm = () => {
const formData = new FormData(e.currentTarget);
- const resetPasswordData = Object.fromEntries(
- formData.entries()
- ) as ResetDTO;
+ const resetPasswordData: ResetDTO = {
+ token: token,
+ old_password: formData.get("old-password") as string,
+ new_password: formData.get("new-password") as string,
+ };
- resetPasswordData.token = token;
+ console.log(resetPasswordData);
setGlobalLoading(true);
diff --git a/client/src/pages/reset-password/page.tsx b/client/src/pages/reset-password/page.tsx
index 621a711..72cfd31 100644
--- a/client/src/pages/reset-password/page.tsx
+++ b/client/src/pages/reset-password/page.tsx
@@ -1,4 +1,4 @@
-import { AuthTitle } from "@/components/auth-title";
+import { Title } from "@/components/title";
import { ResetPasswordForm } from "./_components/reset-password-form";
import { ResetPasswordBack } from "./_components/reset-password-back";
@@ -6,7 +6,7 @@ import { ResetPasswordBack } from "./_components/reset-password-back";
const ResetPasswordPage = () => {
return (
-
+
diff --git a/client/src/pages/root/_components/content/index.tsx b/client/src/pages/root/_components/content/index.tsx
new file mode 100644
index 0000000..821ffaa
--- /dev/null
+++ b/client/src/pages/root/_components/content/index.tsx
@@ -0,0 +1,36 @@
+import { useUserStore } from "@/lib/stores/user-store";
+import { formatDate } from "@/lib/utils/date";
+
+import { WelcomeUser } from "./welcome-user";
+import { InfoPair } from "./info-pair";
+
+const Content = () => {
+ const { user } = useUserStore();
+
+ return (
+
+ );
+};
+
+export { Content };
diff --git a/client/src/pages/root/_components/content/info-pair.tsx b/client/src/pages/root/_components/content/info-pair.tsx
new file mode 100644
index 0000000..9917178
--- /dev/null
+++ b/client/src/pages/root/_components/content/info-pair.tsx
@@ -0,0 +1,14 @@
+interface InfoPairProps {
+ label: string;
+ value?: string;
+}
+
+const InfoPair = ({ label, value }: InfoPairProps) => {
+ return (
+
+ {label}:{value}
+
+ );
+};
+
+export { InfoPair };
diff --git a/client/src/pages/root/_components/content/welcome-user.tsx b/client/src/pages/root/_components/content/welcome-user.tsx
new file mode 100644
index 0000000..c0ed048
--- /dev/null
+++ b/client/src/pages/root/_components/content/welcome-user.tsx
@@ -0,0 +1,29 @@
+import { WAVE } from "@/constants/assets";
+
+interface WelcomeUserProps {
+ name?: string;
+}
+
+const WelcomeUser = ({ name }: WelcomeUserProps) => {
+ return (
+
+
+
+ Hi there{" "}
+
+
+ {name}
+
+
+
+ Welcome to Go + React Auth
+
+
+
+ );
+};
+
+export { WelcomeUser };
diff --git a/client/src/pages/root/_components/footer/index.tsx b/client/src/pages/root/_components/footer/index.tsx
new file mode 100644
index 0000000..212ab8f
--- /dev/null
+++ b/client/src/pages/root/_components/footer/index.tsx
@@ -0,0 +1,11 @@
+const Footer = () => {
+ return (
+
+ );
+};
+
+export { Footer };
diff --git a/client/src/pages/root/_components/header/sign-out-button.tsx b/client/src/pages/root/_components/header/sign-out-button.tsx
index a2b8f14..7057928 100644
--- a/client/src/pages/root/_components/header/sign-out-button.tsx
+++ b/client/src/pages/root/_components/header/sign-out-button.tsx
@@ -4,18 +4,21 @@ import { toast } from "sonner";
import { GenericResponse } from "@/lib/classes/generic-response-class";
import { AuthService } from "@/lib/services/auth-service";
+import { useUserStore } from "@/lib/stores/user-store";
import { useAuthStore } from "@/lib/stores/auth-store";
import IconButton from "@/components/icon-button";
import { SIGNOUTKEY } from "@/constants/keys";
const SignOutButton = () => {
const { setAuthorized } = useAuthStore();
+ const { setUser } = useUserStore();
const { mutate, isPending } = useMutation({
mutationKey: [SIGNOUTKEY],
mutationFn: AuthService.signOut,
onSuccess: (res: GenericResponse) => {
toast.success(res.message);
+ setUser(undefined);
setAuthorized(false);
},
onError: ({ message }) => toast.error(message),
diff --git a/client/src/pages/root/page.tsx b/client/src/pages/root/page.tsx
index f734d65..32a1c28 100644
--- a/client/src/pages/root/page.tsx
+++ b/client/src/pages/root/page.tsx
@@ -1,12 +1,13 @@
+import { Footer } from "./_components/footer";
import { Header } from "./_components/header";
+import { Content } from "./_components/content";
const RootPage = () => {
return (
<>
-
+
+
>
);
};
diff --git a/client/src/pages/sign-in/_components/sign-in-form.tsx b/client/src/pages/sign-in/_components/sign-in-form.tsx
index afdb1fa..4350b43 100644
--- a/client/src/pages/sign-in/_components/sign-in-form.tsx
+++ b/client/src/pages/sign-in/_components/sign-in-form.tsx
@@ -3,11 +3,12 @@ import { useMutation } from "@tanstack/react-query";
import { FormEvent } from "react";
import { toast } from "sonner";
-import { GenericResponse } from "@/lib/classes/generic-response-class";
import { ErrorResponse } from "@/lib/classes/error-response-class";
+import { UserResponse } from "@/lib/classes/user-response-class";
import { AuthService } from "@/lib/services/auth-service";
import { SIGNIN_INPUTS } from "@/constants/collections";
import { useAuthStore } from "@/lib/stores/auth-store";
+import { useUserStore } from "@/lib/stores/user-store";
import { SignInDTO } from "@/lib/DTO/sign-in-dto";
import { Button } from "@/components/text-button";
import { AppRoutes } from "@/constants/routes";
@@ -21,22 +22,26 @@ const SignInForm = () => {
setAuthorized,
setLoading: setGlobalLoading,
} = useAuthStore();
+ const { setUser } = useUserStore();
const { mutate, isPending } = useMutation({
mutationKey: [SIGNINKEY],
mutationFn: AuthService.signIn,
- onSuccess: (res: GenericResponse) => {
+ onSuccess: (res: UserResponse) => {
toast.success(res.message);
+ setUser(res.user);
setAuthorized(true);
setGlobalLoading(false);
},
onError: (error: ErrorResponse) => {
if (error.status == 403) {
toast.error("Please verify to sign in");
+ setUser(undefined);
setGlobalLoading(false);
navigate(AppRoutes.VerifyEmail);
} else {
toast.error(error.message);
+ setUser(undefined);
setAuthorized(false);
setGlobalLoading(false);
}
diff --git a/client/src/pages/sign-in/page.tsx b/client/src/pages/sign-in/page.tsx
index f8d4317..fd4dd84 100644
--- a/client/src/pages/sign-in/page.tsx
+++ b/client/src/pages/sign-in/page.tsx
@@ -1,4 +1,4 @@
-import { AuthTitle } from "@/components/auth-title";
+import { Title } from "@/components/title";
import { Or } from "@/components/or";
import { NoAccountYet } from "./_components/no-account-yet";
@@ -7,7 +7,7 @@ import { SignInForm } from "./_components/sign-in-form";
const SignInPage = () => {
return (
-
+
diff --git a/client/src/pages/sign-up/_components/sign-up-form.tsx b/client/src/pages/sign-up/_components/sign-up-form.tsx
index 2c296ca..7eb6056 100644
--- a/client/src/pages/sign-up/_components/sign-up-form.tsx
+++ b/client/src/pages/sign-up/_components/sign-up-form.tsx
@@ -3,6 +3,7 @@ import { useNavigate } from "react-router-dom";
import { FormEvent, useState } from "react";
import { toast } from "sonner";
+import { GenericResponse } from "@/lib/classes/generic-response-class";
import { ErrorResponse } from "@/lib/classes/error-response-class";
import { AuthService } from "@/lib/services/auth-service";
import { SIGNUP_INPUTS } from "@/constants/collections";
@@ -21,8 +22,8 @@ const SignUpForm = () => {
const { mutate, isPending } = useMutation({
mutationKey: [SIGNUPKEY],
mutationFn: AuthService.signUp,
- onSuccess: () => {
- toast.success("Registered successfully");
+ onSuccess: (res: GenericResponse) => {
+ toast.success(res.message);
setGlobalLoading(false);
navigate(AppRoutes.SignIn);
},
diff --git a/client/src/pages/sign-up/page.tsx b/client/src/pages/sign-up/page.tsx
index 7aef38e..f9a3817 100644
--- a/client/src/pages/sign-up/page.tsx
+++ b/client/src/pages/sign-up/page.tsx
@@ -1,4 +1,4 @@
-import { AuthTitle } from "@/components/auth-title";
+import { Title } from "@/components/title";
import { Or } from "@/components/or";
import { AlreadyHaveAccount } from "./_components/already-have-account";
@@ -7,7 +7,7 @@ import { SignUpForm } from "./_components/sign-up-form";
const SignUpPage = () => {
return (
-
+
diff --git a/client/src/pages/verify-email/page.tsx b/client/src/pages/verify-email/page.tsx
index 57b1f04..1414231 100644
--- a/client/src/pages/verify-email/page.tsx
+++ b/client/src/pages/verify-email/page.tsx
@@ -1,4 +1,4 @@
-import { AuthTitle } from "@/components/auth-title";
+import { Title } from "@/components/title";
import { VerifyEmailForm } from "./_components/verify-email-form";
import { ResendCode } from "./_components/resend-code";
@@ -6,7 +6,7 @@ import { ResendCode } from "./_components/resend-code";
const VerifyEmailPage = () => {
return (
-
+
diff --git a/controllers/auth_controller.go b/controllers/auth_controller.go
index 15cbd5c..5422fd6 100644
--- a/controllers/auth_controller.go
+++ b/controllers/auth_controller.go
@@ -53,12 +53,7 @@ func SignUp(c fiber.Ctx) error {
return c.Status(fiber.StatusInternalServerError).JSON(dto.ErrorDTO{Error: err.Error()})
}
- return c.Status(fiber.StatusCreated).JSON(
- dto.UserDTO{
- Message: "User created successfully",
- User: user,
- },
- )
+ return c.Status(fiber.StatusCreated).JSON(dto.GenericDTO{Message: "User created successfully"})
}
func SignIn(c fiber.Ctx) error {
@@ -98,7 +93,10 @@ func SignIn(c fiber.Ctx) error {
return c.Status(fiber.StatusInternalServerError).JSON(dto.ErrorDTO{Error: "Unable to save sign in credentials"})
}
- return c.Status(fiber.StatusOK).JSON(dto.GenericDTO{Message: "Sign in successful"})
+ return c.Status(fiber.StatusOK).JSON(dto.UserDTO{
+ Message: "Sign in successful",
+ User: user,
+ })
} else {
return c.Status(fiber.StatusForbidden).JSON(dto.ErrorDTO{Error: "User is not verified"})
}