Improve useCommunities (#113)
This commit is contained in:
parent
f67c63830d
commit
22121d9952
|
@ -101,9 +101,13 @@ export function DirectoryCards() {
|
|||
</PageBar>
|
||||
<WeeklyFeature endDate={new Date('07/26/2021')} />
|
||||
<Voting>
|
||||
{communities.map((community) => (
|
||||
<DirectoryCard key={community.publicKey} community={community} />
|
||||
))}
|
||||
{communities.map((community, idx) => {
|
||||
if (community) {
|
||||
return <DirectoryCard key={community.publicKey} community={community} />
|
||||
} else {
|
||||
return <DirectoryCardSkeleton key={idx} />
|
||||
}
|
||||
})}
|
||||
{communities.length === 0 && <DirectoryCardSkeleton />}
|
||||
</Voting>
|
||||
</>
|
||||
|
|
|
@ -45,9 +45,13 @@ export function VotingCards() {
|
|||
</VoteFilter>
|
||||
<FilterList value={sortedBy} setValue={setSortedBy} options={VotingSortingOptions} />
|
||||
</PageBar>
|
||||
{roomsToShow.map((room: any) => (
|
||||
<VotingCard key={room.roomNumber.toString()} room={room} />
|
||||
))}
|
||||
{roomsToShow.map((room: any, idx) => {
|
||||
if (room?.details) {
|
||||
return <VotingCard key={room.roomNumber.toString()} room={room} />
|
||||
} else {
|
||||
return <VotingCardSkeleton key={idx} />
|
||||
}
|
||||
})}
|
||||
{roomsToShow.length === 0 && <VotingCardSkeleton />}
|
||||
</div>
|
||||
)
|
||||
|
|
|
@ -26,63 +26,65 @@ export function isTypeInRoom(voteType: string, room: any) {
|
|||
}
|
||||
|
||||
export function sortVotingFunction(sortedBy: VotingSortingEnum) {
|
||||
switch (sortedBy) {
|
||||
case VotingSortingEnum.AtoZ:
|
||||
return (a: DetailedVotingRoom, b: DetailedVotingRoom) => (a.details.name < b.details.name ? -1 : 1)
|
||||
case VotingSortingEnum.ZtoA:
|
||||
return (a: DetailedVotingRoom, b: DetailedVotingRoom) => (a.details.name < b.details.name ? 1 : -1)
|
||||
case VotingSortingEnum.EndingLatest:
|
||||
return (a: DetailedVotingRoom, b: DetailedVotingRoom) => {
|
||||
return (a: DetailedVotingRoom | undefined, b: DetailedVotingRoom | undefined) => {
|
||||
if (!a) {
|
||||
return 1
|
||||
}
|
||||
if (!b) {
|
||||
return -1
|
||||
}
|
||||
let aSum
|
||||
let bSum
|
||||
switch (sortedBy) {
|
||||
case VotingSortingEnum.AtoZ:
|
||||
return a.details.name < b.details.name ? -1 : 1
|
||||
case VotingSortingEnum.ZtoA:
|
||||
return a.details.name < b.details.name ? 1 : -1
|
||||
case VotingSortingEnum.EndingLatest:
|
||||
return a.endAt < b.endAt ? -1 : 1
|
||||
}
|
||||
case VotingSortingEnum.EndingSoonest:
|
||||
return (a: DetailedVotingRoom, b: DetailedVotingRoom) => {
|
||||
case VotingSortingEnum.EndingSoonest:
|
||||
return a.endAt < b.endAt ? 1 : -1
|
||||
}
|
||||
case VotingSortingEnum.MostVotes:
|
||||
return (a: DetailedVotingRoom, b: DetailedVotingRoom) => {
|
||||
const aSum = a.totalVotesAgainst.add(a.totalVotesFor)
|
||||
const bSum = b.totalVotesAgainst.add(b.totalVotesFor)
|
||||
case VotingSortingEnum.MostVotes:
|
||||
aSum = a.totalVotesAgainst.add(a.totalVotesFor)
|
||||
bSum = b.totalVotesAgainst.add(b.totalVotesFor)
|
||||
return aSum < bSum ? 1 : -1
|
||||
}
|
||||
case VotingSortingEnum.LeastVotes:
|
||||
return (a: DetailedVotingRoom, b: DetailedVotingRoom) => {
|
||||
const aSum = a.totalVotesAgainst.add(a.totalVotesFor)
|
||||
const bSum = b.totalVotesAgainst.add(b.totalVotesFor)
|
||||
case VotingSortingEnum.LeastVotes:
|
||||
aSum = a.totalVotesAgainst.add(a.totalVotesFor)
|
||||
bSum = b.totalVotesAgainst.add(b.totalVotesFor)
|
||||
return aSum < bSum ? -1 : 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function sortDirectoryFunction(sortedBy: DirectorySortingEnum) {
|
||||
switch (sortedBy) {
|
||||
case DirectorySortingEnum.AtoZ:
|
||||
return (a: CommunityDetail, b: CommunityDetail) => (a.name < b.name ? -1 : 1)
|
||||
case DirectorySortingEnum.ZtoA:
|
||||
return (a: CommunityDetail, b: CommunityDetail) => (a.name < b.name ? 1 : -1)
|
||||
case DirectorySortingEnum.IncludedLongAgo:
|
||||
return (a: CommunityDetail, b: CommunityDetail) => {
|
||||
return (a: CommunityDetail | undefined, b: CommunityDetail | undefined) => {
|
||||
if (!a) {
|
||||
return 1
|
||||
}
|
||||
if (!b) {
|
||||
return -1
|
||||
}
|
||||
switch (sortedBy) {
|
||||
case DirectorySortingEnum.AtoZ:
|
||||
return a.name < b.name ? -1 : 1
|
||||
case DirectorySortingEnum.ZtoA:
|
||||
return a.name < b.name ? 1 : -1
|
||||
case DirectorySortingEnum.IncludedLongAgo:
|
||||
if (!a.directoryInfo) return 1
|
||||
if (!b.directoryInfo) return -1
|
||||
return a?.directoryInfo?.additionDate < b?.directoryInfo?.additionDate ? -1 : 1
|
||||
}
|
||||
case DirectorySortingEnum.IncludedRecently:
|
||||
return (a: CommunityDetail, b: CommunityDetail) => {
|
||||
case DirectorySortingEnum.IncludedRecently:
|
||||
if (!a.directoryInfo) return -1
|
||||
if (!b.directoryInfo) return 1
|
||||
return a?.directoryInfo?.additionDate < b?.directoryInfo?.additionDate ? 1 : -1
|
||||
}
|
||||
case DirectorySortingEnum.MostVotes:
|
||||
return (a: CommunityDetail, b: CommunityDetail) => {
|
||||
case DirectorySortingEnum.MostVotes:
|
||||
if (!a.directoryInfo?.featureVotes) return 1
|
||||
if (!b.directoryInfo?.featureVotes) return -1
|
||||
return a?.directoryInfo?.featureVotes < b?.directoryInfo?.featureVotes ? 1 : -1
|
||||
}
|
||||
case DirectorySortingEnum.LeastVotes:
|
||||
return (a: CommunityDetail, b: CommunityDetail) => {
|
||||
case DirectorySortingEnum.LeastVotes:
|
||||
if (!a.directoryInfo?.featureVotes) return 1
|
||||
if (!b.directoryInfo?.featureVotes) return -1
|
||||
return a?.directoryInfo?.featureVotes < b?.directoryInfo?.featureVotes ? -1 : 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,72 +1,24 @@
|
|||
import { useState, useEffect } from 'react'
|
||||
import { CommunityDetail } from '../models/community'
|
||||
import { APIOptions, APIFunction } from './../models/api'
|
||||
import { getCommunityDetails } from '../helpers/apiMock'
|
||||
import { useCommunitiesProvider } from '../providers/communities/provider'
|
||||
|
||||
export function useCommunities(API: APIFunction, options: APIOptions) {
|
||||
const [communities, setCommunities] = useState<CommunityDetail[]>([])
|
||||
const [page, setPage] = useState(0)
|
||||
const [increment, setIncrement] = useState(false)
|
||||
const [loading, setLoading] = useState(true)
|
||||
export function useCommunities(publicKeys: string[]) {
|
||||
const { communitiesDetails, dispatch } = useCommunitiesProvider()
|
||||
|
||||
const handleScroll = (e: Event) => {
|
||||
if (e.target) {
|
||||
const scrollingElement = (e.target as HTMLDocument).scrollingElement
|
||||
if (!scrollingElement?.scrollHeight || !scrollingElement?.scrollTop || !scrollingElement?.clientHeight) {
|
||||
return
|
||||
}
|
||||
if (scrollingElement.scrollHeight - scrollingElement.scrollTop <= scrollingElement.clientHeight + 60) {
|
||||
setPage((prevPage) => prevPage + 1)
|
||||
window.removeEventListener('scroll', handleScroll)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (increment) {
|
||||
if (document.scrollingElement?.clientHeight || document.scrollingElement?.scrollHeight) {
|
||||
if (document.scrollingElement?.clientHeight >= document.scrollingElement?.scrollHeight) {
|
||||
setPage((prevPage) => prevPage + 1)
|
||||
} else {
|
||||
window.addEventListener('scroll', handleScroll)
|
||||
return publicKeys.map((publicKey) => {
|
||||
const detail = communitiesDetails[publicKey]
|
||||
if (detail) {
|
||||
return { ...detail }
|
||||
} else {
|
||||
if (publicKey) {
|
||||
const setCommunity = async () => {
|
||||
const communityDetail = await getCommunityDetails(publicKey)
|
||||
if (communityDetail) {
|
||||
dispatch(communityDetail)
|
||||
}
|
||||
}
|
||||
setCommunity()
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
return () => {
|
||||
window.removeEventListener('scroll', handleScroll)
|
||||
}
|
||||
}, [increment])
|
||||
|
||||
useEffect(() => {
|
||||
const getCommunities = async () => {
|
||||
setLoading(true)
|
||||
const communities = (await API(0, options)).communities
|
||||
setCommunities(communities)
|
||||
setLoading(false)
|
||||
setIncrement(true)
|
||||
}
|
||||
|
||||
setCommunities([])
|
||||
setPage(0)
|
||||
setIncrement(false)
|
||||
getCommunities()
|
||||
}, [options.filterKeyword, options.sortedBy, options.voteType])
|
||||
|
||||
useEffect(() => {
|
||||
const updateCommunities = async () => {
|
||||
setLoading(true)
|
||||
const newCommunities = (await API(page, options)).communities
|
||||
setCommunities((oldCommunities) => [...oldCommunities, ...newCommunities])
|
||||
if (newCommunities.length === options.numberPerPage) {
|
||||
setIncrement(true)
|
||||
}
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
if (page === 0) return
|
||||
|
||||
setIncrement(false)
|
||||
updateCommunities()
|
||||
}, [page])
|
||||
|
||||
return { communities, loading }
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,27 +1,14 @@
|
|||
import { useEffect, useRef, useState } from 'react'
|
||||
import { getCommunityDetails } from '../helpers/apiMock'
|
||||
import { useEffect } from 'react'
|
||||
import { CommunityDetail } from '../models/community'
|
||||
import { useCommunities } from './useCommunities'
|
||||
|
||||
export function useCommunityDetails(publicKey: string, setCommunityDetail: (val: CommunityDetail | undefined) => void) {
|
||||
const [loading, setLoading] = useState(false)
|
||||
const loadingIdx = useRef(0)
|
||||
const [CommunityDetail] = useCommunities([publicKey])
|
||||
|
||||
useEffect(() => {
|
||||
const getDetails = async (key: string) => {
|
||||
const idx = ++loadingIdx.current
|
||||
setLoading(true)
|
||||
setCommunityDetail(await getCommunityDetails(key))
|
||||
if (idx === loadingIdx.current) {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
setCommunityDetail(undefined)
|
||||
if (publicKey) {
|
||||
getDetails(publicKey)
|
||||
}
|
||||
}, [publicKey])
|
||||
setCommunityDetail(CommunityDetail)
|
||||
return () => setCommunityDetail(undefined)
|
||||
}, [JSON.stringify(CommunityDetail)])
|
||||
|
||||
useEffect(() => setCommunityDetail(undefined), [])
|
||||
|
||||
return loading
|
||||
return !CommunityDetail
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { useContractCall } from '@usedapp/core'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { getCommunityDetails } from '../helpers/apiMock'
|
||||
import { isTextInDetails, sortDirectoryFunction } from '../helpers/communityFiltering'
|
||||
import { CommunityDetail, DirectorySortingEnum } from '../models/community'
|
||||
import { useCommunities } from './useCommunities'
|
||||
import { useContracts } from './useContracts'
|
||||
|
||||
export function useDirectoryCommunities(filterKeyword: string, sortedBy: DirectorySortingEnum) {
|
||||
|
@ -14,28 +14,18 @@ export function useDirectoryCommunities(filterKeyword: string, sortedBy: Directo
|
|||
args: [],
|
||||
}) ?? [[]]
|
||||
|
||||
const [unfilteredComm, setUnfilteredComm] = useState(communities)
|
||||
const [filteredCommunities, setFilteredCommunities] = useState<CommunityDetail[]>([])
|
||||
const unfilteredComm = useCommunities(communities)
|
||||
const [filteredCommunities, setFilteredCommunities] = useState<(CommunityDetail | undefined)[]>([])
|
||||
|
||||
useEffect(() => {
|
||||
const getDetails = async () => {
|
||||
if (communities.length > 0) {
|
||||
const detailedComm = await Promise.all(communities.map(async (key: string) => await getCommunityDetails(key)))
|
||||
setUnfilteredComm(detailedComm)
|
||||
}
|
||||
}
|
||||
getDetails()
|
||||
}, [JSON.stringify(communities)])
|
||||
|
||||
useEffect(() => {
|
||||
const filterCommunities = unfilteredComm.filter((comm: CommunityDetail) => {
|
||||
const filterCommunities = unfilteredComm.filter((comm: CommunityDetail | undefined) => {
|
||||
if (comm) {
|
||||
return isTextInDetails(filterKeyword, comm)
|
||||
}
|
||||
return false
|
||||
return true
|
||||
})
|
||||
setFilteredCommunities(filterCommunities.sort(sortDirectoryFunction(sortedBy)))
|
||||
}, [unfilteredComm, sortedBy, filterKeyword])
|
||||
}, [JSON.stringify(unfilteredComm), sortedBy, filterKeyword])
|
||||
|
||||
return filteredCommunities
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { useContractCall, useContractCalls } from '@usedapp/core'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { getCommunityDetails } from '../helpers/apiMock'
|
||||
import { VotingSortingEnum } from '../models/community'
|
||||
import { DetailedVotingRoom } from '../models/smartContract'
|
||||
import { useContracts } from './useContracts'
|
||||
import { isTextInDetails, isTypeInRoom, sortVotingFunction } from '../helpers/communityFiltering'
|
||||
import { useCommunities } from './useCommunities'
|
||||
|
||||
export function useVotingCommunities(
|
||||
filterKeyword: string,
|
||||
|
@ -32,31 +32,28 @@ export function useVotingCommunities(
|
|||
})
|
||||
|
||||
const votingRooms = useContractCalls(contractCalls)
|
||||
const publicKeys = votingRooms.map((votingRoom: any) => votingRoom?.community)
|
||||
const communitiesDetails = useCommunities(publicKeys)
|
||||
|
||||
useEffect(() => {
|
||||
if (votingRooms.length > 0) {
|
||||
const getPromises = async () => {
|
||||
const rooms = await Promise.all(
|
||||
votingRooms.map(async (el: any) => {
|
||||
if (el) {
|
||||
return { ...el, details: await getCommunityDetails(el.community) }
|
||||
}
|
||||
return undefined
|
||||
})
|
||||
)
|
||||
setRoomsWithCommunity(rooms)
|
||||
}
|
||||
getPromises()
|
||||
const rooms = votingRooms.map((el: any) => {
|
||||
if (el) {
|
||||
return { ...el, details: communitiesDetails.find((comm) => comm?.publicKey === el.community) }
|
||||
}
|
||||
return undefined
|
||||
})
|
||||
setRoomsWithCommunity(rooms)
|
||||
}
|
||||
}, [JSON.stringify(votingRooms)])
|
||||
}, [JSON.stringify(votingRooms), JSON.stringify(communitiesDetails)])
|
||||
|
||||
useEffect(() => {
|
||||
const filteredRooms = roomsWithCommunity.filter((room: any) => {
|
||||
if (room) {
|
||||
if (room && room.details) {
|
||||
return isTextInDetails(filterKeyword, room.details) && isTypeInRoom(voteType, room)
|
||||
}
|
||||
return false
|
||||
})
|
||||
return true
|
||||
}) as (any | undefined)[]
|
||||
setFilteredRooms(filteredRooms.sort(sortVotingFunction(sortedBy)))
|
||||
}, [roomsWithCommunity, filterKeyword, voteType, sortedBy])
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import { DAppProvider, ChainId } from '@usedapp/core'
|
|||
import { DEFAULT_CONFIG } from '@usedapp/core/dist/cjs/src/model/config/default'
|
||||
import { ConfigProvider } from './providers/config/provider'
|
||||
import { WakuProvider } from './providers/waku/provider'
|
||||
import { CommunitiesProvider } from './providers/communities/provider'
|
||||
|
||||
const config = {
|
||||
readOnlyChainId: ChainId.Ropsten,
|
||||
|
@ -23,7 +24,9 @@ render(
|
|||
<WakuProvider>
|
||||
<DAppProvider config={config}>
|
||||
<ConfigProvider>
|
||||
<App />
|
||||
<CommunitiesProvider>
|
||||
<App />
|
||||
</CommunitiesProvider>
|
||||
</ConfigProvider>
|
||||
</DAppProvider>
|
||||
</WakuProvider>
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
import React, { ReactNode, useReducer, createContext, useContext } from 'react'
|
||||
import { CommunityDetail } from '../../models/community'
|
||||
|
||||
type CommunitiesDetails = {
|
||||
[publicKey: string]: CommunityDetail
|
||||
}
|
||||
|
||||
const CommunitiesContext = createContext<{
|
||||
communitiesDetails: CommunitiesDetails
|
||||
dispatch: (details: CommunityDetail) => void
|
||||
}>({
|
||||
communitiesDetails: {},
|
||||
dispatch: () => undefined,
|
||||
})
|
||||
|
||||
export function useCommunitiesProvider() {
|
||||
return useContext(CommunitiesContext)
|
||||
}
|
||||
|
||||
function communitiesReducer(state: CommunitiesDetails, action: CommunityDetail) {
|
||||
return { ...state, [action.publicKey]: action }
|
||||
}
|
||||
|
||||
interface CommunitiesProviderProps {
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
export function CommunitiesProvider({ children }: CommunitiesProviderProps) {
|
||||
const [communitiesDetails, dispatch] = useReducer(communitiesReducer, {})
|
||||
return <CommunitiesContext.Provider value={{ communitiesDetails, dispatch }} children={children} />
|
||||
}
|
Loading…
Reference in New Issue