First edits made like in the video.

This commit is contained in:
StockiP
2022-11-01 17:04:55 +01:00
parent 5e9d67bef4
commit 9fdfe8b23f
31 changed files with 69943 additions and 12522 deletions

View File

@@ -1,10 +0,0 @@
import { render } from "@testing-library/react";
import React from "react";
import App from "./App";
test("renders learn react link", () => {
const { getByText } = render(<App />);
const linkElement = getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
});

View File

@@ -0,0 +1 @@
<svg width="12" height="7" viewBox="0 0 12 7" fill="none" xmlns="http://www.w3.org/2000/svg" class="sc-3zewi2-11 kHQTSW"><path d="M0.97168 1L6.20532 6L11.439 1" stroke="#AEAEAE"></path></svg>

After

Width:  |  Height:  |  Size: 191 B

View File

Before

Width:  |  Height:  |  Size: 211 KiB

After

Width:  |  Height:  |  Size: 211 KiB

View File

@@ -0,0 +1,5 @@
import chevronDown from "./chevron-down.svg";
import ethereumLogo from "./ethereumLogo.png";
import uniswapLogo from "./uniswapLogo.png";
export { chevronDown, ethereumLogo, uniswapLogo };

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

View File

@@ -1,55 +0,0 @@
import styled from "styled-components";
export const Body = styled.div`
align-items: center;
color: white;
display: flex;
flex-direction: column;
font-size: calc(10px + 2vmin);
justify-content: center;
margin-top: 40px;
`;
export const Button = styled.button`
background-color: white;
border: none;
border-radius: 8px;
color: #282c34;
cursor: pointer;
font-size: 16px;
margin: 0px 20px;
padding: 12px 24px;
text-align: center;
text-decoration: none;
`;
export const Container = styled.div`
background-color: #282c34;
display: flex;
flex-direction: column;
height: calc(100vh);
`;
export const Header = styled.header`
align-items: center;
background-color: #282c34;
color: white;
display: flex;
flex-direction: row;
justify-content: flex-end;
min-height: 70px;
`;
export const Image = styled.img`
height: 40vmin;
margin-bottom: 16px;
pointer-events: none;
`;
export const Link = styled.a.attrs({
target: "_blank",
rel: "noopener noreferrer",
})`
color: #61dafb;
margin-top: 8px;
`;

10
packages/react-app/src/config.js vendored Normal file
View File

@@ -0,0 +1,10 @@
import { Goerli } from "@usedapp/core";
export const ROUTER_ADDRESS = "[YOUR ADDRESS HERE]";
export const DAPP_CONFIG = {
readOnlyChainId: Goerli.chainId,
readOnlyUrls: {
[Goerli.chainId]: "[YOUR URL HERE]",
},
};

View File

@@ -1,15 +0,0 @@
import { gql } from "@apollo/client";
// See more example queries on https://thegraph.com/explorer/subgraph/paulrberg/create-eth-app
const GET_TRANSFERS = gql`
{
transfers(first: 10) {
id
from
to
value
}
}
`;
export default GET_TRANSFERS;

View File

