diff --git a/package.json b/package.json index 9e5c6b1b85..2bd212f0f8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "givethdapp", - "version": "2.33.0", + "version": "2.33.1", "private": true, "scripts": { "build": "next build", diff --git a/pages/_app.tsx b/pages/_app.tsx index 09d9ab89f4..75b114644f 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -67,7 +67,7 @@ export const IntlMessages = { const defaultLocale = process.env.defaultLocale; // Check that PostHog is client-side (used to handle Next.js SSR) -if (typeof window !== 'undefined') { +if (typeof window !== 'undefined' && isProduction) { posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY || '', { api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST || 'https://us.i.posthog.com', diff --git a/src/components/modals/SearchModal.tsx b/src/components/modals/SearchModal.tsx index 64c1ed5b35..cd3195a5b3 100644 --- a/src/components/modals/SearchModal.tsx +++ b/src/components/modals/SearchModal.tsx @@ -108,7 +108,15 @@ export const SearchModal: FC = ({ setShowModal }) => { useEffect(() => { if (term) { - router.push(`${Routes.AllProjects}?searchTerm=${term}`); + const updatedQuery = { + ...router.query, + searchTerm: term, + sort: EProjectsSortBy.BestMatch, + }; + router.push({ + pathname: Routes.AllProjects, + query: updatedQuery, + }); closeModal(); } }, [closeModal, router, term]); diff --git a/src/components/project-card/ProjectCard.tsx b/src/components/project-card/ProjectCard.tsx index 5612a7ecd9..9dfd88caa6 100644 --- a/src/components/project-card/ProjectCard.tsx +++ b/src/components/project-card/ProjectCard.tsx @@ -147,7 +147,6 @@ const ProjectCard = (props: IProjectCard) => { ); setRecurringDonationSumInQF(totalAmountStreamed); } - console.log(id, totalAmountStreamed); } }; diff --git a/src/components/views/donate/DonateIndex.tsx b/src/components/views/donate/DonateIndex.tsx index 7369bf6b1e..f6f38df6ff 100644 --- a/src/components/views/donate/DonateIndex.tsx +++ b/src/components/views/donate/DonateIndex.tsx @@ -11,7 +11,6 @@ import { Flex, B, Button, - H4, } from '@giveth/ui-design-system'; import { useIntl } from 'react-intl'; import { useRouter } from 'next/router'; @@ -459,41 +458,4 @@ const ButtonStyled = styled(Button)` text-transform: capitalize; `; -const ProjectImage = styled.img` - border-radius: 16px; - width: 100%; - object-fit: cover; // Ensures the image covers the entire container - height: 380px; - position: relative; -`; - -const GradientOverlay = styled.div` - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 380px; - background: linear-gradient( - to top, - rgba(1, 1, 27, 0.6), - transparent - ); /* Dark navy to transparent gradient */ - border-radius: 16px; -`; - -const Title = styled(H4)` - position: absolute; - bottom: 40px; - left: 40px; - color: #ffffff; - font-weight: bold; - text-align: left; - z-index: 1; - max-width: 90%; // Set max-width to a suitable percentage value based on your preference - white-space: pre-wrap; // Allows the text to wrap to the next line - > div:first-child { - margin-bottom: 4px; - } -`; - export default DonateIndex; diff --git a/src/components/views/donate/DonatePageProjectDescription.tsx b/src/components/views/donate/DonatePageProjectDescription.tsx index f45b7a699d..8c4608c138 100644 --- a/src/components/views/donate/DonatePageProjectDescription.tsx +++ b/src/components/views/donate/DonatePageProjectDescription.tsx @@ -5,7 +5,6 @@ import { P, IconChevronRight16, brandColors, - mediaQueries, Flex, H5, semanticColors, @@ -230,12 +229,6 @@ const DescriptionSummary = styled(P)` const DonationSectionWrapper = styled(Flex)` justify-content: space-between; flex-direction: column; - ${mediaQueries.tablet} { - flex-direction: row; - } - ${mediaQueries.laptopS} { - flex-direction: column; - } `; const DonateDescription = styled(Flex)` diff --git a/src/components/views/donate/OneTime/SelectTokenModal/SelectTokenModal.tsx b/src/components/views/donate/OneTime/SelectTokenModal/SelectTokenModal.tsx index 00a154a276..f5dbe4f97e 100644 --- a/src/components/views/donate/OneTime/SelectTokenModal/SelectTokenModal.tsx +++ b/src/components/views/donate/OneTime/SelectTokenModal/SelectTokenModal.tsx @@ -26,8 +26,8 @@ import { useGeneralWallet } from '@/providers/generalWalletProvider'; import { wagmiConfig } from '@/wagmiConfigs'; import { ChainType } from '@/types/config'; import { getBalanceForToken } from './services'; -import { fetchTokenBalances } from '@/services/token'; -import { Spinner } from '@/components/Spinner'; +import { fetchEVMTokenBalances } from '@/services/token'; +import { WrappedSpinner } from '@/components/Spinner'; export interface ISelectTokenModalProps extends IModal { tokens?: IProjectAcceptedToken[]; @@ -181,7 +181,7 @@ const SelectTokenInnerModal: FC = ({ try { setBalanceIsLoading(true); const balances = isOnEVM - ? await fetchTokenBalances(filteredTokens, walletAddress) + ? await fetchEVMTokenBalances(filteredTokens, walletAddress) : await Promise.all( filteredTokens.map(async token => { return { @@ -195,7 +195,7 @@ const SelectTokenInnerModal: FC = ({ }), ); setTokenBalances(balances); - setBalanceIsLoading(true); + setBalanceIsLoading(false); } catch (error) { console.error('error on fetchTokenBalances', { error }); } @@ -264,7 +264,7 @@ const SelectTokenInnerModal: FC = ({ /> )) ) : balanceIsLoading ? ( - + ) : (
No token supported on this chain
)} diff --git a/src/components/views/donate/Recurring/SelectTokenModal/SelectTokenModal.tsx b/src/components/views/donate/Recurring/SelectTokenModal/SelectTokenModal.tsx index 182b5bf965..b6aa89e915 100644 --- a/src/components/views/donate/Recurring/SelectTokenModal/SelectTokenModal.tsx +++ b/src/components/views/donate/Recurring/SelectTokenModal/SelectTokenModal.tsx @@ -17,7 +17,7 @@ import { Modal } from '@/components/modals/Modal'; import { useModalAnimation } from '@/hooks/useModalAnimation'; import config from '@/configuration'; import { TokenInfo } from './TokenInfo'; -import { fetchBalance } from '@/services/token'; +import { fetchEVMTokenBalances } from '@/services/token'; import { ISuperToken, IToken } from '@/types/superFluid'; import { StreamInfo } from './StreamInfo'; import { useDonateData } from '@/context/donate.context'; @@ -65,20 +65,6 @@ const SelectTokenInnerModal: FC = ({ return; } - // A helper function to fetch balance for a single token - const fetchTokenBalance = async (token: IToken) => { - try { - const balance = await fetchBalance(token.id, address); - return { symbol: token.symbol, balance }; - } catch (error) { - console.error( - `Error fetching balance for ${token.symbol}:`, - error, - ); - return { symbol: token.symbol, balance: undefined }; - } - }; - // Initiate all balance fetches concurrently const fetchAllBalances = async () => { const _allTokens = superTokens.reduce((acc, token) => { @@ -87,18 +73,13 @@ const SelectTokenInnerModal: FC = ({ return acc; }, [] as IToken[]); - // Create an array of promises for each token balance fetch - const balancePromises = _allTokens.map(token => - fetchTokenBalance(token), - ); - // Wait for all promises to settle - const results = await Promise.all(balancePromises); + const results = await fetchEVMTokenBalances(_allTokens, address); // Process results into a new balances object - const newBalances = results.reduce((acc, { symbol, balance }) => { + const newBalances = results.reduce((acc, { token, balance }) => { if (balance !== undefined) { - acc[symbol] = balance; + acc[token.symbol] = balance; } return acc; }, {} as IBalances); @@ -148,7 +129,7 @@ const SelectTokenInnerModal: FC = ({ const token = superTokens.find( token => token.id === tokenId, ) as IToken; - return ( + return token ? ( = ({ }} isSuperToken={!!token.isSuperToken} /> - ); + ) : null; })} {superTokens.map(token => tokenStreams[token.id] || diff --git a/src/config/production.tsx b/src/config/production.tsx index 88666e3a79..27c51ceb91 100644 --- a/src/config/production.tsx +++ b/src/config/production.tsx @@ -537,6 +537,21 @@ const config: EnvConfig = { isSuperToken: true, coingeckoId: 'usd-coin', }, + { + underlyingToken: { + decimals: 18, + id: '0x4F604735c1cF31399C6E711D5962b2B3E0225AD3', + name: 'Glo Dollar', + symbol: 'USDGLO', + coingeckoId: 'glo-dollar', + }, + decimals: 18, + id: '0x9F41d0AA24E599fd8D0c180Ee3C0F609dc41c622', + name: 'Super Glo Dollar', + symbol: 'USDGLOx', + isSuperToken: true, + coingeckoId: 'glo-dollar', + }, ], }, diff --git a/src/services/givpower.ts b/src/services/givpower.ts index 158178847a..0367b3952a 100644 --- a/src/services/givpower.ts +++ b/src/services/givpower.ts @@ -33,7 +33,8 @@ export const getGIVpowerBalanceByAddress = async (users: string[]) => { console.log('unipool balances res', res); const unipoolBalancesObj: { [key: string]: string } = {}; for (let i = 0; i < res.length; i++) { - const unipoolBalances = res[i].data.unipoolBalances; + const unipoolBalances = res[i].data?.unipoolBalances; + if (!unipoolBalances) continue; for (let i = 0; i < unipoolBalances.length; i++) { const unipoolBalance = unipoolBalances[i]; let currentBalance = unipoolBalancesObj[unipoolBalance.user.id]; diff --git a/src/services/token.ts b/src/services/token.ts index 26e907859f..67f0123e65 100644 --- a/src/services/token.ts +++ b/src/services/token.ts @@ -13,6 +13,7 @@ import { FETCH_MAINNET_TOKEN_PRICES, } from '@/apollo/gql/gqlPrice'; import { IProjectAcceptedToken } from '@/apollo/types/gqlTypes'; +import { IToken } from '@/types/superFluid'; export const fetchPrice = async ( chainId: number | ChainType, @@ -56,27 +57,42 @@ export const fetchBalance = async ( } }; -export const fetchTokenBalances = async ( - tokens: IProjectAcceptedToken[], +export const fetchEVMTokenBalances = async < + T extends IProjectAcceptedToken | IToken, +>( + tokens: T[], // Generic type constrained to IProjectAcceptedToken or IToken walletAddress: string | null, -) => { +): Promise<{ token: T; balance: bigint | undefined }[]> => { if (!walletAddress || !tokens || tokens.length === 0) return []; // Filter out native tokens - const erc20Tokens: IProjectAcceptedToken[] = []; - const nativeTokens: IProjectAcceptedToken[] = []; + const erc20Tokens: T[] = []; + const nativeTokens: T[] = []; + + // Use the correct property name based on the generic token type + const addressLabel = 'address' in tokens[0] ? 'address' : 'id'; + tokens.forEach(token => { - token.address !== AddressZero - ? erc20Tokens.push(token) - : nativeTokens.push(token); + const tokenAddress = token[addressLabel as keyof T] as string; + + if (tokenAddress !== AddressZero) { + erc20Tokens.push(token); + } else { + nativeTokens.push(token); + } }); - const erc20Calls = erc20Tokens.map(token => ({ - address: token.address, - abi: erc20Abi, - functionName: 'balanceOf', - args: [walletAddress], - })); + const erc20Calls = erc20Tokens.map(token => { + const tokenAddress = token[addressLabel as keyof T] as string; + + // Ensure the tokenAddress is cast as Address (format starting with 0x) + return { + address: tokenAddress as Address, // Cast to wagmi Address type + abi: erc20Abi, + functionName: 'balanceOf', + args: [walletAddress], + }; + }); try { // Fetch balances for ERC20 tokens via multicall @@ -107,7 +123,7 @@ export const fetchTokenBalances = async ( // Combine ERC20 and native token balances return [...erc20Balances, ...nativeTokenBalances]; } catch (error) { - console.error('Error fetching token balances:', error); + console.error('Error fetching EVM token balances:', error); // Return undefined balances in case of failure return tokens.map(token => ({ token, balance: undefined }));