submit flow
This commit is contained in:
parent
df750b6dbb
commit
b2dd152fae
|
@ -1,5 +1,6 @@
|
|||
const submit = {
|
||||
visible: false,
|
||||
visible_submit: false,
|
||||
visible_rating: false,
|
||||
id: '',
|
||||
name: '',
|
||||
desc: '',
|
||||
|
@ -11,6 +12,7 @@ const submit = {
|
|||
imgControlMove: false,
|
||||
imgControlX: 0,
|
||||
imgControlY: 0,
|
||||
sntValue: '0',
|
||||
}
|
||||
|
||||
export default submit
|
||||
|
|
|
@ -2,6 +2,7 @@ import hardcodedDapps from '../../common/data/dapps'
|
|||
import * as Categories from '../../common/data/categories'
|
||||
import reducerUtil from '../../common/utils/reducer'
|
||||
import { showAlertAction } from '../Alert/Alert.reducer'
|
||||
import { TYPE_SUBMIT } from '../TransactionStatus/TransactionStatus.utilities'
|
||||
//import BlockchainTool from '../../common/blockchain'
|
||||
|
||||
const ON_FINISH_FETCH_ALL_DAPPS_ACTION =
|
||||
|
@ -100,7 +101,9 @@ export const onFinishFetchByCategoryAction = (category, dapps) => ({
|
|||
})
|
||||
|
||||
const fetchAllDappsInState = async (dispatch, getState) => {
|
||||
const stateDapps = getState().dapps
|
||||
const state = getState()
|
||||
const { transactionStatus } = state
|
||||
const stateDapps = state.dapps
|
||||
if (stateDapps.dapps === null) {
|
||||
try {
|
||||
let dapps = await BlockchainSDK.DiscoverService.getDApps()
|
||||
|
@ -112,6 +115,14 @@ const fetchAllDappsInState = async (dispatch, getState) => {
|
|||
dapps.sort((a, b) => {
|
||||
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))
|
||||
return dapps
|
||||
|
|
|
@ -15,9 +15,12 @@ import {
|
|||
onImgDoneAction,
|
||||
onImgCancelAction,
|
||||
submitAction,
|
||||
switchToRatingAction,
|
||||
onInputSntValueAction,
|
||||
} from './Submit.reducer'
|
||||
|
||||
const mapStateToProps = state => state.submit
|
||||
const mapStateToProps = state =>
|
||||
Object.assign(state.submit, { dapps: state.dapps.dapps })
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
onClickClose: () => dispatch(closeSubmitAction()),
|
||||
onInputName: name => dispatch(onInputNameAction(name)),
|
||||
|
@ -31,6 +34,8 @@ const mapDispatchToProps = dispatch => ({
|
|||
onImgDone: imgBase64 => dispatch(onImgDoneAction(imgBase64)),
|
||||
onSubmit: dapp => dispatch(submitAction(dapp)),
|
||||
onClickTerms: () => dispatch(push('/terms')),
|
||||
switchToRating: () => dispatch(switchToRatingAction()),
|
||||
onInputSntValue: sntValue => dispatch(onInputSntValueAction(sntValue)),
|
||||
})
|
||||
|
||||
export default withRouter(
|
||||
|
|
|
@ -1,12 +1,20 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import ReactImageFallback from 'react-image-fallback'
|
||||
import styles from './Submit.module.scss'
|
||||
import Modal from '../../common/components/Modal'
|
||||
import CategorySelector from '../CategorySelector/CategorySelector.picker'
|
||||
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-tooltip/assets/bootstrap.css'
|
||||
|
||||
const getCategoryName = category =>
|
||||
Categories.find(x => x.key === category).value
|
||||
|
||||
class Submit extends React.Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
@ -24,6 +32,7 @@ class Submit extends React.Component {
|
|||
this.onEndMove = this.onEndMove.bind(this)
|
||||
this.onImgDone = this.onImgDone.bind(this)
|
||||
this.onSubmit = this.onSubmit.bind(this)
|
||||
this.handleSNTChange = this.handleSNTChange.bind(this)
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
|
@ -153,9 +162,29 @@ class Submit extends React.Component {
|
|||
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() {
|
||||
const {
|
||||
visible,
|
||||
dapps,
|
||||
visible_submit,
|
||||
visible_rating,
|
||||
onClickClose,
|
||||
name,
|
||||
desc,
|
||||
|
@ -166,161 +195,256 @@ class Submit extends React.Component {
|
|||
imgControlZoom,
|
||||
onImgCancel,
|
||||
onClickTerms,
|
||||
switchToRating,
|
||||
sntValue,
|
||||
} = this.props
|
||||
|
||||
const canSubmit =
|
||||
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 (
|
||||
<Modal
|
||||
visible={visible && window.location.hash === '#submit'}
|
||||
onClickClose={onClickClose}
|
||||
windowClassName={styles.modalWindow}
|
||||
contentClassName={imgControl ? styles.modalContentImgControl : ''}
|
||||
contentClassName={
|
||||
imgControl || visible_rating ? styles.modalContentFullScreen : ''
|
||||
}
|
||||
>
|
||||
<div className={styles.title}>
|
||||
{imgControl ? 'Position and size your image' : 'Submit a Ðapp'}
|
||||
</div>
|
||||
<div className={imgControl ? styles.cntWithImgControl : ''}>
|
||||
<div className={imgControl ? styles.withImgControl : ''}>
|
||||
<div className={styles.block}>
|
||||
<div className={styles.labelRow}>
|
||||
<span>Name of your Ðapp</span>
|
||||
</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})` }}
|
||||
/>
|
||||
<div className={styles.title}>{this.title()}</div>
|
||||
{visible_submit && (
|
||||
<div className={imgControl ? styles.cntWithImgControl : ''}>
|
||||
<div className={imgControl ? styles.withImgControl : ''}>
|
||||
<div className={styles.block}>
|
||||
<div className={styles.labelRow}>
|
||||
<span>Name of your Ðapp</span>
|
||||
</div>
|
||||
<input
|
||||
className={styles.uploader}
|
||||
type="file"
|
||||
onChange={this.onChangeImage}
|
||||
accept=".jpg, .png"
|
||||
className={styles.input}
|
||||
placeholder="Name"
|
||||
value={name}
|
||||
onChange={this.onInputName}
|
||||
/>
|
||||
</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 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
|
||||
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 className={styles.block}>
|
||||
<div className={styles.labelRow}>
|
||||
<span>Category</span>
|
||||
{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>
|
||||
<CategorySelector
|
||||
category={category === '' ? null : category}
|
||||
className={`${styles.categorySelector} ${
|
||||
category === '' ? styles.categorySelectorEmpty : ''
|
||||
}`}
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{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 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={this.onSubmit}
|
||||
>
|
||||
Continue
|
||||
<div className={styles.footer}>
|
||||
<p className={styles.disclaimer}>
|
||||
SNT you spend to rank your DApp is locked in the store. You can
|
||||
earn back through votes, or withdraw, the majority of this SNT
|
||||
at any time.
|
||||
</p>
|
||||
<button type="submit" onClick={this.onSubmit}>
|
||||
{!sntValue || sntValue === '0'
|
||||
? 'Publish'
|
||||
: 'Stake and Publish'}
|
||||
</button>
|
||||
</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>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Submit.propTypes = {
|
||||
visible: PropTypes.bool.isRequired,
|
||||
visible_submit: PropTypes.bool.isRequired,
|
||||
visible_rating: PropTypes.bool.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
desc: PropTypes.string.isRequired,
|
||||
url: PropTypes.string.isRequired,
|
||||
|
@ -331,6 +455,7 @@ Submit.propTypes = {
|
|||
imgControlMove: PropTypes.bool.isRequired,
|
||||
imgControlX: PropTypes.number.isRequired,
|
||||
imgControlY: PropTypes.number.isRequired,
|
||||
sntValue: PropTypes.string.isRequired,
|
||||
onClickClose: PropTypes.func.isRequired,
|
||||
onInputName: PropTypes.func.isRequired,
|
||||
onInputDesc: PropTypes.func.isRequired,
|
||||
|
@ -342,7 +467,9 @@ Submit.propTypes = {
|
|||
onImgCancel: PropTypes.func.isRequired,
|
||||
onImgDone: PropTypes.func.isRequired,
|
||||
onSubmit: PropTypes.func.isRequired,
|
||||
onInputSntValue: PropTypes.func.isRequired,
|
||||
onClickTerms: PropTypes.func.isRequired,
|
||||
switchToRating: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
export default Submit
|
||||
|
|
|
@ -13,14 +13,14 @@
|
|||
}
|
||||
}
|
||||
|
||||
.modalContentImgControl {
|
||||
.modalContentFullScreen {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
@media (min-width: $desktop) {
|
||||
.modalContentImgControl {
|
||||
.modalContentFullScreen {
|
||||
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,
|
||||
hideAction,
|
||||
} from '../TransactionStatus/TransactionStatus.recuder'
|
||||
import { TYPE_SUBMIT } from '../TransactionStatus/TransactionStatus.utilities'
|
||||
import { showAlertAction } from '../Alert/Alert.reducer'
|
||||
|
||||
// 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_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 = () => {
|
||||
window.location.hash = 'submit'
|
||||
return {
|
||||
|
@ -123,6 +127,7 @@ export const submitAction = dapp => {
|
|||
dapp.name,
|
||||
dapp.img,
|
||||
'Status is an open source mobile DApp browser and messenger build for #Etherium',
|
||||
TYPE_SUBMIT,
|
||||
),
|
||||
)
|
||||
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 => {
|
||||
return Object.assign({}, state, {
|
||||
visible: true,
|
||||
visible_submit: true,
|
||||
visible_rating: false,
|
||||
id: '',
|
||||
name: '',
|
||||
desc: '',
|
||||
|
@ -156,6 +172,7 @@ const showSubmitAfterCheck = state => {
|
|||
imgControlMove: false,
|
||||
imgControlX: 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 = {
|
||||
[SHOW_SUBMIT_AFTER_CHECK]: showSubmitAfterCheck,
|
||||
[CLOSE_SUBMIT]: closeSubmit,
|
||||
|
@ -246,6 +276,8 @@ const map = {
|
|||
[ON_IMG_MOVE]: onImgMove,
|
||||
[ON_IMG_CANCEL]: onImgCancel,
|
||||
[ON_IMG_DONE]: onImgDone,
|
||||
[SWITCH_TO_RATING]: switchToRating,
|
||||
[ON_INPUT_SNT_VALUE]: onInputSntValue,
|
||||
}
|
||||
|
||||
export default reducerUtil(map, submitInitialState)
|
||||
|
|
|
@ -3,6 +3,7 @@ import reducerUtil from '../../common/utils/reducer'
|
|||
import {
|
||||
transactionStatusFetchedInstance,
|
||||
transactionStatusInitInstance,
|
||||
TYPE_NONE,
|
||||
} from './TransactionStatus.utilities'
|
||||
import { onUpdateDappDataAction } from '../Dapps/Dapps.reducer'
|
||||
import { showAlertAction } from '../Alert/Alert.reducer'
|
||||
|
@ -46,9 +47,9 @@ export const hideAction = () => ({
|
|||
payload: null,
|
||||
})
|
||||
|
||||
export const onStartProgressAction = (dappName, dappImg, desc) => ({
|
||||
export const onStartProgressAction = (dappName, dappImg, desc, type) => ({
|
||||
type: ON_START_PROGRESS,
|
||||
payload: { dappName, dappImg, desc },
|
||||
payload: { dappName, dappImg, desc, type },
|
||||
})
|
||||
|
||||
export const onReceiveTransactionInfoAction = (id, tx) => ({
|
||||
|
@ -114,15 +115,17 @@ const hide = state => {
|
|||
const transacationStatus = transactionStatusFetchedInstance()
|
||||
transacationStatus.setDappName('')
|
||||
transacationStatus.setProgress(false)
|
||||
transacationStatus.setType(TYPE_NONE)
|
||||
return Object.assign({}, state, transacationStatus)
|
||||
}
|
||||
|
||||
const onStartProgress = (state, payload) => {
|
||||
const { dappName, dappImg, desc } = payload
|
||||
const { dappName, dappImg, desc, type } = payload
|
||||
const transacationStatus = transactionStatusInitInstance(
|
||||
dappName,
|
||||
dappImg,
|
||||
desc,
|
||||
type,
|
||||
)
|
||||
transacationStatus.persistTransactionData()
|
||||
return Object.assign({}, state, transacationStatus)
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
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 {
|
||||
constructor() {
|
||||
this.dappId = ''
|
||||
|
@ -7,6 +12,7 @@ class TransactionStatus {
|
|||
this.txDesc = ''
|
||||
this.dappName = ''
|
||||
this.dappImg = ''
|
||||
this.type = TYPE_NONE
|
||||
this.progress = false
|
||||
this.published = false
|
||||
this.failed = false
|
||||
|
@ -49,18 +55,24 @@ class TransactionStatus {
|
|||
this.failed = failed
|
||||
this.persistTransactionData()
|
||||
}
|
||||
|
||||
setType(type) {
|
||||
this.type = type
|
||||
this.persistTransactionData()
|
||||
}
|
||||
}
|
||||
|
||||
const getTransactionData = () => {
|
||||
return localStorage.getItem(COOKIE_NAME)
|
||||
}
|
||||
|
||||
export const transactionStatusInitInstance = (name, img, desc) => {
|
||||
export const transactionStatusInitInstance = (name, img, desc, type) => {
|
||||
const model = new TransactionStatus()
|
||||
model.dappName = name
|
||||
model.dappImg = img
|
||||
model.progress = true
|
||||
model.txDesc = desc
|
||||
model.type = type
|
||||
return model
|
||||
}
|
||||
|
||||
|
|
|
@ -174,7 +174,7 @@ class Vote extends Component {
|
|||
</div>
|
||||
</div>
|
||||
{!isUpvote && (
|
||||
<div className={styles.inputArea}>
|
||||
<div className={styles.inputArea} style={{ opacity: 0 }}>
|
||||
<span>{downvoteSNTcost}</span>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
@ -6,6 +6,10 @@ import {
|
|||
onReceiveTransactionInfoAction,
|
||||
checkTransactionStatusAction,
|
||||
} 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_DOWN_VOTE_AFTER_CHEECK = 'VOTE_SHOW_DOWN_VOTE_AFTER_CHEECK'
|
||||
|
@ -138,7 +142,12 @@ export const upVoteAction = (dapp, amount) => {
|
|||
return async dispatch => {
|
||||
dispatch(closeVoteAction())
|
||||
dispatch(
|
||||
onStartProgressAction(dapp.name, dapp.image, `↑ Upvote by ${amount} SNT`),
|
||||
onStartProgressAction(
|
||||
dapp.name,
|
||||
dapp.image,
|
||||
`↑ Upvote by ${amount} SNT`,
|
||||
TYPE_UPVOTE,
|
||||
),
|
||||
)
|
||||
try {
|
||||
const tx = await BlockchainSDK.DiscoverService.upVote(dapp.id, amount)
|
||||
|
@ -158,6 +167,7 @@ export const downVoteAction = (dapp, amount) => {
|
|||
dapp.name,
|
||||
dapp.image,
|
||||
`↓ Downvote by ${amount} SNT`,
|
||||
TYPE_DOWNVOTE,
|
||||
),
|
||||
)
|
||||
try {
|
||||
|
|
Loading…
Reference in New Issue