feat: move to nextjs

This commit is contained in:
apoorvlathey
2024-05-07 00:18:18 +10:00
parent 602ae4389e
commit 032785a316
49 changed files with 9867 additions and 8425 deletions

View File

@@ -1,5 +1,5 @@
REACT_APP_INFURA_KEY=
REACT_APP_WC_PROJECT_ID=
REACT_APP_GITCOIN_GRANTS_ACTIVE=
REACT_APP_GITCOIN_GRANTS_LINK=
REACT_APP_DONATION_ADDRESS=
NEXT_PUBLIC_INFURA_KEY=
NEXT_PUBLIC_WC_PROJECT_ID=
NEXT_PUBLIC_GITCOIN_GRANTS_ACTIVE=
NEXT_PUBLIC_GITCOIN_GRANTS_LINK=
NEXT_PUBLIC_DONATION_ADDRESS=

21
.gitignore vendored
View File

@@ -1,6 +1,4 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
.env
.vercel
# dependencies
/node_modules
@@ -10,17 +8,28 @@
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# local env files
.env*.local
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts

2
.nvmrc
View File

@@ -1 +1 @@
v18.16.1
v18.17.0

View File

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

17
app/layout.tsx Normal file
View File

@@ -0,0 +1,17 @@
import { IndexLayout as IndexLayoutC } from "@/components/layouts/IndexLayout";
import { getMetadata } from "@/utils";
export const metadata = getMetadata({
title: "Impersonator",
description:
"Impersonate any Ethereum Account and Login into DApps via WalletConnect, iframe or Extension!",
images: "https://www.impersonator.xyz/metaIMG.PNG",
});
export default function IndexLayout({
children,
}: {
children: React.ReactNode;
}) {
return <IndexLayoutC>{children}</IndexLayoutC>;
}

15
app/page.tsx Normal file
View File

@@ -0,0 +1,15 @@
import Body from "@/components/Body";
import Navbar from "@/components/Navbar";
import Footer from "@/components/Footer";
const Home = () => {
return (
<div>
<Navbar />
<Body />
<Footer />
</div>
);
};
export default Home;

View File

