From b8ff3e23795d47c20ce4079443774d35b829477a Mon Sep 17 00:00:00 2001 From: miko <34790748+keikari@users.noreply.github.com> Date: Thu, 12 Oct 2023 16:14:56 +0300 Subject: [PATCH] Show short details about account + warn about merged wallets (#2992) Co-authored-by: miko --- flow-typed/Claims.js | 2 + static/app-strings.json | 5 ++ ui/constants/action_types.js | 4 + ui/modal/modalRemoveAccount/index.js | 29 ++++++- ui/modal/modalRemoveAccount/view.jsx | 125 ++++++++++++++++++++++----- ui/redux/actions/claims.js | 6 +- ui/redux/actions/wallet.js | 22 +++++ ui/redux/reducers/claims.js | 14 ++- ui/redux/reducers/wallet.js | 39 +++++++++ ui/redux/selectors/claims.js | 4 +- ui/redux/selectors/wallet.js | 4 + 11 files changed, 227 insertions(+), 27 deletions(-) diff --git a/flow-typed/Claims.js b/flow-typed/Claims.js index 4c3b65d784..e5e17d53b9 100644 --- a/flow-typed/Claims.js +++ b/flow-typed/Claims.js @@ -20,6 +20,7 @@ declare type ClaimsState = { abandoningById: { [string]: boolean }, fetchingChannelClaims: { [string]: number }, fetchingMyChannels: boolean, + fetchingMyChannelsSuccess: ?boolean, fetchingClaimSearchByQuery: { [string]: boolean }, purchaseUriSuccess: boolean, myPurchases: ?Array, @@ -49,6 +50,7 @@ declare type ClaimsState = { myClaimsPageNumber: ?number, myClaimsPageTotalResults: ?number, isFetchingClaimListMine: boolean, + isFetchingClaimListMineSuccess: ?boolean, isCheckingNameForPublish: boolean, checkingPending: boolean, checkingReflecting: boolean, diff --git a/static/app-strings.json b/static/app-strings.json index ef357c3fb6..a163c356cb 100644 --- a/static/app-strings.json +++ b/static/app-strings.json @@ -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--" } diff --git a/ui/constants/action_types.js b/ui/constants/action_types.js index cb43a4b97b..23a020bba3 100644 --- a/ui/constants/action_types.js +++ b/ui/constants/action_types.js @@ -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'; @@ -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'; diff --git a/ui/modal/modalRemoveAccount/index.js b/ui/modal/modalRemoveAccount/index.js index f3de1cf878..7e951e42e7 100644 --- a/ui/modal/modalRemoveAccount/index.js +++ b/ui/modal/modalRemoveAccount/index.js @@ -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); diff --git a/ui/modal/modalRemoveAccount/view.jsx b/ui/modal/modalRemoveAccount/view.jsx index 103ed39055..73b0a78a69 100644 --- a/ui/modal/modalRemoveAccount/view.jsx +++ b/ui/modal/modalRemoveAccount/view.jsx @@ -10,12 +10,41 @@ 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, doHideModal: () => void, doRemoveAccountSequence: () => Promise, + 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); @@ -23,7 +52,24 @@ export default function ModalRemoveAccount(props: Props) { 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); @@ -42,25 +88,49 @@ export default function ModalRemoveAccount(props: Props) { + {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 && ( +
+

{__('Credits: %credits%', { credits: totalBalance })}

+

{__('Publications: %claims%', { claims: totalClaimsCount })}

+ {channelUrls && ( + <> +

{__('Channels:')}

+
    + {channelUrls.map((url) => { + const name = [].concat(url.match(/@[^#]+/)).pop(); + const claimId = [].concat(url.match(/[a-f0-9]+$/)).pop(); + return
  • {name}
  • ; + })} +
+ + )} +
+ )} + } className="confirm__wrapper" actions={ @@ -75,9 +145,18 @@ export default function ModalRemoveAccount(props: Props) { onChange={() => setIsForfeitChecked(!isForfeitChecked)} /> )} + {showButton && isWalletMerged && ( +
+

+ {__( + "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." + )} +

+
+ )}
- {isBusy ? ( - + {isBusy || isLoadingAccountInfo ? ( + ) : ( showButton && (