Browse Source

import my deviation from taquito-boilerplate-react template

master
Dom SP 3 years ago
parent
commit
e792cad76f
20 changed files with 36997 additions and 1 deletions
  1. +23
    -0
      .gitignore
  2. +32
    -1
      README.md
  3. +35876
    -0
      package-lock.json
  4. +47
    -0
      package.json
  5. BIN
      public/built-with-taquito.png
  6. BIN
      public/favicon.png
  7. +34
    -0
      public/index.html
  8. +25
    -0
      public/manifest.json
  9. +3
    -0
      public/robots.txt
  10. +190
    -0
      src/App.css
  11. +203
    -0
      src/App.tsx
  12. +48
    -0
      src/components/BuyButton.tsx
  13. +137
    -0
      src/components/ConnectWallet.tsx
  14. +50
    -0
      src/components/DisconnectWallet.tsx
  15. +70
    -0
      src/components/Transfers.tsx
  16. +75
    -0
      src/components/UpdateContract.tsx
  17. +16
    -0
      src/index.js
  18. +1
    -0
      src/react-app-env.d.ts
  19. +141
    -0
      src/serviceWorker.js
  20. +26
    -0
      tsconfig.json

+ 23
- 0
.gitignore View File

@@ -0,0 +1,23 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# production
/build

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*

+ 32
- 1
README.md View File

@@ -1,3 +1,34 @@
# freaPay

~Webmodule~ to include a "Buy button" with streamlined crypto-pay transaction.
~Webmodule~ to include a "Buy button" with streamlined crypto-pay transaction.

## freaPay 0.1

![Built with Taquito][logo]

A minimal React App with a Buy-Button.
On triggering the Buy-Button a certain amount - given as React Component parameter - of any FA2 compatible contract based asset is transfered to a certain wallet, also given as React Component parameter.
Based on the Taquito Boilerplate React Template

**status: this project is in early development and is not recommended for anything really**


### Getting Started

1. Make sure you have https://nodejs.org/ installed on your computer
2. Clone your new repository:

`git clone <YOUR_REPOSITORY_URL>`

3. Change your current working directory to the newly cloned repository directory.
4. Install dependencies:

`npm install`

5. Start development server:

`npm run start`

6. Open https://localhost:3000 in your browser to see a sample application.

[logo]: https://raw.githubusercontent.com/ecadlabs/taquito-boilerplate/master/assets/built-with-taquito.png "Built with Taquito"

+ 35876
- 0
package-lock.json
File diff suppressed because it is too large
View File


+ 47
- 0
package.json View File

@@ -0,0 +1,47 @@
{
"name": "taquito-boilerplate-react",
"version": "0.1.0",
"private": true,
"dependencies": {
"@ledgerhq/hw-transport-u2f": "^5.22.0",
"@taquito/beacon-wallet": "^9.2.0-stablelib.0",
"@taquito/ledger-signer": "^9.2.0-stablelib.0",
"@taquito/taquito": "^9.2.0-stablelib.0",
"@testing-library/jest-dom": "^5.11.9",
"@testing-library/react": "^11.2.5",
"@testing-library/user-event": "^12.6.3",
"@types/jest": "^26.0.20",
"@types/ledgerhq__hw-transport-u2f": "^4.21.2",
"@types/node": "^14.14.25",
"@types/react": "^17.0.1",
"@types/react-dom": "^17.0.0",
"chokidar": "^3.5.2",
"qrcode-generator": "^1.4.4",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-scripts": "4.0.2",
"typescript": "^4.1.4"
},
"scripts": {
"start": "HTTPS=true react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"update-taquito": "ncu -u --target newest --filter '/^@taquito.*$/' && npm i"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}

BIN
public/built-with-taquito.png View File

Before After
Width: 128  |  Height: 56  |  Size: 7.1KB

BIN
public/favicon.png View File

Before After
Width: 148  |  Height: 148  |  Size: 34KB

+ 34
- 0
public/index.html View File

@@ -0,0 +1,34 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css"
integrity="sha512-1PKOgIY59xJ8Co8+NE6FZ+LOAZKjy+KY8iq0G4B3CyeY6wYHN3yt9PW0XpSriVlkMXe40PTKnXrLnZ9+fkDaog=="
crossorigin="anonymous"
/>
<title>Taquito Boilerplate</title>
</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>

+ 25
- 0
public/manifest.json View File

@@ -0,0 +1,25 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

+ 3
- 0
public/robots.txt View File

@@ -0,0 +1,3 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:

+ 190
- 0
src/App.css View File

@@ -0,0 +1,190 @@
html,
body,
#root {
height: 100%;
width: 100%;
margin: 0px;
padding: 0px;
font-size: 1rem;
}

#root {
display: grid;
}

