Duplicate a question from '...' screen (#622)

* Duplicate a question from '...' screen

* Remove unused code
This commit is contained in:
Austin Chen 2022-07-05 16:26:58 -07:00 committed by GitHub
parent 3a6d28e2c2
commit cb25a7752d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 102 additions and 32 deletions

View File

@ -21,6 +21,7 @@ import { Title } from '../title'
import { TweetButton } from '../tweet-button' import { TweetButton } from '../tweet-button'
import { InfoTooltip } from '../info-tooltip' import { InfoTooltip } from '../info-tooltip'
import { TagsInput } from 'web/components/tags-input' import { TagsInput } from 'web/components/tags-input'
import { DuplicateContractButton } from '../copy-contract-button'
export const contractDetailsButtonClassName = export const contractDetailsButtonClassName =
'group flex items-center rounded-md px-3 py-2 text-sm font-medium cursor-pointer hover:bg-gray-100 text-gray-400 hover:text-gray-500' 'group flex items-center rounded-md px-3 py-2 text-sm font-medium cursor-pointer hover:bg-gray-100 text-gray-400 hover:text-gray-500'
@ -71,6 +72,7 @@ export function ContractInfoDialog(props: { contract: Contract; bets: Bet[] }) {
tweetText={getTweetText(contract, false)} tweetText={getTweetText(contract, false)}
/> />
<ShareEmbedButton contract={contract} toastClassName={'-left-20'} /> <ShareEmbedButton contract={contract} toastClassName={'-left-20'} />
<DuplicateContractButton contract={contract} />
</Row> </Row>
<div /> <div />

View File

@ -0,0 +1,54 @@
import { DuplicateIcon } from '@heroicons/react/outline'
import clsx from 'clsx'
import { Contract } from 'common/contract'
import { getMappedValue } from 'common/pseudo-numeric'
import { trackCallback } from 'web/lib/service/analytics'
export function DuplicateContractButton(props: {
contract: Contract
className?: string
}) {
const { contract, className } = props
return (
<a
className={clsx('btn btn-xs flex-nowrap normal-case', className)}
style={{
backgroundColor: 'white',
border: '2px solid #a78bfa',
// violet-400
color: '#a78bfa',
}}
href={duplicateContractHref(contract)}
onClick={trackCallback('duplicate market')}
target="_blank"
>
<DuplicateIcon className="mr-1.5 h-4 w-4" aria-hidden="true" />
<div>Duplicate</div>
</a>
)
}
// Pass along the Uri to create a new contract
function duplicateContractHref(contract: Contract) {
const params = {
q: contract.question,
closeTime: contract.closeTime || 0,
description: contract.description,
outcomeType: contract.outcomeType,
} as Record<string, any>
if (contract.outcomeType === 'PSEUDO_NUMERIC') {
params.min = contract.min
params.max = contract.max
params.isLogScale = contract.isLogScale
params.initValue = getMappedValue(contract)(contract.initialProbability)
}
return (
`/create?` +
Object.entries(params)
.map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
.join('&')
)
}

View File

@ -28,14 +28,32 @@ import { GroupSelector } from 'web/components/groups/group-selector'
import { CATEGORIES } from 'common/categories' import { CATEGORIES } from 'common/categories'
import { User } from 'common/user' import { User } from 'common/user'
export default function Create() { type NewQuestionParams = {
const [question, setQuestion] = useState('') groupId?: string
// get query params: q: string
const router = useRouter() type: string
const { groupId } = router.query as { groupId: string } description: string
useTracking('view create page') closeTime: string
const creator = useUser() outcomeType: string
// Params for PSEUDO_NUMERIC outcomeType
min?: string
max?: string
isLogScale?: string
initValue?: string
}
export default function Create() {
useTracking('view create page')
const router = useRouter()
const params = router.query as NewQuestionParams
// TODO: Not sure why Question is pulled out as its own component;
// Maybe merge into newContract and then we don't need useEffect here.
const [question, setQuestion] = useState('')
useEffect(() => {
setQuestion(params.q ?? '')
}, [params.q])
const creator = useUser()
useEffect(() => { useEffect(() => {
if (creator === null) router.push('/') if (creator === null) router.push('/')
}, [creator, router]) }, [creator, router])
@ -65,11 +83,7 @@ export default function Create() {
</div> </div>
</form> </form>
<Spacer h={6} /> <Spacer h={6} />
<NewContract <NewContract question={question} params={params} creator={creator} />
question={question}
groupId={groupId}
creator={creator}
/>
</div> </div>
</div> </div>
</Page> </Page>
@ -80,20 +94,21 @@ export default function Create() {
export function NewContract(props: { export function NewContract(props: {
creator: User creator: User
question: string question: string
groupId?: string params?: NewQuestionParams
}) { }) {
const { creator, question, groupId } = props const { creator, question, params } = props
const [outcomeType, setOutcomeType] = useState<outcomeType>('BINARY') const { groupId, initValue } = params ?? {}
const [outcomeType, setOutcomeType] = useState<outcomeType>(
(params?.outcomeType as outcomeType) ?? 'BINARY'
)
const [initialProb] = useState(50) const [initialProb] = useState(50)
const [minString, setMinString] = useState('') const [minString, setMinString] = useState(params?.min ?? '')
const [maxString, setMaxString] = useState('') const [maxString, setMaxString] = useState(params?.max ?? '')
const [isLogScale, setIsLogScale] = useState(false) const [isLogScale, setIsLogScale] = useState<boolean>(!!params?.isLogScale)
const [initialValueString, setInitialValueString] = useState('') const [initialValueString, setInitialValueString] = useState(initValue)
const [description, setDescription] = useState('') const [description, setDescription] = useState(params?.description ?? '')
// const [tagText, setTagText] = useState<string>(tag ?? '')
// const tags = parseWordsAsTags(tagText)
useEffect(() => { useEffect(() => {
if (groupId && creator) if (groupId && creator)
getGroup(groupId).then((group) => { getGroup(groupId).then((group) => {
@ -105,18 +120,17 @@ export function NewContract(props: {
}, [creator, groupId]) }, [creator, groupId])
const [ante, _setAnte] = useState(FIXED_ANTE) const [ante, _setAnte] = useState(FIXED_ANTE)
// useEffect(() => { // If params.closeTime is set, extract out the specified date and time
// if (ante === null && creator) {
// const initialAnte = creator.balance < 100 ? MINIMUM_ANTE : 100
// setAnte(initialAnte)
// }
// }, [ante, creator])
// const [anteError, setAnteError] = useState<string | undefined>()
// By default, close the market a week from today // By default, close the market a week from today
const weekFromToday = dayjs().add(7, 'day').format('YYYY-MM-DD') const weekFromToday = dayjs().add(7, 'day').format('YYYY-MM-DD')
const [closeDate, setCloseDate] = useState<undefined | string>(weekFromToday) const timeInMs = Number(params?.closeTime ?? 0)
const [closeHoursMinutes, setCloseHoursMinutes] = useState<string>('23:59') const initDate = timeInMs
? dayjs(timeInMs).format('YYYY-MM-DD')
: weekFromToday
const initTime = timeInMs ? dayjs(timeInMs).format('HH:mm') : '23:59'
const [closeDate, setCloseDate] = useState<undefined | string>(initDate)
const [closeHoursMinutes, setCloseHoursMinutes] = useState<string>(initTime)
const [marketInfoText, setMarketInfoText] = useState('') const [marketInfoText, setMarketInfoText] = useState('')
const [isSubmitting, setIsSubmitting] = useState(false) const [isSubmitting, setIsSubmitting] = useState(false)
const [selectedGroup, setSelectedGroup] = useState<Group | undefined>( const [selectedGroup, setSelectedGroup] = useState<Group | undefined>(