refactor: some typescript improvements

This commit is contained in:
Vyacheslav Matyukhin 2022-05-09 21:37:28 +04:00
parent 44fbd0cd2b
commit 439a9045da
No known key found for this signature in database
GPG Key ID: 3D2A774C5489F96C
12 changed files with 79 additions and 74 deletions

View File

@ -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);
} }

View File

@ -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) {

View File

@ -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: {

View File

@ -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 => {

View File

@ -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);
}; };

View File

@ -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}

View File

@ -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}

View File

@ -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"

View File

@ -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"
}; };

View File

@ -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> </>
); );
}; };

View File

@ -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;
}; };

View File

@ -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,