.main-box {
margin: auto;
}

.title {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}

h1 {
color: #35636e;
text-align: left;
}

header {
font-size: 1.5rem;
padding: 20px;
background-color: #35636e;
color: white;
}

#dialog {
display: flex;
flex-direction: column;
width: 500px;
border: 1px solid #35636e;
border-radius: 3px;
}

#content {
display: flex;
flex-direction: column;
padding: 20px;
}

#footer {
display: flex;
justify-content: flex-end;
padding-top: 20px;
}

.buttons {
display: flex;
flex-direction: row;
justify-content: space-around;
padding: 0px 10px 20px 10px;
}

.button {
margin-top: 0px;
margin-bottom: 5px;
color: #35636e;
font-size: 1rem;
padding: 15px;
background-color: white;
border-radius: 3px;
border: solid 2px #35636e;
outline: none;
cursor: pointer;
transition: 0.2s;
}
.button:hover {
color: white;
background-color: #35636e;
}
.button:active {
margin-top: 5px;
margin-bottom: 0px;
}

#public-token {
word-break: break-word;
}
#public-token-copy,
#public-token-copy__copied {
float: right;
text-align: center;
margin: 15px 10px;
padding: 5px;
cursor: pointer;
transition: 0.2s;
}
#public-token-copy:hover {
border-radius: 3px;
color: white;
background-color: #35636e;
}

.text-align-center {
text-align: center;
}

a {
text-decoration: none;
color: royalblue;
}
a:hover {
font-style: italic;
}

#tabs {
display: flex;
flex-direction: row;
justify-content: space-around;
border: none;
color: #35636e;
margin: 0px;
transition: 0.3s;
}

#tabs div {
width: 80%;
padding: 20px;
margin: 0px 10px;
border: solid 1px #35636e;
border-bottom: none;
text-align: center;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
cursor: pointer;
}

#tabs div.active {
background-color: #35636e;
color: white;
}

#transfer-inputs {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
padding: 0px 10px 20px 10px;
}

#transfer-inputs input[type="text"] {
padding: 15px;
border-top-left-radius: 3px;
border-bottom-left-radius: 3px;
border: solid 2px #35636e;
outline: none;
font-size: 1rem;
border-right: none;
margin-top: 0px;
margin-bottom: 5px;
}

#transfer-inputs input[type="number"] {
padding: 15px;
width: 60px;
border: solid 2px #35636e;
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
border-left: none;
outline: none;
margin-right: 5px;
font-size: 1rem;
margin-top: 0px;
margin-bottom: 5px;
text-align: right;
}

/* Removes arrows in input number */
/* Chrome, Safari, Edge, Opera */
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}

/* Firefox */
input[type="number"] {
-moz-appearance: textfield;
}

+ 203
- 0
src/App.tsx View File

@@ -0,0 +1,203 @@
import React, { useState } from "react";
import { TezosToolkit } from "@taquito/taquito";
import "./App.css";
import ConnectButton from "./components/ConnectWallet";
import DisconnectButton from "./components/DisconnectWallet";
import qrcode from "qrcode-generator";
import UpdateContract from "./components/UpdateContract";
import Transfers from "./components/Transfers";
import BuyButton from "./components/BuyButton";

enum BeaconConnection {
NONE = "",
LISTENING = "Listening to P2P channel",
CONNECTED = "Channel connected",
PERMISSION_REQUEST_SENT = "Permission request sent, waiting for response",
PERMISSION_REQUEST_SUCCESS = "Wallet is connected"
}

