contract slugs
This commit is contained in:
parent
756f31b1b7
commit
03a3df261c
|
@ -1,5 +1,7 @@
|
|||
export type Contract = {
|
||||
id: string // Chosen by creator; must be unique
|
||||
id: string
|
||||
slug: string // auto-generated; must be unique
|
||||
|
||||
creatorId: string
|
||||
creatorName: string
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import { User } from '../lib/firebase/users'
|
|||
import { formatMoney, formatPercent } from '../lib/util/format'
|
||||
import { Col } from './layout/col'
|
||||
import { Spacer } from './layout/spacer'
|
||||
import { Contract, getContract, path } from '../lib/firebase/contracts'
|
||||
import { Contract, getContractFromId, path } from '../lib/firebase/contracts'
|
||||
import { Row } from './layout/row'
|
||||
import { UserLink } from './user-page'
|
||||
import {
|
||||
|
@ -29,9 +29,11 @@ export function BetsList(props: { user: User }) {
|
|||
const contractIds = _.uniq(loadedBets.map((bet) => bet.contractId))
|
||||
|
||||
let disposed = false
|
||||
Promise.all(contractIds.map((id) => getContract(id))).then((contracts) => {
|
||||
Promise.all(contractIds.map((id) => getContractFromId(id))).then(
|
||||
(contracts) => {
|
||||
if (!disposed) setContracts(contracts.filter(Boolean) as Contract[])
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
return () => {
|
||||
disposed = true
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
import { useEffect, useState } from 'react'
|
||||
import { Contract, listenForContract } from '../lib/firebase/contracts'
|
||||
import {
|
||||
Contract,
|
||||
getContractFromSlug,
|
||||
listenForContract,
|
||||
} from '../lib/firebase/contracts'
|
||||
|
||||
export const useContract = (contractId: string) => {
|
||||
const [contract, setContract] = useState<Contract | null | 'loading'>(
|
||||
|
@ -14,14 +18,20 @@ export const useContract = (contractId: string) => {
|
|||
}
|
||||
|
||||
export const useContractWithPreload = (
|
||||
contractId: string,
|
||||
slug: string,
|
||||
initial: Contract | null
|
||||
) => {
|
||||
const [contract, setContract] = useState<Contract | null>(initial)
|
||||
const [contractId, setContractId] = useState<string | undefined | null>(
|
||||
initial?.id
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
if (contractId) return listenForContract(contractId, setContract)
|
||||
}, [contractId])
|
||||
|
||||
if (contractId !== null)
|
||||
getContractFromSlug(slug).then((c) => setContractId(c?.id || null))
|
||||
}, [contractId, slug])
|
||||
|
||||
return contract
|
||||
}
|
||||
|
|
|
@ -16,7 +16,9 @@ import {
|
|||
import dayjs from 'dayjs'
|
||||
|
||||
export type Contract = {
|
||||
id: string // Chosen by creator; must be unique
|
||||
id: string
|
||||
slug: string // auto-generated; must be unique
|
||||
|
||||
creatorId: string
|
||||
creatorName: string
|
||||
|
||||
|
@ -42,7 +44,7 @@ export function path(contract: Contract) {
|
|||
// For now, derive username from creatorName
|
||||
// Fix this when users can change their own names
|
||||
const username = contract.creatorName.replace(/\s+/g, '')
|
||||
return `/${username}/${contract.id}`
|
||||
return `/${username}/${contract.slug}`
|
||||
}
|
||||
|
||||
export function compute(contract: Contract) {
|
||||
|
@ -66,13 +68,28 @@ export async function setContract(contract: Contract) {
|
|||
await setDoc(docRef, contract)
|
||||
}
|
||||
|
||||
export async function getContract(contractId: string) {
|
||||
export async function pushNewContract(contract: Omit<Contract, 'id'>) {
|
||||
const newContractRef = doc(contractCollection)
|
||||
const fullContract: Contract = { ...contract, id: newContractRef.id }
|
||||
|
||||
await setDoc(newContractRef, fullContract)
|
||||
return fullContract
|
||||
}
|
||||
|
||||
export async function getContractFromId(contractId: string) {
|
||||
const docRef = doc(db, 'contracts', contractId)
|
||||
const result = await getDoc(docRef)
|
||||
|
||||
return result.exists() ? (result.data() as Contract) : undefined
|
||||
}
|
||||
|
||||
export async function getContractFromSlug(slug: string) {
|
||||
const q = query(contractCollection, where('slug', '==', slug))
|
||||
const snapshot = await getDocs(q)
|
||||
|
||||
return snapshot.empty ? undefined : (snapshot.docs[0].data() as Contract)
|
||||
}
|
||||
|
||||
export async function deleteContract(contractId: string) {
|
||||
const docRef = doc(db, 'contracts', contractId)
|
||||
await deleteDoc(docRef)
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
import { Contract, getContract, setContract } from '../firebase/contracts'
|
||||
import {
|
||||
Contract,
|
||||
getContractFromSlug,
|
||||
pushNewContract,
|
||||
setContract,
|
||||
} from '../firebase/contracts'
|
||||
import { User } from '../firebase/users'
|
||||
import { randomString } from '../util/random-string'
|
||||
import { slugify } from '../util/slugify'
|
||||
|
@ -10,16 +15,18 @@ export async function createContract(
|
|||
initialProb: number,
|
||||
creator: User
|
||||
) {
|
||||
const slug = slugify(question).substr(0, 35)
|
||||
const proposedSlug = slugify(question).substring(0, 35)
|
||||
|
||||
const preexistingContract = await getContract(slug)
|
||||
const preexistingContract = await getContractFromSlug(proposedSlug)
|
||||
|
||||
const contractId = preexistingContract ? slug + '-' + randomString() : slug
|
||||
const slug = preexistingContract
|
||||
? proposedSlug + '-' + randomString()
|
||||
: proposedSlug
|
||||
|
||||
const { startYes, startNo } = calcStartPool(initialProb)
|
||||
|
||||
const contract: Contract = {
|
||||
id: contractId,
|
||||
const contract: Omit<Contract, 'id'> = {
|
||||
slug,
|
||||
outcomeType: 'BINARY',
|
||||
|
||||
creatorId: creator.id,
|
||||
|
@ -38,9 +45,7 @@ export async function createContract(
|
|||
lastUpdatedTime: Date.now(),
|
||||
}
|
||||
|
||||
await setContract(contract)
|
||||
|
||||
return contract
|
||||
return await pushNewContract(contract)
|
||||
}
|
||||
|
||||
export function calcStartPool(initialProb: number, initialCapital = 100) {
|
||||
|
|
|
@ -13,17 +13,17 @@ import { useBets } from '../../hooks/use-bets'
|
|||
import { Title } from '../../components/title'
|
||||
import { Spacer } from '../../components/layout/spacer'
|
||||
import { User } from '../../lib/firebase/users'
|
||||
import { Contract, getContract } from '../../lib/firebase/contracts'
|
||||
import { Contract, getContractFromSlug } from '../../lib/firebase/contracts'
|
||||
import { SEO } from '../../components/SEO'
|
||||
|
||||
export async function getStaticProps(props: { params: any }) {
|
||||
const { username, contractId } = props.params
|
||||
const contract = (await getContract(contractId)) || null
|
||||
const { username, slug } = props.params
|
||||
const contract = (await getContractFromSlug(slug)) || null
|
||||
|
||||
return {
|
||||
props: {
|
||||
username,
|
||||
contractId,
|
||||
slug,
|
||||
contract,
|
||||
},
|
||||
|
||||
|
@ -37,12 +37,12 @@ export async function getStaticPaths() {
|
|||
|
||||
export default function ContractPage(props: {
|
||||
contract: Contract | null
|
||||
contractId: string
|
||||
slug: string
|
||||
username: string
|
||||
}) {
|
||||
const user = useUser()
|
||||
|
||||
const contract = useContractWithPreload(props.contractId, props.contract)
|
||||
const contract = useContractWithPreload(props.slug, props.contract)
|
||||
|
||||
if (!contract) {
|
||||
return <div>Contract not found...</div>
|
||||
|
@ -56,7 +56,7 @@ export default function ContractPage(props: {
|
|||
<SEO
|
||||
title={contract.question}
|
||||
description={contract.description}
|
||||
url={`/${props.username}/${props.contractId}`}
|
||||
url={`/${props.username}/${props.slug}`}
|
||||
/>
|
||||
|
||||
<Header />
|
|
@ -6,6 +6,7 @@ import { Header } from '../components/header'
|
|||
import { Spacer } from '../components/layout/spacer'
|
||||
import { Title } from '../components/title'
|
||||
import { useUser } from '../hooks/use-user'
|
||||
import { path } from '../lib/firebase/contracts'
|
||||
import { createContract } from '../lib/service/create-contract'
|
||||
|
||||
// Allow user to create a new contract
|
||||
|
@ -33,7 +34,7 @@ export default function NewContract() {
|
|||
initialProb,
|
||||
creator
|
||||
)
|
||||
await router.push(`contract/${contract.id}`)
|
||||
await router.push(path(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)...`
|
||||
|
|
Loading…
Reference in New Issue
Block a user