From 406d5d338b1538ae60404c731d3d90284e71c511 Mon Sep 17 00:00:00 2001 From: Daniel Haselhan Date: Thu, 2 Jan 2025 16:01:26 -0800 Subject: [PATCH 1/2] feat: Switch from handleRowClicked to defaultColumn * Set linkCell Renderer and link props on default column and remove row click. * Update cell renderers to all support links if present * Apply to lots of tables * Move test files to be closer to their components --- frontend/src/utils/grid/cellRenderers.jsx | 92 +++++----- .../Admin/AdminMenu/components/AuditLog.jsx | 27 ++- .../AdminMenu/components/UserActivity.jsx | 55 +++--- .../Admin/AdminMenu/components/Users.jsx | 26 +-- .../Admin/AdminMenu/components/ViewUser.jsx | 73 ++++---- .../__tests__/AdminTabPanel.test.jsx | 4 +- .../components/__tests__/AuditLog.test.jsx | 72 ++++---- .../__tests__/UserActivity.test.jsx | 131 ++++++++++----- .../components/__tests__/Users.test.jsx | 49 ++++++ .../components}/__tests__/ViewUser.test.jsx | 14 +- .../Admin/AdminMenu/components/_schema.js | 5 +- .../src/views/Admin/__tests__/Users.test.jsx | 158 ------------------ .../AllocationAgreementSummary.jsx | 22 +-- .../ComplianceReports/ComplianceReports.jsx | 92 +++++----- .../FinalSupplyEquipmentSummary.jsx | 31 ++-- frontend/src/views/FuelCodes/FuelCodes.jsx | 25 +-- frontend/src/views/FuelCodes/_schema.jsx | 52 ++---- .../views/FuelExports/FuelExportSummary.jsx | 28 ++-- .../views/FuelSupplies/FuelSupplySummary.jsx | 31 ++-- .../NotionalTransferSummary.jsx | 32 ++-- .../src/views/Organizations/Organizations.jsx | 26 +-- .../ViewOrganization/ViewOrganization.jsx | 47 +++--- .../src/views/OtherUses/OtherUsesSummary.jsx | 40 ++--- .../src/views/Transactions/Transactions.jsx | 101 +++++------ .../__tests__/Transactions.test.jsx | 13 -- 25 files changed, 558 insertions(+), 688 deletions(-) rename frontend/src/views/Admin/{ => AdminMenu/components}/__tests__/AdminTabPanel.test.jsx (92%) create mode 100644 frontend/src/views/Admin/AdminMenu/components/__tests__/Users.test.jsx rename frontend/src/views/Admin/{ => AdminMenu/components}/__tests__/ViewUser.test.jsx (93%) delete mode 100644 frontend/src/views/Admin/__tests__/Users.test.jsx diff --git a/frontend/src/utils/grid/cellRenderers.jsx b/frontend/src/utils/grid/cellRenderers.jsx index abaf0d179..37917345a 100644 --- a/frontend/src/utils/grid/cellRenderers.jsx +++ b/frontend/src/utils/grid/cellRenderers.jsx @@ -1,4 +1,3 @@ -/* eslint-disable react-hooks/exhaustive-deps */ import BCBadge from '@/components/BCBadge' import BCBox from '@/components/BCBox' import { roles } from '@/constants/roles' @@ -7,7 +6,7 @@ import { getAllOrganizationStatuses } from '@/constants/statuses' import { Link, useLocation } from 'react-router-dom' -import { useState, useRef, useEffect, useCallback } from 'react' +import { useCallback, useEffect, useRef, useState } from 'react' import colors from '@/themes/base/colors' export const TextRenderer = (props) => { @@ -20,15 +19,13 @@ export const TextRenderer = (props) => { export const LinkRenderer = (props) => { const location = useLocation() + + const baseUrl = props.isAbsolute ? '' : `${location.pathname}/` + const targetUrl = + baseUrl + + ((props.url && props.url({ data: props.data })) || props?.node?.id) return ( - + {props.valueFormatted || props.value} @@ -69,6 +66,21 @@ const BaseStatusRenderer = ({ /> ) + + if (props.url) { + const baseUrl = props.isAbsolute ? '' : `${location.pathname}/` + const targetUrl = + baseUrl + + ((props.url && props.url({ data: props.data })) || props?.node?.id) + + return ( + + {component} + + ) + } else { + return component + } } export const StatusRenderer = (props) => ( @@ -161,38 +173,6 @@ export const FuelCodeStatusRenderer = (props) => { ) } -export const FuelCodeStatusTextRenderer = (props) => { - const statusArr = getAllFuelCodeStatuses() - const statusColorArr = ['info', 'success', 'error'] - const statusIndex = statusArr.indexOf(props.data.fuelCodeStatus.status) - return ( - - - - - - ) -} export const TransactionStatusRenderer = (props) => { const statusArr = [ @@ -220,7 +200,7 @@ export const TransactionStatusRenderer = (props) => { 'error' ] const statusIndex = statusArr.indexOf(props.data.status) - return ( + const component = ( { /> ) + if (props.url) { + const baseUrl = props.isAbsolute ? '' : `${location.pathname}/` + const targetUrl = + baseUrl + + ((props.url && props.url({ data: props.data })) || props?.node?.id) + + return ( + + {component} + + ) + } else { + return component + } } export const ReportsStatusRenderer = (props) => { const statusArr = [ @@ -428,16 +422,16 @@ const GenericChipRenderer = ({ {renderOverflowChip(hiddenChipsCount)} ) - + const baseUrl = props.isAbsolute ? '' : `${location.pathname}/` + const targetUrl = + baseUrl + + ((props.url && props.url({ data: props.data })) || props?.node?.id) return disableLink ? ( chipContent ) : ( - + {chipContent} - + ) } diff --git a/frontend/src/views/Admin/AdminMenu/components/AuditLog.jsx b/frontend/src/views/Admin/AdminMenu/components/AuditLog.jsx index a6f994c90..d6dad401c 100644 --- a/frontend/src/views/Admin/AdminMenu/components/AuditLog.jsx +++ b/frontend/src/views/Admin/AdminMenu/components/AuditLog.jsx @@ -1,16 +1,15 @@ -import { useRef, useCallback } from 'react' +import { useCallback, useMemo, useRef } from 'react' import BCBox from '@/components/BCBox' import BCDataGridServer from '@/components/BCDataGrid/BCDataGridServer' import BCTypography from '@/components/BCTypography' import { useTranslation } from 'react-i18next' import { auditLogColDefs, defaultAuditLogSortModel } from './_schema' -import { apiRoutes, ROUTES } from '@/constants/routes' -import { useNavigate } from 'react-router-dom' +import { apiRoutes } from '@/constants/routes' +import { LinkRenderer } from '@/utils/grid/cellRenderers.jsx' export const AuditLog = () => { const { t } = useTranslation(['common', 'admin']) const gridRef = useRef() - const navigate = useNavigate() const gridOptions = { overlayNoRowsTemplate: t('admin:auditLogsNotFound'), @@ -24,16 +23,14 @@ export const AuditLog = () => { const apiEndpoint = apiRoutes.getAuditLogs - const handleRowClicked = useCallback( - (params) => { - const { auditLogId } = params.data - const path = ROUTES.ADMIN_AUDIT_LOG_VIEW.replace( - ':auditLogId', - auditLogId - ) - navigate(path) - }, - [navigate] + const defaultColDef = useMemo( + () => ({ + cellRenderer: LinkRenderer, + cellRendererParams: { + url: (data) => data.data.auditLogId + } + }), + [] ) return ( @@ -54,7 +51,7 @@ export const AuditLog = () => { enableCopyButton={false} enableExportButton={true} exportName="AuditLog" - handleRowClicked={handleRowClicked} + defaultColDef={defaultColDef} /> ) diff --git a/frontend/src/views/Admin/AdminMenu/components/UserActivity.jsx b/frontend/src/views/Admin/AdminMenu/components/UserActivity.jsx index f54b5120a..ca8e57582 100644 --- a/frontend/src/views/Admin/AdminMenu/components/UserActivity.jsx +++ b/frontend/src/views/Admin/AdminMenu/components/UserActivity.jsx @@ -1,16 +1,15 @@ import BCBox from '@/components/BCBox' import BCTypography from '@/components/BCTypography' import { useTranslation } from 'react-i18next' -import { useCallback } from 'react' -import { useNavigate } from 'react-router-dom' +import { useCallback, useMemo } from 'react' import { userActivityColDefs } from '@/views/Admin/AdminMenu/components/_schema' import { ROUTES } from '@/constants/routes' import { BCGridViewer } from '@/components/BCDataGrid/BCGridViewer' import { useGetUserActivities } from '@/hooks/useUser' +import { LinkRenderer } from '@/utils/grid/cellRenderers.jsx' export const UserActivity = () => { const { t } = useTranslation(['common', 'admin']) - const navigate = useNavigate() const getRowId = useCallback((params) => { return `${ @@ -18,31 +17,31 @@ export const UserActivity = () => { }-${params.data.transactionType}-${params.data.transactionId}` }, []) - const handleRowClicked = useCallback( - (params) => { - const { transactionType, transactionId } = params.data - - let route - switch (transactionType) { - case 'Transfer': - route = ROUTES.TRANSFERS_VIEW.replace(':transferId', transactionId) - break - case 'AdminAdjustment': - route = ROUTES.ADMIN_ADJUSTMENT_VIEW.replace( - ':transactionId', - transactionId - ) - break - case 'InitiativeAgreement': - route = ROUTES.INITIATIVE_AGREEMENT_VIEW.replace( - ':transactionId', - transactionId - ) + const defaultColDef = useMemo( + () => ({ + cellRenderer: LinkRenderer, + cellRendererParams: { + isAbsolute: true, + url: (data) => { + const { transactionType, transactionId } = data.data + switch (transactionType) { + case 'Transfer': + return ROUTES.TRANSFERS_VIEW.replace(':transferId', transactionId) + case 'AdminAdjustment': + return ROUTES.ADMIN_ADJUSTMENT_VIEW.replace( + ':transactionId', + transactionId + ) + case 'InitiativeAgreement': + return ROUTES.INITIATIVE_AGREEMENT_VIEW.replace( + ':transactionId', + transactionId + ) + } + } } - - navigate(route) - }, - [navigate] + }), + [] ) return ( @@ -64,7 +63,7 @@ export const UserActivity = () => { defaultMinWidth: 50, defaultMaxWidth: 600 }} - onRowClicked={handleRowClicked} + defaultColDef={defaultColDef} /> diff --git a/frontend/src/views/Admin/AdminMenu/components/Users.jsx b/frontend/src/views/Admin/AdminMenu/components/Users.jsx index 4c67e3e63..65de1813f 100644 --- a/frontend/src/views/Admin/AdminMenu/components/Users.jsx +++ b/frontend/src/views/Admin/AdminMenu/components/Users.jsx @@ -1,20 +1,16 @@ -/* eslint-disable react-hooks/exhaustive-deps */ -// @mui component import BCTypography from '@/components/BCTypography' import BCButton from '@/components/BCButton' import BCBox from '@/components/BCBox' import BCAlert from '@/components/BCAlert' import BCDataGridServer from '@/components/BCDataGrid/BCDataGridServer' -// icons import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { faCirclePlus } from '@fortawesome/free-solid-svg-icons' -// hooks import { useLocation, useNavigate } from 'react-router-dom' -import { useCallback, useRef, useState, useEffect } from 'react' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' - -import { ROUTES, apiRoutes } from '@/constants/routes' -import { usersColumnDefs, idirUserDefaultFilter } from './_schema' +import { apiRoutes, ROUTES } from '@/constants/routes' +import { idirUserDefaultFilter, usersColumnDefs } from './_schema' +import { LinkRenderer } from '@/utils/grid/cellRenderers.jsx' export const Users = () => { const { t } = useTranslation(['common', 'admin']) @@ -45,9 +41,15 @@ export const Users = () => { return params.data.userProfileId.toString() }, []) - const handleRowClicked = useCallback((params) => { - navigate(`${ROUTES.ADMIN_USERS}/${params.data.userProfileId}`) - }) + const defaultColDef = useMemo( + () => ({ + cellRenderer: LinkRenderer, + cellRendererParams: { + url: (data) => data.data.userProfileId + } + }), + [] + ) const gridRef = useRef() useEffect(() => { @@ -98,9 +100,9 @@ export const Users = () => { defaultSortModel={defaultSortModel} defaultFilterModel={idirUserDefaultFilter} handleGridKey={handleGridKey} - handleRowClicked={handleRowClicked} enableResetButton={false} enableCopyButton={false} + defaultColDef={defaultColDef} /> diff --git a/frontend/src/views/Admin/AdminMenu/components/ViewUser.jsx b/frontend/src/views/Admin/AdminMenu/components/ViewUser.jsx index 6ad30a1b6..833dfc3ec 100644 --- a/frontend/src/views/Admin/AdminMenu/components/ViewUser.jsx +++ b/frontend/src/views/Admin/AdminMenu/components/ViewUser.jsx @@ -1,19 +1,23 @@ import Loading from '@/components/Loading' import BCTypography from '@/components/BCTypography' -import { FloatingAlert, BCAlert2 } from '@/components/BCAlert' +import { BCAlert2, FloatingAlert } from '@/components/BCAlert' import BCDataGridServer from '@/components/BCDataGrid/BCDataGridServer' -import { useRef, useCallback, useEffect, useState } from 'react' -import { useNavigate, useParams } from 'react-router-dom' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { useParams } from 'react-router-dom' import { useUser } from '@/hooks/useUser' import { useCurrentUser } from '@/hooks/useCurrentUser' import { useTranslation } from 'react-i18next' import { phoneNumberFormatter } from '@/utils/formatters' -import { RoleSpanRenderer, StatusRenderer } from '@/utils/grid/cellRenderers' import { - userActivityColDefs, - defaultSortModel + LinkRenderer, + RoleSpanRenderer, + StatusRenderer +} from '@/utils/grid/cellRenderers' +import { + defaultSortModel, + userActivityColDefs } from '@/views/Admin/AdminMenu/components/_schema' -import { ROUTES, apiRoutes } from '@/constants/routes' +import { apiRoutes, ROUTES } from '@/constants/routes' import { roles } from '@/constants/roles' import { useOrganizationUser } from '@/hooks/useOrganization' import { Role } from '@/components/Role' @@ -33,7 +37,6 @@ export const ViewUser = () => { const { userID, orgID } = useParams() const { data: currentUser, hasRoles } = useCurrentUser() - const navigate = useNavigate() const [editButtonRoute, setEditButtonRoute] = useState(null) const { data, isLoading, isLoadingError, isError, error } = hasRoles( @@ -73,35 +76,31 @@ export const ViewUser = () => { }` }, []) - const handleRowClicked = useCallback( - (params) => { - const { transactionType, transactionId } = params.data - let route - switch (transactionType) { - case 'Transfer': - route = ROUTES.TRANSFERS_VIEW.replace(':transferId', transactionId) - break - case 'AdminAdjustment': - route = ROUTES.ADMIN_ADJUSTMENT_VIEW.replace( - ':transactionId', - transactionId - ) - break - case 'InitiativeAgreement': - route = ROUTES.INITIATIVE_AGREEMENT_VIEW.replace( - ':transactionId', - transactionId - ) - break - default: - route = null - } - - if (route) { - navigate(route) + const defaultColDef = useMemo( + () => ({ + cellRenderer: LinkRenderer, + cellRendererParams: { + isAbsolute: true, + url: (data) => { + const { transactionType, transactionId } = data.data + switch (transactionType) { + case 'Transfer': + return ROUTES.TRANSFERS_VIEW.replace(':transferId', transactionId) + case 'AdminAdjustment': + return ROUTES.ADMIN_ADJUSTMENT_VIEW.replace( + ':transactionId', + transactionId + ) + case 'InitiativeAgreement': + return ROUTES.INITIATIVE_AGREEMENT_VIEW.replace( + ':transactionId', + transactionId + ) + } + } } - }, - [navigate] + }), + [] ) useEffect(() => { @@ -208,7 +207,7 @@ export const ViewUser = () => { gridOptions={gridOptions} defaultSortModel={defaultSortModel} enableCopyButton={false} - handleRowClicked={handleRowClicked} + defaultColDef={defaultColDef} /> diff --git a/frontend/src/views/Admin/__tests__/AdminTabPanel.test.jsx b/frontend/src/views/Admin/AdminMenu/components/__tests__/AdminTabPanel.test.jsx similarity index 92% rename from frontend/src/views/Admin/__tests__/AdminTabPanel.test.jsx rename to frontend/src/views/Admin/AdminMenu/components/__tests__/AdminTabPanel.test.jsx index 42affc7d2..bde91178e 100644 --- a/frontend/src/views/Admin/__tests__/AdminTabPanel.test.jsx +++ b/frontend/src/views/Admin/AdminMenu/components/__tests__/AdminTabPanel.test.jsx @@ -2,8 +2,8 @@ import { describe, it, expect } from 'vitest' import { render, screen } from '@testing-library/react' import { ThemeProvider } from '@mui/material/styles' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' -import theme from '@/themes' // Make sure this path is correct -import { AdminTabPanel } from '../AdminMenu/components/AdminTabPanel' +import theme from '@/themes/index.js' // Make sure this path is correct +import { AdminTabPanel } from '../AdminTabPanel.jsx' // Custom render function with all necessary providers const customRender = (ui, options = {}) => { diff --git a/frontend/src/views/Admin/AdminMenu/components/__tests__/AuditLog.test.jsx b/frontend/src/views/Admin/AdminMenu/components/__tests__/AuditLog.test.jsx index 8cef96958..f62a29394 100644 --- a/frontend/src/views/Admin/AdminMenu/components/__tests__/AuditLog.test.jsx +++ b/frontend/src/views/Admin/AdminMenu/components/__tests__/AuditLog.test.jsx @@ -1,51 +1,61 @@ -import { render, screen, fireEvent } from '@testing-library/react' -import { AuditLog } from '../AuditLog' -import { useNavigate } from 'react-router-dom' -import { vi } from 'vitest' +import React from 'react' +import { fireEvent, render, screen } from '@testing-library/react' +import { beforeEach, describe, expect, it, vi } from 'vitest' +import { AuditLog } from '@/views/Admin/AdminMenu/index.js' +import { wrapper } from '@/tests/utils/wrapper.jsx' -// Mock necessary modules +// Mock i18n vi.mock('react-i18next', () => ({ useTranslation: () => ({ t: (key) => key }) })) -vi.mock('react-router-dom', () => ({ - ...vi.importActual('react-router-dom'), - useNavigate: vi.fn() -})) - -// Mock the BCBox component -vi.mock('@/components/BCBox', () => ({ - default: ({ children }) =>
{children}
-})) +// Mock react-router-dom +const navigateMock = vi.fn() +vi.mock('react-router-dom', async () => { + const actual = await vi.importActual('react-router-dom') + return { + ...actual, + useNavigate: () => navigateMock + } +}) -// Mock the BCDataGridServer component +// Mock BCDataGridServer so we can inspect props & simulate row clicks vi.mock('@/components/BCDataGrid/BCDataGridServer', () => ({ - default: ({ handleRowClicked }) => ( -
- -
- ) + default: ({ handleRowClicked, ...props }) => { + // We'll return some basic UI with a button to simulate a row-click. + return ( +
+ +
+ ) + } })) describe('AuditLog Component', () => { - const navigateMock = vi.fn() - beforeEach(() => { vi.clearAllMocks() - useNavigate.mockReturnValue(navigateMock) }) it('renders correctly', () => { - render() + render(, { wrapper }) expect(screen.getByText('admin:AuditLog')).toBeInTheDocument() + expect(screen.getByTestId('bc-datagrid-server')).toBeInTheDocument() + }) + + it('passes the correct props to BCDataGridServer', () => { + render(, { wrapper }) + expect(screen.getByText('Mock Row')).toBeInTheDocument() }) - it('navigates to the correct path when a row is clicked', () => { - render() - const mockRowButton = screen.getByText('Mock Row') - fireEvent.click(mockRowButton) - expect(navigateMock).toHaveBeenCalledWith('/admin/audit-log/123') + it('uses getRowId to return auditLogId', () => { + const params = { data: { auditLogId: 'TEST_ID' } } + const rowId = params.data.auditLogId // or call the function directly + expect(rowId).toBe('TEST_ID') }) }) diff --git a/frontend/src/views/Admin/AdminMenu/components/__tests__/UserActivity.test.jsx b/frontend/src/views/Admin/AdminMenu/components/__tests__/UserActivity.test.jsx index fa3b92cc5..e3ac19898 100644 --- a/frontend/src/views/Admin/AdminMenu/components/__tests__/UserActivity.test.jsx +++ b/frontend/src/views/Admin/AdminMenu/components/__tests__/UserActivity.test.jsx @@ -1,83 +1,132 @@ import React from 'react' import { render, screen } from '@testing-library/react' -import { vi, describe, it, expect, beforeEach } from 'vitest' +import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest' import { UserActivity } from '../UserActivity' import { wrapper } from '@/tests/utils/wrapper' +import { BCGridViewer } from '@/components/BCDataGrid/BCGridViewer' -// Mock react-i18next vi.mock('react-i18next', () => ({ useTranslation: () => ({ t: (key) => key }) })) -// Mock react-router-dom const mockUseNavigate = vi.fn() -vi.mock('react-router-dom', () => ({ - ...vi.importActual('react-router-dom'), - useNavigate: () => mockUseNavigate -})) - -// Mock constants -vi.mock('@/constants/routes', () => ({ - ROUTES: { - TRANSFERS_VIEW: '/transfers/:transferId', - ADMIN_ADJUSTMENT_VIEW: '/admin-adjustment/:transactionId', - INITIATIVE_AGREEMENT_VIEW: '/initiative-agreement/:transactionId' +vi.mock('react-router-dom', async () => { + const actual = await vi.importActual('react-router-dom') + return { + ...actual, + useNavigate: () => mockUseNavigate } -})) +}) -// Mock userActivityColDefs vi.mock('@/views/Admin/AdminMenu/components/_schema', () => ({ - userActivityColDefs: () => [ + userActivityColDefs: [ { headerName: 'Column 1', field: 'col1' }, { headerName: 'Column 2', field: 'col2' } ] })) -// Variable to hold the onRowClicked function -let onRowClickedMock - -// Mock BCGridViewer +// -- Mock BCGridViewer so we can inspect its props -- vi.mock('@/components/BCDataGrid/BCGridViewer', () => ({ - BCGridViewer: (props) => { - onRowClickedMock = props.onRowClicked - return
BCGridViewer
- } + BCGridViewer: vi.fn(() =>
BCGridViewer
) +})) + +vi.mock('@/hooks/useUser', () => ({ + useGetUserActivities: () => ({ + data: { activities: [] }, // or mock real data if needed + isLoading: false, + isError: false + }) })) describe('UserActivity', () => { beforeEach(() => { - vi.resetAllMocks() + vi.clearAllMocks() + }) + + afterEach(() => { + vi.restoreAllMocks() }) - it('renders the component', () => { + it('renders the heading and the grid', () => { render(, { wrapper }) + + // 1. Heading check expect(screen.getByText('admin:UserActivity')).toBeInTheDocument() + + // 2. BCGridViewer check expect(screen.getByTestId('bc-grid-viewer')).toBeInTheDocument() }) - it('navigates to the correct route when transactionType is Transfer', () => { + it('passes the correct props to BCGridViewer', () => { render(, { wrapper }) - onRowClickedMock({ - data: { transactionType: 'Transfer', transactionId: '123' } - }) - expect(mockUseNavigate).toHaveBeenCalledWith('/transfers/123') + + // BCGridViewer has been mocked, so we can inspect its calls + expect(BCGridViewer).toHaveBeenCalledTimes(1) + const gridProps = BCGridViewer.mock.calls[0][0] + + // 1) gridKey + expect(gridProps.gridKey).toBe('all-user-activities-grid') + + // 2) columnDefs + expect(gridProps.columnDefs).toEqual([ + { headerName: 'Column 1', field: 'col1' }, + { headerName: 'Column 2', field: 'col2' } + ]) + + // 3) dataKey + expect(gridProps.dataKey).toBe('activities') + + // 4) getRowId + expect(gridProps.getRowId).toBeDefined() + // Optionally check the logic of getRowId + // This is a unit-style check; you can do something like: + const mockParams = { + data: { transactionType: 'AdminAdjustment', transactionId: '123' } + } + expect(gridProps.getRowId(mockParams)).toBe('adminadjustment-123') + + // 5) defaultColDef + expect(gridProps.defaultColDef).toBeDefined() + expect(typeof gridProps.defaultColDef.cellRendererParams.url).toBe( + 'function' + ) }) - it('navigates to the correct route when transactionType is AdminAdjustment', () => { + it('generates correct URLs for each transaction type', () => { render(, { wrapper }) - onRowClickedMock({ - data: { transactionType: 'AdminAdjustment', transactionId: '456' } + + // Extract the defaultColDef from BCGridViewer props + const gridProps = BCGridViewer.mock.calls[0][0] + const { url } = gridProps.defaultColDef.cellRendererParams + + // Test different transaction types + const mockData = (transactionType, transactionId) => ({ + data: { transactionType, transactionId } }) - expect(mockUseNavigate).toHaveBeenCalledWith('/admin-adjustment/456') + + // Transfer + expect(url(mockData('Transfer', 'ABC123'))).toBe('/transfers/ABC123') + + // AdminAdjustment + expect(url(mockData('AdminAdjustment', 'XYZ789'))).toBe( + '/admin-adjustment/XYZ789' + ) + + // InitiativeAgreement + expect(url(mockData('InitiativeAgreement', 'IA555'))).toBe( + '/initiative-agreement/IA555' + ) }) - it('navigates to the correct route when transactionType is InitiativeAgreement', () => { + // If you want to verify that no rows found message is shown if data is empty + it('shows the overlayNoRowsTemplate when there are no activities', () => { render(, { wrapper }) - onRowClickedMock({ - data: { transactionType: 'InitiativeAgreement', transactionId: '789' } - }) - expect(mockUseNavigate).toHaveBeenCalledWith('/initiative-agreement/789') + + // BCGridViewer props + const gridProps = BCGridViewer.mock.calls[0][0] + // Because data is mocked to [] + expect(gridProps.overlayNoRowsTemplate).toBe('admin:activitiesNotFound') }) }) diff --git a/frontend/src/views/Admin/AdminMenu/components/__tests__/Users.test.jsx b/frontend/src/views/Admin/AdminMenu/components/__tests__/Users.test.jsx new file mode 100644 index 000000000..6373303a5 --- /dev/null +++ b/frontend/src/views/Admin/AdminMenu/components/__tests__/Users.test.jsx @@ -0,0 +1,49 @@ +import { vi, describe, it, expect, beforeEach } from 'vitest' +import { render, screen, fireEvent, waitFor } from '@testing-library/react' +import { Users } from '../Users.jsx' +import { wrapper } from '@/tests/utils/wrapper.jsx' + +// Mock dependencies +vi.mock('react-i18next', () => ({ + useTranslation: () => ({ + t: (key) => key + }) +})) + +// Mock BCDataGridServer component +vi.mock('@/components/BCDataGrid/BCDataGridServer', () => ({ + default: () =>
Mocked DataGrid
+})) + +describe('Users Component', () => { + beforeEach(() => { + vi.clearAllMocks() + }) + + it('renders without crashing', () => { + render(, { wrapper }) + expect(screen.getByText('admin:Users')).toBeInTheDocument() + }) + + it('displays the New User button', () => { + render(, { wrapper }) + const newUserButton = screen.getByText('admin:newUserBtn') + expect(newUserButton).toBeInTheDocument() + }) + + it('navigates to add user page when New User button is clicked', async () => { + render(, { wrapper }) + const newUserButton = screen.getByText('admin:newUserBtn') + fireEvent.click(newUserButton) + + // Check if the navigation occurred + await waitFor(() => { + expect(window.location.href).toContain('/admin/users/add') + }) + }) + + it('renders BCDataGridServer with correct props', () => { + render(, { wrapper }) + expect(screen.getByTestId('mocked-data-grid')).toBeInTheDocument() + }) +}) diff --git a/frontend/src/views/Admin/__tests__/ViewUser.test.jsx b/frontend/src/views/Admin/AdminMenu/components/__tests__/ViewUser.test.jsx similarity index 93% rename from frontend/src/views/Admin/__tests__/ViewUser.test.jsx rename to frontend/src/views/Admin/AdminMenu/components/__tests__/ViewUser.test.jsx index 6968208fa..e5055cbb2 100644 --- a/frontend/src/views/Admin/__tests__/ViewUser.test.jsx +++ b/frontend/src/views/Admin/AdminMenu/components/__tests__/ViewUser.test.jsx @@ -2,12 +2,12 @@ import React from 'react' import { vi, describe, it, expect, beforeEach } from 'vitest' import { render, screen, fireEvent, waitFor } from '@testing-library/react' import { useLocation } from 'react-router-dom' -import * as useUserHook from '@/hooks/useUser' -import * as useCurrentUserHook from '@/hooks/useCurrentUser' -import * as useOrganizationHook from '@/hooks/useOrganization' -import * as formatters from '@/utils/formatters' -import { wrapper } from '@/tests/utils/wrapper' -import { ViewUser } from '../AdminMenu/components/ViewUser' +import * as useUserHook from '@/hooks/useUser.js' +import * as useCurrentUserHook from '@/hooks/useCurrentUser.js' +import * as useOrganizationHook from '@/hooks/useOrganization.js' +import * as formatters from '@/utils/formatters.js' +import { wrapper } from '@/tests/utils/wrapper.jsx' +import { ViewUser } from '../ViewUser.jsx' // Mocks vi.mock('@react-keycloak/web', () => ({ @@ -153,7 +153,7 @@ describe('ViewUser Component', () => { wrapper({ children, initialEntries: ['/admin/users/1'] }) } ) - + const editButton = screen.getByRole('button', { name: /admin:editBtn/i }) fireEvent.click(editButton) diff --git a/frontend/src/views/Admin/AdminMenu/components/_schema.js b/frontend/src/views/Admin/AdminMenu/components/_schema.js index eadea1422..235c31187 100644 --- a/frontend/src/views/Admin/AdminMenu/components/_schema.js +++ b/frontend/src/views/Admin/AdminMenu/components/_schema.js @@ -1,6 +1,6 @@ import { - phoneNumberFormatter, dateFormatter, + phoneNumberFormatter, timezoneFormatter } from '@/utils/formatters' import { @@ -26,7 +26,6 @@ export const usersColumnDefs = (t) => [ field: 'firstName', minWidth: 250, headerName: t('admin:userColLabels.userName'), - cellRenderer: LinkRenderer, valueGetter: (params) => params.data.firstName + ' ' + params.data.lastName }, { @@ -68,14 +67,12 @@ export const usersColumnDefs = (t) => [ colId: 'email', field: 'keycloakEmail', headerName: t('admin:userColLabels.email'), - cellRenderer: LinkRenderer, minWidth: 300 }, { colId: 'phone', field: 'phone', headerName: t('admin:userColLabels.phone'), - cellRenderer: LinkRenderer, valueFormatter: phoneNumberFormatter, filter: 'agTextColumnFilter', minWidth: 120 diff --git a/frontend/src/views/Admin/__tests__/Users.test.jsx b/frontend/src/views/Admin/__tests__/Users.test.jsx deleted file mode 100644 index 166b59d24..000000000 --- a/frontend/src/views/Admin/__tests__/Users.test.jsx +++ /dev/null @@ -1,158 +0,0 @@ -import { vi, describe, it, expect, beforeEach } from 'vitest' -import { render, screen, fireEvent, waitFor } from '@testing-library/react' -import { MemoryRouter, Route, Routes, useLocation } from 'react-router-dom' -import { QueryClient, QueryClientProvider } from '@tanstack/react-query' -import { Users } from '../AdminMenu/components/Users' -import { ThemeProvider } from '@mui/material' -import theme from '@/themes' - -// Mock dependencies -vi.mock('react-i18next', () => ({ - useTranslation: () => ({ - t: (key) => key - }) -})) - -vi.mock('@/constants/routes', () => ({ - ROUTES: { - ADMIN_USERS_ADD: '/admin/users/add', - ADMIN_USERS: '/admin/users' - }, - apiRoutes: { - listUsers: '/api/users' - } -})) - -vi.mock('../AdminMenu/components/_schema', () => ({ - usersColumnDefs: vi.fn(() => []), - idirUserDefaultFilter: [] -})) - -vi.mock('@/utils/formatters', () => ({ - calculateRowHeight: vi.fn(() => 50) -})) - -// Mock BCDataGridServer component -vi.mock('@/components/BCDataGrid/BCDataGridServer', () => ({ - default: ({ handleRowClicked }) => ( -
handleRowClicked({ data: { userProfileId: '123' } })} - > - Mocked DataGrid -
- ) -})) - -// Helper component to access current location -const LocationDisplay = () => { - const location = useLocation() - return
{location.pathname}
-} - -const WrapperComponent = ({ children, initialEntries = ['/'] }) => { - const queryClient = new QueryClient() - return ( - - - - - - {children} - - - } - /> - - - - - ) -} - -describe('Users Component', () => { - beforeEach(() => { - vi.clearAllMocks() - }) - - it('renders without crashing', () => { - render( - - - - ) - expect(screen.getByText('admin:Users')).toBeInTheDocument() - }) - - it('displays the New User button', () => { - render( - - - - ) - const newUserButton = screen.getByText('admin:newUserBtn') - expect(newUserButton).toBeInTheDocument() - }) - - it('navigates to add user page when New User button is clicked', async () => { - render( - - - - ) - const newUserButton = screen.getByText('admin:newUserBtn') - fireEvent.click(newUserButton) - - // Check if the navigation occurred - await waitFor(() => { - expect(screen.getByTestId('location-display')).toHaveTextContent( - '/admin/users/add' - ) - }) - }) - - it('renders BCDataGridServer with correct props', () => { - render( - - - - ) - expect(screen.getByTestId('mocked-data-grid')).toBeInTheDocument() - }) - - it('displays alert message when location state has a message', () => { - const initialEntries = [ - { - pathname: '/admin/users', - state: { message: 'Test alert message', severity: 'success' } - } - ] - render( - - - - ) - expect(screen.getByText('Test alert message')).toBeInTheDocument() - }) - - it('handles row click correctly', async () => { - render( - - - - ) - - // Simulate a row click - const mockedDataGrid = screen.getByTestId('mocked-data-grid') - fireEvent.click(mockedDataGrid) - - // Check if the navigation occurred - await waitFor(() => { - const locationDisplay = screen.getByTestId('location-display') - expect(locationDisplay.textContent).toBe('/admin/users/123') - }) - }) -}) diff --git a/frontend/src/views/AllocationAgreements/AllocationAgreementSummary.jsx b/frontend/src/views/AllocationAgreements/AllocationAgreementSummary.jsx index 70a536d18..3ecf13546 100644 --- a/frontend/src/views/AllocationAgreements/AllocationAgreementSummary.jsx +++ b/frontend/src/views/AllocationAgreements/AllocationAgreementSummary.jsx @@ -9,6 +9,7 @@ import { useTranslation } from 'react-i18next' import { useLocation, useParams, useNavigate } from 'react-router-dom' import { v4 as uuid } from 'uuid' import { COMPLIANCE_REPORT_STATUSES } from '@/constants/statuses.js' +import { LinkRenderer } from '@/utils/grid/cellRenderers.jsx' export const AllocationAgreementSummary = ({ data, status }) => { const [alertMessage, setAlertMessage] = useState('') @@ -47,9 +48,14 @@ export const AllocationAgreementSummary = ({ data, status }) => { const defaultColDef = useMemo( () => ({ floatingFilter: false, - filter: false + filter: false, + cellRenderer: + status === COMPLIANCE_REPORT_STATUSES.DRAFT ? LinkRenderer : undefined, + cellRendererParams: { + url: () => 'allocation-agreements' + } }), - [] + [status] ) const columns = useMemo( @@ -137,17 +143,6 @@ export const AllocationAgreementSummary = ({ data, status }) => { setGridKey(`allocation-agreements-grid-${uuid()}`) } - const handleRowClicked = (params) => { - if (status === COMPLIANCE_REPORT_STATUSES.DRAFT) { - navigate( - ROUTES.REPORTS_ADD_ALLOCATION_AGREEMENTS.replace( - ':compliancePeriod', - compliancePeriod - ).replace(':complianceReportId', complianceReportId) - ) - } - } - return (
@@ -172,7 +167,6 @@ export const AllocationAgreementSummary = ({ data, status }) => { enableCopyButton={false} defaultColDef={defaultColDef} suppressPagination={data.allocationAgreements.length <= 10} - handleRowClicked={handleRowClicked} /> diff --git a/frontend/src/views/ComplianceReports/ComplianceReports.jsx b/frontend/src/views/ComplianceReports/ComplianceReports.jsx index 504d42990..4be8bcde3 100644 --- a/frontend/src/views/ComplianceReports/ComplianceReports.jsx +++ b/frontend/src/views/ComplianceReports/ComplianceReports.jsx @@ -1,25 +1,20 @@ -// mui components import { Stack } from '@mui/material' import BCBox from '@/components/BCBox' import BCAlert from '@/components/BCAlert' import BCDataGridServer from '@/components/BCDataGrid/BCDataGridServer' -// react components import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import { useLocation, useNavigate } from 'react-router-dom' -// Services import { Role } from '@/components/Role' -// constants import { roles } from '@/constants/roles' import { apiRoutes, ROUTES } from '@/constants/routes' import { COMPLIANCE_REPORT_STATUSES } from '@/constants/statuses' -// hooks import { useCurrentUser } from '@/hooks/useCurrentUser' import { useCreateComplianceReport } from '@/hooks/useComplianceReports' -// internal components import { defaultSortModel, reportsColDefs } from './components/_schema' import { NewComplianceReportButton } from './components/NewComplianceReportButton' import BCTypography from '@/components/BCTypography' +import { LinkRenderer } from '@/utils/grid/cellRenderers.jsx' export const ComplianceReports = () => { const { t } = useTranslation(['common', 'report']) @@ -44,19 +39,9 @@ export const ComplianceReports = () => { (params) => params.data.complianceReportId.toString(), [] ) - const handleRowClicked = useCallback( - ({ data }) => { - const mappedRoute = ROUTES.REPORTS_VIEW.replace( - ':compliancePeriod', - data.compliancePeriod.description - ).replace(':complianceReportId', data.complianceReportId) - navigate(mappedRoute) - }, - [navigate] - ) const handleGridKey = useCallback(() => { - setGridKey(`reports-grid`) + setGridKey('reports-grid') }, []) useEffect(() => { @@ -66,42 +51,53 @@ export const ComplianceReports = () => { } }, [location.state]) - const { - mutate: createComplianceReport, - isLoading: isCreating, - isError - } = useCreateComplianceReport(currentUser?.organization?.organizationId, { - onSuccess: (response, variables) => { - setAlertMessage( - t('report:actionMsgs.successText', { - status: 'created' - }) - ) - setIsButtonLoading(false) - setAlertSeverity('success') - navigate( - ROUTES.REPORTS_VIEW.replace( - ':compliancePeriod', - response.data.compliancePeriod.description - ).replace(':complianceReportId', response.data.complianceReportId), - { state: { data: response.data, newReport: true } } - ) - alertRef.current.triggerAlert() - }, - onError: (_error, _variables) => { - setIsButtonLoading(false) - const errorMsg = _error.response.data?.detail - setAlertMessage(errorMsg) - setAlertSeverity('error') - alertRef.current.triggerAlert() - } - }) + const { mutate: createComplianceReport, isLoading: isCreating } = + useCreateComplianceReport(currentUser?.organization?.organizationId, { + onSuccess: (response, variables) => { + setAlertMessage( + t('report:actionMsgs.successText', { + status: 'created' + }) + ) + setIsButtonLoading(false) + setAlertSeverity('success') + navigate( + ROUTES.REPORTS_VIEW.replace( + ':compliancePeriod', + response.data.compliancePeriod.description + ).replace(':complianceReportId', response.data.complianceReportId), + { state: { data: response.data, newReport: true } } + ) + alertRef.current.triggerAlert() + }, + onError: (_error, _variables) => { + setIsButtonLoading(false) + const errorMsg = _error.response.data?.detail + setAlertMessage(errorMsg) + setAlertSeverity('error') + alertRef.current.triggerAlert() + } + }) useEffect(() => { if (isCreating) { setIsButtonLoading(true) } }, [isCreating]) + + const defaultColDef = useMemo( + () => ({ + floatingFilter: false, + filter: false, + cellRenderer: LinkRenderer, + cellRendererParams: { + url: (data) => + `${data.data.compliancePeriod.description}/${data.data.complianceReportId}` + } + }), + [] + ) + return ( <>
@@ -159,8 +155,8 @@ export const ComplianceReports = () => { defaultFilterModel={location.state?.filters} gridOptions={gridOptions} handleGridKey={handleGridKey} - handleRowClicked={handleRowClicked} enableCopyButton={false} + defaultColDef={defaultColDef} /> diff --git a/frontend/src/views/FinalSupplyEquipments/FinalSupplyEquipmentSummary.jsx b/frontend/src/views/FinalSupplyEquipments/FinalSupplyEquipmentSummary.jsx index a8c7935a1..699ef8c97 100644 --- a/frontend/src/views/FinalSupplyEquipments/FinalSupplyEquipmentSummary.jsx +++ b/frontend/src/views/FinalSupplyEquipments/FinalSupplyEquipmentSummary.jsx @@ -1,12 +1,12 @@ import BCAlert from '@/components/BCAlert' import BCBox from '@/components/BCBox' import BCDataGridServer from '@/components/BCDataGrid/BCDataGridServer' -import { apiRoutes, ROUTES } from '@/constants/routes' -import { CommonArrayRenderer } from '@/utils/grid/cellRenderers' +import { apiRoutes } from '@/constants/routes' +import { CommonArrayRenderer, LinkRenderer } from '@/utils/grid/cellRenderers' import Grid2 from '@mui/material/Unstable_Grid2/Grid2' import { useEffect, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' -import { useLocation, useParams, useNavigate } from 'react-router-dom' +import { useLocation, useParams } from 'react-router-dom' import { v4 as uuid } from 'uuid' import { numberFormatter } from '@/utils/formatters.js' import { COMPLIANCE_REPORT_STATUSES } from '@/constants/statuses.js' @@ -15,12 +15,11 @@ export const FinalSupplyEquipmentSummary = ({ data, status }) => { const [alertMessage, setAlertMessage] = useState('') const [alertSeverity, setAlertSeverity] = useState('info') const [gridKey, setGridKey] = useState('final-supply-equipments-grid') - const { complianceReportId, compliancePeriod } = useParams() + const { complianceReportId } = useParams() const gridRef = useRef() const { t } = useTranslation(['common', 'finalSupplyEquipments']) const location = useLocation() - const navigate = useNavigate() useEffect(() => { if (location.state?.message) { @@ -45,10 +44,16 @@ export const FinalSupplyEquipmentSummary = ({ data, status }) => { const defaultColDef = useMemo( () => ({ floatingFilter: false, - filter: false + filter: false, + cellRenderer: + status === COMPLIANCE_REPORT_STATUSES.DRAFT ? LinkRenderer : undefined, + cellRendererParams: { + url: () => 'final-supply-equipments' + } }), - [] + [status] ) + const columns = useMemo( () => [ { @@ -188,17 +193,6 @@ export const FinalSupplyEquipmentSummary = ({ data, status }) => { setGridKey(`final-supply-equipments-grid-${uuid()}`) } - const handleRowClicked = () => { - if (status === COMPLIANCE_REPORT_STATUSES.DRAFT) { - navigate( - ROUTES.REPORTS_ADD_FINAL_SUPPLY_EQUIPMENTS.replace( - ':compliancePeriod', - compliancePeriod - ).replace(':complianceReportId', complianceReportId) - ) - } - } - return (
@@ -223,7 +217,6 @@ export const FinalSupplyEquipmentSummary = ({ data, status }) => { enableCopyButton={false} defaultColDef={defaultColDef} suppressPagination={data.finalSupplyEquipments.length <= 10} - handleRowClicked={handleRowClicked} /> diff --git a/frontend/src/views/FuelCodes/FuelCodes.jsx b/frontend/src/views/FuelCodes/FuelCodes.jsx index fba322f9a..a19fd7a7f 100644 --- a/frontend/src/views/FuelCodes/FuelCodes.jsx +++ b/frontend/src/views/FuelCodes/FuelCodes.jsx @@ -14,10 +14,11 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { Stack } from '@mui/material' import BCTypography from '@/components/BCTypography' import Grid2 from '@mui/material/Unstable_Grid2/Grid2' -import { useEffect, useState } from 'react' +import { useEffect, useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' import { useLocation, useNavigate } from 'react-router-dom' import { fuelCodeColDefs } from './_schema' +import { LinkRenderer } from '@/utils/grid/cellRenderers.jsx' const FuelCodesBase = () => { const [isDownloadingFuelCodes, setIsDownloadingFuelCodes] = useState(false) @@ -40,11 +41,15 @@ const FuelCodesBase = () => { return params.data.fuelCodeId.toString() } - const handleRowClicked = (params) => { - navigate( - ROUTES.FUELCODES_EDIT.replace(':fuelCodeID', params.data.fuelCodeId) - ) - } + const defaultColDef = useMemo( + () => ({ + cellRenderer: LinkRenderer, + cellRendererParams: { + url: (data) => data.data.fuelCodeId + } + }), + [] + ) const handleDownloadFuelCodes = async () => { setIsDownloadingFuelCodes(true) @@ -110,14 +115,10 @@ const FuelCodesBase = () => { columnDefs={fuelCodeColDefs(t)} query={useGetFuelCodes} queryParams={{ cacheTime: 0, staleTime: 0 }} - dataKey={'fuelCodes'} + dataKey="fuelCodes" getRowId={getRowId} - onRowClicked={handleRowClicked} overlayNoRowsTemplate={t('fuelCode:noFuelCodesFound')} - autoSizeStrategy={{ - defaultMinWidth: 50, - defaultMaxWidth: 600 - }} + defaultColDef={defaultColDef} /> diff --git a/frontend/src/views/FuelCodes/_schema.jsx b/frontend/src/views/FuelCodes/_schema.jsx index 48bbd4715..d2eade3b5 100644 --- a/frontend/src/views/FuelCodes/_schema.jsx +++ b/frontend/src/views/FuelCodes/_schema.jsx @@ -1,6 +1,6 @@ import { CommonArrayRenderer, - FuelCodeStatusTextRenderer, + FuelCodeStatusRenderer, TextRenderer } from '@/utils/grid/cellRenderers' import { numberFormatter, timezoneFormatter } from '@/utils/formatters' @@ -23,19 +23,17 @@ export const fuelCodeColDefs = (t) => [ }, suppressFloatingFilterButton: true, valueGetter: (params) => params.data.fuelCodeStatus.status, - cellRenderer: FuelCodeStatusTextRenderer + cellRenderer: FuelCodeStatusRenderer }, { field: 'prefix', headerName: t('fuelCode:fuelCodeColLabels.prefix'), - valueGetter: (params) => params.data.fuelCodePrefix.prefix, suppressFloatingFilterButton: true, - cellRenderer: TextRenderer + valueGetter: (params) => params.data.fuelCodePrefix.prefix }, { field: 'fuelSuffix', headerName: t('fuelCode:fuelCodeColLabels.fuelSuffix'), - cellRenderer: TextRenderer, type: 'numericColumn', filter: 'agNumberColumnFilter', suppressFloatingFilterButton: true, @@ -47,7 +45,6 @@ export const fuelCodeColDefs = (t) => [ { field: 'carbonIntensity', headerName: t('fuelCode:fuelCodeColLabels.carbonIntensity'), - cellRenderer: TextRenderer, type: 'numericColumn', filter: 'agNumberColumnFilter', filterParams: { @@ -57,86 +54,65 @@ export const fuelCodeColDefs = (t) => [ }, { field: 'edrms', - headerName: t('fuelCode:fuelCodeColLabels.edrms'), - cellRenderer: TextRenderer + headerName: t('fuelCode:fuelCodeColLabels.edrms') }, { field: 'company', headerName: t('fuelCode:fuelCodeColLabels.company'), - cellRenderer: TextRenderer, minWidth: 300 }, { field: 'contactName', headerName: t('fuelCode:fuelCodeColLabels.contactName'), - cellRenderer: TextRenderer, minWidth: 300 }, { field: 'contactEmail', headerName: t('fuelCode:fuelCodeColLabels.contactEmail'), - cellRenderer: TextRenderer, minWidth: 300 }, { field: 'applicationDate', headerName: t('fuelCode:fuelCodeColLabels.applicationDate'), - floatingFilterComponent: BCDateFloatingFilter, - suppressFloatingFilterButton: true, - minWidth: 250, - cellRenderer: TextRenderer + filter: false }, { field: 'approvalDate', headerName: t('fuelCode:fuelCodeColLabels.approvalDate'), - cellRenderer: TextRenderer, - floatingFilterComponent: BCDateFloatingFilter, - suppressFloatingFilterButton: true, - minWidth: 250 + filter: false }, { field: 'effectiveDate', headerName: t('fuelCode:fuelCodeColLabels.effectiveDate'), - cellRenderer: TextRenderer, - floatingFilterComponent: BCDateFloatingFilter, - suppressFloatingFilterButton: true, - minWidth: 250 + filter: false }, { field: 'expirationDate', headerName: t('fuelCode:fuelCodeColLabels.expirationDate'), - cellRenderer: TextRenderer, - floatingFilterComponent: BCDateFloatingFilter, - suppressFloatingFilterButton: true, - minWidth: 250 + filter: false }, { field: 'fuelType', headerName: t('fuelCode:fuelCodeColLabels.fuelType'), - cellRenderer: TextRenderer, valueGetter: (params) => params.data.fuelType.fuelType }, { field: 'feedstock', - headerName: t('fuelCode:fuelCodeColLabels.feedstock'), - cellRenderer: TextRenderer + headerName: t('fuelCode:fuelCodeColLabels.feedstock') }, { field: 'feedstockLocation', headerName: t('fuelCode:fuelCodeColLabels.feedstockLocation'), - cellRenderer: TextRenderer, minWidth: 300 }, { field: 'feedstockMisc', headerName: t('fuelCode:fuelCodeColLabels.misc'), - cellRenderer: TextRenderer, minWidth: 495 }, { field: 'fuelProductionFacilityCity', headerName: t('fuelCode:fuelCodeColLabels.fuelProductionFacilityCity'), - cellRenderer: TextRenderer, minWidth: 325 }, { @@ -144,27 +120,23 @@ export const fuelCodeColDefs = (t) => [ headerName: t( 'fuelCode:fuelCodeColLabels.fuelProductionFacilityProvinceState' ), - cellRenderer: TextRenderer, minWidth: 325 }, { field: 'fuelProductionFacilityCountry', headerName: t('fuelCode:fuelCodeColLabels.fuelProductionFacilityCountry'), - cellRenderer: TextRenderer, minWidth: 325 }, { field: 'facilityNameplateCapacity', headerName: t('fuelCode:fuelCodeColLabels.facilityNameplateCapacity'), valueFormatter: numberFormatter, - cellRenderer: TextRenderer, minWidth: 290, type: 'numericColumn' }, { field: 'facilityNameplateCapacityUnit', headerName: t('fuelCode:fuelCodeColLabels.facilityNameplateCapacityUnit'), - cellRenderer: TextRenderer, minWidth: 290 }, { @@ -183,7 +155,7 @@ export const fuelCodeColDefs = (t) => [ params.data.feedstockFuelTransportModes.map( (item) => item.feedstockFuelTransportMode.transportMode ), - cellRenderer: (props) => + cellRenderer: (props) => }, { field: 'finishedFuelTransportMode', @@ -201,12 +173,11 @@ export const fuelCodeColDefs = (t) => [ params.data.finishedFuelTransportModes.map( (item) => item.finishedFuelTransportMode.transportMode ), - cellRenderer: (props) => + cellRenderer: (props) => }, { field: 'formerCompany', headerName: t('fuelCode:fuelCodeColLabels.formerCompany'), - cellRenderer: TextRenderer, minWidth: 300 }, { @@ -225,7 +196,6 @@ export const fuelCodeColDefs = (t) => [ { field: 'notes', headerName: t('fuelCode:fuelCodeColLabels.notes'), - cellRenderer: TextRenderer, minWidth: 600 } ] diff --git a/frontend/src/views/FuelExports/FuelExportSummary.jsx b/frontend/src/views/FuelExports/FuelExportSummary.jsx index 76898317f..ef9cbd5b0 100644 --- a/frontend/src/views/FuelExports/FuelExportSummary.jsx +++ b/frontend/src/views/FuelExports/FuelExportSummary.jsx @@ -6,20 +6,19 @@ import { formatNumberWithCommas as valueFormatter } from '@/utils/formatters' import Grid2 from '@mui/material/Unstable_Grid2/Grid2' import { useEffect, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' -import { useLocation, useParams, useNavigate } from 'react-router-dom' +import { useLocation, useParams } from 'react-router-dom' import i18n from '@/i18n' -import { ROUTES } from '@/constants/routes' import { COMPLIANCE_REPORT_STATUSES } from '@/constants/statuses.js' +import { LinkRenderer } from '@/utils/grid/cellRenderers.jsx' export const FuelExportSummary = ({ data, status }) => { const [alertMessage, setAlertMessage] = useState('') const [alertSeverity, setAlertSeverity] = useState('info') - const { complianceReportId, compliancePeriod } = useParams() + const { complianceReportId } = useParams() const gridRef = useRef() const { t } = useTranslation(['common', 'fuelExport']) const location = useLocation() - const navigate = useNavigate() useEffect(() => { if (location.state?.message) { @@ -45,9 +44,14 @@ export const FuelExportSummary = ({ data, status }) => { const defaultColDef = useMemo( () => ({ floatingFilter: false, - filter: false + filter: false, + cellRenderer: + status === COMPLIANCE_REPORT_STATUSES.DRAFT ? LinkRenderer : undefined, + cellRendererParams: { + url: () => 'fuel-exports' + } }), - [] + [status] ) // TODO: The values for the following columns must be determined @@ -125,17 +129,6 @@ export const FuelExportSummary = ({ data, status }) => { return params.data.fuelExportId.toString() } - const handleRowClicked = () => { - if (status === COMPLIANCE_REPORT_STATUSES.DRAFT) { - navigate( - ROUTES.REPORTS_ADD_FUEL_EXPORTS.replace( - ':compliancePeriod', - compliancePeriod - ).replace(':complianceReportId', complianceReportId) - ) - } - } - return (
@@ -158,7 +151,6 @@ export const FuelExportSummary = ({ data, status }) => { enableCopyButton={false} defaultColDef={defaultColDef} suppressPagination={data.fuelExports.length <= 10} - onRowClicked={handleRowClicked} /> diff --git a/frontend/src/views/FuelSupplies/FuelSupplySummary.jsx b/frontend/src/views/FuelSupplies/FuelSupplySummary.jsx index b9808f1ad..af7843444 100644 --- a/frontend/src/views/FuelSupplies/FuelSupplySummary.jsx +++ b/frontend/src/views/FuelSupplies/FuelSupplySummary.jsx @@ -1,27 +1,26 @@ import BCAlert from '@/components/BCAlert' import BCBox from '@/components/BCBox' import BCDataGridServer from '@/components/BCDataGrid/BCDataGridServer' -import { apiRoutes, ROUTES } from '@/constants/routes' +import { apiRoutes } from '@/constants/routes' import { formatNumberWithCommas as valueFormatter } from '@/utils/formatters' import Grid2 from '@mui/material/Unstable_Grid2/Grid2' import { useEffect, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' -import { useLocation, useNavigate, useParams } from 'react-router-dom' +import { useLocation, useParams } from 'react-router-dom' import { v4 as uuid } from 'uuid' import i18n from '@/i18n' -import { StandardCellWarningAndErrors } from '@/utils/grid/errorRenderers' import { COMPLIANCE_REPORT_STATUSES } from '@/constants/statuses.js' +import { LinkRenderer } from '@/utils/grid/cellRenderers.jsx' export const FuelSupplySummary = ({ data, status }) => { const [alertMessage, setAlertMessage] = useState('') const [alertSeverity, setAlertSeverity] = useState('info') const [gridKey, setGridKey] = useState(`fuel-supplies-grid`) - const { complianceReportId, compliancePeriod } = useParams() + const { complianceReportId } = useParams() const gridRef = useRef() const { t } = useTranslation(['common', 'fuelSupply']) const location = useLocation() - const navigate = useNavigate() useEffect(() => { if (location.state?.message) { @@ -47,12 +46,16 @@ export const FuelSupplySummary = ({ data, status }) => { const defaultColDef = useMemo( () => ({ floatingFilter: false, - filter: false + filter: false, + cellRenderer: + status === COMPLIANCE_REPORT_STATUSES.DRAFT ? LinkRenderer : undefined, + cellRendererParams: { + url: () => 'supply-of-fuel' + } }), - [] + [status] ) - // TODO: The values for the following columns must be determined const columns = useMemo( () => [ { @@ -127,17 +130,6 @@ export const FuelSupplySummary = ({ data, status }) => { setGridKey(`fuel-supplies-grid-${uuid()}`) } - const handleRowClicked = () => { - if (status === COMPLIANCE_REPORT_STATUSES.DRAFT) { - navigate( - ROUTES.REPORTS_ADD_SUPPLY_OF_FUEL.replace( - ':compliancePeriod', - compliancePeriod - ).replace(':complianceReportId', complianceReportId) - ) - } - } - return (
@@ -162,7 +154,6 @@ export const FuelSupplySummary = ({ data, status }) => { enableCopyButton={false} defaultColDef={defaultColDef} suppressPagination={data.fuelSupplies.length <= 10} - handleRowClicked={handleRowClicked} /> diff --git a/frontend/src/views/NotionalTransfers/NotionalTransferSummary.jsx b/frontend/src/views/NotionalTransfers/NotionalTransferSummary.jsx index daa71fae1..282e72164 100644 --- a/frontend/src/views/NotionalTransfers/NotionalTransferSummary.jsx +++ b/frontend/src/views/NotionalTransfers/NotionalTransferSummary.jsx @@ -3,21 +3,20 @@ import BCBox from '@/components/BCBox' import { BCGridViewer } from '@/components/BCDataGrid/BCGridViewer' import { useGetNotionalTransfers } from '@/hooks/useNotionalTransfer' import Grid2 from '@mui/material/Unstable_Grid2/Grid2' -import { useEffect, useState, useMemo } from 'react' +import { useEffect, useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' -import { useLocation, useParams, useNavigate } from 'react-router-dom' +import { useLocation, useParams } from 'react-router-dom' import { formatNumberWithCommas as valueFormatter } from '@/utils/formatters' -import { ROUTES } from '@/constants/routes' import { COMPLIANCE_REPORT_STATUSES } from '@/constants/statuses.js' +import { LinkRenderer } from '@/utils/grid/cellRenderers.jsx' export const NotionalTransferSummary = ({ data, status }) => { const [alertMessage, setAlertMessage] = useState('') const [alertSeverity, setAlertSeverity] = useState('info') - const { complianceReportId, compliancePeriod } = useParams() + const { complianceReportId } = useParams() const { t } = useTranslation(['common', 'notionalTransfers']) const location = useLocation() - const navigate = useNavigate() useEffect(() => { if (location.state?.message) { @@ -30,22 +29,16 @@ export const NotionalTransferSummary = ({ data, status }) => { const defaultColDef = useMemo( () => ({ floatingFilter: false, - filter: false + filter: false, + cellRenderer: + status === COMPLIANCE_REPORT_STATUSES.DRAFT ? LinkRenderer : undefined, + cellRendererParams: { + url: () => 'notional-transfers' + } }), - [] + [status] ) - const handleRowClicked = () => { - if (status === COMPLIANCE_REPORT_STATUSES.DRAFT) { - navigate( - ROUTES.REPORTS_ADD_NOTIONAL_TRANSFERS.replace( - ':compliancePeriod', - compliancePeriod - ).replace(':complianceReportId', complianceReportId) - ) - } - } - const columns = [ { headerName: t('notionalTransfer:notionalTransferColLabels.legalName'), @@ -95,7 +88,7 @@ export const NotionalTransferSummary = ({ data, status }) => { defaultColDef={defaultColDef} query={useGetNotionalTransfers} queryParams={{ complianceReportId }} - dataKey={'notionalTransfers'} + dataKey="notionalTransfers" suppressPagination={data?.length <= 10} autoSizeStrategy={{ type: 'fitCellContents', @@ -105,7 +98,6 @@ export const NotionalTransferSummary = ({ data, status }) => { enableCellTextSelection ensureDomOrder handleRo - onRowClicked={handleRowClicked} /> diff --git a/frontend/src/views/Organizations/Organizations.jsx b/frontend/src/views/Organizations/Organizations.jsx index aad8c2aa7..bca77d4fa 100644 --- a/frontend/src/views/Organizations/Organizations.jsx +++ b/frontend/src/views/Organizations/Organizations.jsx @@ -12,7 +12,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { organizationsColDefs } from './ViewOrganization/_schema' // react components import { ROUTES, apiRoutes } from '@/constants/routes' -import { useCallback, useEffect, useRef, useState } from 'react' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { useLocation, useNavigate } from 'react-router-dom' import { useTranslation } from 'react-i18next' // Services @@ -20,6 +20,7 @@ import { DownloadButton } from '@/components/DownloadButton' import { useApiService } from '@/services/useApiService' import { roles } from '@/constants/roles' import { Role } from '@/components/Role' +import { LinkRenderer } from '@/utils/grid/cellRenderers.jsx' export const Organizations = () => { const { t } = useTranslation(['common', 'org']) @@ -39,12 +40,7 @@ export const Organizations = () => { const location = useLocation() const defaultSortModel = [{ field: 'name', direction: 'asc' }] - // eslint-disable-next-line react-hooks/exhaustive-deps - const handleRowClicked = useCallback((params) => { - navigate( - ROUTES.ORGANIZATIONS_VIEW.replace(':orgID', params.data.organizationId) - ) - }) + const apiService = useApiService() const [isDownloadingOrgs, setIsDownloadingOrgs] = useState(false) const [isDownloadingUsers, setIsDownloadingUsers] = useState(false) @@ -85,6 +81,16 @@ export const Organizations = () => { } } + const defaultColDef = useMemo( + () => ({ + cellRenderer: LinkRenderer, + cellRendererParams: { + url: (data) => data.data.organizationId + } + }), + [] + ) + return ( <>
@@ -137,16 +143,16 @@ export const Organizations = () => { diff --git a/frontend/src/views/Organizations/ViewOrganization/ViewOrganization.jsx b/frontend/src/views/Organizations/ViewOrganization/ViewOrganization.jsx index d3c8dcf40..05fc5fbb6 100644 --- a/frontend/src/views/Organizations/ViewOrganization/ViewOrganization.jsx +++ b/frontend/src/views/Organizations/ViewOrganization/ViewOrganization.jsx @@ -5,24 +5,24 @@ import BCAlert from '@/components/BCAlert' import BCDataGridServer from '@/components/BCDataGrid/BCDataGridServer' import Loading from '@/components/Loading' import BCWidgetCard from '@/components/BCWidgetCard/BCWidgetCard' -import colors from '@/themes/base/colors.js' import { faCirclePlus } from '@fortawesome/free-solid-svg-icons' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' -import { useCallback, useEffect, useRef, useState } from 'react' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' -import { ROUTES, apiRoutes } from '@/constants/routes' +import { apiRoutes, ROUTES } from '@/constants/routes' import { useCurrentUser } from '@/hooks/useCurrentUser' import { useOrganization, useOrganizationBalance } from '@/hooks/useOrganization' import { constructAddress } from '@/utils/constructAddress' -import { calculateRowHeight, phoneNumberFormatter } from '@/utils/formatters' +import { phoneNumberFormatter } from '@/utils/formatters' import { useLocation, useNavigate, useParams } from 'react-router-dom' import { defaultSortModel, getUserColumnDefs } from './_schema' import { Role } from '@/components/Role' import { roles } from '@/constants/roles' import { ORGANIZATION_STATUSES } from '@/constants/statuses' +import { LinkRenderer } from '@/utils/grid/cellRenderers.jsx' export const ViewOrganization = () => { const { t } = useTranslation(['common', 'org']) @@ -71,23 +71,26 @@ export const ViewOrganization = () => { includeHiddenColumnsInQuickFilter: true } - const handleRowClicked = useCallback( - (params) => - // Based on the user Type (BCeID or IDIR) navigate to specific view - hasRoles(roles.supplier) - ? navigate( - ROUTES.ORGANIZATION_VIEWUSER.replace( - ':userID', - params.data.userProfileId - ) - ) - : navigate( - ROUTES.ORGANIZATIONS_VIEWUSER.replace(':orgID', orgID).replace( - ':userID', - params.data.userProfileId - ) - ), - [hasRoles, navigate, orgID] + const defaultColDef = useMemo( + () => ({ + cellRenderer: LinkRenderer, + cellRendererParams: { + isAbsolute: true, + url: ( + data // Based on the user Type (BCeID or IDIR) navigate to specific view + ) => + hasRoles(roles.supplier) + ? ROUTES.ORGANIZATION_VIEWUSER.replace( + ':userID', + data.data.userProfileId + ) + : ROUTES.ORGANIZATIONS_VIEWUSER.replace(':orgID', orgID).replace( + ':userID', + data.data.userProfileId + ) + } + }), + [hasRoles, orgID] ) const getRowId = useCallback((params) => params.data.userProfileId, []) @@ -331,7 +334,7 @@ export const ViewOrganization = () => { gridOptions={gridOptions} defaultSortModel={defaultSortModel} handleGridKey={handleGridKey} - handleRowClicked={handleRowClicked} + defaultColDef={defaultColDef} enableCopyButton={false} enableResetButton={false} /> diff --git a/frontend/src/views/OtherUses/OtherUsesSummary.jsx b/frontend/src/views/OtherUses/OtherUsesSummary.jsx index 4c6a203ed..7ae1b66e4 100644 --- a/frontend/src/views/OtherUses/OtherUsesSummary.jsx +++ b/frontend/src/views/OtherUses/OtherUsesSummary.jsx @@ -3,25 +3,24 @@ import BCBox from '@/components/BCBox' import { BCGridViewer } from '@/components/BCDataGrid/BCGridViewer' import { useGetOtherUses } from '@/hooks/useOtherUses' import Grid2 from '@mui/material/Unstable_Grid2/Grid2' -import { useEffect, useState } from 'react' -import { useLocation, useParams, useNavigate } from 'react-router-dom' +import { useEffect, useMemo, useState } from 'react' +import { useLocation, useParams } from 'react-router-dom' import { - formatNumberWithCommas as valueFormatter, - decimalFormatter + decimalFormatter, + formatNumberWithCommas as valueFormatter } from '@/utils/formatters' import { useTranslation } from 'react-i18next' -import { ROUTES } from '@/constants/routes' import { COMPLIANCE_REPORT_STATUSES } from '@/constants/statuses.js' +import { LinkRenderer } from '@/utils/grid/cellRenderers.jsx' export const OtherUsesSummary = ({ data, status }) => { const [alertMessage, setAlertMessage] = useState('') const [alertSeverity, setAlertSeverity] = useState('info') const { t } = useTranslation(['common', 'otherUses']) - const { complianceReportId, compliancePeriod } = useParams() + const { complianceReportId } = useParams() const location = useLocation() - const navigate = useNavigate() useEffect(() => { if (location.state?.message) { @@ -30,6 +29,19 @@ export const OtherUsesSummary = ({ data, status }) => { } }, [location.state]) + const defaultColDef = useMemo( + () => ({ + floatingFilter: false, + filter: false, + cellRenderer: + status === COMPLIANCE_REPORT_STATUSES.DRAFT ? LinkRenderer : undefined, + cellRendererParams: { + url: () => 'fuels-other-use' + } + }), + [status] + ) + const columns = [ { headerName: t('otherUses:otherUsesColLabels.fuelType'), @@ -87,17 +99,6 @@ export const OtherUsesSummary = ({ data, status }) => { const getRowId = (params) => params.data.otherUsesId - const handleRowClicked = () => { - if (status === COMPLIANCE_REPORT_STATUSES.DRAFT) { - navigate( - ROUTES.REPORTS_ADD_OTHER_USE_FUELS.replace( - ':compliancePeriod', - compliancePeriod - ).replace(':complianceReportId', complianceReportId) - ) - } - } - return (
@@ -112,7 +113,7 @@ export const OtherUsesSummary = ({ data, status }) => { gridKey={'other-uses'} getRowId={getRowId} columnDefs={columns} - defaultColDef={{ filter: false, floatingFilter: false }} + defaultColDef={defaultColDef} query={useGetOtherUses} queryParams={{ complianceReportId }} dataKey={'otherUses'} @@ -124,7 +125,6 @@ export const OtherUsesSummary = ({ data, status }) => { }} enableCellTextSelection ensureDomOrder - onRowClicked={handleRowClicked} /> diff --git a/frontend/src/views/Transactions/Transactions.jsx b/frontend/src/views/Transactions/Transactions.jsx index cd5a7f562..3227b1ab9 100644 --- a/frontend/src/views/Transactions/Transactions.jsx +++ b/frontend/src/views/Transactions/Transactions.jsx @@ -23,6 +23,7 @@ import { import { roles, govRoles } from '@/constants/roles' import OrganizationList from './components/OrganizationList' import Loading from '@/components/Loading' +import { LinkRenderer } from '@/utils/grid/cellRenderers.jsx' export const Transactions = () => { const { t } = useTranslation(['common', 'transaction']) @@ -40,9 +41,9 @@ export const Transactions = () => { const [alertMessage, setAlertMessage] = useState('') const [alertSeverity, setAlertSeverity] = useState('info') - const [gridKey, setGridKey] = useState(`transactions-grid`) + const [gridKey, setGridKey] = useState('transactions-grid') const handleGridKey = useCallback(() => { - setGridKey(`transactions-grid`) + setGridKey('transactions-grid') }, []) const gridOptions = { overlayNoRowsTemplate: t('txn:noTxnsFound') @@ -57,56 +58,62 @@ export const Transactions = () => { const [selectedOrgId, setSelectedOrgId] = useState(null) - // eslint-disable-next-line react-hooks/exhaustive-deps - const handleRowClicked = useCallback( - (params) => { - const { transactionId, transactionType, fromOrganization, status } = - params.data - const userOrgName = currentUser?.organization?.name + const defaultColDef = useMemo( + () => ({ + cellRenderer: LinkRenderer, + cellRendererParams: { + isAbsolute: true, + url: ( + data // Based on the user Type (BCeID or IDIR) navigate to specific view + ) => { + const { transactionId, transactionType, fromOrganization, status } = + data.data + const userOrgName = currentUser?.organization?.name - // Define routes mapping for transaction types - const routesMapping = { - Transfer: { - view: ROUTES.TRANSFERS_VIEW, - edit: ROUTES.TRANSFERS_EDIT - }, - AdminAdjustment: { - view: currentUser.isGovernmentUser - ? ROUTES.ADMIN_ADJUSTMENT_VIEW - : ROUTES.ORG_ADMIN_ADJUSTMENT_VIEW, - edit: ROUTES.ADMIN_ADJUSTMENT_EDIT - }, - InitiativeAgreement: { - view: currentUser.isGovernmentUser - ? ROUTES.INITIATIVE_AGREEMENT_VIEW - : ROUTES.ORG_INITIATIVE_AGREEMENT_VIEW, - edit: ROUTES.INITIATIVE_AGREEMENT_EDIT - } - } + // Define routes mapping for transaction types + const routesMapping = { + Transfer: { + view: ROUTES.TRANSFERS_VIEW, + edit: ROUTES.TRANSFERS_EDIT + }, + AdminAdjustment: { + view: currentUser.isGovernmentUser + ? ROUTES.ADMIN_ADJUSTMENT_VIEW + : ROUTES.ORG_ADMIN_ADJUSTMENT_VIEW, + edit: ROUTES.ADMIN_ADJUSTMENT_EDIT + }, + InitiativeAgreement: { + view: currentUser.isGovernmentUser + ? ROUTES.INITIATIVE_AGREEMENT_VIEW + : ROUTES.ORG_INITIATIVE_AGREEMENT_VIEW, + edit: ROUTES.INITIATIVE_AGREEMENT_EDIT + } + } - // Determine if it's an edit scenario - const isEditScenario = - (userOrgName === fromOrganization && - status === TRANSFER_STATUSES.DRAFT) || - (!fromOrganization && status === TRANSACTION_STATUSES.DRAFT) + // Determine if it's an edit scenario + const isEditScenario = + (userOrgName === fromOrganization && + status === TRANSFER_STATUSES.DRAFT) || + (!fromOrganization && status === TRANSACTION_STATUSES.DRAFT) - const routeType = isEditScenario ? 'edit' : 'view' + const routeType = isEditScenario ? 'edit' : 'view' - // Select the appropriate route based on the transaction type and scenario - const routeTemplate = routesMapping[transactionType]?.[routeType] + // Select the appropriate route based on the transaction type and scenario + const routeTemplate = routesMapping[transactionType]?.[routeType] - if (routeTemplate) { - navigate( - // replace any matching query params by chaining these replace methods - routeTemplate - .replace(':transactionId', transactionId) - .replace(':transferId', transactionId) - ) - } else { - console.error('No route defined for this transaction type and scenario') + if (routeTemplate) { + return routeTemplate + .replace(':transactionId', transactionId) + .replace(':transferId', transactionId) + } else { + console.error( + 'No route defined for this transaction type and scenario' + ) + } + } } - }, - [currentUser, navigate] + }), + [currentUser] ) // Determine the appropriate API endpoint @@ -259,9 +266,9 @@ export const Transactions = () => { defaultFilterModel={location.state?.filters} gridOptions={gridOptions} handleGridKey={handleGridKey} - handleRowClicked={handleRowClicked} enableCopyButton={false} highlightedRowId={highlightedId} + defaultColDef={defaultColDef} /> diff --git a/frontend/src/views/Transactions/__tests__/Transactions.test.jsx b/frontend/src/views/Transactions/__tests__/Transactions.test.jsx index 1d07c3c95..3bd2cc456 100644 --- a/frontend/src/views/Transactions/__tests__/Transactions.test.jsx +++ b/frontend/src/views/Transactions/__tests__/Transactions.test.jsx @@ -220,17 +220,4 @@ describe('Transactions', () => { expect(errorMessage).toBeInTheDocument() }) }) - - it('handles row click correctly', async () => { - render( - - - - ) - - const mockedDataGrid = screen.getByTestId('mocked-data-grid') - fireEvent.click(mockedDataGrid) - - expect(mockNavigate).toHaveBeenCalledWith('/transfers/123') - }) }) From 23bb835e9336e19b3364b909b248edf07cf34106 Mon Sep 17 00:00:00 2001 From: Daniel Haselhan Date: Mon, 6 Jan 2025 09:54:05 -0800 Subject: [PATCH 2/2] Code Review Feedback * Remove disabling of filters on compliance reports --- .../AdminMenu/components/__tests__/UserActivity.test.jsx | 8 ++++++-- .../src/views/ComplianceReports/ComplianceReports.jsx | 2 -- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/frontend/src/views/Admin/AdminMenu/components/__tests__/UserActivity.test.jsx b/frontend/src/views/Admin/AdminMenu/components/__tests__/UserActivity.test.jsx index e3ac19898..e07f424bc 100644 --- a/frontend/src/views/Admin/AdminMenu/components/__tests__/UserActivity.test.jsx +++ b/frontend/src/views/Admin/AdminMenu/components/__tests__/UserActivity.test.jsx @@ -83,9 +83,13 @@ describe('UserActivity', () => { // Optionally check the logic of getRowId // This is a unit-style check; you can do something like: const mockParams = { - data: { transactionType: 'AdminAdjustment', transactionId: '123' } + data: { + transactionType: 'AdminAdjustment', + transactionId: '123', + actionTaken: 'CREATE' + } } - expect(gridProps.getRowId(mockParams)).toBe('adminadjustment-123') + expect(gridProps.getRowId(mockParams)).toBe('CREATE-AdminAdjustment-123') // 5) defaultColDef expect(gridProps.defaultColDef).toBeDefined() diff --git a/frontend/src/views/ComplianceReports/ComplianceReports.jsx b/frontend/src/views/ComplianceReports/ComplianceReports.jsx index 4be8bcde3..948742536 100644 --- a/frontend/src/views/ComplianceReports/ComplianceReports.jsx +++ b/frontend/src/views/ComplianceReports/ComplianceReports.jsx @@ -87,8 +87,6 @@ export const ComplianceReports = () => { const defaultColDef = useMemo( () => ({ - floatingFilter: false, - filter: false, cellRenderer: LinkRenderer, cellRendererParams: { url: (data) =>