mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Merge branch 'develop' of github.com:MetaMask/metamask-extension into minimal
This commit is contained in:
commit
89ec45d6d5
17
.github/workflows/do-not-merge.yml
vendored
Normal file
17
.github/workflows/do-not-merge.yml
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# Fails the pull request if it has the "DO-NOT-MERGE" label
|
||||||
|
|
||||||
|
name: Check "DO-NOT-MERGE" label
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [opened, reopened, labeled, unlabeled, synchronize]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
do-not-merge:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: ${{ contains(github.event.pull_request.labels.*.name, 'DO-NOT-MERGE') }}
|
||||||
|
steps:
|
||||||
|
- name: 'Check for label "DO-NOT-MERGE"'
|
||||||
|
run: |
|
||||||
|
echo 'This check fails PRs with the "DO-NOT-MERGE" label to block merging'
|
||||||
|
exit 1
|
41
app/_locales/en/messages.json
generated
41
app/_locales/en/messages.json
generated
@ -1636,6 +1636,12 @@
|
|||||||
"general": {
|
"general": {
|
||||||
"message": "General"
|
"message": "General"
|
||||||
},
|
},
|
||||||
|
"globalTitle": {
|
||||||
|
"message": "Global menu"
|
||||||
|
},
|
||||||
|
"globalTourDescription": {
|
||||||
|
"message": "See your portfolio, connected sites, settings, and more"
|
||||||
|
},
|
||||||
"goBack": {
|
"goBack": {
|
||||||
"message": "Go back"
|
"message": "Go back"
|
||||||
},
|
},
|
||||||
@ -2396,6 +2402,9 @@
|
|||||||
"noNFTs": {
|
"noNFTs": {
|
||||||
"message": "No NFTs yet"
|
"message": "No NFTs yet"
|
||||||
},
|
},
|
||||||
|
"noReport": {
|
||||||
|
"message": "No Report"
|
||||||
|
},
|
||||||
"noSnaps": {
|
"noSnaps": {
|
||||||
"message": "You don't have any snaps installed."
|
"message": "You don't have any snaps installed."
|
||||||
},
|
},
|
||||||
@ -3052,6 +3061,12 @@
|
|||||||
"permissions": {
|
"permissions": {
|
||||||
"message": "Permissions"
|
"message": "Permissions"
|
||||||
},
|
},
|
||||||
|
"permissionsTitle": {
|
||||||
|
"message": "Permissions"
|
||||||
|
},
|
||||||
|
"permissionsTourDescription": {
|
||||||
|
"message": "Find your connected accounts and manage permissions here"
|
||||||
|
},
|
||||||
"personalAddressDetected": {
|
"personalAddressDetected": {
|
||||||
"message": "Personal address detected. Input the token contract address."
|
"message": "Personal address detected. Input the token contract address."
|
||||||
},
|
},
|
||||||
@ -3233,6 +3248,12 @@
|
|||||||
"replace": {
|
"replace": {
|
||||||
"message": "replace"
|
"message": "replace"
|
||||||
},
|
},
|
||||||
|
"reportLastRun": {
|
||||||
|
"message": "Report last run"
|
||||||
|
},
|
||||||
|
"reportLastRunTooltip": {
|
||||||
|
"message": "The date and time of when the last AML/CFT report was run"
|
||||||
|
},
|
||||||
"requestFailed": {
|
"requestFailed": {
|
||||||
"message": "Request failed"
|
"message": "Request failed"
|
||||||
},
|
},
|
||||||
@ -3362,9 +3383,18 @@
|
|||||||
"revokeSpendingCapTooltipText": {
|
"revokeSpendingCapTooltipText": {
|
||||||
"message": "This third party will be unable to spend any more of your current or future tokens."
|
"message": "This third party will be unable to spend any more of your current or future tokens."
|
||||||
},
|
},
|
||||||
|
"riskRating": {
|
||||||
|
"message": "Risk rating"
|
||||||
|
},
|
||||||
|
"riskRatingTooltip": {
|
||||||
|
"message": "The risk rating of the address you are interacting with based on your risk settings"
|
||||||
|
},
|
||||||
"rpcUrl": {
|
"rpcUrl": {
|
||||||
"message": "New RPC URL"
|
"message": "New RPC URL"
|
||||||
},
|
},
|
||||||
|
"runReport": {
|
||||||
|
"message": "Run report"
|
||||||
|
},
|
||||||
"safeTransferFrom": {
|
"safeTransferFrom": {
|
||||||
"message": "Safe transfer from"
|
"message": "Safe transfer from"
|
||||||
},
|
},
|
||||||
@ -3579,6 +3609,9 @@
|
|||||||
"showPrivateKeys": {
|
"showPrivateKeys": {
|
||||||
"message": "Show Private Keys"
|
"message": "Show Private Keys"
|
||||||
},
|
},
|
||||||
|
"showReport": {
|
||||||
|
"message": "Show report"
|
||||||
|
},
|
||||||
"showTestnetNetworks": {
|
"showTestnetNetworks": {
|
||||||
"message": "Show test networks"
|
"message": "Show test networks"
|
||||||
},
|
},
|
||||||
@ -3649,7 +3682,7 @@
|
|||||||
"description": "$1 is the dApp origin requesting the snap and $2 is the snap name"
|
"description": "$1 is the dApp origin requesting the snap and $2 is the snap name"
|
||||||
},
|
},
|
||||||
"snapInstallWarningCheck": {
|
"snapInstallWarningCheck": {
|
||||||
"message": "Ensure that the permission below align with your intended actions. Only proceed with authors you trust."
|
"message": "Ensure that the permission below aligns with your intended actions. Only proceed with authors you trust."
|
||||||
},
|
},
|
||||||
"snapInstallWarningCheckPlural": {
|
"snapInstallWarningCheckPlural": {
|
||||||
"message": "Ensure that the permissions below align with your intended actions. Only proceed with authors you trust."
|
"message": "Ensure that the permissions below align with your intended actions. Only proceed with authors you trust."
|
||||||
@ -4279,6 +4312,12 @@
|
|||||||
"switchedTo": {
|
"switchedTo": {
|
||||||
"message": "You have switched to"
|
"message": "You have switched to"
|
||||||
},
|
},
|
||||||
|
"switcherTitle": {
|
||||||
|
"message": "Network switcher"
|
||||||
|
},
|
||||||
|
"switcherTourDescription": {
|
||||||
|
"message": "Click the icon to switch networks or add a new network"
|
||||||
|
},
|
||||||
"switchingNetworksCancelsPendingConfirmations": {
|
"switchingNetworksCancelsPendingConfirmations": {
|
||||||
"message": "Switching networks will cancel all pending confirmations"
|
"message": "Switching networks will cancel all pending confirmations"
|
||||||
},
|
},
|
||||||
|
@ -46,6 +46,7 @@ export default class AppStateController extends EventEmitter {
|
|||||||
nftsDetectionNoticeDismissed: false,
|
nftsDetectionNoticeDismissed: false,
|
||||||
showTestnetMessageInDropdown: true,
|
showTestnetMessageInDropdown: true,
|
||||||
showBetaHeader: isBeta(),
|
showBetaHeader: isBeta(),
|
||||||
|
showProductTour: true,
|
||||||
trezorModel: null,
|
trezorModel: null,
|
||||||
currentPopupId: undefined,
|
currentPopupId: undefined,
|
||||||
...initState,
|
...initState,
|
||||||
@ -331,6 +332,15 @@ export default class AppStateController extends EventEmitter {
|
|||||||
this.store.updateState({ showBetaHeader });
|
this.store.updateState({ showBetaHeader });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether the product tour should be shown
|
||||||
|
*
|
||||||
|
* @param showProductTour
|
||||||
|
*/
|
||||||
|
setShowProductTour(showProductTour) {
|
||||||
|
this.store.updateState({ showProductTour });
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a property indicating the model of the user's Trezor hardware wallet
|
* Sets a property indicating the model of the user's Trezor hardware wallet
|
||||||
*
|
*
|
||||||
|
@ -2061,6 +2061,8 @@ export default class MetamaskController extends EventEmitter {
|
|||||||
),
|
),
|
||||||
setShowBetaHeader:
|
setShowBetaHeader:
|
||||||
appStateController.setShowBetaHeader.bind(appStateController),
|
appStateController.setShowBetaHeader.bind(appStateController),
|
||||||
|
setShowProductTour:
|
||||||
|
appStateController.setShowProductTour.bind(appStateController),
|
||||||
updateNftDropDownState:
|
updateNftDropDownState:
|
||||||
appStateController.updateNftDropDownState.bind(appStateController),
|
appStateController.updateNftDropDownState.bind(appStateController),
|
||||||
setFirstTimeUsedNetwork:
|
setFirstTimeUsedNetwork:
|
||||||
|
@ -122,100 +122,100 @@ exports[`SignatureRequestSIWE (Sign in with Ethereum) should match snapshot 1`]
|
|||||||
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row"
|
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row"
|
||||||
>
|
>
|
||||||
<h4
|
<h4
|
||||||
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row typography typography--h4 typography--weight-normal typography--style-normal typography--color-text-default"
|
class="box mm-text mm-text--body-lg-medium box--margin-top-2 box--margin-bottom-2 box--flex-direction-row box--color-text-default"
|
||||||
>
|
>
|
||||||
Message:
|
Message:
|
||||||
</h4>
|
</h4>
|
||||||
<h6
|
<p
|
||||||
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row typography signature-request-siwe-message__sub-text typography--h6 typography--weight-normal typography--style-normal typography--color-text-default"
|
class="box mm-text signature-request-siwe-message__sub-text mm-text--body-md mm-text--overflow-wrap-break-word box--margin-top-2 box--margin-bottom-2 box--flex-direction-row box--color-text-default"
|
||||||
>
|
>
|
||||||
Click to sign in and accept the Terms of Service: https://community.metamask.io/tos
|
Click to sign in and accept the Terms of Service: https://community.metamask.io/tos
|
||||||
</h6>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row"
|
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row"
|
||||||
>
|
>
|
||||||
<h4
|
<h4
|
||||||
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row typography typography--h4 typography--weight-normal typography--style-normal typography--color-text-default"
|
class="box mm-text mm-text--body-lg-medium box--margin-top-2 box--margin-bottom-2 box--flex-direction-row box--color-text-default"
|
||||||
>
|
>
|
||||||
URI:
|
URI:
|
||||||
</h4>
|
</h4>
|
||||||
<h6
|
<p
|
||||||
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row typography signature-request-siwe-message__sub-text typography--h6 typography--weight-normal typography--style-normal typography--color-text-default"
|
class="box mm-text signature-request-siwe-message__sub-text mm-text--body-md mm-text--overflow-wrap-break-word box--margin-top-2 box--margin-bottom-2 box--flex-direction-row box--color-text-default"
|
||||||
>
|
>
|
||||||
http://localhost:8080
|
http://localhost:8080
|
||||||
</h6>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row"
|
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row"
|
||||||
>
|
>
|
||||||
<h4
|
<h4
|
||||||
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row typography typography--h4 typography--weight-normal typography--style-normal typography--color-text-default"
|
class="box mm-text mm-text--body-lg-medium box--margin-top-2 box--margin-bottom-2 box--flex-direction-row box--color-text-default"
|
||||||
>
|
>
|
||||||
Version:
|
Version:
|
||||||
</h4>
|
</h4>
|
||||||
<h6
|
<p
|
||||||
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row typography signature-request-siwe-message__sub-text typography--h6 typography--weight-normal typography--style-normal typography--color-text-default"
|
class="box mm-text signature-request-siwe-message__sub-text mm-text--body-md mm-text--overflow-wrap-break-word box--margin-top-2 box--margin-bottom-2 box--flex-direction-row box--color-text-default"
|
||||||
>
|
>
|
||||||
1
|
1
|
||||||
</h6>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row"
|
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row"
|
||||||
>
|
>
|
||||||
<h4
|
<h4
|
||||||
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row typography typography--h4 typography--weight-normal typography--style-normal typography--color-text-default"
|
class="box mm-text mm-text--body-lg-medium box--margin-top-2 box--margin-bottom-2 box--flex-direction-row box--color-text-default"
|
||||||
>
|
>
|
||||||
Chain ID:
|
Chain ID:
|
||||||
</h4>
|
</h4>
|
||||||
<h6
|
<p
|
||||||
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row typography signature-request-siwe-message__sub-text typography--h6 typography--weight-normal typography--style-normal typography--color-text-default"
|
class="box mm-text signature-request-siwe-message__sub-text mm-text--body-md mm-text--overflow-wrap-break-word box--margin-top-2 box--margin-bottom-2 box--flex-direction-row box--color-text-default"
|
||||||
>
|
>
|
||||||
1
|
1
|
||||||
</h6>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row"
|
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row"
|
||||||
>
|
>
|
||||||
<h4
|
<h4
|
||||||
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row typography typography--h4 typography--weight-normal typography--style-normal typography--color-text-default"
|
class="box mm-text mm-text--body-lg-medium box--margin-top-2 box--margin-bottom-2 box--flex-direction-row box--color-text-default"
|
||||||
>
|
>
|
||||||
Nonce:
|
Nonce:
|
||||||
</h4>
|
</h4>
|
||||||
<h6
|
<p
|
||||||
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row typography signature-request-siwe-message__sub-text typography--h6 typography--weight-normal typography--style-normal typography--color-text-default"
|
class="box mm-text signature-request-siwe-message__sub-text mm-text--body-md mm-text--overflow-wrap-break-word box--margin-top-2 box--margin-bottom-2 box--flex-direction-row box--color-text-default"
|
||||||
>
|
>
|
||||||
STMt6KQMwwdOXE306
|
STMt6KQMwwdOXE306
|
||||||
</h6>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row"
|
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row"
|
||||||
>
|
>
|
||||||
<h4
|
<h4
|
||||||
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row typography typography--h4 typography--weight-normal typography--style-normal typography--color-text-default"
|
class="box mm-text mm-text--body-lg-medium box--margin-top-2 box--margin-bottom-2 box--flex-direction-row box--color-text-default"
|
||||||
>
|
>
|
||||||
Issued At:
|
Issued At:
|
||||||
</h4>
|
</h4>
|
||||||
<h6
|
<p
|
||||||
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row typography signature-request-siwe-message__sub-text typography--h6 typography--weight-normal typography--style-normal typography--color-text-default"
|
class="box mm-text signature-request-siwe-message__sub-text mm-text--body-md mm-text--overflow-wrap-break-word box--margin-top-2 box--margin-bottom-2 box--flex-direction-row box--color-text-default"
|
||||||
>
|
>
|
||||||
2023-03-18T21:40:40.823Z
|
2023-03-18T21:40:40.823Z
|
||||||
</h6>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row"
|
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row"
|
||||||
>
|
>
|
||||||
<h4
|
<h4
|
||||||
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row typography typography--h4 typography--weight-normal typography--style-normal typography--color-text-default"
|
class="box mm-text mm-text--body-lg-medium box--margin-top-2 box--margin-bottom-2 box--flex-direction-row box--color-text-default"
|
||||||
>
|
>
|
||||||
Resources: 2
|
Resources: 2
|
||||||
</h4>
|
</h4>
|
||||||
<h6
|
<p
|
||||||
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row typography signature-request-siwe-message__sub-text typography--h6 typography--weight-normal typography--style-normal typography--color-text-default"
|
class="box mm-text signature-request-siwe-message__sub-text mm-text--body-md mm-text--overflow-wrap-break-word box--margin-top-2 box--margin-bottom-2 box--flex-direction-row box--color-text-default"
|
||||||
>
|
>
|
||||||
ipfs://Qme7ss3ARVgxv6rXqVPiikMJ8u2NLgmgszg13pYrDKEoiu
|
ipfs://Qme7ss3ARVgxv6rXqVPiikMJ8u2NLgmgszg13pYrDKEoiu
|
||||||
https://example.com/my-web2-claim.json
|
https://example.com/my-web2-claim.json
|
||||||
</h6>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,6 +8,5 @@
|
|||||||
&__sub-text {
|
&__sub-text {
|
||||||
white-space: pre-line;
|
white-space: pre-line;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
word-wrap: break-word;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import Box from '../../../ui/box';
|
import Box from '../../../ui/box';
|
||||||
import Typography from '../../../ui/typography';
|
import { Text } from '../../../component-library';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
FLEX_DIRECTION,
|
FLEX_DIRECTION,
|
||||||
TypographyVariant,
|
OVERFLOW_WRAP,
|
||||||
|
TextVariant,
|
||||||
} from '../../../../helpers/constants/design-system';
|
} from '../../../../helpers/constants/design-system';
|
||||||
|
|
||||||
const SignatureRequestSIWEMessage = ({ data }) => {
|
const SignatureRequestSIWEMessage = ({ data }) => {
|
||||||
@ -14,21 +15,22 @@ const SignatureRequestSIWEMessage = ({ data }) => {
|
|||||||
<Box flexDirection={FLEX_DIRECTION.COLUMN}>
|
<Box flexDirection={FLEX_DIRECTION.COLUMN}>
|
||||||
{data.map(({ label, value }, i) => (
|
{data.map(({ label, value }, i) => (
|
||||||
<Box key={i.toString()} marginTop={2} marginBottom={2}>
|
<Box key={i.toString()} marginTop={2} marginBottom={2}>
|
||||||
<Typography
|
<Text
|
||||||
variant={TypographyVariant.H4}
|
as="h4"
|
||||||
|
variant={TextVariant.bodyLgMedium}
|
||||||
marginTop={2}
|
marginTop={2}
|
||||||
marginBottom={2}
|
marginBottom={2}
|
||||||
>
|
>
|
||||||
{label}
|
{label}
|
||||||
</Typography>
|
</Text>
|
||||||
<Typography
|
<Text
|
||||||
className="signature-request-siwe-message__sub-text"
|
className="signature-request-siwe-message__sub-text"
|
||||||
variant={TypographyVariant.H6}
|
overflowWrap={OVERFLOW_WRAP.BREAK_WORD}
|
||||||
marginTop={2}
|
marginTop={2}
|
||||||
marginBottom={2}
|
marginBottom={2}
|
||||||
>
|
>
|
||||||
{value}
|
{value}
|
||||||
</Typography>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
))}
|
))}
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -64,7 +64,15 @@ export default function SignatureRequestSIWE({
|
|||||||
const isSIWEDomainValid = checkSIWEDomain();
|
const isSIWEDomainValid = checkSIWEDomain();
|
||||||
|
|
||||||
const [isShowingDomainWarning, setIsShowingDomainWarning] = useState(false);
|
const [isShowingDomainWarning, setIsShowingDomainWarning] = useState(false);
|
||||||
const [agreeToDomainWarning, setAgreeToDomainWarning] = useState(false);
|
const [hasAgreedToDomainWarning, setHasAgreedToDomainWarning] =
|
||||||
|
useState(false);
|
||||||
|
|
||||||
|
const showSecurityProviderBanner =
|
||||||
|
(txData?.securityProviderResponse?.flagAsDangerous !== undefined &&
|
||||||
|
txData?.securityProviderResponse?.flagAsDangerous !==
|
||||||
|
SECURITY_PROVIDER_MESSAGE_SEVERITIES.NOT_MALICIOUS) ||
|
||||||
|
(txData?.securityProviderResponse &&
|
||||||
|
Object.keys(txData.securityProviderResponse).length === 0);
|
||||||
|
|
||||||
const onSign = useCallback(
|
const onSign = useCallback(
|
||||||
async (event) => {
|
async (event) => {
|
||||||
@ -96,15 +104,13 @@ export default function SignatureRequestSIWE({
|
|||||||
isSIWEDomainValid={isSIWEDomainValid}
|
isSIWEDomainValid={isSIWEDomainValid}
|
||||||
subjectMetadata={targetSubjectMetadata}
|
subjectMetadata={targetSubjectMetadata}
|
||||||
/>
|
/>
|
||||||
{(txData?.securityProviderResponse?.flagAsDangerous !== undefined &&
|
|
||||||
txData?.securityProviderResponse?.flagAsDangerous !==
|
{showSecurityProviderBanner && (
|
||||||
SECURITY_PROVIDER_MESSAGE_SEVERITIES.NOT_MALICIOUS) ||
|
|
||||||
(txData?.securityProviderResponse &&
|
|
||||||
Object.keys(txData.securityProviderResponse).length === 0) ? (
|
|
||||||
<SecurityProviderBannerMessage
|
<SecurityProviderBannerMessage
|
||||||
securityProviderResponse={txData.securityProviderResponse}
|
securityProviderResponse={txData.securityProviderResponse}
|
||||||
/>
|
/>
|
||||||
) : null}
|
)}
|
||||||
|
|
||||||
<Message data={formatMessageParams(parsedMessage, t)} />
|
<Message data={formatMessageParams(parsedMessage, t)} />
|
||||||
{!isMatchingAddress && (
|
{!isMatchingAddress && (
|
||||||
<BannerAlert
|
<BannerAlert
|
||||||
@ -165,16 +171,16 @@ export default function SignatureRequestSIWE({
|
|||||||
onSubmit={onSign}
|
onSubmit={onSign}
|
||||||
submitText={t('confirm')}
|
submitText={t('confirm')}
|
||||||
submitButtonType="danger-primary"
|
submitButtonType="danger-primary"
|
||||||
disabled={!agreeToDomainWarning}
|
disabled={!hasAgreedToDomainWarning}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div className="signature-request-siwe__warning-popover__checkbox-wrapper">
|
<div className="signature-request-siwe__warning-popover__checkbox-wrapper">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
id="signature-request-siwe_domain-checkbox"
|
id="signature-request-siwe_domain-checkbox"
|
||||||
checked={agreeToDomainWarning}
|
checked={hasAgreedToDomainWarning}
|
||||||
className="signature-request-siwe__warning-popover__checkbox-wrapper__checkbox"
|
className="signature-request-siwe__warning-popover__checkbox-wrapper__checkbox"
|
||||||
onClick={() => setAgreeToDomainWarning((checked) => !checked)}
|
onClick={() => setHasAgreedToDomainWarning((checked) => !checked)}
|
||||||
/>
|
/>
|
||||||
<label
|
<label
|
||||||
className="signature-request-siwe__warning-popover__checkbox-wrapper__label"
|
className="signature-request-siwe__warning-popover__checkbox-wrapper__label"
|
||||||
|
@ -13,32 +13,38 @@ import {
|
|||||||
AvatarAccountSize,
|
AvatarAccountSize,
|
||||||
} from './avatar-account.types';
|
} from './avatar-account.types';
|
||||||
|
|
||||||
export const AvatarAccount = ({
|
export const AvatarAccount = React.forwardRef(
|
||||||
size = AvatarAccountSize.Md,
|
(
|
||||||
address,
|
{
|
||||||
className,
|
size = AvatarAccountSize.Md,
|
||||||
variant = AvatarAccountVariant.Jazzicon,
|
address,
|
||||||
...props
|
className,
|
||||||
}) => (
|
variant = AvatarAccountVariant.Jazzicon,
|
||||||
<AvatarBase
|
...props
|
||||||
size={size}
|
},
|
||||||
className={classnames('mm-avatar-account', className)}
|
ref,
|
||||||
{...props}
|
) => (
|
||||||
>
|
<AvatarBase
|
||||||
{variant === AvatarAccountVariant.Jazzicon ? (
|
ref={ref}
|
||||||
<Jazzicon
|
size={size}
|
||||||
className={classnames('mm-avatar-account__jazzicon')}
|
className={classnames('mm-avatar-account', className)}
|
||||||
address={address}
|
{...props}
|
||||||
diameter={AvatarAccountDiameter[size]}
|
>
|
||||||
/>
|
{variant === AvatarAccountVariant.Jazzicon ? (
|
||||||
) : (
|
<Jazzicon
|
||||||
<BlockieIdenticon
|
className={classnames('mm-avatar-account__jazzicon')}
|
||||||
address={address}
|
address={address}
|
||||||
diameter={AvatarAccountDiameter[size]}
|
diameter={AvatarAccountDiameter[size]}
|
||||||
borderRadius="50%"
|
/>
|
||||||
/>
|
) : (
|
||||||
)}
|
<BlockieIdenticon
|
||||||
</AvatarBase>
|
address={address}
|
||||||
|
diameter={AvatarAccountDiameter[size]}
|
||||||
|
borderRadius="50%"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</AvatarBase>
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
AvatarAccount.propTypes = {
|
AvatarAccount.propTypes = {
|
||||||
@ -66,3 +72,5 @@ AvatarAccount.propTypes = {
|
|||||||
*/
|
*/
|
||||||
...Box.propTypes,
|
...Box.propTypes,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
AvatarAccount.displayName = 'AvatarAccount';
|
||||||
|
@ -112,4 +112,15 @@ describe('AvatarAccount', () => {
|
|||||||
'mm-avatar-base--size-xl',
|
'mm-avatar-base--size-xl',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
it('should forward a ref to the root html element', () => {
|
||||||
|
const ref = React.createRef();
|
||||||
|
render(
|
||||||
|
<AvatarAccount
|
||||||
|
address="0x5CfE73b6021E818B776b421B1c4Db2474086a7e1"
|
||||||
|
ref={ref}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
expect(ref.current).not.toBeNull();
|
||||||
|
expect(ref.current.nodeName).toBe('DIV');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -19,44 +19,51 @@ import { Text } from '../text';
|
|||||||
|
|
||||||
import { AVATAR_BASE_SIZES } from './avatar-base.constants';
|
import { AVATAR_BASE_SIZES } from './avatar-base.constants';
|
||||||
|
|
||||||
export const AvatarBase = ({
|
export const AvatarBase = React.forwardRef(
|
||||||
size = AVATAR_BASE_SIZES.MD,
|
(
|
||||||
children,
|
{
|
||||||
backgroundColor = BackgroundColor.backgroundAlternative,
|
size = AVATAR_BASE_SIZES.MD,
|
||||||
borderColor = BorderColor.borderDefault,
|
children,
|
||||||
color = TextColor.textDefault,
|
backgroundColor = BackgroundColor.backgroundAlternative,
|
||||||
className,
|
borderColor = BorderColor.borderDefault,
|
||||||
...props
|
color = TextColor.textDefault,
|
||||||
}) => {
|
className,
|
||||||
let fallbackTextVariant;
|
...props
|
||||||
|
},
|
||||||
|
ref,
|
||||||
|
) => {
|
||||||
|
let fallbackTextVariant;
|
||||||
|
|
||||||
|
if (size === AVATAR_BASE_SIZES.LG || size === AVATAR_BASE_SIZES.XL) {
|
||||||
|
fallbackTextVariant = TextVariant.bodyLgMedium;
|
||||||
|
} else if (size === AVATAR_BASE_SIZES.SM || size === AVATAR_BASE_SIZES.MD) {
|
||||||
|
fallbackTextVariant = TextVariant.bodySm;
|
||||||
|
} else {
|
||||||
|
fallbackTextVariant = TextVariant.bodyXs;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Text
|
||||||
|
className={classnames(
|
||||||
|
'mm-avatar-base',
|
||||||
|
`mm-avatar-base--size-${size}`,
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
ref={ref}
|
||||||
|
as="div"
|
||||||
|
display={DISPLAY.FLEX}
|
||||||
|
justifyContent={JustifyContent.center}
|
||||||
|
alignItems={AlignItems.center}
|
||||||
|
borderRadius={BorderRadius.full}
|
||||||
|
variant={fallbackTextVariant}
|
||||||
|
textTransform={TEXT_TRANSFORM.UPPERCASE}
|
||||||
|
{...{ backgroundColor, borderColor, color, ...props }}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Text>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
if (size === AVATAR_BASE_SIZES.LG || size === AVATAR_BASE_SIZES.XL) {
|
|
||||||
fallbackTextVariant = TextVariant.bodyLgMedium;
|
|
||||||
} else if (size === AVATAR_BASE_SIZES.SM || size === AVATAR_BASE_SIZES.MD) {
|
|
||||||
fallbackTextVariant = TextVariant.bodySm;
|
|
||||||
} else {
|
|
||||||
fallbackTextVariant = TextVariant.bodyXs;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<Text
|
|
||||||
className={classnames(
|
|
||||||
'mm-avatar-base',
|
|
||||||
`mm-avatar-base--size-${size}`,
|
|
||||||
className,
|
|
||||||
)}
|
|
||||||
as="div"
|
|
||||||
display={DISPLAY.FLEX}
|
|
||||||
justifyContent={JustifyContent.center}
|
|
||||||
alignItems={AlignItems.center}
|
|
||||||
borderRadius={BorderRadius.full}
|
|
||||||
variant={fallbackTextVariant}
|
|
||||||
textTransform={TEXT_TRANSFORM.UPPERCASE}
|
|
||||||
{...{ backgroundColor, borderColor, color, ...props }}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</Text>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
AvatarBase.propTypes = {
|
AvatarBase.propTypes = {
|
||||||
/**
|
/**
|
||||||
* The size of the AvatarBase.
|
* The size of the AvatarBase.
|
||||||
@ -95,3 +102,5 @@ AvatarBase.propTypes = {
|
|||||||
*/
|
*/
|
||||||
...Text.propTypes,
|
...Text.propTypes,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
AvatarBase.displayName = 'AvatarBase';
|
||||||
|
@ -121,4 +121,10 @@ describe('AvatarBase', () => {
|
|||||||
`box--border-color-${Color.errorDefault}`,
|
`box--border-color-${Color.errorDefault}`,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
it('should forward a ref to the root html element', () => {
|
||||||
|
const ref = React.createRef();
|
||||||
|
render(<AvatarBase ref={ref}>A</AvatarBase>);
|
||||||
|
expect(ref.current).not.toBeNull();
|
||||||
|
expect(ref.current.nodeName).toBe('DIV');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -15,43 +15,48 @@ import {
|
|||||||
import { useI18nContext } from '../../../hooks/useI18nContext';
|
import { useI18nContext } from '../../../hooks/useI18nContext';
|
||||||
import { AVATAR_FAVICON_SIZES } from './avatar-favicon.constants';
|
import { AVATAR_FAVICON_SIZES } from './avatar-favicon.constants';
|
||||||
|
|
||||||
export const AvatarFavicon = ({
|
export const AvatarFavicon = React.forwardRef(
|
||||||
size = Size.MD,
|
(
|
||||||
src,
|
{
|
||||||
name = 'avatar-favicon',
|
size = Size.MD,
|
||||||
className,
|
src,
|
||||||
fallbackIconProps,
|
name = 'avatar-favicon',
|
||||||
borderColor = BorderColor.transparent,
|
className,
|
||||||
...props
|
fallbackIconProps,
|
||||||
}) => {
|
borderColor = BorderColor.transparent,
|
||||||
const t = useI18nContext();
|
...props
|
||||||
|
},
|
||||||
return (
|
ref,
|
||||||
<AvatarBase
|
) => {
|
||||||
size={size}
|
const t = useI18nContext();
|
||||||
display={DISPLAY.FLEX}
|
return (
|
||||||
alignItems={AlignItems.center}
|
<AvatarBase
|
||||||
justifyContent={JustifyContent.center}
|
ref={ref}
|
||||||
className={classnames('mm-avatar-favicon', className)}
|
size={size}
|
||||||
{...{ borderColor, ...props }}
|
display={DISPLAY.FLEX}
|
||||||
>
|
alignItems={AlignItems.center}
|
||||||
{src ? (
|
justifyContent={JustifyContent.center}
|
||||||
<img
|
className={classnames('mm-avatar-favicon', className)}
|
||||||
className="mm-avatar-favicon__image"
|
{...{ borderColor, ...props }}
|
||||||
src={src}
|
>
|
||||||
alt={t('logo', [name])}
|
{src ? (
|
||||||
/>
|
<img
|
||||||
) : (
|
className="mm-avatar-favicon__image"
|
||||||
<Icon
|
src={src}
|
||||||
name={IconName.Global}
|
alt={t('logo', [name])}
|
||||||
color={IconColor.iconDefault}
|
/>
|
||||||
size={size}
|
) : (
|
||||||
{...fallbackIconProps}
|
<Icon
|
||||||
/>
|
name={IconName.Global}
|
||||||
)}
|
color={IconColor.iconDefault}
|
||||||
</AvatarBase>
|
size={size}
|
||||||
);
|
{...fallbackIconProps}
|
||||||
};
|
/>
|
||||||
|
)}
|
||||||
|
</AvatarBase>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
AvatarFavicon.propTypes = {
|
AvatarFavicon.propTypes = {
|
||||||
/**
|
/**
|
||||||
@ -87,3 +92,5 @@ AvatarFavicon.propTypes = {
|
|||||||
*/
|
*/
|
||||||
...Box.propTypes,
|
...Box.propTypes,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
AvatarFavicon.displayName = 'AvatarFavicon';
|
||||||
|
@ -105,4 +105,10 @@ describe('AvatarFavicon', () => {
|
|||||||
);
|
);
|
||||||
expect(getByTestId('classname')).toHaveClass('mm-avatar-favicon--test');
|
expect(getByTestId('classname')).toHaveClass('mm-avatar-favicon--test');
|
||||||
});
|
});
|
||||||
|
it('should forward a ref to the root html element', () => {
|
||||||
|
const ref = React.createRef();
|
||||||
|
render(<AvatarFavicon name="test" ref={ref} />);
|
||||||
|
expect(ref.current).not.toBeNull();
|
||||||
|
expect(ref.current.nodeName).toBe('DIV');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -19,33 +19,39 @@ import { AvatarBase } from '../avatar-base';
|
|||||||
|
|
||||||
import { AVATAR_ICON_SIZES } from './avatar-icon.constants';
|
import { AVATAR_ICON_SIZES } from './avatar-icon.constants';
|
||||||
|
|
||||||
export const AvatarIcon = ({
|
export const AvatarIcon = React.forwardRef(
|
||||||
size = Size.MD,
|
(
|
||||||
color = TextColor.primaryDefault,
|
{
|
||||||
backgroundColor = BackgroundColor.primaryMuted,
|
size = Size.MD,
|
||||||
className,
|
color = TextColor.primaryDefault,
|
||||||
iconProps,
|
backgroundColor = BackgroundColor.primaryMuted,
|
||||||
iconName,
|
className,
|
||||||
...props
|
iconProps,
|
||||||
}) => (
|
iconName,
|
||||||
<AvatarBase
|
...props
|
||||||
size={size}
|
},
|
||||||
display={DISPLAY.FLEX}
|
ref,
|
||||||
alignItems={AlignItems.center}
|
) => (
|
||||||
justifyContent={JustifyContent.center}
|
<AvatarBase
|
||||||
color={color}
|
ref={ref}
|
||||||
backgroundColor={backgroundColor}
|
|
||||||
borderColor={BorderColor.transparent}
|
|
||||||
className={classnames('mm-avatar-icon', className)}
|
|
||||||
{...props}
|
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
color={IconColor.inherit}
|
|
||||||
name={iconName}
|
|
||||||
size={size}
|
size={size}
|
||||||
{...iconProps}
|
display={DISPLAY.FLEX}
|
||||||
/>
|
alignItems={AlignItems.center}
|
||||||
</AvatarBase>
|
justifyContent={JustifyContent.center}
|
||||||
|
color={color}
|
||||||
|
backgroundColor={backgroundColor}
|
||||||
|
borderColor={BorderColor.transparent}
|
||||||
|
className={classnames('mm-avatar-icon', className)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
color={IconColor.inherit}
|
||||||
|
name={iconName}
|
||||||
|
size={size}
|
||||||
|
{...iconProps}
|
||||||
|
/>
|
||||||
|
</AvatarBase>
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
AvatarIcon.propTypes = {
|
AvatarIcon.propTypes = {
|
||||||
@ -87,3 +93,5 @@ AvatarIcon.propTypes = {
|
|||||||
*/
|
*/
|
||||||
...Box.propTypes,
|
...Box.propTypes,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
AvatarIcon.displayName = 'AvatarIcon';
|
||||||
|
@ -105,4 +105,10 @@ describe('AvatarIcon', () => {
|
|||||||
'box--background-color-success-muted',
|
'box--background-color-success-muted',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
it('should forward a ref to the root html element', () => {
|
||||||
|
const ref = React.createRef();
|
||||||
|
render(<AvatarIcon iconName={IconName.SwapHorizontal} ref={ref} />);
|
||||||
|
expect(ref.current).not.toBeNull();
|
||||||
|
expect(ref.current.nodeName).toBe('DIV');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -14,70 +14,76 @@ import {
|
|||||||
} from '../../../helpers/constants/design-system';
|
} from '../../../helpers/constants/design-system';
|
||||||
import { AVATAR_NETWORK_SIZES } from './avatar-network.constants';
|
import { AVATAR_NETWORK_SIZES } from './avatar-network.constants';
|
||||||
|
|
||||||
export const AvatarNetwork = ({
|
export const AvatarNetwork = React.forwardRef(
|
||||||
size = Size.MD,
|
(
|
||||||
name,
|
{
|
||||||
src,
|
size = Size.MD,
|
||||||
showHalo,
|
name,
|
||||||
color = TextColor.textDefault,
|
src,
|
||||||
backgroundColor = BackgroundColor.backgroundAlternative,
|
showHalo,
|
||||||
borderColor = BorderColor.transparent,
|
color = TextColor.textDefault,
|
||||||
className,
|
backgroundColor = BackgroundColor.backgroundAlternative,
|
||||||
...props
|
borderColor = BorderColor.transparent,
|
||||||
}) => {
|
className,
|
||||||
const [showFallback, setShowFallback] = useState(false);
|
...props
|
||||||
|
},
|
||||||
|
ref,
|
||||||
|
) => {
|
||||||
|
const [showFallback, setShowFallback] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setShowFallback(!src);
|
setShowFallback(!src);
|
||||||
}, [src]);
|
}, [src]);
|
||||||
|
|
||||||
const fallbackString = name && name[0] ? name[0] : '?';
|
const fallbackString = name && name[0] ? name[0] : '?';
|
||||||
|
|
||||||
const handleOnError = () => {
|
const handleOnError = () => {
|
||||||
setShowFallback(true);
|
setShowFallback(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AvatarBase
|
<AvatarBase
|
||||||
size={size}
|
ref={ref}
|
||||||
display={DISPLAY.FLEX}
|
size={size}
|
||||||
alignItems={AlignItems.center}
|
display={DISPLAY.FLEX}
|
||||||
justifyContent={JustifyContent.center}
|
alignItems={AlignItems.center}
|
||||||
className={classnames(
|
justifyContent={JustifyContent.center}
|
||||||
'mm-avatar-network',
|
className={classnames(
|
||||||
showHalo && 'mm-avatar-network--with-halo',
|
'mm-avatar-network',
|
||||||
className,
|
showHalo && 'mm-avatar-network--with-halo',
|
||||||
)}
|
className,
|
||||||
{...{ backgroundColor, borderColor, color, ...props }}
|
)}
|
||||||
>
|
{...{ backgroundColor, borderColor, color, ...props }}
|
||||||
{showFallback ? (
|
>
|
||||||
fallbackString
|
{showFallback ? (
|
||||||
) : (
|
fallbackString
|
||||||
<>
|
) : (
|
||||||
{showHalo && (
|
<>
|
||||||
|
{showHalo && (
|
||||||
|
<img
|
||||||
|
src={src}
|
||||||
|
className={
|
||||||
|
showHalo ? 'mm-avatar-network__network-image--blurred' : ''
|
||||||
|
}
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<img
|
<img
|
||||||
src={src}
|
|
||||||
className={
|
className={
|
||||||
showHalo ? 'mm-avatar-network__network-image--blurred' : ''
|
showHalo
|
||||||
|
? 'mm-avatar-network__network-image--size-reduced'
|
||||||
|
: 'mm-avatar-network__network-image'
|
||||||
}
|
}
|
||||||
aria-hidden="true"
|
onError={handleOnError}
|
||||||
|
src={src}
|
||||||
|
alt={`${name} logo` || 'network logo'}
|
||||||
/>
|
/>
|
||||||
)}
|
</>
|
||||||
<img
|
)}
|
||||||
className={
|
</AvatarBase>
|
||||||
showHalo
|
);
|
||||||
? 'mm-avatar-network__network-image--size-reduced'
|
},
|
||||||
: 'mm-avatar-network__network-image'
|
);
|
||||||
}
|
|
||||||
onError={handleOnError}
|
|
||||||
src={src}
|
|
||||||
alt={`${name} logo` || 'network logo'}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</AvatarBase>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
AvatarNetwork.propTypes = {
|
AvatarNetwork.propTypes = {
|
||||||
/**
|
/**
|
||||||
@ -123,3 +129,5 @@ AvatarNetwork.propTypes = {
|
|||||||
*/
|
*/
|
||||||
...Box.propTypes,
|
...Box.propTypes,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
AvatarNetwork.displayName = 'AvatarNetwork';
|
||||||
|
@ -123,4 +123,10 @@ describe('AvatarNetwork', () => {
|
|||||||
`box--border-color-${BorderColor.errorDefault}`,
|
`box--border-color-${BorderColor.errorDefault}`,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
it('should forward a ref to the root html element', () => {
|
||||||
|
const ref = React.createRef();
|
||||||
|
render(<AvatarNetwork ref={ref} />);
|
||||||
|
expect(ref.current).not.toBeNull();
|
||||||
|
expect(ref.current.nodeName).toBe('DIV');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -14,70 +14,76 @@ import {
|
|||||||
} from '../../../helpers/constants/design-system';
|
} from '../../../helpers/constants/design-system';
|
||||||
import { AVATAR_TOKEN_SIZES } from './avatar-token.constants';
|
import { AVATAR_TOKEN_SIZES } from './avatar-token.constants';
|
||||||
|
|
||||||
export const AvatarToken = ({
|
export const AvatarToken = React.forwardRef(
|
||||||
size = Size.MD,
|
(
|
||||||
name,
|
{
|
||||||
src,
|
size = Size.MD,
|
||||||
showHalo,
|
name,
|
||||||
color = TextColor.textDefault,
|
src,
|
||||||
backgroundColor = BackgroundColor.backgroundAlternative,
|
showHalo,
|
||||||
borderColor = BorderColor.transparent,
|
color = TextColor.textDefault,
|
||||||
className,
|
backgroundColor = BackgroundColor.backgroundAlternative,
|
||||||
...props
|
borderColor = BorderColor.transparent,
|
||||||
}) => {
|
className,
|
||||||
const [showFallback, setShowFallback] = useState(false);
|
...props
|
||||||
|
},
|
||||||
|
ref,
|
||||||
|
) => {
|
||||||
|
const [showFallback, setShowFallback] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setShowFallback(!src);
|
setShowFallback(!src);
|
||||||
}, [src]);
|
}, [src]);
|
||||||
|
|
||||||
const handleOnError = () => {
|
const handleOnError = () => {
|
||||||
setShowFallback(true);
|
setShowFallback(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const fallbackString = name && name[0] ? name[0] : '?';
|
const fallbackString = name && name[0] ? name[0] : '?';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AvatarBase
|
<AvatarBase
|
||||||
size={size}
|
ref={ref}
|
||||||
display={DISPLAY.FLEX}
|
size={size}
|
||||||
alignItems={AlignItems.center}
|
display={DISPLAY.FLEX}
|
||||||
justifyContent={JustifyContent.center}
|
alignItems={AlignItems.center}
|
||||||
className={classnames(
|
justifyContent={JustifyContent.center}
|
||||||
'mm-avatar-token',
|
className={classnames(
|
||||||
showHalo && 'mm-avatar-token--with-halo',
|
'mm-avatar-token',
|
||||||
className,
|
showHalo && 'mm-avatar-token--with-halo',
|
||||||
)}
|
className,
|
||||||
{...{ backgroundColor, borderColor, color, ...props }}
|
)}
|
||||||
>
|
{...{ backgroundColor, borderColor, color, ...props }}
|
||||||
{showFallback ? (
|
>
|
||||||
fallbackString
|
{showFallback ? (
|
||||||
) : (
|
fallbackString
|
||||||
<>
|
) : (
|
||||||
{showHalo && (
|
<>
|
||||||
|
{showHalo && (
|
||||||
|
<img
|
||||||
|
src={src}
|
||||||
|
className={
|
||||||
|
showHalo ? 'mm-avatar-token__token-image--blurred' : ''
|
||||||
|
}
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<img
|
<img
|
||||||
src={src}
|
|
||||||
className={
|
className={
|
||||||
showHalo ? 'mm-avatar-token__token-image--blurred' : ''
|
showHalo
|
||||||
|
? 'mm-avatar-token__token-image--size-reduced'
|
||||||
|
: 'mm-avatar-token__token-image'
|
||||||
}
|
}
|
||||||
aria-hidden="true"
|
onError={handleOnError}
|
||||||
|
src={src}
|
||||||
|
alt={`${name} logo` || 'token logo'}
|
||||||
/>
|
/>
|
||||||
)}
|
</>
|
||||||
<img
|
)}
|
||||||
className={
|
</AvatarBase>
|
||||||
showHalo
|
);
|
||||||
? 'mm-avatar-token__token-image--size-reduced'
|
},
|
||||||
: 'mm-avatar-token__token-image'
|
);
|
||||||
}
|
|
||||||
onError={handleOnError}
|
|
||||||
src={src}
|
|
||||||
alt={`${name} logo` || 'token logo'}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</AvatarBase>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
AvatarToken.propTypes = {
|
AvatarToken.propTypes = {
|
||||||
/**
|
/**
|
||||||
@ -123,3 +129,5 @@ AvatarToken.propTypes = {
|
|||||||
*/
|
*/
|
||||||
...Box.propTypes,
|
...Box.propTypes,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
AvatarToken.displayName = 'AvatarToken';
|
||||||
|
@ -121,4 +121,10 @@ describe('AvatarToken', () => {
|
|||||||
`box--border-color-${BorderColor.errorDefault}`,
|
`box--border-color-${BorderColor.errorDefault}`,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
it('should forward a ref to the root html element', () => {
|
||||||
|
const ref = React.createRef();
|
||||||
|
render(<AvatarToken ref={ref} />);
|
||||||
|
expect(ref.current).not.toBeNull();
|
||||||
|
expect(ref.current.nodeName).toBe('DIV');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -0,0 +1,144 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`ComplianceDetails should render correctly 1`] = `
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
class="box compliance-details box--padding-right-4 box--padding-left-4 box--display-flex box--flex-direction-column"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="box compliance-details__row box--padding-top-4 box--padding-bottom-4 box--display-flex box--flex-direction-column box--justify-content-center box--height-2/3"
|
||||||
|
>
|
||||||
|
<p
|
||||||
|
class="box mm-text mm-text--body-md box--flex-direction-row box--color-text-default"
|
||||||
|
>
|
||||||
|
Address
|
||||||
|
</p>
|
||||||
|
<p
|
||||||
|
class="box mm-text mm-text--body-xs box--flex-direction-row box--color-text-default"
|
||||||
|
>
|
||||||
|
0xAddress
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="box compliance-details__row box--padding-top-4 box--padding-bottom-4 box--display-flex box--flex-direction-column box--justify-content-center box--height-2/3"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="box box--margin-bottom-1 box--display-flex box--flex-direction-row box--align-items-center box--color-text-alternative"
|
||||||
|
>
|
||||||
|
<p
|
||||||
|
class="box mm-text mm-text--body-md box--margin-right-2 box--flex-direction-row box--color-text-default"
|
||||||
|
>
|
||||||
|
Risk rating
|
||||||
|
</p>
|
||||||
|
<div
|
||||||
|
class="info-tooltip"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
aria-describedby="tippy-tooltip-1"
|
||||||
|
class="info-tooltip__tooltip-container"
|
||||||
|
data-original-title="null"
|
||||||
|
data-tooltipped=""
|
||||||
|
style="display: inline;"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
viewBox="0 0 10 10"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M5 0C2.2 0 0 2.2 0 5s2.2 5 5 5 5-2.2 5-5-2.2-5-5-5zm0 2c.4 0 .7.3.7.7s-.3.7-.7.7-.7-.2-.7-.6.3-.8.7-.8zm.7 6H4.3V4.3h1.5V8z"
|
||||||
|
fill="var(--color-icon-alternative)"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="box compliance-row__column-risk compliance-row__column-risk--green box--flex-direction-row"
|
||||||
|
>
|
||||||
|
<p
|
||||||
|
class="box mm-text mm-text--body-md box--flex-direction-row box--color-text-default"
|
||||||
|
>
|
||||||
|
low
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="box compliance-details__row box--padding-top-4 box--padding-bottom-4 box--display-flex box--flex-direction-column box--justify-content-center box--height-2/3"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="box box--display-flex box--flex-direction-row box--align-items-center box--color-text-alternative"
|
||||||
|
>
|
||||||
|
<p
|
||||||
|
class="box mm-text mm-text--body-md box--margin-right-2 box--flex-direction-row box--color-text-default"
|
||||||
|
>
|
||||||
|
Report last run
|
||||||
|
</p>
|
||||||
|
<div
|
||||||
|
class="info-tooltip"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
aria-describedby="tippy-tooltip-2"
|
||||||
|
class="info-tooltip__tooltip-container"
|
||||||
|
data-original-title="null"
|
||||||
|
data-tooltipped=""
|
||||||
|
style="display: inline;"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
viewBox="0 0 10 10"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M5 0C2.2 0 0 2.2 0 5s2.2 5 5 5 5-2.2 5-5-2.2-5-5-5zm0 2c.4 0 .7.3.7.7s-.3.7-.7.7-.7-.2-.7-.6.3-.8.7-.8zm.7 6H4.3V4.3h1.5V8z"
|
||||||
|
fill="var(--color-icon-alternative)"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p
|
||||||
|
class="box mm-text mm-text--body-md box--flex-direction-row box--color-text-default"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="box box--flex-direction-row"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="swaps-footer"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="swaps-footer__buttons swaps-footer__buttons--border"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="page-container__footer swaps-footer__custom-page-container-footer-class"
|
||||||
|
>
|
||||||
|
<footer>
|
||||||
|
<button
|
||||||
|
class="button btn--rounded btn-secondary page-container__footer-button page-container__footer-button__cancel swaps-footer__custom-page-container-footer-button-class"
|
||||||
|
data-testid="page-container-footer-cancel"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
Show report
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="button btn--rounded btn-primary page-container__footer-button swaps-footer__custom-page-container-footer-button-class"
|
||||||
|
data-testid="page-container-footer-next"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
Run report
|
||||||
|
</button>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
@ -0,0 +1,159 @@
|
|||||||
|
import React, { useContext, useEffect, useState } from 'react';
|
||||||
|
import { useSelector, useDispatch } from 'react-redux';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import classnames from 'classnames';
|
||||||
|
import { I18nContext } from '../../../contexts/i18n';
|
||||||
|
import InfoTooltip from '../../ui/info-tooltip';
|
||||||
|
import SwapsFooter from '../../../pages/swaps/swaps-footer';
|
||||||
|
import {
|
||||||
|
fetchHistoricalReports,
|
||||||
|
getComplianceHistoricalReportsByAddress,
|
||||||
|
getComplianceTenantSubdomain,
|
||||||
|
} from '../../../ducks/institutional/institutional';
|
||||||
|
import { formatDate } from '../../../helpers/utils/util';
|
||||||
|
import Box from '../../ui/box';
|
||||||
|
import { Text } from '../../component-library';
|
||||||
|
import {
|
||||||
|
TextColor,
|
||||||
|
TextVariant,
|
||||||
|
JustifyContent,
|
||||||
|
AlignItems,
|
||||||
|
BLOCK_SIZES,
|
||||||
|
DISPLAY,
|
||||||
|
FLEX_DIRECTION,
|
||||||
|
} from '../../../helpers/constants/design-system';
|
||||||
|
|
||||||
|
const ComplianceDetails = ({ address, onClose, onGenerate }) => {
|
||||||
|
const t = useContext(I18nContext);
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
dispatch(fetchHistoricalReports(address));
|
||||||
|
}, [address, dispatch]);
|
||||||
|
|
||||||
|
const [lastReport, setLastReport] = useState(null);
|
||||||
|
const historicalReports = useSelector(
|
||||||
|
getComplianceHistoricalReportsByAddress(address),
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (historicalReports && historicalReports.length) {
|
||||||
|
setLastReport(
|
||||||
|
historicalReports.reduce((prev, cur) =>
|
||||||
|
prev.createTime > cur.createTime ? prev : cur,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, [historicalReports]);
|
||||||
|
|
||||||
|
const complianceTenantSubdomain = useSelector(getComplianceTenantSubdomain);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
display={DISPLAY.FLEX}
|
||||||
|
flexDirection={FLEX_DIRECTION.COLUMN}
|
||||||
|
paddingLeft={4}
|
||||||
|
paddingRight={4}
|
||||||
|
className="compliance-details"
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
display={DISPLAY.FLEX}
|
||||||
|
flexDirection={FLEX_DIRECTION.COLUMN}
|
||||||
|
justifyContent={JustifyContent.center}
|
||||||
|
height={BLOCK_SIZES.TWO_THIRDS}
|
||||||
|
paddingTop={4}
|
||||||
|
paddingBottom={4}
|
||||||
|
className="compliance-details__row"
|
||||||
|
>
|
||||||
|
<Text>{t('address')}</Text>
|
||||||
|
<Text variant={TextVariant.bodyXs}>{address}</Text>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
display={DISPLAY.FLEX}
|
||||||
|
flexDirection={FLEX_DIRECTION.COLUMN}
|
||||||
|
justifyContent={JustifyContent.center}
|
||||||
|
height={BLOCK_SIZES.TWO_THIRDS}
|
||||||
|
paddingTop={4}
|
||||||
|
paddingBottom={4}
|
||||||
|
className="compliance-details__row"
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
display={DISPLAY.FLEX}
|
||||||
|
alignItems={AlignItems.center}
|
||||||
|
marginBottom={1}
|
||||||
|
color={TextColor.textAlternative}
|
||||||
|
>
|
||||||
|
<Text marginRight={2}>{t('riskRating')}</Text>
|
||||||
|
<InfoTooltip
|
||||||
|
position="bottom"
|
||||||
|
contentText={<span>{t('riskRatingTooltip')}</span>}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
className={classnames('compliance-row__column-risk', {
|
||||||
|
'compliance-row__column-risk--green': lastReport?.risk === 'low',
|
||||||
|
'compliance-row__column-risk--yellow':
|
||||||
|
lastReport?.risk === 'medium',
|
||||||
|
'compliance-row__column-risk--orange': lastReport?.risk === 'high',
|
||||||
|
'compliance-row__column-risk--red':
|
||||||
|
lastReport?.risk === 'unacceptable',
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Text>{lastReport ? lastReport.risk : t('noReport')}</Text>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
display={DISPLAY.FLEX}
|
||||||
|
flexDirection={FLEX_DIRECTION.COLUMN}
|
||||||
|
justifyContent={JustifyContent.center}
|
||||||
|
height={BLOCK_SIZES.TWO_THIRDS}
|
||||||
|
paddingTop={4}
|
||||||
|
paddingBottom={4}
|
||||||
|
className="compliance-details__row"
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
display={DISPLAY.FLEX}
|
||||||
|
alignItems={AlignItems.center}
|
||||||
|
color={TextColor.textAlternative}
|
||||||
|
>
|
||||||
|
<Text marginRight={2}>{t('reportLastRun')}</Text>
|
||||||
|
<InfoTooltip
|
||||||
|
position="bottom"
|
||||||
|
contentText={<span>{t('reportLastRunTooltip')}</span>}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
<Text color={TextColor.textDefault}>
|
||||||
|
{lastReport
|
||||||
|
? formatDate(new Date(lastReport.createTime).getTime())
|
||||||
|
: 'N/A'}
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
<SwapsFooter
|
||||||
|
onSubmit={() => {
|
||||||
|
onGenerate(address);
|
||||||
|
onClose();
|
||||||
|
}}
|
||||||
|
submitText={t('runReport')}
|
||||||
|
onCancel={() =>
|
||||||
|
global.platform.openTab({
|
||||||
|
url: `https://${complianceTenantSubdomain}.compliance.codefi.network/app/kyt/addresses/${lastReport.address}/${lastReport.reportId}`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
cancelText={t('showReport')}
|
||||||
|
hideCancel={!lastReport}
|
||||||
|
approveActive={lastReport}
|
||||||
|
showTopBorder
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
ComplianceDetails.propTypes = {
|
||||||
|
address: PropTypes.string,
|
||||||
|
onClose: PropTypes.func,
|
||||||
|
onGenerate: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ComplianceDetails;
|
@ -0,0 +1,48 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Provider } from 'react-redux';
|
||||||
|
import configureStore from '../../../store/store';
|
||||||
|
import testData from '../../../../.storybook/test-data';
|
||||||
|
import ComplianceDetails from '.';
|
||||||
|
|
||||||
|
const customData = {
|
||||||
|
...testData,
|
||||||
|
metamask: {
|
||||||
|
institutionalFeatures: {
|
||||||
|
complianceProjectId: '',
|
||||||
|
complianceClientId: '',
|
||||||
|
reportsInProgress: {},
|
||||||
|
historicalReports: {
|
||||||
|
'0xAddress': [
|
||||||
|
{
|
||||||
|
reportId: 'reportId',
|
||||||
|
address: '0xAddress',
|
||||||
|
risk: 'low',
|
||||||
|
creatTime: new Date(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const store = configureStore(customData);
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Components/Institutional/ComplianceDetails',
|
||||||
|
decorators: [(story) => <Provider store={store}>{story()}</Provider>],
|
||||||
|
component: ComplianceDetails,
|
||||||
|
args: {
|
||||||
|
address: '0xAddress',
|
||||||
|
onClose: () => undefined,
|
||||||
|
onGenerate: () => undefined,
|
||||||
|
},
|
||||||
|
argTypes: {
|
||||||
|
onClick: {
|
||||||
|
action: 'onClick',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DefaultStory = (args) => <ComplianceDetails {...args} />;
|
||||||
|
|
||||||
|
DefaultStory.storyName = 'ComplianceDetails';
|
@ -0,0 +1,67 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import configureStore from 'redux-mock-store';
|
||||||
|
import { fireEvent, screen } from '@testing-library/react';
|
||||||
|
import thunk from 'redux-thunk';
|
||||||
|
import { renderWithProvider } from '../../../../test/lib/render-helpers';
|
||||||
|
import ComplianceDetails from './compliance-details';
|
||||||
|
|
||||||
|
const initState = {
|
||||||
|
metamask: {
|
||||||
|
institutionalFeatures: {
|
||||||
|
complianceProjectId: '',
|
||||||
|
complianceClientId: '',
|
||||||
|
reportsInProgress: {},
|
||||||
|
historicalReports: {
|
||||||
|
'0xAddress': [
|
||||||
|
{
|
||||||
|
reportId: 'reportId',
|
||||||
|
address: '0xAddress',
|
||||||
|
risk: 'low',
|
||||||
|
creatTime: new Date(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const middlewares = [thunk];
|
||||||
|
const mockStore = configureStore(middlewares);
|
||||||
|
|
||||||
|
describe('ComplianceDetails', () => {
|
||||||
|
const props = {
|
||||||
|
address: '0xAddress',
|
||||||
|
onClose: jest.fn(),
|
||||||
|
onGenerate: jest.fn(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const store = mockStore(initState);
|
||||||
|
|
||||||
|
it('should render correctly', () => {
|
||||||
|
const { container } = renderWithProvider(
|
||||||
|
<ComplianceDetails
|
||||||
|
address={props.address}
|
||||||
|
onClose={props.onClose}
|
||||||
|
onGenerate={props.onGenerate}
|
||||||
|
/>,
|
||||||
|
store,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(container).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('runs onGenerate fuction', () => {
|
||||||
|
renderWithProvider(
|
||||||
|
<ComplianceDetails
|
||||||
|
address={props.address}
|
||||||
|
onClose={props.onClose}
|
||||||
|
onGenerate={props.onGenerate}
|
||||||
|
/>,
|
||||||
|
store,
|
||||||
|
);
|
||||||
|
|
||||||
|
fireEvent.click(screen.queryByTestId('page-container-footer-next'));
|
||||||
|
|
||||||
|
expect(props.onGenerate).toHaveBeenCalledTimes(1);
|
||||||
|
expect(props.onGenerate).toHaveBeenCalledWith(props.address);
|
||||||
|
});
|
||||||
|
});
|
1
ui/components/institutional/compliance-details/index.js
Normal file
1
ui/components/institutional/compliance-details/index.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { default } from './compliance-details';
|
@ -0,0 +1,5 @@
|
|||||||
|
.compliance-details {
|
||||||
|
&__row {
|
||||||
|
border-top: 1px solid var(--color-border-muted);
|
||||||
|
}
|
||||||
|
}
|
11
ui/components/institutional/institutional-components.scss
Normal file
11
ui/components/institutional/institutional-components.scss
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
/**
|
||||||
|
* Please import your styles in order of atomicity.
|
||||||
|
* The most atomic styles should be imported first.
|
||||||
|
* This will help improve specificity and reduce the chance of
|
||||||
|
* unintended overrides.
|
||||||
|
**/
|
||||||
|
@import 'compliance-details/index';
|
||||||
|
@import 'compliance-settings/index';
|
||||||
|
@import 'jwt-dropdown/jwt-dropdown';
|
||||||
|
@import 'jwt-url-form/jwt-url-form';
|
||||||
|
@import 'note-to-trader/index';
|
@ -23,7 +23,6 @@ import {
|
|||||||
} from '../../../helpers/constants/design-system';
|
} from '../../../helpers/constants/design-system';
|
||||||
import {
|
import {
|
||||||
AvatarNetwork,
|
AvatarNetwork,
|
||||||
Button,
|
|
||||||
ButtonIcon,
|
ButtonIcon,
|
||||||
IconName,
|
IconName,
|
||||||
PickerNetwork,
|
PickerNetwork,
|
||||||
@ -31,29 +30,41 @@ import {
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
getCurrentNetwork,
|
getCurrentNetwork,
|
||||||
|
getOnboardedInThisUISession,
|
||||||
getOriginOfCurrentTab,
|
getOriginOfCurrentTab,
|
||||||
getSelectedIdentity,
|
getSelectedIdentity,
|
||||||
|
getShowProductTour,
|
||||||
} from '../../../selectors';
|
} from '../../../selectors';
|
||||||
import { GlobalMenu, AccountPicker } from '..';
|
import { GlobalMenu, ProductTour, AccountPicker } from '..';
|
||||||
|
|
||||||
import Box from '../../ui/box/box';
|
import Box from '../../ui/box/box';
|
||||||
import { toggleAccountMenu, toggleNetworkMenu } from '../../../store/actions';
|
import {
|
||||||
|
hideProductTour,
|
||||||
|
toggleAccountMenu,
|
||||||
|
toggleNetworkMenu,
|
||||||
|
} from '../../../store/actions';
|
||||||
import MetafoxLogo from '../../ui/metafox-logo';
|
import MetafoxLogo from '../../ui/metafox-logo';
|
||||||
import { getEnvironmentType } from '../../../../app/scripts/lib/util';
|
import { getEnvironmentType } from '../../../../app/scripts/lib/util';
|
||||||
import { ENVIRONMENT_TYPE_POPUP } from '../../../../shared/constants/app';
|
import { ENVIRONMENT_TYPE_POPUP } from '../../../../shared/constants/app';
|
||||||
import ConnectedStatusIndicator from '../../app/connected-status-indicator';
|
import ConnectedStatusIndicator from '../../app/connected-status-indicator';
|
||||||
|
import { useI18nContext } from '../../../hooks/useI18nContext';
|
||||||
|
import { getCompletedOnboarding } from '../../../ducks/metamask/metamask';
|
||||||
|
|
||||||
export const AppHeader = ({ onClick }) => {
|
export const AppHeader = ({ onClick }) => {
|
||||||
const trackEvent = useContext(MetaMetricsContext);
|
const trackEvent = useContext(MetaMetricsContext);
|
||||||
const [accountOptionsMenuOpen, setAccountOptionsMenuOpen] = useState(false);
|
const [accountOptionsMenuOpen, setAccountOptionsMenuOpen] = useState(false);
|
||||||
|
const [multichainProductTourStep, setMultichainProductTourStep] = useState(1);
|
||||||
const menuRef = useRef(false);
|
const menuRef = useRef(false);
|
||||||
const origin = useSelector(getOriginOfCurrentTab);
|
const origin = useSelector(getOriginOfCurrentTab);
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const isUnlocked = useSelector((state) => state.metamask.isUnlocked);
|
const isUnlocked = useSelector((state) => state.metamask.isUnlocked);
|
||||||
|
const t = useI18nContext();
|
||||||
// Used for account picker
|
// Used for account picker
|
||||||
const identity = useSelector(getSelectedIdentity);
|
const identity = useSelector(getSelectedIdentity);
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
const completedOnboarding = useSelector(getCompletedOnboarding);
|
||||||
|
const onboardedInThisUISession = useSelector(getOnboardedInThisUISession);
|
||||||
|
const showProductTourPopup = useSelector(getShowProductTour);
|
||||||
|
|
||||||
// Used for network icon / dropdown
|
// Used for network icon / dropdown
|
||||||
const currentNetwork = useSelector(getCurrentNetwork);
|
const currentNetwork = useSelector(getCurrentNetwork);
|
||||||
@ -64,12 +75,17 @@ export const AppHeader = ({ onClick }) => {
|
|||||||
getEnvironmentType() === ENVIRONMENT_TYPE_POPUP &&
|
getEnvironmentType() === ENVIRONMENT_TYPE_POPUP &&
|
||||||
origin &&
|
origin &&
|
||||||
origin !== browser.runtime.id;
|
origin !== browser.runtime.id;
|
||||||
|
const showProductTour =
|
||||||
|
completedOnboarding && !onboardedInThisUISession && showProductTourPopup;
|
||||||
|
const productTourDirection = document
|
||||||
|
.querySelector('[dir]')
|
||||||
|
?.getAttribute('dir');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isUnlocked && !popupStatus ? (
|
{isUnlocked && !popupStatus ? (
|
||||||
<Box
|
<Box
|
||||||
display={DISPLAY.FLEX}
|
display={[DISPLAY.NONE, DISPLAY.FLEX]}
|
||||||
alignItems={AlignItems.center}
|
alignItems={AlignItems.center}
|
||||||
margin={2}
|
margin={2}
|
||||||
className="multichain-app-header-logo"
|
className="multichain-app-header-logo"
|
||||||
@ -112,25 +128,43 @@ export const AppHeader = ({ onClick }) => {
|
|||||||
padding={2}
|
padding={2}
|
||||||
gap={2}
|
gap={2}
|
||||||
>
|
>
|
||||||
{popupStatus ? (
|
<AvatarNetwork
|
||||||
<Button
|
margin={2}
|
||||||
className="multichain-app-header__contents--avatar-network"
|
className="multichain-app-header__contents--avatar-network"
|
||||||
justifyContent={JustifyContent.flexStart}
|
ref={menuRef}
|
||||||
>
|
as="button"
|
||||||
<AvatarNetwork
|
aria-label="Network Menu" // TODO: needs locale
|
||||||
name={currentNetwork?.nickname}
|
padding={0}
|
||||||
src={currentNetwork?.rpcPrefs?.imageUrl}
|
name={currentNetwork?.nickname}
|
||||||
size={Size.SM}
|
src={currentNetwork?.rpcPrefs?.imageUrl}
|
||||||
onClick={() => dispatch(toggleNetworkMenu())}
|
size={Size.SM}
|
||||||
/>
|
onClick={() => dispatch(toggleNetworkMenu())}
|
||||||
</Button>
|
display={[DISPLAY.FLEX, DISPLAY.NONE]} // show on popover hide on desktop
|
||||||
) : (
|
/>
|
||||||
<PickerNetwork
|
<PickerNetwork
|
||||||
label={currentNetwork?.nickname}
|
margin={2}
|
||||||
src={currentNetwork?.rpcPrefs?.imageUrl}
|
label={currentNetwork?.nickname}
|
||||||
onClick={() => dispatch(toggleNetworkMenu())}
|
src={currentNetwork?.rpcPrefs?.imageUrl}
|
||||||
|
onClick={() => dispatch(toggleNetworkMenu())}
|
||||||
|
display={[DISPLAY.NONE, DISPLAY.FLEX]} // show on desktop hide on popover
|
||||||
|
/>
|
||||||
|
{showProductTour &&
|
||||||
|
popupStatus &&
|
||||||
|
multichainProductTourStep === 1 ? (
|
||||||
|
<ProductTour
|
||||||
|
className="multichain-app-header__product-tour"
|
||||||
|
anchorElement={menuRef.current}
|
||||||
|
title={t('switcherTitle')}
|
||||||
|
description={t('switcherTourDescription')}
|
||||||
|
currentStep="1"
|
||||||
|
totalSteps="3"
|
||||||
|
onClick={() =>
|
||||||
|
setMultichainProductTourStep(multichainProductTourStep + 1)
|
||||||
|
}
|
||||||
|
positionObj={productTourDirection === 'rtl' ? '0%' : '88%'}
|
||||||
|
productTourDirection={productTourDirection}
|
||||||
/>
|
/>
|
||||||
)}
|
) : null}
|
||||||
|
|
||||||
<AccountPicker
|
<AccountPicker
|
||||||
address={identity.address}
|
address={identity.address}
|
||||||
@ -143,8 +177,34 @@ export const AppHeader = ({ onClick }) => {
|
|||||||
justifyContent={JustifyContent.spaceBetween}
|
justifyContent={JustifyContent.spaceBetween}
|
||||||
>
|
>
|
||||||
{showStatus ? (
|
{showStatus ? (
|
||||||
<ConnectedStatusIndicator
|
<Box ref={menuRef}>
|
||||||
onClick={() => history.push(CONNECTED_ACCOUNTS_ROUTE)}
|
<ConnectedStatusIndicator
|
||||||
|
onClick={() => history.push(CONNECTED_ACCOUNTS_ROUTE)}
|
||||||
|
/>
|
||||||
|
</Box>
|
||||||
|
) : null}{' '}
|
||||||
|
{popupStatus && multichainProductTourStep === 2 ? (
|
||||||
|
<ProductTour
|
||||||
|
className="multichain-app-header__product-tour"
|
||||||
|
anchorElement={menuRef.current}
|
||||||
|
closeMenu={() => setAccountOptionsMenuOpen(false)}
|
||||||
|
prevIcon
|
||||||
|
title={t('permissionsTitle')}
|
||||||
|
description={t('permissionsTourDescription')}
|
||||||
|
currentStep="2"
|
||||||
|
totalSteps="3"
|
||||||
|
prevClick={() =>
|
||||||
|
setMultichainProductTourStep(
|
||||||
|
multichainProductTourStep - 1,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
onClick={() =>
|
||||||
|
setMultichainProductTourStep(
|
||||||
|
multichainProductTourStep + 1,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
positionObj={productTourDirection === 'rtl' ? '74%' : '12%'}
|
||||||
|
productTourDirection={productTourDirection}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
<Box
|
<Box
|
||||||
@ -176,6 +236,28 @@ export const AppHeader = ({ onClick }) => {
|
|||||||
closeMenu={() => setAccountOptionsMenuOpen(false)}
|
closeMenu={() => setAccountOptionsMenuOpen(false)}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
|
{showProductTour &&
|
||||||
|
popupStatus &&
|
||||||
|
multichainProductTourStep === 3 ? (
|
||||||
|
<ProductTour
|
||||||
|
className="multichain-app-header__product-tour"
|
||||||
|
anchorElement={menuRef.current}
|
||||||
|
closeMenu={() => setAccountOptionsMenuOpen(false)}
|
||||||
|
prevIcon
|
||||||
|
title={t('globalTitle')}
|
||||||
|
description={t('globalTourDescription')}
|
||||||
|
currentStep="3"
|
||||||
|
totalSteps="3"
|
||||||
|
prevClick={() =>
|
||||||
|
setMultichainProductTourStep(multichainProductTourStep - 1)
|
||||||
|
}
|
||||||
|
onClick={() => {
|
||||||
|
hideProductTour();
|
||||||
|
}}
|
||||||
|
positionObj={productTourDirection === 'rtl' ? '89%' : '0%'}
|
||||||
|
productTourDirection={productTourDirection}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
</Box>
|
</Box>
|
||||||
) : (
|
) : (
|
||||||
<Box
|
<Box
|
||||||
|
@ -30,15 +30,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&--avatar-network {
|
&--avatar-network {
|
||||||
background-color: transparent;
|
padding: 0; // TODO: Remove once https://github.com/MetaMask/metamask-extension/pull/17006 is merged
|
||||||
width: min-content;
|
|
||||||
padding: 8px;
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:active {
|
|
||||||
box-shadow: none;
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,6 +97,9 @@ describe('App Header', () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
appState: {
|
||||||
|
onboardedInThisUISession: false,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const mockStore = configureStore();
|
const mockStore = configureStore();
|
||||||
|
@ -11,3 +11,4 @@ export { AddressCopyButton } from './address-copy-button';
|
|||||||
export { MultichainConnectedSiteMenu } from './multichain-connected-site-menu';
|
export { MultichainConnectedSiteMenu } from './multichain-connected-site-menu';
|
||||||
export { NetworkListItem } from './network-list-item';
|
export { NetworkListItem } from './network-list-item';
|
||||||
export { NetworkListMenu } from './network-list-menu';
|
export { NetworkListMenu } from './network-list-menu';
|
||||||
|
export { ProductTour } from './product-tour-popover';
|
||||||
|
@ -14,3 +14,4 @@
|
|||||||
@import 'multichain-token-list-item/multichain-token-list-item';
|
@import 'multichain-token-list-item/multichain-token-list-item';
|
||||||
@import 'network-list-item/';
|
@import 'network-list-item/';
|
||||||
@import 'network-list-menu/';
|
@import 'network-list-menu/';
|
||||||
|
@import 'product-tour-popover/product-tour-popover';
|
||||||
|
1
ui/components/multichain/product-tour-popover/index.js
Normal file
1
ui/components/multichain/product-tour-popover/index.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { ProductTour } from './product-tour-popover';
|
@ -0,0 +1,179 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import classnames from 'classnames';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import Box from '../../ui/box/box';
|
||||||
|
import {
|
||||||
|
AlignItems,
|
||||||
|
BLOCK_SIZES,
|
||||||
|
BorderRadius,
|
||||||
|
BackgroundColor,
|
||||||
|
DISPLAY,
|
||||||
|
IconColor,
|
||||||
|
JustifyContent,
|
||||||
|
Size,
|
||||||
|
TextColor,
|
||||||
|
TextVariant,
|
||||||
|
TextAlign,
|
||||||
|
} from '../../../helpers/constants/design-system';
|
||||||
|
import {
|
||||||
|
ButtonBase,
|
||||||
|
ButtonIcon,
|
||||||
|
IconName,
|
||||||
|
Text,
|
||||||
|
} from '../../component-library';
|
||||||
|
import { useI18nContext } from '../../../hooks/useI18nContext';
|
||||||
|
import { Menu } from '../../ui/menu';
|
||||||
|
|
||||||
|
export const ProductTour = ({
|
||||||
|
className,
|
||||||
|
prevIcon,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
currentStep,
|
||||||
|
totalSteps,
|
||||||
|
positionObj = '5%',
|
||||||
|
closeMenu,
|
||||||
|
anchorElement,
|
||||||
|
onClick,
|
||||||
|
prevClick,
|
||||||
|
productTourDirection,
|
||||||
|
...props
|
||||||
|
}) => {
|
||||||
|
const t = useI18nContext();
|
||||||
|
return (
|
||||||
|
<Menu
|
||||||
|
className={classnames(
|
||||||
|
'multichain-product-tour-menu',
|
||||||
|
{
|
||||||
|
'multichain-product-tour-menu--rtl': productTourDirection === 'rtl',
|
||||||
|
},
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
anchorElement={anchorElement}
|
||||||
|
onHide={closeMenu}
|
||||||
|
data-testid="multichain-product-tour-menu-popover"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
className="multichain-product-tour-menu__container"
|
||||||
|
backgroundColor={BackgroundColor.infoDefault}
|
||||||
|
borderRadius={BorderRadius.LG}
|
||||||
|
padding={4}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
borderWidth={1}
|
||||||
|
className="multichain-product-tour-menu__arrow"
|
||||||
|
display={DISPLAY.FLEX}
|
||||||
|
justifyContent={JustifyContent.center}
|
||||||
|
alignItems={AlignItems.center}
|
||||||
|
style={{ right: positionObj }}
|
||||||
|
/>
|
||||||
|
<Box
|
||||||
|
display={DISPLAY.FLEX}
|
||||||
|
alignItems={AlignItems.center}
|
||||||
|
className="multichain-product-tour-menu__header"
|
||||||
|
>
|
||||||
|
{prevIcon ? (
|
||||||
|
<ButtonIcon
|
||||||
|
iconName={IconName.ArrowLeft}
|
||||||
|
size={Size.SM}
|
||||||
|
color={IconColor.infoInverse}
|
||||||
|
onClick={prevClick}
|
||||||
|
className="multichain-product-tour-menu__previous-icon"
|
||||||
|
data-testid="multichain-product-tour-menu-popover-prevIcon"
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
<Text
|
||||||
|
textAlign={TextAlign.Center}
|
||||||
|
variant={TextVariant.headingSm}
|
||||||
|
width={BLOCK_SIZES.FULL}
|
||||||
|
color={TextColor.infoInverse}
|
||||||
|
>
|
||||||
|
{title}
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
|
<Text
|
||||||
|
paddingBottom={2}
|
||||||
|
paddingTop={2}
|
||||||
|
color={TextColor.infoInverse}
|
||||||
|
variant={TextVariant.bodyMd}
|
||||||
|
>
|
||||||
|
{description}
|
||||||
|
</Text>
|
||||||
|
<Box
|
||||||
|
display={DISPLAY.FLEX}
|
||||||
|
alignItems={AlignItems.center}
|
||||||
|
justifyContent={JustifyContent.spaceBetween}
|
||||||
|
>
|
||||||
|
<Text
|
||||||
|
paddingBottom={2}
|
||||||
|
paddingTop={2}
|
||||||
|
color={TextColor.infoInverse}
|
||||||
|
variant={TextVariant.bodyMd}
|
||||||
|
>
|
||||||
|
{currentStep}/{totalSteps}
|
||||||
|
</Text>
|
||||||
|
<ButtonBase
|
||||||
|
backgroundColor={BackgroundColor.primaryInverse}
|
||||||
|
color={TextColor.primaryDefault}
|
||||||
|
className="multichain-product-tour-menu__button"
|
||||||
|
onClick={onClick}
|
||||||
|
>
|
||||||
|
{t('recoveryPhraseReminderConfirm')}
|
||||||
|
</ButtonBase>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Menu>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
ProductTour.propTypes = {
|
||||||
|
/**
|
||||||
|
* The element that the menu should display next to
|
||||||
|
*/
|
||||||
|
anchorElement: PropTypes.instanceOf(window.Element),
|
||||||
|
/**
|
||||||
|
* Function that closes this menu
|
||||||
|
*/
|
||||||
|
closeMenu: PropTypes.func.isRequired,
|
||||||
|
/**
|
||||||
|
* Additional classNames to be added
|
||||||
|
*/
|
||||||
|
className: PropTypes.string,
|
||||||
|
/**
|
||||||
|
* Boolean to decide whether to show prevIcon or not
|
||||||
|
*/
|
||||||
|
prevIcon: PropTypes.bool,
|
||||||
|
/**
|
||||||
|
* Title of the popover
|
||||||
|
*/
|
||||||
|
title: PropTypes.string,
|
||||||
|
/**
|
||||||
|
* Description of the popover
|
||||||
|
*/
|
||||||
|
description: PropTypes.string,
|
||||||
|
/**
|
||||||
|
* Current step in the product tour
|
||||||
|
*/
|
||||||
|
currentStep: PropTypes.string,
|
||||||
|
/**
|
||||||
|
* Total steps in the product tour
|
||||||
|
*/
|
||||||
|
totalSteps: PropTypes.string,
|
||||||
|
/**
|
||||||
|
* PositionObj to decide the position of the popover tip
|
||||||
|
*/
|
||||||
|
positionObj: PropTypes.string,
|
||||||
|
/**
|
||||||
|
* The onClick handler to be passed
|
||||||
|
*/
|
||||||
|
onClick: PropTypes.func,
|
||||||
|
/**
|
||||||
|
* The handler to be passed to prevIcon
|
||||||
|
*/
|
||||||
|
prevClick: PropTypes.func,
|
||||||
|
/**
|
||||||
|
* Direction to determine the css for menu component
|
||||||
|
*/
|
||||||
|
productTourDirection: PropTypes.string,
|
||||||
|
};
|
@ -0,0 +1,57 @@
|
|||||||
|
.multichain-product-tour-menu {
|
||||||
|
width: 344px;
|
||||||
|
box-shadow: none;
|
||||||
|
left: -7px !important;
|
||||||
|
top: 10px !important; //important is required here since Menu has absolute position added via inline style in base component.
|
||||||
|
|
||||||
|
&--rtl {
|
||||||
|
left: 6px !important;
|
||||||
|
right: 6px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__arrow,
|
||||||
|
&__arrow::before {
|
||||||
|
position: absolute;
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
background: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__arrow {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
visibility: hidden;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__arrow::before {
|
||||||
|
display: block;
|
||||||
|
background-color: inherit;
|
||||||
|
visibility: visible;
|
||||||
|
content: '';
|
||||||
|
transform: rotate(45deg);
|
||||||
|
border-radius: 2px 0 0 0;
|
||||||
|
top: -7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__header {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__previous-icon {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__button {
|
||||||
|
&:hover {
|
||||||
|
color: var(--color-primary-default);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
opacity: 0.5;
|
||||||
|
background-color: var(--color-primary-inverse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { ProductTour } from './product-tour-popover';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Components/Multichain/ProductTour',
|
||||||
|
component: ProductTour,
|
||||||
|
argTypes: {
|
||||||
|
prevIcon: {
|
||||||
|
control: 'boolean',
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
control: 'text',
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
control: 'text',
|
||||||
|
},
|
||||||
|
currentStep: {
|
||||||
|
control: 'text',
|
||||||
|
},
|
||||||
|
totalSteps: {
|
||||||
|
control: 'text',
|
||||||
|
},
|
||||||
|
positionObj: {
|
||||||
|
control: 'text',
|
||||||
|
},
|
||||||
|
onClick: {
|
||||||
|
action: 'onClick',
|
||||||
|
},
|
||||||
|
onHide: {
|
||||||
|
action: 'onHide',
|
||||||
|
},
|
||||||
|
closeMenu: {
|
||||||
|
action: 'closeMenu',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
args: {
|
||||||
|
prevIcon: true,
|
||||||
|
title: 'Permissions',
|
||||||
|
description: 'Find your connected accounts and manage permissions here.',
|
||||||
|
currentStep: '1',
|
||||||
|
totalSteps: '3',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const Template = (args) => {
|
||||||
|
return <ProductTour {...args} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DefaultStory = Template.bind({});
|
||||||
|
|
||||||
|
export const CustomPopoverTipPosition = Template.bind({});
|
||||||
|
CustomPopoverTipPosition.args = {
|
||||||
|
positionObj: '80%',
|
||||||
|
};
|
@ -0,0 +1,30 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { render } from '@testing-library/react';
|
||||||
|
|
||||||
|
import { ProductTour } from './product-tour-popover';
|
||||||
|
|
||||||
|
describe('DetectedTokensBanner', () => {
|
||||||
|
const props = {
|
||||||
|
title: 'Permissions',
|
||||||
|
description: 'Find your connected accounts and manage permissions here.',
|
||||||
|
currentStep: '1',
|
||||||
|
totalSteps: '3',
|
||||||
|
};
|
||||||
|
it('should render correctly', () => {
|
||||||
|
const { getByTestId } = render(
|
||||||
|
<ProductTour anchorElement={document.body} {...props} />,
|
||||||
|
);
|
||||||
|
const menuContainer = getByTestId('multichain-product-tour-menu-popover');
|
||||||
|
expect(menuContainer).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render prev Icon', () => {
|
||||||
|
const { getByTestId } = render(
|
||||||
|
<ProductTour anchorElement={document.body} {...props} prevIcon />,
|
||||||
|
);
|
||||||
|
const prevIcon = getByTestId(
|
||||||
|
'multichain-product-tour-menu-popover-prevIcon',
|
||||||
|
);
|
||||||
|
expect(prevIcon).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
@ -11,6 +11,9 @@
|
|||||||
@import '../components/component-library/component-library-components.scss';
|
@import '../components/component-library/component-library-components.scss';
|
||||||
@import '../components/app/app-components';
|
@import '../components/app/app-components';
|
||||||
@import '../components/ui/ui-components';
|
@import '../components/ui/ui-components';
|
||||||
|
///: BEGIN:ONLY_INCLUDE_IN(mmi)
|
||||||
|
@import '../components/institutional/institutional-components';
|
||||||
|
///: END:ONLY_INCLUDE_IN
|
||||||
@import '../components/multichain/multichain-components.scss';
|
@import '../components/multichain/multichain-components.scss';
|
||||||
@import '../pages/pages';
|
@import '../pages/pages';
|
||||||
@import './errors.scss';
|
@import './errors.scss';
|
||||||
|
@ -20,8 +20,12 @@ export const SUPPORT_REQUEST_LINK = _supportRequestLink;
|
|||||||
export const CONTRACT_ADDRESS_LINK = _contractAddressLink;
|
export const CONTRACT_ADDRESS_LINK = _contractAddressLink;
|
||||||
export const PASSWORD_MIN_LENGTH = 8;
|
export const PASSWORD_MIN_LENGTH = 8;
|
||||||
export const OUTDATED_BROWSER_VERSIONS = {
|
export const OUTDATED_BROWSER_VERSIONS = {
|
||||||
chrome: '<80',
|
// Chrome and Edge should match the latest Chrome version released ~2 years ago
|
||||||
edge: '<80',
|
chrome: '<90',
|
||||||
firefox: '<78',
|
edge: '<90',
|
||||||
opera: '<67',
|
// Firefox should match the most recent end-of-life extended support release
|
||||||
|
firefox: '<91',
|
||||||
|
// Opera should be set to the equivalent of the Chrome version set
|
||||||
|
// See https://en.wikipedia.org/wiki/History_of_the_Opera_web_browser
|
||||||
|
opera: '<76',
|
||||||
};
|
};
|
||||||
|
@ -367,7 +367,7 @@ export const PERMISSION_DESCRIPTIONS = deepFreeze({
|
|||||||
label: t('permission_ethereumProvider'),
|
label: t('permission_ethereumProvider'),
|
||||||
description: t('permission_ethereumProviderDescription'),
|
description: t('permission_ethereumProviderDescription'),
|
||||||
leftIcon: ICON_NAMES.ETHEREUM,
|
leftIcon: ICON_NAMES.ETHEREUM,
|
||||||
weight: 1,
|
weight: 2,
|
||||||
id: 'ethereum-provider-access',
|
id: 'ethereum-provider-access',
|
||||||
message: t('ethereumProviderAccess', [targetSubjectMetadata?.origin]),
|
message: t('ethereumProviderAccess', [targetSubjectMetadata?.origin]),
|
||||||
}),
|
}),
|
||||||
|
@ -204,56 +204,56 @@ describe('util', () => {
|
|||||||
});
|
});
|
||||||
it('should return false when given a modern chrome browser', () => {
|
it('should return false when given a modern chrome browser', () => {
|
||||||
const browser = Bowser.getParser(
|
const browser = Bowser.getParser(
|
||||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.2623.112 Safari/537.36',
|
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.2623.112 Safari/537.36',
|
||||||
);
|
);
|
||||||
const result = util.getIsBrowserDeprecated(browser);
|
const result = util.getIsBrowserDeprecated(browser);
|
||||||
expect(result).toStrictEqual(false);
|
expect(result).toStrictEqual(false);
|
||||||
});
|
});
|
||||||
it('should return true when given an outdated chrome browser', () => {
|
it('should return true when given an outdated chrome browser', () => {
|
||||||
const browser = Bowser.getParser(
|
const browser = Bowser.getParser(
|
||||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.2623.112 Safari/537.36',
|
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.2623.112 Safari/537.36',
|
||||||
);
|
);
|
||||||
const result = util.getIsBrowserDeprecated(browser);
|
const result = util.getIsBrowserDeprecated(browser);
|
||||||
expect(result).toStrictEqual(true);
|
expect(result).toStrictEqual(true);
|
||||||
});
|
});
|
||||||
it('should return false when given a modern firefox browser', () => {
|
it('should return false when given a modern firefox browser', () => {
|
||||||
const browser = Bowser.getParser(
|
const browser = Bowser.getParser(
|
||||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Firefox/78.0',
|
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Firefox/91.0',
|
||||||
);
|
);
|
||||||
const result = util.getIsBrowserDeprecated(browser);
|
const result = util.getIsBrowserDeprecated(browser);
|
||||||
expect(result).toStrictEqual(false);
|
expect(result).toStrictEqual(false);
|
||||||
});
|
});
|
||||||
it('should return true when given an outdated firefox browser', () => {
|
it('should return true when given an outdated firefox browser', () => {
|
||||||
const browser = Bowser.getParser(
|
const browser = Bowser.getParser(
|
||||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:75.0) Gecko/20100101 Firefox/75.0',
|
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:75.0) Gecko/20100101 Firefox/90.0',
|
||||||
);
|
);
|
||||||
const result = util.getIsBrowserDeprecated(browser);
|
const result = util.getIsBrowserDeprecated(browser);
|
||||||
expect(result).toStrictEqual(true);
|
expect(result).toStrictEqual(true);
|
||||||
});
|
});
|
||||||
it('should return false when given a modern opera browser', () => {
|
it('should return false when given a modern opera browser', () => {
|
||||||
const browser = Bowser.getParser(
|
const browser = Bowser.getParser(
|
||||||
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_16_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.3578.98 Safari/537.36 OPR/68.0.3135.47',
|
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_16_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.3578.98 Safari/537.36 OPR/76.0.3135.47',
|
||||||
);
|
);
|
||||||
const result = util.getIsBrowserDeprecated(browser);
|
const result = util.getIsBrowserDeprecated(browser);
|
||||||
expect(result).toStrictEqual(false);
|
expect(result).toStrictEqual(false);
|
||||||
});
|
});
|
||||||
it('should return true when given an outdated opera browser', () => {
|
it('should return true when given an outdated opera browser', () => {
|
||||||
const browser = Bowser.getParser(
|
const browser = Bowser.getParser(
|
||||||
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_16_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36 OPR/58.0.3135.47',
|
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_16_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.3578.98 Safari/537.36 OPR/58.0.3135.47',
|
||||||
);
|
);
|
||||||
const result = util.getIsBrowserDeprecated(browser);
|
const result = util.getIsBrowserDeprecated(browser);
|
||||||
expect(result).toStrictEqual(true);
|
expect(result).toStrictEqual(true);
|
||||||
});
|
});
|
||||||
it('should return false when given a modern edge browser', () => {
|
it('should return false when given a modern edge browser', () => {
|
||||||
const browser = Bowser.getParser(
|
const browser = Bowser.getParser(
|
||||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.3578.98 Safari/537.36 Edg/81.0.416.68',
|
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.3578.98 Safari/537.36 Edg/90.0.416.68',
|
||||||
);
|
);
|
||||||
const result = util.getIsBrowserDeprecated(browser);
|
const result = util.getIsBrowserDeprecated(browser);
|
||||||
expect(result).toStrictEqual(false);
|
expect(result).toStrictEqual(false);
|
||||||
});
|
});
|
||||||
it('should return true when given an outdated edge browser', () => {
|
it('should return true when given an outdated edge browser', () => {
|
||||||
const browser = Bowser.getParser(
|
const browser = Bowser.getParser(
|
||||||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36 Edge/71.0.416.68',
|
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.3578.98 Safari/537.36 Edge/89.0.416.68',
|
||||||
);
|
);
|
||||||
const result = util.getIsBrowserDeprecated(browser);
|
const result = util.getIsBrowserDeprecated(browser);
|
||||||
expect(result).toStrictEqual(true);
|
expect(result).toStrictEqual(true);
|
||||||
|
@ -1041,6 +1041,9 @@ export function getShowBetaHeader(state) {
|
|||||||
return state.metamask.showBetaHeader;
|
return state.metamask.showBetaHeader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getShowProductTour(state) {
|
||||||
|
return state.metamask.showProductTour;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* To get the useTokenDetection flag which determines whether a static or dynamic token list is used
|
* To get the useTokenDetection flag which determines whether a static or dynamic token list is used
|
||||||
*
|
*
|
||||||
@ -1420,6 +1423,10 @@ export function getCustomTokenAmount(state) {
|
|||||||
return state.appState.customTokenAmount;
|
return state.appState.customTokenAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getOnboardedInThisUISession(state) {
|
||||||
|
return state.appState.onboardedInThisUISession;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* To get the useCurrencyRateCheck flag which to check if the user prefers currency conversion
|
* To get the useCurrencyRateCheck flag which to check if the user prefers currency conversion
|
||||||
*
|
*
|
||||||
|
@ -4560,6 +4560,10 @@ export function hideBetaHeader() {
|
|||||||
return submitRequestToBackground('setShowBetaHeader', [false]);
|
return submitRequestToBackground('setShowBetaHeader', [false]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function hideProductTour() {
|
||||||
|
return submitRequestToBackground('setShowProductTour', [false]);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: codeword NOT_A_THUNK @brad-decker
|
// TODO: codeword NOT_A_THUNK @brad-decker
|
||||||
export function setTransactionSecurityCheckEnabled(
|
export function setTransactionSecurityCheckEnabled(
|
||||||
transactionSecurityCheckEnabled: boolean,
|
transactionSecurityCheckEnabled: boolean,
|
||||||
|
Loading…
Reference in New Issue
Block a user