From d550a15e9088ca7d03306b172a5cb580eb395dcf Mon Sep 17 00:00:00 2001 From: jakogri Date: Tue, 4 Jun 2024 05:15:30 +0300 Subject: [PATCH] =?UTF-8?q?16.05.2024=20=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=BB=20=D0=BF=D1=80=D0=BE=D0=B3=D1=80=D0=B0=D0=BC=D0=BC?= =?UTF-8?q?=D1=83=20=D0=B2=20=D1=81=D0=BE=D0=BE=D1=82=D0=B2=D0=B5=D1=82?= =?UTF-8?q?=D1=81=D1=82=D0=B2=D0=B8=D0=B8=20=D1=81=20=D1=82=D0=B5=D0=BC,?= =?UTF-8?q?=20=D1=87=D1=82=D0=BE=20=D0=B1=D0=BE=D0=BB=D1=8C=D1=88=D0=B5=20?= =?UTF-8?q?=D0=BD=D0=B5=D1=82=20=D0=B7=D0=B0=D0=B4=E2=80=A6=20(#177)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 16.05.2024 изменил программу в соответствии с тем, что больше нет задеплоиных компаний, а только кошельки компаний. * 17.05.2024 исправил модуль CampaignPage. Теперь программа после отсылки донатов выходит в основной список. * 24.05.2024 внёс исправление в функцию handleLoadOneCampaign. Убрал из условий отбора компании поле deleted. * 27.05.2024 Внёс изменения во внешний вид.Добавил внизу строчку пробела. Исправил ошибку с неправильным показом количества всего собранных компанией донатов, как в общем списке так и в форме показа отдельной компании. * 28.05.2024 изменил файл package.json, чтобы можно было запускать и под Windows, и под Linux. --- package.json | 4 + server/server.js | 4 + server/serverLib.js | 143 +++++++-- src/components/App.js | 2 - src/components/CampaignList.js | 9 +- src/components/CampaignPage.js | 249 +++++++--------- src/components/CreateCampaign.js | 305 +++++++++---------- src/components/EditCampaign.js | 489 ++++++++++++++----------------- src/components/TRC20.js | 3 + src/components/TextEditor.js | 5 + src/components/UserCampaigns.js | 3 - src/lang/translationEN.json | 11 +- src/lang/translationRU.json | 11 +- src/util/Utilities.js | 14 +- 14 files changed, 630 insertions(+), 622 deletions(-) create mode 100644 src/components/TRC20.js diff --git a/package.json b/package.json index 4ca4dd4..9558709 100644 --- a/package.json +++ b/package.json @@ -74,11 +74,15 @@ "typescript": "^3.9.9" }, "scripts": { + "start-react-windows": "set NODE_OPTIONS=--openssl-legacy-provider && react-scripts start", "start-react": "export NODE_OPTIONS=--openssl-legacy-provider && react-scripts start", + "start-windows": "set NODE_OPTIONS=--openssl-legacy-provider && cd server && node server.js", "start": "export NODE_OPTIONS=--openssl-legacy-provider && cd server && node server.js", "postinstall": "npm config set legacy-peer-deps true && cd server && npm --loglevel=error install", "install-all": "npm config set legacy-peer-deps true && npm --loglevel=error install && cd server && npm --loglevel=error install", + "build-windows": "set NODE_OPTIONS=--openssl-legacy-provider && react-scripts build && mv build/index.html build/_index.html", "build": "export NODE_OPTIONS=--openssl-legacy-provider && react-scripts build && mv build/index.html build/_index.html", + "test-windows": "set NODE_OPTIONS=--openssl-legacy-provider && react-scripts test", "test": "export NODE_OPTIONS=--openssl-legacy-provider && react-scripts test", "eject": "react-scripts eject" }, diff --git a/server/server.js b/server/server.js index ee96d6d..729328e 100644 --- a/server/server.js +++ b/server/server.js @@ -195,6 +195,10 @@ APP.post('/api/donate/adddanate', async (req, res) => { } }); +APP.post('/api/campaign/updateWallet', async (req, res) => { + const DB = CLIENT.db(DBNAME); + serverLib.handleUpdateCampaignWallet(req, res, Sentry, DB); +}); APP.post('/api/campaign/update', (req, res) => { if(serverLib.authenticated(req, res, Sentry)) { diff --git a/server/serverLib.js b/server/serverLib.js index ee4a80d..96f23b1 100644 --- a/server/serverLib.js +++ b/server/serverLib.js @@ -29,6 +29,7 @@ class ServerLib { this.emailCode.set(req.body.mydata.to_email, randCode); return(text); } catch (err) { + console.log(err); Sentry.captureException(new Error(err)); res.sendStatus(500); } @@ -62,6 +63,7 @@ class ServerLib { await myCollection.insertOne(ITEM); res.send('success'); } catch (err) { + console.log(err); Sentry.captureException(new Error(err)); res.sendStatus(500); } @@ -74,6 +76,7 @@ class ServerLib { await myCollection.updateOne({'_id': req.body.mydata.to_email}, {$set: {password:password}}); res.send('success'); } catch (err) { + console.log(err); Sentry.captureException(new Error(err)); res.sendStatus(500); } @@ -142,6 +145,7 @@ class ServerLib { res.send('success'); }).catch(console.error); } catch (err) { + console.log(err); Sentry.captureException(new Error(err)); res.sendStatus(500); } @@ -152,19 +156,22 @@ class ServerLib { campaignID: req.body.mydata.campaignID.toLowerCase(), donatorID: req.body.mydata.donatorID.toLowerCase(), raisedAmount: req.body.mydata.raisedAmount, + tipAmount: req.body.mydata.tipAmount, transactionHash: req.body.mydata.transactionHash, chainId: req.body.mydata.chainId, coinAddress: req.body.mydata.coinAddress, + blockChainOrt: req.body.mydata.blockChainOrt, donateDate: Date.now(), deleted: false, checked: false } - try { const myCollection = await DB.collection('donations'); await myCollection.insertOne(ITEM); + await this.handleUpdateCampaignWallet(req, res, Sentry, DB); res.send('success'); } catch (err) { + console.log(err); Sentry.captureException(new Error(err)); res.sendStatus(500); } @@ -195,15 +202,15 @@ class ServerLib { raisedAmount: 0, creationDate: Date.now(), lastDonationTime: 0, - coins: req.body.mydata.coins, - addresses: req.body.mydata.addresses, - accounts: req.body.mydata.accounts, active: false, email: req.body.mydata.email, countryCode: req.body.mydata.countryCode, number: req.body.mydata.number, telegram: req.body.mydata.telegram, website: req.body.mydata.website, + payout_address: req.body.mydata.payout_address, + payout_chain: req.body.mydata.payout_chain, + complete:req.body.mydata.complete, new: true } try { @@ -211,6 +218,7 @@ class ServerLib { await myCollection.insertOne(ITEM); return true } catch (err) { + console.log(err); Sentry.captureException(new Error(err)); return false; } @@ -234,6 +242,7 @@ class ServerLib { await myCollection.updateOne({'_id': req.body.mydata.address}, {$set: req.body.mydata.dataToUpdate}); res.send('success'); } catch (err) { + console.log(err); Sentry.captureException(new Error(err)); res.sendStatus(500); } @@ -252,6 +261,7 @@ class ServerLib { await myCollection.updateOne({'_id': req.body.id}, {$set: {deleted:true}}); res.send('success'); } catch (err) { + console.log(err); Sentry.captureException(new Error(err)); res.sendStatus(500); } @@ -260,16 +270,23 @@ class ServerLib { async handleLoadFinishedCampaigns(req, res, Sentry, DB) { try{ - let pipeline = [ - { $match: {successful: true, deleted:{ $exists : false}}}, - {$sort: {raisedAmount: -1, raisedOnCoinbase: -1, _id: 1}}, - { $skip : req.body.startRec}, - { $limit:req.body.compaignsCount} + {$lookup: {from :"campaign_wallet", localField: "_id", foreignField: "campaign_id", as : "wallet"}}, + {$match: {successful: true, + $or:[{deleted:{ $exists : false}}, {deleted:false}],"wallet":{ $ne : []},"active":true, complete:true}}, + {$set: {wallet: {$arrayElemAt: ["$wallet.addres_base58",0]},donate_count:{$arrayElemAt: ["$wallet.donate_count",0]}}}, + {$sort: {donate_count: -1, raisedOnCoinbase: -1, _id: 1}}, + {$skip : req.body.startRec}, + { $limit:req.body.compaignsCount} ]; + let pipeline1 = [ + { $lookup: {from :"campaign_wallet", localField: "_id", foreignField: "campaign_id", as : "wallet"}}, + { $match: {successful:true, + $or:[{deleted:{ $exists : false}}, {deleted:false}],"wallet":{ $ne : []},"active":true, complete:true}} + ]; let curArr = await DB.collection('campaigns').aggregate(pipeline).toArray(); - let arCount = await DB.collection('campaigns').count({successful: true, deleted:{ $exists : false }}); - let result = {curArr:curArr, arCount:arCount}; + let curArr1 = await DB.collection('campaigns').aggregate(pipeline1).toArray(); + let result = {curArr:curArr, arCount:curArr1.length}; res.send(result); } catch (err) { console.log(err); @@ -281,16 +298,25 @@ class ServerLib { async handleLoadAllCampaigns(req, res, Sentry, DB) { try{ let pipeline = [ - { $match: {active: true, deleted:{ $exists : false}}}, - {$sort: {lastDonationTime: -1, raisedAmount: -1, raisedOnCoinbase: -1, _id: 1}}, + {$lookup: {from :"campaign_wallet", localField: "_id", foreignField: "campaign_id", as : "wallet"}}, + {$match: {$or:[{successful:false },{successful:{$exists : false}}], + $or:[{deleted:{ $exists : false}}, {deleted:false}],"wallet":{ $ne : []},"active":true, complete:true}}, + {$set: {wallet: {$arrayElemAt: ["$wallet.addres_base58",0]},donate_count:{$sum:{$arrayElemAt: ["$wallet.donate_count",0]}}}}, + {$sort: {donate_count: -1, raisedOnCoinbase: -1, _id: 1}}, { $skip : req.body.startRec}, { $limit: req.body.compaignsCount} ]; + let pipeline1 = [ + { $lookup: {from :"campaign_wallet", localField: "_id", foreignField: "campaign_id", as : "wallet"}}, + { $match: {$or:[{successful:false },{successful:{$exists : false}}], + $or:[{deleted:{ $exists : false}}, {deleted:false}],"wallet":{ $ne : []},"active":true, complete:true}} + ]; let curArr = await DB.collection('campaigns').aggregate(pipeline).toArray(); - let arCount = await DB.collection('campaigns').count({active: true, deleted:{ $exists : false }}); - let result = {curArr:curArr, arCount:arCount}; + let curArr1 = await DB.collection('campaigns').aggregate(pipeline1).toArray(); + let result = {curArr:curArr, arCount:curArr1.length}; res.send(result); } catch (err) { + console.log(err); Sentry.captureException(new Error(err)); res.sendStatus(500); } @@ -310,6 +336,7 @@ class ServerLib { res.send(result); } } catch (err) { + console.log(err); Sentry.captureException(new Error(err)); res.send("error"); } @@ -324,6 +351,7 @@ class ServerLib { let result = await DB.collection('donations').aggregate(pipeline).toArray(); res.send(result); } catch (err) { + console.log(err); Sentry.captureException(new Error(err)); res.sendn("error"); } @@ -335,7 +363,11 @@ class ServerLib { let result = await myCollection.findOne({"key" : req.body.KEY, "deleted":{ $exists : false }}); if (result) res.send(result._id) else res.send(req.body.KEY); - } catch (err) {Sentry.captureException(new Error(err));} + } catch (err) { + console.log(err); + Sentry.captureException(new Error(err)); + res.sendStatus(500); + } } async handlecheckKey(req, res, Sentry, DB) { @@ -344,7 +376,11 @@ class ServerLib { let result = await myCollection.findOne({"key" : req.body.KEY, "deleted":{ $exists : false }}); if (result) res.send(true) else res.send(false); - } catch (err) {Sentry.captureException(new Error(err));} + } catch (err) { + console.log(err); + Sentry.captureException(new Error(err)); + res.sendStatus(500); + } } async handleGetCoinsList(req, res, Sentry, DB) { @@ -353,7 +389,11 @@ class ServerLib { let coins = await myCollection.find();//aggregate([{$group:{ _id : "$chain", coins:{$push: "$coin"}}}]); const result = await coins.toArray(); res.send(result); - } catch (err) {Sentry.captureException(new Error(err));} + } catch (err) { + console.log(err); + Sentry.captureException(new Error(err)); + res.sendStatus(500); + } } async handleGetTipForHeo(req, res, Sentry, DB) { @@ -365,6 +405,7 @@ class ServerLib { } catch (err) { console.log(err); Sentry.captureException(new Error(err)); + res.sendStatus(500); } } @@ -374,15 +415,54 @@ class ServerLib { let chains = await myCollection.distinct("chain"); const result = await chains.toArray(); res.send(result._id); - } catch (err) {Sentry.captureException(new Error(err));} + } catch (err) { + console.log(err); + Sentry.captureException(new Error(err)); + res.sendStatus(500); + } + } + + async handleUpdateCampaignWallet(req, res, Sentry, DB) { + try { + const myCollection = await DB.collection('campaign_wallet'); + await myCollection.updateOne({'campaign_id': req.body.mydata.campaignID, 'wallet_ort': req.body.mydata.blockChainOrt}, + {$inc: {"donate_count":req.body.mydata.raisedAmount, "heo_donate":req.body.mydata.tipAmount}}); + return true; + } catch (err) { + console.log(err); + Sentry.captureException(new Error(err)); + res.sendStatus(500); + } } async handleLoadOneCampaign(req, res, Sentry, DB) { try { const myCollection = await DB.collection('campaigns'); - let result = await myCollection.findOne({"_id" : req.body.ID, "deleted":{ $exists : false }}); + const walletColection = await DB.collection('campaign_wallet'); + let result = await myCollection.findOne({"_id" : req.body.ID }); + let donate = await DB.collection('donations').find({campaignID: req.body.ID}).toArray(); + let campaign_wallets = await walletColection.find({"campaign_id" : req.body.ID}). + project({_id:0,wallet_ort:1,addres_base58:1,addres_hex:1,coin_name:1}).toArray(); + for(let i=0; i - diff --git a/src/components/CampaignList.js b/src/components/CampaignList.js index 9106818..e271300 100644 --- a/src/components/CampaignList.js +++ b/src/components/CampaignList.js @@ -148,11 +148,11 @@ class CampaignList extends Component { campaigns.forEach( campaign => { const found = donates.find(element => element._id === campaign._id); let totalQuantity = found ? found.totalQuantity : 0; - let raisedAmount = campaign.raisedAmount ? parseFloat(campaign.raisedAmount) : 0; + let raisedAmount = campaign.raisedAmount? parseFloat(campaign.raisedAmount) : 0; let fiatDonations = campaign.fiatDonations ? parseFloat(campaign.fiatDonations) : 0; let raisedOnCoinbase = campaign.raisedOnCoinbase ? parseFloat(campaign.raisedOnCoinbase) : 0; if(raisedAmount || fiatDonations || raisedOnCoinbase || totalQuantity) { - campaign["raisedAmount"] = Math.round((raisedAmount + fiatDonations + raisedOnCoinbase + totalQuantity) * 100)/100; + campaign.donate_count = Math.round((raisedAmount + fiatDonations + raisedOnCoinbase + totalQuantity) * 100)/100; } //dedupe coin names for "accepting" section let dedupedCoinNames = []; @@ -203,8 +203,8 @@ class CampaignList extends Component { {`${DescriptionPreview(item.description, i18n.language)}...`}     

- ${item.raisedAmount}{i18n.t('raised')}${item.maxAmount} {i18n.t('goal')}

- + ${item.donate_count}{i18n.t('raised')}${item.maxAmount} {i18n.t('goal')}

+ @@ -262,6 +262,7 @@ class CampaignList extends Component { } + ); diff --git a/src/components/CampaignPage.js b/src/components/CampaignPage.js index 8f45a58..ac064f6 100644 --- a/src/components/CampaignPage.js +++ b/src/components/CampaignPage.js @@ -7,6 +7,7 @@ import ReactTextCollapse from 'react-text-collapse'; import ReactPlayer from 'react-player'; import { Link } from "react-router-dom"; import { Trans } from 'react-i18next'; +import tron_abi from './TRC20'; import { i18nString, initWeb3, @@ -21,7 +22,6 @@ import { Editor, EditorState, convertFromRaw, CompositeDecorator } from "draft-j import '../css/campaignPage.css'; import '../css/modal.css'; import ReactGA from "react-ga4"; -import web3 from 'web3'; import bnbIcon from '../images/binance-coin-bnb-logo.png'; import busdIcon from '../images/binance-usd-busd-logo.png'; import usdcIcon from '../images/usd-coin-usdc-logo.png'; @@ -40,7 +40,8 @@ const IMG_MAP = {"BUSD": busdIcon, "USDC": usdcIcon, "USDT": usdtLogo, "ETH": ethIcon, - "cUSD": cusdIcon}; + "cUSD": cusdIcon, +}; const PAYMENT_ERROR_MESSAGES = { declined: "cardPaymentDeclined", @@ -83,6 +84,9 @@ class CampaignPage extends Component { modalButtonMessage: "", modalButtonVariant: "", chainId:"", + campaign_wallets:[], + chain_addres:"", + token_addres:"", chains:[], chains_coins:[], coins:[], @@ -92,30 +96,34 @@ class CampaignPage extends Component { fiatPaymentEnabled: false, fiatPaymentProvider: '', recurringFiatPayments: false, - cur_chain: -1 + cur_chain: -1, + tipForHeo: 0 }; this.handleGetCCInfo = this.handleGetCCInfo.bind(this); this.handleCCInfoCancel = this.handleCCInfoCancel.bind(this); - + this.blockChainOrt = ""; } + async handleGetCCInfo(info) { - await this.setState({ccinfo : info}); + this.setState({ccinfo : info}); this.handleDonateFiat(); - } + handleCCInfoCancel() { this.setState({showCCinfoModal : false}); } handleDonationAmount = (e) => { let donationAmount = parseInt(e.target.value); - let tipAmount = parseInt(this.state.tipAmount); + let tipAmount = Math.max(1, parseInt(parseInt(donationAmount)/100 * this.state.tipForHeo));; this.setState({tipAmount: tipAmount, donationAmount: donationAmount, totalAmount: (donationAmount + tipAmount)}); }; + handleTipAmount = (e) => { let tipAmount = parseInt(e.target.value); this.setState({tipAmount: tipAmount, totalAmount: (tipAmount + parseInt(this.state.donationAmount))}); }; + handleRecurringAmount = (e) => { this.setState({recurringAmount: e.target.value}); }; @@ -129,7 +137,7 @@ class CampaignPage extends Component { } this.setState({cur_chain: -1}); return(-1); - } + }; async getCampaign(address) { var campaign = {}; @@ -153,37 +161,6 @@ class CampaignPage extends Component { return campaign; } - updateRaisedAmount = async () => { - var modalMessage; - let data = {campaignID: this.state.campaignId}; - var donateAmount; - await axios.post('/api/campaign/getalldonations', {mydata: data}, {headers: {"Content-Type": "application/json"}}) - .then(res => { - donateAmount = (res.data === 0 || res.data.length === 0) ? 0 : parseFloat(res.data[0].totalQuantity); - }).catch(err => { - if (err.response) { - modalMessage = 'technicalDifficulties'} - else if(err.request) { - modalMessage = 'checkYourConnection' - } - console.log(err); - this.setState({ - showError: true, - modalMessage: modalMessage, - }) - }) - if(!donateAmount) { - donateAmount = 0; - } - let baseAmount = this.state.campaign.raisedAmount ? parseFloat(this.state.campaign.raisedAmount) : 0; - let fiatDonations = this.state.campaign.fiatDonations ? parseFloat(this.state.campaign.fiatDonations) : 0; - let raisedOnCoinbase = this.state.campaign.raisedOnCoinbase ? parseFloat(this.state.campaign.raisedOnCoinbase) : 0; - if(baseAmount || fiatDonations || raisedOnCoinbase || donateAmount) { - let raisedAmount = Math.round((baseAmount + fiatDonations + raisedOnCoinbase + donateAmount) * 100)/100; - this.setState({raisedAmount : raisedAmount}); - } - } - handleDonateCoinbaseCommerce = async () => { let data = { amount: this.state.totalAmount, @@ -206,7 +183,7 @@ class CampaignPage extends Component { window.open(resp.data.redirectUrl, '_self'); } else { this.setState({ - showModal: true, modalTitle: 'failed', + showModal: true, modalTitle: 'failed', goHome: false, errorIcon: 'XCircle', modalButtonMessage: 'closeBtn', modalMessage: "failedConnectCoinbaseCommerce", modalButtonVariant: '#E63C36', waitToClose: false, tryAgainCC: false @@ -215,7 +192,7 @@ class CampaignPage extends Component { } catch (err) { console.log(err); this.setState({ - showModal: true, modalTitle: 'failed', + showModal: true, modalTitle: 'failed', goHome: false, errorIcon: 'XCircle', modalButtonMessage: 'closeBtn', modalMessage: err.response.data, modalButtonVariant: '#E63C36', waitToClose: false, tryAgainCC: false @@ -239,7 +216,7 @@ class CampaignPage extends Component { try { this.setState({ showCCWarningModal:false, - showModal: true, modalTitle: 'processingWait', + showModal: true, modalTitle: 'processingWait', goHome: false, modalMessage: "plzWait", errorIcon: 'HourglassSplit', modalButtonVariant: "gold", waitToClose: true }); @@ -249,7 +226,7 @@ class CampaignPage extends Component { window.open(resp.data.redirectUrl, '_self'); } else if(resp.data.paymentStatus === "success") { this.setState({ - showModal: true, modalTitle: 'complete', + showModal: true, modalTitle: 'complete', goHome: true, modalMessage: 'thankYouFiatDonation', errorIcon: 'CheckCircle', modalButtonMessage: 'closeBtn', modalButtonVariant: '#588157', waitToClose: false, tryAgainCC: false, ccinfo: {} @@ -257,7 +234,7 @@ class CampaignPage extends Component { } else { this.setState({ showModal: true, modalTitle: 'failed', modalMessage: PAYMENT_ERROR_MESSAGES[resp.data.paymentStatus], - errorIcon: 'XCircle', modalButtonMessage: 'tryAgain', + errorIcon: 'XCircle', modalButtonMessage: 'tryAgain', goHome: false, modalButtonVariant: '#E63C36', waitToClose: false, tryAgainCC: false }); this.setState(prevState => ({ @@ -270,7 +247,7 @@ class CampaignPage extends Component { } catch (err) { if (err.response.status === 503) { this.setState({ - showModal: true, modalTitle: 'failed', + showModal: true, modalTitle: 'failed', goHome: false, errorIcon: 'XCircle', modalButtonMessage: 'closeBtn', modalMessage: err.response.data, modalButtonVariant: '#E63C36', waitToClose: false, tryAgainCC: false @@ -279,7 +256,7 @@ class CampaignPage extends Component { } console.log(err.response) this.setState({ - showModal: true, modalTitle: 'failed', + showModal: true, modalTitle: 'failed', goHome: false, errorIcon: 'XCircle', modalButtonMessage: 'tryAgain', modalButtonVariant: '#E63C36', waitToClose: false, tryAgainCC: (this.state.fiatPaymentProvider !== 'stripe') }); @@ -300,7 +277,7 @@ class CampaignPage extends Component { } try { this.setState({ - showCCWarningModal:false, + showCCWarningModal:false, goHome: false, showModal: true, modalTitle: 'processingWait', modalMessage: "plzWait", errorIcon: 'HourglassSplit', modalButtonVariant: "gold", waitToClose: true @@ -311,7 +288,7 @@ class CampaignPage extends Component { window.open(resp.data.redirectUrl, '_self'); } else if(resp.data.paymentStatus === "success") { this.setState({ - showModal: true, modalTitle: 'complete', + showModal: true, modalTitle: 'complete', goHome: true, modalMessage: 'thankYouFiatDonation', errorIcon: 'CheckCircle', modalButtonMessage: 'closeBtn', modalButtonVariant: '#588157', waitToClose: false, tryAgainCC: false, ccinfo: {} @@ -319,7 +296,7 @@ class CampaignPage extends Component { } else { this.setState({ showModal: true, modalTitle: 'failed', modalMessage: PAYMENT_ERROR_MESSAGES[resp.data.paymentStatus], - errorIcon: 'XCircle', modalButtonMessage: 'tryAgain', + errorIcon: 'XCircle', modalButtonMessage: 'tryAgain', goHome: false, modalButtonVariant: '#E63C36', waitToClose: false, tryAgainCC: false }); this.setState(prevState => ({ @@ -332,7 +309,7 @@ class CampaignPage extends Component { } catch (err) { if (err.response.status === 503) { this.setState({ - showModal: true, modalTitle: 'failed', + showModal: true, modalTitle: 'failed', goHome: false, errorIcon: 'XCircle', modalButtonMessage: 'closeBtn', modalMessage: err.response.data, modalButtonVariant: '#E63C36', waitToClose: false, tryAgainCC: false @@ -341,7 +318,7 @@ class CampaignPage extends Component { } console.log(err.response) this.setState({ - showModal: true, modalTitle: 'failed', + showModal: true, modalTitle: 'failed', goHome: false, errorIcon: 'XCircle', modalButtonMessage: 'tryAgain', }) } @@ -351,35 +328,29 @@ class CampaignPage extends Component { this.setState({showCoinbaseModal: true}); } - saveDonateToDb = async (value, decimals, transactionHash, chainId, coinAddress) => { + saveDonateToDb = async (transactionHash, chainId, coinAddress) => { let accounts = this.state.accounts; - if (window.blockChainOrt === "ethereum"){ - if(decimals === 18) { - value = parseFloat(web3.utils.fromWei(value)); - } else { - value = parseFloat(value/Math.pow(10, decimals)); - } - } - else if (window.blockChainOrt === "tron"){ - value = parseFloat(window.tronWeb.fromSun(value)); - } let donateData - if (window.blockChainOrt === "ethereum"){ + if (this.blockChainOrt === "ethereum"){ donateData = { campaignID : this.state.campaignId, donatorID: accounts[0], - raisedAmount: value, + raisedAmount: this.state.donationAmount, + tipAmount: this.state.tipAmount, transactionHash: transactionHash, chainId: chainId, + blockChainOrt: "Ethereum", coinAddress: coinAddress }; - } else if (window.blockChainOrt === "tron"){ + } else if (this.blockChainOrt === "tron"){ donateData = { campaignID : this.state.campaignId, donatorID: window.tronAdapter.address, - raisedAmount: value, + raisedAmount: this.state.donationAmount, + tipAmount: this.state.tipAmount, transactionHash: transactionHash, chainId: chainId, + blockChainOrt: "Tron", coinAddress: coinAddress }; } @@ -391,44 +362,38 @@ class CampaignPage extends Component { modalButtonMessage: 'returnHome', modalButtonVariant: "#588157", waitToClose: false }); - await this.updateRaisedAmount(); + this.setState({raisedAmount: this.state.raisedAmount + this.state.donationAmount}); } - - handleDonateClick = async(chain_name, coin_address, blockChainOrt) =>{ - if(blockChainOrt === "ethereum"){ - window.blockChainOrt = "ethereum"; - if (this.state.campaign.new === false) await this.handleDonateOld(chain_name, coin_address); - else await this.handleDonateNew(chain_name, coin_address); + + handleDonateClick = async(wallet_ort, addres_base58, addres_hex, coin_addres, chain_name) =>{ + if(wallet_ort === "Ethereum"){ + this.blockChainOrt = "ethereum"; + //if (this.state.campaign.new === false) await this.handleDonateOld(chain_name, addres_hex); + await this.handleDonateNew(chain_name, addres_hex); } - else if(blockChainOrt === "tron"){ - window.blockChainOrt = "tron"; - await this.handleDonateTron(chain_name, coin_address); + else if(wallet_ort === "Tron"){ + this.blockChainOrt = "tron"; + await this.handleDonateTron(chain_name, addres_base58, coin_addres); } } - handleDonateTron = async (chainId, coinAddress) =>{ + handleDonateTron = async (chainId, addres_base58, coinAddress) =>{ try{ await clearTronProvider(); await initTronadapter(); - await initTron(chainId, this); - let TRC20Coin = (await import("../remote/"+ chainId + "/TRC20")).default; - let HEOCampaign = (await import("../remote/"+ chainId + "/HEOCampaign")).default; - let campaignAddress = this.state.campaign.addresses[chainId]; - let campaignInstance = await window.tronWeb.contract(HEOCampaign, window.tronWeb.address.fromHex(campaignAddress)); - var toDonate = window.tronWeb.toSun(this.state.donationAmount); - var coinInstance = await window.tronWeb.contract(TRC20Coin, window.tronWeb.address.fromHex(coinAddress)); - var decimals = coinInstance.methods.decimals().call(); + await initTron(chainId); + var toDonate = window.tronWeb.toSun(this.state.totalAmount); + var coinInstance = await window.tronWeb.contract(tron_abi, coinAddress); ReactGA.event({ category: "donation", action: "donate_button_click", - value: parseInt(this.state.donationAmount), // optional, must be a number + value: parseInt(this.state.totalAmount), // optional, must be a number nonInteraction: false }); //check if donating to oneself - let beneficiaryAdres = await campaignInstance.methods.beneficiary().call(); - if(window.tronWeb.address.toHex(window.tronAdapter.address).toLowerCase() === beneficiaryAdres.toLowerCase()) { + if(window.tronAdapter.address.toLowerCase() === addres_base58.toLowerCase()) { this.setState({ - showModal: true, modalTitle: 'notAllowed', + showModal: true, modalTitle: 'notAllowed', goHome: false, modalMessage: 'donateToYourSelf', errorIcon: 'ExclamationTriangle', modalButtonMessage: 'closeBtn', modalButtonVariant: '#E63C36', waitToClose: false @@ -439,13 +404,13 @@ class CampaignPage extends Component { nonInteraction: false }); console.log("Tronadapter address" + window.tronAdapter.address); - console.log("Beneficiary" + beneficiaryAdres); return; } - let result = await coinInstance.methods.transfer(campaignAddress, toDonate) + let result = await coinInstance.methods.transfer(addres_base58, toDonate) .send({from:window.tronAdapter.address,callValue:0,feeLimit:15000000000,shouldPollResponse:false}); + this.setState({showModal:true, - modalTitle: 'processingWait', + modalTitle: 'processingWait', goHome: false, modalMessage: 'waitingForNetwork', errorIcon:'HourglassSplit', modalButtonVariant: "gold", waitToClose: true}); let txnObject; @@ -459,15 +424,16 @@ class CampaignPage extends Component { }while(m !== 2); if (txnObject.receipt.result === "SUCCESS"){ this.setState({ - showModal: true, modalTitle: 'complete', + showModal: true, modalTitle: 'complete', goHome: true, modalMessage: 'thankYouDonation', errorIcon: 'CheckCircle', modalButtonMessage: 'closeBtn', modalButtonVariant: '#588157', waitToClose: false }); - this.saveDonateToDb(toDonate,decimals, txnObject.txID, chainId, coinAddress); + this.saveDonateToDb(txnObject.id, chainId, coinAddress); + }else { this.setState({ - showModal: true, modalTitle: 'failed', + showModal: true, modalTitle: 'failed', goHome: false, errorIcon: 'XCircle', modalButtonMessage: 'closeBtn', modalButtonVariant: '#E63C36', waitToClose: false, modalMessage: 'blockChainTransactionFailed' @@ -481,7 +447,7 @@ class CampaignPage extends Component { } } catch (err) { this.setState({ - showModal: true, modalTitle: 'failed', + showModal: true, modalTitle: 'failed', goHome: false, errorIcon: 'XCircle', modalButtonMessage: 'closeBtn', modalButtonVariant: '#E63C36', waitToClose: false, modalMessage: 'blockChainTransactionFailed' @@ -525,7 +491,7 @@ class CampaignPage extends Component { //check if donating to oneself if(accounts[0].toLowerCase() === this.state.campaign.beneficiaryId.toLowerCase()) { this.setState({ - showModal: true, modalTitle: 'notAllowed', + showModal: true, modalTitle: 'notAllowed', goHome: false, modalMessage: 'donateToYourSelf', errorIcon: 'ExclamationTriangle', modalButtonMessage: 'closeBtn', modalButtonVariant: '#E63C36', waitToClose: false @@ -568,7 +534,7 @@ class CampaignPage extends Component { } catch (err) { this.setState({ showModal: true, modalTitle: 'failed', modalMessage: 'blockChainTransactionFailed', - errorIcon: 'XCircle', modalButtonMessage: 'closeBtn', + errorIcon: 'XCircle', modalButtonMessage: 'closeBtn', goHome: false, modalButtonVariant: '#E63C36', waitToClose: false }); console.log(err); @@ -580,9 +546,8 @@ class CampaignPage extends Component { ).once('transactionHash', function(transactionHash) { that.setState({modalMessage: "waitingForNetwork"}) }); - await this.updateRaisedAmount(accounts, campaignInstance, web3, 18); this.setState({ - showModal: true, modalTitle: 'complete', + showModal: true, modalTitle: 'complete', goHome: true, modalMessage: 'thankYouDonation', errorIcon: 'CheckCircle', modalButtonMessage: 'closeBtn', modalButtonVariant: '#588157', waitToClose: false @@ -590,7 +555,7 @@ class CampaignPage extends Component { } catch (err) { this.setState({ showModal: true, modalTitle: 'failed', modalMessage: 'blockChainTransactionFailed', - errorIcon: 'XCircle', modalButtonMessage: 'closeBtn', + errorIcon: 'XCircle', modalButtonMessage: 'closeBtn', goHome: false, modalButtonVariant: '#E63C36', waitToClose: false }); console.log("donateNative transaction failed"); @@ -602,7 +567,7 @@ class CampaignPage extends Component { ERC20Coin = (await import("../remote/"+ chainId + "/ERC20")).default; var coinInstance = new web3.eth.Contract(ERC20Coin, coinAddress); this.setState({ - showModal: true, modalTitle: 'processingWait', + showModal: true, modalTitle: 'processingWait', goHome: false, modalMessage: "approveSpend", errorIcon: 'HourglassSplit', modalButtonVariant: "#E63C36", waitToClose: false, modalButtonMessage: 'abortBtn', @@ -648,7 +613,7 @@ class CampaignPage extends Component { ); }).on('error', function(error) { that.setState({ - showModal: true, modalTitle: 'failed', + showModal: true, modalTitle: 'failed', goHome: false, errorIcon: 'XCircle', modalButtonMessage: 'closeBtn', modalButtonVariant: '#E63C36', waitToClose: false, modalMessage: 'blockChainTransactionFailed' @@ -702,7 +667,7 @@ class CampaignPage extends Component { if(result.code) { this.setState({ - showModal: true, modalTitle: 'failed', + showModal: true, modalTitle: 'failed', goHome: false, errorIcon: 'XCircle', modalButtonMessage: 'closeBtn', modalButtonVariant: '#E63C36', waitToClose: false, modalMessage: 'blockChainTransactionFailed' @@ -716,9 +681,8 @@ class CampaignPage extends Component { clearWeb3Provider(this); return; } - await this.updateRaisedAmount(accounts, campaignInstance, web3, decimals); this.setState({ - showModal: true, modalTitle: 'complete', + showModal: true, modalTitle: 'complete', goHome: true, modalMessage: 'thankYouDonation', errorIcon: 'CheckCircle', modalButtonMessage: 'closeBtn', modalButtonVariant: '#588157', waitToClose: false @@ -822,7 +786,7 @@ class CampaignPage extends Component { {from:accounts[0], value:(""+toDonate)} ).once('transactionHash', function(transactionHash) { that.setState({modalMessage: "waitingForNetwork"}); - that.saveDonateToDb(toDonate, 0, transactionHash, chainId, coinAddress); + that.saveDonateToDb(transactionHash, chainId, coinAddress); web3.eth.getTransaction(transactionHash).then( function(txnObject) { if(txnObject) { @@ -843,24 +807,16 @@ class CampaignPage extends Component { }); console.log(err); } - } else { + } else { try { await campaignInstance.methods.donateNative().send( {from:accounts[0], value:(""+toDonate)} ).once('transactionHash', function(transactionHash) { that.setState({modalMessage: "waitingForNetwork"}); - let decimals = 0; - coinInstance.methods.decimals().call({from:accounts[0]}, function(err, result) { - if(err) { - console.log(`Failed to fetch decimals from ${coinAddress} `); - console.log(err); - } - else decimals = result; - }); - that.saveDonateToDb(toDonate, decimals, transactionHash, chainId, coinAddress); + that.saveDonateToDb(transactionHash, chainId, coinAddress); }); this.setState({ - showModal: true, modalTitle: 'complete', + showModal: true, modalTitle: 'complete', goHome: true, modalMessage: 'thankYouDonation', errorIcon: 'CheckCircle', modalButtonMessage: 'closeBtn', modalButtonVariant: '#588157', waitToClose: false @@ -868,7 +824,7 @@ class CampaignPage extends Component { } catch (err) { this.setState({ showModal: true, modalTitle: 'failed', modalMessage: 'blockChainTransactionFailed', - errorIcon: 'XCircle', modalButtonMessage: 'closeBtn', + errorIcon: 'XCircle', modalButtonMessage: 'closeBtn', goHome: false, modalButtonVariant: '#E63C36', waitToClose: false }); console.log("donateNative transaction failed"); @@ -880,7 +836,7 @@ class CampaignPage extends Component { ERC20Coin = (await import("../remote/"+ chainId + "/ERC20")).default; this.setState({ - showModal: true, modalTitle: 'processingWait', + showModal: true, modalTitle: 'processingWait', goHome: false, modalMessage: "approveSpend", errorIcon: 'HourglassSplit', modalButtonVariant: "#E63C36", waitToClose: false, modalButtonMessage: 'abortBtn', @@ -914,7 +870,7 @@ class CampaignPage extends Component { {from:accounts[0]} ).once('transactionHash', function(transactionHash) { console.log(`Got donation trnasaction hash ${transactionHash}`); - that.saveDonateToDb(toDonate,decimals, transactionHash, chainId, coinAddress); + that.saveDonateToDb(transactionHash, chainId, coinAddress); ReactGA.event({ category: "donation", action: "donation_hash", @@ -939,7 +895,7 @@ class CampaignPage extends Component { nonInteraction: false }); that.setState({ - showModal: true, modalTitle: 'failed', + showModal: true, modalTitle: 'failed', goHome: false, errorIcon: 'XCircle', modalButtonMessage: 'closeBtn', modalButtonVariant: '#E63C36', waitToClose: false, modalMessage: 'blockChainTransactionFailed' @@ -966,11 +922,11 @@ class CampaignPage extends Component { ).once('transactionHash', function(transactionHash) { console.log(`transaction hash for donateERC20 ${transactionHash}`); that.setState({modalMessage: "waitingForNetwork"}); - that.saveDonateToDb(toDonate,decimals, transactionHash, chainId, coinAddress); + that.saveDonateToDb(transactionHash, chainId, coinAddress); }); if(result.code) { this.setState({ - showModal: true, modalTitle: 'failed', + showModal: true, modalTitle: 'failed', goHome: false, errorIcon: 'XCircle', modalButtonMessage: 'closeBtn', modalButtonVariant: '#E63C36', waitToClose: false, modalMessage: 'blockChainTransactionFailed' @@ -985,7 +941,7 @@ class CampaignPage extends Component { return; } this.setState({ - showModal: true, modalTitle: 'complete', + showModal: true, modalTitle: 'complete', goHome: true, modalMessage: 'thankYouDonation', errorIcon: 'CheckCircle', modalButtonMessage: 'closeBtn', modalButtonVariant: '#588157', waitToClose: false @@ -995,7 +951,7 @@ class CampaignPage extends Component { } } catch (err) { this.setState({ - showModal: true, modalTitle: 'failed', + showModal: true, modalTitle: 'failed', goHome: false, errorIcon: 'XCircle', modalButtonMessage: 'closeBtn', modalButtonVariant: '#E63C36', waitToClose: false, modalMessage: 'blockChainTransactionFailed' @@ -1013,7 +969,7 @@ class CampaignPage extends Component { } catch (err) { console.log(err); this.setState({ - showModal: true, modalTitle: 'failed', + showModal: true, modalTitle: 'failed', goHome: false, errorIcon: 'XCircle', modalButtonMessage: 'closeBtn', modalButtonVariant: '#E63C36', waitToClose: false, modalMessage: 'blockChainConnectFailed' @@ -1061,6 +1017,7 @@ class CampaignPage extends Component { label: this.state.modalTitle, // optional, must be a number nonInteraction: false }); + if(this.state.goHome) this.props.history.push('/'); } }> @@ -1173,10 +1130,14 @@ class CampaignPage extends Component { } } }>some valueUSD } - - {this.state.chains_coins.map((item, i) => - this.handleDonateClick(item.chain, item.coin.address, item.blockChainOrt)}>some value{item.coin.name} ({item.chain_name }) + {this.state.campaign_wallets.map((item, i) => + + this.handleDonateClick(item.wallet_ort, item.addres_base58, item.addres_hex,item.coin_addres,item.chainId)}> + some value{item.coin_name} + )} + + Coinbase commerce { this.handleDonateCoinbaseCommerce(); @@ -1263,20 +1224,25 @@ class CampaignPage extends Component { modalMessage: modalMessage }) }) - let campaign = await this.getCampaign(campaignId); if(!campaign) { this.props.history.push("/404"); return; } - let tipForHeo = 10; + this.state.campaign_wallets = campaign.campaign_wallets; let result = await axios.post('/api/gettipforheo', {headers: {"Content-Type": "application/json"}}); if(result) { - tipForHeo = Number(result.data); + this.state.tipForHeo = Number(result.data); } this.state.donationAmount = campaign.defaultDonationAmount ? campaign.defaultDonationAmount : 20; - this.state.tipAmount = Math.max(1, parseInt(parseInt(this.state.donationAmount)/100 * tipForHeo)); + this.state.tipAmount = Math.max(1, parseInt(parseInt(this.state.donationAmount)/100 * this.state.tipForHeo)); this.state.totalAmount = parseInt(campaign.defaultDonationAmount) + this.state.tipAmount; + let totalQuantity = campaign.totalQuantity? parseFloat(campaign.totalQuantity) : 0; + let raisedAmount = campaign.raisedAmount? parseFloat(campaign.raisedAmount) : 0; + let fiatDonations = campaign.fiatDonations ? parseFloat(campaign.fiatDonations) : 0; + let raisedOnCoinbase = campaign.raisedOnCoinbase ? parseFloat(campaign.raisedOnCoinbase) : 0; + raisedAmount = Math.round((raisedAmount + fiatDonations + raisedOnCoinbase + totalQuantity) * 100)/100; + this.state.raisedAmount = raisedAmount; campaign.percentRaised = 100 * (this.state.raisedAmount)/campaign.maxAmount; var contentState = {}; var lng @@ -1308,7 +1274,6 @@ class CampaignPage extends Component { chains.push(configChains[ch]); } } - let globals = config.get("GLOBALS"); globals.forEach(element => { if(element._id === 'FIATPAYMENT') { @@ -1349,6 +1314,7 @@ class CampaignPage extends Component { dedupedCoinNames.push(coinName); } } + await axios.post('/api/getcoinslist') .then(res => { let chains_coins = []; @@ -1384,7 +1350,6 @@ class CampaignPage extends Component { campaign : campaign, coins: dedupedCoinNames }); - await this.updateRaisedAmount(); ReactGA.send({ hitType: "pageview", page: this.props.location.pathname }); const params = new Proxy(new URLSearchParams(window.location.search), { get: (searchParams, prop) => searchParams.get(prop), @@ -1393,7 +1358,7 @@ class CampaignPage extends Component { if(params.fp) { if(params.fp === 's') { this.setState({ - showModal: true, modalTitle: 'complete', + showModal: true, modalTitle: 'complete', goHome: true, modalMessage: 'thankYouFiatDonation', errorIcon: 'CheckCircle', modalButtonMessage: 'closeBtn', modalButtonVariant: '#588157', waitToClose: false, tryAgainCC: false, ccinfo: {} @@ -1401,7 +1366,7 @@ class CampaignPage extends Component { } else if(params.fp === 'f') { this.setState({ showModal: true, modalTitle: 'failed', modalMessage: 'failed3ds', - errorIcon: 'XCircle', modalButtonMessage: 'tryAgain', + errorIcon: 'XCircle', modalButtonMessage: 'tryAgain', goHome: false, modalButtonVariant: '#E63C36', waitToClose: false, tryAgainCC: true, donationAmount: params.am }); @@ -1409,13 +1374,13 @@ class CampaignPage extends Component { if(params.state ==='declined' || params.state==='cancelled') { this.setState({ showModal: true, modalTitle: 'failed', modalMessage: 'cardPaymentDeclined', - errorIcon: 'XCircle', modalButtonMessage: 'tryAgain', + errorIcon: 'XCircle', modalButtonMessage: 'tryAgain', goHome: false, modalButtonVariant: '#E63C36', waitToClose: false, tryAgainCC: false, donationAmount: params.am, ccinfo: {} }); } else { this.setState({ - showModal: true, modalTitle: 'complete', + showModal: true, modalTitle: 'complete', goHome: true, modalMessage: 'thankYouFiatDonation', errorIcon: 'CheckCircle', modalButtonMessage: 'closeBtn', modalButtonVariant: '#588157', waitToClose: false, tryAgainCC: false, ccinfo: {} @@ -1462,10 +1427,6 @@ function findLinkEntities(contentBlock, callback, contentState) { function checkDonationTransaction(txnObject, decimals, chainId, that) { if(txnObject.blockNumber) { console.log(`Donation transaction successful in block ${txnObject.blockNumber}`); - - if(decimals > 0) { - that.updateRaisedAmount(); - } that.setState({ showModal: true, modalTitle: 'complete', modalMessage: 'thankYouDonation', diff --git a/src/components/CreateCampaign.js b/src/components/CreateCampaign.js index addd10c..c83977d 100644 --- a/src/components/CreateCampaign.js +++ b/src/components/CreateCampaign.js @@ -8,7 +8,7 @@ import uuid from 'react-uuid'; import axios from 'axios'; import { Trans } from 'react-i18next'; import i18n from '../util/i18n'; -import {checkEmail,isValidUrl,blockchains} from '../util/Utilities'; +import {checkEmail,isValidUrl} from '../util/Utilities'; import {getEditorStateEn, getEditorStateRu, TextEditorEn, TextEditorRu, setEditorStateEn, setEditorStateRu} from '../components/TextEditor'; import { ChevronLeft, CheckCircle, ExclamationTriangle, HourglassSplit, XCircle } from 'react-bootstrap-icons'; import '../css/createCampaign.css'; @@ -69,10 +69,19 @@ class CreateCampaign extends React.Component { countryCode:"", number:"", website:"", + badWebsite:false, + badKey:false, + badEmail:false, + noCountryCode:false, + notValidAddr:false, + noCoverImage:false, + longDescRequired:false, + longDescEnIncludRu:false, telegram:"", - blockchain:"", + blockchain:"Tron", wallet:"" } + this.mistake = false; }; onSubmit = (e) => { @@ -102,15 +111,12 @@ class CreateCampaign extends React.Component { help_value += e.target.value[i]; } let key = help_value.toLowerCase().replaceAll(" ", "-"); - this.setState({key: key}); + if((key !== "")&&(this.state.key === "")) this.setState({key: key}); } - } - else if(e.target.name === 'fiatPayments') - this.setState({fiatPayments: e.target.checked}); - else if(e.target.name === 'countryCode'){ - this.setState({ countryCode: e.target.value }); - } - else if(e.target.name === 'campaignURL'){ + } + else if(e.target.name === 'fiatPayments') this.setState({fiatPayments: e.target.checked}); + else if(e.target.name === 'countryCode') this.setState({ countryCode: e.target.value }); + else if(e.target.name === 'campaignURL'){ help_value = ''; for(i = 0; i < e.target.value.length; i++){ if ((/^[-A-Za-z0-9]*$/.test(e.target.value[i]) === true)||(e.target.value[i] === ' ')) @@ -118,8 +124,8 @@ class CreateCampaign extends React.Component { } let key = help_value.toLowerCase().replaceAll(" ", "-"); this.setState({key: key}); - } - else if(e.target.name === 'number'){ + } + else if(e.target.name === 'number'){ help_value = ''; for(let i = 0; i < e.target.value.length; i++){ if ((/^[-0-9]*$/.test(e.target.value[i]) === true)||(e.target.value[i] === ' ')) @@ -127,8 +133,8 @@ class CreateCampaign extends React.Component { } e.target.value = help_value; this.setState({ [e.target.name]: e.target.value }); - } - else if(e.target.name === 'wallet'){ + } + else if(e.target.name === 'wallet'){ help_value = ''; for(i = 0; i < e.target.value.length; i++){ if (/^[A-Za-z0-9]*$/.test(e.target.value[i]) === true) @@ -148,60 +154,24 @@ class CreateCampaign extends React.Component { this.setState({qrCodeImageFile:e.target.files[0], qrCodeImageURL: URL.createObjectURL(e.target.files[0])}); }; - async handleClick (event) { + async handleClick () { let imgID = uuid(); let qrImgID = uuid(); let result; + this.mistake = false; try { - if(!this.state.orgEn) { - this.setState( - {showModal:true, modalTitle: 'requiredFieldsTitle', - modalMessage: 'orgRequiredEn', modalIcon: 'ExclamationTriangle', - waitToClose: false, - modalButtonMessage: 'closeBtn', modalButtonVariant: '#E63C36' - }); - return false; - } - if(!this.state.cn) { - this.setState( - {showModal:true, modalTitle: 'requiredFieldsTitle', - modalMessage: 'cnRequired', modalIcon: 'ExclamationTriangle', - waitToClose: false, - modalButtonMessage: 'closeBtn', modalButtonVariant: '#E63C36' - }); - return false; - } - if(this.state.website){ + if(this.state.orgEn.trim() === "") this.mistake = true; + if(this.state.cn.trim() === "") this.mistake = true; + if(this.state.website.trim() !== ""){ result = await isValidUrl(this.state.website); if(!result){ - this.setState( - {showModal:true, modalTitle: 'requiredFieldsTitle', - modalMessage: 'badWebsite', modalIcon: 'ExclamationTriangle', - waitToClose: false, - modalButtonMessage: 'closeBtn', modalButtonVariant: '#E63C36' - }); - return false; + this.setState({badWebsite:true}); + this.mistake = true; } } - if(!this.state.titleEn) { - this.setState( - {showModal:true, modalTitle: 'requiredFieldsTitle', - modalMessage: 'titleRequired', modalIcon: 'ExclamationTriangle', - waitToClose: false, - modalButtonMessage: 'closeBtn', modalButtonVariant: '#E63C36' - }); - return false; - } - if(!this.state.descriptionEn) { - this.setState( - {showModal:true, modalTitle: 'requiredFieldsTitle', - modalMessage: 'shortDescRequired', modalIcon: 'ExclamationTriangle', - waitToClose: false, - modalButtonMessage: 'closeBtn', modalButtonVariant: '#E63C36' - }); - return false; - } - if(!this.state.key) { + if(this.state.titleEn.trim() === "") this.mistake = true; + if(this.state.descriptionEn.trim() === "") this.mistake = true; + if(this.state.key.trim() === ""){ this.setState( {showModal:true, modalTitle: 'requiredFieldsTitle', modalMessage: 'campaignURLRequired', modalIcon: 'ExclamationTriangle', @@ -210,7 +180,7 @@ class CreateCampaign extends React.Component { }); return false; } - if(this.state.key){ + if(this.state.key.trim() !== ""){ let data = {KEY : this.state.key}; let res = await axios.post('/api/campaign/checkKey', data, {headers: {"Content-Type": "application/json"}}); @@ -222,104 +192,55 @@ class CreateCampaign extends React.Component { modalButtonMessage: 'closeBtn', modalButtonVariant: '#E63C36' }); - return false; + return false; } } - if(!this.state.email) { - this.setState( - {showModal:true, modalTitle: 'requiredFieldsTitle', - modalMessage: 'emailRequired', modalIcon: 'ExclamationTriangle', - waitToClose: false, - modalButtonMessage: 'closeBtn', modalButtonVariant: '#E63C36' - }); - return false; - } - result = await checkEmail(this.state.email); - if(!result) { - this.setState( - {showModal:true, modalTitle: 'requiredFieldsTitle', - modalMessage: 'emailFaulty', modalIcon: 'ExclamationTriangle', - waitToClose: false, - modalButtonMessage: 'closeBtn', modalButtonVariant: '#E63C36' - }); - return false; - } - if ((this.state.number)&&(this.state.countryCode.trim()==="")){ - this.setState( - {showModal:true, modalTitle: 'requiredFieldsTitle', - modalMessage: 'countryCodeRequired', modalIcon: 'ExclamationTriangle', - waitToClose: false, - modalButtonMessage: 'closeBtn', modalButtonVariant: '#E63C36' - }); - return false; - } - if (!this.state.blockchain){ - this.setState( - {showModal:true, modalTitle: 'requiredFieldsTitle', - modalMessage: 'selectBlockchain', modalIcon: 'ExclamationTriangle', - waitToClose: false, - modalButtonMessage: 'closeBtn', modalButtonVariant: '#E63C36' - }); - return false; + if(this.state.email.trim() === "")this.mistake = true; + if(this.state.email.trim() !== "" ){ + result = await checkEmail(this.state.email); + if(!result){ + this.setState({badEmail:true}); + this.mistake = true; + } } - if (!this.state.wallet){ - this.setState( - {showModal:true, modalTitle: 'requiredFieldsTitle', - modalMessage: 'enterWallet', modalIcon: 'ExclamationTriangle', - waitToClose: false, - modalButtonMessage: 'closeBtn', modalButtonVariant: '#E63C36' - }); - return false; + if ((this.state.number.trim() !== "")&&(this.state.countryCode.trim()==="")){ + this.setState({noCountryCode:true}); + this.mistake = true; } - if (this.state.blockchain === "Ethereum"){ + if (this.state.wallet.trim() === "") this.mistake = true; + if ((this.state.blockchain === "Ethereum")&&(this.state.wallet.trim() !== "")){ if((this.state.wallet.substring(0,2) !== "0x")||(this.state.wallet.length !== 42)) { - this.setState( - {showModal:true, modalTitle: 'requiredFieldsTitle', - modalMessage: 'notValidAddr', modalIcon: 'ExclamationTriangle', - waitToClose: false, - modalButtonMessage: 'closeBtn', modalButtonVariant: '#E63C36' - }); - return false; + this.setState({notValidAddr:true}); + this.mistake = true; } } - if (this.state.blockchain === "Tron"){ + if ((this.state.blockchain === "Tron")&&(this.state.wallet.trim() !== "")){ if((this.state.wallet.substring(0,1) !== "T")||(this.state.wallet.length !== 34)) { - this.setState( - {showModal:true, modalTitle: 'requiredFieldsTitle', - modalMessage: 'notValidAddr', modalIcon: 'ExclamationTriangle', - waitToClose: false, - modalButtonMessage: 'closeBtn', modalButtonVariant: '#E63C36' - }); - return false; + this.setState({notValidAddr:true}); + this.mistake = true; } } let n = 0; let EditorStateEn = await getEditorStateEn(); + if(!EditorStateEn){ + this.setState({longDescRequired:true}); + this.mistake = true; + } if (EditorStateEn){ for (let i = 0; i < EditorStateEn.blocks.length; i++){ n = n + EditorStateEn.blocks[i].text.length; } if (n < 3) { - this.setState( - {showModal:true, modalTitle: 'requiredFieldsTitle', - modalMessage: 'longDescRequired', modalIcon: 'ExclamationTriangle', - waitToClose: false, - modalButtonMessage: 'closeBtn', modalButtonVariant: '#E63C36' - }); - return false; + this.setState({longDescRequired:true}); + this.mistake = true; } for (let i = 0; i < EditorStateEn.blocks.length; i++){ for(let j = 0; j < getEditorStateEn().blocks[i].text.length; j++){ if (/^[А-Яа-я]*$/.test(getEditorStateEn().blocks[i].text[j]) === true){ - this.setState( - {showModal:true, modalTitle: 'requiredFieldsTitle', - modalMessage: 'longDescEnIncludRu', modalIcon: 'ExclamationTriangle', - waitToClose: false, - modalButtonMessage: 'closeBtn', modalButtonVariant: '#E63C36' - }); - return false; + this.setState({longDescEnIncludRu:true}); + this.mistake = true; } } } @@ -327,31 +248,32 @@ class CreateCampaign extends React.Component { let qrImgUrl = ''; let imgUrl = await this.uploadImageS3('main', imgID); if (imgUrl) this.setState({imgUrl:imgUrl}); + else{ + this.setState({noCoverImage:true}); + this.mistake = true; + } if(this.state.qrCodeImageURL) { qrImgUrl = await this.uploadImageS3('qrCode', qrImgID); - if(qrImgUrl) this.setState({imgUrl:imgUrl}); - } - if(imgUrl) { - let campaignData = {mainImageURL:imgUrl, - qrCodeImageURL:qrImgUrl} - await this.addCampaignToDb(campaignData); + if(qrImgUrl) this.setState({qrImgUrl:qrImgUrl}); } + if(this.mistake === true) this.setState({showModalМistakes:true}) + else await this.addCampaignToDb(); } catch(error) { console.log(error); } } - async addCampaignToDb(campaignData) { + async addCampaignToDb() { try { + let campaignData = {}; + campaignData.qrCodeImageUR = this.state.qrImgUrl; + campaignData.mainImageURL = this.state.imgUrl; campaignData.key = this.state.key; campaignData.id = uuid(); campaignData.title = {}; campaignData.title["default"] = this.state.titleEn; campaignData.title["en"] = this.state.titleEn; campaignData.title["ru"] = this.state.titleRu; - campaignData.addresses = {}; - campaignData.accounts = {}; - campaignData.coins = {}; campaignData.description = {}; campaignData.description["default"] = this.state.descriptionEn; campaignData.description["en"] = this.state.descriptionEn; @@ -384,11 +306,14 @@ class CreateCampaign extends React.Component { campaignData.website = this.state.website; campaignData.payout_chain = this.state.blockchain; campaignData.payout_address = this.state.wallet; + if(this.mistake === true) campaignData.complete = false; + else campaignData.complete = true; let res = await axios.post('/api/campaign/add', {mydata : campaignData}, {headers: {"Content-Type": "application/json"}}); if (res.data === 'success'){ + if(this.mistake === true) { this.setState({showModal:true, goHome: true, - modalMessage: 'campaignwWillBePublished', + modalMessage: 'campaignSavedWithErrors', modalTitle: 'success', modalIcon: 'CheckCircle', modalButtonMessage: 'ok', @@ -396,6 +321,18 @@ class CreateCampaign extends React.Component { campaignID: campaignData.id, campaignData:campaignData }); + } + else { + this.setState({showModal:true, goHome: true, + modalMessage: 'campaignSaved', + modalTitle: 'success', + modalIcon: 'CheckCircle', + modalButtonMessage: 'ok', + modalButtonVariant: "#588157", waitToClose: false, isInDB: true, + campaignID: campaignData.id, + campaignData:campaignData + }); + } } else{ this.setState({showModal: true, goHome: false, @@ -425,12 +362,7 @@ class CreateCampaign extends React.Component { modalButtonVariant: "gold", waitToClose: true }); if(type === 'main' && (!this.state.mainImageFile || !this.state.mainImageFile.type)) { - this.setState( - {showModal:true, modalTitle: 'coverImageRequiredTitle', - modalMessage: 'coverImageRequired', modalIcon: 'ExclamationTriangle', - waitToClose: false, - modalButtonMessage: 'closeBtn', modalButtonVariant: '#E63C36' - }); + this.setState({noCoverImage:true, showModal:false}); return false; } let fileType; @@ -456,12 +388,7 @@ class CreateCampaign extends React.Component { this.setState({showModal:false}); return (res.data); } else { - console.log('error uploading image: res.data is empty'); - this.setState({showModal: true, goHome: false, - modalTitle: 'imageUploadFailed', - modalMessage: 'technicalDifficulties', - modalIcon: 'XCircle', modalButtonMessage: 'closeBtn', - modalButtonVariant: "#E63C36", waitToClose: false}); + this.setState({noCoverImage:true, showModal:false}); return false; } } catch(err) { @@ -493,6 +420,55 @@ class CreateCampaign extends React.Component { render() { return (
+ {}} className='myModal' centered> + +

