Skip to content

Commit 9354f9a

Browse files
authored
Merge pull request #80 from algorithm-ssau/master
Sync
2 parents 0861bc2 + 3f847a7 commit 9354f9a

File tree

16 files changed

+118
-232
lines changed

16 files changed

+118
-232
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@
8282
cd turn-of-events
8383

8484
### Доступ
85-
Сайт доступен по адресу [http://217.198.13.157/](http://217.198.13.157/)
85+
Сайт доступен по адресу [http://83.217.223.128/](http://83.217.223.128/)
8686

8787
# Вклад в проект
8888
* Лысов Илья [SecurityTrip](https://github.com/SecurityTrip) - Team Lead, Backend

docker-compose.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,8 @@ services:
189189
context: ./user-service
190190
dockerfile: Dockerfile
191191
environment:
192-
SPRING_PROFILES_ACTIVE: "docker"
192+
- SPRING_PROFILES_ACTIVE=docker
193+
- JWT_SECRET=D4fN8Qr6Zu1WgX9Cv3PyL5Mk2Jh7Vt0s
193194
ports:
194195
- "8000:8080"
195196
networks:

frontend/src/App.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import './App.css'
21
import 'bootstrap/dist/css/bootstrap.min.css';
2+
import './App.css'
33
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
44
import Header from './components/Header/Header'
55
import Events from './components/Events/Events'

frontend/src/components/EventCard/EventCard.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Card } from 'react-bootstrap';
22
import { useNavigate } from 'react-router-dom';
33
import './EventCard.css';
44

5-
const EventCard = ({ id, title, date, location, description, customClass }) => {
5+
const EventCard = ({ id, title, date, location, description, imageUrl, customClass }) => {
66
const navigate = useNavigate();
77
const handleCardClick = () => {
88
if (id) {
@@ -12,7 +12,7 @@ const EventCard = ({ id, title, date, location, description, customClass }) => {
1212

1313
return (
1414
<Card className={`event-card ${customClass || ''}`} onClick={handleCardClick} style={{ cursor: 'pointer' }}>
15-
<Card.Img variant="top" src="https://via.placeholder.com/300x200" />
15+
<Card.Img variant="top" src={imageUrl || "https://via.placeholder.com/300x200"} />
1616
<Card.Body>
1717
<Card.Title>{title || 'Название мероприятия'}</Card.Title>
1818
<div className="event-details">

frontend/src/components/Events/Events.jsx

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,28 +8,42 @@ const Events = ({ title }) => {
88
const [events, setEvents] = useState([]);
99
const [loading, setLoading] = useState(true);
1010
const [error, setError] = useState(null);
11+
const [page, setPage] = useState(1);
12+
const [totalPages, setTotalPages] = useState(1);
1113

1214
useEffect(() => {
1315
const fetchEvents = async () => {
16+
setLoading(true);
17+
setError(null);
1418
try {
15-
const response = await axios.get('/api/events');
16-
console.log('Ответ сервера /api/events:', response.data);
19+
// В запросе нумерация страниц с 0
20+
const response = await axios.get(`/api/events?page=${page - 1}&size=9&sortBy=id&sortDir=asc`);
21+
// Ожидаем, что response.data.content - массив мероприятий, response.data.totalPages - всего страниц
1722
if (response.data && Array.isArray(response.data.content)) {
1823
setEvents(response.data.content);
24+
setTotalPages(response.data.totalPages || 1);
1925
setError(null);
2026
} else {
2127
setEvents([]);
28+
setTotalPages(1);
2229
setError('Некорректный формат ответа от сервера');
2330
}
2431
} catch (err) {
2532
setError('Ошибка загрузки мероприятий');
2633
setEvents([]);
34+
setTotalPages(1);
2735
} finally {
2836
setLoading(false);
2937
}
3038
};
3139
fetchEvents();
32-
}, []);
40+
}, [page]);
41+
42+
const handlePageChange = (newPage) => {
43+
if (newPage >= 1 && newPage <= totalPages) {
44+
setPage(newPage);
45+
}
46+
};
3347

3448
return (
3549
<section>
@@ -43,20 +57,33 @@ const Events = ({ title }) => {
4357
</div>
4458
)}
4559
{!loading && !error && events.length > 0 && (
46-
<Row xs={1} md={2} lg={3} className="g-4">
47-
{events.map((event) => (
48-
<Col key={event.id}>
49-
<EventCard
50-
id={event.id}
51-
title={event.title}
52-
date={event.date}
53-
location={event.place}
54-
description={event.description}
55-
customClass=""
56-
/>
57-
</Col>
58-
))}
59-
</Row>
60+
<>
61+
<Row xs={1} md={2} lg={3} className="g-4">
62+
{events.map((event) => (
63+
<Col key={event.id}>
64+
<EventCard
65+
id={event.id}
66+
title={event.title}
67+
date={event.date}
68+
location={event.place}
69+
description={event.description}
70+
imageUrl={event.imageUrl}
71+
customClass=""
72+
/>
73+
</Col>
74+
))}
75+
</Row>
76+
{/* Пагинация */}
77+
<div style={{ display: 'flex', justifyContent: 'center', marginTop: 24 }}>
78+
<button onClick={() => handlePageChange(page - 1)} disabled={page === 1} style={{marginRight: 8}}>
79+
Назад
80+
</button>
81+
<span style={{margin: '0 12px'}}>Страница {page} из {totalPages}</span>
82+
<button onClick={() => handlePageChange(page + 1)} disabled={page === totalPages}>
83+
Вперёд
84+
</button>
85+
</div>
86+
</>
6087
)}
6188
</div>
6289
</section>

frontend/src/components/Header/Header.css

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,33 @@
8787
transition: background-color 0.2s ease;
8888
}
8989

90+
.profile-dropdown .dropdown-item.profile-right {
91+
text-align: right;
92+
}
93+
94+
.profile-dropdown .dropdown-item img {
95+
vertical-align: middle;
96+
}
97+
9098
.profile-dropdown .dropdown-item:hover {
9199
background-color: #f5f5f5;
92100
}
93101

102+
.dropstart .dropdown-toggle::before {
103+
display: none !important;
104+
content: none !important;
105+
border: none !important;
106+
margin: 0 !important;
107+
padding: 0 !important;
108+
width: 0 !important;
109+
height: 0 !important;
110+
}
111+
112+
.dropstart .dropdown-menu[data-bs-popper] {
113+
top: 0px;
114+
right: -10%;
115+
}
116+
94117
/* Адаптивные стили */
95118
@media (max-width: 768px) {
96119
.header {
@@ -105,4 +128,5 @@
105128
.header .logo {
106129
font-size: 1.1rem;
107130
}
131+
108132
}

frontend/src/components/Header/Header.jsx

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useState, useRef, useEffect } from 'react';
2-
import { Navbar, Container, Form, Nav, NavDropdown } from 'react-bootstrap';
2+
import { Navbar, Container, Form, Nav, NavDropdown, SplitButton, Dropdown } from 'react-bootstrap';
33
import { useAuth } from '../../context/AuthContext';
44
import LoginButton from '../LoginButton/LoginButton';
55
import './Header.css';
@@ -35,39 +35,37 @@ const Header = () => {
3535
/>
3636
</Form>
3737
{/* Условный рендеринг: кнопка "Войти" или иконка профиля */}
38-
{isAuthenticated ? (
38+
{isAuthenticated ? (
3939
<div className="profile-container" ref={menuRef} style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
40-
<div
41-
className="profile-trigger"
42-
style={{ display: 'flex', alignItems: 'center', gap: '10px', cursor: 'pointer' }}
43-
onClick={() => setIsMenuOpen((prev) => !prev)}
44-
>
40+
<Dropdown show={isMenuOpen} onToggle={() => setIsMenuOpen((prev) => !prev)} className="profile-dropdown" align="start" drop="start">
41+
<Dropdown.Toggle
42+
as="span"
43+
id="profile-dropdown"
44+
style={{ border: 'none', background: 'none', padding: 0, cursor: 'pointer' }}
45+
onClick={() => setIsMenuOpen((prev) => !prev)}
46+
>
4547
<div className="profile-icon">
4648
<img
47-
src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGNsYXNzPSJsdWNpZGUgbHVjaWRlLXVzZXIiPjxwYXRoIGQ9Ik0xOSAyMXYtMmE0IDQgMCAwIDAtNC00SDlhNCA0IDAgMCAwLTQgNHYyIi8+PGNpcmNsZSBjeD0iMTIiIGN5PSI3IiByPSI0Ii8+PC9zdmc+"
49+
src={'./icons8-гость-мужчина-48.png'}
4850
alt="Профиль"
4951
className="profile-image"
5052
/>
5153
</div>
52-
<span style={{ fontWeight: 500, color: '#0F114B', fontSize: '1rem', whiteSpace: 'nowrap' }}>{user?.username}</span>
53-
</div>
54-
<NavDropdown
55-
title={null} // убираем стрелку
56-
id="basic-nav-dropdown"
57-
show={isMenuOpen}
58-
onToggle={() => {}}
59-
align="end"
60-
className="profile-dropdown"
61-
style={{ marginLeft: '0' }}
62-
renderToggle={undefined} // предотвращаем появление стрелки
63-
>
64-
<NavDropdown.Item onClick={() => {
65-
window.location.href = '/organizer';
66-
}}>Профиль</NavDropdown.Item>
67-
<NavDropdown.Item>Настройки</NavDropdown.Item>
68-
<NavDropdown.Divider />
69-
<NavDropdown.Item onClick={logout}>Выход</NavDropdown.Item>
70-
</NavDropdown>
54+
</Dropdown.Toggle>
55+
<Dropdown.Menu>
56+
<Dropdown.Item>
57+
<img src="./icons8-гость-мужчина-48.png" alt="" />
58+
{user && user.username ? user.username : 'Имя'}
59+
</Dropdown.Item>
60+
<Dropdown.Divider />
61+
<Dropdown.Item className="profile-right" onClick={() => { window.location.href = '/organizer'; }}>
62+
Профиль
63+
</Dropdown.Item>
64+
<Dropdown.Item className="profile-right">Настройки</Dropdown.Item>
65+
<Dropdown.Divider />
66+
<Dropdown.Item className="profile-right" onClick={logout}>Выход</Dropdown.Item>
67+
</Dropdown.Menu>
68+
</Dropdown>
7169
</div>
7270
) : (
7371
<LoginButton />

frontend/src/components/UpcomingEvents/UpcomingEvents.jsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ function getRandomEvents(events, maxCount) {
1414
return shuffled.slice(0, count);
1515
}
1616

17-
const UpcomingEvents = ({ title = "Ближайшие мероприятия", maxCount = 6 }) => {
17+
const UpcomingEvents = ({ title = "Ближайшие мероприятия", maxCount = 10 }) => {
1818
const [activeIndex, setActiveIndex] = useState(0);
1919
const [events, setEvents] = useState([]);
2020
const [visibleCards, setVisibleCards] = useState([]);
@@ -26,8 +26,8 @@ const UpcomingEvents = ({ title = "Ближайшие мероприятия", m
2626
setLoading(true);
2727
setError(null);
2828
try {
29-
const response = await axios.get('/api/events');
30-
const allEvents = response.data && Array.isArray(response.data.content) ? response.data.content : [];
29+
const response = await axios.get('/api/events/upcoming');
30+
const allEvents = Array.isArray(response.data) ? response.data : [];
3131
const randomEvents = getRandomEvents(allEvents, maxCount);
3232
setEvents(randomEvents);
3333
} catch (err) {
@@ -99,8 +99,9 @@ const UpcomingEvents = ({ title = "Ближайшие мероприятия", m
9999
id={item.event.id}
100100
title={item.event.title}
101101
date={item.event.date}
102-
location={item.event.place || item.event.location}
102+
location={item.event.place}
103103
description={item.event.description}
104+
imageUrl={item.event.imageUrl}
104105
/>
105106
</div>
106107
))}

kubernetes/api-gateway-deployment.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ spec:
2323
env:
2424
- name: SPRING_PROFILES_ACTIVE
2525
value: "k8s"
26+
- name: JWT_SECRET
27+
valueFrom:
28+
secretKeyRef:
29+
name: jwt-secret
30+
key: secret
2631
resources:
2732
limits:
2833
memory: "700Mi"

kubernetes/parser-service-configmap.yaml

Lines changed: 0 additions & 11 deletions
This file was deleted.

0 commit comments

Comments
 (0)