diff --git a/web/components/feed-create.tsx b/web/components/feed-create.tsx index 0f57a982..a2b7f245 100644 --- a/web/components/feed-create.tsx +++ b/web/components/feed-create.tsx @@ -1,42 +1,66 @@ import { useUser } from '../hooks/use-user' -import { ResolutionOrChance } from './contract-card' import { AvatarWithIcon } from './contract-feed' import { Col } from './layout/col' import { Title } from './title' import Textarea from 'react-expanding-textarea' +import { useState } from 'react' +import { Spacer } from './layout/spacer' +import { NewContract } from '../pages/create' export default function FeedCreate() { const user = useUser() + const [question, setQuestion] = useState('') + if (!user) { + // TODO: Improve logged-out experience return } - const question = 'Ask a question...' - const description = - 'Resolves YES under no circumstances, but perhaps lorem ipsum will come and save the day!\nI kinda doubt it though...' + const placeholders = [ + 'Will I make a new friend this week?', + 'Will we discover that the world is a simulation?', + 'Will anyone I know get engaged this year?', + 'Will humans set foot on Mars by the end of 2030?', + 'If I switch jobs, will I have more free time in 6 months than I do now?', + 'Will any cryptocurrency eclipse Bitcoin by market cap?', + ] + // Rotate through a new placeholder each day + // Easter egg idea: click your own name to shuffle the placeholder + const daysSinceEpoch = Math.floor(Date.now() / 1000 / 60 / 60 / 24) + const placeholder = placeholders[daysSinceEpoch % placeholders.length] return ( <Col className="items-center"> - <div className="w-full max-w-3xl bg-indigo-50 rounded-md"> - <div className="relative flex items-start space-x-3 p-4"> + <div className="w-full max-w-3xl bg-indigo-50 rounded-md p-4"> + <div className="relative flex items-start space-x-3"> <AvatarWithIcon username={user.username} avatarUrl={user.avatarUrl || ''} /> <div className="min-w-0 flex-1 py-1.5"> - {/* Text form to type a question */} - {/* TODO: Figure out how to get rid of border; but also show focus for accessibility */} + {/* TODO: Show focus, for accessibility */} <Textarea - className="text-lg sm:text-xl text-indigo-700 w-full border-transparent focus:border-transparent bg-transparent p-0 appearance-none resize-none outline-hidden focus:outline-none" - placeholder={question} + className="text-lg sm:text-xl text-indigo-700 w-full border-transparent focus:border-transparent bg-transparent p-0 appearance-none resize-none focus:ring-transparent" + placeholder={`e.g. ${placeholder}`} + value={question} + onClick={(e) => e.stopPropagation()} + onChange={(e) => setQuestion(e.target.value || '')} /> - - {/* "Create" button on the bottom right */} - <button className="float-right bg-indigo-500 text-white text-sm font-semibold py-2 px-4 rounded-md"> - CREATE MARKET - </button> + <Spacer h={4} /> </div> </div> + {/* Hide component instead of deleting, so edits to NewContract don't get lost */} + <div className={question ? '' : 'hidden'}> + <NewContract question={question} /> + </div> + {/* Show a fake "Create Market" button, which gets replaced with the NewContract one*/} + {!question && ( + <div className="flex justify-end"> + <button className="btn" disabled> + Create Market + </button> + </div> + )} </div> </Col> ) diff --git a/web/pages/create.tsx b/web/pages/create.tsx index ac1c9c51..867a8e2f 100644 --- a/web/pages/create.tsx +++ b/web/pages/create.tsx @@ -5,19 +5,50 @@ import dayjs from 'dayjs' import Textarea from 'react-expanding-textarea' import { Spacer } from '../components/layout/spacer' -import { Title } from '../components/title' import { useUser } from '../hooks/use-user' import { Contract, contractPath } from '../lib/firebase/contracts' -import { Page } from '../components/page' import { createContract } from '../lib/firebase/api-call' import { Row } from '../components/layout/row' import { AmountInput } from '../components/amount-input' import { MINIMUM_ANTE } from '../../common/antes' import { InfoTooltip } from '../components/info-tooltip' import { CREATOR_FEE } from '../../common/fees' +import { Page } from '../components/page' +import { Title } from '../components/title' + +export default function Create() { + const [question, setQuestion] = useState('') + + return ( + <Page> + <div className="w-full max-w-2xl mx-auto"> + <Title text="Create a new prediction market" /> + + <div className="bg-gray-100 rounded-lg shadow-md px-6 py-4"> + <form> + <div className="form-control w-full"> + <label className="label"> + <span className="mb-1">Question</span> + </label> + + <Textarea + placeholder="e.g. Will the Democrats win the 2024 US presidential election?" + className="input input-bordered resize-none" + value={question} + onChange={(e) => setQuestion(e.target.value || '')} + /> + </div> + </form> + <NewContract question={question} /> + </div> + </div> + </Page> + ) +} // Allow user to create a new contract -export default function NewContract() { +export function NewContract(props: { question: string }) { + const question = props.question const creator = useUser() useEffect(() => { @@ -29,7 +60,6 @@ export default function NewContract() { }, []) const [initialProb, setInitialProb] = useState(50) - const [question, setQuestion] = useState('') const [description, setDescription] = useState('') const [ante, setAnte] = useState<number | undefined>(undefined) @@ -82,141 +112,118 @@ export default function NewContract() { await router.push(contractPath(result.contract as Contract)) } - // 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)...` - const descriptionPlaceholder = `Provide more detail on how you will resolve this market. (Optional)` + const descriptionPlaceholder = `(Optional) Describe how you will resolve this market.\ne.g. This market resolves to "YES" if, two weeks after closing, the...` if (!creator) return <></> return ( - <Page> - <div className="w-full max-w-2xl mx-auto"> - <Title text="Create a new prediction market" /> + <form> + <Spacer h={4} /> - <div className="bg-gray-100 rounded-lg shadow-md px-6 py-4"> - <form> - <div className="form-control w-full"> - <label className="label"> - <span className="mb-1">Question</span> - </label> - - <Textarea - placeholder="e.g. Will the Democrats win the 2024 US presidential election?" - className="input input-bordered resize-none" - disabled={isSubmitting} - value={question} - onChange={(e) => setQuestion(e.target.value || '')} - /> - </div> - - <Spacer h={4} /> - - <div className="form-control"> - <label className="label"> - <span className="mb-1">Initial probability</span> - </label> - <Row className="items-center gap-2"> - <label className="input-group input-group-lg w-fit text-lg"> - <input - type="number" - value={initialProb} - className="input input-bordered input-md text-lg" - disabled={isSubmitting} - min={1} - max={99} - onChange={(e) => - setInitialProb(parseInt(e.target.value.substring(0, 2))) - } - /> - <span>%</span> - </label> - <input - type="range" - className="range range-primary" - min={1} - max={99} - value={initialProb} - onChange={(e) => setInitialProb(parseInt(e.target.value))} - /> - </Row> - </div> - - <Spacer h={4} /> - - <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} /> - - <div className="form-control items-start mb-1"> - <label className="label gap-2 mb-1"> - <span>Last trading day</span> - <InfoTooltip text="Trading allowed through 11:59 pm local time on this date." /> - </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> - - <Spacer h={4} /> - - <div className="form-control items-start mb-1"> - <label className="label gap-2 mb-1"> - <span>Market ante</span> - <InfoTooltip - text={`Subsidize your market to encourage trading. Ante bets are set to match your initial probability. - You earn ${CREATOR_FEE * 100}% of trading volume.`} - /> - </label> - <AmountInput - amount={ante} - minimumAmount={MINIMUM_ANTE} - onChange={setAnte} - error={anteError} - setError={setAnteError} - disabled={isSubmitting} - /> - </div> - - <Spacer h={4} /> - - <div className="flex justify-end my-4"> - <button - type="submit" - className={clsx( - 'btn btn-primary', - isSubmitting && 'loading disabled' - )} - disabled={isSubmitting || !isValid} - onClick={(e) => { - e.preventDefault() - submit() - }} - > - {isSubmitting ? 'Creating...' : 'Create market'} - </button> - </div> - </form> - </div> + <div className="form-control"> + <label className="label"> + <span className="mb-1">Initial probability</span> + </label> + <Row className="items-center gap-2"> + <label className="input-group input-group-lg w-fit text-lg"> + <input + type="number" + value={initialProb} + className="input input-bordered input-md text-lg" + disabled={isSubmitting} + min={1} + max={99} + onChange={(e) => + setInitialProb(parseInt(e.target.value.substring(0, 2))) + } + /> + <span>%</span> + </label> + <input + type="range" + className="range range-primary" + min={1} + max={99} + value={initialProb} + onChange={(e) => setInitialProb(parseInt(e.target.value))} + /> + </Row> </div> - </Page> + + <Spacer h={4} /> + + <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} /> + + <div className="form-control items-start mb-1"> + <label className="label gap-2 mb-1"> + <span>Last trading day</span> + <InfoTooltip text="Trading allowed through 11:59 pm local time on this date." /> + </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> + + <Spacer h={4} /> + + <div className="form-control items-start mb-1"> + <label className="label gap-2 mb-1"> + <span>Market ante</span> + <InfoTooltip + text={`Subsidize your market to encourage trading. Ante bets are set to match your initial probability. + You earn ${CREATOR_FEE * 100}% of trading volume.`} + /> + </label> + <AmountInput + amount={ante} + minimumAmount={MINIMUM_ANTE} + onChange={setAnte} + error={anteError} + setError={setAnteError} + disabled={isSubmitting} + /> + </div> + + <Spacer h={4} /> + + <div className="flex justify-end my-4"> + <button + type="submit" + className={clsx( + 'btn btn-primary', + isSubmitting && 'loading disabled' + )} + disabled={isSubmitting || !isValid} + onClick={(e) => { + e.preventDefault() + submit() + }} + > + {isSubmitting ? 'Creating...' : 'Create market'} + </button> + </div> + </form> ) }