From 0ad4cc34c37febfa4ce980ebe7d470451817323e Mon Sep 17 00:00:00 2001 From: Craig Yu Date: Tue, 6 Feb 2024 12:07:24 -0800 Subject: [PATCH] Feat/497 connect backend and frontend for client search (#831) * fix: client search on edit seedlot info * feat: integrate endpoint * feat: refactor client search table and modal * fix: better constants --- .../provider/ForestClientApiProvider.java | 15 +- frontend/src/api-service/forestClientsAPI.ts | 160 +----------------- .../ClientSearchModal/ClientSearchFields.tsx | 4 +- .../ClientSearchModal/constants.ts | 16 ++ .../ClientSearchModal/constants.tsx | 39 ----- .../ClientSearchModal/definitions.ts | 10 +- .../ClientSearchModal/index.tsx | 115 +++---------- .../ApplicantAgencyFields/index.tsx | 14 +- .../components/ClientSearchTable/constants.ts | 10 +- .../ClientSearchTable/definitions.ts | 11 +- .../components/ClientSearchTable/index.tsx | 147 ++++++++++++---- .../src/components/ClientSearchTable/utils.ts | 6 +- .../LotApplicantAndInfoForm/index.tsx | 23 +-- .../src/components/SeedlotTable/index.tsx | 2 +- .../src/components/SeedlotTable/styles.scss | 21 --- frontend/src/styles/custom.scss | 22 +++ .../ForestClientDisplayType.ts | 8 - .../ForestClientSearchType.ts | 4 + 18 files changed, 232 insertions(+), 395 deletions(-) create mode 100644 frontend/src/components/ApplicantAgencyFields/ClientSearchModal/constants.ts delete mode 100644 frontend/src/components/ApplicantAgencyFields/ClientSearchModal/constants.tsx delete mode 100644 frontend/src/types/ForestClientTypes/ForestClientDisplayType.ts create mode 100644 frontend/src/types/ForestClientTypes/ForestClientSearchType.ts diff --git a/backend/src/main/java/ca/bc/gov/backendstartapi/provider/ForestClientApiProvider.java b/backend/src/main/java/ca/bc/gov/backendstartapi/provider/ForestClientApiProvider.java index 462c5fa69..a93045be1 100644 --- a/backend/src/main/java/ca/bc/gov/backendstartapi/provider/ForestClientApiProvider.java +++ b/backend/src/main/java/ca/bc/gov/backendstartapi/provider/ForestClientApiProvider.java @@ -176,13 +176,15 @@ public List fetchLocationsByClientNumber( "fetchLocationsByClientNumber", page); - if (!shouldFetchAll) { + int responseSize = response.getBody().size(); + + if (!shouldFetchAll || responseSize == 0) { return response.getBody(); } totalCount = Integer.parseInt(response.getHeaders().get("x-total-count").get(0)); - totalFetched += response.getBody().size(); + totalFetched += responseSize; page += 1; @@ -285,9 +287,16 @@ public List fetchClientsByClientName(String clientName) { "fetchClientsByClientName", page); + int responseSize = response.getBody().size(); + + // Empty response will not have a x-total-count header so we return the empty array here. + if (responseSize == 0) { + return result; + } + totalCount = Integer.parseInt(response.getHeaders().get("x-total-count").get(0)); - totalFetched += response.getBody().size(); + totalFetched += responseSize; page += 1; diff --git a/frontend/src/api-service/forestClientsAPI.ts b/frontend/src/api-service/forestClientsAPI.ts index 0dea29ec5..0b715a91f 100644 --- a/frontend/src/api-service/forestClientsAPI.ts +++ b/frontend/src/api-service/forestClientsAPI.ts @@ -2,7 +2,7 @@ import ApiConfig from './ApiConfig'; import api from './api'; import { ForestClientType } from '../types/ForestClientTypes/ForestClientType'; import ApplicantAgenciesItems from '../mock-server/fixtures/ApplicantAgenciesItems'; -import { ForestClientDisplayType } from '../types/ForestClientTypes/ForestClientDisplayType'; +import { ForestClientSearchType } from '../types/ForestClientTypes/ForestClientSearchType'; import { ClientSearchOptions } from '../components/ApplicantAgencyFields/ClientSearchModal/definitions'; export const getForestClientLocation = (clientNumber: string, locationCode: string) => { @@ -37,159 +37,13 @@ export const getAllAgencies = (): string[] => { return options; }; -// Leaving this here for testing/demo on the FE -// REMOVE AFTER REAL API IS DONE -const forestClientMockData: Array = [ - { - acronym: 'WFP', - number: '00149081', - fullName: 'WESTERN FOREST PRODUCTS INC.', - locationCode: '28', - location: '#118-1334 ISLAND HIGHWAY', - city: 'CAMPBELL RIVER' - }, - { - acronym: 'WFP', - number: '00149081', - fullName: 'WESTERN FOREST PRODUCTS INC.', - locationCode: '25', - location: '#201 - 65 FRONT STREET', - city: 'NANAIMO' - }, - { - acronym: 'WFP', - number: '00149081', - fullName: 'WESTERN FOREST PRODUCTS INC.', - locationCode: '26', - location: '800 1055 WEST GEORGIA STREET', - city: 'VANCOUVER' - }, - { - acronym: 'MOF', - number: '00012797', - fullName: 'MINISTRY OF FORESTS', - locationCode: '00', - location: '18793 32ND AVENUE', - city: 'SURREY' - }, - { - acronym: 'MOF', - number: '00012797', - fullName: 'MINISTRY OF FORESTS', - locationCode: '02', - location: '17000 DOMANO BLVD', - city: 'PRINCE GEORGE' - }, - { - acronym: 'MOF', - number: '00012797', - fullName: 'MINISTRY OF FORESTS', - locationCode: '07', - location: '4300 NORTH ROAD', - city: 'VICTORIA' - }, - { - acronym: 'MOF', - number: '00012797', - fullName: 'MINISTRY OF FORESTS', - locationCode: '08', - location: '9800 140TH STREET', - city: 'SURREY' - }, - { - acronym: 'TBA', - number: '00132184', - fullName: 'TIMBER SALES MANAGER BABINE', - locationCode: '01', - location: 'BURNS LAKE TSO', - city: 'BURNS LAKE' - }, - { - acronym: 'TBA', - number: '00132184', - fullName: 'TIMBER SALES MANAGER BABINE', - locationCode: '00', - location: 'BURNS LAKE TIMBER SALES OFFICE BOX 999', - city: 'BURNS LAKE' - }, - { - acronym: 'TCC', - number: '00132197', - fullName: 'TIMBER SALES MANAGER CARIBOO-CHILCOTIN', - locationCode: '02', - location: 'TCC - WILLIAMS LAKE FIELD TEAM 200-640 BORLAND ST', - city: 'WILLIAMS LAKE' - }, - { - acronym: 'TCC', - number: '00132197', - fullName: 'TIMBER SALES MANAGER CARIBOO-CHILCOTIN', - locationCode: '01', - location: 'TCC - QUESNEL FIELD TEAM 322 JOHNSTON AVENUE', - city: 'QUESNEL' - }, - { - acronym: 'TCC', - number: '00132197', - fullName: 'TIMBER SALES MANAGER CARIBOO-CHILCOTIN', - locationCode: '00', - location: 'CARIBOO CHILCOTIN TIMBER SALES OFFICE 200-640 BORLAND ST', - city: 'WILLIAMS LAKE' - }, - { - acronym: 'TCH', - number: '00132186', - fullName: 'TIMBER SALES MANAGER CHINOOK', - locationCode: '03', - location: '7077 DUNCAN STREET', - city: 'POWELL RIVER' - }, - { - acronym: 'TCH', - number: '00132186', - fullName: 'TIMBER SALES MANAGER CHINOOK', - locationCode: '01', - location: '101-42000 LOGGERS LANE', - city: 'SQUAMISH' - }, - { - acronym: 'TCH', - number: '00132186', - fullName: 'TIMBER SALES MANAGER CHINOOK', - locationCode: '02', - location: '1229 CEMETERY ROAD PO BOX 39', - city: 'QUEEN CHARLOTTE CITY' - }, - { - acronym: 'TCH', - number: '00132186', - fullName: 'TIMBER SALES MANAGER CHINOOK', - locationCode: '00', - location: '46360 AIRPORT ROAD', - city: 'CHILLIWACK' - } -]; - export const searchForestClients = ( - searchWord: string, - searchOption: ClientSearchOptions + searchQuery: string, + searchType: ClientSearchOptions ) => { - const returnPromise = new Promise((resolve, reject) => { - setTimeout(() => { - const filteredResults = forestClientMockData.filter( - (client: ForestClientDisplayType) => client[searchOption].includes(searchWord.toUpperCase()) - ); - if (searchWord === 'all') { - resolve(forestClientMockData); - } else if (searchWord !== 'error') { - resolve(filteredResults); - } else { - reject(new Error('Error on fake backend :(')); - } - }, 3000); - }); - - returnPromise.then((res: any): ForestClientDisplayType[] => res.data); + const url = new URL(`${ApiConfig.forestClient}/search`); + url.searchParams.append('type', searchType); + url.searchParams.append('query', searchQuery); - return returnPromise; + return api.get(url.toString()).then((res) => (res.data) as ForestClientSearchType[]); }; diff --git a/frontend/src/components/ApplicantAgencyFields/ClientSearchModal/ClientSearchFields.tsx b/frontend/src/components/ApplicantAgencyFields/ClientSearchModal/ClientSearchFields.tsx index 23d9ed3da..d518ba764 100644 --- a/frontend/src/components/ApplicantAgencyFields/ClientSearchModal/ClientSearchFields.tsx +++ b/frontend/src/components/ApplicantAgencyFields/ClientSearchModal/ClientSearchFields.tsx @@ -68,7 +68,9 @@ const ClientSearchFields = ({ className="client-search-button" disabled={mutationFn.isLoading} onClick={ - () => mutationFn.mutate({ word: searchWord, option: searchOption.option }) + searchWord.length + ? () => mutationFn.mutate() + : null } > Search diff --git a/frontend/src/components/ApplicantAgencyFields/ClientSearchModal/constants.ts b/frontend/src/components/ApplicantAgencyFields/ClientSearchModal/constants.ts new file mode 100644 index 000000000..2a79aa33a --- /dev/null +++ b/frontend/src/components/ApplicantAgencyFields/ClientSearchModal/constants.ts @@ -0,0 +1,16 @@ +import { ClientSearchDropdown } from './definitions'; + +export const clientSearchOptions: Array = [ + { + label: 'Full name', + option: 'client_name' + }, + { + label: 'Acronym', + option: 'acronym' + }, + { + label: 'Number', + option: 'client_number' + } +]; diff --git a/frontend/src/components/ApplicantAgencyFields/ClientSearchModal/constants.tsx b/frontend/src/components/ApplicantAgencyFields/ClientSearchModal/constants.tsx deleted file mode 100644 index 6714575fe..000000000 --- a/frontend/src/components/ApplicantAgencyFields/ClientSearchModal/constants.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import React from 'react'; -import { ClientSearchDropdown } from './definitions'; - -export const clientSearchOptions: Array = [ - { - label: 'Full name', - option: 'fullName' - }, - { - label: 'Acronym', - option: 'acronym' - }, - { - label: 'Number', - option: 'number' - } -]; - -export const getEmptySectionDescription = (message: string) => { - if (message) { - return ( - - Something went wrong while trying to search for users... -
- Error Message: - {` ${message}`} -
- ); - } - return ( - - Start by searching for a client or agency acronym, -
- number, or name. The matching results will be -
- shown here. -
- ); -}; diff --git a/frontend/src/components/ApplicantAgencyFields/ClientSearchModal/definitions.ts b/frontend/src/components/ApplicantAgencyFields/ClientSearchModal/definitions.ts index 679fa1817..86be65ced 100644 --- a/frontend/src/components/ApplicantAgencyFields/ClientSearchModal/definitions.ts +++ b/frontend/src/components/ApplicantAgencyFields/ClientSearchModal/definitions.ts @@ -1,4 +1,5 @@ import { UseMutationResult } from '@tanstack/react-query'; +import { ForestClientSearchType } from '../../../types/ForestClientTypes/ForestClientSearchType'; export interface ClientSearchModalProps { linkText: string; @@ -6,22 +7,17 @@ export interface ClientSearchModalProps { applySelectedClient: Function; } -export type ClientSearchOptions = 'acronym' | 'fullName' | 'number'; +export type ClientSearchOptions = 'acronym' | 'client_name' | 'client_number'; export type ClientSearchDropdown = { label: string; option: ClientSearchOptions }; -export type MutationParams = { - word: string; - option: ClientSearchOptions -}; - export type ClientSearchFieldsProps = { searchWord: string, setSearchWord: Function, searchOption: ClientSearchDropdown, setSearchOption: Function, - mutationFn: UseMutationResult + mutationFn: UseMutationResult }; diff --git a/frontend/src/components/ApplicantAgencyFields/ClientSearchModal/index.tsx b/frontend/src/components/ApplicantAgencyFields/ClientSearchModal/index.tsx index a7a6a7b0d..c227c5da2 100644 --- a/frontend/src/components/ApplicantAgencyFields/ClientSearchModal/index.tsx +++ b/frontend/src/components/ApplicantAgencyFields/ClientSearchModal/index.tsx @@ -7,23 +7,19 @@ import { Modal, FlexGrid, Row, - Column, - Pagination, - DataTableSkeleton + Column } from '@carbon/react'; import ClientSearchTable from '../../ClientSearchTable'; -import EmptySection from '../../EmptySection'; import ClientSearchFields from './ClientSearchFields'; import { searchForestClients } from '../../../api-service/forestClientsAPI'; -import PaginationChangeType from '../../../types/PaginationChangeType'; -import { ForestClientDisplayType } from '../../../types/ForestClientTypes/ForestClientDisplayType'; +import { ForestClientSearchType } from '../../../types/ForestClientTypes/ForestClientSearchType'; import { - ClientSearchDropdown, ClientSearchModalProps, MutationParams + ClientSearchDropdown, ClientSearchModalProps } from './definitions'; -import { clientSearchOptions, getEmptySectionDescription } from './constants'; +import { clientSearchOptions } from './constants'; import './styles.scss'; @@ -38,86 +34,16 @@ const ClientSearchModal = ( const [searchWord, setSearchWord] = useState(''); const [searchOption, setSearchOption] = useState(clientSearchOptions[0]); - const [showTable, setShowTable] = useState(false); - const [searchResults, setSearchResults] = useState([]); - const [selectedClient, setSelectedClient] = useState(); + const [selectedClient, setSelectedClient] = useState(); const [disableApplyButton, setDisableApplyButton] = useState(true); - const [errorMessage, setErrorMessage] = useState(''); const searchClientMutation = useMutation({ - mutationFn: (requestParam: MutationParams) => { - setShowTable(true); - return searchForestClients( - requestParam.word, - requestParam.option - ); - }, - onSuccess: (res: any) => { - setSearchResults(res); - }, - onError: (error: Error) => { - setShowTable(false); - setErrorMessage(error.message); - } + mutationFn: () => searchForestClients( + searchWord, + searchOption.option + ) }); - const [currPageNumber, setCurrPageNumber] = useState(0); - const [currPageSize, setCurrPageSize] = useState(10); - const [curIndex, setCurIndex] = useState(0); - - const handlePagination = (paginationObj: PaginationChangeType) => { - if (paginationObj.forwardBtnRef) { - setCurIndex(curIndex - paginationObj.pageSize); - } else { - setCurIndex(curIndex + paginationObj.pageSize); - } - setCurrPageNumber(paginationObj.page - 1); - setCurrPageSize(paginationObj.pageSize); - }; - - const tablePagination = () => ( - { - handlePagination(paginationObj); - } - } - /> - ); - - const showResultsTable = () => ( - searchClientMutation.isLoading - ? ( - - ) - : ( - 10} - tablePagination={tablePagination()} - selectClientFn={(client: ForestClientDisplayType) => { - if (disableApplyButton) { - setDisableApplyButton(false); - } - setSelectedClient(client); - }} - currentSelected={selectedClient} - /> - ) - ); - return ( <>