SOURCE CODE : https://github.com/CyrilCartoux/kickstarter_solidity_nextJs
npm install next react react-dom
npm install --save semantic-ui-react
npm install --save semantic-ui-css
npm install next-routes (--legacy-peer-deps if needed)
Create a folder /pages
On ajoute dans package.json
"scripts": {
"test": "mocha",
"dev": "next dev"
},
On se rend ensuite sur localhost:3000 pour voir notre app
On creer un fichier web3.js a la racine de notre projet
import Web3 from "web3";
let web3;
if (typeof window !== "undefined" && typeof window.ethereum !== "undefined") {
// We are in the browser and metamask is running.
window.ethereum.request({ method: "eth_requestAccounts" });
web3 = new Web3(window.ethereum);
} else {
// We are on the server *OR* the user is not running metamask
const provider = new Web3.providers.HttpProvider(
"<https://rinkeby.infura.io/v3/b015e80a4e4f408bb6e01c005263de11>"
);
web3 = new Web3(provider);
}
export default web3;
On creer factory.js pour interagir avec le campaignfactory
import web3 from "./web3";
import CampaignFactory from './build/CampaignFactory.json';
// create contract instance
const instance = new web3.eth.Contract(
// abi / interface
JSON.parse(CampaignFactory.interface),
// address
'0x4BFF4AF6bbA80A9c4a8e0dd7702434F0b1BA9f96'
);
export default instance;
On va creer campaign.js pour interagir avec une campagne en particulier
On lui passera en parametre une addresse
import web3 from "./web3";
import Campaign from './build/Campaign.json';
// create contract instance
export default address => {
return new web3.eth.Contract(
// abi / interface
JSON.parse(Campaign.interface),
address
)
};
On va creer notre composant liste de campaigns
import React,{ Component } from "react";
import { Card, Button } from "semantic-ui-react";
import factory from '../ethereum/factory';
import Layout from "../components/Layout";
class CampaignIndex extends Component {
static async getInitialProps() {
// fetch campaigns
const campaigns = await factory.methods.getDeployedCampaigns().call();
// returns props object
return {
campaigns
}
}
renderCampaigns() {
const items = this.props.campaigns.map(address => {
return {
header: address,
description: <a>View campaign</a>,
fluid: true
}
})
return <Card.Group items={items} />;
}
render() {
return (
<Layout>
<div>
<h3>Open campaigns</h3>
<Button floated="right" content="Create Campaign" icon="add circle" primary />
{this.renderCampaigns()}
</div>
</Layout>
);
}
}
export default CampaignIndex;
Composant détail d’une Campaign
import React, { Component } from "react";
import { Card, Grid, Button } from "semantic-ui-react";
import Layout from "../../components/Layout";
import Campaign from "../../ethereum/campaign";
import web3 from "../../ethereum/web3";
import ContributeForm from "../../components/ContributeForm";
import { Link } from "../../routes";
class CampaignShow extends Component {
static async getInitialProps(props) {
const campaign = Campaign(props.query.address);
const summary = await campaign.methods.getSummary().call();
return {
address: props.query.address,
minimumContribution: summary[0],
balance: summary[1],
requestsCount: summary[2],
approversCount: summary[3],
manager: summary[4],
};
}
renderCards() {
const {
balance,
manager,
minimumContribution,
requestsCount,
approversCount,
} = this.props;
const items = [
{
header: manager,
meta: "Address of Manager",
description:
"The manager created this campaign and can create requests to withdraw money",
style: { overflowWrap: "break-word" },
},
{
header: (minimumContribution/1e18),
meta: "Minimum Contribution (ether)",
description:
"You must contribute at least this much wei to become an approver",
},
{
header: requestsCount,
meta: "Number of Requests",
description:
"A request tries to withdraw money from the contract. Requests must be approved by approvers",
},
{
header: approversCount,
meta: "Number of Approvers",
description:
"Number of people who have already donated to this campaign",
},
{
header: web3.utils.fromWei(balance, "ether"),
meta: "Campaign Balance (ether)",
description:
"The balance is how much money this campaign has left to spend.",
},
];
return <Card.Group items={items} />;
}
render() {
return (
<Layout>
<h3>Campaign Show</h3>
<Grid>
<Grid.Row>
<Grid.Column width={10}>{this.renderCards()}</Grid.Column>
<Grid.Column width={6}>
<ContributeForm address={this.props.address} />
</Grid.Column>
</Grid.Row>
<Grid.Row>
<Grid.Column>
<Link route={`/campaigns/${this.props.address}/requests`}>
<a>
<Button primary>View Requests</Button>
</a>
</Link>
</Grid.Column>
</Grid.Row>
</Grid>
</Layout>
);
}
}
export default CampaignShow;