@@ -1,11 +1,59 @@
body {
@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@100;200;300;400;500;600;700;800;900&display=swap");
@tailwind base;
@tailwind components;
@tailwind utilities;
/* Chrome, Safari, Edge, Opera */
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans",
"Droid Sans", "Helvetica Neue", sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace;
/* Firefox */
input[type="number"] {
-moz-appearance: textfield;
}
.gradient_btn {
background: linear-gradient(
103.91deg,
#9b51e0 21.01%,
rgba(48, 129, 237, 0.8) 100%
);
}
.pink_gradient {
position: absolute;
top: 0%;
left: 0%;
width: 123px;
height: 123px;
border-radius: 50%;
background: #fb37ff;
filter: blur(200px);
}
.blue_gradient {
position: absolute;
bottom: 0%;
right: 0%;
width: 123px;
height: 123px;
border-radius: 50%;
background: #18b2de;
filter: blur(200px);
}
.gradient-border {
background: linear-gradient(
168.82deg,
#fb37ff 1.7%,
rgba(155, 111, 238, 0) 27.12%,
rgba(123, 127, 234, 0) 61.28%,
#1bb2de 99.52%
);
}

View File

@@ -1,37 +1,17 @@
import "./index.css";
import { ApolloClient, ApolloProvider, InMemoryCache } from "@apollo/client";
import { DAppProvider, Mainnet } from "@usedapp/core";
import React from "react";
import ReactDOM from "react-dom";
import { DAppProvider } from "@usedapp/core";
import App from "./App";
import { DAPP_CONFIG } from "./config";
// IMPORTANT, PLEASE READ
// To avoid disruptions in your app, change this to your own Infura project id.
// https://infura.io/register
const INFURA_PROJECT_ID = "529670718fd74cd2a041466303daecd7";
const config = {
readOnlyChainId: Mainnet.chainId,
readOnlyUrls: {
[Mainnet.chainId]: "https://mainnet.infura.io/v3/" + INFURA_PROJECT_ID,
},
}
// You should replace this url with your own and put it into a .env file
// See all subgraphs: https://thegraph.com/explorer/
const client = new ApolloClient({
cache: new InMemoryCache(),
uri: "https://api.thegraph.com/subgraphs/name/paulrberg/create-eth-app",
});
import "./index.css";
ReactDOM.render(
<React.StrictMode>
<DAppProvider config={config}>
<ApolloProvider client={client}>
<App />
</ApolloProvider>
<DAppProvider config={DAPP_CONFIG}>
<App />
</DAppProvider>
</React.StrictMode>,
document.getElementById("root"),
);
document.getElementById("root")
);

View File

@@ -1,5 +0,0 @@
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import "@testing-library/jest-dom/extend-expect";

50
packages/react-app/src/styles/index.js vendored Normal file
View File

@@ -0,0 +1,50 @@
const styles = {
// App.js
container: "flex justify-center min-h-screen sm:px-16 px-6 bg-site-black",
innerContainer:
"flex justify-between items-center flex-col max-w-[1280px] w-full",
header: "flex flex-row justify-between items-center w-full sm:py-10 py-6",
exchangeContainer:
"flex-1 flex justify-start items-center flex-col w-full mt-10",
headTitle: "text-white font-poppins font-black text-5xl tracking-wide",
subTitle: "text-dim-white font-poppins font-medium mt-3 text-base",
exchangeBoxWrapper: "mt-10 w-full flex justify-center",
exchangeBox:
"relative md:max-w-[700px] md:min-w-[500px] min-w-full max-w-full gradient-border p-[2px] rounded-3xl",
exchange:
"w-full min-h-[400px] bg-site-black backdrop-blur-[4px] rounded-3xl shadow-card flex p-10",
// AmountIn & AmountOut
amountContainer:
"flex justify-between items-center flex-row w-full min-w-full bg-site-dim border-[1px] border-transparent hover:border-site-dim2 min-h-[96px] sm:p-8 p-4 rounded-[20px]",
amountInput:
"w-full flex-1 bg-transparent outline-none font-poppins font-black text-2xl text-white",
currencyButton:
"flex flex-row items-center bg-site-dim2 py-2 px-4 rounded-xl font-poppins font-bold text-white",
currencyList:
"absolute z-10 right-0 bg-site-black border-[1px] border-site-dim2 w-full mt-2 rounded-lg min-w-[170px] overflow-hidden",
currencyListItem:
"font-poppins font-medium text-base text-white hover:text-dim-white px-5 py-3 hover:bg-site-dim2 cursor-pointer",
// Exchange
actionButton:
"border-none outline-none px-6 py-2 font-poppins font-bold text-lg rounded-2xl leading-[24px] transition-all min-h-[56px]",
message: "font-poppins font-lg text-white font-bold mt-7",
// WalletButton
walletButton:
"bg-site-pink border-none outline-none px-6 py-2 font-poppins font-bold text-lg text-white rounded-3xl leading-[24px] hover:bg-pink-600 transition-all",
// loader
loader: "flex justify-center items-center flex-col w-full min-h-full",
loaderImg: "w-56 h-56 object-contain",
loaderText:
"font-poppins font-normal text-dim-white text-lg text-center mt-10",
// balance
balance: "w-full text-left mt-2 ml-2",
balanceText: "font-poppins font-normal text-dim-white",
balanceBold: "font-semibold text-white",
};
export default styles;

