Implement visibility option for new markets

This commit is contained in:
James Grugett 2022-08-20 14:31:32 -05:00
parent dd6c5dc97a
commit 09e8993cd4
6 changed files with 48 additions and 16 deletions

View File

@ -31,7 +31,7 @@ export type Contract<T extends AnyContractType = AnyContractType> = {
description: string | JSONContent // More info about what the contract is about description: string | JSONContent // More info about what the contract is about
tags: string[] tags: string[]
lowercaseTags: string[] lowercaseTags: string[]
visibility: 'public' | 'unlisted' visibility: visibility
createdTime: number // Milliseconds since epoch createdTime: number // Milliseconds since epoch
lastUpdatedTime?: number // Updated on new bet or comment lastUpdatedTime?: number // Updated on new bet or comment
@ -143,3 +143,6 @@ export const MAX_DESCRIPTION_LENGTH = 16000
export const MAX_TAG_LENGTH = 60 export const MAX_TAG_LENGTH = 60
export const CPMM_MIN_POOL_QTY = 0.01 export const CPMM_MIN_POOL_QTY = 0.01
export type visibility = 'public' | 'unlisted'
export const VISIBILITIES = ['public', 'unlisted'] as const

View File

@ -9,6 +9,7 @@ import {
Numeric, Numeric,
outcomeType, outcomeType,
PseudoNumeric, PseudoNumeric,
visibility,
} from './contract' } from './contract'
import { User } from './user' import { User } from './user'
import { parseTags, richTextToString } from './util/parse' import { parseTags, richTextToString } from './util/parse'
@ -34,7 +35,8 @@ export function getNewContract(
isLogScale: boolean, isLogScale: boolean,
// for multiple choice // for multiple choice
answers: string[] answers: string[],
visibility: visibility
) { ) {
const tags = parseTags( const tags = parseTags(
[ [
@ -70,7 +72,7 @@ export function getNewContract(
description, description,
tags, tags,
lowercaseTags, lowercaseTags,
visibility: 'public', visibility,
isResolved: false, isResolved: false,
createdTime: Date.now(), createdTime: Date.now(),
closeTime, closeTime,

View File

@ -10,6 +10,7 @@ import {
MultipleChoiceContract, MultipleChoiceContract,
NumericContract, NumericContract,
OUTCOME_TYPES, OUTCOME_TYPES,
VISIBILITIES,
} from '../../common/contract' } from '../../common/contract'
import { slugify } from '../../common/util/slugify' import { slugify } from '../../common/util/slugify'
import { randomString } from '../../common/util/random' import { randomString } from '../../common/util/random'
@ -69,6 +70,7 @@ const bodySchema = z.object({
), ),
outcomeType: z.enum(OUTCOME_TYPES), outcomeType: z.enum(OUTCOME_TYPES),
groupId: z.string().min(1).max(MAX_ID_LENGTH).optional(), groupId: z.string().min(1).max(MAX_ID_LENGTH).optional(),
visibility: z.enum(VISIBILITIES).optional(),
}) })
const binarySchema = z.object({ const binarySchema = z.object({
@ -90,8 +92,15 @@ const multipleChoiceSchema = z.object({
}) })
export const createmarket = newEndpoint({}, async (req, auth) => { export const createmarket = newEndpoint({}, async (req, auth) => {
const { question, description, tags, closeTime, outcomeType, groupId } = const {
validate(bodySchema, req.body) question,
description,
tags,
closeTime,
outcomeType,
groupId,
visibility = 'public',
} = validate(bodySchema, req.body)
let min, max, initialProb, isLogScale, answers let min, max, initialProb, isLogScale, answers
@ -196,7 +205,8 @@ export const createmarket = newEndpoint({}, async (req, auth) => {
min ?? 0, min ?? 0,
max ?? 0, max ?? 0,
isLogScale ?? false, isLogScale ?? false,
answers ?? [] answers ?? [],
visibility
) )
if (ante) await chargeUser(user.id, ante, true) if (ante) await chargeUser(user.id, ante, true)

View File

@ -22,7 +22,7 @@ async function unlistContracts() {
const contractRef = firestore.doc(`contracts/${contract.id}`) const contractRef = firestore.doc(`contracts/${contract.id}`)
console.log('Updating', contract.question) console.log('Updating', contract.question)
await contractRef.update({ visibility: 'soft-unlisted' }) await contractRef.update({ visibility: 'unlisted' })
} }
} }

View File

@ -255,13 +255,12 @@ function ContractSearchControls(props: {
? additionalFilters ? additionalFilters
: [ : [
...additionalFilters, ...additionalFilters,
'visibility:public',
filter === 'open' ? 'isResolved:false' : '', filter === 'open' ? 'isResolved:false' : '',
filter === 'closed' ? 'isResolved:false' : '', filter === 'closed' ? 'isResolved:false' : '',
filter === 'resolved' ? 'isResolved:true' : '', filter === 'resolved' ? 'isResolved:true' : '',
// Newest sort requires public visibility.
sort === 'newest' ? 'visibility:public' : '',
pillFilter && pillFilter !== 'personal' && pillFilter !== 'your-bets' pillFilter && pillFilter !== 'personal' && pillFilter !== 'your-bets'
? `groupLinks.slug:${pillFilter}` ? `groupLinks.slug:${pillFilter}`
: '', : '',

View File

@ -15,6 +15,7 @@ import {
MAX_DESCRIPTION_LENGTH, MAX_DESCRIPTION_LENGTH,
MAX_QUESTION_LENGTH, MAX_QUESTION_LENGTH,
outcomeType, outcomeType,
visibility,
} from 'common/contract' } from 'common/contract'
import { formatMoney } from 'common/util/format' import { formatMoney } from 'common/util/format'
import { removeUndefinedProps } from 'common/util/object' import { removeUndefinedProps } from 'common/util/object'
@ -150,6 +151,7 @@ export function NewContract(props: {
undefined undefined
) )
const [showGroupSelector, setShowGroupSelector] = useState(true) const [showGroupSelector, setShowGroupSelector] = useState(true)
const [visibility, setVisibility] = useState<visibility>('public')
const closeTime = closeDate const closeTime = closeDate
? dayjs(`${closeDate}T${closeHoursMinutes}`).valueOf() ? dayjs(`${closeDate}T${closeHoursMinutes}`).valueOf()
@ -234,6 +236,7 @@ export function NewContract(props: {
isLogScale, isLogScale,
answers, answers,
groupId: selectedGroup?.id, groupId: selectedGroup?.id,
visibility,
}) })
) )
track('create market', { track('create market', {
@ -367,17 +370,32 @@ export function NewContract(props: {
</> </>
)} )}
<div className={'mt-2'}> <div className="form-control mb-1 items-start gap-1">
<GroupSelector <label className="label gap-2">
selectedGroup={selectedGroup} <span className="mb-1">Visibility</span>
setSelectedGroup={setSelectedGroup} </label>
creator={creator} <ChoicesToggleGroup
options={{ showSelector: showGroupSelector, showLabel: true }} currentChoice={visibility}
setChoice={(choice) => setVisibility(choice as visibility)}
choicesMap={{
Public: 'public',
Unlisted: 'unlisted',
}}
isSubmitting={isSubmitting}
/> />
</div> </div>
<Spacer h={6} /> <Spacer h={6} />
<GroupSelector
selectedGroup={selectedGroup}
setSelectedGroup={setSelectedGroup}
creator={creator}
options={{ showSelector: showGroupSelector, showLabel: true }}
/>
<Spacer h={6} />
<div className="form-control mb-1 items-start"> <div className="form-control mb-1 items-start">
<label className="label mb-1 gap-2"> <label className="label mb-1 gap-2">
<span>Question closes in</span> <span>Question closes in</span>