diff --git a/.i18n-codegen.json b/.i18n-codegen.json index e52852be8948..ded70c3006bd 100644 --- a/.i18n-codegen.json +++ b/.i18n-codegen.json @@ -217,6 +217,18 @@ "trans": "Translate", "sourceMap": "inline" } + }, + { + "input": "./packages/mask/src/plugins/Tips/locales/en-US.json", + "output": "./packages/mask/src/plugins/Tips/locales/i18n_generated", + "parser": "i18next", + "generator": { + "type": "i18next/react-hooks", + "hooks": "useI18N", + "namespace": "com.maskbook.tip", + "trans": "Translate", + "sourceMap": "inline" + } } ] } diff --git a/packages/mask/src/components/shared/ApplicationBoard.tsx b/packages/mask/src/components/shared/ApplicationBoard.tsx index 0ed24c752ecd..e9f01cef7f1f 100644 --- a/packages/mask/src/components/shared/ApplicationBoard.tsx +++ b/packages/mask/src/components/shared/ApplicationBoard.tsx @@ -25,6 +25,7 @@ import { useLastRecognizedIdentity } from '../DataSource/useActivatedUI' import { useSetupGuideStatusState } from '../DataSource/useNextID' import { useMyPersonas } from '../DataSource/useMyPersonas' import { WalletMessages } from '../../plugins/Wallet/messages' +import { PersonaContext } from '../../extension/popups/pages/Personas/hooks/usePersonaContext' const useStyles = makeStyles()((theme) => { const smallQuery = `@media (max-width: ${theme.breakpoints.values.sm}px)` @@ -83,8 +84,14 @@ const useStyles = makeStyles()((theme) => { }, } }) - export function ApplicationBoard() { + return ( + + + + ) +} +function ApplicationBoardContent() { const { classes } = useStyles() const theme = useTheme() const { t } = useI18N() @@ -180,6 +187,7 @@ function RenderEntryComponentWithNextIDRequired({ application }: RenderEntryComp const { t } = useI18N() const platform = ui.configuration.nextIDConfig?.platform as NextIDPlatform const lastState = useSetupGuideStatusState() + const { currentPersona } = PersonaContext.useContainer() const lastRecognized = useLastRecognizedIdentity() const username = useMemo(() => { return lastState.username || (!lastRecognized.identifier.isUnknown ? lastRecognized.identifier.userId : '') @@ -205,7 +213,7 @@ function RenderEntryComponentWithNextIDRequired({ application }: RenderEntryComp currentPersonaPublicKey: currentPersona?.fingerprint, currentSNSConnectedPersonaPublicKey: currentSNSConnectedPersona?.fingerprint, } - }, [platform, username, ui, personas]) + }, [platform, username, ui, personas, currentPersona]) const { isNextIDVerify, isSNSConnectToCurrentPersona, @@ -214,7 +222,7 @@ function RenderEntryComponentWithNextIDRequired({ application }: RenderEntryComp } = ApplicationCurrentStatus ?? {} const { closeDialog } = useRemoteControlledDialog(WalletMessages.events.walletStatusDialogUpdated) - const onNextIDVerify = useCallback(() => { + const onNextIdVerify = useCallback(() => { closeDialog() CrossIsolationMessages.events.verifyNextID.sendToAll(undefined) }, []) @@ -222,22 +230,23 @@ function RenderEntryComponentWithNextIDRequired({ application }: RenderEntryComp if (!application.entry.RenderEntryComponent) return null const RenderEntryComponent = application.entry.RenderEntryComponent - + const shouldVerifyNextId = Boolean(!isNextIDVerify && ApplicationCurrentStatus) + const shouldDisplayTooltipHint = ApplicationCurrentStatus?.isSNSConnectToCurrentPersona === false return ( ) } diff --git a/packages/mask/src/components/shared/VerifyWallet/CurrentWalletBox.tsx b/packages/mask/src/components/shared/VerifyWallet/CurrentWalletBox.tsx index ba1dc22d236e..9df906ccc2c1 100644 --- a/packages/mask/src/components/shared/VerifyWallet/CurrentWalletBox.tsx +++ b/packages/mask/src/components/shared/VerifyWallet/CurrentWalletBox.tsx @@ -108,6 +108,7 @@ export function CurrentWalletBox(props: CurrentWalletBox) { const account = notInPop ? frontAccount : wallet.account const { Utils } = useWeb3State() ?? {} const { value: domain } = useReverseAddress(wallet.account) + const _providerType = wallet.providerType ?? providerType return account ? (
- {wallet.providerType ?? providerType !== ProviderType.MaskWallet ? ( + {_providerType !== ProviderType.MaskWallet ? ( {domain && Utils?.formatDomainName ? Utils.formatDomainName(domain) diff --git a/packages/mask/src/components/shared/VerifyWallet/Steps.tsx b/packages/mask/src/components/shared/VerifyWallet/Steps.tsx index 32ac5104b04f..3d2ffb0db91e 100644 --- a/packages/mask/src/components/shared/VerifyWallet/Steps.tsx +++ b/packages/mask/src/components/shared/VerifyWallet/Steps.tsx @@ -17,7 +17,6 @@ import { useEffect } from 'react' import { useI18N } from '../../../utils' import type { Web3Plugin } from '@masknet/plugin-infra/src/web3-types' import type { ChainId, NetworkType, ProviderType } from '@masknet/web3-shared-evm' -import type { PersonaInformation } from '@masknet/shared-base' import { LoadingButton } from '@mui/lab' const useStyles = makeStyles()((theme) => ({ @@ -92,7 +91,7 @@ export enum SignSteps { interface StepsProps { step: SignSteps - persona: PersonaInformation + nickname?: string wallet: Web3Plugin.ConnectionResult disableConfirm?: boolean confirmLoading: boolean @@ -113,7 +112,7 @@ export function Steps(props: StepsProps) { const navigate = useNavigate() const { changeWallet, - persona, + nickname, wallet, disableConfirm, onConfirm, @@ -181,7 +180,7 @@ export function Steps(props: StepsProps) {
{t('wallet_verify_persona_name', { - personaName: persona.nickname ?? 'Persona Name', + personaName: nickname ?? 'Persona Name', })} diff --git a/packages/mask/src/extension/popups/pages/Personas/VerifyWallet/index.tsx b/packages/mask/src/extension/popups/pages/Personas/VerifyWallet/index.tsx index 7eff6b0dcd91..681068696009 100644 --- a/packages/mask/src/extension/popups/pages/Personas/VerifyWallet/index.tsx +++ b/packages/mask/src/extension/popups/pages/Personas/VerifyWallet/index.tsx @@ -156,7 +156,7 @@ const VerifyWallet = memo(() => {
- - - ) - }, - PostActions() { - if (!Flags.next_id_tip_enabled) return null - return ( - - - - ) - }, } export default sns diff --git a/packages/mask/src/plugins/NextID/components/BindingItem.tsx b/packages/mask/src/plugins/NextID/components/BindingItem.tsx index 54a0438ddd20..3619ac2cd908 100644 --- a/packages/mask/src/plugins/NextID/components/BindingItem.tsx +++ b/packages/mask/src/plugins/NextID/components/BindingItem.tsx @@ -9,7 +9,7 @@ import { ExternalLink } from 'react-feather' import { NetworkPluginID, useNetworkDescriptor, useWeb3State } from '@masknet/plugin-infra/web3' import { useI18N } from '../locales' import { ImageIcon } from '@masknet/shared' -import { TipButton } from './Tip' +import { TipButton } from '../../../plugins/Tips/components' import { useCurrentVisitingIdentity } from '../../../components/DataSource/useActivatedUI' const useStyles = makeStyles()((theme) => ({ diff --git a/packages/mask/src/plugins/NextID/locales/en-US.json b/packages/mask/src/plugins/NextID/locales/en-US.json index e18a9c69bf11..172eb75f2245 100644 --- a/packages/mask/src/plugins/NextID/locales/en-US.json +++ b/packages/mask/src/plugins/NextID/locales/en-US.json @@ -45,30 +45,10 @@ "copy_success_of_wallet_address": "Copy wallet address successfully!", "disconnect_warning": "This wallet will no longer show up in your web 3 profile page. Your Mask friends can no longer give tips to this wallet, or browse NFTs, donations and other on-chain information of this address.", "tips": "Tips", - "tip_to": "To", "token_insufficient_balance": "Insufficient balance", - "tip_type_token": "Token", - "tip_type_nft": "NFT", - "tip_wallets_missed": "Wallets not found.", - "send_tip": "Send", "sending_tip": "Sending...", "nft_not_belong_to_you": "The collectible doesn't exist or belong to you.", "send_tip_successfully": "Sent tip successfully.", "send_specific_tip_successfully": "Sent {{amount}} {{name}} tip successfully.", - "tip_share": "Share", - "tip_connect_wallet_message": "Please connect to a wallet.", - "tip_connect_wallet": "Connect Wallet", - "search": "Search", - "tip_contracts": "Contracts", - "tip_mask_promote": "Install https://mask.io/download-links to send your first tip.", - "tip_token_share_post": "I just tipped {{amount}} {{symbol}} to @{{recipientSnsId}}'s wallet address {{recipient}}\n\n{{promote}}", - "tip_nft_share_post": "I just tipped a {{name}} to @{{recipientSnsId}}'s wallet address {{recipient}}\n\n{{promote}}", - "tip_add": "Add", - "tip_adding": "Adding", - "tip_add_collectibles": "Add Collectibles", - "tip_add_collectibles_contract_address": "Input contract address", - "tip_add_collectibles_token_id": "Token ID", - "tip_add_collectibles_error": "The contract address is incorrect or the collectible does not belong to you.", - "tip_loading": "Loading", - "tip_empty_nft": "No any collectible is available to preview. Please add your collectible here." + "search": "Search" } diff --git a/packages/mask/src/plugins/Tips/SNSAdaptor/TipsEntranceDialog.tsx b/packages/mask/src/plugins/Tips/SNSAdaptor/TipsEntranceDialog.tsx index 8423e7250331..5ff2f176e802 100644 --- a/packages/mask/src/plugins/Tips/SNSAdaptor/TipsEntranceDialog.tsx +++ b/packages/mask/src/plugins/Tips/SNSAdaptor/TipsEntranceDialog.tsx @@ -18,7 +18,7 @@ import { LoadingButton } from '@mui/lab' import { Button, ButtonProps, DialogContent } from '@mui/material' import formatDateTime from 'date-fns/format' import { cloneDeep } from 'lodash-unified' -import { FC, useCallback, useMemo, useState } from 'react' +import { FC, useCallback, useEffect, useMemo, useState } from 'react' import { useAsyncFn, useAsyncRetry } from 'react-use' import ActionButton from '../../../extension/options-page/DashboardComponents/ActionButton' import Services from '../../../extension/service' @@ -26,6 +26,7 @@ import { useI18N } from '../../../utils' import { getKvPayload, setKvPatchData, useKvGet } from '../hooks/useKv' import { useTipsWalletsList } from '../hooks/useTipsWalletsList' import { useProvedWallets } from '../hooks/useProvedWallets' +import { useSupportedNetworks } from '../hooks/useSupportedNetworks' import AddWalletView from './bodyViews/AddWallet' import SettingView from './bodyViews/Setting' import WalletsView from './bodyViews/Wallets' @@ -101,9 +102,11 @@ export function TipsEntranceDialog({ open, onClose }: TipsEntranceDialogProps) { const [hasChanged, setHasChanged] = useState(false) const [rawPatchData, setRawPatchData] = useState([]) const [rawWalletList, setRawWalletList] = useState([]) - const supportedNetworks = useActivatedPlugin(PluginId.Tips, 'any')?.enableRequirement?.web3?.[ - NetworkPluginID.PLUGIN_EVM - ]?.tipsSupportedChains + const plugin = useActivatedPlugin(PluginId.Tips, 'any') + const supportedNetworks = useSupportedNetworks( + Object.keys(plugin?.enableRequirement.web3 ?? {}) as NetworkPluginID[], + ) + const { showSnackbar } = useCustomSnackbar() const account = useAccount() const nowTime = formatDateTime(new Date(), 'yyyy-MM-dd HH:mm') @@ -112,10 +115,9 @@ export function TipsEntranceDialog({ open, onClose }: TipsEntranceDialogProps) { setShowAlert(true) return Services.Settings.getCurrentPersonaIdentifier() }, [open]) - const { value: currentPersona } = useAsyncRetry( - () => Services.Identity.queryPersona(currentPersonaIdentifier as ECKeyIdentifier), - [currentPersonaIdentifier], - ) + const { value: currentPersona } = useAsyncRetry(() => { + return Services.Identity.queryPersona(currentPersonaIdentifier!) + }, [currentPersonaIdentifier]) const clickBack = () => { if (bodyViewStep === BodyViewStep.Main) { onClose() @@ -123,13 +125,11 @@ export function TipsEntranceDialog({ open, onClose }: TipsEntranceDialogProps) { setBodyViewStep(BodyViewStep.Main) } } - const { value: kv, retry: retryKv } = useKvGet() - const { loading, value: proofRes, retry: retryProof } = useProvedWallets() - const list = useTipsWalletsList( - proofRes as BindingProof[], - currentPersona?.publicHexKey, - kv?.val as NextIDStorageInfo, + const { value: kv, retry: retryKv } = useKvGet>( + currentPersonaIdentifier?.publicKeyAsHex, ) + const { loading, value: proofRes, retry: retryProof } = useProvedWallets(currentPersonaIdentifier) + const list = useTipsWalletsList(proofRes, currentPersona?.publicHexKey, kv?.ok ? kv.val : undefined) useMemo(() => { setHasChanged(false) setRawPatchData(list) @@ -146,14 +146,7 @@ export function TipsEntranceDialog({ open, onClose }: TipsEntranceDialogProps) { retryProof() retryKv() } - const titleTail = ( - { - setBodyViewStep(bodyViewStep === BodyViewStep.Wallets ? BodyViewStep.AddWallet : BodyViewStep.Wallets) - }} - /> - ) + const setAsDefault = (idx: number) => { const changed = cloneDeep(rawPatchData) changed.forEach((x: any) => (x.isDefault = 0)) @@ -198,7 +191,9 @@ export function TipsEntranceDialog({ open, onClose }: TipsEntranceDialogProps) { return false } }, [hasChanged, rawPatchData]) - const { setDialog } = useRemoteControlledDialog(WalletMessages.events.selectProviderDialogUpdated) + const { setDialog, open: providerDialogOpen } = useRemoteControlledDialog( + WalletMessages.events.selectProviderDialogUpdated, + ) const onConnectWalletClick = useCallback(() => { if (account) { setBodyViewStep(BodyViewStep.AddWallet) @@ -207,11 +202,15 @@ export function TipsEntranceDialog({ open, onClose }: TipsEntranceDialogProps) { open: true, pluginID: NetworkPluginID.PLUGIN_EVM, }) - WalletMessages.events.walletsUpdated.on(() => { - setBodyViewStep(BodyViewStep.AddWallet) - }) } }, [account]) + + useEffect(() => { + if (!providerDialogOpen) return + return WalletMessages.events.walletsUpdated.on(() => { + setBodyViewStep(BodyViewStep.AddWallet) + }) + }, [providerDialogOpen]) const [confirmState, onConfirmRelease] = useAsyncFn( async (wallet: BindingProof | undefined) => { try { @@ -255,7 +254,20 @@ export function TipsEntranceDialog({ open, onClose }: TipsEntranceDialogProps) { ) return ( - + { + setBodyViewStep( + bodyViewStep === BodyViewStep.Wallets ? BodyViewStep.AddWallet : BodyViewStep.Wallets, + ) + }} + /> + }> {loading ? (
@@ -300,7 +312,7 @@ export function TipsEntranceDialog({ open, onClose }: TipsEntranceDialogProps) { /> )} {bodyViewStep === BodyViewStep.AddWallet && ( - + )} {![BodyViewStep.AddWallet, BodyViewStep.Wallets].includes(bodyViewStep) && rawPatchData.length > 0 && ( diff --git a/packages/mask/src/plugins/Tips/SNSAdaptor/bodyViews/AddWallet.tsx b/packages/mask/src/plugins/Tips/SNSAdaptor/bodyViews/AddWallet.tsx index 96d26794466f..0faa80893765 100644 --- a/packages/mask/src/plugins/Tips/SNSAdaptor/bodyViews/AddWallet.tsx +++ b/packages/mask/src/plugins/Tips/SNSAdaptor/bodyViews/AddWallet.tsx @@ -2,7 +2,9 @@ import { BindingProof, NextIDAction, NextIDPlatform } from '@masknet/shared-base import { WalletMessages } from '@masknet/plugin-wallet' import { useRemoteControlledDialog } from '@masknet/shared-base-ui' import { + ChainId, isSameAddress, + NetworkType, ProviderType, resolveProviderName, useAccount, @@ -18,11 +20,28 @@ import { NextIDProof } from '@masknet/web3-providers' import Services from '../../../../extension/service' import { useCustomSnackbar } from '@masknet/theme' import formatDateTime from 'date-fns/format' -import { NetworkPluginID, useProviderDescriptor, useReverseAddress, useWeb3State } from '@masknet/plugin-infra/web3' +import { + NetworkPluginID, + useProviderDescriptor, + useReverseAddress, + useWeb3State, + Web3Plugin, +} from '@masknet/plugin-infra/web3' import { useI18N } from '../../../../utils' +import type { Persona } from '../../../../database' interface AddWalletViewProps { - currentPersona: any + currentPersona: Pick< + Persona, + | 'publicHexKey' + | 'identifier' + | 'hasPrivateKey' + | 'mnemonic' + | 'createdAt' + | 'updatedAt' + | 'linkedProfiles' + | 'nickname' + > bindings: BindingProof[] onCancel: () => void } @@ -42,7 +61,7 @@ const AddWalletView = memo(({ currentPersona, bindings, onCancel }: AddWalletVie const { Utils } = useWeb3State() ?? {} const isNotEvm = useProviderDescriptor()?.providerAdaptorPluginID !== NetworkPluginID.PLUGIN_EVM const nowTime = formatDateTime(new Date(), 'yyyy-MM-dd HH:mm') - const isBound = bindings.filter((x) => isSameAddress(x.identity, wallet.account)).length > 0 + const isBound = bindings.some((x) => isSameAddress(x.identity, wallet.account)) const walletName = () => { if (isNotEvm) return `${resolveProviderName(providerType)} Wallet` @@ -144,14 +163,9 @@ const AddWalletView = memo(({ currentPersona, bindings, onCancel }: AddWalletVie isBound={isBound} notEvm={isNotEvm} notConnected={!wallet.account} - wallet={{ - account: wallet.account, - chainId: wallet.chainId, - networkType: wallet.networkType, - providerType: wallet.providerType, - }} + wallet={wallet as Web3Plugin.ConnectionResult} walletName={walletName()} - persona={currentPersona} + nickname={currentPersona.nickname} step={step} confirmLoading={confirmLoading || payloadLoading} disableConfirm={isBound || isNotEvm || !wallet.account} diff --git a/packages/mask/src/plugins/Tips/SNSAdaptor/components/WalletItem.tsx b/packages/mask/src/plugins/Tips/SNSAdaptor/components/WalletItem.tsx index f39c1b5c53b9..44b6b0a86b9f 100644 --- a/packages/mask/src/plugins/Tips/SNSAdaptor/components/WalletItem.tsx +++ b/packages/mask/src/plugins/Tips/SNSAdaptor/components/WalletItem.tsx @@ -1,7 +1,7 @@ import { useReverseAddress, useWeb3State } from '@masknet/plugin-infra/web3' import { FormattedAddress, useSnackbarCallback } from '@masknet/shared' import { makeStyles } from '@masknet/theme' -import { ChainId, isSameAddress, useWallets } from '@masknet/web3-shared-evm' +import { ChainId, formatEthereumAddress, isSameAddress, useWallets } from '@masknet/web3-shared-evm' import { Link, Typography } from '@mui/material' import { useMemo } from 'react' import { useCopyToClipboard } from 'react-use' @@ -103,7 +103,7 @@ export function WalletItem({ const onCopy = useSnackbarCallback( async (ev: React.MouseEvent) => { ev.stopPropagation() - copyToClipboard(address) + copyToClipboard(formatEthereumAddress(address)) }, [], undefined, diff --git a/packages/mask/src/plugins/Tips/SNSAdaptor/index.tsx b/packages/mask/src/plugins/Tips/SNSAdaptor/index.tsx index eb0055072fdd..8a6f38fa2d51 100644 --- a/packages/mask/src/plugins/Tips/SNSAdaptor/index.tsx +++ b/packages/mask/src/plugins/Tips/SNSAdaptor/index.tsx @@ -1,14 +1,19 @@ +import { TipsIcon } from '@masknet/icons' import type { Plugin } from '@masknet/plugin-infra' -import { base } from '../base' +import { PluginI18NFieldRender } from '@masknet/plugin-infra/content-script' import { ApplicationEntry } from '@masknet/shared' import { useState } from 'react' +import { base } from '../base' +import { PostTipButton, TipTaskManager } from '../components' +import { RootContext } from '../contexts' +import { setupStorage, storageDefaultValue } from '../storage' import { TipsEntranceDialog } from './TipsEntranceDialog' -import { PluginI18NFieldRender } from '@masknet/plugin-infra/content-script' -import { TipsIcon } from '@masknet/icons' const sns: Plugin.SNSAdaptor.Definition = { ...base, - init(signal) {}, + init(_, context) { + setupStorage(context.createKVStorage('memory', storageDefaultValue)) + }, ApplicationEntries: [ (() => { const name = base.name @@ -23,7 +28,7 @@ const sns: Plugin.SNSAdaptor.Definition = { title={} {...EntryComponentProps} icon={icon} - onClick={() => setOpen(true)} + onClick={EntryComponentProps.onClick ?? (() => setOpen(true))} /> setOpen(false)} /> @@ -38,6 +43,20 @@ const sns: Plugin.SNSAdaptor.Definition = { } })(), ], + GlobalInjection() { + return ( + + + + ) + }, + PostActions() { + return ( + + + + ) + }, } export default sns diff --git a/packages/mask/src/plugins/Tips/assets/flow.png b/packages/mask/src/plugins/Tips/assets/flow.png new file mode 100644 index 000000000000..df6dac58f726 Binary files /dev/null and b/packages/mask/src/plugins/Tips/assets/flow.png differ diff --git a/packages/mask/src/plugins/Tips/assets/solana.png b/packages/mask/src/plugins/Tips/assets/solana.png new file mode 100644 index 000000000000..9b71187458b1 Binary files /dev/null and b/packages/mask/src/plugins/Tips/assets/solana.png differ diff --git a/packages/mask/src/plugins/Tips/base.ts b/packages/mask/src/plugins/Tips/base.ts index 80dc57fff70b..c055f214de2a 100644 --- a/packages/mask/src/plugins/Tips/base.ts +++ b/packages/mask/src/plugins/Tips/base.ts @@ -1,6 +1,7 @@ import { Plugin, PluginId } from '@masknet/plugin-infra' import { NetworkPluginID } from '@masknet/plugin-infra/web3' import { ChainId } from '@masknet/web3-shared-evm' +import { languages } from './locales/languages' export const base: Plugin.Shared.Definition = { ID: PluginId.Tips, @@ -29,8 +30,8 @@ export const base: Plugin.Shared.Definition = { ChainId.Aurora, ChainId.Conflux, ], - tipsSupportedChains: [{ name: 'Evm Chain', icon: new URL('./assets/Tip.png', import.meta.url) }], }, }, }, + i18n: languages, } diff --git a/packages/mask/src/plugins/NextID/components/Tip/AddDialog.tsx b/packages/mask/src/plugins/Tips/components/AddDialog.tsx similarity index 98% rename from packages/mask/src/plugins/NextID/components/Tip/AddDialog.tsx rename to packages/mask/src/plugins/Tips/components/AddDialog.tsx index 0a845139048f..6d910f090ad4 100644 --- a/packages/mask/src/plugins/NextID/components/Tip/AddDialog.tsx +++ b/packages/mask/src/plugins/Tips/components/AddDialog.tsx @@ -14,8 +14,8 @@ import { Button, DialogContent, FormControl, TextField, Typography } from '@mui/ import { FC, useCallback, useEffect, useMemo, useState } from 'react' import { useAsyncFn } from 'react-use' import { EthereumAddress } from 'wallet.ts' -import { WalletRPC } from '../../../Wallet/messages' -import { useI18N } from '../../locales' +import { WalletRPC } from '../../Wallet/messages' +import { useI18N } from '../locales' const useStyles = makeStyles()((theme) => ({ addButton: { diff --git a/packages/mask/src/plugins/NextID/components/Tip/NFTSection/NFTList.tsx b/packages/mask/src/plugins/Tips/components/NFTSection/NFTList.tsx similarity index 97% rename from packages/mask/src/plugins/NextID/components/Tip/NFTSection/NFTList.tsx rename to packages/mask/src/plugins/Tips/components/NFTSection/NFTList.tsx index 1205fe7ad0e3..4fe997d244f6 100644 --- a/packages/mask/src/plugins/NextID/components/Tip/NFTSection/NFTList.tsx +++ b/packages/mask/src/plugins/Tips/components/NFTSection/NFTList.tsx @@ -6,7 +6,7 @@ import { Checkbox, Link, List, ListItem, Radio } from '@mui/material' import classnames from 'classnames' import { noop } from 'lodash-unified' import { FC, useCallback } from 'react' -import type { TipNFTKeyPair } from '../../../types' +import type { TipNFTKeyPair } from '../../types' interface Props { selectedPairs: TipNFTKeyPair[] @@ -134,8 +134,8 @@ export const NFTList: FC = ({ selectedPairs, tokens, onChange, limit = 1, const link = Utils?.resolveNonFungibleTokenLink && token.contract ? Utils.resolveNonFungibleTokenLink( - token.contract?.chainId, - token.contract?.address, + token.contract.chainId, + token.contract.address, token.tokenId, ) : undefined diff --git a/packages/mask/src/plugins/NextID/components/Tip/NFTSection/index.tsx b/packages/mask/src/plugins/Tips/components/NFTSection/index.tsx similarity index 96% rename from packages/mask/src/plugins/NextID/components/Tip/NFTSection/index.tsx rename to packages/mask/src/plugins/Tips/components/NFTSection/index.tsx index 5fe00ba9286c..849b82601caf 100644 --- a/packages/mask/src/plugins/NextID/components/Tip/NFTSection/index.tsx +++ b/packages/mask/src/plugins/Tips/components/NFTSection/index.tsx @@ -7,10 +7,10 @@ import classnames from 'classnames' import { uniqWith } from 'lodash-unified' import { FC, HTMLProps, useEffect, useMemo, useState } from 'react' import { useAsyncFn, useTimeoutFn } from 'react-use' -import { WalletMessages } from '../../../../Wallet/messages' -import { useTip } from '../../../contexts' -import { useI18N } from '../../../locales' -import type { TipNFTKeyPair } from '../../../types' +import { WalletMessages } from '../../../Wallet/messages' +import { useTip } from '../../contexts' +import { useI18N } from '../../locales' +import type { TipNFTKeyPair } from '../../types' import { NFTList } from './NFTList' export * from './NFTList' diff --git a/packages/mask/src/plugins/NextID/components/Tip/TipButton.tsx b/packages/mask/src/plugins/Tips/components/TipButton.tsx similarity index 73% rename from packages/mask/src/plugins/NextID/components/Tip/TipButton.tsx rename to packages/mask/src/plugins/Tips/components/TipButton.tsx index e1a67cc537a0..4314bfd6f309 100644 --- a/packages/mask/src/plugins/NextID/components/Tip/TipButton.tsx +++ b/packages/mask/src/plugins/Tips/components/TipButton.tsx @@ -7,12 +7,13 @@ import type { TooltipProps } from '@mui/material' import classnames from 'classnames' import { uniq } from 'lodash-unified' import { FC, HTMLProps, MouseEventHandler, useCallback, useEffect, useMemo } from 'react' -import { useAsync, useAsyncFn, useAsyncRetry } from 'react-use' -import Services from '../../../../extension/service' -import { activatedSocialNetworkUI } from '../../../../social-network' -import { useI18N } from '../../locales' -import { PluginNextIDMessages } from '../../messages' -import { MaskMessages } from '../../../../../shared' +import { useAsyncRetry } from 'react-use' +import { MaskMessages } from '../../../../shared' +import Services from '../../../extension/service' +import { activatedSocialNetworkUI } from '../../../social-network' +import { usePublicWallets } from '../hooks/usePublicWallets' +import { useI18N } from '../locales' +import { PluginNextIDMessages } from '../messages' interface Props extends HTMLProps { addresses?: string[] @@ -81,49 +82,30 @@ export const TipButton: FC = ({ return NextIDProof.queryIsBound(receiverPersona.publicHexKey, platform, receiver.userId, true) }, [receiverPersona?.publicHexKey, platform, receiver?.userId]) - const [walletsState, queryBindings] = useAsyncFn(async () => { - if (!receiver) return EMPTY_LIST - - const persona = await Services.Identity.queryPersonaByProfile(receiver) - if (!persona?.publicHexKey) return EMPTY_LIST - - const bindings = await NextIDProof.queryExistedBindingByPersona(persona.publicHexKey, true) - if (!bindings) return EMPTY_LIST - - const wallets = bindings.proofs.filter((p) => p.platform === NextIDPlatform.Ethereum).map((p) => p.identity) - return wallets - }, [receiver]) - - useAsync(queryBindings, [queryBindings]) - useEffect(() => { return MaskMessages.events.ownProofChanged.on(() => { retryLoadVerifyInfo() - queryBindings() }) }, []) - const allAddresses = useMemo(() => { - return uniq([...(walletsState.value || []), ...addresses]) - }, [walletsState.value, addresses]) + const publicWallets = usePublicWallets(receiver) + const allAddresses = useMemo(() => uniq([...publicWallets, ...addresses]), [publicWallets, addresses]) - const disabled = loadingPersona || loadingVerifyInfo || !isAccountVerified || allAddresses.length === 0 + const isChecking = loadingPersona || loadingVerifyInfo + const disabled = isChecking || !isAccountVerified || allAddresses.length === 0 const sendTip: MouseEventHandler = useCallback( async (evt) => { evt.stopPropagation() evt.preventDefault() if (disabled) return - if (walletsState.loading || !walletsState.value) { - await queryBindings() - } if (!allAddresses.length || !receiver?.userId) return PluginNextIDMessages.tipTask.sendToLocal({ recipientSnsId: receiver.userId, addresses: allAddresses, }) }, - [disabled, walletsState, allAddresses, receiver?.userId, queryBindings], + [disabled, allAddresses, receiver?.userId], ) const dom = (
= ({ return ( diff --git a/packages/mask/src/plugins/NextID/components/Tip/TipDialog.tsx b/packages/mask/src/plugins/Tips/components/TipDialog.tsx similarity index 95% rename from packages/mask/src/plugins/NextID/components/Tip/TipDialog.tsx rename to packages/mask/src/plugins/Tips/components/TipDialog.tsx index 43e733d37edc..9f944db06ba0 100644 --- a/packages/mask/src/plugins/NextID/components/Tip/TipDialog.tsx +++ b/packages/mask/src/plugins/Tips/components/TipDialog.tsx @@ -21,14 +21,14 @@ import { import { DialogContent, Link, Typography } from '@mui/material' import { useCallback, useEffect, useMemo } from 'react' import { useBoolean } from 'react-use' -import { hasNativeAPI, nativeAPI } from '../../../../../shared/native-rpc' -import { NetworkTab } from '../../../../components/shared/NetworkTab' -import { activatedSocialNetworkUI } from '../../../../social-network' -import { WalletMessages } from '../../../Wallet/messages' -import { TargetChainIdContext, useTip } from '../../contexts' -import { useI18N } from '../../locales' -import { TipType } from '../../types' -import { ConfirmModal } from '../ConfirmModal' +import { hasNativeAPI, nativeAPI } from '../../../../shared/native-rpc' +import { NetworkTab } from '../../../components/shared/NetworkTab' +import { activatedSocialNetworkUI } from '../../../social-network' +import { WalletMessages } from '../../Wallet/messages' +import { TargetChainIdContext, useTip } from '../contexts' +import { useI18N } from '../locales' +import { TipType } from '../types' +import { ConfirmModal } from './common/ConfirmModal' import { AddDialog } from './AddDialog' import { TipForm } from './TipForm' diff --git a/packages/mask/src/plugins/NextID/components/Tip/TipForm.tsx b/packages/mask/src/plugins/Tips/components/TipForm.tsx similarity index 96% rename from packages/mask/src/plugins/NextID/components/Tip/TipForm.tsx rename to packages/mask/src/plugins/Tips/components/TipForm.tsx index baa272a78c6a..3c151a6e67b3 100644 --- a/packages/mask/src/plugins/NextID/components/Tip/TipForm.tsx +++ b/packages/mask/src/plugins/Tips/components/TipForm.tsx @@ -17,11 +17,11 @@ import { } from '@mui/material' import classnames from 'classnames' import { FC, memo, useRef, useState } from 'react' -import ActionButton from '../../../../extension/options-page/DashboardComponents/ActionButton' -import { EthereumChainBoundary } from '../../../../web3/UI/EthereumChainBoundary' -import { TargetChainIdContext, useTip, useTipValidate } from '../../contexts' -import { useI18N } from '../../locales' -import { TipType } from '../../types' +import ActionButton from '../../../extension/options-page/DashboardComponents/ActionButton' +import { EthereumChainBoundary } from '../../../web3/UI/EthereumChainBoundary' +import { TargetChainIdContext, useTip, useTipValidate } from '../contexts' +import { useI18N } from '../locales' +import { TipType } from '../types' import { NFTSection } from './NFTSection' import { TokenSection } from './TokenSection' diff --git a/packages/mask/src/plugins/NextID/components/Tip/TipTaskManager.tsx b/packages/mask/src/plugins/Tips/components/TipTaskManager.tsx similarity index 86% rename from packages/mask/src/plugins/NextID/components/Tip/TipTaskManager.tsx rename to packages/mask/src/plugins/Tips/components/TipTaskManager.tsx index de1c69eb36ce..2aa43907e175 100644 --- a/packages/mask/src/plugins/NextID/components/Tip/TipTaskManager.tsx +++ b/packages/mask/src/plugins/Tips/components/TipTaskManager.tsx @@ -1,8 +1,8 @@ import { FC, useCallback, useEffect, useState } from 'react' import { EMPTY_LIST } from '@masknet/shared-base' -import { TipTaskProvider } from '../../contexts' -import { PluginNextIDMessages } from '../../messages' -import type { TipTask } from '../../types' +import { TipTaskProvider } from '../contexts' +import { PluginNextIDMessages } from '../messages' +import type { TipTask } from '../types' import { TipDialog } from './TipDialog' let id = 0 diff --git a/packages/mask/src/plugins/NextID/components/Tip/TokenSection/index.tsx b/packages/mask/src/plugins/Tips/components/TokenSection/index.tsx similarity index 92% rename from packages/mask/src/plugins/NextID/components/Tip/TokenSection/index.tsx rename to packages/mask/src/plugins/Tips/components/TokenSection/index.tsx index 2ad861a59cbc..bf08d00bc56b 100644 --- a/packages/mask/src/plugins/NextID/components/Tip/TokenSection/index.tsx +++ b/packages/mask/src/plugins/Tips/components/TokenSection/index.tsx @@ -8,9 +8,9 @@ import { } from '@masknet/web3-shared-evm' import BigNumber from 'bignumber.js' import { FC, useCallback, useEffect, useMemo } from 'react' -import { TokenAmountPanel } from '../../../../../web3/UI/TokenAmountPanel' -import { useGasConfig } from '../../../../Trader/SNSAdaptor/trader/hooks/useGasConfig' -import { TargetChainIdContext, useTip } from '../../../contexts' +import { TokenAmountPanel } from '../../../../web3/UI/TokenAmountPanel' +import { useGasConfig } from '../../../Trader/SNSAdaptor/trader/hooks/useGasConfig' +import { TargetChainIdContext, useTip } from '../../contexts' const GAS_LIMIT = 21000 export const TokenSection: FC = () => { diff --git a/packages/mask/src/plugins/NextID/components/ConfirmModal.tsx b/packages/mask/src/plugins/Tips/components/common/ConfirmModal.tsx similarity index 100% rename from packages/mask/src/plugins/NextID/components/ConfirmModal.tsx rename to packages/mask/src/plugins/Tips/components/common/ConfirmModal.tsx diff --git a/packages/mask/src/plugins/NextID/components/Tip/index.ts b/packages/mask/src/plugins/Tips/components/index.ts similarity index 100% rename from packages/mask/src/plugins/NextID/components/Tip/index.ts rename to packages/mask/src/plugins/Tips/components/index.ts diff --git a/packages/mask/src/plugins/NextID/contexts/RootContext.tsx b/packages/mask/src/plugins/Tips/contexts/RootContext.tsx similarity index 100% rename from packages/mask/src/plugins/NextID/contexts/RootContext.tsx rename to packages/mask/src/plugins/Tips/contexts/RootContext.tsx diff --git a/packages/mask/src/plugins/NextID/contexts/TargetChainIdContext.ts b/packages/mask/src/plugins/Tips/contexts/TargetChainIdContext.ts similarity index 100% rename from packages/mask/src/plugins/NextID/contexts/TargetChainIdContext.ts rename to packages/mask/src/plugins/Tips/contexts/TargetChainIdContext.ts diff --git a/packages/mask/src/plugins/NextID/contexts/Tip/TipContext.ts b/packages/mask/src/plugins/Tips/contexts/Tip/TipContext.ts similarity index 100% rename from packages/mask/src/plugins/NextID/contexts/Tip/TipContext.ts rename to packages/mask/src/plugins/Tips/contexts/Tip/TipContext.ts diff --git a/packages/mask/src/plugins/NextID/contexts/Tip/TipTaskProvider.tsx b/packages/mask/src/plugins/Tips/contexts/Tip/TipTaskProvider.tsx similarity index 100% rename from packages/mask/src/plugins/NextID/contexts/Tip/TipTaskProvider.tsx rename to packages/mask/src/plugins/Tips/contexts/Tip/TipTaskProvider.tsx diff --git a/packages/mask/src/plugins/NextID/contexts/Tip/index.ts b/packages/mask/src/plugins/Tips/contexts/Tip/index.ts similarity index 100% rename from packages/mask/src/plugins/NextID/contexts/Tip/index.ts rename to packages/mask/src/plugins/Tips/contexts/Tip/index.ts diff --git a/packages/mask/src/plugins/NextID/contexts/Tip/type.ts b/packages/mask/src/plugins/Tips/contexts/Tip/type.ts similarity index 100% rename from packages/mask/src/plugins/NextID/contexts/Tip/type.ts rename to packages/mask/src/plugins/Tips/contexts/Tip/type.ts diff --git a/packages/mask/src/plugins/NextID/contexts/Tip/useNftTip.ts b/packages/mask/src/plugins/Tips/contexts/Tip/useNftTip.ts similarity index 100% rename from packages/mask/src/plugins/NextID/contexts/Tip/useNftTip.ts rename to packages/mask/src/plugins/Tips/contexts/Tip/useNftTip.ts diff --git a/packages/mask/src/plugins/NextID/contexts/Tip/useTipValidate.ts b/packages/mask/src/plugins/Tips/contexts/Tip/useTipValidate.ts similarity index 100% rename from packages/mask/src/plugins/NextID/contexts/Tip/useTipValidate.ts rename to packages/mask/src/plugins/Tips/contexts/Tip/useTipValidate.ts diff --git a/packages/mask/src/plugins/NextID/contexts/Tip/useTokenTip.ts b/packages/mask/src/plugins/Tips/contexts/Tip/useTokenTip.ts similarity index 100% rename from packages/mask/src/plugins/NextID/contexts/Tip/useTokenTip.ts rename to packages/mask/src/plugins/Tips/contexts/Tip/useTokenTip.ts diff --git a/packages/mask/src/plugins/NextID/contexts/index.ts b/packages/mask/src/plugins/Tips/contexts/index.ts similarity index 100% rename from packages/mask/src/plugins/NextID/contexts/index.ts rename to packages/mask/src/plugins/Tips/contexts/index.ts diff --git a/packages/mask/src/plugins/Tips/hooks/useKv.ts b/packages/mask/src/plugins/Tips/hooks/useKv.ts index 44e440644742..39fa32329047 100644 --- a/packages/mask/src/plugins/Tips/hooks/useKv.ts +++ b/packages/mask/src/plugins/Tips/hooks/useKv.ts @@ -13,11 +13,11 @@ const getCurrentPersonaPublicKey = async () => { if (!currentPersona?.publicHexKey) return '' return currentPersona.publicHexKey } -export function useKvGet() { +export function useKvGet(publicKey: string | null | undefined) { return useAsyncRetry(async () => { - const publicHexKey = await getCurrentPersonaPublicKey() - return NextIDStorage.get(publicHexKey) - }) + if (!publicKey) return null + return NextIDStorage.get(publicKey) + }, [publicKey]) } export const getKvPayload = async (patchData: unknown) => { diff --git a/packages/mask/src/plugins/Tips/hooks/useProfilePublicKey.ts b/packages/mask/src/plugins/Tips/hooks/useProfilePublicKey.ts new file mode 100644 index 000000000000..6365ce44b504 --- /dev/null +++ b/packages/mask/src/plugins/Tips/hooks/useProfilePublicKey.ts @@ -0,0 +1,12 @@ +import type { ProfileIdentifier } from '@masknet/shared-base' +import { useAsync } from 'react-use' +import Services from '../../../extension/service' + +export function useProfilePublicKey(receiver: ProfileIdentifier | undefined) { + const { value: publicKey } = useAsync(async () => { + if (!receiver) return + const persona = await Services.Identity.queryPersonaByProfile(receiver) + return persona?.publicHexKey + }, [receiver]) + return publicKey +} diff --git a/packages/mask/src/plugins/Tips/hooks/useProvedWallets.ts b/packages/mask/src/plugins/Tips/hooks/useProvedWallets.ts index f9d3743a1c1d..1eccb8b6f860 100644 --- a/packages/mask/src/plugins/Tips/hooks/useProvedWallets.ts +++ b/packages/mask/src/plugins/Tips/hooks/useProvedWallets.ts @@ -1,19 +1,18 @@ -import { useAsyncRetry } from 'react-use' +import { EMPTY_LIST, NextIDPersonaBindings, NextIDPlatform, PersonaIdentifier } from '@masknet/shared-base' import { NextIDProof } from '@masknet/web3-providers' +import { useAsyncRetry } from 'react-use' import Services from '../../../extension/service' -import { EMPTY_OBJECT, NextIDPersonaBindings, NextIDPlatform } from '@masknet/shared-base' -export function useProvedWallets() { +export function useProvedWallets(personaIdentifier: PersonaIdentifier | undefined) { const res = useAsyncRetry(async () => { - const currentPersonaIdentifier = await Services.Settings.getCurrentPersonaIdentifier() - if (!currentPersonaIdentifier) return EMPTY_OBJECT - const currentPersona = await Services.Identity.queryPersona(currentPersonaIdentifier) - if (!currentPersona?.publicHexKey) return EMPTY_OBJECT + if (!personaIdentifier) return EMPTY_LIST + const currentPersona = await Services.Identity.queryPersona(personaIdentifier) + if (!currentPersona?.publicHexKey) return EMPTY_LIST const { proofs } = (await NextIDProof.queryExistedBindingByPersona( currentPersona.publicHexKey, )) as NextIDPersonaBindings return proofs.filter((x) => x.platform === NextIDPlatform.Ethereum) - }, []) + }, [personaIdentifier]) return res } diff --git a/packages/mask/src/plugins/Tips/hooks/usePublicWallets.ts b/packages/mask/src/plugins/Tips/hooks/usePublicWallets.ts new file mode 100644 index 000000000000..0006ac944260 --- /dev/null +++ b/packages/mask/src/plugins/Tips/hooks/usePublicWallets.ts @@ -0,0 +1,55 @@ +import { PluginId } from '@masknet/plugin-infra' +import { BindingProof, EMPTY_LIST, NextIDPlatform, NextIDStorageInfo, ProfileIdentifier } from '@masknet/shared-base' +import { NextIDProof } from '@masknet/web3-providers' +import { uniq } from 'lodash-unified' +import { useEffect, useMemo } from 'react' +import { useAsync, useAsyncFn } from 'react-use' +import { MaskMessages } from '../../../utils' +import { useKvGet } from './useKv' +import { useProfilePublicKey } from './useProfilePublicKey' + +export function usePublicWallets(profile: ProfileIdentifier | undefined) { + const publicKey = useProfilePublicKey(profile) + const { value: kv } = useKvGet>(publicKey) + const [NextIDWalletsState, queryWallets] = useAsyncFn(async () => { + if (!publicKey) return EMPTY_LIST + + const bindings = await NextIDProof.queryExistedBindingByPersona(publicKey, true) + if (!bindings) return EMPTY_LIST + + const wallets = bindings.proofs.filter((p) => p.platform === NextIDPlatform.Ethereum).map((p) => p.identity) + return wallets + }, [publicKey]) + useAsync(queryWallets, [queryWallets]) + + const walletsFromCloud = useMemo(() => { + if (kv?.ok) { + if (!kv.val.proofs.length) return null + const tipWallets = kv.val.proofs.map((x) => + x.content[PluginId.Tips].filter((y) => y.platform === NextIDPlatform.Ethereum), + )[0] + if (!tipWallets) return EMPTY_LIST + return tipWallets + .filter((x) => { + if (NextIDWalletsState.value) { + // Sometimes, the wallet might get deleted from next.id + return x.isPublic && NextIDWalletsState.value.includes(x.identity) + } else { + return x.isPublic + } + }) + .map((x) => x.identity) + } + return null + }, [kv, NextIDWalletsState.value]) + + useEffect(() => { + return MaskMessages.events.ownProofChanged.on(() => { + queryWallets() + }) + }, []) + + return useMemo(() => { + return walletsFromCloud || uniq(NextIDWalletsState.value || []) + }, [NextIDWalletsState.value, walletsFromCloud]) +} diff --git a/packages/mask/src/plugins/Tips/hooks/useSupportedNetworks.ts b/packages/mask/src/plugins/Tips/hooks/useSupportedNetworks.ts new file mode 100644 index 000000000000..7dd9ff4ed1c6 --- /dev/null +++ b/packages/mask/src/plugins/Tips/hooks/useSupportedNetworks.ts @@ -0,0 +1,14 @@ +import { NetworkPluginID } from '@masknet/plugin-infra/web3' + +export function useSupportedNetworks(keys: NetworkPluginID[]) { + // todo support solana flow when NextID supported + const networkMap = { + [NetworkPluginID.PLUGIN_EVM]: { name: 'EVM Chian', icon: new URL('../assets/evmChains.png', import.meta.url) }, + [NetworkPluginID.PLUGIN_FLOW]: { name: 'Solana Chain', icon: new URL('../assets/solana.png', import.meta.url) }, + [NetworkPluginID.PLUGIN_SOLANA]: { name: 'Flow Chain', icon: new URL('../assets/flow.png', import.meta.url) }, + } + return keys.reduce((res: Array<{ name: string; icon: URL }>, x) => { + res.push(networkMap[x]) + return res + }, []) +} diff --git a/packages/mask/src/plugins/Tips/hooks/useTipsWalletsList.ts b/packages/mask/src/plugins/Tips/hooks/useTipsWalletsList.ts index de1ee9c6cf3c..32d8a73d37bf 100644 --- a/packages/mask/src/plugins/Tips/hooks/useTipsWalletsList.ts +++ b/packages/mask/src/plugins/Tips/hooks/useTipsWalletsList.ts @@ -1,20 +1,27 @@ import { BindingProof, EMPTY_LIST, NextIDStorageInfo } from '@masknet/shared-base' import { isSameAddress } from '@masknet/web3-shared-evm' import { PluginId } from '@masknet/plugin-infra' -export function useTipsWalletsList(proofList: BindingProof[], identity?: string, kv?: NextIDStorageInfo) { +import { sortBy } from 'lodash-unified' + +export function useTipsWalletsList( + proofList: BindingProof[] | undefined, + identity?: string, + kv?: NextIDStorageInfo, +) { if (!proofList || !proofList.length) return EMPTY_LIST - proofList - .sort((a, b) => Number.parseInt(b.last_checked_at, 10) - Number.parseInt(a.last_checked_at, 10)) - .forEach((wallet, idx) => (wallet.rawIdx = proofList.length - idx - 1)) - if (kv && kv.proofs.length > 0 && proofList.length > 0) { + const proofs = sortBy(proofList, (x) => -Number.parseInt(x.last_checked_at, 10)).map( + (wallet, index, list): BindingProof => ({ + ...wallet, + rawIdx: list.length - index - 1, + }), + ) + if (kv && kv.proofs.length > 0 && proofs.length > 0) { const kvCache = kv.proofs.find((x) => x.identity === identity) if (!kvCache) return EMPTY_LIST - const result: BindingProof[] = proofList.reduce((res, x) => { + const result = proofs.reduce((res, x) => { x.isDefault = 0 x.isPublic = 1 - const temp = (kvCache?.content[PluginId.Tips] as BindingProof[]).filter((i) => - isSameAddress(x.identity, i.identity), - ) + const temp = (kvCache?.content[PluginId.Tips]).filter((i) => isSameAddress(x.identity, i.identity)) if (temp && temp.length > 0) { x.isDefault = temp[0].isDefault x.isPublic = temp[0].isPublic @@ -30,13 +37,12 @@ export function useTipsWalletsList(proofList: BindingProof[], identity?: string, } return result } - proofList.forEach((x, idx) => { + proofs.forEach((x, idx) => { x.isPublic = 1 x.isDefault = 0 if (idx === 0) { x.isDefault = 1 - return } }) - return proofList + return proofs } diff --git a/packages/mask/src/plugins/Tips/locales/en-US.json b/packages/mask/src/plugins/Tips/locales/en-US.json new file mode 100644 index 000000000000..7d4a603b7f4f --- /dev/null +++ b/packages/mask/src/plugins/Tips/locales/en-US.json @@ -0,0 +1,29 @@ +{ + "tips": "Tips", + "tip_to": "To", + "token_insufficient_balance": "Insufficient balance", + "send_tip": "Send", + "sending_tip": "Sending...", + "nft_not_belong_to_you": "The collectible doesn't exist or belong to you.", + "send_tip_successfully": "Sent tip successfully.", + "send_specific_tip_successfully": "Sent {{amount}} {{name}} tip successfully.", + "tip_share": "Share", + "tip_connect_wallet_message": "Please connect to a wallet.", + "tip_connect_wallet": "Connect Wallet", + "search": "Search", + "tip_type_token": "Token", + "tip_type_nft": "NFT", + "tip_wallets_missed": "Wallets not found.", + "tip_contracts": "Contracts", + "tip_mask_promote": "Install https://mask.io/download-links to send your first tip.", + "tip_token_share_post": "I just tipped {{amount}} {{symbol}} to @{{recipientSnsId}}'s wallet address {{recipient}}\n\n{{promote}}", + "tip_nft_share_post": "I just tipped a {{name}} to @{{recipientSnsId}}'s wallet address {{recipient}}\n\n{{promote}}", + "tip_add": "Add", + "tip_adding": "Adding", + "tip_add_collectibles": "Add Collectibles", + "tip_add_collectibles_contract_address": "Input contract address", + "tip_add_collectibles_token_id": "Token ID", + "tip_add_collectibles_error": "The contract address is incorrect or the collectible does not belong to you.", + "tip_loading": "Loading", + "tip_empty_nft": "No any collectible is available to preview. Please add your collectible here." +} diff --git a/packages/mask/src/plugins/Tips/locales/index.ts b/packages/mask/src/plugins/Tips/locales/index.ts new file mode 100644 index 000000000000..d6ead60252e4 --- /dev/null +++ b/packages/mask/src/plugins/Tips/locales/index.ts @@ -0,0 +1,6 @@ +// This file is auto generated. DO NOT EDIT +// Run `npx gulp sync-languages` to regenerate. +// Default fallback language in a family of languages are chosen by the alphabet order +// To overwrite this, please overwrite packages/scripts/src/locale-kit-next/index.ts + +export * from './i18n_generated' diff --git a/packages/mask/src/plugins/Tips/locales/ja-JP.json b/packages/mask/src/plugins/Tips/locales/ja-JP.json new file mode 100644 index 000000000000..0967ef424bce --- /dev/null +++ b/packages/mask/src/plugins/Tips/locales/ja-JP.json @@ -0,0 +1 @@ +{} diff --git a/packages/mask/src/plugins/Tips/locales/ko-KR.json b/packages/mask/src/plugins/Tips/locales/ko-KR.json new file mode 100644 index 000000000000..0967ef424bce --- /dev/null +++ b/packages/mask/src/plugins/Tips/locales/ko-KR.json @@ -0,0 +1 @@ +{} diff --git a/packages/mask/src/plugins/Tips/locales/languages.ts b/packages/mask/src/plugins/Tips/locales/languages.ts new file mode 100644 index 000000000000..b0b73b68c8b3 --- /dev/null +++ b/packages/mask/src/plugins/Tips/locales/languages.ts @@ -0,0 +1,34 @@ +// This file is auto generated. DO NOT EDIT +// Run `npx gulp sync-languages` to regenerate. +// Default fallback language in a family of languages are chosen by the alphabet order +// To overwrite this, please overwrite packages/scripts/src/locale-kit-next/index.ts +import en_US from './en-US.json' +import ja_JP from './ja-JP.json' +import ko_KR from './ko-KR.json' +import qya_AA from './qya-AA.json' +import zh_CN from './zh-CN.json' +import zh_TW from './zh-TW.json' +export const languages = { + en: en_US, + ja: ja_JP, + ko: ko_KR, + qy: qya_AA, + 'zh-CN': zh_CN, + zh: zh_TW, +} +// @ts-ignore +if (import.meta.webpackHot) { + // @ts-ignore + import.meta.webpackHot.accept( + ['./en-US.json', './ja-JP.json', './ko-KR.json', './qya-AA.json', './zh-CN.json', './zh-TW.json'], + () => + globalThis.dispatchEvent?.( + new CustomEvent('MASK_I18N_HMR', { + detail: [ + 'com.mask.next_id', + { en: en_US, ja: ja_JP, ko: ko_KR, qy: qya_AA, 'zh-CN': zh_CN, zh: zh_TW }, + ], + }), + ), + ) +} diff --git a/packages/mask/src/plugins/Tips/locales/qya-AA.json b/packages/mask/src/plugins/Tips/locales/qya-AA.json new file mode 100644 index 000000000000..2b66e91a02dc --- /dev/null +++ b/packages/mask/src/plugins/Tips/locales/qya-AA.json @@ -0,0 +1,74 @@ +{ + "wallet": "crwdns13073:0crwdne13073:0", + "persona": "crwdns13075:0crwdne13075:0", + "unsupported_network": "crwdns13077:0crwdne13077:0", + "connect_wallet__other_user_tip_intro": "crwdns13225:0crwdne13225:0", + "connect_wallet_other_user_tip1": "crwdns14726:0crwdne14726:0", + "connect_wallet_other_user_tip2": "crwdns14728:0crwdne14728:0", + "connect_wallet_other_user_instruction": "crwdns14730:0crwdne14730:0", + "connect_wallet_tip": "crwdns13081:0crwdne13081:0", + "verify_wallet_intro": "crwdns14732:0crwdne14732:0", + "verify_wallet": "crwdns14734:0crwdne14734:0", + "verify_Twitter_ID_intro": "crwdns14736:0crwdne14736:0", + "verify_Twitter_ID": "crwdns14738:0crwdne14738:0", + "verify_other_Twitter_ID_intro": "crwdns14740:0crwdne14740:0", + "verify_Twitter_ID_button": "crwdns14742:0crwdne14742:0", + "verify_wallet_button": "crwdns13083:0crwdne13083:0", + "add_wallet_button": "crwdns13085:0crwdne13085:0", + "verify_wallet_dialog_title": "crwdns13087:0crwdne13087:0", + "bind_wallet_bound_error": "crwdns13089:0crwdne13089:0", + "unbind_wallet_same_account_error": "crwdns13091:0crwdne13091:0", + "unbind_dialog_title": "crwdns13093:0crwdne13093:0", + "persona_sign": "crwdns13095:0crwdne13095:0", + "wallet_sign": "crwdns13097:0crwdne13097:0", + "copied": "crwdns13099:0crwdne13099:0", + "view_on_explorer": "crwdns13101:0crwdne13101:0", + "notify_persona_sign": "crwdns13103:0crwdne13103:0", + "notify_persona_sign_confirm": "crwdns13105:0crwdne13105:0", + "notify_persona_sign_cancel": "crwdns13107:0crwdne13107:0", + "notify_wallet_sign": "crwdns13109:0crwdne13109:0", + "notify_wallet_sign_confirm": "crwdns13111:0crwdne13111:0", + "notify_wallet_sign_cancel": "crwdns13113:0crwdne13113:0", + "notify_wallet_sign_request_title": "crwdns13115:0crwdne13115:0", + "notify_wallet_sign_request_success": "crwdns13117:0crwdne13117:0", + "notify_wallet_sign_request_failed": "crwdns13119:0crwdne13119:0", + "create_persona": "crwdns13121:0crwdne13121:0", + "connect_persona": "crwdns13123:0crwdne13123:0", + "please_create_persona": "crwdns13125:0crwdne13125:0", + "please_connect_persona": "crwdns13127:0crwdne13127:0", + "unbind_persona_tip": "crwdns13129:0crwdne13129:0", + "unbind_wallet_tip": "crwdns13131:0crwdne13131:0", + "done": "crwdns13133:0crwdne13133:0", + "confirm": "crwdns14744:0crwdne14744:0", + "cancel": "crwdns14746:0crwdne14746:0", + "delete": "crwdns14748:0crwdne14748:0", + "copy_success_of_wallet_address": "crwdns13135:0crwdne13135:0", + "disconnect_warning": "crwdns14750:0crwdne14750:0", + "tips": "crwdns14752:0crwdne14752:0", + "tip_to": "crwdns14754:0crwdne14754:0", + "token_insufficient_balance": "crwdns14756:0crwdne14756:0", + "tip_type_token": "crwdns14758:0crwdne14758:0", + "tip_type_nft": "crwdns14760:0crwdne14760:0", + "tip_wallets_missed": "crwdns14762:0crwdne14762:0", + "send_tip": "crwdns14764:0crwdne14764:0", + "sending_tip": "crwdns14766:0crwdne14766:0", + "nft_not_belong_to_you": "crwdns14768:0crwdne14768:0", + "send_tip_successfully": "crwdns14770:0crwdne14770:0", + "send_specific_tip_successfully": "crwdns14772:0{{amount}}crwdnd14772:0{{name}}crwdne14772:0", + "tip_share": "crwdns14774:0crwdne14774:0", + "tip_connect_wallet_message": "crwdns14776:0crwdne14776:0", + "tip_connect_wallet": "crwdns14778:0crwdne14778:0", + "search": "crwdns14780:0crwdne14780:0", + "tip_contracts": "crwdns14782:0crwdne14782:0", + "tip_mask_promote": "crwdns14806:0crwdne14806:0", + "tip_token_share_post": "crwdns14784:0{{amount}}crwdnd14784:0{{symbol}}crwdnd14784:0{{recipientSnsId}}crwdnd14784:0{{recipient}}crwdnd14784:0{{promote}}crwdne14784:0", + "tip_nft_share_post": "crwdns14786:0{{name}}crwdnd14786:0{{recipientSnsId}}crwdnd14786:0{{recipient}}crwdnd14786:0{{promote}}crwdne14786:0", + "tip_add": "crwdns14980:0crwdne14980:0", + "tip_adding": "crwdns14982:0crwdne14982:0", + "tip_add_collectibles": "crwdns14984:0crwdne14984:0", + "tip_add_collectibles_contract_address": "crwdns14986:0crwdne14986:0", + "tip_add_collectibles_token_id": "crwdns14988:0crwdne14988:0", + "tip_add_collectibles_error": "crwdns14990:0crwdne14990:0", + "tip_loading": "crwdns14992:0crwdne14992:0", + "tip_empty_nft": "crwdns14994:0crwdne14994:0" +} diff --git a/packages/mask/src/plugins/Tips/locales/zh-CN.json b/packages/mask/src/plugins/Tips/locales/zh-CN.json new file mode 100644 index 000000000000..c8cda7cda670 --- /dev/null +++ b/packages/mask/src/plugins/Tips/locales/zh-CN.json @@ -0,0 +1,34 @@ +{ + "wallet": "钱包", + "persona": "身份", + "unsupported_network": "此网络尚不支持", + "connect_wallet__other_user_tip_intro": "目前此账号未绑定任何钱包。", + "connect_wallet_tip": "在 Web3 选项卡中,您可以向已安装 Mask Network 的好友展示接收打赏的地址、NFT 收藏品、捐赠记录和其他链上信息。", + "verify_wallet_button": "验证您的钱包", + "add_wallet_button": "添加钱包", + "verify_wallet_dialog_title": "验证您的钱包", + "bind_wallet_bound_error": "此钱包地址已经被绑定。", + "unbind_wallet_same_account_error": "请切换到需要解绑的钱包地址。", + "unbind_dialog_title": "解绑钱包", + "persona_sign": "身份签名", + "wallet_sign": "钱包签名", + "copied": "已复制", + "view_on_explorer": "在区块链浏览器查看", + "notify_persona_sign": "身份签名", + "notify_persona_sign_confirm": "请在您的身份页面确认此签名", + "notify_persona_sign_cancel": "您的钱包取消了此签名", + "notify_wallet_sign": "钱包签名", + "notify_wallet_sign_confirm": "请在您的钱包确认此签名", + "notify_wallet_sign_cancel": "您的钱包取消了此签名", + "notify_wallet_sign_request_title": "钱包签名", + "notify_wallet_sign_request_success": "签名成功", + "notify_wallet_sign_request_failed": "签名失败", + "create_persona": "创建身份", + "connect_persona": "连接身份", + "please_create_persona": "请创建身份", + "please_connect_persona": "请连接身份", + "unbind_persona_tip": "选择您的身份或当前绑定的钱包来进行签名解绑。", + "unbind_wallet_tip": "选择您的身份或当前绑定的钱包来进行签名解绑。", + "done": "完成", + "copy_success_of_wallet_address": "成功复制钱包地址!" +} diff --git a/packages/mask/src/plugins/Tips/locales/zh-TW.json b/packages/mask/src/plugins/Tips/locales/zh-TW.json new file mode 100644 index 000000000000..e0da32129b34 --- /dev/null +++ b/packages/mask/src/plugins/Tips/locales/zh-TW.json @@ -0,0 +1,26 @@ +{ + "wallet": "錢包", + "connect_wallet__other_user_tip_intro": "錢包尋找失敗!", + "verify_wallet_button": "驗證錢包", + "add_wallet_button": "新增錢包", + "verify_wallet_dialog_title": "驗證錢包", + "bind_wallet_bound_error": "此錢包地址已被綁定", + "notify_wallet_sign": "錢包簽名", + "notify_wallet_sign_cancel": "取消錢包簽名", + "notify_wallet_sign_request_title": "錢包簽名", + "notify_wallet_sign_request_success": "簽署成功", + "notify_wallet_sign_request_failed": "簽署失敗", + "done": "完成", + "confirm": "確認", + "cancel": "取消", + "delete": "刪除", + "copy_success_of_wallet_address": "複製錢包地址成功!", + "tip_to": "到", + "token_insufficient_balance": "餘額不足", + "tip_type_token": "代幣", + "tip_type_nft": "非同質化代幣 (NFT)", + "tip_wallets_missed": "錢包定位失敗!", + "send_tip": "送出", + "sending_tip": "傳送中…", + "send_tip_successfully": "小費打賞成功" +} diff --git a/packages/mask/src/plugins/NextID/messages.ts b/packages/mask/src/plugins/Tips/messages.ts similarity index 59% rename from packages/mask/src/plugins/NextID/messages.ts rename to packages/mask/src/plugins/Tips/messages.ts index 36b8f8ced22d..852376176d1c 100644 --- a/packages/mask/src/plugins/NextID/messages.ts +++ b/packages/mask/src/plugins/Tips/messages.ts @@ -1,5 +1,4 @@ -import { createPluginMessage, PluginMessageEmitter } from '@masknet/plugin-infra' -import { PLUGIN_ID } from './constants' +import { createPluginMessage, PluginId, PluginMessageEmitter } from '@masknet/plugin-infra' import type { TipTask } from './types' export interface TipMessage { @@ -9,4 +8,4 @@ export interface TipMessage { } if (import.meta.webpackHot) import.meta.webpackHot.accept() -export const PluginNextIDMessages: PluginMessageEmitter = createPluginMessage(PLUGIN_ID) +export const PluginNextIDMessages: PluginMessageEmitter = createPluginMessage(PluginId.Tips) diff --git a/packages/mask/src/plugins/NextID/storage/index.ts b/packages/mask/src/plugins/Tips/storage/index.ts similarity index 100% rename from packages/mask/src/plugins/NextID/storage/index.ts rename to packages/mask/src/plugins/Tips/storage/index.ts diff --git a/packages/mask/src/plugins/NextID/types/index.ts b/packages/mask/src/plugins/Tips/types/index.ts similarity index 100% rename from packages/mask/src/plugins/NextID/types/index.ts rename to packages/mask/src/plugins/Tips/types/index.ts diff --git a/packages/mask/src/plugins/NextID/types/tip.ts b/packages/mask/src/plugins/Tips/types/tip.ts similarity index 100% rename from packages/mask/src/plugins/NextID/types/tip.ts rename to packages/mask/src/plugins/Tips/types/tip.ts diff --git a/packages/mask/src/social-network-adaptor/twitter.com/injection/Tip/ProfileTipButton.tsx b/packages/mask/src/social-network-adaptor/twitter.com/injection/Tip/ProfileTipButton.tsx index b23b444d28a9..3b4809ef4d53 100644 --- a/packages/mask/src/social-network-adaptor/twitter.com/injection/Tip/ProfileTipButton.tsx +++ b/packages/mask/src/social-network-adaptor/twitter.com/injection/Tip/ProfileTipButton.tsx @@ -2,7 +2,7 @@ import { MutationObserverWatcher } from '@dimensiondev/holoflows-kit' import { makeStyles } from '@masknet/theme' import { useEffect, useState } from 'react' import { useCurrentVisitingIdentity } from '../../../../components/DataSource/useActivatedUI' -import { TipButton } from '../../../../plugins/NextID/components/Tip/TipButton' +import { TipButton } from '../../../../plugins/Tips/components' import { createReactRootShadowed, startWatch, useLocationChange } from '../../../../utils' import { profileFollowButtonSelector as selector, diff --git a/packages/plugin-infra/src/types.ts b/packages/plugin-infra/src/types.ts index 5e10d22f5ed3..ee36255c0809 100644 --- a/packages/plugin-infra/src/types.ts +++ b/packages/plugin-infra/src/types.ts @@ -314,12 +314,8 @@ export namespace Plugin.SNSAdaptor { */ RenderEntryComponent?: (props: { disabled: boolean - nextIdVerification?: { - toolTipHint: string - isNextIDVerify: boolean | undefined - isSNSConnectToCurrentPersona: boolean | undefined - onNextIDVerify(): void - } + tooltipHint?: string + onClick?: () => void }) => JSX.Element | null /** * Used to order the applications on the board diff --git a/packages/plugin-infra/src/web3-types.ts b/packages/plugin-infra/src/web3-types.ts index eb6a64759a8c..fcc289bd62a6 100644 --- a/packages/plugin-infra/src/web3-types.ts +++ b/packages/plugin-infra/src/web3-types.ts @@ -63,7 +63,6 @@ export declare namespace Web3Plugin { NetworkPluginID, { supportedChainIds?: number[] - tipsSupportedChains?: Array<{ name: string; icon: URL }> } > > diff --git a/packages/shared-base/src/NextID/type.ts b/packages/shared-base/src/NextID/type.ts index 6be69ffca959..17c8f914b586 100644 --- a/packages/shared-base/src/NextID/type.ts +++ b/packages/shared-base/src/NextID/type.ts @@ -37,8 +37,8 @@ export interface BindingProof { is_valid: boolean last_checked_at: string rawIdx?: number - isDefault?: number - isPublic?: number + isDefault?: 0 | 1 + isPublic?: 0 | 1 } interface Pagination { @@ -59,9 +59,9 @@ export interface NextIDStoragePayload { signPayload: string createdAt: string } -export interface NextIDStorageInfo { +export interface NextIDStorageInfo { persona: string - proofs: NextIDStorageProofs[] + proofs: NextIDStorageProofs[] } export interface NextIDStorageProofs { content: { diff --git a/packages/shared/src/UI/components/ApplicationEntry/index.tsx b/packages/shared/src/UI/components/ApplicationEntry/index.tsx index 72422e7004e6..02788bf9f241 100644 --- a/packages/shared/src/UI/components/ApplicationEntry/index.tsx +++ b/packages/shared/src/UI/components/ApplicationEntry/index.tsx @@ -40,54 +40,36 @@ const useStyles = makeStyles()((theme) => ({ }, })) -interface Props { +interface ApplicationEntryProps { icon: React.ReactNode title: React.ReactNode disabled?: boolean - nextIdVerification?: { - toolTipHint: string - isNextIDVerify: boolean | undefined - isSNSConnectToCurrentPersona: boolean | undefined - onNextIDVerify(): void - } + tooltipHint?: string onClick: () => void } -export function ApplicationEntry(props: Props) { - const { title, onClick, disabled: _disabled = false, icon, nextIdVerification } = props - const disabled = - nextIdVerification && - (nextIdVerification?.isNextIDVerify === undefined || !nextIdVerification?.isSNSConnectToCurrentPersona) - ? true - : _disabled - const tooltip = - nextIdVerification?.isSNSConnectToCurrentPersona === false ? nextIdVerification?.toolTipHint : undefined +export function ApplicationEntry(props: ApplicationEntryProps) { + const { title, onClick, disabled = false, icon, tooltipHint } = props const { classes } = useStyles() const jsx = (
{} - : !nextIdVerification?.isNextIDVerify && nextIdVerification - ? nextIdVerification?.onNextIDVerify - : onClick - }> + onClick={disabled ? () => {} : onClick}>
{icon}
{title}
) - return tooltip ? ( + return tooltipHint ? ( {tooltip}}> + disableHoverListener={!tooltipHint} + title={{tooltipHint}}> {jsx} ) : ( diff --git a/packages/web3-providers/src/NextID/kv.ts b/packages/web3-providers/src/NextID/kv.ts index 84fa80f8060d..d9dcaefcaf4f 100644 --- a/packages/web3-providers/src/NextID/kv.ts +++ b/packages/web3-providers/src/NextID/kv.ts @@ -2,7 +2,7 @@ * Document url: https://github.com/nextdotid/kv_server/blob/develop/docs/api.apib */ import urlcat from 'urlcat' -import type { NextIDStoragePayload, NextIDPlatform, NextIDStorageInfo } from '@masknet/shared-base' +import type { NextIDStoragePayload, NextIDPlatform } from '@masknet/shared-base' import { fetchJSON } from './helper' import type { Result } from 'ts-results' import type { NextIDBaseAPI } from '../types' @@ -29,7 +29,7 @@ export class NextIDStorageAPI implements NextIDBaseAPI.Storage { * @param personaPublicKey * */ - async get(personaPublicKey: string): Promise> { + async get(personaPublicKey: string): Promise> { return fetchJSON(urlcat(BASE_URL, '/v1/kv', { persona: personaPublicKey })) }