Skip to content

Commit

Permalink
consolidated following and membership DAOs list
Browse files Browse the repository at this point in the history
  • Loading branch information
NoahSaso committed Apr 20, 2024
1 parent 2e7c5a1 commit 5af5a01
Show file tree
Hide file tree
Showing 19 changed files with 270 additions and 469 deletions.
1 change: 1 addition & 0 deletions packages/i18n/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -1876,6 +1876,7 @@
"winningChoice": "Winning choice",
"withdrawTokenSwap": "Withdraw Token Swap",
"withdrawValidatorCommission": "Claim validator commission",
"yourDaos": "Your DAOs",
"yourNotifiers": "Your notifiers",
"yourSubmission": "Your submission"
},
Expand Down
10 changes: 2 additions & 8 deletions packages/stateful/components/nft/NftSelectionModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,19 +100,13 @@ export const NftSelectionModal = ({
)
const nftChains = uniqueChainIds.map(getChainForChainId)
const filterOptions = useMemo(
() => [
(): TypedOption<FilterFn<{ chainId: string }>>[] => [
{
id: 'all',
label: t('title.all'),
value: () => true,
},
...nftChains.map(
(
chain
): TypedOption<FilterFn<{ chainId: string }>> & {
id: string
} => ({
id: chain.chain_name,
(chain): TypedOption<FilterFn<{ chainId: string }>> => ({
label: getDisplayNameForChainId(chain.chain_id),
value: (nft) => nft.chainId === chain.chain_id,
})
Expand Down
36 changes: 1 addition & 35 deletions packages/stateful/components/pages/AccountDaos.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import { useRouter } from 'next/router'

import { useChain } from '@dao-dao/stateless'

import { useProfile } from '../../hooks'
import { WalletDaos } from '../wallet'

export const AccountDaos = () => {
Expand All @@ -13,36 +10,5 @@ export const AccountDaos = () => {
throw new Error('Invalid address.')
}

const { chain_id: chainId } = useChain()
const { chains } = useProfile({
address,
onlySupported: true,
})

return (
<WalletDaos
chainWallets={
chains.loading
? {
loading: true,
errored: false,
}
: {
loading: false,
errored: false,
updating: chains.updating,
data:
// If no chains found, no profile; just show current chain.
chains.data.length === 0
? [
{
chainId,
address,
},
]
: chains.data,
}
}
/>
)
return <WalletDaos address={address} />
}
45 changes: 4 additions & 41 deletions packages/stateful/components/profile/ProfileDaos.tsx
Original file line number Diff line number Diff line change
@@ -1,45 +1,8 @@
import { useCallback } from 'react'
import { useSetRecoilState } from 'recoil'

import { commandModalVisibleAtom } from '@dao-dao/state/recoil'
import { ProfileDaos as StatelessProfileDaos } from '@dao-dao/stateless'

import { useFeed } from '../../feed'
import { useLoadingFollowingDaoCardInfos, useProfile } from '../../hooks'
import { DaoCard } from '../dao/DaoCard'
import { LinkWrapper } from '../LinkWrapper'
import { WalletDaos } from '../wallet'
import { ProfileAddChains } from './ProfileAddChains'

export const ProfileDaos = () => {
const setCommandModalVisible = useSetRecoilState(commandModalVisibleAtom)

const followingDaosLoading = useLoadingFollowingDaoCardInfos()
const feed = useFeed()

const { chains } = useProfile({
onlySupported: true,
})

const openSearch = useCallback(
() => setCommandModalVisible(true),
[setCommandModalVisible]
)
import { ProfileFeed } from './ProfileFeed'

return (
<StatelessProfileDaos
ProfileAddChains={ProfileAddChains}
WalletDaos={WalletDaos}
chains={chains}
feedProps={{
state: feed,
LinkWrapper,
}}
followingDaosProps={{
DaoCard,
openSearch,
followingDaos: followingDaosLoading,
}}
/>
)
}
export const ProfileDaos = () => (
<StatelessProfileDaos ProfileFeed={ProfileFeed} WalletDaos={WalletDaos} />
)
10 changes: 10 additions & 0 deletions packages/stateful/components/profile/ProfileFeed.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { ProfileFeed as StatelessProfileFeed } from '@dao-dao/stateless'

import { useFeed } from '../../feed'
import { LinkWrapper } from '../LinkWrapper'

export const ProfileFeed = () => {
const feed = useFeed()

return <StatelessProfileFeed LinkWrapper={LinkWrapper} state={feed} />
}
1 change: 1 addition & 0 deletions packages/stateful/components/profile/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ export * from './MergeProfilesModal'
export * from './ProfileActions'
export * from './ProfileAddChains'
export * from './ProfileDaos'
export * from './ProfileFeed'
export * from './ProfileProposalCard'
export * from './ProfileWallet'
112 changes: 93 additions & 19 deletions packages/stateful/components/wallet/WalletDaos.tsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,115 @@
import { waitForAny } from 'recoil'
import { useCallback } from 'react'
import { useTranslation } from 'react-i18next'
import { constSelector, useSetRecoilState, waitForAny } from 'recoil'

import { commandModalVisibleAtom } from '@dao-dao/state/recoil'
import {
WalletDaos as StatelessWalletDaos,
useCachedLoadingWithError,
useChain,
} from '@dao-dao/stateless'
import { StatefulWalletDaosProps } from '@dao-dao/types'
import { transformLoadingDataWithError } from '@dao-dao/utils'
import { LazyDaoCardProps, StatefulWalletDaosProps } from '@dao-dao/types'
import { getSupportedChains } from '@dao-dao/utils'

import { walletDaosSelector } from '../../recoil'
import { useProfile } from '../../hooks/useProfile'
import {
lazyWalletDaosSelector,
lazyWalletFollowingDaosSelector,
} from '../../recoil'
import { LazyDaoCard } from '../dao'
import { ProfileAddChains } from '../profile/ProfileAddChains'

export const WalletDaos = ({ address }: StatefulWalletDaosProps) => {
const { t } = useTranslation()

const { chain_id: chainId } = useChain()
const { connected, chains } = useProfile({
address,
onlySupported: true,
})

const missingChains =
!chains.loading && chains.data.length < getSupportedChains().length

export const WalletDaos = ({
chainWallets,
...props
}: StatefulWalletDaosProps) => {
const walletDaos = useCachedLoadingWithError(
chainWallets.loading || chainWallets.errored
chains.loading
? undefined
: // If no chains and an address is passed, just use the current chain.
chains.data.length === 0 && address
? waitForAny([
waitForAny([
lazyWalletDaosSelector({
chainId,
address,
}),
// Can't load following DAOs if there are no chains and thus no
// public key to load from.
constSelector([]),
]),
])
: waitForAny(
chainWallets.data.map((chainWallet) =>
walletDaosSelector(chainWallet)
chains.data.map(({ chainId, address, publicKey }) =>
waitForAny([
lazyWalletDaosSelector({
chainId,
address,
}),
// If wallet connected, load following.
connected
? lazyWalletFollowingDaosSelector({
chainId,
publicKey,
})
: constSelector([]),
])
)
),
(data) =>
data
.flatMap((loadable) => loadable.valueMaybe() || [])
.flatMap((loadable): LazyDaoCardProps[] => {
if (loadable.state !== 'hasValue') {
return []
}

const [memberOf, following] = loadable.contents

return [
...(memberOf.valueMaybe()?.map((props) => ({
...props,
isMember: true,
})) || []),
...(following.valueMaybe()?.map((props) => ({
...props,
isFollowed: true,
})) || []),
]
})
.sort((a, b) => a.name.localeCompare(b.name))
)

const setCommandModalVisible = useSetRecoilState(commandModalVisibleAtom)
const openSearch = useCallback(
() => setCommandModalVisible(true),
[setCommandModalVisible]
)

return (
<StatelessWalletDaos
{...props}
LazyDaoCard={LazyDaoCard}
chainIds={transformLoadingDataWithError(chainWallets, (data) =>
data.map(({ chainId }) => chainId)
<div className="flex flex-col gap-4">
<StatelessWalletDaos
LazyDaoCard={LazyDaoCard}
daos={walletDaos}
includesFollowing={!address}
openSearch={address ? undefined : openSearch}
/>

{missingChains && connected && (
<ProfileAddChains
className="self-end"
onlySupported
prompt={t('button.addChains')}
promptTooltip={t('info.supportedChainDaosNotShowingUpPrompt')}
/>
)}
daos={chainWallets.errored ? chainWallets : walletDaos}
/>
</div>
)
}
81 changes: 65 additions & 16 deletions packages/stateful/recoil/selectors/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
} from 'recoil'

import {
DaoCoreV2Selectors,
accountsSelector,
genericTokenSelector,
nativeBalancesSelector,
Expand Down Expand Up @@ -38,6 +39,7 @@ import {
loadableToLoadingData,
} from '@dao-dao/utils'

import { followingDaosSelector } from './dao/following'
import {
walletLazyNftCardInfosSelector,
walletStakedLazyNftCardInfosSelector,
Expand Down Expand Up @@ -379,13 +381,12 @@ export const allWalletNftsSelector = selectorFamily<
},
})

// Get DAOs this wallet is a member of.
export const walletDaosSelector = selectorFamily<
// Get lazy card info for DAOs this wallet is a member of.
export const lazyWalletDaosSelector = selectorFamily<
LazyDaoCardProps[],
// Can be any wallet address.
WithChainId<{ address: string }>
>({
key: 'walletDaos',
key: 'lazyWalletDaos',
get:
({ chainId, address }) =>
({ get }) => {
Expand All @@ -405,19 +406,67 @@ export const walletDaosSelector = selectorFamily<
return []
}

const lazyDaoCards = daos
.map(
({ dao, config, proposalCount }): LazyDaoCardProps => ({
chainId,
coreAddress: dao,
name: config.name,
description: config.description,
imageUrl: config.image_url || getFallbackImage(dao),
isInactive:
INACTIVE_DAO_NAMES.includes(config.name) || proposalCount === 0,
})
const lazyDaoCards = daos.map(
({ dao, config, proposalCount }): LazyDaoCardProps => ({
chainId,
coreAddress: dao,
name: config.name,
description: config.description,
imageUrl: config.image_url || getFallbackImage(dao),
isInactive:
INACTIVE_DAO_NAMES.includes(config.name) || proposalCount === 0,
})
)

return lazyDaoCards
},
})

// Get lazy card info for DAOs this wallet is following.
export const lazyWalletFollowingDaosSelector = selectorFamily<
LazyDaoCardProps[],
WithChainId<{ publicKey: string }>
>({
key: 'lazyWalletFollowingDaos',
get:
({ chainId, publicKey }) =>
({ get }) => {
const daos = get(
followingDaosSelector({
chainId,
walletPublicKey: publicKey,
})
)

const daosWithConfigs = get(
waitForAny(
daos.map((dao) =>
DaoCoreV2Selectors.configSelector({
chainId,
contractAddress: dao,
params: [],
})
)
)
.sort((a, b) => a.name.localeCompare(b.name))
).flatMap((loadable, index) =>
loadable.contents
? {
coreAddress: daos[index],
config: loadable.contents,
}
: []
)

const lazyDaoCards = daosWithConfigs.map(
({ coreAddress, config }): LazyDaoCardProps => ({
chainId,
coreAddress,
name: config.name,
description: config.description,
imageUrl: config.image_url || getFallbackImage(coreAddress),
isInactive: INACTIVE_DAO_NAMES.includes(config.name),
})
)

return lazyDaoCards
},
Expand Down
Loading

0 comments on commit 5af5a01

Please sign in to comment.