Fold type, fold page, query for fold contracts
This commit is contained in:
parent
5ce23c0bdb
commit
7a2eac604d
17
common/fold.ts
Normal file
17
common/fold.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
export type Fold = {
|
||||
id: string
|
||||
slug: string
|
||||
name: string
|
||||
curatorId: string // User id
|
||||
createdTime: number
|
||||
|
||||
tags: string
|
||||
|
||||
contractIds: string[]
|
||||
excludedContractIds: string[]
|
||||
|
||||
// Invariant: exactly one of the following is defined.
|
||||
// Default: creatorIds: undefined, excludedCreatorIds: []
|
||||
creatorIds?: string[]
|
||||
excludedCreatorIds?: string[]
|
||||
}
|
|
@ -35,5 +35,8 @@ service cloud.firestore {
|
|||
allow read;
|
||||
}
|
||||
|
||||
match /folds/{foldId} {
|
||||
allow read;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -75,9 +75,7 @@ const recentCommentsQuery = query(
|
|||
)
|
||||
|
||||
export async function getRecentComments() {
|
||||
const snapshot = await getDocs(recentCommentsQuery)
|
||||
const comments = snapshot.docs.map((doc) => doc.data() as Comment)
|
||||
return comments
|
||||
return getValues<Comment>(recentCommentsQuery)
|
||||
}
|
||||
|
||||
export function listenForRecentComments(
|
||||
|
|
|
@ -54,7 +54,7 @@ export function contractMetrics(contract: Contract) {
|
|||
}
|
||||
|
||||
const db = getFirestore(app)
|
||||
const contractCollection = collection(db, 'contracts')
|
||||
export const contractCollection = collection(db, 'contracts')
|
||||
|
||||
// Push contract to Firestore
|
||||
export async function setContract(contract: Contract) {
|
||||
|
|
57
web/lib/firebase/folds.ts
Normal file
57
web/lib/firebase/folds.ts
Normal file
|
@ -0,0 +1,57 @@
|
|||
import { collection, query, where } from 'firebase/firestore'
|
||||
import { Fold } from '../../../common/fold'
|
||||
import { Contract, contractCollection } from './contracts'
|
||||
import { db } from './init'
|
||||
import { getValues } from './utils'
|
||||
|
||||
const foldCollection = collection(db, 'folds')
|
||||
|
||||
export async function getFoldBySlug(slug: string) {
|
||||
const q = query(foldCollection, where('slug', '==', slug))
|
||||
const folds = await getValues<Fold>(q)
|
||||
|
||||
return folds.length === 0 ? null : folds[0]
|
||||
}
|
||||
|
||||
export async function getFoldContracts(fold: Fold) {
|
||||
const {
|
||||
tags,
|
||||
contractIds,
|
||||
excludedContractIds,
|
||||
creatorIds,
|
||||
excludedCreatorIds,
|
||||
} = fold
|
||||
|
||||
const [tagsContracts, includedContracts] = await Promise.all([
|
||||
// TODO: if tags.length > 10, execute multiple parallel queries
|
||||
getValues<Contract>(
|
||||
query(contractCollection, where('tags', 'array-contains-any', tags))
|
||||
),
|
||||
|
||||
// TODO: if contractIds.length > 10, execute multiple parallel queries
|
||||
contractIds.length > 0
|
||||
? getValues<Contract>(
|
||||
query(contractCollection, where('id', 'in', contractIds))
|
||||
)
|
||||
: [],
|
||||
])
|
||||
|
||||
const excludedContractsSet = new Set(excludedContractIds)
|
||||
|
||||
const creatorSet = creatorIds ? new Set(creatorIds) : undefined
|
||||
const excludedCreatorSet = excludedCreatorIds
|
||||
? new Set(excludedCreatorIds)
|
||||
: undefined
|
||||
|
||||
const approvedContracts = tagsContracts.filter((contract) => {
|
||||
const { id, creatorId } = contract
|
||||
|
||||
if (excludedContractsSet.has(id)) return false
|
||||
if (creatorSet && !creatorSet.has(creatorId)) return false
|
||||
if (excludedCreatorSet && excludedCreatorSet.has(creatorId)) return false
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
return [...approvedContracts, ...includedContracts]
|
||||
}
|
|
@ -8,8 +8,8 @@ import {
|
|||
DocumentReference,
|
||||
} from 'firebase/firestore'
|
||||
|
||||
export const getValue = async <T>(collectionName: string, docName: string) => {
|
||||
const snap = await getDoc(doc(db, collectionName, docName))
|
||||
export const getValue = async <T>(doc: DocumentReference) => {
|
||||
const snap = await getDoc(doc)
|
||||
return snap.exists() ? (snap.data() as T) : null
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,9 @@ import { Bet, listAllBets } from '../../lib/firebase/bets'
|
|||
import { Comment, listAllComments } from '../../lib/firebase/comments'
|
||||
import Custom404 from '../404'
|
||||
|
||||
export async function getStaticProps(props: { params: any }) {
|
||||
export async function getStaticProps(props: {
|
||||
params: { username: string; contractSlug: string }
|
||||
}) {
|
||||
const { username, contractSlug } = props.params
|
||||
const contract = (await getContractFromSlug(contractSlug)) || null
|
||||
const contractId = contract?.id
|
||||
|
|
|
@ -68,15 +68,17 @@ export function ActivityFeed(props: {
|
|||
contracts: Contract[]
|
||||
contractBets: Bet[][]
|
||||
contractComments: Comment[][]
|
||||
listenForChanges?: boolean
|
||||
}) {
|
||||
const { contractBets, contractComments } = props
|
||||
const { contractBets, contractComments, listenForChanges } = props
|
||||
const contracts = useContracts() ?? props.contracts
|
||||
const recentComments = useRecentComments()
|
||||
const activeContracts = recentComments
|
||||
? findActiveContracts(contracts, recentComments)
|
||||
: props.contracts
|
||||
const activeContracts =
|
||||
listenForChanges && recentComments
|
||||
? findActiveContracts(contracts, recentComments)
|
||||
: props.contracts
|
||||
|
||||
return contracts.length > 0 ? (
|
||||
return activeContracts.length > 0 ? (
|
||||
<Col className="items-center">
|
||||
<Col className="w-full max-w-3xl">
|
||||
<Title text="Recent Activity" />
|
||||
|
|
63
web/pages/fold/[foldSlug].tsx
Normal file
63
web/pages/fold/[foldSlug].tsx
Normal file
|
@ -0,0 +1,63 @@
|
|||
import { Fold } from '../../../common/fold'
|
||||
import { Comment } from '../../../common/comment'
|
||||
import { Page } from '../../components/page'
|
||||
import { Title } from '../../components/title'
|
||||
import { Bet, listAllBets } from '../../lib/firebase/bets'
|
||||
import { getRecentComments, listAllComments } from '../../lib/firebase/comments'
|
||||
import { Contract } from '../../lib/firebase/contracts'
|
||||
import { getFoldBySlug, getFoldContracts } from '../../lib/firebase/folds'
|
||||
import { ActivityFeed, findActiveContracts } from '../activity'
|
||||
|
||||
export async function getStaticProps(props: { params: { foldSlug: string } }) {
|
||||
const { foldSlug } = props.params
|
||||
|
||||
const recentCommentsPromise = getRecentComments().catch(() => [])
|
||||
|
||||
const fold = await getFoldBySlug(foldSlug)
|
||||
const contracts = fold ? await getFoldContracts(fold) : []
|
||||
|
||||
const recentComments = await recentCommentsPromise
|
||||
const activeContracts = findActiveContracts(contracts, recentComments)
|
||||
const activeContractBets = await Promise.all(
|
||||
activeContracts.map((contract) => listAllBets(contract.id))
|
||||
)
|
||||
const activeContractComments = await Promise.all(
|
||||
activeContracts.map((contract) => listAllComments(contract.id))
|
||||
)
|
||||
|
||||
return {
|
||||
props: {
|
||||
fold,
|
||||
activeContracts,
|
||||
activeContractBets,
|
||||
activeContractComments,
|
||||
},
|
||||
|
||||
revalidate: 60, // regenerate after a minute
|
||||
}
|
||||
}
|
||||
|
||||
export async function getStaticPaths() {
|
||||
return { paths: [], fallback: 'blocking' }
|
||||
}
|
||||
|
||||
export default function FoldPage(props: {
|
||||
fold: Fold
|
||||
activeContracts: Contract[]
|
||||
activeContractBets: Bet[][]
|
||||
activeContractComments: Comment[][]
|
||||
}) {
|
||||
const { fold, activeContracts, activeContractBets, activeContractComments } =
|
||||
props
|
||||
|
||||
return (
|
||||
<Page>
|
||||
<Title text={fold.name} />
|
||||
<ActivityFeed
|
||||
contracts={activeContracts}
|
||||
contractBets={activeContractBets}
|
||||
contractComments={activeContractComments}
|
||||
/>
|
||||
</Page>
|
||||
)
|
||||
}
|
|
@ -73,6 +73,7 @@ const Home = (props: {
|
|||
contracts={activeContracts}
|
||||
contractBets={activeContractBets}
|
||||
contractComments={activeContractComments}
|
||||
listenForChanges
|
||||
/>
|
||||
</Page>
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue
Block a user