feat: reactive search with useEffect
This commit is contained in:
parent
23a4003f31
commit
c92d131ae3
|
@ -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,
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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 = [];
|
Loading…
Reference in New Issue
Block a user