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() useEffect(() => { if (groupId) return listenForGroup(groupId, setGroup) }, [groupId]) return group } export const useGroups = () => { const [groups, setGroups] = useState() useEffect(() => { return listenForGroups(setGroups) }, []) return groups } export const useOpenGroups = () => { const [groups, setGroups] = useState([]) 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( 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 groupIds = useMemberGroupIds(user) const [groups, setGroups] = useState(cachedGroups) useEffect(() => { if (groupIds) { Promise.all(groupIds.map((id) => getGroup(id))).then((groups) => setGroups(filterDefined(groups)) ) } }, [groupIds]) return groups } export function useMembers(groupId: string | undefined) { const [members, setMembers] = useState([]) useEffect(() => { if (groupId) listenForValues(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([]) useEffect(() => { if (groupId) return listenForValues(groupMembers(groupId), (docs) => { setMemberIds(docs.map((doc) => doc.userId)) }) }, [groupId]) return memberIds } export const useGroupsWithContract = (contract: Contract) => { const [groups, setGroups] = useState([]) 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([]) useEffect(() => { if (groupId) return listenForGroupContractDocs(groupId, (docs) => setContractIds(docs.map((doc) => doc.contractId)) ) }, [groupId]) return contractIds }