c6d034545a
* Add dailyScore: product of unique bettors (3 days) and probChanges.day * Increase memory and duration of scoreContracts * Home: Smaller prob change card for groups. Use dailyScore for sort order (algolia) * Add back hover
174 lines
4.5 KiB
TypeScript
174 lines
4.5 KiB
TypeScript
import { useEffect, useState } from 'react'
|
|
import { Group } from 'common/group'
|
|
import { User } from 'common/user'
|
|
import {
|
|
getGroup,
|
|
getMemberGroups,
|
|
GroupMemberDoc,
|
|
groupMembers,
|
|
listenForGroup,
|
|
listenForGroupContractDocs,
|
|
listenForGroups,
|
|
listenForMemberGroupIds,
|
|
listenForOpenGroups,
|
|
listGroups,
|
|
topFollowedGroupsQuery,
|
|
} from 'web/lib/firebase/groups'
|
|
import { getUser } from 'web/lib/firebase/users'
|
|
import { filterDefined } from 'common/util/array'
|
|
import { Contract } from 'common/contract'
|
|
import { keyBy, uniq, uniqBy } from 'lodash'
|
|
import { listenForValues } from 'web/lib/firebase/utils'
|
|
import { useQuery } from 'react-query'
|
|
import { useFirestoreQueryData } from '@react-query-firebase/firestore'
|
|
import { limit, query } from 'firebase/firestore'
|
|
import { useTrendingContracts } from './use-contracts'
|
|
|
|
export const useGroup = (groupId: string | undefined) => {
|
|
const [group, setGroup] = useState<Group | null | undefined>()
|
|
|
|
useEffect(() => {
|
|
if (groupId) return listenForGroup(groupId, setGroup)
|
|
}, [groupId])
|
|
|
|
return group
|
|
}
|
|
|
|
export const useGroups = () => {
|
|
const [groups, setGroups] = useState<Group[] | undefined>()
|
|
|
|
useEffect(() => {
|
|
return listenForGroups(setGroups)
|
|
}, [])
|
|
|
|
return groups
|
|
}
|
|
|
|
export const useOpenGroups = () => {
|
|
const [groups, setGroups] = useState<Group[]>([])
|
|
|
|
useEffect(() => {
|
|
return listenForOpenGroups(setGroups)
|
|
}, [])
|
|
|
|
return groups
|
|
}
|
|
|
|
export const useTopFollowedGroups = (count: number) => {
|
|
const result = useFirestoreQueryData(
|
|
['top-followed-contracts', count],
|
|
query(topFollowedGroupsQuery, limit(count))
|
|
)
|
|
return result.data
|
|
}
|
|
|
|
export const useTrendingGroups = () => {
|
|
const topGroups = useTopFollowedGroups(200)
|
|
const groupsById = keyBy(topGroups, 'id')
|
|
|
|
const trendingContracts = useTrendingContracts(200)
|
|
|
|
const groupLinks = uniqBy(
|
|
(trendingContracts ?? []).map((c) => c.groupLinks ?? []).flat(),
|
|
(link) => link.groupId
|
|
)
|
|
|
|
return filterDefined(
|
|
groupLinks.map((link) => groupsById[link.groupId])
|
|
).filter((group) => group.totalMembers >= 3)
|
|
}
|
|
|
|
export const useMemberGroups = (userId: string | null | undefined) => {
|
|
const result = useQuery(['member-groups', userId ?? ''], () =>
|
|
getMemberGroups(userId ?? '')
|
|
)
|
|
return result.data
|
|
}
|
|
|
|
export const useMemberGroupIds = (user: User | null | undefined) => {
|
|
const cachedGroups = useMemberGroups(user?.id)
|
|
|
|
const [memberGroupIds, setMemberGroupIds] = useState<string[] | undefined>(
|
|
cachedGroups?.map((g) => g.id)
|
|
)
|
|
|
|
useEffect(() => {
|
|
if (user) {
|
|
return listenForMemberGroupIds(user.id, (groupIds) => {
|
|
setMemberGroupIds(groupIds)
|
|
})
|
|
}
|
|
}, [user])
|
|
|
|
return memberGroupIds
|
|
}
|
|
|
|
export function useMemberGroupsSubscription(user: User | null | undefined) {
|
|
const cachedGroups = useMemberGroups(user?.id)
|
|
const [groups, setGroups] = useState(cachedGroups)
|
|
|
|
const userId = user?.id
|
|
useEffect(() => {
|
|
if (userId) {
|
|
return listenForMemberGroupIds(userId, (groupIds) => {
|
|
Promise.all(groupIds.map((id) => getGroup(id))).then((groups) =>
|
|
setGroups(filterDefined(groups))
|
|
)
|
|
})
|
|
}
|
|
}, [userId])
|
|
|
|
return groups
|
|
}
|
|
|
|
export function useMembers(groupId: string | undefined) {
|
|
const [members, setMembers] = useState<User[]>([])
|
|
useEffect(() => {
|
|
if (groupId)
|
|
listenForValues<GroupMemberDoc>(groupMembers(groupId), (memDocs) => {
|
|
const memberIds = memDocs.map((memDoc) => memDoc.userId)
|
|
Promise.all(memberIds.map((id) => getUser(id))).then((users) => {
|
|
setMembers(users)
|
|
})
|
|
})
|
|
}, [groupId])
|
|
return members
|
|
}
|
|
|
|
export function useMemberIds(groupId: string | null) {
|
|
const [memberIds, setMemberIds] = useState<string[]>([])
|
|
useEffect(() => {
|
|
if (groupId)
|
|
return listenForValues<GroupMemberDoc>(groupMembers(groupId), (docs) => {
|
|
setMemberIds(docs.map((doc) => doc.userId))
|
|
})
|
|
}, [groupId])
|
|
return memberIds
|
|
}
|
|
|
|
export const useGroupsWithContract = (contract: Contract) => {
|
|
const [groups, setGroups] = useState<Group[]>([])
|
|
|
|
useEffect(() => {
|
|
if (contract.groupSlugs)
|
|
listGroups(uniq(contract.groupSlugs)).then((groups) =>
|
|
setGroups(filterDefined(groups))
|
|
)
|
|
}, [contract.groupSlugs])
|
|
|
|
return groups
|
|
}
|
|
|
|
export function useGroupContractIds(groupId: string) {
|
|
const [contractIds, setContractIds] = useState<string[]>([])
|
|
|
|
useEffect(() => {
|
|
if (groupId)
|
|
return listenForGroupContractDocs(groupId, (docs) =>
|
|
setContractIds(docs.map((doc) => doc.contractId))
|
|
)
|
|
}, [groupId])
|
|
|
|
return contractIds
|
|
}
|