Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: improve web vitals #250

Merged
merged 26 commits into from
Jan 26, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
9ba6e09
Some optimisation
Dozie2001 Nov 28, 2024
a2b6e87
Merge branch 'master' of github.com:RevokeCash/revoke.cash into web-v…
Dozie2001 Nov 28, 2024
6c9a81b
Merge branch 'master' into web-vitals
Dozie2001 Dec 7, 2024
ba29ffd
improve-mix-panel-fcp and its various impors across the components an…
Dozie2001 Dec 7, 2024
b867e11
improve-mix-panel-fcp and its various impors across the components an…
Dozie2001 Dec 7, 2024
c7df271
chore: fixing linting issues
Dozie2001 Dec 25, 2024
f7437f3
chore: fixing linting issues
Dozie2001 Dec 25, 2024
be4ffc6
Merge branch 'master' of github.com:RevokeCash/revoke.cash into web-v…
Dozie2001 Dec 27, 2024
19c7690
fix: optimised demo video and thumbnail
Dozie2001 Dec 28, 2024
aee3439
chore: memosised components
Dozie2001 Dec 28, 2024
d96258d
chore: optimised lcp for add-network
Dozie2001 Dec 28, 2024
1efb2b7
Merge branch 'master' of github.com:RevokeCash/revoke.cash into web-v…
Dozie2001 Jan 4, 2025
16492d2
Merge branch 'master' of github.com:RevokeCash/revoke.cash into web-v…
Dozie2001 Jan 9, 2025
d0e788e
refactor: layoutshift
Dozie2001 Jan 9, 2025
17e9b34
Merge remote-tracking branch 'origin/master' into web-vitals
rkalis Jan 16, 2025
168af56
chore: move analytics to export default
rkalis Jan 16, 2025
4d41e7e
Discard changes to app/[locale]/learn/wallets/add-network/[slug]/page…
rkalis Jan 16, 2025
ae33a0f
Discard changes to app/[locale]/og.jpg/learn/[category]/route.tsx
rkalis Jan 16, 2025
fdd0d57
Discard changes to app/[locale]/og.jpg/learn/wallets/add-network/[slu…
rkalis Jan 16, 2025
fb49f30
Discard changes to app/[locale]/og.jpg/learn/wallets/add-network/rout…
rkalis Jan 16, 2025
ea1e28b
Discard changes to components/common/ChainLogo.tsx
rkalis Jan 16, 2025
bc3d860
Revert "chore: optimised lcp for add-network"
rkalis Jan 16, 2025
7c496d7
Revert "refactor: layoutshift"
rkalis Jan 16, 2025
2ce3efe
chore: small changes
rkalis Jan 16, 2025
4d734c2
chore: small changes
rkalis Jan 20, 2025
c39e041
Merge branch 'master' of github.com:RevokeCash/revoke.cash into web-v…
Dozie2001 Jan 23, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions app/Analytics.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
'use client';

import { usePathname } from 'lib/i18n/navigation';
import { init, track } from 'lib/utils/analytics';
import analytics from 'lib/utils/analytics';
import Script from 'next/script';
import { useEffect } from 'react';

const Analytics = () => {
const path = usePathname();

useEffect(() => {
init();
analytics.init();
}, []);

useEffect(() => {
if (!path) return;
track('Viewed Page', { path });
analytics.track('Viewed Page', { path });
}, [path]);

// SimpleAnalytics
Expand Down
4 changes: 2 additions & 2 deletions components/common/Logo.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use client';

import Image from 'next/image';
import { useState } from 'react';
import { memo, useState } from 'react';
import { twMerge } from 'tailwind-merge';
import PlaceholderIcon from './PlaceholderIcon';

Expand Down Expand Up @@ -54,4 +54,4 @@ const Logo = ({ src, alt, size, square, border, className }: Props) => {
);
};

export default Logo;
export default memo(Logo);
12 changes: 2 additions & 10 deletions components/common/donate/DonateButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,13 @@ const DonateButton = ({ size, style, className, type }: Props) => {
const t = useTranslations();
const [open, setOpen] = useState(false);

const handleOpen = () => {
setOpen(true);
};

const handleClose = () => {
setOpen(false);
};

return (
<>
<Button style={style ?? 'primary'} size={size} className={className} onClick={handleOpen}>
<Button style={style ?? 'primary'} size={size} className={className} onClick={() => setOpen(true)}>
{t('common.buttons.donate')}
</Button>

<DonateModal open={open} setOpen={(open) => (open ? handleOpen() : handleClose())} type={type} />
<DonateModal open={open} setOpen={setOpen} type={type} />
</>
);
};
Expand Down
4 changes: 2 additions & 2 deletions components/common/donate/DonateModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Button from 'components/common/Button';
import Modal from 'components/common/Modal';
import { useDonate } from 'lib/hooks/ethereum/useDonate';
import { useTranslations } from 'next-intl';
import { useEffect, useState } from 'react';
import { memo, useEffect, useState } from 'react';
import { useAsyncCallback } from 'react-async-hook';
import { useChainId } from 'wagmi';
import Input from '../Input';
Expand Down Expand Up @@ -79,4 +79,4 @@ const DonateModal = ({ open, setOpen, type }: Props) => {
);
};

