Dockerで構築するEthereum PET-SHOP TRUFFLE BOXES（その3）

[その1](https://qiita.com/JQinglong/items/b471d79a105f92001618)、[その2](https://qiita.com/JQinglong/items/bfbd97745cf7d981668e)からの続きでで、[ETHEREUM PET SHOP チュートリアル](https://www.trufflesuite.com/tutorials/pet-shop)をやっていきます。

## Creating a user interface to interact with the smart contract

今度は、UIの作成です。

最初に見たように、基本的な画面は表示されるようになっています。
チュートリアルのUI変更の最初としては、/src/js/app.js の、データを読み込んでいるinit() が、initWeb3() を呼び出しているので、これに手を入れていくとのこと。

まずは、web3のインスタンス作成。web3とは、[web3 JavaScript library](https://github.com/ethereum/web3.js/)。これを使って、Ethereum ブロックチェーンとやりとりをします。

次は、スマートコントラクトのインスタンス作成です。
これは、truffle-contract ライブラリが行います。

まずやりたいのは、Adoption に接続して、getAdopters() を呼び出すことで、これをmarkAdopted Functionで行います。
養育引受済みのペットは、adoptボタン（引受ボタン）を使用不可にして、文字を「Success」にします。
console.log(err.message);
で、コンソールログ出力が可能です。

最後に、adopt() で引受ける処理を作成します。

これらを記載した、app.js は下記のようになります。

```js:app.js
App = {
  web3Provider: null,
  contracts: {},

  init: async function() {
    // Load pets.
    $.getJSON('../pets.json', function(data) {
      var petsRow = $('#petsRow');
      var petTemplate = $('#petTemplate');

      for (i = 0; i < data.length; i ++) {
        petTemplate.find('.panel-title').text(data[i].name);
        petTemplate.find('img').attr('src', data[i].picture);
        petTemplate.find('.pet-breed').text(data[i].breed);
        petTemplate.find('.pet-age').text(data[i].age);
        petTemplate.find('.pet-location').text(data[i].location);
        petTemplate.find('.btn-adopt').attr('data-id', data[i].id);

        petsRow.append(petTemplate.html());
      }
    });

    return await App.initWeb3();
  },

  initWeb3: async function() {

    // Modern dapp browsers...
    if (window.ethereum) {
      App.web3Provider = window.ethereum;
      try {
        // Request account access
        await window.ethereum.enable();
      } catch (error) {
        // User denied account access...
        console.error("User denied account access")
      }
    }
    // Legacy dapp browsers...
    else if (window.web3) {
      App.web3Provider = window.web3.currentProvider;
    }
    // If no injected web3 instance is detected, fall back to Ganache
    else {
      App.web3Provider = new Web3.providers.HttpProvider('http://localhost:7545');
    }
    web3 = new Web3(App.web3Provider);

    return App.initContract();
  },

  initContract: function() {

    $.getJSON('Adoption.json', function(data) {
      // Get the necessary contract artifact file and instantiate it with truffle-contract
      var AdoptionArtifact = data;
      App.contracts.Adoption = TruffleContract(AdoptionArtifact);
    
      // Set the provider for our contract
      App.contracts.Adoption.setProvider(App.web3Provider);
    
      // Use our contract to retrieve and mark the adopted pets
      return App.markAdopted();
    });

    return App.bindEvents();
  },

  bindEvents: function() {
    $(document).on('click', '.btn-adopt', App.handleAdopt);
  },

  markAdopted: function(adopters, account) {

    var adoptionInstance;

    App.contracts.Adoption.deployed().then(function(instance) {
      adoptionInstance = instance;

      return adoptionInstance.getAdopters.call();
    }).then(function(adopters) {
      for (i = 0; i < adopters.length; i++) {
        if (adopters[i] !== '0x0000000000000000000000000000000000000000') {
          $('.panel-pet').eq(i).find('button').text('Success').attr('disabled', true);
        }
      }
    }).catch(function(err) {
      console.log(err.message);
    });

  },

  handleAdopt: function(event) {
    event.preventDefault();

    var petId = parseInt($(event.target).data('id'));

    var adoptionInstance;

    web3.eth.getAccounts(function(error, accounts) {
      if (error) {
        console.log(error);
      }
    
      var account = accounts[0];
    
      App.contracts.Adoption.deployed().then(function(instance) {
        adoptionInstance = instance;
    
        // Execute adopt as a transaction by sending account
        return adoptionInstance.adopt(petId, {from: account});
      }).then(function(result) {
        return App.markAdopted();
      }).catch(function(err) {
        console.log(err.message);
      });
    });

  }

};

$(function() {
  $(window).load(function() {
    App.init();
  });
});

```

## Interacting with the dapp in a browser

では、ブラウザでdappを使用します。

最初は、MetaMask のインストールから説明が始まりますが、ここではインストールされているものとして、スキップします。チュートリアルでいうと、6.まで終わっている状態です。
その状態で、MetaMaskをganacheのネットワークに接続するわけですが、http://127.0.0.1:7545 ではなく、HTTP://10.200.10.1:7545 に接続します。e

ここまで来ると、ローカルサーバを起動して、dapp を使うことができるということで、その仕組みとして、lite-server が使用されているとのことです。

では、改めて、ブラウザでアプリを開いてみます。
チュートリアルでは、npm run dev を叩くとなっていますが、docker-compose で起動時にこれを実行することになっています。
いったん、Docker 環境を抜けます。

```shell:
/usr/src/app # exit
```
そして、起動しなおします。

```shell:
$ docker-compose down
$ docker-compose up -d
```

http://localhost:8003/
あれ、全部Successになってる・・・

<img width="400" alt="スクリーンショット 2020-03-29 23.36.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77307/3e08af91-f391-485b-a220-1dfad1ffdedc.png">

最後がイマイチですが、とりあえず、ここまでがチュートリアルでした。

Docker を使用して、開発する流れはできたかなと思います。
次は何をすれば良いのだろう・・・