const App = () => {
const [Tezos, setTezos] = useState<TezosToolkit>(
new TezosToolkit("https://mainnet.api.tez.ie/")
);
const [contract, setContract] = useState<any>(undefined);
const [publicToken, setPublicToken] = useState<string | null>("");
const [wallet, setWallet] = useState<any>(null);
const [userAddress, setUserAddress] = useState<string>("");
const [userBalance, setUserBalance] = useState<number>(0);
const [storage, setStorage] = useState<number>(0);
const [copiedPublicToken, setCopiedPublicToken] = useState<boolean>(false);
const [beaconConnection, setBeaconConnection] = useState<boolean>(false);
const [activeTab, setActiveTab] = useState<string>("transfer");

// Granadanet Increment/Decrement contract
const contractAddress: string = "KT1K3XVNzsmur7VRgY8CAHPUENaErzzEpe4e";

const generateQrCode = (): { __html: string } => {
const qr = qrcode(0, "L");
qr.addData(publicToken || "");
qr.make();

return { __html: qr.createImgTag(4) };
};

if (publicToken && (!userAddress || isNaN(userBalance))) {
return (
<div className="main-box">
<h1>Taquito Boilerplate</h1>

<div id="dialog">
<header>Try the Taquito Boilerplate App!</header>
<div id="content">
<p className="text-align-center">
<i className="fas fa-broadcast-tower"></i>&nbsp; Connecting to
your wallet
</p>
<div
dangerouslySetInnerHTML={generateQrCode()}
className="text-align-center"
></div>
<p id="public-token">
{copiedPublicToken ? (
<span id="public-token-copy__copied">
<i className="far fa-thumbs-up"></i>
</span>
) : (
<span
id="public-token-copy"
onClick={() => {
if (publicToken) {
navigator.clipboard.writeText(publicToken);
setCopiedPublicToken(true);
setTimeout(() => setCopiedPublicToken(false), 2000);
}
}}
>
<i className="far fa-copy"></i>
</span>
)}

<span>
Public token: <span>{publicToken}</span>
</span>
</p>
<p className="text-align-center">
Status: {beaconConnection ? "Connected" : "Disconnected"}
</p>
</div>
</div>
<div id="footer">
<img src="built-with-taquito.png" alt="Built with Taquito" />
</div>
</div>
);
} else if (userAddress && !isNaN(userBalance)) {
return (
<div className="main-box">
<h1>Taquito Boilerplate</h1>
<div id="tabs">
<div
id="transfer"
className={activeTab === "transfer" ? "active" : ""}
onClick={() => setActiveTab("transfer")}
>
Make a transfer
</div>
<div
id="contract"
className={activeTab === "contract" ? "active" : ""}
onClick={() => setActiveTab("contract")}
>
Interact with a contract
</div>
</div>
<div id="dialog">
<div id="content">


<p>
<i className="far fa-address-card"></i>&nbsp; {userAddress}
</p>
<p>
<i className="fas fa-piggy-bank"></i>&nbsp;
{(userBalance / 1000000).toLocaleString("en-US")} ꜩ
</p>
</div>
<BuyButton
Tezos={Tezos}
FA2address="KT1BB1uMwVvJ1M3vVHXWALs1RWdgTp1rnXTR"
receiver="tz1hJncvXvL2VyctPE685GJPXDaRJ7dtiwjm"
amount={100}
/>
<DisconnectButton
wallet={wallet}
setPublicToken={setPublicToken}
setUserAddress={setUserAddress}
setUserBalance={setUserBalance}
setWallet={setWallet}
setTezos={setTezos}
setBeaconConnection={setBeaconConnection}
/>
</div>
<div id="footer">
<img src="built-with-taquito.png" alt="Built with Taquito" />
</div>
</div>
);
} else if (!publicToken && !userAddress && !userBalance) {
return (
<div className="main-box">
<div className="title">
<h1>Taquito Boilerplate</h1>
<a href="https://app.netlify.com/start/deploy?repository=https://github.com/ecadlabs/taquito-boilerplate">
<img
src="https://www.netlify.com/img/deploy/button.svg"
alt="netlify-button"
/>
</a>
</div>
<div id="dialog">
<header>Welcome to Taquito Boilerplate App!</header>
<div id="content">
<p>Hello!</p>
<p>
This is a template Tezos dApp built using Taquito. It's a starting
point for you to hack on and build your own dApp for Tezos.
<br />
If you have not done so already, go to the{" "}
<a
href="https://github.com/ecadlabs/taquito-boilerplate"
target="_blank"
rel="noopener noreferrer"
>
Taquito boilerplate Github page
</a>{" "}
and click the <em>"Use this template"</em> button.
</p>
<p>Go forth and Tezos!</p>
</div>
<ConnectButton
Tezos={Tezos}
setContract={setContract}
setPublicToken={setPublicToken}
setWallet={setWallet}
setUserAddress={setUserAddress}
setUserBalance={setUserBalance}
setStorage={setStorage}
contractAddress={contractAddress}
setBeaconConnection={setBeaconConnection}
wallet={wallet}
/>
</div>
<div id="footer">
<img src="built-with-taquito.png" alt="Built with Taquito" />
</div>
</div>
);
} else {
return <div>An error has occurred</div>;
}
};

