diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index f29ac12..dc530c8 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -7,8 +7,6 @@ on: workflows: [build] types: - completed - branches: - - main workflow_dispatch: env: @@ -16,30 +14,22 @@ env: SSH_AUTH_SOCK: /tmp/ssh_agent.sock SSH_HOST: ${{ secrets.SSH_HOST }} SSH_USER: ${{ secrets.SSH_USER }} - SSH_PORT: ${{ secrets.SSH_PORT }} - + jobs: - deploy: + build: runs-on: ubuntu-latest - if: ${{ github.event.workflow_run.conclusion == 'success' }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v2 - run: 'command -v ssh-agent >/dev/null || ( apt-get update -y && apt-get install openssh-client -y )' - name: Set up SSH private key. run: eval "$(ssh-agent -s)" - run: mkdir -p ~/.ssh - - run: ssh-keyscan -p $SSH_PORT $SSH_HOST >> ~/.ssh/known_hosts + - run: ssh-keyscan ${{ secrets.SSH_HOST }} >> ~/.ssh/known_hosts - run: ssh-agent -a $SSH_AUTH_SOCK > /dev/null - run: ssh-add - <<< "${{ secrets.SSH_KEY }}" - - name: Add image tag to .version file - run: | - echo $IMAGE_TAG > .version - scp -P 666 .version $SSH_USER@$SSH_HOST:~/YetAnotherCalendar/.version - + - name: Update docker compose run: | - ssh $SSH_USER@$SSH_HOST -p $SSH_PORT "cd YetAnotherCalendar/ && git pull origin main - YET_ANOTHER_CALENDAR_VERSION=$(cat .version) docker compose -f docker-compose.prod.yaml pull - YET_ANOTHER_CALENDAR_VERSION=$(cat .version) docker compose -f docker-compose.prod.yaml up -d" - \ No newline at end of file + ssh $SSH_USER@$SSH_HOST "cd YetAnotherCalendar/ && YET_ANOTHER_CALENDAR_VERSION=$IMAGE_TAG docker compose up -d --build" + \ No newline at end of file diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index caa3691..23562fc 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -20,6 +20,7 @@ const App = () => { if (response.status === 200) { setAuthData({email, password, personId}); localStorage.setItem('token', response.data["_netology-on-rails_session"]); + return {success: true}; } else { return {success: false, message: "Неверный логин или пароль."}; diff --git a/frontend/src/components/Calendar/Calendar.jsx b/frontend/src/components/Calendar/Calendar.jsx index 6fedcd5..c4ec2c3 100644 --- a/frontend/src/components/Calendar/Calendar.jsx +++ b/frontend/src/components/Calendar/Calendar.jsx @@ -5,6 +5,9 @@ import cross from "../../img/arrow.png"; import '../../style/header.scss'; import '../../style/calendar.scss'; +import DatePicker from "./DataPicker"; +import camera from "../../img/camera.png"; + const Calendar = ({events}) => { console.log('events:', events); @@ -91,10 +94,9 @@ const Calendar = ({events}) => { - {/* Информация о дедлайнах */} -
+
{netology?.homework?.length > 0 && netology.homework.map((homeworkItem, index) => ( - { ))}
+ +
@@ -126,29 +130,28 @@ const Calendar = ({events}) => { - + {weekDays.map((day, index) => ( ))} - {/*TODO: написать логику*/} - - + @@ -160,7 +163,7 @@ const Calendar = ({events}) => { {[1, 2, 3, 4, 5, 6, 7].map((lessonNumber) => ( {weekDays.map((day, index) => { const eventsForDay = getEventsForDay(day.date); @@ -169,13 +172,14 @@ const Calendar = ({events}) => { - ); - })} - - ))} - + ) : (
+ )} + + ); + })} + + ) + ) + } +
{day.day}
- дедлайны - + {/*TODO: написать логику*/} +
дедлайны +
Скрыть
- - +
ТюмГУ
+
Нетология
- +
ТюмГУ
- +
Нетология
- {lessonNumber} пара
{lessonNumber * 2 + 8}:00 - {lessonNumber * 2 + 9}:30 + {lessonNumber} пара
{lessonNumber * 2 + 8}:00 {lessonNumber * 2 + 9}:30
{eventsForSlot.length > 0 ? ( eventsForSlot.map(event => ( -
+
+ {camera}/ ТюмГУ
{event.nameShort}
{event.name}
{new Date(event.start).toLocaleTimeString([], { - hour: '2-digit', - minute: '2-digit' + hour: '2-digit', + minute: '2-digit' })} - {new Date(event.end).toLocaleTimeString([], { hour: '2-digit', @@ -185,15 +189,16 @@ const Calendar = ({events}) => { {event.teacher_full_name}
)) - ) : ( -
- )} -
diff --git a/frontend/src/components/Calendar/DataPicker.jsx b/frontend/src/components/Calendar/DataPicker.jsx index 6bed40b..92660af 100644 --- a/frontend/src/components/Calendar/DataPicker.jsx +++ b/frontend/src/components/Calendar/DataPicker.jsx @@ -1,41 +1,67 @@ -import React, { useRef, useEffect, useState } from "react"; -import Flatpickr from "flatpickr"; -import weekSelect from "flatpickr"; +import React, { useEffect, useState } from "react"; import "flatpickr/dist/flatpickr.css"; -import flatpickr from "flatpickr"; -import { Russian } from "flatpickr/dist/l10n/ru.js"; +// import flatpickr from "flatpickr"; +// import { Russian } from "flatpickr/dist/l10n/ru.js"; +import "../../style/DatePicker.scss"; // Для стилей компонента const DatePicker = () => { - const datePickerRef = useRef(null); + // const datePickerRef = useRef(null); + const [currentDate, setCurrentDate] = useState(new Date()); // Текущая дата + const [weekRange, setWeekRange] = useState(""); - const [dateOnCalendar, setDateOnCalendar] = useState("2024-09-19"); - const [weekNumber, setWeekNumber] = useState(null); + // Рассчитать начало и конец недели + const calculateWeekRange = (date) => { + const startOfWeek = new Date(date); + const endOfWeek = new Date(date); + // Получаем понедельник текущей недели + startOfWeek.setDate(date.getDate() - date.getDay() + 1); // Понедельник + endOfWeek.setDate(startOfWeek.getDate() + 6); // Воскресенье + + const formatOptions = { day: "numeric", month: "long" }; + const startFormatted = startOfWeek.toLocaleDateString("ru-RU", formatOptions); + const endFormatted = endOfWeek.toLocaleDateString("ru-RU", formatOptions); + + return `${startFormatted} – ${endFormatted}`; + }; + + // Обновить диапазон недели при изменении даты useEffect(() => { - flatpickr(datePickerRef.current, { - locale: Russian, - onChange: [ - () => { - setWeekNumber( - this.selectedDates[0] ? setWeekNumber(this.selectedDates[0]) : null, - ); - console.log(weekNumber); - }, - ], + setWeekRange(calculateWeekRange(currentDate)); + }, [currentDate]); + + // Обработчик для переключения недель + const handlePrevWeek = () => { + setCurrentDate((prevDate) => { + const newDate = new Date(prevDate); + newDate.setDate(prevDate.getDate() - 7); // Переключение на предыдущую неделю + return newDate; }); - }, []); + }; + + const handleNextWeek = () => { + setCurrentDate((prevDate) => { + const newDate = new Date(prevDate); + newDate.setDate(prevDate.getDate() + 7); // Переключение на следующую неделю + return newDate; + }); + }; return ( -
- setDateOnCalendar(e.target.value)} - /> +
+
+ {weekRange} +
+ + +
+
); }; -flatpickr.l10ns.default.firstDayOfWeek = 1; + export default DatePicker; diff --git a/frontend/src/components/Calendar/exportICS.jsx b/frontend/src/components/Calendar/exportICS.jsx new file mode 100644 index 0000000..e69de29 diff --git a/frontend/src/components/Header/Header.js b/frontend/src/components/Header/Header.js index aa61965..a5a592c 100644 --- a/frontend/src/components/Header/Header.js +++ b/frontend/src/components/Header/Header.js @@ -23,15 +23,18 @@ export default function Header() { {cross}
-
-
- Дедлайн Нетология {arrow} 23.09.2024 -
-
- Программирование на Python -
-
- Домашнее задание с самопроверкой(дедлайн 12.12.24) +
+
+
+ Дедлайн Нетология {arrow}/ 23.09.2024 +
+
+ Программирование на Python +
+
+ Домашнее задание с самопроверкой(дедлайн 12.12.24) +
@@ -48,7 +51,7 @@ export default function Header() { Вс 29.09 - + дедлайны @@ -71,9 +74,12 @@ export default function Header() { - + Математический анализ +
+ diff --git a/frontend/src/pages/CalendarRoute.jsx b/frontend/src/pages/CalendarRoute.jsx index 83067f4..b2548cd 100644 --- a/frontend/src/pages/CalendarRoute.jsx +++ b/frontend/src/pages/CalendarRoute.jsx @@ -1,7 +1,7 @@ import React, { useEffect, useState } from 'react'; import { getNetologyCourse, bulkEvents } from '../services/api'; // Ваши API-запросы import Calendar from "../components/Calendar/Calendar"; -// import Header from "../components/Header/Header"; +import Header from "../components/Header/Header"; const CalendarRoute = ({ email, password, personId, token }) => { const [events, setEvents] = useState(null); @@ -42,21 +42,25 @@ const CalendarRoute = ({ email, password, personId, token }) => { const courseData = await getNetologyCourse(token); console.log('Данные курса:', courseData); - const fetchedCalendarId = courseData?.id; + const calendarId = courseData?.id; + console.log('calendarId add storage', calendarId) + localStorage.setItem('calendarId', calendarId); - if (fetchedCalendarId) { + if (calendarId) { const eventsResponse = await bulkEvents( email, // Email пользователя password, // Пароль пользователя token, // Токен сессии - fetchedCalendarId, // ID календаря + calendarId, // ID календаря "2024-10-14T00:00:00+03:00", // Дата начала "2024-10-20T23:59:59+03:00", // Дата окончания personId // ID участника ); console.log('События:', eventsResponse.data); setEvents(eventsResponse.data); - + // cached_at + localStorage.setItem('cached_at', eventsResponse.data.cached_at); // Сохраняем cached_at localstorage + console.log('eventsResponse.data.cached_at', eventsResponse.data.cached_at) // Сохраняем события в localStorage saveEventsToLocalStorage(eventsResponse.data); } @@ -82,7 +86,7 @@ const CalendarRoute = ({ email, password, personId, token }) => { return (
- {/*
*/} +
); }; diff --git a/frontend/src/pages/LoginRoute.jsx b/frontend/src/pages/LoginRoute.jsx index c3afbf1..c0b0617 100644 --- a/frontend/src/pages/LoginRoute.jsx +++ b/frontend/src/pages/LoginRoute.jsx @@ -49,6 +49,7 @@ const LoginRoute = ({onLogin, onSearch}) => { const handleSelect = (person) => { setFullName(person.fullName); // Устанавливаем выбранное имя setPersonId(person.personId); // Сохраняем personId + localStorage.setItem('personId', personId); // Сохраняем personId localstorage setShowSuggestions(false); // Скрываем список после выбора }; diff --git a/frontend/src/services/api.js b/frontend/src/services/api.js index 9793c54..ed3affd 100644 --- a/frontend/src/services/api.js +++ b/frontend/src/services/api.js @@ -93,4 +93,28 @@ export async function refreshBulkEvents(sessionToken, calendarId, timeMin, timeM } } +// export file +export async function exportICS(sessionToken, calendarId, timeMin, timeMax, attendeePersonId) { + try { + const response = await axios.post( + `${BACKEND_URL}/api/bulk/export_ics/?calendar_id=${calendarId}`, // URL с calendar_id в параметрах + { + timeMin, + timeMax, + size: 50, + attendeePersonId: [attendeePersonId], + }, + { + headers: { + "_netology-on-rails_session": sessionToken, // Токен сессии + "Content-Type": "application/json", + "time_zone": "Europe/Moscow", // Добавляем time_zone в заголовки + }, + } + ); + return response; + } catch (e) { + return e.response; + } +} diff --git a/frontend/src/style/DatePicker.scss b/frontend/src/style/DatePicker.scss new file mode 100644 index 0000000..a423e45 --- /dev/null +++ b/frontend/src/style/DatePicker.scss @@ -0,0 +1,40 @@ +.date-picker-wrapper { + width: fit-content; + margin-left: auto; + display: flex; + align-items: center; + justify-content: space-between; + padding: 10px; + background-color: #f3f4f6; + border-radius: 8px; + font-family: Arial, sans-serif; +} + +.week-display { + display: flex; + align-items: center; +} + +.week-range { + font-size: 16px; + font-weight: bold; +} + +.week-navigation { + display: flex; + margin-left: 10px; +} + +.prev-week-btn, .next-week-btn { + background-color: #e0e0e0; + border: none; + padding: 5px 10px; + margin: 0 5px; + border-radius: 4px; + cursor: pointer; + font-size: 16px; +} + +.prev-week-btn:hover, .next-week-btn:hover { + background-color: #d0d0d0; +} diff --git a/frontend/src/style/calendar.scss b/frontend/src/style/calendar.scss index e5b8648..e0fd383 100644 --- a/frontend/src/style/calendar.scss +++ b/frontend/src/style/calendar.scss @@ -1,48 +1,47 @@ -//&-info { -// height: 28px; -// margin-top: 6px; -// width: 95%; -// text-align: left; -// padding: 5px 11px; -// border: none; -// background: #F46386; -// border-radius: 6px; -// color: #fff; -// font-family: "Roboto", sans-serif; -// font-weight: 700; -// font-size: 13px; -// transition: color 0.3s linear; -// -// &:hover { -// cursor: pointer; -// color: #F46386; -// background-color: #fff; -// border: 2px solid #F46386; -// } -// } - -//&-info-on { -// height: 28px; -// margin-top: 4px; -// width: 95%; -// text-align: left; -// padding: 5px 11px; -// color: #F46386; -// background-color: #fff; -// border: 2px solid #F46386; -// border-radius: 6px; -// font-family: "Roboto", sans-serif; -// font-weight: 700; -// font-size: 13px; -// transition: color 0.3s linear; -// -// &:hover { -// cursor: pointer; -// color: #fff; -// background-color: #F46386; -// border: none; -// } -// } +.deadline { + &-info { + height: 28px; + margin-top: 6px; + width: 95%; + text-align: left; + padding: 5px 11px; + border: none; + background: #F46386; + border-radius: 6px; + color: #fff; + font-family: "Roboto", sans-serif; + font-weight: 700; + font-size: 13px; + transition: color 0.3s linear; + &:hover { + cursor: pointer; + color: #F46386; + background-color: #fff; + border: 2px solid #F46386; + } + } + &-info-on { + height: 28px; + margin-top: 4px; + width: 95%; + text-align: left; + padding: 5px 11px; + color: #F46386; + background-color: #fff; + border: 2px solid #F46386; + border-radius: 6px; + font-family: "Roboto", sans-serif; + font-weight: 700; + font-size: 13px; + transition: color 0.3s linear; + &:hover { + cursor: pointer; + color: #fff; + background-color: #F46386; + border: none; + } + } +} .shedule-table { width: 100%; diff --git a/frontend/src/style/header.scss b/frontend/src/style/header.scss index d02a8e9..ad78dbb 100644 --- a/frontend/src/style/header.scss +++ b/frontend/src/style/header.scss @@ -19,8 +19,9 @@ align-items: center; margin-bottom: 22px; } +} - &-deadline { +.rectangle { display: flex; justify-content: flex-end; flex-direction: row-reverse; @@ -39,7 +40,6 @@ text-decoration: none; } } -} .shedule-export { @@ -210,22 +210,22 @@ text-align: left; } -.calendar-date { - position: absolute; - top: 165px; - right: 248px; - background-color: #ecedf0; - width: 406px; - height: 32px; - border-radius: 6px; - border: 1px solid rgba(217, 217, 217, 0.5); - font-family: "Unbounded", sans-serif; - font-weight: 500; - font-size: 15px; - padding-left: 14px; - transition: color 0.2s linear; - - &:hover { - background-color: #e7e7ea; - } -} \ No newline at end of file +//.calendar-date { +// position: absolute; +// top: 165px; +// right: 248px; +// background-color: #ecedf0; +// width: 406px; +// height: 32px; +// border-radius: 6px; +// border: 1px solid rgba(217, 217, 217, 0.5); +// font-family: "Unbounded", sans-serif; +// font-weight: 500; +// font-size: 15px; +// padding-left: 14px; +// transition: color 0.2s linear; +// +// &:hover { +// background-color: #e7e7ea; +// } +//} \ No newline at end of file