._.
This commit is contained in:
parent
fbadc3a052
commit
11051d9fc7
@ -324,7 +324,7 @@ def get_events():
|
|||||||
resp.append({
|
resp.append({
|
||||||
'title': event.title,
|
'title': event.title,
|
||||||
'date': str(event.datetime_event.date()),
|
'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,
|
'description': event.title,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
BIN
WEB/app/public/image.png
Normal file
BIN
WEB/app/public/image.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 876 B |
@ -116,5 +116,18 @@
|
|||||||
|
|
||||||
.events {
|
.events {
|
||||||
margin: 2vw;
|
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;
|
||||||
|
}
|
||||||
|
|||||||
60
WEB/app/src/app/components/event-card.js
Normal file
60
WEB/app/src/app/components/event-card.js
Normal 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;
|
||||||
@ -1,11 +1,8 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import { useState } from "react";
|
|
||||||
|
|
||||||
const Header = () => {
|
|
||||||
const [searchString, setSearchString] = useState('');
|
|
||||||
|
|
||||||
|
const Header = ({ setSearchString }) => {
|
||||||
|
|
||||||
const onSearchStringChange = (e) => {
|
const onSearchStringChange = (e) => {
|
||||||
setSearchString(e.target.value);
|
setSearchString(e.target.value);
|
||||||
@ -16,7 +13,6 @@ const Header = () => {
|
|||||||
<Image src={"/Logo.png"} width={80} height={80} alt=""/>
|
<Image src={"/Logo.png"} width={80} height={80} alt=""/>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={searchString}
|
|
||||||
onChange={onSearchStringChange}
|
onChange={onSearchStringChange}
|
||||||
placeholder="Введите для поиска"
|
placeholder="Введите для поиска"
|
||||||
className="search-string"
|
className="search-string"
|
||||||
|
|||||||
@ -5,20 +5,24 @@ import Header from './components/header.js';
|
|||||||
import EmployeeCard from './components/employee-card.js';
|
import EmployeeCard from './components/employee-card.js';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import RSSFeed from './components/news-card.js';
|
import RSSFeed from './components/news-card.js';
|
||||||
|
import EventCard from './components/event-card';
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
|
const [searchString, setSearchString] = useState('');
|
||||||
const [employees, setEmployees] = useState([]);
|
const [employees, setEmployees] = useState([]);
|
||||||
const [news, setNews] = useState([]);
|
const [news, setNews] = useState([]);
|
||||||
|
const [events, setEvents] = useState([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchEmployees();
|
fetchEmployees();
|
||||||
fetchRSS();
|
fetchRSS();
|
||||||
|
fetchEvents();
|
||||||
|
|
||||||
const interval = setInterval(
|
const interval = setInterval(
|
||||||
() => {
|
() => {
|
||||||
fetchEmployees();
|
fetchEmployees();
|
||||||
fetchRSS();
|
fetchRSS();
|
||||||
|
fetchEvents();
|
||||||
}, 5000
|
}, 5000
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -27,6 +31,10 @@ export default function Home() {
|
|||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
filterData();
|
||||||
|
}, [searchString])
|
||||||
|
|
||||||
const fetchEmployees = async () => {
|
const fetchEmployees = async () => {
|
||||||
try {
|
try {
|
||||||
const data = await fetch('http://localhost:5000/employees');
|
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 () => {
|
const fetchRSS = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch("http://127.0.0.1:5000/rss");
|
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 (
|
return (
|
||||||
<>
|
<>
|
||||||
<Header />
|
<Header setSearchString={setSearchString} />
|
||||||
<div className="page">
|
<div className="page">
|
||||||
|
|
||||||
<div className="user-list">
|
<div className="user-list">
|
||||||
@ -67,10 +107,14 @@ export default function Home() {
|
|||||||
|
|
||||||
<div className='user-row-list'>
|
<div className='user-row-list'>
|
||||||
|
|
||||||
{employees.map(
|
{filteredEmployees.length > 0 ? (
|
||||||
(employee) => (
|
filteredEmployees.map(
|
||||||
<EmployeeCard key={employee.id} employee={employee} />
|
(employee) => (
|
||||||
|
<EmployeeCard key={employee.id} employee={employee} />
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
) : (
|
||||||
|
<h2>Сотрудники не найдены</h2>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@ -91,6 +135,15 @@ export default function Home() {
|
|||||||
<h1>
|
<h1>
|
||||||
События
|
События
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
|
{filteredEvents.length > 0 ? (filteredEvents.map(
|
||||||
|
(event, index) => (
|
||||||
|
<EventCard key={index} event={event} />
|
||||||
|
)
|
||||||
|
)) : (
|
||||||
|
<h2>События не найдены</h2>
|
||||||
|
)}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@ -101,9 +154,11 @@ export default function Home() {
|
|||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<div className='news-block'>
|
<div className='news-block'>
|
||||||
{news.map((article, index) => (
|
{filteredNews.length > 0? (filteredNews.map((article, index) => (
|
||||||
<RSSFeed key={index} article={article} index={index}/>
|
<RSSFeed key={index} article={article} index={index} />
|
||||||
))
|
))) : (
|
||||||
|
<h2>Новости не найдены</h2>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user