diff --git a/frontend/src/components/Calendar/DataPicker.jsx b/frontend/src/components/Calendar/DataPicker.jsx index 72e9247..14c78a6 100644 --- a/frontend/src/components/Calendar/DataPicker.jsx +++ b/frontend/src/components/Calendar/DataPicker.jsx @@ -12,24 +12,24 @@ const DatePicker = ({ setDate, initialDate, disableButtons }) => { const [weekRange, setWeekRange] = useState(""); const [selectedDate, setSelectedDate] = useState(new Date(initialDate.start)); - // Функция для вычисления начала и конца недели const calculateWeekDates = useCallback((date) => { const startOfWeek = new Date(date); - const endOfWeek = new Date(date); - startOfWeek.setDate(date.getDate() - (date.getDay() === 0 ? 6 : date.getDay() - 1)); // Пн + startOfWeek.setDate(date.getDate() - ((date.getDay() || 7) - 1)); // Пн + + const endOfWeek = new Date(startOfWeek); endOfWeek.setDate(startOfWeek.getDate() + 6); // Вс - // Форматируем даты в нужный формат return { - start: `${startOfWeek.toISOString().split("T")[0]}T00:00:00+00:00`, - end: `${endOfWeek.toISOString().split("T")[0]}T23:59:59+00:00`, + start: `${startOfWeek.getFullYear()}-${(startOfWeek.getMonth() + 1).toString().padStart(2, '0')}-${startOfWeek.getDate().toString().padStart(2, '0')}T00:00:00+00:00`, + end: `${endOfWeek.getFullYear()}-${(endOfWeek.getMonth() + 1).toString().padStart(2, '0')}-${endOfWeek.getDate().toString().padStart(2, '0')}T23:59:59+00:00`, }; }, []); const calculateWeekRange = useCallback((date) => { const startOfWeek = new Date(date); - const endOfWeek = new Date(date); - startOfWeek.setDate(date.getDate() - (date.getDay() === 0 ? 6 : date.getDay() - 1)); // Пн + startOfWeek.setDate(date.getDate() - ((date.getDay() || 7) - 1)); // Пн + + const endOfWeek = new Date(startOfWeek); endOfWeek.setDate(startOfWeek.getDate() + 6); // Вс const formatOptions = { day: "numeric", month: "long" }; @@ -39,6 +39,14 @@ const DatePicker = ({ setDate, initialDate, disableButtons }) => { return `${startFormatted} – ${endFormatted}`; }, []); + // Установка начальной недели при загрузке + useEffect(() => { + const initialRange = calculateWeekRange(selectedDate); + const initialDates = calculateWeekDates(selectedDate); + setWeekRange(initialRange); + setDate(initialDates); + }, [selectedDate, calculateWeekRange, calculateWeekDates, setDate]); + useEffect(() => { const fpInstance = flatpickr(datePickerRef.current, { locale: Russian, @@ -48,8 +56,8 @@ const DatePicker = ({ setDate, initialDate, disableButtons }) => { const selectedDate = selectedDates[0]; setSelectedDate(selectedDate); setWeekRange(calculateWeekRange(selectedDate)); - const newDates = calculateWeekDates(selectedDate); // Обновляем даты - setDate(newDates); // Устанавливаем новые даты в родительском компоненте + const newDates = calculateWeekDates(selectedDate); + setDate(newDates); } } }); @@ -57,18 +65,15 @@ const DatePicker = ({ setDate, initialDate, disableButtons }) => { return () => { fpInstance.destroy(); }; - }, [setDate, initialDate.start, calculateWeekRange, calculateWeekDates]); - - useEffect(() => { - setWeekRange(calculateWeekRange(selectedDate)); - }, [selectedDate, calculateWeekRange]); + }, [setDate, calculateWeekRange, calculateWeekDates]); const handlePrevWeek = () => { setSelectedDate((prev) => { const newDate = new Date(prev); newDate.setDate(prev.getDate() - 7); - setWeekRange(calculateWeekRange(newDate)); + const newRange = calculateWeekRange(newDate); const newDates = calculateWeekDates(newDate); + setWeekRange(newRange); setDate(newDates); return newDate; }); @@ -78,8 +83,9 @@ const DatePicker = ({ setDate, initialDate, disableButtons }) => { setSelectedDate((prev) => { const newDate = new Date(prev); newDate.setDate(prev.getDate() + 7); - setWeekRange(calculateWeekRange(newDate)); + const newRange = calculateWeekRange(newDate); const newDates = calculateWeekDates(newDate); + setWeekRange(newRange); setDate(newDates); return newDate; }); diff --git a/frontend/src/components/Calendar/DeadLine.jsx b/frontend/src/components/Calendar/DeadLine.jsx index e1ef1d3..776c055 100644 --- a/frontend/src/components/Calendar/DeadLine.jsx +++ b/frontend/src/components/Calendar/DeadLine.jsx @@ -16,7 +16,7 @@ const DeadLine = ({date, events, setSelectedEvent}) => { {monthDays.map((day, index) => { - const adjustedDay = new Date(new Date(date.start).setDate(new Date(date.start).getDate() + index + 1)).toISOString().split('T')[0]; + const adjustedDay = new Date(new Date(date.start).setDate(new Date(date.start).getDate() + index)).toISOString().split('T')[0]; const deadlines = events?.netology?.homework.filter(homework => { const homeworkDeadline = new Date(homework.deadline).toISOString().split('T')[0]; diff --git a/frontend/src/elements/ErrorMessage.jsx b/frontend/src/elements/ErrorMessage.jsx new file mode 100644 index 0000000..98f8524 --- /dev/null +++ b/frontend/src/elements/ErrorMessage.jsx @@ -0,0 +1,11 @@ +import React from 'react'; + +const ErrorMessage = ({message}) => { + return ( +
+

{message}

+
+ ); +}; + +export default ErrorMessage; \ No newline at end of file diff --git a/frontend/src/pages/CalendarRoute.jsx b/frontend/src/pages/CalendarRoute.jsx index 76b67c2..08e24bd 100644 --- a/frontend/src/pages/CalendarRoute.jsx +++ b/frontend/src/pages/CalendarRoute.jsx @@ -17,6 +17,7 @@ import EventsDetail from "../components/Calendar/EventsDetail"; import DeadLine from "../components/Calendar/DeadLine"; import DaysNumber from "../components/Calendar/DaysNumber"; import LessonTimes from "../components/Calendar/LessonTimes"; +import ErrorMessage from "../elements/ErrorMessage"; const CalendarRoute = () => { const initialDate = useMemo(() => getCurrentWeekDates(), []); @@ -26,7 +27,7 @@ const CalendarRoute = () => { const [error, setError] = useState(null); const [selectedEvent, setSelectedEvent] = useState(null); - console.log('date', date) + // console.log('date', date) const fetchCourseAndEvents = useCallback(async () => { setLoading(true); @@ -65,9 +66,6 @@ const CalendarRoute = () => { fetchCourseAndEvents(); }, [fetchCourseAndEvents]); - if (loading) return ; - if (error) return
{error}
; - const handleDataUpdate = (updatedEvents) => { setEvents(updatedEvents); }; @@ -84,26 +82,32 @@ const CalendarRoute = () => {
Мое расписание - - + +
- +
- - + +
- - - - - - - - -
+ {loading ? ( + + ) : error ? ( + + ) : ( + + + + + + + + +
+ )}
diff --git a/frontend/src/services/api.js b/frontend/src/services/api.js index 1d80378..9033865 100644 --- a/frontend/src/services/api.js +++ b/frontend/src/services/api.js @@ -54,27 +54,21 @@ export async function getNetologyCourse(sessionToken) { } } -// calendar -export async function bulkEvents({calendarId, timeZone, attendeePersonId, timeMin, timeMax, sessionToken, lms_user }) { - // console.log('calendarId, timeZone, attendeePersonId, timeMin, timeMax, sessionToken', calendarId, timeZone, attendeePersonId, timeMin, timeMax, sessionToken) - // const calendarId = 45526; // Ваш ID календаря - // const timeZone = 'Europe/Moscow'; // Часовой пояс - // const attendeePersonId = '5a3d9024-d210-4bfb-a622-0a55ab5bac1a'; // Ваш ID участника +const apiRequest = async (endpoint, {calendarId, timeZone, attendeePersonId, timeMin, timeMax, sessionToken, lms_user}) => { const requestBody = { body: { timeMin: timeMin, timeMax: timeMax, size: 50, - attendeePersonId: [attendeePersonId], // Обратите внимание на правильность имени свойства + attendeePersonId: [attendeePersonId], }, - lms_user: lms_user || { id: 0, token: sessionToken, is_enabled: false }, // Использовать переданный lms_user или значение по умолчанию - + lms_user: lms_user || { id: 0, token: sessionToken, is_enabled: false }, }; try { const response = await axios.post( - `${BACKEND_URL}/api/bulk/events/?calendar_id=${calendarId}&time_zone=${timeZone}`, + `${BACKEND_URL}${endpoint}?calendar_id=${calendarId}&time_zone=${timeZone}`, requestBody, { headers: { @@ -86,66 +80,119 @@ export async function bulkEvents({calendarId, timeZone, attendeePersonId, timeMi return response; } catch (error) { console.error('Ошибка при получении данных:', error.response ? error.response.data : error.message); + throw error; // Пробрасываем ошибку, если необходимо } }; -// Refresh calendar -export async function refreshBulkEvents({calendarId, timeZone, attendeePersonId, timeMin, timeMax, sessionToken, lms_user }) { - try { - const requestBody = { - body: { - timeMin: timeMin, - timeMax: timeMax, - size: 50, - attendeePersonId: [attendeePersonId], // Обратите внимание на правильность имени свойства - }, - lms_user: lms_user || { id: 0, token: sessionToken, is_enabled: false }, // Использовать переданный lms_user или значение по умолчанию +// Теперь используем apiRequest для реализации ваших функций +export const bulkEvents = (params) => { + return apiRequest('/api/bulk/events/', params); +}; - }; +export const refreshBulkEvents = (params) => { + return apiRequest('/api/bulk/refresh_events/', params); +}; - const response = await axios.post( - `${BACKEND_URL}/api/bulk/refresh_events/?calendar_id=${calendarId}&time_zone=${timeZone}`, - requestBody, - { - headers: { - "_netology-on-rails_session": sessionToken, // Токен сессии - "Content-Type": "application/json", - }, - } - ); - return response; - } catch (e) { - return e.response; - } -} +export const exportICS = (params) => { + return apiRequest('/api/bulk/export_ics/', params); +}; -// export file -export async function exportICS({calendarId, timeZone, attendeePersonId, timeMin, timeMax, sessionToken, lms_user }) { - try { - const requestBody = { - body: { - timeMin: timeMin, - timeMax: timeMax, - size: 50, - attendeePersonId: [attendeePersonId], // Обратите внимание на правильность имени свойства - }, - lms_user: lms_user || { id: 0, token: sessionToken, is_enabled: false }, // Использовать переданный lms_user или значение по умолчанию - }; - const response = await axios.post( - `${BACKEND_URL}/api/bulk/export_ics/?calendar_id=${calendarId}&time_zone=${timeZone}`, - requestBody, - { - headers: { - "_netology-on-rails_session": sessionToken, - "Content-Type": "application/json", - }, - } - ); - return response; - } catch (e) { - return e.response; - } -} + + +// // calendar +// export async function bulkEvents({calendarId, timeZone, attendeePersonId, timeMin, timeMax, sessionToken, lms_user }) { +// // console.log('calendarId, timeZone, attendeePersonId, timeMin, timeMax, sessionToken', calendarId, timeZone, attendeePersonId, timeMin, timeMax, sessionToken) +// // const calendarId = 45526; // Ваш ID календаря +// // const timeZone = 'Europe/Moscow'; // Часовой пояс +// // const attendeePersonId = '5a3d9024-d210-4bfb-a622-0a55ab5bac1a'; // Ваш ID участника +// +// const requestBody = { +// body: { +// timeMin: timeMin, +// timeMax: timeMax, +// size: 50, +// attendeePersonId: [attendeePersonId], // Обратите внимание на правильность имени свойства +// }, +// lms_user: lms_user || { id: 0, token: sessionToken, is_enabled: false }, // Использовать переданный lms_user или значение по умолчанию +// +// }; +// +// try { +// const response = await axios.post( +// `${BACKEND_URL}/api/bulk/events/?calendar_id=${calendarId}&time_zone=${timeZone}`, +// requestBody, +// { +// headers: { +// 'Content-Type': 'application/json', +// '_netology-on-rails_session': sessionToken, +// }, +// } +// ); +// return response; +// } catch (error) { +// console.error('Ошибка при получении данных:', error.response ? error.response.data : error.message); +// } +// }; +// +// // Refresh calendar +// export async function refreshBulkEvents({calendarId, timeZone, attendeePersonId, timeMin, timeMax, sessionToken, lms_user }) { +// try { +// const requestBody = { +// body: { +// timeMin: timeMin, +// timeMax: timeMax, +// size: 50, +// attendeePersonId: [attendeePersonId], // Обратите внимание на правильность имени свойства +// }, +// lms_user: lms_user || { id: 0, token: sessionToken, is_enabled: false }, // Использовать переданный lms_user или значение по умолчанию +// +// }; +// +// const response = await axios.post( +// `${BACKEND_URL}/api/bulk/refresh_events/?calendar_id=${calendarId}&time_zone=${timeZone}`, +// requestBody, +// { +// headers: { +// "_netology-on-rails_session": sessionToken, // Токен сессии +// "Content-Type": "application/json", +// }, +// } +// ); +// return response; +// } catch (e) { +// return e.response; +// } +// } +// +// // export file +// export async function exportICS({calendarId, timeZone, attendeePersonId, timeMin, timeMax, sessionToken, lms_user }) { +// try { +// const requestBody = { +// body: { +// timeMin: timeMin, +// timeMax: timeMax, +// size: 50, +// attendeePersonId: [attendeePersonId], // Обратите внимание на правильность имени свойства +// }, +// lms_user: lms_user || { id: 0, token: sessionToken, is_enabled: false }, // Использовать переданный lms_user или значение по умолчанию +// +// }; +// +// const response = await axios.post( +// `${BACKEND_URL}/api/bulk/export_ics/?calendar_id=${calendarId}&time_zone=${timeZone}`, +// requestBody, +// { +// headers: { +// "_netology-on-rails_session": sessionToken, +// "Content-Type": "application/json", +// }, +// } +// ); +// return response; +// } catch (e) { +// return e.response; +// } +// } diff --git a/frontend/src/style/header.scss b/frontend/src/style/header.scss index b1129e4..2398916 100644 --- a/frontend/src/style/header.scss +++ b/frontend/src/style/header.scss @@ -262,4 +262,16 @@ width: 50px; height: 50px; border-radius: 50%; -} \ No newline at end of file +} + +// src/components/ErrorMessage.scss + +.error-message { + background-color: #f8d7da; + color: #721c24; + border: 1px solid #f5c6cb; + padding: 15px; + border-radius: 5px; + margin: 20px 0; + font-size: 16px; +} diff --git a/frontend/src/utils/dateUtils.js b/frontend/src/utils/dateUtils.js index bd5b1ac..54d88b0 100644 --- a/frontend/src/utils/dateUtils.js +++ b/frontend/src/utils/dateUtils.js @@ -1,48 +1,10 @@ -// export const getCurrentWeekDates = () => { -// const today = new Date(); -// const dayOfWeek = today.getDay(); -// const mondayOffset = dayOfWeek === 0 ? -6 : 1 - dayOfWeek; -// const sundayOffset = 7 - dayOfWeek; -// -// const startOfWeek = new Date(today); -// startOfWeek.setDate(today.getDate() + mondayOffset); -// startOfWeek.setUTCHours(0, 0, 0, 0); -// -// const endOfWeek = new Date(today); -// endOfWeek.setDate(today.getDate() + sundayOffset); -// endOfWeek.setUTCHours(23, 59, 59, 0); -// -// const formatToRequiredISO = (date) => { -// const year = date.getUTCFullYear(); -// const month = String(date.getUTCMonth() + 1).padStart(2, '0'); -// const day = String(date.getUTCDate()).padStart(2, '0'); -// const hours = String(date.getUTCHours()).padStart(2, '0'); -// const minutes = String(date.getUTCMinutes()).padStart(2, '0'); -// const seconds = String(date.getUTCSeconds()).padStart(2, '0'); -// -// return `${year}-${month}-${day}T${hours}:${minutes}:${seconds}+00:00`; -// }; -// -// const formattedStart = formatToRequiredISO(startOfWeek); -// const formattedEnd = formatToRequiredISO(endOfWeek); -// -// // console.log("Formatted Start:", formattedStart); -// // console.log("Formatted End:", formattedEnd); -// -// return { -// start: formattedStart, -// end: formattedEnd, -// }; -// }; - - // export const getCurrentWeekDates = () => { // const today = new Date(); // const dayOfWeek = today.getDay(); // 0 (вс) - 6 (сб) // // // Смещение для понедельника -// const mondayOffset = (dayOfWeek === 0 ? -5 : 2 - dayOfWeek); // Смещаем на 1 день вперед для начала с понедельника -// const sundayOffset = 8 - dayOfWeek; // Смещаем конец недели на 1 день вперед +// const mondayOffset = (dayOfWeek === 0 ? -6 : 1 - dayOfWeek); // Смещаем на 0 или -6 для начала с понедельника +// const sundayOffset = 7 - dayOfWeek; // Конец недели (вс) - смещаем на 0 или 6 // // const startOfWeek = new Date(today); // startOfWeek.setDate(today.getDate() + mondayOffset); @@ -77,9 +39,9 @@ export const getCurrentWeekDates = () => { const today = new Date(); const dayOfWeek = today.getDay(); // 0 (вс) - 6 (сб) - // Смещение для понедельника - const mondayOffset = (dayOfWeek === 0 ? -6 : 1 - dayOfWeek); // Смещаем на 0 или -6 для начала с понедельника - const sundayOffset = 7 - dayOfWeek; // Конец недели (вс) - смещаем на 0 или 6 + // Смещение к началу недели (понедельнику) + const mondayOffset = dayOfWeek === 0 ? -6 : 1 - dayOfWeek; + const sundayOffset = dayOfWeek === 0 ? 0 : 7 - dayOfWeek; const startOfWeek = new Date(today); startOfWeek.setDate(today.getDate() + mondayOffset); @@ -103,7 +65,6 @@ export const getCurrentWeekDates = () => { const formattedStart = formatToRequiredISO(startOfWeek); const formattedEnd = formatToRequiredISO(endOfWeek); - // Возвращаем начальную и конечную даты недели return { start: formattedStart, end: formattedEnd,