diff --git a/frontend/package.json b/frontend/package.json index 1a78f51..a7f5f04 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -12,6 +12,7 @@ "dependencies": { "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", + "@fullcalendar/core": "^6.1.9", "@fullcalendar/daygrid": "^6.1.9", "@fullcalendar/interaction": "^6.1.9", "@fullcalendar/react": "^6.1.9", diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 271029a..a23ba2c 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -11,6 +11,9 @@ dependencies: '@emotion/styled': specifier: ^11.11.0 version: 11.11.0(@emotion/react@11.11.1)(@types/react@18.2.33)(react@18.2.0) + '@fullcalendar/core': + specifier: ^6.1.9 + version: 6.1.9 '@fullcalendar/daygrid': specifier: ^6.1.9 version: 6.1.9(@fullcalendar/core@6.1.9) diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index e9bb13b..cfa3a5a 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -6,7 +6,8 @@ import LoginPage from './components/authentication/LoginPage'; import SignUpPage from './components/authentication/SignUpPage'; import NavBar from './components/Nav/Navbar'; import Home from './components/Home'; -import ProfileUpdate from './components/ProfileUpdatePage' +import ProfileUpdate from './components/ProfileUpdatePage'; +import Calendar from './components/calendar/calendar'; const App = () => { return ( @@ -19,6 +20,7 @@ const App = () => { }/> }/> }/> + }/> diff --git a/frontend/src/api/TaskApi.jsx b/frontend/src/api/TaskApi.jsx new file mode 100644 index 0000000..e56662b --- /dev/null +++ b/frontend/src/api/TaskApi.jsx @@ -0,0 +1,23 @@ +import axios from 'axios'; + +// Create an Axios instance with common configurations +const axiosInstance = axios.create({ + baseURL: 'http://127.0.0.1:8000/api/', + timeout: 5000, + headers: { + 'Authorization': "Bearer " + localStorage.getItem('access_token'), + 'Content-Type': 'application/json', + 'accept': 'application/json', + } +}); + +export const fetchTodoTasks = () => { + return axiosInstance + .get('todo/') + .then((response) => { + return response.data; + }) + .catch(error => { + throw error; + }); +}; \ No newline at end of file diff --git a/frontend/src/components/calendar/TaskDataHandler.jsx b/frontend/src/components/calendar/TaskDataHandler.jsx new file mode 100644 index 0000000..3c123e9 --- /dev/null +++ b/frontend/src/components/calendar/TaskDataHandler.jsx @@ -0,0 +1,42 @@ +import { fetchTodoTasks } from '../../api/TaskApi'; + +let eventGuid = 0 + +// function getDateAndTime(dateString) { +// const dateObject = new Date(dateString); + +// const year = dateObject.getFullYear(); +// const month = (dateObject.getMonth() + 1).toString().padStart(2, '0'); +// const day = dateObject.getDate().toString().padStart(2, '0'); +// const dateFormatted = `${year}-${month}-${day}`; + +// const hours = dateObject.getUTCHours().toString().padStart(2, '0'); +// const minutes = dateObject.getUTCMinutes().toString().padStart(2, '0'); +// const seconds = dateObject.getUTCSeconds().toString().padStart(2, '0'); +// const timeFormatted = `T${hours}:${minutes}:${seconds}`; + +// return dateFormatted + timeFormatted; +// } + +const mapResponseToEvents = (response) => { + return response.map(item => ({ + id: createEventId(), + title: item.title, + start: item.start_event, + end: item.end_event, + })); +} + +export async function getEvents() { + try { + const response = await fetchTodoTasks(); + return mapResponseToEvents(response); + } catch (error) { + console.error(error); + return []; + } +} + +export function createEventId() { + return String(eventGuid++); +} \ No newline at end of file diff --git a/frontend/src/components/calendar/calendar.jsx b/frontend/src/components/calendar/calendar.jsx index 2c6dbf7..443d4bc 100644 --- a/frontend/src/components/calendar/calendar.jsx +++ b/frontend/src/components/calendar/calendar.jsx @@ -1,28 +1,127 @@ -import React from 'react'; -import FullCalendar from '@fullcalendar/react'; -import dayGridPlugin from '@fullcalendar/daygrid'; -import timeGridPlugin from '@fullcalendar/timegrid'; +import React, { useState } from 'react'; +import { formatDate } from "@fullcalendar/core"; +import FullCalendar from "@fullcalendar/react"; +import dayGridPlugin from "@fullcalendar/daygrid"; +import timeGridPlugin from "@fullcalendar/timegrid"; +import interactionPlugin from "@fullcalendar/interaction"; +import { getEvents, createEventId } from "./TaskDataHandler"; +import './index.css' -const Calendar = () => { +export default class Calendar extends React.Component { + state = { + weekendsVisible: true, + currentEvents: [], + }; + + render() { + return ( +
+ {this.renderSidebar()} +
+ +
+
+ ); + } + + renderSidebar() { + return ( +
+
+

Instructions

+
    +
  • Select dates and you will be prompted to create a new event
  • +
  • Drag, drop, and resize events
  • +
  • Click an event to delete it
  • +
+
+
+ +
+
+

All Events ({this.state.currentEvents.length})

+
    {this.state.currentEvents.map(renderSidebarEvent)}
+
+
+ ); + } + + handleWeekendsToggle = () => { + this.setState({ + weekendsVisible: !this.state.weekendsVisible, + }); + }; + + handleDateSelect = selectInfo => { + let title = prompt("Please enter a new title for your event"); + let calendarApi = selectInfo.view.calendar; + + calendarApi.unselect(); // clear date selection + + if (title) { + calendarApi.addEvent({ + id: createEventId(), + title, + start: selectInfo.startStr, + end: selectInfo.endStr, + allDay: selectInfo.allDay, + }); + } + }; + + handleEventClick = clickInfo => { + if (confirm(`Are you sure you want to delete the event '${clickInfo.event.title}'`)) { + clickInfo.event.remove(); + } + }; + + handleEvents = events => { + this.setState({ + currentEvents: events, + }); + }; +} + +function renderEventContent(eventInfo) { return ( -
- -
+ <> + {eventInfo.timeText} + {eventInfo.event.title} + ); -}; +} -export default Calendar; +function renderSidebarEvent(event) { + return ( +
  • + {formatDate(event.start, { year: "numeric", month: "short", day: "numeric" })} + {event.title} +
  • + ); +} diff --git a/frontend/src/components/calendar/calendarPage.jsx b/frontend/src/components/calendar/calendarPage.jsx deleted file mode 100644 index 7b5dbd7..0000000 --- a/frontend/src/components/calendar/calendarPage.jsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react' - -function calendarPage() { - return ( -
    - -
    - ) -} - -export default calendarPage diff --git a/frontend/src/components/calendar/index.css b/frontend/src/components/calendar/index.css new file mode 100644 index 0000000..e5086bd --- /dev/null +++ b/frontend/src/components/calendar/index.css @@ -0,0 +1,55 @@ + +html, +body, +body > div { /* the react root */ + margin: 0; + padding: 0; + height: 100%; +} + +h2 { + margin: 0; + font-size: 16px; +} + +ul { + margin: 0; + padding: 0 0 0 1.5em; +} + +li { + margin: 1.5em 0; + padding: 0; +} + +b { /* used for event dates/times */ + margin-right: 3px; +} + +.demo-app { + display: flex; + min-height: 100%; + font-family: Arial, Helvetica Neue, Helvetica, sans-serif; + font-size: 14px; +} + +.demo-app-sidebar { + width: 300px; + line-height: 1.5; + background: #eaf9ff; + border-right: 1px solid #d3e2e8; +} + +.demo-app-sidebar-section { + padding: 2em; +} + +.demo-app-main { + flex-grow: 1; + padding: 3em; +} + +.fc { /* the calendar root */ + max-width: 1100px; + margin: 0 auto; +}