Skip to content
Open
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: 6 additions & 1 deletion src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { useState } from "react";
import { RouterProvider } from "react-router-dom";
import { MyProvider } from "./context/MyContext";

import routes from "./routes";
import "./App.css";

function App() {
return <RouterProvider router={routes} />;
return (
<MyProvider>
<RouterProvider router={routes} />
</MyProvider>
);
}

export default App;
4 changes: 2 additions & 2 deletions src/api/api.config.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
export const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:8000';
export const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:8080';

export const endpoints = {
// Auth endpoints
register: `${API_BASE_URL}/api/v1/users/register`,
register: `${API_BASE_URL}/users/create`,
login: `${API_BASE_URL}/api/v1/users/login`,
logout: `${API_BASE_URL}/api/v1/users/logout`,

Expand Down
19 changes: 11 additions & 8 deletions src/api/auth/register.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,22 @@ import api from "../api.intercepter";

/**
* Register function that creates a new user account
* @param {string} firstName - User's first name
* @param {string} lastName - User's last name
* @param {string} email - User email
* @param {string} password - User password
* @returns {Promise} - Promise that resolves to the registration response
* @param {Object} userData - User registration data
* @param {string} userData.name - User's full name
* @param {string} userData.username - User's username
* @param {string} userData.email - User email
* @param {string} userData.password - User password
* @returns {Promise} - Promise that resolves to the registration response (timestamp)
*/
export const registerAPI = async (firstName, lastName, email, password) => {
export const registerAPI = async (userData) => {
try {
const { name, username, email, password } = userData;
const response = await api.post(endpoints.register, {
firstName,
lastName,
name,
username,
email,
password,
blogs: []
});
return response.data;
} catch (error) {
Expand Down
18 changes: 17 additions & 1 deletion src/context/MyContext.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,28 @@ import { createContext, useContext, useState, useCallback } from "react";
const MyContext = createContext();

export const MyProvider = ({ children }) => {
const [userProfile, setUserProfile] = useState(null);
const [userProfile, setUserProfile] = useState(() => {
const storedUser = localStorage.getItem('user');
return storedUser ? JSON.parse(storedUser) : null;
});
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);
const [profileFetched, setProfileFetched] = useState(false);
const [isAuthenticated, setIsAuthenticated] = useState(
() => localStorage.getItem('isAuthenticated') === 'true'
);

const updateUserProfile = useCallback((profile) => {
setUserProfile(profile);
setError(null);
setProfileFetched(true);
}, []);

const setAuthenticatedState = useCallback((authenticated) => {
setIsAuthenticated(authenticated);
localStorage.setItem('isAuthenticated', authenticated.toString());
}, []);

const setLoadingState = useCallback((loading) => {
setIsLoading(loading);
}, []);
Expand All @@ -31,6 +42,9 @@ export const MyProvider = ({ children }) => {
setUserProfile(null);
setProfileFetched(false);
setError(null);
setIsAuthenticated(false);
localStorage.removeItem('isAuthenticated');
localStorage.removeItem('user');
}, []);

return (
Expand All @@ -40,11 +54,13 @@ export const MyProvider = ({ children }) => {
isLoading,
error,
profileFetched,
isAuthenticated,
updateUserProfile,
setLoadingState,
setErrorState,
clearError,
clearUserProfile,
setAuthenticatedState,
}}
>
{children}
Expand Down
62 changes: 53 additions & 9 deletions src/pages/RegisterPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ import { useState } from "react";
import { Link, useNavigate } from "react-router-dom";
import { useMyContext } from "../context/MyContext";
import { FiEye, FiEyeOff } from "react-icons/fi";
import { registerAPI } from "../api";
import { setAuthData } from "../api/utils/auth";
import "./AuthPages.css";

const RegisterPage = () => {
const [formData, setFormData] = useState({
name: "",
username: "",
email: "",
password: "",
confirmPassword: "",
Expand All @@ -15,7 +18,7 @@ const RegisterPage = () => {
const [isLoading, setIsLoading] = useState(false);
const [showPassword1, setShowPassword1] = useState(false);
const [showPassword2, setShowPassword2] = useState(false);
const { updateUserProfile, setLoadingState, setErrorState } = useMyContext();
const { setLoadingState, setErrorState, updateUserProfile, setAuthenticatedState } = useMyContext();
const navigate = useNavigate();

const handleChange = (e) => {
Expand All @@ -42,6 +45,14 @@ const RegisterPage = () => {
newErrors.name = "Name must be at least 2 characters";
}

if (!formData.username.trim()) {
newErrors.username = "Username is required";
} else if (formData.username.trim().length < 3) {
newErrors.username = "Username must be at least 3 characters";
} else if (!/^[a-zA-Z0-9_]+$/.test(formData.username)) {
newErrors.username = "Username can only contain letters, numbers, and underscores";
}

if (!formData.email.trim()) {
newErrors.email = "Email is required";
} else if (!/\S+@\S+\.\S+/.test(formData.email)) {
Expand Down Expand Up @@ -75,20 +86,34 @@ const RegisterPage = () => {
setLoadingState(true);

try {
// Simulate API call - replace with actual registration logic
await new Promise((resolve) => setTimeout(resolve, 2000));
// Call the actual register API
const response = await registerAPI({
name: formData.name,
username: formData.username,
email: formData.email,
password: formData.password
});

// Mock successful registration - replace with actual API response
const mockUser = {
id: Date.now(),
// Registration successful - auto-login the user
const userData = {
id: response, // Using response as user ID
name: formData.name,
username: formData.username,
email: formData.email,
};

updateUserProfile(mockUser);
navigate("/dashboard");


// Set authentication state and user data
setAuthenticatedState(true);
localStorage.setItem('user', JSON.stringify(userData));
updateUserProfile(userData);
setErrorState(""); // Clear any previous errors

// Force a full page reload to dashboard to bypass React state timing issues
window.location.replace('/dashboard');
} catch (error) {
setErrorState("Registration failed. Please try again.");
setErrorState(error.message || "Registration failed. Please try again.");
} finally {
setIsLoading(false);
setLoadingState(false);
Expand Down Expand Up @@ -124,6 +149,25 @@ const RegisterPage = () => {
)}
</div>

<div className="form-group">
<label htmlFor="username" className="form-label">
Username
</label>
<input
type="text"
id="username"
name="username"
value={formData.username}
onChange={handleChange}
className={`form-input ${errors.username ? "error" : ""}`}
placeholder="Choose a username"
disabled={isLoading}
/>
{errors.username && (
<span className="error-message">{errors.username}</span>
)}
</div>

<div className="form-group">
<label htmlFor="email" className="form-label">
Email Address
Expand Down
8 changes: 6 additions & 2 deletions src/routes/ProtectedRoute.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { Navigate } from "react-router-dom";
import { isAuthenticated } from "../api";
import { useMyContext } from "../context/MyContext";

function ProtectedRoute({ children }) {
if (!isAuthenticated()) {
const { userProfile, isAuthenticated } = useMyContext();

// Check if user is authenticated using context state
if (!userProfile || !isAuthenticated) {
console.log('ProtectedRoute - Redirecting to login');
return <Navigate to="/login" replace />;
}

Expand Down
7 changes: 4 additions & 3 deletions src/routes/PublicRoute.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Navigate } from "react-router-dom";
import { isAuthenticated } from "../api";
import { useMyContext } from "../context/MyContext";

function PublicRoute({ children }) {
if (isAuthenticated()) {
return <Navigate to="/" replace />;
const { isAuthenticated } = useMyContext();
if (isAuthenticated) {
return <Navigate to="/dashboard" replace />;
}

return children;
Expand Down