From 2a134b3c9aa0e33bd39f6654098405db73ef30a4 Mon Sep 17 00:00:00 2001 From: Austin Chen Date: Tue, 16 Aug 2022 10:52:43 -0700 Subject: [PATCH] Add a box for contributing to the bounty --- functions/src/resolve-market.ts | 8 +-- web/components/bounty/bounty-box.tsx | 73 +++++++++++++++++++++++++ web/pages/[username]/[contractSlug].tsx | 19 +++++-- 3 files changed, 88 insertions(+), 12 deletions(-) create mode 100644 web/components/bounty/bounty-box.tsx diff --git a/functions/src/resolve-market.ts b/functions/src/resolve-market.ts index b7faec78..a84cbfe8 100644 --- a/functions/src/resolve-market.ts +++ b/functions/src/resolve-market.ts @@ -2,13 +2,7 @@ import * as admin from 'firebase-admin' import { z } from 'zod' import { difference, uniq, mapValues, groupBy, sumBy } from 'lodash' -import { - AnswerContract, - Contract, - FreeResponseContract, - MultipleChoiceContract, - RESOLUTIONS, -} from '../../common/contract' +import { AnswerContract, Contract, RESOLUTIONS } from '../../common/contract' import { User } from '../../common/user' import { Bet } from '../../common/bet' import { getUser, isProd, payUser } from './utils' diff --git a/web/components/bounty/bounty-box.tsx b/web/components/bounty/bounty-box.tsx new file mode 100644 index 00000000..868834c7 --- /dev/null +++ b/web/components/bounty/bounty-box.tsx @@ -0,0 +1,73 @@ +import clsx from 'clsx' +import { BountyContract } from 'common/contract' +import { User } from 'common/user' +import { useState } from 'react' +import { addBounty } from 'web/lib/firebase/api' +import { BuyAmountInput } from '../amount-input' +import { Spacer } from '../layout/spacer' +import { Title } from '../title' + +export function BountyBox(props: { + className?: string + user?: User | null + contract: BountyContract +}) { + const { className, user, contract } = props + const [amount, setAmount] = useState() + const [isSubmitting, setIsSubmitting] = useState(false) + const [error, setError] = useState() + + const donateDisabled = isSubmitting || !amount || error + + const onSubmit: React.FormEventHandler = async (e) => { + if (!user || donateDisabled) return + + e.preventDefault() + setIsSubmitting(true) + setError(undefined) + + await addBounty({ + amount, + contractId: contract.id, + }) + + setIsSubmitting(false) + setAmount(undefined) + } + + return ( +
+ + <form onSubmit={onSubmit}> + <label + className="mb-2 block text-sm text-gray-500" + htmlFor="donate-input" + > + Contribute + </label> + <BuyAmountInput + inputClassName="w-full max-w-none donate-input" + amount={amount} + onChange={setAmount} + error={error} + setError={setError} + /> + + <Spacer h={8} /> + + {user && ( + <button + type="submit" + className={clsx( + 'btn w-full', + donateDisabled ? 'btn-disabled' : 'btn-primary', + isSubmitting && 'loading' + )} + > + Add to bounty + </button> + )} + </form> + </div> + ) +} diff --git a/web/pages/[username]/[contractSlug].tsx b/web/pages/[username]/[contractSlug].tsx index 84e1f362..763a908b 100644 --- a/web/pages/[username]/[contractSlug].tsx +++ b/web/pages/[username]/[contractSlug].tsx @@ -42,6 +42,7 @@ import { listUsers } from 'web/lib/firebase/users' import { FeedComment } from 'web/components/feed/feed-comments' import { Title } from 'web/components/title' import { FeedBet } from 'web/components/feed/feed-bets' +import { BountyBox } from 'web/components/bounty/bounty-box' export const getStaticProps = fromPropz(getStaticPropz) export async function getStaticPropz(props: { @@ -116,30 +117,38 @@ export function ContractPageSidebar(props: { const isBinary = outcomeType === 'BINARY' const isPseudoNumeric = outcomeType === 'PSEUDO_NUMERIC' const isNumeric = outcomeType === 'NUMERIC' + const isBounty = outcomeType === 'BOUNTY' const allowTrade = tradingAllowed(contract) const allowResolve = !isResolved && isCreator && !!user const hasSidePanel = - (isBinary || isNumeric || isPseudoNumeric) && (allowTrade || allowResolve) + (isBinary || isNumeric || isPseudoNumeric || isBounty) && + (allowTrade || allowResolve) + if (!hasSidePanel) { + return null + } - return hasSidePanel ? ( + return ( <Col className="gap-4"> {allowTrade && (isNumeric ? ( <NumericBetPanel className="hidden xl:flex" contract={contract} /> + ) : isBounty ? ( + <BountyBox contract={contract} user={user ?? null} /> ) : ( <BetPanel className="hidden xl:flex" contract={contract as CPMMBinaryContract} /> ))} + {allowResolve && (isNumeric || isPseudoNumeric ? ( <NumericResolutionPanel creator={user} contract={contract} /> - ) : ( + ) : isBinary ? ( <ResolutionPanel creator={user} contract={contract} /> - ))} + ) : null)} </Col> - ) : null + ) } export function ContractPageContent(