From 34607262f3269724d93e1594f41a87203788467c Mon Sep 17 00:00:00 2001 From: James Grugett Date: Fri, 11 Feb 2022 01:10:59 -0600 Subject: [PATCH] Answer datatype and MULTI outcome type for Contract --- common/answer.ts | 12 +++++++++ common/contract.ts | 29 ++++++++++++++++----- web/hooks/use-answers.ts | 13 ++++++++++ web/lib/firebase/answers.ts | 52 +++++++++++++++++++++++++++++++++++++ 4 files changed, 99 insertions(+), 7 deletions(-) create mode 100644 common/answer.ts create mode 100644 web/hooks/use-answers.ts create mode 100644 web/lib/firebase/answers.ts diff --git a/common/answer.ts b/common/answer.ts new file mode 100644 index 00000000..344d382f --- /dev/null +++ b/common/answer.ts @@ -0,0 +1,12 @@ +export type Answer = { + id: string + contractId: string + createdTime: number + + userId: string + username: string + name: string + avatarUrl?: string + + text: string +} diff --git a/common/contract.ts b/common/contract.ts index ed642cfa..3b57b766 100644 --- a/common/contract.ts +++ b/common/contract.ts @@ -1,4 +1,4 @@ -export type Contract = { +export type Contract = { id: string slug: string // auto-generated; must be unique @@ -11,14 +11,26 @@ export type Contract = { description: string // More info about what the contract is about tags: string[] lowercaseTags: string[] - outcomeType: 'BINARY' // | 'MULTI' | 'interval' | 'date' + outcomeType: outcomeType visibility: 'public' | 'unlisted' mechanism: 'dpm-2' - phantomShares: { YES: number; NO: number } - pool: { YES: number; NO: number } - totalShares: { YES: number; NO: number } - totalBets: { YES: number; NO: number } + phantomShares: { + BINARY: { YES: number; NO: number } + MULTI: { [answerId: string]: number } + }[outcomeType] + pool: { + BINARY: { YES: number; NO: number } + MULTI: { [answerId: string]: number } + }[outcomeType] + totalShares: { + BINARY: { YES: number; NO: number } + MULTI: { [answerId: string]: number } + }[outcomeType] + totalBets: { + BINARY: { YES: number; NO: number } + MULTI: { [answerId: string]: number } + }[outcomeType] createdTime: number // Milliseconds since epoch lastUpdatedTime: number // If the question or description was changed @@ -26,7 +38,10 @@ export type Contract = { isResolved: boolean resolutionTime?: number // When the contract creator resolved the market - resolution?: outcome // Chosen by creator; must be one of outcomes + resolution?: { + BINARY: outcome + MULTI: string + }[outcomeType] resolutionProbability?: number volume24Hours: number diff --git a/web/hooks/use-answers.ts b/web/hooks/use-answers.ts new file mode 100644 index 00000000..efac8db7 --- /dev/null +++ b/web/hooks/use-answers.ts @@ -0,0 +1,13 @@ +import { useEffect, useState } from 'react' +import { Answer } from '../../common/answer' +import { listenForAnswers } from '../lib/firebase/answers' + +export const useAnswers = (contractId: string) => { + const [answers, setAnswers] = useState() + + useEffect(() => { + if (contractId) return listenForAnswers(contractId, setAnswers) + }, [contractId]) + + return answers +} diff --git a/web/lib/firebase/answers.ts b/web/lib/firebase/answers.ts new file mode 100644 index 00000000..8b50e859 --- /dev/null +++ b/web/lib/firebase/answers.ts @@ -0,0 +1,52 @@ +import { doc, collection, setDoc } from 'firebase/firestore' + +import { getValues, listenForValues } from './utils' +import { db } from './init' +import { User } from '../../../common/user' +import { Answer } from '../../../common/answer' + +function getAnswersCollection(contractId: string) { + return collection(db, 'contracts', contractId, 'answers') +} + +export async function createAnswer( + contractId: string, + text: string, + user: User +) { + const { id: userId, username, name, avatarUrl } = user + + const ref = doc(getAnswersCollection(contractId)) + + const answer: Answer = { + id: ref.id, + contractId, + createdTime: Date.now(), + userId, + username, + name, + avatarUrl, + text, + } + + return await setDoc(ref, answer) +} + +export async function listAllAnswers(contractId: string) { + const answers = await getValues(getAnswersCollection(contractId)) + answers.sort((c1, c2) => c1.createdTime - c2.createdTime) + return answers +} + +export function listenForAnswers( + contractId: string, + setAnswers: (answers: Answer[]) => void +) { + return listenForValues( + getAnswersCollection(contractId), + (answers) => { + answers.sort((c1, c2) => c1.createdTime - c2.createdTime) + setAnswers(answers) + } + ) +}