submit flow
This commit is contained in:
parent
df750b6dbb
commit
b2dd152fae
|
@ -1,5 +1,6 @@
|
||||||
const submit = {
|
const submit = {
|
||||||
visible: false,
|
visible_submit: false,
|
||||||
|
visible_rating: false,
|
||||||
id: '',
|
id: '',
|
||||||
name: '',
|
name: '',
|
||||||
desc: '',
|
desc: '',
|
||||||
|
@ -11,6 +12,7 @@ const submit = {
|
||||||
imgControlMove: false,
|
imgControlMove: false,
|
||||||
imgControlX: 0,
|
imgControlX: 0,
|
||||||
imgControlY: 0,
|
imgControlY: 0,
|
||||||
|
sntValue: '0',
|
||||||
}
|
}
|
||||||
|
|
||||||
export default submit
|
export default submit
|
||||||
|
|
|
@ -2,6 +2,7 @@ import hardcodedDapps from '../../common/data/dapps'
|
||||||
import * as Categories from '../../common/data/categories'
|
import * as Categories from '../../common/data/categories'
|
||||||
import reducerUtil from '../../common/utils/reducer'
|
import reducerUtil from '../../common/utils/reducer'
|
||||||
import { showAlertAction } from '../Alert/Alert.reducer'
|
import { showAlertAction } from '../Alert/Alert.reducer'
|
||||||
|
import { TYPE_SUBMIT } from '../TransactionStatus/TransactionStatus.utilities'
|
||||||
//import BlockchainTool from '../../common/blockchain'
|
//import BlockchainTool from '../../common/blockchain'
|
||||||
|
|
||||||
const ON_FINISH_FETCH_ALL_DAPPS_ACTION =
|
const ON_FINISH_FETCH_ALL_DAPPS_ACTION =
|
||||||
|
@ -100,7 +101,9 @@ export const onFinishFetchByCategoryAction = (category, dapps) => ({
|
||||||
})
|
})
|
||||||
|
|
||||||
const fetchAllDappsInState = async (dispatch, getState) => {
|
const fetchAllDappsInState = async (dispatch, getState) => {
|
||||||
const stateDapps = getState().dapps
|
const state = getState()
|
||||||
|
const { transactionStatus } = state
|
||||||
|
const stateDapps = state.dapps
|
||||||
if (stateDapps.dapps === null) {
|
if (stateDapps.dapps === null) {
|
||||||
try {
|
try {
|
||||||
let dapps = await BlockchainSDK.DiscoverService.getDApps()
|
let dapps = await BlockchainSDK.DiscoverService.getDApps()
|
||||||
|
@ -112,6 +115,14 @@ const fetchAllDappsInState = async (dispatch, getState) => {
|
||||||
dapps.sort((a, b) => {
|
dapps.sort((a, b) => {
|
||||||
return b.sntValue - a.sntValue
|
return b.sntValue - a.sntValue
|
||||||
})
|
})
|
||||||
|
if (transactionStatus.type === TYPE_SUBMIT) {
|
||||||
|
for (let i = 0; i < dapps.length; i += 1) {
|
||||||
|
if (dapps[i].id === transactionStatus.dappId) {
|
||||||
|
dapps.splice(i, 1)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dispatch(onFinishFetchAllDappsAction(dapps))
|
dispatch(onFinishFetchAllDappsAction(dapps))
|
||||||
return dapps
|
return dapps
|
||||||
|
|
|
@ -15,9 +15,12 @@ import {
|
||||||
onImgDoneAction,
|
onImgDoneAction,
|
||||||
onImgCancelAction,
|
onImgCancelAction,
|
||||||
submitAction,
|
submitAction,
|
||||||
|
switchToRatingAction,
|
||||||
|
onInputSntValueAction,
|
||||||
} from './Submit.reducer'
|
} from './Submit.reducer'
|
||||||
|
|
||||||
const mapStateToProps = state => state.submit
|
const mapStateToProps = state =>
|
||||||
|
Object.assign(state.submit, { dapps: state.dapps.dapps })
|
||||||
const mapDispatchToProps = dispatch => ({
|
const mapDispatchToProps = dispatch => ({
|
||||||
onClickClose: () => dispatch(closeSubmitAction()),
|
onClickClose: () => dispatch(closeSubmitAction()),
|
||||||
onInputName: name => dispatch(onInputNameAction(name)),
|
onInputName: name => dispatch(onInputNameAction(name)),
|
||||||
|
@ -31,6 +34,8 @@ const mapDispatchToProps = dispatch => ({
|
||||||
onImgDone: imgBase64 => dispatch(onImgDoneAction(imgBase64)),
|
onImgDone: imgBase64 => dispatch(onImgDoneAction(imgBase64)),
|
||||||
onSubmit: dapp => dispatch(submitAction(dapp)),
|
onSubmit: dapp => dispatch(submitAction(dapp)),
|
||||||
onClickTerms: () => dispatch(push('/terms')),
|
onClickTerms: () => dispatch(push('/terms')),
|
||||||
|
switchToRating: () => dispatch(switchToRatingAction()),
|
||||||
|
onInputSntValue: sntValue => dispatch(onInputSntValueAction(sntValue)),
|
||||||
})
|
})
|
||||||
|
|
||||||
export default withRouter(
|
export default withRouter(
|
||||||
|
|
|
@ -1,12 +1,20 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
|
import ReactImageFallback from 'react-image-fallback'
|
||||||
import styles from './Submit.module.scss'
|
import styles from './Submit.module.scss'
|
||||||
import Modal from '../../common/components/Modal'
|
import Modal from '../../common/components/Modal'
|
||||||
import CategorySelector from '../CategorySelector/CategorySelector.picker'
|
import CategorySelector from '../CategorySelector/CategorySelector.picker'
|
||||||
import Slider from '../../common/components/Slider/Slider'
|
import Slider from '../../common/components/Slider/Slider'
|
||||||
|
import CategoriesUtils from '../Categories/Categories.utils'
|
||||||
|
import Categories from '../../common/utils/categories'
|
||||||
|
import icon from '../../common/assets/images/icon.svg'
|
||||||
|
import sntIcon from '../../common/assets/images/SNT.svg'
|
||||||
import 'rc-slider/assets/index.css'
|
import 'rc-slider/assets/index.css'
|
||||||
import 'rc-tooltip/assets/bootstrap.css'
|
import 'rc-tooltip/assets/bootstrap.css'
|
||||||
|
|
||||||
|
const getCategoryName = category =>
|
||||||
|
Categories.find(x => x.key === category).value
|
||||||
|
|
||||||
class Submit extends React.Component {
|
class Submit extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
|
@ -24,6 +32,7 @@ class Submit extends React.Component {
|
||||||
this.onEndMove = this.onEndMove.bind(this)
|
this.onEndMove = this.onEndMove.bind(this)
|
||||||
this.onImgDone = this.onImgDone.bind(this)
|
this.onImgDone = this.onImgDone.bind(this)
|
||||||
this.onSubmit = this.onSubmit.bind(this)
|
this.onSubmit = this.onSubmit.bind(this)
|
||||||
|
this.handleSNTChange = this.handleSNTChange.bind(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate() {
|
componentDidUpdate() {
|
||||||
|
@ -153,9 +162,29 @@ class Submit extends React.Component {
|
||||||
onSubmit(dapp)
|
onSubmit(dapp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleSNTChange(e) {
|
||||||
|
const { value } = e.target
|
||||||
|
if (value !== '' && /^[1-9][0-9]*$/.test(value) === false) return
|
||||||
|
|
||||||
|
const intValue = value === '' ? 0 : parseInt(value, 10)
|
||||||
|
if (intValue > 1571296) return
|
||||||
|
|
||||||
|
const { dapp, onInputSntValue, fetchVoteRating } = this.props
|
||||||
|
onInputSntValue(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
title() {
|
||||||
|
const { visible_submit, visible_rating, imgControl } = this.props
|
||||||
|
if (visible_submit)
|
||||||
|
return imgControl ? 'Position and size your image' : 'Submit a Ðapp'
|
||||||
|
return 'Ðapp rating'
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
visible,
|
dapps,
|
||||||
|
visible_submit,
|
||||||
|
visible_rating,
|
||||||
onClickClose,
|
onClickClose,
|
||||||
name,
|
name,
|
||||||
desc,
|
desc,
|
||||||
|
@ -166,161 +195,256 @@ class Submit extends React.Component {
|
||||||
imgControlZoom,
|
imgControlZoom,
|
||||||
onImgCancel,
|
onImgCancel,
|
||||||
onClickTerms,
|
onClickTerms,
|
||||||
|
switchToRating,
|
||||||
|
sntValue,
|
||||||
} = this.props
|
} = this.props
|
||||||
|
|
||||||
const canSubmit =
|
const canSubmit =
|
||||||
name !== '' && desc !== '' && url !== '' && img !== '' && category !== ''
|
name !== '' && desc !== '' && url !== '' && img !== '' && category !== ''
|
||||||
|
|
||||||
|
const visible = visible_submit || visible_rating
|
||||||
|
|
||||||
|
/* rating */
|
||||||
|
let currentSNTamount = 0
|
||||||
|
let dappsByCategory = []
|
||||||
|
let catPosition = 0
|
||||||
|
let afterVoteRating = null
|
||||||
|
let afterVoteCategoryPosition = null
|
||||||
|
|
||||||
|
if (visible_rating) {
|
||||||
|
dappsByCategory = dapps.filter(dapp_ => dapp_.category === category)
|
||||||
|
|
||||||
|
catPosition = dappsByCategory.length + 1
|
||||||
|
if (sntValue !== '') {
|
||||||
|
afterVoteRating = parseInt(sntValue, 10)
|
||||||
|
afterVoteCategoryPosition = 1
|
||||||
|
for (let i = 0; i < dappsByCategory.length; ++i) {
|
||||||
|
if (dappsByCategory[i].sntValue < afterVoteRating) break
|
||||||
|
afterVoteCategoryPosition++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
visible={visible && window.location.hash === '#submit'}
|
visible={visible && window.location.hash === '#submit'}
|
||||||
onClickClose={onClickClose}
|
onClickClose={onClickClose}
|
||||||
windowClassName={styles.modalWindow}
|
windowClassName={styles.modalWindow}
|
||||||
contentClassName={imgControl ? styles.modalContentImgControl : ''}
|
contentClassName={
|
||||||
|
imgControl || visible_rating ? styles.modalContentFullScreen : ''
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<div className={styles.title}>
|
<div className={styles.title}>{this.title()}</div>
|
||||||
{imgControl ? 'Position and size your image' : 'Submit a Ðapp'}
|
{visible_submit && (
|
||||||
</div>
|
<div className={imgControl ? styles.cntWithImgControl : ''}>
|
||||||
<div className={imgControl ? styles.cntWithImgControl : ''}>
|
<div className={imgControl ? styles.withImgControl : ''}>
|
||||||
<div className={imgControl ? styles.withImgControl : ''}>
|
<div className={styles.block}>
|
||||||
<div className={styles.block}>
|
<div className={styles.labelRow}>
|
||||||
<div className={styles.labelRow}>
|
<span>Name of your Ðapp</span>
|
||||||
<span>Name of your Ðapp</span>
|
</div>
|
||||||
</div>
|
|
||||||
<input
|
|
||||||
className={styles.input}
|
|
||||||
placeholder="Name"
|
|
||||||
value={name}
|
|
||||||
onChange={this.onInputName}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className={styles.block}>
|
|
||||||
<div className={styles.labelRow}>
|
|
||||||
<span>A short description</span>
|
|
||||||
<span>{desc.length}/140</span>
|
|
||||||
</div>
|
|
||||||
<textarea
|
|
||||||
className={styles.input}
|
|
||||||
placeholder="Max 140 characters"
|
|
||||||
value={desc}
|
|
||||||
onChange={this.onInputDesc}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className={styles.block}>
|
|
||||||
<div className={styles.labelRow}>
|
|
||||||
<span>URL</span>
|
|
||||||
</div>
|
|
||||||
<input
|
|
||||||
className={styles.input}
|
|
||||||
placeholder="https://your.dapp.cool"
|
|
||||||
value={url}
|
|
||||||
onChange={this.onInputUrl}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className={styles.block}>
|
|
||||||
<div className={styles.labelRow}>
|
|
||||||
<span>Upload the logo or icon of your Ðapp</span>
|
|
||||||
</div>
|
|
||||||
<div className={styles.imgCnt}>
|
|
||||||
<span>Choose image</span>
|
|
||||||
<div
|
|
||||||
className={styles.imgHolder}
|
|
||||||
style={{ backgroundImage: `url(${img})` }}
|
|
||||||
/>
|
|
||||||
<input
|
<input
|
||||||
className={styles.uploader}
|
className={styles.input}
|
||||||
type="file"
|
placeholder="Name"
|
||||||
onChange={this.onChangeImage}
|
value={name}
|
||||||
accept=".jpg, .png"
|
onChange={this.onInputName}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.imgInfo}>
|
<div className={styles.block}>
|
||||||
The image should be a square 1:1 ratio JPG or PNG file, minimum
|
<div className={styles.labelRow}>
|
||||||
size is 160 × 160 pixels. The image will be placed in a circle
|
<span>A short description</span>
|
||||||
|
<span>{desc.length}/140</span>
|
||||||
|
</div>
|
||||||
|
<textarea
|
||||||
|
className={styles.input}
|
||||||
|
placeholder="Max 140 characters"
|
||||||
|
value={desc}
|
||||||
|
onChange={this.onInputDesc}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className={styles.block}>
|
||||||
|
<div className={styles.labelRow}>
|
||||||
|
<span>URL</span>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
className={styles.input}
|
||||||
|
placeholder="https://your.dapp.cool"
|
||||||
|
value={url}
|
||||||
|
onChange={this.onInputUrl}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className={styles.block}>
|
||||||
|
<div className={styles.labelRow}>
|
||||||
|
<span>Upload the logo or icon of your Ðapp</span>
|
||||||
|
</div>
|
||||||
|
<div className={styles.imgCnt}>
|
||||||
|
<span>Choose image</span>
|
||||||
|
<div
|
||||||
|
className={styles.imgHolder}
|
||||||
|
style={{ backgroundImage: `url(${img})` }}
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
className={styles.uploader}
|
||||||
|
type="file"
|
||||||
|
onChange={this.onChangeImage}
|
||||||
|
accept=".jpg, .png"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className={styles.imgInfo}>
|
||||||
|
The image should be a square 1:1 ratio JPG or PNG file,
|
||||||
|
minimum size is 160 × 160 pixels. The image will be placed in
|
||||||
|
a circle
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={styles.block}>
|
||||||
|
<div className={styles.labelRow}>
|
||||||
|
<span>Category</span>
|
||||||
|
</div>
|
||||||
|
<CategorySelector
|
||||||
|
category={category === '' ? null : category}
|
||||||
|
className={`${styles.categorySelector} ${
|
||||||
|
category === '' ? styles.categorySelectorEmpty : ''
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className={`${styles.block} ${styles.blockSubmit}`}>
|
||||||
|
<div className={styles.terms}>
|
||||||
|
By continuing you agree to our
|
||||||
|
<a onClick={onClickTerms}> Terms and Conditions.</a>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
className={styles.submitButton}
|
||||||
|
type="submit"
|
||||||
|
disabled={!canSubmit}
|
||||||
|
onClick={switchToRating}
|
||||||
|
>
|
||||||
|
Continue
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.block}>
|
{imgControl && (
|
||||||
<div className={styles.labelRow}>
|
<div className={styles.imgControl}>
|
||||||
<span>Category</span>
|
<div
|
||||||
|
className={styles.imgCanvasCnt}
|
||||||
|
onMouseDown={this.onStartMove}
|
||||||
|
onMouseMove={this.onMouseMove}
|
||||||
|
onMouseUp={this.onEndMove}
|
||||||
|
onMouseLeave={this.onEndMove}
|
||||||
|
onTouchStart={this.onStartMove}
|
||||||
|
onTouchMove={this.onTouchMove}
|
||||||
|
onTouchEnd={this.onEndMove}
|
||||||
|
onTouchCancel={this.onEndMove}
|
||||||
|
>
|
||||||
|
<canvas
|
||||||
|
ref={this.imgCanvas}
|
||||||
|
className={styles.imgCanvas}
|
||||||
|
width="160"
|
||||||
|
height="160"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className={styles.controls}>
|
||||||
|
<div className={styles.slider}>
|
||||||
|
<div className={styles.minZoom} />
|
||||||
|
<Slider
|
||||||
|
min={0}
|
||||||
|
max={300}
|
||||||
|
value={imgControlZoom}
|
||||||
|
onChange={this.onChangeZoom}
|
||||||
|
/>
|
||||||
|
<div className={styles.maxZoom} />
|
||||||
|
</div>
|
||||||
|
<div className={styles.actionsCnt}>
|
||||||
|
<button
|
||||||
|
className={`${styles.button} ${styles.cancelButton}`}
|
||||||
|
onClick={onImgCancel}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className={`${styles.button} ${styles.doneButton}`}
|
||||||
|
onClick={this.onImgDone}
|
||||||
|
>
|
||||||
|
Done
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<CategorySelector
|
)}
|
||||||
category={category === '' ? null : category}
|
</div>
|
||||||
className={`${styles.categorySelector} ${
|
)}
|
||||||
category === '' ? styles.categorySelectorEmpty : ''
|
{visible_rating && (
|
||||||
}`}
|
<>
|
||||||
|
<div className={styles.dapp}>
|
||||||
|
<ReactImageFallback
|
||||||
|
className={styles.image}
|
||||||
|
src={img}
|
||||||
|
fallbackImage={icon}
|
||||||
|
alt="App icon"
|
||||||
|
width={24}
|
||||||
|
height={24}
|
||||||
|
/>
|
||||||
|
{name}
|
||||||
|
</div>
|
||||||
|
<div className={styles.items}>
|
||||||
|
<div className={styles.itemRow}>
|
||||||
|
<span className={styles.item}>
|
||||||
|
<img src={sntIcon} alt="SNT" width="24" height="24" />
|
||||||
|
{currentSNTamount.toLocaleString()}
|
||||||
|
</span>
|
||||||
|
{afterVoteRating !== null &&
|
||||||
|
afterVoteRating !== currentSNTamount && (
|
||||||
|
<span className={styles.greenBadge}>
|
||||||
|
{`${afterVoteRating.toLocaleString()} ↑`}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className={styles.itemRow}>
|
||||||
|
<span className={styles.item}>
|
||||||
|
<img
|
||||||
|
src={CategoriesUtils(category)}
|
||||||
|
alt={getCategoryName(category)}
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
/>
|
||||||
|
{`${getCategoryName(category)} №${catPosition}`}
|
||||||
|
</span>
|
||||||
|
{afterVoteCategoryPosition !== null &&
|
||||||
|
afterVoteCategoryPosition !== catPosition && (
|
||||||
|
<span className={styles.greenBadge}>
|
||||||
|
{`№${afterVoteCategoryPosition} ↑`}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={`${styles.inputArea} ${styles.inputAreaBorder}`}>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={sntValue}
|
||||||
|
onChange={this.handleSNTChange}
|
||||||
|
style={{ width: `${21 * Math.max(1, sntValue.length)}px` }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={`${styles.block} ${styles.blockSubmit}`}>
|
<div className={styles.footer}>
|
||||||
<div className={styles.terms}>
|
<p className={styles.disclaimer}>
|
||||||
By continuing you agree to our
|
SNT you spend to rank your DApp is locked in the store. You can
|
||||||
<a onClick={onClickTerms}> Terms and Conditions.</a>
|
earn back through votes, or withdraw, the majority of this SNT
|
||||||
</div>
|
at any time.
|
||||||
<button
|
</p>
|
||||||
className={styles.submitButton}
|
<button type="submit" onClick={this.onSubmit}>
|
||||||
type="submit"
|
{!sntValue || sntValue === '0'
|
||||||
disabled={!canSubmit}
|
? 'Publish'
|
||||||
onClick={this.onSubmit}
|
: 'Stake and Publish'}
|
||||||
>
|
|
||||||
Continue
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</>
|
||||||
{imgControl && (
|
)}
|
||||||
<div className={styles.imgControl}>
|
|
||||||
<div
|
|
||||||
className={styles.imgCanvasCnt}
|
|
||||||
onMouseDown={this.onStartMove}
|
|
||||||
onMouseMove={this.onMouseMove}
|
|
||||||
onMouseUp={this.onEndMove}
|
|
||||||
onMouseLeave={this.onEndMove}
|
|
||||||
onTouchStart={this.onStartMove}
|
|
||||||
onTouchMove={this.onTouchMove}
|
|
||||||
onTouchEnd={this.onEndMove}
|
|
||||||
onTouchCancel={this.onEndMove}
|
|
||||||
>
|
|
||||||
<canvas
|
|
||||||
ref={this.imgCanvas}
|
|
||||||
className={styles.imgCanvas}
|
|
||||||
width="160"
|
|
||||||
height="160"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className={styles.controls}>
|
|
||||||
<div className={styles.slider}>
|
|
||||||
<div className={styles.minZoom} />
|
|
||||||
<Slider
|
|
||||||
min={0}
|
|
||||||
max={300}
|
|
||||||
value={imgControlZoom}
|
|
||||||
onChange={this.onChangeZoom}
|
|
||||||
/>
|
|
||||||
<div className={styles.maxZoom} />
|
|
||||||
</div>
|
|
||||||
<div className={styles.actionsCnt}>
|
|
||||||
<button
|
|
||||||
className={`${styles.button} ${styles.cancelButton}`}
|
|
||||||
onClick={onImgCancel}
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className={`${styles.button} ${styles.doneButton}`}
|
|
||||||
onClick={this.onImgDone}
|
|
||||||
>
|
|
||||||
Done
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</Modal>
|
</Modal>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Submit.propTypes = {
|
Submit.propTypes = {
|
||||||
visible: PropTypes.bool.isRequired,
|
visible_submit: PropTypes.bool.isRequired,
|
||||||
|
visible_rating: PropTypes.bool.isRequired,
|
||||||
name: PropTypes.string.isRequired,
|
name: PropTypes.string.isRequired,
|
||||||
desc: PropTypes.string.isRequired,
|
desc: PropTypes.string.isRequired,
|
||||||
url: PropTypes.string.isRequired,
|
url: PropTypes.string.isRequired,
|
||||||
|
@ -331,6 +455,7 @@ Submit.propTypes = {
|
||||||
imgControlMove: PropTypes.bool.isRequired,
|
imgControlMove: PropTypes.bool.isRequired,
|
||||||
imgControlX: PropTypes.number.isRequired,
|
imgControlX: PropTypes.number.isRequired,
|
||||||
imgControlY: PropTypes.number.isRequired,
|
imgControlY: PropTypes.number.isRequired,
|
||||||
|
sntValue: PropTypes.string.isRequired,
|
||||||
onClickClose: PropTypes.func.isRequired,
|
onClickClose: PropTypes.func.isRequired,
|
||||||
onInputName: PropTypes.func.isRequired,
|
onInputName: PropTypes.func.isRequired,
|
||||||
onInputDesc: PropTypes.func.isRequired,
|
onInputDesc: PropTypes.func.isRequired,
|
||||||
|
@ -342,7 +467,9 @@ Submit.propTypes = {
|
||||||
onImgCancel: PropTypes.func.isRequired,
|
onImgCancel: PropTypes.func.isRequired,
|
||||||
onImgDone: PropTypes.func.isRequired,
|
onImgDone: PropTypes.func.isRequired,
|
||||||
onSubmit: PropTypes.func.isRequired,
|
onSubmit: PropTypes.func.isRequired,
|
||||||
|
onInputSntValue: PropTypes.func.isRequired,
|
||||||
onClickTerms: PropTypes.func.isRequired,
|
onClickTerms: PropTypes.func.isRequired,
|
||||||
|
switchToRating: PropTypes.func.isRequired,
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Submit
|
export default Submit
|
||||||
|
|
|
@ -13,14 +13,14 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.modalContentImgControl {
|
.modalContentFullScreen {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: $desktop) {
|
@media (min-width: $desktop) {
|
||||||
.modalContentImgControl {
|
.modalContentFullScreen {
|
||||||
height: 512px;
|
height: 512px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -271,3 +271,142 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* rating */
|
||||||
|
.dapp {
|
||||||
|
height: 48px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-family: $font;
|
||||||
|
font-weight: 500;
|
||||||
|
padding: 0 calculateRem(12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dapp .image {
|
||||||
|
max-width: 24px;
|
||||||
|
max-height: 24px;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin-right: calculateRem(12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.items {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
font-family: $font;
|
||||||
|
}
|
||||||
|
|
||||||
|
.items .itemRow {
|
||||||
|
height: 32px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 calculateRem(12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.items .item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.items .item img {
|
||||||
|
margin-right: calculateRem(12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge {
|
||||||
|
border-radius: 24px;
|
||||||
|
color: #ffffff;
|
||||||
|
font-family: $font;
|
||||||
|
font-size: calculateRem(15);
|
||||||
|
margin-right: calculateRem(16);
|
||||||
|
margin-left: auto;
|
||||||
|
padding: calculateRem(3) calculateRem(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
.greenBadge {
|
||||||
|
@extend .badge;
|
||||||
|
background: #44d058;
|
||||||
|
}
|
||||||
|
|
||||||
|
.redBadge {
|
||||||
|
@extend .badge;
|
||||||
|
background: #f00;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inputArea {
|
||||||
|
width: calc(100% - 2 * 16px);
|
||||||
|
height: 64px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inputArea.inputAreaBorder {
|
||||||
|
border-bottom: 1px solid #eef2f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inputArea input {
|
||||||
|
width: 19px;
|
||||||
|
border: none;
|
||||||
|
text-align: center;
|
||||||
|
font-size: calculateRem(32);
|
||||||
|
line-height: calculateRem(28);
|
||||||
|
font-family: $font;
|
||||||
|
margin-right: calculateRem(6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.inputArea input:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inputArea::after {
|
||||||
|
transition: all 0.05s ease-in-out;
|
||||||
|
content: 'SNT';
|
||||||
|
color: #939ba1;
|
||||||
|
font-size: calculateRem(32);
|
||||||
|
line-height: calculateRem(28);
|
||||||
|
font-family: $font;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inputArea span {
|
||||||
|
font-size: calculateRem(32);
|
||||||
|
line-height: calculateRem(28);
|
||||||
|
font-family: $font;
|
||||||
|
margin-right: calculateRem(6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer button {
|
||||||
|
background: $link-color;
|
||||||
|
border-radius: 8px;
|
||||||
|
color: #fff;
|
||||||
|
margin: calculateRem(10) auto;
|
||||||
|
border: none;
|
||||||
|
font-family: $font;
|
||||||
|
padding: calculateRem(11) calculateRem(38);
|
||||||
|
font-size: calculateRem(15);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer button:disabled,
|
||||||
|
.footer button[disabled] {
|
||||||
|
background: $text-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer .disclaimer {
|
||||||
|
font-size: calculateRem(15);
|
||||||
|
color: $text-color;
|
||||||
|
line-height: 22px;
|
||||||
|
font-family: $font;
|
||||||
|
padding: calculateRem(16);
|
||||||
|
border-bottom: 1px solid #eef2f5;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer .disclaimer a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: $link-color;
|
||||||
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import {
|
||||||
onStartProgressAction,
|
onStartProgressAction,
|
||||||
hideAction,
|
hideAction,
|
||||||
} from '../TransactionStatus/TransactionStatus.recuder'
|
} from '../TransactionStatus/TransactionStatus.recuder'
|
||||||
|
import { TYPE_SUBMIT } from '../TransactionStatus/TransactionStatus.utilities'
|
||||||
import { showAlertAction } from '../Alert/Alert.reducer'
|
import { showAlertAction } from '../Alert/Alert.reducer'
|
||||||
|
|
||||||
// import BlockchainTool from '../../common/blockchain'
|
// import BlockchainTool from '../../common/blockchain'
|
||||||
|
@ -36,6 +37,9 @@ const ON_IMG_MOVE = 'SUBMIT_ON_IMG_MOVE'
|
||||||
const ON_IMG_CANCEL = 'SUBMIT_ON_IMG_CANCEL'
|
const ON_IMG_CANCEL = 'SUBMIT_ON_IMG_CANCEL'
|
||||||
const ON_IMG_DONE = 'SUBMIT_ON_IMG_DONE'
|
const ON_IMG_DONE = 'SUBMIT_ON_IMG_DONE'
|
||||||
|
|
||||||
|
const SWITCH_TO_RATING = 'SUBMIT_SWITCH_TO_RATING'
|
||||||
|
const ON_INPUT_SNT_VALUE = 'SUBMIT_ON_INPUT_SNT_VALUE'
|
||||||
|
|
||||||
export const showSubmitActionAfterCheck = () => {
|
export const showSubmitActionAfterCheck = () => {
|
||||||
window.location.hash = 'submit'
|
window.location.hash = 'submit'
|
||||||
return {
|
return {
|
||||||
|
@ -123,6 +127,7 @@ export const submitAction = dapp => {
|
||||||
dapp.name,
|
dapp.name,
|
||||||
dapp.img,
|
dapp.img,
|
||||||
'Status is an open source mobile DApp browser and messenger build for #Etherium',
|
'Status is an open source mobile DApp browser and messenger build for #Etherium',
|
||||||
|
TYPE_SUBMIT,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
try {
|
try {
|
||||||
|
@ -142,9 +147,20 @@ export const submitAction = dapp => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const switchToRatingAction = () => ({
|
||||||
|
type: SWITCH_TO_RATING,
|
||||||
|
paylaod: null,
|
||||||
|
})
|
||||||
|
|
||||||
|
export const onInputSntValueAction = sntValue => ({
|
||||||
|
type: ON_INPUT_SNT_VALUE,
|
||||||
|
payload: sntValue,
|
||||||
|
})
|
||||||
|
|
||||||
const showSubmitAfterCheck = state => {
|
const showSubmitAfterCheck = state => {
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
visible: true,
|
visible_submit: true,
|
||||||
|
visible_rating: false,
|
||||||
id: '',
|
id: '',
|
||||||
name: '',
|
name: '',
|
||||||
desc: '',
|
desc: '',
|
||||||
|
@ -156,6 +172,7 @@ const showSubmitAfterCheck = state => {
|
||||||
imgControlMove: false,
|
imgControlMove: false,
|
||||||
imgControlX: 0,
|
imgControlX: 0,
|
||||||
imgControlY: 0,
|
imgControlY: 0,
|
||||||
|
sntValue: '0',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,6 +250,19 @@ const onImgDone = (state, imgBase64) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const switchToRating = state => {
|
||||||
|
return Object.assign({}, state, {
|
||||||
|
visible_submit: false,
|
||||||
|
visible_rating: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const onInputSntValue = (state, sntValue) => {
|
||||||
|
return Object.assign({}, state, {
|
||||||
|
sntValue,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const map = {
|
const map = {
|
||||||
[SHOW_SUBMIT_AFTER_CHECK]: showSubmitAfterCheck,
|
[SHOW_SUBMIT_AFTER_CHECK]: showSubmitAfterCheck,
|
||||||
[CLOSE_SUBMIT]: closeSubmit,
|
[CLOSE_SUBMIT]: closeSubmit,
|
||||||
|
@ -246,6 +276,8 @@ const map = {
|
||||||
[ON_IMG_MOVE]: onImgMove,
|
[ON_IMG_MOVE]: onImgMove,
|
||||||
[ON_IMG_CANCEL]: onImgCancel,
|
[ON_IMG_CANCEL]: onImgCancel,
|
||||||
[ON_IMG_DONE]: onImgDone,
|
[ON_IMG_DONE]: onImgDone,
|
||||||
|
[SWITCH_TO_RATING]: switchToRating,
|
||||||
|
[ON_INPUT_SNT_VALUE]: onInputSntValue,
|
||||||
}
|
}
|
||||||
|
|
||||||
export default reducerUtil(map, submitInitialState)
|
export default reducerUtil(map, submitInitialState)
|
||||||
|
|
|
@ -3,6 +3,7 @@ import reducerUtil from '../../common/utils/reducer'
|
||||||
import {
|
import {
|
||||||
transactionStatusFetchedInstance,
|
transactionStatusFetchedInstance,
|
||||||
transactionStatusInitInstance,
|
transactionStatusInitInstance,
|
||||||
|
TYPE_NONE,
|
||||||
} from './TransactionStatus.utilities'
|
} from './TransactionStatus.utilities'
|
||||||
import { onUpdateDappDataAction } from '../Dapps/Dapps.reducer'
|
import { onUpdateDappDataAction } from '../Dapps/Dapps.reducer'
|
||||||
import { showAlertAction } from '../Alert/Alert.reducer'
|
import { showAlertAction } from '../Alert/Alert.reducer'
|
||||||
|
@ -46,9 +47,9 @@ export const hideAction = () => ({
|
||||||
payload: null,
|
payload: null,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const onStartProgressAction = (dappName, dappImg, desc) => ({
|
export const onStartProgressAction = (dappName, dappImg, desc, type) => ({
|
||||||
type: ON_START_PROGRESS,
|
type: ON_START_PROGRESS,
|
||||||
payload: { dappName, dappImg, desc },
|
payload: { dappName, dappImg, desc, type },
|
||||||
})
|
})
|
||||||
|
|
||||||
export const onReceiveTransactionInfoAction = (id, tx) => ({
|
export const onReceiveTransactionInfoAction = (id, tx) => ({
|
||||||
|
@ -114,15 +115,17 @@ const hide = state => {
|
||||||
const transacationStatus = transactionStatusFetchedInstance()
|
const transacationStatus = transactionStatusFetchedInstance()
|
||||||
transacationStatus.setDappName('')
|
transacationStatus.setDappName('')
|
||||||
transacationStatus.setProgress(false)
|
transacationStatus.setProgress(false)
|
||||||
|
transacationStatus.setType(TYPE_NONE)
|
||||||
return Object.assign({}, state, transacationStatus)
|
return Object.assign({}, state, transacationStatus)
|
||||||
}
|
}
|
||||||
|
|
||||||
const onStartProgress = (state, payload) => {
|
const onStartProgress = (state, payload) => {
|
||||||
const { dappName, dappImg, desc } = payload
|
const { dappName, dappImg, desc, type } = payload
|
||||||
const transacationStatus = transactionStatusInitInstance(
|
const transacationStatus = transactionStatusInitInstance(
|
||||||
dappName,
|
dappName,
|
||||||
dappImg,
|
dappImg,
|
||||||
desc,
|
desc,
|
||||||
|
type,
|
||||||
)
|
)
|
||||||
transacationStatus.persistTransactionData()
|
transacationStatus.persistTransactionData()
|
||||||
return Object.assign({}, state, transacationStatus)
|
return Object.assign({}, state, transacationStatus)
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
const COOKIE_NAME = 'TRANSACTION_STATUS_COOKIE'
|
const COOKIE_NAME = 'TRANSACTION_STATUS_COOKIE'
|
||||||
|
|
||||||
|
export const TYPE_NONE = 0
|
||||||
|
export const TYPE_SUBMIT = 1
|
||||||
|
export const TYPE_UPVOTE = 2
|
||||||
|
export const TYPE_DOWNVOTE = 3
|
||||||
|
|
||||||
class TransactionStatus {
|
class TransactionStatus {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.dappId = ''
|
this.dappId = ''
|
||||||
|
@ -7,6 +12,7 @@ class TransactionStatus {
|
||||||
this.txDesc = ''
|
this.txDesc = ''
|
||||||
this.dappName = ''
|
this.dappName = ''
|
||||||
this.dappImg = ''
|
this.dappImg = ''
|
||||||
|
this.type = TYPE_NONE
|
||||||
this.progress = false
|
this.progress = false
|
||||||
this.published = false
|
this.published = false
|
||||||
this.failed = false
|
this.failed = false
|
||||||
|
@ -49,18 +55,24 @@ class TransactionStatus {
|
||||||
this.failed = failed
|
this.failed = failed
|
||||||
this.persistTransactionData()
|
this.persistTransactionData()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setType(type) {
|
||||||
|
this.type = type
|
||||||
|
this.persistTransactionData()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getTransactionData = () => {
|
const getTransactionData = () => {
|
||||||
return localStorage.getItem(COOKIE_NAME)
|
return localStorage.getItem(COOKIE_NAME)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const transactionStatusInitInstance = (name, img, desc) => {
|
export const transactionStatusInitInstance = (name, img, desc, type) => {
|
||||||
const model = new TransactionStatus()
|
const model = new TransactionStatus()
|
||||||
model.dappName = name
|
model.dappName = name
|
||||||
model.dappImg = img
|
model.dappImg = img
|
||||||
model.progress = true
|
model.progress = true
|
||||||
model.txDesc = desc
|
model.txDesc = desc
|
||||||
|
model.type = type
|
||||||
return model
|
return model
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -174,7 +174,7 @@ class Vote extends Component {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{!isUpvote && (
|
{!isUpvote && (
|
||||||
<div className={styles.inputArea}>
|
<div className={styles.inputArea} style={{ opacity: 0 }}>
|
||||||
<span>{downvoteSNTcost}</span>
|
<span>{downvoteSNTcost}</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -6,6 +6,10 @@ import {
|
||||||
onReceiveTransactionInfoAction,
|
onReceiveTransactionInfoAction,
|
||||||
checkTransactionStatusAction,
|
checkTransactionStatusAction,
|
||||||
} from '../TransactionStatus/TransactionStatus.recuder'
|
} from '../TransactionStatus/TransactionStatus.recuder'
|
||||||
|
import {
|
||||||
|
TYPE_UPVOTE,
|
||||||
|
TYPE_DOWNVOTE,
|
||||||
|
} from '../TransactionStatus/TransactionStatus.utilities'
|
||||||
|
|
||||||
const SHOW_UP_VOTE_AFTER_CHECK = 'VOTE_SHOW_UP_VOTE_AFTER_CHECK'
|
const SHOW_UP_VOTE_AFTER_CHECK = 'VOTE_SHOW_UP_VOTE_AFTER_CHECK'
|
||||||
const SHOW_DOWN_VOTE_AFTER_CHEECK = 'VOTE_SHOW_DOWN_VOTE_AFTER_CHEECK'
|
const SHOW_DOWN_VOTE_AFTER_CHEECK = 'VOTE_SHOW_DOWN_VOTE_AFTER_CHEECK'
|
||||||
|
@ -138,7 +142,12 @@ export const upVoteAction = (dapp, amount) => {
|
||||||
return async dispatch => {
|
return async dispatch => {
|
||||||
dispatch(closeVoteAction())
|
dispatch(closeVoteAction())
|
||||||
dispatch(
|
dispatch(
|
||||||
onStartProgressAction(dapp.name, dapp.image, `↑ Upvote by ${amount} SNT`),
|
onStartProgressAction(
|
||||||
|
dapp.name,
|
||||||
|
dapp.image,
|
||||||
|
`↑ Upvote by ${amount} SNT`,
|
||||||
|
TYPE_UPVOTE,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
try {
|
try {
|
||||||
const tx = await BlockchainSDK.DiscoverService.upVote(dapp.id, amount)
|
const tx = await BlockchainSDK.DiscoverService.upVote(dapp.id, amount)
|
||||||
|
@ -158,6 +167,7 @@ export const downVoteAction = (dapp, amount) => {
|
||||||
dapp.name,
|
dapp.name,
|
||||||
dapp.image,
|
dapp.image,
|
||||||
`↓ Downvote by ${amount} SNT`,
|
`↓ Downvote by ${amount} SNT`,
|
||||||
|
TYPE_DOWNVOTE,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
try {
|
try {
|
||||||
|
|
Loading…
Reference in New Issue