From d23c40e97ccf92d3cc82a80bbffe520e1a1125a6 Mon Sep 17 00:00:00 2001 From: benjamin fuentes Date: Thu, 11 Jan 2024 20:14:04 +0100 Subject: [PATCH] Mobile-tutorial (#214) * fist commit to prepare the rest of the tutorial * version ready to be reviewed * fix broken link * fix typo * Added remarks from Tim * Grammar and style for parts 1 and 2 * wip grammar and style for parts 3 and 4 * Grammar and punctuation for parts 3 and 4 * Remove redundant Tezos from title * adding company name * adding author --------- Co-authored-by: Tim McMackin --- docs/tutorials.mdx | 12 +- docs/tutorials/build-an-nft-marketplace.md | 1 + .../build-an-nft-marketplace/part-1.md | 135 +- .../build-an-nft-marketplace/part-2.md | 177 +-- .../build-an-nft-marketplace/part-3.md | 359 ++--- .../build-an-nft-marketplace/part-4.md | 359 ++--- docs/tutorials/dapp.md | 2 +- docs/tutorials/dapp/part-1.md | 90 +- docs/tutorials/dapp/part-2.md | 2 +- docs/tutorials/dapp/part-3.md | 64 +- docs/tutorials/dapp/part-4.md | 92 +- docs/tutorials/mobile.md | 54 + docs/tutorials/mobile/part-1.md | 125 ++ docs/tutorials/mobile/part-2.md | 1153 +++++++++++++++++ docs/tutorials/mobile/part-3.md | 829 ++++++++++++ docs/tutorials/mobile/part-4.md | 134 ++ sidebars.js | 14 + static/img/tutorials/mobile-alice.png | Bin 0 -> 247404 bytes static/img/tutorials/mobile-build.png | Bin 0 -> 231941 bytes static/img/tutorials/mobile-home.png | Bin 0 -> 67111 bytes static/img/tutorials/mobile-kukai.png | Bin 0 -> 73764 bytes static/img/tutorials/mobile-picHOME.png | Bin 0 -> 86021 bytes static/img/tutorials/mobile-run.png | Bin 0 -> 130174 bytes static/img/tutorials/mobile-sign.png | Bin 0 -> 9814 bytes 24 files changed, 2962 insertions(+), 640 deletions(-) create mode 100644 docs/tutorials/mobile.md create mode 100644 docs/tutorials/mobile/part-1.md create mode 100644 docs/tutorials/mobile/part-2.md create mode 100644 docs/tutorials/mobile/part-3.md create mode 100644 docs/tutorials/mobile/part-4.md create mode 100644 static/img/tutorials/mobile-alice.png create mode 100644 static/img/tutorials/mobile-build.png create mode 100644 static/img/tutorials/mobile-home.png create mode 100644 static/img/tutorials/mobile-kukai.png create mode 100644 static/img/tutorials/mobile-picHOME.png create mode 100644 static/img/tutorials/mobile-run.png create mode 100644 static/img/tutorials/mobile-sign.png diff --git a/docs/tutorials.mdx b/docs/tutorials.mdx index ba661e719..8149c111a 100644 --- a/docs/tutorials.mdx +++ b/docs/tutorials.mdx @@ -4,8 +4,8 @@ title: Tutorials These tutorials can help you get started developing different kinds of applications on Tezos in as little as 15 minutes. -import TutorialCard from "@site/src/components/TutorialCard"; -import TutorialCardContainer from "@site/src/components/TutorialCardContainer"; +import TutorialCard from '@site/src/components/TutorialCard'; +import TutorialCardContainer from '@site/src/components/TutorialCardContainer'; ## Beginner @@ -109,4 +109,12 @@ These tutorials are intended for developers who are familiar with Tezos and want link="Start tutorial" /> + + diff --git a/docs/tutorials/build-an-nft-marketplace.md b/docs/tutorials/build-an-nft-marketplace.md index f9375839c..8241e96fa 100644 --- a/docs/tutorials/build-an-nft-marketplace.md +++ b/docs/tutorials/build-an-nft-marketplace.md @@ -1,5 +1,6 @@ --- title: Build an NFT marketplace +authors: 'Benjamin Fuentes (Marigold)' lastUpdated: 8nd November 2023 --- diff --git a/docs/tutorials/build-an-nft-marketplace/part-1.md b/docs/tutorials/build-an-nft-marketplace/part-1.md index 12e3b940a..418247299 100644 --- a/docs/tutorials/build-an-nft-marketplace/part-1.md +++ b/docs/tutorials/build-an-nft-marketplace/part-1.md @@ -1,5 +1,6 @@ --- -title: "Part 1: Minting tokens" +title: 'Part 1: Minting tokens' +authors: 'Benjamin Fuentes (Marigold)' lastUpdated: 8th November 2023 --- @@ -564,17 +565,17 @@ The mint page uses a form that accepts information and an image and sends a tran ```typescript const validationSchema = yup.object({ - name: yup.string().required("Name is required"), - description: yup.string().required("Description is required"), - symbol: yup.string().required("Symbol is required"), + name: yup.string().required('Name is required'), + description: yup.string().required('Description is required'), + symbol: yup.string().required('Symbol is required'), }); const formik = useFormik({ initialValues: { - name: "", - description: "", + name: '', + description: '', token_id: 0, - symbol: "WINE", + symbol: 'WINE', } as TZIP21TokenMetadata, validationSchema: validationSchema, onSubmit: (values) => { @@ -586,7 +587,7 @@ The mint page uses a form that accepts information and an image and sends a tran 1. After this code, add state variables for the image and its URL: ```typescript - const [pictureUrl, setPictureUrl] = useState(""); + const [pictureUrl, setPictureUrl] = useState(''); const [file, setFile] = useState(null); ``` @@ -605,9 +606,9 @@ The mint page uses a form that accepts information and an image and sends a tran const toggleDrawer = (open: boolean) => (event: React.KeyboardEvent | React.MouseEvent) => { if ( - event.type === "keydown" && - ((event as React.KeyboardEvent).key === "Tab" || - (event as React.KeyboardEvent).key === "Shift") + event.type === 'keydown' && + ((event as React.KeyboardEvent).key === 'Tab' || + (event as React.KeyboardEvent).key === 'Shift') ) { return; } @@ -625,29 +626,29 @@ The mint page uses a form that accepts information and an image and sends a tran //IPFS if (file) { const formData = new FormData(); - formData.append("file", file); + formData.append('file', file); const requestHeaders: HeadersInit = new Headers(); requestHeaders.set( - "pinata_api_key", + 'pinata_api_key', `${import.meta.env.VITE_PINATA_API_KEY}` ); requestHeaders.set( - "pinata_secret_api_key", + 'pinata_secret_api_key', `${import.meta.env.VITE_PINATA_API_SECRET}` ); const resFile = await fetch( - "https://api.pinata.cloud/pinning/pinFileToIPFS", + 'https://api.pinata.cloud/pinning/pinFileToIPFS', { - method: "post", + method: 'post', body: formData, headers: requestHeaders, } ); const responseJson = await resFile.json(); - console.log("responseJson", responseJson); + console.log('responseJson', responseJson); const thumbnailUri = `ipfs://${responseJson.IpfsHash}`; setPictureUrl( @@ -667,13 +668,13 @@ The mint page uses a form that accepts information and an image and sends a tran //close directly the form setFormOpen(false); enqueueSnackbar( - "Wine collection is minting ... it will be ready on next block, wait for the confirmation message before minting another collection", - { variant: "info" } + 'Wine collection is minting ... it will be ready on next block, wait for the confirmation message before minting another collection', + { variant: 'info' } ); await op.confirmation(2); - enqueueSnackbar("Wine collection minted", { variant: "success" }); + enqueueSnackbar('Wine collection minted', { variant: 'success' }); refreshUserContextOnPageReload(); //force all app to refresh the context } @@ -682,7 +683,7 @@ The mint page uses a form that accepts information and an image and sends a tran let tibe: TransactionInvalidBeaconError = new TransactionInvalidBeaconError(error); enqueueSnackbar(tibe.data_message, { - variant: "error", + variant: 'error', autoHideDuration: 10000, }); } @@ -700,7 +701,7 @@ The mint page uses a form that accepts information and an image and sends a tran useEffect(() => { (async () => { if (nftContratTokenMetadataMap && nftContratTokenMetadataMap.size > 0) { - formik.setFieldValue("token_id", nftContratTokenMetadataMap.size); + formik.setFieldValue('token_id', nftContratTokenMetadataMap.size); } })(); }, [nftContratTokenMetadataMap?.size]); @@ -709,8 +710,8 @@ The mint page uses a form that accepts information and an image and sends a tran 1. Replace the imports at the top of the file with these imports: ```typescript - import { AddCircleOutlined, Close } from "@mui/icons-material"; - import OpenWithIcon from "@mui/icons-material/OpenWith"; + import { AddCircleOutlined, Close } from '@mui/icons-material'; + import OpenWithIcon from '@mui/icons-material/OpenWith'; import { Box, Button, @@ -719,18 +720,18 @@ The mint page uses a form that accepts information and an image and sends a tran TextField, Toolbar, useMediaQuery, - } from "@mui/material"; - import Paper from "@mui/material/Paper"; - import Typography from "@mui/material/Typography"; - import { useFormik } from "formik"; - import React, { useEffect, useState } from "react"; - import * as yup from "yup"; - import { TZIP21TokenMetadata, UserContext, UserContextType } from "./App"; - import { useSnackbar } from "notistack"; - import { BigNumber } from "bignumber.js"; - import { address, bytes, nat } from "./type-aliases"; - import { char2Bytes } from "@taquito/utils"; - import { TransactionInvalidBeaconError } from "./TransactionInvalidBeaconError"; + } from '@mui/material'; + import Paper from '@mui/material/Paper'; + import Typography from '@mui/material/Typography'; + import { useFormik } from 'formik'; + import React, { useEffect, useState } from 'react'; + import * as yup from 'yup'; + import { TZIP21TokenMetadata, UserContext, UserContextType } from './App'; + import { useSnackbar } from 'notistack'; + import { BigNumber } from 'bignumber.js'; + import { address, bytes, nat } from './type-aliases'; + import { char2Bytes } from '@taquito/utils'; + import { TransactionInvalidBeaconError } from './TransactionInvalidBeaconError'; ``` 1. Save the file. @@ -790,7 +791,7 @@ Follow these steps to show the tokens that you have minted: 1. In the `MintPage.tsx` file, replace the `"//TODO"` comment with this code: ```typescript - + ( @@ -818,24 +819,24 @@ Follow these steps to show the tokens that you have minted: sx={ isTablet ? { - width: "auto", - marginLeft: "33%", - maxHeight: "50vh", + width: 'auto', + marginLeft: '33%', + maxHeight: '50vh', } - : { width: "100%", maxHeight: "40vh" } + : { width: '100%', maxHeight: '40vh' } } component="img" image={token.thumbnailUri?.replace( - "ipfs://", - "https://gateway.pinata.cloud/ipfs/" + 'ipfs://', + 'https://gateway.pinata.cloud/ipfs/' )} /> - {"ID : " + token_id} - {"Symbol : " + token.symbol} - {"Description : " + token.description} + {'ID : ' + token_id} + {'Symbol : ' + token.symbol} + {'Description : ' + token.description} @@ -893,8 +894,8 @@ Follow these steps to show the tokens that you have minted: 1. Replace the imports at the top of the file with these imports: ```typescript - import SwipeableViews from "react-swipeable-views"; - import OpenWithIcon from "@mui/icons-material/OpenWith"; + import SwipeableViews from 'react-swipeable-views'; + import OpenWithIcon from '@mui/icons-material/OpenWith'; import { Box, Button, @@ -906,26 +907,26 @@ Follow these steps to show the tokens that you have minted: TextField, Toolbar, useMediaQuery, - } from "@mui/material"; - import Card from "@mui/material/Card"; - import CardContent from "@mui/material/CardContent"; + } from '@mui/material'; + import Card from '@mui/material/Card'; + import CardContent from '@mui/material/CardContent'; import { AddCircleOutlined, Close, KeyboardArrowLeft, KeyboardArrowRight, - } from "@mui/icons-material"; - import Paper from "@mui/material/Paper"; - import Typography from "@mui/material/Typography"; - import { useFormik } from "formik"; - import React, { useEffect, useState } from "react"; - import * as yup from "yup"; - import { TZIP21TokenMetadata, UserContext, UserContextType } from "./App"; - import { useSnackbar } from "notistack"; - import { BigNumber } from "bignumber.js"; - import { address, bytes, nat } from "./type-aliases"; - import { char2Bytes } from "@taquito/utils"; - import { TransactionInvalidBeaconError } from "./TransactionInvalidBeaconError"; + } from '@mui/icons-material'; + import Paper from '@mui/material/Paper'; + import Typography from '@mui/material/Typography'; + import { useFormik } from 'formik'; + import React, { useEffect, useState } from 'react'; + import * as yup from 'yup'; + import { TZIP21TokenMetadata, UserContext, UserContextType } from './App'; + import { useSnackbar } from 'notistack'; + import { BigNumber } from 'bignumber.js'; + import { address, bytes, nat } from './type-aliases'; + import { char2Bytes } from '@taquito/utils'; + import { TransactionInvalidBeaconError } from './TransactionInvalidBeaconError'; ``` 1. Open the web page in the browser again and see that the NFT you created is shown, as in this picture: diff --git a/docs/tutorials/build-an-nft-marketplace/part-2.md b/docs/tutorials/build-an-nft-marketplace/part-2.md index 8ba3a96e1..33f7501bc 100644 --- a/docs/tutorials/build-an-nft-marketplace/part-2.md +++ b/docs/tutorials/build-an-nft-marketplace/part-2.md @@ -1,5 +1,6 @@ --- -title: "Part 2: Buying and selling tokens" +title: 'Part 2: Buying and selling tokens' +authors: 'Benjamin Fuentes (Marigold)' last_update: date: 8 November 2023 --- @@ -218,10 +219,10 @@ The contract storage must store the tokens that are offered for sale and their p 1. Open the sale page in the `./src/OffersPage.tsx` file and replace it with this code: ```typescript - import { InfoOutlined } from "@mui/icons-material"; - import SellIcon from "@mui/icons-material/Sell"; + import { InfoOutlined } from '@mui/icons-material'; + import SellIcon from '@mui/icons-material/Sell'; - import * as api from "@tzkt/sdk-api"; + import * as api from '@tzkt/sdk-api'; import { Box, @@ -238,25 +239,25 @@ The contract storage must store the tokens that are offered for sale and their p Tooltip, Typography, useMediaQuery, - } from "@mui/material"; - import Paper from "@mui/material/Paper"; - import BigNumber from "bignumber.js"; - import { useFormik } from "formik"; - import { useSnackbar } from "notistack"; - import React, { Fragment, useEffect, useState } from "react"; - import * as yup from "yup"; - import { UserContext, UserContextType } from "./App"; - import ConnectButton from "./ConnectWallet"; - import { TransactionInvalidBeaconError } from "./TransactionInvalidBeaconError"; - import { address, nat } from "./type-aliases"; + } from '@mui/material'; + import Paper from '@mui/material/Paper'; + import BigNumber from 'bignumber.js'; + import { useFormik } from 'formik'; + import { useSnackbar } from 'notistack'; + import React, { Fragment, useEffect, useState } from 'react'; + import * as yup from 'yup'; + import { UserContext, UserContextType } from './App'; + import ConnectButton from './ConnectWallet'; + import { TransactionInvalidBeaconError } from './TransactionInvalidBeaconError'; + import { address, nat } from './type-aliases'; const itemPerPage: number = 6; const validationSchema = yup.object({ price: yup .number() - .required("Price is required") - .positive("ERROR: The number must be greater than 0!"), + .required('Price is required') + .positive('ERROR: The number must be greater than 0!'), }); type Offer = { @@ -265,7 +266,7 @@ The contract storage must store the tokens that are offered for sale and their p }; export default function OffersPage() { - api.defaults.baseUrl = "https://api.ghostnet.tzkt.io"; + api.defaults.baseUrl = 'https://api.ghostnet.tzkt.io'; const [selectedTokenId, setSelectedTokenId] = React.useState(0); const [currentPageIndex, setCurrentPageIndex] = useState(1); @@ -297,14 +298,14 @@ The contract storage must store the tokens that are offered for sale and their p }, validationSchema: validationSchema, onSubmit: (values) => { - console.log("onSubmit: (values)", values, selectedTokenId); + console.log('onSubmit: (values)', values, selectedTokenId); sell(selectedTokenId, values.price); }, }); const initPage = async () => { if (storage) { - console.log("context is not empty, init page now"); + console.log('context is not empty, init page now'); ownerTokenIds = new Set(); offersTokenIDMap = new Map(); @@ -313,7 +314,7 @@ The contract storage must store the tokens that are offered for sale and their p ).id.toNumber(); const token_ids = await api.bigMapsGetKeys(token_metadataBigMapId, { - micheline: "Json", + micheline: 'Json', active: true, }); @@ -330,35 +331,35 @@ The contract storage must store the tokens that are offered for sale and their p offersTokenIDMap.set(token_idKey.key, ownerOffers); console.log( - "found for " + + 'found for ' + owner + - " on token_id " + + ' on token_id ' + token_idKey.key + - " with balance " + + ' with balance ' + 1 ); } else { - console.log("skip to next token id"); + console.log('skip to next token id'); } }) ); setOwnerTokenIds(new Set(ownerTokenIds)); //force refresh setOffersTokenIDMap(new Map(offersTokenIDMap)); //force refresh } else { - console.log("context is empty, wait for parent and retry ..."); + console.log('context is empty, wait for parent and retry ...'); } }; useEffect(() => { (async () => { - console.log("after a storage changed"); + console.log('after a storage changed'); await initPage(); })(); }, [storage]); useEffect(() => { (async () => { - console.log("on Page init"); + console.log('on Page init'); await initPage(); })(); }, []); @@ -375,14 +376,14 @@ The contract storage must store the tokens that are offered for sale and their p await op?.confirmation(2); enqueueSnackbar( - "Wine collection (token_id=" + + 'Wine collection (token_id=' + token_id + - ") offer for " + + ') offer for ' + 1 + - " units at price of " + + ' units at price of ' + price + - " XTZ", - { variant: "success" } + ' XTZ', + { variant: 'success' } ); refreshUserContextOnPageReload(); //force all app to refresh the context @@ -391,18 +392,18 @@ The contract storage must store the tokens that are offered for sale and their p let tibe: TransactionInvalidBeaconError = new TransactionInvalidBeaconError(error); enqueueSnackbar(tibe.data_message, { - variant: "error", + variant: 'error', autoHideDuration: 10000, }); } }; - const isDesktop = useMediaQuery("(min-width:1100px)"); - const isTablet = useMediaQuery("(min-width:600px)"); + const isDesktop = useMediaQuery('(min-width:1100px)'); + const isTablet = useMediaQuery('(min-width:600px)'); return ( - + Sell my bottles {ownerTokenIds && ownerTokenIds.size != 0 ? ( @@ -430,18 +431,18 @@ The contract storage must store the tokens that are offered for sale and their p : false ) .map(([token_id]) => ( - + - {" "} - {"ID : " + token_id.toString()}{" "} + {' '} + {'ID : ' + token_id.toString()}{' '} - {"Description : " + + {'Description : ' + nftContratTokenMetadataMap.get(token_id) ?.description} @@ -454,14 +455,14 @@ The contract storage must store the tokens that are offered for sale and their p title={nftContratTokenMetadataMap.get(token_id)?.name} /> @@ -469,14 +470,14 @@ The contract storage must store the tokens that are offered for sale and their p {offersTokenIDMap.get(token_id) - ? "Traded : " + + ? 'Traded : ' + 1 + - " (price : " + + ' (price : ' + offersTokenIDMap .get(token_id) ?.price.dividedBy(1000000) + - " Tz)" - : ""} + ' Tz)' + : ''} @@ -496,7 +497,7 @@ The contract storage must store the tokens that are offered for sale and their p ) : (
{ setSelectedTokenId(Number(token_id)); formik.handleSubmit(values); @@ -536,11 +537,11 @@ The contract storage must store the tokens that are offered for sale and their p )} - ))}{" "} + ))}{' '} ) : ( - + Sorry, you don't own any bottles, buy or mint some first )} @@ -586,8 +587,8 @@ In this section, you add a catalog page to show the bottles that are on sale and 1. Open the file `./src/WineCataloguePage.tsx` and replace it with this code: ```typescript - import { InfoOutlined } from "@mui/icons-material"; - import ShoppingCartIcon from "@mui/icons-material/ShoppingCart"; + import { InfoOutlined } from '@mui/icons-material'; + import ShoppingCartIcon from '@mui/icons-material/ShoppingCart'; import { Box, Button, @@ -600,19 +601,19 @@ In this section, you add a catalog page to show the bottles that are on sale and Pagination, Tooltip, useMediaQuery, - } from "@mui/material"; - import Paper from "@mui/material/Paper"; - import Typography from "@mui/material/Typography"; - - import BigNumber from "bignumber.js"; - import { useFormik } from "formik"; - import { useSnackbar } from "notistack"; - import React, { Fragment, useState } from "react"; - import * as yup from "yup"; - import { UserContext, UserContextType } from "./App"; - import ConnectButton from "./ConnectWallet"; - import { TransactionInvalidBeaconError } from "./TransactionInvalidBeaconError"; - import { address, nat } from "./type-aliases"; + } from '@mui/material'; + import Paper from '@mui/material/Paper'; + import Typography from '@mui/material/Typography'; + + import BigNumber from 'bignumber.js'; + import { useFormik } from 'formik'; + import { useSnackbar } from 'notistack'; + import React, { Fragment, useState } from 'react'; + import * as yup from 'yup'; + import { UserContext, UserContextType } from './App'; + import ConnectButton from './ConnectWallet'; + import { TransactionInvalidBeaconError } from './TransactionInvalidBeaconError'; + import { address, nat } from './type-aliases'; const itemPerPage: number = 6; @@ -646,7 +647,7 @@ In this section, you add a catalog page to show the bottles that are on sale and }, validationSchema: validationSchema, onSubmit: (values) => { - console.log("onSubmit: (values)", values, selectedOfferEntry); + console.log('onSubmit: (values)', values, selectedOfferEntry); buy(selectedOfferEntry!); }, }); @@ -668,13 +669,13 @@ In this section, you add a catalog page to show the bottles that are on sale and await op?.confirmation(2); enqueueSnackbar( - "Bought " + + 'Bought ' + 1 + - " unit of Wine collection (token_id:" + + ' unit of Wine collection (token_id:' + selectedOfferEntry[0] + - ")", + ')', { - variant: "success", + variant: 'success', } ); @@ -684,16 +685,16 @@ In this section, you add a catalog page to show the bottles that are on sale and let tibe: TransactionInvalidBeaconError = new TransactionInvalidBeaconError(error); enqueueSnackbar(tibe.data_message, { - variant: "error", + variant: 'error', autoHideDuration: 10000, }); } }; - const isDesktop = useMediaQuery("(min-width:1100px)"); - const isTablet = useMediaQuery("(min-width:600px)"); + const isDesktop = useMediaQuery('(min-width:1100px)'); + const isTablet = useMediaQuery('(min-width:600px)'); return ( - + Wine catalogue @@ -722,24 +723,24 @@ In this section, you add a catalog page to show the bottles that are on sale and : false ) .map(([token_id, offer]) => ( - + - {" "} - {"ID : " + token_id.toString()}{" "} + {' '} + {'ID : ' + token_id.toString()}{' '} - {"Description : " + + {'Description : ' + nftContratTokenMetadataMap.get( token_id.toString() )?.description} - {"Seller : " + offer.owner}{" "} + {'Seller : ' + offer.owner}{' '} } @@ -753,24 +754,24 @@ In this section, you add a catalog page to show the bottles that are on sale and } /> - {" "} - {"Price : " + + {' '} + {'Price : ' + offer.price.dividedBy(1000000) + - " XTZ"} + ' XTZ'} @@ -790,7 +791,7 @@ In this section, you add a catalog page to show the bottles that are on sale and ) : ( { setSelectedOfferEntry([token_id, offer]); formik.handleSubmit(values); @@ -807,7 +808,7 @@ In this section, you add a catalog page to show the bottles that are on sale and ) : ( - + Sorry, there is not NFT to buy yet, you need to mint or sell bottles first diff --git a/docs/tutorials/build-an-nft-marketplace/part-3.md b/docs/tutorials/build-an-nft-marketplace/part-3.md index 4c1f1ff3e..cce516051 100644 --- a/docs/tutorials/build-an-nft-marketplace/part-3.md +++ b/docs/tutorials/build-an-nft-marketplace/part-3.md @@ -1,5 +1,6 @@ --- -title: "Part 3: Managing tokens with quantities" +title: 'Part 3: Managing tokens with quantities' +authors: 'Benjamin Fuentes (Marigold)' last_update: date: 8 November 2023 --- @@ -274,11 +275,11 @@ To use the single-asset template, you must change the code that your smart contr ```typescript const refreshUserContextOnPageReload = async () => { - console.log("refreshUserContext"); + console.log('refreshUserContext'); //CONTRACT try { let c = await Tezos.contract.at(nftContractAddress, tzip12); - console.log("nftContractAddress", nftContractAddress); + console.log('nftContractAddress', nftContractAddress); let nftContrat: NftWalletType = await Tezos.wallet.at( nftContractAddress @@ -289,17 +290,17 @@ To use the single-asset template, you must change the code that your smart contr let tokenMetadata: TZIP21TokenMetadata = (await c .tzip12() .getTokenMetadata(0)) as TZIP21TokenMetadata; - nftContratTokenMetadataMap.set("0", tokenMetadata); + nftContratTokenMetadataMap.set('0', tokenMetadata); setNftContratTokenMetadataMap(new Map(nftContratTokenMetadataMap)); //new Map to force refresh } catch (error) { - console.log("error refreshing nftContratTokenMetadataMap: "); + console.log('error refreshing nftContratTokenMetadataMap: '); } setNftContrat(nftContrat); setStorage(storage); } catch (error) { - console.log("error refreshing nft contract: ", error); + console.log('error refreshing nft contract: ', error); } //USER @@ -310,7 +311,7 @@ To use the single-asset template, you must change the code that your smart contr setUserBalance(balance.toNumber()); } - console.log("refreshUserContext ended."); + console.log('refreshUserContext ended.'); }; ``` @@ -319,7 +320,7 @@ To use the single-asset template, you must change the code that your smart contr 1. Replace the content of the `src/MintPage.tsx` file with this code: ```typescript - import OpenWithIcon from "@mui/icons-material/OpenWith"; + import OpenWithIcon from '@mui/icons-material/OpenWith'; import { Button, CardHeader, @@ -330,29 +331,29 @@ To use the single-asset template, you must change the code that your smart contr TextField, Toolbar, useMediaQuery, - } from "@mui/material"; - import Box from "@mui/material/Box"; - import Card from "@mui/material/Card"; - import CardContent from "@mui/material/CardContent"; - import Paper from "@mui/material/Paper"; - import Typography from "@mui/material/Typography"; - import { BigNumber } from "bignumber.js"; - import { useSnackbar } from "notistack"; - import React, { useEffect, useState } from "react"; - import { TZIP21TokenMetadata, UserContext, UserContextType } from "./App"; - import { TransactionInvalidBeaconError } from "./TransactionInvalidBeaconError"; + } from '@mui/material'; + import Box from '@mui/material/Box'; + import Card from '@mui/material/Card'; + import CardContent from '@mui/material/CardContent'; + import Paper from '@mui/material/Paper'; + import Typography from '@mui/material/Typography'; + import { BigNumber } from 'bignumber.js'; + import { useSnackbar } from 'notistack'; + import React, { useEffect, useState } from 'react'; + import { TZIP21TokenMetadata, UserContext, UserContextType } from './App'; + import { TransactionInvalidBeaconError } from './TransactionInvalidBeaconError'; import { AddCircleOutlined, Close, KeyboardArrowLeft, KeyboardArrowRight, - } from "@mui/icons-material"; - import { char2Bytes } from "@taquito/utils"; - import { useFormik } from "formik"; - import SwipeableViews from "react-swipeable-views"; - import * as yup from "yup"; - import { address, bytes, nat } from "./type-aliases"; + } from '@mui/icons-material'; + import { char2Bytes } from '@taquito/utils'; + import { useFormik } from 'formik'; + import SwipeableViews from 'react-swipeable-views'; + import * as yup from 'yup'; + import { address, bytes, nat } from './type-aliases'; export default function MintPage() { const { userAddress, @@ -362,7 +363,7 @@ To use the single-asset template, you must change the code that your smart contr nftContratTokenMetadataMap, } = React.useContext(UserContext) as UserContextType; const { enqueueSnackbar } = useSnackbar(); - const [pictureUrl, setPictureUrl] = useState(""); + const [pictureUrl, setPictureUrl] = useState(''); const [file, setFile] = useState(null); const [activeStep, setActiveStep] = React.useState(0); @@ -379,21 +380,21 @@ To use the single-asset template, you must change the code that your smart contr setActiveStep(step); }; const validationSchema = yup.object({ - name: yup.string().required("Name is required"), - description: yup.string().required("Description is required"), - symbol: yup.string().required("Symbol is required"), + name: yup.string().required('Name is required'), + description: yup.string().required('Description is required'), + symbol: yup.string().required('Symbol is required'), quantity: yup .number() - .required("Quantity is required") - .positive("ERROR: The number must be greater than 0!"), + .required('Quantity is required') + .positive('ERROR: The number must be greater than 0!'), }); const formik = useFormik({ initialValues: { - name: "", - description: "", + name: '', + description: '', token_id: 0, - symbol: "WINE", + symbol: 'WINE', quantity: 1, } as TZIP21TokenMetadata & { quantity: number }, validationSchema: validationSchema, @@ -419,29 +420,29 @@ To use the single-asset template, you must change the code that your smart contr //IPFS if (file) { const formData = new FormData(); - formData.append("file", file); + formData.append('file', file); const requestHeaders: HeadersInit = new Headers(); requestHeaders.set( - "pinata_api_key", + 'pinata_api_key', `${import.meta.env.VITE_PINATA_API_KEY}` ); requestHeaders.set( - "pinata_secret_api_key", + 'pinata_secret_api_key', `${import.meta.env.VITE_PINATA_API_SECRET}` ); const resFile = await fetch( - "https://api.pinata.cloud/pinning/pinFileToIPFS", + 'https://api.pinata.cloud/pinning/pinFileToIPFS', { - method: "post", + method: 'post', body: formData, headers: requestHeaders, } ); const responseJson = await resFile.json(); - console.log("responseJson", responseJson); + console.log('responseJson', responseJson); const thumbnailUri = `ipfs://${responseJson.IpfsHash}`; setPictureUrl( @@ -461,13 +462,13 @@ To use the single-asset template, you must change the code that your smart contr //close directly the form setFormOpen(false); enqueueSnackbar( - "Wine collection is minting ... it will be ready on next block, wait for the confirmation message before minting another collection", - { variant: "info" } + 'Wine collection is minting ... it will be ready on next block, wait for the confirmation message before minting another collection', + { variant: 'info' } ); await op.confirmation(2); - enqueueSnackbar("Wine collection minted", { variant: "success" }); + enqueueSnackbar('Wine collection minted', { variant: 'success' }); refreshUserContextOnPageReload(); //force all app to refresh the context } @@ -476,7 +477,7 @@ To use the single-asset template, you must change the code that your smart contr let tibe: TransactionInvalidBeaconError = new TransactionInvalidBeaconError(error); enqueueSnackbar(tibe.data_message, { - variant: "error", + variant: 'error', autoHideDuration: 10000, }); } @@ -487,16 +488,16 @@ To use the single-asset template, you must change the code that your smart contr const toggleDrawer = (open: boolean) => (event: React.KeyboardEvent | React.MouseEvent) => { if ( - event.type === "keydown" && - ((event as React.KeyboardEvent).key === "Tab" || - (event as React.KeyboardEvent).key === "Shift") + event.type === 'keydown' && + ((event as React.KeyboardEvent).key === 'Tab' || + (event as React.KeyboardEvent).key === 'Shift') ) { return; } setFormOpen(open); }; - const isTablet = useMediaQuery("(min-width:600px)"); + const isTablet = useMediaQuery('(min-width:600px)'); return ( @@ -507,21 +508,21 @@ To use the single-asset template, you must change the code that your smart contr } sx={{ p: 1, - position: "absolute", - right: "0", - display: formOpen ? "none" : "block", + position: 'absolute', + right: '0', + display: formOpen ? 'none' : 'block', zIndex: 1, }} onClick={toggleDrawer(!formOpen)} > - {" Mint Form " + + {' Mint Form ' + (storage!.administrators.indexOf(userAddress! as address) < 0 - ? " (You are not admin)" - : "")} + ? ' (You are not admin)' + : '')} ) : ( - "" + '' )} - + Mint a new collection ) : ( - "" + '' )} ) : ( - "" + '' )} - + Mint a new collection ) : ( - "" + '' )}