From 5fa481d78015599361dc6f20c82a0f596230a734 Mon Sep 17 00:00:00 2001 From: unclebill Date: Tue, 8 Mar 2022 11:35:50 +0800 Subject: [PATCH 01/15] feat: integrate tip into next.id --- cspell.json | 3 +- packages/icons/plugins/Currency.tsx | 24 ++- packages/mask/shared-ui/locales/en-US.json | 3 - packages/mask/shared-ui/locales/qya-AA.json | 3 - packages/mask/shared-ui/locales/zh-CN.json | 2 - packages/mask/shared/flags.ts | 4 +- .../src/plugins/NextID/SNSAdaptor/index.tsx | 4 +- .../plugins/NextID/components/BindingItem.tsx | 22 ++- .../plugins/NextID/components/NextIdPage.tsx | 3 +- .../components/tip/NFTSection/NFTList.tsx | 82 +++++---- .../components/tip/NFTSection/index.tsx | 6 +- .../NextID/components/tip/TipButton.tsx | 64 +++++-- .../plugins/NextID/components/tip/TipForm.tsx | 19 +- .../plugins/NextID/contexts/TipContext.tsx | 167 ------------------ .../mask/src/plugins/NextID/contexts/index.ts | 2 +- .../plugins/NextID/contexts/tip/TipContext.ts | 38 ++++ .../NextID/contexts/tip/TipTaskProvider.tsx | 79 +++++++++ .../src/plugins/NextID/contexts/tip/index.ts | 3 + .../src/plugins/NextID/contexts/tip/type.ts | 3 + .../plugins/NextID/contexts/tip/useNftTip.ts | 21 +++ .../NextID/contexts/tip/useTipValidate.ts | 27 +++ .../NextID/contexts/tip/useTokenTip.ts | 26 +++ .../src/plugins/NextID/locales/en-US.json | 9 +- 23 files changed, 363 insertions(+), 251 deletions(-) delete mode 100644 packages/mask/src/plugins/NextID/contexts/TipContext.tsx create mode 100644 packages/mask/src/plugins/NextID/contexts/tip/TipContext.ts create mode 100644 packages/mask/src/plugins/NextID/contexts/tip/TipTaskProvider.tsx create mode 100644 packages/mask/src/plugins/NextID/contexts/tip/index.ts create mode 100644 packages/mask/src/plugins/NextID/contexts/tip/type.ts create mode 100644 packages/mask/src/plugins/NextID/contexts/tip/useNftTip.ts create mode 100644 packages/mask/src/plugins/NextID/contexts/tip/useTipValidate.ts create mode 100644 packages/mask/src/plugins/NextID/contexts/tip/useTokenTip.ts diff --git a/cspell.json b/cspell.json index aa4c82a87783..1e209716c562 100644 --- a/cspell.json +++ b/cspell.json @@ -379,7 +379,8 @@ "walletlink", "wnative", "xdescribe", - "xtest" + "xtest", + "deletable" ], "ignoreRegExpList": ["/@servie/"], "overrides": [ diff --git a/packages/icons/plugins/Currency.tsx b/packages/icons/plugins/Currency.tsx index 2538c608d41d..4dbdbc3794a4 100644 --- a/packages/icons/plugins/Currency.tsx +++ b/packages/icons/plugins/Currency.tsx @@ -5,31 +5,39 @@ export const Currency: typeof SvgIcon = createIcon( 'Currency', - + + - , '0 0 25 25', ) diff --git a/packages/mask/shared-ui/locales/en-US.json b/packages/mask/shared-ui/locales/en-US.json index 3064c07e26be..b980d2e2e253 100644 --- a/packages/mask/shared-ui/locales/en-US.json +++ b/packages/mask/shared-ui/locales/en-US.json @@ -495,9 +495,6 @@ "plugin_trader_no_trade": "Please select a trade", "plugin_trader_gas": "GAS", "plugin_tip_tip": "Tip", - "plugin_tip_send": "Send", - "plugin_tip_token": "Token", - "plugin_tip_nft": "NFT", "plugin_poll_display_name": "Plugin: Poll", "plugin_poll_question_hint": "Ask a question…", "plugin_poll_options_hint": "choice", diff --git a/packages/mask/shared-ui/locales/qya-AA.json b/packages/mask/shared-ui/locales/qya-AA.json index b8f163bb8e1a..36e7f234cd8c 100644 --- a/packages/mask/shared-ui/locales/qya-AA.json +++ b/packages/mask/shared-ui/locales/qya-AA.json @@ -495,9 +495,6 @@ "plugin_trader_no_trade": "crwdns10483:0crwdne10483:0", "plugin_trader_gas": "crwdns10485:0crwdne10485:0", "plugin_tip_tip": "crwdns14546:0crwdne14546:0", - "plugin_tip_send": "crwdns14548:0crwdne14548:0", - "plugin_tip_token": "crwdns14550:0crwdne14550:0", - "plugin_tip_nft": "crwdns14552:0crwdne14552:0", "plugin_poll_display_name": "crwdns4941:0crwdne4941:0", "plugin_poll_question_hint": "crwdns4943:0crwdne4943:0", "plugin_poll_options_hint": "crwdns4945:0crwdne4945:0", diff --git a/packages/mask/shared-ui/locales/zh-CN.json b/packages/mask/shared-ui/locales/zh-CN.json index 4439951dba51..5c74b04f2faf 100644 --- a/packages/mask/shared-ui/locales/zh-CN.json +++ b/packages/mask/shared-ui/locales/zh-CN.json @@ -479,8 +479,6 @@ "plugin_trader_no_enough_liquidity": "流动性不足", "plugin_trader_no_trade": "请选择一个交易", "plugin_tip_tip": "打赏", - "plugin_tip_send": "发送", - "plugin_tip_token": "代币", "plugin_poll_display_name": "插件:投票", "plugin_poll_question_hint": "询问...", "plugin_poll_options_hint": "选项", diff --git a/packages/mask/shared/flags.ts b/packages/mask/shared/flags.ts index 3a02f63f634e..3c6c724e60aa 100644 --- a/packages/mask/shared/flags.ts +++ b/packages/mask/shared/flags.ts @@ -58,8 +58,8 @@ export const Flags = { celo_enabled: true, aurora_enabled: true, nft_airdrop_enabled: false, - post_actions_enabled: false, - next_id_tip_enabled: false, + post_actions_enabled: true, + next_id_tip_enabled: true, // #region Functionality missing / broken /** diff --git a/packages/mask/src/plugins/NextID/SNSAdaptor/index.tsx b/packages/mask/src/plugins/NextID/SNSAdaptor/index.tsx index aee858243f8e..8274f326b7e7 100644 --- a/packages/mask/src/plugins/NextID/SNSAdaptor/index.tsx +++ b/packages/mask/src/plugins/NextID/SNSAdaptor/index.tsx @@ -3,7 +3,7 @@ import { base } from '../base' import { PLUGIN_ID } from '../constants' import { NextIdPage } from '../components/NextIdPage' import { RootContext } from '../contexts' -import { TipButton, TipTaskManager } from '../components/tip' +import { PostTipButton, TipTaskManager } from '../components/tip' import { Flags } from '../../../../shared' const sns: Plugin.SNSAdaptor.Definition = { @@ -31,7 +31,7 @@ const sns: Plugin.SNSAdaptor.Definition = { if (!Flags.next_id_tip_enabled) return null return ( - + ) }, diff --git a/packages/mask/src/plugins/NextID/components/BindingItem.tsx b/packages/mask/src/plugins/NextID/components/BindingItem.tsx index 225546f430d7..031a99c21655 100644 --- a/packages/mask/src/plugins/NextID/components/BindingItem.tsx +++ b/packages/mask/src/plugins/NextID/components/BindingItem.tsx @@ -9,6 +9,7 @@ import { ExternalLink } from 'react-feather' import { NetworkPluginID, useNetworkDescriptor, useWeb3State } from '@masknet/plugin-infra' import { useI18N } from '../locales' import { ImageIcon } from '@masknet/shared' +import { TipButton } from './tip' const useStyles = makeStyles()((theme) => ({ item: { @@ -18,11 +19,6 @@ const useStyles = makeStyles()((theme) => ({ borderRadius: 8, alignItems: 'center', }, - trashIcon: { - fontSize: 20, - stroke: theme.palette.text.primary, - cursor: 'pointer', - }, copy: { fontSize: 16, stroke: theme.palette.text.primary, @@ -40,15 +36,24 @@ const useStyles = makeStyles()((theme) => ({ linkIcon: { marginRight: theme.spacing(1), }, + tipButton: { + display: 'inline-block', + }, + delButton: { + fontSize: 20, + stroke: theme.palette.text.primary, + cursor: 'pointer', + marginLeft: theme.spacing(1), + }, })) interface Item { platform: Platform identity: string - enableAction: boolean + deletable: boolean onUnBind(address: string): void } -export const BindingItem = memo(({ platform, identity, enableAction, onUnBind }) => { +export const BindingItem = memo(({ platform, identity, deletable, onUnBind }) => { const t = useI18N() const { Utils } = useWeb3State() ?? {} const { classes } = useStyles() @@ -77,7 +82,8 @@ export const BindingItem = memo(({ platform, identity, enableAction, onUnB - {enableAction && onUnBind(identity)} />} + + {deletable && onUnBind(identity)} />} ) diff --git a/packages/mask/src/plugins/NextID/components/NextIdPage.tsx b/packages/mask/src/plugins/NextID/components/NextIdPage.tsx index dac61c8c38c8..773609a02840 100644 --- a/packages/mask/src/plugins/NextID/components/NextIdPage.tsx +++ b/packages/mask/src/plugins/NextID/components/NextIdPage.tsx @@ -60,6 +60,7 @@ export function NextIdPage({}: NextIDPageProps) { return Services.Identity.queryPersonaByProfile(currentProfileIdentifier.identifier) }, [currentProfileIdentifier, personaConnectStatus.hasPersona]) + console.log('identifier', visitingPersonaIdentifier.identifier) const { value: bindings, loading } = useAsync(async () => { if (!currentPersona) return if (isOwn) { @@ -102,7 +103,7 @@ export function NextIdPage({}: NextIDPageProps) { {bindings.proofs.map((x) => ( void limit?: number className: string @@ -45,16 +47,17 @@ export function arrayRemove(arr: T[], item: T): T[] { return arr.splice(idx, 1) } -export const NFTList: FC = ({ selectedIds, onChange, limit = 1, tokens, className }) => { +export const NFTList: FC = ({ selectedIds, tokens, enableTokenIds = [], onChange, limit = 1, className }) => { const chainId = useChainId() const { classes } = useStyles() + const isRadio = limit === 1 const reachedLimit = selectedIds.length >= limit const toggleItem = useCallback( (currentId: string) => { - const disabled = !selectedIds.includes(currentId) && reachedLimit - if (!onChange || disabled) return + if (!onChange) return + if (isRadio) return onChange([currentId]) let newIds = [...selectedIds] if (selectedIds.includes(currentId)) { arrayRemove(newIds, currentId) @@ -63,37 +66,52 @@ export const NFTList: FC = ({ selectedIds, onChange, limit = 1, tokens, c } onChange(newIds) }, - [selectedIds, onChange, reachedLimit], + [selectedIds, onChange, isRadio, reachedLimit], ) + const SelectComponent = isRadio ? Radio : Checkbox + const t = useI18N() + return ( - {tokens.map((token) => ( - { - toggleItem(token.tokenId) - }}> - - { - toggleItem(token.tokenId) - }} - className={classes.checkbox} - checked={selectedIds.includes(token.tokenId)} - /> - - ))} + {tokens.map((token) => { + const isOwned = !enableTokenIds.includes(token.tokenId) + const disabled = (reachedLimit && !selectedIds.includes(token.tokenId)) || isOwned + return ( + + { + if (disabled) return + toggleItem(token.tokenId) + }}> + + { + if (disabled) return + toggleItem(token.tokenId) + }} + className={classes.checkbox} + checked={selectedIds.includes(token.tokenId)} + /> + + + ) + })} ) } diff --git a/packages/mask/src/plugins/NextID/components/tip/NFTSection/index.tsx b/packages/mask/src/plugins/NextID/components/tip/NFTSection/index.tsx index 9be8858769f3..b93e195515d7 100644 --- a/packages/mask/src/plugins/NextID/components/tip/NFTSection/index.tsx +++ b/packages/mask/src/plugins/NextID/components/tip/NFTSection/index.tsx @@ -30,11 +30,11 @@ const useStyles = makeStyles()((theme) => ({ gridGap: 18, }, keyword: { - borderRadius: 6, + borderRadius: 8, marginRight: theme.spacing(1.5), }, searchButton: { - borderRadius: 6, + borderRadius: 8, width: 100, }, row: { @@ -62,6 +62,7 @@ export const NFTSection: FC = ({ className, ...rest }) => { }, [erc721TokenDetailedCallback]) const tokens = useMemo(() => (searchedToken ? [searchedToken] : myTokens), [searchedToken, myTokens]) + const enableTokenIds = useMemo(() => myTokens.map((t) => t.tokenId), [myTokens]) return (
@@ -85,6 +86,7 @@ export const NFTSection: FC = ({ className, ...rest }) => { className={classes.list} selectedIds={selectedIds} tokens={tokens} + enableTokenIds={enableTokenIds} onChange={(ids) => { setErc721TokenId(ids.length ? ids[0] : null) }} diff --git a/packages/mask/src/plugins/NextID/components/tip/TipButton.tsx b/packages/mask/src/plugins/NextID/components/tip/TipButton.tsx index b45e72f17998..28c7de7bbd0d 100644 --- a/packages/mask/src/plugins/NextID/components/tip/TipButton.tsx +++ b/packages/mask/src/plugins/NextID/components/tip/TipButton.tsx @@ -1,28 +1,72 @@ import { Currency } from '@masknet/icons' -import { useAccount } from '@masknet/web3-shared-evm' +import { usePostInfoDetails } from '@masknet/plugin-infra' +import type { ProfileIdentifier } from '@masknet/shared-base' +import { makeStyles } from '@masknet/theme' import classnames from 'classnames' -import { FC, HTMLProps, MouseEventHandler, useCallback } from 'react' +import { FC, HTMLProps, MouseEventHandler, useCallback, useEffect, useMemo } from 'react' +import { useAsyncFn } from 'react-use' +import Services from '../../../../extension/service' import { PluginNextIdMessages } from '../../messages' +import { Platform } from '../../types' -interface Props extends HTMLProps {} +interface Props extends HTMLProps { + addresses?: string[] + receiver?: ProfileIdentifier +} + +const useStyles = makeStyles()({ + tipButton: { + cursor: 'pointer', + }, +}) + +export const TipButton: FC = ({ className, receiver, addresses = [], ...rest }) => { + const { classes } = useStyles() + + const [state, queryBindings] = useAsyncFn(async () => { + if (!receiver) return [] + + const persona = await Services.Identity.queryPersonaByProfile(receiver) + if (!persona) return [] + + const bindings = await Services.Helper.queryExistedBinding(persona.identifier) + if (!bindings) return [] -export const TipButton: FC = ({ className, ...rest }) => { - // So far it is not possible to fetch wallets of user - const account = useAccount() + const wallets = bindings.proofs.filter((p) => p.platform === Platform.ethereum).map((p) => p.identity) + return wallets + }, [receiver]) + + useEffect(() => { + queryBindings() + }, [queryBindings]) + + const allAddresses = useMemo(() => [...(state.value || []), ...addresses], [state.value, addresses]) const sendTip: MouseEventHandler = useCallback( - (evt) => { + async (evt) => { evt.stopPropagation() evt.preventDefault() + if (state.loading || !state.value) { + await queryBindings() + } + if (!allAddresses.length) return PluginNextIdMessages.tipTask.sendToLocal({ - addresses: [account], + addresses: allAddresses, }) }, - [account], + [state, allAddresses], ) + + if (allAddresses.length === 0) return null + return ( -
+
) } + +export const PostTipButton: FC = (props) => { + const identifier = usePostInfoDetails.author() + return +} diff --git a/packages/mask/src/plugins/NextID/components/tip/TipForm.tsx b/packages/mask/src/plugins/NextID/components/tip/TipForm.tsx index 92c059f21a12..a6b7b61df224 100644 --- a/packages/mask/src/plugins/NextID/components/tip/TipForm.tsx +++ b/packages/mask/src/plugins/NextID/components/tip/TipForm.tsx @@ -7,10 +7,10 @@ import { Box, FormControl, FormControlLabel, MenuItem, Radio, RadioGroup, Select import { FC, memo, useCallback, useRef, useState } from 'react' import { v4 as uuid } from 'uuid' import ActionButton from '../../../../extension/options-page/DashboardComponents/ActionButton' -import { useI18N } from '../../../../utils' import { EthereumChainBoundary } from '../../../../web3/UI/EthereumChainBoundary' import { TokenAmountPanel } from '../../../../web3/UI/TokenAmountPanel' -import { TargetChainIdContext, useTip } from '../../contexts' +import { TargetChainIdContext, useTip, useTipValidate } from '../../contexts' +import { useI18N } from '../../locales' import { TipType } from '../../types' import { NFTSection } from './NFTSection' @@ -46,7 +46,7 @@ const useStyles = makeStyles()((theme) => { }) export const TipForm: FC = memo(() => { - const { t } = useI18N() + const t = useI18N() const { targetChainId: chainId } = TargetChainIdContext.useContainer() const { classes } = useStyles() const { @@ -59,8 +59,10 @@ export const TipForm: FC = memo(() => { setToken, amount, setAmount, + isSending, sendTip, } = useTip() + const [isValid, validateMessage] = useTipValidate() const { Utils } = useWeb3State() const selectRef = useRef(null) const [id] = useState(uuid) @@ -90,10 +92,11 @@ export const TipForm: FC = memo(() => { token?.address || '', ) // #endregion + const buttonLabel = isSending ? t.sending_tip() : isValid || !validateMessage ? t.send_tip() : validateMessage return ( - To + {t.tip_to()} { - setRecipient(e.target.value) - }} - MenuProps={{ - anchorOrigin: { - vertical: 'bottom', - horizontal: 'center', - }, - container: selectRef.current, - BackdropProps: { - invisible: true, - }, - }}> - {recipientAddresses.map((address) => ( - - {Utils?.formatDomainName?.(address) || address} - - ))} - - - - { - setTipType(e.target.value as TipType) - }}> - } label={t.tip_type_token()} /> - } label={t.tip_type_nft()} /> - - - {tipType === TipType.Token ? ( - - + + + + { + setTipType(e.target.value as TipType) + }}> + } label={t.tip_type_token()} /> + } label={t.tip_type_nft()} /> + - ) : ( - - )} + {tipType === TipType.Token ? ( + + + + ) : ( + + )} +
Date: Wed, 9 Mar 2022 20:07:07 +0800 Subject: [PATCH 05/15] fixup! fix: style --- cspell.json | 5 +++-- packages/mask/src/plugins/NextID/components/BindingItem.tsx | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/cspell.json b/cspell.json index 1e209716c562..5ff39800d228 100644 --- a/cspell.json +++ b/cspell.json @@ -288,6 +288,7 @@ "cryptoartai", "cusd", "defi", + "deletable", "devnet", "drawed", "energi", @@ -364,6 +365,7 @@ "switcher", "testweb", "tinycolor", + "tipable", "treeshake", "txreceipt", "txts", @@ -379,8 +381,7 @@ "walletlink", "wnative", "xdescribe", - "xtest", - "deletable" + "xtest" ], "ignoreRegExpList": ["/@servie/"], "overrides": [ diff --git a/packages/mask/src/plugins/NextID/components/BindingItem.tsx b/packages/mask/src/plugins/NextID/components/BindingItem.tsx index 29deccbf55bf..100462ed8a79 100644 --- a/packages/mask/src/plugins/NextID/components/BindingItem.tsx +++ b/packages/mask/src/plugins/NextID/components/BindingItem.tsx @@ -41,6 +41,7 @@ const useStyles = makeStyles()((theme) => ({ alignItems: 'center', }, tipButtonLabel: { + color: theme.palette.text.primary, fontSize: 14, marginLeft: theme.spacing(0.5), }, From 6bc66cc3ac00c58ee929bd958ca98ec4454400a4 Mon Sep 17 00:00:00 2001 From: unclebill Date: Thu, 10 Mar 2022 11:00:10 +0800 Subject: [PATCH 06/15] fix: share to sns after sending --- .../NextID/components/tip/TipButton.tsx | 11 +++++----- .../plugins/NextID/components/tip/TipForm.tsx | 20 +++++++++++++++++-- .../plugins/NextID/contexts/tip/TipContext.ts | 2 ++ .../NextID/contexts/tip/TipTaskProvider.tsx | 3 ++- packages/mask/src/plugins/NextID/types/tip.ts | 2 +- 5 files changed, 29 insertions(+), 9 deletions(-) diff --git a/packages/mask/src/plugins/NextID/components/tip/TipButton.tsx b/packages/mask/src/plugins/NextID/components/tip/TipButton.tsx index 4b706f1538af..885497be852e 100644 --- a/packages/mask/src/plugins/NextID/components/tip/TipButton.tsx +++ b/packages/mask/src/plugins/NextID/components/tip/TipButton.tsx @@ -29,7 +29,7 @@ const useStyles = makeStyles()({ export const TipButton: FC = ({ className, receiver, addresses = [], children, ...rest }) => { const { classes } = useStyles() - const [state, queryBindings] = useAsyncFn(async () => { + const [walletsState, queryBindings] = useAsyncFn(async () => { if (!receiver) return [] const persona = await Services.Identity.queryPersonaByProfile(receiver) @@ -44,21 +44,22 @@ export const TipButton: FC = ({ className, receiver, addresses = [], chil useAsync(queryBindings, [queryBindings]) - const allAddresses = useMemo(() => [...(state.value || []), ...addresses], [state.value, addresses]) + const allAddresses = useMemo(() => [...(walletsState.value || []), ...addresses], [walletsState.value, addresses]) const sendTip: MouseEventHandler = useCallback( async (evt) => { evt.stopPropagation() evt.preventDefault() - if (state.loading || !state.value) { + if (walletsState.loading || !walletsState.value) { await queryBindings() } - if (!allAddresses.length) return + if (!allAddresses.length || !receiver?.userId) return PluginNextIdMessages.tipTask.sendToLocal({ + recipientSnsId: receiver.userId, addresses: allAddresses, }) }, - [state, allAddresses], + [walletsState, allAddresses, receiver?.userId], ) if (allAddresses.length === 0) return null diff --git a/packages/mask/src/plugins/NextID/components/tip/TipForm.tsx b/packages/mask/src/plugins/NextID/components/tip/TipForm.tsx index 8371a8885fd9..c41b43d9e8bb 100644 --- a/packages/mask/src/plugins/NextID/components/tip/TipForm.tsx +++ b/packages/mask/src/plugins/NextID/components/tip/TipForm.tsx @@ -15,9 +15,10 @@ import { Typography, } from '@mui/material' import classnames from 'classnames' -import { FC, memo, useCallback, useRef, useState } from 'react' +import { FC, memo, useCallback, useMemo, useRef, useState } from 'react' import { v4 as uuid } from 'uuid' import ActionButton from '../../../../extension/options-page/DashboardComponents/ActionButton' +import { activatedSocialNetworkUI } from '../../../../social-network' import { EthereumChainBoundary } from '../../../../web3/UI/EthereumChainBoundary' import { TokenAmountPanel } from '../../../../web3/UI/TokenAmountPanel' import { TargetChainIdContext, useTip, useTipValidate } from '../../contexts' @@ -70,6 +71,7 @@ export const TipForm: FC = memo((props) => { const { classes } = useStyles() const { recipient, + recipientSnsId, recipients: recipientAddresses, tipType, setTipType, @@ -105,6 +107,20 @@ export const TipForm: FC = memo((props) => { }, }) }, [id, token?.address]) + + const shareLink = useMemo(() => { + return activatedSocialNetworkUI.utils.getShareLinkURL?.( + `I just tipped ${amount} ${token?.symbol} to @${recipientSnsId}'s wallet address ${recipient} + +Install https://mask.io/download-links to tip my best friend.`, + ) + }, [amount, token?.symbol, recipient, recipientSnsId]) + + const handleSend = useCallback(async () => { + await sendTip() + window.open(shareLink) + }, [sendTip, shareLink]) + // balance const { value: tokenBalance = '0', loading: loadingTokenBalance } = useFungibleTokenBalance( token?.type || EthereumTokenType.Native, @@ -189,7 +205,7 @@ export const TipForm: FC = memo((props) => { className={classes.tipButton} fullWidth disabled={!isValid || isSending} - onClick={sendTip}> + onClick={handleSend}> {buttonLabel} diff --git a/packages/mask/src/plugins/NextID/contexts/tip/TipContext.ts b/packages/mask/src/plugins/NextID/contexts/tip/TipContext.ts index 09a392d7c7b2..2f8713ccc72a 100644 --- a/packages/mask/src/plugins/NextID/contexts/tip/TipContext.ts +++ b/packages/mask/src/plugins/NextID/contexts/tip/TipContext.ts @@ -5,6 +5,7 @@ import { TipType } from '../../types' export interface ContextOptions { recipient: string + recipientSnsId: string setRecipient: Dispatch> tipType: TipType setTipType: Dispatch> @@ -22,6 +23,7 @@ export interface ContextOptions { export const TipContext = createContext({ recipient: '', + recipientSnsId: '', setRecipient: noop, tipType: TipType.NFT, setTipType: noop, diff --git a/packages/mask/src/plugins/NextID/contexts/tip/TipTaskProvider.tsx b/packages/mask/src/plugins/NextID/contexts/tip/TipTaskProvider.tsx index 1c8c7865ced5..7a3318657deb 100644 --- a/packages/mask/src/plugins/NextID/contexts/tip/TipTaskProvider.tsx +++ b/packages/mask/src/plugins/NextID/contexts/tip/TipTaskProvider.tsx @@ -42,6 +42,7 @@ export const TipTaskProvider: FC = ({ children, task }) => { const contextValue = useMemo(() => { return { recipient, + recipientSnsId: task.recipientSnsId || '', setRecipient, recipients, setRecipients, @@ -56,7 +57,7 @@ export const TipTaskProvider: FC = ({ children, task }) => { erc721Contract, setErc721Contract, } - }, [recipient, recipients, tipType, amount, erc721TokenId, erc721Contract, token]) + }, [recipient, task.recipientSnsId, recipients, tipType, amount, erc721TokenId, erc721Contract, token]) return {children} } diff --git a/packages/mask/src/plugins/NextID/types/tip.ts b/packages/mask/src/plugins/NextID/types/tip.ts index 5a6c6d55d09f..2e6cbde0e5cd 100644 --- a/packages/mask/src/plugins/NextID/types/tip.ts +++ b/packages/mask/src/plugins/NextID/types/tip.ts @@ -5,6 +5,6 @@ export enum TipType { export interface TipTask { to?: string - snsID?: string + recipientSnsId?: string addresses: string[] } From 81970ec4cb8e12a5619b11d189caa4261959811f Mon Sep 17 00:00:00 2001 From: unclebill Date: Thu, 10 Mar 2022 11:31:29 +0800 Subject: [PATCH 07/15] fix: also show tip button on post that the author haven't bind any wallet --- .../plugins/NextID/components/BindingItem.tsx | 7 +++++- .../plugins/NextID/components/NextIdPage.tsx | 10 ++++---- .../NextID/components/tip/TipButton.tsx | 24 +++++++++++++------ 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/packages/mask/src/plugins/NextID/components/BindingItem.tsx b/packages/mask/src/plugins/NextID/components/BindingItem.tsx index 100462ed8a79..08aaea073333 100644 --- a/packages/mask/src/plugins/NextID/components/BindingItem.tsx +++ b/packages/mask/src/plugins/NextID/components/BindingItem.tsx @@ -10,6 +10,7 @@ import { NetworkPluginID, useNetworkDescriptor, useWeb3State } from '@masknet/pl import { useI18N } from '../locales' import { ImageIcon } from '@masknet/shared' import { TipButton } from './tip' +import { useCurrentVisitingIdentity } from '../../../components/DataSource/useActivatedUI' const useStyles = makeStyles()((theme) => ({ item: { @@ -65,6 +66,7 @@ export const BindingItem = memo(({ platform, identity, tipable, deletable, const { Utils } = useWeb3State() ?? {} const { classes } = useStyles() const networkDescriptor = useNetworkDescriptor(ChainId.Mainnet, NetworkPluginID.PLUGIN_EVM) + const visitingPersona = useCurrentVisitingIdentity() if (platform === Platform.ethereum) { return ( @@ -90,7 +92,10 @@ export const BindingItem = memo(({ platform, identity, tipable, deletable, {tipable ? ( - + {t.tip()} ) : null} diff --git a/packages/mask/src/plugins/NextID/components/NextIdPage.tsx b/packages/mask/src/plugins/NextID/components/NextIdPage.tsx index 076fc89ec9a2..eb4b797a675c 100644 --- a/packages/mask/src/plugins/NextID/components/NextIdPage.tsx +++ b/packages/mask/src/plugins/NextID/components/NextIdPage.tsx @@ -1,15 +1,15 @@ -import { useI18N } from '../locales' import { makeStyles } from '@masknet/theme' import { Box, Button, Skeleton, Stack, Typography } from '@mui/material' import { useMemo, useState } from 'react' -import { BindDialog } from './BindDialog' import { useAsync, useAsyncRetry, useCounter } from 'react-use' +import { useCurrentVisitingIdentity, useLastRecognizedIdentity } from '../../../components/DataSource/useActivatedUI' +import { usePersonaConnectStatus } from '../../../components/DataSource/usePersonaConnectStatus' import Services from '../../../extension/service' -import { BindingItem } from './BindingItem' +import { useI18N } from '../locales' import type { Platform } from '../types' +import { BindDialog } from './BindDialog' +import { BindingItem } from './BindingItem' import { UnbindDialog } from './UnbindDialog' -import { useCurrentVisitingIdentity, useLastRecognizedIdentity } from '../../../components/DataSource/useActivatedUI' -import { usePersonaConnectStatus } from '../../../components/DataSource/usePersonaConnectStatus' const useStyles = makeStyles()((theme) => ({ tip: { diff --git a/packages/mask/src/plugins/NextID/components/tip/TipButton.tsx b/packages/mask/src/plugins/NextID/components/tip/TipButton.tsx index 885497be852e..e599246870b9 100644 --- a/packages/mask/src/plugins/NextID/components/tip/TipButton.tsx +++ b/packages/mask/src/plugins/NextID/components/tip/TipButton.tsx @@ -2,6 +2,7 @@ import { Currency } from '@masknet/icons' import { usePostInfoDetails } from '@masknet/plugin-infra' import type { ProfileIdentifier } from '@masknet/shared-base' import { makeStyles } from '@masknet/theme' +import { EMPTY_LIST } from '@masknet/web3-shared-evm' import classnames from 'classnames' import { FC, HTMLProps, MouseEventHandler, useCallback, useMemo } from 'react' import { useAsync, useAsyncFn } from 'react-use' @@ -24,19 +25,23 @@ const useStyles = makeStyles()({ height: 46, alignItems: 'center', }, + disabled: { + opacity: 0.4, + cursor: 'default', + }, }) export const TipButton: FC = ({ className, receiver, addresses = [], children, ...rest }) => { const { classes } = useStyles() const [walletsState, queryBindings] = useAsyncFn(async () => { - if (!receiver) return [] + if (!receiver) return EMPTY_LIST const persona = await Services.Identity.queryPersonaByProfile(receiver) - if (!persona) return [] + if (!persona) return EMPTY_LIST const bindings = await Services.Helper.queryExistedBinding(persona.identifier) - if (!bindings) return [] + if (!bindings) return EMPTY_LIST const wallets = bindings.proofs.filter((p) => p.platform === Platform.ethereum).map((p) => p.identity) return wallets @@ -46,10 +51,13 @@ export const TipButton: FC = ({ className, receiver, addresses = [], chil const allAddresses = useMemo(() => [...(walletsState.value || []), ...addresses], [walletsState.value, addresses]) + const disabled = allAddresses.length === 0 + const sendTip: MouseEventHandler = useCallback( async (evt) => { evt.stopPropagation() evt.preventDefault() + if (disabled) return if (walletsState.loading || !walletsState.value) { await queryBindings() } @@ -59,13 +67,15 @@ export const TipButton: FC = ({ className, receiver, addresses = [], chil addresses: allAddresses, }) }, - [walletsState, allAddresses, receiver?.userId], + [disabled, walletsState, allAddresses, receiver?.userId], ) - if (allAddresses.length === 0) return null - return ( -
+
{children}
From 554ab4ce69a412c0cc5ecebbc09b0c9c3126b0ac Mon Sep 17 00:00:00 2001 From: unclebill Date: Thu, 10 Mar 2022 13:57:13 +0800 Subject: [PATCH 08/15] fix: some bugs --- .../mask/src/plugins/NextID/components/tip/TipButton.tsx | 5 ++++- packages/mask/src/plugins/NextID/components/tip/TipForm.tsx | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/mask/src/plugins/NextID/components/tip/TipButton.tsx b/packages/mask/src/plugins/NextID/components/tip/TipButton.tsx index e599246870b9..c49db4065a9d 100644 --- a/packages/mask/src/plugins/NextID/components/tip/TipButton.tsx +++ b/packages/mask/src/plugins/NextID/components/tip/TipButton.tsx @@ -4,6 +4,7 @@ import type { ProfileIdentifier } from '@masknet/shared-base' import { makeStyles } from '@masknet/theme' import { EMPTY_LIST } from '@masknet/web3-shared-evm' import classnames from 'classnames' +import { uniq } from 'lodash-unified' import { FC, HTMLProps, MouseEventHandler, useCallback, useMemo } from 'react' import { useAsync, useAsyncFn } from 'react-use' import Services from '../../../../extension/service' @@ -49,7 +50,9 @@ export const TipButton: FC = ({ className, receiver, addresses = [], chil useAsync(queryBindings, [queryBindings]) - const allAddresses = useMemo(() => [...(walletsState.value || []), ...addresses], [walletsState.value, addresses]) + const allAddresses = useMemo(() => { + return uniq([...(walletsState.value || []), ...addresses]) + }, [walletsState.value, addresses]) const disabled = allAddresses.length === 0 diff --git a/packages/mask/src/plugins/NextID/components/tip/TipForm.tsx b/packages/mask/src/plugins/NextID/components/tip/TipForm.tsx index c41b43d9e8bb..3199b738468f 100644 --- a/packages/mask/src/plugins/NextID/components/tip/TipForm.tsx +++ b/packages/mask/src/plugins/NextID/components/tip/TipForm.tsx @@ -99,6 +99,7 @@ export const TipForm: FC = memo((props) => { ) const onSelectTokenChipClick = useCallback(() => { setSelectTokenDialog({ + chainId, open: true, uuid: id, disableNativeToken: false, @@ -106,7 +107,7 @@ export const TipForm: FC = memo((props) => { selectedTokens: token ? [token.address] : [], }, }) - }, [id, token?.address]) + }, [id, token?.address, chainId]) const shareLink = useMemo(() => { return activatedSocialNetworkUI.utils.getShareLinkURL?.( From fd893237df2e0950e59214095152a213c29a20c4 Mon Sep 17 00:00:00 2001 From: unclebill Date: Thu, 10 Mar 2022 14:15:36 +0800 Subject: [PATCH 09/15] fix: pending until confirmed --- .../plugins/NextID/components/tip/TipForm.tsx | 16 +++++++++------- .../NextID/contexts/tip/TipTaskProvider.tsx | 9 ++++++--- .../src/plugins/NextID/contexts/tip/useNftTip.ts | 11 ++++++++--- .../evm/hooks/useERC721TokenTransferCallback.ts | 7 +++++++ 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/packages/mask/src/plugins/NextID/components/tip/TipForm.tsx b/packages/mask/src/plugins/NextID/components/tip/TipForm.tsx index 3199b738468f..742053b1c72f 100644 --- a/packages/mask/src/plugins/NextID/components/tip/TipForm.tsx +++ b/packages/mask/src/plugins/NextID/components/tip/TipForm.tsx @@ -2,7 +2,7 @@ import { useWeb3State } from '@masknet/plugin-infra' import { SelectTokenDialogEvent, WalletMessages } from '@masknet/plugin-wallet' import { useRemoteControlledDialog } from '@masknet/shared' import { makeStyles } from '@masknet/theme' -import { EthereumTokenType, useFungibleTokenBalance } from '@masknet/web3-shared-evm' +import { EthereumTokenType, TransactionStateType, useFungibleTokenBalance } from '@masknet/web3-shared-evm' import { Box, BoxProps, @@ -15,7 +15,7 @@ import { Typography, } from '@mui/material' import classnames from 'classnames' -import { FC, memo, useCallback, useMemo, useRef, useState } from 'react' +import { FC, memo, useCallback, useEffect, useMemo, useRef, useState } from 'react' import { v4 as uuid } from 'uuid' import ActionButton from '../../../../extension/options-page/DashboardComponents/ActionButton' import { activatedSocialNetworkUI } from '../../../../social-network' @@ -81,6 +81,7 @@ export const TipForm: FC = memo((props) => { amount, setAmount, isSending, + sendState, sendTip, } = useTip() const [isValid, validateMessage] = useTipValidate() @@ -117,10 +118,11 @@ Install https://mask.io/download-links to tip my best friend.`, ) }, [amount, token?.symbol, recipient, recipientSnsId]) - const handleSend = useCallback(async () => { - await sendTip() - window.open(shareLink) - }, [sendTip, shareLink]) + useEffect(() => { + if (sendState.type === TransactionStateType.CONFIRMED) { + window.open(shareLink) + } + }, [sendState.type]) // balance const { value: tokenBalance = '0', loading: loadingTokenBalance } = useFungibleTokenBalance( @@ -206,7 +208,7 @@ Install https://mask.io/download-links to tip my best friend.`, className={classes.tipButton} fullWidth disabled={!isValid || isSending} - onClick={handleSend}> + onClick={sendTip}> {buttonLabel} diff --git a/packages/mask/src/plugins/NextID/contexts/tip/TipTaskProvider.tsx b/packages/mask/src/plugins/NextID/contexts/tip/TipTaskProvider.tsx index 7a3318657deb..853d30344868 100644 --- a/packages/mask/src/plugins/NextID/contexts/tip/TipTaskProvider.tsx +++ b/packages/mask/src/plugins/NextID/contexts/tip/TipTaskProvider.tsx @@ -67,16 +67,19 @@ export function useTip() { const nftTipTuple = useNftTip() const sendTipTuple = context.tipType === TipType.Token ? tokenTipTuple : nftTipTuple + const sendState = sendTipTuple[0] + const sendTip = sendTipTuple[1] + const isSending = [ TransactionStateType.WAIT_FOR_CONFIRMING, TransactionStateType.HASH, TransactionStateType.RECEIPT, - ].includes(sendTipTuple[0].type) + ].includes(sendState.type) return { ...context, isSending, - sendState: sendTipTuple[0], - sendTip: sendTipTuple[1], + sendState, + sendTip, } } diff --git a/packages/mask/src/plugins/NextID/contexts/tip/useNftTip.ts b/packages/mask/src/plugins/NextID/contexts/tip/useNftTip.ts index 8f1edc773cdb..5327fbefeaa0 100644 --- a/packages/mask/src/plugins/NextID/contexts/tip/useNftTip.ts +++ b/packages/mask/src/plugins/NextID/contexts/tip/useNftTip.ts @@ -1,5 +1,5 @@ -import { EthereumTokenType, useTokenTransferCallback } from '@masknet/web3-shared-evm' -import { useCallback, useContext } from 'react' +import { EthereumTokenType, TransactionStateType, useTokenTransferCallback } from '@masknet/web3-shared-evm' +import { useCallback, useContext, useEffect } from 'react' import { TipContext } from './TipContext' import type { TipTuple } from './type' @@ -11,10 +11,15 @@ export function useNftTip(): TipTuple { EthereumTokenType.ERC721, erc721Contract?.address || '', ) + useEffect(() => { + if (transferState.type === TransactionStateType.CONFIRMED) { + resetTransferCallback() + } + }, [transferState.type, resetTransferCallback]) + const sendTip = useCallback(async () => { if (!erc721TokenId) return await transferCallback(erc721TokenId, recipient) - resetTransferCallback() }, [erc721TokenId, recipient, transferCallback, resetTransferCallback]) return [transferState, sendTip] diff --git a/packages/web3-shared/evm/hooks/useERC721TokenTransferCallback.ts b/packages/web3-shared/evm/hooks/useERC721TokenTransferCallback.ts index fb61243453e1..befa46b29abc 100644 --- a/packages/web3-shared/evm/hooks/useERC721TokenTransferCallback.ts +++ b/packages/web3-shared/evm/hooks/useERC721TokenTransferCallback.ts @@ -76,6 +76,13 @@ export function useERC721TokenTransferCallback(address?: string) { }) resolve(hash) }) + .on(TransactionEventType.CONFIRMATION, (no, receipt) => { + setTransferState({ + type: TransactionStateType.CONFIRMED, + no, + receipt, + }) + }) .on(TransactionEventType.ERROR, (error) => { setTransferState({ type: TransactionStateType.FAILED, From 4911204a940470580aa1bfc56c041573bd52a266 Mon Sep 17 00:00:00 2001 From: unclebill Date: Thu, 10 Mar 2022 15:02:54 +0800 Subject: [PATCH 10/15] fixup! fix: pending until confirmed --- .../NextID/components/tip/TipDialog.tsx | 21 +++++++- .../plugins/NextID/components/tip/TipForm.tsx | 26 ++-------- .../plugins/NextID/contexts/tip/TipContext.ts | 13 ++++- .../NextID/contexts/tip/TipTaskProvider.tsx | 50 +++++++++++-------- .../plugins/NextID/contexts/tip/useNftTip.ts | 33 +++++++----- .../NextID/contexts/tip/useTokenTip.ts | 15 +++--- .../hooks/useERC721TokenTransferCallback.ts | 1 + 7 files changed, 95 insertions(+), 64 deletions(-) diff --git a/packages/mask/src/plugins/NextID/components/tip/TipDialog.tsx b/packages/mask/src/plugins/NextID/components/tip/TipDialog.tsx index 4dfaf6de3eb4..bdd04a502e87 100644 --- a/packages/mask/src/plugins/NextID/components/tip/TipDialog.tsx +++ b/packages/mask/src/plugins/NextID/components/tip/TipDialog.tsx @@ -1,11 +1,13 @@ import { PluginId, useActivatedPlugin, usePluginIDContext } from '@masknet/plugin-infra' import { makeStyles } from '@masknet/theme' -import { EMPTY_LIST } from '@masknet/web3-shared-evm' +import { EMPTY_LIST, TransactionStateType } from '@masknet/web3-shared-evm' import { DialogContent } from '@mui/material' +import { useEffect, useMemo } from 'react' import { InjectedDialog } from '../../../../components/shared/InjectedDialog' import { NetworkTab } from '../../../../components/shared/NetworkTab' +import { activatedSocialNetworkUI } from '../../../../social-network' import { useI18N } from '../../../../utils' -import { TargetChainIdContext } from '../../contexts' +import { TargetChainIdContext, useTip } from '../../contexts' import { TipForm } from './TipForm' const useStyles = makeStyles()((theme) => ({ @@ -57,6 +59,21 @@ export function TipDialog({ open = false, onClose }: TipDialogProps) { const { classes } = useStyles() const { targetChainId, setTargetChainId } = TargetChainIdContext.useContainer() + const { amount, token, recipientSnsId, recipient, sendState } = useTip() + + const shareLink = useMemo(() => { + return activatedSocialNetworkUI.utils.getShareLinkURL?.( + `I just tipped ${amount} ${token?.symbol} to @${recipientSnsId}'s wallet address ${recipient} + +Install https://mask.io/download-links to tip my best friend.`, + ) + }, [amount, token?.symbol, recipient, recipientSnsId]) + + useEffect(() => { + if (sendState.type !== TransactionStateType.CONFIRMED) return + window.open(shareLink) + onClose?.() + }, [sendState.type, onClose]) return ( diff --git a/packages/mask/src/plugins/NextID/components/tip/TipForm.tsx b/packages/mask/src/plugins/NextID/components/tip/TipForm.tsx index 742053b1c72f..781ba0710b88 100644 --- a/packages/mask/src/plugins/NextID/components/tip/TipForm.tsx +++ b/packages/mask/src/plugins/NextID/components/tip/TipForm.tsx @@ -2,7 +2,7 @@ import { useWeb3State } from '@masknet/plugin-infra' import { SelectTokenDialogEvent, WalletMessages } from '@masknet/plugin-wallet' import { useRemoteControlledDialog } from '@masknet/shared' import { makeStyles } from '@masknet/theme' -import { EthereumTokenType, TransactionStateType, useFungibleTokenBalance } from '@masknet/web3-shared-evm' +import { EthereumTokenType, useFungibleTokenBalance } from '@masknet/web3-shared-evm' import { Box, BoxProps, @@ -15,10 +15,9 @@ import { Typography, } from '@mui/material' import classnames from 'classnames' -import { FC, memo, useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { FC, memo, useCallback, useRef, useState } from 'react' import { v4 as uuid } from 'uuid' import ActionButton from '../../../../extension/options-page/DashboardComponents/ActionButton' -import { activatedSocialNetworkUI } from '../../../../social-network' import { EthereumChainBoundary } from '../../../../web3/UI/EthereumChainBoundary' import { TokenAmountPanel } from '../../../../web3/UI/TokenAmountPanel' import { TargetChainIdContext, useTip, useTipValidate } from '../../contexts' @@ -65,13 +64,12 @@ const useStyles = makeStyles()((theme) => { interface Props extends BoxProps {} -export const TipForm: FC = memo((props) => { +export const TipForm: FC = memo(({ className, ...rest }) => { const t = useI18N() const { targetChainId: chainId } = TargetChainIdContext.useContainer() const { classes } = useStyles() const { recipient, - recipientSnsId, recipients: recipientAddresses, tipType, setTipType, @@ -81,7 +79,6 @@ export const TipForm: FC = memo((props) => { amount, setAmount, isSending, - sendState, sendTip, } = useTip() const [isValid, validateMessage] = useTipValidate() @@ -110,20 +107,6 @@ export const TipForm: FC = memo((props) => { }) }, [id, token?.address, chainId]) - const shareLink = useMemo(() => { - return activatedSocialNetworkUI.utils.getShareLinkURL?.( - `I just tipped ${amount} ${token?.symbol} to @${recipientSnsId}'s wallet address ${recipient} - -Install https://mask.io/download-links to tip my best friend.`, - ) - }, [amount, token?.symbol, recipient, recipientSnsId]) - - useEffect(() => { - if (sendState.type === TransactionStateType.CONFIRMED) { - window.open(shareLink) - } - }, [sendState.type]) - // balance const { value: tokenBalance = '0', loading: loadingTokenBalance } = useFungibleTokenBalance( token?.type || EthereumTokenType.Native, @@ -131,9 +114,10 @@ Install https://mask.io/download-links to tip my best friend.`, ) // #endregion const buttonLabel = isSending ? t.sending_tip() : isValid || !validateMessage ? t.send_tip() : validateMessage + console.log({ isSending, buttonLabel }) return ( - +
{t.tip_to()} diff --git a/packages/mask/src/plugins/NextID/contexts/tip/TipContext.ts b/packages/mask/src/plugins/NextID/contexts/tip/TipContext.ts index 2f8713ccc72a..79acc615f4cd 100644 --- a/packages/mask/src/plugins/NextID/contexts/tip/TipContext.ts +++ b/packages/mask/src/plugins/NextID/contexts/tip/TipContext.ts @@ -1,4 +1,9 @@ -import type { ERC721ContractDetailed, FungibleTokenDetailed } from '@masknet/web3-shared-evm' +import { + ERC721ContractDetailed, + FungibleTokenDetailed, + TransactionState, + TransactionStateType, +} from '@masknet/web3-shared-evm' import { noop } from 'lodash-unified' import { createContext, Dispatch, SetStateAction } from 'react' import { TipType } from '../../types' @@ -19,6 +24,9 @@ export interface ContextOptions { setErc721TokenId: Dispatch> erc721Contract: ERC721ContractDetailed | null setErc721Contract: Dispatch> + sendTip: () => Promise + isSending: boolean + sendState: TransactionState } export const TipContext = createContext({ @@ -37,4 +45,7 @@ export const TipContext = createContext({ setErc721TokenId: noop, erc721Contract: null, setErc721Contract: noop, + sendTip: noop as () => Promise, + isSending: false, + sendState: { type: TransactionStateType.UNKNOWN }, }) diff --git a/packages/mask/src/plugins/NextID/contexts/tip/TipTaskProvider.tsx b/packages/mask/src/plugins/NextID/contexts/tip/TipTaskProvider.tsx index 853d30344868..509085794984 100644 --- a/packages/mask/src/plugins/NextID/contexts/tip/TipTaskProvider.tsx +++ b/packages/mask/src/plugins/NextID/contexts/tip/TipTaskProvider.tsx @@ -38,6 +38,18 @@ export const TipTaskProvider: FC = ({ children, task }) => { if (!nativeTokenDetailed) return setToken(nativeTokenDetailed) }, [nativeTokenDetailed]) + const tokenTipTuple = useTokenTip(recipient, token, amount) + const nftTipTuple = useNftTip(recipient, erc721TokenId, erc721Contract) + + const sendTipTuple = tipType === TipType.Token ? tokenTipTuple : nftTipTuple + const sendState = sendTipTuple[0] + const sendTip = sendTipTuple[1] + + const isSending = [ + TransactionStateType.WAIT_FOR_CONFIRMING, + TransactionStateType.HASH, + TransactionStateType.RECEIPT, + ].includes(sendState.type) const contextValue = useMemo(() => { return { @@ -56,30 +68,26 @@ export const TipTaskProvider: FC = ({ children, task }) => { setErc721TokenId, erc721Contract, setErc721Contract, + sendTip, + isSending, + sendState, } - }, [recipient, task.recipientSnsId, recipients, tipType, amount, erc721TokenId, erc721Contract, token]) + }, [ + recipient, + task.recipientSnsId, + recipients, + tipType, + amount, + erc721TokenId, + erc721Contract, + token, + sendTip, + isSending, + sendState, + ]) return {children} } export function useTip() { - const context = useContext(TipContext) - const tokenTipTuple = useTokenTip() - const nftTipTuple = useNftTip() - - const sendTipTuple = context.tipType === TipType.Token ? tokenTipTuple : nftTipTuple - const sendState = sendTipTuple[0] - const sendTip = sendTipTuple[1] - - const isSending = [ - TransactionStateType.WAIT_FOR_CONFIRMING, - TransactionStateType.HASH, - TransactionStateType.RECEIPT, - ].includes(sendState.type) - - return { - ...context, - isSending, - sendState, - sendTip, - } + return useContext(TipContext) } diff --git a/packages/mask/src/plugins/NextID/contexts/tip/useNftTip.ts b/packages/mask/src/plugins/NextID/contexts/tip/useNftTip.ts index 5327fbefeaa0..621509e736cf 100644 --- a/packages/mask/src/plugins/NextID/contexts/tip/useNftTip.ts +++ b/packages/mask/src/plugins/NextID/contexts/tip/useNftTip.ts @@ -1,26 +1,33 @@ -import { EthereumTokenType, TransactionStateType, useTokenTransferCallback } from '@masknet/web3-shared-evm' -import { useCallback, useContext, useEffect } from 'react' -import { TipContext } from './TipContext' +import { + ERC721ContractDetailed, + EthereumTokenType, + TransactionStateType, + useTokenTransferCallback, +} from '@masknet/web3-shared-evm' +import { useCallback, useEffect } from 'react' import type { TipTuple } from './type' -export function useNftTip(): TipTuple { - const context = useContext(TipContext) - const { recipient, erc721TokenId, erc721Contract } = context - +export function useNftTip( + recipient: string, + tokenId: string | null, + contract: ERC721ContractDetailed | null, +): TipTuple { const [transferState, transferCallback, resetTransferCallback] = useTokenTransferCallback( EthereumTokenType.ERC721, - erc721Contract?.address || '', + contract?.address || '', ) useEffect(() => { - if (transferState.type === TransactionStateType.CONFIRMED) { - resetTransferCallback() + if (transferState.type !== TransactionStateType.CONFIRMED) { + return } + console.log('resetTransferCallback') + resetTransferCallback() }, [transferState.type, resetTransferCallback]) const sendTip = useCallback(async () => { - if (!erc721TokenId) return - await transferCallback(erc721TokenId, recipient) - }, [erc721TokenId, recipient, transferCallback, resetTransferCallback]) + if (!tokenId) return + await transferCallback(tokenId, recipient) + }, [tokenId, recipient, transferCallback]) return [transferState, sendTip] } diff --git a/packages/mask/src/plugins/NextID/contexts/tip/useTokenTip.ts b/packages/mask/src/plugins/NextID/contexts/tip/useTokenTip.ts index e4513c0367d4..29869812ab1b 100644 --- a/packages/mask/src/plugins/NextID/contexts/tip/useTokenTip.ts +++ b/packages/mask/src/plugins/NextID/contexts/tip/useTokenTip.ts @@ -1,13 +1,16 @@ import { rightShift } from '@masknet/web3-shared-base' -import { EthereumTokenType, isSameAddress, useTokenConstants, useTokenTransferCallback } from '@masknet/web3-shared-evm' -import { useCallback, useContext } from 'react' -import { TipContext } from './TipContext' +import { + EthereumTokenType, + FungibleTokenDetailed, + isSameAddress, + useTokenConstants, + useTokenTransferCallback, +} from '@masknet/web3-shared-evm' +import { useCallback } from 'react' import type { TipTuple } from './type' -export function useTokenTip(): TipTuple { +export function useTokenTip(recipient: string, token: FungibleTokenDetailed | null, amount: string): TipTuple { const { NATIVE_TOKEN_ADDRESS } = useTokenConstants() - const context = useContext(TipContext) - const { token, amount, recipient } = context const isNativeToken = isSameAddress(token?.address, NATIVE_TOKEN_ADDRESS) diff --git a/packages/web3-shared/evm/hooks/useERC721TokenTransferCallback.ts b/packages/web3-shared/evm/hooks/useERC721TokenTransferCallback.ts index befa46b29abc..f10a568be45e 100644 --- a/packages/web3-shared/evm/hooks/useERC721TokenTransferCallback.ts +++ b/packages/web3-shared/evm/hooks/useERC721TokenTransferCallback.ts @@ -14,6 +14,7 @@ export function useERC721TokenTransferCallback(address?: string) { const transferCallback = useCallback( async (tokenId?: string, recipient?: string, gasConfig?: GasConfig) => { + console.log({ account, recipient, tokenId, erc721Contract }) if (!account || !recipient || !tokenId || !erc721Contract) { setTransferState({ type: TransactionStateType.UNKNOWN, From 132b2a1e9c92a40ad8cb9a44da017f229e21a280 Mon Sep 17 00:00:00 2001 From: unclebill Date: Fri, 11 Mar 2022 12:08:03 +0800 Subject: [PATCH 11/15] fix: add confirm dialog --- packages/mask/shared-ui/locales/en-US.json | 1 - packages/mask/shared-ui/locales/qya-AA.json | 1 - packages/mask/shared-ui/locales/zh-CN.json | 1 - .../NextID/components/ConfirmModal.tsx | 61 ++++++++++++++++++ .../components/tip/NFTSection/index.tsx | 11 +++- .../NextID/components/tip/TipDialog.tsx | 64 +++++++++++++------ .../plugins/NextID/components/tip/TipForm.tsx | 19 +++++- .../plugins/NextID/contexts/tip/useNftTip.ts | 1 - .../src/plugins/NextID/locales/en-US.json | 4 +- .../hooks/useERC721TokenTransferCallback.ts | 1 - 10 files changed, 133 insertions(+), 31 deletions(-) create mode 100644 packages/mask/src/plugins/NextID/components/ConfirmModal.tsx diff --git a/packages/mask/shared-ui/locales/en-US.json b/packages/mask/shared-ui/locales/en-US.json index 3c7c1ab7e5db..1e02104217cc 100644 --- a/packages/mask/shared-ui/locales/en-US.json +++ b/packages/mask/shared-ui/locales/en-US.json @@ -494,7 +494,6 @@ "plugin_trader_no_enough_liquidity": "No enough liquidity", "plugin_trader_no_trade": "Please select a trade", "plugin_trader_gas": "GAS", - "plugin_tip_tip": "Tip", "plugin_poll_display_name": "Plugin: Poll", "plugin_poll_question_hint": "Ask a question…", "plugin_poll_options_hint": "choice", diff --git a/packages/mask/shared-ui/locales/qya-AA.json b/packages/mask/shared-ui/locales/qya-AA.json index 50de3eccc996..b822f00c0298 100644 --- a/packages/mask/shared-ui/locales/qya-AA.json +++ b/packages/mask/shared-ui/locales/qya-AA.json @@ -493,7 +493,6 @@ "plugin_trader_no_enough_liquidity": "crwdns10481:0crwdne10481:0", "plugin_trader_no_trade": "crwdns10483:0crwdne10483:0", "plugin_trader_gas": "crwdns10485:0crwdne10485:0", - "plugin_tip_tip": "crwdns14546:0crwdne14546:0", "plugin_poll_display_name": "crwdns4941:0crwdne4941:0", "plugin_poll_question_hint": "crwdns4943:0crwdne4943:0", "plugin_poll_options_hint": "crwdns4945:0crwdne4945:0", diff --git a/packages/mask/shared-ui/locales/zh-CN.json b/packages/mask/shared-ui/locales/zh-CN.json index 8144f1c2ba00..0b2c443f0ff0 100644 --- a/packages/mask/shared-ui/locales/zh-CN.json +++ b/packages/mask/shared-ui/locales/zh-CN.json @@ -477,7 +477,6 @@ "plugin_trader_gas_option": "{{option}} ({{value}}) Gwei", "plugin_trader_no_enough_liquidity": "流动性不足", "plugin_trader_no_trade": "请选择一个交易", - "plugin_tip_tip": "打赏", "plugin_poll_display_name": "插件:投票", "plugin_poll_question_hint": "询问...", "plugin_poll_options_hint": "选项", diff --git a/packages/mask/src/plugins/NextID/components/ConfirmModal.tsx b/packages/mask/src/plugins/NextID/components/ConfirmModal.tsx new file mode 100644 index 000000000000..e1e8ed62a23a --- /dev/null +++ b/packages/mask/src/plugins/NextID/components/ConfirmModal.tsx @@ -0,0 +1,61 @@ +import { makeStyles } from '@masknet/theme' +import { Button, DialogActions, DialogContent } from '@mui/material' +import type { FC, ReactNode } from 'react' +import { InjectedDialog, InjectedDialogProps } from '../../../components/shared/InjectedDialog' + +const useStyles = makeStyles()((theme) => ({ + confirmDialog: { + width: 480, + height: 290, + }, + content: { + display: 'flex', + flexDirection: 'column', + justifyContent: 'center', + justifyItems: 'center', + padding: theme.spacing(3), + boxSizing: 'border-box', + }, + icon: { + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + }, + message: { + color: theme.palette.text.primary, + textAlign: 'center', + fontSize: 18, + }, + actions: { + marginTop: theme.spacing(3), + }, +})) + +interface Props extends InjectedDialogProps { + message: string | ReactNode + icon?: ReactNode + confirmText?: string + onConfirm?(): void +} + +export const ConfirmModal: FC = ({ className, message, icon, confirmText, onConfirm, ...rest }) => { + const { classes } = useStyles() + confirmText = confirmText || 'Confirm' + return ( + + + {icon ?
{icon}
: null} +
{message}
+
+ + + +
+ ) +} diff --git a/packages/mask/src/plugins/NextID/components/tip/NFTSection/index.tsx b/packages/mask/src/plugins/NextID/components/tip/NFTSection/index.tsx index d1d06be52dcc..5e2f34a95471 100644 --- a/packages/mask/src/plugins/NextID/components/tip/NFTSection/index.tsx +++ b/packages/mask/src/plugins/NextID/components/tip/NFTSection/index.tsx @@ -48,7 +48,7 @@ interface Props extends HTMLProps {} export const NFTSection: FC = ({ className, ...rest }) => { const { t } = useI18N() - const { erc721Contract, setErc721Contract, erc721TokenId, setErc721TokenId } = useTip() + const { erc721Contract, setErc721Contract, erc721TokenId, setErc721TokenId, isSending } = useTip() const [tokenId, setTokenId, erc721TokenDetailedCallback] = useERC721TokenDetailedCallback(erc721Contract) const { classes } = useStyles() const account = useAccount() @@ -77,9 +77,16 @@ export const NFTSection: FC = ({ className, ...rest }) => { classes={{ root: classes.keyword }} value={tokenId} onChange={(id) => setTokenId(id)} + inputBaseProps={{ + disabled: isSending, + }} label="" /> - diff --git a/packages/mask/src/plugins/NextID/components/tip/TipDialog.tsx b/packages/mask/src/plugins/NextID/components/tip/TipDialog.tsx index bdd04a502e87..fe5f4e8f81f0 100644 --- a/packages/mask/src/plugins/NextID/components/tip/TipDialog.tsx +++ b/packages/mask/src/plugins/NextID/components/tip/TipDialog.tsx @@ -2,13 +2,17 @@ import { PluginId, useActivatedPlugin, usePluginIDContext } from '@masknet/plugi import { makeStyles } from '@masknet/theme' import { EMPTY_LIST, TransactionStateType } from '@masknet/web3-shared-evm' import { DialogContent } from '@mui/material' -import { useEffect, useMemo } from 'react' +import { useCallback, useEffect, useMemo } from 'react' import { InjectedDialog } from '../../../../components/shared/InjectedDialog' import { NetworkTab } from '../../../../components/shared/NetworkTab' import { activatedSocialNetworkUI } from '../../../../social-network' -import { useI18N } from '../../../../utils' import { TargetChainIdContext, useTip } from '../../contexts' import { TipForm } from './TipForm' +import { ConfirmModal } from '../ConfirmModal' +import { useBoolean } from 'react-use' +import { useI18N } from '../../locales' +import { SuccessIcon } from '@masknet/icons' +import { TipType } from '../../types' const useStyles = makeStyles()((theme) => ({ content: { @@ -55,39 +59,59 @@ export function TipDialog({ open = false, onClose }: TipDialogProps) { const pluginID = usePluginIDContext() const tipDefinition = useActivatedPlugin(PluginId.NextID, 'any') const chainIdList = tipDefinition?.enableRequirement.web3?.[pluginID]?.supportedChainIds ?? EMPTY_LIST - const { t } = useI18N() + const t = useI18N() const { classes } = useStyles() + const [confirmModalIsOpen, openConfirmModal] = useBoolean(false) const { targetChainId, setTargetChainId } = TargetChainIdContext.useContainer() - const { amount, token, recipientSnsId, recipient, sendState } = useTip() + const { tipType, amount, token, recipientSnsId, recipient, sendState, erc721Contract } = useTip() const shareLink = useMemo(() => { + const assetName = tipType === TipType.Token ? `${amount} ${token?.symbol}` : `a ${erc721Contract?.name} NFT` return activatedSocialNetworkUI.utils.getShareLinkURL?.( - `I just tipped ${amount} ${token?.symbol} to @${recipientSnsId}'s wallet address ${recipient} + `I just tipped ${assetName} to @${recipientSnsId}'s wallet address ${recipient} Install https://mask.io/download-links to tip my best friend.`, ) - }, [amount, token?.symbol, recipient, recipientSnsId]) + }, [amount, tipType, erc721Contract?.name, token?.symbol, recipient, recipientSnsId]) + + const successMessage = t.send_tip_successfully() useEffect(() => { if (sendState.type !== TransactionStateType.CONFIRMED) return + openConfirmModal(true) + }, [sendState.type]) + + const handleConfirm = useCallback(() => { window.open(shareLink) + openConfirmModal(false) onClose?.() - }, [sendState.type, onClose]) + }, [onClose]) return ( - - -
- -
- -
-
+ <> + + +
+ +
+ +
+
+ openConfirmModal(false)} + icon={} + message={successMessage} + confirmText={t.tip_share()} + onConfirm={handleConfirm} + /> + ) } diff --git a/packages/mask/src/plugins/NextID/components/tip/TipForm.tsx b/packages/mask/src/plugins/NextID/components/tip/TipForm.tsx index 781ba0710b88..c10983361b00 100644 --- a/packages/mask/src/plugins/NextID/components/tip/TipForm.tsx +++ b/packages/mask/src/plugins/NextID/components/tip/TipForm.tsx @@ -114,7 +114,6 @@ export const TipForm: FC = memo(({ className, ...rest }) => { ) // #endregion const buttonLabel = isSending ? t.sending_tip() : isValid || !validateMessage ? t.send_tip() : validateMessage - console.log({ isSending, buttonLabel }) return ( @@ -125,6 +124,7 @@ export const TipForm: FC = memo(({ className, ...rest }) => {