This commit is contained in:
Андрей Дувакин 2025-01-21 21:11:58 +05:00
parent fbadc3a052
commit 11051d9fc7
6 changed files with 140 additions and 16 deletions

View File

@ -324,7 +324,7 @@ def get_events():
resp.append({
'title': event.title,
'date': str(event.datetime_event.date()),
'author': f'{user.last_name} {user.first_name}',
'author': f'{user.last_name} {user.first_name[0]}. {user.patronymic[0]}.',
'description': event.title,
})

BIN
WEB/app/public/image.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 876 B

View File

@ -116,5 +116,18 @@
.events {
margin: 2vw;
border: 1px solid black;
}
.event-card-body {
background-color: #2f9836;
height: 100px;
margin: 5px;
color: white;
padding: 1vw;
}
.last-row {
display: flex;
flex-direction: row;
justify-content: space-between;
}

View File

@ -0,0 +1,60 @@
const EventCard = (event) => {
return (
<>
<div className="event-card-body">
<strong>{event.event.title}</strong>
<p>{event.event.description}</p>
<div className="last-row">
<div>
<button className="calendar-button" onClick={() => downloadICS(event)}>
<img src="/image.png" alt="" width='20px'/>
</button>
{event.event.date}
</div>
{event.event.author}
</div>
</div>
</>
)
}
const downloadICS = (event) => {
const { title, description, date, author } = event.event;
const startDate = new Date(date).toISOString().replace(/[-:]/g, "").split(".")[0] + "Z";
const uid = crypto.randomUUID();
const dtStamp = new Date().toISOString().replace(/[-:]/g, "").split(".")[0] + "Z";
const icsContent = `BEGIN:VCALENDAR
VERSION:2.0
BEGIN:VEVENT
SUMMARY:${title}
DTSTART:${startDate}
DTEND:${startDate}
DTSTAMP:${dtStamp}
UID:${uid}
DESCRIPTION:${description}
LOCATION:Не указано
ORGANIZER:${author}
STATUS:CONFIRMED
PRIORITY:0
END:VEVENT
END:VCALENDAR`;
const blob = new Blob([icsContent], { type: "text/calendar" });
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = `${title}.ics`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
};
export default EventCard;

View File

@ -1,11 +1,8 @@
'use client';
import Image from "next/image";
import { useState } from "react";
const Header = () => {
const [searchString, setSearchString] = useState('');
const Header = ({ setSearchString }) => {
const onSearchStringChange = (e) => {
setSearchString(e.target.value);
@ -16,7 +13,6 @@ const Header = () => {
<Image src={"/Logo.png"} width={80} height={80} alt=""/>
<input
type="text"
value={searchString}
onChange={onSearchStringChange}
placeholder="Введите для поиска"
className="search-string"

View File

@ -5,20 +5,24 @@ import Header from './components/header.js';
import EmployeeCard from './components/employee-card.js';
import { useEffect, useState } from 'react';
import RSSFeed from './components/news-card.js';
import EventCard from './components/event-card';
export default function Home() {
const [searchString, setSearchString] = useState('');
const [employees, setEmployees] = useState([]);
const [news, setNews] = useState([]);
const [events, setEvents] = useState([]);
useEffect(() => {
fetchEmployees();
fetchRSS();
fetchEvents();
const interval = setInterval(
() => {
fetchEmployees();
fetchRSS();
fetchEvents();
}, 5000
)
@ -27,6 +31,10 @@ export default function Home() {
}
}, []);
useEffect(() => {
filterData();
}, [searchString])
const fetchEmployees = async () => {
try {
const data = await fetch('http://localhost:5000/employees');
@ -41,6 +49,20 @@ export default function Home() {
}
}
const fetchEvents = async () => {
try {
const data = await fetch('http://localhost:5000/events');
if (data.ok) {
const json_data = await data.json();
setEvents(json_data)
}
} catch {
}
}
const fetchRSS = async () => {
try {
const response = await fetch("http://127.0.0.1:5000/rss");
@ -55,9 +77,27 @@ export default function Home() {
}
};
const filterData = (data, fields) => {
if (data === undefined) {
return data;
}
if (!searchString.trim()) return data;
return data.filter(item =>
fields.some(field =>
String(item[field] || "").toLowerCase().includes(searchString.toLowerCase())
)
);
};
const filteredEmployees = filterData(employees, ["last_name", "first_name", "patronymic", "post", "email", "phone", "birthday"]);
const filteredEvents = filterData(events, ["title", "description", "author"]);
const filteredNews = filterData(news, ["title", "description"]);
return (
<>
<Header />
<Header setSearchString={setSearchString} />
<div className="page">
<div className="user-list">
@ -67,10 +107,14 @@ export default function Home() {
<div className='user-row-list'>
{employees.map(
{filteredEmployees.length > 0 ? (
filteredEmployees.map(
(employee) => (
<EmployeeCard key={employee.id} employee={employee} />
)
)
) : (
<h2>Сотрудники не найдены</h2>
)}
</div>
@ -91,6 +135,15 @@ export default function Home() {
<h1>
События
</h1>
{filteredEvents.length > 0 ? (filteredEvents.map(
(event, index) => (
<EventCard key={index} event={event} />
)
)) : (
<h2>События не найдены</h2>
)}
</div>
</div>
@ -101,9 +154,11 @@ export default function Home() {
</h1>
<div className='news-block'>
{news.map((article, index) => (
<RSSFeed key={index} article={article} index={index}/>
))
{filteredNews.length > 0? (filteredNews.map((article, index) => (
<RSSFeed key={index} article={article} index={index} />
))) : (
<h2>Новости не найдены</h2>
)
}
</div>