export default App;

+ 48
- 0
src/components/BuyButton.tsx View File

@@ -0,0 +1,48 @@
import React, { Dispatch, SetStateAction, useState, useEffect } from "react";
import { TezosToolkit } from "@taquito/taquito";
import { BeaconWallet } from "@taquito/beacon-wallet";


const BuyButton = ({
Tezos,
FA2address,
receiver,
amount
}: {
Tezos: TezosToolkit,
FA2address: string,
receiver: string,
amount: number
}): JSX.Element => {

const makePayment = async (): Promise<void> => {
const contract = await Tezos.wallet.at(FA2address);
const transfer_params = [
{
from_: "tz1LigkX55duWS2pZt4u5qTAWUu6Sb9bMxbg",
txs: [{
to_: "tz1hJncvXvL2VyctPE685GJPXDaRJ7dtiwjm",
token_id:0,
amount: amount
}]
}
];
const op = await contract.methods.transfer(transfer_params).send();
await op.confirmation();
}
return (
<div className="buttons">
<button
className="myButton"
onClick={makePayment}
>
{FA2address}
</button>
</div>
);
};

export default BuyButton;

+ 137
- 0
src/components/ConnectWallet.tsx View File

@@ -0,0 +1,137 @@
import React, { Dispatch, SetStateAction, useState, useEffect } from "react";
import { TezosToolkit } from "@taquito/taquito";
import { BeaconWallet } from "@taquito/beacon-wallet";
import {
NetworkType,
BeaconEvent,
defaultEventCallbacks
} from "@airgap/beacon-sdk";
import TransportU2F from "@ledgerhq/hw-transport-u2f";
import { LedgerSigner } from "@taquito/ledger-signer";

type ButtonProps = {
Tezos: TezosToolkit;
setContract: Dispatch<SetStateAction<any>>;
setWallet: Dispatch<SetStateAction<any>>;
setUserAddress: Dispatch<SetStateAction<string>>;
setUserBalance: Dispatch<SetStateAction<number>>;
setStorage: Dispatch<SetStateAction<number>>;
contractAddress: string;
setBeaconConnection: Dispatch<SetStateAction<boolean>>;
setPublicToken: Dispatch<SetStateAction<string | null>>;
wallet: BeaconWallet;
};

const ConnectButton = ({
Tezos,
setContract,
setWallet,
setUserAddress,
setUserBalance,
setStorage,
contractAddress,
setBeaconConnection,
setPublicToken,
wallet
}: ButtonProps): JSX.Element => {
const [loadingNano, setLoadingNano] = useState<boolean>(false);

const setup = async (userAddress: string): Promise<void> => {
setUserAddress(userAddress);
// updates balance
const balance = await Tezos.tz.getBalance(userAddress);
setUserBalance(balance.toNumber());
// creates contract instance
const contract = await Tezos.wallet.at(contractAddress);
const storage: any = await contract.storage();
setContract(contract);
setStorage(storage.toNumber());
};

const connectWallet = async (): Promise<void> => {
try {
await wallet.requestPermissions({
network: {
type: NetworkType.MAINNET,
rpcUrl: "https://mainnet.api.tez.ie/"
}
});
// gets user's address
const userAddress = await wallet.getPKH();
await setup(userAddress);
setBeaconConnection(true);
} catch (error) {
console.log(error);
}
};

const connectNano = async (): Promise<void> => {
try {
setLoadingNano(true);
const transport = await TransportU2F.create();
const ledgerSigner = new LedgerSigner(transport, "44'/1729'/0'/0'", true);

Tezos.setSignerProvider(ledgerSigner);

//Get the public key and the public key hash from the Ledger
const userAddress = await Tezos.signer.publicKeyHash();
await setup(userAddress);
} catch (error) {
console.log("Error!", error);
setLoadingNano(false);
}
};

useEffect(() => {
(async () => {
// creates a wallet instance
const wallet = new BeaconWallet({
name: "Taquito Boilerplate",
preferredNetwork: NetworkType.MAINNET,
disableDefaultEvents: true, // Disable all events / UI. This also disables the pairing alert.
eventHandlers: {
// To keep the pairing alert, we have to add the following default event handlers back
[BeaconEvent.PAIR_INIT]: {
handler: defaultEventCallbacks.PAIR_INIT
},
[BeaconEvent.PAIR_SUCCESS]: {
handler: data => setPublicToken(data.publicKey)
}
}
});
Tezos.setWalletProvider(wallet);
setWallet(wallet);
// checks if wallet was connected before
const activeAccount = await wallet.client.getActiveAccount();
if (activeAccount) {
const userAddress = await wallet.getPKH();
await setup(userAddress);
setBeaconConnection(true);
}
})();
}, []);

return (
<div className="buttons">
<button className="button" onClick={connectWallet}>
<span>
<i className="fas fa-wallet"></i>&nbsp; Connect with wallet
</span>
</button>
<button className="button" disabled={loadingNano} onClick={connectNano}>
{loadingNano ? (
<span>
<i className="fas fa-spinner fa-spin"></i>&nbsp; Loading, please
wait
</span>
) : (
<span>
<i className="fab fa-usb"></i>&nbsp; Connect with Ledger Nano
</span>
)}
</button>
</div>
);
};

export default ConnectButton;

+ 50
- 0
src/components/DisconnectWallet.tsx View File

@@ -0,0 +1,50 @@
import React, { Dispatch, SetStateAction } from "react";
import { BeaconWallet } from "@taquito/beacon-wallet";
import { TezosToolkit } from "@taquito/taquito";

interface ButtonProps {
wallet: BeaconWallet | null;
setPublicToken: Dispatch<SetStateAction<string | null>>;
setUserAddress: Dispatch<SetStateAction<string>>;
setUserBalance: Dispatch<SetStateAction<number>>;
setWallet: Dispatch<SetStateAction<any>>;
setTezos: Dispatch<SetStateAction<TezosToolkit>>;
setBeaconConnection: Dispatch<SetStateAction<boolean>>;
}

const DisconnectButton = ({
wallet,
setPublicToken,
setUserAddress,
setUserBalance,
setWallet,
setTezos,
setBeaconConnection
}: ButtonProps): JSX.Element => {
const disconnectWallet = async (): Promise<void> => {
//window.localStorage.clear();
setUserAddress("");
setUserBalance(0);
setWallet(null);
const tezosTK = new TezosToolkit("https://api.tez.ie/rpc/granadanet");
setTezos(tezosTK);
setBeaconConnection(false);
setPublicToken(null);
console.log("disconnecting wallet");
if (wallet) {
await wallet.client.removeAllAccounts();
await wallet.client.removeAllPeers();
await wallet.client.destroy();
}
};

return (
<div className="buttons">
<button className="button" onClick={disconnectWallet}>
<i className="fas fa-times"></i>&nbsp; Disconnect wallet
</button>
</div>
);
};

