diff --git a/packages/extension-polkagate/src/fullscreen/governance/InternetConnectivity.tsx b/packages/extension-polkagate/src/fullscreen/governance/InternetConnectivity.tsx index 88d0984c9..ea2eccb10 100644 --- a/packages/extension-polkagate/src/fullscreen/governance/InternetConnectivity.tsx +++ b/packages/extension-polkagate/src/fullscreen/governance/InternetConnectivity.tsx @@ -32,15 +32,11 @@ function InternetConnectivity (): React.ReactElement { useEffect(() => { checkInternetAccess().then((_isOnline) => { - console.log('internet check result:', _isOnline); - setIsOnline(_isOnline); }).catch(console.error); const intervalId = setInterval(() => { checkInternetAccess().then((_isOnline) => { - console.log('internet check result:', _isOnline); - setIsOnline(_isOnline); }).catch(console.error); }, CHECK_INTERNET_CONNECTIVITY_PERIOD); diff --git a/packages/extension-polkagate/src/fullscreen/governance/index.tsx b/packages/extension-polkagate/src/fullscreen/governance/index.tsx index d7963c2bf..416f92b48 100644 --- a/packages/extension-polkagate/src/fullscreen/governance/index.tsx +++ b/packages/extension-polkagate/src/fullscreen/governance/index.tsx @@ -1,20 +1,20 @@ // Copyright 2019-2024 @polkadot/extension-polkagate authors & contributors // SPDX-License-Identifier: Apache-2.0 -// @ts-nocheck - /* eslint-disable react/jsx-max-props-per-line */ +import type { u32 } from '@polkadot/types-codec'; import type { LatestReferenda } from './utils/types'; import { Container, Grid, Typography, useTheme } from '@mui/material'; +// @ts-ignore import { CubeGrid } from 'better-react-spinkit'; import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'; import { useParams } from 'react-router'; import { useLocation } from 'react-router-dom'; import { ReferendaContext, Warning } from '../../components'; -import { useApi, useChain, useChainName, useDecidingCount, useFullscreen, useTracks, useTranslation } from '../../hooks'; +import { useDecidingCount, useFullscreen, useInfo, useTracks, useTranslation } from '../../hooks'; import { GOVERNANCE_CHAINS } from '../../util/constants'; import HorizontalWaiting from './components/HorizontalWaiting'; import { getAllVotes } from './post/myVote/util'; @@ -33,13 +33,12 @@ export type Fellowship = [string, number]; export default function Governance (): React.ReactElement { useFullscreen(); - const { t } = useTranslation(); - const { state } = useLocation(); const theme = useTheme(); + const { t } = useTranslation(); + const { state } = useLocation() as unknown as {state: {selectedSubMenu?: string}}; const { address, topMenu } = useParams<{ address: string, topMenu: 'referenda' | 'fellowship' }>(); - const api = useApi(address); - const chain = useChain(address); - const chainName = useChainName(address); + + const { api, chain, chainName } = useInfo(address); const decidingCounts = useDecidingCount(address); const chainChangeRef = useRef(''); const refsContext = useContext(ReferendaContext); @@ -47,8 +46,9 @@ export default function Governance (): React.ReactElement { const { fellowshipTracks, tracks } = useTracks(address); const pageTrackRef = useRef({ listFinished: false, page: 1, subMenu: 'All', topMenu }); + const [menuOpen, setMenuOpen] = useState(false); - const [selectedSubMenu, setSelectedSubMenu] = useState(state?.selectedSubMenu as string || 'All'); + const [selectedSubMenu, setSelectedSubMenu] = useState(state?.selectedSubMenu || 'All'); const [referendumCount, setReferendumCount] = useState<{ referenda: number | undefined, fellowship: number | undefined }>({ fellowship: undefined, referenda: undefined }); const [referenda, setReferenda] = useState(); const [filteredReferenda, setFilteredReferenda] = useState(); @@ -77,7 +77,7 @@ export default function Governance (): React.ReactElement { fetchJson(); }, []); - const referendaTrackId = tracks?.find((t) => String(t[1].name) === selectedSubMenu.toLowerCase().replace(' ', '_'))?.[0]?.toNumber() as number; + const referendaTrackId = tracks?.find((t) => String(t[1].name) === selectedSubMenu.toLowerCase().replace(' ', '_'))?.[0]?.toNumber()!; // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const currentTrack = useMemo(() => { if (!tracks && !fellowshipTracks) { @@ -131,7 +131,7 @@ export default function Governance (): React.ReactElement { return; } - if (!api.consts.referenda || !api.query.referenda) { + if (!api.consts['referenda'] || !api.query['referenda']) { console.log('OpenGov is not supported on this chain'); setNotSupportedChain(true); // to reset refs on non supported chain, or when chain has changed @@ -143,19 +143,23 @@ export default function Governance (): React.ReactElement { setNotSupportedChain(false); - api.query.referenda.referendumCount().then((count) => { - referendumCount.referenda = count?.toNumber(); + api.query['referenda']['referendumCount']().then((count) => { + referendumCount.referenda = (count as u32)?.toNumber(); setReferendumCount({ ...referendumCount }); }).catch(console.error); - api.query.fellowshipReferenda && api.query.fellowshipReferenda.referendumCount().then((count) => { - referendumCount.fellowship = count?.toNumber(); + api.query['fellowshipReferenda']?.['referendumCount']().then((count) => { + referendumCount.fellowship = (count as u32)?.toNumber(); setReferendumCount({ ...referendumCount }); }).catch(console.error); // eslint-disable-next-line react-hooks/exhaustive-deps }, [api, chainName]); const addFellowshipOriginsFromSb = useCallback(async (resPA: LatestReferenda[]): Promise => { + if (!chainName) { + return; + } + const resSb = await getReferendumsListSb(chainName, topMenu, pageTrackRef.current.page * LATEST_REFERENDA_LIMIT_TO_LOAD_PER_REQUEST); if (resSb) { @@ -297,8 +301,9 @@ export default function Governance (): React.ReactElement { return; } - api.query.fellowshipCollective && api.query.fellowshipCollective.members.entries().then((keys) => { + api.query['fellowshipCollective']?.['members'].entries().then((keys) => { const fellowships = keys.map(([{ args: [id] }, option]) => { + //@ts-ignore return [id.toString(), option?.value?.rank?.toNumber()] as Fellowship; }); @@ -312,6 +317,47 @@ export default function Governance (): React.ReactElement { setGetMore(pageTrackRef.current.page); }, [pageTrackRef]); + const observerInstance = useRef(); + const target = document.getElementById('observerObj'); + + useEffect(() => { + const observerCallback = (entries: IntersectionObserverEntry[]): void => { + const [entry] = entries; + + if (!entry.isIntersecting) { + return; // If the observer object is not in view, do nothing + } + + if (isLoadingMore) { + return; // If already fetching, do nothing + } + + if (pageTrackRef.current.listFinished) { + observerInstance.current?.disconnect(); + + return; + } + + getMoreReferenda(); + }; + + const options = { + root: document.getElementById('scrollArea'), + rootMargin: '0px', + threshold: 1.0 // Trigger when 100% of the target (observerObj) is visible + }; + + observerInstance.current = new IntersectionObserver(observerCallback, options); + + if (target) { + observerInstance.current.observe(target); // Start observing the target + } + + return () => { + observerInstance.current?.disconnect(); + }; + }, [chainName, getMoreReferenda, isLoadingMore, target]); + return ( <> @@ -335,16 +381,19 @@ export default function Governance (): React.ReactElement { decidingCounts={decidingCounts} menuOpen={menuOpen} setMenuOpen={setMenuOpen} + // @ts-ignore setSelectedSubMenu={setSelectedSubMenu} /> - + {selectedSubMenu === 'All' ? {notSupportedChain - ? + ? {t('Open Governance is not supported on the {{chainName}}', { replace: { chainName } })} : !!referenda?.length && referendumCount[topMenu] && referenda.length < (referendumCount[topMenu] || 0) ? - {t('Loaded {{count}} out of {{referendumCount}} referenda. Click here to load more', { replace: { count: referenda?.length || 0, referendumCount: referendumCount[topMenu] } })} +
: {t('No more referenda to load.')} @@ -404,6 +453,9 @@ export default function Governance (): React.ReactElement { : isLoadingMore && + + {t('Loaded {{count}} out of {{referendumCount}} referenda ...', { replace: { count: referenda?.length || 0, referendumCount: referendumCount[topMenu] } })} + } diff --git a/packages/extension-polkagate/src/fullscreen/governance/post/Chronology.tsx b/packages/extension-polkagate/src/fullscreen/governance/post/Chronology.tsx index 8502f294a..c7ca8436a 100644 --- a/packages/extension-polkagate/src/fullscreen/governance/post/Chronology.tsx +++ b/packages/extension-polkagate/src/fullscreen/governance/post/Chronology.tsx @@ -137,7 +137,7 @@ export default function Chronology ({ address, currentTreasuryApprovalList, refe {!expanded && - {`(${sortedHistory?.length ? treasuryLabel || pascalCaseToTitleCase(sortedHistory[0].status)?.trim() : 'Unknown'})`} + ({ isTreasury && isExecuted ? treasuryLabel : sortedHistory?.length ? treasuryLabel || pascalCaseToTitleCase(sortedHistory[0].status)?.trim() : ''}) } diff --git a/packages/extension-polkagate/src/fullscreen/governance/topMenu/FellowshipMenu.tsx b/packages/extension-polkagate/src/fullscreen/governance/topMenu/FellowshipMenu.tsx index e4fd94b7c..277d9f73b 100644 --- a/packages/extension-polkagate/src/fullscreen/governance/topMenu/FellowshipMenu.tsx +++ b/packages/extension-polkagate/src/fullscreen/governance/topMenu/FellowshipMenu.tsx @@ -1,15 +1,15 @@ // Copyright 2019-2024 @polkadot/extension-polkagate authors & contributors // SPDX-License-Identifier: Apache-2.0 -// @ts-nocheck /* eslint-disable react/jsx-max-props-per-line */ +import type { Count } from '../../../hooks/useDecidingCount'; + import { AdminPanelSettings as AdminsIcon, BorderAll as All, Groups3 as Groups3Icon, List as ListIcon } from '@mui/icons-material/'; import { Container, Grid, Typography, useTheme } from '@mui/material'; import React, { useCallback } from 'react'; import { useHistory } from 'react-router-dom'; -import { Count } from '../../../hooks/useDecidingCount'; import { MAX_WIDTH } from '../utils/consts'; import { findItemDecidingCount } from './ReferendaMenu'; @@ -21,7 +21,7 @@ interface Props { } -export default function FellowshipMenu({ address, decidingCounts, setMenuOpen, setSelectedSubMenu }: Props): React.ReactElement { +export default function FellowshipMenu ({ address, decidingCounts, setMenuOpen, setSelectedSubMenu }: Props): React.ReactElement { const history = useHistory(); const theme = useTheme(); @@ -29,7 +29,7 @@ export default function FellowshipMenu({ address, decidingCounts, setMenuOpen, s setMenuOpen(false); }, [setMenuOpen]); - function MenuItem({ borderWidth = '2px', clickable = true, fontWeight, icon, item, top = false, width = '18%' }: { item: string, icon?: React.ReactElement, top?: boolean, width?: string, borderWidth?: string, fontWeight?: number, clickable?: boolean }): React.ReactElement { + function MenuItem ({ borderWidth = '2px', clickable = true, fontWeight, icon, item, top = false, width = '18%' }: { item: string, icon?: React.ReactElement, top?: boolean, width?: string, borderWidth?: string, fontWeight?: number, clickable?: boolean }): React.ReactElement { const decidingCount = findItemDecidingCount(item, decidingCounts); const onSubMenuClick = useCallback(() => { @@ -44,7 +44,9 @@ export default function FellowshipMenu({ address, decidingCounts, setMenuOpen, s return ( {icon} diff --git a/packages/extension-polkagate/src/fullscreen/governance/topMenu/ReferendaMenu.tsx b/packages/extension-polkagate/src/fullscreen/governance/topMenu/ReferendaMenu.tsx index e769f6f34..a51d0febe 100644 --- a/packages/extension-polkagate/src/fullscreen/governance/topMenu/ReferendaMenu.tsx +++ b/packages/extension-polkagate/src/fullscreen/governance/topMenu/ReferendaMenu.tsx @@ -1,15 +1,15 @@ // Copyright 2019-2024 @polkadot/extension-polkagate authors & contributors // SPDX-License-Identifier: Apache-2.0 -// @ts-nocheck /* eslint-disable react/jsx-max-props-per-line */ +import type { Count } from '../../../hooks/useDecidingCount'; + import { AccountBalance as TreasuryIcon, AdminPanelSettings as AdminsIcon, BorderAll as All, Cancel, Hub as Root } from '@mui/icons-material/'; import { Container, Grid, Typography, useTheme } from '@mui/material'; import React, { useCallback } from 'react'; import { useHistory } from 'react-router-dom'; -import { Count } from '../../../hooks/useDecidingCount'; import { MAX_WIDTH } from '../utils/consts'; interface Props { @@ -30,7 +30,7 @@ export const findItemDecidingCount = (item: string, decidingCounts: Count[] | un return filtered?.[1]; }; -export default function ReferendaMenu({ address, decidingCounts, setMenuOpen, setSelectedSubMenu }: Props): React.ReactElement { +export default function ReferendaMenu ({ address, decidingCounts, setMenuOpen, setSelectedSubMenu }: Props): React.ReactElement { const history = useHistory(); const theme = useTheme(); const onMouseLeave = useCallback(() => { @@ -51,7 +51,9 @@ export default function ReferendaMenu({ address, decidingCounts, setMenuOpen, se return ( {icon} diff --git a/packages/extension-polkagate/src/fullscreen/governance/utils/consts.ts b/packages/extension-polkagate/src/fullscreen/governance/utils/consts.ts index 5be5c0339..f6a31ef37 100644 --- a/packages/extension-polkagate/src/fullscreen/governance/utils/consts.ts +++ b/packages/extension-polkagate/src/fullscreen/governance/utils/consts.ts @@ -4,7 +4,7 @@ import { BN } from '@polkadot/util'; export const MAX_WIDTH = '1280px'; -export const LATEST_REFERENDA_LIMIT_TO_LOAD_PER_REQUEST = 30; +export const LATEST_REFERENDA_LIMIT_TO_LOAD_PER_REQUEST = 50; export const TRACK_LIMIT_TO_LOAD_PER_REQUEST = LATEST_REFERENDA_LIMIT_TO_LOAD_PER_REQUEST; export const REFERENDA_LIMIT_SAVED_LOCAL = 2 * LATEST_REFERENDA_LIMIT_TO_LOAD_PER_REQUEST; diff --git a/packages/extension-polkagate/src/fullscreen/governance/utils/helpers.ts b/packages/extension-polkagate/src/fullscreen/governance/utils/helpers.ts index 49bdbada3..b15638857 100644 --- a/packages/extension-polkagate/src/fullscreen/governance/utils/helpers.ts +++ b/packages/extension-polkagate/src/fullscreen/governance/utils/helpers.ts @@ -253,7 +253,6 @@ export async function getAllVotesFromPA (chainName: string, refIndex: number, li headers: { 'x-network': chainName.charAt(0).toLowerCase() + chainName.slice(1) } }; - // return fetch(`https://api.polkassembly.io/api/v1/votes?postId=${refIndex}&page=1&listingLimit=${listingLimit}&voteType=${isFellowship ? 'Fellowship' : 'ReferendumV2'}&sortBy=time`, requestOptions) // eslint-disable-next-line @typescript-eslint/no-unsafe-return return fetch(`https://api.polkassembly.io/api/v1/votes?postId=${refIndex}&page=1&listingLimit=${listingLimit}&voteType=${isFellowship ? 'Fellowship' : 'ReferendumV2'}`, requestOptions) .then((response) => response.json()) @@ -395,13 +394,13 @@ interface RefListSb { }[]; } -export async function getReferendumsListSb (chainName: string, type: TopMenu, listingLimit = 30): Promise { +export async function getReferendumsListSb (chainName: string, type: 'referenda' | 'fellowship', listingLimit = 30): Promise { console.log('Getting ref list from sb ...'); return new Promise((resolve) => { try { // eslint-disable-next-line @typescript-eslint/no-floating-promises - postData('https://' + chainName + `.api.subscan.io/api/scan/${type.toLocaleLowerCase()}/referendums`, + postData('https://' + chainName + `.api.subscan.io/api/scan/${type.toLowerCase()}/referendums`, { // page:1, row: listingLimit