начало разработки страницы профиля

This commit is contained in:
Lobstervova
2026-02-06 00:01:57 +03:00
parent 54df67a3db
commit 52b93038c4
9 changed files with 1543 additions and 13 deletions

View File

@@ -50,12 +50,14 @@ public class SecurityConfig {
.addFilterAt(authenticationWebFilter, SecurityWebFiltersOrder.AUTHENTICATION)
//.addFilterAfter(errorHandlingFilter, SecurityWebFiltersOrder.AUTHENTICATION)
.authorizeExchange(exchange -> exchange
.pathMatchers("/account/login","/error","/error/**").permitAll()
.pathMatchers("/account/login","/error","/error/**", "/account/logout").permitAll()
.pathMatchers("/account/**").authenticated()
.anyExchange().permitAll()
)
.formLogin(loginSpec -> loginSpec.loginPage("/account/login").authenticationSuccessHandler(authenticationSuccessHandler()))
.logout(logoutSpec -> logoutSpec.logoutSuccessHandler(logoutSuccessHandler()))
.logout(logoutSpec -> logoutSpec
.logoutUrl("/account/logout") // ← URL для логаута
.logoutSuccessHandler(logoutSuccessHandler()))
.requestCache(requestCacheSpec -> requestCacheSpec.requestCache(serverRequestCache()))
.build();
}

View File

@@ -1,5 +1,6 @@
package com.example.dateplanner.controllers.web;
import ch.qos.logback.core.model.Model;
import com.example.dateplanner.models.entities.AppUser;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -20,4 +21,15 @@ import java.util.Map;
@RequestMapping("/account")
public class AccountController {
@GetMapping("/profile")
public Mono<Rendering> profile() {
Map<String, Object> model = new HashMap<>();
model.put("title", "Profile");
model.put("index", "profile");
return Mono.just(
Rendering.view("template")
.model(model)
.build()
);
}
}

View File

