Skip to content

Commit

Permalink
Merge pull request #184 from mr-loop-1/feature/name-and-surname
Browse files Browse the repository at this point in the history
replace username with name and surname
  • Loading branch information
erenfn authored Sep 6, 2024
2 parents 95f2674 + e1f1c94 commit fedad32
Show file tree
Hide file tree
Showing 11 changed files with 131 additions and 51 deletions.
25 changes: 25 additions & 0 deletions backend/migrations/20240906060143-add-name-surname-to-users.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
'use strict';

/** @type {import('sequelize-cli').Migration} */
module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.addColumn("users", "name", {
type: Sequelize.STRING(50),
allowNull: false,
});
await queryInterface.addColumn("users", "surname", {
type: Sequelize.STRING(50),
});
await queryInterface.removeColumn("users", "username");
},

down: async (queryInterface, Sequelize) => {
await queryInterface.removeColumn("users", "name");
await queryInterface.removeColumn("users", "surname");
await queryInterface.addColumn("users", "username", {
type: Sequelize.STRING(50),
allowNull: false,
unique: true
});
},
};
4 changes: 2 additions & 2 deletions backend/src/controllers/auth.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ const { TOKEN_LIFESPAN } = require('../utils/constants');

const register = async (req, res) => {
try {
const { username, email, password } = req.body;
const { name, surname, email, password } = req.body;
const existingUser = await User.findOne({ where: { email } });
if (existingUser) return res.status(400).json({ error: "User already exists" });

const hashedPassword = await bcrypt.hash(password, 10);
const newUser = await User.create({ username, email, password: hashedPassword });
const newUser = await User.create({ name, surname, email, password: hashedPassword });
const token = generateToken({ id: newUser.id, email: newUser.email });

await Token.create({ token, userId: newUser.id, type: 'auth' });
Expand Down
19 changes: 14 additions & 5 deletions backend/src/controllers/user.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,18 @@ const getUsersList = async (req, res) => {

const { rows: users, count: totalUsers } = await User.findAndCountAll({
where: {
username: {
[Sequelize.Op.like]: `%${search}%`,
},
[Sequelize.Op.or]: [
{
name: {
[Sequelize.Op.like]: `%${search}%`,
},
},
{
surname: {
[Sequelize.Op.like]: `%${search}%`,
},
},
],
},
limit: parseInt(limit),
offset: parseInt(offset),
Expand All @@ -37,8 +46,8 @@ const getCurrentUser = async (req, res) => {
const userId = req.user.id;
const user = await User.findOne({ where: { id : userId } });
if (user){
const { username, email, role } = user;
return res.status(200).json({ user: { username, email, role } });
const { name, surname, email, role } = user;
return res.status(200).json({ user: { name, surname, email, role } });
}
else{
return res.status(400).json({ error: "User not found" });
Expand Down
6 changes: 4 additions & 2 deletions backend/src/models/User.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ module.exports = (sequelize, DataTypes) => {
primaryKey: true,
autoIncrement: true,
},
username: {
name: {
type: DataTypes.STRING(50),
allowNull: false,
unique: true,
},
surname: {
type: DataTypes.STRING(50),
},
email: {
type: DataTypes.STRING(100),
Expand Down
9 changes: 5 additions & 4 deletions frontend/src/components/Header/Header.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,17 @@ import { getCurrentUser } from '../../services/loginServices';
import Cookies from 'js-cookie';

function Header({ }) {
const initialUsername = Cookies.get('username') || 'username';
const initialFullName = Cookies.get('fullName') || 'John Doe';
const initialRole = Cookies.get('role') || 'role';

const [isDropdownOpen, setIsDropdownOpen] = useState(false);
const [user, setUser] = useState({ username: initialUsername, role: initialRole });
const [user, setUser] = useState({ fullName: initialFullName, role: initialRole });

useEffect(() => {
const fetchUser = async () => {
const userData = await getCurrentUser();
setUser(userData);
const fullName = userData.surname ? userData.name + " " + userData.surname : userData.name;
setUser({ fullName, role: userData.role });
};
fetchUser();
}, [user]);
Expand All @@ -33,7 +34,7 @@ function Header({ }) {
<div className="user-info">
<Avatar src="/vendetta.png" alt="User" size="medium" />
<div className="user-details">
<div className="user-name">{user.username}</div>
<div className="user-name">{user.fullName}</div>
<div className="user-role">{user.role}</div>
</div>
<button className="dropdown-button" onClick={handleDropdownClick}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ import React from 'react';
import PropTypes from 'prop-types';
import styles from './UserTitle.module.scss'

const UserTitle = ({ userName }) => {
const UserTitle = ({ fullName }) => {
return (
<div className={styles.title}>
Hello, {userName}
Hello, {fullName}
</div>
);
};

UserTitle.propTypes = {
userName: PropTypes.string.isRequired,
fullName: PropTypes.string.isRequired,
};

export default UserTitle;
4 changes: 2 additions & 2 deletions frontend/src/scenes/dashboard/Dashboard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import StatisticCardList from "../../components/HomePageComponents/StatisticCard
import CreateActivityButtonList from "../../components/HomePageComponents/CreateActivityButtonList/CreateActivityButtonList";
import { useNavigate } from "react-router-dom";

const Dashboard = ({ username }) => {
const Dashboard = ({ fullName }) => {
const navigate = useNavigate();
const metrics = [
{ metricName: "Popup views", metricValue: 5000, changeRate: 5 },
Expand All @@ -32,7 +32,7 @@ const Dashboard = ({ username }) => {
<>
<div className={styles.container}>
<div className={styles.top}>
<UserTitle userName={username} />
<UserTitle fullName={fullName} />
<DateDisplay />
</div>
<div className={styles.text}>
Expand Down
10 changes: 5 additions & 5 deletions frontend/src/scenes/home/Home.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,22 @@ import { getCurrentUser } from '../../services/loginServices';
import Cookies from 'js-cookie';

const Home = () => {
const initialUsername = Cookies.get('username') || 'username';
const [username, setUsername] = useState(initialUsername);
const initialFullName = Cookies.get('fullName') || 'John Doe';
const [fullName, setFullName] = useState(initialFullName);

useEffect(() => {
const fetchUser = async () => {
const user = await getCurrentUser();
setUsername(user.username);
setFullName(user.surname ? user.name + " " + user.surname : user.name);
};
fetchUser();
}, [username]);
}, [fullName]);

return (
<div className="app">
<div className="content">
<HomePageTemplate>
<Dashboard username={username} />
<Dashboard fullName={fullName} />
</HomePageTemplate>
</div>
</div>
Expand Down
48 changes: 35 additions & 13 deletions frontend/src/scenes/login/CreateAccountPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import CustomLink from '../../components/CustomLink/CustomLink';
import { useAuth } from '../../services/authProvider';

function CreateAccountPage() {
const [formData, setFormData] = useState({ username: '', email: '', password: '' });
const [validation, setValidation] = useState({ isUsernameValid: false, isEmailValid: false, isPasswordValid: false });
const [formData, setFormData] = useState({ name: '', surname: '', email: '', password: '' });
const [validation, setValidation] = useState({ isNameValid: false, isSurnameValid: false, isEmailValid: false, isPasswordValid: false });
const [passwordChecks, setPasswordChecks] = useState({ hasSpecialCharacter: false, atLeastEightCharacters: false });
const [error, setError] = useState('');
const navigate = useNavigate();
Expand All @@ -20,8 +20,11 @@ function CreateAccountPage() {
setFormData({ ...formData, [name]: value });

switch (name) {
case 'username':
setValidation((prev) => ({ ...prev, isUsernameValid: value.length > 0 }));
case 'name':
setValidation((prev) => ({ ...prev, isNameValid: value.length > 0 }));
break;
case 'surname':
setValidation((prev) => ({ ...prev, isSurnameValid: value.length > 0 }));
break;
case 'email':
setValidation((prev) => ({ ...prev, isEmailValid: validateEmail(value) }));
Expand All @@ -43,14 +46,18 @@ function CreateAccountPage() {
const validateEmail = (email) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);

const handleSignUp = async () => {
const { isUsernameValid, isEmailValid, isPasswordValid } = validation;
if (!isUsernameValid || !isEmailValid || !isPasswordValid) {
const { name, surname, email, password } = formData;
const { isNameValid, isSurnameValid, isEmailValid, isPasswordValid } = validation;

if (!isNameValid || (surname && !isSurnameValid) || !isEmailValid || !isPasswordValid) {
alert('Please fill out the form correctly.');
return;
}

const userData = { name: name, surname: surname, email: email, password: password };

try {
const response = await signUp(formData);
const response = await signUp(userData);
login();
navigate('/');
} catch (error) {
Expand All @@ -71,20 +78,35 @@ function CreateAccountPage() {
<h2>Create an account</h2>
<div className="form-group">
<div className='check-div'>
{validation.isUsernameValid && <CheckCircleIcon style={{ color: 'green', fontSize: '20px' }} />}
<label htmlFor="username">Username*:</label>
{validation.isNameValid && <CheckCircleIcon style={{ color: 'green', fontSize: '20px' }} />}
<label htmlFor="name">Name*:</label>
</div>
<input
id="username"
id="name"
type="name"
name="username"
value={formData.username}
name="name"
value={formData.name}
onChange={handleInputChange}
placeholder="Enter your username"
placeholder="Enter your name"
/>
{error && <div className="error-message">{error}</div>}
</div>

<div className="form-group">
<div className='check-div'>
{validation.isSurnameValid && <CheckCircleIcon style={{ color: 'green', fontSize: '20px' }} />}
<label htmlFor="surname">Surname*:</label>
</div>
<input
id="surname"
type="name"
name="surname"
value={formData.surname}
onChange={handleInputChange}
placeholder="Enter your surname"
/>
</div>

<div className="form-group">
<div className='check-div'>
{validation.isEmailValid && <CheckCircleIcon style={{ color: 'green', fontSize: '20px' }} />}
Expand Down
5 changes: 3 additions & 2 deletions frontend/src/services/loginServices.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,15 @@ export const getCurrentUser = async ()=> {
try {
const response = await apiClient.get('users/current-user');
const user = response.data.user;
const fullName = user.surname ? user.name + " " + user.surname : user.name;

Cookies.set('username', user.username);
Cookies.set('fullName', fullName);
Cookies.set('role', user.role);

return user;
} catch (error) {
console.error('Get user error:', error.response);
return {'username': 'John Doe', 'role': 'visitor'}
return {'fullName': 'John Doe', 'role': 'visitor'}
}
};

Expand Down
Loading

0 comments on commit fedad32

Please sign in to comment.