Introduction to Fitbit dapp

A-Lin

About Me

Profile

  • JAVA 5 years
  • Javascript 3 years
  • conference speaker
    • JSDC.tw 2016
    • Testing Day 2018
    • Modern Web 2016, 2018
  • coding coach

 

  • alincode@gmail.com

for this example, we don't use large front-end framework

Lightweight Module

  • nanohtml
  • morphdom
  • csjs-inject
  • budo
  • browserify

nanohtml (bel)

HTML template strings for the Browser with support for Server Side Rendering in Node.
// insert DOM element
const html = require('nanohtml');
const element = html`<div>Hello!</div>`;
document.body.appendChild(element);

// bind event
function hi(event) { alert('Hello'); }
var button = bel`<button class="primary" onclick=${hi}>click me</button>`

morphdom

Fast and lightweight DOM diffing/patching (no virtual DOM needed)
const html = require('nanohtml');
const morphdom = require('morphdom');

const element = html`<div>hello</div>`;
const newElement = html`<div>Hi</div>`;

// update DOM element
morphdom(element, newElement)

csjs-inject

A CSJS wrapper module that works exactly like CSJS, but adds auto-injection of styles into the DOM.
const csjs = require('csjs-inject');

const css = csjs `
  .input {
    margin: 10px;
    width: 500px;
    font-size: 20px;
  }
`

const inputAccount
 = html `<input class=${css.input} type="text" placeholder="input your account"/>`;

budo

// install module
npm install budo -g

// live reload mode
budo src/01.js:bundle.js --live --open --dir ./static
a dev server for rapid prototyping

--open:set port number
--live:switch dev live mode
--dir: set public directory

browserify

Browserify lets you require('modules') in the browser by bundling up all of your dependencies.
// install module
npm install browserify -g

// package module
browserify src/01.js > static/01.js
const Web3 = require('web3');
const html = require('nanohtml');
const csjs = require('csjs-inject');
const morphdom = require('morphdom');
<script src="https://cdn.jsdelivr.net/gh/ethereum/web3.js/dist/web3.min.js"/>
if you don't use require symptom

Fitbit DApp

Player

Funder

Owner

role

guest

View

  • player of amount
  • how many players
  • funder of amount
  • how many funders
  • funder list
  • goal step
  • during
  • isSign
  • isOwner

Action

  • bet
  • fund

player

View

  • isSign
  • begin step
  • ​current step

Action

  • fund

funder

special logical

  • first time
    • insert a new row
  • second time
    • update amount

fund

owner

View

  • endAt
  • state

Action

step1:contest done
step2:award

Start to build DApp

All Step

step1: import module
step2: initial web3.js instance
step3: connect with smart contract
step4: CSS inject
step5: DOM element
step6: listening smart contract event
step7: implement DOM Event
step8: preload data
step9: render

Step1 : import module

const Web3 = require('web3');
const html = require('nanohtml');
const csjs = require('csjs-inject');
const morphdom = require('morphdom');

Step2: initial web3.js instance

if (typeof web3 !== 'undefined') {
  web3 = new Web3(web3.currentProvider);
} else {
  alert('initial failed');
}

Step3: connect with smart contract

const ABI = require('./abi.json');
const DEFAULT_ADDRESS = '0x0c972a74a9806f249968720035ebda65b653360c';
const myContract = new web3.eth.Contract(ABI, DEFAULT_ADDRESS);

Step4 : CSS inject

const css = csjs `
  .box {
    margin: 10px;
  }
  .input {
    margin-top: 10px;
    margin-right: 10px;
    width: 500px;
    font-size: 20px;
  }
  .button {
    margin-top: 10px;
    margin-right: 10px;
    font-size: 20px;
    width: 180px;
    background-color: #4CAF50;
    color: white;
  }
  img {
    border: 1px solid #ddd;
    border-radius: 4px;
    padding: 5px;
    width: 150px;
  }
`

Step5: DOM element

const fundAmountElement = bel `<input class=${css.input} type="text"/>`;
const fundNameElement = bel `<input class=${css.input} type="text"/>`;

const fundAreaElement = bel `
  <div class="${css.box6}">
    I want to sponsor this contest with ${fundAmountElement} ETH!<br>
    Name you want to be added to our sponsorship board. ${fundNameElement}<br>
    <button class=${css.shortButton} onclick=${fund}> Fund </button> (min 0.5 ETH)
  </div>
`

Step6 : listening smart contract event

// Generate filter options
const options = {
  // filter: {
  //   _from: process.env.WALLET_FROM,
  //   _to: process.env.WALLET_TO,
  //   _value: process.env.AMOUNT
  // },
  fromBlock: 'latest'
}

myContract.events.NewFundLog(options, async (error, event) => {
  if (error) {
    console.log(error)
    return
  }
  const ether = web3.utils.fromWei(event.returnValues.amount, "ether");
  const name = event.returnValues.name;
  location.reload();

  // const newElement = html`<div class="${css.result}">.......</div>`
  // morphdom(resultElement, newElement);
  return
})

Step7 : implement DOM Event

function fund(event) {
  let account = web3.eth.defaultAccount;

  // send contract
  myContract.methods.fund(inputName.value).send({
    from: account,
    value: web3.utils.toWei(inputAmount.value, "ether")
  }, (err, data) => {
    if (err) return console.error(err);
    console.log('>>> fund ok.');
  });
}
function fund(string _name) public minimizeContribute onlyOnTime payable {
  if(funders[msg.sender].amount != 0) {
    funders[msg.sender].amount += msg.value;
    funders[msg.sender].name = _name;
  } else {
    funders[msg.sender] = Funder(msg.sender, msg.value, now, _name);
    funderIndexs.push(msg.sender);
  }
  fundersOfAmount += msg.value;
}

smart contract

DApp

Step8 :

Preload Data

function start() {
  console.log('=== start ===');
  step1({});
}

function step1(result) {
  // call contract
  myContract.methods.getFunders().call((err, data) => {
    if (err) return console.error(err);
    result.funders = data;
    step2(result);
  })
}

function step2(result) {
  step3(result)
}

function lastStep(result) {
  render(result)
}
function getFunders() public view returns (string[], uint[]) {
  string[] memory names = new string[](funderIndexs.length);
  uint[] memory amounts = new uint[](funderIndexs.length);
        
  for (uint i = 0; i < funderIndexs.length; i++) {
    Funder storage funder = funders[funderIndexs[i]];
    names[i] = funder.name;
    amounts[i] = funder.amount;
  }
        
  return (names, amounts);
}

smart contract

DApp

Step9 : Render

function lastStep(result) {
  console.log('>>> last step');
  render(result)
}

function render(result) {
  console.log('>>> result:', result);
  document.body.appendChild(html `
  <div class=${css.box} id="app">

    // skip...

    Name: ${inputName}<br>
    Amount: ${inputAmount}<br>
    
    // skip...

  </div>
 `)
}

if (typeof web3 !== 'undefined') start();

prepare to deploy

browserify src/index.js > bundle.js
<!doctype html>
<html>
<head><meta charset="utf-8"></head>
<body>
  <script src="bundle.js"></script>
</body>
</html>
package module
index.html
directory
* src
  - abi.json
  - index.js
- index.html
- bundle.js

good job, we finish.

Introduction_to_fitbit_dapp

By alincode

Introduction_to_fitbit_dapp

by alincode

  • 1,303