Skip to content

Commit

Permalink
Merge pull request #161 from Code-Hammers/CHE-113/story/Profiles-Impr…
Browse files Browse the repository at this point in the history
…ovements

[CHE 113] Profiles Improvements
  • Loading branch information
brok3turtl3 authored Aug 10, 2024
2 parents 4224d74 + f19b3f7 commit 1cb7462
Show file tree
Hide file tree
Showing 20 changed files with 795 additions and 79 deletions.
Binary file added .DS_Store
Binary file not shown.
50 changes: 46 additions & 4 deletions __tests__/profileController.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,30 @@ xdescribe('Profile Controller Tests', () => {
mockRequest = {
params: { userID: '65117c94f000c9930ef5c0ee' },
body: {
firstName: 'Bobby',
lastName: 'Orr',
availabilityForNetworking: true,
careerInformation: {
currentPosition: {
company: 'CodeHammers',
title: 'Developer',
},
pastPositions: [
{
company: 'CodeHammers',
title: 'Junior Developer',
startDate: '2020-01-01',
endDate: '2021-01-01',
},
],
},
cohort: 'ECRI-TEST',
email: '[email protected]',
gitHubProfile: 'Ghub',
linkedInProfile: 'Lin',
nickName: 'Johnny',
personalBio: 'I love dogs!',
skills: ['Javascript', 'Typescript', 'React', 'Nodejs'],
socialMediaLinks: 'SMlinks',
specializations: ['Javascript', 'React'],
},
};
mockResponse = {
Expand All @@ -114,9 +135,30 @@ xdescribe('Profile Controller Tests', () => {
it('should handle profile update', async () => {
(Profile.findOneAndUpdate as jest.Mock).mockResolvedValue({
_id: '65117c94f000c9930ef5c0ee',
firstName: 'Bobby',
lastName: 'Orr',
availabilityForNetworking: true,
careerInformation: {
currentPosition: {
company: 'CodeHammers',
title: 'Developer',
},
pastPositions: [
{
company: 'CodeHammers',
title: 'Junior Developer',
startDate: '2020-01-01',
endDate: '2021-01-01',
},
],
},
cohort: 'ECRI-TEST',
email: '[email protected]',
gitHubProfile: 'Ghub',
linkedInProfile: 'Lin',
nickName: 'Johnny',
personalBio: 'I love dogs!',
skills: ['Javascript', 'Typescript', 'React', 'Nodejs'],
socialMediaLinks: 'SMlinks',
specializations: ['Javascript', 'React'],
});

await updateProfile(mockRequest as Request, mockResponse as Response, mockNext);
Expand Down
Binary file added client/src/assets/blogLogo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added client/src/assets/github_icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added client/src/assets/linkedInLogo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added client/src/assets/twitterLogo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 9 additions & 9 deletions client/src/components/Header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,16 @@ const Header = () => {

return (
<div
className="fixed top-0 left-0 right-0 bg-gray-600 text-white p-4 md:p-6 flex items-center justify-between"
className="bg-gray-600 fixed flex items-center justify-between left-0 md:p-6 p-4 right-0 text-white top-0"
style={{ margin: '10px 20px 0 20px', zIndex: 1000 }}
>
<Link to="/app/main" className="flex items-center">
<img src={logo} alt="Code Hammers Logo" className="h-12 md:h-16" />
<h1 className="ml-3 text-xl md:text-2xl font-bold">Code Hammers</h1>
<h1 className="font-bold md:text-2xl ml-3 text-xl">Code Hammers</h1>
</Link>

<div className="flex-grow mx-10">
<div className="flex justify-evenly space-x-4 md:space-x-6 lg:space-x-10">
<div className="flex justify-evenly lg:space-x-10 md:space-x-6 space-x-4">
<Link
to="/app/directory"
className={`text-lg md:text-xl ${
Expand All @@ -60,15 +60,15 @@ const Header = () => {
</Link>
<Link
to="/app/profiles"
className={`text-lg md:text-xl ${
className={`md:text-xl text-lg ${
currentPath === 'profiles' ? 'text-gray-300' : 'hover:text-gray-300'
} transition transform hover:scale-105`}
>
Profiles
</Link>
<Link
to="/app/forums"
className={`text-lg md:text-xl ${
className={`md:text-xl text-lg ${
currentPath === 'forums' ? 'text-gray-300' : 'hover:text-gray-300'
} transition transform hover:scale-105`}
>
Expand All @@ -79,18 +79,18 @@ const Header = () => {
<div className="relative">
<button
onClick={() => setShowDropdown(!showDropdown)}
className="bg-gray-700 hover:bg-gray-800 font-bold py-2 px-4 rounded"
className="bg-blue-500 font-bold hover:bg-blue-700 px-4 py-2 rounded text-white"
>
Account
</button>
{showDropdown && (
<div
ref={dropdownRef}
className="absolute right-0 mt-2 py-2 w-48 bg-gray-700 rounded-md shadow-xl z-20"
className="absolute bg-gray-700 mt-2 py-2 right-0 rounded-md shadow-xl w-48 z-20"
>
<a
href="#!"
className="block px-4 py-2 text-sm text-white hover:bg-gray-800"
className="block hover:bg-gray-800 px-4 py-2 text-sm text-white"
onClick={() => {
navigate('/app/editProfile');
setShowDropdown(false);
Expand All @@ -100,7 +100,7 @@ const Header = () => {
</a>
<a
href="#!"
className="block px-4 py-2 text-sm text-white hover:bg-gray-800"
className="block hover:bg-gray-800 px-4 py-2 text-sm text-white"
onClick={handleLogout}
>
Logout
Expand Down
53 changes: 53 additions & 0 deletions client/src/components/ProfileInput/ProfileInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React from 'react';

interface EditProfileInputProps {
label: string;
type: string;
value: string;
name: string;
onChange: (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
onKeyDown?: (e: React.KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>) => void; // Add onKeyDown as optional
placeholder?: string;
}

const EditProfileInput = ({
label,
type,
value,
name,
onChange,
onKeyDown,
placeholder,
}: EditProfileInputProps) => {
return (
<div className="mb-4">
<label className="block font-bold mb-2 text-sm" htmlFor={name}>
{label}
</label>
{type === 'textarea' ? (
<textarea
className="bg-gray-800 p-2 rounded text-white w-full"
id={name}
name={name}
value={value}
onChange={onChange}
style={{ maxHeight: '200px' }}
maxLength={1000}
/>
) : (
<input
className="bg-gray-800 p-2 rounded text-white w-full"
id={name}
name={name}
type={type}
value={value}
onChange={onChange}
onKeyDown={onKeyDown}
placeholder={placeholder}
/>
)}
</div>
);
};

export default EditProfileInput;
17 changes: 13 additions & 4 deletions client/src/components/ProfileThumb/ProfileThumb.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,27 @@ interface ProfileThumbProps {
const ProfileThumb = ({ profile }: ProfileThumbProps) => {
const defaultImage = 'https://picsum.photos/200';

const shortenBio = (bio: string | undefined, wordLimit: number) => {
if (!bio) return;
const words: string[] = bio.split(' ');
if (words.length > wordLimit) {
return words.slice(0, wordLimit).join(' ') + '...';
}
return bio;
};

return (
<div className="bg-gradient-to-r from-gray-700 via-gray-800 to-gray-900 text-white p-4 rounded-lg flex flex-col items-center justify-center h-64 w-64">
<div className="bg-gradient-to-r flex flex-col from-gray-700 h-64 items-center justify-center p-4 rounded-lg text-white to-gray-900 via-gray-800 w-64">
<img
src={profile.profilePhoto || defaultImage}
alt={profile.firstName || 'Default Profile'}
className="rounded-full h-24 w-24 object-cover mb-4"
className="h-24 mb-4 object-cover rounded-full w-24"
/>

<h1 className="text-xl font-bold mb-2">
<h1 className="font-bold mb-2 text-xl">
{profile.firstName} {profile.lastName}
</h1>
<h2 className="text-md mb-2">{profile.personalBio}</h2>
<h2 className="max-h-10 mb-2 text-xs">{shortenBio(profile.personalBio, 8)}</h2>
</div>
);
};
Expand Down
10 changes: 9 additions & 1 deletion client/src/features/userProfile/userProfileSlice.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import axios from 'axios';
import { IProfile } from '../../../types/profile';
import { NavigateFunction } from 'react-router-dom';

export interface ProfileState {
profile: IProfile | null;
Expand Down Expand Up @@ -31,11 +32,18 @@ export const fetchUserProfile = createAsyncThunk(
},
);

interface UpdateUserProfileArgs extends Partial<IProfile> {
userID: string;
navigate: NavigateFunction;
}

export const updateUserProfile = createAsyncThunk(
'profile/updateUserProfile',
async ({ userID, ...updateData }: Partial<IProfile> & { userID: string }, thunkAPI) => {
async ({ userID, navigate, ...updateData }: UpdateUserProfileArgs, thunkAPI) => {
try {
console.log('userId before axios call: ', userID);
const response = await axios.put(`/api/profiles/${userID}`, updateData);
navigate(`/app/profile/${userID}`);
return response.data;
} catch (error) {
let errorMessage = 'An error occurred during profile update';
Expand Down
Loading

0 comments on commit 1cb7462

Please sign in to comment.