refactor: some typescript improvements
This commit is contained in:
parent
44fbd0cd2b
commit
439a9045da
|
@ -2,7 +2,7 @@ import axios from "axios";
|
||||||
|
|
||||||
import { applyIfSecretExists } from "../utils/getSecrets";
|
import { applyIfSecretExists } from "../utils/getSecrets";
|
||||||
|
|
||||||
async function rebuildNetlifySiteWithNewData_inner(cookie) {
|
async function rebuildNetlifySiteWithNewData_inner(cookie: string) {
|
||||||
let payload = {};
|
let payload = {};
|
||||||
let response = await axios.post(cookie, payload);
|
let response = await axios.post(cookie, payload);
|
||||||
let data = response.data;
|
let data = response.data;
|
||||||
|
@ -10,6 +10,6 @@ async function rebuildNetlifySiteWithNewData_inner(cookie) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function rebuildNetlifySiteWithNewData() {
|
export async function rebuildNetlifySiteWithNewData() {
|
||||||
let cookie = process.env.REBUIDNETLIFYHOOKURL;
|
const cookie = process.env.REBUIDNETLIFYHOOKURL || "";
|
||||||
await applyIfSecretExists(cookie, rebuildNetlifySiteWithNewData_inner);
|
await applyIfSecretExists(cookie, rebuildNetlifySiteWithNewData_inner);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,10 +8,10 @@ import { FetchedQuestion, Platform } from "./";
|
||||||
const platformName = "betfair";
|
const platformName = "betfair";
|
||||||
|
|
||||||
/* Definitions */
|
/* Definitions */
|
||||||
let endpoint = process.env.SECRET_BETFAIR_ENDPOINT;
|
const endpoint = process.env.SECRET_BETFAIR_ENDPOINT;
|
||||||
|
|
||||||
/* Utilities */
|
/* Utilities */
|
||||||
let arraysEqual = (a, b) => {
|
const arraysEqual = (a: string[], b: string[]) => {
|
||||||
if (a === b) return true;
|
if (a === b) return true;
|
||||||
if (a == null || b == null) return false;
|
if (a == null || b == null) return false;
|
||||||
if (a.length !== b.length) return false;
|
if (a.length !== b.length) return false;
|
||||||
|
@ -26,7 +26,8 @@ let arraysEqual = (a, b) => {
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
let mergeRunners = (runnerCatalog, runnerBook) => {
|
|
||||||
|
const mergeRunners = (runnerCatalog, runnerBook) => {
|
||||||
let keys = Object.keys(runnerCatalog);
|
let keys = Object.keys(runnerCatalog);
|
||||||
let result = [];
|
let result = [];
|
||||||
for (let key of keys) {
|
for (let key of keys) {
|
||||||
|
|
|
@ -8,8 +8,8 @@ import { Platform } from "./";
|
||||||
const platformName = "givewellopenphil";
|
const platformName = "givewellopenphil";
|
||||||
|
|
||||||
/* Support functions */
|
/* Support functions */
|
||||||
async function fetchPage(url: string) {
|
async function fetchPage(url: string): Promise<string> {
|
||||||
let response = await axios({
|
const response = await axios({
|
||||||
url: url,
|
url: url,
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
|
|
|
@ -5,13 +5,14 @@ import { Question } from "@prisma/client";
|
||||||
import { prisma } from "../database/prisma";
|
import { prisma } from "../database/prisma";
|
||||||
import { platforms } from "../platforms";
|
import { platforms } from "../platforms";
|
||||||
|
|
||||||
let cookie = process.env.ALGOLIA_MASTER_API_KEY;
|
let cookie = process.env.ALGOLIA_MASTER_API_KEY || "";
|
||||||
const algoliaAppId = process.env.NEXT_PUBLIC_ALGOLIA_APP_ID;
|
const algoliaAppId = process.env.NEXT_PUBLIC_ALGOLIA_APP_ID || "";
|
||||||
const client = algoliasearch(algoliaAppId, cookie);
|
const client = algoliasearch(algoliaAppId, cookie);
|
||||||
const index = client.initIndex("metaforecast");
|
const index = client.initIndex("metaforecast");
|
||||||
|
|
||||||
export type AlgoliaQuestion = Omit<Question, "timestamp"> & {
|
export type AlgoliaQuestion = Omit<Question, "timestamp"> & {
|
||||||
timestamp: string;
|
timestamp: string;
|
||||||
|
optionsstringforsearch?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getoptionsstringforsearch = (record: Question): string => {
|
const getoptionsstringforsearch = (record: Question): string => {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { EventHandler, SyntheticEvent, useState } from "react";
|
import React, { ChangeEvent, EventHandler, SyntheticEvent, useState } from "react";
|
||||||
|
|
||||||
import { Button } from "../common/Button";
|
import { Button } from "../common/Button";
|
||||||
import { InfoBox } from "../common/InfoBox";
|
import { InfoBox } from "../common/InfoBox";
|
||||||
|
@ -18,7 +18,7 @@ export const DashboardCreator: React.FC<Props> = ({ handleSubmit }) => {
|
||||||
const [value, setValue] = useState(exampleInput);
|
const [value, setValue] = useState(exampleInput);
|
||||||
const [acting, setActing] = useState(false);
|
const [acting, setActing] = useState(false);
|
||||||
|
|
||||||
const handleChange = (event) => {
|
const handleChange = (event: ChangeEvent<HTMLTextAreaElement>) => {
|
||||||
setValue(event.target.value);
|
setValue(event.target.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/* Imports */
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Handles, Rail, Slider, Tracks } from "react-compound-slider";
|
import {
|
||||||
|
GetHandleProps, GetTrackProps, Handles, Rail, Slider, SliderItem, Tracks
|
||||||
|
} from "react-compound-slider";
|
||||||
|
|
||||||
// https://sghall.github.io/react-compound-slider/#/getting-started/tutorial
|
// https://sghall.github.io/react-compound-slider/#/getting-started/tutorial
|
||||||
|
|
||||||
|
@ -24,12 +25,11 @@ const railStyle = {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Support functions */
|
/* Support functions */
|
||||||
function Handle({
|
const Handle: React.FC<{
|
||||||
handle: { id, value, percent },
|
handle: SliderItem;
|
||||||
getHandleProps,
|
getHandleProps: GetHandleProps;
|
||||||
displayFunction,
|
displayFunction: (value: number) => string;
|
||||||
handleWidth,
|
}> = ({ handle: { id, value, percent }, getHandleProps, displayFunction }) => {
|
||||||
}) {
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="justify-center text-center text-gray-600 text-xs">
|
<div className="justify-center text-center text-gray-600 text-xs">
|
||||||
|
@ -53,9 +53,13 @@ function Handle({
|
||||||
></div>
|
></div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
function Track({ source, target, getTrackProps }) {
|
const Track: React.FC<{
|
||||||
|
source: SliderItem;
|
||||||
|
target: SliderItem;
|
||||||
|
getTrackProps: GetTrackProps;
|
||||||
|
}> = ({ source, target, getTrackProps }) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
@ -74,16 +78,15 @@ function Track({ source, target, getTrackProps }) {
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
value: number;
|
value: number;
|
||||||
onChange: (event: any) => void;
|
onChange: (value: number) => void;
|
||||||
displayFunction: (value: number) => string;
|
displayFunction: (value: number) => string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Body */
|
/* Body */
|
||||||
// Two functions, essentially identical.
|
|
||||||
export const SliderElement: React.FC<Props> = ({
|
export const SliderElement: React.FC<Props> = ({
|
||||||
onChange,
|
onChange,
|
||||||
value,
|
value,
|
||||||
|
@ -96,21 +99,20 @@ export const SliderElement: React.FC<Props> = ({
|
||||||
}
|
}
|
||||||
domain={[0, 200]}
|
domain={[0, 200]}
|
||||||
values={[value]}
|
values={[value]}
|
||||||
onChange={onChange}
|
onChange={(values) => onChange(values[0])}
|
||||||
>
|
>
|
||||||
<Rail>
|
<Rail>
|
||||||
{({ getRailProps }) => <div style={railStyle} {...getRailProps()} />}
|
{({ getRailProps }) => <div style={railStyle} {...getRailProps()} />}
|
||||||
</Rail>
|
</Rail>
|
||||||
<Handles>
|
<Handles>
|
||||||
{({ handles, getHandleProps }) => (
|
{({ handles, getHandleProps }) => (
|
||||||
<div className="slider-handles">
|
<div>
|
||||||
{handles.map((handle) => (
|
{handles.map((handle) => (
|
||||||
<Handle
|
<Handle
|
||||||
key={handle.id}
|
key={handle.id}
|
||||||
handle={handle}
|
handle={handle}
|
||||||
getHandleProps={getHandleProps}
|
getHandleProps={getHandleProps}
|
||||||
displayFunction={displayFunction}
|
displayFunction={displayFunction}
|
||||||
handleWidth={"15em"}
|
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
@ -118,7 +120,7 @@ export const SliderElement: React.FC<Props> = ({
|
||||||
</Handles>
|
</Handles>
|
||||||
<Tracks right={false}>
|
<Tracks right={false}>
|
||||||
{({ tracks, getTrackProps }) => (
|
{({ tracks, getTrackProps }) => (
|
||||||
<div className="slider-tracks">
|
<div>
|
||||||
{tracks.map(({ id, source, target }) => (
|
{tracks.map(({ id, source, target }) => (
|
||||||
<Track
|
<Track
|
||||||
key={id}
|
key={id}
|
||||||
|
|
|
@ -173,7 +173,7 @@ export const QuestionCard: React.FC<Props> = ({
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{question.platform.id === "guesstimate" && (
|
{question.platform.id === "guesstimate" && question.visualization && (
|
||||||
<img
|
<img
|
||||||
className="rounded-sm"
|
className="rounded-sm"
|
||||||
src={question.visualization}
|
src={question.visualization}
|
||||||
|
|
|
@ -74,7 +74,7 @@ const LargeQuestionCard: React.FC<{
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mb-8">
|
<div className="mb-8">
|
||||||
{question.platform.id === "guesstimate" ? (
|
{question.platform.id === "guesstimate" && question.visualization ? (
|
||||||
<a className="no-underline" href={question.url} target="_blank">
|
<a className="no-underline" href={question.url} target="_blank">
|
||||||
<img
|
<img
|
||||||
className="rounded-sm"
|
className="rounded-sm"
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { ChangeEvent } from "react";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
value: string;
|
value: string;
|
||||||
onChange: (v: string) => void;
|
onChange: (v: string) => void;
|
||||||
|
@ -9,7 +11,7 @@ export const QueryForm: React.FC<Props> = ({
|
||||||
onChange,
|
onChange,
|
||||||
placeholder,
|
placeholder,
|
||||||
}) => {
|
}) => {
|
||||||
const handleInputChange = (event) => {
|
const handleInputChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
onChange(event.target.value); // In this case, the query, e.g. "COVID.19"
|
onChange(event.target.value); // In this case, the query, e.g. "COVID.19"
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import React, { Fragment, useMemo, useState } from "react";
|
import React, { useMemo, useState } from "react";
|
||||||
import { useQuery } from "urql";
|
import { useQuery } from "urql";
|
||||||
|
|
||||||
import { PlatformConfig } from "../../../backend/platforms";
|
import { PlatformConfig } from "../../../backend/platforms";
|
||||||
|
@ -126,7 +126,8 @@ export const SearchScreen: React.FC<Props> = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateRoute = () => {
|
const updateRoute = () => {
|
||||||
const stringify = (key: string, value: any) => {
|
const stringify = (key: string, obj: { [k: string]: any }) => {
|
||||||
|
const value = obj[key];
|
||||||
if (key === "forecastingPlatforms") {
|
if (key === "forecastingPlatforms") {
|
||||||
return value.join("|");
|
return value.join("|");
|
||||||
} else {
|
} else {
|
||||||
|
@ -134,15 +135,16 @@ export const SearchScreen: React.FC<Props> = ({
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const query = {};
|
const query: { [k: string]: string } = {};
|
||||||
for (const key of Object.keys(defaultQueryParameters)) {
|
for (const key of Object.keys(defaultQueryParameters)) {
|
||||||
const value = stringify(key, queryParameters[key]);
|
const value = stringify(key, queryParameters);
|
||||||
const defaultValue = stringify(key, defaultQueryParameters[key]);
|
const defaultValue = stringify(key, defaultQueryParameters);
|
||||||
if (value === defaultValue) continue;
|
if (value === defaultValue) continue;
|
||||||
query[key] = value;
|
query[key] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (numDisplay !== defaultNumDisplay) query["numDisplay"] = numDisplay;
|
if (numDisplay !== defaultNumDisplay)
|
||||||
|
query["numDisplay"] = String(numDisplay);
|
||||||
|
|
||||||
router.replace(
|
router.replace(
|
||||||
{
|
{
|
||||||
|
@ -191,8 +193,8 @@ export const SearchScreen: React.FC<Props> = ({
|
||||||
(Math.round(value) === 1 ? "" : "s")
|
(Math.round(value) === 1 ? "" : "s")
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
const onChangeSliderForNumDisplay = (event) => {
|
const onChangeSliderForNumDisplay = (value: number) => {
|
||||||
setNumDisplay(Math.round(event[0]));
|
setNumDisplay(Math.round(value));
|
||||||
setForceSearch(forceSearch + 1); // FIXME - force new search iff numDisplay is greater than last search limit
|
setForceSearch(forceSearch + 1); // FIXME - force new search iff numDisplay is greater than last search limit
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -200,10 +202,10 @@ export const SearchScreen: React.FC<Props> = ({
|
||||||
const displayFunctionNumForecasts = (value: number) => {
|
const displayFunctionNumForecasts = (value: number) => {
|
||||||
return "# Forecasts > " + Math.round(value);
|
return "# Forecasts > " + Math.round(value);
|
||||||
};
|
};
|
||||||
const onChangeSliderForNumForecasts = (event) => {
|
const onChangeSliderForNumForecasts = (value: number) => {
|
||||||
setQueryParameters({
|
setQueryParameters({
|
||||||
...queryParameters,
|
...queryParameters,
|
||||||
forecastsThreshold: Math.round(event[0]),
|
forecastsThreshold: Math.round(value),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -230,7 +232,7 @@ export const SearchScreen: React.FC<Props> = ({
|
||||||
|
|
||||||
/* Final return */
|
/* Final return */
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<>
|
||||||
<label className="mb-4 mt-4 flex flex-row justify-center items-center">
|
<label className="mb-4 mt-4 flex flex-row justify-center items-center">
|
||||||
<div className="w-10/12 mb-2">
|
<div className="w-10/12 mb-2">
|
||||||
<QueryForm
|
<QueryForm
|
||||||
|
@ -317,6 +319,6 @@ export const SearchScreen: React.FC<Props> = ({
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</Fragment>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -36,5 +36,8 @@ export const getUrqlClientOptions = (ssr: SSRExchange) => ({
|
||||||
export const ssrUrql = () => {
|
export const ssrUrql = () => {
|
||||||
const ssrCache = ssrExchange({ isClient: false });
|
const ssrCache = ssrExchange({ isClient: false });
|
||||||
const client = initUrqlClient(getUrqlClientOptions(ssrCache), false);
|
const client = initUrqlClient(getUrqlClientOptions(ssrCache), false);
|
||||||
|
if (!client) {
|
||||||
|
throw new Error("Expected non-null client instance from initUrqlClient");
|
||||||
|
}
|
||||||
return [ssrCache, client] as const;
|
return [ssrCache, client] as const;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,18 +1,31 @@
|
||||||
import algoliasearch from "algoliasearch";
|
import algoliasearch from "algoliasearch";
|
||||||
|
|
||||||
|
import { Hit } from "@algolia/client-search";
|
||||||
|
|
||||||
import { AlgoliaQuestion } from "../../backend/utils/algolia";
|
import { AlgoliaQuestion } from "../../backend/utils/algolia";
|
||||||
|
|
||||||
const client = algoliasearch(
|
const client = algoliasearch(
|
||||||
process.env.NEXT_PUBLIC_ALGOLIA_APP_ID,
|
process.env.NEXT_PUBLIC_ALGOLIA_APP_ID || "",
|
||||||
process.env.NEXT_PUBLIC_ALGOLIA_SEARCH_KEY
|
process.env.NEXT_PUBLIC_ALGOLIA_SEARCH_KEY || ""
|
||||||
);
|
);
|
||||||
const index = client.initIndex("metaforecast");
|
const index = client.initIndex("metaforecast");
|
||||||
|
|
||||||
let buildFilter = ({
|
interface SearchOpts {
|
||||||
|
queryString: string;
|
||||||
|
hitsPerPage?: number;
|
||||||
|
starsThreshold: number;
|
||||||
|
filterByPlatforms: string[];
|
||||||
|
forecastsThreshold: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const buildFilter = ({
|
||||||
starsThreshold,
|
starsThreshold,
|
||||||
filterByPlatforms,
|
filterByPlatforms,
|
||||||
forecastsThreshold,
|
forecastsThreshold,
|
||||||
}) => {
|
}: Pick<
|
||||||
|
SearchOpts,
|
||||||
|
"starsThreshold" | "filterByPlatforms" | "forecastsThreshold"
|
||||||
|
>) => {
|
||||||
const starsFilter = starsThreshold
|
const starsFilter = starsThreshold
|
||||||
? `qualityindicators.stars >= ${starsThreshold}`
|
? `qualityindicators.stars >= ${starsThreshold}`
|
||||||
: null;
|
: null;
|
||||||
|
@ -35,26 +48,15 @@ let buildFilter = ({
|
||||||
return finalFilter;
|
return finalFilter;
|
||||||
};
|
};
|
||||||
|
|
||||||
let buildFacetFilter = ({ filterByPlatforms }) => {
|
const noExactMatch = (queryString: string, result: Hit<AlgoliaQuestion>) => {
|
||||||
let platformsFilter = [];
|
|
||||||
if (filterByPlatforms.length > 0) {
|
|
||||||
platformsFilter = [
|
|
||||||
[filterByPlatforms.map((platform) => `platform:${platform}`)],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
console.log(platformsFilter);
|
|
||||||
console.log(
|
|
||||||
"searchWithAlgolia.js/searchWithAlgolia/buildFacetFilter",
|
|
||||||
platformsFilter
|
|
||||||
);
|
|
||||||
return platformsFilter;
|
|
||||||
};
|
|
||||||
|
|
||||||
let noExactMatch = (queryString, result) => {
|
|
||||||
queryString = queryString.toLowerCase();
|
queryString = queryString.toLowerCase();
|
||||||
let title = result.title.toLowerCase();
|
|
||||||
let description = result.description.toLowerCase();
|
const title = result.title.toLowerCase();
|
||||||
let optionsstringforsearch = result.optionsstringforsearch.toLowerCase();
|
const description = result.description.toLowerCase();
|
||||||
|
const optionsstringforsearch = (
|
||||||
|
result.optionsstringforsearch || ""
|
||||||
|
).toLowerCase();
|
||||||
|
|
||||||
return !(
|
return !(
|
||||||
title.includes(queryString) ||
|
title.includes(queryString) ||
|
||||||
description.includes(queryString) ||
|
description.includes(queryString) ||
|
||||||
|
@ -62,14 +64,6 @@ let noExactMatch = (queryString, result) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
interface SearchOpts {
|
|
||||||
queryString: string;
|
|
||||||
hitsPerPage?: number;
|
|
||||||
starsThreshold: number;
|
|
||||||
filterByPlatforms: string[];
|
|
||||||
forecastsThreshold: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
// only query string
|
// only query string
|
||||||
export default async function searchWithAlgolia({
|
export default async function searchWithAlgolia({
|
||||||
queryString,
|
queryString,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user