Skip to content
Snippets Groups Projects
Commit 761dcb27 authored by Beth Davies's avatar Beth Davies
Browse files

Add edit functionality to profile page

parent 2b427934
Branches
No related tags found
No related merge requests found
package polish_community_group_11.polish_community.profile.controllers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import polish_community_group_11.polish_community.profile.models.Profile;
import polish_community_group_11.polish_community.profile.services.ProfileService;
import polish_community_group_11.polish_community.register.models.User;
import polish_community_group_11.polish_community.register.services.UserService;
import java.io.IOException;
import java.io.InputStream;
import java.lang.invoke.MethodHandles;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
@Controller
public class ProfileController {
private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
@Autowired
private UserService userService;
@Autowired
......@@ -32,14 +47,31 @@ public class ProfileController {
}
@PostMapping("/update")
public String updateProfile(@ModelAttribute Profile profile, Authentication authentication) {
public String updateProfile(@ModelAttribute Profile profile, Authentication authentication,@RequestParam("newPicture") MultipartFile newPicture)
throws IOException {
String username = authentication.getName();
User user = userService.findByEmail(username);
profile.setUserId(user.getId());
if (!newPicture.isEmpty()) {
String fileName = StringUtils.cleanPath(newPicture.getOriginalFilename());
String uploadDir = "build/resources/main/static/assets/user-photos/" + user.getId();
Path uploadPath = Paths.get(uploadDir);
if (!Files.exists(uploadPath)) {
Files.createDirectories(uploadPath);
}
try (InputStream inputStream = newPicture.getInputStream()) {
Path filePath = uploadPath.resolve(fileName);
Files.copy(inputStream, filePath, StandardCopyOption.REPLACE_EXISTING);
profile.setProfilePicture("/assets/user-photos/" + user.getId() + "/" + fileName);
}
}
profileService.updateProfile(profile);
return "redirect:/profile";
}
private Profile getProfileForAuthenticatedUser(Authentication authentication) {
LOG.info("getting profile for {} - isAuthenticated: {}", authentication.getName(), authentication.isAuthenticated());
String username = authentication.getName();
User user = userService.findByEmail(username);
......
......@@ -14,8 +14,10 @@ public class Profile {
private String fullName;
private String email;
private String profilePicture;
private LocalDate dateOfBirth;
private LocalDate dob;
private String bio;
private String phoneNumber;
private String organisation;
private boolean showPhoneNumber;
private boolean showDob;
}
......@@ -21,7 +21,9 @@ public class ProfileRepositoryImpl implements ProfileRepository {
rs.getDate("dob").toLocalDate(),
rs.getString("bio"),
rs.getString("phone_number"),
rs.getString("organization")
rs.getString("organization"),
rs.getBoolean("show_phone_number"),
rs.getBoolean("show_dob")
);
}
@Override
......@@ -34,7 +36,7 @@ public class ProfileRepositoryImpl implements ProfileRepository {
public Profile getProfile(Integer id) {
String sql = "SELECT u.id as user_id, " +
"u.fullname, u.email, u.dob, u.organization, " +
"up.profile_picture, up.phone_number, up.bio " +
"up.profile_picture, up.phone_number, up.bio, up.show_phone_number, up.show_dob " +
"FROM users u LEFT JOIN user_profile up ON " +
"u.id = up.user_id WHERE u.id = ?";
return jdbcTemplate.queryForObject(sql, rowMapper, id);
......@@ -44,7 +46,7 @@ public class ProfileRepositoryImpl implements ProfileRepository {
@Override
public void updateProfile(Profile profile) {
String sql = "UPDATE user_profile SET profile_picture = ?," +
" bio = ?, phone_number = ? WHERE user_id = ?";
jdbcTemplate.update(sql, profile.getProfilePicture(), profile.getBio(), profile.getPhoneNumber(), profile.getUserId());
" bio = ?, phone_number = ?, show_phone_number = ?, show_dob = ? WHERE user_id = ?";
jdbcTemplate.update(sql, profile.getProfilePicture(), profile.getBio(), profile.getPhoneNumber(),profile.isShowPhoneNumber(), profile.isShowDob(), profile.getUserId());
}
};
......@@ -155,6 +155,8 @@ CREATE TABLE IF NOT EXISTS user_profile (
profile_picture TEXT,
bio TEXT,
phone_number VARCHAR(20),
show_phone_number BOOLEAN DEFAULT FALSE,
show_dob BOOLEAN DEFAULT FALSE,
FOREIGN KEY (user_id) REFERENCES users(id)
ON DELETE CASCADE
ON UPDATE CASCADE
......
......@@ -21,7 +21,7 @@
border-radius: 50%;
object-fit: cover;
margin-bottom: 20px;
border: 3px solid var(--primary-color);
border: 3px solid var(--border-color);
}
.full-name {
......@@ -29,7 +29,7 @@
margin-bottom: 10px;
color: var(--text-color);
}
.email {
.email, #edit-email {
font-size: 14px;
color: var(--text-color);
margin-bottom: 15px;
......@@ -39,7 +39,10 @@
color: var(--secondary-text-color);
margin-bottom: 15px;
}
.optional-field {
/*#edit-organisation {*/
/* color: var(--text-color);*/
/*}*/
.optional-field, #edit-bio, #edit-phone-number, #edit-phone-number {
font-size: 14px;
color: var(--text-color);
margin-bottom: 10px;
......@@ -55,14 +58,27 @@
transition: background-color 0.3s ease;
}
/*#editForm input,
#editForm textarea {
display: block;
#edit-profile-form input[type="text"],
#edit-profile-form input[type="tel"],
#edit-profile-form textarea {
width: 100%;
padding: 8px;
margin-bottom: 10px;
padding: 5px;
}*/
border: 1px solid var(--secondary-text-color);
border-radius: 5px;
background-color: var(--background-color);
color: var(--text-color);
}
.checkbox-container {
display: flex;
justify-content: space-between;
margin-bottom: 10px;
}
.not-editable {
cursor: not-allowed;
background-color: var(--secondary-color) !important;
}
@media (max-width: 768px) {
.profile-card {
......@@ -74,15 +90,16 @@
height: 120px;
}
.full-name {
.full-name{
font-size: 20px;
}
.email {
.email, #edit-email {
font-size: 14px;
}
.optional-field {
.optional-field, #edit-bio, #edit-phone-number{
font-size: 12px;
}
}
\ No newline at end of file
}
document.addEventListener('DOMContentLoaded', function () {
const profileCard = document.getElementById('profile-card');
const editForm = document.getElementById('edit-profile-form');
const editBtn = document.getElementById('edit-profile-btn');
const cancelBtn = document.getElementById('cancel-edit');
const profilePictureInput = document.getElementById('profile-picture-input');
const changeProfilePictureBtn = document.getElementById('change-profile-picture-btn');
const editProfilePicture = document.getElementById('edit-profile-picture');
fetch('/profile-json')
.then(response => response.json())
.then(profile => {
......@@ -12,12 +19,14 @@ document.addEventListener('DOMContentLoaded', function () {
if (profile.bio) {
document.getElementById('bio').innerHTML = profile.bio;
}
if (profile.dob) {
if (profile.showDob && profile.dob) {
document.getElementById('date-of-birth').innerHTML = profile.dob;
}
if (profile.showPhoneNumber && profile.phoneNumber) {
document.getElementById('phone-number').innerHTML = `Phone: ${profile.phoneNumber}`;
}
populateEditForm(profile);
updateProfileCard(profile);
})
.catch(error => {
......@@ -25,7 +34,50 @@ document.addEventListener('DOMContentLoaded', function () {
console.error('Error stack:', error.stack);
document.getElementById('profile-container').innerHTML = 'Error loading profile.';
});
document.getElementById('edit-profile-btn').addEventListener('click', () => {
console.log('edit button clicked');
editBtn.addEventListener('click', () => {
profileCard.style.display = 'none';
editForm.style.display = 'block';
});
cancelBtn.addEventListener('click', () => {
editForm.style.display = 'none';
profileCard.style.display = 'block';
});
changeProfilePictureBtn.addEventListener('click', () => {
profilePictureInput.click();
});
profilePictureInput.addEventListener('change', (event) => {
const file = event.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = (e) => {
editProfilePicture.src = e.target.result;
};
reader.readAsDataURL(file);
}
});
function updateProfileCard(profile) {
document.getElementById('profile-picture').src = profile.profilePicture || '/assets/default-profile.jpg';
document.getElementById('full-name').textContent = profile.fullName;
document.getElementById('email').textContent = profile.email;
document.getElementById('organisation').textContent = profile.organisation || '';
document.getElementById('bio').textContent = profile.bio || '';
document.getElementById('date-of-birth').textContent = profile.showDob && profile.dob ? profile.dob : '';
document.getElementById('phone-number').textContent = profile.showPhoneNumber && profile.phoneNumber ? `Phone: ${profile.phoneNumber}` : '';
}
function populateEditForm(profile) {
document.getElementById('edit-profile-picture').src = profile.profilePicture || '/assets/default-profile.jpg';
document.getElementById('original-profile-picture').value = profile.profilePicture;
document.getElementById('edit-full-name').value = profile.fullName;
document.getElementById('edit-email').value = profile.email;
document.getElementById('edit-organisation').value = profile.organisation || '';
document.getElementById('edit-bio').value = profile.bio || '';
document.getElementById('edit-date-of-birth').value = profile.dob || '';
document.getElementById('edit-phone-number').value = profile.phoneNumber || '';
document.getElementById('show-dob').checked = profile.showDob;
document.getElementById('show-number').checked = profile.showPhoneNumber;
}
});
\ No newline at end of file
......@@ -24,5 +24,24 @@
</div>
<button class="edit-profile-btn" id="edit-profile-btn">Edit Profile</button>
</div>
<form id="edit-profile-form" class="profile-card" style="display: none" th:action="@{/update}" method="post" enctype="multipart/form-data">
<img id="edit-profile-picture" src="/assets/default-profile.jpg" alt="Profile Picture" class="profile-picture">
<input type="file" id="profile-picture-input" name="newPicture" accept="image/*" style="display: none;">
<br>
<button type="button" id="change-profile-picture-btn">Change Profile Picture</button>
<input type="hidden" id="original-profile-picture" name="profilePicture" readonly>
<input type="text" class="not-editable" id="edit-full-name" readonly>
<input type="text" class="not-editable" id="edit-email" readonly>
<input type="text" class="not-editable" id="edit-organisation" readonly placeholder="Organisation">
<textarea id="edit-bio" name="bio" placeholder="Bio" class="optional-field"></textarea>
<input type="text" class="not-editable" id="edit-date-of-birth" readonly>
<input type="tel" id="edit-phone-number" name="phoneNumber" placeholder="Phone Number" class="optional-field">
<div class="checkbox-container">
<label><input type="checkbox" id="show-dob" name="showDob"> Show Date of Birth</label>
<label><input type="checkbox" id="show-number" name="showPhoneNumber"> Show Phone Number</label>
</div>
<button type="submit" class="edit-profile-btn">Save Changes</button>
<button type="button" id="cancel-edit" class="edit-profile-btn">Cancel</button>
</form>
</section>
</html>
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment