2021-12-14 01:07:28 +00:00
import router from 'next/router'
2021-12-16 03:58:28 +00:00
import { useEffect , useState } from 'react'
2022-01-05 05:51:26 +00:00
import clsx from 'clsx'
import dayjs from 'dayjs'
2022-01-06 08:45:30 +00:00
import Textarea from 'react-expanding-textarea'
2021-12-14 01:07:28 +00:00
2021-12-16 02:31:14 +00:00
import { Spacer } from '../components/layout/spacer'
import { Title } from '../components/title'
import { useUser } from '../hooks/use-user'
2022-01-12 19:01:04 +00:00
import { Contract , contractPath } from '../lib/firebase/contracts'
2021-12-20 04:06:30 +00:00
import { Page } from '../components/page'
2022-01-05 18:23:58 +00:00
import { createContract } from '../lib/firebase/api-call'
2022-01-06 08:45:30 +00:00
import { Row } from '../components/layout/row'
2022-01-11 03:41:42 +00:00
import { AmountInput } from '../components/amount-input'
2022-01-14 23:39:17 +00:00
import { MINIMUM_ANTE } from '../../common/antes'
2021-12-14 01:07:28 +00:00
2021-12-10 17:54:16 +00:00
// Allow user to create a new contract
export default function NewContract() {
const creator = useUser ( )
2021-12-16 03:58:28 +00:00
useEffect ( ( ) = > {
2021-12-16 07:00:35 +00:00
if ( creator === null ) router . push ( '/' )
2022-01-05 18:23:58 +00:00
} , [ creator ] )
useEffect ( ( ) = > {
2022-01-14 23:39:17 +00:00
createContract ( { } ) . catch ( ) // warm up function
2022-01-05 18:23:58 +00:00
} , [ ] )
2021-12-16 03:58:28 +00:00
2021-12-14 01:07:28 +00:00
const [ initialProb , setInitialProb ] = useState ( 50 )
const [ question , setQuestion ] = useState ( '' )
const [ description , setDescription ] = useState ( '' )
2022-01-05 05:51:26 +00:00
2022-01-12 05:29:50 +00:00
const [ ante , setAnte ] = useState < number | undefined > ( undefined )
2022-01-14 23:39:17 +00:00
useEffect ( ( ) = > {
if ( creator ) {
const initialAnte = creator . balance < 100 ? 10 : 100
setAnte ( initialAnte )
}
} , [ creator ] )
2022-01-11 03:41:42 +00:00
const [ anteError , setAnteError ] = useState < string | undefined > ( )
2022-01-03 05:21:25 +00:00
const [ closeDate , setCloseDate ] = useState ( '' )
2022-01-05 05:51:26 +00:00
2021-12-14 01:07:28 +00:00
const [ isSubmitting , setIsSubmitting ] = useState ( false )
2022-01-03 05:21:25 +00:00
2022-01-05 05:51:26 +00:00
const closeTime = dateToMillis ( closeDate ) || undefined
2022-01-03 05:21:25 +00:00
// We'd like this to look like "Apr 2, 2022, 23:59:59 PM PT" but timezones are hard with dayjs
2022-01-05 05:51:26 +00:00
const formattedCloseTime = closeTime ? new Date ( closeTime ) . toString ( ) : ''
2022-01-14 23:39:17 +00:00
const remainingBalance = ( creator ? . balance || 0 ) - ( ante || 0 )
2022-01-03 05:21:25 +00:00
const isValid =
initialProb > 0 &&
initialProb < 100 &&
question . length > 0 &&
2022-01-14 23:39:17 +00:00
ante !== undefined &&
ante >= MINIMUM_ANTE &&
ante <= remainingBalance &&
2022-01-03 05:21:25 +00:00
// If set, closeTime must be in the future
2022-01-12 05:40:41 +00:00
closeTime &&
closeTime > Date . now ( )
2021-12-14 01:07:28 +00:00
async function submit() {
2022-01-03 05:21:25 +00:00
// TODO: Tell users why their contract is invalid
if ( ! creator || ! isValid ) return
2021-12-14 01:07:28 +00:00
setIsSubmitting ( true )
2022-01-05 05:51:26 +00:00
const result : any = await createContract ( {
2021-12-14 07:30:09 +00:00
question ,
description ,
initialProb ,
2022-01-05 05:51:26 +00:00
ante ,
closeTime : closeTime || undefined ,
} ) . then ( ( r ) = > r . data || { } )
if ( result . status !== 'success' ) {
console . log ( 'error creating contract' , result )
return
}
2022-01-12 19:01:04 +00:00
await router . push ( contractPath ( result . contract as Contract ) )
2022-01-05 05:51:26 +00:00
}
2022-01-12 05:40:41 +00:00
// const descriptionPlaceholder = `e.g. This market will resolve to “Yes” if, by June 2, 2021, 11:59:59 PM ET, Paxlovid (also known under PF-07321332)...`
2022-01-14 23:39:17 +00:00
const descriptionPlaceholder = ` Provide more detail on how you will resolve this market. (Optional) `
2021-12-10 17:54:16 +00:00
2021-12-16 03:58:28 +00:00
if ( ! creator ) return < > < / >
2021-12-10 17:54:16 +00:00
return (
2021-12-20 04:06:30 +00:00
< Page >
2021-12-18 23:40:39 +00:00
< Title text = "Create a new prediction market" / >
2022-01-14 23:39:17 +00:00
< div className = "w-full max-w-2xl bg-gray-100 rounded-lg shadow-md px-6 py-4" >
2021-12-18 23:40:39 +00:00
{ /* Create a Tailwind form that takes in all the fields needed for a new contract */ }
{ /* When the form is submitted, create a new contract in the database */ }
< form >
2022-01-03 18:39:44 +00:00
< div className = "form-control w-full" >
< label className = "label" >
2022-01-07 03:32:46 +00:00
< span className = "mb-1" > Question < / span >
2022-01-03 18:39:44 +00:00
< / label >
2022-01-06 08:45:30 +00:00
< Textarea
2022-01-14 23:39:17 +00:00
placeholder = "e.g. Will the Democrats win the 2024 US presidential election?"
2022-01-06 08:45:30 +00:00
className = "input input-bordered resize-none"
2022-01-06 03:05:46 +00:00
disabled = { isSubmitting }
2022-01-03 18:39:44 +00:00
value = { question }
onChange = { ( e ) = > setQuestion ( e . target . value || '' ) }
/ >
< / div >
< Spacer h = { 4 } / >
2022-01-03 05:21:25 +00:00
2022-01-03 18:39:44 +00:00
< div className = "form-control" >
< label className = "label" >
2022-01-07 03:32:46 +00:00
< span className = "mb-1" > Initial probability < / span >
2022-01-03 18:39:44 +00:00
< / label >
2022-01-06 08:45:30 +00:00
< Row className = "items-center gap-2" >
2022-01-14 23:39:17 +00:00
< label className = "input-group input-group-lg w-fit text-lg" >
2022-01-06 08:45:30 +00:00
< input
type = "number"
value = { initialProb }
2022-01-14 23:39:17 +00:00
className = "input input-bordered input-md text-lg"
2022-01-06 08:45:30 +00:00
disabled = { isSubmitting }
min = { 1 }
max = { 99 }
onChange = { ( e ) = >
setInitialProb ( parseInt ( e . target . value . substring ( 0 , 2 ) ) )
}
/ >
< span > % < / span >
< / label >
2022-01-03 05:21:25 +00:00
< input
2022-01-06 08:45:30 +00:00
type = "range"
className = "range range-primary"
2022-01-03 18:39:44 +00:00
min = { 1 }
max = { 99 }
2022-01-06 08:45:30 +00:00
value = { initialProb }
onChange = { ( e ) = > setInitialProb ( parseInt ( e . target . value ) ) }
2022-01-03 05:21:25 +00:00
/ >
2022-01-06 08:45:30 +00:00
< / Row >
2022-01-03 18:39:44 +00:00
< / div >
2022-01-03 05:21:25 +00:00
2022-01-03 18:39:44 +00:00
< Spacer h = { 4 } / >
2022-01-14 23:39:17 +00:00
< div className = "form-control" >
< label className = "label" >
< span className = "mb-1" > Description < / span >
< / label >
< Textarea
className = "textarea w-full textarea-bordered"
rows = { 3 }
placeholder = { descriptionPlaceholder }
value = { description }
disabled = { isSubmitting }
onClick = { ( e ) = > e . stopPropagation ( ) }
onChange = { ( e ) = > setDescription ( e . target . value || '' ) }
/ >
< / div >
< Spacer h = { 4 } / >
2022-01-12 05:40:41 +00:00
< div className = "form-control items-start mb-1" >
< label className = "label" >
2022-01-14 23:39:17 +00:00
< span className = "mb-1" > Last trading day < / span >
2022-01-12 05:40:41 +00:00
< / label >
< input
type = "date"
className = "input input-bordered"
onClick = { ( e ) = > e . stopPropagation ( ) }
onChange = { ( e ) = > setCloseDate ( e . target . value || '' ) }
min = { new Date ( ) . toISOString ( ) . split ( 'T' ) [ 0 ] }
disabled = { isSubmitting }
value = { closeDate }
/ >
< / div >
2022-01-14 23:39:17 +00:00
{ / * < l a b e l >
2022-01-12 05:40:41 +00:00
< span className = "label-text text-gray-500 ml-1" >
No trading after this date
< / span >
2022-01-14 23:39:17 +00:00
< / label > * / }
2022-01-12 05:40:41 +00:00
< Spacer h = { 4 } / >
2022-01-14 23:39:17 +00:00
< div className = "form-control mb-1" >
2022-01-03 18:39:44 +00:00
< label className = "label" >
2022-01-14 23:39:17 +00:00
< span className = "mb-1" > Subsidize your market < / span >
2022-01-03 18:39:44 +00:00
< / label >
2022-01-14 23:39:17 +00:00
< AmountInput
amount = { ante }
minimumAmount = { MINIMUM_ANTE }
onChange = { setAnte }
error = { anteError }
setError = { setAnteError }
2022-01-06 03:05:46 +00:00
disabled = { isSubmitting }
2022-01-03 18:39:44 +00:00
/ >
2021-12-18 23:40:39 +00:00
< / div >
< Spacer h = { 4 } / >
< div className = "flex justify-end my-4" >
< button
type = "submit"
2022-01-05 05:51:26 +00:00
className = { clsx (
'btn btn-primary' ,
isSubmitting && 'loading disabled'
) }
2022-01-03 05:21:25 +00:00
disabled = { isSubmitting || ! isValid }
2021-12-18 23:40:39 +00:00
onClick = { ( e ) = > {
e . preventDefault ( )
submit ( )
} }
>
2022-01-05 05:51:26 +00:00
{ isSubmitting ? 'Creating...' : 'Create market' }
2021-12-18 23:40:39 +00:00
< / button >
< / div >
< / form >
2021-12-10 17:54:16 +00:00
< / div >
2021-12-20 04:06:30 +00:00
< / Page >
2021-12-10 17:54:16 +00:00
)
}
2022-01-05 05:51:26 +00:00
// Given a date string like '2022-04-02',
// return the time just before midnight on that date (in the user's local time), as millis since epoch
function dateToMillis ( date : string ) {
return dayjs ( date )
. set ( 'hour' , 23 )
. set ( 'minute' , 59 )
. set ( 'second' , 59 )
. valueOf ( )
}