export default DonateModal;
export default memo(DonateModal);
4 changes: 2 additions & 2 deletions components/exploits/ExploitChecker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
} from 'lib/hooks/page-context/AddressPageContext';
import { isNullish } from 'lib/utils';
import { getAllowanceKey } from 'lib/utils/allowances';
import { track } from 'lib/utils/analytics';
import analytics from 'lib/utils/analytics';
import { getEventKey } from 'lib/utils/events';
import { type Exploit, getExploitStatus } from 'lib/utils/exploits';
import ExploitStatus from './ExploitStatus';
Expand All @@ -29,7 +29,7 @@ const ExploitChecker = ({ exploit }: Props) => {
queryKey: ['exploit-status', exploit.slug, allowances?.map(getAllowanceKey), events?.map(getEventKey)],
queryFn: () => {
const status = getExploitStatus(events!, allowances!, exploit);
track('Exploit Checked', { exploit: exploit.slug, account: address, chainId: selectedChainId, status });
analytics.track('Exploit Checked', { exploit: exploit.slug, account: address, chainId: selectedChainId, status });
return status;
},
enabled: !isNullish(address) && !isNullish(events) && !isNullish(allowances) && !isNullish(selectedChainId),
Expand Down
4 changes: 2 additions & 2 deletions components/footer/ColorThemeSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ComputerDesktopIcon, MoonIcon, SunIcon } from '@heroicons/react/24/outl
import Select from 'components/common/select/Select';
import { useColorTheme } from 'lib/hooks/useColorTheme';
import { useMounted } from 'lib/hooks/useMounted';
import { track } from 'lib/utils/analytics';
import analytics from 'lib/utils/analytics';
import { useTranslations } from 'next-intl';

