diff --git a/src/lib/modules/scaffolding/framework/reactBuilder/index.ts b/src/lib/modules/scaffolding/framework/reactBuilder/index.ts index 12d36c142..42b91d019 100644 --- a/src/lib/modules/scaffolding/framework/reactBuilder/index.ts +++ b/src/lib/modules/scaffolding/framework/reactBuilder/index.ts @@ -1,5 +1,6 @@ import Handlebars from "handlebars"; import * as path from "path"; +import { ABIDefinition } from "web3/types"; import { Contract } from "../../../../../typings/contract"; import { Embark } from "../../../../../typings/embark"; @@ -11,6 +12,12 @@ const fs = require("../../../../core/fs"); const utils = require("../../../../utils/utils"); require("../../handlebarHelpers"); +interface ABIDefinitionDecorated extends ABIDefinition { + isIpfsText?: boolean; + isIpfsFile?: boolean; + isStandard?: boolean; +} + const indexTemplatePath = path.join(__dirname, "templates", "index.html.hbs"); const dappTemplatePath = path.join(__dirname, "templates", "dapp.js.hbs"); @@ -64,12 +71,48 @@ export class ReactBuilder implements Builder { const dappData = { contractName, - functions: contract.abiDefinition.filter((entry) => entry.type === "function"), + functions: this.getFunctions(contract), }; return [indexTemplate(indexData), dappTemplate(dappData)]; } + private getFunctions(contract: Contract) { + const ipfsAttributes = this.description.ipfsAttributes(contract.className); + + return contract.abiDefinition.filter((entry) => entry.type === "function").map((entry) => { + const decorated: ABIDefinitionDecorated = entry; + const inputName = entry.inputs && entry.inputs.length > 1 ? entry.inputs[1].name.substring(1, entry.inputs[1].name.length) : ""; + const functionName = entry.name || ""; + + Object.keys(ipfsAttributes).forEach((name) => { + let text = false; + if (ipfsAttributes[name] === "ipfsText") { + text = true; + } + + let ipfs = false; + if (name === inputName || `get${name.charAt(0).toUpperCase() + name.slice(1)}` === functionName) { + ipfs = true; + } + + if (ipfs) { + if (text) { + decorated.isIpfsText = true; + } else { + decorated.isIpfsFile = true; + } + } + }); + + if (!decorated.isIpfsText && !decorated.isIpfsFile) { + decorated.isStandard = true; + } + + return decorated; + }); + } + private installDependencies() { const cmd = "npm install react react-bootstrap react-dom"; return new Promise((resolve, reject) => { diff --git a/src/lib/modules/scaffolding/framework/reactBuilder/templates/dapp.js.hbs b/src/lib/modules/scaffolding/framework/reactBuilder/templates/dapp.js.hbs index d74a73fb7..1d050f16b 100644 --- a/src/lib/modules/scaffolding/framework/reactBuilder/templates/dapp.js.hbs +++ b/src/lib/modules/scaffolding/framework/reactBuilder/templates/dapp.js.hbs @@ -32,13 +32,19 @@ class {{capitalize name}}Form{{@index}} extends Component { }; } - handleChange(e, name){ + handleChangeFile(e) { + const {input} = this.state; + input.file = [e.target]; + this.setState({input}); + } + + handleChange(e, name) { const {input} = this.state; input[name] = e.target.value; this.setState({input}); } - handleCheckbox(e, name){ + handleCheckbox(e, name) { const {input} = this.state; input[name] = e.target.checked; this.setState({input}); @@ -52,6 +58,7 @@ class {{capitalize name}}Form{{@index}} extends Component { this.setState({output: null, error: null, receipt: null}); try { + {{#if isStandard}} {{#ifview stateMutability}} const result = await {{../contractName}}.methods{{methodname ../functions name inputs}}({{#each inputs}}input.{{#ifeq name ''}}field{{else}}{{trim name}}{{/ifeq}}{{#unless @last}}, {{/unless}}{{/each}}).call(); {{#iflengthgt outputs 1}} @@ -59,10 +66,10 @@ class {{capitalize name}}Form{{@index}} extends Component { {{#each outputs}} {{emptyname name @index}}: result[{{@index}}]{{#unless @last}},{{/unless}} {{/each}} - }}); + }}); {{else}} - this.setState({output: result}); - {{/iflengthgt}} + this.setState({output: result}); + {{/iflengthgt}} {{else}} {{#each inputs}} {{#ifarr type}} @@ -73,7 +80,7 @@ class {{capitalize name}}Form{{@index}} extends Component { const toSend = {{../contractName}}.methods{{methodname ../functions name inputs}}({{#each inputs}}input.{{#ifeq name ''}}field{{else}}{{trim name}}{{/ifeq}}{{#unless @last}}, {{/unless}}{{/each}}); const estimatedGas = await toSend.estimateGas({from: web3.eth.defaultAccount}); - + const receipt = await toSend.send({ {{#if payable}} value: value, @@ -86,6 +93,51 @@ class {{capitalize name}}Form{{@index}} extends Component { this.setState({receipt}); {{/ifview}} + {{/if}} + + {{#if isIpfsText}} + {{#ifview stateMutability}} + const result = await {{../contractName}}.methods{{methodname ../functions name inputs}}({{#each inputs}}input.{{#ifeq name ''}}field{{else}}{{trim name}}{{/ifeq}}{{#unless @last}}, {{/unless}}{{/each}}).call(); + const data = await EmbarkJS.Storage.get(result); + this.setState({output: data}); + {{else}} + const hash = await EmbarkJS.Storage.saveText(input.{{inputs.1.name}}); + const toSend = {{../contractName}}.methods{{methodname ../functions name inputs}}(input.{{inputs.0.name}}, hash); + + const estimatedGas = await toSend.estimateGas({from: web3.eth.defaultAccount}); + + const receipt = await toSend.send({ + from: web3.eth.defaultAccount, + gasLimit: estimatedGas + }); + + console.log(receipt); + + this.setState({receipt}); + {{/ifview}} + {{/if}} + + {{#if isIpfsFile}} + {{#ifview stateMutability}} + const result = await {{../contractName}}.methods{{methodname ../functions name inputs}}({{#each inputs}}input.{{#ifeq name ''}}field{{else}}{{trim name}}{{/ifeq}}{{#unless @last}}, {{/unless}}{{/each}}).call(); + const url = EmbarkJS.Storage.getUrl(result); + this.setState({output: url}); + {{else}} + const hash = await EmbarkJS.Storage.uploadFile(input.file) + const toSend = {{../contractName}}.methods{{methodname ../functions name inputs}}(input._id, hash); + + const estimatedGas = await toSend.estimateGas({from: web3.eth.defaultAccount}); + + const receipt = await toSend.send({ + from: web3.eth.defaultAccount, + gasLimit: estimatedGas + }); + + console.log(receipt); + + this.setState({receipt}); + {{/ifview}} + {{/if}} } catch(err) { console.error(err); this.setState({error: err.message}); @@ -99,6 +151,34 @@ class {{capitalize name}}Form{{@index}} extends Component {

{{name}}

{{#if inputs.length}} + {{#if isIpfsFile}} + {{#ifview stateMutability}} + + _id + this.handleChange(e, '_id')} + /> + + {{else}} + + _id + this.handleChange(e, '_id')} + /> + + + File + this.handleChangeFile(e)} + /> + + {{/ifview}} + {{else}} {{#each inputs}} {{#ifeq name ''}}field{{else}}{{name}}{{/ifeq}} @@ -115,14 +195,15 @@ class {{capitalize name}}Form{{@index}} extends Component { /> {{/ifeq}} - {{/each}} + {{/each}} + {{/if}} {{/if}} {{#if payable}} Value Ξ - {isSuccess(receipt.status) ? 'Success' : 'Failure / Revert'} - Transaction Hash: {receipt.transactionHash} - + } {{/ifview}}