feat: /capture and / are static

This commit is contained in:
Vyacheslav Matyukhin 2022-03-25 02:45:21 +03:00
parent 98c7c31a0f
commit f056d257b2
No known key found for this signature in database
GPG Key ID: 3D2A774C5489F96C
3 changed files with 82 additions and 102 deletions

View File

@ -1,33 +1,18 @@
import { GetServerSideProps, NextPage } from 'next'; import { GetStaticProps, NextPage } from 'next';
import React from 'react'; import React from 'react';
import { getFrontpage } from '../backend/frontpage'; import { getFrontpage } from '../backend/frontpage';
import CommonDisplay, { QueryParameters } from '../web/display/commonDisplay'; import CommonDisplay from '../web/display/commonDisplay';
import { displayForecastsWrapperForCapture } from '../web/display/displayForecastsWrappers'; import { displayForecastsWrapperForCapture } from '../web/display/displayForecastsWrappers';
import { platformsWithLabels } from '../web/platforms';
import Layout from './layout'; import Layout from './layout';
/* get Props */ /* get Props */
interface Props { interface Props {
initialQueryParameters: QueryParameters;
defaultResults: any; defaultResults: any;
} }
export const getServerSideProps: GetServerSideProps<Props> = async ( export const getStaticProps: GetStaticProps<Props> = async (context) => {
context
) => {
let urlQuery = context.query;
let initialQueryParameters: QueryParameters = {
query: "",
numDisplay: 21,
starsThreshold: 2,
forecastsThreshold: 0,
forecastingPlatforms: platformsWithLabels, // weird key value format,
...urlQuery,
};
let frontPageForecasts = await getFrontpage(); let frontPageForecasts = await getFrontpage();
frontPageForecasts = frontPageForecasts.map((forecast) => ({ frontPageForecasts = frontPageForecasts.map((forecast) => ({
...forecast, ...forecast,
@ -39,19 +24,18 @@ export const getServerSideProps: GetServerSideProps<Props> = async (
return { return {
props: { props: {
initialQueryParameters: initialQueryParameters,
defaultResults: frontPageForecasts, defaultResults: frontPageForecasts,
}, },
revalidate: 3600 * 6,
}; };
}; };
/* Body */ /* Body */
const Home: NextPage<Props> = ({ defaultResults, initialQueryParameters }) => { const CapturePage: NextPage<Props> = ({ defaultResults }) => {
return ( return (
<Layout page={"capture"}> <Layout page={"capture"}>
<CommonDisplay <CommonDisplay
defaultResults={defaultResults} defaultResults={defaultResults}
initialQueryParameters={initialQueryParameters}
hasSearchbar={true} hasSearchbar={true}
hasCapture={true} hasCapture={true}
hasAdvancedOptions={false} hasAdvancedOptions={false}
@ -63,4 +47,4 @@ const Home: NextPage<Props> = ({ defaultResults, initialQueryParameters }) => {
); );
}; };
export default Home; export default CapturePage;

View File

@ -1,33 +1,18 @@
import { GetServerSideProps, NextPage } from 'next'; import { GetStaticProps, NextPage } from 'next';
import React from 'react'; import React from 'react';
import { getFrontpage } from '../backend/frontpage'; import { getFrontpage } from '../backend/frontpage';
import CommonDisplay, { QueryParameters } from '../web/display/commonDisplay'; import CommonDisplay from '../web/display/commonDisplay';
import { displayForecastsWrapperForSearch } from '../web/display/displayForecastsWrappers'; import { displayForecastsWrapperForSearch } from '../web/display/displayForecastsWrappers';
import { platformsWithLabels } from '../web/platforms';
import Layout from './layout'; import Layout from './layout';
/* get Props */ /* get Props */
interface Props { interface Props {
initialQueryParameters: QueryParameters;
defaultResults: any; defaultResults: any;
} }
export const getServerSideProps: GetServerSideProps<Props> = async ( export const getStaticProps: GetStaticProps<Props> = async (context) => {
context
) => {
let urlQuery = context.query;
let initialQueryParameters: QueryParameters = {
query: "",
numDisplay: 21,
starsThreshold: 2,
forecastsThreshold: 0,
forecastingPlatforms: platformsWithLabels, // weird key value format,
...urlQuery,
};
let frontPageForecasts = await getFrontpage(); let frontPageForecasts = await getFrontpage();
frontPageForecasts = frontPageForecasts.map((forecast) => ({ frontPageForecasts = frontPageForecasts.map((forecast) => ({
...forecast, ...forecast,
@ -39,19 +24,18 @@ export const getServerSideProps: GetServerSideProps<Props> = async (
return { return {
props: { props: {
initialQueryParameters: initialQueryParameters,
defaultResults: frontPageForecasts, defaultResults: frontPageForecasts,
}, },
revalidate: 3600 * 6,
}; };
}; };
/* Body */ /* Body */
const Home: NextPage<Props> = ({ defaultResults, initialQueryParameters }) => { const IndexPage: NextPage<Props> = ({ defaultResults }) => {
return ( return (
<Layout page={"search"}> <Layout page={"search"}>
<CommonDisplay <CommonDisplay
defaultResults={defaultResults} defaultResults={defaultResults}
initialQueryParameters={initialQueryParameters}
hasSearchbar={true} hasSearchbar={true}
hasCapture={false} hasCapture={false}
hasAdvancedOptions={true} hasAdvancedOptions={true}
@ -63,4 +47,4 @@ const Home: NextPage<Props> = ({ defaultResults, initialQueryParameters }) => {
); );
}; };
export default Home; export default IndexPage;

View File

@ -1,6 +1,7 @@
import { useRouter } from 'next/router';
import React, { Fragment, useEffect, useState } from 'react'; import React, { Fragment, useEffect, useState } from 'react';
import { platformNames, PlatformWithLabel } from '../platforms'; import { platformsWithLabels, PlatformWithLabel } from '../platforms';
import searchAccordingToQueryData from '../worker/searchAccordingToQueryData'; import searchAccordingToQueryData from '../worker/searchAccordingToQueryData';
import ButtonsForStars from './buttonsForStars'; import ButtonsForStars from './buttonsForStars';
import Form from './form'; import Form from './form';
@ -20,7 +21,6 @@ export interface QueryParameters extends QueryParametersWithoutNum {
interface Props { interface Props {
defaultResults: any; defaultResults: any;
initialQueryParameters: QueryParameters;
hasSearchbar: boolean; hasSearchbar: boolean;
hasCapture: boolean; hasCapture: boolean;
hasAdvancedOptions: boolean; hasAdvancedOptions: boolean;
@ -34,28 +34,17 @@ interface Props {
}) => React.ReactNode; }) => React.ReactNode;
} }
/* Helper functions */ const defaultQueryParameters: QueryParametersWithoutNum = {
query: "",
// URL slugs starsThreshold: 2,
let transformObjectIntoUrlSlug = (obj: QueryParameters) => { forecastsThreshold: 0,
let results = []; forecastingPlatforms: platformsWithLabels, // weird key value format,
for (let key in obj) {
if (typeof obj[key] === "number" || typeof obj[key] === "string") {
results.push(`${key}=${obj[key]}`);
} else if (key === "forecastingPlatforms") {
let arr = obj[key].map((x) => x.value);
let arrstring = arr.join("|");
results.push(`${key}=${arrstring}`);
}
}
let string = "?" + results.join("&");
return string;
}; };
const defaultNumDisplay = 21;
/* Body */ /* Body */
const CommonDisplay: React.FC<Props> = ({ const CommonDisplay: React.FC<Props> = ({
defaultResults, defaultResults,
initialQueryParameters,
hasSearchbar, hasSearchbar,
hasCapture, hasCapture,
hasAdvancedOptions, hasAdvancedOptions,
@ -63,14 +52,18 @@ const CommonDisplay: React.FC<Props> = ({
displaySeeMoreHint, displaySeeMoreHint,
displayForecastsWrapper, displayForecastsWrapper,
}) => { }) => {
const router = useRouter();
/* States */ /* States */
const [queryParameters, setQueryParameters] = const [queryParameters, setQueryParameters] =
useState<QueryParametersWithoutNum>(initialQueryParameters); useState<QueryParametersWithoutNum>(defaultQueryParameters);
const [numDisplay, setNumDisplay] = useState( const [numDisplay, setNumDisplay] = useState(0);
initialQueryParameters.numDisplay || 21
); const [ready, setReady] = useState(false);
// used to distinguish numDisplay updates which force search and don't force search, see effects below
const [forceSearch, setForceSearch] = useState(0);
const [results, setResults] = useState([]); const [results, setResults] = useState([]);
const [advancedOptions, showAdvancedOptions] = useState(false); const [advancedOptions, showAdvancedOptions] = useState(false);
@ -78,13 +71,29 @@ const CommonDisplay: React.FC<Props> = ({
useState(0); useState(0);
const [showIdToggle, setShowIdToggle] = useState(false); const [showIdToggle, setShowIdToggle] = useState(false);
useEffect(() => {
if (!router.isReady) return;
setQueryParameters({
...defaultQueryParameters,
...router.query,
});
setNumDisplay(
typeof router.query.numDisplay === "string"
? parseInt(router.query.numDisplay)
: defaultNumDisplay
);
setReady(true);
}, [router.isReady]);
/* Functions which I want to have access to the Home namespace */ /* Functions which I want to have access to the Home namespace */
// I don't want to create an "defaultResults" object for each search. // I don't want to create an "defaultResults" object for each search.
async function executeSearchOrAnswerWithDefaultResults( async function executeSearchOrAnswerWithDefaultResults() {
queryData: QueryParameters const queryData = {
) { ...queryParameters,
// the queryData object has the same contents as queryParameters. numDisplay,
// but I wanted to spare myself having to think about namespace conflicts. };
let filterManually = (queryData: QueryParameters, results) => { let filterManually = (queryData: QueryParameters, results) => {
if ( if (
queryData.forecastingPlatforms && queryData.forecastingPlatforms &&
@ -136,43 +145,46 @@ const CommonDisplay: React.FC<Props> = ({
}); });
}; };
useEffect(() => { const updateRoute = () => {
setResults([]); const stringify = (key: string, value: any) => {
let newTimeoutId = setTimeout(async () => { if (key === "forecastingPlatforms") {
let urlSlug = transformObjectIntoUrlSlug({ return value.map((x) => x.value).join("|");
...queryParameters, } else {
numDisplay, return String(value);
});
let urlWithoutDefaultParameters = urlSlug
.replace("?query=&", "?")
.replace("&starsThreshold=2", "")
.replace("&numDisplay=21", "")
.replace("&forecastsThreshold=0", "")
.replace(`&forecastingPlatforms=${platformNames.join("|")}`, "");
console.log(urlWithoutDefaultParameters);
if (urlWithoutDefaultParameters != "?query=") {
if (typeof window !== "undefined") {
if (!window.location.href.includes(urlWithoutDefaultParameters)) {
window.history.replaceState(
null,
"Metaforecast",
urlWithoutDefaultParameters
);
}
} }
};
const query = {};
for (const key of Object.keys(defaultQueryParameters)) {
const value = stringify(key, queryParameters[key]);
const defaultValue = stringify(key, defaultQueryParameters[key]);
if (value === defaultValue) continue;
query[key] = value;
} }
executeSearchOrAnswerWithDefaultResults({ if (numDisplay !== defaultNumDisplay) query["numDisplay"] = numDisplay;
...queryParameters,
numDisplay, router.replace({
pathname: router.pathname,
query,
}); });
};
useEffect(updateRoute, [numDisplay]);
useEffect(() => {
if (!ready) return;
setResults([]);
let newTimeoutId = setTimeout(() => {
updateRoute();
executeSearchOrAnswerWithDefaultResults();
}, 500); }, 500);
// avoid sending results if user has not stopped typing. // avoid sending results if user has not stopped typing.
return () => { return () => {
clearTimeout(newTimeoutId); clearTimeout(newTimeoutId);
}; };
}, [queryParameters]); }, [ready, queryParameters, forceSearch]);
/* State controllers */ /* State controllers */
@ -195,7 +207,7 @@ const CommonDisplay: React.FC<Props> = ({
}; };
let onChangeSliderForNumDisplay = (event) => { let onChangeSliderForNumDisplay = (event) => {
setNumDisplay(Math.round(event[0])); setNumDisplay(Math.round(event[0]));
// FIXME - force new search if numDisplay is greater than last search limit setForceSearch(forceSearch + 1); // FIXME - force new search iff numDisplay is greater than last search limit
}; };
/* Change the forecast threshold */ /* Change the forecast threshold */