mirror of https://github.com/dap-ps/discover.git
Implement API integration logic
This commit is contained in:
parent
4805add080
commit
27358ed66b
|
@ -6,13 +6,14 @@
|
|||
"dependencies": {
|
||||
"@babel/runtime-corejs2": "^7.4.3",
|
||||
"@trailofbits/embark-contract-info": "^1.0.0",
|
||||
"axios": "^0.18.0",
|
||||
"bignumber.js": "^8.1.1",
|
||||
"bs58": "^4.0.1",
|
||||
"connected-react-router": "^6.3.2",
|
||||
"debounce": "^1.2.0",
|
||||
"decimal.js": "^10.0.2",
|
||||
"embark": "^4.0.2",
|
||||
"embark-solium": "0.0.1",
|
||||
"decimal.js": "^10.0.2",
|
||||
"history": "^4.7.2",
|
||||
"moment": "^2.24.0",
|
||||
"node-sass": "^4.11.0",
|
||||
|
|
|
@ -1,48 +1,46 @@
|
|||
/* global web3 */
|
||||
import utils from './utils'
|
||||
import EmbarkJS from '../../embarkArtifacts/embarkjs'
|
||||
import utils from './utils';
|
||||
import EmbarkJS from '../../embarkArtifacts/embarkjs';
|
||||
|
||||
import * as IPFSService from './ipfs'
|
||||
import SNTService from './services/contracts-services/snt-service/snt-service'
|
||||
import DiscoverService from './services/contracts-services/discover-service/discover-service'
|
||||
import SNTService from './services/snt-service/snt-service';
|
||||
import DiscoverService from './services/discover-service/discover-service';
|
||||
|
||||
const initServices = function() {
|
||||
const sharedContext = {
|
||||
account: '0x0000000000000000000000000000000000000000',
|
||||
}
|
||||
account: '0x0000000000000000000000000000000000000000'
|
||||
};
|
||||
|
||||
sharedContext.SNTService = new SNTService(sharedContext)
|
||||
sharedContext.DiscoverService = new DiscoverService(sharedContext)
|
||||
sharedContext.SNTService = new SNTService(sharedContext);
|
||||
sharedContext.DiscoverService = new DiscoverService(sharedContext);
|
||||
|
||||
return {
|
||||
IPFSService,
|
||||
SNTService: sharedContext.SNTService,
|
||||
DiscoverService: sharedContext.DiscoverService,
|
||||
utils,
|
||||
}
|
||||
}
|
||||
utils
|
||||
};
|
||||
};
|
||||
|
||||
const getInstance = async () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const returnInstance = () => {
|
||||
try {
|
||||
const services = initServices()
|
||||
resolve(services)
|
||||
const services = initServices();
|
||||
resolve(services);
|
||||
} catch (error) {
|
||||
reject(error.message)
|
||||
reject(error.message);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (web3.currentProvider) {
|
||||
returnInstance()
|
||||
returnInstance();
|
||||
} else {
|
||||
EmbarkJS.onReady(err => {
|
||||
if (err) reject(err)
|
||||
if (err) reject(err);
|
||||
|
||||
returnInstance()
|
||||
})
|
||||
returnInstance();
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export default { getInstance, utils }
|
||||
export default { getInstance, utils };
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
import bs58 from 'bs58'
|
||||
|
||||
export const base64ToBlob = base64Text => {
|
||||
const byteString = atob(base64Text.split(',')[1])
|
||||
|
||||
const arrayBuffer = new ArrayBuffer(byteString.length)
|
||||
const uintArray = new Uint8Array(arrayBuffer)
|
||||
for (let i = 0; i < byteString.length; i++) {
|
||||
uintArray[i] = byteString.charCodeAt(i)
|
||||
}
|
||||
|
||||
return new Blob([arrayBuffer])
|
||||
}
|
||||
|
||||
export const getBytes32FromIpfsHash = ipfsListing => {
|
||||
const decodedHash = bs58
|
||||
.decode(ipfsListing)
|
||||
.slice(2)
|
||||
.toString('hex')
|
||||
return `0x${decodedHash}`
|
||||
}
|
||||
|
||||
export const getIpfsHashFromBytes32 = bytes32Hex => {
|
||||
const hashHex = `1220${bytes32Hex.slice(2)}`
|
||||
const hashBytes = Buffer.from(hashHex, 'hex')
|
||||
const hashStr = bs58.encode(hashBytes)
|
||||
return hashStr
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
import * as helpers from './helpers'
|
||||
import EmbarkJS from '../../../embarkArtifacts/embarkjs'
|
||||
|
||||
const checkIPFSAvailability = async () => {
|
||||
const isAvailable = await EmbarkJS.Storage.isAvailable()
|
||||
if (!isAvailable) {
|
||||
throw new Error('IPFS Storage is unavailable')
|
||||
}
|
||||
}
|
||||
|
||||
const uploadImage = async base64Image => {
|
||||
const imageFile = [
|
||||
{
|
||||
files: [helpers.base64ToBlob(base64Image)],
|
||||
},
|
||||
]
|
||||
|
||||
return EmbarkJS.Storage.uploadFile(imageFile)
|
||||
}
|
||||
|
||||
const uploadMetadata = async metadata => {
|
||||
const hash = await EmbarkJS.Storage.saveText(metadata)
|
||||
return helpers.getBytes32FromIpfsHash(hash)
|
||||
}
|
||||
|
||||
export const uploadDAppMetadata = async metadata => {
|
||||
try {
|
||||
await checkIPFSAvailability()
|
||||
|
||||
metadata.image = await uploadImage(metadata.image)
|
||||
const uploadedMetadataHash = await uploadMetadata(JSON.stringify(metadata))
|
||||
|
||||
return uploadedMetadataHash
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`Uploading DApp metadata to IPFS failed. Details: ${error.message}`,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const retrieveMetadata = async metadataBytes32 => {
|
||||
const metadataHash = helpers.getIpfsHashFromBytes32(metadataBytes32)
|
||||
return EmbarkJS.Storage.get(metadataHash)
|
||||
}
|
||||
|
||||
const retrieveImageUrl = async imageHash => {
|
||||
return EmbarkJS.Storage.getUrl(imageHash)
|
||||
}
|
||||
|
||||
export const retrieveDAppMetadataByHash = async metadataBytes32 => {
|
||||
try {
|
||||
await checkIPFSAvailability()
|
||||
|
||||
const metadata = JSON.parse(await retrieveMetadata(metadataBytes32))
|
||||
metadata.image = await retrieveImageUrl(metadata.image)
|
||||
|
||||
return metadata
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`Fetching metadata from IPFS failed. Details: ${error.message}`,
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/* global web3 */
|
||||
|
||||
import EmbarkJS from '../../../embarkArtifacts/embarkjs';
|
||||
|
||||
class BlockchainService {
|
||||
constructor(sharedContext, contract, Validator) {
|
||||
this.contract = contract.address;
|
||||
|
||||
this.sharedContext = sharedContext;
|
||||
this.validator = new Validator(this);
|
||||
}
|
||||
|
||||
async getAccount() {
|
||||
try {
|
||||
if (web3 && EmbarkJS.Blockchain.Providers.web3) {
|
||||
const account = (await EmbarkJS.enableEthereum())[0];
|
||||
return (
|
||||
account || (await EmbarkJS.Blockchain.Providers.web3.getAccounts())[0]
|
||||
);
|
||||
}
|
||||
|
||||
return '0x0000000000000000000000000000000000000000';
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
'Could not unlock an account. Consider installing Status on your mobile or Metamask extension'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async __unlockServiceAccount() {
|
||||
this.sharedContext.account = await this.getAccount();
|
||||
|
||||
if (!this.sharedContext.account) {
|
||||
throw new Error('web3 is missing');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default BlockchainService;
|
|
@ -1,35 +0,0 @@
|
|||
/* global web3 */
|
||||
|
||||
import EmbarkJS from '../../../../embarkArtifacts/embarkjs'
|
||||
|
||||
const getAccount = async () => {
|
||||
try {
|
||||
const account = (await EmbarkJS.enableEthereum())[0]
|
||||
return (
|
||||
account || (await EmbarkJS.Blockchain.Providers.web3.getAccounts())[0]
|
||||
)
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
'Could not unlock an account. Consider installing Status on your mobile or Metamask extension',
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class BlockchainService {
|
||||
constructor(sharedContext, contract, Validator) {
|
||||
this.contract = contract.address
|
||||
|
||||
this.sharedContext = sharedContext
|
||||
this.validator = new Validator(this)
|
||||
}
|
||||
|
||||
async __unlockServiceAccount() {
|
||||
if (web3 && EmbarkJS.Blockchain.Providers.web3) {
|
||||
this.sharedContext.account = await getAccount()
|
||||
} else {
|
||||
throw new Error('web3 is missing')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default BlockchainService
|
|
@ -1,178 +0,0 @@
|
|||
/* global web3 */
|
||||
import { broadcastContractFn } from '../helpers'
|
||||
|
||||
import * as ipfsSDK from '../../../ipfs'
|
||||
import BlockchainService from '../blockchain-service'
|
||||
|
||||
import DiscoverValidator from './discover-validator'
|
||||
import DiscoverContract from '../../../../../embarkArtifacts/contracts/Discover'
|
||||
|
||||
class DiscoverService extends BlockchainService {
|
||||
constructor(sharedContext) {
|
||||
super(sharedContext, DiscoverContract, DiscoverValidator)
|
||||
}
|
||||
|
||||
// View methods
|
||||
async upVoteEffect(id, amount) {
|
||||
await this.validator.validateUpVoteEffect(id, amount)
|
||||
|
||||
return DiscoverContract.methods
|
||||
.upvoteEffect(id, amount)
|
||||
.call({ from: this.sharedContext.account })
|
||||
}
|
||||
|
||||
async downVoteCost(id) {
|
||||
const dapp = await this.getDAppById(id)
|
||||
return DiscoverContract.methods
|
||||
.downvoteCost(dapp.id)
|
||||
.call({ from: this.sharedContext.account })
|
||||
}
|
||||
|
||||
async getDAppsCount() {
|
||||
return DiscoverContract.methods
|
||||
.getDAppsCount()
|
||||
.call({ from: this.sharedContext.account })
|
||||
}
|
||||
|
||||
async getDApps() {
|
||||
const dapps = []
|
||||
const dappsCount = await this.getDAppsCount()
|
||||
|
||||
try {
|
||||
for (let i = 0; i < dappsCount; i++) {
|
||||
const dapp = await DiscoverContract.methods
|
||||
.dapps(i)
|
||||
.call({ from: this.sharedContext.account })
|
||||
|
||||
dapp.metadata = await ipfsSDK.retrieveDAppMetadataByHash(dapp.metadata)
|
||||
dapps.push(dapp)
|
||||
}
|
||||
return dapps
|
||||
} catch (error) {
|
||||
throw new Error(`Error fetching dapps. Details: ${error.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
async getDAppById(id) {
|
||||
let dapp
|
||||
try {
|
||||
const dappId = await DiscoverContract.methods
|
||||
.id2index(id)
|
||||
.call({ from: this.sharedContext.account })
|
||||
dapp = await DiscoverContract.methods
|
||||
.dapps(dappId)
|
||||
.call({ from: this.sharedContext.account })
|
||||
} catch (error) {
|
||||
throw new Error('Searching DApp does not exists')
|
||||
}
|
||||
|
||||
if (dapp.id != id) {
|
||||
throw new Error('Error fetching correct data from contract')
|
||||
}
|
||||
|
||||
return dapp
|
||||
}
|
||||
|
||||
async getDAppDataById(id) {
|
||||
const dapp = await this.getDAppById(id)
|
||||
|
||||
try {
|
||||
dapp.metadata = await ipfsSDK.retrieveDAppMetadataByHash(dapp.metadata)
|
||||
return dapp
|
||||
} catch (error) {
|
||||
throw new Error('Error fetching correct data from IPFS')
|
||||
}
|
||||
}
|
||||
|
||||
async safeMax() {
|
||||
return DiscoverContract.methods
|
||||
.safeMax()
|
||||
.call({ from: this.sharedContext.account })
|
||||
}
|
||||
|
||||
async isDAppExists(id) {
|
||||
return DiscoverContract.methods
|
||||
.existingIDs(id)
|
||||
.call({ from: this.sharedContext.account })
|
||||
}
|
||||
|
||||
// Transaction methods
|
||||
async createDApp(amount, metadata) {
|
||||
const dappMetadata = JSON.parse(JSON.stringify(metadata))
|
||||
const dappId = web3.utils.keccak256(JSON.stringify(dappMetadata))
|
||||
|
||||
await this.validator.validateDAppCreation(dappId, amount)
|
||||
|
||||
const uploadedMetadata = await ipfsSDK.uploadDAppMetadata(dappMetadata)
|
||||
|
||||
const callData = DiscoverContract.methods
|
||||
.createDApp(dappId, amount, uploadedMetadata)
|
||||
.encodeABI()
|
||||
|
||||
const createdTx = await this.sharedContext.SNTService.approveAndCall(
|
||||
this.contract,
|
||||
amount,
|
||||
callData,
|
||||
)
|
||||
|
||||
return { tx: createdTx, id: dappId }
|
||||
}
|
||||
|
||||
async upVote(id, amount) {
|
||||
await this.validator.validateUpVoting(id, amount)
|
||||
|
||||
const callData = DiscoverContract.methods.upvote(id, amount).encodeABI()
|
||||
return this.sharedContext.SNTService.approveAndCall(
|
||||
this.contract,
|
||||
amount,
|
||||
callData,
|
||||
)
|
||||
}
|
||||
|
||||
async downVote(id) {
|
||||
const dapp = await this.getDAppById(id)
|
||||
const amount = (await this.downVoteCost(dapp.id)).c
|
||||
|
||||
const callData = DiscoverContract.methods
|
||||
.downvote(dapp.id, amount)
|
||||
.encodeABI()
|
||||
return this.sharedContext.SNTService.approveAndCall(
|
||||
this.contract,
|
||||
amount,
|
||||
callData,
|
||||
)
|
||||
}
|
||||
|
||||
async withdraw(id, amount) {
|
||||
await super.__unlockServiceAccount()
|
||||
await this.validator.validateWithdrawing(id, amount)
|
||||
|
||||
try {
|
||||
return broadcastContractFn(
|
||||
DiscoverContract.methods.withdraw(id, amount).send,
|
||||
this.sharedContext.account,
|
||||
)
|
||||
} catch (error) {
|
||||
throw new Error(`Transfer on withdraw failed. Details: ${error.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
async setMetadata(id, metadata) {
|
||||
await super.__unlockServiceAccount()
|
||||
await this.validator.validateMetadataSet(id)
|
||||
|
||||
const dappMetadata = JSON.parse(JSON.stringify(metadata))
|
||||
const uploadedMetadata = await ipfsSDK.uploadDAppMetadata(dappMetadata)
|
||||
|
||||
try {
|
||||
return broadcastContractFn(
|
||||
DiscoverContract.methods.setMetadata(id, uploadedMetadata).send,
|
||||
this.sharedContext.account,
|
||||
)
|
||||
} catch (error) {
|
||||
throw new Error(`Uploading metadata failed. Details: ${error.message}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default DiscoverService
|
|
@ -0,0 +1,175 @@
|
|||
/* global web3 */
|
||||
import { broadcastContractFn } from '../helpers';
|
||||
import MetadataClient from '../../../clients/metadata-client';
|
||||
|
||||
import BlockchainService from '../blockchain-service';
|
||||
|
||||
import DiscoverValidator from './discover-validator';
|
||||
import DiscoverContract from '../../../../embarkArtifacts/contracts/Discover';
|
||||
|
||||
class DiscoverService extends BlockchainService {
|
||||
constructor(sharedContext) {
|
||||
super(sharedContext, DiscoverContract, DiscoverValidator);
|
||||
}
|
||||
|
||||
// View methods
|
||||
async upVoteEffect(id, amount) {
|
||||
await this.validator.validateUpVoteEffect(id, amount);
|
||||
|
||||
return DiscoverContract.methods
|
||||
.upvoteEffect(id, amount)
|
||||
.call({ from: this.sharedContext.account });
|
||||
}
|
||||
|
||||
async downVoteCost(id) {
|
||||
const dapp = await this.getDAppById(id);
|
||||
return DiscoverContract.methods
|
||||
.downvoteCost(dapp.id)
|
||||
.call({ from: this.sharedContext.account });
|
||||
}
|
||||
|
||||
async getDAppsCount() {
|
||||
return DiscoverContract.methods
|
||||
.getDAppsCount()
|
||||
.call({ from: this.sharedContext.account });
|
||||
}
|
||||
|
||||
async getDAppById(id) {
|
||||
let dapp;
|
||||
try {
|
||||
const dappId = await DiscoverContract.methods
|
||||
.id2index(id)
|
||||
.call({ from: this.sharedContext.account });
|
||||
|
||||
dapp = await DiscoverContract.methods
|
||||
.dapps(dappId)
|
||||
.call({ from: this.sharedContext.account });
|
||||
} catch (error) {
|
||||
throw new Error('Searching DApp does not exists');
|
||||
}
|
||||
|
||||
if (dapp.id != id) {
|
||||
throw new Error('Error fetching correct data from contract');
|
||||
}
|
||||
|
||||
return dapp;
|
||||
}
|
||||
|
||||
async getDAppDataById(id) {
|
||||
const dapp = await this.getDAppById(id);
|
||||
|
||||
try {
|
||||
const dappMetadata = await MetadataClient.retrieveMetadata(dapp.metadata);
|
||||
dapp.metadata = dappMetadata.details;
|
||||
dapp.metadata.status = dappMetadata.status;
|
||||
|
||||
return dapp;
|
||||
} catch (error) {
|
||||
throw new Error('Error fetching correct data');
|
||||
}
|
||||
}
|
||||
|
||||
async safeMax() {
|
||||
return DiscoverContract.methods
|
||||
.safeMax()
|
||||
.call({ from: this.sharedContext.account });
|
||||
}
|
||||
|
||||
async isDAppExists(id) {
|
||||
return DiscoverContract.methods
|
||||
.existingIDs(id)
|
||||
.call({ from: this.sharedContext.account });
|
||||
}
|
||||
|
||||
async checkIfCreatorOfDApp(id) {
|
||||
const dapp = this.getDAppById(id);
|
||||
this.sharedContext.account = await super.getAccount();
|
||||
|
||||
return dapp.developer == this.sharedContext.account;
|
||||
}
|
||||
|
||||
// Transaction methods
|
||||
async createDApp(amount, metadata) {
|
||||
await super.__unlockServiceAccount();
|
||||
|
||||
const dappMetadata = JSON.parse(JSON.stringify(metadata));
|
||||
dappMetadata.uploader = this.sharedContext.account;
|
||||
|
||||
const dappId = web3.utils.keccak256(JSON.stringify(dappMetadata));
|
||||
await this.validator.validateDAppCreation(dappId, amount);
|
||||
|
||||
const uploadedMetadata = await MetadataClient.upload(dappMetadata);
|
||||
|
||||
const callData = DiscoverContract.methods
|
||||
.createDApp(dappId, amount, uploadedMetadata)
|
||||
.encodeABI();
|
||||
|
||||
const createdTx = await this.sharedContext.SNTService.approveAndCall(
|
||||
this.contract,
|
||||
amount,
|
||||
callData
|
||||
);
|
||||
|
||||
return { tx: createdTx, id: dappId };
|
||||
}
|
||||
|
||||
async upVote(id, amount) {
|
||||
await this.validator.validateUpVoting(id, amount);
|
||||
|
||||
const callData = DiscoverContract.methods.upvote(id, amount).encodeABI();
|
||||
return this.sharedContext.SNTService.approveAndCall(
|
||||
this.contract,
|
||||
amount,
|
||||
callData
|
||||
);
|
||||
}
|
||||
|
||||
async downVote(id) {
|
||||
const dapp = await this.getDAppById(id);
|
||||
const amount = (await this.downVoteCost(dapp.id)).c;
|
||||
|
||||
const callData = DiscoverContract.methods
|
||||
.downvote(dapp.id, amount)
|
||||
.encodeABI();
|
||||
return this.sharedContext.SNTService.approveAndCall(
|
||||
this.contract,
|
||||
amount,
|
||||
callData
|
||||
);
|
||||
}
|
||||
|
||||
async withdraw(id, amount) {
|
||||
await super.__unlockServiceAccount();
|
||||
await this.validator.validateWithdrawing(id, amount);
|
||||
|
||||
try {
|
||||
return broadcastContractFn(
|
||||
DiscoverContract.methods.withdraw(id, amount).send,
|
||||
this.sharedContext.account
|
||||
);
|
||||
} catch (error) {
|
||||
throw new Error(`Transfer on withdraw failed. Details: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
async setMetadata(id, metadata) {
|
||||
await super.__unlockServiceAccount();
|
||||
await this.validator.validateMetadataSet(id);
|
||||
|
||||
const dappMetadata = JSON.parse(JSON.stringify(metadata));
|
||||
dappMetadata.uploader = this.sharedContext.account;
|
||||
|
||||
const uploadedMetadata = await MetadataClient.upload(dappMetadata);
|
||||
|
||||
try {
|
||||
return broadcastContractFn(
|
||||
DiscoverContract.methods.setMetadata(id, uploadedMetadata).send,
|
||||
this.sharedContext.account
|
||||
);
|
||||
} catch (error) {
|
||||
throw new Error(`Uploading metadata failed. Details: ${error.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default DiscoverService;
|
|
@ -1,67 +1,69 @@
|
|||
class DiscoverValidator {
|
||||
constructor(service) {
|
||||
this.service = service
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
async validateUpVoteEffect(id, amount) {
|
||||
const dapp = await this.service.getDAppById(id)
|
||||
const dapp = await this.service.getDAppById(id);
|
||||
|
||||
const safeMax = await this.service.safeMax()
|
||||
const safeMax = await this.service.safeMax();
|
||||
if (Number(dapp.balance) + amount > safeMax) {
|
||||
throw new Error(
|
||||
`You cannot upvote by this much, try with a lower amount. Maximum upvote amount:
|
||||
${Number(safeMax) - Number(dapp.balance)}`,
|
||||
)
|
||||
${Number(safeMax) - Number(dapp.balance)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async validateDAppCreation(id, amount) {
|
||||
const dappExists = await this.service.isDAppExists(id)
|
||||
const dappExists = await this.service.isDAppExists(id);
|
||||
if (dappExists) {
|
||||
throw new Error('You must submit a unique ID')
|
||||
throw new Error('You must submit a unique ID');
|
||||
}
|
||||
|
||||
if (amount <= 0) {
|
||||
throw new Error(
|
||||
'You must spend some SNT to submit a ranking in order to avoid spam',
|
||||
)
|
||||
'You must spend some SNT to submit a ranking in order to avoid spam'
|
||||
);
|
||||
}
|
||||
|
||||
const safeMax = await this.service.safeMax()
|
||||
const safeMax = await this.service.safeMax();
|
||||
if (amount > safeMax) {
|
||||
throw new Error('You cannot stake more SNT than the ceiling dictates')
|
||||
throw new Error('You cannot stake more SNT than the ceiling dictates');
|
||||
}
|
||||
}
|
||||
|
||||
async validateUpVoting(id, amount) {
|
||||
await this.validateUpVoteEffect(id, amount)
|
||||
await this.validateUpVoteEffect(id, amount);
|
||||
|
||||
if (amount <= 0) {
|
||||
throw new Error('You must send some SNT in order to upvote')
|
||||
throw new Error('You must send some SNT in order to upvote');
|
||||
}
|
||||
}
|
||||
|
||||
async validateWithdrawing(id, amount) {
|
||||
const dapp = await this.service.getDAppById(id)
|
||||
const dapp = await this.service.getDAppById(id);
|
||||
|
||||
if (dapp.developer.toLowerCase() != this.service.sharedContext.account) {
|
||||
throw new Error('Only the developer can withdraw SNT staked on this data')
|
||||
throw new Error(
|
||||
'Only the developer can withdraw SNT staked on this data'
|
||||
);
|
||||
}
|
||||
|
||||
if (amount > dapp.available) {
|
||||
throw new Error(
|
||||
'You can only withdraw a percentage of the SNT staked, less what you have already received',
|
||||
)
|
||||
'You can only withdraw a percentage of the SNT staked, less what you have already received'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async validateMetadataSet(id) {
|
||||
const dapp = await this.service.getDAppById(id)
|
||||
const dapp = await this.service.getDAppById(id);
|
||||
|
||||
if (dapp.developer.toLowerCase() != this.service.sharedContext.account) {
|
||||
throw new Error('Only the developer can update the metadata')
|
||||
throw new Error('Only the developer can update the metadata');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default DiscoverValidator
|
||||
export default DiscoverValidator;
|
|
@ -2,10 +2,10 @@ export const broadcastContractFn = (contractMethod, account) => {
|
|||
return new Promise((resolve, reject) => {
|
||||
contractMethod({ from: account })
|
||||
.on('transactionHash', hash => {
|
||||
resolve(hash)
|
||||
resolve(hash);
|
||||
})
|
||||
.on('error', error => {
|
||||
reject(error.message)
|
||||
})
|
||||
})
|
||||
}
|
||||
reject(error.message);
|
||||
});
|
||||
});
|
||||
};
|
|
@ -1,57 +1,57 @@
|
|||
import { broadcastContractFn } from '../helpers'
|
||||
import { broadcastContractFn } from '../helpers';
|
||||
|
||||
import BlockchainService from '../blockchain-service'
|
||||
import BlockchainService from '../blockchain-service';
|
||||
|
||||
import SNTValidator from './snt-validator'
|
||||
import SNTToken from '../../../../../embarkArtifacts/contracts/SNT'
|
||||
import SNTValidator from './snt-validator';
|
||||
import SNTToken from '../../../../embarkArtifacts/contracts/SNT';
|
||||
|
||||
class SNTService extends BlockchainService {
|
||||
constructor(sharedContext) {
|
||||
super(sharedContext, SNTToken, SNTValidator)
|
||||
super(sharedContext, SNTToken, SNTValidator);
|
||||
}
|
||||
|
||||
async allowance(from, to) {
|
||||
return SNTToken.methods
|
||||
.allowance(from, to)
|
||||
.call({ from: this.sharedContext.account })
|
||||
.call({ from: this.sharedContext.account });
|
||||
}
|
||||
|
||||
async balanceOf(account) {
|
||||
return SNTToken.methods
|
||||
.balanceOf(account)
|
||||
.call({ from: this.sharedContext.account })
|
||||
.call({ from: this.sharedContext.account });
|
||||
}
|
||||
|
||||
async controller() {
|
||||
return SNTToken.methods
|
||||
.controller()
|
||||
.call({ from: this.sharedContext.account })
|
||||
.call({ from: this.sharedContext.account });
|
||||
}
|
||||
|
||||
async transferable() {
|
||||
return SNTToken.methods
|
||||
.transfersEnabled()
|
||||
.call({ from: this.sharedContext.account })
|
||||
.call({ from: this.sharedContext.account });
|
||||
}
|
||||
|
||||
async approveAndCall(spender, amount, callData) {
|
||||
await super.__unlockServiceAccount()
|
||||
await this.validator.validateApproveAndCall(spender, amount)
|
||||
await super.__unlockServiceAccount();
|
||||
await this.validator.validateApproveAndCall(spender, amount);
|
||||
|
||||
return broadcastContractFn(
|
||||
SNTToken.methods.approveAndCall(spender, amount, callData).send,
|
||||
this.sharedContext.account,
|
||||
)
|
||||
this.sharedContext.account
|
||||
);
|
||||
}
|
||||
|
||||
// This is for testing purpose only
|
||||
async generateTokens() {
|
||||
await super.__unlockServiceAccount()
|
||||
await super.__unlockServiceAccount();
|
||||
|
||||
await SNTToken.methods
|
||||
.generateTokens(this.sharedContext.account, 10000)
|
||||
.send({ from: this.sharedContext.account })
|
||||
.send({ from: this.sharedContext.account });
|
||||
}
|
||||
}
|
||||
|
||||
export default SNTService
|
||||
export default SNTService;
|
|
@ -1,35 +1,35 @@
|
|||
class SNTValidator {
|
||||
constructor(service) {
|
||||
this.service = service
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
async validateSNTTransferFrom(amount) {
|
||||
const toBalance = await this.service.balanceOf(
|
||||
this.service.sharedContext.account,
|
||||
)
|
||||
this.service.sharedContext.account
|
||||
);
|
||||
|
||||
if (toBalance < amount) {
|
||||
throw new Error('Not enough SNT balance')
|
||||
throw new Error('Not enough SNT balance');
|
||||
}
|
||||
}
|
||||
|
||||
async validateApproveAndCall(spender, amount) {
|
||||
const isTransferableToken = await this.service.transferable()
|
||||
const isTransferableToken = await this.service.transferable();
|
||||
if (!isTransferableToken) {
|
||||
throw new Error('Token is not transferable')
|
||||
throw new Error('Token is not transferable');
|
||||
}
|
||||
|
||||
await this.validateSNTTransferFrom(amount)
|
||||
await this.validateSNTTransferFrom(amount);
|
||||
|
||||
const allowance = await this.service.allowance(
|
||||
this.service.sharedContext.account,
|
||||
spender,
|
||||
)
|
||||
spender
|
||||
);
|
||||
|
||||
if (amount != 0 && allowance != 0) {
|
||||
throw new Error('You have allowance already')
|
||||
throw new Error('You have allowance already');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default SNTValidator
|
||||
export default SNTValidator;
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"UPLOAD": "http://localhost:4000/metadata",
|
||||
"UPDATE": "http://localhost:4000/metadata/update",
|
||||
"RETRIEVE_METADATA": "http://localhost:4000/metadata",
|
||||
"RETRIEVE_ALL_METADATA": "http://localhost:4000/metadata/all"
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
const axios = require('axios');
|
||||
|
||||
const DEFAULT_HEADERS = {
|
||||
Accept: 'application/json',
|
||||
'Content-type': 'application/json'
|
||||
};
|
||||
|
||||
const executeRequest = async function(method, url, reqStruct) {
|
||||
return axios({
|
||||
method,
|
||||
url,
|
||||
data: {
|
||||
...reqStruct.body
|
||||
},
|
||||
headers: {
|
||||
...DEFAULT_HEADERS,
|
||||
...reqStruct.headers
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
class HTTPClient {
|
||||
static async postRequest(url, body, headers = '') {
|
||||
return executeRequest('POST', url, { body, headers });
|
||||
}
|
||||
|
||||
static async getRequest(url, headers = '') {
|
||||
return executeRequest('GET', url, { headers });
|
||||
}
|
||||
}
|
||||
|
||||
export default HTTPClient;
|
|
@ -0,0 +1,6 @@
|
|||
// If you want to use IPFSClient -> extend it
|
||||
import APIClient from './metadata-clients/api-client';
|
||||
|
||||
class MetadataClient extends APIClient {}
|
||||
|
||||
export default new MetadataClient();
|
|
@ -0,0 +1,45 @@
|
|||
import HTTPClient from '../http-client';
|
||||
|
||||
import * as helpers from '../../utils/metadata-utils';
|
||||
import metadataClientEndpoints from '../endpoints/metadata-client-endpoints';
|
||||
|
||||
class APIClient {
|
||||
async upload(metadata) {
|
||||
const uploadedDataResponse = await HTTPClient.postRequest(
|
||||
metadataClientEndpoints.UPLOAD,
|
||||
{ details: metadata }
|
||||
);
|
||||
|
||||
return helpers.getBytes32FromIpfsHash(uploadedDataResponse.data.hash);
|
||||
}
|
||||
|
||||
async retrieveMetadata(metadataBytes32) {
|
||||
const convertedHash = helpers.getIpfsHashFromBytes32(metadataBytes32);
|
||||
const retrievedMetadataResponse = await HTTPClient.getRequest(
|
||||
`${metadataClientEndpoints.RETRIEVE_METADATA}/${convertedHash}`
|
||||
);
|
||||
|
||||
return retrievedMetadataResponse.data;
|
||||
}
|
||||
|
||||
async retrieveAllDappsMetadata() {
|
||||
const retrievedDAppsMetadataResponse = await HTTPClient.getRequest(
|
||||
`${metadataClientEndpoints.RETRIEVE_ALL_METADATA}`
|
||||
);
|
||||
|
||||
const formatedDappsMetadata = {};
|
||||
const metadataHashes = Object.keys(retrievedDAppsMetadataResponse.data);
|
||||
for (let i = 0; i < metadataHashes.length; i++) {
|
||||
const convertedDappMetadataHash = helpers.getBytes32FromIpfsHash(
|
||||
metadataHashes[i]
|
||||
);
|
||||
|
||||
formatedDappsMetadata[convertedDappMetadataHash] =
|
||||
retrievedDAppsMetadataResponse.data[metadataHashes[i]];
|
||||
}
|
||||
|
||||
return formatedDappsMetadata;
|
||||
}
|
||||
}
|
||||
|
||||
export default APIClient;
|
|
@ -0,0 +1,69 @@
|
|||
import * as helpers from '../../utils/metadata-utils';
|
||||
import EmbarkJS from '../../../embarkArtifacts/embarkjs';
|
||||
|
||||
const checkIPFSAvailability = async () => {
|
||||
const isAvailable = await EmbarkJS.Storage.isAvailable();
|
||||
if (!isAvailable) {
|
||||
throw new Error('IPFS Storage is unavailable');
|
||||
}
|
||||
};
|
||||
|
||||
const uploadImage = async base64Image => {
|
||||
const imageFile = [
|
||||
{
|
||||
files: [helpers.base64ToBlob(base64Image)]
|
||||
}
|
||||
];
|
||||
|
||||
return EmbarkJS.Storage.uploadFile(imageFile);
|
||||
};
|
||||
|
||||
const uploadMetadata = async metadata => {
|
||||
const hash = await EmbarkJS.Storage.saveText(metadata);
|
||||
return helpers.getBytes32FromIpfsHash(hash);
|
||||
};
|
||||
|
||||
const retrieveMetadata = async metadataBytes32 => {
|
||||
const metadataHash = helpers.getIpfsHashFromBytes32(metadataBytes32);
|
||||
return EmbarkJS.Storage.get(metadataHash);
|
||||
};
|
||||
|
||||
const retrieveImageUrl = async imageHash => {
|
||||
return EmbarkJS.Storage.getUrl(imageHash);
|
||||
};
|
||||
|
||||
class IPFSClient {
|
||||
async upload(metadata) {
|
||||
try {
|
||||
await checkIPFSAvailability();
|
||||
|
||||
metadata.image = await uploadImage(metadata.image);
|
||||
const uploadedMetadataHash = await uploadMetadata(
|
||||
JSON.stringify(metadata)
|
||||
);
|
||||
|
||||
return uploadedMetadataHash;
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`Uploading DApp metadata to IPFS failed. Details: ${error.message}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async retrieveMetadata(metadataBytes32) {
|
||||
try {
|
||||
await checkIPFSAvailability();
|
||||
|
||||
const metadata = JSON.parse(await retrieveMetadata(metadataBytes32));
|
||||
metadata.image = await retrieveImageUrl(metadata.image);
|
||||
|
||||
return metadata;
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`Fetching metadata from IPFS failed. Details: ${error.message}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default IPFSClient;
|
|
@ -0,0 +1,28 @@
|
|||
import bs58 from 'bs58';
|
||||
|
||||
export const base64ToBlob = base64Text => {
|
||||
const byteString = atob(base64Text.split(',')[1]);
|
||||
|
||||
const arrayBuffer = new ArrayBuffer(byteString.length);
|
||||
const uintArray = new Uint8Array(arrayBuffer);
|
||||
for (let i = 0; i < byteString.length; i++) {
|
||||
uintArray[i] = byteString.charCodeAt(i);
|
||||
}
|
||||
|
||||
return new Blob([arrayBuffer]);
|
||||
};
|
||||
|
||||
export const getBytes32FromIpfsHash = ipfsListing => {
|
||||
const decodedHash = bs58
|
||||
.decode(ipfsListing)
|
||||
.slice(2)
|
||||
.toString('hex');
|
||||
return `0x${decodedHash}`;
|
||||
};
|
||||
|
||||
export const getIpfsHashFromBytes32 = bytes32Hex => {
|
||||
const hashHex = `1220${bytes32Hex.slice(2)}`;
|
||||
const hashBytes = Buffer.from(hashHex, 'hex');
|
||||
const hashStr = bs58.encode(hashBytes);
|
||||
return hashStr;
|
||||
};
|
|
@ -1,308 +1,308 @@
|
|||
// 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 BlockchainSDK from '../../common/blockchain'
|
||||
import { TYPE_SUBMIT } from '../TransactionStatus/TransactionStatus.utilities'
|
||||
import * as Categories from '../../common/data/categories';
|
||||
import reducerUtil from '../../common/utils/reducer';
|
||||
import { showAlertAction } from '../Alert/Alert.reducer';
|
||||
import BlockchainSDK from '../../common/blockchain';
|
||||
import { TYPE_SUBMIT } from '../TransactionStatus/TransactionStatus.utilities';
|
||||
|
||||
const ON_FINISH_FETCH_ALL_DAPPS_ACTION =
|
||||
'DAPPS_ON_FINISH_FETCH_ALL_DAPPS_ACTION'
|
||||
'DAPPS_ON_FINISH_FETCH_ALL_DAPPS_ACTION';
|
||||
|
||||
const ON_START_FETCH_HIGHEST_RANKED = 'DAPPS_ON_START_FETCH_HIGHEST_RANKED'
|
||||
const ON_FINISH_FETCH_HIGHEST_RANKED = 'DAPPS_ON_FINISH_FETCH_HIGHEST_RANKED'
|
||||
const ON_START_FETCH_RECENTLY_ADDED = 'DAPPS_ON_START_FETCH_RECENTLY_ADDED'
|
||||
const ON_FINISH_FETCH_RECENTLY_ADDED = 'DAPPS_ON_FINISH_FETCH_RECENTLY_ADDED'
|
||||
const ON_START_FETCH_HIGHEST_RANKED = 'DAPPS_ON_START_FETCH_HIGHEST_RANKED';
|
||||
const ON_FINISH_FETCH_HIGHEST_RANKED = 'DAPPS_ON_FINISH_FETCH_HIGHEST_RANKED';
|
||||
const ON_START_FETCH_RECENTLY_ADDED = 'DAPPS_ON_START_FETCH_RECENTLY_ADDED';
|
||||
const ON_FINISH_FETCH_RECENTLY_ADDED = 'DAPPS_ON_FINISH_FETCH_RECENTLY_ADDED';
|
||||
|
||||
const ON_START_FETCH_BY_CATEGORY = 'DAPPS_ON_START_FETCH_BY_CATEGORY'
|
||||
const ON_FINISH_FETCH_BY_CATEGORY = 'DAPPS_ON_FINISH_FETCH_BY_CATEGORY'
|
||||
const ON_START_FETCH_BY_CATEGORY = 'DAPPS_ON_START_FETCH_BY_CATEGORY';
|
||||
const ON_FINISH_FETCH_BY_CATEGORY = 'DAPPS_ON_FINISH_FETCH_BY_CATEGORY';
|
||||
|
||||
const ON_UPDATE_DAPP_DATA = 'DAPPS_ON_UPDATE_DAPP_DATA'
|
||||
const ON_UPDATE_DAPP_DATA = 'DAPPS_ON_UPDATE_DAPP_DATA';
|
||||
|
||||
const RECENTLY_ADDED_SIZE = 50
|
||||
const HIGHEST_RANKED_SIZE = 50
|
||||
const RECENTLY_ADDED_SIZE = 50;
|
||||
const HIGHEST_RANKED_SIZE = 50;
|
||||
|
||||
class DappsState {
|
||||
constructor() {
|
||||
this.items = []
|
||||
this.hasMore = true
|
||||
this.fetched = null
|
||||
this.items = [];
|
||||
this.hasMore = true;
|
||||
this.fetched = null;
|
||||
}
|
||||
|
||||
canFetch() {
|
||||
return this.hasMore && this.fetched !== true
|
||||
return this.hasMore && this.fetched !== true;
|
||||
}
|
||||
|
||||
setFetched(fetched) {
|
||||
this.fetched = fetched
|
||||
this.fetched = fetched;
|
||||
}
|
||||
|
||||
appendItems(items) {
|
||||
const availableNames = new Set()
|
||||
let addedItems = 0
|
||||
const availableNames = new Set();
|
||||
let addedItems = 0;
|
||||
for (let i = 0; i < this.items.length; i += 1)
|
||||
availableNames.add(this.items[i].name)
|
||||
availableNames.add(this.items[i].name);
|
||||
for (let i = 0; i < items.length; i += 1) {
|
||||
if (availableNames.has(items[i].name) === false) {
|
||||
addedItems += 1
|
||||
this.items.push(items[i])
|
||||
addedItems += 1;
|
||||
this.items.push(items[i]);
|
||||
}
|
||||
}
|
||||
|
||||
this.hasMore = addedItems !== 0
|
||||
this.hasMore = addedItems !== 0;
|
||||
}
|
||||
|
||||
cloneWeakItems() {
|
||||
this.items = [...this.items]
|
||||
return this
|
||||
this.items = [...this.items];
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
export const onFinishFetchAllDappsAction = dapps => ({
|
||||
type: ON_FINISH_FETCH_ALL_DAPPS_ACTION,
|
||||
payload: dapps,
|
||||
})
|
||||
payload: dapps
|
||||
});
|
||||
|
||||
export const onStartFetchHighestRankedAction = () => ({
|
||||
type: ON_START_FETCH_HIGHEST_RANKED,
|
||||
payload: null,
|
||||
})
|
||||
payload: null
|
||||
});
|
||||
|
||||
export const onFinishFetchHighestRankedAction = highestRanked => ({
|
||||
type: ON_FINISH_FETCH_HIGHEST_RANKED,
|
||||
payload: highestRanked,
|
||||
})
|
||||
payload: highestRanked
|
||||
});
|
||||
|
||||
export const onStartFetchRecentlyAddedAction = () => ({
|
||||
type: ON_START_FETCH_RECENTLY_ADDED,
|
||||
payload: null,
|
||||
})
|
||||
payload: null
|
||||
});
|
||||
|
||||
export const onFinishFetchRecentlyAddedAction = recentlyAdded => ({
|
||||
type: ON_FINISH_FETCH_RECENTLY_ADDED,
|
||||
payload: recentlyAdded,
|
||||
})
|
||||
payload: recentlyAdded
|
||||
});
|
||||
|
||||
export const onStartFetchByCategoryAction = category => ({
|
||||
type: ON_START_FETCH_BY_CATEGORY,
|
||||
payload: category,
|
||||
})
|
||||
payload: category
|
||||
});
|
||||
|
||||
export const onFinishFetchByCategoryAction = (category, dapps) => ({
|
||||
type: ON_FINISH_FETCH_BY_CATEGORY,
|
||||
payload: { category, dapps },
|
||||
})
|
||||
payload: { category, dapps }
|
||||
});
|
||||
|
||||
const fetchAllDappsInState = async (dispatch, getState) => {
|
||||
const state = getState()
|
||||
const { transactionStatus } = state
|
||||
const stateDapps = state.dapps
|
||||
const state = getState();
|
||||
const { transactionStatus } = state;
|
||||
const stateDapps = state.dapps;
|
||||
if (stateDapps.dapps === null) {
|
||||
try {
|
||||
const blockchain = await BlockchainSDK.getInstance()
|
||||
let dapps = await blockchain.DiscoverService.getDApps()
|
||||
const blockchain = await BlockchainSDK.getInstance();
|
||||
let dapps = await blockchain.DiscoverService.getDApps();
|
||||
dapps = dapps.map(dapp => {
|
||||
return Object.assign(dapp.metadata, {
|
||||
id: dapp.id,
|
||||
sntValue: parseInt(dapp.effectiveBalance, 10),
|
||||
})
|
||||
})
|
||||
sntValue: parseInt(dapp.effectiveBalance, 10)
|
||||
});
|
||||
});
|
||||
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
|
||||
dapps.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dispatch(onFinishFetchAllDappsAction(dapps))
|
||||
return dapps
|
||||
dispatch(onFinishFetchAllDappsAction(dapps));
|
||||
return dapps;
|
||||
} catch (e) {
|
||||
dispatch(showAlertAction(e.message))
|
||||
dispatch(onFinishFetchAllDappsAction([]))
|
||||
return []
|
||||
dispatch(showAlertAction(e.message));
|
||||
dispatch(onFinishFetchAllDappsAction([]));
|
||||
return [];
|
||||
}
|
||||
}
|
||||
return stateDapps.dapps
|
||||
}
|
||||
return stateDapps.dapps;
|
||||
};
|
||||
|
||||
export const fetchAllDappsAction = () => {
|
||||
return async (dispatch, getState) => {
|
||||
dispatch(onStartFetchHighestRankedAction())
|
||||
dispatch(onStartFetchRecentlyAddedAction())
|
||||
dispatch(onStartFetchHighestRankedAction());
|
||||
dispatch(onStartFetchRecentlyAddedAction());
|
||||
|
||||
const dapps = await fetchAllDappsInState(dispatch, getState)
|
||||
const dapps = await fetchAllDappsInState(dispatch, getState);
|
||||
|
||||
const highestRanked = dapps.slice(0, HIGHEST_RANKED_SIZE)
|
||||
let recentlyAdded = [...dapps]
|
||||
const highestRanked = dapps.slice(0, HIGHEST_RANKED_SIZE);
|
||||
let recentlyAdded = [...dapps];
|
||||
recentlyAdded.sort((a, b) => {
|
||||
return new Date().getTime(b.dateAdded) - new Date(a.dateAdded).getTime()
|
||||
})
|
||||
recentlyAdded = recentlyAdded.slice(0, RECENTLY_ADDED_SIZE)
|
||||
return new Date().getTime(b.dateAdded) - new Date(a.dateAdded).getTime();
|
||||
});
|
||||
recentlyAdded = recentlyAdded.slice(0, RECENTLY_ADDED_SIZE);
|
||||
|
||||
dispatch(onFinishFetchHighestRankedAction(highestRanked))
|
||||
dispatch(onFinishFetchRecentlyAddedAction(recentlyAdded))
|
||||
}
|
||||
}
|
||||
dispatch(onFinishFetchHighestRankedAction(highestRanked));
|
||||
dispatch(onFinishFetchRecentlyAddedAction(recentlyAdded));
|
||||
};
|
||||
};
|
||||
|
||||
export const fetchByCategoryAction = category => {
|
||||
return async (dispatch, getState) => {
|
||||
dispatch(onStartFetchByCategoryAction(category))
|
||||
dispatch(onStartFetchByCategoryAction(category));
|
||||
|
||||
const dapps = await fetchAllDappsInState(dispatch, getState)
|
||||
const filteredByCategory = dapps.filter(dapp => dapp.category === category)
|
||||
const dappsCategoryState = getState().dapps.dappsCategoryMap.get(category)
|
||||
const from = dappsCategoryState.items.length
|
||||
const to = Math.min(from + 5, filteredByCategory.length)
|
||||
const dappsCategorySlice = filteredByCategory.slice(from, to)
|
||||
const dapps = await fetchAllDappsInState(dispatch, getState);
|
||||
const filteredByCategory = dapps.filter(dapp => dapp.category === category);
|
||||
const dappsCategoryState = getState().dapps.dappsCategoryMap.get(category);
|
||||
const from = dappsCategoryState.items.length;
|
||||
const to = Math.min(from + 5, filteredByCategory.length);
|
||||
const dappsCategorySlice = filteredByCategory.slice(from, to);
|
||||
|
||||
dispatch(onFinishFetchByCategoryAction(category, dappsCategorySlice))
|
||||
}
|
||||
}
|
||||
dispatch(onFinishFetchByCategoryAction(category, dappsCategorySlice));
|
||||
};
|
||||
};
|
||||
|
||||
export const onUpdateDappDataAction = dapp => ({
|
||||
type: ON_UPDATE_DAPP_DATA,
|
||||
payload: dapp,
|
||||
})
|
||||
payload: dapp
|
||||
});
|
||||
|
||||
const onFinishFetchAllDapps = (state, dapps) => {
|
||||
return Object.assign({}, state, { dapps })
|
||||
}
|
||||
return Object.assign({}, state, { dapps });
|
||||
};
|
||||
|
||||
const onStartFetchHightestRanked = state => {
|
||||
return Object.assign({}, state, {
|
||||
highestRankedFetched: false,
|
||||
})
|
||||
}
|
||||
highestRankedFetched: false
|
||||
});
|
||||
};
|
||||
|
||||
const onFinishFetchHighestRanked = (state, payload) => {
|
||||
return Object.assign({}, state, {
|
||||
highestRanked: payload,
|
||||
highestRankedFetched: true,
|
||||
})
|
||||
}
|
||||
highestRankedFetched: true
|
||||
});
|
||||
};
|
||||
|
||||
const onStartFetchRecentlyAdded = state => {
|
||||
return Object.assign({}, state, {
|
||||
recentlyAddedFetched: false,
|
||||
})
|
||||
}
|
||||
recentlyAddedFetched: false
|
||||
});
|
||||
};
|
||||
|
||||
const onFinishFetchRecentlyAdded = (state, payload) => {
|
||||
return Object.assign({}, state, {
|
||||
recentlyAdded: payload,
|
||||
recentlyAddedFetched: true,
|
||||
})
|
||||
}
|
||||
recentlyAddedFetched: true
|
||||
});
|
||||
};
|
||||
|
||||
const onStartFetchByCategory = (state, payload) => {
|
||||
const dappsCategoryMap = new Map()
|
||||
const dappsCategoryMap = new Map();
|
||||
state.dappsCategoryMap.forEach((dappState, category) => {
|
||||
dappsCategoryMap.set(category, dappState.cloneWeakItems())
|
||||
if (category === payload) dappState.setFetched(true)
|
||||
})
|
||||
dappsCategoryMap.set(category, dappState.cloneWeakItems());
|
||||
if (category === payload) dappState.setFetched(true);
|
||||
});
|
||||
return Object.assign({}, state, {
|
||||
dappsCategoryMap,
|
||||
})
|
||||
}
|
||||
dappsCategoryMap
|
||||
});
|
||||
};
|
||||
|
||||
const onFinishFetchByCategory = (state, payload) => {
|
||||
const { category, dapps } = payload
|
||||
const { category, dapps } = payload;
|
||||
|
||||
const dappsCategoryMap = new Map()
|
||||
const dappsCategoryMap = new Map();
|
||||
state.dappsCategoryMap.forEach((dappState, category_) => {
|
||||
dappsCategoryMap.set(category_, dappState)
|
||||
dappsCategoryMap.set(category_, dappState);
|
||||
if (category_ === category) {
|
||||
dappState.setFetched(false)
|
||||
dappState.appendItems(dapps)
|
||||
dappState.setFetched(false);
|
||||
dappState.appendItems(dapps);
|
||||
}
|
||||
})
|
||||
});
|
||||
return Object.assign({}, state, {
|
||||
dappsCategoryMap,
|
||||
})
|
||||
}
|
||||
dappsCategoryMap
|
||||
});
|
||||
};
|
||||
|
||||
const insertDappIntoSortedArray = (source, dapp, cmp) => {
|
||||
for (let i = 0; i < source.length; i += 1) {
|
||||
if (cmp(source[i], dapp) === true) {
|
||||
source.splice(i, 0, dapp)
|
||||
break
|
||||
source.splice(i, 0, dapp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onUpdateDappData = (state, dapp) => {
|
||||
const dappsCategoryMap = new Map()
|
||||
const { dapps } = state
|
||||
let { highestRanked, recentlyAdded } = state
|
||||
let update = false
|
||||
const dappsCategoryMap = new Map();
|
||||
const { dapps } = state;
|
||||
let { highestRanked, recentlyAdded } = state;
|
||||
let update = false;
|
||||
|
||||
state.dappsCategoryMap.forEach((dappState, category_) => {
|
||||
dappsCategoryMap.set(category_, dappState.cloneWeakItems())
|
||||
})
|
||||
dappsCategoryMap.set(category_, dappState.cloneWeakItems());
|
||||
});
|
||||
|
||||
for (let i = 0; i < dapps.length; i += 1) {
|
||||
if (dapps[i].id === dapp.id) {
|
||||
dapps[i] = dapp
|
||||
update = true
|
||||
break
|
||||
dapps[i] = dapp;
|
||||
update = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (update === false) {
|
||||
insertDappIntoSortedArray(dapps, dapp, (target, dappItem) => {
|
||||
return target.sntValue < dappItem.sntValue
|
||||
})
|
||||
return target.sntValue < dappItem.sntValue;
|
||||
});
|
||||
insertDappIntoSortedArray(highestRanked, dapp, (target, dappItem) => {
|
||||
return target.sntValue < dappItem.sntValue
|
||||
})
|
||||
highestRanked = state.highestRanked.splice(0, HIGHEST_RANKED_SIZE)
|
||||
return target.sntValue < dappItem.sntValue;
|
||||
});
|
||||
highestRanked = state.highestRanked.splice(0, HIGHEST_RANKED_SIZE);
|
||||
insertDappIntoSortedArray(recentlyAdded, dapp, (target, dappItem) => {
|
||||
return (
|
||||
new Date().getTime(target.dateAdded) <
|
||||
new Date(dappItem.dateAdded).getTime()
|
||||
)
|
||||
})
|
||||
recentlyAdded = recentlyAdded.splice(0, RECENTLY_ADDED_SIZE)
|
||||
);
|
||||
});
|
||||
recentlyAdded = recentlyAdded.splice(0, RECENTLY_ADDED_SIZE);
|
||||
|
||||
const dappState = dappsCategoryMap.get(dapp.category)
|
||||
const dappState = dappsCategoryMap.get(dapp.category);
|
||||
insertDappIntoSortedArray(dappState.items, dapp, (target, dappItem) => {
|
||||
return target.sntValue < dappItem.sntValue
|
||||
})
|
||||
return target.sntValue < dappItem.sntValue;
|
||||
});
|
||||
} else {
|
||||
for (let i = 0; i < highestRanked.length; i += 1) {
|
||||
if (highestRanked[i].id === dapp.id) {
|
||||
highestRanked[i] = dapp
|
||||
break
|
||||
highestRanked[i] = dapp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < recentlyAdded.length; i += 1) {
|
||||
if (recentlyAdded[i].id === dapp.id) {
|
||||
recentlyAdded[i] = dapp
|
||||
break
|
||||
recentlyAdded[i] = dapp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
dappsCategoryMap.forEach(dappState => {
|
||||
const dappStateRef = dappState
|
||||
const dappStateRef = dappState;
|
||||
for (let i = 0; i < dappStateRef.items.length; i += 1) {
|
||||
if (dappStateRef.items[i].id === dapp.id) {
|
||||
dappStateRef.items[i] = dapp
|
||||
break
|
||||
dappStateRef.items[i] = dapp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
return Object.assign({}, state, {
|
||||
dapps: [...dapps],
|
||||
highestRanked: [...highestRanked],
|
||||
recentlyAdded: [...recentlyAdded],
|
||||
dappsCategoryMap,
|
||||
})
|
||||
}
|
||||
dappsCategoryMap
|
||||
});
|
||||
};
|
||||
|
||||
const map = {
|
||||
[ON_FINISH_FETCH_ALL_DAPPS_ACTION]: onFinishFetchAllDapps,
|
||||
|
@ -312,17 +312,17 @@ const map = {
|
|||
[ON_FINISH_FETCH_RECENTLY_ADDED]: onFinishFetchRecentlyAdded,
|
||||
[ON_START_FETCH_BY_CATEGORY]: onStartFetchByCategory,
|
||||
[ON_FINISH_FETCH_BY_CATEGORY]: onFinishFetchByCategory,
|
||||
[ON_UPDATE_DAPP_DATA]: onUpdateDappData,
|
||||
}
|
||||
[ON_UPDATE_DAPP_DATA]: onUpdateDappData
|
||||
};
|
||||
|
||||
const dappsCategoryMap = new Map()
|
||||
dappsCategoryMap.set(Categories.EXCHANGES, new DappsState())
|
||||
dappsCategoryMap.set(Categories.MARKETPLACES, new DappsState())
|
||||
dappsCategoryMap.set(Categories.COLLECTIBLES, new DappsState())
|
||||
dappsCategoryMap.set(Categories.GAMES, new DappsState())
|
||||
dappsCategoryMap.set(Categories.SOCIAL_NETWORKS, new DappsState())
|
||||
dappsCategoryMap.set(Categories.UTILITIES, new DappsState())
|
||||
dappsCategoryMap.set(Categories.OTHER, new DappsState())
|
||||
const dappsCategoryMap = new Map();
|
||||
dappsCategoryMap.set(Categories.EXCHANGES, new DappsState());
|
||||
dappsCategoryMap.set(Categories.MARKETPLACES, new DappsState());
|
||||
dappsCategoryMap.set(Categories.COLLECTIBLES, new DappsState());
|
||||
dappsCategoryMap.set(Categories.GAMES, new DappsState());
|
||||
dappsCategoryMap.set(Categories.SOCIAL_NETWORKS, new DappsState());
|
||||
dappsCategoryMap.set(Categories.UTILITIES, new DappsState());
|
||||
dappsCategoryMap.set(Categories.OTHER, new DappsState());
|
||||
|
||||
const dappsInitialState = {
|
||||
dapps: null,
|
||||
|
@ -330,7 +330,7 @@ const dappsInitialState = {
|
|||
highestRankedFetched: null,
|
||||
recentlyAdded: [],
|
||||
recentlyAddedFetched: null,
|
||||
dappsCategoryMap,
|
||||
}
|
||||
dappsCategoryMap
|
||||
};
|
||||
|
||||
export default reducerUtil(map, dappsInitialState)
|
||||
export default reducerUtil(map, dappsInitialState);
|
||||
|
|
|
@ -1,149 +1,150 @@
|
|||
import submitInitialState from '../../common/data/submit'
|
||||
import reducerUtil from '../../common/utils/reducer'
|
||||
import submitInitialState from '../../common/data/submit';
|
||||
import reducerUtil from '../../common/utils/reducer';
|
||||
import {
|
||||
onReceiveTransactionInfoAction,
|
||||
checkTransactionStatusAction,
|
||||
onStartProgressAction,
|
||||
hideAction,
|
||||
} from '../TransactionStatus/TransactionStatus.recuder'
|
||||
import { TYPE_SUBMIT } from '../TransactionStatus/TransactionStatus.utilities'
|
||||
import { showAlertAction } from '../Alert/Alert.reducer'
|
||||
hideAction
|
||||
} from '../TransactionStatus/TransactionStatus.recuder';
|
||||
import { TYPE_SUBMIT } from '../TransactionStatus/TransactionStatus.utilities';
|
||||
import { showAlertAction } from '../Alert/Alert.reducer';
|
||||
|
||||
import BlockchainSDK from '../../common/blockchain'
|
||||
import BlockchainSDK from '../../common/blockchain';
|
||||
|
||||
const SHOW_SUBMIT_AFTER_CHECK = 'SUBMIT_SHOW_SUBMIT_AFTER_CHECK'
|
||||
const CLOSE_SUBMIT = 'SUBMIT_CLOSE_SUBMIT'
|
||||
const ON_INPUT_NAME = 'SUBMIT_ON_INPUT_NAME'
|
||||
const ON_INPUT_DESC = 'SUBMIT_ON_INPUT_DESC'
|
||||
const ON_INPUT_URL = 'SUBMIT_ON_INPUT_URL'
|
||||
const ON_SELECT_CATEGORY = 'SUBMIT_ON_SELECT_CATEGORY'
|
||||
const ON_IMG_READ = 'SUBMIT_ON_IMG_READ'
|
||||
const ON_IMG_ZOOM = 'SUBMIT_ON_IMG_ZOOM'
|
||||
const ON_IMG_MOVE_CONTROL = 'SUBMIT_ON_IMG_MOVE_CONTROL'
|
||||
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 SHOW_SUBMIT_AFTER_CHECK = 'SUBMIT_SHOW_SUBMIT_AFTER_CHECK';
|
||||
const CLOSE_SUBMIT = 'SUBMIT_CLOSE_SUBMIT';
|
||||
const ON_INPUT_NAME = 'SUBMIT_ON_INPUT_NAME';
|
||||
const ON_INPUT_DESC = 'SUBMIT_ON_INPUT_DESC';
|
||||
const ON_INPUT_URL = 'SUBMIT_ON_INPUT_URL';
|
||||
const ON_SELECT_CATEGORY = 'SUBMIT_ON_SELECT_CATEGORY';
|
||||
const ON_IMG_READ = 'SUBMIT_ON_IMG_READ';
|
||||
const ON_IMG_ZOOM = 'SUBMIT_ON_IMG_ZOOM';
|
||||
const ON_IMG_MOVE_CONTROL = 'SUBMIT_ON_IMG_MOVE_CONTROL';
|
||||
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'
|
||||
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'
|
||||
window.location.hash = 'submit';
|
||||
return {
|
||||
type: SHOW_SUBMIT_AFTER_CHECK,
|
||||
payload: null,
|
||||
}
|
||||
}
|
||||
payload: null
|
||||
};
|
||||
};
|
||||
|
||||
export const showSubmitAction = () => {
|
||||
return (dispatch, getState) => {
|
||||
const state = getState()
|
||||
const state = getState();
|
||||
if (state.transactionStatus.progress) {
|
||||
dispatch(
|
||||
showAlertAction(
|
||||
'There is an active transaction. Please wait for it to finish and then you could be able to create your Ðapp',
|
||||
),
|
||||
)
|
||||
} else dispatch(showSubmitActionAfterCheck())
|
||||
}
|
||||
}
|
||||
'There is an active transaction. Please wait for it to finish and then you could be able to create your Ðapp'
|
||||
)
|
||||
);
|
||||
} else dispatch(showSubmitActionAfterCheck());
|
||||
};
|
||||
};
|
||||
|
||||
export const closeSubmitAction = () => {
|
||||
window.history.back()
|
||||
window.history.back();
|
||||
return {
|
||||
type: CLOSE_SUBMIT,
|
||||
payload: null,
|
||||
}
|
||||
}
|
||||
payload: null
|
||||
};
|
||||
};
|
||||
|
||||
export const onInputNameAction = name => ({
|
||||
type: ON_INPUT_NAME,
|
||||
payload: name,
|
||||
})
|
||||
payload: name
|
||||
});
|
||||
|
||||
export const onInputDescAction = desc => ({
|
||||
type: ON_INPUT_DESC,
|
||||
payload: desc.substring(0, 140),
|
||||
})
|
||||
payload: desc.substring(0, 140)
|
||||
});
|
||||
|
||||
export const onInputUrlAction = url => ({
|
||||
type: ON_INPUT_URL,
|
||||
payload: url,
|
||||
})
|
||||
payload: url
|
||||
});
|
||||
|
||||
export const onSelectCategoryAction = category => ({
|
||||
type: ON_SELECT_CATEGORY,
|
||||
payload: category,
|
||||
})
|
||||
payload: category
|
||||
});
|
||||
|
||||
export const onImgReadAction = imgBase64 => ({
|
||||
type: ON_IMG_READ,
|
||||
payload: imgBase64,
|
||||
})
|
||||
payload: imgBase64
|
||||
});
|
||||
|
||||
export const onImgZoomAction = zoom => ({
|
||||
type: ON_IMG_ZOOM,
|
||||
payload: zoom,
|
||||
})
|
||||
payload: zoom
|
||||
});
|
||||
|
||||
export const onImgMoveControlAction = move => ({
|
||||
type: ON_IMG_MOVE_CONTROL,
|
||||
payload: move,
|
||||
})
|
||||
payload: move
|
||||
});
|
||||
|
||||
export const onImgMoveAction = (x, y) => ({
|
||||
type: ON_IMG_MOVE,
|
||||
payload: { x, y },
|
||||
})
|
||||
payload: { x, y }
|
||||
});
|
||||
|
||||
export const onImgCancelAction = () => ({
|
||||
type: ON_IMG_CANCEL,
|
||||
payload: null,
|
||||
})
|
||||
payload: null
|
||||
});
|
||||
|
||||
export const onImgDoneAction = imgBase64 => ({
|
||||
type: ON_IMG_DONE,
|
||||
payload: imgBase64,
|
||||
})
|
||||
payload: imgBase64
|
||||
});
|
||||
|
||||
export const submitAction = (dapp, sntValue) => {
|
||||
return async dispatch => {
|
||||
dispatch(closeSubmitAction())
|
||||
dispatch(closeSubmitAction());
|
||||
dispatch(
|
||||
onStartProgressAction(
|
||||
dapp.name,
|
||||
dapp.img,
|
||||
'Status is an open source mobile DApp browser and messenger build for #Etherium',
|
||||
TYPE_SUBMIT,
|
||||
),
|
||||
)
|
||||
TYPE_SUBMIT
|
||||
)
|
||||
);
|
||||
try {
|
||||
const blockchain = await BlockchainSDK.getInstance()
|
||||
const blockchain = await BlockchainSDK.getInstance();
|
||||
const { tx, id } = await blockchain.DiscoverService.createDApp(sntValue, {
|
||||
name: dapp.name,
|
||||
url: dapp.url,
|
||||
desc: dapp.desc,
|
||||
description: dapp.desc,
|
||||
category: dapp.category,
|
||||
image: dapp.img,
|
||||
})
|
||||
dispatch(onReceiveTransactionInfoAction(id, tx))
|
||||
dispatch(checkTransactionStatusAction(tx))
|
||||
dateAdded: Date.now()
|
||||
});
|
||||
dispatch(onReceiveTransactionInfoAction(id, tx));
|
||||
dispatch(checkTransactionStatusAction(tx));
|
||||
} catch (e) {
|
||||
dispatch(hideAction())
|
||||
dispatch(showAlertAction(e.message))
|
||||
dispatch(hideAction());
|
||||
dispatch(showAlertAction(e.message));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export const switchToRatingAction = () => ({
|
||||
type: SWITCH_TO_RATING,
|
||||
paylaod: null,
|
||||
})
|
||||
paylaod: null
|
||||
});
|
||||
|
||||
export const onInputSntValueAction = sntValue => ({
|
||||
type: ON_INPUT_SNT_VALUE,
|
||||
payload: sntValue,
|
||||
})
|
||||
payload: sntValue
|
||||
});
|
||||
|
||||
const showSubmitAfterCheck = state => {
|
||||
return Object.assign({}, state, {
|
||||
|
@ -160,39 +161,39 @@ const showSubmitAfterCheck = state => {
|
|||
imgControlMove: false,
|
||||
imgControlX: 0,
|
||||
imgControlY: 0,
|
||||
sntValue: '0',
|
||||
})
|
||||
}
|
||||
sntValue: '0'
|
||||
});
|
||||
};
|
||||
|
||||
const closeSubmit = state => {
|
||||
return Object.assign({}, state, {
|
||||
visible: false,
|
||||
})
|
||||
}
|
||||
visible: false
|
||||
});
|
||||
};
|
||||
|
||||
const onInputName = (state, name) => {
|
||||
return Object.assign({}, state, {
|
||||
name,
|
||||
})
|
||||
}
|
||||
name
|
||||
});
|
||||
};
|
||||
|
||||
const onInputDesc = (state, desc) => {
|
||||
return Object.assign({}, state, {
|
||||
desc,
|
||||
})
|
||||
}
|
||||
desc
|
||||
});
|
||||
};
|
||||
|
||||
const onInputUrl = (state, url) => {
|
||||
return Object.assign({}, state, {
|
||||
url,
|
||||
})
|
||||
}
|
||||
url
|
||||
});
|
||||
};
|
||||
|
||||
const onSelectCategory = (state, category) => {
|
||||
return Object.assign({}, state, {
|
||||
category,
|
||||
})
|
||||
}
|
||||
category
|
||||
});
|
||||
};
|
||||
|
||||
const onImgRead = (state, imgBase64) => {
|
||||
return Object.assign({}, state, {
|
||||
|
@ -201,55 +202,55 @@ const onImgRead = (state, imgBase64) => {
|
|||
imgControlZoom: 0,
|
||||
imgControlMove: false,
|
||||
imgControlX: 0,
|
||||
imgControlY: 0,
|
||||
})
|
||||
}
|
||||
imgControlY: 0
|
||||
});
|
||||
};
|
||||
|
||||
const onImgZoom = (state, zoom) => {
|
||||
return Object.assign({}, state, {
|
||||
imgControlZoom: zoom,
|
||||
})
|
||||
}
|
||||
imgControlZoom: zoom
|
||||
});
|
||||
};
|
||||
|
||||
const onImgMoveControl = (state, move) => {
|
||||
return Object.assign({}, state, {
|
||||
imgControlMove: move,
|
||||
})
|
||||
}
|
||||
imgControlMove: move
|
||||
});
|
||||
};
|
||||
|
||||
const onImgMove = (state, payload) => {
|
||||
return Object.assign({}, state, {
|
||||
imgControlX: payload.x,
|
||||
imgControlY: payload.y,
|
||||
})
|
||||
}
|
||||
imgControlY: payload.y
|
||||
});
|
||||
};
|
||||
|
||||
const onImgCancel = state => {
|
||||
return Object.assign({}, state, {
|
||||
img: '',
|
||||
imgControl: false,
|
||||
})
|
||||
}
|
||||
imgControl: false
|
||||
});
|
||||
};
|
||||
|
||||
const onImgDone = (state, imgBase64) => {
|
||||
return Object.assign({}, state, {
|
||||
img: imgBase64,
|
||||
imgControl: false,
|
||||
})
|
||||
}
|
||||
imgControl: false
|
||||
});
|
||||
};
|
||||
|
||||
const switchToRating = state => {
|
||||
return Object.assign({}, state, {
|
||||
visible_submit: false,
|
||||
visible_rating: true,
|
||||
})
|
||||
}
|
||||
visible_rating: true
|
||||
});
|
||||
};
|
||||
|
||||
const onInputSntValue = (state, sntValue) => {
|
||||
return Object.assign({}, state, {
|
||||
sntValue,
|
||||
})
|
||||
}
|
||||
sntValue
|
||||
});
|
||||
};
|
||||
|
||||
const map = {
|
||||
[SHOW_SUBMIT_AFTER_CHECK]: showSubmitAfterCheck,
|
||||
|
@ -265,7 +266,7 @@ const map = {
|
|||
[ON_IMG_CANCEL]: onImgCancel,
|
||||
[ON_IMG_DONE]: onImgDone,
|
||||
[SWITCH_TO_RATING]: switchToRating,
|
||||
[ON_INPUT_SNT_VALUE]: onInputSntValue,
|
||||
}
|
||||
[ON_INPUT_SNT_VALUE]: onInputSntValue
|
||||
};
|
||||
|
||||
export default reducerUtil(map, submitInitialState)
|
||||
export default reducerUtil(map, submitInitialState);
|
||||
|
|
Loading…
Reference in New Issue