export default DisconnectButton;

+ 70
- 0
src/components/Transfers.tsx View File

@@ -0,0 +1,70 @@
import React, { useState, Dispatch, SetStateAction } from "react";
import { TezosToolkit } from "@taquito/taquito";

const Transfers = ({
Tezos,
setUserBalance,
userAddress
}: {
Tezos: TezosToolkit;
setUserBalance: Dispatch<SetStateAction<number>>;
userAddress: string;
}): JSX.Element => {
const [recipient, setRecipient] = useState<string>("");
const [amount, setAmount] = useState<string>("");
const [loading, setLoading] = useState<boolean>(false);

const sendTransfer = async (): Promise<void> => {
if (recipient && amount) {
setLoading(true);
try {
const op = await Tezos.wallet
.transfer({ to: recipient, amount: parseInt(amount) })
.send();
await op.confirmation();
setRecipient("");
setAmount("");
const balance = await Tezos.tz.getBalance(userAddress);
setUserBalance(balance.toNumber());
} catch (error) {
console.log(error);
} finally {
setLoading(false);
}
}
};

return (
<div id="transfer-inputs">
<input
type="text"
placeholder="Recipient"
value={recipient}
onChange={e => setRecipient(e.target.value)}
/>
<input
type="number"
placeholder="Amount"
value={amount}
onChange={e => setAmount(e.target.value)}
/>
<button
className="button"
disabled={!recipient && !amount}
onClick={sendTransfer}
>
{loading ? (
<span>
<i className="fas fa-spinner fa-spin"></i>&nbsp; Please wait
</span>
) : (
<span>
<i className="far fa-paper-plane"></i>&nbsp; Send
</span>
)}
</button>
</div>
);
};

export default Transfers;

+ 75
- 0
src/components/UpdateContract.tsx View File

@@ -0,0 +1,75 @@
import React, { useState, Dispatch, SetStateAction } from "react";
import { TezosToolkit, WalletContract } from "@taquito/taquito";

interface UpdateContractProps {
contract: WalletContract | any;
setUserBalance: Dispatch<SetStateAction<any>>;
Tezos: TezosToolkit;
userAddress: string;
setStorage: Dispatch<SetStateAction<number>>;
}

const UpdateContract = ({ contract, setUserBalance, Tezos, userAddress, setStorage }: UpdateContractProps) => {
const [loadingIncrement, setLoadingIncrement] = useState<boolean>(false);
const [loadingDecrement, setLoadingDecrement] = useState<boolean>(false);

const increment = async (): Promise<void> => {
setLoadingIncrement(true);
try {
const op = await contract.methods.increment(1).send();
await op.confirmation();
const newStorage: any = await contract.storage();
if (newStorage) setStorage(newStorage.toNumber());
setUserBalance(await Tezos.tz.getBalance(userAddress));
} catch (error) {
console.log(error);
} finally {
setLoadingIncrement(false);
}
};

const decrement = async (): Promise<void> => {
setLoadingDecrement(true);
try {
const op = await contract.methods.decrement(1).send();
await op.confirmation();
const newStorage: any = await contract.storage();
if (newStorage) setStorage(newStorage.toNumber());
setUserBalance(await Tezos.tz.getBalance(userAddress));
} catch (error) {
console.log(error);
} finally {
setLoadingDecrement(false);
}
};

if (!contract && !userAddress) return <div>&nbsp;</div>;
return (
<div className="buttons">
<button className="button" disabled={loadingIncrement} onClick={increment}>
{loadingIncrement ? (
<span>
<i className="fas fa-spinner fa-spin"></i>&nbsp; Please wait
</span>
) : (
<span>
<i className="fas fa-plus"></i>&nbsp; Increment by 1
</span>
)}
</button>
<button className="button" onClick={decrement}>
{loadingDecrement ? (
<span>
<i className="fas fa-spinner fa-spin"></i>&nbsp; Please wait
</span>
) : (
<span>
<i className="fas fa-minus"></i>&nbsp; Decrement by 1
</span>
)}
</button>
</div>
);
};

