diff --git a/src/assets/locales/en/common.json b/src/assets/locales/en/common.json index bbead2169..2c599e538 100644 --- a/src/assets/locales/en/common.json +++ b/src/assets/locales/en/common.json @@ -1018,9 +1018,7 @@ "myDaos": "My DAOs", "popular": "Popular", "newest": "Newest", - "walletBased": "Wallet-based", - "showMore": "Show more", - "tokenBased": "Token-based" + "showMore": "Show more" }, "activeProposals": "Active proposals", "showMore": "Show more", @@ -1039,7 +1037,8 @@ "linkURL": "https://aragon.org/education-portal" }, "toggleFilter": { - "Favourites": "Following", + "favourites": "Following", + "featuredDAOs": "Featured", "allDAOs": "All DAOs ", "member": "Member" }, diff --git a/src/components/daoCard/index.tsx b/src/components/daoCard/index.tsx index 0d63afada..56dc89b24 100644 --- a/src/components/daoCard/index.tsx +++ b/src/components/daoCard/index.tsx @@ -1,7 +1,6 @@ import {AvatarDao} from '@aragon/ods-old'; -import {Icon, IconType} from '@aragon/ods'; +import {AvatarIcon, Icon, IconType} from '@aragon/ods'; import React from 'react'; -import {useTranslation} from 'react-i18next'; import styled from 'styled-components'; import useScreen from 'hooks/useScreen'; import {generatePath, useHref} from 'react-router-dom'; @@ -11,15 +10,18 @@ import {toDisplayEns} from 'utils/library'; import {Dashboard} from 'utils/paths'; import {IDao} from 'services/aragon-backend/domain/dao'; +interface IDaoWithOverride extends IDao { + overrideUrl?: string; +} + export interface IDaoCardProps { - dao: IDao; + dao: IDaoWithOverride; } export const DaoCard = (props: IDaoCardProps) => { const {dao} = props; - const {name, daoAddress, logo, ens, description, network, pluginName} = dao; + const {name, daoAddress, logo, ens, description, network, overrideUrl} = dao; - const {t} = useTranslation(); const {isDesktop} = useScreen(); const {avatar} = useResolveDaoAvatar(logo); @@ -29,23 +31,18 @@ export const DaoCard = (props: IDaoCardProps) => { }); const daoUrl = useHref(daoPage); - // TODO: This should be changed for new plugin types - const daoType = - pluginName === 'token-voting.plugin.dao.eth' || - pluginName === 'token-voting-repo' - ? t('explore.explorer.tokenBased') - : t('explore.explorer.walletBased'); + const resolvedDaoUrl = overrideUrl ?? daoUrl; return ( - +
{name} -

- {toDisplayEns(ens)} -

