Skip to content

Commit

Permalink
Merge pull request #639 from poanetwork/bulk-import-whitelist-#600
Browse files Browse the repository at this point in the history
(Feature) Bulk import whitelist
  • Loading branch information
vbaranov committed Mar 2, 2018
2 parents cb34b81 + c3795db commit c862894
Show file tree
Hide file tree
Showing 13 changed files with 119 additions and 163 deletions.
8 changes: 1 addition & 7 deletions ICO_wizard_state_example.json
Original file line number Diff line number Diff line change
Expand Up @@ -2520,11 +2520,6 @@
"_store": {}
}
],
"whiteListInput": {
"addr": "",
"min": "",
"max": ""
},
"tier": "Tier 1",
"updatable": "on",
"whitelistdisabled": "no"
Expand All @@ -2535,10 +2530,9 @@
"updatable": "on",
"whitelist": [],
"whiteListElements": [],
"whiteListInput": {},
"startTime": "2017-10-03T00:05:00",
"endTime": "2017-10-07T00:05:00"
}
],
"children": []
}
}
22 changes: 22 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
"mobx-react": "^4.3.3",
"moment": "^2.20.1",
"object-assign": "4.1.1",
"papaparse": "^4.3.7",
"path": "^0.12.7",
"postcss-flexbugs-fixes": "3.0.0",
"postcss-loader": "2.0.6",
Expand All @@ -81,6 +82,7 @@
"react-countdown-clock": "^2.0.0",
"react-dev-utils": "^3.0.2",
"react-dom": "^15.6.1",
"react-dropzone": "^4.2.8",
"react-error-overlay": "^1.0.9",
"react-router-dom": "^4.1.2",
"solc": "^0.4.14",
Expand Down
117 changes: 68 additions & 49 deletions src/components/Common/WhitelistInputBlock.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import React from 'react'
import Web3 from 'web3';
import update from 'immutability-helper';
import Dropzone from 'react-dropzone';
import Papa from 'papaparse'
import '../../assets/stylesheets/application.css';
import { InputField } from './InputField'
import { TEXT_FIELDS, defaultState, VALIDATION_TYPES } from '../../utils/constants'
import { TEXT_FIELDS, VALIDATION_TYPES } from '../../utils/constants'
import { validateAddress } from '../../utils/utils'
import { WhitelistItem } from './WhitelistItem'
import { getOldState } from '../../utils/utils'
import { inject, observer } from 'mobx-react'
const { ADDRESS, MIN, MAX } = TEXT_FIELDS
const {VALID, INVALID} = VALIDATION_TYPES;
Expand All @@ -15,22 +17,23 @@ const {VALID, INVALID} = VALIDATION_TYPES;
export class WhitelistInputBlock extends React.Component {
constructor (props) {
super(props)
let oldState = getOldState(props, defaultState)
this.state = Object.assign({}, oldState, {
this.state = {
addr: '',
min: '',
max: '',
validation: {
address: {
pristine: true,
valid: INVALID
}
}
})
}
}

addWhitelistItem = () => {
const { tierStore } = this.props
const crowdsaleNum = this.props.num
const tier = tierStore.tiers[crowdsaleNum]
const { addr, min, max } = tier.whitelistInput
const { addr, min, max } = this.state

this.setState(update(this.state, {
validation: {
Expand All @@ -44,51 +47,26 @@ export class WhitelistInputBlock extends React.Component {
return
}

this.setState(update(this.state, {
this.setState({
addr: '',
min: '',
max: '',
validation: {
address: {
$set: {
pristine: true,
valid: INVALID
}
pristine: true,
valid: INVALID
}
}
}))

this.clearWhiteListInputs()

const whitelist = tier.whitelist.slice()

const isAdded = whitelist.find(item => item.addr === addr && !item.deleted)

if (isAdded) return

const whitelistElements = tier.whitelistElements.slice()
const whitelistNum = whitelistElements.length

whitelistElements.push({ addr, min, max, whitelistNum, crowdsaleNum })
whitelist.push({ addr, min, max })

tierStore.setTierProperty(whitelistElements, 'whitelistElements', crowdsaleNum)
tierStore.setTierProperty(whitelist, 'whitelist', crowdsaleNum)
}
})

clearWhiteListInputs = () => {
const whitelistInput = {
addr: '',
min: '',
max: ''
}
this.props.tierStore.setTierProperty(whitelistInput, 'whitelistInput', this.props.num)
tierStore.addWhitelistItem({ addr, min, max }, crowdsaleNum)
}

handleAddressChange = e => {
this.props.onChange(e, 'crowdsale', this.props.num, 'whitelist_addr')

const address = e.target.value
handleAddressChange = address => {
const isAddressValid = Web3.utils.isAddress(address) ? VALID : INVALID;

const newState = update(this.state, {
addr: { $set: address },
validation: {
address: {
$set: {
Expand All @@ -102,20 +80,61 @@ export class WhitelistInputBlock extends React.Component {
this.setState(newState)
}

isAddress = (address) => validateAddress(address)
isNumber = (number) => !isNaN(parseFloat(number))

onDrop = (acceptedFiles, rejectedFiles) => {
acceptedFiles.forEach(file => {
Papa.parse(file, {
skipEmptyLines: true,
complete: results => {
results.data.forEach((row) => {
if (row.length !== 3) return

const [addr, min, max] = row

if (!this.isAddress(addr) || !this.isNumber(min) || !this.isNumber(max)) return

this.props.tierStore.addWhitelistItem({ addr, min, max }, this.props.num)
})
}
})
})
}


render () {
const { num } = this.props
const { whitelistInput, whitelistElements } = this.props.tierStore.tiers[num]
const { whitelistElements } = this.props.tierStore.tiers[num]

const dropzoneStyle = {
position: 'relative',
marginTop: '-15px',
marginBottom: '15px'
}
const uploadCSVStyle = {
textDecoration: 'underline',
cursor: 'pointer'
}

return (
<div className="white-list-container">
<Dropzone
onDrop={this.onDrop}
accept=".csv"
style={dropzoneStyle}
>
<span style={uploadCSVStyle}>Upload CSV</span>
</Dropzone>

<div className="white-list-input-container">
<div className="white-list-input-container-inner">
<InputField
side='white-list-input-property white-list-input-property-left'
type='text'
title={ADDRESS}
value={whitelistInput && whitelistInput.addr}
onChange={e => this.handleAddressChange(e)}
value={this.state.addr}
onChange={e => this.handleAddressChange(e.target.value)}
description={`Address of a whitelisted account. Whitelists are inherited. E.g., if an account whitelisted on Tier 1 and didn't buy max cap on Tier 1, he can buy on Tier 2, and following tiers.`}
pristine={this.state.validation.address.pristine}
valid={this.state.validation.address.valid}
Expand All @@ -125,16 +144,16 @@ export class WhitelistInputBlock extends React.Component {
side='white-list-input-property white-list-input-property-middle'
type='number'
title={MIN}
value={whitelistInput && whitelistInput.min}
onChange={e => this.props.onChange(e, 'crowdsale', num, 'whitelist_min')}
value={this.state.min}
onChange={e => this.setState({ min: e.target.value })}
description={`Minimum amount tokens to buy. Not a minimal size of a transaction. If minCap is 1 and user bought 1 token in a previous transaction and buying 0.1 token it will allow him to buy.`}
/>
<InputField
side='white-list-input-property white-list-input-property-right'
type='number'
title={MAX}
value={whitelistInput && whitelistInput.max}
onChange={e => this.props.onChange(e, 'crowdsale', num, 'whitelist_max')}
value={this.state.max}
onChange={e => this.setState({ max: e.target.value })}
description={`Maximum is the hard limit.`}
/>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/components/Common/WhitelistItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { inject, observer } from 'mobx-react'
export class WhitelistItem extends React.Component {
removeItem () {
const { tierStore, crowdsaleNum, whitelistNum } = this.props
tierStore.removeWhiteListItem(whitelistNum, crowdsaleNum)
tierStore.removeWhitelistItem(whitelistNum, crowdsaleNum)
}

render () {
Expand Down
9 changes: 0 additions & 9 deletions src/components/manage/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -370,14 +370,6 @@ export class Manage extends Component {
})
}

changeState = (event, parent, key, property) => {
const { tierStore } = this.props
const whitelistInputProps = { ...tierStore.tiers[key].whitelistInput }
const prop = property.split('_')[1]
whitelistInputProps[prop] = event.target.value
tierStore.setTierProperty(whitelistInputProps, 'whitelistInput', key)
}

clickedWhiteListInputBlock = e => {
if (e.target.classList.contains('button_fill_plus')) {
this.setState({ formPristine: false })
Expand All @@ -389,7 +381,6 @@ export class Manage extends Component {
<WhitelistInputBlock
key={index.toString()}
num={index}
onChange={(e, contract, num, prop) => this.changeState(e, contract, num, prop)}
/>
)
}
Expand Down
7 changes: 1 addition & 6 deletions src/components/manage/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -202,12 +202,7 @@ export const processTier = (crowdsaleAddress, crowdsaleNum) => {

const newTier = {
whitelist: [],
whitelistElements: [],
whitelistInput: {
addr: '',
min: '',
max: ''
}
whitelistElements: []
}

const initialValues = {}
Expand Down
20 changes: 0 additions & 20 deletions src/components/stepFour/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,6 @@ export const addWhitelist = () => {

for (let i = 0; i <= round; i++) {
const tier = tierStore.tiers[i]
const whitelistInput = tier.whitelistInput

for (let j = 0; j < tier.whitelist.length; j++) {
let itemIsAdded = false
Expand All @@ -418,25 +417,6 @@ export const addWhitelist = () => {
whitelist.push.apply(whitelist, tier.whitelist)
}
}

if (whitelistInput.addr && whitelistInput.min && whitelistInput.max) {
let itemIsAdded = false

for (let k = 0; k < whitelist.length; k++) {
if (whitelist[k].addr === whitelistInput.addr) {
itemIsAdded = true
break
}
}

if (!itemIsAdded) {
whitelist.push({
'addr': whitelistInput.addr,
'min': whitelistInput.min,
'max': whitelistInput.max
})
}
}
}

console.log('whitelist:', whitelist)
Expand Down
12 changes: 1 addition & 11 deletions src/components/stepThree/CrowdsaleBlock.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,6 @@ export class CrowdsaleBlock extends React.Component {
tierStore.setTierProperty(startTime, "startTime", num);
tierStore.setTierProperty(endTime, "endTime", num);
}
changeState = (event, parent, key, property) => {
if (property.indexOf("whitelist_") === 0) {
const { tierStore } = this.props;
const whitelistInputProps = { ...tierStore.tiers[key].whitelistInput };
const prop = property.split("_")[1];

whitelistInputProps[prop] = event.target.value;
tierStore.setTierProperty(whitelistInputProps, "whitelistInput", key);
}
};

updateTierStore = (event, property) => {
const { tierStore, num } = this.props;
Expand All @@ -43,7 +33,7 @@ export class CrowdsaleBlock extends React.Component {
<div className="section-title">
<p className="title">Whitelist</p>
</div>
<WhitelistInputBlock num={num} onChange={(e, cntrct, num, prop) => this.changeState(e, cntrct, num, prop)} />
<WhitelistInputBlock num={num} />
</div>
);
return (
Expand Down
Loading

0 comments on commit c862894

Please sign in to comment.