From 690b3f0f364974e4368f48798053801a80149437 Mon Sep 17 00:00:00 2001 From: Sampo Tawast <5328394+sirtawast@users.noreply.github.com> Date: Mon, 9 Dec 2024 10:10:30 +0200 Subject: [PATCH] fix: limit search list items to 30 without user action (#3638) --- .../applications/api/v1/search_views.py | 51 +++++++++++-------- .../handler/public/locales/en/common.json | 3 +- .../handler/public/locales/fi/common.json | 3 +- .../handler/public/locales/sv/common.json | 3 +- .../ApplicationsArchive.tsx | 33 +++++++++++- .../useApplicationsArchive.ts | 6 ++- .../src/hooks/useSearchApplicationQuery.ts | 5 +- 7 files changed, 76 insertions(+), 28 deletions(-) diff --git a/backend/benefit/applications/api/v1/search_views.py b/backend/benefit/applications/api/v1/search_views.py index c49b94dd3d..fd41646c0d 100755 --- a/backend/benefit/applications/api/v1/search_views.py +++ b/backend/benefit/applications/api/v1/search_views.py @@ -60,6 +60,7 @@ def get(self, request): archived = request.query_params.get("archived") == "1" or False search_from_archival = request.query_params.get("archival") == "1" or False application_number = request.query_params.get("app_no") + load_all = request.query_params.get("load_all") == "1" or False subsidy_in_effect = request.query_params.get("subsidy_in_effect") @@ -101,6 +102,7 @@ def get(self, request): detected_pattern, application_number, search_from_archival, + load_all, ) @@ -133,7 +135,7 @@ def _prepare_application_queryset(archived, subsidy_in_effect, years_since_decis - relativedelta(years=years_since_decision), ), ) - return queryset + return queryset.order_by("-modified_at") def _prepare_archival_application_queryset(subsidy_in_effect, years_since_decision): @@ -160,10 +162,11 @@ def search_applications( application_queryset, archival_application_queryset, search_string, - in_memory_filter_str, + in_memory_filter_string, detected_pattern, application_number=None, search_from_archival=False, + load_all=False, ) -> Response: if application_number: querysets = _query_by_application_number( @@ -172,9 +175,9 @@ def search_applications( application_queryset = querysets["application_queryset"] archival_application_queryset = querysets["archival_application_queryset"] - if search_string == "" and in_memory_filter_str == "": + if search_string == "" and in_memory_filter_string == "": return _query_and_respond_to_empty_search( - application_queryset, archival_application_queryset + application_queryset, archival_application_queryset, load_all ) # Return early in case of number-like pattern @@ -210,14 +213,14 @@ def search_applications( # Use filter string to perform in-memory search if ( detected_pattern in [SearchPattern.COMPANY, SearchPattern.IN_MEMORY] - and in_memory_filter_str != "" + and in_memory_filter_string != "" ): in_memory_results = _perform_in_memory_search( applications, detected_pattern, application_queryset, search_string, - in_memory_filter_str, + in_memory_filter_string, HandlerApplicationListSerializer, ) filtered_data = in_memory_results["data"] @@ -230,7 +233,7 @@ def search_applications( detected_pattern, archival_application_queryset, search_string, - in_memory_filter_str, + in_memory_filter_string, ArchivalApplicationListSerializer, ) filtered_data += in_memory_results_archival["data"] @@ -249,7 +252,7 @@ def search_applications( detected_pattern, search_string, in_memory_results, - in_memory_filter_str, + in_memory_filter_string, ) @@ -332,19 +335,27 @@ def _query_by_application_number( def _query_and_respond_to_empty_search( - application_queryset, archival_application_queryset + application_queryset, archival_application_queryset, load_all ): data = [] - data += HandlerApplicationListSerializer(application_queryset, many=True).data - data += ArchivalApplicationListSerializer( - archival_application_queryset, many=True - ).data + if load_all: + data += HandlerApplicationListSerializer(application_queryset, many=True).data + data += ArchivalApplicationListSerializer( + archival_application_queryset, many=True + ).data + else: + data += HandlerApplicationListSerializer( + application_queryset[:30], many=True + ).data + data += ArchivalApplicationListSerializer( + archival_application_queryset[:30], many=True + ).data return _create_search_response(None, data, SearchPattern.ALL, "") def _query_and_respond_to_ssn( application_queryset, - search_query_str, + search_query_string, detected_pattern, ): """ @@ -352,31 +363,31 @@ def _query_and_respond_to_ssn( filter by exact SSN and if no match is found then try uppercase """ application_queryset = application_queryset.filter( - employee__social_security_number=search_query_str + employee__social_security_number=search_query_string ) if application_queryset.count() == 0: application_queryset = application_queryset.filter( - employee__social_security_number=search_query_str.upper() + employee__social_security_number=search_query_string.upper() ) return _create_search_response( application_queryset, None, detected_pattern, - search_query_str, + search_query_string, ) def _query_and_respond_to_archival_application( - archival_application_queryset, search_query_str, detected_pattern + archival_application_queryset, search_query_string, detected_pattern ): archival_application_queryset = archival_application_queryset.filter( - Q(application_number__icontains=search_query_str) + Q(application_number__icontains=search_query_string) ) return _create_search_response( queryset=archival_application_queryset, serialized_data=None, detected_pattern=detected_pattern, - search_query_str=search_query_str, + search_query_str=search_query_string, serializer=ArchivalApplicationListSerializer, ) diff --git a/frontend/benefit/handler/public/locales/en/common.json b/frontend/benefit/handler/public/locales/en/common.json index b7ddc4f560..ed6f0b3bed 100644 --- a/frontend/benefit/handler/public/locales/en/common.json +++ b/frontend/benefit/handler/public/locales/en/common.json @@ -1469,7 +1469,8 @@ "previous": "Edellinen", "send": "Lähetä", "deleting": "Poistetaan...", - "submitting": "Lähetetään..." + "submitting": "Lähetetään...", + "loadMore": "Lataa lisää" }, "status": { "draft": "Luonnos", diff --git a/frontend/benefit/handler/public/locales/fi/common.json b/frontend/benefit/handler/public/locales/fi/common.json index 4cb897194b..9214495f26 100644 --- a/frontend/benefit/handler/public/locales/fi/common.json +++ b/frontend/benefit/handler/public/locales/fi/common.json @@ -1469,7 +1469,8 @@ "previous": "Edellinen", "send": "Lähetä", "deleting": "Poistetaan...", - "submitting": "Lähetetään..." + "submitting": "Lähetetään...", + "loadMore": "Lataa lisää" }, "status": { "draft": "Luonnos", diff --git a/frontend/benefit/handler/public/locales/sv/common.json b/frontend/benefit/handler/public/locales/sv/common.json index 4ffa699ae7..4f5c08c423 100644 --- a/frontend/benefit/handler/public/locales/sv/common.json +++ b/frontend/benefit/handler/public/locales/sv/common.json @@ -1469,7 +1469,8 @@ "previous": "Edellinen", "send": "Lähetä", "deleting": "Poistetaan...", - "submitting": "Lähetetään..." + "submitting": "Lähetetään...", + "loadMore": "Lataa lisää" }, "status": { "draft": "Luonnos", diff --git a/frontend/benefit/handler/src/components/applicationsArchive/ApplicationsArchive.tsx b/frontend/benefit/handler/src/components/applicationsArchive/ApplicationsArchive.tsx index b70ab47606..a4d95f43a9 100644 --- a/frontend/benefit/handler/src/components/applicationsArchive/ApplicationsArchive.tsx +++ b/frontend/benefit/handler/src/components/applicationsArchive/ApplicationsArchive.tsx @@ -1,5 +1,6 @@ import { ROUTES } from 'benefit/handler/constants'; import { + Button, IconCross, RadioButton, SearchInput, @@ -15,6 +16,7 @@ import { $Grid, $GridCell, } from 'shared/components/forms/section/FormSection.sc'; +import { focusAndScrollToSelector } from 'shared/utils/dom.utils'; import styled from 'styled-components'; import ApplicationArchiveList from './ApplicationArchiveList'; @@ -45,6 +47,9 @@ const $SearchInputArea = styled.div` const ApplicationsArchive: React.FC = () => { const [searchString, setSearchString] = React.useState(''); const [initialQuery, setInitialQuery] = React.useState(true); + const [loadAll, setLoadAll] = React.useState(false); + const [displayLoadAll, setDisplayLoadAll] = React.useState(true); + const [subsidyInEffect, setSubsidyInEffect] = React.useState( SUBSIDY_IN_EFFECT.RANGE_THREE_YEARS @@ -65,7 +70,8 @@ const ApplicationsArchive: React.FC = () => { true, subsidyInEffect, decisionRange, - applicationNum ? applicationNum.toString() : null + applicationNum ? applicationNum.toString() : null, + loadAll ); const onSearch = (value: string): void => { @@ -80,6 +86,8 @@ const ApplicationsArchive: React.FC = () => { setFilterSelection(selection); setDecisionRange(null); setSubsidyInEffect(value); + setDisplayLoadAll(true); + setLoadAll(false); }; const handleDecisionFilterChange = ( selection: FILTER_SELECTION, @@ -88,11 +96,15 @@ const ApplicationsArchive: React.FC = () => { setFilterSelection(selection); setDecisionRange(value); setSubsidyInEffect(null); + setDisplayLoadAll(true); + setLoadAll(false); }; const handleFiltersOff = (): void => { setDecisionRange(null); setSubsidyInEffect(null); setFilterSelection(FILTER_SELECTION.NO_FILTER); + setDisplayLoadAll(true); + setLoadAll(false); }; React.useEffect(() => { @@ -102,9 +114,10 @@ const ApplicationsArchive: React.FC = () => { setInitialQuery(false); } else if (!isSearchLoading) { submitSearch(searchString); + setLoadAll(false); } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [filterSelection, applicationNum, router, initialQuery]); + }, [filterSelection, applicationNum, router, initialQuery, loadAll]); return ( @@ -220,6 +233,22 @@ const ApplicationsArchive: React.FC = () => { data={searchResults?.matches} isSearchLoading={isSearchLoading} /> + {displayLoadAll && + !isSearchLoading && + searchString.length === 0 && + searchResults?.matches?.length >= 30 && ( + + )} ); }; diff --git a/frontend/benefit/handler/src/components/applicationsArchive/useApplicationsArchive.ts b/frontend/benefit/handler/src/components/applicationsArchive/useApplicationsArchive.ts index e934e7dcd4..6d76019e1f 100644 --- a/frontend/benefit/handler/src/components/applicationsArchive/useApplicationsArchive.ts +++ b/frontend/benefit/handler/src/components/applicationsArchive/useApplicationsArchive.ts @@ -80,7 +80,8 @@ const useApplicationsArchive = ( includeArchivalApplications: boolean, subsidyInEffect: SUBSIDY_IN_EFFECT, decisionRange: number, - applicationNum?: string + applicationNum?: string, + loadAll?: boolean ): ApplicationListProps => { const { t } = useTranslation(); @@ -95,7 +96,8 @@ const useApplicationsArchive = ( includeArchivalApplications, subsidyInEffect, decisionRange, - applicationNum + applicationNum, + loadAll ); const shouldHideList = diff --git a/frontend/benefit/handler/src/hooks/useSearchApplicationQuery.ts b/frontend/benefit/handler/src/hooks/useSearchApplicationQuery.ts index 8d99c8c7b3..42e3a3e192 100644 --- a/frontend/benefit/handler/src/hooks/useSearchApplicationQuery.ts +++ b/frontend/benefit/handler/src/hooks/useSearchApplicationQuery.ts @@ -16,7 +16,8 @@ const useSearchApplicationQuery = ( includeArchivalApplications = false, subsidyInEffect?: SUBSIDY_IN_EFFECT, decisionRange?: DECISION_RANGE, - applicationNum?: string + applicationNum?: string, + loadAll = false ): UseMutationResult => { const { axios, handleResponse } = useBackendAPI(); const { t } = useTranslation(); @@ -28,12 +29,14 @@ const useSearchApplicationQuery = ( subsidy_in_effect?: SUBSIDY_IN_EFFECT; years_since_decision?: DECISION_RANGE; app_no?: string; + load_all?: string; } = { q, ...(archived && { archived: '1' }), ...(includeArchivalApplications && { archival: '1' }), ...(subsidyInEffect && { subsidy_in_effect: subsidyInEffect }), ...(decisionRange && { years_since_decision: decisionRange }), + ...(loadAll && { load_all: '1' }), }; if (applicationNum) {