From c96b7818d6d9b254321e473e2609bb606816041d Mon Sep 17 00:00:00 2001 From: Macaulay Precious <87583799+Precious-Macaulay@users.noreply.github.com> Date: Thu, 22 Feb 2024 02:29:15 +0000 Subject: [PATCH 1/3] Allow user to sort issue #1013 Fix --- frontend/src/components/task/task-table.js | 164 +++++++++++++++++---- 1 file changed, 135 insertions(+), 29 deletions(-) diff --git a/frontend/src/components/task/task-table.js b/frontend/src/components/task/task-table.js index 299f4162..633604f7 100644 --- a/frontend/src/components/task/task-table.js +++ b/frontend/src/components/task/task-table.js @@ -157,6 +157,70 @@ const styles = theme => ({ }, }) +const tableHeaderMetadata = { + "task.table.head.task": { sortable: true, numeric: false, dataBaseKey: "title" }, + "task.table.head.status": { sortable: true, numeric: false, dataBaseKey: "status" }, + "task.table.head.project": { sortable: true, numeric: false, dataBaseKey: "Project.name" }, + "task.table.head.value": { sortable: true, numeric: true, dataBaseKey: "value" }, + "task.table.head.labels": { sortable: true, numeric: false, dataBaseKey: "Labels" }, + "task.table.head.createdAt": { sortable: true, numeric: false, dataBaseKey: "createdAt" } +} + +const getSortingValue = (item, fieldId) => { + const getValue = (item, dataBaseKey) => { + const keys = dataBaseKey.split("."); + return keys.reduce((obj, key) => (obj && obj[key] !== 'undefined') ? obj[key] : undefined, item); + }; + + const metadata = tableHeaderMetadata[fieldId]; + if (!metadata) { + console.error(`No metadata found for fieldId: ${fieldId}`); + return null; + } + + const { numeric, dataBaseKey } = metadata; + + const value = getValue(item, dataBaseKey); + + if (value === undefined) { + console.error(`Failed to get value for fieldId: ${fieldId}`); + return null; + } + + if (Date.parse(value)) { + return new Date(value).getTime(); + } + + if (numeric) { + const parsedValue = parseFloat(value); + if (isNaN(parsedValue)) { + console.error(`Failed to parse numeric value for fieldId: ${fieldId}`); + return null; + } + return parsedValue; + } + return value; +}; + +const sortData = (data, sortedBy, sortDirection) => { + if (sortDirection === 'none') { + return data; // Return the original data if no sorting is required + } + + return [...data].sort((a, b) => { + let aValue = getSortingValue(a, sortedBy); + let bValue = getSortingValue(b, sortedBy); + + if (aValue === null || bValue === null) { + return 0; + } + + const comparator = String(aValue).localeCompare(String(bValue), 'en', { numeric: true, sensitivity: 'base', ignorePunctuation: true }); + + return sortDirection === 'asc' ? comparator : -comparator + }); +}; + class CustomPaginationActionsTable extends React.Component { constructor(props) { super(props) @@ -164,9 +228,41 @@ class CustomPaginationActionsTable extends React.Component { this.state = { page: 0, rowsPerPage: 10, + sortedBy: null, + sortDirection: 'asc', + sortedData: this.props.tasks.data } } + componentDidUpdate(prevProps) { + if (prevProps.tasks !== this.props.tasks) { + const { sortedBy, sortDirection } = this.state; + const newSortedData = sortData(this.props.tasks.data, sortedBy, sortDirection); + this.setState({ + sortedData: newSortedData + }); + } + } + + handleSort = (fieldId, sortDirection) => { + const newSortedData = sortData(this.props.tasks.data, fieldId, sortDirection); + + return { + sortedBy: fieldId, + sortDirection, + sortedData: newSortedData, + }; + } + + sortHandler = (fieldId) => { + this.setState((prevState) => { + const { sortedBy, sortDirection } = prevState; + const newSortDirection = sortedBy === fieldId ? (sortDirection === 'asc' ? 'desc' : (sortDirection === 'desc' ? 'none' : 'asc')) : 'asc'; + return this.handleSort(fieldId, newSortDirection); + }); + }; + + handleChangePage = (event, page) => { this.setState({ page }) }; @@ -189,8 +285,39 @@ class CustomPaginationActionsTable extends React.Component { render() { const { classes, tasks } = this.props - const { rowsPerPage, page } = this.state - const emptyRows = tasks.data.length ? rowsPerPage - Math.min(rowsPerPage, tasks.data.length - page * rowsPerPage) : 0 + const { rowsPerPage, page, sortedBy, sortDirection, sortedData } = this.state; + + const emptyRows = sortedData.length ? rowsPerPage - Math.min(rowsPerPage, sortedData.length - page * rowsPerPage) : 0 + const TableCellWithSortLogic = ({ fieldId, defineMessage, sortHandler }) => { + return ( + { + return sortHandler(fieldId) + } + } + > + + + ) + } + + const TableHeadCustom = () => { + console.log() + return ( + + + {Object.entries(tableHeaderMetadata).map(([fieldId, metadata]) => ( + + + + ))} + + + ); + }; if (tasks.completed && tasks.data.length === 0) { @@ -208,30 +335,9 @@ class CustomPaginationActionsTable extends React.Component {
- - - - - - - - - - - - - - - - - - - - - - + - {tasks.data.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage).map(n => { + {sortedData.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage).map(n => { const assigned = n.Assigns.find(a => a.id === n.assigned) const assignedUser = assigned && assigned.User return ( @@ -299,11 +405,11 @@ class CustomPaginationActionsTable extends React.Component { this.handleChangePage(e, page)} - onChangeRowsPerPage={(e, page) => this.handleChangeRowsPerPage(e, page)} + onPageChange={(e, page) => this.handleChangePage(e, page)} + onRowsPerPageChange={(e, page) => this.handleChangeRowsPerPage(e, page)} Actions={TablePaginationActionsWrapped} /> @@ -323,4 +429,4 @@ CustomPaginationActionsTable.propTypes = { user: PropTypes.object, } -export default injectIntl(withRouter(withStyles(styles)(CustomPaginationActionsTable))) +export default injectIntl(withRouter(withStyles(styles)(CustomPaginationActionsTable))) \ No newline at end of file From f98bd0b53bf1d562b1889e3adb27d2f48f6ffafb Mon Sep 17 00:00:00 2001 From: Macaulay Precious <87583799+Precious-Macaulay@users.noreply.github.com> Date: Thu, 22 Feb 2024 02:43:18 +0000 Subject: [PATCH 2/3] added pmd file to root --- pmd.xml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 pmd.xml diff --git a/pmd.xml b/pmd.xml new file mode 100644 index 00000000..f39b32c2 --- /dev/null +++ b/pmd.xml @@ -0,0 +1,12 @@ + + + + + + + + + \ No newline at end of file From eb5ae7f15cef0552f23c3c88997c7315d34c1dea Mon Sep 17 00:00:00 2001 From: Macaulay Precious <87583799+Precious-Macaulay@users.noreply.github.com> Date: Sat, 24 Feb 2024 00:39:16 +0000 Subject: [PATCH 3/3] fix sorting issue in task table --- frontend/src/components/task/task-table.js | 33 ++++++++++++++-------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/frontend/src/components/task/task-table.js b/frontend/src/components/task/task-table.js index bbea91cb..89218fe5 100644 --- a/frontend/src/components/task/task-table.js +++ b/frontend/src/components/task/task-table.js @@ -167,6 +167,7 @@ const tableHeaderMetadata = { } const getSortingValue = (item, fieldId) => { + const getValue = (item, dataBaseKey) => { const keys = dataBaseKey.split("."); return keys.reduce((obj, key) => (obj && obj[key] !== 'undefined') ? obj[key] : undefined, item); @@ -187,10 +188,6 @@ const getSortingValue = (item, fieldId) => { return null; } - if (Date.parse(value)) { - return new Date(value).getTime(); - } - if (numeric) { const parsedValue = parseFloat(value); if (isNaN(parsedValue)) { @@ -203,21 +200,33 @@ const getSortingValue = (item, fieldId) => { }; const sortData = (data, sortedBy, sortDirection) => { - if (sortDirection === 'none') { - return data; // Return the original data if no sorting is required - } + if (sortDirection === 'none') return data; return [...data].sort((a, b) => { let aValue = getSortingValue(a, sortedBy); let bValue = getSortingValue(b, sortedBy); + // Handle null values if (aValue === null || bValue === null) { - return 0; + return (aValue === null ? (sortDirection === 'asc' ? -1 : 1) : (sortDirection === 'asc' ? 1 : -1)); } - const comparator = String(aValue).localeCompare(String(bValue), 'en', { numeric: true, sensitivity: 'base', ignorePunctuation: true }); + // Handle date sorting + if (sortedBy === 'task.table.head.createdAt') { + let aDate = new Date(aValue).getTime(); + let bDate = new Date(bValue).getTime(); + return (sortDirection === 'asc' ? aDate - bDate : bDate - aDate); + } - return sortDirection === 'asc' ? comparator : -comparator + // Handle labels array sorting + if (sortedBy === 'task.table.head.labels') { + aValue = aValue.map(label => label.name).join(''); + bValue = bValue.map(label => label.name).join(''); + } + + // Handle string sorting + let comparator = String(aValue).localeCompare(String(bValue), 'en', { numeric: true, sensitivity: 'base', ignorePunctuation: true }); + return (sortDirection === 'asc' ? comparator : -comparator); }); }; @@ -320,13 +329,13 @@ class CustomPaginationActionsTable extends React.Component { if (tasks.completed && tasks.data.length === 0) { - + return (
-
+
); } return (