From d3342aece35f1226248c9251eee72a30c6843772 Mon Sep 17 00:00:00 2001 From: Luke Liew Mouawad Date: Fri, 5 Apr 2024 21:14:42 +0100 Subject: [PATCH 1/4] fixed bug where consultant could resubmit data in wrong format --- .../TimesheetCard.js | 50 ++++++++++--------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/frontend/src/Components/View_Saved_Timesheets_Page/TimesheetCard.js b/frontend/src/Components/View_Saved_Timesheets_Page/TimesheetCard.js index 62e78011..1b4ca9fd 100644 --- a/frontend/src/Components/View_Saved_Timesheets_Page/TimesheetCard.js +++ b/frontend/src/Components/View_Saved_Timesheets_Page/TimesheetCard.js @@ -9,28 +9,30 @@ export default function TimesheetCard(props) { function resubmitTimesheet() { if(hasResubmitted != true) { - console.log("Resubmitting timesheet " + props.id) - fetch('http://127.0.0.1:5000/update_timesheet/' + props.id, { - method: "PUT", - headers: { "Content-Type": "application/json" }, - credentials: 'include', - body: JSON.stringify({ - start_time: newStartTime, - end_time: newEndTime - }) - }).then(response => { - if (response.ok) { - console.log("Timesheet updated successfully"); - return response.json(); - } else { - throw new Error('Failed to update timesheet with status: ' + response.status); - } - }).then(data => { - console.log(data); // Handle the success response - }).catch(error => { - console.error(error); // Handle any errors - }); - setHasResubmitted(true) + if(/^([01]?[0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$/.test(newStartTime) && /^([01]?[0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$/.test(newEndTime)) { + console.log("Resubmitting timesheet " + props.id) + fetch('http://127.0.0.1:5000/update_timesheet/' + props.id, { + method: "PUT", + headers: { "Content-Type": "application/json" }, + credentials: 'include', + body: JSON.stringify({ + start_time: newStartTime, + end_time: newEndTime + }) + }).then(response => { + if (response.ok) { + console.log("Timesheet updated successfully"); + return response.json(); + } else { + throw new Error('Failed to update timesheet with status: ' + response.status); + } + }).then(data => { + console.log(data); // Handle the success response + }).catch(error => { + console.error(error); // Handle any errors + }); + setHasResubmitted(true) + } } } @@ -46,14 +48,14 @@ export default function TimesheetCard(props) { return(

Day : {props.day}

Old Work Start : {props.workStart}

- setNewStartTime(e.target.value)} />

Old Work End : {props.workEnd}

- Date: Sat, 6 Apr 2024 12:01:40 +0100 Subject: [PATCH 2/4] bug fix with timesheet edit --- backend/timesheets/routes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/timesheets/routes.py b/backend/timesheets/routes.py index 629de07f..c0113d07 100644 --- a/backend/timesheets/routes.py +++ b/backend/timesheets/routes.py @@ -137,7 +137,7 @@ def put(self, timesheet_id): timesheet.end_work_time = end_time timesheet.status = "pending" - time_elapsed = datetime.strptime(end_work_time, "%H:%M:%S") - datetime.strptime(start_work_time, "%H:%M:%S") + time_elapsed = datetime.strptime(timesheet.end_work_time, "%H:%M:%S") - datetime.strptime(timesheet.start_work_time, "%H:%M:%S") time_elapsed = time_elapsed.total_seconds() timesheet.hours_worked = time_elapsed From f8fc3c05f6f70a7c3b8d7fc7b44226934ba04f8c Mon Sep 17 00:00:00 2001 From: Luke Liew Mouawad Date: Sat, 6 Apr 2024 14:41:00 +0100 Subject: [PATCH 3/4] added filtering options to consultant view saved timesheets page --- .../Consultant/ViewSavedTimesheets.module.css | 4 ++ .../Consultant/view_saved_timesheets_page.js | 67 ++++++++++++++++++- 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/frontend/src/Pages/Consultant/ViewSavedTimesheets.module.css b/frontend/src/Pages/Consultant/ViewSavedTimesheets.module.css index fbc13664..5021eec4 100644 --- a/frontend/src/Pages/Consultant/ViewSavedTimesheets.module.css +++ b/frontend/src/Pages/Consultant/ViewSavedTimesheets.module.css @@ -6,4 +6,8 @@ body{ margin: 0; padding: 0; +} + +.filterTitle{ + color: aliceblue; } \ No newline at end of file diff --git a/frontend/src/Pages/Consultant/view_saved_timesheets_page.js b/frontend/src/Pages/Consultant/view_saved_timesheets_page.js index 3c8a3380..e4486fc8 100644 --- a/frontend/src/Pages/Consultant/view_saved_timesheets_page.js +++ b/frontend/src/Pages/Consultant/view_saved_timesheets_page.js @@ -11,8 +11,56 @@ export default function ViewSavedTimesheetsPage() { {pageName : "View Saved Timesheets", pageLink : "/view_saved_timesheet", iconPath : "./Home_Page_Icons/Consultant/view_saved_timesheets.svg"}] const [timesheets, setTimesheets] = useState([]); + const [selectedTimeFilter, setSelectedTimeFilter] = useState('') + const [selectedStatusFilter, setSelectedStatusFilter] = useState('') + const [filteredTimesheets, setFilteredTimesheets] = useState([]) var timesheetsArray = [] + //set default options for filters + if(selectedTimeFilter == '' && selectedStatusFilter == '') { + setSelectedTimeFilter('new_to_old') + setSelectedStatusFilter('all') + console.log(selectedTimeFilter) + } + + + + //handle when user selects different filters + const handleTimeFilterChange = (event) => { + setSelectedTimeFilter(event.target.value) + } + useEffect(() => { + console.log(selectedTimeFilter) + if(timesheetsArray.length != 0) { + //filter results by time + const filteredTimeArray = selectedTimeFilter == 'new_to_old' ? timesheetsArray.reverse() : timesheetsArray + setFilteredTimesheets(filteredTimeArray) + + //filter results by status + if(selectedStatusFilter != 'all') { + setFilteredTimesheets(filteredTimeArray.filter(item => item.status === selectedStatusFilter)) + } + } + }, [selectedTimeFilter]); + + + const handleStatusFilterChange = (event) => { + setSelectedStatusFilter(event.target.value) + } + useEffect(() => { + console.log(selectedStatusFilter) + if(timesheetsArray.length != 0) { + const filteredTimeArray = selectedTimeFilter == 'new_to_old' ? timesheetsArray.reverse() : timesheetsArray + setFilteredTimesheets(filteredTimeArray) + + //filter results by status + if(selectedStatusFilter != 'all') { + setFilteredTimesheets(filteredTimeArray.filter(item => item.status === selectedStatusFilter)) + } + console.log(filteredTimesheets, "filtered timesheets") + } + }, [selectedStatusFilter]); + //api call useEffect(() => { const fetchData = async () =>{ @@ -61,7 +109,24 @@ export default function ViewSavedTimesheetsPage() {

Saved Timesheets

- {timesheetsArray.map(timesheetData => ( + +

{selectedTimeFilter} : {selectedStatusFilter}

+ + + + + + + + {filteredTimesheets.map(timesheetData => ( Date: Sat, 6 Apr 2024 19:50:31 +0100 Subject: [PATCH 4/4] added filtering options to viewing timesheets pages for line manager and consultant --- .../Consultant/view_saved_timesheets_page.js | 112 +++++++++++------- .../view_consultant_timesheet_page.css | 0 .../view_consultant_timesheet_page.js | 101 ++++++++++++++-- 3 files changed, 158 insertions(+), 55 deletions(-) create mode 100644 frontend/src/Pages/Line_Manager/view_consultant_timesheet_page.css diff --git a/frontend/src/Pages/Consultant/view_saved_timesheets_page.js b/frontend/src/Pages/Consultant/view_saved_timesheets_page.js index e4486fc8..477c56dc 100644 --- a/frontend/src/Pages/Consultant/view_saved_timesheets_page.js +++ b/frontend/src/Pages/Consultant/view_saved_timesheets_page.js @@ -11,23 +11,17 @@ export default function ViewSavedTimesheetsPage() { {pageName : "View Saved Timesheets", pageLink : "/view_saved_timesheet", iconPath : "./Home_Page_Icons/Consultant/view_saved_timesheets.svg"}] const [timesheets, setTimesheets] = useState([]); - const [selectedTimeFilter, setSelectedTimeFilter] = useState('') - const [selectedStatusFilter, setSelectedStatusFilter] = useState('') + const [selectedTimeFilter, setSelectedTimeFilter] = useState('new_to_old') + const [selectedStatusFilter, setSelectedStatusFilter] = useState('all') const [filteredTimesheets, setFilteredTimesheets] = useState([]) - var timesheetsArray = [] - - //set default options for filters - if(selectedTimeFilter == '' && selectedStatusFilter == '') { - setSelectedTimeFilter('new_to_old') - setSelectedStatusFilter('all') - console.log(selectedTimeFilter) - } - + const [hasSelectedFiltering, setHasSelectedFiltering] = useState(false) + var timesheetsArray = [] //handle when user selects different filters const handleTimeFilterChange = (event) => { setSelectedTimeFilter(event.target.value) + setHasSelectedFiltering(true) } useEffect(() => { console.log(selectedTimeFilter) @@ -46,6 +40,7 @@ export default function ViewSavedTimesheetsPage() { const handleStatusFilterChange = (event) => { setSelectedStatusFilter(event.target.value) + setHasSelectedFiltering(true) } useEffect(() => { console.log(selectedStatusFilter) @@ -102,39 +97,64 @@ export default function ViewSavedTimesheetsPage() { timesheetsArray.push(entry[1]) }) - console.log(timesheetsArray) - - return( - <> - -
-

Saved Timesheets

- -

{selectedTimeFilter} : {selectedStatusFilter}

- - - - - - - - {filteredTimesheets.map(timesheetData => ( - - ))} -
- - ) + if(timesheetsArray.length != 0) { + const reversedTimesheetsArray = reverseArray(timesheetsArray) + console.log(filteredTimesheets, reversedTimesheetsArray) + return( + <> + +
+

Saved Timesheets

+ +

{selectedTimeFilter} : {selectedStatusFilter}

+ + + + + + + + { + filteredTimesheets.length == 0 && !hasSelectedFiltering? + reversedTimesheetsArray.map(timesheetData => ( + + )) : + filteredTimesheets.map(timesheetData => ( + + ))} +
+ + ) + } + else { + return( +

Loading data

+ ) + } +} + +function reverseArray(arrayToReverse) { + var reversedArray = [] + for(let i=arrayToReverse.length-1; i>=0; i--) { + reversedArray.push(arrayToReverse[i]) + } + return reversedArray } \ No newline at end of file diff --git a/frontend/src/Pages/Line_Manager/view_consultant_timesheet_page.css b/frontend/src/Pages/Line_Manager/view_consultant_timesheet_page.css new file mode 100644 index 00000000..e69de29b diff --git a/frontend/src/Pages/Line_Manager/view_consultant_timesheet_page.js b/frontend/src/Pages/Line_Manager/view_consultant_timesheet_page.js index 9bc52912..8ef33218 100644 --- a/frontend/src/Pages/Line_Manager/view_consultant_timesheet_page.js +++ b/frontend/src/Pages/Line_Manager/view_consultant_timesheet_page.js @@ -1,12 +1,17 @@ import { useState, useEffect } from "react"; import TimesheetDayCard from "../../Components/View_Consultant_Timesheet/TimesheetDayCard"; +import styles from './view_consultant_timesheet_page.css' export default function ConsultantTimesheetViewerPage() { const [selectedConsultantName, setSelectedConsultantName] = useState('') const [foundTimesheets, setFoundTimesheets] = useState([]) var storedConsultantName = localStorage.getItem("selectedConsultant") + const [selectedTimeFilter, setSelectedTimeFilter] = useState('new_to_old') + const [selectedStatusFilter, setSelectedStatusFilter] = useState('all') + const [filteredTimesheets, setFilteredTimesheets] = useState([]) var foundTimesheetsArray = [] + const [hasSelectedFiltering, setHasSelectedFiltering] = useState(false) if(selectedConsultantName == '') { setSelectedConsultantName(storedConsultantName) @@ -16,6 +21,49 @@ export default function ConsultantTimesheetViewerPage() { document.title = "Viewing " + selectedConsultantName + "'s Timesheets" + + + //handle when user selects different filters + const handleTimeFilterChange = (event) => { + setSelectedTimeFilter(event.target.value) + setHasSelectedFiltering(true) + } + useEffect(() => { + console.log(selectedTimeFilter) + if(foundTimesheetsArray.length != 0) { + //filter results by time + const filteredTimeArray = selectedTimeFilter == 'new_to_old' ? foundTimesheetsArray.reverse() : foundTimesheetsArray + setFilteredTimesheets(filteredTimeArray) + + //filter results by status + if(selectedStatusFilter != 'all') { + setFilteredTimesheets(filteredTimeArray.filter(item => item.status === selectedStatusFilter)) + } + } + }, [selectedTimeFilter]); + + + const handleStatusFilterChange = (event) => { + setSelectedStatusFilter(event.target.value) + setHasSelectedFiltering(true) + } + useEffect(() => { + console.log(selectedStatusFilter) + if(foundTimesheetsArray.length != 0) { + const filteredTimeArray = selectedTimeFilter == 'new_to_old' ? foundTimesheetsArray.reverse() : foundTimesheetsArray + setFilteredTimesheets(filteredTimeArray) + + //filter results by status + if(selectedStatusFilter != 'all') { + setFilteredTimesheets(filteredTimeArray.filter(item => item.status === selectedStatusFilter)) + } + console.log(filteredTimesheets, "filtered timesheets") + } + }, [selectedStatusFilter]); + + + + //api call to fetch timesheets of specific user useEffect(() => { const fetchData = async () =>{ @@ -54,14 +102,49 @@ export default function ConsultantTimesheetViewerPage() { }) console.log(foundTimesheetsArray) + console.log(hasSelectedFiltering) + + if(foundTimesheetsArray.length != 0) { + const reversedTimesheetsArray = reverseArray(foundTimesheetsArray) + + return( + <> +

{selectedConsultantName}

+ +

{selectedTimeFilter} : {selectedStatusFilter}

- return( - <> -

{selectedConsultantName}

-
- {foundTimesheetsArray.map(timesheetDayData => ( - - ))} -
- ) + + + + + + +
+ { + filteredTimesheets.length == 0 && !hasSelectedFiltering ? + reversedTimesheetsArray.map(timesheetDayData => ( + + )) : + filteredTimesheets.map(timesheetDayData => ( + + ))} +
+ ) + } +} + +function reverseArray(arrayToReverse) { + var reversedArray = [] + for(let i=arrayToReverse.length-1; i>=0; i--) { + reversedArray.push(arrayToReverse[i]) + } + return reversedArray } \ No newline at end of file