/ packages / DApp / src / hooks / useCommunities.ts
useCommunities.ts
  1  import { useMemo, useState } from 'react'
  2  import { useCommunitiesProvider } from '../providers/communities/provider'
  3  import { CommunityDetail } from '../models/community'
  4  import { useEffect } from 'react'
  5  import { useContractCalls } from '@usedapp/core'
  6  import { useContracts } from './useContracts'
  7  import { useWaku } from '../providers/waku/provider'
  8  import { deserializePublicKey, serializePublicKey } from '@status-im/js'
  9  import { BigNumber } from 'ethers'
 10  import { useFeaturedVotes } from '../providers/featuredVotes/provider'
 11  import { getRequestClient } from '../lib/request-client'
 12  
 13  export function useCommunities(publicKeys: string[]): CommunityDetail[] {
 14    const { communitiesDetails, dispatch } = useCommunitiesProvider()
 15    const { waku } = useWaku()
 16    const { votes } = useFeaturedVotes()
 17    const [processedKeys, setProcessedKeys] = useState<Set<string>>(new Set())
 18  
 19    const { votingContract } = useContracts()
 20  
 21    const votingHistories =
 22      useContractCalls(
 23        publicKeys.map((publicKey) => {
 24          return {
 25            abi: votingContract.interface,
 26            address: votingContract.address,
 27            method: 'getVotingHistory',
 28            args: [publicKey],
 29          }
 30        }),
 31      ) ?? []
 32  
 33    useEffect(() => {
 34      setProcessedKeys(new Set())
 35  
 36      if (!waku || publicKeys.length === 0) {
 37        return
 38      }
 39  
 40      const fetch = async () => {
 41        const newProcessedKeys = new Set<string>()
 42  
 43        for (const publicKey of publicKeys) {
 44          try {
 45            const deserializedPublicKey = deserializePublicKey(publicKey)
 46  
 47            if (communitiesDetails[deserializedPublicKey]) {
 48              newProcessedKeys.add(publicKey)
 49              continue
 50            }
 51  
 52            const requestClient = getRequestClient(waku)
 53            const community = await requestClient.fetchCommunityDescription(deserializedPublicKey)
 54  
 55            if (!community) {
 56              console.warn(`Community ${deserializedPublicKey} not found`)
 57              newProcessedKeys.add(publicKey)
 58              continue
 59            }
 60  
 61            dispatch({
 62              publicKey: deserializedPublicKey,
 63              name: community!.identity!.displayName,
 64              description: community!.identity!.description,
 65              ens: community!.identity!.ensName,
 66              icon: community!.identity!.images.large
 67                ? URL.createObjectURL(
 68                    new Blob([new Uint8Array(community!.identity!.images.large.payload)], {
 69                      type: 'image/jpeg',
 70                    }),
 71                  )
 72                : null,
 73              link: `https://status.app/c#${serializePublicKey(publicKey)}`,
 74              currentVoting: undefined,
 75              tags: community.tags,
 76              numberOfMembers: Object.keys(community.members).length,
 77              votingHistory: [],
 78              validForAddition: true,
 79            })
 80            newProcessedKeys.add(publicKey)
 81          } catch (error) {
 82            console.error('Error fetching community', error)
 83            newProcessedKeys.add(publicKey)
 84          }
 85        }
 86  
 87        setProcessedKeys(newProcessedKeys)
 88      }
 89  
 90      fetch()
 91    }, [waku, JSON.stringify(publicKeys), JSON.stringify(communitiesDetails)])
 92  
 93    const allProcessed = publicKeys.length > 0 && publicKeys.every((key) => processedKeys.has(key))
 94  
 95    const communities = useMemo(() => {
 96      if (!allProcessed) {
 97        return []
 98      }
 99  
100      return publicKeys
101        .map((publicKey, index) => {
102          const deserializedPublicKey = deserializePublicKey(publicKey)
103          if (!communitiesDetails[deserializedPublicKey]) {
104            return
105          }
106  
107          const votingRooms = votingHistories[index]?.[0]
108  
109          const votingHistory =
110            votingRooms?.map((room: any) => {
111              const endAt = new Date(room.endAt.toNumber() * 1000)
112              return {
113                ID: room.roomNumber.toNumber(),
114                type: room.voteType === 1 ? 'Add' : 'Remove',
115                result:
116                  endAt > new Date() ? 'Ongoing' : room.totalVotesFor.gt(room.totalVotesAgainst) ? 'Passed' : 'Failed',
117                date: endAt,
118              } as const
119            }) ?? []
120  
121          return {
122            ...communitiesDetails[deserializedPublicKey],
123            votingHistory,
124            featureVotes: votes?.[publicKey]?.sum ?? BigNumber.from(0),
125          }
126        })
127        .filter(Boolean)
128    }, [publicKeys, votingHistories, communitiesDetails, votes, allProcessed])
129  
130    // TypeScript doesn't know that the filter above removes undefined values
131    return communities as CommunityDetail[]
132  }