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 on front-end-tpl code in tut: PoE #876

Merged
merged 1 commit into from
Mar 7, 2022
Merged
Changes from all commits
Commits
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
279 changes: 138 additions & 141 deletions v3/tutorials/02-proof-of-existence/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -429,152 +429,149 @@ This React component enables you to expose the proof-of-existence capabilities a

1. Copy and paste the following code into the`src/TemplateModule.js` file:

```javascript
// React and Semantic UI elements.
import React, { useState, useEffect } from 'react'
import { Form, Input, Grid, Message } from 'semantic-ui-react'

// Pre-built Substrate front-end utilities for connecting to a node
// and making a transaction.
import { useSubstrate } from './substrate-lib'
import { TxButton } from './substrate-lib/components'

// Polkadot-JS utilities for hashing data.
import { blake2AsHex } from '@polkadot/util-crypto'

// Main Proof Of Existence component is exported.
export function Main(props) {
// Establish an API to talk to the Substrate node.
const { api } = useSubstrate()
// Get the selected user from the `AccountSelector` component.
const { accountPair } = props
// React hooks for all the state variables we track.
// Learn more at: https://reactjs.org/docs/hooks-intro.html
const [status, setStatus] = useState('')
const [digest, setDigest] = useState('')
const [owner, setOwner] = useState('')
const [block, setBlock] = useState(0)
// Our `FileReader()` which is accessible from our functions below.
let fileReader
// Takes our file, and creates a digest using the Blake2 256 hash function
const bufferToDigest = () => {
// Turns the file content to a hexadecimal representation.
const content = Array.from(new Uint8Array(fileReader.result))
.map(b => b.toString(16).padStart(2, '0'))
.join('')
const hash = blake2AsHex(content, 256)
setDigest(hash)
}

// Callback function for when a new file is selected.
const handleFileChosen = file => {
fileReader = new FileReader()
fileReader.onloadend = bufferToDigest
fileReader.readAsArrayBuffer(file)
}

// React hook to update the owner and block number information for a file
useEffect(() => {
let unsubscribe
// Polkadot-JS API query to the `proofs` storage item in our pallet.
// This is a subscription, so it will always get the latest value,
// even if it changes.
api.query.templateModule
.proofs(digest, result => {
// Our storage item returns a tuple, which is represented as an array.
setOwner(result[0].toString())
setBlock(result[1].toNumber())
})
.then(unsub => {
unsubscribe = unsub
})
return () => unsubscribe && unsubscribe()
// This tells the React hook to update whenever the file digest changes
// (when a new file is chosen), or when the storage subscription says the
// value of the storage item has updated.
}, [digest, api.query.templateModule])

// We can say a file digest is claimed if the stored block number is not 0
function isClaimed() {
return block !== 0
}

// The actual UI elements which are returned from our component.
return (
<Grid.Column>
<h1>Proof of Existence</h1>
{/* Show warning or success message if the file is or is not claimed. */}
<Form success={!!digest && !isClaimed()} warning={isClaimed()}>
<Form.Field>
{/* File selector with a callback to `handleFileChosen`. */}
<Input
type="file"
id="file"
label="Your File"
onChange={e => handleFileChosen(e.target.files[0])}
/>
{/* Show this message if the file is available to be claimed */}
<Message success header="File Digest Unclaimed" content={digest} />
{/* Show this message if the file is already claimed. */}
<Message
warning
header="File Digest Claimed"
list={[digest, `Owner: ${owner}`, `Block: ${block}`]}
/>
</Form.Field>
{/* Buttons for interacting with the component. */}
<Form.Field>
{/* Button to create a claim. Only active if a file is selected, and not already claimed. Updates the `status`. */}
<TxButton
accountPair={accountPair}
label={'Create Claim'}
setStatus={setStatus}
type="SIGNED-TX"
disabled={isClaimed() || !digest}
attrs={{
palletRpc: 'templateModule',
callable: 'createClaim',
inputParams: [digest],
paramFields: [true],
}}
/>
{/* Button to revoke a claim. Only active if a file is selected, and is already claimed. Updates the `status`. */}
<TxButton
accountPair={accountPair}
label="Revoke Claim"
setStatus={setStatus}
type="SIGNED-TX"
disabled={!isClaimed() || owner !== accountPair.address}
attrs={{
palletRpc: 'templateModule',
callable: 'revokeClaim',
inputParams: [digest],
paramFields: [true],
}}
/>
</Form.Field>
{/* Status message about the transaction. */}
<div style={{ overflowWrap: 'break-word' }}>{status}</div>
</Form>
</Grid.Column>
)
}

export default function TemplateModule(props) {
const { api } = useSubstrate()
return api.query.templateModule && api.query.templateModule.proofs ? (
<Main {...props} />
) : null
}
```
```javascript
import React, { useEffect, useState } from 'react'
import { Form, Input, Grid, Message } from 'semantic-ui-react'

// Pre-built Substrate front-end utilities for connecting to a node
// and making a transaction.
import { useSubstrateState } from './substrate-lib'
import { TxButton } from './substrate-lib/components'

// Polkadot-JS utilities for hashing data.
import { blake2AsHex } from '@polkadot/util-crypto'

// Main Proof Of Existence component is exported.
function Main(props) {
// Establish an API to talk to the Substrate node.
const { api, currentAccount } = useSubstrateState()
// React hooks for all the state variables we track.
// Learn more at: https://reactjs.org/docs/hooks-intro.html
const [status, setStatus] = useState('')
const [digest, setDigest] = useState('')
const [owner, setOwner] = useState('')
const [block, setBlock] = useState(0)

// Our `FileReader()` which is accessible from our functions below.
let fileReader
// Takes our file, and creates a digest using the Blake2 256 hash function
const bufferToDigest = () => {
// Turns the file content to a hexadecimal representation.
const content = Array.from(new Uint8Array(fileReader.result))
.map(b => b.toString(16).padStart(2, '0'))
.join('')
const hash = blake2AsHex(content, 256)
setDigest(hash)
}

// Callback function for when a new file is selected.
const handleFileChosen = file => {
fileReader = new FileReader()
fileReader.onloadend = bufferToDigest
fileReader.readAsArrayBuffer(file)
}

// React hook to update the owner and block number information for a file
useEffect(() => {
let unsubscribe
// Polkadot-JS API query to the `proofs` storage item in our pallet.
// This is a subscription, so it will always get the latest value,
// even if it changes.
api.query.templateModule
.proofs(digest, result => {
// Our storage item returns a tuple, which is represented as an array.
setOwner(result[0].toString())
setBlock(result[1].toNumber())
})
.then(unsub => {
unsubscribe = unsub
})
return () => unsubscribe && unsubscribe()
// This tells the React hook to update whenever the file digest changes
// (when a new file is chosen), or when the storage subscription says the
// value of the storage item has updated.
}, [digest, api.query.templateModule])

// We can say a file digest is claimed if the stored block number is not 0
function isClaimed() {
return block !== 0
}

// The actual UI elements which are returned from our component.
return (
<Grid.Column>
<h1>Proof of Existence</h1>
{/* Show warning or success message if the file is or is not claimed. */}
<Form success={!!digest && !isClaimed()} warning={isClaimed()}>
<Form.Field>
{/* File selector with a callback to `handleFileChosen`. */}
<Input
type="file"
id="file"
label="Your File"
onChange={e => handleFileChosen(e.target.files[0])}
/>
{/* Show this message if the file is available to be claimed */}
<Message success header="File Digest Unclaimed" content={digest} />
{/* Show this message if the file is already claimed. */}
<Message
warning
header="File Digest Claimed"
list={[digest, `Owner: ${owner}`, `Block: ${block}`]}
/>
</Form.Field>
{/* Buttons for interacting with the component. */}
<Form.Field>
{/* Button to create a claim. Only active if a file is selected, and not already claimed. Updates the `status`. */}
<TxButton
label="Create Claim"
type="SIGNED-TX"
setStatus={setStatus}
disabled={isClaimed() || !digest}
attrs={{
palletRpc: 'templateModule',
callable: 'createClaim',
inputParams: [digest],
paramFields: [true],
}}
/>
{/* Button to revoke a claim. Only active if a file is selected, and is already claimed. Updates the `status`. */}
<TxButton
label="Revoke Claim"
type="SIGNED-TX"
setStatus={setStatus}
disabled={!isClaimed() || owner !== currentAccount.address}
attrs={{
palletRpc: 'templateModule',
callable: 'revokeClaim',
inputParams: [digest],
paramFields: [true],
}}
/>
</Form.Field>
{/* Status message about the transaction. */}
<div style={{ overflowWrap: 'break-word' }}>{status}</div>
</Form>
</Grid.Column>
)
}

export default function TemplateModule(props) {
const { api } = useSubstrateState()
return api.query.templateModule ? <Main {...props} /> : null
}
```

1. Save your changes and close the file.

1. Start the front-end template by running the following command:

```bash
yarn start
```
```bash
# If you haven't installed the dependencies
yarn install
# Start the project
yarn start
```

This will open up a new tab with the front-end serving at **http://localhost:8000**.

Expand Down