From a044317166ae1201354667e138a4dbd34daad93f Mon Sep 17 00:00:00 2001 From: Nico Date: Sun, 28 Apr 2024 13:57:24 +0200 Subject: [PATCH 1/3] Context update after actions --- src/component/Calendar.jsx | 3 ++- src/component/Context.jsx | 20 ++++++++++++++++---- src/component/CreateMember.jsx | 30 ++++++++++++++++++------------ src/component/DeleteMember.jsx | 5 +++-- 4 files changed, 39 insertions(+), 19 deletions(-) diff --git a/src/component/Calendar.jsx b/src/component/Calendar.jsx index 00e636f..3fe4e2f 100644 --- a/src/component/Calendar.jsx +++ b/src/component/Calendar.jsx @@ -8,7 +8,7 @@ import '../styles/calender.css' function MyCalendar() { const localizer = dayjsLocalizer(dayjs); - const { teams, members } = useContext(TeamDataContext); + const { teams, members, refreshTeamData } = useContext(TeamDataContext); const [events, setEvents] = useState([]); const [selectedEvent, setSelectedEvent] = useState(null); @@ -43,6 +43,7 @@ function MyCalendar() { }); setEvents(formattedEvents); + refreshTeamData() } catch (error) { console.error("Error fetching events:", error); } diff --git a/src/component/Context.jsx b/src/component/Context.jsx index 07fec3e..af6bc4e 100644 --- a/src/component/Context.jsx +++ b/src/component/Context.jsx @@ -7,9 +7,13 @@ const TeamDataProvider = ({ children }) => { const [teams, setTeams] = useState([]); const [members, setMembers] = useState([]); const [timeOff, setTimeOff] = useState([]); + const [dataIsOld, setDataIsOld] = useState(false); - useEffect(() => { - const fetchData = async () => { + const refreshTeamData = () => { + setDataIsOld(true) + } + + const fetchData = async () => { try { const [teamsResponse, membersResponse, timeOffResponse] = await Promise.all([ fetch(apiPath('/teams')), @@ -28,12 +32,20 @@ const TeamDataProvider = ({ children }) => { console.error('Error fetching data:', error); } }; - + + useEffect(() => { fetchData(); }, []); + useEffect(() => { + if(dataIsOld) { + fetchData(); + setDataIsOld(false) + } + }, [dataIsOld]); + return ( - + {children} ); diff --git a/src/component/CreateMember.jsx b/src/component/CreateMember.jsx index 09b5c4d..70df033 100644 --- a/src/component/CreateMember.jsx +++ b/src/component/CreateMember.jsx @@ -1,13 +1,12 @@ import { useState, useEffect, useContext } from "react"; import { useParams } from "react-router-dom"; -import { apiPath } from '../api'; -import { TeamDataContext } from '../component/Context'; -import '../styles/createMember.css' +import { apiPath } from "../api"; +import { TeamDataContext } from "../component/Context"; +import "../styles/createMember.css"; function CreateMember() { - const { code } = useParams(); - const contextData = useContext(TeamDataContext); - const teams = contextData.teams; + const { code } = useParams(); + const { teams, refreshTeamData } = useContext(TeamDataContext); const [teamId, setTeamId] = useState(null); const [memberData, setMemberData] = useState({ @@ -15,11 +14,11 @@ function CreateMember() { last_name: "", email: "", color: "#000000", - allowed_dayoff: 0, + allowed_dayoff: 0, }); useEffect(() => { - const team = teams.find(team => team.team_code === code); + const team = teams.find((team) => team.team_code === code); if (team) { setTeamId(team.id); } else { @@ -31,7 +30,7 @@ function CreateMember() { e.preventDefault(); try { - const response = await fetch(apiPath('/members'), { + const response = await fetch(apiPath("/members"), { method: "POST", headers: { "Content-Type": "application/json", @@ -39,13 +38,20 @@ function CreateMember() { body: JSON.stringify({ ...memberData, team_id: teamId, - assigned_dayoff: 0, + assigned_dayoff: 0, }), }); if (response.ok) { alert("Member created successfully!"); - setMemberData({ first_name: "", last_name: "", email: "", color: "#000000", allowed_dayoff: 0 }); + refreshTeamData(); + setMemberData({ + first_name: "", + last_name: "", + email: "", + color: "#000000", + allowed_dayoff: 0, + }); } else { const data = await response.json(); alert(data.error || "Failed to create member. Please try again."); @@ -58,7 +64,7 @@ function CreateMember() { const handleChange = (e) => { const { name, value } = e.target; - setMemberData(prevState => ({ + setMemberData((prevState) => ({ ...prevState, [name]: value, })); diff --git a/src/component/DeleteMember.jsx b/src/component/DeleteMember.jsx index 961347b..80d3159 100644 --- a/src/component/DeleteMember.jsx +++ b/src/component/DeleteMember.jsx @@ -5,7 +5,7 @@ import { useParams } from 'react-router-dom'; import '../styles/deleteMember.css'; const DeleteMember = () => { - const { members, teams } = useContext(TeamDataContext); + const { members, teams, setMembers } = useContext(TeamDataContext); const [selectedMember, setSelectedMember] = useState(''); const [filteredMembers, setFilteredMembers] = useState([]); const { code } = useParams(); @@ -48,9 +48,10 @@ const DeleteMember = () => { }); if (response.ok) { - const updatedMembers = filteredMembers.filter(member => member.id !== selectedMember); + const updatedMembers = filteredMembers.filter(member => member.id !== Number(selectedMember)); setFilteredMembers(updatedMembers); alert('Member deleted successfully'); + setMembers(updatedMembers) } else { alert('Failed to delete member. Please try again.'); } From 457b03240a306ed936cc912ecc2f195da0a2b6fa Mon Sep 17 00:00:00 2001 From: Nico Date: Mon, 29 Apr 2024 13:28:39 +0200 Subject: [PATCH 2/3] Added Delete timeoff functionality --- src/backend/API/timeoff.js | 33 ++++++++++++++++++++++++++------- src/component/Calendar.jsx | 23 +++++++++++++++++++++-- src/pages/Team.jsx | 4 +--- src/styles/deleteTimeoff.css | 11 +++++++++++ src/styles/team.css | 1 + 5 files changed, 60 insertions(+), 12 deletions(-) create mode 100644 src/styles/deleteTimeoff.css diff --git a/src/backend/API/timeoff.js b/src/backend/API/timeoff.js index 5dd82f1..16b4560 100644 --- a/src/backend/API/timeoff.js +++ b/src/backend/API/timeoff.js @@ -2,20 +2,24 @@ const express = require("express"); const router = express.Router(); const db = require("../database"); -router.get('/', async (req, res) => { +router.get("/", async (req, res) => { try { - const allTimeOffs = await db.select('*').from('timeoff'); - res.json(allTimeOffs); + const allTimeOffs = await db.select("*").from("timeoff"); + res.json(allTimeOffs); } catch (error) { console.error(error); - res.status(500).json({ error: 'An unexpected error occurred while processing your request.' }); + res + .status(500) + .json({ + error: "An unexpected error occurred while processing your request.", + }); } }); router.post("/:id", async (request, response) => { - const { start_date, end_date, description, member_id } = request.body; + const { start_date, end_date, description, member_id } = request.body; if (!start_date || !end_date || !description || !member_id) { - return response.status(400).json({ error: 'Missing required fields' }); + return response.status(400).json({ error: "Missing required fields" }); } const addTimeOff = { @@ -30,9 +34,24 @@ router.post("/:id", async (request, response) => { await db("timeoff").insert(addTimeOff); response.status(201).json("New timeoff has been added"); } catch (error) { - console.error(error); + console.error(error); response.status(500).json({ error: "Failed to add a new timeoff" }); } }); +router.delete("/", async (request, response) => { + const eventId = request.body.id; + if (!eventId) { + return response.status(400).json({ error: "Event ID is required" }); + } + + try { + await db("timeoff").where({ id: eventId }).del(); + response.status(204).send(); + } catch (error) { + console.error(error); + response.status(500).json({ error: "Failed to delete the event" }); + } +}); + module.exports = router; diff --git a/src/component/Calendar.jsx b/src/component/Calendar.jsx index 3fe4e2f..72873d5 100644 --- a/src/component/Calendar.jsx +++ b/src/component/Calendar.jsx @@ -4,7 +4,8 @@ import dayjs from "dayjs"; import "react-big-calendar/lib/css/react-big-calendar.css"; import { TeamDataContext } from "../component/Context"; import { apiPath } from "../api"; -import '../styles/calender.css' +import "../styles/calender.css"; +import '../styles/deleteTimeoff.css'; function MyCalendar() { const localizer = dayjsLocalizer(dayjs); @@ -34,6 +35,7 @@ function MyCalendar() { (member) => member.id === event.member_id ); return { + id: event.id, start: new Date(event.start_date), end: new Date(event.end_date), title: member ? `${member.first_name} ${member.last_name}` : "", @@ -43,7 +45,7 @@ function MyCalendar() { }); setEvents(formattedEvents); - refreshTeamData() + refreshTeamData(); } catch (error) { console.error("Error fetching events:", error); } @@ -56,6 +58,22 @@ function MyCalendar() { setSelectedEvent(event); }; + const handleDeleteEvent = async () => { + try { + await fetch(apiPath(`/timeoff`), { + method: "DELETE", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ id: selectedEvent.id }), + }); + setEvents(events.filter((event) => event.id !== selectedEvent.id)); + setSelectedEvent(null); + } catch (error) { + console.error("Error deleting event:", error); + } + }; + return (

{selectedEvent.title}

{selectedEvent.description}

+
)} diff --git a/src/pages/Team.jsx b/src/pages/Team.jsx index e6492dc..d9f744a 100644 --- a/src/pages/Team.jsx +++ b/src/pages/Team.jsx @@ -27,9 +27,7 @@ return( -
-

Day Off Rank

-
+ diff --git a/src/styles/deleteTimeoff.css b/src/styles/deleteTimeoff.css new file mode 100644 index 0000000..52418cf --- /dev/null +++ b/src/styles/deleteTimeoff.css @@ -0,0 +1,11 @@ +button { + width: 8em; + background-color: #e10808; + color: white; + border: none; + border-radius: 10px; + cursor: pointer; + font-family: 'Poppins'; + padding: 6px; + margin: 1em; +} \ No newline at end of file diff --git a/src/styles/team.css b/src/styles/team.css index 929f6fb..c0c3d11 100644 --- a/src/styles/team.css +++ b/src/styles/team.css @@ -9,6 +9,7 @@ .container-section { display: flex; + height: 69em; } .left-section { From 41517f50146b62fec42c81e511fd57e7a3c6d6d8 Mon Sep 17 00:00:00 2001 From: Nico Date: Mon, 29 Apr 2024 13:35:57 +0200 Subject: [PATCH 3/3] Added a confirmation message --- src/component/Calendar.jsx | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/component/Calendar.jsx b/src/component/Calendar.jsx index 72873d5..fd75216 100644 --- a/src/component/Calendar.jsx +++ b/src/component/Calendar.jsx @@ -5,13 +5,14 @@ import "react-big-calendar/lib/css/react-big-calendar.css"; import { TeamDataContext } from "../component/Context"; import { apiPath } from "../api"; import "../styles/calender.css"; -import '../styles/deleteTimeoff.css'; +import "../styles/deleteTimeoff.css"; function MyCalendar() { const localizer = dayjsLocalizer(dayjs); const { teams, members, refreshTeamData } = useContext(TeamDataContext); const [events, setEvents] = useState([]); const [selectedEvent, setSelectedEvent] = useState(null); + const [showDeleteConfirmation, setShowDeleteConfirmation] = useState(false); useEffect(() => { const teamCode = window.location.pathname.split("/").pop(); @@ -59,6 +60,10 @@ function MyCalendar() { }; const handleDeleteEvent = async () => { + setShowDeleteConfirmation(true); + }; + + const confirmDelete = async () => { try { await fetch(apiPath(`/timeoff`), { method: "DELETE", @@ -69,11 +74,16 @@ function MyCalendar() { }); setEvents(events.filter((event) => event.id !== selectedEvent.id)); setSelectedEvent(null); + setShowDeleteConfirmation(false); } catch (error) { console.error("Error deleting event:", error); } }; + const cancelDelete = () => { + setShowDeleteConfirmation(false); + }; + return (
{selectedEvent.title}

{selectedEvent.description}

+ {showDeleteConfirmation && ( +
+

Are you sure you want to delete this event?

+ + +
+ )}
)}