From 0d56ad603e01ebeb5dc194529ad8037fd332169a Mon Sep 17 00:00:00 2001 From: jahooma Date: Mon, 13 Dec 2021 18:00:02 -0600 Subject: [PATCH] Add UI for resolution panel! --- web/components/resolution-panel.tsx | 81 +++++++++++++++++++++++++++++ web/components/yes-no-selector.tsx | 72 +++++++++++++++++-------- web/pages/contract/[contractId].tsx | 12 ++++- 3 files changed, 141 insertions(+), 24 deletions(-) create mode 100644 web/components/resolution-panel.tsx diff --git a/web/components/resolution-panel.tsx b/web/components/resolution-panel.tsx new file mode 100644 index 00000000..167ccdcb --- /dev/null +++ b/web/components/resolution-panel.tsx @@ -0,0 +1,81 @@ +import clsx from 'clsx' +import React, { useState } from 'react' + +import { Contract } from '../lib/firebase/contracts' +import { Col } from './layout/col' +import { Title } from './title' +import { User } from '../lib/firebase/users' +import { YesNoCancelSelector } from './yes-no-selector' +import { Spacer } from './layout/spacer' + +export function ResolutionPanel(props: { + creator: User + contract: Contract + className?: string +}) { + const { creator, contract, className } = props + + const [outcome, setOutcome] = useState<'YES' | 'NO' | 'CANCEL' | undefined>() + + const resolveDisabled = false + + function resolve() {} + + return ( + + + + <div className="pt-2 pb-1 text-sm text-gray-500">Resolve outcome</div> + <YesNoCancelSelector + className="p-2" + selected={outcome} + onSelect={setOutcome} + /> + + <Spacer h={3} /> + + <div className="text-gray-500 text-sm"> + {outcome === 'YES' ? ( + <> + Winnings will be paid out to Yes bettors. You earn 1% of the No + bets. + </> + ) : outcome === 'NO' ? ( + <> + Winnings will be paid out to No bettors. You earn 1% of the Yes + bets. + </> + ) : outcome === 'CANCEL' ? ( + <>All bets will be returned with no fees.</> + ) : ( + <>Resolving this market will immediately pay out bettors.</> + )} + </div> + + <Spacer h={3} /> + + <button + className={clsx( + 'btn border-none self-start m-2', + resolveDisabled + ? 'btn-disabled' + : outcome === 'YES' + ? 'btn-primary' + : outcome === 'NO' + ? 'bg-red-400 hover:bg-red-500' + : outcome === 'CANCEL' + ? 'bg-yellow-400 hover:bg-yellow-500' + : 'btn-disabled' + )} + onClick={resolveDisabled ? undefined : resolve} + > + Resolve + </button> + </Col> + ) +} diff --git a/web/components/yes-no-selector.tsx b/web/components/yes-no-selector.tsx index 43e60585..f6e2fb61 100644 --- a/web/components/yes-no-selector.tsx +++ b/web/components/yes-no-selector.tsx @@ -1,32 +1,64 @@ +import clsx from 'clsx' import React from 'react' import { Row } from './layout/row' export function YesNoSelector(props: { selected: 'YES' | 'NO' onSelect: (selected: 'YES' | 'NO') => void - yesLabel?: string - noLabel?: string className?: string }) { - const { selected, onSelect, yesLabel, noLabel, className } = props + const { selected, onSelect, className } = props return ( - <Row className={className}> + <Row className={clsx('space-x-3', className)}> <Button - color={selected === 'YES' ? 'green' : 'deemphasized'} - hideFocusRing + color={selected === 'YES' ? 'green' : 'gray'} onClick={() => onSelect('YES')} > - {yesLabel ?? 'Yes'} + Yes </Button> <Button - color={selected === 'NO' ? 'red' : 'deemphasized'} - hideFocusRing + color={selected === 'NO' ? 'red' : 'gray'} onClick={() => onSelect('NO')} - className="ml-3" > - {noLabel ?? 'No'} + No + </Button> + </Row> + ) +} + +export function YesNoCancelSelector(props: { + selected: 'YES' | 'NO' | 'CANCEL' | undefined + onSelect: (selected: 'YES' | 'NO' | 'CANCEL') => void + className?: string +}) { + const { selected, onSelect, className } = props + + return ( + <Row className={clsx('space-x-3', className)}> + <Button + color={selected === 'YES' ? 'green' : 'gray'} + onClick={() => onSelect('YES')} + className="px-6" + > + Yes + </Button> + + <Button + color={selected === 'NO' ? 'red' : 'gray'} + onClick={() => onSelect('NO')} + className="px-6" + > + No + </Button> + + <Button + color={selected === 'CANCEL' ? 'yellow' : 'gray'} + onClick={() => onSelect('CANCEL')} + className="px-6" + > + Cancel </Button> </Row> ) @@ -35,22 +67,20 @@ export function YesNoSelector(props: { function Button(props: { className?: string onClick?: () => void - color: 'green' | 'red' | 'deemphasized' - hideFocusRing?: boolean + color: 'green' | 'red' | 'yellow' | 'gray' children?: any }) { - const { className, onClick, children, color, hideFocusRing } = props + const { className, onClick, children, color } = props return ( <button type="button" - className={classNames( + className={clsx( 'inline-flex items-center px-8 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-white', - !hideFocusRing && 'focus:outline-none focus:ring-2 focus:ring-offset-2', color === 'green' && 'btn-primary', - color === 'red' && 'bg-red-400 hover:bg-red-500 focus:ring-red-400', - color === 'deemphasized' && - 'text-gray-700 bg-gray-300 hover:bg-gray-400 focus:ring-gray-400', + color === 'red' && 'bg-red-400 hover:bg-red-500', + color === 'yellow' && 'bg-yellow-400 hover:bg-yellow-500', + color === 'gray' && 'text-gray-700 bg-gray-300 hover:bg-gray-400', className )} onClick={onClick} @@ -59,7 +89,3 @@ function Button(props: { </button> ) } - -function classNames(...classes: any[]) { - return classes.filter(Boolean).join(' ') -} diff --git a/web/pages/contract/[contractId].tsx b/web/pages/contract/[contractId].tsx index 365a5a77..50eb63a6 100644 --- a/web/pages/contract/[contractId].tsx +++ b/web/pages/contract/[contractId].tsx @@ -5,8 +5,12 @@ import { Header } from '../../components/header' import { ContractOverview } from '../../components/contract-overview' import { BetPanel } from '../../components/bet-panel' import { Col } from '../../components/layout/col' +import { useUser } from '../../hooks/use-user' +import { ResolutionPanel } from '../../components/resolution-panel' export default function ContractPage() { + const user = useUser() + const router = useRouter() const { contractId } = router.query as { contractId: string } @@ -20,6 +24,8 @@ export default function ContractPage() { return <div>Contract not found...</div> } + const isCreator = user?.id === contract.creatorId + return ( <div className="max-w-7xl mx-auto sm:px-6 lg:px-8"> <Header /> @@ -29,7 +35,11 @@ export default function ContractPage() { <div className="mt-12 md:mt-0" /> - <BetPanel className="self-start" contract={contract} /> + {isCreator ? ( + <ResolutionPanel className="self-start" creator={user} contract={contract} /> + ) : ( + <BetPanel className="self-start" contract={contract} /> + )} </Col> </div> )