diff --git a/packages/app/index.js b/packages/app/index.js index e3744aff..1cb00b3a 100644 --- a/packages/app/index.js +++ b/packages/app/index.js @@ -1,4 +1,3 @@ -import React from 'react'; // Import the crypto getRandomValues shim (**BEFORE** the shims) import 'react-native-get-random-values'; diff --git a/packages/app/src/components/CollectiveHomeCard.tsx b/packages/app/src/components/CollectiveHomeCard.tsx index 90ce7917..a895fbd6 100644 --- a/packages/app/src/components/CollectiveHomeCard.tsx +++ b/packages/app/src/components/CollectiveHomeCard.tsx @@ -1,4 +1,4 @@ -import { Image, StyleSheet, Text, TouchableOpacity, TouchableOpacityProps, View } from 'react-native'; +import { Image, StyleSheet, Text, TouchableOpacity, View } from 'react-native'; import { InterSemiBold, InterSmall } from '../utils/webFonts'; import useCrossNavigate from '../routes/useCrossNavigate'; diff --git a/packages/app/src/components/ImpactButton.tsx b/packages/app/src/components/ImpactButton.tsx index 35bcb017..7ae280c9 100644 --- a/packages/app/src/components/ImpactButton.tsx +++ b/packages/app/src/components/ImpactButton.tsx @@ -1,4 +1,4 @@ -import { Image, Text, TouchableOpacity, View, StyleSheet } from 'react-native'; +import { Image, Platform, Text, TouchableOpacity, View, StyleSheet } from 'react-native'; import { InterSemiBold } from '../utils/webFonts'; import { Colors } from '../utils/colors'; @@ -14,7 +14,13 @@ function ImpactButton({ title, onClick }: ImpactButtonProps) { const { isDesktopView } = useScreenSize(); return ( - + {title} diff --git a/packages/app/src/components/Layout/Layout.tsx b/packages/app/src/components/Layout/Layout.tsx index dc12b005..cee63f70 100644 --- a/packages/app/src/components/Layout/Layout.tsx +++ b/packages/app/src/components/Layout/Layout.tsx @@ -41,7 +41,7 @@ function Layout({ children, breadcrumbPath }: LayoutProps) { styles.scrollView, { ...(!isMobileView && { maxHeight: scrollViewHeight, minHeight: scrollViewHeight }) }, { paddingBottom: isCollectivePage ? 61 : 0 }, - { paddingHorizontal: isTabletView ? 48 : isMobileView ? 8 : 24 }, + { paddingHorizontal: isTabletView ? 48 : isMobileView ? 0 : isCollectivePage ? 0 : 24 }, ]; return ( diff --git a/packages/app/src/components/ViewCollective.tsx b/packages/app/src/components/ViewCollective.tsx index e1668a9c..ff13e62f 100644 --- a/packages/app/src/components/ViewCollective.tsx +++ b/packages/app/src/components/ViewCollective.tsx @@ -1,5 +1,5 @@ -import { StyleSheet, Text, Image } from 'react-native'; -import { Link, View } from 'native-base'; +import { StyleSheet, Image } from 'react-native'; +import { Link, useBreakpointValue, Text, View, VStack } from 'native-base'; import { useAccount, useEnsName } from 'wagmi'; import RowItem from './RowItem'; @@ -13,7 +13,7 @@ import { Colors } from '../utils/colors'; import { useScreenSize } from '../theme/hooks'; import { formatTime } from '../lib/formatTime'; -import { Collective } from '../models/models'; +import { Collective, DonorCollective } from '../models/models'; import { useDonorCollectiveByAddresses, useGetTokenPrice } from '../hooks'; import { AtIcon, @@ -33,11 +33,138 @@ import { } from '../assets/'; import { calculateGoodDollarAmounts } from '../lib/calculateGoodDollarAmounts'; import FlowingDonationsRowItem from './FlowingDonationsRowItem'; -import { defaultInfoLabel, SUBGRAPH_POLL_INTERVAL } from '../models/constants'; +import { defaultInfoLabel, GDToken, SUBGRAPH_POLL_INTERVAL } from '../models/constants'; import env from '../lib/env'; -import { ActiveStreamCard } from './ActiveStreamCard'; -import { WalletDonatedCard } from './WalletCards/WalletDonatedCard'; +import { useGetTokenBalance } from '../hooks/useGetTokenBalance'; +import { useFlowingBalance } from '../hooks/useFlowingBalance'; +import { GoodDollarAmount } from './GoodDollarAmount'; +import { styles as walletCardStyles } from '../components/WalletCards/styles'; +import { formatFlowRate } from '../lib/formatFlowRate'; +import { StopDonationActionButton } from './StopDonationActionButton'; +const HasDonatedCard = ({ + donorCollective, + tokenPrice, +}: { + donorCollective?: DonorCollective; + tokenPrice?: number; +}) => { + const { address } = useAccount(); + const { data: ensName } = useEnsName({ address, chainId: 1 }); + const userName = ensName ?? 'This wallet'; + const { navigate } = useCrossNavigate(); + const isDonating = donorCollective && donorCollective.flowRate !== '0'; + const hasDonated = isDonating || (donorCollective && donorCollective.contribution !== '0'); + const donorBalance = useGetTokenBalance(GDToken.address, donorCollective?.donor as any); + const secondsLeft = isDonating ? Number(BigInt(donorBalance) / BigInt(donorCollective?.flowRate || 1)) : 0; + const endDate = formatTime(Date.now() / 1000 + secondsLeft); + + const { wei: donationsFormatted, usdValue: donationsUsdValue } = useFlowingBalance( + donorCollective?.contribution || '0', + donorCollective?.timestamp || 0, // Timestamp in Subgraph's UTC. + donorCollective?.flowRate || '0', + tokenPrice + ); + const container = useBreakpointValue({ + base: { + flexDirection: 'column', + borderTopWidth: 1, + borderColor: 'goodGrey.600', + gap: 4, + marginTop: 8, + }, + xl: { + gap: 8, + flexDirection: 'row', + borderTopWidth: 1, + borderColor: 'goodGrey.600', + marginTop: 8, + paddingTop: 8, + marginBottom: 8, + justifyContent: 'space-between', + }, + }); + if (!donorCollective || !hasDonated) return null; + return ( + + + + + You {isDonating ? 'Support' : 'Supported'} this GoodCollective!! + + + + {userName} has donated + + G$ + + + = {donationsUsdValue || 0} USD + {isDonating ? ( + + Donation Streaming Rate + G$ {formatFlowRate(donorCollective.flowRate)} / Monthly + + ) : null} + + {/* Stream Rate */} + + {/* Dates */} + + {isDonating ? ( + <> + + Date Initiated + {formatTime(donorCollective.timestamp)} + + + + Estimated End Date + {endDate} + + + ) : null} + + + {/* Buttons */} + + {isDonating ? ( + + ) : ( + { + navigate(`/donate/${donorCollective.collective}`); + }} + /> + )} + + { + navigate(`/collective/${donorCollective.collective}/donors`); + }} + /> + + + + + ); +}; interface ViewCollectiveProps { collective: Collective; } @@ -63,11 +190,7 @@ function ViewCollective({ collective }: ViewCollectiveProps) { const infoLabel = collective.ipfs.rewardDescription ?? defaultInfoLabel; const { address } = useAccount(); - const { data: ensName } = useEnsName({ address, chainId: 1 }); - const userName = ensName ?? 'This wallet'; const maybeDonorCollective = useDonorCollectiveByAddresses(address ?? '', poolAddress, SUBGRAPH_POLL_INTERVAL); - const isDonating = maybeDonorCollective && maybeDonorCollective.flowRate !== '0'; - const hasDonated = isDonating || (maybeDonorCollective && maybeDonorCollective.contribution !== '0'); const { price: tokenPrice } = useGetTokenPrice('G$'); @@ -76,7 +199,6 @@ function ViewCollective({ collective }: ViewCollectiveProps) { tokenPrice, 2 ); - if (isDesktopView) { return ( @@ -119,66 +241,25 @@ function ViewCollective({ collective }: ViewCollectiveProps) { {infoLabel} - {hasDonated ? ( - - {!isDesktopView && ( - <> - - - You {isDonating ? 'Support' : 'Supported'} this GoodCollective!! - - - )} - - - {isDonating ? ( - - ) : ( - { - navigate(`/donate/${poolAddress}`); - }} - /> - )}{' '} - { - navigate(`/collective/${poolAddress}/donors`); - }} - /> - - - ) : ( - - { - navigate(`/donate/${poolAddress}`); - }} - /> - { - navigate(`/collective/${poolAddress}/donors`); - }} - /> - - )} + + { + navigate(`/donate/${poolAddress}`); + }} + /> + { + navigate(`/collective/${poolAddress}/donors`); + }} + /> + @@ -215,6 +296,7 @@ function ViewCollective({ collective }: ViewCollectiveProps) { /> + @@ -301,62 +383,7 @@ function ViewCollective({ collective }: ViewCollectiveProps) { currency={collective.rewardToken} /> - - {hasDonated ? ( - - - You {isDonating ? 'Support' : 'Supported'} this GoodCollective!! - - - {isDonating ? ( - - ) : ( - { - navigate(`/donate/${poolAddress}`); - }} - /> - )} - { - navigate(`/collective/${poolAddress}/donors`); - }} - /> - - - ) : ( - - { - navigate(`/donate/${poolAddress}`); - }} - /> - { - navigate(`/collective/${poolAddress}/donors`); - }} - /> - - )} + diff --git a/packages/app/src/hooks/useFetchFullName.ts b/packages/app/src/hooks/useFetchFullName.ts index 53347898..bfa34ce8 100644 --- a/packages/app/src/hooks/useFetchFullName.ts +++ b/packages/app/src/hooks/useFetchFullName.ts @@ -49,7 +49,7 @@ export function useFetchFullNames(addresses: string[]): any { const hashedAddresses = Object.keys(addressToHashMapping); - const { data, error } = useMongoDbQuery(findProfiles, { + const { data } = useMongoDbQuery(findProfiles, { variables: { query: { index: { walletAddress: { hash_in: hashedAddresses } }, diff --git a/packages/app/src/theme/theme.ts b/packages/app/src/theme/theme.ts index e5ff5681..022d6fbc 100644 --- a/packages/app/src/theme/theme.ts +++ b/packages/app/src/theme/theme.ts @@ -19,7 +19,7 @@ export const nbTheme = extendTheme({ 300: '#CCCCCC', 400: '#B0B0B0', 500: '#1F2937', - 600: '#5A5A5A', + 600: '#D4D4D4', }, goodPurple: { 100: '#E2EAFF',