const ColorThemeSelect = () => {
Expand All @@ -19,7 +19,7 @@ const ColorThemeSelect = () => {
] as const;

const selectTheme = (option: (typeof options)[number]) => {
track('Changed Color Theme', { theme: option.value });
analytics.track('Changed Color Theme', { theme: option.value });
setTheme(option.value);
};

Expand Down
4 changes: 2 additions & 2 deletions components/footer/LanguageSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import Select from 'components/common/select/Select';
import type { Locale } from 'lib/i18n/config';
import { useCsrRouter } from 'lib/i18n/csr-navigation';
import { usePathname } from 'lib/i18n/navigation';
import { track } from 'lib/utils/analytics';
import analytics from 'lib/utils/analytics';
import { useLocale } from 'next-intl';
import type { FormatOptionLabelMeta } from 'react-select';

Expand Down Expand Up @@ -36,7 +36,7 @@ const LanguageSelect = () => {

const selectLanguage = (option: Option) => {
const newLocale = option.value;
track('Changed language', { from: locale, to: newLocale });
analytics.track('Changed language', { from: locale, to: newLocale });
router.replace(path, { locale: newLocale, scroll: false, showProgress: false, retainSearchParams: ['chainId'] });
persistLocaleCookie(newLocale);
};
Expand Down
14 changes: 7 additions & 7 deletions components/header/SearchBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import AddressSearchBox from 'components/common/AddressSearchBox';
import Button from 'components/common/Button';
import { useCsrRouter } from 'lib/i18n/csr-navigation';
import { useTranslations } from 'next-intl';
import { useRef, useState } from 'react';
import { useCallback, useRef, useState } from 'react';
import { twMerge } from 'tailwind-merge';
import { useAccount } from 'wagmi';

Expand All @@ -16,21 +16,21 @@ const SearchBar = () => {
const { address } = useAccount();
const timerRef = useRef<NodeJS.Timeout>();

const onFocus = () => {
const onFocus = useCallback(() => {
clearTimeout(timerRef.current);
setIsFocused(true);
};
}, []);

const onBlur = () => {
const onBlur = useCallback(() => {
timerRef.current = setTimeout(() => setIsFocused(false), 200);
};
}, []);

const onClick = () => {
const onClick = useCallback(() => {
if (address) {
setValue(address);
router.push(`/address/${address}`, { retainSearchParams: ['chainId'] });
}
};
}, [address, router]);

return (
<div className="relative w-full">
Expand Down
5 changes: 3 additions & 2 deletions components/landing/DemoVideo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ const DemoVideo = () => {
controls
muted
loop
preload="metadata"
preload="metadata" // Preload the video fully for faster LCP
playsInline
poster="/assets/images/thumbnail/demo-thumbnail.webp"
>
<source src="/assets/videos/demo.mp4#t=0.001" type="video/mp4" />
<source src="/assets/videos/demo.mp4" type="video/mp4" />
</video>
);
};
Expand Down
4 changes: 2 additions & 2 deletions components/signatures/cells/CancelMarketplaceCell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useHandleTransaction } from 'lib/hooks/ethereum/useHandleTransaction';
import { useAddressPageContext } from 'lib/hooks/page-context/AddressPageContext';
import { type Marketplace, type OnCancel, type TransactionSubmitted, TransactionType } from 'lib/interfaces';
import { waitForTransactionConfirmation } from 'lib/utils';
import { track } from 'lib/utils/analytics';
import analytics from 'lib/utils/analytics';
import { usePublicClient, useWalletClient } from 'wagmi';
import CancelCell from './CancelCell';

Expand All @@ -21,7 +21,7 @@ const CancelMarketplaceCell = ({ marketplace, onCancel }: Props) => {
const sendCancelTransaction = async (): Promise<TransactionSubmitted> => {
const hash = await marketplace?.cancelSignatures(walletClient!);

track('Cancelled Marketplace Signatures', {
analytics.track('Cancelled Marketplace Signatures', {
chainId: selectedChainId,
account: address,
marketplace: marketplace.name,
Expand Down
8 changes: 6 additions & 2 deletions components/signatures/cells/CancelPermitCell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useHandleTransaction } from 'lib/hooks/ethereum/useHandleTransaction';
import { useAddressPageContext } from 'lib/hooks/page-context/AddressPageContext';
import { type OnCancel, type TransactionSubmitted, TransactionType } from 'lib/interfaces';
import { waitForTransactionConfirmation } from 'lib/utils';
import { track } from 'lib/utils/analytics';
import analytics from 'lib/utils/analytics';
import { permit } from 'lib/utils/permit';
import { type PermitTokenData, isErc721Contract } from 'lib/utils/tokens';
import { usePublicClient, useWalletClient } from 'wagmi';
Expand All @@ -25,7 +25,11 @@ const CancelPermitCell = ({ token, onCancel }: Props) => {
if (isErc721Contract(token.contract)) throw new Error('Cannot cancel ERC721 tokens');
const hash = await permit(walletClient!, token.contract, DUMMY_ADDRESS, 0n);

track('Cancelled Permit Signatures', { chainId: selectedChainId, account: address, token: token.contract.address });
analytics.track('Cancelled Permit Signatures', {
chainId: selectedChainId,
account: address,
token: token.contract.address,
});

const waitForConfirmation = async () => {
// TODO: Deduplicate this with the CancelMarketplaceCell
Expand Down
6 changes: 3 additions & 3 deletions lib/hooks/ethereum/EthereumProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { abstractWalletConnector } from '@abstract-foundation/agw-react/connecto
import { useCsrRouter } from 'lib/i18n/csr-navigation';
import { usePathname } from 'lib/i18n/navigation';
import { ORDERED_CHAINS, createViemPublicClientForChain, getViemChainConfig } from 'lib/utils/chains';
import { type ReactNode, useEffect } from 'react';
import { type ReactNode, memo, useEffect } from 'react';
import type { Chain } from 'viem';
import { WagmiProvider, createConfig, useAccount, useConnect } from 'wagmi';
import { coinbaseWallet, injected, safe, walletConnect } from 'wagmi/connectors';
Expand Down Expand Up @@ -50,7 +50,7 @@ export const EthereumProvider = ({ children }: Props) => {
);
};

const EthereumProviderChild = ({ children }: Props) => {
const EthereumProviderChild = memo(({ children }: Props) => {
const { connectAsync, connectors } = useConnect();
const { connector, address } = useAccount();
const router = useCsrRouter();
Expand Down Expand Up @@ -105,7 +105,7 @@ const EthereumProviderChild = ({ children }: Props) => {
}, [address]);

return <>{children}</>;
};
});

const isIframe = () => {
return typeof window !== 'undefined' && window?.parent !== window;
Expand Down
4 changes: 2 additions & 2 deletions lib/hooks/ethereum/useAllowances.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
getAllowancesFromEvents,
stripAllowanceData,
} from 'lib/utils/allowances';
import { track } from 'lib/utils/analytics';
import analytics from 'lib/utils/analytics';
import { type TimeLog, type TokenEvent, getEventKey } from 'lib/utils/events';
import { hasZeroBalance } from 'lib/utils/tokens';
import { useLayoutEffect, useState } from 'react';
Expand All @@ -30,7 +30,7 @@ export const useAllowances = (address: Address, events: TokenEvent[] | undefined
queryKey: ['allowances', address, chainId, events?.map(getEventKey)],
queryFn: async () => {
const allowances = getAllowancesFromEvents(address, events!, publicClient, chainId);
track('Fetched Allowances', { account: address, chainId });
analytics.track('Fetched Allowances', { account: address, chainId });
return allowances;
},
// If events (transfers + approvals) don't change, derived allowances also shouldn't change, even if allowances
Expand Down
4 changes: 2 additions & 2 deletions lib/hooks/ethereum/useDonate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { DonateButtonType } from 'components/common/donate/DonateModal';
import { DONATION_ADDRESS } from 'lib/constants';
import { type TransactionSubmitted, TransactionType } from 'lib/interfaces';
import { waitForTransactionConfirmation } from 'lib/utils';
import { track } from 'lib/utils/analytics';
import analytics from 'lib/utils/analytics';
import { type DocumentedChainId, getChainName, getChainNativeToken, getDefaultDonationAmount } from 'lib/utils/chains';
import { type SendTransactionParameters, parseEther } from 'viem';
import { usePublicClient, useWalletClient } from 'wagmi';
Expand Down Expand Up @@ -65,7 +65,7 @@ export const getTipSelection = (chainId: DocumentedChainId, amount: string) => {
export const trackDonate = (chainId: DocumentedChainId, amount: string, type: DonateButtonType) => {
if (!Number(amount)) return;

track('Donated', {
analytics.track('Donated', {
chainId,
chainName: getChainName(chainId),
nativeToken: getChainNativeToken(chainId),
Expand Down
6 changes: 3 additions & 3 deletions lib/utils/allowances.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { type TransactionSubmitted, TransactionType } from 'lib/interfaces';
import type { TransactionStore } from 'lib/stores/transaction-store';
import { type Address, type PublicClient, type WalletClient, type WriteContractParameters, formatUnits } from 'viem';
import { deduplicateArray, isNullish, waitForTransactionConfirmation, writeContractUnlessExcessiveGas } from '.';
import { track } from './analytics';
import analytics from './analytics';
import { isNetworkError, isRevertedError, isUserRejectionError, parseErrorMessage, stringifyError } from './errors';
import {
type Erc20ApprovalEvent,
Expand Down Expand Up @@ -514,7 +514,7 @@ export const prepareUpdateErc20Allowance = async (

export const trackRevokeTransaction = (allowance: TokenAllowanceData, newAmount?: string) => {
if (isErc721Contract(allowance.contract)) {
track('Revoked ERC721 allowance', {
analytics.track('Revoked ERC721 allowance', {
chainId: allowance.chainId,
account: allowance.owner,
spender: allowance.payload?.spender,
Expand All @@ -525,7 +525,7 @@ export const trackRevokeTransaction = (allowance: TokenAllowanceData, newAmount?

const isRevoke = !newAmount || newAmount === '0';

track(isRevoke ? 'Revoked ERC20 allowance' : 'Updated ERC20 allowance', {
analytics.track(isRevoke ? 'Revoked ERC20 allowance' : 'Updated ERC20 allowance', {
chainId: allowance.chainId,
account: allowance.owner,
spender: allowance.payload?.spender,
Expand Down
29 changes: 20 additions & 9 deletions lib/utils/analytics.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,26 @@
import mixpanel from 'mixpanel-browser';

export const init = () => {
if (process.env.NEXT_PUBLIC_MIXPANEL_API_KEY) {
mixpanel.init(process.env.NEXT_PUBLIC_MIXPANEL_API_KEY, { ip: false });
}
};
const analytics = {
isInitialized: false,
// init only when first used
init() {
if (this.isInitialized) return;
const apiKey = process.env.NEXT_PUBLIC_MIXPANEL_API_KEY;
if (apiKey && typeof window !== 'undefined') {
mixpanel.init(apiKey, { ip: false });
this.isInitialized = true;
}
},

export const track = (eventName: string, eventProperties: any) => {
if (typeof window === 'undefined') return;
track(eventName: string, eventProperties?: Record<string, any>) {
if (typeof window === 'undefined' || !process.env.NEXT_PUBLIC_MIXPANEL_API_KEY) return;
// lazy initialize if not already done
if (!this.isInitialized) {
this.init();
}

if (process.env.NEXT_PUBLIC_MIXPANEL_API_KEY) {
mixpanel.track(eventName, eventProperties);
}
},
};

export default analytics;
4 changes: 2 additions & 2 deletions lib/utils/batch-revoke.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { getTipSelection } from 'lib/hooks/ethereum/useDonate';
import type { TokenAllowanceData } from './allowances';
import { track } from './analytics';
import analytics from './analytics';

export type BatchType = 'eip5792' | 'queued';

Expand All @@ -11,7 +11,7 @@ export const trackBatchRevoke = (
tipAmount: string,
batchType: BatchType,
) => {
track('Batch Revoked', {
analytics.track('Batch Revoked', {
chainId,
address,
allowances: allowances.length,
Expand Down
4 changes: 2 additions & 2 deletions lib/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
pad,
slice,
} from 'viem';
import { track } from './analytics';
import analytics from './analytics';
import type { Log, TokenEvent } from './events';

export const assertFulfilled = <T>(item: PromiseSettledResult<T>): item is PromiseFulfilledResult<T> => {
Expand Down Expand Up @@ -126,7 +126,7 @@ export const throwIfExcessiveGas = (chainId: number, address: Address, estimated

// Track excessive gas usage so we can blacklist tokens
// TODO: Use a different tool than analytics for this
track('Excessive gas limit', { chainId, address, estimatedGas: estimatedGas.toString() });
analytics.track('Excessive gas limit', { chainId, address, estimatedGas: estimatedGas.toString() });

throw new Error(
'This transaction has an excessive gas cost. It is most likely a spam token, so you do not need to revoke this approval.',
Expand Down
Loading
Loading