Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions components/auth/sign-in-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ import { PasswordInput } from "../ui/passwor-input";
import { Button } from "../ui/button";
import { Separator } from "../ui/separator";
import { signInSchema } from "@/utils/authValidationSchema";
import { useAuth } from "@/hooks/auth/useAuth";

export default function SignInForm() {
const { login } = useAuth();
const formik = useFormik({
initialValues: {
email: "",
Expand All @@ -18,8 +20,13 @@ export default function SignInForm() {
},
validationSchema: signInSchema,
onSubmit: async (values) => {
const formData = {
identifier: values.email,
password: values.password,
};
try {
// Here you would typically call an API endpoint
await login(formData)
console.log("Form submitted:", values);
// Simulate successful signin
// router.push("/dashboard");
Expand Down
24 changes: 21 additions & 3 deletions components/auth/sign-up-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,14 @@ import { FormInput } from "../ui/form-input";
import { PasswordInput } from "../ui/passwor-input";
import { Button } from "../ui/button";
import { signUpSchema } from "@/utils/authValidationSchema";
// import { useState } from "react";
// import { useAuth } from "@/hooks/auth/useAuth";

export default function SignUpForm() {
// const { signup } = useAuth();

// const [error, setError] = useState<string | null>(null);
// const [isLoading, setIsLoading] = useState(false);
const formik = useFormik({
initialValues: {
fullName: "",
Expand All @@ -19,10 +25,22 @@ export default function SignUpForm() {
},
validationSchema: signUpSchema,
onSubmit: async (values) => {
console.log(values);
// const formData = {
// email: values.email,
// password: values.password,
// }
// setError(null);
// setIsLoading(true);

try {
console.log("Form submitted:", values);
} catch (error) {
console.error("Signup error:", error);
// await signup(formData);
alert("User created successfully!");
} catch (err) {
console.log("Signup error:", err);
// setError(err.message || "An error occurred during signup.");
} finally {
// setIsLoading(false);
}
},
});
Expand Down
158 changes: 158 additions & 0 deletions hooks/auth/useAuth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { userService } from "@/services/api";
import { useState, useEffect } from "react";

// Define types for auth state
export interface AuthTokens {
accessToken: string;
refreshToken: string;
}

export interface AuthUser {
id: string;
username: string;
address: string;
email: string | null;
picture: string | null;
isVerified: boolean;
roles: string;
createdAt: string;
updatedAt: string;
}

export interface AuthState {
isAuthenticated: boolean;
user: AuthUser | null;
tokens: AuthTokens | null;
}

// API response types
interface LoginResponse {
message: string;
user?: AuthUser;
tokens: AuthTokens;
}

// Local storage keys
const AUTH_TOKENS_KEY = "auth_tokens";
const AUTH_USER_KEY = "auth_user";

// Helper functions for localStorage
const getStoredTokens = (): AuthTokens | null => {
if (typeof window === "undefined") return null;
const tokensStr = localStorage.getItem(AUTH_TOKENS_KEY);
return tokensStr ? JSON.parse(tokensStr) : null;
};

const getStoredUser = (): AuthUser | null => {
if (typeof window === "undefined") return null;
const userStr = localStorage.getItem(AUTH_USER_KEY);
return userStr ? JSON.parse(userStr) : null;
};

// Set stored values
const setStoredAuth = (tokens: AuthTokens | null, user: AuthUser | null) => {
if (typeof window === "undefined") return;

if (tokens) {
localStorage.setItem(AUTH_TOKENS_KEY, JSON.stringify(tokens));
} else {
localStorage.removeItem(AUTH_TOKENS_KEY);
}

if (user) {
localStorage.setItem(AUTH_USER_KEY, JSON.stringify(user));
} else {
localStorage.removeItem(AUTH_USER_KEY);
}
};

export function useAuth() {
const queryClient = useQueryClient();
const [isInitialized, setIsInitialized] = useState(false);

// Initialize auth state from localStorage
useEffect(() => {
const tokens = getStoredTokens();
const user = getStoredUser();

if (tokens) {
queryClient.setQueryData(["auth"], {
isAuthenticated: true,
tokens,
user,
});
}

setIsInitialized(true);
}, [queryClient]);

const authState = queryClient.getQueryData<AuthState>(["auth"]) || {
isAuthenticated: false,
tokens: null,
user: null,
};

// Create User mutation
const createUserMutation = useMutation<LoginResponse, Error, any>({
mutationFn: userService.createUser,
onSuccess: (data) => {
console.log("User created successfully:", data);
const newAuthState = {
isAuthenticated: true,
tokens: data.tokens,
user: data.user || getStoredUser(),
};

// Update query cache
queryClient.setQueryData(["auth"], newAuthState);

// Store in localStorage
setStoredAuth(data.tokens, data.user || getStoredUser());
},
});

// Login mutation
const loginMutation = useMutation<LoginResponse, Error, any>({
mutationFn: userService.createUser,
onSuccess: (data) => {
console.log("Login successful:", data);
const newAuthState = {
isAuthenticated: true,
tokens: data.tokens,
user: data.user || getStoredUser(),
};

// Update query cache
queryClient.setQueryData(["auth"], newAuthState);

// Store in localStorage
setStoredAuth(data.tokens, data.user || getStoredUser());
},
});

// Logout function
const logout = () => {
queryClient.setQueryData(["auth"], {
isAuthenticated: false,
tokens: null,
user: null,
});

setStoredAuth(null, null);

// Invalidate queries that depend on auth
queryClient.invalidateQueries({ queryKey: ["auth"] });
};

return {
isAuthenticated: authState.isAuthenticated,
user: authState.user,
tokens: authState.tokens,
login: loginMutation.mutateAsync,
signup: createUserMutation.mutateAsync,
logout,
isLoading: loginMutation.isPending,
error: loginMutation.error,
};
}
6 changes: 5 additions & 1 deletion services/api/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ export const API_CONFIG = {
export const API_ENDPOINTS = {
// Auth endpoints
AUTH: {
CREATE: "/auth/login",
CREATE: "/auth/initiate-signup",
VERIFY: "/auth/verify-signup",
LOGIN: "/auth/login",
LOGOUT: "/auth/logout",
REFRESH: "/auth/refresh",
},


Expand Down
46 changes: 42 additions & 4 deletions services/api/userService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,19 @@ import axiosClient from "./axiosClient";
// import { apiClient } from "./client";

interface CreateUserParams {
address: string;
username: string;
picture?: string;
email: string;
phone: string;
password: string;
}

interface VerifySignupParams {
email: string;
otp: string;
}

interface LoginParams {
identifier: string;
password: string;
}

interface User {
Expand Down Expand Up @@ -34,6 +44,34 @@ const createUser = async (params: CreateUserParams): Promise<AuthResponse> => {
return response.data;
};

const verifySignup = async (
params: VerifySignupParams
): Promise<AuthResponse> => {
const response = await axiosClient.post(API_ENDPOINTS.AUTH.VERIFY, params);
return response.data;
};

const login = async (params: LoginParams): Promise<AuthResponse> => {
const response = await axiosClient.post(API_ENDPOINTS.AUTH.LOGIN, params);
return response.data;
};

const logout = async (): Promise<{ message: string }> => {
const response = await axiosClient.post(API_ENDPOINTS.AUTH.LOGOUT);
return response.data;
};

const refreshToken = async (token: string): Promise<AuthResponse> => {
const response = await axiosClient.post(API_ENDPOINTS.AUTH.REFRESH, {
token,
});
return response.data;
};

export const userService = {
createUser,
};
verifySignup,
login,
logout,
refreshToken,
};