110
packages/react-app/src/utils/helpers.js vendored Normal file
View File

@@ -0,0 +1,110 @@
import { Contract } from "@ethersproject/contracts";
import { abis } from "@my-app/contracts";
import { useCall } from "@usedapp/core";
import { parseUnits } from "ethers/lib/utils";
import { useEffect } from "react";
import { ROUTER_ADDRESS } from "../config";
export const getAvailableTokens = (pools) =>
pools.reduce((prev, curr) => {
prev[curr.token0Address] = curr.token0Name;
prev[curr.token1Address] = curr.token1Name;
return prev;
}, {});
export const getCounterpartTokens = (pools, fromToken) => pools
.filter((cur) => cur.token0Address === fromToken || cur.token1Address)
.reduce((prev, curr) => {
if (curr.token0Address === fromToken) {
prev[curr.token1Address] = curr.token1Name;
} else if (curr.token1Address === fromToken) {
prev[curr.token0Address] = curr.token0Name;
}
return prev;
}, {});
export const findPoolByTokens = (pools, fromToken, toToken) => {
if (!Array.isArray(pools) || !fromToken || !toToken) return undefined;
return pools.find((cur) =>
(cur.token0Address === fromToken && cur.token1Address === toToken) ||
(cur.token1Address === fromToken && cur.token0Address === toToken)
);
};
export const isOperationPending = (operationState) =>
operationState.status === "PendingSignature" || operationState.status === "Mining";
export const isOperationFailed = (operationState) =>
operationState.status === "Fail" || operationState.status === "Exception";
export const isOperationSucceeded = (operationState) =>
operationState.status === "Success";
export const getFailureMessage = (swapApproveState, swapExecuteState) => {
if (isOperationPending(swapApproveState) || isOperationPending(swapExecuteState)) {
return undefined;
}
if (isOperationFailed(swapApproveState)) {
return "Approval failed - " + swapApproveState.errorMessage;
}
if (isOperationFailed(swapExecuteState)) {
return "Swap failed - " + swapExecuteState.errorMessage;
}
return undefined;
};
export const getSuccessMessage = (swapApproveState, swapExecuteState) => {
if (isOperationPending(swapExecuteState) ||isOperationPending(swapApproveState)) {
return undefined;
}
if (isOperationSucceeded(swapExecuteState)) {
return "Swap executed successfully";
}
if (isOperationSucceeded(swapApproveState)) {
return "Approval successful";
}
return undefined;
};
export const useAmountsOut = (pairAddress, amountIn, fromToken, toToken) => {
const isValidAmountIn = amountIn.gt(parseUnits("0"));
const areParamsValid = !!(pairAddress && isValidAmountIn && fromToken && toToken);
const { error, value } =
useCall(
areParamsValid && {
contract: new Contract(ROUTER_ADDRESS, abis.router02),
method: "getAmountsOut",
args: [amountIn, [fromToken, toToken]],
}
) ?? {};
return error ? parseUnits("0") : value?.amounts[1];
}
export const useOnClickOutside = (ref, handler) => {
useEffect(() => {
const listener = (event) => {
// Do nothing if clicking ref's element or descendent elements
if (!ref.current || ref.current.contains(event.target)) {
return;
}
handler(event);
};
document.addEventListener("mousedown", listener);
document.addEventListener("touchstart", listener);
return () => {
document.removeEventListener("mousedown", listener);
document.removeEventListener("touchstart", listener);
};
}, [ref, handler]);
}

10
packages/react-app/src/utils/index.js vendored Normal file
View File

@@ -0,0 +1,10 @@
export {
getAvailableTokens,
getCounterpartTokens,
findPoolByTokens,
isOperationPending,
getFailureMessage,
getSuccessMessage,
useAmountsOut,
useOnClickOutside
} from './helpers';