From b48a895fddc2b22f96622d0030dba9e8691fd654 Mon Sep 17 00:00:00 2001 From: Jerry Wang Date: Fri, 3 May 2024 12:39:39 -0700 Subject: [PATCH 1/3] add sort header basic fn; need more tweet --- client/components/form/ApplicationTable.tsx | 91 ++++++++++++++++----- 1 file changed, 71 insertions(+), 20 deletions(-) diff --git a/client/components/form/ApplicationTable.tsx b/client/components/form/ApplicationTable.tsx index db26017..0807565 100644 --- a/client/components/form/ApplicationTable.tsx +++ b/client/components/form/ApplicationTable.tsx @@ -1,34 +1,85 @@ import Link from 'next/link'; +import { useRouter } from 'next/router'; +import { useMemo } from 'react'; import { ApplicationTableProps } from '../../constants/interfaces'; import { formatDate } from 'utils'; type Props = { applications: ApplicationTableProps[] }; +enum Order { + ASC = 'ASC', + DESC = 'DESC', +} + +enum OrderBy { + CONFIRMATION_ID = 'confirmationId', + ASSIGNED_TO = 'assignedTo', + STATUS = 'status', + SUBMISSION_ID = 'submissionId', + UPDATED_AT = 'updatedAt', +} const TableHeader: React.FC = () => { - const headers = [ - 'Confirmation ID', - 'Funding Year', - 'Applicant Name', - 'Application Type', - 'Project Title', - 'Estimated Cost', - 'Asks', - 'Assigned to', - 'Last Updated', - 'Status', + const router = useRouter(); + const { query } = router; + const currentSort: OrderBy | '' = (query.orderBy as OrderBy) || ''; + const sortOrder: Order | undefined = (query.order as Order) || undefined; + + const handleSort = (field: string) => { + // const order = (field === currentSort && sortOrder === Order.ASC) ? Order.DESC : Order.ASC; + let order: Order | undefined = Order.ASC; + if (field === currentSort && sortOrder === Order.ASC) { + order = Order.DESC; + } else if (field === currentSort && sortOrder === Order.DESC) { + order = undefined; + } + const newQuery = { ...query }; + if (order) { + newQuery.orderBy = field; + newQuery.order = order; + } else { + delete newQuery.orderBy; + delete newQuery.order; + } + router.push({ query: newQuery }); + }; + + const getSortIcon = (field: string) => { + if (field === currentSort) { + return sortOrder === Order.ASC ? '↑' : sortOrder === Order.DESC ? '↓' : ''; + } + return ''; + }; + + type Column = { + name: string; + field: string; + }; + + const columns: Column[] = [ + { name: 'Confirmation ID', field: 'confirmationId' }, + { name: 'Funding Year', field: 'fundingYear' }, + { name: 'Applicant Name', field: 'applicantName' }, + { name: 'Application Type', field: 'applicationType.name' }, + { name: 'Project Title', field: 'projectTitle' }, + { name: 'Estimated Cost', field: 'totalEstimatedCost' }, + { name: 'Asks', field: 'asks' }, + { name: 'Assigned to', field: 'assignedTo.displayName' }, + { name: 'Last Updated', field: 'updatedAt' }, + { name: 'Status', field: 'status.name' }, ]; const tdStyles = - 'table-td table-header px-6 py-4 text-left text-sm font-strong border-b-2 border-bcYellowWarning'; + 'table-td table-header cursor-pointer px-6 py-4 text-left text-sm font-strong border-b-2 border-bcYellowWarning'; + + const headers = useMemo(() => { + return columns.map(({ name, field }) => ( + handleSort(field)}> + {name} {getSortIcon(field)} + + )); + }, [columns, currentSort, sortOrder]); return ( - - {headers && - headers.map((title: string, index: number) => ( - - {title} - - ))} - + {headers} ); }; From de1a21fcf01bb641eb40e63007fe7c88d893c60a Mon Sep 17 00:00:00 2001 From: Jerry Wang Date: Mon, 6 May 2024 15:31:36 -0700 Subject: [PATCH 2/3] add all headers to be sortable --- api/src/application/application.service.ts | 8 +++++- api/src/common/enums.ts | 8 ++++++ client/components/form/ApplicationTable.tsx | 30 +++++++++++++-------- 3 files changed, 34 insertions(+), 12 deletions(-) diff --git a/api/src/application/application.service.ts b/api/src/application/application.service.ts index c33b01f..31ec2a3 100644 --- a/api/src/application/application.service.ts +++ b/api/src/application/application.service.ts @@ -80,7 +80,13 @@ export class ApplicationService { } if (query.orderBy) { - queryBuilder.orderBy({ [`app.${query.orderBy}`]: query.order }); + if ( + ['applicationType.name', 'assignedTo.displayName', 'status.name'].includes(query.orderBy) + ) { + queryBuilder.orderBy({ [`${query.orderBy}`]: query.order }); + } else { + queryBuilder.orderBy({ [`app.${query.orderBy}`]: query.order }); + } } query.filter(queryBuilder); diff --git a/api/src/common/enums.ts b/api/src/common/enums.ts index 061bd2e..b29786a 100644 --- a/api/src/common/enums.ts +++ b/api/src/common/enums.ts @@ -9,6 +9,14 @@ export enum ApplicationSortOptions { STATUS = 'status', SUBMISSION_ID = 'submissionId', UPDATED_AT = 'updatedAt', + FUNDING_YEAR = 'fundingYear', + APPLICANT_NAME = 'applicantName', + APPLICATION_TYPE_NAME = 'applicationType.name', + TOTAL_ESTIMATED_COST = 'totalEstimatedCost', + ASKS = 'asks', + ASSIGNED_TO_DISPLAYNAME = 'assignedTo.displayName', + STATUS_NAME = 'status.name', + PROJECT_TITLE = 'projectTitle' } export enum AxiosResponseTypes { diff --git a/client/components/form/ApplicationTable.tsx b/client/components/form/ApplicationTable.tsx index 0807565..de966b7 100644 --- a/client/components/form/ApplicationTable.tsx +++ b/client/components/form/ApplicationTable.tsx @@ -16,6 +16,14 @@ enum OrderBy { STATUS = 'status', SUBMISSION_ID = 'submissionId', UPDATED_AT = 'updatedAt', + FUNDING_YEAR = 'fundingYear', + APPLICANT_NAME = 'applicantName', + APPLICATION_TYPE_NAME = 'applicationType.name', + TOTAL_ESTIMATED_COST = 'totalEstimatedCost', + ASKS = 'asks', + ASSIGNED_TO_DISPLAYNAME = 'assignedTo.displayName', + STATUS_NAME = 'status.name', + PROJECT_TITLE = 'projectTitle', } const TableHeader: React.FC = () => { @@ -25,7 +33,6 @@ const TableHeader: React.FC = () => { const sortOrder: Order | undefined = (query.order as Order) || undefined; const handleSort = (field: string) => { - // const order = (field === currentSort && sortOrder === Order.ASC) ? Order.DESC : Order.ASC; let order: Order | undefined = Order.ASC; if (field === currentSort && sortOrder === Order.ASC) { order = Order.DESC; @@ -53,19 +60,20 @@ const TableHeader: React.FC = () => { type Column = { name: string; field: string; + sortable?: boolean; }; const columns: Column[] = [ - { name: 'Confirmation ID', field: 'confirmationId' }, - { name: 'Funding Year', field: 'fundingYear' }, - { name: 'Applicant Name', field: 'applicantName' }, - { name: 'Application Type', field: 'applicationType.name' }, - { name: 'Project Title', field: 'projectTitle' }, - { name: 'Estimated Cost', field: 'totalEstimatedCost' }, - { name: 'Asks', field: 'asks' }, - { name: 'Assigned to', field: 'assignedTo.displayName' }, - { name: 'Last Updated', field: 'updatedAt' }, - { name: 'Status', field: 'status.name' }, + { name: 'Confirmation ID', field: 'confirmationId', sortable: true }, + { name: 'Funding Year', field: 'fundingYear', sortable: true }, + { name: 'Applicant Name', field: 'applicantName', sortable: true }, + { name: 'Application Type', field: 'applicationType.name', sortable: true }, + { name: 'Project Title', field: 'projectTitle', sortable: true }, + { name: 'Estimated Cost', field: 'totalEstimatedCost', sortable: true }, + { name: 'Asks', field: 'asks', sortable: true }, + { name: 'Assigned to', field: 'assignedTo.displayName', sortable: true }, + { name: 'Last Updated', field: 'updatedAt', sortable: true }, + { name: 'Status', field: 'status.name', sortable: true }, ]; const tdStyles = 'table-td table-header cursor-pointer px-6 py-4 text-left text-sm font-strong border-b-2 border-bcYellowWarning'; From fb5ca521a93474c99053828e675b49ddd0349682 Mon Sep 17 00:00:00 2001 From: Jerry Wang Date: Mon, 6 May 2024 15:36:29 -0700 Subject: [PATCH 3/3] fix format --- api/src/common/enums.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/common/enums.ts b/api/src/common/enums.ts index b29786a..2ea5b2d 100644 --- a/api/src/common/enums.ts +++ b/api/src/common/enums.ts @@ -16,7 +16,7 @@ export enum ApplicationSortOptions { ASKS = 'asks', ASSIGNED_TO_DISPLAYNAME = 'assignedTo.displayName', STATUS_NAME = 'status.name', - PROJECT_TITLE = 'projectTitle' + PROJECT_TITLE = 'projectTitle', } export enum AxiosResponseTypes {