refactor: rename forecast -> question (see #40)

This commit is contained in:
Vyacheslav Matyukhin 2022-04-13 00:47:06 +03:00
parent 2ee82cdd15
commit 6543a729f3
No known key found for this signature in database
GPG Key ID: 3D2A774C5489F96C
31 changed files with 190 additions and 196 deletions

View File

@ -13,7 +13,7 @@
# React # React
- create one file per one component (tiny helper components in the same file are fine) - create one file per one component (tiny helper components in the same file are fine)
- name file identically to the component it describes (e.g. `const DisplayForecasts: React.FC<Props> = ...` in `DisplayForecasts.ts`) - name file identically to the component it describes (e.g. `const DisplayQuestions: React.FC<Props> = ...` in `DisplayQuestions.ts`)
- use named export instead of default export for all React components - use named export instead of default export for all React components
- it's better for refactoring - it's better for refactoring
- and it plays well with `React.FC` typing - and it plays well with `React.FC` typing

View File

@ -1,13 +1,13 @@
import { Pool, PoolClient } from "pg"; import { Pool, PoolClient } from "pg";
import { Forecast } from "../platforms"; import { Question } from "../platforms";
import { hash } from "../utils/hash"; import { hash } from "../utils/hash";
import { measureTime } from "../utils/measureTime"; import { measureTime } from "../utils/measureTime";
import { roughSizeOfObject } from "../utils/roughSize"; import { roughSizeOfObject } from "../utils/roughSize";
const forecastTableNames = ["questions", "history"]; const questionTableNames = ["questions", "history"];
const allTableNames = [...forecastTableNames, "dashboards", "frontpage"]; const allTableNames = [...questionTableNames, "dashboards", "frontpage"];
/* Postgres database connection code */ /* Postgres database connection code */
const databaseURL = process.env.DIGITALOCEAN_POSTGRES; const databaseURL = process.env.DIGITALOCEAN_POSTGRES;
@ -51,11 +51,11 @@ export async function pgBulkInsert({
tableName, tableName,
client, client,
}: { }: {
data: Forecast[]; data: Question[];
tableName: string; tableName: string;
client: PoolClient; client: PoolClient;
}) { }) {
if (!forecastTableNames.includes(tableName)) { if (!questionTableNames.includes(tableName)) {
throw Error( throw Error(
`Table ${tableName} not in whitelist; stopping to avoid tricky sql injections` `Table ${tableName} not in whitelist; stopping to avoid tricky sql injections`
); );
@ -171,11 +171,11 @@ export async function pgUpsert({
tableName, tableName,
replacePlatform, replacePlatform,
}: { }: {
contents: Forecast[]; contents: Question[];
tableName: string; tableName: string;
replacePlatform?: string; replacePlatform?: string;
}) { }) {
if (!forecastTableNames.includes(tableName)) { if (!questionTableNames.includes(tableName)) {
throw Error( throw Error(
`Table ${tableName} not in whitelist; stopping to avoid tricky sql injections` `Table ${tableName} not in whitelist; stopping to avoid tricky sql injections`
); );

View File

@ -1,7 +1,7 @@
import { pgRead, pool } from "./database/pg-wrapper"; import { pgRead, pool } from "./database/pg-wrapper";
import { Forecast } from "./platforms"; import { Question } from "./platforms";
export async function getFrontpage(): Promise<Forecast[]> { export async function getFrontpage(): Promise<Question[]> {
const res = await pool.query( const res = await pool.query(
"SELECT frontpage_sliced FROM frontpage ORDER BY id DESC LIMIT 1" "SELECT frontpage_sliced FROM frontpage ORDER BY id DESC LIMIT 1"
); );
@ -9,7 +9,7 @@ export async function getFrontpage(): Promise<Forecast[]> {
return res.rows[0].frontpage_sliced; return res.rows[0].frontpage_sliced;
} }
export async function getFrontpageFull(): Promise<Forecast[]> { export async function getFrontpageFull(): Promise<Question[]> {
const res = await pool.query( const res = await pool.query(
"SELECT frontpage_full FROM frontpage ORDER BY id DESC LIMIT 1" "SELECT frontpage_full FROM frontpage ORDER BY id DESC LIMIT 1"
); );

View File

@ -3,7 +3,7 @@ import axios from "axios";
import https from "https"; import https from "https";
import { calculateStars } from "../utils/stars"; import { calculateStars } from "../utils/stars";
import { Forecast, Platform } from "./"; import { Platform, Question } from "./";
const platformName = "betfair"; const platformName = "betfair";
@ -80,7 +80,7 @@ async function whipIntoShape(data) {
async function processPredictions(data) { async function processPredictions(data) {
let predictions = await whipIntoShape(data); let predictions = await whipIntoShape(data);
// console.log(JSON.stringify(predictions, null, 4)) // console.log(JSON.stringify(predictions, null, 4))
let results: Forecast[] = predictions.map((prediction) => { let results: Question[] = predictions.map((prediction) => {
/* if(Math.floor(Math.random() * 10) % 20 ==0){ /* if(Math.floor(Math.random() * 10) % 20 ==0){
console.log(JSON.stringify(prediction, null, 4)) console.log(JSON.stringify(prediction, null, 4))
} */ } */

View File

@ -2,7 +2,7 @@
import axios from "axios"; import axios from "axios";
import { calculateStars } from "../utils/stars"; import { calculateStars } from "../utils/stars";
import { Forecast, Platform } from "./"; import { Platform, Question } from "./";
const platformName = "fantasyscotus"; const platformName = "fantasyscotus";
@ -67,7 +67,7 @@ async function processData(data) {
let historicalPercentageCorrect = data.stats.pcnt_correct; let historicalPercentageCorrect = data.stats.pcnt_correct;
let historicalProbabilityCorrect = let historicalProbabilityCorrect =
Number(historicalPercentageCorrect.replace("%", "")) / 100; Number(historicalPercentageCorrect.replace("%", "")) / 100;
let results: Forecast[] = []; let results: Question[] = [];
for (let event of events) { for (let event of events) {
if (event.accuracy == "") { if (event.accuracy == "") {
let id = `${platformName}-${event.id}`; let id = `${platformName}-${event.id}`;
@ -75,7 +75,7 @@ async function processData(data) {
let predictionData = await getPredictionsData(event.docket_url); let predictionData = await getPredictionsData(event.docket_url);
let pAffirm = predictionData.proportionAffirm; let pAffirm = predictionData.proportionAffirm;
//let trackRecord = event.prediction.includes("Affirm") ? historicalProbabilityCorrect : 1-historicalProbabilityCorrect //let trackRecord = event.prediction.includes("Affirm") ? historicalProbabilityCorrect : 1-historicalProbabilityCorrect
let eventObject: Forecast = { let eventObject: Question = {
id: id, id: id,
title: `In ${event.short_name}, the SCOTUS will affirm the lower court's decision`, title: `In ${event.short_name}, the SCOTUS will affirm the lower court's decision`,
url: `https://fantasyscotus.net/user-predictions${event.docket_url}`, url: `https://fantasyscotus.net/user-predictions${event.docket_url}`,

View File

@ -16,7 +16,7 @@ import { smarkets } from "./smarkets";
import { wildeford } from "./wildeford"; import { wildeford } from "./wildeford";
import { xrisk } from "./xrisk"; import { xrisk } from "./xrisk";
export interface Forecast { export interface Question {
id: string; id: string;
// "fantasyscotus-580" // "fantasyscotus-580"
@ -63,8 +63,8 @@ export interface Forecast {
extra?: any; extra?: any;
} }
// fetcher should return null if platform failed to fetch forecasts for some reason // fetcher should return null if platform failed to fetch questions for some reason
export type PlatformFetcher = () => Promise<Forecast[] | null>; export type PlatformFetcher = () => Promise<Question[] | null>;
export interface Platform { export interface Platform {
name: string; // short name for ids and `platform` db column, e.g. "xrisk" name: string; // short name for ids and `platform` db column, e.g. "xrisk"
@ -76,7 +76,7 @@ export interface Platform {
// draft for the future callback-based streaming/chunking API: // draft for the future callback-based streaming/chunking API:
// interface FetchOptions { // interface FetchOptions {
// since?: string; // some kind of cursor, Date object or opaque string? // since?: string; // some kind of cursor, Date object or opaque string?
// save: (forecasts: Forecast[]) => Promise<void>; // save: (questions: Question[]) => Promise<void>;
// } // }
// export type PlatformFetcher = (options: FetchOptions) => Promise<void>; // export type PlatformFetcher = (options: FetchOptions) => Promise<void>;

View File

@ -1,12 +1,11 @@
/* Imports */ /* Imports */
import axios from "axios"; import axios from "axios";
import { Tabletojson } from "tabletojson";
import { applyIfSecretExists } from "../utils/getSecrets"; import { applyIfSecretExists } from "../utils/getSecrets";
import { measureTime } from "../utils/measureTime"; import { measureTime } from "../utils/measureTime";
import { calculateStars } from "../utils/stars"; import { calculateStars } from "../utils/stars";
import toMarkdown from "../utils/toMarkdown"; import toMarkdown from "../utils/toMarkdown";
import { Forecast, Platform } from "./"; import { Platform, Question } from "./";
/* Definitions */ /* Definitions */
const platformName = "infer"; const platformName = "infer";
@ -78,12 +77,12 @@ async function fetchStats(questionUrl, cookie) {
let comments_count = firstEmbeddedJson.question.comments_count; let comments_count = firstEmbeddedJson.question.comments_count;
let numforecasters = firstEmbeddedJson.question.predictors_count; let numforecasters = firstEmbeddedJson.question.predictors_count;
let numforecasts = firstEmbeddedJson.question.prediction_sets_count; let numforecasts = firstEmbeddedJson.question.prediction_sets_count;
let forecastType = firstEmbeddedJson.question.type; let questionType = firstEmbeddedJson.question.type;
if ( if (
forecastType.includes("Binary") || questionType.includes("Binary") ||
forecastType.includes("NonExclusiveOpinionPoolQuestion") || questionType.includes("NonExclusiveOpinionPoolQuestion") ||
forecastType.includes("Forecast::Question") || questionType.includes("Forecast::Question") ||
!forecastType.includes("Forecast::MultiTimePeriodQuestion") !questionType.includes("Forecast::MultiTimePeriodQuestion")
) { ) {
options = firstEmbeddedJson.question.answers.map((answer) => ({ options = firstEmbeddedJson.question.answers.map((answer) => ({
name: answer.name, name: answer.name,
@ -148,7 +147,7 @@ function sleep(ms) {
async function infer_inner(cookie: string) { async function infer_inner(cookie: string) {
let i = 1; let i = 1;
let response = await fetchPage(i, cookie); let response = await fetchPage(i, cookie);
let results: Forecast[] = []; let results: Question[] = [];
await measureTime(async () => { await measureTime(async () => {
// console.log("Downloading... This might take a couple of minutes. Results will be shown.") // console.log("Downloading... This might take a couple of minutes. Results will be shown.")
@ -179,7 +178,7 @@ async function infer_inner(cookie: string) {
let questionNumRegex = new RegExp("questions/([0-9]+)"); let questionNumRegex = new RegExp("questions/([0-9]+)");
let questionNum = url.match(questionNumRegex)[1]; //.split("questions/")[1].split("-")[0]; let questionNum = url.match(questionNumRegex)[1]; //.split("questions/")[1].split("-")[0];
let id = `${platformName}-${questionNum}`; let id = `${platformName}-${questionNum}`;
let question: Forecast = { let question: Question = {
id: id, id: id,
title: title, title: title,
description: moreinfo.description, description: moreinfo.description,

View File

@ -2,7 +2,7 @@
import axios from "axios"; import axios from "axios";
import { calculateStars } from "../utils/stars"; import { calculateStars } from "../utils/stars";
import { Forecast, Platform } from "./"; import { Platform, Question } from "./";
/* Definitions */ /* Definitions */
const platformName = "manifold"; const platformName = "manifold";
@ -23,7 +23,7 @@ async function fetchData() {
return response; return response;
} }
function showStatistics(results: Forecast[]) { function showStatistics(results: Question[]) {
console.log(`Num unresolved markets: ${results.length}`); console.log(`Num unresolved markets: ${results.length}`);
let sum = (arr) => arr.reduce((tally, a) => tally + a, 0); let sum = (arr) => arr.reduce((tally, a) => tally + a, 0);
let num2StarsOrMore = results.filter( let num2StarsOrMore = results.filter(
@ -44,7 +44,7 @@ function showStatistics(results: Forecast[]) {
} }
async function processPredictions(predictions) { async function processPredictions(predictions) {
let results: Forecast[] = await predictions.map((prediction) => { let results: Question[] = await predictions.map((prediction) => {
let id = `${platformName}-${prediction.id}`; // oops, doesn't match platform name let id = `${platformName}-${prediction.id}`; // oops, doesn't match platform name
let probability = prediction.probability; let probability = prediction.probability;
let options = [ let options = [
@ -59,7 +59,7 @@ async function processPredictions(predictions) {
type: "PROBABILITY", type: "PROBABILITY",
}, },
]; ];
const result: Forecast = { const result: Question = {
id: id, id: id,
title: prediction.question, title: prediction.question,
url: prediction.url, url: prediction.url,

View File

@ -2,7 +2,7 @@
import axios from "axios"; import axios from "axios";
import { calculateStars } from "../utils/stars"; import { calculateStars } from "../utils/stars";
import { Forecast, Platform } from "./"; import { Platform, Question } from "./";
/* Definitions */ /* Definitions */
const platformName = "polymarket"; const platformName = "polymarket";
@ -68,7 +68,7 @@ export const polymarket: Platform = {
label: "PolyMarket", label: "PolyMarket",
color: "#00314e", color: "#00314e",
async fetcher() { async fetcher() {
let results: Forecast[] = []; let results: Question[] = [];
let webpageEndpointData = await fetchAllContractInfo(); let webpageEndpointData = await fetchAllContractInfo();
for (let marketInfo of webpageEndpointData) { for (let marketInfo of webpageEndpointData) {
let address = marketInfo.marketMakerAddress; let address = marketInfo.marketMakerAddress;
@ -102,7 +102,7 @@ export const polymarket: Platform = {
}); });
} }
let result: Forecast = { let result: Question = {
id: id, id: id,
title: marketInfo.question, title: marketInfo.question,
url: "https://polymarket.com/market/" + marketInfo.slug, url: "https://polymarket.com/market/" + marketInfo.slug,

View File

@ -3,7 +3,7 @@ import { JSDOM } from "jsdom";
import { calculateStars } from "../utils/stars"; import { calculateStars } from "../utils/stars";
import toMarkdown from "../utils/toMarkdown"; import toMarkdown from "../utils/toMarkdown";
import { Forecast, Platform } from "./"; import { Platform, Question } from "./";
const platformName = "rootclaim"; const platformName = "rootclaim";
const jsonEndpoint = const jsonEndpoint =
@ -50,7 +50,7 @@ export const rootclaim: Platform = {
color: "#0d1624", color: "#0d1624",
async fetcher() { async fetcher() {
const claims = await fetchAllRootclaims(); const claims = await fetchAllRootclaims();
const results: Forecast[] = []; const results: Question[] = [];
for (const claim of claims) { for (const claim of claims) {
const id = `${platformName}-${claim.slug.toLowerCase()}`; const id = `${platformName}-${claim.slug.toLowerCase()}`;
@ -71,7 +71,7 @@ export const rootclaim: Platform = {
const description = await fetchDescription(url, claim.isclaim); const description = await fetchDescription(url, claim.isclaim);
let obj: Forecast = { let obj: Question = {
id, id,
title: toMarkdown(claim.question).replace("\n", ""), title: toMarkdown(claim.question).replace("\n", ""),
url, url,

View File

@ -1,7 +1,7 @@
import axios from "axios"; import axios from "axios";
import { calculateStars } from "../utils/stars"; import { calculateStars } from "../utils/stars";
import { Forecast, Platform } from "./"; import { Platform, Question } from "./";
/* Definitions */ /* Definitions */
const platformName = "smarkets"; const platformName = "smarkets";
@ -159,7 +159,7 @@ export const smarkets: Platform = {
name = name+ (contractName=="Yes"?'':` (${contracts["contracts"][0].name})`) name = name+ (contractName=="Yes"?'':` (${contracts["contracts"][0].name})`)
} }
*/ */
let result: Forecast = { let result: Question = {
id: id, id: id,
title: name, title: name,
url: "https://smarkets.com/event/" + market.event_id + market.slug, url: "https://smarkets.com/event/" + market.event_id + market.slug,

View File

@ -8,14 +8,14 @@ import { pgRead } from "../../database/pg-wrapper";
/* Utilities */ /* Utilities */
/* Support functions */ /* Support functions */
let getQualityIndicators = (forecast) => const getQualityIndicators = (question) =>
Object.entries(forecast.qualityindicators) Object.entries(question.qualityindicators)
.map((entry) => `${entry[0]}: ${entry[1]}`) .map((entry) => `${entry[0]}: ${entry[1]}`)
.join("; "); .join("; ");
/* Body */ /* Body */
let main = async () => { const main = async () => {
let highQualityPlatforms = [ let highQualityPlatforms = [
"CSET-foretell", "CSET-foretell",
"Foretold", "Foretold",
@ -24,21 +24,21 @@ let main = async () => {
"PredictIt", "PredictIt",
"Rootclaim", "Rootclaim",
]; ];
let json = await pgRead({ tableName: "questions" }); const json = await pgRead({ tableName: "questions" });
console.log(json.length); console.log(json.length);
//let uniquePlatforms = [...new Set(json.map(forecast => forecast.platform))] //let uniquePlatforms = [...new Set(json.map(forecast => forecast.platform))]
//console.log(uniquePlatforms) //console.log(uniquePlatforms)
let forecastsFromGoodPlatforms = json.filter((forecast) => const questionsFromGoodPlatforms = json.filter((question) =>
highQualityPlatforms.includes(forecast.platform) highQualityPlatforms.includes(question.platform)
); );
let tsv = const tsv =
"index\ttitle\turl\tqualityindicators\n" + "index\ttitle\turl\tqualityindicators\n" +
forecastsFromGoodPlatforms questionsFromGoodPlatforms
.map((forecast, index) => { .map((question, index) => {
let row = `${index}\t${forecast.title}\t${ let row = `${index}\t${question.title}\t${
forecast.url question.url
}\t${getQualityIndicators(forecast)}`; }\t${getQualityIndicators(question)}`;
console.log(row); console.log(row);
return row; return row;
}) })

View File

@ -8,8 +8,8 @@ import { pgRead } from "../../database/pg-wrapper";
/* Utilities */ /* Utilities */
/* Support functions */ /* Support functions */
let getQualityIndicators = (forecast) => let getQualityIndicators = (question) =>
Object.entries(forecast.qualityindicators) Object.entries(question.qualityindicators)
.map((entry) => `${entry[0]}: ${entry[1]}`) .map((entry) => `${entry[0]}: ${entry[1]}`)
.join("; "); .join("; ");
@ -28,22 +28,22 @@ let main = async () => {
let highQualityPlatforms = ["Metaculus"]; // ['CSET-foretell', 'Foretold', 'Good Judgment Open', 'Metaculus', 'PredictIt', 'Rootclaim'] let highQualityPlatforms = ["Metaculus"]; // ['CSET-foretell', 'Foretold', 'Good Judgment Open', 'Metaculus', 'PredictIt', 'Rootclaim']
let json = await pgRead({ tableName: "questions" }); let json = await pgRead({ tableName: "questions" });
console.log(json.length); console.log(json.length);
//let uniquePlatforms = [...new Set(json.map(forecast => forecast.platform))] //let uniquePlatforms = [...new Set(json.map(question => question.platform))]
//console.log(uniquePlatforms) //console.log(uniquePlatforms)
let forecastsFromGoodPlatforms = json.filter((forecast) => let questionsFromGoodPlatforms = json.filter((question) =>
highQualityPlatforms.includes(forecast.platform) highQualityPlatforms.includes(question.platform)
); );
let forecastsFromGoodPlatformsShuffled = shuffleArray( let questionsFromGoodPlatformsShuffled = shuffleArray(
forecastsFromGoodPlatforms questionsFromGoodPlatforms
); );
let tsv = let tsv =
"index\ttitle\turl\tqualityindicators\n" + "index\ttitle\turl\tqualityindicators\n" +
forecastsFromGoodPlatforms questionsFromGoodPlatforms
.map((forecast, index) => { .map((question, index) => {
let row = `${index}\t${forecast.title}\t${ let row = `${index}\t${question.title}\t${
forecast.url question.url
}\t${getQualityIndicators(forecast)}`; }\t${getQualityIndicators(question)}`;
console.log(row); console.log(row);
return row; return row;
}) })

View File

@ -1,7 +1,7 @@
import { NextPage } from "next"; import { NextPage } from "next";
import React from "react"; import React from "react";
import { displayForecastsWrapperForCapture } from "../web/display/displayForecastsWrappers"; import { displayQuestionsWrapperForCapture } from "../web/display/displayQuestionsWrappers";
import { Layout } from "../web/display/Layout"; import { Layout } from "../web/display/Layout";
import { Props } from "../web/search/anySearchPage"; import { Props } from "../web/search/anySearchPage";
import CommonDisplay from "../web/search/CommonDisplay"; import CommonDisplay from "../web/search/CommonDisplay";
@ -18,7 +18,7 @@ const CapturePage: NextPage<Props> = (props) => {
hasAdvancedOptions={false} hasAdvancedOptions={false}
placeholder={"Get best title match..."} placeholder={"Get best title match..."}
displaySeeMoreHint={false} displaySeeMoreHint={false}
displayForecastsWrapper={displayForecastsWrapperForCapture} displayQuestionsWrapper={displayQuestionsWrapperForCapture}
/> />
</Layout> </Layout>
); );

View File

@ -2,13 +2,13 @@ import { GetServerSideProps, NextPage } from "next";
import Error from "next/error"; import Error from "next/error";
import { DashboardItem } from "../../../backend/dashboards"; import { DashboardItem } from "../../../backend/dashboards";
import { DisplayForecasts } from "../../../web/display/DisplayForecasts"; import { DisplayQuestions } from "../../../web/display/DisplayQuestions";
import { FrontendForecast } from "../../../web/platforms"; import { FrontendQuestion } from "../../../web/platforms";
import { getDashboardForecastsByDashboardId } from "../../../web/worker/getDashboardForecasts";
import { reqToBasePath } from "../../../web/utils"; import { reqToBasePath } from "../../../web/utils";
import { getDashboardQuestionsByDashboardId } from "../../../web/worker/getDashboardQuestions";
interface Props { interface Props {
dashboardForecasts: FrontendForecast[]; dashboardQuestions: FrontendQuestion[];
dashboardItem: DashboardItem; dashboardItem: DashboardItem;
numCols?: number; numCols?: number;
} }
@ -19,8 +19,8 @@ export const getServerSideProps: GetServerSideProps<Props> = async (
const dashboardId = context.query.id as string; const dashboardId = context.query.id as string;
const numCols = Number(context.query.numCols); const numCols = Number(context.query.numCols);
const { dashboardItem, dashboardForecasts } = const { dashboardItem, dashboardQuestions } =
await getDashboardForecastsByDashboardId({ await getDashboardQuestionsByDashboardId({
dashboardId, dashboardId,
basePath: reqToBasePath(context.req), // required on server side to find the API endpoint basePath: reqToBasePath(context.req), // required on server side to find the API endpoint
}); });
@ -31,7 +31,7 @@ export const getServerSideProps: GetServerSideProps<Props> = async (
return { return {
props: { props: {
dashboardForecasts, dashboardQuestions,
dashboardItem, dashboardItem,
numCols: !numCols ? null : numCols < 5 ? numCols : 4, numCols: !numCols ? null : numCols < 5 ? numCols : 4,
}, },
@ -39,7 +39,7 @@ export const getServerSideProps: GetServerSideProps<Props> = async (
}; };
const EmbedDashboardPage: NextPage<Props> = ({ const EmbedDashboardPage: NextPage<Props> = ({
dashboardForecasts, dashboardQuestions,
dashboardItem, dashboardItem,
numCols, numCols,
}) => { }) => {
@ -57,9 +57,9 @@ const EmbedDashboardPage: NextPage<Props> = ({
numCols || 3 numCols || 3
} gap-4 mb-6`} } gap-4 mb-6`}
> >
<DisplayForecasts <DisplayQuestions
results={dashboardForecasts} results={dashboardQuestions}
numDisplay={dashboardForecasts.length} numDisplay={dashboardQuestions.length}
showIdToggle={false} showIdToggle={false}
/> />
</div> </div>

View File

@ -3,16 +3,16 @@ import Error from "next/error";
import Link from "next/link"; import Link from "next/link";
import { DashboardItem } from "../../../backend/dashboards"; import { DashboardItem } from "../../../backend/dashboards";
import { DisplayForecasts } from "../../../web/display/DisplayForecasts"; import { DisplayQuestions } from "../../../web/display/DisplayQuestions";
import { InfoBox } from "../../../web/display/InfoBox"; import { InfoBox } from "../../../web/display/InfoBox";
import { Layout } from "../../../web/display/Layout"; import { Layout } from "../../../web/display/Layout";
import { LineHeader } from "../../../web/display/LineHeader"; import { LineHeader } from "../../../web/display/LineHeader";
import { FrontendForecast } from "../../../web/platforms"; import { FrontendQuestion } from "../../../web/platforms";
import { reqToBasePath } from "../../../web/utils"; import { reqToBasePath } from "../../../web/utils";
import { getDashboardForecastsByDashboardId } from "../../../web/worker/getDashboardForecasts"; import { getDashboardQuestionsByDashboardId } from "../../../web/worker/getDashboardQuestions";
interface Props { interface Props {
dashboardForecasts: FrontendForecast[]; dashboardQuestions: FrontendQuestion[];
dashboardItem: DashboardItem; dashboardItem: DashboardItem;
} }
@ -21,8 +21,8 @@ export const getServerSideProps: GetServerSideProps<Props> = async (
) => { ) => {
const dashboardId = context.query.id as string; const dashboardId = context.query.id as string;
const { dashboardForecasts, dashboardItem } = const { dashboardQuestions, dashboardItem } =
await getDashboardForecastsByDashboardId({ await getDashboardQuestionsByDashboardId({
dashboardId, dashboardId,
basePath: reqToBasePath(context.req), // required on server side to find the API endpoint basePath: reqToBasePath(context.req), // required on server side to find the API endpoint
}); });
@ -33,7 +33,7 @@ export const getServerSideProps: GetServerSideProps<Props> = async (
return { return {
props: { props: {
dashboardForecasts, dashboardQuestions,
dashboardItem, dashboardItem,
}, },
}; };
@ -78,7 +78,7 @@ const DashboardMetadata: React.FC<{ dashboardItem: DashboardItem }> = ({
/* Body */ /* Body */
const ViewDashboardPage: NextPage<Props> = ({ const ViewDashboardPage: NextPage<Props> = ({
dashboardForecasts, dashboardQuestions,
dashboardItem, dashboardItem,
}) => { }) => {
return ( return (
@ -91,9 +91,9 @@ const ViewDashboardPage: NextPage<Props> = ({
)} )}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
<DisplayForecasts <DisplayQuestions
results={dashboardForecasts} results={dashboardQuestions}
numDisplay={dashboardForecasts.length} numDisplay={dashboardQuestions.length}
showIdToggle={false} showIdToggle={false}
/> />
</div> </div>

View File

@ -1,7 +1,7 @@
import { NextPage } from "next"; import { NextPage } from "next";
import React from "react"; import React from "react";
import { displayForecastsWrapperForSearch } from "../web/display/displayForecastsWrappers"; import { displayQuestionsWrapperForSearch } from "../web/display/displayQuestionsWrappers";
import { Layout } from "../web/display/Layout"; import { Layout } from "../web/display/Layout";
import { Props } from "../web/search/anySearchPage"; import { Props } from "../web/search/anySearchPage";
import CommonDisplay from "../web/search/CommonDisplay"; import CommonDisplay from "../web/search/CommonDisplay";
@ -18,7 +18,7 @@ const IndexPage: NextPage<Props> = (props) => {
hasAdvancedOptions={true} hasAdvancedOptions={true}
placeholder={"Find forecasts about..."} placeholder={"Find forecasts about..."}
displaySeeMoreHint={true} displaySeeMoreHint={true}
displayForecastsWrapper={displayForecastsWrapperForSearch} displayQuestionsWrapper={displayQuestionsWrapperForSearch}
/> />
</Layout> </Layout>
); );

View File

@ -4,12 +4,12 @@ import { GetServerSideProps, NextPage } from "next";
import React from "react"; import React from "react";
import { platforms } from "../backend/platforms"; import { platforms } from "../backend/platforms";
import { DisplayForecast } from "../web/display/DisplayForecast"; import { DisplayQuestion } from "../web/display/DisplayQuestion";
import { FrontendForecast } from "../web/platforms"; import { FrontendQuestion } from "../web/platforms";
import searchAccordingToQueryData from "../web/worker/searchAccordingToQueryData"; import searchAccordingToQueryData from "../web/worker/searchAccordingToQueryData";
interface Props { interface Props {
results: FrontendForecast[]; results: FrontendQuestion[];
} }
export const getServerSideProps: GetServerSideProps<Props> = async ( export const getServerSideProps: GetServerSideProps<Props> = async (
@ -25,7 +25,7 @@ export const getServerSideProps: GetServerSideProps<Props> = async (
...urlQuery, ...urlQuery,
}; };
let results: FrontendForecast[] = []; let results: FrontendQuestion[] = [];
if (initialQueryParameters.query != "") { if (initialQueryParameters.query != "") {
results = await searchAccordingToQueryData(initialQueryParameters, 1); results = await searchAccordingToQueryData(initialQueryParameters, 1);
} }
@ -46,8 +46,8 @@ const SecretEmbedPage: NextPage<Props> = ({ results }) => {
<div> <div>
<div id="secretEmbed"> <div id="secretEmbed">
{result ? ( {result ? (
<DisplayForecast <DisplayQuestion
forecast={result} question={result}
showTimeStamp={true} showTimeStamp={true}
expandFooterToFullWidth={true} expandFooterToFullWidth={true}
/> />

View File

@ -1,38 +0,0 @@
import React from "react";
import { FrontendForecast } from "../platforms";
import { DisplayForecast } from "./DisplayForecast";
interface Props {
results: FrontendForecast[];
numDisplay: number;
showIdToggle: boolean;
}
export const DisplayForecasts: React.FC<Props> = ({
results,
numDisplay,
showIdToggle,
}) => {
if (!results) {
return <></>;
}
return (
<>
{results.slice(0, numDisplay).map((result) => (
/*let displayWithMetaculusCapture =
fuseSearchResult.item.platform == "Metaculus"
? metaculusEmbed(fuseSearchResult.item)
: displayForecast({ ...fuseSearchResult.item });
*/
<DisplayForecast
key={result.id}
forecast={result}
showTimeStamp={false}
expandFooterToFullWidth={false}
showIdToggle={showIdToggle}
/>
))}
</>
);
};

View File

@ -2,16 +2,16 @@ import domtoimage from "dom-to-image"; // https://github.com/tsayen/dom-to-image
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { CopyToClipboard } from "react-copy-to-clipboard"; import { CopyToClipboard } from "react-copy-to-clipboard";
import { FrontendForecast } from "../platforms"; import { FrontendQuestion } from "../platforms";
import { uploadToImgur } from "../worker/uploadToImgur"; import { uploadToImgur } from "../worker/uploadToImgur";
import { DisplayForecast } from "./DisplayForecast"; import { DisplayQuestion } from "./DisplayQuestion";
function displayOneForecastInner(result: FrontendForecast, containerRef) { function displayOneQuestionInner(result: FrontendQuestion, containerRef) {
return ( return (
<div ref={containerRef}> <div ref={containerRef}>
{result ? ( {result ? (
<DisplayForecast <DisplayQuestion
forecast={result} question={result}
showTimeStamp={true} showTimeStamp={true}
expandFooterToFullWidth={true} expandFooterToFullWidth={true}
/> />
@ -168,10 +168,10 @@ let generateMetaculusSource = (result, hasDisplayBeenCaptured) => {
}; };
interface Props { interface Props {
result: FrontendForecast; result: FrontendQuestion;
} }
export const DisplayOneForecastForCapture: React.FC<Props> = ({ result }) => { export const DisplayOneQuestionForCapture: React.FC<Props> = ({ result }) => {
const [hasDisplayBeenCaptured, setHasDisplayBeenCaptured] = useState(false); const [hasDisplayBeenCaptured, setHasDisplayBeenCaptured] = useState(false);
useEffect(() => { useEffect(() => {
@ -226,7 +226,7 @@ export const DisplayOneForecastForCapture: React.FC<Props> = ({ result }) => {
return ( return (
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 w-full justify-center"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4 w-full justify-center">
<div className="flex col-span-1 items-center justify-center"> <div className="flex col-span-1 items-center justify-center">
{displayOneForecastInner(result, containerRef)} {displayOneQuestionInner(result, containerRef)}
</div> </div>
<div className="flex col-span-1 items-center justify-center"> <div className="flex col-span-1 items-center justify-center">
{generateCaptureButton(result, onCaptureButtonClick)} {generateCaptureButton(result, onCaptureButtonClick)}

View File

@ -243,7 +243,7 @@ interface Props {
expandFooterToFullWidth: boolean; expandFooterToFullWidth: boolean;
} }
export const ForecastFooter: React.FC<Props> = ({ export const QuestionFooter: React.FC<Props> = ({
stars, stars,
platform, platform,
platformLabel, platformLabel,

View File

@ -1,9 +1,9 @@
import { FaRegClipboard } from "react-icons/fa"; import { FaRegClipboard } from "react-icons/fa";
import ReactMarkdown from "react-markdown"; import ReactMarkdown from "react-markdown";
import { FrontendForecast } from "../../platforms"; import { FrontendQuestion } from "../../platforms";
import { Card } from "../Card"; import { Card } from "../Card";
import { ForecastFooter } from "./ForecastFooter"; import { QuestionFooter } from "./QuestionFooter";
const truncateText = (length: number, text: string): string => { const truncateText = (length: number, text: string): string => {
if (!text) { if (!text) {
@ -268,14 +268,14 @@ const LastUpdated: React.FC<{ timestamp: string }> = ({ timestamp }) => (
// Main component // Main component
interface Props { interface Props {
forecast: FrontendForecast; question: FrontendQuestion;
showTimeStamp: boolean; showTimeStamp: boolean;
expandFooterToFullWidth: boolean; expandFooterToFullWidth: boolean;
showIdToggle?: boolean; showIdToggle?: boolean;
} }
export const DisplayForecast: React.FC<Props> = ({ export const DisplayQuestion: React.FC<Props> = ({
forecast: { question: {
id, id,
title, title,
url, url,
@ -372,7 +372,7 @@ export const DisplayForecast: React.FC<Props> = ({
<LastUpdated timestamp={timestamp} /> <LastUpdated timestamp={timestamp} />
</div> </div>
<div className="w-full"> <div className="w-full">
<ForecastFooter <QuestionFooter
stars={qualityindicators.stars} stars={qualityindicators.stars}
platform={platform} platform={platform}
platformLabel={platformLabel || platform} // author || platformLabel, platformLabel={platformLabel || platform} // author || platformLabel,

View File

@ -0,0 +1,33 @@
import React from "react";
import { FrontendQuestion } from "../platforms";
import { DisplayQuestion } from "./DisplayQuestion";
interface Props {
results: FrontendQuestion[];
numDisplay: number;
showIdToggle: boolean;
}
export const DisplayQuestions: React.FC<Props> = ({
results,
numDisplay,
showIdToggle,
}) => {
if (!results) {
return <></>;
}
return (
<>
{results.slice(0, numDisplay).map((result) => (
<DisplayQuestion
key={result.id}
question={result}
showTimeStamp={false}
expandFooterToFullWidth={false}
showIdToggle={showIdToggle}
/>
))}
</>
);
};

View File

@ -1,14 +1,14 @@
import { DisplayForecasts } from "./DisplayForecasts"; import { DisplayOneQuestionForCapture } from "./DisplayOneQuestionForCapture";
import { DisplayOneForecastForCapture } from "./DisplayOneForecastForCapture"; import { DisplayQuestions } from "./DisplayQuestions";
export function displayForecastsWrapperForSearch({ export function displayQuestionsWrapperForSearch({
results, results,
numDisplay, numDisplay,
showIdToggle, showIdToggle,
}) { }) {
return ( return (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
<DisplayForecasts <DisplayQuestions
results={results || []} results={results || []}
numDisplay={numDisplay} numDisplay={numDisplay}
showIdToggle={showIdToggle} showIdToggle={showIdToggle}
@ -17,13 +17,13 @@ export function displayForecastsWrapperForSearch({
); );
} }
export function displayForecastsWrapperForCapture({ export function displayQuestionsWrapperForCapture({
results, results,
whichResultToDisplayAndCapture, whichResultToDisplayAndCapture,
}) { }) {
return ( return (
<div className="grid grid-cols-1 w-full justify-center"> <div className="grid grid-cols-1 w-full justify-center">
<DisplayOneForecastForCapture <DisplayOneQuestionForCapture
result={results[whichResultToDisplayAndCapture]} result={results[whichResultToDisplayAndCapture]}
/> />
</div> </div>

View File

@ -1,20 +1,20 @@
import { Forecast, PlatformConfig } from "../backend/platforms"; import { PlatformConfig, Question } from "../backend/platforms";
export type FrontendForecast = Forecast & { export type FrontendQuestion = Question & {
platformLabel: string; platformLabel: string;
visualization?: any; visualization?: any;
}; };
// ok on client side // ok on client side
export const addLabelsToForecasts = ( export const addLabelsToQuestions = (
forecasts: Forecast[], questions: Question[],
platformsConfig: PlatformConfig[] platformsConfig: PlatformConfig[]
): FrontendForecast[] => { ): FrontendQuestion[] => {
const platformNameToLabel = Object.fromEntries( const platformNameToLabel = Object.fromEntries(
platformsConfig.map((platform) => [platform.name, platform.label]) platformsConfig.map((platform) => [platform.name, platform.label])
); );
return forecasts.map((result) => ({ return questions.map((result) => ({
...result, ...result,
platformLabel: platformNameToLabel[result.platform] || result.platform, platformLabel: platformNameToLabel[result.platform] || result.platform,
})); }));

View File

@ -6,7 +6,7 @@ import { MultiSelectPlatform } from "../display/MultiSelectPlatform";
import { QueryForm } from "../display/QueryForm"; import { QueryForm } from "../display/QueryForm";
import { SliderElement } from "../display/SliderElement"; import { SliderElement } from "../display/SliderElement";
import { useNoInitialEffect } from "../hooks"; import { useNoInitialEffect } from "../hooks";
import { FrontendForecast } from "../platforms"; import { FrontendQuestion } from "../platforms";
import searchAccordingToQueryData from "../worker/searchAccordingToQueryData"; import searchAccordingToQueryData from "../worker/searchAccordingToQueryData";
import { Props as AnySearchPageProps, QueryParameters } from "./anySearchPage"; import { Props as AnySearchPageProps, QueryParameters } from "./anySearchPage";
@ -16,8 +16,8 @@ interface Props extends AnySearchPageProps {
hasAdvancedOptions: boolean; hasAdvancedOptions: boolean;
placeholder: string; placeholder: string;
displaySeeMoreHint: boolean; displaySeeMoreHint: boolean;
displayForecastsWrapper: (opts: { displayQuestionsWrapper: (opts: {
results: FrontendForecast[]; results: FrontendQuestion[];
numDisplay: number; numDisplay: number;
whichResultToDisplayAndCapture: number; whichResultToDisplayAndCapture: number;
showIdToggle: boolean; showIdToggle: boolean;
@ -38,7 +38,7 @@ const CommonDisplay: React.FC<Props> = ({
hasAdvancedOptions, hasAdvancedOptions,
placeholder, placeholder,
displaySeeMoreHint, displaySeeMoreHint,
displayForecastsWrapper, displayQuestionsWrapper,
}) => { }) => {
const router = useRouter(); const router = useRouter();
/* States */ /* States */
@ -68,7 +68,7 @@ const CommonDisplay: React.FC<Props> = ({
const filterManually = ( const filterManually = (
queryData: QueryParameters, queryData: QueryParameters,
results: FrontendForecast[] results: FrontendQuestion[]
) => { ) => {
if ( if (
queryData.forecastingPlatforms && queryData.forecastingPlatforms &&
@ -99,13 +99,13 @@ const CommonDisplay: React.FC<Props> = ({
setResults(results); setResults(results);
} }
// I don't want the function which display forecasts (displayForecasts) to change with a change in queryParameters. But I want it to have access to the queryParameters, and in particular access to queryParameters.numDisplay. Hence why this function lives inside Home. // I don't want the component which display questions (DisplayQuestions) to change with a change in queryParameters. But I want it to have access to the queryParameters, and in particular access to queryParameters.numDisplay. Hence why this function lives inside Home.
const getInfoToDisplayForecastsFunction = () => { const getInfoToDisplayQuestionsFunction = () => {
const numDisplayRounded = const numDisplayRounded =
numDisplay % 3 != 0 numDisplay % 3 != 0
? numDisplay + (3 - (Math.round(numDisplay) % 3)) ? numDisplay + (3 - (Math.round(numDisplay) % 3))
: numDisplay; : numDisplay;
return displayForecastsWrapper({ return displayQuestionsWrapper({
results, results,
numDisplay: numDisplayRounded, numDisplay: numDisplayRounded,
whichResultToDisplayAndCapture, whichResultToDisplayAndCapture,
@ -307,7 +307,7 @@ const CommonDisplay: React.FC<Props> = ({
</div> </div>
) : null} ) : null}
<div>{getInfoToDisplayForecastsFunction()}</div> <div>{getInfoToDisplayQuestionsFunction()}</div>
{displaySeeMoreHint && {displaySeeMoreHint &&
(!results || (results.length != 0 && numDisplay < results.length)) ? ( (!results || (results.length != 0 && numDisplay < results.length)) ? (

View File

@ -2,7 +2,7 @@ import { GetServerSideProps } from "next";
import { getFrontpage } from "../../backend/frontpage"; import { getFrontpage } from "../../backend/frontpage";
import { getPlatformsConfig, PlatformConfig, platforms } from "../../backend/platforms"; import { getPlatformsConfig, PlatformConfig, platforms } from "../../backend/platforms";
import { addLabelsToForecasts, FrontendForecast } from "../platforms"; import { addLabelsToQuestions, FrontendQuestion } from "../platforms";
import searchAccordingToQueryData from "../worker/searchAccordingToQueryData"; import searchAccordingToQueryData from "../worker/searchAccordingToQueryData";
/* Common code for / and /capture */ /* Common code for / and /capture */
@ -15,8 +15,8 @@ export interface QueryParameters {
} }
export interface Props { export interface Props {
defaultResults: FrontendForecast[]; defaultResults: FrontendQuestion[];
initialResults: FrontendForecast[]; initialResults: FrontendQuestion[];
initialQueryParameters: QueryParameters; initialQueryParameters: QueryParameters;
defaultQueryParameters: QueryParameters; defaultQueryParameters: QueryParameters;
initialNumDisplay: number; initialNumDisplay: number;
@ -61,7 +61,7 @@ export const getServerSideProps: GetServerSideProps<Props> = async (
const defaultNumDisplay = 21; const defaultNumDisplay = 21;
const initialNumDisplay = Number(urlQuery.numDisplay) || defaultNumDisplay; const initialNumDisplay = Number(urlQuery.numDisplay) || defaultNumDisplay;
const defaultResults = addLabelsToForecasts( const defaultResults = addLabelsToQuestions(
await getFrontpage(), await getFrontpage(),
platformsConfig platformsConfig
); );

View File

@ -1,25 +1,25 @@
import axios from "axios"; import axios from "axios";
import { DashboardItem } from "../../backend/dashboards"; import { DashboardItem } from "../../backend/dashboards";
import { Forecast, getPlatformsConfig } from "../../backend/platforms"; import { getPlatformsConfig, Question } from "../../backend/platforms";
import { addLabelsToForecasts, FrontendForecast } from "../platforms"; import { addLabelsToQuestions, FrontendQuestion } from "../platforms";
export async function getDashboardForecastsByDashboardId({ export async function getDashboardQuestionsByDashboardId({
dashboardId, dashboardId,
basePath, basePath,
}: { }: {
dashboardId: string; dashboardId: string;
basePath?: string; basePath?: string;
}): Promise<{ }): Promise<{
dashboardForecasts: FrontendForecast[]; dashboardQuestions: FrontendQuestion[];
dashboardItem: DashboardItem; dashboardItem: DashboardItem;
}> { }> {
console.log("getDashboardForecastsByDashboardId: "); console.log("getDashboardQuestionsByDashboardId: ");
if (typeof window === undefined && !basePath) { if (typeof window === undefined && !basePath) {
throw new Error("`basePath` option is required on server side"); throw new Error("`basePath` option is required on server side");
} }
let dashboardForecasts: Forecast[] = []; let dashboardQuestions: Question[] = [];
let dashboardItem: DashboardItem | null = null; let dashboardItem: DashboardItem | null = null;
try { try {
let { data } = await axios({ let { data } = await axios({
@ -31,18 +31,18 @@ export async function getDashboardForecastsByDashboardId({
}); });
console.log(data); console.log(data);
dashboardForecasts = data.dashboardContents; dashboardQuestions = data.dashboardContents;
dashboardItem = data.dashboardItem as DashboardItem; dashboardItem = data.dashboardItem as DashboardItem;
} catch (error) { } catch (error) {
console.log(error); console.log(error);
} finally { } finally {
const labeledDashboardForecasts = addLabelsToForecasts( const labeledDashboardQuestions = addLabelsToQuestions(
dashboardForecasts, dashboardQuestions,
getPlatformsConfig({ withGuesstimate: false }) getPlatformsConfig({ withGuesstimate: false })
); );
return { return {
dashboardForecasts: labeledDashboardForecasts, dashboardQuestions: labeledDashboardQuestions,
dashboardItem, dashboardItem,
}; };
} }

View File

@ -1,4 +1,4 @@
import { FrontendForecast } from "../platforms"; import { FrontendQuestion } from "../platforms";
import { QueryParameters } from "../search/anySearchPage"; import { QueryParameters } from "../search/anySearchPage";
import searchGuesstimate from "./searchGuesstimate"; import searchGuesstimate from "./searchGuesstimate";
import searchWithAlgolia from "./searchWithAlgolia"; import searchWithAlgolia from "./searchWithAlgolia";
@ -6,8 +6,8 @@ import searchWithAlgolia from "./searchWithAlgolia";
export default async function searchAccordingToQueryData( export default async function searchAccordingToQueryData(
queryData: QueryParameters, queryData: QueryParameters,
limit: number limit: number
): Promise<FrontendForecast[]> { ): Promise<FrontendQuestion[]> {
let results: FrontendForecast[] = []; let results: FrontendQuestion[] = [];
try { try {
// defs // defs

View File

@ -1,7 +1,7 @@
/* Imports */ /* Imports */
import axios from "axios"; import axios from "axios";
import { FrontendForecast } from "../platforms"; import { FrontendQuestion } from "../platforms";
/* Definitions */ /* Definitions */
let urlEndPoint = let urlEndPoint =
@ -11,7 +11,7 @@ let urlEndPoint =
export default async function searchGuesstimate( export default async function searchGuesstimate(
query query
): Promise<FrontendForecast[]> { ): Promise<FrontendQuestion[]> {
let response = await axios({ let response = await axios({
url: urlEndPoint, url: urlEndPoint,
// credentials: "omit", // credentials: "omit",
@ -31,7 +31,7 @@ export default async function searchGuesstimate(
}); });
const models: any[] = response.data.hits; const models: any[] = response.data.hits;
const mappedModels: FrontendForecast[] = models.map((model, index) => { const mappedModels: FrontendQuestion[] = models.map((model, index) => {
let description = model.description let description = model.description
? model.description.replace(/\n/g, " ").replace(/ /g, " ") ? model.description.replace(/\n/g, " ").replace(/ /g, " ")
: ""; : "";
@ -57,7 +57,7 @@ export default async function searchGuesstimate(
// filter for duplicates. Surprisingly common. // filter for duplicates. Surprisingly common.
let uniqueTitles = []; let uniqueTitles = [];
let uniqueModels: FrontendForecast[] = []; let uniqueModels: FrontendQuestion[] = [];
for (let model of mappedModels) { for (let model of mappedModels) {
if (!uniqueTitles.includes(model.title) && !model.title.includes("copy")) { if (!uniqueTitles.includes(model.title) && !model.title.includes("copy")) {
uniqueModels.push(model); uniqueModels.push(model);

View File

@ -1,6 +1,6 @@
import algoliasearch from "algoliasearch"; import algoliasearch from "algoliasearch";
import { FrontendForecast } from "../platforms"; import { FrontendQuestion } from "../platforms";
const client = algoliasearch( const client = algoliasearch(
process.env.NEXT_PUBLIC_ALGOLIA_APP_ID, process.env.NEXT_PUBLIC_ALGOLIA_APP_ID,
@ -82,8 +82,8 @@ export default async function searchWithAlgolia({
starsThreshold, starsThreshold,
filterByPlatforms, filterByPlatforms,
forecastsThreshold, forecastsThreshold,
}): Promise<FrontendForecast[]> { }): Promise<FrontendQuestion[]> {
let response = await index.search<FrontendForecast>(queryString, { let response = await index.search<FrontendQuestion>(queryString, {
hitsPerPage, hitsPerPage,
filters: buildFilter({ filters: buildFilter({
starsThreshold, starsThreshold,
@ -93,7 +93,7 @@ export default async function searchWithAlgolia({
//facetFilters: buildFacetFilter({filterByPlatforms}), //facetFilters: buildFacetFilter({filterByPlatforms}),
getRankingInfo: true, getRankingInfo: true,
}); });
let results: FrontendForecast[] = response.hits; let results: FrontendQuestion[] = response.hits;
let recursionError = ["metaforecast", "metaforecasts", "metaforecasting"]; let recursionError = ["metaforecast", "metaforecasts", "metaforecasting"];
if ( if (