{description} @@ -58,10 +55,9 @@ export const DaoCard = (props: IDaoCardProps) => { /> {CHAIN_METADATA[network].name} - - - {daoType} - + {overrideUrl != null && ( + + )}
); @@ -109,7 +105,7 @@ const Description = styled.p.attrs({ `; const DaoMetadataWrapper = styled.div.attrs({ - className: 'flex flex-row space-x-6', + className: 'flex flex-row justify-between items-center', })``; const IconLabel = styled.p.attrs({ className: 'text-neutral-600 ft-text-sm', diff --git a/src/containers/daoExplorer/daoExplorer.tsx b/src/containers/daoExplorer/daoExplorer.tsx index c345633f4..b956e4216 100644 --- a/src/containers/daoExplorer/daoExplorer.tsx +++ b/src/containers/daoExplorer/daoExplorer.tsx @@ -23,6 +23,8 @@ import { quickFilters, } from '../daoFilterModal/data'; import {Toggle, ToggleGroup} from '@aragon/ods'; +import {useFeaturedDaos} from 'hooks/useFeaturedDaos'; +import classNames from 'classnames'; const followedDaoToDao = (dao: NavigationDao): IDao => ({ creatorAddress: '' as Address, @@ -38,7 +40,7 @@ const followedDaoToDao = (dao: NavigationDao): IDao => ({ export const DaoExplorer = () => { const {t} = useTranslation(); - const {isConnected, address} = useWallet(); + const {isConnected, address, methods} = useWallet(); const [showAdvancedFilters, setShowAdvancedFilters] = useState(false); const [activeDropdown, setActiveDropdown] = useState(false); @@ -78,8 +80,6 @@ export const DaoExplorer = () => { if (!filters) return ''; - if (filters.quickFilter !== DEFAULT_FILTERS.quickFilter) count++; - // plugin Name filter if (filters.pluginNames?.length !== 0) count++; @@ -103,6 +103,9 @@ export const DaoExplorer = () => { const {isLoading, hasNextPage, isFetchingNextPage, fetchNextPage} = useFollowList ? followedDaosResult : newDaosResult; + const {data: featuredDaoList, isLoading: isLoadingFeaturedDaos} = + useFeaturedDaos(); + const totalDaos = useFollowList ? followedDaosResult.data?.pages[0].total ?? 0 : newDaosResult.data?.pages[0].total ?? 0; @@ -128,10 +131,47 @@ export const DaoExplorer = () => { const noDaosFound = isLoading === false && totalDaos === 0; + const noFeaturedDaosFound = + isLoadingFeaturedDaos === false && + featuredDaoList == null && + filters.quickFilter === 'featuredDaos'; + const handleClearFilters = () => { dispatch({type: FilterActionTypes.RESET, payload: DEFAULT_FILTERS}); }; + const handleWalletButtonClick = () => { + if (isConnected) { + return; + } + + methods.selectWallet().catch((err: Error) => { + console.error(err); + }); + }; + + const showSortFilter = filters.quickFilter !== 'featuredDaos' && isConnected; + + const filterGroupClassName = classNames('flex justify-between w-full', { + 'flex flex-col items-center gap-y-3 md:flex-row md:justify-between': + isConnected, + }); + + const toggleGroupClassName = classNames('flex flex-row w-full', { + 'grid w-full grid-cols-2 gap-1 text-center md:flex md:w-fit md:flex-row': + isConnected, + }); + + const toggleClassName = classNames({ + 'flex w-full justify-center md:w-fit': isConnected, + }); + + const buttonGroupContainerClassName = classNames('shrink-0', { + 'flex w-full md:w-fit justify-end': filters.quickFilter === 'featuredDaos', + 'flex gap-x-3 w-full md:w-fit justify-between': + isConnected && filters.quickFilter !== 'featuredDaos', + }); + /************************************************* * Render * *************************************************/ @@ -139,101 +179,118 @@ export const DaoExplorer = () => { {t('explore.explorer.title')} - +
- {quickFilters.map(f => { - return ( + {quickFilters + .filter(f => { + if ( + !isConnected && + (f.value === 'memberOf' || f.value === 'following') + ) { + return false; + } + return true; + }) + .map(f => ( - ); - })} + ))} - +
+ {showSortFilter && ( +
+ + {filters.quickFilter !== 'following' && ( + { + setActiveDropdown(e); + }} + customTrigger={ +
+ )} - {filters.quickFilter !== 'following' && ( - { - setActiveDropdown(e); - }} - customTrigger={ -
+
+ {noDaosFound || noFeaturedDaosFound ? ( { /> ) : ( - {filteredDaoList?.map( - (dao: IDao, index: React.Key | null | undefined) => ( - - ) + {filters.quickFilter === 'featuredDaos' ? ( + <> + {featuredDaoList?.map( + (dao: IDao, index: React.Key | null | undefined) => ( + + ) + )} + {isLoadingFeaturedDaos && ( + + )} + + ) : ( + <> + {filteredDaoList?.map( + (dao: IDao, index: React.Key | null | undefined) => ( + + ) + )} + {isLoading && } + )} - {isLoading && } )}
- {totalDaos != null && totalDaos > 0 && totalDaosShown > 0 && ( -
- {hasNextPage && ( - - )} - - {t('explore.pagination.label.amountOf DAOs', { - amount: totalDaosShown, - total: totalDaos, - })} - -
- )} + {totalDaos != null && + totalDaos > 0 && + totalDaosShown > 0 && + filters.quickFilter !== 'featuredDaos' && ( +
+ {hasNextPage && ( + + )} + + {t('explore.pagination.label.amountOf DAOs', { + amount: totalDaosShown, + total: totalDaos, + })} + +
+ )} = ({onClose}) => { iconLeft={IconType.CLOSE} variant="tertiary" size="sm" - responsiveSize={{lg: 'lg'}} + responsiveSize={{lg: 'md'}} onClick={onClose} /> @@ -92,11 +87,10 @@ const Header: React.FC = ({onClose}) => { type ContentProps = Pick; const ModalContent: React.FC = ({ - filters: {networks, quickFilter, pluginNames, showTestnets}, + filters: {networks, pluginNames, showTestnets}, onFilterChange, }) => { const {t} = useTranslation(); - const {isConnected} = useWallet(); const testnetsFilters = networkFilters.flatMap(f => f.testnet ? f.value : [] @@ -109,14 +103,6 @@ const ModalContent: React.FC = ({ /************************************************* * Callbacks and Handlers * *************************************************/ - const toggleQuickFilters = (value?: string | string[]) => { - if (value && !Array.isArray(value)) { - onFilterChange({ - type: FilterActionTypes.SET_QUICK_FILTER, - payload: value as QuickFilterValue, - }); - } - }; const toggleNetworks = (value?: string[]) => { onFilterChange({ @@ -152,29 +138,6 @@ const ModalContent: React.FC = ({ *************************************************/ return (
- {/* Quick Filters */} - - - {quickFilters.map(f => { - return ( - - ); - })} - - - {/* Blockchain Filters */} diff --git a/src/hooks/useFeaturedDaos.ts b/src/hooks/useFeaturedDaos.ts new file mode 100644 index 000000000..51f0d6cc9 --- /dev/null +++ b/src/hooks/useFeaturedDaos.ts @@ -0,0 +1,20 @@ +import {useQuery} from '@tanstack/react-query'; +import {IDao} from 'services/aragon-backend/domain/dao'; + +const FEATURED_DAOS_URL = + 'https://raw.githubusercontent.com/aragon/app/refs/heads/develop/src/assets/data/featured-daos.json'; + +const fetchFeaturedDaos = async (): Promise => { + const response = await fetch(FEATURED_DAOS_URL); + + if (!response.ok) { + throw new Error('Failed to fetch featured DAOs'); + } + + const data: IDao[] = await response.json(); + return data; +}; + +export const useFeaturedDaos = () => { + return useQuery({queryKey: ['featuredDaos'], queryFn: fetchFeaturedDaos}); +}; diff --git a/src/pages/explore.tsx b/src/pages/explore.tsx index 9cc139103..823cc37d6 100644 --- a/src/pages/explore.tsx +++ b/src/pages/explore.tsx @@ -1,7 +1,6 @@ import React, {useEffect} from 'react'; import 'react-responsive-carousel/lib/styles/carousel.min.css'; import styled from 'styled-components'; - import {GridLayout} from 'components/layout'; import Carousel from 'containers/carousel'; import {DaoExplorer} from 'containers/daoExplorer';