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 }