Remove group details cache, update group directly
This commit is contained in:
parent
e5e13cc598
commit
6a35d3bf2d
|
@ -1,6 +1,5 @@
|
||||||
import { Answer } from './answer'
|
import { Answer } from './answer'
|
||||||
import { Fees } from './fees'
|
import { Fees } from './fees'
|
||||||
import { GroupDetails } from 'common/group'
|
|
||||||
|
|
||||||
export type AnyMechanism = DPM | CPMM
|
export type AnyMechanism = DPM | CPMM
|
||||||
export type AnyOutcomeType = Binary | FreeResponse | Numeric
|
export type AnyOutcomeType = Binary | FreeResponse | Numeric
|
||||||
|
@ -25,8 +24,6 @@ export type Contract<T extends AnyContractType = AnyContractType> = {
|
||||||
lowercaseTags: string[]
|
lowercaseTags: string[]
|
||||||
visibility: 'public' | 'unlisted'
|
visibility: 'public' | 'unlisted'
|
||||||
|
|
||||||
groupDetails?: GroupDetails[] // Starting with one group per contract
|
|
||||||
|
|
||||||
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
|
||||||
lastBetTime?: number
|
lastBetTime?: number
|
||||||
|
|
|
@ -13,9 +13,3 @@ export type Group = {
|
||||||
export const MAX_GROUP_NAME_LENGTH = 75
|
export const MAX_GROUP_NAME_LENGTH = 75
|
||||||
export const MAX_ABOUT_LENGTH = 140
|
export const MAX_ABOUT_LENGTH = 140
|
||||||
export const MAX_ID_LENGTH = 60
|
export const MAX_ID_LENGTH = 60
|
||||||
|
|
||||||
export type GroupDetails = {
|
|
||||||
groupId: string
|
|
||||||
groupSlug: string
|
|
||||||
groupName: string
|
|
||||||
}
|
|
||||||
|
|
|
@ -11,7 +11,6 @@ import {
|
||||||
import { User } from './user'
|
import { User } from './user'
|
||||||
import { parseTags } from './util/parse'
|
import { parseTags } from './util/parse'
|
||||||
import { removeUndefinedProps } from './util/object'
|
import { removeUndefinedProps } from './util/object'
|
||||||
import { GroupDetails } from 'common/group'
|
|
||||||
|
|
||||||
export function getNewContract(
|
export function getNewContract(
|
||||||
id: string,
|
id: string,
|
||||||
|
@ -28,8 +27,7 @@ export function getNewContract(
|
||||||
// used for numeric markets
|
// used for numeric markets
|
||||||
bucketCount: number,
|
bucketCount: number,
|
||||||
min: number,
|
min: number,
|
||||||
max: number,
|
max: number
|
||||||
groupDetails?: GroupDetails
|
|
||||||
) {
|
) {
|
||||||
const tags = parseTags(
|
const tags = parseTags(
|
||||||
`${question} ${description} ${extraTags.map((tag) => `#${tag}`).join(' ')}`
|
`${question} ${description} ${extraTags.map((tag) => `#${tag}`).join(' ')}`
|
||||||
|
@ -71,7 +69,6 @@ export function getNewContract(
|
||||||
liquidityFee: 0,
|
liquidityFee: 0,
|
||||||
platformFee: 0,
|
platformFee: 0,
|
||||||
},
|
},
|
||||||
groupDetails: groupDetails ? [groupDetails] : undefined,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return contract as Contract
|
return contract as Contract
|
||||||
|
|
|
@ -77,19 +77,6 @@ export const createmarket = newEndpoint(['POST'], async (req, auth) => {
|
||||||
}
|
}
|
||||||
const user = userDoc.data() as User
|
const user = userDoc.data() as User
|
||||||
|
|
||||||
let group = null
|
|
||||||
if (groupId) {
|
|
||||||
const groupDoc = await firestore.collection('groups').doc(groupId).get()
|
|
||||||
if (!groupDoc.exists) {
|
|
||||||
throw new APIError(400, 'No group exists with the given group ID.')
|
|
||||||
}
|
|
||||||
|
|
||||||
group = groupDoc.data() as Group
|
|
||||||
if (!group.memberIds.includes(user.id)) {
|
|
||||||
throw new APIError(400, 'User is not a member of the group.')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const userContractsCreatedTodaySnapshot = await firestore
|
const userContractsCreatedTodaySnapshot = await firestore
|
||||||
.collection(`contracts`)
|
.collection(`contracts`)
|
||||||
.where('creatorId', '==', auth.uid)
|
.where('creatorId', '==', auth.uid)
|
||||||
|
@ -104,6 +91,30 @@ export const createmarket = newEndpoint(['POST'], async (req, auth) => {
|
||||||
if (ante > user.balance && !isFree)
|
if (ante > user.balance && !isFree)
|
||||||
throw new APIError(400, `Balance must be at least ${ante}.`)
|
throw new APIError(400, `Balance must be at least ${ante}.`)
|
||||||
|
|
||||||
|
const slug = await getSlug(question)
|
||||||
|
const contractRef = firestore.collection('contracts').doc()
|
||||||
|
|
||||||
|
let group = null
|
||||||
|
if (groupId) {
|
||||||
|
const groupDocRef = await firestore.collection('groups').doc(groupId)
|
||||||
|
const groupDoc = await groupDocRef.get()
|
||||||
|
if (!groupDoc.exists) {
|
||||||
|
throw new APIError(400, 'No group exists with the given group ID.')
|
||||||
|
}
|
||||||
|
|
||||||
|
group = groupDoc.data() as Group
|
||||||
|
if (!group.memberIds.includes(user.id)) {
|
||||||
|
throw new APIError(
|
||||||
|
400,
|
||||||
|
'User must be a member of the group to add markets to it.'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (!group.contractIds.includes(contractRef.id))
|
||||||
|
await groupDocRef.update({
|
||||||
|
contractIds: [...group.contractIds, contractRef.id],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
'creating contract for',
|
'creating contract for',
|
||||||
user.username,
|
user.username,
|
||||||
|
@ -113,8 +124,6 @@ export const createmarket = newEndpoint(['POST'], async (req, auth) => {
|
||||||
ante || 0
|
ante || 0
|
||||||
)
|
)
|
||||||
|
|
||||||
const slug = await getSlug(question)
|
|
||||||
const contractRef = firestore.collection('contracts').doc()
|
|
||||||
const contract = getNewContract(
|
const contract = getNewContract(
|
||||||
contractRef.id,
|
contractRef.id,
|
||||||
slug,
|
slug,
|
||||||
|
@ -128,14 +137,7 @@ export const createmarket = newEndpoint(['POST'], async (req, auth) => {
|
||||||
tags ?? [],
|
tags ?? [],
|
||||||
NUMERIC_BUCKET_COUNT,
|
NUMERIC_BUCKET_COUNT,
|
||||||
min ?? 0,
|
min ?? 0,
|
||||||
max ?? 0,
|
max ?? 0
|
||||||
group
|
|
||||||
? {
|
|
||||||
groupId: group.id,
|
|
||||||
groupName: group.name,
|
|
||||||
groupSlug: group.slug,
|
|
||||||
}
|
|
||||||
: undefined
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if (!isFree && ante) await chargeUser(user.id, ante, true)
|
if (!isFree && ante) await chargeUser(user.id, ante, true)
|
||||||
|
|
|
@ -28,6 +28,7 @@ import { UserFollowButton } from '../follow-button'
|
||||||
import { groupPath } from 'web/lib/firebase/groups'
|
import { groupPath } from 'web/lib/firebase/groups'
|
||||||
import { SiteLink } from 'web/components/site-link'
|
import { SiteLink } from 'web/components/site-link'
|
||||||
import { DAY_MS } from 'common/util/time'
|
import { DAY_MS } from 'common/util/time'
|
||||||
|
import { useGroupsWithContract } from 'web/hooks/use-group'
|
||||||
|
|
||||||
export function MiscDetails(props: {
|
export function MiscDetails(props: {
|
||||||
contract: Contract
|
contract: Contract
|
||||||
|
@ -110,10 +111,10 @@ export function ContractDetails(props: {
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
}) {
|
}) {
|
||||||
const { contract, bets, isCreator, disabled } = props
|
const { contract, bets, isCreator, disabled } = props
|
||||||
const { closeTime, creatorName, creatorUsername, creatorId, groupDetails } =
|
const { closeTime, creatorName, creatorUsername, creatorId } = contract
|
||||||
contract
|
|
||||||
const { volumeLabel, resolvedDate } = contractMetrics(contract)
|
const { volumeLabel, resolvedDate } = contractMetrics(contract)
|
||||||
|
// Find a group that this contract id is in
|
||||||
|
const groups = useGroupsWithContract(contract.id)
|
||||||
return (
|
return (
|
||||||
<Row className="flex-1 flex-wrap items-center gap-x-4 gap-y-2 text-sm text-gray-500">
|
<Row className="flex-1 flex-wrap items-center gap-x-4 gap-y-2 text-sm text-gray-500">
|
||||||
<Row className="items-center gap-2">
|
<Row className="items-center gap-2">
|
||||||
|
@ -134,11 +135,12 @@ export function ContractDetails(props: {
|
||||||
)}
|
)}
|
||||||
{!disabled && <UserFollowButton userId={creatorId} small />}
|
{!disabled && <UserFollowButton userId={creatorId} small />}
|
||||||
</Row>
|
</Row>
|
||||||
{groupDetails && (
|
{/*// TODO: we can add contracts to multiple groups but only show the first it was added to*/}
|
||||||
|
{groups && groups.length > 0 && (
|
||||||
<Row className={'line-clamp-1 mt-1 max-w-[200px]'}>
|
<Row className={'line-clamp-1 mt-1 max-w-[200px]'}>
|
||||||
<SiteLink href={`${groupPath(groupDetails[0].groupSlug)}`}>
|
<SiteLink href={`${groupPath(groups[0].slug)}`}>
|
||||||
<UserGroupIcon className="mx-1 mb-1 inline h-5 w-5" />
|
<UserGroupIcon className="mx-1 mb-1 inline h-5 w-5" />
|
||||||
<span>{groupDetails[0].groupName}</span>
|
<span>{groups[0].name}</span>
|
||||||
</SiteLink>
|
</SiteLink>
|
||||||
</Row>
|
</Row>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { useEffect, useState } from 'react'
|
||||||
import { Group } from 'common/group'
|
import { Group } from 'common/group'
|
||||||
import { User } from 'common/user'
|
import { User } from 'common/user'
|
||||||
import {
|
import {
|
||||||
|
getGroupsWithContractId,
|
||||||
listenForGroup,
|
listenForGroup,
|
||||||
listenForGroups,
|
listenForGroups,
|
||||||
listenForMemberGroups,
|
listenForMemberGroups,
|
||||||
|
@ -76,3 +77,13 @@ export function useMembers(group: Group) {
|
||||||
}, [group])
|
}, [group])
|
||||||
return members
|
return members
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const useGroupsWithContract = (contractId: string | undefined) => {
|
||||||
|
const [groups, setGroups] = useState<Group[] | null | undefined>()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (contractId) getGroupsWithContractId(contractId, setGroups)
|
||||||
|
}, [contractId])
|
||||||
|
|
||||||
|
return groups
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
import {
|
import {
|
||||||
collection,
|
collection,
|
||||||
|
collectionGroup,
|
||||||
deleteDoc,
|
deleteDoc,
|
||||||
doc,
|
doc,
|
||||||
|
orderBy,
|
||||||
query,
|
query,
|
||||||
updateDoc,
|
updateDoc,
|
||||||
where,
|
where,
|
||||||
|
@ -82,3 +84,15 @@ export function listenForMemberGroups(
|
||||||
setGroups(sorted)
|
setGroups(sorted)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getGroupsWithContractId(
|
||||||
|
contractId: string,
|
||||||
|
setGroups: (groups: Group[]) => void
|
||||||
|
) {
|
||||||
|
const q = query(
|
||||||
|
groupCollection,
|
||||||
|
where('contractIds', 'array-contains', contractId)
|
||||||
|
)
|
||||||
|
const groups = await getValues<Group>(q)
|
||||||
|
setGroups(groups)
|
||||||
|
}
|
||||||
|
|
|
@ -451,15 +451,7 @@ function AddContractButton(props: { group: Group; user: User }) {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return listenForUserContracts(user.id, (contracts) => {
|
return listenForUserContracts(user.id, (contracts) => {
|
||||||
setContracts(
|
setContracts(contracts.filter((c) => !group.contractIds.includes(c.id)))
|
||||||
contracts.filter(
|
|
||||||
(c) =>
|
|
||||||
!group.contractIds.includes(c.id) &&
|
|
||||||
// TODO: It'll be easy to allow questions to be in multiple groups as long as we
|
|
||||||
// have the on-update-group function update the newly added contract's groupDetails (via contractIds)
|
|
||||||
!c.groupDetails
|
|
||||||
)
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
}, [group.contractIds, user.id])
|
}, [group.contractIds, user.id])
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user