export default UpdateContract;

+ 16
- 0
src/index.js View File

@@ -0,0 +1,16 @@
import React from "react";
import ReactDOM from "react-dom";
import App from "./App.tsx";
import * as serviceWorker from "./serviceWorker";

ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById("root")
);

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

+ 1
- 0
src/react-app-env.d.ts View File

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

+ 141
- 0
src/serviceWorker.js View File

@@ -0,0 +1,141 @@
// This optional code is used to register a service worker.
// register() is not called by default.

// This lets the app load faster on subsequent visits in production, and gives
// it offline capabilities. However, it also means that developers (and users)
// will only see deployed updates on subsequent visits to a page, after all the
// existing tabs open on the page have been closed, since previously cached
// resources are updated in the background.

// To learn more about the benefits of this model and instructions on how to
// opt-in, read https://bit.ly/CRA-PWA

const isLocalhost = Boolean(
window.location.hostname === 'localhost' ||
// [::1] is the IPv6 localhost address.
window.location.hostname === '[::1]' ||
// 127.0.0.0/8 are considered localhost for IPv4.
window.location.hostname.match(
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
)
);

export function register(config) {
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
// The URL constructor is available in all browsers that support SW.
const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
if (publicUrl.origin !== window.location.origin) {
// Our service worker won't work if PUBLIC_URL is on a different origin
// from what our page is served on. This might happen if a CDN is used to
// serve assets; see https://github.com/facebook/create-react-app/issues/2374
return;
}

window.addEventListener('load', () => {
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;

if (isLocalhost) {
// This is running on localhost. Let's check if a service worker still exists or not.
checkValidServiceWorker(swUrl, config);

// Add some additional logging to localhost, pointing developers to the
// service worker/PWA documentation.
navigator.serviceWorker.ready.then(() => {
console.log(
'This web app is being served cache-first by a service ' +
'worker. To learn more, visit https://bit.ly/CRA-PWA'
);
});
} else {
// Is not localhost. Just register service worker
registerValidSW(swUrl, config);
}
});
}
}

function registerValidSW(swUrl, config) {
navigator.serviceWorker
.register(swUrl)
.then(registration => {
registration.onupdatefound = () => {
const installingWorker = registration.installing;
if (installingWorker == null) {
return;
}
installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
// At this point, the updated precached content has been fetched,
// but the previous service worker will still serve the older
// content until all client tabs are closed.
console.log(
'New content is available and will be used when all ' +
'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
);

// Execute callback
if (config && config.onUpdate) {
config.onUpdate(registration);
}
} else {
// At this point, everything has been precached.
// It's the perfect time to display a
// "Content is cached for offline use." message.
console.log('Content is cached for offline use.');

// Execute callback
if (config && config.onSuccess) {
config.onSuccess(registration);
}
}
}
};
};
})
.catch(error => {
console.error('Error during service worker registration:', error);
});
}

function checkValidServiceWorker(swUrl, config) {
// Check if the service worker can be found. If it can't reload the page.
fetch(swUrl, {
headers: { 'Service-Worker': 'script' },
})
.then(response => {
// Ensure service worker exists, and that we really are getting a JS file.
const contentType = response.headers.get('content-type');
if (
response.status === 404 ||
(contentType != null && contentType.indexOf('javascript') === -1)
) {
// No service worker found. Probably a different app. Reload the page.
navigator.serviceWorker.ready.then(registration => {
registration.unregister().then(() => {
window.location.reload();
});
});
} else {
// Service worker found. Proceed as normal.
registerValidSW(swUrl, config);
}
})
.catch(() => {
console.log(
'No internet connection found. App is running in offline mode.'
);
});
}

export function unregister() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready
.then(registration => {
registration.unregister();
})
.catch(error => {
console.error(error.message);
});
}
}

+ 26
- 0
tsconfig.json View File

@@ -0,0 +1,26 @@
{
"compilerOptions": {
"target": "es6",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"noFallthroughCasesInSwitch": true
},
"include": [
"src"
]
}

Loading…
Cancel
Save