diff --git a/packages/app/src/components/DonorsList/DonorsList.tsx b/packages/app/src/components/DonorsList/DonorsList.tsx
index 3ae7e416..8af41762 100644
--- a/packages/app/src/components/DonorsList/DonorsList.tsx
+++ b/packages/app/src/components/DonorsList/DonorsList.tsx
@@ -24,12 +24,13 @@ function DonorsList({ donors, listStyle }: DonorsListProps) {
const userAddresses = useMemo(() => {
return sortedDonors.map((donor) => donor.donor as `0x${string}`);
}, [sortedDonors]);
+
const userFullNames = useFetchFullNames(userAddresses);
return (
{sortedDonors.map((donor, index) => (
-
+
))}
);
diff --git a/packages/app/src/components/DonorsList/DonorsListItem.tsx b/packages/app/src/components/DonorsList/DonorsListItem.tsx
index 752c8c53..d7eda602 100644
--- a/packages/app/src/components/DonorsList/DonorsListItem.tsx
+++ b/packages/app/src/components/DonorsList/DonorsListItem.tsx
@@ -7,6 +7,7 @@ import Decimal from 'decimal.js';
import { formatAddress } from '../../lib/formatAddress';
import { ethers } from 'ethers';
import { useEnsName } from 'wagmi';
+import { useFlowingBalance } from '../../hooks/useFlowingBalance';
interface DonorsListItemProps {
donor: DonorCollective;
@@ -14,13 +15,14 @@ interface DonorsListItemProps {
userFullName?: string;
}
-export const DonorsListItem = (props: DonorsListItemProps) => {
- const { donor, rank, userFullName } = props;
+export const DonorsListItem = ({ donor, rank, userFullName }: DonorsListItemProps) => {
const { navigate } = useCrossNavigate();
- const formattedDonations: string = new Decimal(ethers.utils.formatEther(donor.contribution) ?? 0).toFixed(
- 2,
- Decimal.ROUND_DOWN
+ const { formatted: formattedDonations } = useFlowingBalance(
+ donor.contribution,
+ donor.timestamp,
+ donor.flowRate,
+ undefined
);
const { data: ensName } = useEnsName({ address: donor.donor as `0x${string}`, chainId: 1 });
diff --git a/packages/app/src/components/FlowingCurrentPoolRowItem.tsx b/packages/app/src/components/FlowingCurrentPoolRowItem.tsx
index 61266dbf..4468acb5 100644
--- a/packages/app/src/components/FlowingCurrentPoolRowItem.tsx
+++ b/packages/app/src/components/FlowingCurrentPoolRowItem.tsx
@@ -6,6 +6,7 @@ import { useDonorCollectivesFlowingBalancesWithAltStaticBalance } from '../hooks
import { DonorCollective } from '../models/models';
import { useGetTokenBalance } from '../hooks/useGetTokenBalance';
import { SupportedNetwork } from '../models/constants';
+import Decimal from 'decimal.js';
interface FlowingDonationsRowItemProps {
rowInfo: string;
@@ -14,6 +15,7 @@ interface FlowingDonationsRowItemProps {
tokenPrice: number | undefined;
currency?: string;
imageUrl: string;
+ additionalBalance?: string;
}
function FlowingDonationsRowItem({
@@ -23,14 +25,18 @@ function FlowingDonationsRowItem({
tokenPrice,
currency,
imageUrl,
+ additionalBalance,
}: FlowingDonationsRowItemProps) {
const [isDesktopResolution] = useMediaQuery({
minWidth: 920,
});
const currentBalance = useGetTokenBalance('G$', collective, SupportedNetwork.CELO);
+ const balanceUsed = additionalBalance
+ ? new Decimal(currentBalance).add(additionalBalance).toFixed(0, Decimal.ROUND_DOWN)
+ : currentBalance;
const { formatted: formattedCurrentPool, usdValue: usdValueCurrentPool } =
- useDonorCollectivesFlowingBalancesWithAltStaticBalance(currentBalance, donorCollectives, tokenPrice);
+ useDonorCollectivesFlowingBalancesWithAltStaticBalance(balanceUsed, donorCollectives, tokenPrice);
return (
diff --git a/packages/app/src/components/Header/ConnectedAccountDisplay.tsx b/packages/app/src/components/Header/ConnectedAccountDisplay.tsx
index 9584294b..9f65613d 100644
--- a/packages/app/src/components/Header/ConnectedAccountDisplay.tsx
+++ b/packages/app/src/components/Header/ConnectedAccountDisplay.tsx
@@ -1,11 +1,13 @@
import { Image, StyleSheet, Text, View } from 'react-native';
+import { useEnsName, useNetwork } from 'wagmi';
+
import { InterRegular } from '../../utils/webFonts';
import { formatAddress } from '../../lib/formatAddress';
-import { useEnsName, useNetwork } from 'wagmi';
import { Colors } from '../../utils/colors';
import { PlaceholderAvatar } from '../../assets';
import { useGetTokenBalance } from '../../hooks/useGetTokenBalance';
import { formatNumberWithCommas } from '../../lib/formatFiatCurrency';
+import { SupportedNetwork } from '../../models/constants';
interface ConnectedAccountDisplayProps {
isDesktopResolution: boolean;
@@ -17,8 +19,9 @@ export const ConnectedAccountDisplay = (props: ConnectedAccountDisplayProps) =>
const { chain } = useNetwork();
let chainName = chain?.name.replace(/\d+|\s/g, '');
- if (chainName !== 'Celo') {
- chainName = 'None';
+ console.log('chainName', { chainName, chain: chain });
+ if (!(chainName && chainName.toUpperCase() in SupportedNetwork)) {
+ chainName = 'Unsupported Network';
}
const tokenBalance = useGetTokenBalance('G$', address, chain?.id, true);
@@ -33,7 +36,7 @@ export const ConnectedAccountDisplay = (props: ConnectedAccountDisplayProps) =>
{chainName}
diff --git a/packages/app/src/components/RowItem.tsx b/packages/app/src/components/RowItem.tsx
index 91eb8758..b8516981 100644
--- a/packages/app/src/components/RowItem.tsx
+++ b/packages/app/src/components/RowItem.tsx
@@ -25,15 +25,15 @@ function RowItem({ rowInfo, rowData, balance, currency, imageUrl }: RowItemProps
{rowInfo}
-
-
+
+
{currency} {rowData}
{isDesktopResolution && currency && = {usdBalance} USD}
{!isDesktopResolution && currency && = {usdBalance} USD}
-
-
+
+
);
}
diff --git a/packages/app/src/components/StewardsList/StewardsList.tsx b/packages/app/src/components/StewardsList/StewardsList.tsx
index 6f0cc632..a8f5aaca 100644
--- a/packages/app/src/components/StewardsList/StewardsList.tsx
+++ b/packages/app/src/components/StewardsList/StewardsList.tsx
@@ -41,7 +41,7 @@ function StewardList({ listType, stewards, titleStyle, listStyle }: StewardListP
showActions={listType === 'viewStewards'}
key={steward.steward}
profileImage={profileImages[index % profileImages.length]}
- userFullName={userFullNames[index]}
+ userFullName={userFullNames[steward.steward]}
/>
))}
diff --git a/packages/app/src/components/ViewCollective.tsx b/packages/app/src/components/ViewCollective.tsx
index 7052813c..51fa598b 100644
--- a/packages/app/src/components/ViewCollective.tsx
+++ b/packages/app/src/components/ViewCollective.tsx
@@ -30,7 +30,6 @@ import {
WebIcon,
} from '../assets/';
import { calculateGoodDollarAmounts } from '../lib/calculateGoodDollarAmounts';
-import FlowingDonationsRowItem from './FlowingDonationsRowItem';
import { useDeleteFlow } from '../hooks/useContractCalls/useDeleteFlow';
import ErrorModal from './modals/ErrorModal';
import FlowingCurrentPoolRowItem from './FlowingCurrentPoolRowItem';
@@ -189,12 +188,14 @@ function ViewCollective({ collective }: ViewCollectiveProps) {
-
-
| undefined =>
storage: new AsyncStorageWrapper(AsyncStorage),
});
- const client = new ApolloClient({
- cache,
- link: new HttpLink({
- uri: mongoDbUri,
- fetch: async (uri, options) => {
- const accessToken = await getValidAccessToken();
- if (!options) {
- options = {};
- }
- if (!options.headers) {
- options.headers = {};
- }
- (options.headers as Record).Authorization = `Bearer ${accessToken}`;
- return fetch(uri, options);
- },
- }),
- defaultOptions: {
- watchQuery: {
- fetchPolicy: 'cache-and-network',
- },
- query: {
- fetchPolicy: 'cache-first',
- },
+ const httpLink = new HttpLink({
+ uri: mongoDbUri,
+ fetch: async (uri, options) => {
+ const accessToken = await getValidAccessToken();
+ if (!options) {
+ options = {};
+ }
+ if (!options.headers) {
+ options.headers = {};
+ }
+ (options.headers as Record).Authorization = `Bearer ${accessToken}`;
+ return fetch(uri, options);
},
});
- setApolloClient(client);
+
+ try {
+ const client = new ApolloClient({
+ cache,
+ link: from([errorLink, retryLink, httpLink]),
+ defaultOptions: {
+ watchQuery: {
+ fetchPolicy: 'cache-and-network',
+ },
+ query: {
+ fetchPolicy: 'cache-first',
+ },
+ },
+ });
+ setApolloClient(client);
+ } catch (error) {
+ console.error(error);
+ } finally {
+ return;
+ }
}
initApollo().catch(console.error);
diff --git a/packages/app/src/hooks/apollo/useCreateSubgraphApolloClient.ts b/packages/app/src/hooks/apollo/useCreateSubgraphApolloClient.ts
index 30392758..a19904ec 100644
--- a/packages/app/src/hooks/apollo/useCreateSubgraphApolloClient.ts
+++ b/packages/app/src/hooks/apollo/useCreateSubgraphApolloClient.ts
@@ -1,22 +1,28 @@
import { useEffect, useState } from 'react';
-import { ApolloClient, InMemoryCache, NormalizedCacheObject } from '@apollo/client';
+import { ApolloClient, from, HttpLink, InMemoryCache, NormalizedCacheObject } from '@apollo/client';
import { AsyncStorageWrapper, persistCache } from 'apollo3-cache-persist';
import AsyncStorage from '@react-native-async-storage/async-storage';
+import { errorLink, retryLink } from '../../utils/apolloLinkUtils';
+
const subgraphUri = 'https://api.thegraph.com/subgraphs/name/gooddollar/goodcollective';
export const useCreateSubgraphApolloClient = (): ApolloClient | undefined => {
const [apolloClient, setApolloClient] = useState | undefined>();
useEffect(() => {
+ const httpLink = new HttpLink({
+ uri: subgraphUri,
+ });
async function initApollo() {
const cache = new InMemoryCache();
await persistCache({
cache,
storage: new AsyncStorageWrapper(AsyncStorage),
});
+
const client = new ApolloClient({
- uri: subgraphUri,
+ link: from([errorLink, retryLink, httpLink]),
cache,
defaultOptions: {
watchQuery: {
diff --git a/packages/app/src/hooks/useFetchFullName.ts b/packages/app/src/hooks/useFetchFullName.ts
index 424ee79c..78df913c 100644
--- a/packages/app/src/hooks/useFetchFullName.ts
+++ b/packages/app/src/hooks/useFetchFullName.ts
@@ -5,6 +5,12 @@ import { useMongoDbQuery } from './apollo/useMongoDbQuery';
interface UserProfile {
fullName?: { display?: string };
+ index: {
+ walletAddress: {
+ hash: string;
+ display?: string;
+ };
+ };
}
interface UserProfilesResponse {
@@ -17,6 +23,11 @@ const findProfiles = gql`
fullName {
display
}
+ index {
+ walletAddress {
+ hash
+ }
+ }
}
}
`;
@@ -27,22 +38,34 @@ export function useFetchFullName(address?: string): string | undefined {
return names[0];
}
-export function useFetchFullNames(addresses: string[]): (string | undefined)[] {
- const hashedAddresses = useMemo(() => {
- return addresses.map((address: string) => ethers.utils.keccak256(address));
- }, [addresses]);
+export function useFetchFullNames(addresses: string[]): any {
+ const addressToHashMapping = addresses.reduce((acc: any, address) => {
+ const hash = ethers.utils.keccak256(address);
+ acc[hash] = address;
+ return acc;
+ }, {});
+
+ const hashedAddresses = Object.keys(addressToHashMapping);
const { data, error } = useMongoDbQuery(findProfiles, {
- variables: { query: { index: { walletAddress: { hash_in: hashedAddresses } } } },
+ variables: {
+ query: {
+ index: { walletAddress: { hash_in: hashedAddresses } },
+ },
+ },
});
return useMemo(() => {
- if (error) {
- console.error(error);
- }
if (!data || data.user_profiles.length === 0) {
- return [];
+ return {};
}
- return data.user_profiles.map((profile) => profile?.fullName?.display);
- }, [data, error]);
+ return data.user_profiles.reduce((acc: Record, profile) => {
+ if (!profile) return {};
+ const { hash } = profile.index.walletAddress;
+ const { display } = profile.fullName ?? {};
+ const address = addressToHashMapping[hash];
+ acc[address] = display ?? '';
+ return acc;
+ }, {});
+ }, [data, addressToHashMapping]);
}
diff --git a/packages/app/src/hooks/useSwapRoute.tsx b/packages/app/src/hooks/useSwapRoute.tsx
index 104f4d4d..e488a6c7 100644
--- a/packages/app/src/hooks/useSwapRoute.tsx
+++ b/packages/app/src/hooks/useSwapRoute.tsx
@@ -1,7 +1,7 @@
import { AlphaRouter, SwapRoute, SwapType, V3Route } from '@uniswap/smart-order-router';
import { CurrencyAmount, Percent, TradeType } from '@uniswap/sdk-core';
import { useAccount, useNetwork } from 'wagmi';
-import { GDToken } from '../models/constants';
+import { GDToken, SupportedNetwork } from '../models/constants';
import { useEthersSigner } from './useEthersSigner';
import { calculateRawTotalDonation } from '../lib/calculateRawTotalDonation';
import Decimal from 'decimal.js';
@@ -39,13 +39,13 @@ export function useSwapRoute(
const [route, setRoute] = useState(undefined);
useEffect(() => {
- if (!address || !chain?.id || !signer?.provider || tokenIn.symbol === 'G$') {
+ if (!address || !chain?.id || chain.id !== SupportedNetwork.CELO || !signer?.provider || tokenIn.symbol === 'G$') {
setRoute(undefined);
return;
}
const router = new AlphaRouter({
- chainId: chain.id,
+ chainId: chain.id as number,
provider: signer.provider,
});
diff --git a/packages/app/src/utils/apolloLinkUtils.ts b/packages/app/src/utils/apolloLinkUtils.ts
new file mode 100644
index 00000000..d64d8d90
--- /dev/null
+++ b/packages/app/src/utils/apolloLinkUtils.ts
@@ -0,0 +1,27 @@
+import { onError } from '@apollo/client/link/error';
+import { RetryLink } from '@apollo/client/link/retry';
+
+// ref:https://www.apollographql.com/docs/react/data/error-handling/#advanced-error-handling-with-apollo-link
+export const errorLink = onError(({ graphQLErrors, networkError }) => {
+ if (graphQLErrors)
+ graphQLErrors.forEach(({ message, locations, path }) =>
+ console.error(`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`)
+ );
+ if (networkError) {
+ console.error(`[Network error]: ${networkError}`);
+ throw networkError;
+ }
+});
+
+// ref: https://www.apollographql.com/docs/react/api/link/apollo-link-retry/
+export const retryLink = new RetryLink({
+ delay: {
+ initial: 500,
+ max: Infinity,
+ jitter: true,
+ },
+ attempts: {
+ max: 3,
+ retryIf: (error, _operation) => !!error,
+ },
+});