Skip to content

Commit

Permalink
F #2544 ability to withdraw any tokens bigger than withdraw limit
Browse files Browse the repository at this point in the history
  • Loading branch information
RamRamez committed Sep 27, 2021
1 parent 8b9c763 commit 6503e6e
Show file tree
Hide file tree
Showing 9 changed files with 107 additions and 21 deletions.
10 changes: 8 additions & 2 deletions src/components/TraceConversationAction.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable react/prefer-stateless-function */
// @dev: not prefering stateless here because functionality will be extended
// @dev: not preferring stateless here because functionality will be extended
import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types';

Expand All @@ -16,7 +16,7 @@ import LPTrace from '../models/LPTrace';

class TraceConversationAction extends Component {
render() {
const { messageContext, trace, isAmountEnoughForWithdraw } = this.props;
const { messageContext, trace, isAmountEnoughForWithdraw, withdrawalTokens } = this.props;

switch (messageContext) {
case 'proposed':
Expand All @@ -38,6 +38,7 @@ class TraceConversationAction extends Component {
<WithdrawTraceFundsButton
trace={trace}
isAmountEnoughForWithdraw={isAmountEnoughForWithdraw}
withdrawalTokens={withdrawalTokens}
/>
);

Expand Down Expand Up @@ -68,6 +69,11 @@ TraceConversationAction.propTypes = {
).isRequired,
messageContext: PropTypes.string.isRequired,
isAmountEnoughForWithdraw: PropTypes.bool.isRequired,
withdrawalTokens: PropTypes.arrayOf(PropTypes.shape({})),
};

TraceConversationAction.defaultProps = {
withdrawalTokens: [],
};

export default React.memo(TraceConversationAction);
13 changes: 12 additions & 1 deletion src/components/TraceConversationItem.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,12 @@ const getEtherScanUrl = ({ messageContext }) =>
? config.homeEtherscan
: config.etherscan;

function TraceConversationItem({ conversation, trace, isAmountEnoughForWithdraw }) {
function TraceConversationItem({
conversation,
trace,
isAmountEnoughForWithdraw,
withdrawalTokens,
}) {
if (!conversation) return null;
const { txHash, messageContext, message, performedByRole, createdAt, owner } = conversation;

Expand Down Expand Up @@ -180,6 +185,7 @@ function TraceConversationItem({ conversation, trace, isAmountEnoughForWithdraw
messageContext={messageContext}
trace={trace}
isAmountEnoughForWithdraw={isAmountEnoughForWithdraw}
withdrawalTokens={withdrawalTokens}
/>
</div>

Expand All @@ -195,6 +201,11 @@ TraceConversationItem.propTypes = {
).isRequired,
conversation: PropTypes.instanceOf(Object).isRequired,
isAmountEnoughForWithdraw: PropTypes.bool.isRequired,
withdrawalTokens: PropTypes.arrayOf(PropTypes.shape({})),
};

TraceConversationItem.defaultProps = {
withdrawalTokens: [],
};

export default React.memo(TraceConversationItem);
5 changes: 4 additions & 1 deletion src/components/TraceConversations.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import BridgedTrace from '../models/BridgedTrace';
import LPPCappedTrace from '../models/LPPCappedTrace';
import LPTrace from '../models/LPTrace';

const TraceConversations = ({ trace, maxHeight, isAmountEnoughForWithdraw }) => {
const TraceConversations = ({ trace, maxHeight, isAmountEnoughForWithdraw, withdrawalTokens }) => {
const conversationsNumPerLoad = 5;
const [conversations, setConversations] = useState({});
const [isLoading, setLoading] = useState(true);
Expand Down Expand Up @@ -66,6 +66,7 @@ const TraceConversations = ({ trace, maxHeight, isAmountEnoughForWithdraw }) =>
conversation={conversation}
trace={trace}
isAmountEnoughForWithdraw={isAmountEnoughForWithdraw}
withdrawalTokens={withdrawalTokens}
/>
))}
</div>
Expand All @@ -85,10 +86,12 @@ TraceConversations.propTypes = {
).isRequired,
maxHeight: PropTypes.string,
isAmountEnoughForWithdraw: PropTypes.bool.isRequired,
withdrawalTokens: PropTypes.arrayOf(PropTypes.shape({})),
};

TraceConversations.defaultProps = {
maxHeight: 'unset',
withdrawalTokens: [],
};

export default React.memo(TraceConversations);
8 changes: 7 additions & 1 deletion src/components/ViewTraceAlerts.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import BridgedTrace from '../models/BridgedTrace';
import LPPCappedTrace from '../models/LPPCappedTrace';
import LPTrace from '../models/LPTrace';

const ViewTraceAlerts = ({ trace, campaign, isAmountEnoughForWithdraw }) => {
const ViewTraceAlerts = ({ trace, campaign, isAmountEnoughForWithdraw, withdrawalTokens }) => {
const {
state: { currentUser, userIsCommunityOwner },
} = useContext(UserContext);
Expand Down Expand Up @@ -92,6 +92,7 @@ const ViewTraceAlerts = ({ trace, campaign, isAmountEnoughForWithdraw }) => {
<WithdrawTraceFundsButton
trace={trace}
isAmountEnoughForWithdraw={isAmountEnoughForWithdraw}
withdrawalTokens={withdrawalTokens}
/>
</ProjectViewActionAlert>
)}
Expand All @@ -105,6 +106,11 @@ ViewTraceAlerts.propTypes = {
).isRequired,
campaign: PropTypes.instanceOf(Campaign).isRequired,
isAmountEnoughForWithdraw: PropTypes.bool.isRequired,
withdrawalTokens: PropTypes.arrayOf(PropTypes.shape({})),
};

ViewTraceAlerts.defaultProps = {
withdrawalTokens: [],
};

export default React.memo(ViewTraceAlerts);
50 changes: 44 additions & 6 deletions src/components/WithdrawTraceFundsButton.jsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import React, { Fragment, useContext } from 'react';
import React, { Fragment, useContext, useRef } from 'react';
import PropTypes from 'prop-types';
import { Modal, Select } from 'antd';

import TraceService from 'services/TraceService';
import Trace from 'models/Trace';
import { authenticateUser, checkBalance } from 'lib/middleware';
import { Modal } from 'antd';
import { Context as Web3Context } from '../contextProviders/Web3Provider';
import { Context as NotificationContext } from '../contextProviders/NotificationModalProvider';
import { Context as UserContext } from '../contextProviders/UserProvider';
import DonationBlockchainService from '../services/DonationBlockchainService';
import LPTrace from '../models/LPTrace';
import config from '../configuration';
import { Context as UserContext } from '../contextProviders/UserProvider';
import ErrorHandler from '../lib/ErrorHandler';
import BridgedTrace from '../models/BridgedTrace';
import LPPCappedTrace from '../models/LPPCappedTrace';
Expand All @@ -21,7 +21,7 @@ import {
} from '../services/ConversionRateService';
import { displayTransactionError, txNotification } from '../lib/helpers';

const WithdrawTraceFundsButton = ({ trace, isAmountEnoughForWithdraw }) => {
const WithdrawTraceFundsButton = ({ trace, isAmountEnoughForWithdraw, withdrawalTokens }) => {
const {
state: { currentUser },
} = useContext(UserContext);
Expand All @@ -33,6 +33,8 @@ const WithdrawTraceFundsButton = ({ trace, isAmountEnoughForWithdraw }) => {
actions: { minPayoutWarningInWithdraw },
} = useContext(NotificationContext);

const selectedTokens = useRef([]);

async function sendWithdrawAnalyticsEvent(txUrl) {
const donationsCounters = trace.donationCounters.filter(dc => dc.currentBalance.gt(0));
// eslint-disable-next-line no-restricted-syntax
Expand Down Expand Up @@ -85,6 +87,15 @@ const WithdrawTraceFundsButton = ({ trace, isAmountEnoughForWithdraw }) => {
minPayoutWarningInWithdraw();
return;
}

let defaultValue;
if (withdrawalTokens.length === 1) {
const token = withdrawalTokens[0];
// eslint-disable-next-line react/prop-types
defaultValue = token.address;
selectedTokens.current = defaultValue;
}

Modal.confirm({
title: isRecipient ? 'Withdrawal Funds to Wallet' : 'Disburse Funds to Recipient',
content: (
Expand All @@ -111,16 +122,39 @@ const WithdrawTraceFundsButton = ({ trace, isAmountEnoughForWithdraw }) => {
{isRecipient ? 'your' : "the recipient's"} wallet.
</div>
)}

<div className="my-3 font-weight-bold">Select tokens to withdraw:</div>
<Select
mode="multiple"
id="token-select"
allowClear
placeholder="------ Select tokens ------"
defaultValue={defaultValue}
onChange={address => {
selectedTokens.current = address;
}}
disabled={withdrawalTokens.length === 1}
style={{ width: '100%' }}
className="ant-select-custom-multiple"
>
{withdrawalTokens.map(item => (
<Select.Option value={item.address} key={item.symbol}>
{item.symbol}
</Select.Option>
))}
</Select>
</Fragment>
),
cancelText: 'Cancel',
okText: 'Yes, withdrawal',
okText: 'Withdrawal',
centered: true,
width: 500,
onOk: () =>
TraceService.withdraw({
web3,
trace,
from: userAddress,
selectedTokens: selectedTokens.current,
onTxHash: txUrl => {
sendWithdrawAnalyticsEvent(txUrl);
txNotification('Initiating withdrawal from Trace...', txUrl, true);
Expand All @@ -137,7 +171,6 @@ const WithdrawTraceFundsButton = ({ trace, isAmountEnoughForWithdraw }) => {
// TODO: need to update feathers to reset the donations to previous state as this
else displayTransactionError(txUrl);
},
web3,
}),
});
})
Expand Down Expand Up @@ -170,6 +203,11 @@ WithdrawTraceFundsButton.propTypes = {
[Trace, BridgedTrace, LPPCappedTrace, LPTrace].map(PropTypes.instanceOf),
).isRequired,
isAmountEnoughForWithdraw: PropTypes.bool.isRequired,
withdrawalTokens: PropTypes.arrayOf(PropTypes.shape({})),
};

WithdrawTraceFundsButton.defaultProps = {
withdrawalTokens: [],
};

export default React.memo(WithdrawTraceFundsButton);
21 changes: 14 additions & 7 deletions src/components/views/ViewTrace.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,16 @@ const ViewTrace = props => {
const [trace, setTrace] = useState({});
const [communityTitle, setCommunityTitle] = useState('');
const [notFound, setNotFound] = useState(false);
const [isAmountEnoughForWithdraw, setIsAmountEnoughForWithdraw] = useState(true);
const [currency, setCurrency] = useState(null);
const [currentBalanceValue, setCurrentBalanceValue] = useState(0);
const [currentBalanceUsdValue, setCurrentBalanceUsdValue] = useState(0);
const [withdrawalTokens, setWithdrawalTokens] = useState([]);

const donationsObserver = useRef();
const traceSubscription = useRef();
const newDonations = useRef(0);
const donationsPerBatch = 50;
const isAmountEnoughForWithdraw = withdrawalTokens.length > 0;

const getCommunityTitle = async communityId => {
if (communityId === 0) return;
Expand Down Expand Up @@ -196,16 +197,20 @@ const ViewTrace = props => {
if (!currentBalanceUsdValue) {
return;
}
const _withdrawalTokens = [];
// eslint-disable-next-line no-restricted-syntax
for (const currencyUsdValue of currentBalanceUsdValue) {
// if usdValue is zero we should not set setIsAmountEnoughForWithdraw(false) because we check
// minimumPayoutUsdValue comparison when usdValue for a currency is not zero
if (currencyUsdValue.usdValue && currencyUsdValue.usdValue < minimumPayoutUsdValue) {
setIsAmountEnoughForWithdraw(false);
return;
if (currencyUsdValue.usdValue >= minimumPayoutUsdValue) {
const token = activeTokenWhitelist.find(
_token => _token.symbol === currencyUsdValue.currency,
);
_withdrawalTokens.push(token);
}
}
setIsAmountEnoughForWithdraw(true);

if (_withdrawalTokens.length) {
setWithdrawalTokens(_withdrawalTokens);
}
}, [currentBalanceUsdValue]);

const isActiveTrace = () => {
Expand Down Expand Up @@ -380,6 +385,7 @@ const ViewTrace = props => {
trace={trace}
campaign={campaign}
isAmountEnoughForWithdraw={isAmountEnoughForWithdraw}
withdrawalTokens={withdrawalTokens}
/>

<div id="description">
Expand Down Expand Up @@ -624,6 +630,7 @@ const ViewTrace = props => {
trace={trace}
isAmountEnoughForWithdraw={isAmountEnoughForWithdraw}
maxHeight={`${detailsCardHeight}px`}
withdrawalTokens={withdrawalTokens}
/>
</div>
</div>
Expand Down
3 changes: 1 addition & 2 deletions src/components/views/verification/Main.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,7 @@ const Verification = props => {
setStep(step + 1);
})
.catch(err => {
if (err.message) ErrorHandler(err, err.message);
else ErrorHandler(err, 'Something went wrong!');
ErrorHandler(err, err.message);
})
.finally(() => setIsSaving(false));
};
Expand Down
7 changes: 6 additions & 1 deletion src/services/DonationBlockchainService.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -839,7 +839,7 @@ class DonationBlockchainService {
.then(({ total }) => total);
}

static async getTraceDonations(traceId) {
static async getTraceDonations(traceId, selectedTokens) {
const service = feathersClient.service('/donations');
let data = [];
let total;
Expand All @@ -857,6 +857,11 @@ class DonationBlockchainService {
$limit: spare || 1,
$sort: { tokenAddress: 1, pledgeId: 1 }, // group by token
};

if (selectedTokens) {
query.tokenAddress = { $in: selectedTokens };
}

// eslint-disable-next-line no-await-in-loop
const resp = await service.find({ query });

Expand Down
11 changes: 11 additions & 0 deletions src/styles/_antOverrides.scss
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,17 @@
}
}

//Ant custom multi select with ant-select-custom-multiple class
.ant-select-custom-multiple {
.ant-select-selection-overflow {
margin-top: -3px;
}
.ant-select-selection-item {
line-height: 30px !important;
height: 30px;
}
}

.ant-picker {
width: 100%;
border: 2px solid #dfdae8;
Expand Down

0 comments on commit 6503e6e

Please sign in to comment.