Skip to content

Commit

Permalink
Show short details about account + warn about merged wallets (#2992)
Browse files Browse the repository at this point in the history
Co-authored-by: miko <sauce47@posteo.net>
  • Loading branch information
keikari and miko authored Oct 12, 2023
1 parent f900045 commit b8ff3e2
Show file tree
Hide file tree
Showing 11 changed files with 227 additions and 27 deletions.
2 changes: 2 additions & 0 deletions flow-typed/Claims.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ declare type ClaimsState = {
abandoningById: { [string]: boolean },
fetchingChannelClaims: { [string]: number },
fetchingMyChannels: boolean,
fetchingMyChannelsSuccess: ?boolean,
fetchingClaimSearchByQuery: { [string]: boolean },
purchaseUriSuccess: boolean,
myPurchases: ?Array<string>,
Expand Down Expand Up @@ -49,6 +50,7 @@ declare type ClaimsState = {
myClaimsPageNumber: ?number,
myClaimsPageTotalResults: ?number,
isFetchingClaimListMine: boolean,
isFetchingClaimListMineSuccess: ?boolean,
isCheckingNameForPublish: boolean,
checkingPending: boolean,
checkingReflecting: boolean,
Expand Down
5 changes: 5 additions & 0 deletions static/app-strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2952,6 +2952,11 @@
"Remove content and send deletion request" : "Remove content and send deletion request",
"Remove content" : "Remove content",
"IMPORTANT: this donation is sent without a comment. If you want to include a comment, click the $ next to the comment input area.": "IMPORTANT: this donation is sent without a comment. If you want to include a comment, click the $ next to the comment input area.",
"Failed to load account info. If the issue persists, please reach out to help@odysee.com for support.": "Failed to load account info. If the issue persists, please reach out to help@odysee.com for support.",
"We detected multiple wallets on this account. Please make sure this account doesn't have any credits, publications or channels that you don't want to lose. If you aren't sure, please reach out to help@odysee.com for support.": "We detected multiple wallets on this account. Please make sure this account doesn't have any credits, publications or channels that you don't want to lose. If you aren't sure, please reach out to help@odysee.com for support.",
"Credits: %credits%": "Credits: %credits%",
"Publications: %claims%": "Publications: %claims%",
"Channels:": "Channels",

"--end--": "--end--"
}
4 changes: 4 additions & 0 deletions ui/constants/action_types.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ export const GET_NEW_ADDRESS_COMPLETED = 'GET_NEW_ADDRESS_COMPLETED';
export const FETCH_TRANSACTIONS_STARTED = 'FETCH_TRANSACTIONS_STARTED';
export const FETCH_TRANSACTIONS_COMPLETED = 'FETCH_TRANSACTIONS_COMPLETED';
export const FETCH_TRANSACTIONS_FAILED = 'FETCH_TRANSACTIONS_FAILED';
export const FETCH_ACCOUNT_LIST_STARTED = 'FETCH_ACCOUNT_LIST_STARTED';
export const FETCH_ACCOUNT_LIST_COMPLETED = 'FETCH_ACCOUNT_LIST_COMPLETED';
export const FETCH_ACCOUNT_LIST_FAILED = 'FETCH_ACCOUNT_LIST_FAILED';
export const UPDATE_BALANCE = 'UPDATE_BALANCE';
export const CHECK_ADDRESS_IS_MINE_STARTED = 'CHECK_ADDRESS_IS_MINE_STARTED';
export const CHECK_ADDRESS_IS_MINE_COMPLETED = 'CHECK_ADDRESS_IS_MINE_COMPLETED';
Expand Down Expand Up @@ -164,6 +167,7 @@ export const FETCH_CHANNEL_CLAIMS_COMPLETED = 'FETCH_CHANNEL_CLAIMS_COMPLETED';
export const FETCH_CHANNEL_CLAIM_COUNT_STARTED = 'FETCH_CHANNEL_CLAIM_COUNT_STARTED';
export const FETCH_CLAIM_LIST_MINE_STARTED = 'FETCH_CLAIM_LIST_MINE_STARTED';
export const FETCH_CLAIM_LIST_MINE_COMPLETED = 'FETCH_CLAIM_LIST_MINE_COMPLETED';
export const FETCH_CLAIM_LIST_MINE_FAILED = 'FETCH_CLAIM_LIST_MINE_FAILED';
export const ABANDON_CLAIM_STARTED = 'ABANDON_CLAIM_STARTED';
export const ABANDON_CLAIM_SUCCEEDED = 'ABANDON_CLAIM_SUCCEEDED';
export const FETCH_CHANNEL_LIST_STARTED = 'FETCH_CHANNEL_LIST_STARTED';
Expand Down
29 changes: 28 additions & 1 deletion ui/modal/modalRemoveAccount/index.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,45 @@
import { connect } from 'react-redux';
import {
selectMyChannelClaimUrls,
selectFetchingMyChannels,
selectFetchingMyChannelsSuccess,
selectIsFetchingClaimListMine,
selectIsFetchingClaimListMineSuccess,
selectMyClaimsPageItemCount,
} from 'redux/selectors/claims';
import { doHideModal } from 'redux/actions/app';
import { selectTotalBalance } from 'redux/selectors/wallet';
import {
selectTotalBalance,
selectIsFetchingAccounts,
selectIsWalletMerged,
selectIsFetchingAccountsSuccess,
} from 'redux/selectors/wallet';
import { doFetchAccountList } from 'redux/actions/wallet';
import { selectUser } from 'redux/selectors/user';
import { doFetchChannelListMine, doFetchClaimListMine } from 'redux/actions/claims';
import { doRemoveAccountSequence } from './thunk';
import ModalRemoveAccount from './view';

const select = (state) => ({
isPendingDeletion: selectUser(state)?.pending_deletion,
totalBalance: selectTotalBalance(state),
totalClaimsCount: selectMyClaimsPageItemCount(state),
channelUrls: selectMyChannelClaimUrls(state),
isFetchingChannels: selectFetchingMyChannels(state),
isFetchingChannelsSuccess: selectFetchingMyChannelsSuccess(state),
isFetchingClaims: selectIsFetchingClaimListMine(state),
isFetchingClaimsSuccess: selectIsFetchingClaimListMineSuccess(state),
isFetchingAccounts: selectIsFetchingAccounts(state),
isFetchingAccountsSuccess: selectIsFetchingAccountsSuccess(state),
isWalletMerged: selectIsWalletMerged(state),
});

const perform = {
doHideModal,
doRemoveAccountSequence,
doFetchChannelListMine,
doFetchClaimListMine,
doFetchAccountList,
};

export default connect(select, perform)(ModalRemoveAccount);
125 changes: 102 additions & 23 deletions ui/modal/modalRemoveAccount/view.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,66 @@ import { FormField } from 'component/common/form';
type Props = {
isPendingDeletion: ?boolean,
totalBalance: number,
totalClaimsCount: number,
isFetchingChannels: boolean,
isFetchingChannelsSuccess: ?boolean,
isFetchingClaims: boolean,
isFetchingClaimsSuccess: ?boolean,
isFetchingAccounts: boolean,
isFetchingAccountsSuccess: ?boolean,
isWalletMerged: ?boolean,
channelUrls: ?Array<string>,
doHideModal: () => void,
doRemoveAccountSequence: () => Promise<any>,
doFetchChannelListMine: () => void,
doFetchClaimListMine: (page: number, pageSize: number, resolve: boolean) => void,
doFetchAccountList: () => void,
};

export default function ModalRemoveAccount(props: Props) {
const { isPendingDeletion, totalBalance, doHideModal, doRemoveAccountSequence } = props;
const {
isPendingDeletion,
totalBalance,
totalClaimsCount,
isFetchingChannels,
isFetchingChannelsSuccess,
isFetchingClaims,
isFetchingClaimsSuccess,
isFetchingAccounts,
isFetchingAccountsSuccess,
isWalletMerged,
channelUrls,
doHideModal,
doRemoveAccountSequence,
doFetchChannelListMine,
doFetchClaimListMine,
doFetchAccountList,
} = props;

const [buttonClicked, setButtonClicked] = React.useState(false);
const [status, setStatus] = React.useState(null);
const [isBusy, setIsBusy] = React.useState(false);
const [isForfeitChecked, setIsForfeitChecked] = React.useState(false);

const isWalletEmpty = totalBalance <= 0.005;
const showButton = !buttonClicked && (!isPendingDeletion || !isWalletEmpty);
const isLoadingAccountInfo = isFetchingChannels || isFetchingAccounts || isFetchingClaims;
const isLoadingAccountInfoSuccess = isFetchingChannelsSuccess && isFetchingAccountsSuccess && isFetchingClaimsSuccess;
const showButton =
!buttonClicked &&
(!isPendingDeletion || !isWalletEmpty) &&
isLoadingAccountInfoSuccess &&
!isLoadingAccountInfo;

React.useEffect(() => {
if (!isPendingDeletion || !isWalletEmpty) {
doFetchAccountList();
const page = 1,
pageSize = 1,
resolve = false;
doFetchClaimListMine(page, pageSize, resolve);
doFetchChannelListMine();
}
}, [isPendingDeletion, isWalletEmpty, doFetchAccountList, doFetchClaimListMine, doFetchChannelListMine]);

async function handleOnClick() {
setButtonClicked(true);
Expand All @@ -42,25 +88,49 @@ export default function ModalRemoveAccount(props: Props) {
<Card
title={__('Delete account')}
subtitle={
isBusy
? ''
: status === 'error_occurred'
? __(
'Sorry, there may have been an issue when wiping the account and/or sending the deletion request. Please check back in few minutes, and try again. If the issue persists please contact help@odysee.com for possible next steps.'
)
: isPendingDeletion && isWalletEmpty && !buttonClicked
? __('Account has already been queued for deletion.')
: isPendingDeletion && !isWalletEmpty && !buttonClicked
? __(
'Account has already been queued for deletion. If you still have content/credits on the account which you want removed, click "Remove content".'
)
: !isPendingDeletion && !buttonClicked
? __(
"Remove all content from the account and send a deletion request to Odysee. Removing the content is a permanent action and can't be undone."
)
: __(
'Account has been queued for deletion, and content has been removed. You will receive an email confirmation once the deletion is completed. It may take few minutes for content to completely disappear.'
)
<>
{isBusy
? ''
: !isLoadingAccountInfo && !isLoadingAccountInfoSuccess
? __(
'Failed to load account info. If the issue persists, please reach out to help@odysee.com for support.'
)
: status === 'error_occurred'
? __(
'Sorry, there may have been an issue when wiping the account and/or sending the deletion request. Please check back in few minutes, and try again. If the issue persists please contact help@odysee.com for possible next steps.'
)
: isPendingDeletion && isWalletEmpty && !buttonClicked
? __('Account has already been queued for deletion.')
: isPendingDeletion && !isWalletEmpty && !buttonClicked
? __(
'Account has already been queued for deletion. If you still have content/credits on the account which you want removed, click "Remove content".'
)
: !isPendingDeletion && !buttonClicked
? __(
"Remove all content from the account and send a deletion request to Odysee. Removing the content is a permanent action and can't be undone."
)
: __(
'Account has been queued for deletion, and content has been removed. You will receive an email confirmation once the deletion is completed. It may take few minutes for content to completely disappear.'
)}
{showButton && (
<div className="help">
<p>{__('Credits: %credits%', { credits: totalBalance })}</p>
<p>{__('Publications: %claims%', { claims: totalClaimsCount })}</p>
{channelUrls && (
<>
<p>{__('Channels:')}</p>
<ul>
{channelUrls.map((url) => {
const name = [].concat(url.match(/@[^#]+/)).pop();
const claimId = [].concat(url.match(/[a-f0-9]+$/)).pop();
return <li key={claimId}>{name}</li>;
})}
</ul>
</>
)}
</div>
)}
</>
}
className="confirm__wrapper"
actions={
Expand All @@ -75,9 +145,18 @@ export default function ModalRemoveAccount(props: Props) {
onChange={() => setIsForfeitChecked(!isForfeitChecked)}
/>
)}
{showButton && isWalletMerged && (
<div className="help--warning">
<p>
{__(
"We detected multiple wallets on this account. Please make sure this account doesn't have any credits, publications or channels that you don't want to lose. If you aren't sure, please reach out to help@odysee.com for support."
)}
</p>
</div>
)}
<div className="section__actions">
{isBusy ? (
<BusyIndicator message={__('Removing content...')} />
{isBusy || isLoadingAccountInfo ? (
<BusyIndicator message={isBusy ? __('Removing content...') : __('Loading account info...')} />
) : (
showButton && (
<Button
Expand Down
6 changes: 5 additions & 1 deletion ui/redux/actions/claims.js
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,8 @@ export function doFetchClaimListMine(
page_size: pageSize,
claim_type: claimTypes,
resolve,
}).then(async (result: StreamListResponse) => {
})
.then(async (result: StreamListResponse) => {
dispatch({
type: ACTIONS.FETCH_CLAIM_LIST_MINE_COMPLETED,
data: {
Expand Down Expand Up @@ -324,6 +325,9 @@ export function doFetchClaimListMine(
if (fetchViewCount && claimIds.length > 0) {
dispatch(doFetchViewCount(claimIds.join(',')));
}
})
.catch(() => {
dispatch({ type: ACTIONS.FETCH_CLAIM_LIST_MINE_FAILED });
});
};
}
Expand Down
22 changes: 22 additions & 0 deletions ui/redux/actions/wallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
selectPendingOtherTransactions,
selectPendingConsolidateTxid,
selectPendingMassClaimTxid,
selectIsFetchingAccounts,
} from 'redux/selectors/wallet';
import { resolveApiMessage } from 'util/api-message';
import { creditsToString } from 'util/format-credits';
Expand Down Expand Up @@ -75,6 +76,27 @@ export function doUpdateBalance() {
};
}

export function doFetchAccountList(page = 1, pageSize = 99999) {
return (dispatch, getState) => {
const state = getState();
const isFetching = selectIsFetchingAccounts(state);

if (isFetching) return;

dispatch({ type: ACTIONS.FETCH_ACCOUNT_LIST_STARTED });

const callback = (response) => {
dispatch({ type: ACTIONS.FETCH_ACCOUNT_LIST_COMPLETED, data: response.items });
};

const failure = () => {
dispatch({ type: ACTIONS.FETCH_ACCOUNT_LIST_FAILED });
};

Lbry.account_list({ page, page_size: pageSize }).then(callback, failure);
};
}

export function doBalanceSubscribe() {
return (dispatch) => {
dispatch(doUpdateBalance());
Expand Down
14 changes: 13 additions & 1 deletion ui/redux/reducers/claims.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const defaultState: ClaimsState = {
fetchingMyPurchases: false,
fetchingMyPurchasesError: undefined,
fetchingMyChannels: false,
fetchingMyChannelsSuccess: undefined,
abandoningById: {},
pendingById: {},
reflectingById: {},
Expand All @@ -54,6 +55,7 @@ const defaultState: ClaimsState = {
myClaimsPageNumber: undefined,
myClaimsPageTotalResults: undefined,
isFetchingClaimListMine: false,
isFetchingClaimListMineSuccess: undefined,
isFetchingMyPurchases: false,
isCheckingNameForPublish: false,
checkingPending: false,
Expand Down Expand Up @@ -367,6 +369,7 @@ reducers[ACTIONS.RESOLVE_URIS_FAIL] = (state: ClaimsState, action: any): ClaimsS
reducers[ACTIONS.FETCH_CLAIM_LIST_MINE_STARTED] = (state: ClaimsState): ClaimsState =>
Object.assign({}, state, {
isFetchingClaimListMine: true,
isFetchingClaimListMineSuccess: undefined,
});

reducers[ACTIONS.FETCH_CLAIM_LIST_MINE_COMPLETED] = (state: ClaimsState, action: any): ClaimsState => {
Expand Down Expand Up @@ -430,6 +433,7 @@ reducers[ACTIONS.FETCH_CLAIM_LIST_MINE_COMPLETED] = (state: ClaimsState, action:
});

return Object.assign({}, state, {
isFetchingClaimListMineSuccess: true,
isFetchingClaimListMine: false,
myClaims: Array.from(myClaimIds),
resolvedCollectionsById: newResolvedCollectionsById,
Expand All @@ -443,8 +447,14 @@ reducers[ACTIONS.FETCH_CLAIM_LIST_MINE_COMPLETED] = (state: ClaimsState, action:
});
};

reducers[ACTIONS.FETCH_CLAIM_LIST_MINE_FAILED] = (state: ClaimsState): ClaimsState =>
Object.assign({}, state, {
isFetchingClaimListMine: false,
isFetchingClaimListMineSuccess: false,
});

reducers[ACTIONS.FETCH_CHANNEL_LIST_STARTED] = (state: ClaimsState): ClaimsState =>
Object.assign({}, state, { fetchingMyChannels: true });
Object.assign({}, state, { fetchingMyChannels: true, fetchingMyChannelsSuccess: undefined });

reducers[ACTIONS.FETCH_CHANNEL_LIST_COMPLETED] = (state: ClaimsState, action: any): ClaimsState => {
const { claims }: { claims: Array<ChannelClaim> } = action.data;
Expand Down Expand Up @@ -495,6 +505,7 @@ reducers[ACTIONS.FETCH_CHANNEL_LIST_COMPLETED] = (state: ClaimsState, action: an
claimsByUri: resolveDelta(state.claimsByUri, byUriDelta),
channelClaimCounts,
fetchingMyChannels: false,
fetchingMyChannelsSuccess: true,
myChannelClaimsById: newMyChannelClaimsById,
myClaims: myClaimIds ? Array.from(myClaimIds) : null,
});
Expand All @@ -503,6 +514,7 @@ reducers[ACTIONS.FETCH_CHANNEL_LIST_COMPLETED] = (state: ClaimsState, action: an
reducers[ACTIONS.FETCH_CHANNEL_LIST_FAILED] = (state: ClaimsState, action: any): ClaimsState => {
return Object.assign({}, state, {
fetchingMyChannels: false,
fetchingMyChannelsSuccess: false,
});
};

Expand Down
Loading

0 comments on commit b8ff3e2

Please sign in to comment.