feat: reactive search with useEffect

This commit is contained in:
Vyacheslav Matyukhin 2022-03-25 01:23:07 +03:00
parent 23a4003f31
commit c92d131ae3
No known key found for this signature in database
GPG Key ID: 3D2A774C5489F96C
3 changed files with 63 additions and 68 deletions

View File

@ -15,8 +15,8 @@ export const getServerSideProps: GetServerSideProps = async (context) => {
let initialQueryParameters = { let initialQueryParameters = {
query: "", query: "",
numDisplay: 21,
starsThreshold: 2, starsThreshold: 2,
numDisplay: 21, // 20
forecastsThreshold: 0, forecastsThreshold: 0,
forecastingPlatforms: platformsWithLabels, // weird key value format, forecastingPlatforms: platformsWithLabels, // weird key value format,
...urlQuery, ...urlQuery,

View File

@ -1,4 +1,4 @@
import React, { Fragment, useState } from 'react'; import React, { Fragment, useEffect, useState } from 'react';
import { platformNames, PlatformWithLabel } from '../platforms'; import { platformNames, PlatformWithLabel } from '../platforms';
import searchAccordingToQueryData from '../worker/searchAccordingToQueryData'; import searchAccordingToQueryData from '../worker/searchAccordingToQueryData';
@ -7,14 +7,17 @@ import Form from './form';
import MultiSelectPlatform from './multiSelectPlatforms'; import MultiSelectPlatform from './multiSelectPlatforms';
import { SliderElement } from './slider'; import { SliderElement } from './slider';
export interface QueryParameters { interface QueryParametersWithoutNum {
query: string; query: string;
numDisplay: number;
starsThreshold: number; starsThreshold: number;
forecastsThreshold: number; forecastsThreshold: number;
forecastingPlatforms: PlatformWithLabel[]; forecastingPlatforms: PlatformWithLabel[];
} }
export interface QueryParameters extends QueryParametersWithoutNum {
numDisplay: number;
}
interface Props { interface Props {
initialResults: any; initialResults: any;
defaultResults: any; defaultResults: any;
@ -64,17 +67,13 @@ const CommonDisplay: React.FC<Props> = ({
}) => { }) => {
/* States */ /* States */
const [queryParameters, setQueryParameters] = useState( const [queryParameters, setQueryParameters] =
initialQueryParameters useState<QueryParametersWithoutNum>(initialQueryParameters);
);
let initialSearchSpeedSettings = { const [numDisplay, setNumDisplay] = useState(
timeoutId: null, initialQueryParameters.numDisplay || 21
awaitEndTyping: 500,
time: Date.now(),
};
const [searchSpeedSettings, setSearchSpeedSettings] = useState(
initialSearchSpeedSettings
); );
const [results, setResults] = useState(initialResults); const [results, setResults] = useState(initialResults);
const [advancedOptions, showAdvancedOptions] = useState(false); const [advancedOptions, showAdvancedOptions] = useState(false);
const [whichResultToDisplayAndCapture, setWhichResultToDisplayAndCapture] = const [whichResultToDisplayAndCapture, setWhichResultToDisplayAndCapture] =
@ -128,10 +127,9 @@ const CommonDisplay: React.FC<Props> = ({
showIdToggle, showIdToggle,
}) => { }) => {
let numDisplayRounded = let numDisplayRounded =
queryParameters.numDisplay % 3 != 0 numDisplay % 3 != 0
? queryParameters.numDisplay + ? numDisplay + (3 - (Math.round(numDisplay) % 3))
(3 - (Math.round(queryParameters.numDisplay) % 3)) : numDisplay;
: queryParameters.numDisplay;
return displayForecastsWrapper({ return displayForecastsWrapper({
results, results,
numDisplay: numDisplayRounded, numDisplay: numDisplayRounded,
@ -140,19 +138,20 @@ const CommonDisplay: React.FC<Props> = ({
}); });
}; };
/* State controllers */ useEffect(() => {
let onChangeSearchInputs = (newQueryParameters: QueryParameters) => {
setQueryParameters(newQueryParameters); // ({ ...newQueryParameters, processedUrlYet: true });
setResults([]); setResults([]);
clearTimeout(searchSpeedSettings.timeoutId); let newTimeoutId = setTimeout(async () => {
let newtimeoutId = setTimeout(async () => { let urlSlug = transformObjectIntoUrlSlug({
let urlSlug = transformObjectIntoUrlSlug(newQueryParameters); ...queryParameters,
numDisplay,
});
let urlWithoutDefaultParameters = urlSlug let urlWithoutDefaultParameters = urlSlug
.replace("?query=&", "?") .replace("?query=&", "?")
.replace("&starsThreshold=2", "") .replace("&starsThreshold=2", "")
.replace("&numDisplay=21", "") .replace("&numDisplay=21", "")
.replace("&forecastsThreshold=0", "") .replace("&forecastsThreshold=0", "")
.replace(`&forecastingPlatforms=${platformNames.join("|")}`, ""); .replace(`&forecastingPlatforms=${platformNames.join("|")}`, "");
console.log(urlWithoutDefaultParameters);
if (urlWithoutDefaultParameters != "?query=") { if (urlWithoutDefaultParameters != "?query=") {
if (typeof window !== "undefined") { if (typeof window !== "undefined") {
if (!window.location.href.includes(urlWithoutDefaultParameters)) { if (!window.location.href.includes(urlWithoutDefaultParameters)) {
@ -165,34 +164,40 @@ const CommonDisplay: React.FC<Props> = ({
} }
} }
executeSearchOrAnswerWithDefaultResults(newQueryParameters); executeSearchOrAnswerWithDefaultResults({
setSearchSpeedSettings({ ...searchSpeedSettings, timeoutId: null }); ...queryParameters,
}, searchSpeedSettings.awaitEndTyping); numDisplay,
setSearchSpeedSettings({ ...searchSpeedSettings, timeoutId: newtimeoutId }); });
}, 500);
// avoid sending results if user has not stopped typing. // avoid sending results if user has not stopped typing.
return () => {
clearTimeout(newTimeoutId);
}; };
}, [queryParameters]);
/* State controllers */
/* Change the stars threshold */ /* Change the stars threshold */
let onChangeStars = (value: number) => { let onChangeStars = (value: number) => {
let newQueryParameters: QueryParameters = { setQueryParameters({
...queryParameters, ...queryParameters,
starsThreshold: value, starsThreshold: value,
}; });
onChangeSearchInputs(newQueryParameters);
}; };
/* Change the number of elements to display */ /* Change the number of elements to display */
let displayFunctionNumDisplaySlider = (value) => { let displayFunctionNumDisplaySlider = (value) => {
return Math.round(value) != 1 return (
? "Show " + Math.round(value) + " results" "Show " +
: "Show " + Math.round(value) + " result"; Math.round(value) +
" result" +
(Math.round(value) === 1 ? "" : "s")
);
}; };
let onChangeSliderForNumDisplay = (event) => { let onChangeSliderForNumDisplay = (event) => {
let newQueryParameters: QueryParameters = { setNumDisplay(Math.round(event[0]));
...queryParameters, // FIXME - force new search if numDisplay is greater than last search limit
numDisplay: Math.round(event[0]),
};
onChangeSearchInputs(newQueryParameters); // Slightly inefficient because it recomputes the search in time, but it makes my logic easier.
}; };
/* Change the forecast threshold */ /* Change the forecast threshold */
@ -200,26 +205,26 @@ const CommonDisplay: React.FC<Props> = ({
return "# Forecasts > " + Math.round(value); return "# Forecasts > " + Math.round(value);
}; };
let onChangeSliderForNumForecasts = (event) => { let onChangeSliderForNumForecasts = (event) => {
let newQueryParameters = { setQueryParameters({
...queryParameters, ...queryParameters,
forecastsThreshold: Math.round(event[0]), forecastsThreshold: Math.round(event[0]),
}; });
onChangeSearchInputs(newQueryParameters);
}; };
/* Change on the search bar */ /* Change on the search bar */
let onChangeSearchBar = (value: string) => { let onChangeSearchBar = (value: string) => {
let newQueryParameters = { ...queryParameters, query: value }; setQueryParameters({
onChangeSearchInputs(newQueryParameters); ...queryParameters,
query: value,
});
}; };
/* Change selected platforms */ /* Change selected platforms */
let onChangeSelectedPlatforms = (value) => { let onChangeSelectedPlatforms = (value) => {
let newQueryParameters = { setQueryParameters({
...queryParameters, ...queryParameters,
forecastingPlatforms: value, forecastingPlatforms: value,
}; });
onChangeSearchInputs(newQueryParameters);
}; };
// Change show id // Change show id
@ -236,7 +241,6 @@ const CommonDisplay: React.FC<Props> = ({
}; };
let onClickForward = (whichResultToDisplayAndCapture: number) => { let onClickForward = (whichResultToDisplayAndCapture: number) => {
setWhichResultToDisplayAndCapture(whichResultToDisplayAndCapture + 1); setWhichResultToDisplayAndCapture(whichResultToDisplayAndCapture + 1);
// setTimeout(()=> {onClickForward(whichResultToDisplayAndCapture+1)}, 5000)
}; };
/* Final return */ /* Final return */
@ -300,7 +304,7 @@ const CommonDisplay: React.FC<Props> = ({
</div> </div>
<div className="flex row-start-3 row-end-3 col-start-1 col-end-4 md:col-start-3 md:col-end-3 md:row-start-1 md:row-end-1 lg:col-start-3 lg:col-end-3 lg:row-start-1 lg:row-end-1 items-center justify-center mb-4"> <div className="flex row-start-3 row-end-3 col-start-1 col-end-4 md:col-start-3 md:col-end-3 md:row-start-1 md:row-end-1 lg:col-start-3 lg:col-end-3 lg:row-start-1 lg:row-end-1 items-center justify-center mb-4">
<SliderElement <SliderElement
value={queryParameters.numDisplay} value={numDisplay}
onChange={onChangeSliderForNumDisplay} onChange={onChangeSliderForNumDisplay}
displayFunction={displayFunctionNumDisplaySlider} displayFunction={displayFunctionNumDisplaySlider}
/> />
@ -329,31 +333,22 @@ const CommonDisplay: React.FC<Props> = ({
})} })}
</div> </div>
{displaySeeMoreHint ? ( {displaySeeMoreHint &&
(!results || (results.length != 0 && numDisplay < results.length)) ? (
<div> <div>
<p <p className="mt-4 mb-4">
className={`mt-4 mb-4 ${
!results ||
(results.length != 0 &&
queryParameters.numDisplay < results.length)
? ""
: "hidden"
}`}
>
{"Can't find what you were looking for?"} {"Can't find what you were looking for?"}
<span <span
className={`cursor-pointer text-blue-800 ${ className={`cursor-pointer text-blue-800 ${
!results ? "hidden" : "" !results ? "hidden" : ""
}`} }`}
onClick={() => { onClick={() => {
setQueryParameters({ setNumDisplay(numDisplay * 2);
...queryParameters,
numDisplay: queryParameters.numDisplay * 2,
});
}} }}
> >
{" Show more, or"} {" Show more,"}
</span>{" "} </span>
{" or "}
<a <a
href="https://www.metaculus.com/questions/create/" href="https://www.metaculus.com/questions/create/"
className="cursor-pointer text-blue-800 no-underline" className="cursor-pointer text-blue-800 no-underline"

View File

@ -1,5 +1,5 @@
import searchWithAlgolia from "./searchWithAlgolia.js"; import searchGuesstimate from './searchGuesstimate.js';
import searchGuesstimate from "./searchGuesstimate.js"; import searchWithAlgolia from './searchWithAlgolia.js';
export default async function searchAccordingToQueryData(queryData) { export default async function searchAccordingToQueryData(queryData) {
let results = []; let results = [];