manifold/web/hooks/use-group.ts
2022-09-18 16:57:20 -05:00

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
}