Skip to content

Commit

Permalink
added isDebouncing in geosearch and naf slice, adjusted ui for RSAuto…
Browse files Browse the repository at this point in the history
…complete
  • Loading branch information
enguerranws committed Feb 3, 2025
1 parent 583ce3a commit 20f6e1d
Show file tree
Hide file tree
Showing 13 changed files with 111 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export const AppellationAutocomplete = ({
}) => {
if (!searchTerm) return "Saisissez un métier";
if (searchTerm.length < ROME_AND_APPELLATION_MIN_SEARCH_TEXT_LENGTH)
return "Saisissez au moins 3 caractères";
return "Saisissez au moins 2 caractères";
if (isSearching || searchTerm !== debounceSearchTerm) return "...";
return "Aucun métier trouvé";
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,20 @@ export const NafAutocomplete = ({
const dispatch = useDispatch();
const [searchTerm, setSearchTerm] = useState("");
const isLoading = useAppSelector(nafSelectors.isLoading);
const isDebouncing = useAppSelector(nafSelectors.isDebouncing);
const options = useAppSelector(nafSelectors.currentNafSections);
return (
<RSAutocomplete
{...props}
selectProps={{
isLoading,
isDebouncing,
inputValue: searchTerm,
noOptionsMessage: () => <>Saisissez au moins 3 caractères</>,
placeholder: "Ex : Administration publique",
onChange: (nafSectionSuggestion, actionMeta) => {
if (nafSectionSuggestion && actionMeta.action === "select-option") {
onNafSelected(nafSectionSuggestion.value);
dispatch(nafSlice.actions.queryWasEmptied());
}
if (
actionMeta.action === "clear" ||
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const PlaceAutocomplete = ({

const [searchTerm, setSearchTerm] = useState<string>("");
const isSearching: boolean = useAppSelector(geosearchSelectors.isLoading);
const isDebouncing: boolean = useAppSelector(geosearchSelectors.isDebouncing);
const searchSuggestions = useAppSelector(geosearchSelectors.suggestions);
const options = searchSuggestions.map((suggestion) => ({
value: suggestion,
Expand All @@ -32,11 +33,11 @@ export const PlaceAutocomplete = ({
<RSAutocomplete
{...props}
selectProps={{
isDebouncing,
inputId: props.id ?? "im-select__input--place",
isLoading: isSearching,
loadingMessage: () => <>Recherche de ville en cours... 🔎</>,
inputValue: searchTerm,
noOptionsMessage: () => <>Saisissez au moins 3 caractères</>,
placeholder: "Ex : Saint-Denis, La Réunion, France",
onChange: (searchResult, actionMeta) => {
if (actionMeta.action === "clear") {
Expand All @@ -50,6 +51,7 @@ export const PlaceAutocomplete = ({
searchResult.value,
),
);
dispatch(geosearchSlice.actions.queryWasEmptied());
}
},
options,
Expand Down
26 changes: 18 additions & 8 deletions front/src/app/pages/search/SearchPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ const radiusOptions = ["1", "2", "5", "10", "20", "50", "100"].map(
value: distance,
}),
);
const nafLabelMaxLength = 40;

const getSearchRouteParam = (
currentKey: keyof SearchPageParams,
Expand Down Expand Up @@ -194,7 +195,21 @@ export const SearchPage = ({

const placeInputLabel = <>...dans la ville</>;
const shouldShowInitialScreen = searchStatus === "noSearchMade";

const displayAppellationsOrNaf = () => {
const appellationDisplayed = formValues.appellations?.length
? formValues.appellations.map(
(appellation) => appellation.appellationLabel,
)
: [];
const nafDisplayed = formValues.nafLabel
? [
formValues.nafLabel.length > nafLabelMaxLength
? `${formValues.nafLabel.substring(0, nafLabelMaxLength)}...`
: formValues.nafLabel,
]
: [];
return [...appellationDisplayed, ...nafDisplayed].join(" - ");
};
return (
<HeaderFooterLayout>
<MainWrapper vSpacing={0} layout="fullscreen">
Expand Down Expand Up @@ -337,13 +352,7 @@ export const SearchPage = ({
defaultValue="Tous les métiers"
iconId="fr-icon-briefcase-fill"
id={domElementIds.search.appellationFilterTag}
values={
formValues.appellations
? formValues.appellations.map(
(appellation) => appellation.appellationLabel,
)
: []
}
values={[displayAppellationsOrNaf()]}
onReset={() => {
const updatedValues = {
...tempValue,
Expand Down Expand Up @@ -400,6 +409,7 @@ export const SearchPage = ({
setTempValue({
...tempValue,
nafCodes: nafSectionSuggestion.nafCodes,
nafLabel: nafSectionSuggestion.label,
});
}}
onNafClear={() => {
Expand Down
20 changes: 16 additions & 4 deletions front/src/core-logic/domain/geosearch/geosearch.selectors.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,28 @@
import { createSelector } from "@reduxjs/toolkit";
import { createRootSelector } from "src/core-logic/storeConfig/store";

const suggestions = createRootSelector((state) => state.geosearch.suggestions);
const geosearchState = createRootSelector((state) => state.geosearch);

const isLoading = createRootSelector((state) => state.geosearch.isLoading);
const isDebouncing = createSelector(
geosearchState,
(state) => state.isDebouncing,
);

const query = createRootSelector((state) => state.geosearch.query);
const suggestions = createSelector(
geosearchState,
(state) => state.suggestions,
);

const value = createRootSelector((state) => state.geosearch.value);
const isLoading = createSelector(geosearchState, (state) => state.isLoading);

const query = createSelector(geosearchState, (state) => state.query);

const value = createSelector(geosearchState, (state) => state.value);

export const geosearchSelectors = {
suggestions,
isLoading,
query,
value,
isDebouncing,
};
9 changes: 5 additions & 4 deletions front/src/core-logic/domain/geosearch/geosearch.slice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,33 @@ type GeoSearchState = {
value: LookupSearchResult | null;
query: string;
isLoading: boolean;
isDebouncing: boolean;
};

const initialState: GeoSearchState = {
suggestions: [],
query: "",
value: null,
isLoading: false,
isDebouncing: false,
};

export const geosearchSlice = createSlice({
name: "geosearch",
initialState,
reducers: {
queryWasEmptied: (state) => {
state.suggestions = [];
state.value = null;
},
queryWasEmptied: (_state) => initialState,
queryHasChanged: (state, _action: PayloadAction<LookupLocationInput>) => {
state.suggestions = [];
state.isDebouncing = true;
},
suggestionsHaveBeenRequested: (
state,
action: PayloadAction<LookupLocationInput>,
) => {
state.query = action.payload;
state.isLoading = true;
state.isDebouncing = false;
},
suggestionsSuccessfullyFetched: (
state,
Expand Down
20 changes: 16 additions & 4 deletions front/src/core-logic/domain/geosearch/geosearch.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
expectObjectsToMatch,
expectToEqual,
} from "shared";
import { geosearchSelectors } from "src/core-logic/domain/geosearch/geosearch.selectors";
import {
TestDependencies,
createTestStore,
Expand Down Expand Up @@ -37,14 +38,17 @@ describe("Geosearch epic", () => {
it("should update the searched query and reset the state", () => {
const query = "foi";
store.dispatch(geosearchSlice.actions.queryHasChanged(query));
expectDebouncingToBe(true);
dependencies.scheduler.flush();
expectDebouncingToBe(false);
expectLoadingToBe(true);
expectQueryToBe(query);
});

it("shouldn't update the searched query if threshold is not reached", () => {
const query = "fo";
store.dispatch(geosearchSlice.actions.queryHasChanged(query));
expectDebouncingToBe(true);
dependencies.scheduler.flush();
expectLoadingToBe(false);
expectQueryToBe("");
Expand All @@ -62,7 +66,9 @@ describe("Geosearch epic", () => {
},
];
store.dispatch(geosearchSlice.actions.queryHasChanged(query));
expectDebouncingToBe(true);
dependencies.scheduler.flush();
expectDebouncingToBe(false);
expectLoadingToBe(true);
dependencies.addressGateway.lookupLocationResults$.next(
expectedSuggestions,
Expand Down Expand Up @@ -95,15 +101,21 @@ describe("Geosearch epic", () => {
});

const expectQueryToBe = (expected: string) => {
expectToEqual(store.getState().geosearch.query, expected);
expectToEqual(geosearchSelectors.query(store.getState()), expected);
};
const expectLoadingToBe = (expected: boolean) => {
expectToEqual(store.getState().geosearch.isLoading, expected);
expectToEqual(geosearchSelectors.isLoading(store.getState()), expected);
};
const expectDebouncingToBe = (expected: boolean) => {
expectToEqual(geosearchSelectors.isDebouncing(store.getState()), expected);
};
const expectSuggestionsToBe = (expected: LookupSearchResult[]) => {
expectArraysToEqual(store.getState().geosearch.suggestions, expected);
expectArraysToEqual(
geosearchSelectors.suggestions(store.getState()),
expected,
);
};
const expectSelectedSuggestionToBe = (expected: LookupSearchResult) => {
expectObjectsToMatch(store.getState().geosearch.value, expected);
expectObjectsToMatch(geosearchSelectors.value(store.getState()), expected);
};
});
3 changes: 3 additions & 0 deletions front/src/core-logic/domain/naf/naf.selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ const currentNafSections = createSelector(
(state) => state.currentNafSections,
);

const isDebouncing = createSelector(nafState, (state) => state.isDebouncing);

export const nafSelectors = {
isLoading,
currentNafSections,
isDebouncing,
};
4 changes: 4 additions & 0 deletions front/src/core-logic/domain/naf/naf.slice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import { NafSectionSuggestion } from "shared";

export type NafState = {
isLoading: boolean;
isDebouncing: boolean;
currentNafSections: NafSectionSuggestion[];
};

export const initialState: NafState = {
isLoading: false,
isDebouncing: false,
currentNafSections: [],
};

Expand All @@ -17,13 +19,15 @@ export const nafSlice = createSlice({
reducers: {
queryHasChanged: (state, _action: PayloadAction<string>) => {
state.currentNafSections = [];
state.isDebouncing = true;
},
queryWasEmptied: (state) => {
state.isLoading = false;
state.currentNafSections = [];
},
searchSectionsRequested: (state, _action: PayloadAction<string>) => {
state.isLoading = true;
state.isDebouncing = false;
},
searchSectionsSucceeded: (
state,
Expand Down
10 changes: 10 additions & 0 deletions front/src/core-logic/domain/naf/naf.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,23 @@ describe("naf slice", () => {
it("should fetch naf sections and update the state", () => {
expectToMatchState(store.getState(), initialState);
store.dispatch(nafSlice.actions.queryHasChanged("query"));
expectToMatchState(store.getState(), {
currentNafSections: [],
isLoading: false,
isDebouncing: true,
});
dependencies.scheduler.flush();
expectToMatchState(store.getState(), {
currentNafSections: [],
isLoading: true,
isDebouncing: false,
});
// feed gateway
dependencies.nafGateway.nafSuggestions$.next(expectedResults);
expectToMatchState(store.getState(), {
currentNafSections: expectedResults,
isLoading: false,
isDebouncing: false,
});
});

Expand All @@ -49,6 +56,7 @@ describe("naf slice", () => {
expectToMatchState(store.getState(), {
currentNafSections: [],
isLoading: true,
isDebouncing: false,
});
dependencies.nafGateway.nafSuggestions$.error(new Error("test"));
expectToMatchState(store.getState(), initialState);
Expand All @@ -62,6 +70,7 @@ describe("naf slice", () => {
expectToMatchState(store.getState(), {
currentNafSections: expectedResults,
isLoading: false,
isDebouncing: false,
});
store.dispatch(nafSlice.actions.queryHasChanged("qu"));
dependencies.scheduler.flush();
Expand All @@ -76,6 +85,7 @@ describe("naf slice", () => {
expectToMatchState(store.getState(), {
currentNafSections: expectedResults,
isLoading: false,
isDebouncing: false,
});
store.dispatch(nafSlice.actions.queryWasEmptied());
dependencies.scheduler.flush();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,15 @@
}
&__option {
&:hover {
background-color: var(--hover-tint);
background-color: var(--background-overlap-grey-hover);
cursor: pointer;
}
&--is-focused {
background-color: var(--background-overlap-grey-hover);
}
}
&__menu-list {
@extend .fr-menu__list !optional;
}
&__menu-notice {
color: var(--grey-425-625);
Expand Down
Loading

0 comments on commit 20f6e1d

Please sign in to comment.