Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jatin get profile images from website #2714

Open
wants to merge 11 commits into
base: development
Choose a base branch
from
56 changes: 50 additions & 6 deletions src/components/UserProfile/UserProfile.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,12 @@ import {
} from 'utils/constants';

import { getTimeEndDateEntriesByPeriod } from '../../actions/timeEntries.js';
import ProfileImageModal from './UserProfileModal/suggestedProfileModal';
import ConfirmRemoveModal from './UserProfileModal/confirmRemoveModal';
import { formatDateYYYYMMDD, CREATED_DATE_CRITERIA } from 'utils/formatDate.js';

function UserProfile(props) {
const darkMode = useSelector(state => state.theme.darkMode);

/* Constant values */
const initialFormValid = {
firstName: true,
Expand Down Expand Up @@ -116,6 +117,27 @@ function UserProfile(props) {
const [showConfirmDialog, setShowConfirmDialog] = useState(false);
const [pendingRehireableStatus, setPendingRehireableStatus] = useState(null);
const [isRehireable, setIsRehireable] = useState(null);
const [isModalOpen, setIsModalOpen] = useState(false);
// Function to toggle the modal
const toggleModal = () => setIsModalOpen(!isModalOpen);
const [isRemoveModalOpen, setIsRemoveModalOpen] = useState(false);
const toggleRemoveModal = () => setIsRemoveModalOpen(!isRemoveModalOpen);


const updateRemovedImage = async () =>{
try {
let response=await axios.put(ENDPOINTS.USERS_REMOVE_PROFILE_IMAGE,{'user_id':userProfile._id})
await loadUserProfile()
toast.success("Profile Image Removed")
} catch (error) {
console.log(error)
toast.error("Failed to remove profile Image.")
}
}
const confirmRemoveImage = async () => {
updateRemovedImage()
toggleRemoveModal(); // Close the remove confirmation modal
};

const userProfileRef = useRef();

Expand Down Expand Up @@ -290,7 +312,6 @@ function UserProfile(props) {
console.error('Error fetching team users:', error);
}
};

const loadUserTasks = async () => {
const userId = props?.match?.params?.userId;
axios
Expand Down Expand Up @@ -421,7 +442,7 @@ function UserProfile(props) {
const onAssignProject = assignedProject => {
setProjects(prevProjects => [...prevProjects, assignedProject]);
};

const onUpdateTask = (taskId, updatedTask) => {
const newTask = {
updatedTask,
Expand Down Expand Up @@ -507,7 +528,7 @@ function UserProfile(props) {
setModalTitle('Save & Refresh');
setModalMessage('');
}
};
}

/**
* Modifies the userProfile's infringements using a predefined operation
Expand Down Expand Up @@ -786,7 +807,6 @@ function UserProfile(props) {
}

const { firstName, lastName, profilePic, jobTitle = '' } = userProfile;

const { userId: targetUserId } = props.match ? props.match.params : { userId: undefined };

/** Login User's email */
Expand Down Expand Up @@ -891,7 +911,7 @@ function UserProfile(props) {
<Col md="4" id="profileContainer">
<div className="profile-img">
<Image
src={profilePic || '/pfp-default.png'}
src={profilePic!==undefined?profilePic : '/pfp-default.png'}
alt="Profile Picture"
roundedCircle
className="profilePicture bg-white"
Expand All @@ -914,7 +934,31 @@ function UserProfile(props) {
/>
</div>
) : null}

</div>
<div
style={{ display: 'flex', justifyContent: 'center', gap: '10px', marginTop: '20px' }}>
{(userProfile?.profilePic!==undefined)?
<Button color="danger" onClick={toggleRemoveModal} className="remove-button">
Remove Image</Button>:<></>}
{((userProfile?.profilePic==undefined ||
userProfile?.profilePic==null ||
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of == use ===

userProfile?.profilePic=="")&&
(userProfile?.suggestedProfilePics!==undefined &&
userProfile?.suggestedProfilePics!==null &&
userProfile?.suggestedProfilePics.length!==0
))?
<Button color="primary" onClick={toggleModal}>Suggested Profile Image</Button>
:null}
</div>

{userProfile!==undefined && userProfile.suggestedProfilePics!==undefined?<ProfileImageModal isOpen={isModalOpen} toggleModal={toggleModal} userProfile={userProfile}/>:<></>}
<ConfirmRemoveModal
isOpen={isRemoveModalOpen}
toggleModal={toggleRemoveModal}
confirmRemove={confirmRemoveImage}
/>

<QuickSetupModal
setSaved={setSaved}
handleSubmit={handleSubmit}
Expand Down
121 changes: 121 additions & 0 deletions src/components/UserProfile/UserProfileModal/UserProfileModal.css
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,124 @@
-webkit-transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
}

/* Profile Image Modal - Suggested Profile Links Grid */
.suggestedProfileLinks {
display: grid;
grid-template-columns: repeat(3, 1fr); /* 3 columns of images */
gap: 10px;
text-align: center;
margin-top: 20px;
}

/* Scrollable container for images */
.scrollable-container {
max-height: 300px; /* Limit height to make it scrollable */
overflow-y: auto; /* Enable vertical scroll if content overflows */
padding-right: 10px; /* Add padding for better look when scrolling */
}

/* Individual profile tile */
.suggestedProfileTile {
cursor: pointer;
padding: 10px;
transition: border 0.3s ease;
}

.suggestedProfileTile img {
width: 100px;
height: 100px;
border-radius: 50%;
object-fit: cover;
border: 2px solid transparent;
}

/* Text under each profile image */
.suggestedProfileTile p {
margin-top: 8px;
font-size: 14px;
}

/* Highlight selected image with a border */
.suggestedProfileTile.selected img {
border: 2px solid #007bff; /* Primary blue border for selected image */
}

/* General Button Styling for All Modal Buttons */
.modal-button {
flex: 1;
padding: 10px;
margin-right: 10px;
background-color: #007bff; /* Primary Blue for Set Image or Confirm */
border: none;
color: white;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s ease;
}

/* Last button (either Set Image or Cancel) should not have a right margin */
.modal-button:last-child {
margin-right: 0;
}

/* Hover effect for modal buttons */
.modal-button:hover {
background-color: #0056b3; /* Darker blue on hover */
}

/* Specific Styling for Remove Button */
.remove-button {
background-color: #dc3545; /* Bootstrap Danger Color */
border: none;
padding: 10px 20px;
color: white;
border-radius: 5px;
cursor: pointer;
margin-left: 10px;
transition: background-color 0.3s ease;
}

.remove-button:hover {
background-color: #c82333; /* Darker red for hover effect */
}

/* Button group for confirm/cancel modal */
.button-group {
display: flex;
justify-content: space-between;
margin-top: 20px;
}

/* Specific Close button styling (can use modal-button class as well) */
.close-button {
flex: 1;
background-color: #6c757d; /* Bootstrap Secondary Color */
border: none;
padding: 10px;
color: white;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s ease;
margin-right: 10px; /* Ensure proper spacing */
}

.close-button:hover {
background-color: #5a6268; /* Darker gray for hover effect */
}

/* Set Image Button */
.set-image-button {
flex: 1;
background-color: #007bff; /* Bootstrap Primary Color */
border: none;
padding: 10px;
color: white;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s ease;
}

.set-image-button:hover {
background-color: #0056b3; /* Darker blue for hover effect */
}
28 changes: 28 additions & 0 deletions src/components/UserProfile/UserProfileModal/confirmRemoveModal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from "react";
import { Modal, ModalHeader, ModalBody, Button } from "reactstrap";

const ConfirmRemoveModal = ({ isOpen, toggleModal, confirmRemove }) => {
return (
<Modal isOpen={isOpen} toggle={toggleModal}>
<ModalHeader toggle={toggleModal}>Remove Profile Image</ModalHeader>
<ModalBody>
<p>Are you sure you want to remove the selected profile image?</p>
<div className="button-group">
<Button color="secondary" onClick={toggleModal} className="modal-button">
Cancel
</Button>
<Button
color="danger"
onClick={confirmRemove}
className="modal-button"
style={{ marginLeft: '10px' }}
>
Confirm
</Button>
</div>
</ModalBody>
</Modal>
);
};

export default ConfirmRemoveModal;
110 changes: 110 additions & 0 deletions src/components/UserProfile/UserProfileModal/suggestedProfileModal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import React, { useState } from "react";
import { Modal, ModalHeader, ModalBody, Button } from "reactstrap";
import './UserProfileModal.css'; // For custom styling
import axios from "axios";
import { ENDPOINTS } from "utils/URL";
import { toast } from "react-toastify";
import { useEffect } from "react";

const ProfileImageModal = ({ isOpen, toggleModal, userProfile }) => {

const [selectedImage, setSelectedImage] = useState(null);
const suggestedProfilePics=userProfile.suggestedProfilePics;
const [allImages,setAllImages]=useState(suggestedProfilePics);
const [flag,setFlag]=useState(false)
// Function to handle image selection

const handleImageSelect = (image) => {
setSelectedImage(image); // Store the selected image info
};


async function imageUrlToPngBase64(url) {
try {
// Fetch the image as a buffer
const response = await axios.get(url, { responseType: "arraybuffer" });

if (response.status !== 200) {
throw new Error(`Failed to fetch the image: ${response.statusText}`);
}

const imageBuffer = Buffer.from(response.data);

// Convert the image to PNG format using sharp
const pngBuffer = await sharp(imageBuffer).png().toBuffer();

// Convert the PNG buffer to a base64 string
const base64Png = pngBuffer.toString("base64");

return `data:image/png;base64,${base64Png}`;;
} catch (error) {
console.error(`An error occurred: ${error.message}`);
return null;
}
}

useEffect(()=>{
if(suggestedProfilePics.length!==0 && allImages[0].nitro_src===undefined){
console.log("Inside");
var values=allImages;
for(let i=0;i<values.length;i++){
imageUrlToPngBase64(values[i].src).then((resolve)=>{
values[i].nitro_src=resolve;
})
}
setAllImages(values)
setFlag(true)
}
},[allImages])

const updateProfileImage= async ()=>{
try {
await axios.put(ENDPOINTS.USERS_UPDATE_PROFILE_FROM_WEBSITE,{'selectedImage':selectedImage,'user_id':userProfile._id})
toast.success("Profile Image Updated")
}
catch (error) {
console.log(error)
toast.error("Image Update Failed")
}
}

return (
<Modal isOpen={isOpen} toggle={toggleModal}>
<ModalHeader toggle={toggleModal}>Select a Profile Image</ModalHeader>
<ModalBody>
<div className="suggestedProfileLinks scrollable-container">
{suggestedProfilePics.map((image, index) => (
<div
key={index}
className={`suggestedProfileTile ${selectedImage === image ? 'selected' : ''}`}
onClick={() => handleImageSelect(image)}
>
<img src={flag?image.nitro_src:image.nitro_src} alt={image.alt} />
{/* <p>{image.title!==undefined && image.title.trim()!==""?image.title:image.alt.split(" ").slice(0, 3).join(" ")}</p> */}
</div>
))}
</div>

<div className="button-group">
<Button color="secondary" onClick={toggleModal} className="modal-button">
Close
</Button>
<Button
color="primary"
onClick={() => {
if (selectedImage) {
toggleModal(); // Close the modal after setting the image
updateProfileImage()
}
}}
className="modal-button"
>
Set Image
</Button>
</div>
</ModalBody>
</Modal>
);
};

export default ProfileImageModal;
2 changes: 2 additions & 0 deletions src/utils/URL.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ export const ENDPOINTS = {
ADD_BLUE_SQUARE: userId => `${APIEndpoint}/userprofile/${userId}/addInfringement`,
MODIFY_BLUE_SQUARE: (userId, blueSquareId) => `${APIEndpoint}/userprofile/${userId}/infringements/${blueSquareId}`,
USERS_ALLTEAMCODE_CHANGE : `${APIEndpoint}/AllTeamCodeChanges`,
USERS_REMOVE_PROFILE_IMAGE: `${APIEndpoint}/userProfile/profileImage/remove`,
USERS_UPDATE_PROFILE_FROM_WEBSITE: `${APIEndpoint}/userProfile/profileImage/imagefromwebsite`,
USER_PROFILE_BASIC_INFO : `${APIEndpoint}/userProfile/basicInfo`,

INFO_COLLECTIONS: `${APIEndpoint}/informations`,
Expand Down