I am developing this project using Spring Boot for backend and react for frontend, I connected this front end and back end. Then Sign Up and Sign in is working without any error but when I am going to get login information to display front end the error message is showing. I created function of the front end. when clicked Login/Sign Up button then it going to user profile that function based on role (USER/OWNER/ADMIN). but related login user details cannot display. The special thing is when I run that API in postman that function is working without any error.
import axios from 'axios';
import React, { useState } from 'react';
import { useNavigate, useLocation } from 'react-router-dom'; // Import useNavigate hook
import ForgotPasswordPopup from '../components/ForgotPasswordPopup';
import EnterCodePopup from '../components/EnterCodePopup';
import ChangePasswordPopup from '../components/ChangePasswordPopup';
import './login.css';
import MailOutlineIcon from '@mui/icons-material/MailOutline';
import LockIcon from '@mui/icons-material/Lock';
import CloseIcon from '@mui/icons-material/Close';
import { GoogleLogin } from '@react-oauth/google'; // Import from @react-oauth/google
export default function Login() {
const [step, setStep] = useState(null);
const navigate = useNavigate(); // Initialize navigate function
const [email, setEmail] = useState(''); // State for email input
const [password, setPassword] = useState('');
const location = useLocation();
const [error, setError] = useState(''); // State to show login errors
// Get the page the user was trying to access before being redirected to login
const redirectTo = location.state?.from?.pathname || '/'; // Defaults to home page if no previous page
const openForgotPassword = () => setStep('forgot');
const openEnterCode = () => setStep('code');
const openChangePassword = () => setStep('change');
const closePopup = () => setStep(null);
// Navigate to the signup page when the signup button is clicked
const handleSignup = () => {
navigate('/signup'); // Navigate to your signup page
};
// Function to handle Google Login success
const handleGoogleSuccess = (response) => {
console.log('Google login successful:', response);
localStorage.setItem('authToken', 'google-auth-token');
navigate(redirectTo); // Navigate to the intended page after successful login
};
// Function to handle Google Login failure
const handleGoogleFailure = (error) => {
console.log('Google login failed:', error);
// Handle failed login here
};
// Function to go back to the previous page
const handleClose = () => {
navigate(-1); // Navigates back to the previous page
};
// Handle email/password form submission
const handleSignIn = async (e) => {
e.preventDefault();
setError(''); // Reset error message
try {
// Send a POST request to the backend API
const response = await axios.post(${process.env.REACT_APP_API_URL}/SignInUser/SignIn, {
email,
password,
});
const { role, token } = response.data; // Assuming your backend returns a user object with a role
console.log('Email login successful');
// Store authentication token in localStorage
localStorage.setItem('authToken',token); // Assuming the token is returned
// Redirect based on user role
switch (role) {
case 'User':
navigate('/userprofile');
break;
case 'Owner':
navigate('/ownerprofile');
break;
case 'Admin':
navigate('/adminprofile');
break;
default:
navigate('/'); // Fallback in case role is unrecognized
}
} catch (error) {
if (error.response) {
// Handle specific errors based on the response from the backend
if (error.response.status === 401) {
setError('Incorrect email or password');
} else {
setError('Login failed. Please try again.');
}
} else {
setError('Login failed. Please try again.');
}
}
};
return (
<div className="login-container">
<div className="login">
<div className="login-left">
<img src="/images/1.png" alt="logo" className="logo"/>
<p className="signup-text">Don't have an account?</p>
<button className="signup-button" onClick={handleSignup}>SIGN UP</button>
<img src="/images/1.1.png" alt="login vector" className='vectorimage1'/>
</div>
<div className="login-right">
{/* Update CloseIcon to use handleClose on click */}
<CloseIcon className="close-icon" onClick={handleClose} />
<div className="login-right-signup">
<p className="signup-text">Don't have an account?</p>
<button className="signup-button" onClick={handleSignup}>SIGN UP</button>
</div>
<h2 className="signin-header">Sign in Here</h2>
<form onSubmit={handleSignIn}>
<div className="input">
<input type="email" placeholder="Email" className="input-field" value={email}
onChange={(e) => setEmail(e.target.value)} // Update email state
/>
<MailOutlineIcon className="icon"/>
<input type="password" placeholder="Password" className="input-field"
value={password}
onChange={(e) => setPassword(e.target.value)} // Update password state
/>
<LockIcon className="icon"/>
</div>
<div className="input-field-container">
<button type="button" className="forgot-password" onClick={openForgotPassword}>Forget Your Password?</button>
</div>
<button type="submit" className="signin-button">SIGN IN</button>
</form>
{error && <p style={{ color: 'red' }}>{error}</p>}
<div className="or-divider"><span>OR</span></div>
{/* Use GoogleLogin from @react-oauth/google */}
<GoogleLogin
onSuccess={handleGoogleSuccess}
onError={handleGoogleFailure}
render={({ onClick, disabled }) => (
<button onClick={onClick} disabled={disabled} className="google-signin-button">
<img src="/images/1.2.png" alt="Google logo" className="googlelogo"/>
Google
</button>
)}
/>
</div>
</div>
{step === 'forgot' && <ForgotPasswordPopup onClose={closePopup} onNext={openEnterCode} />}
{step === 'code' && <EnterCodePopup onClose={closePopup} onNext={openChangePassword} />}
{step === 'change' && <ChangePasswordPopup onClose={closePopup} />}
</div>
);
}
import React,{useState} from 'react';
import NavigationBar from '../../components/NavigationBar';
import Footer from '../../components/Footer';
import UserContent from '../../components/UserProfile/UserContent';
import {Avatar,Typography} from '@mui/material';
import ChatBubbleOutlineIcon from '@mui/icons-material/ChatBubbleOutline';
import StarOutlineIcon from '@mui/icons-material/StarOutline';
import PersonOutlineIcon from '@mui/icons-material/PersonOutline';
import MenuIcon from '@mui/icons-material/Menu';
import './userProfile.css';
const UserProfile = () => {
const [activeMenuItem, setActiveMenuItem] = useState('Profile');
const [isSidebarVisible, setSidebarVisible] = useState(false);
const toggleSidebar = () => {
setSidebarVisible(!isSidebarVisible);
};
return (
<div className="userprofile">
{/* Navigation bar at the top */}
<div className="nav">
<NavigationBar />
</div>
{/* Menu icon for small screens */}
<div className="menu-icon" onClick={toggleSidebar}>
<MenuIcon />
</div>
{/* Main container with sidebar and content */}
<div className={userprofile-container ${isSidebarVisible ? 'show-sidebar' : ''}}>
{/* Sidebar Section */}
<div className={userprofile-sidebar ${isSidebarVisible ? 'show-sidebar' : ''}}>
<div className="sidebar-header">
<Avatar className="avatar" />
<Typography variant="h6" className="sidebar-title"sx={{margin:'2px',fontFamily:'"Josefin Sans", sans-serif'}} >User</Typography>
</div>
<ul className="sidebar-menu">
<li
className={sidebar-menu-item ${activeMenuItem === 'Profile' ? 'active' : ''}}
onClick={() => setActiveMenuItem('Profile')}
>
<PersonOutlineIcon className="menu-icon" />
<span className="menu-text">Profile</span>
</li>
<li
className={sidebar-menu-item ${activeMenuItem === 'Chats' ? 'active' : ''}}
onClick={() => setActiveMenuItem('Chats')}
>
<ChatBubbleOutlineIcon className="menu-icon" />
<span className="menu-text">Chats</span>
</li>
<li
className={sidebar-menu-item ${activeMenuItem === 'Ratings' ? 'active' : ''}}
onClick={() => setActiveMenuItem('Ratings')}
>
<StarOutlineIcon className="menu-icon" />
<span className="menu-text">Ratings</span>
</li>
</ul>
</div>
{/* Main Content Section */}
<div className="userprofile-content">
{/* Content can go here */}
<UserContent
activeMenuItem={activeMenuItem}
setActiveMenuItem={setActiveMenuItem}
/>
</div>
</div>
<div className='footer'>
<Footer/>
</div>
</div>
);
};
export default UserProfile;
import axios from 'axios';
// Create an Axios instance with a base URL
const api = axios.create({
baseURL: process.env.REACT_APP_API_URL,
});
// Request interceptor for adding token
api.interceptors.request.use(
(config) => {
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = Bearer ${token};
}
return config;
},
(error) => Promise.reject(error)
);
// Function to fetch all boarding places
export const fetchBoardingPlaces = async () => {
try {
const response = await api.get('/boarding-places');
return response.data;
} catch (error) {
console.error('Error fetching boarding places:', error);
throw new Error('Unable to fetch boarding places. Please try again later.');
}
};
// Function to fetch a boarding place by ID
export const fetchBoardingPlaceById = async (id) => {
try {
const response = await api.get(/boarding-places/${id});
return response.data;
} catch (error) {
console.error(Error fetching boarding place ${id}:, error);
throw new Error(Unable to fetch boarding place ${id}.);
}
};
// Change user password
export const changePassword = async (newPassword) => {
const token = localStorage.getItem('token'); // Retrieve token
const response = await api.put('/change-password', { password: newPassword }, {
headers: {
Authorization: Bearer ${token},
},
});
return response.data; // Return success message or user data if needed
};
// Fetch user data
export const fetchUserData = async (token, userId) => {
try {
const response = await api.get(/loginuser/${userId}, {
headers: {
Authorization: Bearer ${token},
},
});
return response.data; // Return user data
} catch (error) {
console.error('Error fetching user data:', error);
throw error; // Propagate the error for further handling
}
};
import React from 'react';
import UserAccount from './UserAccount';
import UserChats from './UserChats';
import UserRatings from './UserRatings';
const UserContent = ({ activeMenuItem }) => {
return (
<div>
{activeMenuItem === 'Profile' && <UserAccount/>}
{activeMenuItem === 'Chats' && <UserChats />}
{activeMenuItem === 'Ratings' && <UserRatings />}
</div>
);
};
export default UserContent;
import React, { useState, useEffect } from 'react';
import { TextField, Button, Typography, Container, Grid } from '@mui/material';
import { fetchUserData, changePassword } from '../../apiService'; // Import the API functions
const UserAccount = () => {
const [userData, setUserData] = useState({
userId: '',
email: '',
name: '',
});
const [newPassword, setNewPassword] = useState('');
const [confirmPassword, setConfirmPassword] = useState('');
const [error, setError] = useState('');
const [successMessage, setSuccessMessage] = useState('');
useEffect(() => {
const fetchUserDetails = async () => {
try {
const data = await fetchUserData(); // Call API to get user data
setUserData(data);
} catch (error) {
console.error('Error fetching user data:', error);
}
};
fetchUserDetails();
}, []);
const handleChangePassword = async (e) => {
e.preventDefault();
setError('');
setSuccessMessage('');
// Basic validation for password change
if (!newPassword || !confirmPassword) {
setError('Both password fields are required.');
return;
}
if (newPassword !== confirmPassword) {
setError('Passwords do not match.');
return;
}
try {
await changePassword(newPassword); // Call API to update the password
setSuccessMessage('Password changed successfully!');
setNewPassword('');
setConfirmPassword('');
} catch (error) {
setError('Error changing password. Please try again.');
}
};
return (
<Container maxWidth="sm" style={{ padding: '20px', backgroundColor: '#f5f5f5', borderRadius: '8px' }}>
<Typography variant="h5" gutterBottom style={{ color: 'gray', fontSize: '36px' }}>
User Account
</Typography>
{/* Display user details */}
<Grid container spacing={1}>
<Grid item xs={12}>
<Typography variant="h6">User ID: {userData.userId}</Typography>
</Grid>
<Grid item xs={12}>
<Typography variant="h6">Email: {userData.email}</Typography>
</Grid>
<Grid item xs={12}>
<Typography variant="h6">Name: {userData.name}</Typography>
</Grid>
</Grid>
<Typography variant="h6" style={{ marginTop: '20px', color: '#72d6c9' }}>Change Password</Typography>
<form onSubmit={handleChangePassword}>
<TextField
label="New Password"
type="password"
fullWidth
value={newPassword}
onChange={(e) => setNewPassword(e.target.value)}
required
/>
<TextField
label="Confirm Password"
type="password"
fullWidth
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
required
/>
{error && <Typography color="error">{error}</Typography>}
{successMessage && <Typography color="primary">{successMessage}</Typography>}
<Button type="submit" variant="contained" color="primary" fullWidth style={{ marginTop: '20px', backgroundColor: '#72d6c9' }}>
Change Password
</Button>
</form>
</Container>
);
};
export default UserAccount;
package com.example.testing.controller;
import com.example.testing.dto.LoginUserDto;
import com.example.testing.dto.ReturnLoginUserDto;
import com.example.testing.service.LoginUserService;
import com.example.testing.utill.JWTAuthenticator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@CrossOrigin(origins = "http://localhost:3000")
@RestController
@RequestMapping("/loginuser")
public class LoginUserController {
@Autowired
LoginUserService service;
@Autowired
JWTAuthenticator jwtAuthenticator;
@PostMapping("/saveLoginUser")
public ResponseEntity<Object> saveLoginUser(@RequestBody LoginUserDto loginUserDto){
ReturnLoginUserDto returnLoginUserDto = service.saveLoginUser(loginUserDto);
if (returnLoginUserDto != null) {
return new ResponseEntity<>("Register Success", HttpStatus.OK);
} else {
return new ResponseEntity<>("Already regitered with this Email", HttpStatus.CREATED);
}
}
@GetMapping("/{id}")
public ResponseEntity<Object> getLoginUserById(@PathVariable Integer id) {
LoginUserDto loginUserDto = service.getLoginUserById(id);
if (loginUserDto != null) {
return new ResponseEntity<>(loginUserDto, HttpStatus.OK);
}
return new ResponseEntity<>("User not found", HttpStatus.NOT_FOUND);
}
}
package com.example.testing.service;
import com.example.testing.dto.LoginUserDto;
import com.example.testing.dto.ReturnLoginUserDto;
import com.example.testing.entity.LoginUser;
import com.example.testing.repo.LoginUserRepo;
import com.example.testing.utill.SignInMail;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class LoginUserService {
@Autowired
LoginUserRepo loginUserRepo;
@Autowired
SignInMail signInMail;
@Autowired
PasswordEncoder passwordEncoder;
public ReturnLoginUserDto saveLoginUser(LoginUserDto loginUserDto) {
String encodedPassword = passwordEncoder.encode(loginUserDto.getPassword());
if (loginUserRepo.existsLoginUserByEmail(loginUserDto.getEmail())) {
return null;
}
LoginUser save = loginUserRepo.save(
new LoginUser(loginUserDto.getContactNo(),encodedPassword,loginUserDto.getEmail(),loginUserDto.getRole()));
signInMail.sendEmail(loginUserDto);
return new ReturnLoginUserDto(save.getEmail(), save.getId());
}
public List<LoginUserDto> getAllLoginUser(){
List<LoginUser> all = loginUserRepo.findAll();
List<LoginUserDto> loginUserDtos = new ArrayList<>();
for(LoginUser loginUser : all){
loginUserDtos.add(new LoginUserDto(loginUser.getId(), loginUser.getContactNo(), loginUser.getPassword(), loginUser.getEmail(), loginUser.getRole()));
}
return loginUserDtos;
}
}
package com.example.testing.entity;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
public class LoginUser {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private Integer contactNo;
private String password;
private String email;
private String role;
@OneToOne(mappedBy = "loginUser", cascade = CascadeType.ALL)
private BoardingOwner boardingOwner;
public LoginUser(Integer contactNo, String password, String email, String role) {
this.contactNo = contactNo;
this.password = password;
this.email = email;
this.role = role;
}
public LoginUser(Integer id, Integer contactNo, String password, String email) {
}
}
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@AllArgsConstructor
@NoArgsConstructor
@Data
public class LoginUserDto {
private Integer id;
private Integer contactNo;
private String password;
private String email;
public String role;
}
we need to show the details of login user its own profile, we need to know, how to integrate correctly.
2
Answers
Since the API is working without issues in Postman but your front-end application is encountering CORS errors (As the console suggest) it suggests that you need to configure
CORS (Cross-Origin Resource Sharing)
to allow requests from your front end.Here is a sample CORS configuration that you can add to your
Spring Boot
application.Note that additionally, as the console logs show some undefined values in the URLs, you may want to verify that all URL paths are constructed correctly on the front end. Check that any dynamic parameters are properly initialized before making the API requests.
There is an API issue while accessing through different origins, it is followed for best security practice, to fix this, you can use the @CrossOrigin Annotation. This can be applied to controller or specific methods to allow access.