Merge remote-tracking branch 'origin/develop' into yushi/fix-sign-tx
# Conflicts: # packages/yoroi-extension/package-lock.json
# Conflicts: # packages/yoroi-extension/package-lock.json
name: SonarQube Checks
on:
# Trigger analysis when pushing to your main branches, and when creating a pull request.
push:
branches:
- main
- master
- develop
- 'releases/**'
pull_request:
types: [opened, synchronize, reopened]
jobs:
sonarqube:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
# Disabling shallow clone is recommended for improving relevancy of reporting
fetch-depth: 0
- name: SonarQube Scan
uses: sonarsource/sonarqube-scan-action@master
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
if: github.event.review && (github.event.review.state == 'approved' || contains(github.event.review.body, '/check') || contains(github.event.review.body, '/release-check'))
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Read .nvmrc
run: echo ::set-output name=NVMRC::$(cat .nvmrc)
id: nvm
run: echo "NVMRC=$(cat .nvmrc)" >> $GITHUB_OUTPUT
- name: Setup node
uses: actions/setup-node@v1
uses: actions/setup-node@v3
with:
node-version: '${{ steps.nvm.outputs.NVMRC }}'
- name: Cache node modules
# https://docs.github.com/en/actions/guides/caching-dependencies-to-speed-up-workflows
uses: actions/cache@v2
uses: actions/cache@v3
env:
cache-name: cache-yoroi-extension-node-modules
with:
${{ runner.os }}-build-${{ env.cache-name }}-
${{ runner.os }}-build-
${{ runner.os }}-
- name: npm install
run: |
. install-all.sh
- name: tests
run: |
npm run test
matrix:
browser: ['chrome', 'firefox']
fail-fast: false
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Forcefully update the Chrome browser
if: matrix.browser=='chrome'
run: brew update && brew upgrade --cask google-chrome
- name: Forcefully install Firefox for Developers browser
if: matrix.browser=='firefox'
run: |
brew update
brew tap homebrew/cask-versions && brew install --cask firefox-developer-edition
echo "FIREFOX_DEV=/Applications/Firefox Developer Edition.app/Contents/MacOS/firefox-bin" >> $GITHUB_ENV
- name: Read .nvmrc
run: echo ::set-output name=NVMRC::$(cat .nvmrc)
id: nvm
run: echo "NVMRC=$(cat .nvmrc)" >> $GITHUB_OUTPUT
- name: Setup node
uses: actions/setup-node@v1
uses: actions/setup-node@v3
with:
node-version: '${{ steps.nvm.outputs.NVMRC }}'
- name: Cache extension node modules
# https://docs.github.com/en/actions/guides/caching-dependencies-to-speed-up-workflows
uses: actions/cache@v2
uses: actions/cache@v3
env:
cache-name: cache-yoroi-extension-node-modules
with:
${{ runner.os }}-build-${{ env.cache-name }}-
${{ runner.os }}-build-
${{ runner.os }}-
- name: Cache connector node modules
# https://docs.github.com/en/actions/guides/caching-dependencies-to-speed-up-workflows
uses: actions/cache@v2
uses: actions/cache@v3
env:
cache-name: cache-yoroi-connector-node-modules
with:
${{ runner.os }}-build-${{ env.cache-name }}-
${{ runner.os }}-build-
${{ runner.os }}-
- name: npm install
run: |
. install-all.sh
- name: Build the test version
working-directory: ./packages/yoroi-extension
run: npm run test:build
- name: Create the report's folder
working-directory: ./packages/yoroi-extension
run: |
mkdir reports
touch ./reports/cucumberReports.json
- name: Run dapp connector tests
working-directory: ./packages/yoroi-extension
env:
MAILSAC_API_KEY: ${{ secrets.MAILSAC_API_KEY }}
run: npm run test:run:e2e:dApp:${{ matrix.browser }}
- name: Archive tests screenshots and logs
if: ${{ failure() }}
uses: actions/upload-artifact@v3
with:
name: testRunsData_${{ matrix.browser }}
name: testRunsData_E2E_tests_dApp_${{ matrix.browser }}
path: ./packages/yoroi-extension/testRunsData_${{ matrix.browser }}
Trezor_Model_T_emulator:
matrix:
browser: ['chrome', 'firefox']
fail-fast: false
steps:
- name: Forcefully update the Chrome browser
if: matrix.browser=='chrome'
- uses: actions/checkout@v3
- name: Read .nvmrc
run: echo ::set-output name=NVMRC::$(cat .nvmrc)
id: nvm
run: echo "NVMRC=$(cat .nvmrc)" >> $GITHUB_OUTPUT
- name: Setup node
uses: actions/setup-node@v3
with:
node-version: '${{ steps.nvm.outputs.NVMRC }}'
- name: Cache extension node modules
# https://docs.github.com/en/actions/guides/caching-dependencies-to-speed-up-workflows
uses: actions/cache@v3
run: |
. install-all.sh
- name: Build the test version using emulators
- name: Build the test version
working-directory: ./packages/yoroi-extension
run: npm run test:build
if: ${{ failure() }}
uses: actions/upload-artifact@v3
with:
name: testRunsData_${{ matrix.browser }}
name: testRunsData_Trezor_Model_T_emulator_${{ matrix.browser }}
path: ./packages/yoroi-extension/testRunsData_${{ matrix.browser }}
E2E_smoke_tests:
matrix:
browser: ['chrome', 'firefox']
fail-fast: false
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Forcefully update the Chrome browser
if: matrix.browser=='chrome'
run: |
echo "FIREFOX_DEV=/opt/firefoxdev/firefox-bin" >> $GITHUB_ENV
- name: Read .nvmrc
run: echo ::set-output name=NVMRC::$(cat .nvmrc)
id: nvm
run: echo "NVMRC=$(cat .nvmrc)" >> $GITHUB_OUTPUT
- name: Setup node
uses: actions/setup-node@v2
uses: actions/setup-node@v3
with:
node-version: '${{ steps.nvm.outputs.NVMRC }}'
- name: Cache extension node modules
# https://docs.github.com/en/actions/guides/caching-dependencies-to-speed-up-workflows
uses: actions/cache@v2
uses: actions/cache@v3
env:
cache-name: cache-yoroi-extension-node-modules
with:
- name: Cache connector node modules
# https://docs.github.com/en/actions/guides/caching-dependencies-to-speed-up-workflows
| Firefox | Chrome | Edge |
|---|----|----|
| [<img src="https://pbs.twimg.com/profile_images/1399715004010532871/H_xS5LMU_400x400.jpg" width="48">](https://addons.mozilla.org/en-US/firefox/addon/yoroi/) | [<img src="https://pbs.twimg.com/profile_images/1037025533182193664/aCWlGSZF_400x400.jpg" width="48">](https://chrome.google.com/webstore/detail/yoroi/ffnbelfdoeiohenkjibnmadjiehjhajb) | [<img src="https://pbs.twimg.com/profile_images/1314301428995743750/xnhDug3t_400x400.jpg" width="48">](https://microsoftedge.microsoft.com/addons/detail/yoroi/akoiaibnepcedcplijmiamnaigbepmcb) |
| [<img src="https://img.icons8.com/external-those-icons-flat-those-icons/96/external-Firefox-logos-and-brands-those-icons-flat-those-icons.png" width="50">](https://addons.mozilla.org/en-US/firefox/addon/yoroi/) | [<img src="https://img.icons8.com/fluency/96/chrome.png" width="60">](https://chrome.google.com/webstore/detail/yoroi/ffnbelfdoeiohenkjibnmadjiehjhajb) | [<img src="https://img.icons8.com/color/64/ms-edge-new.png" width="60">](https://microsoftedge.microsoft.com/addons/detail/yoroi/akoiaibnepcedcplijmiamnaigbepmcb) |
Looking for Yoroi Mobile? See [here](https://github.com/Emurgo/yoroi-mobile)
import { Bech32Prefix } from "../../yoroi-extension/app/config/stringConfig";
import { bytesToHex, hexToBytes } from "./coreUtils";
const cardanoAccessBtnRow = document.querySelector("#request-button-row");
const cardanoAuthCheck = document.querySelector("#check-identification");
const cardanoAccessBtn = document.querySelector("#request-access");
const connectionStatus = document.querySelector("#connection-status");
const walletPlateSpan = document.querySelector("#wallet-plate");
const walletIconSpan = document.querySelector("#wallet-icon");
const getUnUsedAddresses = document.querySelector("#get-unused-addresses");
const getUsedAddresses = document.querySelector("#get-used-addresses");
const getChangeAddress = document.querySelector("#get-change-address");
const getRewardAddresses = document.querySelector("#get-reward-addresses");
const getAccountBalance = document.querySelector("#get-balance");
const isEnabledBtn = document.querySelector("#is-enabled");
const getUtxos = document.querySelector("#get-utxos");
const submitTx = document.querySelector("#submit-tx");
const signTx = document.querySelector("#sign-tx");
const showUtxos = document.querySelector("#show-utxos");
const createTx = document.querySelector("#create-tx");
const getCollateralUtxos = document.querySelector("#get-collateral-utxos");
const signData = document.querySelector("#sign-data");
const alertEl = document.querySelector("#alert");
const spinner = document.querySelector("#spinner");
const utxosContainer = document.querySelector("#utxos");
const getNFTs = document.getElementById("nfts");
const getNetworkId = document.getElementById("get-network-id");
const get = (selector) => document.querySelector(selector);
const getAll = (selector) => document.querySelectorAll(selector);
const cardanoAccessBtnRow = get("#request-button-row");
const cardanoAuthCheck = get("#check-identification");
const cardanoAccessBtn = get("#request-access");
const connectionStatus = get("#connection-status");
const walletPlateSpan = get("#wallet-plate");
const walletIconSpan = get("#wallet-icon");
const getUnUsedAddresses = get("#get-unused-addresses");
const getUsedAddresses = get("#get-used-addresses");
const getChangeAddress = get("#get-change-address");
const getRewardAddresses = get("#get-reward-addresses");
const getAccountBalance = get("#get-balance");
const isEnabledBtn = get("#is-enabled");
const getUtxos = get("#get-utxos");
const submitTx = get("#submit-tx");
const signTx = get("#sign-tx");
const showUtxos = get("#show-utxos");
const getCollateralUtxos = get("#get-collateral-utxos");
const signData = get("#sign-data");
const alertEl = get("#alert");
const spinner = get("#spinner");
const utxosContainer = get("#utxos");
const getNFTs = get("#nfts");
const getNetworkId = get("#get-network-id");
let accessGranted = false;
let cardanoApi;
function alertError(text) {
toggleSpinner("hide");
alertEl.className = "alert alert-danger overflow-scroll";
alertEl.className = "alert alert-danger overflow-auto";
alertEl.innerHTML = text;
}
function alertSuccess(text) {
alertEl.className = "alert alert-success overflow-scroll";
alertEl.className = "alert alert-success overflow-auto";
alertEl.innerHTML = text;
}
let utxosHTML = "";
for (let idx in utxos) {
const utxo = utxos[idx];
const amountInADA = Number(utxo.amount) / 1000000;
const numOfAssets = utxo.assets.length;
utxosHTML += `
<li id='${idx}' class="utxo-item list-group-item d-flex justify-content-between align-items-center ${
selectedUtxoIdx == idx && "bg-primary text-white"
}" style='cursor: pointer;'>
<p id='${idx}' class='mb-0'>${utxo.utxo_id.slice(0, 50)}</p>
<span class="badge bg-primary rounded-pill">${utxo.amount}</span>
<p id='${idx}' class='mb-0'>${utxo.utxo_id.slice(0, 25)}</p>
<div>
${numOfAssets ? `<span class="badge bg-primary rounded-pill">${utxo.assets.length} Assets</span>` : ''}
<span class="badge bg-primary rounded-pill">${amountInADA} ADA</span>
</div>
</li>
`;
}
utxosHTML += `
<input class="w-100 mt-3 p-1" placeholder="Receiver addresss..." type="text" id="create-tx-receiver" />
<button id="create-tx" class="btn btn-light mt-3 w-100">[Experimental] Create Tx</button>
`;
utxosContainer.innerHTML = utxosHTML;
"mb-5"
);
// Add select utxo handler for each list item
document.querySelectorAll(".utxo-item").forEach((el) => {
getAll(".utxo-item").forEach((el) => {
el.addEventListener("click", selectUtxo);
});
// Add event handler for create tx button
document
.querySelector("#create-tx")
.addEventListener("click", createTxHandler);
get("#create-tx").addEventListener("click", createTxHandler);
}
function createTxHandler(e) {
const selectedUtxo = utxos[selectedUtxoIdx];
if (!selectedUtxo) {
alertError("Failed to select a random utxo from the available list!");
alertError("No utxo selected");
return;
}
expectedPolicyId,
});
let receiver = get('#create-tx-receiver').value || selectedUtxo.receiver;
const outputHex = bytesToHex(
CardanoWasm.TransactionOutput.new(
CardanoWasm.Address.from_bech32(selectedUtxo.receiver),
CardanoWasm.Address.from_bech32(receiver),
CardanoWasm.Value.new(CardanoWasm.BigNum.from_str("1000000"))
).to_bytes()
);
const includeOutputs = [];
const includeTargets = [];
let targetAddress = selectedUtxo.receiver;
let targetAddress = receiver;
let targetDataHash = null;
/****** FLAGS ******/
console.log("[createTx] Including asset:", asset);
txReq.includeTargets.push({
// do not specify value, the connector will use minimum value
address: selectedUtxo.receiver,
address: receiver,
assets: {
[asset.assetId]: "1",
},
address = addressToCbor(address);
}
const payload = document.querySelector("#sign-data-payload").value;
const payload = get("#sign-data-payload").value;
let payloadHex;
if (payload.startsWith("0x")) {
payloadHex = Buffer.from(payload.replace("^0x", ""), "hex").toString("hex");
);
}
window.onload = () => {
const onload = () => {
if (typeof window.cardano === "undefined") {
alertError("Cardano API not found");
} else {
);
}
};
setTimeout(onload, 100);
)
)}
/>
<Route
path={ROUTES.NFTS.ROOT}
component={(props) => (
)
)}
/>
<Route
exact
path={ROUTES.WALLETS.ADD}
path={ROUTES.SWITCH}
component={(props) => <WalletSwitch {...props} stores={stores} actions={actions} />}
/>
<Route
exact
path={ROUTES.REVAMP.CATALYST_VOTING}
component={(props) => <VotingPage {...props} stores={stores} actions={actions} />}
/>
<Redirect to={ROUTES.MY_WALLETS} />
</Switch>
</Suspense>
path={ROUTES.WALLETS.CATALYST_VOTING}
component={(props) => <VotingPage {...props} stores={stores} actions={actions} />}
/>
<Route
exact
path={ROUTES.REVAMP.TRANSFER}
component={(props) => <Transfer {...props} stores={stores} actions={actions} />}
/>
</Switch>
);
"NetworkId": 250,
"TokenId": 6,
},
Object {
"Digest": 6.262633522161549e-167,
"Identifier": "",
"IsDefault": true,
"IsNFT": false,
"Metadata": Object {
"assetName": "",
"longName": null,
"numberOfDecimals": 6,
"policyId": "",
"ticker": "TADA",
"type": "Cardano",
},
"NetworkId": 350,
"TokenId": 7,
},
],
},
Object {
"NetworkId": 250,
"TokenId": 6,
},
Object {
"Digest": 6.262633522161549e-167,
"Identifier": "",
"IsDefault": true,
"IsNFT": false,
"Metadata": Object {
"assetName": "",
"longName": null,
"numberOfDecimals": 6,
"policyId": "",
"ticker": "TADA",
"type": "Cardano",
},
"NetworkId": 350,
"TokenId": 7,
},
],
},
Object {
"NetworkId": 250,
"TokenId": 6,
},
Object {
"Digest": 6.262633522161549e-167,
"Identifier": "",
"IsDefault": true,
"IsNFT": false,
"Metadata": Object {
"assetName": "",
"longName": null,
"numberOfDecimals": 6,
"policyId": "",
"ticker": "TADA",
"type": "Cardano",
},
"NetworkId": 350,
"TokenId": 7,
},
],
},
Object {
"NetworkId": 250,
"TokenId": 6,
},
Object {
"Digest": 6.262633522161549e-167,
"Identifier": "",
"IsDefault": true,
"IsNFT": false,
"Metadata": Object {
"assetName": "",
"longName": null,
"numberOfDecimals": 6,
"policyId": "",
"ticker": "TADA",
"type": "Cardano",
},
"NetworkId": 350,
"TokenId": 7,
},
],
},
Object {
"NetworkId": 250,
"TokenId": 6,
},
Object {
"Digest": 6.262633522161549e-167,
"Identifier": "",
"IsDefault": true,
"IsNFT": false,
"Metadata": Object {
"assetName": "",
"longName": null,
"numberOfDecimals": 6,
"policyId": "",
"ticker": "TADA",
"type": "Cardano",
},
"NetworkId": 350,
"TokenId": 7,
},
],
},
Object {
Fork: CardanoForks.Haskell,
}: NetworkRow),
CardanoPreviewTestnet: ({
NetworkId: 3_00,
NetworkId: 3_50,
NetworkName: 'Cardano Preview Testnet',
Backend: {
BackendService: environment.isTest()
Object.freeze({
StartAt: 0,
ChainNetworkId: '0',
ByronNetworkId: 1,
GenesisDate: '1654041600000',
ByronNetworkId: 2,
GenesisDate: '1666656000000',
SlotsPerEpoch: 21600,
SlotDuration: 20,
}),
Object.freeze({
StartAt: 0,
SlotsPerEpoch: 432000,
SlotsPerEpoch: 86400,
SlotDuration: 1,
PerEpochPercentageReward: 69344,
LinearFee: {
"Name": "CardanoScan",
"NetworkId": 250,
},
Object {
"Endpoints": Object {
"address": "https://preview.cardanoscan.io/address/",
"pool": "https://preview.cardanoscan.io/pool/",
"stakeAddress": "https://preview.cardanoscan.io/stakeKey/",
"token": "https://preview.cardanoscan.io/token/",
"transaction": "https://preview.cardanoscan.io/transaction/",
},
"ExplorerId": 550,
"IsBackup": true,
"Name": "CardanoScan",
"NetworkId": 350,
},
Object {
"Endpoints": Object {
"address": "https://adastat.net/address/",
"NetworkId": 250,
"NetworkName": "Cardano Preprod Testnet",
},
Object {
"Backend": Object {
"BackendService": "https://preview-backend.emurgornd.com",
"TokenInfoService": "https://stage-cdn.yoroiwallet.com",
"WebSocket": "wss://preview-backend.emurgornd.com:443",
},
"BaseConfig": Array [
Object {
"ByronNetworkId": 2,
"ChainNetworkId": "0",
"GenesisDate": "1666656000000",
"SlotDuration": 20,
"SlotsPerEpoch": 21600,
"StartAt": 0,
},
Object {
"CoinsPerUtxoWord": "34482",
"KeyDeposit": "2000000",
"LinearFee": Object {
"coefficient": "44",
"constant": "155381",
},
"MinimumUtxoVal": "1000000",
"PerEpochPercentageReward": 69344,
"PoolDeposit": "500000000",
"SlotDuration": 1,
"SlotsPerEpoch": 86400,
"StartAt": 0,
},
],
"CoinType": 2147485463,
"Fork": 0,
"NetworkId": 350,
"NetworkName": "Cardano Preview Testnet",
},
],
"PreferredExplorer": Array [],
"PriceData": Array [],
"NetworkId": 250,
"TokenId": 6,
},
Object {
"Digest": 6.262633522161549e-167,
"Identifier": "",
"IsDefault": true,
"IsNFT": false,
"Metadata": Object {
"assetName": "",
"longName": null,
"numberOfDecimals": 6,
"policyId": "",
"ticker": "TADA",
"type": "Cardano",
},
"NetworkId": 350,
"TokenId": 7,
},
],
"TokenList": Array [],
"Transaction": Array [],
"NetworkId": 250,
"TokenId": 6,
},
Object {
"Digest": 6.262633522161549e-167,
"Identifier": "",
"IsDefault": true,
"IsNFT": false,
"Metadata": Object {
"assetName": "",
"longName": null,
"numberOfDecimals": 6,
"policyId": "",
"ticker": "TADA",
"type": "Cardano",
},
"NetworkId": 350,
"TokenId": 7,
},
],
},
Object {
CATALYST_ROUND_INFO: networkForLocalStorage + '-CATALYST_ROUND_INFO',
// ========== CONNECTOR ========== //
ERGO_CONNECTOR_WHITELIST: 'connector_whitelist',
SELECTED_WALLET: 'SELECTED_WALLET',
};
export type SetCustomUserThemeRequest = {|
export type WalletsNavigation = {|
ergo: number[],
cardano: number[],
quickAccess: number[],
|}
/**
unsetUserTheme: void => Promise<void> = () => removeLocalItem(storageKeys.THEME);
// ========== Select Wallet ========== //
getSelectedWalletId: void => number | null = () => {
const id = localStorage.getItem(storageKeys.SELECTED_WALLET);
if (!id) return null
if (isNaN(Number(id))) throw new Error(`Invalid wallet Id: ${id}`);
return Number(id)
}
setSelectedWalletId: number => void = (id) => {
localStorage.setItem(storageKeys.SELECTED_WALLET, id.toString())
}
// ========== Custom User Theme ========== //
getCustomUserTheme: void => Promise<?string> = () => getLocalItem(storageKeys.CUSTOM_THEME);
if(Array.isArray(result)) return {
cardano: [],
ergo: [],
quickAccess: [],
}
return result
<svg width="24" height="24">
<g fill="none" fill-rule="evenodd">
<path d="M0 0h24v24H0z"/>
<path stroke="#6B7384" stroke-width="1.5" stroke-linejoin="round" d="M12 17l-5.87785252 3.0901699 1.12256994-6.5450849-4.75528258-4.63525494 6.5716389-.95491503L12 2l2.9389263 5.95491503 6.5716389.95491503-4.7552826 4.63525494 1.1225699 6.5450849z"/>
</g>
</svg>
\ No newline at end of file
<svg width="24" height="24">
<g fill="none" fill-rule="evenodd">
<path d="M0 0h24v24H0z"/>
<path stroke="#6B7384" stroke-width="1.5" fill="#6B7384" stroke-linejoin="round" d="M12 17l-5.87785252 3.0901699 1.12256994-6.5450849-4.75528258-4.63525494 6.5716389-.95491503L12 2l2.9389263 5.95491503 6.5716389.95491503-4.7552826 4.63525494 1.1225699 6.5450849z"/>
</g>
</svg>
\ No newline at end of file
theme.name === 'classic' ? { shrink: true, ...InputLabelProps } : { ...InputLabelProps }
}
InputProps={{
disableUnderline: revamp,
...(theme.name === 'classic' ? { notched: false } : {}),
endAdornment:
type === 'password' ? (
{Boolean(error) === true ? <ErrorIcon /> : done === true ? <DoneIcon /> : null}
</InputAdornment>
),
disableUnderline: revamp,
placeholder: placeholder != null ? placeholder : '',
}}
{...props}
type Props = {|
+currentTheme: Theme,
+selectTheme: ({| theme: string |}) => PossiblyAsync<void>,
+onSubmit: (theme: string) => PossiblyAsync<void>,
+onExternalLinkClick: MouseEvent => void,
+switchToFirstWallet: void => void,
|};
const NEW_THEME = THEMES.YOROI_REVAMP
render(): Node {
const {
currentTheme,
selectTheme,
onSubmit,
onExternalLinkClick,
} = this.props;
const { intl } = this.context;
value={currentTheme === NEW_THEME ? NEW_THEME : OLD_THEME}
onChange={(e) => {
const theme = e.target.value === NEW_THEME ? NEW_THEME : THEMES.YOROI_MODERN
selectTheme({ theme })
onSubmit(theme)
}}
sx={{
display: 'flex',
row
value={currentTheme}
onChange={(e) => {
selectTheme({ theme: e.target.value })
onSubmit(e.target.value)
}}
>
<Box sx={{ display: 'flex', flexDirection: 'column', justifyContent: 'flex-start', marginRight: '24px' }}>
// @flow
import { Component } from 'react';
import type { Node } from 'react';
import { observer } from 'mobx-react';
import styles from './NavDropdownContentRevamp.scss';
import { intlShape } from 'react-intl';
import type { $npm$ReactIntl$IntlFormat } from 'react-intl';
import globalMessages from '../../i18n/global-messages';
import { Button } from '@mui/material';
type Props = {|
+openWalletInfoDialog: void => void,
+contentComponents?: ?Node,
+walletsCount?: number,
|};
@observer
export default class NavDropdownContentRevamp extends Component<Props> {
static contextTypes: {| intl: $npm$ReactIntl$IntlFormat |} = {
intl: intlShape.isRequired,
};
static defaultProps: {| contentComponents: void, walletsCount: void |} = {
contentComponents: undefined,
walletsCount: undefined,
};
render(): Node {
const { contentComponents, walletsCount, openWalletInfoDialog } = this.props;
const { intl } = this.context;
return (
<div className={styles.wrapper}>
<div className={styles.card}>
{contentComponents}
<div className={styles.footer}>
<Button sx={{ width: '100%' }} onClick={() => openWalletInfoDialog()}>
{intl.formatMessage(globalMessages.allWalletsLabel)}{' '}
{walletsCount != null ? <span> ({walletsCount})</span> : null}
</Button>
</div>
</div>
</div>
);
}
}
.wrapper {
position: absolute;
padding-top: 33px;
top: 30px;
width: 100%;
right: 0;
z-index: 1;
}
.card {
overflow: hidden;
border-radius: 8px;
background-color: #FFF;
width: 100%;
border: 1px solid #eaedf2;
box-shadow: 0 10px 30px 0 rgba(24, 26, 30, 0.12);
}
.footer {
border-top: 1px solid #dce0e9;
display: flex;
justify-content: center;
button {
padding: 20px 0;
color: var(--yoroi-palette-secondary-300);
text-transform: uppercase;
font-size: 14px;
text-align: center;
font-weight: 500;
}
}
// @flow
import React, { Component } from 'react';
import type { Node, ElementRef } from 'react';
import { observer } from 'mobx-react';
import styles from './NavDropdownRevamp.scss';
import NavDropdownContentRevamp from './NavDropdownContentRevamp';
type Props = {|
+headerComponent?: ?Node,
+contentComponents?: ?Node,
+walletsCount?: number,
+openWalletInfoDialog: void => void,
|};
type State = {|
isExpanded: boolean,
|};
@observer
export default class NavDropdownRevamp extends Component<Props, State> {
static defaultProps: {| contentComponents: void, headerComponent: void, walletsCount: void |} = {
headerComponent: undefined,
contentComponents: undefined,
walletsCount: undefined,
};
state: State = {
isExpanded: false,
};
buttonRef: ?ElementRef<*>;
constructor(props: Props) {
super(props);
this.buttonRef = React.createRef();
}
toggleExpansion: void => void = () => {
this.setState(prevState => ({ isExpanded: !prevState.isExpanded }));
};
render(): Node {
const { headerComponent, contentComponents, walletsCount, openWalletInfoDialog } = this.props;
const { isExpanded } = this.state;
return (
<div
className={styles.wrapper}
onMouseEnter={this.toggleExpansion}
onMouseLeave={this.toggleExpansion}
>
<div className={styles.component}>{headerComponent}</div>
{isExpanded ? (
<NavDropdownContentRevamp
contentComponents={contentComponents}
walletsCount={walletsCount}
openWalletInfoDialog={openWalletInfoDialog}
/>
) : null}
</div>
);
}
}
Fixes #348
Fixes #347
Fixes #412
Fixes #347
Fixes #348
Fixes #347
From https://github.com/input-output-hk/ouroboros-network at ff2331f0d254944f7c375078e6a3eb8e4f8770db
From https://github.com/input-output-hk/ouroboros-network at ff2331f0d254944f7c375078e6a3eb8e4f8770db
Fixes #347
Fixes #347
Fixes #347