@@ -4,7 +4,7 @@
@import url('https://fonts.googleapis.com/css2?family=Merriweather:ital,opsz,wght@0,18..144,300..900;1,18..144,300..900&display=swap');
body {
font-family: "Roboto Condensed", sans-serif !important;
font-family: 'Segoe UI', system-ui, sans-serif !important;
font-optical-sizing: auto !important;
font-weight: 400 !important;
font-style: normal !important;

View File

@@ -0,0 +1,81 @@
.sidebar {
background: white;
border-radius: 20px;
padding: 25px;
box-shadow: 0 10px 30px rgba(0,0,0,0.08);
position: sticky;
top: 30px;
height: fit-content;
}
.profile-main-content {
background: white;
border-radius: 20px;
padding: 40px;
box-shadow: 0 10px 30px rgba(0,0,0,0.08);
min-height: 600px;
}
.profile-user-avatar {
width: 120px;
height: 120px;
border-radius: 50%;
object-fit: cover;
border: 5px solid white;
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
margin-bottom: 20px;
}
.match-badge {
background: linear-gradient(45deg, #E74C3CFF, #FD79A8FF);
color: white;
padding: 5px 15px;
border-radius: 20px;
font-size: 0.9rem;
font-weight: 600;
}
.profile-completion {
background: #F9F7F7FF;
border-radius: 15px;
padding: 20px;
margin: 20px 0;
}
.completion-percentage {
font-size: 2.5rem;
font-weight: 700;
color: #E74C3CFF;
line-height: 1;
}
.progress {
height: 10px !important;
border-radius: 5px !important;
}
.progress-bar {
background-color: #E74C3CFF !important;
border-radius: 5px;
}
.profile-nav-link-custom {
color: #2D3436FF;
padding: 15px 20px;
border-radius: 15px;
margin-bottom: 10px;
transition: all 0.3s;
font-weight: 500;
}
.profile-nav-link-custom:hover {
background: rgba(231, 76, 60, 0.1) !important;
color: #E74C3CFF !important;
transform: translateX(5px) !important;
}
.profile-nav-link-custom.active {
background: rgba(231, 76, 60, 0.1) !important;
color: #E74C3CFF !important;
border-left: 4px solid #E74C3CFF !important;
}

View File

@@ -2,3 +2,4 @@
@import "main.css";
@import "header.css";
@import "places.css";
@import "profile.css";

View File

@@ -1,5 +1,6 @@
function initHeader($header){
console.log("init header date")
let authSection
if(!auth) {
authSection = `
@@ -15,18 +16,20 @@ function initHeader($header){
<div id="userProfileContainer" class="dropdown ms-0 ms-lg-3 mt-2 mt-lg-0">
<a href="#" class="d-flex align-items-center text-decoration-none dropdown-toggle"
data-bs-toggle="dropdown" aria-expanded="false">
<div class="user-avatar" id="userAvatar">А</div>
<span class="ms-2 d-md-inline" id="userName">Алексей</span>
<div class="user-avatar" id="userAvatar">${user.firstName.charAt(0)}${user.lastName.charAt(0)}</div>
<span class="ms-2 d-md-inline" id="userName">${user.firstName}</span>
</a>
<ul class="dropdown-menu dropdown-user">
<li>
<div class="user-info">
<div class="user-avatar" id="dropdownUserAvatar">А</div>
<div class="user-details">
<h6 id="dropdownUserName">Алексей Петров</h6>
<small id="dropdownUserEmail">alexey@example.com</small>
<a href="/account/profile" class="text-decoration-none text-black">
<div class="user-info">
<div class="user-avatar" id="dropdownUserAvatar">${user.firstName.charAt(0)}${user.lastName.charAt(0)}</div>
<div class="user-details">
<h6 id="dropdownUserName">${user.firstName} ${user.lastName}</h6>
<small id="dropdownUserEmail">${user.phone}</small>
</div>
</div>
</div>
</a>
</li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="#"><i class="fas fa-heart"></i> Мои избранные</a></li>
@@ -36,7 +39,14 @@ function initHeader($header){
<li><a class="dropdown-item" href="#" onclick="showAddPlaceModal()"><i class="fas fa-plus-circle"></i> Добавить место</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="#"><i class="fas fa-cog"></i> Настройки</a></li>
<li><a class="dropdown-item text-danger" href="#" onclick="logout()"><i class="fas fa-sign-out-alt"></i> Выйти</a></li>
<li>
<form action="/account/logout" method="post" style="display: inline;">
<input type="hidden" name="_csrf" value="${csrf.token}"/>
<button type="submit" class="dropdown-item text-danger" style="border: none; background: none; width: 100%; text-align: left;">
<i class="fas fa-sign-out-alt"></i> Выйти
</button>
</form>
</li>
</ul>
</div>
`;
@@ -179,4 +189,4 @@ function initHeader($header){
</div>
</div>
`)
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,85 @@
<div class="container py-5" id="mainPageContainer">
<div class="row">
<div class="col-lg-4 mb-4">
<div class="sidebar">
<div class="text-center">
<img src="https://images.unsplash.com/photo-1556909114-f6e7ad7d3136?ixlib=rb-4.0.3&auto=format&fit=crop&w=800&q=80"
class="profile-user-avatar" alt="Анна">
<h4 class="mb-1">Анна, 26</h4>
<p class="text-muted mb-3">Москва</p>
<div class="match-badge">Профиль на 85%</div>
</div>
<div class="profile-completion">
<div class="d-flex justify-content-between mb-2">
<span>Заполненность профиля:</span>
<span class="completion-percentage">85%</span>
</div>
<div class="progress">
<div class="progress-bar" style="width: 85%"></div>
</div>
<p class="small text-muted mt-2 mb-0">Полный профиль привлекает на 60% больше откликов</p>
</div>
<nav class="nav flex-column" id="profile-sections-navigator">
<a class="profile-nav-link-custom active" data-section="profileSection" href="#"
onclick="showSection('profile')">
<i class="fas fa-user me-3"></i>Мой профиль
</a>
<a class="profile-nav-link-custom" data-section="proposalsSection" href="#"
onclick="showSection('proposals')">
<i class="fas fa-heart me-3"></i>Мои предложения
<span class="notification-badge">3</span>
</a>
<a class="profile-nav-link-custom" data-section="organizationsSection" href="#"
onclick="showSection('organizations')">
<i class="fas fa-building me-3"></i>Мои организации
</a>
<a class="profile-nav-link-custom" data-section="eventsSection" href="#"
onclick="showSection('events')">
<i class="fas fa-calendar-alt me-3"></i>Мероприятия
</a>
<a class="profile-nav-link-custom" data-section="settingsSection" href="#"
onclick="showSection('settings')">
<i class="fas fa-cog me-3"></i>Настройки
</a>
</nav>
<div class="mt-4">
<button class="btn btn-heart w-100" onclick="createNewProposal()">
<i class="fas fa-plus me-2"></i>Предложить свидание
</button>
</div>
</div>
</div>
<div class="col-lg-8">
<div class="profile-main-content">
<div class="section-content d-block" id="profileSection">
1
</div>
<div class="section-content d-none" id="proposalsSection">
2
</div>
<div class="section-content d-none" id="organizationsSection">
3
</div>
<div class="section-content d-none" id="eventsSection">
4
</div>
<div class="section-content d-none" id="settingsSection">
5
</div>
</div>
</div>
</div>
</div>
<script>
$('#profile-sections-navigator').on('click', '.profile-nav-link-custom', function () {
$('#profile-sections-navigator').find('.profile-nav-link-custom').removeClass('active');
$(this).addClass('active');
const selectedSectionId = $(this).data('section');
console.log(selectedSectionId);
$('.section-content').removeClass('d-block').addClass('d-none');
$(`#${selectedSectionId}`).removeClass('d-none').addClass('d-block');
})
</script>

View File

@@ -26,6 +26,7 @@
<header th:insert="~{blocks/header}" style="margin-bottom: 64px"></header>
<main th:if="${index} == 'home'" th:insert="~{pages/home}"></main>
<main th:if="${index} == 'profile'" th:insert="~{pages/profile}"></main>
<footer class="mt-auto" th:insert="~{blocks/footer}"></footer>
</body>