@@ -1,7 +1,8 @@
"use client";
import "@rainbow-me/rainbowkit/styles.css";
import ReactDOM from "react-dom";
import App from "./App";
import { CacheProvider } from "@chakra-ui/next-js";
import { ChakraProvider } from "@chakra-ui/react";
import {
connectorsForWallets,
@@ -17,8 +18,8 @@ import { configureChains, createConfig, WagmiConfig } from "wagmi";
import { mainnet, optimism, base, arbitrum } from "wagmi/chains";
import { publicProvider } from "wagmi/providers/public";
import theme from "./theme";
import { SafeInjectProvider } from "./contexts/SafeInjectContext";
import theme from "@/style/theme";
import { SafeInjectProvider } from "@/contexts/SafeInjectContext";
const { chains, publicClient } = configureChains(
// the first chain is used by rainbowWallet to determine which chain to use
@@ -26,7 +27,7 @@ const { chains, publicClient } = configureChains(
[publicProvider()]
);
const projectId = process.env.REACT_APP_WC_PROJECT_ID!;
const projectId = process.env.NEXT_PUBLIC_WC_PROJECT_ID!;
const connectors = connectorsForWallets([
{
groupName: "Recommended",
@@ -44,7 +45,9 @@ export const wagmiConfig = createConfig({
publicClient,
});
ReactDOM.render(
export const Providers = ({ children }: { children: React.ReactNode }) => {
return (
<CacheProvider>
<ChakraProvider theme={theme}>
<WagmiConfig config={wagmiConfig}>
<RainbowKitProvider
@@ -52,11 +55,10 @@ ReactDOM.render(
theme={darkTheme()}
modalSize={"compact"}
>
<SafeInjectProvider>
<App />
</SafeInjectProvider>
<SafeInjectProvider>{children}</SafeInjectProvider>
</RainbowKitProvider>
</WagmiConfig>
</ChakraProvider>,
document.getElementById("root")
);
</ChakraProvider>
</CacheProvider>
);
};

26
components/Analytics.tsx Normal file
View File

@@ -0,0 +1,26 @@
import Script from "next/script";
const GA_ID = "G-QFNMM9LXBY";
export const Analytics = () => {
return (
<>
<Script
strategy="afterInteractive"
src={`https://www.googletagmanager.com/gtag/js?id=${GA_ID}`}
/>
<Script
id="google-analytics"
strategy="afterInteractive"
dangerouslySetInnerHTML={{
__html: `
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '${GA_ID}');
`,
}}
/>
</>
);
};

View File

@@ -1,12 +1,7 @@
"use client";
import { useState, useEffect } from "react";
import {
Container,
useColorMode,
useToast,
Center,
Spacer,
Flex,
} from "@chakra-ui/react";
import { Container, useToast, Center, Spacer, Flex } from "@chakra-ui/react";
import { SingleValue } from "chakra-react-select";
// WC v2
@@ -37,7 +32,7 @@ const WCMetadata = {
};
const core = new Core({
projectId: process.env.REACT_APP_WC_PROJECT_ID,
projectId: process.env.NEXT_PUBLIC_WC_PROJECT_ID,
});
const primaryNetworkIds = [
@@ -70,8 +65,6 @@ const allNetworksOptions = [
];
function Body() {
const { colorMode } = useColorMode();
const bgColor = { light: "white", dark: "gray.700" };
const addressFromURL = new URLSearchParams(window.location.search).get(
"address"
);
@@ -143,7 +136,7 @@ function Body() {
setProvider(
new ethers.providers.JsonRpcProvider(
`https://mainnet.infura.io/v3/${process.env.REACT_APP_INFURA_KEY}`
`https://mainnet.infura.io/v3/${process.env.NEXT_PUBLIC_INFURA_KEY}`
)
);

View File

@@ -1,6 +1,7 @@
"use client";
import { useState } from "react";
import {
useColorMode,
Flex,
VStack,
Heading,
@@ -46,9 +47,6 @@ const Social = ({ icon, link }: { icon: IconProp; link: string }) => {
};
function Footer() {
const { colorMode } = useColorMode();
const underlineColor = { light: "gray.500", dark: "gray.400" };
const { isConnected } = useAccount();
const { chain } = useNetwork();
@@ -64,7 +62,7 @@ function Footer() {
const handleDonate = async (value: string) => {
try {
await sendTransaction({
to: process.env.REACT_APP_DONATION_ADDRESS!,
to: process.env.NEXT_PUBLIC_DONATION_ADDRESS!,
value: parseEther(value),
});
launchConfetti();
@@ -79,7 +77,7 @@ function Footer() {
};
return (
<Flex py="4" borderTop="2px" borderTopColor={underlineColor[colorMode]}>
<Flex py="4" borderTop="2px" borderTopColor={"gray.400"}>
<Spacer flex="1" />
{showConfetti && (
<Box zIndex={9999} position={"fixed"} top={0} left={0}>
@@ -102,11 +100,11 @@ function Footer() {
<Stack direction={{ base: "column", md: "row" }}>
<Center>Found the project helpful?</Center>
<HStack>
{process.env.REACT_APP_GITCOIN_GRANTS_ACTIVE === "true" ? (
{process.env.NEXT_PUBLIC_GITCOIN_GRANTS_ACTIVE === "true" ? (
<>
<Text>Support it on</Text>
<Link
href={process.env.REACT_APP_GITCOIN_GRANTS_LINK}
href={process.env.NEXT_PUBLIC_GITCOIN_GRANTS_LINK}
isExternal
>
<HStack fontWeight="bold" textDecor="underline">

View File

@@ -1,6 +1,5 @@
import {
Button,
useColorMode,
Flex,
Heading,
Spacer,
@@ -10,20 +9,16 @@ import {
Text,
Image,
} from "@chakra-ui/react";
import { SunIcon, MoonIcon } from "@chakra-ui/icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faGithub } from "@fortawesome/free-brands-svg-icons";
function Navbar() {
const { colorMode } = useColorMode();
const underlineColor = { light: "gray.500", dark: "gray.400" };
return (
<Flex
py="4"
px={["2", "4", "10", "10"]}
borderBottom="2px"
borderBottomColor={underlineColor[colorMode]}
borderBottomColor={"gray.400"}
>
<Spacer flex="1" />
<Heading

View File

@@ -0,0 +1,30 @@
import { Providers } from "@/app/providers";
import { Analytics } from "@/components/Analytics";
export const IndexLayout = ({ children }: { children: React.ReactNode }) => {
return (
<html lang="en">
{/* Farcaster Frame */}
<head>
<meta property="fc:frame" content="vNext" />
<meta
property="fc:frame:image"
content="https://frame.impersonator.xyz/impersonator.gif"
/>
<meta
property="fc:frame:post_url"
content="https://frame.impersonator.xyz/api/frame"
/>
<meta
property="fc:frame:input:text"
content="Type ENS or Address to impersonate..."
/>
<meta property="fc:frame:button:1" content="🕵️ Start" />
</head>
<body>
<Analytics />
<Providers>{children}</Providers>
</body>
</html>
);
};

16
next.config.js Normal file
View File

@@ -0,0 +1,16 @@
const nextConfig = {
reactStrictMode: true,
webpack: (config) => {
config.resolve.fallback = { fs: false, net: false, tls: false };
config.externals.push("pino-pretty");
return config;
},
compiler: {
styledComponents: true,
},
experimental: {
windowHistorySupport: true,
},
};
module.exports = nextConfig;

View File

@@ -3,8 +3,15 @@
"version": "0.1.0",
"homepage": ".",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@chakra-ui/icons": "^1.0.14",
"@chakra-ui/next-js": "^2.2.0",
"@chakra-ui/react": "^2.8.1",
"@emotion/react": "^11",
"@emotion/styled": "^11",
@@ -13,10 +20,6 @@
"@fortawesome/free-solid-svg-icons": "^6.4.0",
"@fortawesome/react-fontawesome": "^0.1.18",
"@rainbow-me/rainbowkit": "^1.0.11",
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
"@types/jest": "^27.4.0",
"@types/node": "^17.0.10",
"@types/react": "^17.0.38",
"@types/react-dom": "^17.0.11",
@@ -33,6 +36,7 @@
"ethers": "^5.4.5",
"evm-rpcs-list": "^2.0.3",
"framer-motion": "^4",
"next": "^14.2.3",
"react": "^18.2.0",
"react-confetti": "^6.1.0",
"react-dom": "^18.2.0",
@@ -43,36 +47,7 @@
"wagmi": "^1.4.2",
"web-vitals": "^1.0.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
"chrome >= 67",
"edge >= 79",
"firefox >= 68",
"opera >= 54",
"safari >= 14"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"resolutions": {
"react-error-overlay": "6.0.9"
},
"devDependencies": {
"react-error-overlay": "6.0.9"
"pino-pretty": "^11.0.0"
}
}

17679
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,93 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script
async
src="https://www.googletagmanager.com/gtag/js?id=G-QFNMM9LXBY"
></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag("js", new Date());
gtag("config", "G-QFNMM9LXBY");
</script>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/logo.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<!-- Primary Meta Tags -->
<title>Impersonator</title>
<meta name="title" content="Impersonator" />
<meta
name="description"
content="Impersonate any Ethereum Account and Login into DApps via WalletConnect!"
/>
<!-- Open Graph / Facebook -->
<meta property="og:type" content="website" />
<meta property="og:url" content="https://www.impersonator.xyz/" />
<meta property="og:title" content="Impersonator" />
<meta
property="og:description"
content="Impersonate any Ethereum Account and Login into DApps via WalletConnect!"
/>
<meta
property="og:image"
content="https://www.impersonator.xyz/metaIMG.PNG"
/>
<!-- Twitter -->
<meta property="twitter:card" content="summary_large_image" />
<meta property="twitter:url" content="https://www.impersonator.xyz/" />
<meta property="twitter:title" content="Impersonator" />
<meta
property="twitter:description"
content="Impersonate any Ethereum Account and Login into DApps via WalletConnect!"
/>
<meta
property="twitter:image"
content="https://www.impersonator.xyz/metaIMG.PNG"
/>
<!-- Farcaster Frame -->
<meta property="fc:frame" content="vNext" />
<meta property="fc:frame:image" content="https://frame.impersonator.xyz/impersonator.gif" />
<meta property="fc:frame:post_url" content="https://frame.impersonator.xyz/api/frame" />
<meta property="fc:frame:input:text" content="Type ENS or Address to impersonate..." />
<meta property="fc:frame:button:1" content="🕵️ Start" />
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>

View File

@@ -1,15 +0,0 @@
{
"short_name": "React App",
"name": "Impersonator",
"icons": [
{
"src": "logo.png",
"type": "image/png",
"sizes": "418x418"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

View File

@@ -1,15 +0,0 @@
import Body from "./components/Body";
import Navbar from "./components/Navbar";
import Footer from "./components/Footer";
function App() {
return (
<div>
<Navbar />
<Body />
<Footer />
</div>
);
}
export default App;

View File

@@ -1 +0,0 @@
/// <reference types="react-scripts" />

View File

@@ -1,20 +1,29 @@
{
"compilerOptions": {
"target": "ESNext",
"target": "ES2020",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx"
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"baseUrl": ".",
"paths": {
"@/*": ["./*"]
}
},
"include": ["src"]
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}

28
utils/index.ts Normal file
View File

@@ -0,0 +1,28 @@
import { Metadata } from "next";
export const getMetadata = (_metadata: {
title: string;
description: string;
images: string;
}) => {
const metadata: Metadata = {
title: _metadata.title,
description: _metadata.description,
twitter: {
card: "summary_large_image",
creator: "@apoorvlathey",
title: _metadata.title,
description: _metadata.description,
images: _metadata.images,
},
openGraph: {
type: "website",
title: _metadata.title,
description: _metadata.description,
images: _metadata.images,
},
robots: "index, follow",
};
return metadata;
};