+ + +

+ +
+ + + {(this.state.orgEn === "")&&

} + {(this.state.cn === "")&&

} + {(this.state.badWebsite === true)&&

} + {(this.state.titleEn === "")&&

} + {(this.state.descriptionEn === "")&&

} + {(this.state.email === "")&&

} + {(this.state.badEmail === true)&&

} + {(this.state.noCountryCode === true)&&

} + {(this.state.wallet === "")&&

} + {(this.state.notValidAddr === true)&&

} + {(this.state.longDescRequired === true)&&

} + {(this.state.longDescEnIncludRu === true)&&

} + {(this.state.noCoverImage=== true)&&

} +
+ + + + + + + + + +
+
{}} className='myModal' centered> @@ -753,13 +729,9 @@ class CreateCampaign extends React.Component { - - - - {blockchains.map((data) => - - )} - + + + diff --git a/src/components/EditCampaign.js b/src/components/EditCampaign.js index 02c2dfa..cc06d5a 100644 --- a/src/components/EditCampaign.js +++ b/src/components/EditCampaign.js @@ -1,17 +1,18 @@ import React from 'react'; import countries from '../countries'; -import {Container, Form, Col, Button, DropdownButton, Dropdown, Image, Modal, Row} from 'react-bootstrap'; +import {Container, Form, Col, Button, Image, Modal, Row} from 'react-bootstrap'; import ReactPlayer from 'react-player'; import {getCountryCodeForRegionCode} from 'awesome-phonenumber'; import config from "react-global-configuration"; import axios from 'axios'; import { Trans } from 'react-i18next'; +import uuid from 'react-uuid'; import i18n from '../util/i18n'; import { ChevronLeft, CheckCircle, ExclamationTriangle, HourglassSplit, XCircle } from 'react-bootstrap-icons'; import { Link } from 'react-router-dom'; import { getEditorStateEn, getEditorStateRu, TextEditorEn, TextEditorRu, setEditorStateEn, setEditorStateRu, editorStateHasChangedRu, editorStateHasChangedEn } from '../components/TextEditor'; -import { initWeb3, checkAuth, initWeb3Modal, initTronadapter, checkAuthTron, initTron, checkEmail, isValidUrl,blockchains} from '../util/Utilities'; +import { initWeb3Modal, initTronadapter, checkEmail, isValidUrl, countWordsString} from '../util/Utilities'; import '../css/createCampaign.css'; import '../css/modal.css'; import ReactGA from "react-ga4"; @@ -65,11 +66,14 @@ class EditCampaign extends React.Component { key: "", chainId:"", tronChainId:"", - isInTron:false, - isInEtherium:false, - resultEtherium : true, - resultTron: true, - active:false, + badWebsite:false, + badKey:false, + badEmail:false, + noCountryCode:false, + notValidAddr:false, + noCoverImage:false, + longDescRequired:false, + longDescEnIncludRu:false, email:"", countryCode:"", number:"", @@ -131,219 +135,107 @@ class EditCampaign extends React.Component { } handleClick = async () => { + let imgID; + if(this.state.imgID === "") imgID = this.state.imgID + else imgID = uuid(); let result; - if (this.state.maxAmount_old !== this.state.maxAmount){ - if ((window.ethereum)&&(this.state.isInEtherium)){ - await initWeb3Modal(this.state.chainId, this); - await initWeb3(this.state.chainId, this); - // is the user logged in? - if(!this.state.isLoggedIn) { - await checkAuth(this.state.chainId, this); + this.mistake = false; + try{ + if(this.state.orgEn.trim() === "") this.mistake = true; + if(this.state.cn.trim() === "") this.mistake = true; + if(this.state.website.trim() !== ""){ + result = await isValidUrl(this.state.website); + if(!result){ + this.setState({badWebsite:true}); + this.mistake = true; + } + } + if(this.state.titleEn.trim() === "") this.mistake = true; + if(this.state.descriptionEn.trim() === "") this.mistake = true; + if(this.state.email.trim() === "")this.mistake = true; + if(this.state.email.trim() !== "" ){ + result = await checkEmail(this.state.email); + if(!result){ + this.setState({badEmail:true}); + this.mistake = true; + } } - } - if ((window.tron)&&(this.state.isInTron)){ - await initTronadapter(); - await initTron(this.state.tronChainId, this); - // is the user logged in? - if(!this.state.isLoggedInTron) { - await checkAuthTron(this.state.tronChainId, this); + if ((this.state.number.trim() !== "")&&(this.state.countryCode.trim()==="")){ + this.setState({noCountryCode:true}); + this.mistake = true; } - } - } - - this.setState({resultEtherium : true, resultTron: true}); - //check if this campaign belongs to this user - if(editorStateHasChangedEn()|| editorStateHasChangedRu()) { - this.state.updateMeta = true; - } - if(!this.state.orgEn) { - this.setState( - {showModal:true, modalTitle: 'requiredFieldsTitle', - modalMessage: 'orgRequiredEn', modalIcon: 'ExclamationTriangle', - waitToClose: false, - modalButtonMessage: 'closeBtn', modalButtonVariant: '#E63C36' - }); - return false; - } - if(!this.state.cn) { - this.setState( - {showModal:true, modalTitle: 'requiredFieldsTitle', - modalMessage: 'cnRequired', modalIcon: 'ExclamationTriangle', - waitToClose: false, - modalButtonMessage: 'closeBtn', modalButtonVariant: '#E63C36' - }); - return false; - } - if(this.state.website){ - result = await isValidUrl(this.state.website); - if(!result){ - this.setState( - {showModal:true, modalTitle: 'requiredFieldsTitle', - modalMessage: 'badWebsite', modalIcon: 'ExclamationTriangle', - waitToClose: false, - modalButtonMessage: 'closeBtn', modalButtonVariant: '#E63C36' - }); - return false; + if (this.state.wallet.trim() === "") this.mistake = true; + if ((this.state.blockchain === "Ethereum")&&(this.state.wallet.trim() !== "")){ + if((this.state.wallet.substring(0,2) !== "0x")||(this.state.wallet.length !== 42)) + { + this.setState({notValidAddr:true}); + this.mistake = true; + } } - } - if(!this.state.titleEn) { - this.setState( - {showModal:true, modalTitle: 'requiredFieldsTitle', - modalMessage: 'titleRequired', modalIcon: 'ExclamationTriangle', - waitToClose: false, - modalButtonMessage: 'closeBtn', modalButtonVariant: '#E63C36' - }); - return false; - } - if(!this.state.email) { - this.setState( - {showModal:true, modalTitle: 'requiredFieldsTitle', - modalMessage: 'emailRequired', modalIcon: 'ExclamationTriangle', - waitToClose: false, - modalButtonMessage: 'closeBtn', modalButtonVariant: '#E63C36' - }); - return false; - } - result = await checkEmail(this.state.email); - if(!result) { - this.setState( - {showModal:true, modalTitle: 'requiredFieldsTitle', - modalMessage: 'emailFaulty', modalIcon: 'ExclamationTriangle', - waitToClose: false, - modalButtonMessage: 'closeBtn', modalButtonVariant: '#E63C36' - }); - return false; - } - if ((this.state.number)&&(this.state.countryCode.trim()==="")){ - this.setState( - {showModal:true, modalTitle: 'requiredFieldsTitle', - modalMessage: 'countryCodeRequired', modalIcon: 'ExclamationTriangle', - waitToClose: false, - modalButtonMessage: 'closeBtn', modalButtonVariant: '#E63C36' - }); - return false; - } - if(!this.state.descriptionEn) { - this.setState( - {showModal:true, modalTitle: 'requiredFieldsTitle', - modalMessage: 'shortDescRequired', modalIcon: 'ExclamationTriangle', - waitToClose: false, - modalButtonMessage: 'closeBtn', modalButtonVariant: '#E63C36' - }); - return false; - } - if (!this.state.blockchain){ - this.setState( - {showModal:true, modalTitle: 'requiredFieldsTitle', - modalMessage: 'selectBlockchain', modalIcon: 'ExclamationTriangle', - waitToClose: false, - modalButtonMessage: 'closeBtn', modalButtonVariant: '#E63C36' - }); - return false; - } - if (!this.state.wallet){ - this.setState( - {showModal:true, modalTitle: 'requiredFieldsTitle', - modalMessage: 'enterWallet', modalIcon: 'ExclamationTriangle', - waitToClose: false, - modalButtonMessage: 'closeBtn', modalButtonVariant: '#E63C36' - }); - return false; - } - if (this.state.blockchain === "Ethereum"){ - if((this.state.wallet.substring(0,2) !== "0x")||(this.state.wallet.length !== 42)) - { - this.setState( - {showModal:true, modalTitle: 'requiredFieldsTitle', - modalMessage: 'notValidAddr', modalIcon: 'ExclamationTriangle', - waitToClose: false, - modalButtonMessage: 'closeBtn', modalButtonVariant: '#E63C36' - }); - return false; - } - } - if (this.state.blockchain === "Tron"){ - if((this.state.wallet.substring(0,1) !== "T")||(this.state.wallet.length !== 34)) - { - this.setState( - {showModal:true, modalTitle: 'requiredFieldsTitle', - modalMessage: 'notValidAddr', modalIcon: 'ExclamationTriangle', - waitToClose: false, - modalButtonMessage: 'closeBtn', modalButtonVariant: '#E63C36' - }); - return false; - } - } - let n = 0; - let EditorStateEn = await getEditorStateEn(); - if (EditorStateEn){ - for (let i = 0; i < EditorStateEn.blocks.length; i++){ - n = n + EditorStateEn.blocks[i].text.length; - } - if (n < 3) { - this.setState( - {showModal:true, modalTitle: 'requiredFieldsTitle', - modalMessage: 'longDescRequired', modalIcon: 'ExclamationTriangle', - waitToClose: false, - modalButtonMessage: 'closeBtn', modalButtonVariant: '#E63C36' - }); - return false; - } - for (let i = 0; i < EditorStateEn.blocks.length; i++){ - for(let j = 0; j < EditorStateEn.blocks[i].text.length; j++){ - if (/^[А-Яа-я]*$/.test(EditorStateEn.blocks[i].text[j]) === true){ - this.setState( - {showModal:true, modalTitle: 'requiredFieldsTitle', - modalMessage: 'longDescEnIncludRu', modalIcon: 'ExclamationTriangle', - waitToClose: false, - modalButtonMessage: 'closeBtn', modalButtonVariant: '#E63C36' - }); - return false; - } - } - } - } - - this.setState({showModal:true, modalTitle: 'processingWait', - modalMessage: 'waitingForNetwork', - modalIcon:'HourglassSplit', - modalButtonVariant: "gold", waitToClose: true}); - var newImgUrl = this.state.mainImageURL; - if(this.state.updateImage) { - newImgUrl = await this.uploadImageS3('main'); - if(!newImgUrl) { - this.setState({showModal:true, - modalTitle: 'imageUploadFailed', - modalMessage: 'technicalDifficulties', - modalIcon:'XCircle', modalButtonMessage: 'returnHome', - modalButtonVariant: "#E63C36", waitToClose: false}); - return; + if ((this.state.blockchain === "Tron")&&(this.state.wallet.trim() !== "")){ + if((this.state.wallet.substring(0,1) !== "T")||(this.state.wallet.length !== 34)) + { + this.setState({notValidAddr:true}); + this.mistake = true; + } } - } - //updating existing HEOCampaign - if(this.state.updateMeta){ - if(!(await this.updateCampaign())) { - this.setState({showModal : true, - modalTitle: 'updatingAmountFailed', - modalMessage: this.state.currentError, - modalIcon:'XCircle', modalButtonMessage: 'closeBtn', - modalButtonVariant: "#E63C36", waitToClose: false}); - return; + let n = 0; + let EditorStateEn = await getEditorStateEn(); + if(!EditorStateEn){ + this.setState({longDescRequired:true}); + this.mistake = true; + } + if (EditorStateEn){ + for (let i = 0; i < EditorStateEn.blocks.length; i++){ + n = n + countWordsString(EditorStateEn.blocks[i].text); + } + if (n < 3) { + this.setState({longDescRequired:true}); + this.mistake = true; + } + for (let i = 0; i < EditorStateEn.blocks.length; i++){ + for(let j = 0; j < getEditorStateEn().blocks[i].text.length; j++){ + if (/^[А-Яа-я]*$/.test(getEditorStateEn().blocks[i].text[j]) === true){ + this.setState({longDescEnIncludRu:true}); + this.mistake = true; + } + } + } + } + var newImgUrl = this.state.mainImageURL; + if(this.state.updateImage) { + newImgUrl = await this.uploadImageS3('main', imgID); + if(!newImgUrl) { + this.setState({noCoverImage:true}); + this.mistake = true; + } + else this.setState({mainImageURL: newImgUrl}); + } + else if(this.state.mainImageURL === "") { + this.setState({noCoverImage:true}); + this.mistake = true; + } + + if(this.mistake === true) this.setState({showModalМistakes:true}) + else{ + result = await this.updateCampaign(); + if (result === false) + this.setState({showModal : true, + modalTitle: 'failed', + modalMessage: 'errorWritingCampaignToDB', + modalIcon:'XCircle', modalButtonMessage: 'closeBtn', + modalButtonVariant: "#E63C36", waitToClose: false}); + else this.setState({ + showModal: true, modalTitle: 'complete', goHome: true, + modalMessage: 'updateSuccessfull', + modalIcon: 'CheckCircle', modalButtonMessage: 'closeBtn', + modalButtonVariant: '#588157', waitToClose: false + }); + } + } catch(error) { + console.log(error); } - result = await this.updateCampaign(); - if (result === false) - this.setState({showModal : true, - modalTitle: 'failed', - modalMessage: 'errorWritingCampaignToDB', - modalIcon:'XCircle', modalButtonMessage: 'closeBtn', - modalButtonVariant: "#E63C36", waitToClose: false}); - else this.setState({ - showModal: true, modalTitle: 'complete', goHome: true, - modalMessage: 'updateSuccessfull', - modalIcon: 'CheckCircle', modalButtonMessage: 'closeBtn', - modalButtonVariant: '#588157', waitToClose: false - }); } async updateCampaign() { @@ -386,15 +278,11 @@ class EditCampaign extends React.Component { data.org["en"] = this.state.orgEn; data.org["default"] = this.state.orgEn; data.org["ru"] = this.state.orgRu; - data.addresses = this.state.addresses; - data.accounts = this.state.line_accounts; data.payout_chain = this.state.blockchain; data.payout_address = this.state.wallet; - console.log(`Updating title to`); - console.log(data.title); - console.log(`Updating org to`); - console.log(data.org); - let dataForDB = {address: this.state.campaignId, dataToUpdate: data}; + if(this.mistake === true) data.complete = false; + else data.complete = true; + let dataForDB = {address: this.state.campaignId, dataToUpdate: data}; try { let res = await axios.post('/api/campaign/update', {mydata : dataForDB}, {headers: {"Content-Type": "application/json"}}); @@ -417,34 +305,63 @@ class EditCampaign extends React.Component { } } - async uploadImageS3(type) { - this.setState({showModal:true, modalTitle: 'processingWait', - modalMessage: 'uploadingImageWait', modalIcon:'HourglassSplit', - modalButtonVariant: "gold", waitToClose: true}); - let imgID = this.state.imgID; + async uploadImageS3 (type, imgID) { + this.setState( + {showModal:true, modalTitle: 'processingWait', + modalMessage: 'uploadingImageWait', modalIcon: 'HourglassSplit', + modalButtonVariant: "gold", waitToClose: true + }); + if(type === 'main' && (!this.state.mainImageFile || !this.state.mainImageFile.type)) { + this.setState({noCoverImage:true, showModal:false}); + return false; + } + let fileType; const formData = new FormData(); if(type === 'main') { - this.setState({ imageFileName : imgID,}); - let fileType = this.state.mainImageFile.type.split("/")[1]; + fileType = this.state.mainImageFile.type.split("/")[1]; formData.append( "myFile", this.state.mainImageFile, `${imgID}.${fileType}`, ); + } else if(type === 'qrCode') { + fileType = this.state.qrCodeImageFile.type.split("/")[1]; + formData.append( + "myFile", + this.state.qrCodeImageFile, + `${imgID}.${fileType}`, + ); } try { let res = await axios.post('/api/uploadimage', formData); - if(type === 'main') { - this.setState({showModal: false, mainImageURL: res.data}); + if((res)&&(res.data)) { + this.setState({showModal:false}); + return (res.data); + } else { + this.setState({noCoverImage:true, showModal:false}); + return false; } - return res.data; - } catch (err) { - if(err.response) { - this.setState({currentError : 'technicalDifficulties'}); + } catch(err) { + if (err.response) { + console.log('response error in uploading main image- ' + err.response.status); + this.setState({showModal: true, goHome: false, + modalTitle: 'imageUploadFailed', + modalMessage: 'technicalDifficulties', + modalIcon: 'XCircle', modalButtonMessage: 'returnHome', + modalButtonVariant: "#E63C36", waitToClose: false}); } else if (err.request) { - this.setState({currentError : 'checkYourConnection'}); + console.log('No response in uploading main image' + err.message); + this.setState({showModal: true, goHome: false, + modalTitle: 'imageUploadFailed', + modalMessage: 'checkYourConnection', + modalIcon: 'XCircle', modalButtonMessage: 'returnHome', + modalButtonVariant: "#E63C36", waitToClose: false}); } else { - this.setState({currentError : ''}); + console.log('error uploading image ' + err.message); + this.setState({showModal: true, goHome: false, + modalTitle: 'imageUploadFailed', + modalIcon: 'XCircle', modalButtonMessage: 'returnHome', + modalButtonVariant: "#E63C36", waitToClose: false}); } return false; } @@ -453,6 +370,66 @@ class EditCampaign extends React.Component { render() { return (
+ {}} className='myModal' centered> + +

+ + +

+ +
+ + + {(this.state.orgEn === "")&&

} + {(this.state.cn === "")&&

} + {(this.state.badWebsite === true)&&

} + {(this.state.titleEn === "")&&

} + {(this.state.descriptionEn === "")&&

} + {(this.state.email === "")&&

} + {(this.state.badEmail === true)&&

} + {(this.state.noCountryCode === true)&&

} + {(this.state.wallet === "")&&

} + {(this.state.notValidAddr === true)&&

} + {(this.state.longDescRequired === true)&&

} + {(this.state.longDescEnIncludRu === true)&&

} + {(this.state.noCoverImage=== true)&&

} +
+ + + + + + + + + +
+
{}} className='myModal' centered>

{this.state.modalIcon === 'CheckCircle' && } @@ -681,12 +658,8 @@ class EditCampaign extends React.Component { - - - {blockchains.map((data) => - - )} - + - - - {this.state.addresses[this.state.chainId] && - - } - - - {this.state.addresses[this.state.tronChainId] && - - } - - - - - - - {(((!this.state.addresses[this.state.tronChainId])||(!this.state.addresses[this.state.chainId]))&&(window.ethereum||window.tron)&&(this.state.active)) && - - {(!this.state.addresses[this.state.chainId] && window.ethereum)&& { - await this.saveToEtherium(true); - }} >Etherium} - {(!this.state.addresses[this.state.tronChainId] && window.tron)&& { - await this.savetoTron(true); - }}>Tron} - } - + +

@@ -871,10 +818,6 @@ class EditCampaign extends React.Component { this.setState({website : dbCampaignObj.website}); if (dbCampaignObj.telegram) this.setState({telegram : dbCampaignObj.telegram}); - console.log(`Set title to`); - console.log(this.state.ogTitle); - console.log(`Set org to`); - console.log(this.state.ogOrg); } } diff --git a/src/components/TRC20.js b/src/components/TRC20.js new file mode 100644 index 0000000..14494cf --- /dev/null +++ b/src/components/TRC20.js @@ -0,0 +1,3 @@ +const abi = [{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_upgradedAddress","type":"address"}],"name":"deprecate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"deprecated","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_evilUser","type":"address"}],"name":"addBlackList","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"upgradedAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"maximumFee","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"unpause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_maker","type":"address"}],"name":"getBlackListStatus","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"paused","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_subtractedValue","type":"uint256"}],"name":"decreaseApproval","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"who","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_value","type":"uint256"}],"name":"calcFee","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"pause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"who","type":"address"}],"name":"oldBalanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newBasisPoints","type":"uint256"},{"name":"newMaxFee","type":"uint256"}],"name":"setParams","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"amount","type":"uint256"}],"name":"issue","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_addedValue","type":"uint256"}],"name":"increaseApproval","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"amount","type":"uint256"}],"name":"redeem","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"remaining","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"basisPointsRate","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"isBlackListed","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_clearedUser","type":"address"}],"name":"removeBlackList","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"MAX_UINT","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_blackListedUser","type":"address"}],"name":"destroyBlackFunds","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_initialSupply","type":"uint256"},{"name":"_name","type":"string"},{"name":"_symbol","type":"string"},{"name":"_decimals","type":"uint8"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_blackListedUser","type":"address"},{"indexed":false,"name":"_balance","type":"uint256"}],"name":"DestroyedBlackFunds","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"Issue","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"Redeem","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"newAddress","type":"address"}],"name":"Deprecate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_user","type":"address"}],"name":"AddedBlackList","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_user","type":"address"}],"name":"RemovedBlackList","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"feeBasisPoints","type":"uint256"},{"indexed":false,"name":"maxFee","type":"uint256"}],"name":"Params","type":"event"},{"anonymous":false,"inputs":[],"name":"Pause","type":"event"},{"anonymous":false,"inputs":[],"name":"Unpause","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"}]; + +export default abi; diff --git a/src/components/TextEditor.js b/src/components/TextEditor.js index 0a0d93b..b82f3aa 100644 --- a/src/components/TextEditor.js +++ b/src/components/TextEditor.js @@ -423,6 +423,7 @@ class TextEditorEn extends TextEditor{ componentDidMount() { if(STOREDSTATEEN.length) { this.setState({editorState : EditorState.createWithContent(STOREDSTATEEN, this.createDecorator())}); + } else { this.setState({editorState : EditorState.createEmpty(this.createDecorator())}); } @@ -504,6 +505,8 @@ class TextEditorRu extends TextEditor{ componentDidMount() { if(STOREDSTATERU.length) { this.setState({editorState : EditorState.createWithContent(STOREDSTATERU, this.createDecorator())}); + DESCRIPTIONRAWRU = convertToRaw(this.state.editorState.getCurrentContent()); + STATEHASCHANGEDRU = true; } else { this.setState({editorState : EditorState.createEmpty(this.createDecorator())}); } @@ -568,6 +571,7 @@ class TextEditorRu extends TextEditor{ function setEditorState(storedState, hasContent) { if(hasContent) { + const contentState = convertFromRaw(storedState); STOREDSTATE = contentState; } else { @@ -577,6 +581,7 @@ class TextEditorRu extends TextEditor{ function setEditorStateEn(storedState, hasContent) { if(hasContent) { + DESCRIPTIONRAWEN = storedState; const contentState = convertFromRaw(storedState); STOREDSTATEEN = contentState; } else { diff --git a/src/components/UserCampaigns.js b/src/components/UserCampaigns.js index 4a783ed..895bda0 100644 --- a/src/components/UserCampaigns.js +++ b/src/components/UserCampaigns.js @@ -349,9 +349,6 @@ class UserCampaigns extends Component { - {item.new && - - } diff --git a/src/lang/translationEN.json b/src/lang/translationEN.json index cf0affb..5ce952d 100644 --- a/src/lang/translationEN.json +++ b/src/lang/translationEN.json @@ -62,7 +62,7 @@ "campaignDescription": "Campaign description", "createCampaignBtn": "CREATE CAMPAIGN", "noUserCampaigns": "You did not create any campaigns yet. Click <1>here to create your first campaign", - "saveCampaignBtn" : "SAVE CAMPAIGN", + "saveCampaignBtn" : "Save campaign", "complete" : "Complete!", "updateSuccessfull" : "Updated Campaign information successfully", "closeBtn" : "Close", @@ -241,6 +241,13 @@ "campaignURL":"Campaign URL", "campaignURLPlaceHolder":"Symbols which will appear in campaign’s address after https://app.heo.finance/campaign/", "campaignURLBad":"This campaign URL already exists in the database, enter another", - "countryCodeRequired": "Please select the country code for the tefon number" + "countryCodeRequired": "Please select the country code for the tefon number", + "notValidAddr":"Not valid wallet address", + "blockchain":"Blockchain", + "wallet": "Wallet address", + "payout":"Payout address", + "enterWallet":"Please enter wallet address", + "campaignSaved":"Campaign saved to database", + "campaignSavedWithErrors":"Campaign saved in database with errors" } diff --git a/src/lang/translationRU.json b/src/lang/translationRU.json index c831ad2..bd15132 100644 --- a/src/lang/translationRU.json +++ b/src/lang/translationRU.json @@ -58,7 +58,7 @@ "campaignDescription": "Описание кампании", "createCampaignBtn": "СОЗДАТЬ КАМПАНИЮ", "noUserCampaigns": "Вы ещё не запустили кампании. Нажмите <1>сюда чтобы создать первую кампанию", - "saveCampaignBtn" : "СОХРАНИТЬ", + "saveCampaignBtn" : "Сохранить кампанию", "complete" : "Успешно!", "updateSuccessfull" : "Информация о кампании успешно обновлена", "closeBtn" : "Закрыть", @@ -237,5 +237,12 @@ "campaignURL":"URL кампании", "campaignURLPlaceHolder":"Символы, которые появятся в адресе кампании после https://app.heo.finance/campaign/", "campaignURLBad":"Такой URL кампании уже есть в базе данных, введите другой", - "countryCodeRequired": "Пожалуйста, выберите код страны для телефонного номера" + "countryCodeRequired": "Пожалуйста, выберите код страны для телефонного номера", + "notValidAddr":"Недопустимый адрес кошелька", + "blockchain":"Блокчейн", + "wallet": "Адрес кошелька", + "payout":"Адрес для выплат", + "enterWallet":"Пожалуйста, введите адрес кошелька", + "campaignSaved":"Кампания сохранена в базе данных", + "campaignSavedWithErrors":"Кампания сохранена в базе данных с ошибками" } diff --git a/src/util/Utilities.js b/src/util/Utilities.js index 8604201..6a84376 100644 --- a/src/util/Utilities.js +++ b/src/util/Utilities.js @@ -163,7 +163,7 @@ const getTronWeb = async () => { return tronWeb; } -const initTron = async (chainId, that) => { +const initTron = async (chainId) => { if(!window.tronWeb) { window.tronWeb = await getTronWeb(); @@ -415,11 +415,21 @@ const encryptCardData = async(keyData, cardData) => { return btoa(encrypted); } +function countWordsString(string){ + var counter = 0; + string=string.replace(/[\s]+/gim, ' '); + string.replace(/(\s+)/g, function (a) { + counter++; + }); + return counter; +} + const blockchains = [ {value:"Ethereum"}, {value:"Tron"} ]; export {DescriptionPreview, i18nString, GetLanguage, LogIn, initWeb3, checkAuth, initWeb3Modal, clearWeb3Provider,clearTronProvider, - getPCIPublicKey, encryptCardData, LogInTron, initTronadapter, checkAuthTron, initTron, getTronWeb, checkEmail, isValidUrl,blockchains}; + getPCIPublicKey, encryptCardData, LogInTron, initTronadapter, checkAuthTron, initTron, getTronWeb, checkEmail, isValidUrl,blockchains, + countWordsString}; export default Utilities;