Skip to content

Commit

Permalink
Merge pull request #85 from sympoll/fix-upload-user-pictures
Browse files Browse the repository at this point in the history
Fix upload user pictures and more
  • Loading branch information
Idan-sh authored Sep 8, 2024
2 parents ef35c09 + 5618b0d commit 5c5cbca
Show file tree
Hide file tree
Showing 9 changed files with 117 additions and 33 deletions.
9 changes: 3 additions & 6 deletions src/cmps/feed/poll/Poll.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { useUser } from "../../../context/UserContext";
import DeletePollButton from "../../global/DeletePollButton";
import { useMembers } from "../../../context/MemebersContext";
import { UserRoleName } from "../../../models/enum/UserRoleName.enum";
import { fetchPicture } from "../../../services/media.service";

interface PollProps {
pollId: string;
Expand Down Expand Up @@ -186,9 +187,7 @@ export default function Poll({
<div className="poll-info-title">
<div className="poll-info-title__row1">
<ProfilePicture
imageUrl={
creatorProfilePictureUrl ? creatorProfilePictureUrl : defaultProfilePictureUrl
}
imageUrl={creatorProfilePictureUrl}
altText={creatorName + "'s profile picture"}
onClick={navigateToCreatorProfile}
></ProfilePicture>
Expand All @@ -213,9 +212,7 @@ export default function Poll({
<div className="poll-info-title">
<div className="poll-info-title__row1">
<ProfilePicture
imageUrl={
groupProfilePictureUrl ? groupProfilePictureUrl : defaultGroupProfilePictureUrl
}
imageUrl={groupProfilePictureUrl}
altText={creatorName + "'s profile picture"}
onClick={navigateToGroupProfile}
></ProfilePicture>
Expand Down
18 changes: 16 additions & 2 deletions src/cmps/global/ProfilePicture.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
import defaultProfilePictureUrl from "/imgs/profile/blank-profile-picture.jpg";
import { fetchPicture } from "../../services/media.service";

interface ProfilePictureProps {
imageUrl: string;
Expand All @@ -14,6 +16,18 @@ export default function ProfilePicture({
altText = "Profile Picture"
}: ProfilePictureProps) {
const [isHovered, setIsHovered] = useState(false);
const [image, setImage] = useState<string>(defaultProfilePictureUrl)

useEffect(() => {
fetchPicture(imageUrl)
.then((data) => {
console.log("Fetched user's profile picture");
setImage(data ?? defaultProfilePictureUrl);
})
.catch((error) => {
console.log("Unable to fetch user's profile picture");
});
},[])

return (
<div
Expand All @@ -32,7 +46,7 @@ export default function ProfilePicture({
height: size,
opacity: onClick ? (isHovered ? 0.9 : 1) : 1
}}
src={imageUrl}
src={image}
alt={altText}
onMouseEnter={() => setIsHovered(true)} // Set hover state to true on mouse enter
onMouseLeave={() => setIsHovered(false)} // Reset hover state on mouse leave
Expand Down
43 changes: 34 additions & 9 deletions src/cmps/profile/GroupProfile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { UserRoleName } from "../../models/enum/UserRoleName.enum";
import { fetchUserData } from "../../services/user.profile.service";
import defaultProfilePictureUrl from "/imgs/profile/blank-group-profile-picture.jpg";
import defaultProfileBannerUrl from "/imgs/profile/blank-profile-banner.jpg";
import { uploadGroupProfileImage } from "../../services/media.service";
import { fetchPicture, uploadGroupProfileImage } from "../../services/media.service";
import { useUser } from "../../context/UserContext";

export default function GroupInfo() {
Expand All @@ -45,6 +45,10 @@ export default function GroupInfo() {
const [isProfilePictureMenuVisible, setIsProfilePictureMenuVisible] = useState<boolean>(false);
const [isProfileBannerMenuVisible, setIsProfileBannerMenuVisible] = useState<boolean>(false);

const [canSetPictures, setCanSetPictures] = useState(false);
const [profileImageSrc, setProfileImageSrc] = useState<string>(defaultProfilePictureUrl);
const [bannerImageSrc, setBannerImageSrc] = useState<string>(defaultProfileBannerUrl);

const [isUserHasPermissionToAddMember, setIsUserHasPermissionToAddMember] =
useState<boolean>(false);
const [isUserHasPermissionToRmvMember, setIsUserHasPermissionToRmvMember] =
Expand All @@ -70,6 +74,7 @@ export default function GroupInfo() {
.then((data) => {
console.log("Fetched group data for group with ID: ", groupId, data);
setGroupData(data);
setCanSetPictures(true);
setIsLoading(false);
})
.catch((error) => {
Expand All @@ -94,6 +99,30 @@ export default function GroupInfo() {
fetchUserPermissionsInCommandBar();
}, [members]);

useEffect(() => {
if(canSetPictures){
fetchPicture(groupData?.profilePictureUrl)
.then((data) => {
console.log("Fetched group's profile picture");
setProfileImageSrc(data ?? defaultProfilePictureUrl);
})
.catch((error) => {
console.log("Unable to fetch group's profile picture");
});

fetchPicture(groupData?.profileBannerUrl)
.then((data) => {
console.log("Fetched group's bannner picture");
setBannerImageSrc(data ?? defaultProfileBannerUrl);
})
.catch((error) => {
console.log("Unable to fetch group's banner picture");
});

setCanSetPictures(false);
}
}, [canSetPictures])

const fetchUserPermissionsInCommandBar = () => {
console.log("Fetching user permissions in group");
const userRole = getMemberRole(userId);
Expand Down Expand Up @@ -158,6 +187,7 @@ export default function GroupInfo() {
(prevGroupData) =>
prevGroupData && { ...prevGroupData, profilePictureUrl: response.imageUrl }
);
setCanSetPictures(true);
} catch (error) {
console.error("Failed to upload group profile picture: ", error);
}
Expand All @@ -173,6 +203,7 @@ export default function GroupInfo() {
(prevGroupData) =>
prevGroupData && { ...prevGroupData, profileBannerUrl: response.imageUrl }
);
setCanSetPictures(true);
} catch (error) {
console.error("Failed to upload group profile banner: ", error);
}
Expand Down Expand Up @@ -242,9 +273,7 @@ export default function GroupInfo() {
>
<div>
<img
src={
groupData.profileBannerUrl ? groupData.profileBannerUrl : defaultProfileBannerUrl
}
src={bannerImageSrc}
alt="Banner"
className="group-info__banner-img"
/>
Expand Down Expand Up @@ -281,11 +310,7 @@ export default function GroupInfo() {
>
<div>
<img
src={
groupData.profilePictureUrl
? groupData.profilePictureUrl
: defaultProfilePictureUrl
}
src={profileImageSrc}
alt="Profile"
className="group-info__profile-img"
/>
Expand Down
51 changes: 43 additions & 8 deletions src/cmps/profile/UserProfile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
import LoadingAnimation from "../global/LoadingAnimation";
import { getTimePassed } from "../../services/poll.service";
import ContentPageMessage from "../content-page/messege/ContentPageMessage";
import { uploadUserProfileImage } from "../../services/media.service";
import { fetchPicture, uploadUserProfileImage } from "../../services/media.service";
import defaultProfilePictureUrl from "/imgs/profile/blank-profile-picture.jpg";
import defaultProfileBannerUrl from "/imgs/profile/blank-profile-banner.jpg";
import ProfilePicture from "../global/ProfilePicture";
Expand All @@ -30,6 +30,11 @@ export default function UserProfile() {

const [isProfilePictureMenuVisible, setIsProfilePictureMenuVisible] = useState<boolean>(false);
const [isProfileBannerMenuVisible, setIsProfileBannerMenuVisible] = useState<boolean>(false);
const [canSetPictures, setCanSetPictures] = useState(false);
const [profileImageSrc, setProfileImageSrc] = useState<string>(defaultProfilePictureUrl);
const [bannerImageSrc, setBannerImageSrc] = useState<string>(defaultProfileBannerUrl);
const { user } = useUser();

const navigate = useNavigate();

const [isEditDescriptionMenuVisible, setIsEditDescriptionMenuVisible] = useState<boolean>(false);
Expand All @@ -54,6 +59,7 @@ export default function UserProfile() {
console.log("Fetched user data for user with ID: ", userId, data);
setUserData(data);
setDescriptionText(data.description || defaultDescription);
setCanSetPictures(true);
setIsLoading(false);
})
.catch((error) => {
Expand All @@ -71,8 +77,33 @@ export default function UserProfile() {
console.log("Unable to fetch groups of user with ID " + userId);
setErrorMessage("Unable to fetch groups of user with ID " + userId);
});

}, [userId]);

useEffect(() => {
if(canSetPictures){
fetchPicture(userData?.profilePictureUrl)
.then((data) => {
console.log("Fetched user's profile picture");
setProfileImageSrc(data ?? defaultProfilePictureUrl);
})
.catch((error) => {
console.log("Unable to fetch user's profile picture");
});

fetchPicture(userData?.profileBannerUrl)
.then((data) => {
console.log("Fetched user's bannner picture");
setBannerImageSrc(data ?? defaultProfileBannerUrl);
})
.catch((error) => {
console.log("Unable to fetch user's banner picture");
});

setCanSetPictures(false);
}
}, [canSetPictures])

const handleProfileImageUpload = async (event: ChangeEvent<HTMLInputElement>) => {
console.log("User profile picture was added, uploading...");
const file = event.target.files?.[0];
Expand All @@ -92,6 +123,7 @@ export default function UserProfile() {
(prevUserData) =>
prevUserData && { ...prevUserData, profilePictureUrl: response.imageUrl }
);
setCanSetPictures(true);
} catch (error) {
console.error("Failed to upload user profile picture: ", error);
}
Expand All @@ -105,8 +137,9 @@ export default function UserProfile() {
// Update the local user data to include the newly uploaded profile banner
setUserData(
(prevUserData) =>
prevUserData && { ...prevUserData, bannerPictureUrl: response.imageUrl }
prevUserData && { ...prevUserData, profileBannerUrl: response.imageUrl }
);
setCanSetPictures(true);
} catch (error) {
console.error("Failed to upload user profile banner: ", error);
}
Expand Down Expand Up @@ -165,11 +198,15 @@ export default function UserProfile() {
};

const toggleProfilePictureMenu = () => {
setIsProfilePictureMenuVisible(!isProfilePictureMenuVisible);
if(userId === user?.userId){
setIsProfilePictureMenuVisible(!isProfilePictureMenuVisible);
}
};

const toggleProfileBannerMenu = () => {
setIsProfileBannerMenuVisible(!isProfileBannerMenuVisible);
if(userId === user?.userId){
setIsProfileBannerMenuVisible(!isProfileBannerMenuVisible);
}
};

const toggleEditDescriptionMenu = () => {
Expand All @@ -194,7 +231,7 @@ export default function UserProfile() {
<div className="user-profile__profile-banner-container" onClick={toggleProfileBannerMenu}>
<div>
<img
src={userData.bannerPictureUrl ? userData.bannerPictureUrl : defaultProfileBannerUrl}
src={bannerImageSrc}
alt="Banner"
className="user-profile__banner-img"
/>
Expand Down Expand Up @@ -224,9 +261,7 @@ export default function UserProfile() {
>
<div>
<img
src={
userData.profilePictureUrl ? userData.profilePictureUrl : defaultProfilePictureUrl
}
src={profileImageSrc}
alt="Profile"
className="user-profile__profile-img"
/>
Expand Down
2 changes: 1 addition & 1 deletion src/cmps/sidebar/MembersSidebarItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export default function MembersSidebarItem({
<div id="members-sidebar-item-icon">
<ProfilePicture
size="20px"
imageUrl={profilePictureUrl ? profilePictureUrl : defaultProfilePictureUrl}
imageUrl={profilePictureUrl}
/>
</div>
<div id="members-sidebar-item-name">{name}</div>
Expand Down
5 changes: 1 addition & 4 deletions src/cmps/sidebar/SidebarUserInfo.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React, { useEffect, useRef, useState } from "react";
import { UserData } from "../../models/UserData.model";
import { useNavigate } from "react-router-dom";
import defaultProfilePictureUrl from "/imgs/profile/blank-profile-picture.jpg";
import ProfilePicture from "../global/ProfilePicture";
import { useAuth } from "../../context/AuthProvider";

Expand Down Expand Up @@ -41,9 +40,7 @@ export default function SidebarUserInfo({ userData }: SidebarUserInfoProps) {
return (
<div className="sidebar-user-info-container">
<ProfilePicture
imageUrl={
userData.profilePictureUrl ? userData.profilePictureUrl : defaultProfilePictureUrl
}
imageUrl={userData.profilePictureUrl}
onClick={onUsernameClick}
/>
<div className="sidebar-user-info-data">
Expand Down
4 changes: 2 additions & 2 deletions src/context/AuthProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
username: signedUpUser.username,
email: signedUpUser.email,
profilePictureUrl: signedUpUser.profilePictureUrl,
bannerPictureUrl: signedUpUser.bannerPictureUrl,
profileBannerUrl: signedUpUser.profileBannerUrl,
timeCreated: signedUpUser.timeCreated
});
console.log(user);
Expand Down Expand Up @@ -106,7 +106,7 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
username: signedUpUser.username,
email: signedUpUser.email,
profilePictureUrl: signedUpUser.profilePictureUrl,
bannerPictureUrl: signedUpUser.bannerPictureUrl,
profileBannerUrl: signedUpUser.profileBannerUrl,
timeCreated: signedUpUser.timeCreated
});
// If authentication is disabled, mock authenticated state
Expand Down
2 changes: 1 addition & 1 deletion src/models/UserData.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ export interface UserData {
email: string;
description: string;
profilePictureUrl: string;
bannerPictureUrl: string;
profileBannerUrl: string;
timeCreated: string;
}
16 changes: 16 additions & 0 deletions src/services/media.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,19 @@ export async function uploadGroupProfileImage(
throw throwAxiosErr(err);
}
}

export async function fetchPicture(pictureUrl: string | undefined) : Promise<string | undefined> {
console.log(cmpName, "Sending request to receive picture url: " + pictureUrl);
if(pictureUrl){
try{
const response = await axios.get(pictureUrl, {
responseType: "blob",
});

return URL.createObjectURL(response.data);
} catch (err) {
console.error(cmpName, "Error getting the picture: " + pictureUrl + " Error: " + err);
throwAxiosErr(err);
}
}
}

0 comments on commit 5c5cbca

Please sign in to comment.