diff --git a/build-release.sh b/build-release.sh index 0424d18dd8..c584fdf506 100644 --- a/build-release.sh +++ b/build-release.sh @@ -4,6 +4,8 @@ elif [ $1 = "stable-mv2" ]; then RELEASE_TYPE="stable-mv2" elif [ $1 = "nightly" ]; then RELEASE_TYPE="nightly" +elif [ $1 = "nightly-mv2" ]; +then RELEASE_TYPE="nightly-mv2" else echo "First parameter is expected 'stable', 'stable-mv2', or 'nightly'" return 1 diff --git a/package.json b/package.json index c52ae6338f..397d64d3a8 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,8 @@ "flow": "lerna run flow --stream", "test": "lerna run test --stream", "translations:purge": "lerna run translations:purge -- stream", - "dev:all": "concurrently \"npm run dev:stable --prefix packages/yoroi-extension\" \"npm run cardano --prefix packages/yoroi-connector\" \"npm run ergo --prefix packages/yoroi-connector\" " + "dev:all": "concurrently \"npm run dev:stable --prefix packages/yoroi-extension\" \"npm run cardano --prefix packages/yoroi-connector\" ", + "archive:src": "func() { git rev-parse HEAD > COMMIT && git rev-parse --abbrev-ref HEAD > BRANCH && git archive --format zip --add-file COMMIT --add-file BRANCH -o $1 HEAD && rm COMMIT BRANCH; }; func" }, "husky": { "hooks": { diff --git a/packages/yoroi-extension/.eslintrc.js b/packages/yoroi-extension/.eslintrc.js index cc31d07c84..7ea95d166c 100644 --- a/packages/yoroi-extension/.eslintrc.js +++ b/packages/yoroi-extension/.eslintrc.js @@ -73,7 +73,7 @@ module.exports = { 'no-plusplus': 0, 'no-bitwise': 0, 'no-underscore-dangle': 0, - 'no-console': 1, + 'no-console': 0, 'no-mixed-operators': 0, 'no-multi-assign': 0, 'no-undef-init': 0, // need this to improve Flow type inference @@ -86,11 +86,11 @@ module.exports = { 'arrow-body-style': 0, 'key-spacing': 1, 'no-empty-function': 1, - 'max-len': 1, + 'max-len': ['warn', { code: 120 }], 'no-useless-escape': 1, 'prefer-const': 1, 'object-curly-spacing': 1, - 'spaced-comment': 1, + 'spaced-comment': 0, quotes: ['error', 'single', { avoidEscape: true, allowTemplateLiterals: true }], 'import/imports-first': 1, 'react/jsx-indent': 1, diff --git a/packages/yoroi-extension/.flowconfig b/packages/yoroi-extension/.flowconfig index dd79bc1a9d..022d677024 100644 --- a/packages/yoroi-extension/.flowconfig +++ b/packages/yoroi-extension/.flowconfig @@ -31,7 +31,7 @@ deprecated-utility=error [options] types_first=true -include_warnings=true +include_warnings=false esproposal.decorators=ignore module.ignore_non_literal_requires=true module.name_mapper.extension='scss' -> '/flow/mappers/CSSModule.js.flow' diff --git a/packages/yoroi-extension/ampli.json b/packages/yoroi-extension/ampli.json new file mode 100644 index 0000000000..12dc43a863 --- /dev/null +++ b/packages/yoroi-extension/ampli.json @@ -0,0 +1,14 @@ +{ + "Zone": "us", + "OrgId": "208651", + "WorkspaceId": "67ef75aa-dab0-42d1-969d-f186d253bda8", + "SourceId": "829bd2d4-930e-40f5-b717-a9ed8e1235e1", + "Runtime": "browser:typescript-ampli-v2", + "Platform": "Browser", + "Language": "TypeScript", + "SDK": "@amplitude/analytics-browser@^1.0", + "Branch": "main", + "Version": "7.0.0", + "VersionId": "a0985241-d0c0-4bda-bc6d-271830af0067", + "Path": "./ampli" +} \ No newline at end of file diff --git a/packages/yoroi-extension/ampli/README.md b/packages/yoroi-extension/ampli/README.md new file mode 100644 index 0000000000..2d4435f317 --- /dev/null +++ b/packages/yoroi-extension/ampli/README.md @@ -0,0 +1,38 @@ +The coerce the TypeScript Amplitude wrapper to work with flow, do these: + +``` +npm run metrics:pull +``` + +``` +cd ampli +``` + + +``` +npx -p typescript tsc index.ts --outDir . -d -m es6 +``` + +``` +npx flowgen --interface-records --no-inexact --add-flow-header -o index.js.flow index.d.ts +``` + +``` +sed -i 's/amplitude\.Types\.\w*/any/' index.js.flow +sed -i '/export type BaseEvent/d' index.js.flow + +``` + +Edit `ampli.js.flow` to add the line `class BaseEvent {}`. + +Then we have flow-typed ampli library where all event trigger functions are strongly typed. +To use this libray, import like this from source code: +``` +import type { LoadOptionsWithEnvironment } from '../../../ampli/index'; +``` +instead of +``` +import type { LoadOptionsWithEnvironment } from '../../../ampli'; +``` +Due to perhaps a bug in flow, the later short-circuits type checking. + diff --git a/packages/yoroi-extension/ampli/index.js b/packages/yoroi-extension/ampli/index.js new file mode 100644 index 0000000000..ed7971e639 --- /dev/null +++ b/packages/yoroi-extension/ampli/index.js @@ -0,0 +1,1233 @@ +/* tslint:disable */ +/* eslint-disable */ +// @ts-nocheck +/** + * Ampli - A strong typed wrapper for your Analytics + * + * This file is generated by Amplitude. + * To update run 'ampli pull extension' + * + * Required dependencies: @amplitude/analytics-browser@^1.3.0 + * Tracking Plan Version: 7 + * Build: 1.0.0 + * Runtime: browser:typescript-ampli-v2 + * + * [View Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest) + * + * [Full Setup Instructions](https://data.amplitude.com/emurgo/Yoroi/implementation/extension) + */ +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +import * as amplitude from '@amplitude/analytics-browser'; +export var ApiKey = { + production: 'd44950b777177c2ebee5f21f194c1231', + development: '52a980fd5fb8da5fc680687d7e991e18' +}; +/** + * Default Amplitude configuration options. Contains tracking plan information. + */ +export var DefaultConfiguration = __assign({ plan: { + version: '7', + branch: 'main', + source: 'extension', + versionId: 'a0985241-d0c0-4bda-bc6d-271830af0067' + } }, { + ingestionMetadata: { + sourceName: 'browser-typescript-ampli', + sourceVersion: '2.0.0' + } +}); +var AllWalletsPageViewed = /** @class */ (function () { + function AllWalletsPageViewed() { + this.event_type = 'All Wallets Page Viewed'; + } + return AllWalletsPageViewed; +}()); +export { AllWalletsPageViewed }; +var AssetsPageViewed = /** @class */ (function () { + function AssetsPageViewed() { + this.event_type = 'Assets Page Viewed'; + } + return AssetsPageViewed; +}()); +export { AssetsPageViewed }; +var ClaimAdaPageViewed = /** @class */ (function () { + function ClaimAdaPageViewed() { + this.event_type = 'Claim ADA Page Viewed'; + } + return ClaimAdaPageViewed; +}()); +export { ClaimAdaPageViewed }; +var ConnectorPageViewed = /** @class */ (function () { + function ConnectorPageViewed() { + this.event_type = 'Connector Page Viewed'; + } + return ConnectorPageViewed; +}()); +export { ConnectorPageViewed }; +var CreateWalletDetailsStepViewed = /** @class */ (function () { + function CreateWalletDetailsStepViewed() { + this.event_type = 'Create Wallet Details Step Viewed'; + } + return CreateWalletDetailsStepViewed; +}()); +export { CreateWalletDetailsStepViewed }; +var CreateWalletDetailsSubmitted = /** @class */ (function () { + function CreateWalletDetailsSubmitted() { + this.event_type = 'Create Wallet Details Submitted'; + } + return CreateWalletDetailsSubmitted; +}()); +export { CreateWalletDetailsSubmitted }; +var CreateWalletLanguagePageViewed = /** @class */ (function () { + function CreateWalletLanguagePageViewed() { + this.event_type = 'Create Wallet Language Page Viewed'; + } + return CreateWalletLanguagePageViewed; +}()); +export { CreateWalletLanguagePageViewed }; +var CreateWalletLearnPhraseStepViewed = /** @class */ (function () { + function CreateWalletLearnPhraseStepViewed() { + this.event_type = 'Create Wallet Learn Phrase Step Viewed'; + } + return CreateWalletLearnPhraseStepViewed; +}()); +export { CreateWalletLearnPhraseStepViewed }; +var CreateWalletSavePhraseStepViewed = /** @class */ (function () { + function CreateWalletSavePhraseStepViewed() { + this.event_type = 'Create Wallet Save Phrase Step Viewed'; + } + return CreateWalletSavePhraseStepViewed; +}()); +export { CreateWalletSavePhraseStepViewed }; +var CreateWalletSelectMethodPageViewed = /** @class */ (function () { + function CreateWalletSelectMethodPageViewed() { + this.event_type = 'Create Wallet Select Method Page Viewed'; + } + return CreateWalletSelectMethodPageViewed; +}()); +export { CreateWalletSelectMethodPageViewed }; +var CreateWalletTermsPageViewed = /** @class */ (function () { + function CreateWalletTermsPageViewed() { + this.event_type = 'Create Wallet Terms Page Viewed'; + } + return CreateWalletTermsPageViewed; +}()); +export { CreateWalletTermsPageViewed }; +var CreateWalletVerifyPhraseStepViewed = /** @class */ (function () { + function CreateWalletVerifyPhraseStepViewed() { + this.event_type = 'Create Wallet Verify Phrase Step Viewed'; + } + return CreateWalletVerifyPhraseStepViewed; +}()); +export { CreateWalletVerifyPhraseStepViewed }; +var CreateWalletVerifyPhraseWordSelected = /** @class */ (function () { + function CreateWalletVerifyPhraseWordSelected(event_properties) { + this.event_properties = event_properties; + this.event_type = 'Create Wallet Verify Phrase Word Selected'; + this.event_properties = event_properties; + } + return CreateWalletVerifyPhraseWordSelected; +}()); +export { CreateWalletVerifyPhraseWordSelected }; +var DappPopupAddCollateralPageViewed = /** @class */ (function () { + function DappPopupAddCollateralPageViewed() { + this.event_type = 'Dapp Popup Add Collateral Page Viewed'; + } + return DappPopupAddCollateralPageViewed; +}()); +export { DappPopupAddCollateralPageViewed }; +var DappPopupConnectWalletPageViewed = /** @class */ (function () { + function DappPopupConnectWalletPageViewed(event_properties) { + this.event_properties = event_properties; + this.event_type = 'Dapp Popup Connect Wallet Page Viewed'; + this.event_properties = event_properties; + } + return DappPopupConnectWalletPageViewed; +}()); +export { DappPopupConnectWalletPageViewed }; +var DappPopupConnectWalletPasswordPageViewed = /** @class */ (function () { + function DappPopupConnectWalletPasswordPageViewed() { + this.event_type = 'Dapp Popup Connect Wallet Password Page Viewed'; + } + return DappPopupConnectWalletPasswordPageViewed; +}()); +export { DappPopupConnectWalletPasswordPageViewed }; +var DappPopupSignTransactionPageViewed = /** @class */ (function () { + function DappPopupSignTransactionPageViewed() { + this.event_type = 'Dapp Popup Sign Transaction Page Viewed'; + } + return DappPopupSignTransactionPageViewed; +}()); +export { DappPopupSignTransactionPageViewed }; +var DappPopupSignTransactionSubmitted = /** @class */ (function () { + function DappPopupSignTransactionSubmitted() { + this.event_type = 'Dapp Popup Sign Transaction Submitted'; + } + return DappPopupSignTransactionSubmitted; +}()); +export { DappPopupSignTransactionSubmitted }; +var MenuPageViewed = /** @class */ (function () { + function MenuPageViewed() { + this.event_type = 'Menu Page Viewed'; + } + return MenuPageViewed; +}()); +export { MenuPageViewed }; +var NftGalleryDetailsImageViewed = /** @class */ (function () { + function NftGalleryDetailsImageViewed() { + this.event_type = 'NFT Gallery Details Image Viewed'; + } + return NftGalleryDetailsImageViewed; +}()); +export { NftGalleryDetailsImageViewed }; +var NftGalleryDetailsNavigation = /** @class */ (function () { + function NftGalleryDetailsNavigation(event_properties) { + this.event_properties = event_properties; + this.event_type = 'NFT Gallery Details Navigation'; + this.event_properties = event_properties; + } + return NftGalleryDetailsNavigation; +}()); +export { NftGalleryDetailsNavigation }; +var NftGalleryDetailsPageViewed = /** @class */ (function () { + function NftGalleryDetailsPageViewed() { + this.event_type = 'NFT Gallery Details Page Viewed'; + } + return NftGalleryDetailsPageViewed; +}()); +export { NftGalleryDetailsPageViewed }; +var NftGalleryDetailsTab = /** @class */ (function () { + function NftGalleryDetailsTab(event_properties) { + this.event_properties = event_properties; + this.event_type = 'NFT Gallery Details Tab'; + this.event_properties = event_properties; + } + return NftGalleryDetailsTab; +}()); +export { NftGalleryDetailsTab }; +var NftGalleryGridViewSelected = /** @class */ (function () { + function NftGalleryGridViewSelected(event_properties) { + this.event_properties = event_properties; + this.event_type = 'NFT Gallery Grid View Selected'; + this.event_properties = event_properties; + } + return NftGalleryGridViewSelected; +}()); +export { NftGalleryGridViewSelected }; +var NftGalleryPageViewed = /** @class */ (function () { + function NftGalleryPageViewed(event_properties) { + this.event_properties = event_properties; + this.event_type = 'NFT Gallery Page Viewed'; + this.event_properties = event_properties; + } + return NftGalleryPageViewed; +}()); +export { NftGalleryPageViewed }; +var NftGallerySearchActivated = /** @class */ (function () { + function NftGallerySearchActivated(event_properties) { + this.event_properties = event_properties; + this.event_type = 'NFT Gallery Search Activated'; + this.event_properties = event_properties; + } + return NftGallerySearchActivated; +}()); +export { NftGallerySearchActivated }; +var ReceivePageViewed = /** @class */ (function () { + function ReceivePageViewed() { + this.event_type = 'Receive Page Viewed'; + } + return ReceivePageViewed; +}()); +export { ReceivePageViewed }; +var RestoreWalletDetailsStepViewed = /** @class */ (function () { + function RestoreWalletDetailsStepViewed() { + this.event_type = 'Restore Wallet Details Step Viewed'; + } + return RestoreWalletDetailsStepViewed; +}()); +export { RestoreWalletDetailsStepViewed }; +var RestoreWalletDetailsSubmitted = /** @class */ (function () { + function RestoreWalletDetailsSubmitted() { + this.event_type = 'Restore Wallet Details Submitted'; + } + return RestoreWalletDetailsSubmitted; +}()); +export { RestoreWalletDetailsSubmitted }; +var RestoreWalletEnterPhraseStepStatus = /** @class */ (function () { + function RestoreWalletEnterPhraseStepStatus(event_properties) { + this.event_properties = event_properties; + this.event_type = 'Restore Wallet Enter Phrase Step Status'; + this.event_properties = event_properties; + } + return RestoreWalletEnterPhraseStepStatus; +}()); +export { RestoreWalletEnterPhraseStepStatus }; +var RestoreWalletEnterPhraseStepViewed = /** @class */ (function () { + function RestoreWalletEnterPhraseStepViewed(event_properties) { + this.event_properties = event_properties; + this.event_type = 'Restore Wallet Enter Phrase Step Viewed'; + this.event_properties = event_properties; + } + return RestoreWalletEnterPhraseStepViewed; +}()); +export { RestoreWalletEnterPhraseStepViewed }; +var RestoreWalletTypeStepViewed = /** @class */ (function () { + function RestoreWalletTypeStepViewed() { + this.event_type = 'Restore Wallet Type Step Viewed'; + } + return RestoreWalletTypeStepViewed; +}()); +export { RestoreWalletTypeStepViewed }; +var SendInitiated = /** @class */ (function () { + function SendInitiated() { + this.event_type = 'Send Initiated'; + } + return SendInitiated; +}()); +export { SendInitiated }; +var SendSelectAssetPageViewed = /** @class */ (function () { + function SendSelectAssetPageViewed() { + this.event_type = 'Send Select Asset Page Viewed'; + } + return SendSelectAssetPageViewed; +}()); +export { SendSelectAssetPageViewed }; +var SendSelectAssetSelected = /** @class */ (function () { + function SendSelectAssetSelected(event_properties) { + this.event_properties = event_properties; + this.event_type = 'Send Select Asset Selected'; + this.event_properties = event_properties; + } + return SendSelectAssetSelected; +}()); +export { SendSelectAssetSelected }; +var SendSelectAssetUpdated = /** @class */ (function () { + function SendSelectAssetUpdated(event_properties) { + this.event_properties = event_properties; + this.event_type = 'Send Select Asset Updated'; + this.event_properties = event_properties; + } + return SendSelectAssetUpdated; +}()); +export { SendSelectAssetUpdated }; +var SendSummaryPageViewed = /** @class */ (function () { + function SendSummaryPageViewed(event_properties) { + this.event_properties = event_properties; + this.event_type = 'Send Summary Page Viewed'; + this.event_properties = event_properties; + } + return SendSummaryPageViewed; +}()); +export { SendSummaryPageViewed }; +var SendSummarySubmitted = /** @class */ (function () { + function SendSummarySubmitted(event_properties) { + this.event_properties = event_properties; + this.event_type = 'Send Summary Submitted'; + this.event_properties = event_properties; + } + return SendSummarySubmitted; +}()); +export { SendSummarySubmitted }; +var SettingsPageViewed = /** @class */ (function () { + function SettingsPageViewed() { + this.event_type = 'Settings Page Viewed'; + } + return SettingsPageViewed; +}()); +export { SettingsPageViewed }; +var StakingCenterPageViewed = /** @class */ (function () { + function StakingCenterPageViewed() { + this.event_type = 'Staking Center Page Viewed'; + } + return StakingCenterPageViewed; +}()); +export { StakingCenterPageViewed }; +var StakingPageViewed = /** @class */ (function () { + function StakingPageViewed() { + this.event_type = 'Staking Page Viewed'; + } + return StakingPageViewed; +}()); +export { StakingPageViewed }; +var SwapAssetFromChanged = /** @class */ (function () { + function SwapAssetFromChanged(event_properties) { + this.event_properties = event_properties; + this.event_type = 'Swap Asset From Changed'; + this.event_properties = event_properties; + } + return SwapAssetFromChanged; +}()); +export { SwapAssetFromChanged }; +var SwapAssetToChanged = /** @class */ (function () { + function SwapAssetToChanged(event_properties) { + this.event_properties = event_properties; + this.event_type = 'Swap Asset To Changed'; + this.event_properties = event_properties; + } + return SwapAssetToChanged; +}()); +export { SwapAssetToChanged }; +var SwapCancelationSubmitted = /** @class */ (function () { + function SwapCancelationSubmitted(event_properties) { + this.event_properties = event_properties; + this.event_type = 'Swap Cancelation Submitted'; + this.event_properties = event_properties; + } + return SwapCancelationSubmitted; +}()); +export { SwapCancelationSubmitted }; +var SwapConfirmedPageViewed = /** @class */ (function () { + function SwapConfirmedPageViewed(event_properties) { + this.event_properties = event_properties; + this.event_type = 'Swap Confirmed Page Viewed'; + this.event_properties = event_properties; + } + return SwapConfirmedPageViewed; +}()); +export { SwapConfirmedPageViewed }; +var SwapInitiated = /** @class */ (function () { + function SwapInitiated(event_properties) { + this.event_properties = event_properties; + this.event_type = 'Swap Initiated'; + this.event_properties = event_properties; + } + return SwapInitiated; +}()); +export { SwapInitiated }; +var SwapOrderSelected = /** @class */ (function () { + function SwapOrderSelected(event_properties) { + this.event_properties = event_properties; + this.event_type = 'Swap Order Selected'; + this.event_properties = event_properties; + } + return SwapOrderSelected; +}()); +export { SwapOrderSelected }; +var SwapOrderSubmitted = /** @class */ (function () { + function SwapOrderSubmitted(event_properties) { + this.event_properties = event_properties; + this.event_type = 'Swap Order Submitted'; + this.event_properties = event_properties; + } + return SwapOrderSubmitted; +}()); +export { SwapOrderSubmitted }; +var SwapPoolChanged = /** @class */ (function () { + function SwapPoolChanged() { + this.event_type = 'Swap Pool Changed'; + } + return SwapPoolChanged; +}()); +export { SwapPoolChanged }; +var SwapSlippageChanged = /** @class */ (function () { + function SwapSlippageChanged(event_properties) { + this.event_properties = event_properties; + this.event_type = 'Swap Slippage Changed'; + this.event_properties = event_properties; + } + return SwapSlippageChanged; +}()); +export { SwapSlippageChanged }; +var TransactionsPageViewed = /** @class */ (function () { + function TransactionsPageViewed() { + this.event_type = 'Transactions Page Viewed'; + } + return TransactionsPageViewed; +}()); +export { TransactionsPageViewed }; +var VotingPageViewed = /** @class */ (function () { + function VotingPageViewed() { + this.event_type = 'Voting Page Viewed'; + } + return VotingPageViewed; +}()); +export { VotingPageViewed }; +var getVoidPromiseResult = function () { return ({ promise: Promise.resolve() }); }; +// prettier-ignore +var Ampli = /** @class */ (function () { + function Ampli() { + this.disabled = false; + } + Object.defineProperty(Ampli.prototype, "client", { + get: function () { + this.isInitializedAndEnabled(); + return this.amplitude; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Ampli.prototype, "isLoaded", { + get: function () { + return this.amplitude != null; + }, + enumerable: false, + configurable: true + }); + Ampli.prototype.isInitializedAndEnabled = function () { + if (!this.amplitude) { + console.error('ERROR: Ampli is not yet initialized. Have you called ampli.load() on app start?'); + return false; + } + return !this.disabled; + }; + /** + * Initialize the Ampli SDK. Call once when your application starts. + * + * @param options Configuration options to initialize the Ampli SDK with. + */ + Ampli.prototype.load = function (options) { + var _a; + this.disabled = (_a = options.disabled) !== null && _a !== void 0 ? _a : false; + if (this.amplitude) { + console.warn('WARNING: Ampli is already intialized. Ampli.load() should be called once at application startup.'); + return getVoidPromiseResult(); + } + var apiKey = null; + if (options.client && 'apiKey' in options.client) { + apiKey = options.client.apiKey; + } + else if ('environment' in options) { + apiKey = ApiKey[options.environment]; + } + if (options.client && 'instance' in options.client) { + this.amplitude = options.client.instance; + } + else if (apiKey) { + this.amplitude = amplitude.createInstance(); + var configuration = (options.client && 'configuration' in options.client) ? options.client.configuration : {}; + return this.amplitude.init(apiKey, undefined, __assign(__assign({}, DefaultConfiguration), configuration)); + } + else { + console.error("ERROR: ampli.load() requires 'environment', 'client.apiKey', or 'client.instance'"); + } + return getVoidPromiseResult(); + }; + /** + * Identify a user and set user properties. + * + * @param userId The user's id. + * @param options Optional event options. + */ + Ampli.prototype.identify = function (userId, options) { + if (!this.isInitializedAndEnabled()) { + return getVoidPromiseResult(); + } + if (userId) { + options = __assign(__assign({}, options), { user_id: userId }); + } + var amplitudeIdentify = new amplitude.Identify(); + return this.amplitude.identify(amplitudeIdentify, options); + }; + /** + * Flush the event. + */ + Ampli.prototype.flush = function () { + if (!this.isInitializedAndEnabled()) { + return getVoidPromiseResult(); + } + return this.amplitude.flush(); + }; + /** + * Track event + * + * @param event The event to track. + * @param options Optional event options. + */ + Ampli.prototype.track = function (event, options) { + if (!this.isInitializedAndEnabled()) { + return getVoidPromiseResult(); + } + return this.amplitude.track(event, undefined, options); + }; + /** + * All Wallets Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/All%20Wallets%20Page%20Viewed) + * + * This event tracks when a user views the All Wallets page on Menu. Note: only available on Yoroi Mobile. + * + * @param options Amplitude event options. + */ + Ampli.prototype.allWalletsPageViewed = function (options) { + return this.track(new AllWalletsPageViewed(), options); + }; + /** + * Assets Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Assets%20Page%20Viewed) + * + * This event tracks when a user views the Assets page. Note: only available on Yoroi Extension. + * + * @param options Amplitude event options. + */ + Ampli.prototype.assetsPageViewed = function (options) { + return this.track(new AssetsPageViewed(), options); + }; + /** + * Claim ADA Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Claim%20ADA%20Page%20Viewed) + * + * This event tracks when a user views the page to claim Claim /Transfer ADA page in ExtensionEvent: Claim ADA Page Viewed + * + * Description: This event tracks when a user views the page to claim ADA tokens. It provides insights into the number of users who are interested in claiming ADA tokens and can be used to analyze user engagement and conversion rates on the claim page + * + * @param options Amplitude event options. + */ + Ampli.prototype.claimAdaPageViewed = function (options) { + return this.track(new ClaimAdaPageViewed(), options); + }; + /** + * Connector Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Connector%20Page%20Viewed) + * + * This event tracks when a user views the dApp Connector page. + * + * @param options Amplitude event options. + */ + Ampli.prototype.connectorPageViewed = function (options) { + return this.track(new ConnectorPageViewed(), options); + }; + /** + * Create Wallet Details Step Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Create%20Wallet%20Details%20Step%20Viewed) + * + * This event tracks when a user views the details \*\*step 4\*\* while creating a wallet. User will introduce: \* Wallet Name \* Password \* Repeat Password + * + * @param options Amplitude event options. + */ + Ampli.prototype.createWalletDetailsStepViewed = function (options) { + return this.track(new CreateWalletDetailsStepViewed(), options); + }; + /** + * Create Wallet Details Submitted + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Create%20Wallet%20Details%20Submitted) + * + * This event captures the submission of the wallet creation on the last step of the flow (\*\*step 4\*\*). + * + * @param options Amplitude event options. + */ + Ampli.prototype.createWalletDetailsSubmitted = function (options) { + return this.track(new CreateWalletDetailsSubmitted(), options); + }; + /** + * Create Wallet Language Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Create%20Wallet%20Language%20Page%20Viewed) + * + * This event tracks when a user views the page for selecting the language during the wallet creation process on the first time he launch Yoroi. + * + * @param options Amplitude event options. + */ + Ampli.prototype.createWalletLanguagePageViewed = function (options) { + return this.track(new CreateWalletLanguagePageViewed(), options); + }; + /** + * Create Wallet Learn Phrase Step Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Create%20Wallet%20Learn%20Phrase%20Step%20Viewed) + * + * This event tracks when a user view the \*\*first step\*\* of learn about recovery prhase + * + * @param options Amplitude event options. + */ + Ampli.prototype.createWalletLearnPhraseStepViewed = function (options) { + return this.track(new CreateWalletLearnPhraseStepViewed(), options); + }; + /** + * Create Wallet Save Phrase Step Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Create%20Wallet%20Save%20Phrase%20Step%20Viewed) + * + * This event tracks when a user views the \*\*second step\*\* to save their wallet recovery phrase during the wallet creation process + * + * @param options Amplitude event options. + */ + Ampli.prototype.createWalletSavePhraseStepViewed = function (options) { + return this.track(new CreateWalletSavePhraseStepViewed(), options); + }; + /** + * Create Wallet Select Method Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Create%20Wallet%20Select%20Method%20Page%20Viewed) + * + * This event tracks when a user views the page where they can select the method to create a wallet: + * + * \* Create new wallet + * + * \* Restore existing wallet + * + * This event tracks when a user views the page where they can select the method to create a wallet\* Connect hardware wallet + * + * @param options Amplitude event options. + */ + Ampli.prototype.createWalletSelectMethodPageViewed = function (options) { + return this.track(new CreateWalletSelectMethodPageViewed(), options); + }; + /** + * Create Wallet Terms Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Create%20Wallet%20Terms%20Page%20Viewed) + * + * This event tracks when a user views the terms of service agreement page on the creation wallet flow + * + * @param options Amplitude event options. + */ + Ampli.prototype.createWalletTermsPageViewed = function (options) { + return this.track(new CreateWalletTermsPageViewed(), options); + }; + /** + * Create Wallet Verify Phrase Step Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Create%20Wallet%20Verify%20Phrase%20Step%20Viewed) + * + * This event tracks when a user views the verification phrase step while creating a wallet + * + * @param options Amplitude event options. + */ + Ampli.prototype.createWalletVerifyPhraseStepViewed = function (options) { + return this.track(new CreateWalletVerifyPhraseStepViewed(), options); + }; + /** + * Create Wallet Verify Phrase Word Selected + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Create%20Wallet%20Verify%20Phrase%20Word%20Selected) + * + * This event tracks the selection of a specific word during the process of verifying the recovery phrase when creating a wallet + * + * @param properties The event's properties (e.g. recovery_word_order) + * @param options Amplitude event options. + */ + Ampli.prototype.createWalletVerifyPhraseWordSelected = function (properties, options) { + return this.track(new CreateWalletVerifyPhraseWordSelected(properties), options); + }; + /** + * Dapp Popup Add Collateral Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Dapp%20Popup%20Add%20Collateral%20Page%20Viewed) + * + * This event tracks when a user views the "Add Collateral" page in the Dapp Connector Popup + * + * @param options Amplitude event options. + */ + Ampli.prototype.dappPopupAddCollateralPageViewed = function (options) { + return this.track(new DappPopupAddCollateralPageViewed(), options); + }; + /** + * Dapp Popup Connect Wallet Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Dapp%20Popup%20Connect%20Wallet%20Page%20Viewed) + * + * This event is triggered when the dapp connector popup is triggered and the user select the wallet that wants to connect. + * + * @param properties The event's properties (e.g. wallet_count) + * @param options Amplitude event options. + */ + Ampli.prototype.dappPopupConnectWalletPageViewed = function (properties, options) { + return this.track(new DappPopupConnectWalletPageViewed(properties), options); + }; + /** + * Dapp Popup Connect Wallet Password Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Dapp%20Popup%20Connect%20Wallet%20Password%20Page%20Viewed) + * + * This event tracks when a user attempts to connect their wallet by entering their password in the Dapp Connector popup + * + * @param options Amplitude event options. + */ + Ampli.prototype.dappPopupConnectWalletPasswordPageViewed = function (options) { + return this.track(new DappPopupConnectWalletPasswordPageViewed(), options); + }; + /** + * Dapp Popup Sign Transaction Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Dapp%20Popup%20Sign%20Transaction%20Page%20Viewed) + * + * This event tracks when a user loads transaction screenThis event tracks when a user signs a transaction within a Dapp popup within a Dapp Connector Popup + * + * @param options Amplitude event options. + */ + Ampli.prototype.dappPopupSignTransactionPageViewed = function (options) { + return this.track(new DappPopupSignTransactionPageViewed(), options); + }; + /** + * Dapp Popup Sign Transaction Submitted + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Dapp%20Popup%20Sign%20Transaction%20Submitted) + * + * This event tracks the click "confirm" button on submission of a sign transaction request within the Dapp Connector Popup This event tracks the submission of a sign transaction request within the Dapp Popup feature + * + * @param options Amplitude event options. + */ + Ampli.prototype.dappPopupSignTransactionSubmitted = function (options) { + return this.track(new DappPopupSignTransactionSubmitted(), options); + }; + /** + * Menu Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Menu%20Page%20Viewed) + * + * This event is triggered when a user views the menu page within the application + * + * @param options Amplitude event options. + */ + Ampli.prototype.menuPageViewed = function (options) { + return this.track(new MenuPageViewed(), options); + }; + /** + * NFT Gallery Details Image Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/NFT%20Gallery%20Details%20Image%20Viewed) + * + * This event tracks when a user views the NFT image at full screen + * + * @param options Amplitude event options. + */ + Ampli.prototype.nftGalleryDetailsImageViewed = function (options) { + return this.track(new NftGalleryDetailsImageViewed(), options); + }; + /** + * NFT Gallery Details Navigation + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/NFT%20Gallery%20Details%20Navigation) + * + * This event tracks when a use next and previous buttons to navigate across their NFTs. Note: available only on Extension. + * + * @param properties The event's properties (e.g. nft_navigation) + * @param options Amplitude event options. + */ + Ampli.prototype.nftGalleryDetailsNavigation = function (properties, options) { + return this.track(new NftGalleryDetailsNavigation(properties), options); + }; + /** + * NFT Gallery Details Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/NFT%20Gallery%20Details%20Page%20Viewed) + * + * This event tracks when a user views the details page of an NFT item. + * + * @param options Amplitude event options. + */ + Ampli.prototype.nftGalleryDetailsPageViewed = function (options) { + return this.track(new NftGalleryDetailsPageViewed(), options); + }; + /** + * NFT Gallery Details Tab + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/NFT%20Gallery%20Details%20Tab) + * + * This event tracks user interactions with the tab in the NFT Gallery details page. It provides insights into how users engage with specific details of NFTs, such as descriptions, attributes, or additional information + * + * @param properties The event's properties (e.g. nft_tab) + * @param options Amplitude event options. + */ + Ampli.prototype.nftGalleryDetailsTab = function (properties, options) { + return this.track(new NftGalleryDetailsTab(properties), options); + }; + /** + * NFT Gallery Grid View Selected + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/NFT%20Gallery%20Grid%20View%20Selected) + * + * This event is triggered when a user selects the grid view option in the NFT gallery + * + * @param properties The event's properties (e.g. nft_grid_view) + * @param options Amplitude event options. + */ + Ampli.prototype.nftGalleryGridViewSelected = function (properties, options) { + return this.track(new NftGalleryGridViewSelected(properties), options); + }; + /** + * NFT Gallery Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/NFT%20Gallery%20Page%20Viewed) + * + * This event tracks when the NFT gallery it has loaded all nfts metadata + * + * @param properties The event's properties (e.g. nft_count) + * @param options Amplitude event options. + */ + Ampli.prototype.nftGalleryPageViewed = function (properties, options) { + return this.track(new NftGalleryPageViewed(properties), options); + }; + /** + * NFT Gallery Search Activated + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/NFT%20Gallery%20Search%20Activated) + * + * User activates and starts a search in the NFT gallery. Delay of 0.5 seconds. + * + * @param properties The event's properties (e.g. nft_count) + * @param options Amplitude event options. + */ + Ampli.prototype.nftGallerySearchActivated = function (properties, options) { + return this.track(new NftGallerySearchActivated(properties), options); + }; + /** + * Receive Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Receive%20Page%20Viewed) + * + * This event tracks when a user views the Receive page of the Wallet menu. + * + * @param options Amplitude event options. + */ + Ampli.prototype.receivePageViewed = function (options) { + return this.track(new ReceivePageViewed(), options); + }; + /** + * Restore Wallet Details Step Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Restore%20Wallet%20Details%20Step%20Viewed) + * + * Event has no description in tracking plan. + * + * @param options Amplitude event options. + */ + Ampli.prototype.restoreWalletDetailsStepViewed = function (options) { + return this.track(new RestoreWalletDetailsStepViewed(), options); + }; + /** + * Restore Wallet Details Submitted + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Restore%20Wallet%20Details%20Submitted) + * + * Event has no description in tracking plan. + * + * @param options Amplitude event options. + */ + Ampli.prototype.restoreWalletDetailsSubmitted = function (options) { + return this.track(new RestoreWalletDetailsSubmitted(), options); + }; + /** + * Restore Wallet Enter Phrase Step Status + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Restore%20Wallet%20Enter%20Phrase%20Step%20Status) + * + * Event has no description in tracking plan. + * + * @param properties The event's properties (e.g. recovery_prhase_status) + * @param options Amplitude event options. + */ + Ampli.prototype.restoreWalletEnterPhraseStepStatus = function (properties, options) { + return this.track(new RestoreWalletEnterPhraseStepStatus(properties), options); + }; + /** + * Restore Wallet Enter Phrase Step Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Restore%20Wallet%20Enter%20Phrase%20Step%20Viewed) + * + * This event tracks when a user views the step to enter the recovery phrase while restoring a wallet (**Step 2**). + * + * @param properties The event's properties (e.g. recovery_phrase_lenght) + * @param options Amplitude event options. + */ + Ampli.prototype.restoreWalletEnterPhraseStepViewed = function (properties, options) { + return this.track(new RestoreWalletEnterPhraseStepViewed(properties), options); + }; + /** + * Restore Wallet Type Step Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Restore%20Wallet%20Type%20Step%20Viewed) + * + * This event tracks when a user views the **first step after** selecting restore wallet, were they have to choose between: + * + * * 15-word recovery phrase + * + * * 24-word recovery phrase + * + * @param options Amplitude event options. + */ + Ampli.prototype.restoreWalletTypeStepViewed = function (options) { + return this.track(new RestoreWalletTypeStepViewed(), options); + }; + /** + * Send Initiated + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Send%20Initiated) + * + * This event tracks when a user loads the default state of the first step of the multiasset transaction flow. That screen shows receiver address and optional memo + * + * @param options Amplitude event options. + */ + Ampli.prototype.sendInitiated = function (options) { + return this.track(new SendInitiated(), options); + }; + /** + * Send Select Asset Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Send%20Select%20Asset%20Page%20Viewed) + * + * This event tracks when a user views the "Amount" page in the send flow. + * + * @param options Amplitude event options. + */ + Ampli.prototype.sendSelectAssetPageViewed = function (options) { + return this.track(new SendSelectAssetPageViewed(), options); + }; + /** + * Send Select Asset Selected + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Send%20Select%20Asset%20Selected) + * + * When a user click "next" on the send flow: "Amount" step on extension / "Assets added" in mobile + * + * @param properties The event's properties (e.g. asset_count) + * @param options Amplitude event options. + */ + Ampli.prototype.sendSelectAssetSelected = function (properties, options) { + return this.track(new SendSelectAssetSelected(properties), options); + }; + /** + * Send Select Asset Updated + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Send%20Select%20Asset%20Updated) + * + * When an user update the tokens selection on "amount" step: + * \- Add + * \- Remove + * \- Updated + * + * @param properties The event's properties (e.g. asset_count) + * @param options Amplitude event options. + */ + Ampli.prototype.sendSelectAssetUpdated = function (properties, options) { + return this.track(new SendSelectAssetUpdated(properties), options); + }; + /** + * Send Summary Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Send%20Summary%20Page%20Viewed) + * + * When a user loads the Preview page (Could be called comfirmation too) on the send flow. + * + * @param properties The event's properties (e.g. asset_count) + * @param options Amplitude event options. + */ + Ampli.prototype.sendSummaryPageViewed = function (properties, options) { + return this.track(new SendSummaryPageViewed(properties), options); + }; + /** + * Send Summary Submitted + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Send%20Summary%20Submitted) + * + * When a user click "send" on the "Preview" step on the send flow. + * + * @param properties The event's properties (e.g. asset_count) + * @param options Amplitude event options. + */ + Ampli.prototype.sendSummarySubmitted = function (properties, options) { + return this.track(new SendSummarySubmitted(properties), options); + }; + /** + * Settings Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Settings%20Page%20Viewed) + * + * This event tracks when a user views the settings page within the application. + * + * @param options Amplitude event options. + */ + Ampli.prototype.settingsPageViewed = function (options) { + return this.track(new SettingsPageViewed(), options); + }; + /** + * Staking Center Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Staking%20Center%20Page%20Viewed) + * + * This event tracks when a user views the Staking Center page on Staking menu. + * + * @param options Amplitude event options. + */ + Ampli.prototype.stakingCenterPageViewed = function (options) { + return this.track(new StakingCenterPageViewed(), options); + }; + /** + * Staking Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Staking%20Page%20Viewed) + * + * This event tracks when a user views the Staking page. + * + * @param options Amplitude event options. + */ + Ampli.prototype.stakingPageViewed = function (options) { + return this.track(new StakingPageViewed(), options); + }; + /** + * Swap Asset From Changed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Swap%20Asset%20From%20Changed) + * + * When user changed the selected asset on "From" section + * + * Owner: Omar Rozak + * + * @param properties The event's properties (e.g. from_asset) + * @param options Amplitude event options. + */ + Ampli.prototype.swapAssetFromChanged = function (properties, options) { + return this.track(new SwapAssetFromChanged(properties), options); + }; + /** + * Swap Asset To Changed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Swap%20Asset%20To%20Changed) + * + * When user changed the selected asset on "To" section + * + * Owner: Omar Rozak + * + * @param properties The event's properties (e.g. to_asset) + * @param options Amplitude event options. + */ + Ampli.prototype.swapAssetToChanged = function (properties, options) { + return this.track(new SwapAssetToChanged(properties), options); + }; + /** + * Swap Cancelation Submitted + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Swap%20Cancelation%20Submitted) + * + * When user sign a transaction to cancel the swap order + * + * Owner: Omar Rozak + * + * @param properties The event's properties (e.g. from_amount) + * @param options Amplitude event options. + */ + Ampli.prototype.swapCancelationSubmitted = function (properties, options) { + return this.track(new SwapCancelationSubmitted(properties), options); + }; + /** + * Swap Confirmed Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Swap%20Confirmed%20%20Page%20Viewed) + * + * When the user opens Completed Order page + * + * Owner: Omar Rozak + * + * @param properties The event's properties (e.g. swap_tab) + * @param options Amplitude event options. + */ + Ampli.prototype.swapConfirmedPageViewed = function (properties, options) { + return this.track(new SwapConfirmedPageViewed(properties), options); + }; + /** + * Swap Initiated + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Swap%20Initiated) + * + * When user clicks on the swap feature and sees the default state of the swap. + * + * Owner: Omar Rozak + * + * @param properties The event's properties (e.g. from_asset) + * @param options Amplitude event options. + */ + Ampli.prototype.swapInitiated = function (properties, options) { + return this.track(new SwapInitiated(properties), options); + }; + /** + * Swap Order Selected + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Swap%20Order%20Selected) + * + * When user click on "swap" button after selecting asset from, entering the amount of asset form, selecting asset to, entering amount of asset to, and choosing a pool + * + * Owner: Omar Rozak + * + * @param properties The event's properties (e.g. from_amount) + * @param options Amplitude event options. + */ + Ampli.prototype.swapOrderSelected = function (properties, options) { + return this.track(new SwapOrderSelected(properties), options); + }; + /** + * Swap Order Submitted + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Swap%20Order%20Submitted) + * + * When user click confirm on the check out page, after entering their spending password + * + * Owner: Omar Rozak + * + * @param properties The event's properties (e.g. from_amount) + * @param options Amplitude event options. + */ + Ampli.prototype.swapOrderSubmitted = function (properties, options) { + return this.track(new SwapOrderSubmitted(properties), options); + }; + /** + * Swap Pool Changed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Swap%20Pool%20Changed) + * + * When user clicked a different pool on the "Select Pool" page + * + * Owner: Sergio SF + * + * @param options Amplitude event options. + */ + Ampli.prototype.swapPoolChanged = function (options) { + return this.track(new SwapPoolChanged(), options); + }; + /** + * Swap Slippage Changed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Swap%20Slippage%20Changed) + * + * When user click apply on the swap setting page + * + * Owner: Omar Rozak + * + * @param properties The event's properties (e.g. slippage_tolerance) + * @param options Amplitude event options. + */ + Ampli.prototype.swapSlippageChanged = function (properties, options) { + return this.track(new SwapSlippageChanged(properties), options); + }; + /** + * Transactions Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Transactions%20Page%20Viewed) + * + * This event tracks when a user views the transactions page within the wallet. + * + * @param options Amplitude event options. + */ + Ampli.prototype.transactionsPageViewed = function (options) { + return this.track(new TransactionsPageViewed(), options); + }; + /** + * Voting Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Voting%20Page%20Viewed) + * + * This event tracks when a user views the Voting page. + * + * @param options Amplitude event options. + */ + Ampli.prototype.votingPageViewed = function (options) { + return this.track(new VotingPageViewed(), options); + }; + return Ampli; +}()); +export { Ampli }; +export var ampli = new Ampli(); diff --git a/packages/yoroi-extension/ampli/index.js.flow b/packages/yoroi-extension/ampli/index.js.flow new file mode 100644 index 0000000000..53a5f61a96 --- /dev/null +++ b/packages/yoroi-extension/ampli/index.js.flow @@ -0,0 +1,1644 @@ +/** + * Flowtype definitions for index + * Generated by Flowgen from a Typescript Definition + * Flowgen v1.21.0 + * @flow + */ +class BaseEvent {} + +import * as amplitude from "@amplitude/analytics-browser"; +export type Environment = "production" | "development"; +declare export var ApiKey: { [key: Environment]: string }; +/** + * Default Amplitude configuration options. Contains tracking plan information. + */ +declare export var DefaultConfiguration: BrowserOptions; +export type LoadOptionsBase = {| + disabled?: boolean, +|}; +export type LoadOptionsWithEnvironment = {| + ...LoadOptionsBase, + ...{| + environment: Environment, + client?: {| + configuration?: BrowserOptions, + |}, + |}, +|}; +export type LoadOptionsWithApiKey = {| + ...LoadOptionsBase, + ...{| + client: {| + apiKey: string, + configuration?: BrowserOptions, + |}, + |}, +|}; +export type LoadOptionsWithClientInstance = {| + ...LoadOptionsBase, + ...{| + client: {| + instance: BrowserClient, + |}, + |}, +|}; +export type LoadOptions = + | LoadOptionsWithEnvironment + | LoadOptionsWithApiKey + | LoadOptionsWithClientInstance; +export type CreateWalletVerifyPhraseWordSelectedProperties = {| + recovery_word_order?: any, +|}; +export type DappPopupConnectWalletPageViewedProperties = {| + /** + * The total number of wallets that a user have. + * In case of not having any wallet, save 0 as the value. + * + * | Rule | Value | + * |---|---| + * | Type | number | + */ + wallet_count: number, +|}; +export type NftGalleryDetailsNavigationProperties = {| + /** + * Describe the navigation buttons on the NFT details view + * + * | Rule | Value | + * |---|---| + * | Enum Values | Next, Previous | + */ + nft_navigation: "Next" | "Previous", +|}; +export type NftGalleryDetailsTabProperties = {| + /** + * | Rule | Value | + * |---|---| + * | Enum Values | Overview, Metadata | + */ + nft_tab: "Overview" | "Metadata", +|}; +export type NftGalleryGridViewSelectedProperties = {| + /** + * Describe what type of grid is using the NFT gallery + * + * | Rule | Value | + * |---|---| + * | Enum Values | 4_rows, 6_rows | + */ + nft_grid_view?: "4_rows" | "6_rows", +|}; +export type NftGalleryPageViewedProperties = {| + /** + * The total number of NFT's that an user have + * + * | Rule | Value | + * |---|---| + * | Type | integer | + */ + nft_count: number, +|}; +export type NftGallerySearchActivatedProperties = {| + /** + * The total number of NFT's that an user have + * + * | Rule | Value | + * |---|---| + * | Type | integer | + */ + nft_count: number, + + /** + * What user is looking to search on NFT gallery page + */ + nft_search_term: string, +|}; +export type RestoreWalletEnterPhraseStepStatusProperties = {| + recovery_prhase_status: boolean, +|}; +export type RestoreWalletEnterPhraseStepViewedProperties = {| + /** + * | Rule | Value | + * |---|---| + * | Enum Values | 15, 24 | + */ + recovery_phrase_lenght: "15" | "24", +|}; +export type SendSelectAssetSelectedProperties = {| + /** + * Total numbers of assets to be send + * + * | Rule | Value | + * |---|---| + * | Type | number | + */ + asset_count: number, + + /** + * ``` + * nfts: [ + * { + * nft_name: Bored Ape, + * + * }, + * { + * nft_name: Crypto Cats, + * } + * ] + * ``` + */ + nfts?: any[], + + /** + * ``` + * Tokens: [ + * { + * token_name: Ado, + * token_amount: '133', + * }, + * { + * token_name: Ada, + * token_amount: '5', + * } + * ] + * ``` + */ + tokens?: any[], +|}; +export type SendSelectAssetUpdatedProperties = {| + /** + * | Rule | Value | + * |---|---| + * | Type | number | + */ + asset_count: number, + + /** + * ``` + * nfts: [ + * { + * nft_name: Bored Ape, + * + * }, + * { + * nft_name: Crypto Cats, + * } + * ] + * ``` + */ + nfts?: any[], + + /** + * ``` + * Tokens: [ + * { + * token_name: Ado, + * token_amount: '133', + * }, + * { + * token_name: Ada, + * token_amount: '5', + * } + * ] + * ``` + */ + tokens?: any[], +|}; +export type SendSummaryPageViewedProperties = {| + /** + * | Rule | Value | + * |---|---| + * | Type | number | + */ + asset_count: number, + + /** + * ``` + * nfts: [ + * { + * nft_name: Bored Ape, + * + * }, + * { + * nft_name: Crypto Cats, + * } + * ] + * ``` + */ + nfts?: any[], + + /** + * ``` + * Tokens: [ + * { + * token_name: Ado, + * token_amount: '133', + * }, + * { + * token_name: Ada, + * token_amount: '5', + * } + * ] + * ``` + */ + tokens?: any[], +|}; +export type SendSummarySubmittedProperties = {| + /** + * | Rule | Value | + * |---|---| + * | Type | number | + */ + asset_count: number, + + /** + * ``` + * nfts: [ + * { + * nft_name: Bored Ape, + * + * }, + * { + * nft_name: Crypto Cats, + * } + * ] + * ``` + */ + nfts?: any[], + + /** + * ``` + * Tokens: [ + * { + * token_name: Ado, + * token_amount: '133', + * }, + * { + * token_name: Ada, + * token_amount: '5', + * } + * ] + * ``` + */ + tokens?: any[], +|}; +export type SwapAssetFromChangedProperties = {| + /** + * Displaying the asset that the user chose to trade with. + * + * Asset Name Asset Ticker Policy ID + * \[ + * { + * asset_name: 'ADA', + * asset_ticker: 'ADA', + * policy_id: '123456789' + * }, + * \] + */ + from_asset: any[], +|}; +export type SwapAssetToChangedProperties = {| + /** + * Displaying the asset that the user chose to trade to + * + * Asset Name + * Asset Ticker + * Policy ID + */ + to_asset: any[], +|}; +export type SwapCancelationSubmittedProperties = {| + /** + * The amount of asset that the user is swapping from + * + * | Rule | Value | + * |---|---| + * | Type | number | + */ + from_amount: number, + + /** + * Displaying the asset that the user chose to trade with. + * + * Asset Name Asset Ticker Policy ID + * \[ + * { + * asset_name: 'ADA', + * asset_ticker: 'ADA', + * policy_id: '123456789' + * }, + * \] + * + * | Rule | Value | + * |---|---| + * | Unique Items | null | + */ + from_asset: any[], + + /** + * The type of order selected on a given transaction + * + * | Rule | Value | + * |---|---| + * | Enum Values | limit, market | + */ + order_type: "limit" | "market", + + /** + * The name of liquidity pool used for this swap transaction + */ + pool_source: string, + + /** + * The default slippage tolerance is 1%, but users are free to change the slippage. + * + * | Rule | Value | + * |---|---| + * | Type | number | + */ + slippage_tolerance: number, + + /** + * The amount of fees charged on the transaction. The value is in ADA. + * + * | Rule | Value | + * |---|---| + * | Type | number | + */ + swap_fees: number, + + /** + * The amount of asset that the user is swapping to + * + * | Rule | Value | + * |---|---| + * | Type | number | + */ + to_amount: number, + + /** + * Displaying the asset that the user chose to trade to + * + * Asset Name + * Asset Ticker + * Policy ID + * + * | Rule | Value | + * |---|---| + * | Unique Items | null | + */ + to_asset: any[], +|}; +export type SwapConfirmedPageViewedProperties = {| + /** + * Define the tab that is active in the selected page + * + * | Rule | Value | + * |---|---| + * | Enum Values | Open Orders, Complete, Complete Orders | + */ + swap_tab: "Open Orders" | "Complete" | "Complete Orders", +|}; +export type SwapInitiatedProperties = {| + /** + * Displaying the asset that the user chose to trade with. + * + * Asset Name Asset Ticker Policy ID + * \[ + * { + * asset_name: 'ADA', + * asset_ticker: 'ADA', + * policy_id: '123456789' + * }, + * \] + * + * | Rule | Value | + * |---|---| + * | Unique Items | null | + */ + from_asset: any[], + + /** + * The type of order selected on a given transaction + * + * | Rule | Value | + * |---|---| + * | Enum Values | limit, market | + */ + order_type: "limit" | "market", + + /** + * The default slippage tolerance is 1%, but users are free to change the slippage. + * + * | Rule | Value | + * |---|---| + * | Type | number | + */ + slippage_tolerance: number, + + /** + * Displaying the asset that the user chose to trade to + * + * Asset Name + * Asset Ticker + * Policy ID + * + * | Rule | Value | + * |---|---| + * | Unique Items | null | + */ + to_asset: any[], +|}; +export type SwapOrderSelectedProperties = {| + /** + * The amount of asset that the user is swapping from + */ + from_amount: string, + + /** + * Displaying the asset that the user chose to trade with. + * + * Asset Name Asset Ticker Policy ID + * \[ + * { + * asset_name: 'ADA', + * asset_ticker: 'ADA', + * policy_id: '123456789' + * }, + * \] + */ + from_asset: any[], + + /** + * The type of order selected on a given transaction + * + * | Rule | Value | + * |---|---| + * | Enum Values | limit, market | + */ + order_type: "limit" | "market", + + /** + * The name of liquidity pool used for this swap transaction + */ + pool_source: string, + + /** + * The default slippage tolerance is 1%, but users are free to change the slippage. + * + * | Rule | Value | + * |---|---| + * | Type | number | + */ + slippage_tolerance: number, + + /** + * The amount of fees charged on the transaction. The value is in ADA. + * + * | Rule | Value | + * |---|---| + * | Type | number | + */ + swap_fees: number, + + /** + * The amount of asset that the user is swapping to + */ + to_amount: string, + + /** + * Displaying the asset that the user chose to trade to + * + * Asset Name + * Asset Ticker + * Policy ID + */ + to_asset: any[], +|}; +export type SwapOrderSubmittedProperties = {| + /** + * The amount of asset that the user is swapping from + */ + from_amount: string, + + /** + * Displaying the asset that the user chose to trade with. + * + * Asset Name Asset Ticker Policy ID + * \[ + * { + * asset_name: 'ADA', + * asset_ticker: 'ADA', + * policy_id: '123456789' + * }, + * \] + */ + from_asset: any[], + + /** + * The type of order selected on a given transaction + * + * | Rule | Value | + * |---|---| + * | Enum Values | limit, market | + */ + order_type: "limit" | "market", + + /** + * The name of liquidity pool used for this swap transaction + */ + pool_source: string, + + /** + * The default slippage tolerance is 1%, but users are free to change the slippage. + * + * | Rule | Value | + * |---|---| + * | Type | number | + */ + slippage_tolerance: number, + + /** + * The amount of fees charged on the transaction. The value is in ADA. + * + * | Rule | Value | + * |---|---| + * | Type | number | + */ + swap_fees: number, + + /** + * The amount of asset that the user is swapping to + */ + to_amount: string, + + /** + * Displaying the asset that the user chose to trade to + * + * Asset Name + * Asset Ticker + * Policy ID + */ + to_asset: any[], +|}; +export type SwapSlippageChangedProperties = {| + /** + * The default slippage tolerance is 1%, but users are free to change the slippage. + * + * | Rule | Value | + * |---|---| + * | Type | number | + */ + slippage_tolerance: number, +|}; +export type SendProperties = {| + /** + * Total numbers of assets to be send + * + * | Rule | Value | + * |---|---| + * | Type | number | + */ + asset_count: number, + + /** + * ``` + * nfts: [ + * { + * nft_name: Bored Ape, + * + * }, + * { + * nft_name: Crypto Cats, + * } + * ] + * ``` + */ + nfts?: any[], + + /** + * ``` + * Tokens: [ + * { + * token_name: Ado, + * token_amount: '133', + * }, + * { + * token_name: Ada, + * token_amount: '5', + * } + * ] + * ``` + */ + tokens?: any[], +|}; +export type SwapProperties = {| + /** + * The amount of asset that the user is swapping from + */ + from_amount: string, + + /** + * Displaying the asset that the user chose to trade with. + * + * Asset Name Asset Ticker Policy ID + * \[ + * { + * asset_name: 'ADA', + * asset_ticker: 'ADA', + * policy_id: '123456789' + * }, + * \] + */ + from_asset: any[], + + /** + * The type of order selected on a given transaction + * + * | Rule | Value | + * |---|---| + * | Enum Values | limit, market | + */ + order_type: "limit" | "market", + + /** + * The name of liquidity pool used for this swap transaction + */ + pool_source: string, + + /** + * The default slippage tolerance is 1%, but users are free to change the slippage. + * + * | Rule | Value | + * |---|---| + * | Type | number | + */ + slippage_tolerance: number, + + /** + * The amount of fees charged on the transaction. The value is in ADA. + * + * | Rule | Value | + * |---|---| + * | Type | number | + */ + swap_fees: number, + + /** + * The amount of asset that the user is swapping to + */ + to_amount: string, + + /** + * Displaying the asset that the user chose to trade to + * + * Asset Name + * Asset Ticker + * Policy ID + */ + to_asset: any[], +|}; +declare export class AllWalletsPageViewed mixins BaseEvent { + event_type: string; +} +declare export class AssetsPageViewed mixins BaseEvent { + event_type: string; +} +declare export class ClaimAdaPageViewed mixins BaseEvent { + event_type: string; +} +declare export class ConnectorPageViewed mixins BaseEvent { + event_type: string; +} +declare export class CreateWalletDetailsStepViewed mixins BaseEvent { + event_type: string; +} +declare export class CreateWalletDetailsSubmitted mixins BaseEvent { + event_type: string; +} +declare export class CreateWalletLanguagePageViewed mixins BaseEvent { + event_type: string; +} +declare export class CreateWalletLearnPhraseStepViewed mixins BaseEvent { + event_type: string; +} +declare export class CreateWalletSavePhraseStepViewed mixins BaseEvent { + event_type: string; +} +declare export class CreateWalletSelectMethodPageViewed mixins BaseEvent { + event_type: string; +} +declare export class CreateWalletTermsPageViewed mixins BaseEvent { + event_type: string; +} +declare export class CreateWalletVerifyPhraseStepViewed mixins BaseEvent { + event_type: string; +} +declare export class CreateWalletVerifyPhraseWordSelected mixins BaseEvent { + event_properties?: CreateWalletVerifyPhraseWordSelectedProperties; + event_type: string; + constructor( + event_properties?: CreateWalletVerifyPhraseWordSelectedProperties + ): this; +} +declare export class DappPopupAddCollateralPageViewed mixins BaseEvent { + event_type: string; +} +declare export class DappPopupConnectWalletPageViewed mixins BaseEvent { + event_properties: DappPopupConnectWalletPageViewedProperties; + event_type: string; + constructor( + event_properties: DappPopupConnectWalletPageViewedProperties + ): this; +} +declare export class DappPopupConnectWalletPasswordPageViewed mixins BaseEvent { + event_type: string; +} +declare export class DappPopupSignTransactionPageViewed mixins BaseEvent { + event_type: string; +} +declare export class DappPopupSignTransactionSubmitted mixins BaseEvent { + event_type: string; +} +declare export class MenuPageViewed mixins BaseEvent { + event_type: string; +} +declare export class NftGalleryDetailsImageViewed mixins BaseEvent { + event_type: string; +} +declare export class NftGalleryDetailsNavigation mixins BaseEvent { + event_properties: NftGalleryDetailsNavigationProperties; + event_type: string; + constructor(event_properties: NftGalleryDetailsNavigationProperties): this; +} +declare export class NftGalleryDetailsPageViewed mixins BaseEvent { + event_type: string; +} +declare export class NftGalleryDetailsTab mixins BaseEvent { + event_properties: NftGalleryDetailsTabProperties; + event_type: string; + constructor(event_properties: NftGalleryDetailsTabProperties): this; +} +declare export class NftGalleryGridViewSelected mixins BaseEvent { + event_properties?: NftGalleryGridViewSelectedProperties; + event_type: string; + constructor(event_properties?: NftGalleryGridViewSelectedProperties): this; +} +declare export class NftGalleryPageViewed mixins BaseEvent { + event_properties: NftGalleryPageViewedProperties; + event_type: string; + constructor(event_properties: NftGalleryPageViewedProperties): this; +} +declare export class NftGallerySearchActivated mixins BaseEvent { + event_properties: NftGallerySearchActivatedProperties; + event_type: string; + constructor(event_properties: NftGallerySearchActivatedProperties): this; +} +declare export class ReceivePageViewed mixins BaseEvent { + event_type: string; +} +declare export class RestoreWalletDetailsStepViewed mixins BaseEvent { + event_type: string; +} +declare export class RestoreWalletDetailsSubmitted mixins BaseEvent { + event_type: string; +} +declare export class RestoreWalletEnterPhraseStepStatus mixins BaseEvent { + event_properties: RestoreWalletEnterPhraseStepStatusProperties; + event_type: string; + constructor( + event_properties: RestoreWalletEnterPhraseStepStatusProperties + ): this; +} +declare export class RestoreWalletEnterPhraseStepViewed mixins BaseEvent { + event_properties: RestoreWalletEnterPhraseStepViewedProperties; + event_type: string; + constructor( + event_properties: RestoreWalletEnterPhraseStepViewedProperties + ): this; +} +declare export class RestoreWalletTypeStepViewed mixins BaseEvent { + event_type: string; +} +declare export class SendInitiated mixins BaseEvent { + event_type: string; +} +declare export class SendSelectAssetPageViewed mixins BaseEvent { + event_type: string; +} +declare export class SendSelectAssetSelected mixins BaseEvent { + event_properties: SendSelectAssetSelectedProperties; + event_type: string; + constructor(event_properties: SendSelectAssetSelectedProperties): this; +} +declare export class SendSelectAssetUpdated mixins BaseEvent { + event_properties: SendSelectAssetUpdatedProperties; + event_type: string; + constructor(event_properties: SendSelectAssetUpdatedProperties): this; +} +declare export class SendSummaryPageViewed mixins BaseEvent { + event_properties: SendSummaryPageViewedProperties; + event_type: string; + constructor(event_properties: SendSummaryPageViewedProperties): this; +} +declare export class SendSummarySubmitted mixins BaseEvent { + event_properties: SendSummarySubmittedProperties; + event_type: string; + constructor(event_properties: SendSummarySubmittedProperties): this; +} +declare export class SettingsPageViewed mixins BaseEvent { + event_type: string; +} +declare export class StakingCenterPageViewed mixins BaseEvent { + event_type: string; +} +declare export class StakingPageViewed mixins BaseEvent { + event_type: string; +} +declare export class SwapAssetFromChanged mixins BaseEvent { + event_properties: SwapAssetFromChangedProperties; + event_type: string; + constructor(event_properties: SwapAssetFromChangedProperties): this; +} +declare export class SwapAssetToChanged mixins BaseEvent { + event_properties: SwapAssetToChangedProperties; + event_type: string; + constructor(event_properties: SwapAssetToChangedProperties): this; +} +declare export class SwapCancelationSubmitted mixins BaseEvent { + event_properties: SwapCancelationSubmittedProperties; + event_type: string; + constructor(event_properties: SwapCancelationSubmittedProperties): this; +} +declare export class SwapConfirmedPageViewed mixins BaseEvent { + event_properties: SwapConfirmedPageViewedProperties; + event_type: string; + constructor(event_properties: SwapConfirmedPageViewedProperties): this; +} +declare export class SwapInitiated mixins BaseEvent { + event_properties: SwapInitiatedProperties; + event_type: string; + constructor(event_properties: SwapInitiatedProperties): this; +} +declare export class SwapOrderSelected mixins BaseEvent { + event_properties: SwapOrderSelectedProperties; + event_type: string; + constructor(event_properties: SwapOrderSelectedProperties): this; +} +declare export class SwapOrderSubmitted mixins BaseEvent { + event_properties: SwapOrderSubmittedProperties; + event_type: string; + constructor(event_properties: SwapOrderSubmittedProperties): this; +} +declare export class SwapPoolChanged mixins BaseEvent { + event_type: string; +} +declare export class SwapSlippageChanged mixins BaseEvent { + event_properties: SwapSlippageChangedProperties; + event_type: string; + constructor(event_properties: SwapSlippageChangedProperties): this; +} +declare export class TransactionsPageViewed mixins BaseEvent { + event_type: string; +} +declare export class VotingPageViewed mixins BaseEvent { + event_type: string; +} +export type PromiseResult = {| + promise: Promise, +|}; +declare export class Ampli { + client: BrowserClient; + isLoaded: boolean; + + /** + * Initialize the Ampli SDK. Call once when your application starts. + * @param options Configuration options to initialize the Ampli SDK with. + */ + load(options: LoadOptions): PromiseResult; + + /** + * Identify a user and set user properties. + * @param userId The user's id. + * @param options Optional event options. + */ + identify( + userId: string | void, + options?: EventOptions + ): PromiseResult; + + /** + * Flush the event. + */ + flush(): PromiseResult; + + /** + * Track event + * @param event The event to track. + * @param options Optional event options. + */ + track(event: Event, options?: EventOptions): PromiseResult; + + /** + * All Wallets Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/All%20Wallets%20Page%20Viewed) + * + * This event tracks when a user views the All Wallets page on Menu. Note: only available on Yoroi Mobile. + * @param options Amplitude event options. + */ + allWalletsPageViewed( + options?: EventOptions + ): PromiseResult; + + /** + * Assets Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Assets%20Page%20Viewed) + * + * This event tracks when a user views the Assets page. Note: only available on Yoroi Extension. + * @param options Amplitude event options. + */ + assetsPageViewed( + options?: EventOptions + ): PromiseResult; + + /** + * Claim ADA Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Claim%20ADA%20Page%20Viewed) + * + * This event tracks when a user views the page to claim Claim /Transfer ADA page in ExtensionEvent: Claim ADA Page Viewed + * + * Description: This event tracks when a user views the page to claim ADA tokens. It provides insights into the number of users who are interested in claiming ADA tokens and can be used to analyze user engagement and conversion rates on the claim page + * @param options Amplitude event options. + */ + claimAdaPageViewed( + options?: EventOptions + ): PromiseResult; + + /** + * Connector Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Connector%20Page%20Viewed) + * + * This event tracks when a user views the dApp Connector page. + * @param options Amplitude event options. + */ + connectorPageViewed( + options?: EventOptions + ): PromiseResult; + + /** + * Create Wallet Details Step Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Create%20Wallet%20Details%20Step%20Viewed) + * + * This event tracks when a user views the details \*\*step 4\*\* while creating a wallet. User will introduce: \* Wallet Name \* Password \* Repeat Password + * @param options Amplitude event options. + */ + createWalletDetailsStepViewed( + options?: EventOptions + ): PromiseResult; + + /** + * Create Wallet Details Submitted + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Create%20Wallet%20Details%20Submitted) + * + * This event captures the submission of the wallet creation on the last step of the flow (\*\*step 4\*\*). + * @param options Amplitude event options. + */ + createWalletDetailsSubmitted( + options?: EventOptions + ): PromiseResult; + + /** + * Create Wallet Language Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Create%20Wallet%20Language%20Page%20Viewed) + * + * This event tracks when a user views the page for selecting the language during the wallet creation process on the first time he launch Yoroi. + * @param options Amplitude event options. + */ + createWalletLanguagePageViewed( + options?: EventOptions + ): PromiseResult; + + /** + * Create Wallet Learn Phrase Step Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Create%20Wallet%20Learn%20Phrase%20Step%20Viewed) + * + * This event tracks when a user view the \*\*first step\*\* of learn about recovery prhase + * @param options Amplitude event options. + */ + createWalletLearnPhraseStepViewed( + options?: EventOptions + ): PromiseResult; + + /** + * Create Wallet Save Phrase Step Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Create%20Wallet%20Save%20Phrase%20Step%20Viewed) + * + * This event tracks when a user views the \*\*second step\*\* to save their wallet recovery phrase during the wallet creation process + * @param options Amplitude event options. + */ + createWalletSavePhraseStepViewed( + options?: EventOptions + ): PromiseResult; + + /** + * Create Wallet Select Method Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Create%20Wallet%20Select%20Method%20Page%20Viewed) + * + * This event tracks when a user views the page where they can select the method to create a wallet: + * + * \* Create new wallet + * + * \* Restore existing wallet + * + * This event tracks when a user views the page where they can select the method to create a wallet\* Connect hardware wallet + * @param options Amplitude event options. + */ + createWalletSelectMethodPageViewed( + options?: EventOptions + ): PromiseResult; + + /** + * Create Wallet Terms Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Create%20Wallet%20Terms%20Page%20Viewed) + * + * This event tracks when a user views the terms of service agreement page on the creation wallet flow + * @param options Amplitude event options. + */ + createWalletTermsPageViewed( + options?: EventOptions + ): PromiseResult; + + /** + * Create Wallet Verify Phrase Step Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Create%20Wallet%20Verify%20Phrase%20Step%20Viewed) + * + * This event tracks when a user views the verification phrase step while creating a wallet + * @param options Amplitude event options. + */ + createWalletVerifyPhraseStepViewed( + options?: EventOptions + ): PromiseResult; + + /** + * Create Wallet Verify Phrase Word Selected + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Create%20Wallet%20Verify%20Phrase%20Word%20Selected) + * + * This event tracks the selection of a specific word during the process of verifying the recovery phrase when creating a wallet + * @param properties The event's properties (e.g. recovery_word_order) + * @param options Amplitude event options. + */ + createWalletVerifyPhraseWordSelected( + properties?: CreateWalletVerifyPhraseWordSelectedProperties, + options?: EventOptions + ): PromiseResult; + + /** + * Dapp Popup Add Collateral Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Dapp%20Popup%20Add%20Collateral%20Page%20Viewed) + * + * This event tracks when a user views the "Add Collateral" page in the Dapp Connector Popup + * @param options Amplitude event options. + */ + dappPopupAddCollateralPageViewed( + options?: EventOptions + ): PromiseResult; + + /** + * Dapp Popup Connect Wallet Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Dapp%20Popup%20Connect%20Wallet%20Page%20Viewed) + * + * This event is triggered when the dapp connector popup is triggered and the user select the wallet that wants to connect. + * @param properties The event's properties (e.g. wallet_count) + * @param options Amplitude event options. + */ + dappPopupConnectWalletPageViewed( + properties: DappPopupConnectWalletPageViewedProperties, + options?: EventOptions + ): PromiseResult; + + /** + * Dapp Popup Connect Wallet Password Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Dapp%20Popup%20Connect%20Wallet%20Password%20Page%20Viewed) + * + * This event tracks when a user attempts to connect their wallet by entering their password in the Dapp Connector popup + * @param options Amplitude event options. + */ + dappPopupConnectWalletPasswordPageViewed( + options?: EventOptions + ): PromiseResult; + + /** + * Dapp Popup Sign Transaction Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Dapp%20Popup%20Sign%20Transaction%20Page%20Viewed) + * + * This event tracks when a user loads transaction screenThis event tracks when a user signs a transaction within a Dapp popup within a Dapp Connector Popup + * @param options Amplitude event options. + */ + dappPopupSignTransactionPageViewed( + options?: EventOptions + ): PromiseResult; + + /** + * Dapp Popup Sign Transaction Submitted + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Dapp%20Popup%20Sign%20Transaction%20Submitted) + * + * This event tracks the click "confirm" button on submission of a sign transaction request within the Dapp Connector Popup This event tracks the submission of a sign transaction request within the Dapp Popup feature + * @param options Amplitude event options. + */ + dappPopupSignTransactionSubmitted( + options?: EventOptions + ): PromiseResult; + + /** + * Menu Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Menu%20Page%20Viewed) + * + * This event is triggered when a user views the menu page within the application + * @param options Amplitude event options. + */ + menuPageViewed(options?: EventOptions): PromiseResult; + + /** + * NFT Gallery Details Image Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/NFT%20Gallery%20Details%20Image%20Viewed) + * + * This event tracks when a user views the NFT image at full screen + * @param options Amplitude event options. + */ + nftGalleryDetailsImageViewed( + options?: EventOptions + ): PromiseResult; + + /** + * NFT Gallery Details Navigation + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/NFT%20Gallery%20Details%20Navigation) + * + * This event tracks when a use next and previous buttons to navigate across their NFTs. Note: available only on Extension. + * @param properties The event's properties (e.g. nft_navigation) + * @param options Amplitude event options. + */ + nftGalleryDetailsNavigation( + properties: NftGalleryDetailsNavigationProperties, + options?: EventOptions + ): PromiseResult; + + /** + * NFT Gallery Details Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/NFT%20Gallery%20Details%20Page%20Viewed) + * + * This event tracks when a user views the details page of an NFT item. + * @param options Amplitude event options. + */ + nftGalleryDetailsPageViewed( + options?: EventOptions + ): PromiseResult; + + /** + * NFT Gallery Details Tab + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/NFT%20Gallery%20Details%20Tab) + * + * This event tracks user interactions with the tab in the NFT Gallery details page. It provides insights into how users engage with specific details of NFTs, such as descriptions, attributes, or additional information + * @param properties The event's properties (e.g. nft_tab) + * @param options Amplitude event options. + */ + nftGalleryDetailsTab( + properties: NftGalleryDetailsTabProperties, + options?: EventOptions + ): PromiseResult; + + /** + * NFT Gallery Grid View Selected + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/NFT%20Gallery%20Grid%20View%20Selected) + * + * This event is triggered when a user selects the grid view option in the NFT gallery + * @param properties The event's properties (e.g. nft_grid_view) + * @param options Amplitude event options. + */ + nftGalleryGridViewSelected( + properties?: NftGalleryGridViewSelectedProperties, + options?: EventOptions + ): PromiseResult; + + /** + * NFT Gallery Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/NFT%20Gallery%20Page%20Viewed) + * + * This event tracks when the NFT gallery it has loaded all nfts metadata + * @param properties The event's properties (e.g. nft_count) + * @param options Amplitude event options. + */ + nftGalleryPageViewed( + properties: NftGalleryPageViewedProperties, + options?: EventOptions + ): PromiseResult; + + /** + * NFT Gallery Search Activated + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/NFT%20Gallery%20Search%20Activated) + * + * User activates and starts a search in the NFT gallery. Delay of 0.5 seconds. + * @param properties The event's properties (e.g. nft_count) + * @param options Amplitude event options. + */ + nftGallerySearchActivated( + properties: NftGallerySearchActivatedProperties, + options?: EventOptions + ): PromiseResult; + + /** + * Receive Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Receive%20Page%20Viewed) + * + * This event tracks when a user views the Receive page of the Wallet menu. + * @param options Amplitude event options. + */ + receivePageViewed( + options?: EventOptions + ): PromiseResult; + + /** + * Restore Wallet Details Step Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Restore%20Wallet%20Details%20Step%20Viewed) + * + * Event has no description in tracking plan. + * @param options Amplitude event options. + */ + restoreWalletDetailsStepViewed( + options?: EventOptions + ): PromiseResult; + + /** + * Restore Wallet Details Submitted + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Restore%20Wallet%20Details%20Submitted) + * + * Event has no description in tracking plan. + * @param options Amplitude event options. + */ + restoreWalletDetailsSubmitted( + options?: EventOptions + ): PromiseResult; + + /** + * Restore Wallet Enter Phrase Step Status + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Restore%20Wallet%20Enter%20Phrase%20Step%20Status) + * + * Event has no description in tracking plan. + * @param properties The event's properties (e.g. recovery_prhase_status) + * @param options Amplitude event options. + */ + restoreWalletEnterPhraseStepStatus( + properties: RestoreWalletEnterPhraseStepStatusProperties, + options?: EventOptions + ): PromiseResult; + + /** + * Restore Wallet Enter Phrase Step Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Restore%20Wallet%20Enter%20Phrase%20Step%20Viewed) + * + * This event tracks when a user views the step to enter the recovery phrase while restoring a wallet (**Step 2**). + * @param properties The event's properties (e.g. recovery_phrase_lenght) + * @param options Amplitude event options. + */ + restoreWalletEnterPhraseStepViewed( + properties: RestoreWalletEnterPhraseStepViewedProperties, + options?: EventOptions + ): PromiseResult; + + /** + * Restore Wallet Type Step Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Restore%20Wallet%20Type%20Step%20Viewed) + * + * This event tracks when a user views the **first step after** selecting restore wallet, were they have to choose between: + * + * * 15-word recovery phrase + * + * * 24-word recovery phrase + * @param options Amplitude event options. + */ + restoreWalletTypeStepViewed( + options?: EventOptions + ): PromiseResult; + + /** + * Send Initiated + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Send%20Initiated) + * + * This event tracks when a user loads the default state of the first step of the multiasset transaction flow. That screen shows receiver address and optional memo + * @param options Amplitude event options. + */ + sendInitiated(options?: EventOptions): PromiseResult; + + /** + * Send Select Asset Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Send%20Select%20Asset%20Page%20Viewed) + * + * This event tracks when a user views the "Amount" page in the send flow. + * @param options Amplitude event options. + */ + sendSelectAssetPageViewed( + options?: EventOptions + ): PromiseResult; + + /** + * Send Select Asset Selected + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Send%20Select%20Asset%20Selected) + * + * When a user click "next" on the send flow: "Amount" step on extension / "Assets added" in mobile + * @param properties The event's properties (e.g. asset_count) + * @param options Amplitude event options. + */ + sendSelectAssetSelected( + properties: SendSelectAssetSelectedProperties, + options?: EventOptions + ): PromiseResult; + + /** + * Send Select Asset Updated + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Send%20Select%20Asset%20Updated) + * + * When an user update the tokens selection on "amount" step: + * \- Add + * \- Remove + * \- Updated + * @param properties The event's properties (e.g. asset_count) + * @param options Amplitude event options. + */ + sendSelectAssetUpdated( + properties: SendSelectAssetUpdatedProperties, + options?: EventOptions + ): PromiseResult; + + /** + * Send Summary Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Send%20Summary%20Page%20Viewed) + * + * When a user loads the Preview page (Could be called comfirmation too) on the send flow. + * @param properties The event's properties (e.g. asset_count) + * @param options Amplitude event options. + */ + sendSummaryPageViewed( + properties: SendSummaryPageViewedProperties, + options?: EventOptions + ): PromiseResult; + + /** + * Send Summary Submitted + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Send%20Summary%20Submitted) + * + * When a user click "send" on the "Preview" step on the send flow. + * @param properties The event's properties (e.g. asset_count) + * @param options Amplitude event options. + */ + sendSummarySubmitted( + properties: SendSummarySubmittedProperties, + options?: EventOptions + ): PromiseResult; + + /** + * Settings Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Settings%20Page%20Viewed) + * + * This event tracks when a user views the settings page within the application. + * @param options Amplitude event options. + */ + settingsPageViewed( + options?: EventOptions + ): PromiseResult; + + /** + * Staking Center Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Staking%20Center%20Page%20Viewed) + * + * This event tracks when a user views the Staking Center page on Staking menu. + * @param options Amplitude event options. + */ + stakingCenterPageViewed( + options?: EventOptions + ): PromiseResult; + + /** + * Staking Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Staking%20Page%20Viewed) + * + * This event tracks when a user views the Staking page. + * @param options Amplitude event options. + */ + stakingPageViewed( + options?: EventOptions + ): PromiseResult; + + /** + * Swap Asset From Changed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Swap%20Asset%20From%20Changed) + * + * When user changed the selected asset on "From" section + * + * Owner: Omar Rozak + * @param properties The event's properties (e.g. from_asset) + * @param options Amplitude event options. + */ + swapAssetFromChanged( + properties: SwapAssetFromChangedProperties, + options?: EventOptions + ): PromiseResult; + + /** + * Swap Asset To Changed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Swap%20Asset%20To%20Changed) + * + * When user changed the selected asset on "To" section + * + * Owner: Omar Rozak + * @param properties The event's properties (e.g. to_asset) + * @param options Amplitude event options. + */ + swapAssetToChanged( + properties: SwapAssetToChangedProperties, + options?: EventOptions + ): PromiseResult; + + /** + * Swap Cancelation Submitted + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Swap%20Cancelation%20Submitted) + * + * When user sign a transaction to cancel the swap order + * + * Owner: Omar Rozak + * @param properties The event's properties (e.g. from_amount) + * @param options Amplitude event options. + */ + swapCancelationSubmitted( + properties: SwapCancelationSubmittedProperties, + options?: EventOptions + ): PromiseResult; + + /** + * Swap Confirmed Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Swap%20Confirmed%20%20Page%20Viewed) + * + * When the user opens Completed Order page + * + * Owner: Omar Rozak + * @param properties The event's properties (e.g. swap_tab) + * @param options Amplitude event options. + */ + swapConfirmedPageViewed( + properties: SwapConfirmedPageViewedProperties, + options?: EventOptions + ): PromiseResult; + + /** + * Swap Initiated + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Swap%20Initiated) + * + * When user clicks on the swap feature and sees the default state of the swap. + * + * Owner: Omar Rozak + * @param properties The event's properties (e.g. from_asset) + * @param options Amplitude event options. + */ + swapInitiated( + properties: SwapInitiatedProperties, + options?: EventOptions + ): PromiseResult; + + /** + * Swap Order Selected + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Swap%20Order%20Selected) + * + * When user click on "swap" button after selecting asset from, entering the amount of asset form, selecting asset to, entering amount of asset to, and choosing a pool + * + * Owner: Omar Rozak + * @param properties The event's properties (e.g. from_amount) + * @param options Amplitude event options. + */ + swapOrderSelected( + properties: SwapOrderSelectedProperties, + options?: EventOptions + ): PromiseResult; + + /** + * Swap Order Submitted + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Swap%20Order%20Submitted) + * + * When user click confirm on the check out page, after entering their spending password + * + * Owner: Omar Rozak + * @param properties The event's properties (e.g. from_amount) + * @param options Amplitude event options. + */ + swapOrderSubmitted( + properties: SwapOrderSubmittedProperties, + options?: EventOptions + ): PromiseResult; + + /** + * Swap Pool Changed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Swap%20Pool%20Changed) + * + * When user clicked a different pool on the "Select Pool" page + * + * Owner: Sergio SF + * @param options Amplitude event options. + */ + swapPoolChanged( + options?: EventOptions + ): PromiseResult; + + /** + * Swap Slippage Changed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Swap%20Slippage%20Changed) + * + * When user click apply on the swap setting page + * + * Owner: Omar Rozak + * @param properties The event's properties (e.g. slippage_tolerance) + * @param options Amplitude event options. + */ + swapSlippageChanged( + properties: SwapSlippageChangedProperties, + options?: EventOptions + ): PromiseResult; + + /** + * Transactions Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Transactions%20Page%20Viewed) + * + * This event tracks when a user views the transactions page within the wallet. + * @param options Amplitude event options. + */ + transactionsPageViewed( + options?: EventOptions + ): PromiseResult; + + /** + * Voting Page Viewed + * + * [View in Tracking Plan](https://data.amplitude.com/emurgo/Yoroi/events/main/latest/Voting%20Page%20Viewed) + * + * This event tracks when a user views the Voting page. + * @param options Amplitude event options. + */ + votingPageViewed( + options?: EventOptions + ): PromiseResult; +} +declare export var ampli: Ampli; +declare type BrowserOptions = any; +export type BrowserClient = any; +export type IdentifyEvent = any; +export type GroupEvent = any; +export type Event = any; +export type EventOptions = any; +export type Result = any; diff --git a/packages/yoroi-extension/app/App.js b/packages/yoroi-extension/app/App.js index 19b9294b34..12aa34f154 100644 --- a/packages/yoroi-extension/app/App.js +++ b/packages/yoroi-extension/app/App.js @@ -17,11 +17,10 @@ import MaintenancePage from './containers/MaintenancePage'; import CrashPage from './containers/CrashPage'; import { Logger } from './utils/logging'; import { LayoutProvider } from './styles/context/layout'; -import { ThemeProvider } from '@mui/material/styles'; +import { ColorModeProvider } from './styles/context/mode'; import { CssBaseline } from '@mui/material'; import { globalStyles } from './styles/globalStyles'; import Support from './components/widgets/Support'; -import { trackNavigation } from './api/analytics'; // https://github.com/yahoo/react-intl/wiki#loading-locale-data addLocaleData(locales); @@ -50,9 +49,6 @@ class App extends Component { this.mergedMessages = _mergedMessages; }); }); - this.props.history.listen(({ pathname }) => { - trackNavigation(pathname); - }); }; state: State = { @@ -96,7 +92,7 @@ class App extends Component { return (
- + {globalStyles(muiTheme)} @@ -104,7 +100,7 @@ class App extends Component { {this.getContent()} - +
); diff --git a/packages/yoroi-extension/app/Routes.js b/packages/yoroi-extension/app/Routes.js index af8cb8f56a..f174240a40 100644 --- a/packages/yoroi-extension/app/Routes.js +++ b/packages/yoroi-extension/app/Routes.js @@ -38,6 +38,8 @@ const TermsOfUsePagePromise = () => import('./containers/profile/TermsOfUsePage' const TermsOfUsePage = React.lazy(TermsOfUsePagePromise); const UriPromptPagePromise = () => import('./containers/profile/UriPromptPage'); const UriPromptPage = React.lazy(UriPromptPagePromise); +const OptForAnalyticsPagePromise = () => import('./containers/profile/OptForAnalyticsPage'); +const OptForAnalyticsPage = React.lazy(OptForAnalyticsPagePromise); // SETTINGS const GeneralSettingsPagePromise = () => @@ -57,6 +59,9 @@ const TermsOfUseSettingsPage = React.lazy(TermsOfUseSettingsPagePromise); const SupportSettingsPagePromise = () => import('./containers/settings/categories/SupportSettingsPage'); const SupportSettingsPage = React.lazy(SupportSettingsPagePromise); +const AnalyticsSettingsPagePromise = () => + import('./containers/settings/categories/AnalyticsSettingsPage'); +const AnalyticsSettingsPage = React.lazy(AnalyticsSettingsPagePromise); const NightlyPagePromise = () => import('./containers/profile/NightlyPage'); const NightlyPage = React.lazy(NightlyPagePromise); @@ -162,6 +167,8 @@ export const LazyLoadPromises: Array<() => any> = [ ConnectedWebsitesPagePromise, YoroiPalettePagePromise, YoroiThemesPagePromise, + OptForAnalyticsPagePromise, + AnalyticsSettingsPagePromise, ]; // populated by ConfigWebpackPlugin @@ -201,6 +208,11 @@ export const Routes = (stores: StoresMap, actions: ActionsMap): Node => ( path={ROUTES.PROFILE.URI_PROMPT} component={props => } /> + } + /> ( )} /> + ( + + )} + /> ); diff --git a/packages/yoroi-extension/app/actions/ada/delegation-transaction-actions.js b/packages/yoroi-extension/app/actions/ada/delegation-transaction-actions.js index 98751676cf..a92aee6e28 100644 --- a/packages/yoroi-extension/app/actions/ada/delegation-transaction-actions.js +++ b/packages/yoroi-extension/app/actions/ada/delegation-transaction-actions.js @@ -14,6 +14,7 @@ export default class DelegationTransactionActions { signTransaction: AsyncAction<{| password?: string, publicDeriver: PublicDeriver<>, + dialog?: any, |}> = new AsyncAction(); setShouldDeregister: Action = new Action(); complete: Action = new Action(); diff --git a/packages/yoroi-extension/app/actions/base/base-profile-actions.js b/packages/yoroi-extension/app/actions/base/base-profile-actions.js index bafc2a9e91..ce1c6775ae 100644 --- a/packages/yoroi-extension/app/actions/base/base-profile-actions.js +++ b/packages/yoroi-extension/app/actions/base/base-profile-actions.js @@ -16,4 +16,6 @@ export default class BaseProfileActions { updateHideBalance: AsyncAction = new AsyncAction(); acceptNightly: Action = new Action(); updateUnitOfAccount: AsyncAction = new AsyncAction(); + optForAnalytics: Action = new Action(); + markRevampAsAnnounced: AsyncAction < void> = new AsyncAction(); } diff --git a/packages/yoroi-extension/app/actions/common/tx-builder-actions.js b/packages/yoroi-extension/app/actions/common/tx-builder-actions.js index 051feb3132..547e2f1c7f 100644 --- a/packages/yoroi-extension/app/actions/common/tx-builder-actions.js +++ b/packages/yoroi-extension/app/actions/common/tx-builder-actions.js @@ -14,6 +14,7 @@ export default class TxBuilderActions { updateMemo: Action = new Action(); addToken: Action<{| token?: $ReadOnly, + shouldSendAll?: boolean, shouldReset?: boolean, |}> = new Action(); calculateMaxAmount: AsyncAction = new AsyncAction(); diff --git a/packages/yoroi-extension/app/api/ada/index.js b/packages/yoroi-extension/app/api/ada/index.js index fba7b117da..e589e28645 100644 --- a/packages/yoroi-extension/app/api/ada/index.js +++ b/packages/yoroi-extension/app/api/ada/index.js @@ -132,7 +132,7 @@ import type { TokenInfoFunc, RemoteUnspentOutput, GetRecentTransactionHashesFunc, - GetTransactionsByHashesFunc, + GetTransactionsByHashesFunc, MultiAssetSupplyFunc, } from './lib/state-fetch/types'; import type { FilterFunc, } from '../common/lib/state-fetch/currencySpecificTypes'; import { getChainAddressesForDisplay, } from './lib/storage/models/utils'; @@ -239,6 +239,7 @@ export type AdaGetTransactionsRequest = {| getBestBlock: BestBlockFunc, getTokenInfo: TokenInfoFunc, getMultiAssetMetadata: MultiAssetMintMetadataFunc, + getMultiAssetSupply: MultiAssetSupplyFunc, afterTxs?: ?Array, getRecentTransactionHashes: GetRecentTransactionHashesFunc, getTransactionsByHashes: GetTransactionsByHashesFunc, @@ -697,6 +698,7 @@ export default class AdaApi { request.checkAddressesInUse, request.getTokenInfo, request.getMultiAssetMetadata, + request.getMultiAssetSupply, ); } @@ -720,6 +722,7 @@ export default class AdaApi { request.getBestBlock, request.getTokenInfo, request.getMultiAssetMetadata, + request.getMultiAssetSupply, after, ); } diff --git a/packages/yoroi-extension/app/api/ada/lib/state-fetch/IFetcher.js b/packages/yoroi-extension/app/api/ada/lib/state-fetch/IFetcher.js index 4382d7a4cf..70ffa56ee4 100644 --- a/packages/yoroi-extension/app/api/ada/lib/state-fetch/IFetcher.js +++ b/packages/yoroi-extension/app/api/ada/lib/state-fetch/IFetcher.js @@ -12,11 +12,11 @@ import type { CatalystRoundInfoRequest, CatalystRoundInfoResponse, BestBlockRequest, BestBlockResponse, TokenInfoRequest, TokenInfoResponse, - MultiAssetMintMetadataRequest, MultiAssetMintMetadataResponse, + MultiAssetRequest, MultiAssetMintMetadataResponse, GetUtxoDataRequest, GetUtxoDataResponse, GetLatestBlockBySlotReq, GetLatestBlockBySlotRes, GetRecentTransactionHashesRequest, GetRecentTransactionHashesResponse, - GetTransactionsByHashesRequest, GetTransactionsByHashesResponse, + GetTransactionsByHashesRequest, GetTransactionsByHashesResponse, MultiAssetSupplyResponse, } from './types'; import type { FilterUsedRequest, FilterUsedResponse, @@ -35,8 +35,10 @@ export interface IFetcher { getCatalystRoundInfo(body: CatalystRoundInfoRequest): Promise; getTokenInfo(body: TokenInfoRequest): Promise; checkAddressesInUse(body: FilterUsedRequest): Promise; - getMultiAssetMintMetadata(body: MultiAssetMintMetadataRequest) + getMultiAssetMintMetadata(body: MultiAssetRequest) : Promise; + getMultiAssetSupply(body: MultiAssetRequest) + : Promise; getUtxoData(body: GetUtxoDataRequest): Promise; getLatestBlockBySlot(body: GetLatestBlockBySlotReq): Promise; getRecentTransactionHashes diff --git a/packages/yoroi-extension/app/api/ada/lib/state-fetch/batchedFetcher.js b/packages/yoroi-extension/app/api/ada/lib/state-fetch/batchedFetcher.js index b607b2e179..ec3f7dc1c3 100644 --- a/packages/yoroi-extension/app/api/ada/lib/state-fetch/batchedFetcher.js +++ b/packages/yoroi-extension/app/api/ada/lib/state-fetch/batchedFetcher.js @@ -2,28 +2,51 @@ import BigNumber from 'bignumber.js'; import type { - AddressUtxoRequest, AddressUtxoResponse, - TxBodiesRequest, TxBodiesResponse, - UtxoSumRequest, UtxoSumResponse, - HistoryRequest, HistoryResponse, - RewardHistoryFunc, RewardHistoryRequest, RewardHistoryResponse, - PoolInfoFunc, PoolInfoRequest, PoolInfoResponse, - TokenInfoFunc, TokenInfoRequest, TokenInfoResponse, - AccountStateFunc, AccountStateRequest, AccountStateResponse, - CatalystRoundInfoFunc,CatalystRoundInfoRequest, CatalystRoundInfoResponse, - SignedRequest, SignedResponse, - BestBlockRequest, BestBlockResponse, + AddressUtxoRequest, + AddressUtxoResponse, + TxBodiesRequest, + TxBodiesResponse, + UtxoSumRequest, + UtxoSumResponse, + HistoryRequest, + HistoryResponse, + RewardHistoryFunc, + RewardHistoryRequest, + RewardHistoryResponse, + PoolInfoFunc, + PoolInfoRequest, + PoolInfoResponse, + TokenInfoFunc, + TokenInfoRequest, + TokenInfoResponse, + AccountStateFunc, + AccountStateRequest, + AccountStateResponse, + CatalystRoundInfoFunc, + CatalystRoundInfoRequest, + CatalystRoundInfoResponse, + SignedRequest, + SignedResponse, + BestBlockRequest, + BestBlockResponse, AddressUtxoFunc, HistoryFunc, TxBodiesFunc, UtxoSumFunc, RemoteTransaction, - MultiAssetMintMetadataRequest, + MultiAssetRequest, MultiAssetMintMetadataResponse, - GetUtxoDataFunc, GetUtxoDataRequest, GetUtxoDataResponse, + GetUtxoDataFunc, + GetUtxoDataRequest, + GetUtxoDataResponse, GetLatestBlockBySlotFunc, - GetRecentTransactionHashesRequest, GetRecentTransactionHashesResponse, GetRecentTransactionHashesFunc, - GetTransactionsByHashesRequest, GetTransactionsByHashesResponse, GetTransactionsByHashesFunc, + GetRecentTransactionHashesRequest, + GetRecentTransactionHashesResponse, + GetRecentTransactionHashesFunc, + GetTransactionsByHashesRequest, + GetTransactionsByHashesResponse, + GetTransactionsByHashesFunc, + MultiAssetSupplyResponse, } from './types'; import type { FilterFunc, FilterUsedRequest, FilterUsedResponse, @@ -122,7 +145,7 @@ export class BatchedFetcher implements IFetcher { ) getMultiAssetMintMetadata - : MultiAssetMintMetadataRequest => Promise + : MultiAssetRequest => Promise = async (body) => { const { network, assets } = body; const assetChunks = chunk(assets, MINT_METADATA_REQUEST_PAGE_SIZE); @@ -138,6 +161,23 @@ export class BatchedFetcher implements IFetcher { return result; } + getMultiAssetSupply + : MultiAssetRequest => Promise + = async (body) => { + const { network, assets } = body; + const assetChunks = chunk(assets, MINT_METADATA_REQUEST_PAGE_SIZE); + const responses = await Promise.all(assetChunks.map( + batch => this.baseFetcher.getMultiAssetSupply({ network, assets: batch }) + )); + const result = {}; + for (const response of responses) { + for (const [key, value] of Object.entries(response)) { + result[key] = value; + } + } + return result; + } + getAccountState: AccountStateRequest => Promise = (body) => ( batchGetAccountState(this.baseFetcher.getAccountState)(body) ) diff --git a/packages/yoroi-extension/app/api/ada/lib/state-fetch/mockNetwork.js b/packages/yoroi-extension/app/api/ada/lib/state-fetch/mockNetwork.js index 0e89705ba0..6ecb0dd606 100644 --- a/packages/yoroi-extension/app/api/ada/lib/state-fetch/mockNetwork.js +++ b/packages/yoroi-extension/app/api/ada/lib/state-fetch/mockNetwork.js @@ -2,20 +2,38 @@ import BigNumber from 'bignumber.js'; import type { - HistoryRequest, HistoryResponse, HistoryFunc, - BestBlockRequest, BestBlockResponse, BestBlockFunc, - AddressUtxoRequest, AddressUtxoResponse, AddressUtxoFunc, - UtxoSumRequest, UtxoSumResponse, UtxoSumFunc, + HistoryRequest, + HistoryResponse, + HistoryFunc, + BestBlockRequest, + BestBlockResponse, + BestBlockFunc, + AddressUtxoRequest, + AddressUtxoResponse, + AddressUtxoFunc, + UtxoSumRequest, + UtxoSumResponse, + UtxoSumFunc, RewardHistoryFunc, - AccountStateRequest, AccountStateResponse, AccountStateFunc, - PoolInfoRequest, PoolInfoResponse, PoolInfoFunc, - RemoteTransaction, RemoteUnspentOutput, + AccountStateRequest, + AccountStateResponse, + AccountStateFunc, + PoolInfoRequest, + PoolInfoResponse, + PoolInfoFunc, + RemoteTransaction, + RemoteUnspentOutput, SignedRequestInternal, RemoteTransactionInput, TokenInfoFunc, MultiAssetMintMetadataFunc, - GetTransactionsByHashesRequest, GetTransactionsByHashesResponse, GetTransactionsByHashesFunc, - GetRecentTransactionHashesRequest, GetRecentTransactionHashesResponse, GetRecentTransactionHashesFunc, + GetTransactionsByHashesRequest, + GetTransactionsByHashesResponse, + GetTransactionsByHashesFunc, + GetRecentTransactionHashesRequest, + GetRecentTransactionHashesResponse, + GetRecentTransactionHashesFunc, + MultiAssetSupplyFunc, } from './types'; import type { FilterUsedRequest, FilterUsedResponse, FilterFunc, @@ -730,6 +748,10 @@ export function genGetMultiAssetMetadata( return async (_) => ({}); } +export function genGetMultiAssetSupply( +): MultiAssetSupplyFunc { + return async (_) => ({}); +} export class MockUtxoApi implements UtxoApiContract { blockchain: Array; diff --git a/packages/yoroi-extension/app/api/ada/lib/state-fetch/remoteFetcher.js b/packages/yoroi-extension/app/api/ada/lib/state-fetch/remoteFetcher.js index 89fe3f449f..c5a9305d06 100644 --- a/packages/yoroi-extension/app/api/ada/lib/state-fetch/remoteFetcher.js +++ b/packages/yoroi-extension/app/api/ada/lib/state-fetch/remoteFetcher.js @@ -25,7 +25,7 @@ import type { UtxoSumResponse, CatalystRoundInfoRequest, CatalystRoundInfoResponse, - MultiAssetMintMetadataRequest, + MultiAssetRequest, MultiAssetMintMetadataResponse, GetUtxoDataRequest, GetUtxoDataResponse, @@ -33,7 +33,7 @@ import type { GetRecentTransactionHashesRequest, GetRecentTransactionHashesResponse, GetTransactionsByHashesRequest, - GetTransactionsByHashesResponse, + GetTransactionsByHashesResponse, MultiAssetSupplyResponse, } from './types'; import type { FilterUsedRequest, FilterUsedResponse, } from '../../../common/lib/state-fetch/currencySpecificTypes'; @@ -528,7 +528,7 @@ export class RemoteFetcher implements IFetcher { }); } - getMultiAssetMintMetadata: MultiAssetMintMetadataRequest + getMultiAssetMintMetadata: MultiAssetRequest => Promise = async (body) => { const { BackendService } = body.network.Backend; if (BackendService == null) throw new Error(`${nameof(this.getMultiAssetMintMetadata)} missing backend url`); @@ -547,6 +547,25 @@ export class RemoteFetcher implements IFetcher { }); } + getMultiAssetSupply: MultiAssetRequest + => Promise = async (body) => { + const { BackendService } = body.network.Backend; + if (BackendService == null) throw new Error(`${nameof(this.getMultiAssetSupply)} missing backend url`); + return await axios( + `${BackendService}/api/multiAsset/supply?numberFormat=string`, + { + method: 'post', + data: { + assets: body.assets + } + } + ).then(response => response.data.supplies) + .catch((error) => { + Logger.error(`${nameof(RemoteFetcher)}::${nameof(this.getMultiAssetSupply)} error: ` + stringifyError(error)); + return {}; + }); + } + getUtxoData: GetUtxoDataRequest => Promise = async (body) => { const { BackendService } = body.network.Backend; if (body.utxos.length !== 1) { diff --git a/packages/yoroi-extension/app/api/ada/lib/state-fetch/types.js b/packages/yoroi-extension/app/api/ada/lib/state-fetch/types.js index 0746b9e55a..b765ba7806 100644 --- a/packages/yoroi-extension/app/api/ada/lib/state-fetch/types.js +++ b/packages/yoroi-extension/app/api/ada/lib/state-fetch/types.js @@ -374,15 +374,18 @@ export type CatalystRoundInfoFunc = (body: CatalystRoundInfoRequest) // Multi Asset Mint Metadata -export type MultiAssetMintMetadataFunc = (body: MultiAssetMintMetadataRequest) +export type MultiAssetMintMetadataFunc = (body: MultiAssetRequest) => Promise; -export type MultiAssetMintMetadataRequest = {| +export type MultiAssetSupplyFunc = (body: MultiAssetRequest) + => Promise; + +export type MultiAssetRequest = {| ...BackendNetworkInfo, - assets: MultiAssetMintMetadataRequestAsset[] + assets: MultiAssetRequestAsset[] |}; -export type MultiAssetMintMetadataRequestAsset = {| +export type MultiAssetRequestAsset = {| nameHex: string, policy: string |} @@ -391,6 +394,10 @@ export type MultiAssetMintMetadataResponse = {| ...{[key: string]: MultiAssetMintMetadataResponseAsset[]} |} +export type MultiAssetSupplyResponse = {| + ...{[key: string]: string} +|} + export type MultiAssetMintMetadataResponseAsset = {| key: string, metadata: {[key: string]: any} diff --git a/packages/yoroi-extension/app/api/ada/lib/storage/bridge/tests/__snapshots__/multiwallet.test.js.snap b/packages/yoroi-extension/app/api/ada/lib/storage/bridge/tests/__snapshots__/multiwallet.test.js.snap index aac8aefc13..735e3ebf3b 100644 --- a/packages/yoroi-extension/app/api/ada/lib/storage/bridge/tests/__snapshots__/multiwallet.test.js.snap +++ b/packages/yoroi-extension/app/api/ada/lib/storage/bridge/tests/__snapshots__/multiwallet.test.js.snap @@ -765,6 +765,22 @@ Array [ "NetworkId": 350, "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": 450, + "TokenId": 7, + }, ], }, Object { diff --git a/packages/yoroi-extension/app/api/ada/lib/storage/bridge/tests/__snapshots__/shelley.test.js.snap b/packages/yoroi-extension/app/api/ada/lib/storage/bridge/tests/__snapshots__/shelley.test.js.snap index 98bf0fe207..fba5d2a287 100644 --- a/packages/yoroi-extension/app/api/ada/lib/storage/bridge/tests/__snapshots__/shelley.test.js.snap +++ b/packages/yoroi-extension/app/api/ada/lib/storage/bridge/tests/__snapshots__/shelley.test.js.snap @@ -596,6 +596,22 @@ Array [ "NetworkId": 350, "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": 450, + "TokenId": 7, + }, ], }, Object { diff --git a/packages/yoroi-extension/app/api/ada/lib/storage/bridge/tests/__snapshots__/simpleTxs.test.js.snap b/packages/yoroi-extension/app/api/ada/lib/storage/bridge/tests/__snapshots__/simpleTxs.test.js.snap index 128070fc72..515f616442 100644 --- a/packages/yoroi-extension/app/api/ada/lib/storage/bridge/tests/__snapshots__/simpleTxs.test.js.snap +++ b/packages/yoroi-extension/app/api/ada/lib/storage/bridge/tests/__snapshots__/simpleTxs.test.js.snap @@ -600,6 +600,22 @@ Array [ "NetworkId": 350, "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": 450, + "TokenId": 7, + }, ], }, Object { diff --git a/packages/yoroi-extension/app/api/ada/lib/storage/bridge/tests/__snapshots__/status.test.js.snap b/packages/yoroi-extension/app/api/ada/lib/storage/bridge/tests/__snapshots__/status.test.js.snap index 49b2545432..38e9957d74 100644 --- a/packages/yoroi-extension/app/api/ada/lib/storage/bridge/tests/__snapshots__/status.test.js.snap +++ b/packages/yoroi-extension/app/api/ada/lib/storage/bridge/tests/__snapshots__/status.test.js.snap @@ -1054,6 +1054,22 @@ Array [ "NetworkId": 350, "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": 450, + "TokenId": 7, + }, ], }, Object { @@ -2300,6 +2316,22 @@ Array [ "NetworkId": 350, "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": 450, + "TokenId": 7, + }, ], }, Object { diff --git a/packages/yoroi-extension/app/api/ada/lib/storage/bridge/tests/multiwallet.test.js b/packages/yoroi-extension/app/api/ada/lib/storage/bridge/tests/multiwallet.test.js index f672ad9020..090ab051dc 100644 --- a/packages/yoroi-extension/app/api/ada/lib/storage/bridge/tests/multiwallet.test.js +++ b/packages/yoroi-extension/app/api/ada/lib/storage/bridge/tests/multiwallet.test.js @@ -30,7 +30,7 @@ import { genGetMultiAssetMetadata, MockUtxoApi, genGetRecentTransactionHashes, - genGetTransactionsByHashes, + genGetTransactionsByHashes, genGetMultiAssetSupply, } from '../../../state-fetch/mockNetwork'; import { loadLovefieldDB } from '../../database/index'; @@ -400,6 +400,7 @@ async function syncingSimpleTransaction( const getBestBlock = genGetBestBlock(txHistory); const getTokenInfo = genGetTokenInfo(); const getMultiAssetMetadata = genGetMultiAssetMetadata(); + const getMultiAssetSupply = genGetMultiAssetSupply(); const getRecentTransactionHashes = genGetRecentTransactionHashes(txHistory); const getTransactionsByHashes = genGetTransactionsByHashes(txHistory); @@ -421,7 +422,8 @@ async function syncingSimpleTransaction( withUtxos1, checkAddressesInUse, getTokenInfo, - getMultiAssetMetadata + getMultiAssetMetadata, + getMultiAssetSupply, ); await updateTransactions( db, @@ -431,7 +433,8 @@ async function syncingSimpleTransaction( getTransactionsByHashes, getBestBlock, getTokenInfo, - getMultiAssetMetadata + getMultiAssetMetadata, + getMultiAssetSupply, ); await checkPub1HasTx(purposeForTest, publicDeriver1); @@ -469,7 +472,8 @@ async function syncingSimpleTransaction( withUtxos2, checkAddressesInUse, getTokenInfo, - getMultiAssetMetadata + getMultiAssetMetadata, + getMultiAssetSupply, ); await updateTransactions( db, @@ -479,7 +483,8 @@ async function syncingSimpleTransaction( getTransactionsByHashes, getBestBlock, getTokenInfo, - getMultiAssetMetadata + getMultiAssetMetadata, + getMultiAssetSupply, ); await checkPub2HasTx(purposeForTest, publicDeriver2); { @@ -504,7 +509,8 @@ async function syncingSimpleTransaction( withUtxos2, checkAddressesInUse, getTokenInfo, - getMultiAssetMetadata + getMultiAssetMetadata, + getMultiAssetSupply, ); await updateTransactions( db, @@ -514,7 +520,8 @@ async function syncingSimpleTransaction( getTransactionsByHashes, getBestBlock, getTokenInfo, - getMultiAssetMetadata + getMultiAssetMetadata, + getMultiAssetSupply, ); await checkPub2IsEmpty(publicDeriver2); { @@ -556,7 +563,8 @@ async function syncingSimpleTransaction( withUtxos2, checkAddressesInUse, getTokenInfo, - getMultiAssetMetadata + getMultiAssetMetadata, + getMultiAssetSupply, ); await updateTransactions( db, @@ -566,7 +574,8 @@ async function syncingSimpleTransaction( getTransactionsByHashes, getBestBlock, getTokenInfo, - getMultiAssetMetadata + getMultiAssetMetadata, + getMultiAssetSupply, ); await checkPub2HasTx(purposeForTest, publicDeriver2); diff --git a/packages/yoroi-extension/app/api/ada/lib/storage/bridge/tests/shelley.test.js b/packages/yoroi-extension/app/api/ada/lib/storage/bridge/tests/shelley.test.js index 47efbe20bd..b7add3333b 100644 --- a/packages/yoroi-extension/app/api/ada/lib/storage/bridge/tests/shelley.test.js +++ b/packages/yoroi-extension/app/api/ada/lib/storage/bridge/tests/shelley.test.js @@ -23,7 +23,7 @@ import { genGetMultiAssetMetadata, MockUtxoApi, genGetRecentTransactionHashes, - genGetTransactionsByHashes, + genGetTransactionsByHashes, genGetMultiAssetSupply, } from '../../../state-fetch/mockNetwork'; import { HARD_DERIVATION_START, @@ -226,6 +226,7 @@ async function syncingSimpleTransaction( const getBestBlock = genGetBestBlock(txHistory); const getTokenInfo = genGetTokenInfo(); const getMultiAssetMetadata = genGetMultiAssetMetadata(); + const getMultiAssetSupply = genGetMultiAssetSupply(); const getRecentTransactionHashes = genGetRecentTransactionHashes(txHistory); const getTransactionsByHashes = genGetTransactionsByHashes(txHistory); @@ -248,7 +249,8 @@ async function syncingSimpleTransaction( basePubDeriver, checkAddressesInUse, getTokenInfo, - getMultiAssetMetadata + getMultiAssetMetadata, + getMultiAssetSupply, ); await updateTransactions( db, @@ -258,7 +260,8 @@ async function syncingSimpleTransaction( getTransactionsByHashes, getBestBlock, getTokenInfo, - getMultiAssetMetadata + getMultiAssetMetadata, + getMultiAssetSupply, ); { @@ -352,7 +355,8 @@ async function syncingSimpleTransaction( basePubDeriver, checkAddressesInUse, getTokenInfo, - getMultiAssetMetadata + getMultiAssetMetadata, + getMultiAssetSupply, ); await updateTransactions( db, @@ -362,7 +366,8 @@ async function syncingSimpleTransaction( getTransactionsByHashes, getBestBlock, getTokenInfo, - getMultiAssetMetadata + getMultiAssetMetadata, + getMultiAssetSupply, ); { diff --git a/packages/yoroi-extension/app/api/ada/lib/storage/bridge/tests/simpleTxs.test.js b/packages/yoroi-extension/app/api/ada/lib/storage/bridge/tests/simpleTxs.test.js index 49334a3788..bd10f277f0 100644 --- a/packages/yoroi-extension/app/api/ada/lib/storage/bridge/tests/simpleTxs.test.js +++ b/packages/yoroi-extension/app/api/ada/lib/storage/bridge/tests/simpleTxs.test.js @@ -24,7 +24,7 @@ import { genGetMultiAssetMetadata, MockUtxoApi, genGetRecentTransactionHashes, - genGetTransactionsByHashes, + genGetTransactionsByHashes, genGetMultiAssetSupply, } from '../../../state-fetch/mockNetwork'; import { HARD_DERIVATION_START, @@ -317,6 +317,7 @@ async function syncingSimpleTransaction( const getBestBlock = genGetBestBlock(txHistory); const getTokenInfo = genGetTokenInfo(); const getMultiAssetMetadata = genGetMultiAssetMetadata(); + const getMultiAssetSupply = genGetMultiAssetSupply(); const getRecentTransactionHashes = genGetRecentTransactionHashes(txHistory); const getTransactionsByHashes = genGetTransactionsByHashes(txHistory); @@ -341,6 +342,7 @@ async function syncingSimpleTransaction( checkAddressesInUse, getTokenInfo, getMultiAssetMetadata, + getMultiAssetSupply, ); await updateTransactions( db, @@ -350,7 +352,8 @@ async function syncingSimpleTransaction( getTransactionsByHashes, getBestBlock, getTokenInfo, - getMultiAssetMetadata + getMultiAssetMetadata, + getMultiAssetSupply, ); { @@ -445,6 +448,7 @@ async function syncingSimpleTransaction( checkAddressesInUse, getTokenInfo, getMultiAssetMetadata, + getMultiAssetSupply, ); await updateTransactions( db, @@ -454,7 +458,8 @@ async function syncingSimpleTransaction( getTransactionsByHashes, getBestBlock, getTokenInfo, - getMultiAssetMetadata + getMultiAssetMetadata, + getMultiAssetSupply, ); const dbDump2 = (await db.export()).tables; @@ -582,6 +587,7 @@ async function syncingSimpleTransaction( checkAddressesInUse, getTokenInfo, getMultiAssetMetadata, + getMultiAssetSupply, ); await updateTransactions( db, @@ -591,7 +597,8 @@ async function syncingSimpleTransaction( getTransactionsByHashes, getBestBlock, getTokenInfo, - getMultiAssetMetadata + getMultiAssetMetadata, + getMultiAssetSupply, ); { @@ -631,6 +638,7 @@ async function syncingSimpleTransaction( checkAddressesInUse, getTokenInfo, getMultiAssetMetadata, + getMultiAssetSupply, ); await updateTransactions( db, @@ -640,7 +648,8 @@ async function syncingSimpleTransaction( getTransactionsByHashes, getBestBlock, getTokenInfo, - getMultiAssetMetadata + getMultiAssetMetadata, + getMultiAssetSupply, ); { @@ -670,6 +679,7 @@ async function syncingSimpleTransaction( checkAddressesInUse, getTokenInfo, getMultiAssetMetadata, + getMultiAssetSupply, ); await updateTransactions( db, @@ -679,7 +689,8 @@ async function syncingSimpleTransaction( getTransactionsByHashes, getBestBlock, getTokenInfo, - getMultiAssetMetadata + getMultiAssetMetadata, + getMultiAssetSupply, ); { @@ -719,6 +730,7 @@ async function syncingSimpleTransaction( checkAddressesInUse, getTokenInfo, getMultiAssetMetadata, + getMultiAssetSupply, ); await updateTransactions( db, @@ -728,7 +740,8 @@ async function syncingSimpleTransaction( getTransactionsByHashes, getBestBlock, getTokenInfo, - getMultiAssetMetadata + getMultiAssetMetadata, + getMultiAssetSupply, ); { @@ -795,6 +808,7 @@ async function utxoCreatedAndUsed( const getBestBlock = genGetBestBlock(txHistory); const getTokenInfo = genGetTokenInfo(); const getMultiAssetMetadata = genGetMultiAssetMetadata(); + const getMultiAssetSupply = genGetMultiAssetSupply(); const getRecentTransactionHashes = genGetRecentTransactionHashes(txHistory); const getTransactionsByHashes = genGetTransactionsByHashes(txHistory); @@ -821,6 +835,7 @@ async function utxoCreatedAndUsed( checkAddressesInUse, getTokenInfo, getMultiAssetMetadata, + getMultiAssetSupply, ); await updateTransactions( db, @@ -830,7 +845,8 @@ async function utxoCreatedAndUsed( getTransactionsByHashes, getBestBlock, getTokenInfo, - getMultiAssetMetadata + getMultiAssetMetadata, + getMultiAssetSupply, ); { diff --git a/packages/yoroi-extension/app/api/ada/lib/storage/bridge/tests/status.test.js b/packages/yoroi-extension/app/api/ada/lib/storage/bridge/tests/status.test.js index a2bafbcf2f..fe88e6d62b 100644 --- a/packages/yoroi-extension/app/api/ada/lib/storage/bridge/tests/status.test.js +++ b/packages/yoroi-extension/app/api/ada/lib/storage/bridge/tests/status.test.js @@ -23,7 +23,7 @@ import { genGetMultiAssetMetadata, MockUtxoApi, genGetRecentTransactionHashes, - genGetTransactionsByHashes, + genGetTransactionsByHashes, genGetMultiAssetSupply, } from '../../../state-fetch/mockNetwork'; import { loadLovefieldDB } from '../../database/index'; import { @@ -324,6 +324,7 @@ async function baseTest( const getBestBlock = genGetBestBlock(networkTransactions); const getTokenInfo = genGetTokenInfo(); const getMultiAssetMetadata = genGetMultiAssetMetadata(); + const getMultiAssetSupply = genGetMultiAssetSupply(); const getRecentTransactionHashes = genGetRecentTransactionHashes(networkTransactions); const getTransactionsByHashes = genGetTransactionsByHashes(networkTransactions); @@ -343,6 +344,7 @@ async function baseTest( checkAddressesInUse, getTokenInfo, getMultiAssetMetadata, + getMultiAssetSupply, ); await updateTransactions( db, @@ -352,7 +354,8 @@ async function baseTest( getTransactionsByHashes, getBestBlock, getTokenInfo, - getMultiAssetMetadata + getMultiAssetMetadata, + getMultiAssetSupply, ); { @@ -398,6 +401,7 @@ async function baseTest( checkAddressesInUse, getTokenInfo, getMultiAssetMetadata, + getMultiAssetSupply, ); await updateTransactions( db, @@ -408,6 +412,7 @@ async function baseTest( getBestBlock, getTokenInfo, getMultiAssetMetadata, + getMultiAssetSupply, ); { @@ -533,6 +538,7 @@ async function baseTest( checkAddressesInUse, getTokenInfo, getMultiAssetMetadata, + getMultiAssetSupply, ); await updateTransactions( db, @@ -542,7 +548,8 @@ async function baseTest( getTransactionsByHashes, getBestBlock, getTokenInfo, - getMultiAssetMetadata + getMultiAssetMetadata, + getMultiAssetSupply, ); { @@ -723,6 +730,7 @@ async function baseTest( checkAddressesInUse, getTokenInfo, getMultiAssetMetadata, + getMultiAssetSupply, ); await updateTransactions( db, @@ -732,7 +740,8 @@ async function baseTest( getTransactionsByHashes, getBestBlock, getTokenInfo, - getMultiAssetMetadata + getMultiAssetMetadata, + getMultiAssetSupply, ); { @@ -902,6 +911,7 @@ async function baseTest( checkAddressesInUse, getTokenInfo, getMultiAssetMetadata, + getMultiAssetSupply, ); await updateTransactions( db, @@ -911,7 +921,8 @@ async function baseTest( getTransactionsByHashes, getBestBlock, getTokenInfo, - getMultiAssetMetadata + getMultiAssetMetadata, + getMultiAssetSupply, ); /* @@ -1059,6 +1070,7 @@ async function pendingDropped( const getBestBlock = genGetBestBlock(networkTransactions); const getTokenInfo = genGetTokenInfo(); const getMultiAssetMetadata = genGetMultiAssetMetadata(); + const getMultiAssetSupply = genGetMultiAssetSupply(); const getRecentTransactionHashes = genGetRecentTransactionHashes(networkTransactions); const getTransactionsByHashes = genGetTransactionsByHashes(networkTransactions); @@ -1075,6 +1087,7 @@ async function pendingDropped( checkAddressesInUse, getTokenInfo, getMultiAssetMetadata, + getMultiAssetSupply, ); await updateTransactions( db, @@ -1084,7 +1097,8 @@ async function pendingDropped( getTransactionsByHashes, getBestBlock, getTokenInfo, - getMultiAssetMetadata + getMultiAssetMetadata, + getMultiAssetSupply, ); // remove it from backend @@ -1097,6 +1111,7 @@ async function pendingDropped( checkAddressesInUse, getTokenInfo, getMultiAssetMetadata, + getMultiAssetSupply, ); await updateTransactions( db, @@ -1106,7 +1121,8 @@ async function pendingDropped( getTransactionsByHashes, getBestBlock, getTokenInfo, - getMultiAssetMetadata + getMultiAssetMetadata, + getMultiAssetSupply, ); expect((await db.export()).tables.Transaction).toEqual([ diff --git a/packages/yoroi-extension/app/api/ada/lib/storage/bridge/tests/utxo.test.js b/packages/yoroi-extension/app/api/ada/lib/storage/bridge/tests/utxo.test.js index 5701f971e7..4a67b03a52 100644 --- a/packages/yoroi-extension/app/api/ada/lib/storage/bridge/tests/utxo.test.js +++ b/packages/yoroi-extension/app/api/ada/lib/storage/bridge/tests/utxo.test.js @@ -22,7 +22,7 @@ import { genGetMultiAssetMetadata, MockUtxoApi, genGetRecentTransactionHashes, - genGetTransactionsByHashes, + genGetTransactionsByHashes, genGetMultiAssetSupply, } from '../../../state-fetch/mockNetwork'; import { HARD_DERIVATION_START, @@ -277,6 +277,7 @@ async function syncingSimpleTransaction( const getBestBlock = genGetBestBlock(txHistory); const getTokenInfo = genGetTokenInfo(); const getMultiAssetMetadata = genGetMultiAssetMetadata(); + const getMultiAssetSupply = genGetMultiAssetSupply(); const getRecentTransactionHashes = genGetRecentTransactionHashes(txHistory); const getTransactionsByHashes = genGetTransactionsByHashes(txHistory); @@ -299,7 +300,8 @@ async function syncingSimpleTransaction( basePubDeriver, checkAddressesInUse, getTokenInfo, - getMultiAssetMetadata + getMultiAssetMetadata, + getMultiAssetSupply, ); await updateTransactions( db, @@ -309,7 +311,8 @@ async function syncingSimpleTransaction( getTransactionsByHashes, getBestBlock, getTokenInfo, - getMultiAssetMetadata + getMultiAssetMetadata, + getMultiAssetSupply, ); { @@ -420,6 +423,7 @@ async function syncingSimpleTransaction( checkAddressesInUse, getTokenInfo, getMultiAssetMetadata, + getMultiAssetSupply, ); await updateTransactions( db, @@ -429,7 +433,8 @@ async function syncingSimpleTransaction( getTransactionsByHashes, getBestBlock, getTokenInfo, - getMultiAssetMetadata + getMultiAssetMetadata, + getMultiAssetSupply, ); { const response = await basePubDeriver.getAllUtxos(); diff --git a/packages/yoroi-extension/app/api/ada/lib/storage/bridge/updateTransactions.js b/packages/yoroi-extension/app/api/ada/lib/storage/bridge/updateTransactions.js index 398100c07f..70c4ebdc4c 100644 --- a/packages/yoroi-extension/app/api/ada/lib/storage/bridge/updateTransactions.js +++ b/packages/yoroi-extension/app/api/ada/lib/storage/bridge/updateTransactions.js @@ -136,6 +136,9 @@ import type { MultiAssetMintMetadataFunc, GetRecentTransactionHashesFunc, GetTransactionsByHashesFunc, + MultiAssetSupplyFunc, + MultiAssetMintMetadataResponse, + MultiAssetSupplyResponse, } from '../../state-fetch/types'; import { ShelleyCertificateTypes, @@ -165,15 +168,6 @@ type TxData = {| |}>, |}; -type TokensMintMetadata = {| -...{[key: string]: TokenMintMetadata[]} -|} - -type TokenMintMetadata = {| -key: string, -metadata: any -|} - async function rawGetAllTxIds( db: lf$Database, dbTx: lf$Transaction, @@ -918,6 +912,7 @@ export async function updateUtxos( checkAddressesInUse: FilterFunc, getTokenInfo: TokenInfoFunc, getMultiAssetMintMetadata: MultiAssetMintMetadataFunc, + getMultiAssetSupply: MultiAssetSupplyFunc, ): Promise { const withLevels = asHasLevels(publicDeriver); const derivationTables = withLevels == null @@ -1023,6 +1018,7 @@ export async function updateUtxos( tokenIds, getTokenInfo, getMultiAssetMintMetadata, + getMultiAssetSupply, publicDeriver.getParent().getNetworkInfo(), ) ) @@ -1043,6 +1039,7 @@ export async function updateTransactions( getBestBlock: BestBlockFunc, getTokenInfo: TokenInfoFunc, getMultiAssetMetadata: MultiAssetMintMetadataFunc, + getMultiAssetSupply: MultiAssetSupplyFunc, after?: ?After, ): Promise { const withLevels = asHasLevels(publicDeriver); @@ -1116,6 +1113,7 @@ export async function updateTransactions( derivationTables, getTokenInfo, getMultiAssetMetadata, + getMultiAssetSupply, after, ); } @@ -1382,6 +1380,7 @@ async function rawUpdateTransactions( derivationTables: Map, getTokenInfo: TokenInfoFunc, getMultiAssetMetadata: MultiAssetMintMetadataFunc, + getMultiAssetSupply: MultiAssetSupplyFunc, after: ?After, ): Promise { const network = publicDeriver.getParent().getNetworkInfo(); @@ -1536,7 +1535,8 @@ async function rawUpdateTransactions( toAbsoluteSlotNumber, derivationTables, getTokenInfo, - getMultiAssetMetadata + getMultiAssetMetadata, + getMultiAssetSupply, } ); } else { @@ -1617,6 +1617,7 @@ async function updateTransactionBatch( defaultToken: DefaultTokenEntry, getTokenInfo: TokenInfoFunc, getMultiAssetMetadata: MultiAssetMintMetadataFunc, + getMultiAssetSupply: MultiAssetSupplyFunc, |} ): Promise) -: Promise<$ReadOnly> { - if (!tokenIds || tokenIds.length === 0) return {}; - - const nativeAssets = tokenIds + getMultiAssetSupply: MultiAssetSupplyFunc, + network: $ReadOnly +) : Promise<[ + $ReadOnly, + $ReadOnly, +]> { + const assets = (tokenIds||[]) .filter(t => t.indexOf('.') !== -1) .map(t => { const parts = t.split('.'); - const assetName = parts[1]; const policyId = parts[0]; + const assetNameHex = parts[1]; return { - nameHex: assetName, - policy: policyId + nameHex: assetNameHex, + policy: policyId, }; }); - if (!nativeAssets || nativeAssets.length === 0) return {}; + if (assets.length === 0) + return [{}, {}]; - const tokensMintMetadata = await getMultiAssetMetadata({ - network, - assets: nativeAssets - }); + const [tokensMintMetadata, tokensSupply] = await Promise.all([ + getMultiAssetMetadata({ network, assets }), + getMultiAssetSupply({ network, assets }), + ]); - return tokensMintMetadata; + return [tokensMintMetadata, tokensSupply]; }; const TOKEN_INFO_CACHE_TIME = 1 * 60 * 60 * 1000; @@ -2166,6 +2171,7 @@ export async function genCardanoAssetMap( tokenIds: Array, getTokenInfo: TokenInfoFunc, getMultiAssetMetadata: MultiAssetMintMetadataFunc, + getMultiAssetSupply: MultiAssetSupplyFunc, network: $ReadOnly, ): Promise>> { const existingDbRows = (await deps.GetToken.fromIdentifier( @@ -2206,7 +2212,13 @@ export async function genCardanoAssetMap( } catch { tokenInfoResponse = {}; } - const metadata = await getTokenMintMetadata(tokenIds, getMultiAssetMetadata, network); + + const [metadata, supply] = await getTokenMintMetadataAndSupply( + tokenIds, + getMultiAssetMetadata, + getMultiAssetSupply, + network, + ); const databaseInsert = updatingTokenIds .map(tokenId => { @@ -2247,18 +2259,16 @@ export async function genCardanoAssetMap( const assetName = Buffer.from(parts.name.name()).toString('hex'); const policyId = Buffer.from(parts.policyId.to_bytes()).toString('hex'); - const assetNameInMetadata = Buffer.from(assetName, 'hex').toString(); - const identifierInMetadata = `${policyId}.${assetNameInMetadata}`; - - const tokenMetadata = metadata[identifierInMetadata]; + const tokenMetadata = metadata[tokenId]; + const tokenSupplyStr = supply[tokenId]; let isNft = false; let assetMintMetadata: CardanoAssetMintMetadata[] = []; if (tokenMetadata) { - if (tokenMetadata.filter(m => m.key === '721').length > 0) { - isNft = true; - } + const hasMediaMetadata = tokenMetadata.filter(m => m.key === '721').length > 0; + const hasOnlyOneUnit = tokenSupplyStr === '1'; + isNft = hasMediaMetadata && hasOnlyOneUnit; assetMintMetadata = tokenMetadata.map(m => { const metaObj: CardanoAssetMintMetadata = {}; diff --git a/packages/yoroi-extension/app/api/ada/lib/storage/bridge/utils.js b/packages/yoroi-extension/app/api/ada/lib/storage/bridge/utils.js index 011344efa6..21a8a78d3a 100644 --- a/packages/yoroi-extension/app/api/ada/lib/storage/bridge/utils.js +++ b/packages/yoroi-extension/app/api/ada/lib/storage/bridge/utils.js @@ -5,14 +5,14 @@ import { CoreAddressTypes } from '../database/primitives/enums'; import { RustModule } from '../../cardanoCrypto/rustLoader'; import type { NetworkRow } from '../database/primitives/tables'; import { isCardanoHaskell, isErgo } from '../database/prepackaged/networks'; -import { defineMessages, } from 'react-intl'; -import type { $npm$ReactIntl$MessageDescriptor, } from 'react-intl'; +import { defineMessages } from 'react-intl'; +import type { $npm$ReactIntl$MessageDescriptor } from 'react-intl'; import { bech32 as bech32Module } from 'bech32'; export function tryAddressToKind( address: string, parseAs: 'bech32' | 'bytes', - network: $ReadOnly, + network: $ReadOnly ): void | CoreAddressT { try { return addressToKind(address, parseAs, network); @@ -24,7 +24,7 @@ export function tryAddressToKind( export function addressToKind( address: string, parseAs: 'bech32' | 'bytes', - network: $ReadOnly, + network: $ReadOnly ): CoreAddressT { try { return RustModule.WasmScope(Scope => { @@ -34,9 +34,10 @@ export function addressToKind( if (Scope.WalletV4.ByronAddress.is_valid(address)) { return CoreAddressTypes.CARDANO_LEGACY; } - const wasmAddr = parseAs === 'bytes' - ? Scope.WalletV4.Address.from_bytes(Buffer.from(address, 'hex')) - : Scope.WalletV4.Address.from_bech32(address); + const wasmAddr = + parseAs === 'bytes' + ? Scope.WalletV4.Address.from_bytes(Buffer.from(address, 'hex')) + : Scope.WalletV4.Address.from_bech32(address); { const byronAddr = Scope.WalletV4.ByronAddress.from_address(wasmAddr); if (byronAddr) return CoreAddressTypes.CARDANO_LEGACY; @@ -60,9 +61,10 @@ export function addressToKind( throw new Error(`${nameof(addressToKind)} unknown address type`); } if (isErgo(network)) { - const ergoAddress = parseAs === 'bytes' - ? Scope.SigmaRust.NetworkAddress.from_bytes(Buffer.from(address, 'hex')) - : Scope.SigmaRust.NetworkAddress.from_base58(address); + const ergoAddress = + parseAs === 'bytes' + ? Scope.SigmaRust.NetworkAddress.from_bytes(Buffer.from(address, 'hex')) + : Scope.SigmaRust.NetworkAddress.from_base58(address); return ergoAddressToType(ergoAddress); } throw new Error(`${nameof(addressToKind)} not implemented for network ${network.NetworkId}`); @@ -72,29 +74,34 @@ export function addressToKind( } } -export function ergoAddressToType( - address: RustModule.SigmaRust.NetworkAddress, -): CoreAddressT { +export function ergoAddressToType(address: RustModule.SigmaRust.NetworkAddress): CoreAddressT { switch (address.address().address_type_prefix()) { - case RustModule.SigmaRust.AddressTypePrefix.P2Pk: return CoreAddressTypes.ERGO_P2PK; - case RustModule.SigmaRust.AddressTypePrefix.Pay2Sh: return CoreAddressTypes.ERGO_P2SH; - case RustModule.SigmaRust.AddressTypePrefix.Pay2S: return CoreAddressTypes.ERGO_P2S; - default: throw new Error(`${nameof(ergoAddressToType)} unknown Ergo address type ${address.to_base58()}`); + case RustModule.SigmaRust.AddressTypePrefix.P2Pk: + return CoreAddressTypes.ERGO_P2PK; + case RustModule.SigmaRust.AddressTypePrefix.Pay2Sh: + return CoreAddressTypes.ERGO_P2SH; + case RustModule.SigmaRust.AddressTypePrefix.Pay2S: + return CoreAddressTypes.ERGO_P2S; + default: + throw new Error( + `${nameof(ergoAddressToType)} unknown Ergo address type ${address.to_base58()}` + ); } } export function isValidReceiveAddress( bech32: string, - network: $ReadOnly, + network: $ReadOnly ): true | [false, $Exact<$npm$ReactIntl$MessageDescriptor>] { const messages = defineMessages({ invalidAddress: { id: 'wallet.send.form.errors.invalidAddress', - defaultMessage: '!!!Invalid address. Please retype.', + defaultMessage: '!!!Incorrect address format', }, cannotSendToLegacy: { id: 'wallet.send.form.cannotSendToLegacy', - defaultMessage: '!!!Unable to send funds to legacy addresses (any address created before July 29th, 2020).', + defaultMessage: + '!!!Unable to send funds to legacy addresses (any address created before July 29th, 2020).', }, cannotSendToReward: { id: 'wallet.send.form.cannotSendToReward', @@ -140,20 +147,18 @@ export function isValidReceiveAddress( return [false, messages.invalidAddress]; } - throw new Error(`${nameof(isValidReceiveAddress)} Unsupported network ${JSON.stringify(network)}`); + throw new Error( + `${nameof(isValidReceiveAddress)} Unsupported network ${JSON.stringify(network)}` + ); } -export function byronAddrToHex( - base58Addr: string -): string { - return Buffer.from(RustModule.WalletV4.ByronAddress.from_base58( - base58Addr - ).to_bytes()).toString('hex'); +export function byronAddrToHex(base58Addr: string): string { + return Buffer.from(RustModule.WalletV4.ByronAddress.from_base58(base58Addr).to_bytes()).toString( + 'hex' + ); } -export function normalizeToBase58( - addr: string -): void | string { +export function normalizeToBase58(addr: string): void | string { // in Shelley, addresses can be base16, bech32 or base58 // this function normalizes everything to base58 @@ -164,9 +169,7 @@ export function normalizeToBase58( // 2) Try converting from base16 try { - const wasmAddr = RustModule.WalletV4.Address.from_bytes( - Buffer.from(addr, 'hex') - ); + const wasmAddr = RustModule.WalletV4.Address.from_bytes(Buffer.from(addr, 'hex')); const byronAddr = RustModule.WalletV4.ByronAddress.from_address(wasmAddr); if (byronAddr) return byronAddr.to_base58(); return undefined; // wrong address kind @@ -192,7 +195,7 @@ const convertBase32ToHex = (data: any[]) => { }; /* eslint-disable */ -const bigIntToBase58 = (n) => { +const bigIntToBase58 = n => { const base58Alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'; const o = []; @@ -216,17 +219,17 @@ const hexAddressConfig: any = [ { // base validate: (addr: string) => Buffer.from(addr, 'hex').length === 1 + baseAddrLength * 2, - header: /^[0-3]/ + header: /^[0-3]/, }, { // pointer validate: (addr: string) => Buffer.from(addr, 'hex').length >= 1 + baseAddrLength + 3, - header: /^[4-5]/ + header: /^[4-5]/, }, { // enterprise validate: (addr: string) => Buffer.from(addr, 'hex').length === 1 + baseAddrLength, - header: /^[6-7]/ + header: /^[6-7]/, }, { // byron @@ -239,18 +242,16 @@ const hexAddressConfig: any = [ } /* eslint-enable */ }, - header: /^[8]/ + header: /^[8]/, }, { // reward validate: (addr: string) => Buffer.from(addr, 'hex').length === 1 + baseAddrLength, - header: /^[e-f]|[E-F]/ + header: /^[e-f]|[E-F]/, }, ]; -export function normalizeToAddress( - addr: string -): void | RustModule.WalletV4.Address { +export function normalizeToAddress(addr: string): void | RustModule.WalletV4.Address { // in Shelley, addresses can be base16, bech32 or base58 // this function, we try parsing in all encodings possible @@ -271,9 +272,7 @@ export function normalizeToAddress( // 2.3) ...otherwise, validate the address with the validation function defined in the config if (config.validate(hexAddr)) { try { - return RustModule.WalletV4.Address.from_bytes( - Buffer.from(hexAddr, 'hex') - ); + return RustModule.WalletV4.Address.from_bytes(Buffer.from(hexAddr, 'hex')); } catch {} // eslint-disable-line no-empty } } @@ -299,39 +298,29 @@ export function normalizeToAddress( return undefined; } -export function isErgoAddress( - kind: CoreAddressT -): boolean { +export function isErgoAddress(kind: CoreAddressT): boolean { if (kind === CoreAddressTypes.ERGO_P2PK) return true; if (kind === CoreAddressTypes.ERGO_P2SH) return true; if (kind === CoreAddressTypes.ERGO_P2S) return true; return false; } -export function toEnterprise( - address: string -): (void | RustModule.WalletV4.EnterpriseAddress) { +export function toEnterprise(address: string): void | RustModule.WalletV4.EnterpriseAddress { if (RustModule.WalletV4.ByronAddress.is_valid(address)) { return undefined; } - const wasmAddr = RustModule.WalletV4.Address.from_bytes( - Buffer.from(address, 'hex') - ); + const wasmAddr = RustModule.WalletV4.Address.from_bytes(Buffer.from(address, 'hex')); const spendingKey = getCardanoSpendingKeyHash(wasmAddr); if (spendingKey == null) return undefined; const singleAddr = RustModule.WalletV4.EnterpriseAddress.new( wasmAddr.network_id(), - RustModule.WalletV4.Credential.from_keyhash( - spendingKey - ), + RustModule.WalletV4.Credential.from_keyhash(spendingKey) ); return singleAddr; } -export function isCardanoHaskellAddress( - kind: CoreAddressT -): boolean { +export function isCardanoHaskellAddress(kind: CoreAddressT): boolean { if (kind === CoreAddressTypes.CARDANO_LEGACY) return true; if (kind === CoreAddressTypes.CARDANO_BASE) return true; if (kind === CoreAddressTypes.CARDANO_PTR) return true; @@ -341,12 +330,10 @@ export function isCardanoHaskellAddress( } export function getCardanoSpendingKeyHash( - addr: RustModule.WalletV4.Address, -): ( - // null -> legacy address (no key hash) - // undefined -> script hash instead of key hash - RustModule.WalletV4.Ed25519KeyHash | null | void -) { + addr: RustModule.WalletV4.Address +): // null -> legacy address (no key hash) +// undefined -> script hash instead of key hash +RustModule.WalletV4.Ed25519KeyHash | null | void { { const byronAddr = RustModule.WalletV4.ByronAddress.from_address(addr); if (byronAddr) return null; @@ -370,10 +357,7 @@ export function getCardanoSpendingKeyHash( throw new Error(`${nameof(getCardanoSpendingKeyHash)} unknown address type`); } -export function addressToDisplayString( - address: string, - network: $ReadOnly, -): string { +export function addressToDisplayString(address: string, network: $ReadOnly): string { try { if (isCardanoHaskell(network)) { // Need to try parsing as a legacy address first @@ -381,9 +365,7 @@ export function addressToDisplayString( if (RustModule.WalletV4.ByronAddress.is_valid(address)) { return address; } - const wasmAddr = RustModule.WalletV4.Address.from_bytes( - Buffer.from(address, 'hex') - ); + const wasmAddr = RustModule.WalletV4.Address.from_bytes(Buffer.from(address, 'hex')); const byronAddr = RustModule.WalletV4.ByronAddress.from_address(wasmAddr); if (byronAddr == null) { return wasmAddr.to_bech32(); @@ -391,21 +373,19 @@ export function addressToDisplayString( return byronAddr.to_base58(); } if (isErgo(network)) { - const ergoAddr = RustModule.SigmaRust.NetworkAddress.from_bytes( - Buffer.from(address, 'hex') - ); + const ergoAddr = RustModule.SigmaRust.NetworkAddress.from_bytes(Buffer.from(address, 'hex')); return ergoAddr.to_base58(); } - throw new Error(`${nameof(addressToDisplayString)} not implemented for network ${network.NetworkId}`); + throw new Error( + `${nameof(addressToDisplayString)} not implemented for network ${network.NetworkId}` + ); } catch (_e2) { throw new Error(`${nameof(addressToDisplayString)} failed to parse address type ` + address); } } // need to format shelley addresses as base16 but only legacy addresses as base58 -export function toHexOrBase58( - address: RustModule.WalletV4.Address, -): string { +export function toHexOrBase58(address: RustModule.WalletV4.Address): string { const asByron = RustModule.WalletV4.ByronAddress.from_address(address); if (asByron == null) { return Buffer.from(address.to_bytes()).toString('hex'); @@ -413,10 +393,7 @@ export function toHexOrBase58( return asByron.to_base58(); } -export function getAddressPayload( - address: string, - network: $ReadOnly, -): string { +export function getAddressPayload(address: string, network: $ReadOnly): string { try { if (isCardanoHaskell(network)) { // Need to try parsing as a legacy address first @@ -435,21 +412,18 @@ export function getAddressPayload( const ergoAddr = RustModule.SigmaRust.NetworkAddress.from_base58(address); return Buffer.from(ergoAddr.to_bytes()).toString('hex'); } - throw new Error(`${nameof(getAddressPayload)} not implemented for network ${network.NetworkId}`); + throw new Error( + `${nameof(getAddressPayload)} not implemented for network ${network.NetworkId}` + ); } catch (_e2) { throw new Error(`${nameof(getAddressPayload)} failed to parse address type ` + address); } } -export function unwrapStakingKey( - stakingAddress: string, -): RustModule.WalletV4.Credential { - const accountAddress = - RustModule.WalletV4.RewardAddress.from_address( - RustModule.WalletV4.Address.from_bytes( - Buffer.from(stakingAddress, 'hex') - ) - ); +export function unwrapStakingKey(stakingAddress: string): RustModule.WalletV4.Credential { + const accountAddress = RustModule.WalletV4.RewardAddress.from_address( + RustModule.WalletV4.Address.from_bytes(Buffer.from(stakingAddress, 'hex')) + ); if (accountAddress == null) { throw new Error(`${nameof(unwrapStakingKey)} staking key invalid`); } diff --git a/packages/yoroi-extension/app/api/ada/lib/storage/database/index.js b/packages/yoroi-extension/app/api/ada/lib/storage/database/index.js index 13fb992f25..2473af02cf 100644 --- a/packages/yoroi-extension/app/api/ada/lib/storage/database/index.js +++ b/packages/yoroi-extension/app/api/ada/lib/storage/database/index.js @@ -219,13 +219,67 @@ const populateAndCreate = async ( populateExplorerDb(schemaBuilder); populateUtxoDb(schemaBuilder); - const db = await schemaBuilder.connect({ - storeType, - onUpgrade, - }); + let db; + try { + db = await schemaBuilder.connect({ + storeType, + onUpgrade, + }); + } catch (error) { + if (error.code === 201 /* Lovefield error code for dup pk */) { + await fixLovefieldDuplicatePrimaryKey(error.message); + return populateAndCreate(storeType); + } + throw error; + } return db; }; +async function fixLovefieldDuplicatePrimaryKey(errorMessage: string): Promise { + const makeError = (message) => new Error( + `Error when fixing ${errorMessage}: ${message}` + ); + const params = new URL(errorMessage).searchParams; + const [storeName, keyName] = String(params.get('p0')).split('.'); + if (keyName !== 'pk' + storeName) { + throw makeError('unexpected key name'); + } + const fieldName = storeName + 'Id'; + const dupVal = params.get('p1'); + + const toPromise = (request, errMsg) => new Promise((resolve, reject) => { + request.onerror = (_event) => { + reject(makeError(errMsg)); + }; + request.onsuccess = (_event) => { + resolve(request.result); + }; + }); + + const db = await toPromise( + window.indexedDB.open('yoroi-schema'), + 'could not open DB', + ); + + const store = db + .transaction([storeName], 'readwrite') + .objectStore(storeName); + + const allObjects = await toPromise( + store.getAll(), + 'could not get all objects', + ); + const dupObjects = allObjects.filter( + obj => String(obj.value[fieldName]) === dupVal + ); + for (const dupObj of dupObjects.slice(1)) { + await toPromise( + store.delete(dupObj.id), + 'could not delete duplicate object', + ); + } +} + export async function clear( db: lf$Database, ): Promise { diff --git a/packages/yoroi-extension/app/api/ada/lib/storage/database/prepackaged/explorers.js b/packages/yoroi-extension/app/api/ada/lib/storage/database/prepackaged/explorers.js index a3bf5a4a4f..aa298853c6 100644 --- a/packages/yoroi-extension/app/api/ada/lib/storage/database/prepackaged/explorers.js +++ b/packages/yoroi-extension/app/api/ada/lib/storage/database/prepackaged/explorers.js @@ -155,12 +155,32 @@ const CardanoPreviewTestnetExplorers: Array<$ReadOnly> = [ }, ]; +// +const CardanoSanchoTestnetExplorers: Array<$ReadOnly> = [ + { + ExplorerId: 6_50, + NetworkId: networks.CardanoSanchoTestnet.NetworkId, + IsBackup: true, + Endpoints: { + address: 'https://preview.cardanoscan.io/address/', + transaction: 'https://preview.cardanoscan.io/transaction/', + pool: 'https://preview.cardanoscan.io/pool/', + stakeAddress: 'https://preview.cardanoscan.io/stakeKey/', + token: 'https://preview.cardanoscan.io/token/', + }, + Name: 'CardanoScan', + }, +]; + export const prepackagedExplorers: Map>> = new Map([ [networks.CardanoMainnet.NetworkId, CardanoMainnetExplorers], [networks.CardanoTestnet.NetworkId, CardanoTestnetExplorers], [networks.CardanoPreprodTestnet.NetworkId, CardanoPreprodTestnetExplorers], [networks.CardanoPreviewTestnet.NetworkId, CardanoPreviewTestnetExplorers], + [networks.CardanoSanchoTestnet.NetworkId, CardanoSanchoTestnetExplorers], + // Ergo [networks.ErgoMainnet.NetworkId, ErgoExplorers], + // Alonzo [networks.AlonzoTestnet.NetworkId, AlonzoTestnetExplorers], ]); const getOrThrow = function (input: ?T): T { @@ -181,9 +201,14 @@ export const prepackagedDefaultExplorers: [networks.CardanoPreviewTestnet.NetworkId, getOrThrow( CardanoPreviewTestnetExplorers.find(explorer => explorer.IsBackup) )], + [networks.CardanoSanchoTestnet.NetworkId, getOrThrow( + CardanoSanchoTestnetExplorers.find(explorer => explorer.IsBackup) + )], + // Ergo [networks.ErgoMainnet.NetworkId, getOrThrow( ErgoExplorers.find(explorer => explorer.IsBackup) )], + // Alonzo [networks.AlonzoTestnet.NetworkId, getOrThrow( AlonzoTestnetExplorers.find(explorer => explorer.IsBackup) )], diff --git a/packages/yoroi-extension/app/api/ada/lib/storage/database/prepackaged/networks.js b/packages/yoroi-extension/app/api/ada/lib/storage/database/prepackaged/networks.js index c285da527b..13d5ef2f8a 100644 --- a/packages/yoroi-extension/app/api/ada/lib/storage/database/prepackaged/networks.js +++ b/packages/yoroi-extension/app/api/ada/lib/storage/database/prepackaged/networks.js @@ -247,6 +247,46 @@ export const networks = Object.freeze({ CoinType: CoinTypes.CARDANO, Fork: CardanoForks.Haskell, }: NetworkRow), + CardanoSanchoTestnet: ({ + NetworkId: 4_50, + NetworkName: 'Cardano Sancho Testnet', + Backend: { + BackendService: environment.isTest() + ? 'http://localhost:21000' + : 'https://sanchonet-backend.yoroiwallet.com', + WebSocket: environment.isTest() + ? 'ws://localhost:21000' + : 'wss://sanchonet-backend.yoroiwallet.com:443', + TokenInfoService: + 'https://stage-cdn.yoroiwallet.com', + }, + BaseConfig: ([ + Object.freeze({ + StartAt: 0, + ChainNetworkId: '0', + ByronNetworkId: 4, + GenesisDate: '1686789000000', + SlotsPerEpoch: 4320, + SlotDuration: 20, + }), + Object.freeze({ + StartAt: 0, + SlotsPerEpoch: 86400, + SlotDuration: 1, + PerEpochPercentageReward: 69344, + LinearFee: { + coefficient: '44', + constant: '155381', + }, + CoinsPerUtxoWord: '34482', + MinimumUtxoVal: '1000000', + PoolDeposit: '500000000', + KeyDeposit: '2000000', + }) + ]: CardanoHaskellBaseConfig), + CoinType: CoinTypes.CARDANO, + Fork: CardanoForks.Haskell, + }: NetworkRow), }); export function isTestnet( @@ -254,7 +294,8 @@ export function isTestnet( ): boolean { return network.NetworkId === networks.CardanoTestnet.NetworkId || network.NetworkId === networks.CardanoPreprodTestnet.NetworkId - || network.NetworkId === networks.CardanoPreviewTestnet.NetworkId; + || network.NetworkId === networks.CardanoPreviewTestnet.NetworkId + || network.NetworkId === networks.CardanoSanchoTestnet.NetworkId; } @@ -312,6 +353,8 @@ export const defaultAssets: Array< (network === networks.CardanoTestnet || network === networks.CardanoPreprodTestnet || network === networks.CardanoPreviewTestnet + || network === networks.CardanoSanchoTestnet + // Alonzo || network === networks.AlonzoTestnet) ? 'TADA' : 'ADA', diff --git a/packages/yoroi-extension/app/api/ada/lib/storage/tests/__snapshots__/index.test.js.snap b/packages/yoroi-extension/app/api/ada/lib/storage/tests/__snapshots__/index.test.js.snap index 39d963d65e..ffb150a6c0 100644 --- a/packages/yoroi-extension/app/api/ada/lib/storage/tests/__snapshots__/index.test.js.snap +++ b/packages/yoroi-extension/app/api/ada/lib/storage/tests/__snapshots__/index.test.js.snap @@ -833,6 +833,19 @@ Object { "Name": "CardanoScan", "NetworkId": 350, }, + 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": 650, + "IsBackup": true, + "Name": "CardanoScan", + "NetworkId": 450, + }, Object { "Endpoints": Object { "address": "https://explorer.ergoplatform.com/en/addresses/", @@ -1432,6 +1445,41 @@ Object { "NetworkId": 350, "NetworkName": "Cardano Preview Testnet", }, + Object { + "Backend": Object { + "BackendService": "https://sanchonet-backend.yoroiwallet.com", + "TokenInfoService": "https://stage-cdn.yoroiwallet.com", + "WebSocket": "wss://sanchonet-backend.yoroiwallet.com:443", + }, + "BaseConfig": Array [ + Object { + "ByronNetworkId": 4, + "ChainNetworkId": "0", + "GenesisDate": "1686789000000", + "SlotDuration": 20, + "SlotsPerEpoch": 4320, + "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": 450, + "NetworkName": "Cardano Sancho Testnet", + }, ], "PreferredExplorer": Array [], "PriceData": Array [], @@ -1563,6 +1611,22 @@ Object { "NetworkId": 350, "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": 450, + "TokenId": 7, + }, ], "TokenList": Array [], "Transaction": Array [], diff --git a/packages/yoroi-extension/app/api/ada/transactions/shelley/transactions.js b/packages/yoroi-extension/app/api/ada/transactions/shelley/transactions.js index 3d7df5c5f2..0848ff3efc 100644 --- a/packages/yoroi-extension/app/api/ada/transactions/shelley/transactions.js +++ b/packages/yoroi-extension/app/api/ada/transactions/shelley/transactions.js @@ -855,7 +855,7 @@ async function newAdaUnsignedTxFromUtxoForConnector( const txBuilder = await TxBuilder.new(defaultNetworkConfig, utxoSet); - txBuilder.addRequiredInputs( + await txBuilder.addRequiredInputs( await Promise.all( mustIncludeUtxos.map(async ([utxo, witness]) => { let taggedWitness; @@ -884,16 +884,16 @@ async function newAdaUnsignedTxFromUtxoForConnector( // must set TTL before specifying change address, otherwise the TX builder // miscalculate the tx fee by several bytes fewer if (ttl != null) { - txBuilder.setTtl(ttl); + await txBuilder.setTtl(ttl); } else { - txBuilder.setTtl(absSlotNumber.plus(defaultTtlOffset).toNumber()); + await txBuilder.setTtl(absSlotNumber.plus(defaultTtlOffset).toNumber()); } if (validityStart != null) { - txBuilder.setValidityStartInterval(validityStart); + await txBuilder.setValidityStartInterval(validityStart); } if (requiredSigners != null) { - txBuilder.addRequiredSigners(requiredSigners); + await txBuilder.addRequiredSigners(requiredSigners); } const metadata = auxiliaryData.metadata ?? {}; if (Object.keys(metadata).length > 0) { @@ -901,13 +901,13 @@ async function newAdaUnsignedTxFromUtxoForConnector( for (const tag of Object.keys(metadata)) { record[parseInt(tag, 10)] = metadata[tag]; } - txBuilder.withMetadata(record); + await txBuilder.withMetadata(record); } if (auxiliaryData.nativeScripts) { - txBuilder.addNativeScripts(auxiliaryData.nativeScripts); + await txBuilder.addNativeScripts(auxiliaryData.nativeScripts); } - txBuilder.addMint(mint); + await txBuilder.addMint(mint); const sendRequest = await SendRequest.from(outputs.map(output => { const defaultTokenAmount = output.amount.getDefaultEntry().amount.toString(); diff --git a/packages/yoroi-extension/app/api/analytics/index.js b/packages/yoroi-extension/app/api/analytics/index.js deleted file mode 100644 index a77ce0b4da..0000000000 --- a/packages/yoroi-extension/app/api/analytics/index.js +++ /dev/null @@ -1,171 +0,0 @@ -// @flow -import cryptoRandomString from 'crypto-random-string'; -import querystring from 'querystring'; - -import LocalStorageApi, { - loadAnalyticsInstanceId, - saveAnalyticsInstanceId, -} from '../localStorage'; -import { environment } from '../../environment'; -import { TRACKED_ROUTES } from '../../routes-config'; -import type { StoresMap } from '../../stores'; -import { isTestnet as isTestnetFunc } from '../ada/lib/storage/database/prepackaged/networks'; - -const MATOMO_URL = 'https://analytics.emurgo-rnd.com/matomo.php'; -const SITE_ID = '4'; -let INSTANCE_ID; -let stores; - -export async function trackStartup(stores_: StoresMap): Promise { - stores = stores_; - - let event; - if (await (new LocalStorageApi()).getUserLocale() != null) { - INSTANCE_ID = await loadAnalyticsInstanceId(); - if (INSTANCE_ID) { - emitEvent(INSTANCE_ID, 'launch'); - return; - } - event = 'pre-existing-instance'; - } else { - event = 'new-instance'; - } - INSTANCE_ID = generateAnalyticsInstanceId(); - await saveAnalyticsInstanceId(INSTANCE_ID); - emitEvent(INSTANCE_ID, event); -} - -type NewWalletType = 'hardware' | 'created' | 'restored'; - -export function trackWalletCreation(newWalletType: NewWalletType): void { - if (INSTANCE_ID == null) { - return; - } - emitEvent(INSTANCE_ID, 'new-wallet/' + newWalletType); -} - -export function trackNavigation(path: string): void { - if (path.match(TRACKED_ROUTES)) { - if (INSTANCE_ID == null) { - return; - } - emitEvent(INSTANCE_ID, 'navigate' + path); - } -} - -export function trackSend(): void { - if (INSTANCE_ID == null) { - return; - } - emitEvent(INSTANCE_ID, 'new-transaction/send'); -} - -export function trackDelegation(): void { - if (INSTANCE_ID == null) { - return; - } - emitEvent(INSTANCE_ID, 'delegation'); -} - -export function trackWithdrawal(shouldDeregister: boolean): void { - if (INSTANCE_ID == null) { - return; - } - if (shouldDeregister) { - emitEvent(INSTANCE_ID, 'deregister'); - } else { - emitEvent(INSTANCE_ID, 'withdrawal'); - } -} - -export function trackCatalystRegistration(): void { - if (INSTANCE_ID == null) { - return; - } - emitEvent(INSTANCE_ID, 'new-transaction/catalyst'); -} - -export function trackSetLocale(locale: string): void { - if (INSTANCE_ID == null) { - return; - } - emitEvent(INSTANCE_ID, 'set-locale/' + locale); -} - -export function trackSetUnitOfAccount(unitOfAccount: string): void { - if (INSTANCE_ID == null) { - return; - } - emitEvent(INSTANCE_ID, 'unit-of-account/' + unitOfAccount); -} - -export function trackUpdateTheme(theme: string): void { - if (INSTANCE_ID == null) { - return; - } - emitEvent(INSTANCE_ID, 'update-theme/' + theme); -} - -export function trackUriPrompt(choice: 'skip' | 'allow'): void { - if (INSTANCE_ID == null) { - return; - } - emitEvent(INSTANCE_ID, 'uri-prompt/' + choice); -} - -export function trackBuySellDialog(): void { - if (INSTANCE_ID == null) { - return; - } - emitEvent(INSTANCE_ID, 'buy-sell-ada'); -} - -export function trackExportWallet(): void { - if (INSTANCE_ID == null) { - return; - } - emitEvent(INSTANCE_ID, 'export-wallet'); -} - -export function trackRemoveWallet(): void { - if (INSTANCE_ID == null) { - return; - } - emitEvent(INSTANCE_ID, 'remove-wallet'); -} - -export function trackResyncWallet(): void { - if (INSTANCE_ID == null) { - return; - } - emitEvent(INSTANCE_ID, 'resync-wallet'); -} - -function generateAnalyticsInstanceId(): string { - // Matomo requires 16 character hex string - return cryptoRandomString({ length: 16 }); -} - -function emitEvent(instanceId: string, event: string): void { - if (environment.isDev() || environment.isTest()) { - return; - } - - const isTestnet = stores.profile.selectedNetwork != null ? - isTestnetFunc(stores.profile.selectedNetwork) : - false; - - // https://developer.matomo.org/api-reference/tracking-api - const params = { - idsite: SITE_ID, - rec: '1', - action_name: (isTestnet ? 'testnet/' : '') + event, - url: `http://yoroi.extension/${isTestnet ? 'testnet/' : ''}${event}`, - _id: INSTANCE_ID, - rand: `${Date.now()}-${Math.random()}`, - apiv: '1' - }; - const url = `${MATOMO_URL}?${querystring.stringify(params)}`; - - fetch(url); -} diff --git a/packages/yoroi-extension/app/api/common/errors.js b/packages/yoroi-extension/app/api/common/errors.js index 0ec2f1246e..49407dca95 100644 --- a/packages/yoroi-extension/app/api/common/errors.js +++ b/packages/yoroi-extension/app/api/common/errors.js @@ -22,7 +22,7 @@ const messages = defineMessages({ }, incorrectWalletPasswordError: { id: 'api.errors.IncorrectPasswordError', - defaultMessage: '!!!Incorrect spending password. Please retype.', + defaultMessage: '!!!Incorrect password. Please retype.', }, walletAlreadyRestoredError: { id: 'api.errors.WalletAlreadyRestoredError', diff --git a/packages/yoroi-extension/app/api/ergo/lib/storage/bridge/tests/__snapshots__/simpleTxs.test.js.snap b/packages/yoroi-extension/app/api/ergo/lib/storage/bridge/tests/__snapshots__/simpleTxs.test.js.snap index 6fefa50343..ace3bd9bf6 100644 --- a/packages/yoroi-extension/app/api/ergo/lib/storage/bridge/tests/__snapshots__/simpleTxs.test.js.snap +++ b/packages/yoroi-extension/app/api/ergo/lib/storage/bridge/tests/__snapshots__/simpleTxs.test.js.snap @@ -433,6 +433,22 @@ Array [ "NetworkId": 350, "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": 450, + "TokenId": 7, + }, ], }, Object { diff --git a/packages/yoroi-extension/app/api/localStorage/index.js b/packages/yoroi-extension/app/api/localStorage/index.js index f312b63b4c..7512366a4a 100644 --- a/packages/yoroi-extension/app/api/localStorage/index.js +++ b/packages/yoroi-extension/app/api/localStorage/index.js @@ -23,10 +23,11 @@ declare var browser; const networkForLocalStorage = String(environment.getNetworkName()); const storageKeys = { USER_LOCALE: networkForLocalStorage + '-USER-LOCALE', - TERMS_OF_USE_ACCEPTANCE: networkForLocalStorage + '-TERMS-OF-USE-ACCEPTANCE', URI_SCHEME_ACCEPTANCE: networkForLocalStorage + '-URI-SCHEME-ACCEPTANCE', COMPLEXITY_LEVEL: networkForLocalStorage + '-COMPLEXITY-LEVEL', THEME: networkForLocalStorage + '-THEME', + IS_USER_MIGRATED_TO_REVAMP: 'IS_USER_MIGRATED_TO_REVAMP', + IS_REVAMP_THEME_ANNOUNCED: 'IS_REVAMP_THEME_ANNOUNCED', CUSTOM_THEME: networkForLocalStorage + '-CUSTOM-THEME', VERSION: networkForLocalStorage + '-LAST-LAUNCH-VER', HIDE_BALANCE: networkForLocalStorage + '-HIDE-BALANCE', @@ -36,11 +37,13 @@ const storageKeys = { TOGGLE_SIDEBAR: networkForLocalStorage + '-TOGGLE-SIDEBAR', WALLETS_NAVIGATION: networkForLocalStorage + '-WALLETS-NAVIGATION', SUBMITTED_TRANSACTIONS: 'submittedTransactions', - ANALYTICS_INSTANCE_ID: networkForLocalStorage + '-ANALYTICS', CATALYST_ROUND_INFO: networkForLocalStorage + '-CATALYST_ROUND_INFO', // ========== CONNECTOR ========== // ERGO_CONNECTOR_WHITELIST: 'connector_whitelist', SELECTED_WALLET: 'SELECTED_WALLET', + + IS_ANALYTICS_ALLOWED: networkForLocalStorage + '-IS_ANALYTICS_ALLOWED', + ACCEPTED_TOS_VERSION: networkForLocalStorage + '-ACCEPTED_TOS_VERSION', }; export type SetCustomUserThemeRequest = {| @@ -69,20 +72,6 @@ export default class LocalStorageApi { unsetUserLocale: void => Promise = () => removeLocalItem(storageKeys.USER_LOCALE); - // ========== Terms of Use ========== // - - getTermsOfUseAcceptance: void => Promise = () => getLocalItem( - storageKeys.TERMS_OF_USE_ACCEPTANCE - ).then((accepted) => accepted === 'true'); - - setTermsOfUseAcceptance: void => Promise = () => setLocalItem( - storageKeys.TERMS_OF_USE_ACCEPTANCE, JSON.stringify(true) - ); - - unsetTermsOfUseAcceptance: void => Promise = () => removeLocalItem( - storageKeys.TERMS_OF_USE_ACCEPTANCE - ); - // ========== URI Scheme acceptance ========== // getUriSchemeAcceptance: void => Promise = () => getLocalItem( @@ -122,6 +111,22 @@ export default class LocalStorageApi { unsetUserTheme: void => Promise = () => removeLocalItem(storageKeys.THEME); + // ========== Theme Migration ========== // + + getUserRevampMigrationStatus: void => Promise = async () => + (await getLocalItem(storageKeys.IS_USER_MIGRATED_TO_REVAMP)) === 'true'; + + setUserRevampMigrationStatus: boolean => Promise = (status) => + setLocalItem(storageKeys.IS_USER_MIGRATED_TO_REVAMP, status.toString()); + + // ========== Revamp Announcement ========== // + + getUserRevampAnnouncementStatus: void => Promise = async () => + (await getLocalItem(storageKeys.IS_REVAMP_THEME_ANNOUNCED)) === 'true'; + + setUserRevampAnnouncementStatus: boolean => Promise = (status) => + setLocalItem(storageKeys.IS_REVAMP_THEME_ANNOUNCED, status.toString()); + // ========== Select Wallet ========== // getSelectedWalletId: void => number | null = () => { @@ -310,9 +315,43 @@ export default class LocalStorageApi { setWalletsNavigation: (WalletsNavigation) => Promise = value => setLocalItem(storageKeys.WALLETS_NAVIGATION, JSON.stringify(value)); + + loadAcceptedTosVersion: () => Promise = async () => { + const raw = await getLocalItem(storageKeys.ACCEPTED_TOS_VERSION); + if (!raw) { + return undefined; + } + const version = parseFloat(raw); + if (Number.isNaN(version)) { + return undefined; + } + return version; + }; + + saveAcceptedTosVersion: (version: number) => Promise = async (version) => { + await setLocalItem(storageKeys.ACCEPTED_TOS_VERSION, String(version)); + } + + unsetAcceptedTosVersion: void => Promise = + () => removeLocalItem(storageKeys.ACCEPTED_TOS_VERSION); + + loadIsAnalyticsAllowed: () => Promise = async () => { + const json = await getLocalItem(storageKeys.IS_ANALYTICS_ALLOWED); + if (!json) { + return undefined; + } + return JSON.parse(json); + } + + saveIsAnalysticsAllowed: (flag: boolean) => Promise = async (flag) => { + await setLocalItem(storageKeys.IS_ANALYTICS_ALLOWED, JSON.stringify(flag)); + } + + unsetIsAnalyticsAllowed: void => Promise = + () => removeLocalItem(storageKeys.IS_ANALYTICS_ALLOWED); + async reset(): Promise { await this.unsetUserLocale(); - await this.unsetTermsOfUseAcceptance(); await this.unsetUserTheme(); await this.unsetComplexityLevel(); await this.unsetLastLaunchVersion(); @@ -321,6 +360,8 @@ export default class LocalStorageApi { await this.unsetCoinPricePubKeyData(); await this.unsetExternalStorage(); await this.unsetToggleSidebar(); + await this.unsetAcceptedTosVersion(); + await this.unsetIsAnalyticsAllowed(); } getItem: string => Promise = (key) => getLocalItem(key); @@ -383,14 +424,6 @@ export async function loadSubmittedTransactions(): any { return JSON.parse(stored[storageKeys.SUBMITTED_TRANSACTIONS]); } -export async function loadAnalyticsInstanceId(): Promise { - return getLocalItem(storageKeys.ANALYTICS_INSTANCE_ID); -} - -export async function saveAnalyticsInstanceId(id: string): Promise { - await setLocalItem(storageKeys.ANALYTICS_INSTANCE_ID, id); -} - export async function loadCatalystRoundInfo(): Promise { const json = await getLocalItem(storageKeys.CATALYST_ROUND_INFO); if (!json) { diff --git a/packages/yoroi-extension/app/assets/images/analytics-illustration.inline.svg b/packages/yoroi-extension/app/assets/images/analytics-illustration.inline.svg new file mode 100644 index 0000000000..21493be9de --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/analytics-illustration.inline.svg @@ -0,0 +1,176 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/yoroi-extension/app/assets/images/assets-page/arrows-list-active.inline.svg b/packages/yoroi-extension/app/assets/images/assets-page/arrows-list-active.inline.svg new file mode 100644 index 0000000000..8f47a5a891 --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/assets-page/arrows-list-active.inline.svg @@ -0,0 +1,4 @@ + + + + diff --git a/packages/yoroi-extension/app/assets/images/assets-page/arrows-list-from-bottom.inline.svg b/packages/yoroi-extension/app/assets/images/assets-page/arrows-list-from-bottom.inline.svg index dc69fa3a88..48d68526fa 100644 --- a/packages/yoroi-extension/app/assets/images/assets-page/arrows-list-from-bottom.inline.svg +++ b/packages/yoroi-extension/app/assets/images/assets-page/arrows-list-from-bottom.inline.svg @@ -1,11 +1,4 @@ - - - icon/arrows_list_from bottom - - - - - - - - \ No newline at end of file + + + + diff --git a/packages/yoroi-extension/app/assets/images/assets-page/arrows-list-from-top.inline.svg b/packages/yoroi-extension/app/assets/images/assets-page/arrows-list-from-top.inline.svg index 3bd5531b11..6b297afb24 100644 --- a/packages/yoroi-extension/app/assets/images/assets-page/arrows-list-from-top.inline.svg +++ b/packages/yoroi-extension/app/assets/images/assets-page/arrows-list-from-top.inline.svg @@ -1,11 +1,4 @@ - - - icon/arrows_list_from top - - - - - - - - \ No newline at end of file + + + + diff --git a/packages/yoroi-extension/app/assets/images/assets-page/arrows-list.inline.svg b/packages/yoroi-extension/app/assets/images/assets-page/arrows-list.inline.svg index 6a359be847..b15a37dc14 100644 --- a/packages/yoroi-extension/app/assets/images/assets-page/arrows-list.inline.svg +++ b/packages/yoroi-extension/app/assets/images/assets-page/arrows-list.inline.svg @@ -1,11 +1,4 @@ - - - icon/arrows_list - - - - - - - - \ No newline at end of file + + + + diff --git a/packages/yoroi-extension/app/assets/images/assets-page/asset-no.inline.svg b/packages/yoroi-extension/app/assets/images/assets-page/asset-no.inline.svg index 70208f3ac0..0bf2f8ef47 100644 --- a/packages/yoroi-extension/app/assets/images/assets-page/asset-no.inline.svg +++ b/packages/yoroi-extension/app/assets/images/assets-page/asset-no.inline.svg @@ -1,8 +1,8 @@ - + icon/asset-no image - + \ No newline at end of file diff --git a/packages/yoroi-extension/app/assets/images/assets-page/back-arrow.inline.svg b/packages/yoroi-extension/app/assets/images/assets-page/back-arrow.inline.svg new file mode 100644 index 0000000000..cd8d182f73 --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/assets-page/back-arrow.inline.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/yoroi-extension/app/assets/images/assets-page/backarrow.inline.svg b/packages/yoroi-extension/app/assets/images/assets-page/backarrow.inline.svg index cd8d182f73..b8654d49c7 100644 --- a/packages/yoroi-extension/app/assets/images/assets-page/backarrow.inline.svg +++ b/packages/yoroi-extension/app/assets/images/assets-page/backarrow.inline.svg @@ -1,3 +1,3 @@ - - + + diff --git a/packages/yoroi-extension/app/assets/images/assets-page/default-asset-logo.inline.svg b/packages/yoroi-extension/app/assets/images/assets-page/default-asset-logo.inline.svg new file mode 100644 index 0000000000..180d86c23b --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/assets-page/default-asset-logo.inline.svg @@ -0,0 +1,4 @@ + + + + diff --git a/packages/yoroi-extension/app/assets/images/copied.inline.svg b/packages/yoroi-extension/app/assets/images/copied.inline.svg index 760435356c..9a9eff855e 100644 --- a/packages/yoroi-extension/app/assets/images/copied.inline.svg +++ b/packages/yoroi-extension/app/assets/images/copied.inline.svg @@ -1,15 +1,5 @@ - - - - icon/copied - Created with Sketch. - - - - - - - - - - \ No newline at end of file + + + + + diff --git a/packages/yoroi-extension/app/assets/images/copy.inline.svg b/packages/yoroi-extension/app/assets/images/copy.inline.svg index 25fd0e9469..2425b226ca 100644 --- a/packages/yoroi-extension/app/assets/images/copy.inline.svg +++ b/packages/yoroi-extension/app/assets/images/copy.inline.svg @@ -1,12 +1,4 @@ - - - - icon/copy - Created with Sketch. - - - - - - - \ No newline at end of file + + + + diff --git a/packages/yoroi-extension/app/assets/images/cross-dark-revamp.inline.svg b/packages/yoroi-extension/app/assets/images/cross-dark-revamp.inline.svg new file mode 100644 index 0000000000..ae73095834 --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/cross-dark-revamp.inline.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/yoroi-extension/app/assets/images/dapp-connector/no-websites-connected.inline.svg b/packages/yoroi-extension/app/assets/images/dapp-connector/no-dapps-connected.inline.svg similarity index 100% rename from packages/yoroi-extension/app/assets/images/dapp-connector/no-websites-connected.inline.svg rename to packages/yoroi-extension/app/assets/images/dapp-connector/no-dapps-connected.inline.svg diff --git a/packages/yoroi-extension/app/assets/images/dashboard/staking-active.inline.svg b/packages/yoroi-extension/app/assets/images/dashboard/staking-active.inline.svg index 34dc0bc9c0..bbcd8cc68d 100644 --- a/packages/yoroi-extension/app/assets/images/dashboard/staking-active.inline.svg +++ b/packages/yoroi-extension/app/assets/images/dashboard/staking-active.inline.svg @@ -1 +1,6 @@ - \ No newline at end of file + + + + + + diff --git a/packages/yoroi-extension/app/assets/images/dashboard/staking-illustration.inline.svg b/packages/yoroi-extension/app/assets/images/dashboard/staking-illustration.inline.svg new file mode 100644 index 0000000000..7893b4a2da --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/dashboard/staking-illustration.inline.svg @@ -0,0 +1,197 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/yoroi-extension/app/assets/images/dashboard/total-delegated.inline.svg b/packages/yoroi-extension/app/assets/images/dashboard/total-delegated.inline.svg index 61a217ed13..0cbb5c3c80 100644 --- a/packages/yoroi-extension/app/assets/images/dashboard/total-delegated.inline.svg +++ b/packages/yoroi-extension/app/assets/images/dashboard/total-delegated.inline.svg @@ -1 +1,4 @@ - \ No newline at end of file + + + + diff --git a/packages/yoroi-extension/app/assets/images/forms/password-eye-close.inline.svg b/packages/yoroi-extension/app/assets/images/forms/password-eye-close.inline.svg index 0e16364bd5..32bb039168 100644 --- a/packages/yoroi-extension/app/assets/images/forms/password-eye-close.inline.svg +++ b/packages/yoroi-extension/app/assets/images/forms/password-eye-close.inline.svg @@ -1 +1,3 @@ - \ No newline at end of file + + + diff --git a/packages/yoroi-extension/app/assets/images/forms/password-eye.inline.svg b/packages/yoroi-extension/app/assets/images/forms/password-eye.inline.svg index 98dbba0a2a..9dbe97e92f 100644 --- a/packages/yoroi-extension/app/assets/images/forms/password-eye.inline.svg +++ b/packages/yoroi-extension/app/assets/images/forms/password-eye.inline.svg @@ -1 +1,4 @@ - \ No newline at end of file + + + + diff --git a/packages/yoroi-extension/app/assets/images/info-icon-revamp.inline.svg b/packages/yoroi-extension/app/assets/images/info-icon-revamp.inline.svg new file mode 100644 index 0000000000..890c6157cc --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/info-icon-revamp.inline.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/packages/yoroi-extension/app/assets/images/info-warning.inline.svg b/packages/yoroi-extension/app/assets/images/info-warning.inline.svg new file mode 100644 index 0000000000..c9f3cec9b3 --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/info-warning.inline.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/packages/yoroi-extension/app/assets/images/input/icon_24_eye_off.inline.svg b/packages/yoroi-extension/app/assets/images/input/icon_24_eye_off.inline.svg deleted file mode 100644 index 21058ed412..0000000000 --- a/packages/yoroi-extension/app/assets/images/input/icon_24_eye_off.inline.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/packages/yoroi-extension/app/assets/images/input/icon_24_eye_on.inline.svg b/packages/yoroi-extension/app/assets/images/input/icon_24_eye_on.inline.svg deleted file mode 100644 index d2e734e06d..0000000000 --- a/packages/yoroi-extension/app/assets/images/input/icon_24_eye_on.inline.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/packages/yoroi-extension/app/assets/images/new-theme-illustration.inline.svg b/packages/yoroi-extension/app/assets/images/new-theme-illustration.inline.svg new file mode 100644 index 0000000000..921d5d97b1 --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/new-theme-illustration.inline.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/packages/yoroi-extension/app/assets/images/no.inline.svg b/packages/yoroi-extension/app/assets/images/no.inline.svg new file mode 100644 index 0000000000..b97e572244 --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/no.inline.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/yoroi-extension/app/assets/images/revamp/add-memo.inline.svg b/packages/yoroi-extension/app/assets/images/revamp/add-memo.inline.svg new file mode 100644 index 0000000000..2126e688df --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/revamp/add-memo.inline.svg @@ -0,0 +1,4 @@ + + + + diff --git a/packages/yoroi-extension/app/assets/images/revamp/catalyst-step1.inline.svg b/packages/yoroi-extension/app/assets/images/revamp/catalyst-step1.inline.svg new file mode 100644 index 0000000000..d5ac59cede --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/revamp/catalyst-step1.inline.svg @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/yoroi-extension/app/assets/images/revamp/catalyst-step2.inline.svg b/packages/yoroi-extension/app/assets/images/revamp/catalyst-step2.inline.svg new file mode 100644 index 0000000000..78907ccb07 --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/revamp/catalyst-step2.inline.svg @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/yoroi-extension/app/assets/images/revamp/delete.inline.svg b/packages/yoroi-extension/app/assets/images/revamp/delete.inline.svg new file mode 100644 index 0000000000..75036a7532 --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/revamp/delete.inline.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/yoroi-extension/app/assets/images/revamp/fingerprint-info.inline.svg b/packages/yoroi-extension/app/assets/images/revamp/fingerprint-info.inline.svg new file mode 100644 index 0000000000..578e81362c --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/revamp/fingerprint-info.inline.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/packages/yoroi-extension/app/assets/images/revamp/generate-uri.inline.svg b/packages/yoroi-extension/app/assets/images/revamp/generate-uri.inline.svg new file mode 100644 index 0000000000..8f08f9c00d --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/revamp/generate-uri.inline.svg @@ -0,0 +1,4 @@ + + + + diff --git a/packages/yoroi-extension/app/assets/images/revamp/icons/cross.inline.svg b/packages/yoroi-extension/app/assets/images/revamp/icons/cross.inline.svg new file mode 100644 index 0000000000..ae73095834 --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/revamp/icons/cross.inline.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/yoroi-extension/app/assets/images/revamp/icons/exclamation-circle.inline.svg b/packages/yoroi-extension/app/assets/images/revamp/icons/exclamation-circle.inline.svg new file mode 100644 index 0000000000..9203ed1d3e --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/revamp/icons/exclamation-circle.inline.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/packages/yoroi-extension/app/assets/images/revamp/icons/info.inline.svg b/packages/yoroi-extension/app/assets/images/revamp/icons/info.inline.svg new file mode 100644 index 0000000000..dc2f19dbf1 --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/revamp/icons/info.inline.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/packages/yoroi-extension/app/assets/images/revamp/info.inline.svg b/packages/yoroi-extension/app/assets/images/revamp/info.inline.svg new file mode 100644 index 0000000000..890c6157cc --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/revamp/info.inline.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/packages/yoroi-extension/app/assets/images/revamp/no-dapps-connected.inline.svg b/packages/yoroi-extension/app/assets/images/revamp/no-dapps-connected.inline.svg new file mode 100644 index 0000000000..86148a421d --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/revamp/no-dapps-connected.inline.svg @@ -0,0 +1,197 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/yoroi-extension/app/assets/images/revamp/registration-is-not-available.inline.svg b/packages/yoroi-extension/app/assets/images/revamp/registration-is-not-available.inline.svg new file mode 100644 index 0000000000..a17de01dfa --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/revamp/registration-is-not-available.inline.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/yoroi-extension/app/assets/images/revamp/verify-icon.inline.svg b/packages/yoroi-extension/app/assets/images/revamp/verify-icon.inline.svg new file mode 100644 index 0000000000..3f7bea4817 --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/revamp/verify-icon.inline.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/yoroi-extension/app/assets/images/sidebar/open_sidebar.inline.svg b/packages/yoroi-extension/app/assets/images/sidebar/open-sidebar.inline.svg similarity index 100% rename from packages/yoroi-extension/app/assets/images/sidebar/open_sidebar.inline.svg rename to packages/yoroi-extension/app/assets/images/sidebar/open-sidebar.inline.svg diff --git a/packages/yoroi-extension/app/assets/images/sidebar/revamp/yoroi-logo.inline.svg b/packages/yoroi-extension/app/assets/images/sidebar/revamp/yoroi-logo.inline.svg new file mode 100644 index 0000000000..23525eab44 --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/sidebar/revamp/yoroi-logo.inline.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/yoroi-extension/app/assets/images/sidebar/yoroi_logo_expanded.inline.svg b/packages/yoroi-extension/app/assets/images/sidebar/yoroi-logo-expanded.inline.svg similarity index 100% rename from packages/yoroi-extension/app/assets/images/sidebar/yoroi_logo_expanded.inline.svg rename to packages/yoroi-extension/app/assets/images/sidebar/yoroi-logo-expanded.inline.svg diff --git a/packages/yoroi-extension/app/assets/images/sidebar/yoroi_logo.inline.svg b/packages/yoroi-extension/app/assets/images/sidebar/yoroi-logo.inline.svg similarity index 100% rename from packages/yoroi-extension/app/assets/images/sidebar/yoroi_logo.inline.svg rename to packages/yoroi-extension/app/assets/images/sidebar/yoroi-logo.inline.svg diff --git a/packages/yoroi-extension/app/assets/images/social/revamp/discord-24x24.inline.svg b/packages/yoroi-extension/app/assets/images/social/revamp/discord-24x24.inline.svg new file mode 100644 index 0000000000..3346c5ea03 --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/social/revamp/discord-24x24.inline.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/yoroi-extension/app/assets/images/social/revamp/facebook-24x24.inline.svg b/packages/yoroi-extension/app/assets/images/social/revamp/facebook-24x24.inline.svg new file mode 100644 index 0000000000..7991505aef --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/social/revamp/facebook-24x24.inline.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/yoroi-extension/app/assets/images/social/revamp/github-24x24.inline.svg b/packages/yoroi-extension/app/assets/images/social/revamp/github-24x24.inline.svg new file mode 100644 index 0000000000..6f6f5e5306 --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/social/revamp/github-24x24.inline.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/yoroi-extension/app/assets/images/social/revamp/personal-site-24x24.inline.svg b/packages/yoroi-extension/app/assets/images/social/revamp/personal-site-24x24.inline.svg new file mode 100644 index 0000000000..a5fd2dbf85 --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/social/revamp/personal-site-24x24.inline.svg @@ -0,0 +1,4 @@ + + + + diff --git a/packages/yoroi-extension/app/assets/images/social/revamp/telegram-24x24.inline.svg b/packages/yoroi-extension/app/assets/images/social/revamp/telegram-24x24.inline.svg new file mode 100644 index 0000000000..9bc32091d1 --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/social/revamp/telegram-24x24.inline.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/yoroi-extension/app/assets/images/social/revamp/twitch-24x24.inline.svg b/packages/yoroi-extension/app/assets/images/social/revamp/twitch-24x24.inline.svg new file mode 100644 index 0000000000..b45c5c1537 --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/social/revamp/twitch-24x24.inline.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/yoroi-extension/app/assets/images/social/revamp/twitter-24x24.inline.svg b/packages/yoroi-extension/app/assets/images/social/revamp/twitter-24x24.inline.svg new file mode 100644 index 0000000000..6bc9faa644 --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/social/revamp/twitter-24x24.inline.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/yoroi-extension/app/assets/images/social/revamp/youtube-24x24.inline.svg b/packages/yoroi-extension/app/assets/images/social/revamp/youtube-24x24.inline.svg new file mode 100644 index 0000000000..2d77a7ef1a --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/social/revamp/youtube-24x24.inline.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/yoroi-extension/app/assets/images/top-bar/moon.inline.svg b/packages/yoroi-extension/app/assets/images/top-bar/moon.inline.svg new file mode 100644 index 0000000000..1b4d19666d --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/top-bar/moon.inline.svg @@ -0,0 +1,15 @@ + + + + + + + + + \ No newline at end of file diff --git a/packages/yoroi-extension/app/assets/images/top-bar/sun.inline.svg b/packages/yoroi-extension/app/assets/images/top-bar/sun.inline.svg new file mode 100644 index 0000000000..489925601b --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/top-bar/sun.inline.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/yoroi-extension/app/assets/images/transaction/export.inline.svg b/packages/yoroi-extension/app/assets/images/transaction/export.inline.svg index 2a14697675..2528c4184a 100644 --- a/packages/yoroi-extension/app/assets/images/transaction/export.inline.svg +++ b/packages/yoroi-extension/app/assets/images/transaction/export.inline.svg @@ -1,11 +1,4 @@ - - - icon/export - - - - - - - - \ No newline at end of file + + + + diff --git a/packages/yoroi-extension/app/assets/images/transaction/stake.inline.svg b/packages/yoroi-extension/app/assets/images/transaction/stake.inline.svg new file mode 100644 index 0000000000..46ed101875 --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/transaction/stake.inline.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/packages/yoroi-extension/app/assets/images/yes.inline.svg b/packages/yoroi-extension/app/assets/images/yes.inline.svg new file mode 100644 index 0000000000..caa778a4f0 --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/yes.inline.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/packages/yoroi-extension/app/assets/images/yoroi-logo-revamp-blue.inline.svg b/packages/yoroi-extension/app/assets/images/yoroi-logo-revamp-blue.inline.svg new file mode 100644 index 0000000000..4df8f151a3 --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/yoroi-logo-revamp-blue.inline.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/packages/yoroi-extension/app/assets/images/yoroi-logo-revamp-nightly-blue.inline.svg b/packages/yoroi-extension/app/assets/images/yoroi-logo-revamp-nightly-blue.inline.svg new file mode 100644 index 0000000000..bc22bcc925 --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/yoroi-logo-revamp-nightly-blue.inline.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/yoroi-extension/app/assets/images/yoroi-nightly-icon-dark.inline.svg b/packages/yoroi-extension/app/assets/images/yoroi-nightly-icon-dark.inline.svg new file mode 100644 index 0000000000..6f70d51889 --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/yoroi-nightly-icon-dark.inline.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/yoroi-extension/app/components/buySell/BuySellDialog.js b/packages/yoroi-extension/app/components/buySell/BuySellDialog.js index a3497124d6..e368431362 100644 --- a/packages/yoroi-extension/app/components/buySell/BuySellDialog.js +++ b/packages/yoroi-extension/app/components/buySell/BuySellDialog.js @@ -8,14 +8,14 @@ import type { $npm$ReactIntl$IntlFormat } from 'react-intl'; import { truncateAddress } from '../../utils/formatters'; import Dialog from '../widgets/Dialog'; import DialogCloseButton from '../widgets/DialogCloseButton'; -import ChangellyFetcher from './ChangellyFetcher' +import ChangellyFetcher from './ChangellyFetcher'; import styles from './BuySellDialog.scss'; -import { ReactComponent as VerifyIcon } from '../../assets/images/verify-icon.inline.svg' -import VerticalFlexContainer from '../layout/VerticalFlexContainer' -import LoadingSpinner from '../widgets/LoadingSpinner' +import { ReactComponent as VerifyIcon } from '../../assets/images/verify-icon.inline.svg'; +import VerticalFlexContainer from '../layout/VerticalFlexContainer'; +import LoadingSpinner from '../widgets/LoadingSpinner'; import globalMessages from '../../i18n/global-messages'; -import { trackBuySellDialog } from '../../api/analytics'; +import { Box } from '@mui/material'; const messages = defineMessages({ dialogTitle: { @@ -24,11 +24,13 @@ const messages = defineMessages({ }, dialogSelectAddress: { id: 'buysell.dialog.selectAddress', - defaultMessage: '!!!Please select the receiving address. This will be shared with the third party provider called Changelly for the buy / sell of ADA. ', + defaultMessage: + '!!!Please select the receiving address. This will be shared with the third party provider called Changelly for the buy / sell of ADA. ', }, dialogDescription: { id: 'buysell.dialog.instructions', - defaultMessage: '!!!Please select your preferences. On the next screen, confirm your selection by pressing the green arrow on the top right', + defaultMessage: + '!!!Please select your preferences. On the next screen, confirm your selection by pressing the green arrow on the top right', }, dialogManual: { id: 'buysell.dialog.manual', @@ -40,14 +42,15 @@ export type WalletInfo = {| walletName: string, currencyName: string, anAddressFormatted: string, -|} +|}; type Props = {| +onCancel: void => void, - +genWalletList: () => Promise> + +genWalletList: () => Promise>, |}; -const WIDGET_URL = 'https://widget.changelly.com?from=*&to=*&amount=200&fromDefault=usd&toDefault=ada&theme=default&merchant_id=g9qheu8vschp16jj&payment_id=&v=3' +const WIDGET_URL = + 'https://widget.changelly.com?from=*&to=*&amount=200&fromDefault=usd&toDefault=ada&theme=default&merchant_id=g9qheu8vschp16jj&payment_id=&v=3'; type State = {| addressSelected: ?string, @@ -56,7 +59,7 @@ type State = {| @observer export default class BuySellDialog extends Component { - static contextTypes: {|intl: $npm$ReactIntl$IntlFormat|} = { + static contextTypes: {| intl: $npm$ReactIntl$IntlFormat |} = { intl: intlShape.isRequired, }; @@ -65,42 +68,38 @@ export default class BuySellDialog extends Component { walletList: null, }; - async componentDidMount () { + async componentDidMount() { const { intl } = this.context; - const resp = await this.props.genWalletList() + const resp = await this.props.genWalletList(); const wallets = [ ...resp, { walletName: intl.formatMessage(messages.dialogManual), currencyName: '', anAddressFormatted: '', - } - ] - this.setState({ walletList: wallets }) - trackBuySellDialog(); + }, + ]; + this.setState({ walletList: wallets }); } - createRows: ($npm$ReactIntl$IntlFormat, Array) => Node = (intl, wallets) => ( + createRows: ($npm$ReactIntl$IntlFormat, Array) => Node = (intl, wallets) => wallets.map((wallet, i) => { return ( // eslint-disable-next-line react/no-array-index-key
- { wallet.currencyName ? `(${wallet.currencyName}) ` : ''}{wallet.walletName} -
-
- {truncateAddress(wallet.anAddressFormatted)} + {wallet.currencyName ? `(${wallet.currencyName}) ` : ''} + {wallet.walletName}
+
{truncateAddress(wallet.anAddressFormatted)}
{/* Verify Address action */}
- ) - }) - ) + ); + }); render(): Node { const { intl } = this.context; @@ -139,32 +137,27 @@ export default class BuySellDialog extends Component { closeOnOverlayClick={false} onClose={this.props.onCancel} closeButton={} - className="" >
- {intl.formatMessage(messages.dialogSelectAddress)} + {intl.formatMessage(messages.dialogSelectAddress)} {addressNodes}
- ) - } - - return ( - } - className="" - > -
-
- {intl.formatMessage(messages.dialogDescription)} -
- -
-
); + } + return ( + } + > +
+
{intl.formatMessage(messages.dialogDescription)}
+ +
+
+ ); } } diff --git a/packages/yoroi-extension/app/components/buySell/BuySellDialog.scss b/packages/yoroi-extension/app/components/buySell/BuySellDialog.scss index 9c50988475..cf70c7a277 100644 --- a/packages/yoroi-extension/app/components/buySell/BuySellDialog.scss +++ b/packages/yoroi-extension/app/components/buySell/BuySellDialog.scss @@ -4,6 +4,7 @@ padding-left: 40px; padding-right: 40px; max-height: 600px; + max-width: 600px; .description { color: var(--yoroi-palette-gray-900); @@ -20,17 +21,16 @@ flex-direction: column; letter-spacing: 0; line-height: 22px; + max-width: 600px; } .row { display: flex; - flex-direction: row; - height: 60px; - align-items: flex-start; + flex-flow: row nowrap; + align-items: center; + justify-content: space-between; .left { - flex: 7; - .nameAndCurrency { color: var(--yoroi-palette-gray-900); font-size: 16px; @@ -44,15 +44,6 @@ line-height: 22px; } } - .right { - flex: 1; - width: 40px; - height: 40px; - } -} - -.row:first-child { - margin-top: 40px; } .verifyIcon { diff --git a/packages/yoroi-extension/app/components/common/AmountDisplay.js b/packages/yoroi-extension/app/components/common/AmountDisplay.js index 1d7e2d6842..81ab023956 100644 --- a/packages/yoroi-extension/app/components/common/AmountDisplay.js +++ b/packages/yoroi-extension/app/components/common/AmountDisplay.js @@ -45,7 +45,11 @@ export default class AmountDisplay extends Component { if (shouldHideBalance) { balanceDisplay = {hiddenAmount}; - fiatDisplay = {hiddenAmount}; + fiatDisplay = ( + + {hiddenAmount} {currency} + + ); } else { const shiftedAmount = defaultEntry.amount.shiftedBy(-tokenInfo.Metadata.numberOfDecimals); @@ -61,7 +65,7 @@ export default class AmountDisplay extends Component { ); - if (unitOfAccountSetting.enabled && Boolean(showFiat)) { + if (unitOfAccountSetting.enabled) { const ticker = tokenInfo.Metadata.ticker; if (ticker == null) { throw new Error('unexpected main token type'); @@ -85,9 +89,9 @@ export default class AmountDisplay extends Component { {balanceDisplay} {truncateToken(getTokenName(tokenInfo))}

)} - {showFiat === true && unitOfAccountSetting.enabled && ( + {showFiat === true && (

- {fiatDisplay} {currency} + {fiatDisplay || '-'} {currency || 'USD'}

)} diff --git a/packages/yoroi-extension/app/components/common/AmountInput.scss b/packages/yoroi-extension/app/components/common/AmountInput.scss deleted file mode 100644 index 8d2f78f286..0000000000 --- a/packages/yoroi-extension/app/components/common/AmountInput.scss +++ /dev/null @@ -1,30 +0,0 @@ -.component { - width: 100%; - - & > div { - padding: 0px; - margin: 0px; - } - - input { - border: none; - outline: none; - width: 100%; - color: #242838; - font-family: Rubik; - font-size: 24px; - letter-spacing: 0; - line-height: 32px; - background-color: #ffffff; - &:focus { - outline: none; - } - - &::placeholder { - color: #A7AFC0; - font-size: 24px; - letter-spacing: 0; - line-height: 32px; - } - } -} \ No newline at end of file diff --git a/packages/yoroi-extension/app/components/common/Divider.js b/packages/yoroi-extension/app/components/common/Divider.js new file mode 100644 index 0000000000..7a5f2d150c --- /dev/null +++ b/packages/yoroi-extension/app/components/common/Divider.js @@ -0,0 +1,7 @@ +// @flow +import { Box } from '@mui/material'; +import type { Node } from 'react'; + +export function Divider(): Node { + return ; +} diff --git a/packages/yoroi-extension/app/components/common/NumericInputRP.js b/packages/yoroi-extension/app/components/common/NumericInputRP.js index 3fe0e04afe..ab7e3d7005 100644 --- a/packages/yoroi-extension/app/components/common/NumericInputRP.js +++ b/packages/yoroi-extension/app/components/common/NumericInputRP.js @@ -13,7 +13,6 @@ import type { $npm$ReactIntl$IntlFormat } from 'react-intl'; import TextField from './TextField'; import { Box } from '@mui/system'; import { Typography } from '@mui/material'; -import styles from './AmountInput.scss'; type NumericInputValue = null | number | string | BigNumber; @@ -490,7 +489,7 @@ class AmountInput extends Component { right: '10px', fontWeight: 400, fontSize: '0.75rem', - color: 'var(--yoroi-comp-input-text)', + color: 'grayscale.900', }} > {intl.formatMessage(messages.feesLabel, { amount: fees })} @@ -503,7 +502,7 @@ class AmountInput extends Component { position: 'absolute', bottom: '45px', right: error != null && error !== '' ? '45px' : '10px', - color: 'var(--yoroi-comp-input-text)', + color: 'grayscale.900', textTransform: 'uppercase', }} > @@ -529,9 +528,25 @@ class AmountInputRevamp extends Component { const { intl } = this.context; return ( -
+ div': { + padding: '0px', + margin: '0px', + }, + '& input': { + border: 'none', + outline: 'none', + width: '100%', + fontSize: '24px', + lineHeight: '32px', + }, + '& input::placeholder': { color: 'grayscale.600' }, + }} + > -
+
); } } diff --git a/packages/yoroi-extension/app/components/common/TextField.js b/packages/yoroi-extension/app/components/common/TextField.js index f2ad2ffa4d..e59012146a 100644 --- a/packages/yoroi-extension/app/components/common/TextField.js +++ b/packages/yoroi-extension/app/components/common/TextField.js @@ -8,11 +8,10 @@ import { ReactComponent as DoneIcon } from '../../assets/images/forms/done.inlin import { ReactComponent as EyeIcon } from '../../assets/images/forms/password-eye-close.inline.svg'; import { ReactComponent as CloseEyeIcon } from '../../assets/images/forms/password-eye.inline.svg'; import { ReactComponent as QRLogo } from '../../assets/images/qr-code.inline.svg'; -import { ReactComponent as ClosedEyeIconRevamp } from '../../assets/images/input/icon_24_eye_off.inline.svg'; -import { ReactComponent as OpenedEyeIconRevamp } from '../../assets/images/input/icon_24_eye_on.inline.svg'; type Props = {| error?: boolean | string, + helperText?: string, done?: boolean, type?: string, className?: string, @@ -34,6 +33,7 @@ function TextField({ value, disabled, error, + helperText, done, type, inputRef, @@ -56,6 +56,8 @@ function TextField({ event.preventDefault(); }; + const isRevampTheme = theme.name === 'revamp-light'; + return ( - {Boolean(error) === true ? : done === true ? : null} + {Boolean(error) === true && !isRevampTheme ? ( + + ) : done === true && !isRevampTheme ? ( + + ) : null} - {getEyeIcon(theme.name, showPassword)} + {showPassword ? : } ) : QRHandler ? ( @@ -105,14 +111,22 @@ function TextField({ position="end" sx={{ minWidth: '52px', display: 'flex', justifyContent: 'flex-end' }} > - {Boolean(error) === true ? : done === true ? : null} + {Boolean(error) === true && !isRevampTheme ? ( + + ) : done === true && !isRevampTheme ? ( + + ) : null} ) : ( - {Boolean(error) === true ? : done === true ? : null} + {Boolean(error) === true && !isRevampTheme ? ( + + ) : done === true && !isRevampTheme ? ( + + ) : null} ), placeholder: placeholder != null ? placeholder : '', @@ -125,6 +139,7 @@ TextField.defaultProps = { label: '', done: false, error: '', + helperText: ' ', className: '', disabled: false, InputLabelProps: null, @@ -138,11 +153,4 @@ TextField.defaultProps = { placeholder: undefined, }; -function getEyeIcon(theme: 'revamp' | 'classic' | 'modern', showPassword: boolean): Node { - if (theme === 'revamp' && !showPassword) return ; - if (theme === 'revamp' && showPassword) return ; - - return showPassword ? : ; -} - export default TextField; diff --git a/packages/yoroi-extension/app/components/common/Warning.js b/packages/yoroi-extension/app/components/common/Warning.js new file mode 100644 index 0000000000..3a2c793b42 --- /dev/null +++ b/packages/yoroi-extension/app/components/common/Warning.js @@ -0,0 +1,45 @@ +// @flow +import { Box, Typography } from '@mui/material'; +import type { Node } from 'react'; +import { ReactComponent as InfoWarningIcon } from '../../assets/images/info-warning.inline.svg'; +import { FormattedMessage } from 'react-intl'; +import globalMessages from '../../i18n/global-messages'; + +type Props = {| + children?: Node, +|}; + +export default function Warning({ children }: Props): Node { + return ( + theme.palette.yellow[100], + borderRadius: '8px', + }} + > + + + theme.palette.yellow[500]} + sx={{ + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + }} + > + + + + + {children} + + ); +} + +Warning.defaultProps = { + children: undefined, +}; diff --git a/packages/yoroi-extension/app/components/common/card/Card.js b/packages/yoroi-extension/app/components/common/card/Card.js new file mode 100644 index 0000000000..60f6651b4d --- /dev/null +++ b/packages/yoroi-extension/app/components/common/card/Card.js @@ -0,0 +1,39 @@ +// @flow +import type { Node } from 'react'; +import { Box, Typography } from '@mui/material'; +import styles from './Card.scss'; + +type Props = {| + label: string, + description: string | Node, + imageSrc: string, + onClick?: () => void, + children?: Node, + style?: Object, +|}; + +export default function Card(props: Props): Node { + const { label, description, imageSrc, onClick, style } = props; + return ( + + ); +} diff --git a/packages/yoroi-extension/app/components/common/card/Card.scss b/packages/yoroi-extension/app/components/common/card/Card.scss new file mode 100644 index 0000000000..79b2cbf445 --- /dev/null +++ b/packages/yoroi-extension/app/components/common/card/Card.scss @@ -0,0 +1,33 @@ +.component { + background: linear-gradient(180deg, #e4e8f7 0%, #c6f7f7 100%); + border-radius: 8px; + padding: 16px; + width: 100%; + max-width: 312px; + min-height: 352px; + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + cursor: pointer; + position: relative; + z-index: 1; + + &::before { + position: absolute; + content: ''; + top: 0px; + right: 0px; + bottom: 0px; + left: 0px; + background: linear-gradient(180deg, #93f5e1 0%, #c6f7ed 100%); + border-radius: 8px; + z-index: -1; + transition: opacity 300ms linear; + opacity: 0; + } + + &:hover::before { + opacity: 1; + } +} diff --git a/packages/yoroi-extension/app/components/common/stepper/Stepper.js b/packages/yoroi-extension/app/components/common/stepper/Stepper.js index acf0ea402d..334dafecaa 100644 --- a/packages/yoroi-extension/app/components/common/stepper/Stepper.js +++ b/packages/yoroi-extension/app/components/common/stepper/Stepper.js @@ -17,59 +17,78 @@ type Props = {| steps: Array, currentStep: string, setCurrentStep(stepId: string): void, + sx?: Object, |}; function Stepper(props: Props & Intl): Node { - const { intl, steps, currentStep, setCurrentStep } = props; + const { intl, steps, currentStep, setCurrentStep, sx } = props; const currentStepIdx = steps.findIndex(step => step.stepId === currentStep); if (currentStepIdx === -1) throw new Error(`Step to found. Should never happen`); return ( - - - {steps.map(({ stepId, message }, idx) => { - const isCurrentStep = currentStepIdx === idx; - const isPrevStep = idx < currentStepIdx; - const isFutureStep = idx > currentStepIdx; - let stepColor = 'grey.400'; - let cursor = 'pointer'; + + {steps.map(({ stepId, message }, idx) => { + const isCurrentStep = currentStepIdx === idx; + const isPrevStep = idx < currentStepIdx; + const isFutureStep = idx > currentStepIdx; + let stepColor = 'grey.400'; + let cursor = 'pointer'; - if (isCurrentStep) stepColor = 'primary.600'; - else if (isPrevStep) stepColor = 'primary.300'; + if (isCurrentStep) stepColor = 'primary.600'; + else if (isPrevStep) stepColor = 'primary.300'; + if (isFutureStep) cursor = 'not-allowed'; - if (isFutureStep) cursor = 'not-allowed'; - - return ( - { - if (isPrevStep) setCurrentStep(stepId); + return ( + { + if (isPrevStep) setCurrentStep(stepId); + }} + > + - - {isPrevStep ? ( - - ) : ( - - {idx + 1} - - )} - - - {intl.formatMessage(message)} - - - ); - })} - - + {isPrevStep ? ( + + ) : ( + + {idx + 1} + + )} + + + {intl.formatMessage(message)} + + + ); + })} + ); } -export default (injectIntl(observer(Stepper)): ComponentType); +export default (injectIntl(observer(Stepper)): ComponentType); \ No newline at end of file diff --git a/packages/yoroi-extension/app/components/common/stepper/Stepper.scss b/packages/yoroi-extension/app/components/common/stepper/Stepper.scss index 5508f3eb1f..30f817514f 100644 --- a/packages/yoroi-extension/app/components/common/stepper/Stepper.scss +++ b/packages/yoroi-extension/app/components/common/stepper/Stepper.scss @@ -6,12 +6,6 @@ margin-bottom: 48px; } -.stackSteps { - flex-direction: row; - align-items: center; - justify-content: center; -} - .stackStep { width: 24px; height: 24px; @@ -23,4 +17,4 @@ border-style: solid; border-radius: 50%; transition: color 300ms ease; -} +} \ No newline at end of file diff --git a/packages/yoroi-extension/app/components/dapp-connector/ConnectedWebsites/ConnectedWebsitesPage.js b/packages/yoroi-extension/app/components/dapp-connector/ConnectedWebsites/ConnectedWebsitesPage.js index d08fad5f41..c16f02217c 100644 --- a/packages/yoroi-extension/app/components/dapp-connector/ConnectedWebsites/ConnectedWebsitesPage.js +++ b/packages/yoroi-extension/app/components/dapp-connector/ConnectedWebsites/ConnectedWebsitesPage.js @@ -1,20 +1,24 @@ // @flow -import type { Node } from 'react'; -import { Component } from 'react'; -import { observer } from 'mobx-react'; +import type { Node, ComponentType } from 'react'; import type { WhitelistEntry } from '../../../../chrome/extension/connector/types'; -import styles from './ConnectedWebsitesPage.scss'; -import { ReactComponent as NoItemsFoundImg } from '../../../assets/images/dapp-connector/no-websites-connected.inline.svg'; import type { $npm$ReactIntl$IntlFormat } from 'react-intl'; -import { defineMessages, intlShape } from 'react-intl'; -import { connectorMessages } from '../../../i18n/global-messages'; -import { isErgo } from '../../../api/ada/lib/storage/database/prepackaged/networks'; -import WalletRow from './WalletRow'; import type { TokenRow } from '../../../api/ada/lib/storage/database/primitives/tables'; import type { TokenLookupKey, MultiToken } from '../../../api/common/lib/MultiToken'; import type { ConceptualWalletSettingsCache } from '../../../stores/toplevel/WalletSettingsStore'; import type { WalletChecksum } from '@emurgo/cip4-js'; +import { Component } from 'react'; +import { observer } from 'mobx-react'; +import { ReactComponent as NoDappsFoundImg } from '../../../assets/images/dapp-connector/no-dapps-connected.inline.svg'; +import { ReactComponent as NoDappsConnected } from '../../../assets/images/revamp/no-dapps-connected.inline.svg'; +import { defineMessages, intlShape } from 'react-intl'; +import { connectorMessages } from '../../../i18n/global-messages'; +import { isErgo } from '../../../api/ada/lib/storage/database/prepackaged/networks'; import { PublicDeriver } from '../../../api/ada/lib/storage/models/PublicDeriver'; +import { withLayout } from '../../../styles/context/layout'; +import styles from './ConnectedWebsitesPage.scss'; +import WalletRow from './WalletRow'; +import WalletRowRevamp from './WalletRowRevamp'; +import { Box, Typography } from '@mui/material'; type WalletInfo = {| balance: null | MultiToken, plate: WalletChecksum |}; type Props = {| @@ -28,6 +32,10 @@ type Props = {| +getWalletInfo: (PublicDeriver<>) => WalletInfo, |}; +type InjectedProps = {| isRevampLayout: boolean |}; + +type AllProps = {| ...Props, ...InjectedProps |}; + const messages = defineMessages({ connectedWallets: { id: 'connector.connect.connectedWallets', @@ -37,6 +45,10 @@ const messages = defineMessages({ id: 'connector.connect.noWebsitesConnected', defaultMessage: "!!!You don't have any websites connected yet", }, + connectedDapps: { + id: 'connector.connected-dapps.title', + defaultMessage: '!!!Connected DApps ({dappsCount})', + }, walletsLabel: { id: 'connector.connected-dapps.walletsLabel', defaultMessage: '!!!Wallets', @@ -56,17 +68,115 @@ const messages = defineMessages({ }); @observer -export default class ConnectedWebsitesPage extends Component { +class ConnectedWebsitesPage extends Component { static contextTypes: {| intl: $npm$ReactIntl$IntlFormat |} = { intl: intlShape.isRequired, }; + renderRevamp(): Node { + const { intl } = this.context; + const genNoResult = () => ( + + + + + + {intl.formatMessage(messages.noWebsitesConnected)} + + + {intl.formatMessage(connectorMessages.messageReadOnly)} + + + + + ); + + const { whitelistEntries, wallets } = this.props; + if ( + whitelistEntries == null || + whitelistEntries.length === 0 || + wallets == null || + wallets.length === 0 + ) { + return genNoResult(); + } + + const cardanoNodes = whitelistEntries + .map(({ url, protocol, publicDeriverId, image }) => { + const wallet = wallets.find( + cacheEntry => cacheEntry.getPublicDeriverId() === publicDeriverId + ); + + if (wallet == null) return null; + + const isErgoWallet = isErgo(wallet.getParent().getNetworkInfo()); + if (isErgoWallet) return null; + + const { balance, plate } = this.props.getWalletInfo(wallet); + + return [ + , + ]; + }) + .reduce((acc, node) => { + if (node != null) acc.push(node); + return acc; + }, []); + + if (cardanoNodes.length === 0) return genNoResult(); + + return ( + + + + {intl.formatMessage(messages.connectedDapps, { dappsCount: cardanoNodes.length })} + + + + + {intl.formatMessage(messages.walletsLabel)} + + + {intl.formatMessage(messages.dappsLabel)} + + + {cardanoNodes} + + ); + } + render(): Node { + const { isRevampLayout } = this.props; + + if (isRevampLayout) return this.renderRevamp(); + const { intl } = this.context; const genNoResult = () => (
-
- +
+

{intl.formatMessage(messages.noWebsitesConnected)}

{intl.formatMessage(connectorMessages.messageReadOnly)}

@@ -148,3 +258,5 @@ export default class ConnectedWebsitesPage extends Component { ); } } + +export default (withLayout(ConnectedWebsitesPage): ComponentType); diff --git a/packages/yoroi-extension/app/components/dapp-connector/ConnectedWebsites/ConnectedWebsitesPage.scss b/packages/yoroi-extension/app/components/dapp-connector/ConnectedWebsites/ConnectedWebsitesPage.scss index 42a8747868..9112ef4189 100644 --- a/packages/yoroi-extension/app/components/dapp-connector/ConnectedWebsites/ConnectedWebsitesPage.scss +++ b/packages/yoroi-extension/app/components/dapp-connector/ConnectedWebsites/ConnectedWebsitesPage.scss @@ -1,17 +1,16 @@ .component { height: 100%; width: 100%; - background-color: #f0f3f5; + background-color: #fff; display: flex; justify-content: center; .container { width: 750px; - height: 600px; + height: 500px; overflow-y: scroll; background-color: white; - margin-top: 40px; - margin-bottom: 40px; + border: 1px solid #dce0e9; border-radius: 8px; -ms-overflow-style: none; scrollbar-width: none; @@ -29,7 +28,7 @@ & > p { padding-left: 40px; padding-top: 28px; - color: #a7afc0; + color: #000; font-family: Rubik; font-size: 14px; letter-spacing: 0; @@ -70,7 +69,7 @@ } } -.noItems { +.noDappsFound { width: 100%; height: 100%; padding-bottom: 20px; diff --git a/packages/yoroi-extension/app/components/dapp-connector/ConnectedWebsites/WalletRowRevamp.js b/packages/yoroi-extension/app/components/dapp-connector/ConnectedWebsites/WalletRowRevamp.js new file mode 100644 index 0000000000..51267f26ad --- /dev/null +++ b/packages/yoroi-extension/app/components/dapp-connector/ConnectedWebsites/WalletRowRevamp.js @@ -0,0 +1,164 @@ +// @flow + +import type { Node } from 'react'; +import type { MultiToken, TokenLookupKey } from '../../../api/common/lib/MultiToken'; +import type { TokenRow } from '../../../api/ada/lib/storage/database/primitives/tables'; +import type { ConceptualWalletSettingsCache } from '../../../stores/toplevel/WalletSettingsStore'; +import type { $npm$ReactIntl$IntlFormat } from 'react-intl'; +import type { WalletChecksum } from '@emurgo/cip4-js'; +import { Component } from 'react'; +import { getTokenName } from '../../../stores/stateless/tokenHelpers'; +import { hiddenAmount } from '../../../utils/strings'; +import { ReactComponent as DeleteIcon } from '../../../assets/images/revamp/delete.inline.svg'; +import { ReactComponent as NoDappImage } from '../../../assets/images/dapp-connector/no-dapp.inline.svg'; +import { intlShape } from 'react-intl'; +import { splitAmount, truncateToken } from '../../../utils/formatters'; +import { Box, Typography } from '@mui/material'; +import { constructPlate } from '../../topbar/NavPlate'; +import styles from './WalletRow.scss'; + +type Props = {| + +url: ?string, + +protocol: ?string, + +shouldHideBalance: boolean, + +onRemoveWallet: ({| url: ?string, protocol: ?string |}) => void, + +getTokenInfo: ($ReadOnly>) => $ReadOnly, + +settingsCache: ConceptualWalletSettingsCache, + +websiteIcon: string, + +balance: MultiToken | null, + +plate: WalletChecksum, +|}; + +type State = {| + showDeleteIcon: boolean, +|}; + +export default class WalletRowRevamp extends Component { + static contextTypes: {| intl: $npm$ReactIntl$IntlFormat |} = { + intl: intlShape.isRequired, + }; + + state: State = { + showDeleteIcon: false, + }; + + showDeleteIcon: void => void = () => { + this.setState({ showDeleteIcon: true }); + }; + + hideDeleteIcon: void => void = () => { + this.setState({ showDeleteIcon: false }); + }; + + renderAmountDisplay: ({| + shouldHideBalance: boolean, + amount: ?MultiToken, + |}) => Node = request => { + if (request.amount == null) { + return
; + } + + const defaultEntry = request.amount.getDefaultEntry(); + const tokenInfo = this.props.getTokenInfo(defaultEntry); + const shiftedAmount = defaultEntry.amount.shiftedBy(-tokenInfo.Metadata.numberOfDecimals); + + let balanceDisplay; + if (request.shouldHideBalance) { + balanceDisplay = {hiddenAmount}; + } else { + const [beforeDecimalRewards, afterDecimalRewards] = splitAmount( + shiftedAmount, + tokenInfo.Metadata.numberOfDecimals + ); + + balanceDisplay = ( + <> + {beforeDecimalRewards} + {afterDecimalRewards} + + ); + } + + return ( + <> + {balanceDisplay} {truncateToken(getTokenName(tokenInfo))} + + ); + }; + + render(): Node { + const { + url, + protocol, + plate, + onRemoveWallet, + balance, + shouldHideBalance, + settingsCache, + websiteIcon, + } = this.props; + const { showDeleteIcon } = this.state; + + const [, plateIcon] = constructPlate(plate, 0, ''); + + return ( + + + + {plateIcon} + +
+ + {settingsCache.conceptualWalletName} + + + {this.renderAmountDisplay({ + shouldHideBalance, + amount: balance, + })} + +
+
+ + + {websiteIcon ? {url} : } + + + {url} + + + {showDeleteIcon && ( + + + + )} +
+ ); + } +} diff --git a/packages/yoroi-extension/app/components/dapp-connector/Layout/DappConnectorNavbar.js b/packages/yoroi-extension/app/components/dapp-connector/Layout/DappConnectorNavbar.js deleted file mode 100644 index 08facff02d..0000000000 --- a/packages/yoroi-extension/app/components/dapp-connector/Layout/DappConnectorNavbar.js +++ /dev/null @@ -1,21 +0,0 @@ -// @flow -import { Component } from 'react'; -import { observer } from 'mobx-react'; -import styles from './DappConnectorNavbar.scss' -import type { Node } from 'react'; - -type Props = {| - -|} - -@observer -export default class DappConnectorNavbar extends Component { - - render(): Node { - return ( -
-

Dapp connector

-
- ) - } -} \ No newline at end of file diff --git a/packages/yoroi-extension/app/components/dapp-connector/Layout/DappConnectorNavbar.scss b/packages/yoroi-extension/app/components/dapp-connector/Layout/DappConnectorNavbar.scss deleted file mode 100644 index 52496b3453..0000000000 --- a/packages/yoroi-extension/app/components/dapp-connector/Layout/DappConnectorNavbar.scss +++ /dev/null @@ -1,14 +0,0 @@ -.component { - background-color: #FFFFFF; - box-shadow: 0 2px 5px 3px rgba(0, 0, 0, 0.06); - - .header { - color: #38393D; - font-family: Rubik; - font-size: 20px; - font-weight: 500; - letter-spacing: 0; - line-height: 28px; - padding: 32px 40px; - } -} \ No newline at end of file diff --git a/packages/yoroi-extension/app/components/layout/BackgroundColoredLayout.js b/packages/yoroi-extension/app/components/layout/BackgroundColoredLayout.js index 39dd5bc987..5694099ff7 100644 --- a/packages/yoroi-extension/app/components/layout/BackgroundColoredLayout.js +++ b/packages/yoroi-extension/app/components/layout/BackgroundColoredLayout.js @@ -5,16 +5,17 @@ import { Box } from '@mui/system'; type Props = {| +children: Node, + +isRevamp?: boolean, |}; -function BackgroundColoredLayout({ children }: Props): Node { +function BackgroundColoredLayout({ children, isRevamp = false }: Props): Node { return ( {children} diff --git a/packages/yoroi-extension/app/components/layout/TopBarLayout.js b/packages/yoroi-extension/app/components/layout/TopBarLayout.js index 20b4ceb87d..f49ae82223 100644 --- a/packages/yoroi-extension/app/components/layout/TopBarLayout.js +++ b/packages/yoroi-extension/app/components/layout/TopBarLayout.js @@ -4,6 +4,7 @@ import { observer } from 'mobx-react'; import styles from './TopBarLayout.scss'; import { withLayout } from '../../styles/context/layout'; import { Box } from '@mui/system'; +import { THEMES } from '../../styles/utils'; type Props = {| +banner?: Node, @@ -16,10 +17,13 @@ type Props = {| +showInContainer?: boolean, +showAsCard?: boolean, +asModern?: boolean, + +withPadding?: boolean, // default: true +bgcolor?: string, |}; -type InjectedProps = {| isRevampLayout: boolean |}; +type InjectedProps = {| isRevampLayout: boolean, currentTheme: string |}; + +type AllProps = {| ...Props, ...InjectedProps |}; /** Adds a top bar above the wrapped node */ function TopBarLayout({ banner, @@ -31,10 +35,15 @@ function TopBarLayout({ languageSelectionBackground, showInContainer, showAsCard, + currentTheme, isRevampLayout, asModern, + withPadding, bgcolor, -}: Props & InjectedProps) { +}: AllProps) { + const isModern = currentTheme === THEMES.YOROI_MODERN; + const isRevamp = isRevampLayout && asModern !== true && !isModern; + const getContentUnderBanner: void => Node = () => { const topbarComponent = {topbar}; const navbarComponent = {navbar}; @@ -44,19 +53,18 @@ function TopBarLayout({ {navbar != null ? navbarComponent : null} {notification} - {isRevampLayout && asModern !== true ? ( - + {isRevamp ? ( + {children} @@ -90,13 +107,38 @@ function TopBarLayout({ ) : ( - {children} + + {children} + )} ); + if (showInContainer === true) { - return isRevampLayout && asModern !== true ? ( + const boxProperties = { + height: '100%', + minHeight: '200px', + backgroundColor: isRevamp ? 'common.white' : 'var(--yoroi-palette-gray-50)', + maxWidth: '1295px', + paddingLeft: '40px', + paddingRight: '40px', + width: '100%', + marginLeft: 'auto', + marginRight: 'auto', + display: 'flex', + flexDirection: 'column', + maxHeight: 'calc(100vh - 110px)', + overflow: isRevamp ? 'unset' : 'hidden', + pb: isRevamp ? '0px' : '100px', + }; + + return isRevamp ? ( {content} ) : ( - - {content} - + {content} ); } return content; @@ -140,8 +164,8 @@ function TopBarLayout({ return ( {banner} @@ -192,5 +216,6 @@ TopBarLayout.defaultProps = { showInContainer: false, showAsCard: false, asModern: false, + withPadding: true, bgcolor: undefined, }; diff --git a/packages/yoroi-extension/app/components/profile/complexity-level/ComplexityLevelForm.js b/packages/yoroi-extension/app/components/profile/complexity-level/ComplexityLevelForm.js index 37a68879f0..1b888e54a4 100644 --- a/packages/yoroi-extension/app/components/profile/complexity-level/ComplexityLevelForm.js +++ b/packages/yoroi-extension/app/components/profile/complexity-level/ComplexityLevelForm.js @@ -1,7 +1,7 @@ // @flow import { Component } from 'react'; import type { Node, ComponentType } from 'react'; -import { intlShape, defineMessages } from 'react-intl'; +import { intlShape, defineMessages, FormattedHTMLMessage } from 'react-intl'; import type { $npm$ReactIntl$IntlFormat } from 'react-intl'; import styles from './ComplexityLevelForm.scss'; import classnames from 'classnames'; @@ -12,7 +12,8 @@ import { LoadingButton } from '@mui/lab'; import { ComplexityLevels } from '../../../types/complexityLevelType'; import type { ComplexityLevelType } from '../../../types/complexityLevelType'; import { withLayout } from '../../../styles/context/layout'; -import { Box } from '@mui/material'; +import { Box, Typography } from '@mui/material'; +import { settingsMenuMessages } from '../../settings/menu/SettingsMenu'; const messages = defineMessages({ subtitle: { @@ -42,6 +43,10 @@ const messages = defineMessages({ id: 'profile.complexityLevel.selected.label', defaultMessage: '!!!Your current level of Complexity is', }, + selectedLevelLabel: { + id: 'profile.complexityLevel.selected.labelWithLevel', + defaultMessage: '!!!Your current level of Complexity is : {level}', + }, labelChoose: { id: 'global.label.choose', defaultMessage: '!!!Choose', @@ -85,19 +90,125 @@ class ComplexityLevel extends Component { ]; return ( - <> -
-
{intl.formatMessage(messages.subtitle)}
-
- {complexityLevel && ( - <> - {intl.formatMessage(messages.labelSelectedLevel)} :{' '} - - {complexityLevel} + + {isRevampLayout && ( + + {intl.formatMessage(settingsMenuMessages.levelOfComplexity)} + + )} + + + {intl.formatMessage(messages.subtitle)} + + + {complexityLevel && ( + + + + )} + + {isRevampLayout ? ( + + {levels.map(level => { + const isSelected = level.key === complexityLevel; + + return ( + + isSelected + ? theme.palette.gradients.green + : 'linear-gradient( 0deg, var(--yoroi-palette-common-white), var(--yoroi-palette-common-white)), linear-gradient(180deg, #e4e8f7 0%, #c6f7f7 100%)', + backgroundClip: 'content-box, border-box', + backgroundOrigin: 'border-box', + borderRadius: '8px', + alignSelf: 'stretch', + cursor: isSelected ? 'not-allowed' : 'pointer', + position: 'relative', + zIndex: 1, + '&::before': { + position: 'absolute', + content: '""', + top: '0px', + right: '0px', + left: '0px', + bottom: '0px', + background: theme => theme.palette.gradients['blue-green-bg'], + borderRadius: '8px', + zIndex: -1, + opacity: 0, + transition: 'opacity 300ms linear', + }, + '&:hover::before': { + opacity: 1, + }, + }} + onClick={() => this.props.onSubmit(level.key)} + > + + {level.image} + + + {level.name} + + {level.description} + + - - )} -
+ ); + })} + + ) : (
{levels.map(level => (
@@ -121,8 +232,8 @@ class ComplexityLevel extends Component {
))}
-
- + )} +
); } } diff --git a/packages/yoroi-extension/app/components/profile/complexity-level/ComplexityLevelForm.scss b/packages/yoroi-extension/app/components/profile/complexity-level/ComplexityLevelForm.scss index 5fe2926bee..3b563162fe 100644 --- a/packages/yoroi-extension/app/components/profile/complexity-level/ComplexityLevelForm.scss +++ b/packages/yoroi-extension/app/components/profile/complexity-level/ComplexityLevelForm.scss @@ -4,7 +4,8 @@ .component { max-width: 650px; margin: 0 auto; - margin-top: 65px; + margin-top: 24px; + .header { color: var(--yoroi-palette-gray-600); text-align: center; @@ -14,23 +15,14 @@ letter-spacing: 0; line-height: 1.375rem; } + .description { color: var(--yoroi-palette-gray-600); font-size: 1rem; line-height: 1.375rem; text-align: center; } - .selected { - font-size: 1rem; - text-align: center; - margin: 1rem 0; - span { - color: var(--yoroi-comp-button-secondary-text); - font-weight: bold; - text-transform: uppercase; - } - } .cardsWrapper { margin: 30px auto; display: flex; @@ -38,15 +30,17 @@ flex: 1; } } + .card { margin-right: 30px; border-radius: 8px; background-color: var(--yoroi-palette-common-white); - box-shadow: 0 5px 20px 0 rgba(24, 26, 30, 0.08); + border: 1px solid #dce0e9; overflow: hidden; &:last-child { margin-right: 0; } + .cardImage { background-color: var(--yoroi-palette-gray-100); height: 184px; @@ -54,12 +48,15 @@ align-items: center; justify-content: center; } + .simple { background: #f1fdfa; } + .advanced { background: #f3f5fd; } + .cardContent { padding: 24px; color: var(--yoroi-palette-gray-900); @@ -89,3 +86,12 @@ } } } + +:global(.YoroiRevamp) .component { + min-width: 650px; + max-width: unset; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} diff --git a/packages/yoroi-extension/app/components/profile/language-selection/IntroBanner.js b/packages/yoroi-extension/app/components/profile/language-selection/IntroBanner.js index 6a83ddb5d4..8999e207a4 100644 --- a/packages/yoroi-extension/app/components/profile/language-selection/IntroBanner.js +++ b/packages/yoroi-extension/app/components/profile/language-selection/IntroBanner.js @@ -1,43 +1,84 @@ // @flow import { Component } from 'react'; -import type { Node } from 'react'; +import type { Node, ComponentType } from 'react'; import { observer } from 'mobx-react'; import styles from './IntroBanner.scss'; -import { intlShape, } from 'react-intl'; -import { ReactComponent as NightlyLogo } from '../../../assets/images/yoroi-logo-nightly.inline.svg'; -import { ReactComponent as YoroiLogo } from '../../../assets/images/yoroi-logo-blue.inline.svg'; +import { intlShape } from 'react-intl'; +import { ReactComponent as NightlyLogo } from '../../../assets/images/yoroi-logo-nightly.inline.svg'; +import { ReactComponent as YoroiLogo } from '../../../assets/images/yoroi-logo-blue.inline.svg'; import type { $npm$ReactIntl$IntlFormat } from 'react-intl'; +import { withLayout } from '../../../styles/context/layout'; +import type { InjectedLayoutProps } from '../../../styles/context/layout'; +import { ReactComponent as YoroiRevampLogo } from '../../../assets/images/yoroi-logo-revamp-blue.inline.svg'; +// eslint-disable-next-line max-len +import { ReactComponent as YoroiRevampNightlyLogo } from '../../../assets/images/yoroi-logo-revamp-nightly-blue.inline.svg'; +import { Box, Typography } from '@mui/material'; +import globalMessages from '../../../i18n/global-messages'; type Props = {| +isNightly: boolean, |}; @observer -export default class IntroBanner extends Component { - - static contextTypes: {|intl: $npm$ReactIntl$IntlFormat|} = { +class IntroBanner extends Component { + static contextTypes: {| intl: $npm$ReactIntl$IntlFormat |} = { intl: intlShape.isRequired, }; - _getLogo: void => string = () => { - if (this.props.isNightly) { - return NightlyLogo; - } + getLogo: void => string = () => { + if (this.props.isNightly) return NightlyLogo; return YoroiLogo; - } + }; + + getRevampLogo: void => string = () => { + if (this.props.isNightly) return YoroiRevampNightlyLogo; + return YoroiRevampLogo; + }; render(): Node { - const Logo = this._getLogo(); - const title = ''; - return ( + const { renderLayoutComponent } = this.props; + const { intl } = this.context; + const Logo = this.getLogo(); + const RevampLogo = this.getRevampLogo(); + + const classicLayout = (
-
- {title} -
); + + const revampLayout = ( + + + + + + + + {intl.formatMessage(globalMessages.yoroi)} + + + {intl.formatMessage(globalMessages.yoroiIntro)} + + + + ); + + return renderLayoutComponent({ + CLASSIC: classicLayout, + REVAMP: revampLayout, + }); } } + +export default (withLayout(IntroBanner): ComponentType); diff --git a/packages/yoroi-extension/app/components/profile/language-selection/IntroBanner.scss b/packages/yoroi-extension/app/components/profile/language-selection/IntroBanner.scss index e65b64f6bb..b8256f65cf 100644 --- a/packages/yoroi-extension/app/components/profile/language-selection/IntroBanner.scss +++ b/packages/yoroi-extension/app/components/profile/language-selection/IntroBanner.scss @@ -16,10 +16,4 @@ height: 60px; } } - - .mainTitle { - color: var(--yoroi-palette-gray-800); - font-size: 26px; - margin-top: 156px - (64px + 60px); - } } diff --git a/packages/yoroi-extension/app/components/profile/language-selection/LanguageSelectionForm.js b/packages/yoroi-extension/app/components/profile/language-selection/LanguageSelectionForm.js index 8561bc3f68..0c5a856ea0 100644 --- a/packages/yoroi-extension/app/components/profile/language-selection/LanguageSelectionForm.js +++ b/packages/yoroi-extension/app/components/profile/language-selection/LanguageSelectionForm.js @@ -1,11 +1,11 @@ // @flow import { Component } from 'react'; -import type { Node } from 'react'; +import type { Node, ComponentType } from 'react'; import { observer } from 'mobx-react'; import { LoadingButton } from '@mui/lab'; -import { MenuItem } from '@mui/material'; +import { MenuItem, Checkbox, FormControlLabel, Typography, Box, Button } from '@mui/material'; import Select from '../../common/Select'; -import { intlShape } from 'react-intl'; +import { intlShape, FormattedHTMLMessage } from 'react-intl'; import ReactToolboxMobxForm from '../../../utils/ReactToolboxMobxForm'; import LocalizableError from '../../../i18n/LocalizableError'; import type { LanguageType } from '../../../i18n/translations'; @@ -14,37 +14,48 @@ import FlagLabel from '../../widgets/FlagLabel'; import { tier1Languages } from '../../../config/languagesConfig'; import globalMessages, { listOfTranslators } from '../../../i18n/global-messages'; import type { $npm$ReactIntl$IntlFormat } from 'react-intl'; +import ReactMarkdown from 'react-markdown'; +import tosStyles from '../terms-of-use/TermsOfUseText.scss'; +import { withLayout } from '../../../styles/context/layout'; +import type { InjectedLayoutProps } from '../../../styles/context/layout'; +import { ReactComponent as BackIcon } from '../../../assets/images/assets-page/backarrow.inline.svg'; type Props = {| - +onSelectLanguage: {| locale: string |} => void, + +onSelectLanguage: ({| locale: string |}) => void, +languages: Array, - +onSubmit: {| locale: string |} => PossiblyAsync, + +onSubmit: ({| locale: string |}) => PossiblyAsync, +isSubmitting: boolean, +currentLocale: string, +error?: ?LocalizableError, + +localizedTermsOfUse: string, + +localizedPrivacyNotice: string, +|}; + +type State = {| + showing: 'form' | 'tos' | 'privacy', |}; @observer -export default class LanguageSelectionForm extends Component { - static defaultProps: {|error: void|} = { - error: undefined +class LanguageSelectionForm extends Component { + static defaultProps: {| error: void |} = { + error: undefined, }; - static contextTypes: {|intl: $npm$ReactIntl$IntlFormat|} = { + static contextTypes: {| intl: $npm$ReactIntl$IntlFormat |} = { intl: intlShape.isRequired, }; - selectLanguage: string => void = (locale) => { + selectLanguage: string => void = locale => { this.props.onSelectLanguage({ locale }); }; submit: void => void = () => { this.form.submit({ - onSuccess: async (form) => { + onSuccess: async form => { const { languageId } = form.values(); await this.props.onSubmit({ locale: languageId }); }, - onError: () => {} + onError: () => {}, }); }; @@ -53,22 +64,45 @@ export default class LanguageSelectionForm extends Component { languageId: { label: this.context.intl.formatMessage(globalMessages.languageSelectLabel), value: this.props.currentLocale, - } - } + }, + tosAgreement: { + value: false, + }, + }, }); - render(): Node { + state: State = { showing: 'form' }; + + onClickTosLabel: (SyntheticEvent) => void = event => { + const target: Element = (event.target: any); + + if (target.tagName === 'A') { + event.preventDefault(); + } + if (target.id === 'tosLink') { + this.setState({ showing: 'tos' }); + } else if (target.id === 'privacyLink') { + this.setState({ showing: 'privacy' }); + } + }; + + onClickBack: () => void = () => { + this.setState({ showing: 'form' }); + }; + + renderForm(): Node { const { intl } = this.context; const { form } = this; - const { languages, isSubmitting, currentLocale, error } = this.props; + const { languages, isSubmitting, currentLocale, error, renderLayoutComponent } = this.props; const languageId = form.$('languageId'); + const tosAgreement = form.$('tosAgreement'); const languageOptions = languages.map(language => ({ value: language.value, label: intl.formatMessage(language.label), - svg: language.svg + svg: language.svg, })); - return ( + const classicLayout = (
- {error && ( -

- {intl.formatMessage(error, error.values)} -

- )} + {error &&

{intl.formatMessage(error, error.values)}

} + + + + + } + control={ + { + tosAgreement.value = event.target.checked; + }} + /> + } + sx={{ + width: '600px', + marginLeft: '0px', + marginBottom: '20px', + }} + /> {intl.formatMessage(globalMessages.continue)} - {!tier1Languages.includes(currentLocale) && + {!tier1Languages.includes(currentLocale) && (

{intl.formatMessage(globalMessages.languageSelectLabelInfo)}

- {intl.formatMessage(globalMessages.languageSelectInfo)} - {' '} - {listOfTranslators(intl.formatMessage(globalMessages.translationContributors), - intl.formatMessage(globalMessages.translationAcknowledgment))} + {intl.formatMessage(globalMessages.languageSelectInfo)}{' '} + {listOfTranslators( + intl.formatMessage(globalMessages.translationContributors), + intl.formatMessage(globalMessages.translationAcknowledgment) + )}

- } - + )}
); + + const revampLayout = ( + +
+ + {this.context.intl.formatMessage(globalMessages.languageSelectLabelShort)} + + + + {error &&

{intl.formatMessage(error, error.values)}

} + + span': { + color: 'primary.600', + }, + }} + > + + + } + control={ + { + tosAgreement.value = event.target.checked; + }} + /> + } + sx={{ + width: '600px', + marginLeft: '0px', + marginBottom: '24px', + }} + /> + + + + {intl.formatMessage(globalMessages.continue)} + + + + {!tier1Languages.includes(currentLocale) && ( +
+

{intl.formatMessage(globalMessages.languageSelectLabelInfo)}

+

+ {intl.formatMessage(globalMessages.languageSelectInfo)}{' '} + {listOfTranslators( + intl.formatMessage(globalMessages.translationContributors), + intl.formatMessage(globalMessages.translationAcknowledgment) + )} +

+
+ )} +
+
+ ); + + return renderLayoutComponent({ + CLASSIC: classicLayout, + REVAMP: revampLayout, + }); + } + + renderMarkdown(markdown: string): Node { + const { intl } = this.context; + const { renderLayoutComponent } = this.props; + const classicLayout = ( + <> +
+
+
+ +
+
+
+ + + ); + + const revampLayout = ( + <> + +
+
+ +
+
+
+ + + ); + + return renderLayoutComponent({ + CLASSIC: classicLayout, + REVAMP: revampLayout, + }); + } + + render(): Node { + const { showing } = this.state; + if (showing === 'form') { + return this.renderForm(); + } + if (showing === 'tos') { + return this.renderMarkdown(this.props.localizedTermsOfUse); + } + return this.renderMarkdown(this.props.localizedPrivacyNotice); } } + +export default (withLayout(LanguageSelectionForm): ComponentType); diff --git a/packages/yoroi-extension/app/components/profile/language-selection/LanguageSelectionForm.scss b/packages/yoroi-extension/app/components/profile/language-selection/LanguageSelectionForm.scss index 30cc26f073..a3150063d4 100644 --- a/packages/yoroi-extension/app/components/profile/language-selection/LanguageSelectionForm.scss +++ b/packages/yoroi-extension/app/components/profile/language-selection/LanguageSelectionForm.scss @@ -16,6 +16,13 @@ text-align: center; margin-bottom: 1rem; } + + .tosBox { + width: 648px; + } + .tosAgreement>span>span { + color: var(--yoroi-palette-primary-200); + } } .info { @@ -40,3 +47,10 @@ line-height: 1.38; } } + +.back { + position: absolute; + top: 24px; + left: 24px; + cursor: pointer; +} diff --git a/packages/yoroi-extension/app/components/profile/nightly/NightlyForm.js b/packages/yoroi-extension/app/components/profile/nightly/NightlyForm.js index 87072fc132..b101989d86 100644 --- a/packages/yoroi-extension/app/components/profile/nightly/NightlyForm.js +++ b/packages/yoroi-extension/app/components/profile/nightly/NightlyForm.js @@ -2,21 +2,26 @@ import { Component } from 'react'; import type { ComponentType, Node } from 'react'; import { observer } from 'mobx-react'; -import { Button } from '@mui/material'; +import { Box, Button, Typography } from '@mui/material'; import CheckboxLabel from '../../common/CheckboxLabel'; import { defineMessages, intlShape, FormattedHTMLMessage } from 'react-intl'; import styles from './NightlyForm.scss'; import globalMessages from '../../../i18n/global-messages'; import { ReactComponent as NightlyIcon } from '../../../assets/images/yoroi-nightly-icon.inline.svg'; +import { ReactComponent as NightlyIconRevamp } from '../../../assets/images/yoroi-nightly-icon-dark.inline.svg'; import type { $npm$ReactIntl$IntlFormat } from 'react-intl'; import { withLayout } from '../../../styles/context/layout'; import type { InjectedLayoutProps } from '../../../styles/context/layout'; const messages = defineMessages({ + nightlySlogan: { + id: 'profile.nighly.slogan', + defaultMessage: '!!!Testnet wallet for Cardano assets', + }, header: { id: 'profile.nightly.header', defaultMessage: - '!!!Yoroi Nightly automatically updates nightly with the latest in-progress features. Although we will never intentionally push bugs or broken code, features may still be in-progress or contain errors.', + '!!!Yoroi Nightly automatically updates nightly with the latest in-progress features. Although we will never intentionally push bugs or broken code, features may still be in-progress or contain errors.', }, warningHeader: { id: 'profile.nightly.warningHeader', @@ -45,7 +50,7 @@ const messages = defineMessages({ }, acknowledgedRisks: { id: 'profile.nightly.acknowledgedRisks', - defaultMessage: '!!!I Understand the risk', + defaultMessage: '!!!I understand the risk', }, }); @@ -73,9 +78,9 @@ class NightlyForm extends Component { render(): Node { const { intl } = this.context; - const { onSubmit, isRevampLayout } = this.props; + const { onSubmit, isRevampLayout, renderLayoutComponent } = this.props; - return ( + const classicLayout = (
@@ -115,6 +120,117 @@ class NightlyForm extends Component {
); + + const revampLayout = ( + + + + + + {intl.formatMessage(globalMessages.yoroiNightly)} + + + {intl.formatMessage(messages.nightlySlogan)} + + + + + + + + + + {intl.formatMessage(messages.warningHeader)} + + + + {intl.formatMessage(messages.warning1)} + + + {intl.formatMessage(messages.warning2)} + + + + + + + {intl.formatMessage(messages.recommendationHeader)} + + + + {intl.formatMessage(messages.recommendation1)} + + + {intl.formatMessage(messages.recommendation2)} + + + + + + + + + + + + + + + ); + + return renderLayoutComponent({ + CLASSIC: classicLayout, + REVAMP: revampLayout, + }); } } diff --git a/packages/yoroi-extension/app/components/profile/terms-of-use/OptForAnalyticsForm.js b/packages/yoroi-extension/app/components/profile/terms-of-use/OptForAnalyticsForm.js new file mode 100644 index 0000000000..a0bd65122a --- /dev/null +++ b/packages/yoroi-extension/app/components/profile/terms-of-use/OptForAnalyticsForm.js @@ -0,0 +1,192 @@ +// @flow +import { Component } from 'react'; +import type { Node } from 'react'; +import { observer } from 'mobx-react'; +import { defineMessages, intlShape, FormattedHTMLMessage } from 'react-intl'; +import globalMessages from '../../../i18n/global-messages'; +import type { $npm$ReactIntl$IntlFormat } from 'react-intl'; +import styles from './OptForAnalyticsForm.scss'; +import { LoadingButton } from '@mui/lab'; +import FormControlLabel from '@mui/material/FormControlLabel'; +import { ReactComponent as AnalyticsIllustration } from '../../../assets/images/analytics-illustration.inline.svg'; +import { ReactComponent as YesIcon } from '../../../assets/images/yes.inline.svg'; +import { ReactComponent as NoIcon } from '../../../assets/images/no.inline.svg'; +import { Box, Typography } from '@mui/material'; +import { RevampSwitch } from '../../widgets/Switch'; + +const messages = defineMessages({ + title: { + id: 'profile.analytics.title', + defaultMessage: '!!!Join the journey to improve Yoroi', + }, + share: { + id: 'profile.analytics.share', + defaultMessage: + '!!!Share user insights to help us fine tune Yoroi to better serve user preferences and needs.', + }, + line1: { + id: 'profile.analytics.line1', + defaultMessage: '!!!Anonymous analytics data', + }, + line2: { + id: 'profile.analytics.line2', + defaultMessage: '!!!You can always opt-out via Settings', + }, + line3: { + id: 'profile.analytics.line3', + defaultMessage: '!!!We can not access private keys', + }, + line4: { + id: 'profile.analytics.line4', + defaultMessage: '!!!We are not recording IP addresses', + }, + line5: { + id: 'profile.analytics.line5', + defaultMessage: '!!!We do not sell data', + }, + learnMore: { + id: 'profile.analytics.learnMore', + defaultMessage: '!!!Learn more about user insights', + }, + accept: { + id: 'profile.analytics.accept', + defaultMessage: '!!!Accept', + }, + allow: { + id: 'profile.analytics.allow', + defaultMessage: '!!!Allow Yoroi analytics', + }, +}); + +type Props = {| + onOpt: boolean => void, + variant: 'startup' | 'settings', + isOptedIn: boolean, +|}; + +type State = {| + isSubmitting: boolean, +|}; + +@observer +export default class OptForAnalyticsForm extends Component { + static contextTypes: {| intl: $npm$ReactIntl$IntlFormat |} = { + intl: intlShape.isRequired, + }; + + state: State = { isSubmitting: false }; + + onOpt: boolean => void = isOptIn => { + this.setState({ isSubmitting: true }); + this.props.onOpt(isOptIn); + }; + + render(): Node { + const { intl } = this.context; + const { variant, isOptedIn } = this.props; + + const isStartupScreen = variant === 'startup'; + const isSettingsScreen = variant === 'settings'; + + const analyticsDetails = [ + [YesIcon, messages.line1], + [YesIcon, messages.line2], + [NoIcon, messages.line3], + [NoIcon, messages.line4], + [NoIcon, messages.line5], + ]; + + return ( + +
+ {isSettingsScreen && ( +
{intl.formatMessage(messages.title)}
+ )} + + {isSettingsScreen ? ( + {intl.formatMessage(messages.share)} + ) : ( +
+ +
+ )} + + {isStartupScreen && ( + + {intl.formatMessage(messages.title)} + + )} + + + {analyticsDetails.map(([Icon, msg]) => ( + + + + + + + ))} + + + + + {intl.formatMessage(messages.learnMore)} + + + + {isSettingsScreen ? ( + + this.onOpt(event.target.checked)} + /> + + } + labelPlacement="start" + sx={{ marginLeft: '0px', marginTop: '40px' }} + /> + ) : ( + <> +
+ +
+
+ this.onOpt(true)} + loading={this.state.isSubmitting} + > + {intl.formatMessage(messages.accept)} + +
+ + )} +
+
+ ); + } +} diff --git a/packages/yoroi-extension/app/components/profile/terms-of-use/OptForAnalyticsForm.scss b/packages/yoroi-extension/app/components/profile/terms-of-use/OptForAnalyticsForm.scss new file mode 100644 index 0000000000..b4a15d44a4 --- /dev/null +++ b/packages/yoroi-extension/app/components/profile/terms-of-use/OptForAnalyticsForm.scss @@ -0,0 +1,52 @@ +.component { + .centeredBox { + margin: 0 auto; + width: max-content; + } + + .title { + font-family: Rubik; + font-size: 18px; + font-weight: 500; + line-height: 26px; + letter-spacing: 0px; + } + + .learnMore { + color: #4b6dde; + text-decoration: none; + } + + .skip { + text-align: center; + cursor: pointer; + margin-top: 8px; + margin-bottom: 24px; + font-weight: 500; + padding: 9px 20px; + + & button { + text-transform: uppercase; + } + } + + .accept { + width: min-content; + margin: 0 auto; + button { + min-width: 133px; + } + } + + .share { + margin-top: 16px; + margin-bottom: 16px; + } + + .illustration { + display: flex; + align-items: center; + justify-content: center; + margin-top: 16px; + } +} diff --git a/packages/yoroi-extension/app/components/profile/terms-of-use/PrivacyPolicy.js b/packages/yoroi-extension/app/components/profile/terms-of-use/PrivacyPolicy.js deleted file mode 100644 index 208348c074..0000000000 --- a/packages/yoroi-extension/app/components/profile/terms-of-use/PrivacyPolicy.js +++ /dev/null @@ -1,65 +0,0 @@ -// @flow -import { Component } from 'react'; -import type { Node } from 'react'; -import { defineMessages, intlShape, FormattedHTMLMessage } from 'react-intl'; -import { observer } from 'mobx-react'; -import styles from './PrivacyPolicy.scss'; -import type { $npm$ReactIntl$IntlFormat } from 'react-intl'; - -const messages = defineMessages({ - header: { - id: 'profile.privacypolicy.header', - defaultMessage: '!!!Yoroi will...', - }, - neverTrack: { - id: 'profile.privacypolicy.neverTrack', - defaultMessage: '!!!Never track your behavior.', - }, - neverIP: { - id: 'profile.privacypolicy.neverProfile', - defaultMessage: '!!!Never create profiles with your information.', - }, - neverSell: { - id: 'profile.privacypolicy.neverSell', - defaultMessage: '!!!Never sell your data.', - }, - neverAnalytics: { - id: 'profile.privacypolicy.neverAnalytics', - defaultMessage: '!!!Never run any analytics software or 3rd party trackers.', - }, - serverLogs: { - id: 'profile.privacypolicy.serverLogs', - defaultMessage: '!!!Any server log is kept for at most 2 weeks purely for server troubleshooting purposes.', - }, -}); - -type Props = {| -|}; - -@observer -export default class PrivacyPolicy extends Component { - - static contextTypes: {|intl: $npm$ReactIntl$IntlFormat|} = { - intl: intlShape.isRequired, - }; - - render(): Node { - const { intl } = this.context; - - return ( -
-
- {intl.formatMessage(messages.header)} -
    -
  • -
  • -
  • -
  • -
- {intl.formatMessage(messages.serverLogs)} -
-
- ); - } - -} diff --git a/packages/yoroi-extension/app/components/profile/terms-of-use/PrivacyPolicy.scss b/packages/yoroi-extension/app/components/profile/terms-of-use/PrivacyPolicy.scss deleted file mode 100644 index fd1fed039e..0000000000 --- a/packages/yoroi-extension/app/components/profile/terms-of-use/PrivacyPolicy.scss +++ /dev/null @@ -1,16 +0,0 @@ -@import '../../../themes/mixins/unordered-donot-list'; - -.component { - .text { - color: var(--yoroi-support-settings-text); - font-weight: 400; - font-size: 14px; - line-height: 24px; - } - - ul { - margin-top: 6px; - margin-bottom: 6px; - @include unordered-donot-list; - } -} diff --git a/packages/yoroi-extension/app/components/profile/terms-of-use/TermsOfUseForm.js b/packages/yoroi-extension/app/components/profile/terms-of-use/TermsOfUseForm.js index 2a79733d81..e8d50bf08e 100644 --- a/packages/yoroi-extension/app/components/profile/terms-of-use/TermsOfUseForm.js +++ b/packages/yoroi-extension/app/components/profile/terms-of-use/TermsOfUseForm.js @@ -1,22 +1,29 @@ // @flow import { Component } from 'react'; -import type { Node } from 'react'; +import type { Node, ComponentType } from 'react'; import { observer } from 'mobx-react'; import { LoadingButton } from '@mui/lab'; -import { defineMessages, intlShape } from 'react-intl'; -import CheckboxLabel from '../../common/CheckboxLabel'; +import { Box, Button, Checkbox, FormControlLabel, Typography } from '@mui/material'; +import { defineMessages, intlShape, FormattedHTMLMessage } from 'react-intl'; import LocalizableError from '../../../i18n/LocalizableError'; -import TermsOfUseText from './TermsOfUseText'; -import PrivacyPolicy from './PrivacyPolicy'; import styles from './TermsOfUseForm.scss'; -import CenteredBarDecoration from '../../widgets/CenteredBarDecoration'; import globalMessages from '../../../i18n/global-messages'; import type { $npm$ReactIntl$IntlFormat } from 'react-intl'; +import ReactMarkdown from 'react-markdown'; +import tosStyles from './TermsOfUseText.scss'; +import { withLayout } from '../../../styles/context/layout'; +import type { InjectedLayoutProps } from '../../../styles/context/layout'; +import { ReactComponent as BackIcon } from '../../../assets/images/assets-page/backarrow.inline.svg'; const messages = defineMessages({ - checkboxLabel: { - id: 'profile.termsOfUse.checkboxLabel', - defaultMessage: '!!!I agree with the terms of use', + updateTitle: { + id: 'profile.termsOfUse.updateTitle', + defaultMessage: '!!!Terms of Service Agreement and Privacy Notice update', + }, + updateText: { + id: 'profile.termsOfUse.updateText', + defaultMessage: + '!!!We have updated our Terms of Service Agreement and Privacy Policy to enhance your experience. Please review and accept them to keep enjoying Yoroi.', }, }); @@ -25,14 +32,16 @@ type Props = {| +onSubmit: void => PossiblyAsync, +isSubmitting: boolean, +error?: ?LocalizableError, + +localizedPrivacyNotice: string, |}; type State = {| areTermsOfUseAccepted: boolean, + showing: 'form' | 'tos' | 'privacy', |}; @observer -export default class TermsOfUseForm extends Component { +class TermsOfUseForm extends Component { static defaultProps: {| error: void |} = { error: undefined, }; @@ -43,40 +52,66 @@ export default class TermsOfUseForm extends Component { state: State = { areTermsOfUseAccepted: false, + showing: 'form', }; toggleAcceptance() { this.setState(prevState => ({ areTermsOfUseAccepted: !prevState.areTermsOfUseAccepted })); } - render(): Node { + onClickTosLabel: (SyntheticEvent) => void = event => { + const target: Element = (event.target: any); + + if (target.tagName === 'A') { + event.preventDefault(); + } + if (target.id === 'tosLink') { + this.setState({ showing: 'tos' }); + } else if (target.id === 'privacyLink') { + this.setState({ showing: 'privacy' }); + } + }; + + onClickBack: () => void = () => { + this.setState({ showing: 'form' }); + }; + + renderForm(): Node { const { intl } = this.context; - const { isSubmitting, error, localizedTermsOfUse } = this.props; + const { isSubmitting, error, renderLayoutComponent } = this.props; const { areTermsOfUseAccepted } = this.state; - const checkboxLabel = 'checkboxLabel'; - return ( + const classicLayout = (
- -
- -
- +
{intl.formatMessage(messages.updateTitle)}
+
{intl.formatMessage(messages.updateText)}
-
- + + + + } + control={ + + } + sx={{ margin: '0px' }} /> +
+
{intl.formatMessage(globalMessages.continue)} @@ -86,5 +121,145 @@ export default class TermsOfUseForm extends Component {
); + + const revampLayout = ( + + + + {intl.formatMessage(messages.updateTitle)} + + + {intl.formatMessage(messages.updateText)} + + +
+ span': { + color: 'primary.600', + }, + }} + > + + + } + control={ + + } + sx={{ margin: '0px' }} + /> +
+ + + + {intl.formatMessage(globalMessages.continue)} + + + + {error &&

{intl.formatMessage(error, error.values)}

} +
+
+ ); + + return renderLayoutComponent({ + CLASSIC: classicLayout, + REVAMP: revampLayout, + }); + } + + renderMarkdown(markdown: string): Node { + const { intl } = this.context; + const { renderLayoutComponent } = this.props; + + const classicLayout = ( + <> +
+
+
+ +
+
+
+
+ +
+ + ); + const revampLayout = ( + <> + +
+
+ +
+
+
+ + + ); + return renderLayoutComponent({ + CLASSIC: classicLayout, + REVAMP: revampLayout, + }); + } + + render(): Node { + const { showing } = this.state; + if (showing === 'form') { + return this.renderForm(); + } + if (showing === 'tos') { + return this.renderMarkdown(this.props.localizedTermsOfUse); + } + return this.renderMarkdown(this.props.localizedPrivacyNotice); } } + +export default (withLayout(TermsOfUseForm): ComponentType); diff --git a/packages/yoroi-extension/app/components/profile/terms-of-use/TermsOfUseForm.scss b/packages/yoroi-extension/app/components/profile/terms-of-use/TermsOfUseForm.scss index a95481cabe..220d1e89d4 100644 --- a/packages/yoroi-extension/app/components/profile/terms-of-use/TermsOfUseForm.scss +++ b/packages/yoroi-extension/app/components/profile/terms-of-use/TermsOfUseForm.scss @@ -18,7 +18,7 @@ .centeredBox { margin: 0 auto; - width: 800px; + width: 536px; } .error { @@ -27,11 +27,44 @@ margin-bottom: 1rem; } - .checkbox { - display: flex; - align-items: center; - justify-content: space-between; - padding-right: 15px; - padding-top: 40px; + .title { + font-family: Rubik; + font-size: 18px; + font-weight: 500; + line-height: 26px; + letter-spacing: 0px; + text-align: center; + } + + .text { + font-family: Rubik; + font-size: 16px; + font-weight: 400; + line-height: 24px; + letter-spacing: 0px; + text-align: center; + width: 424px; + margin: 40px auto; + } + + .agreement { + margin: 10px auto; + width: max-content; } + + .submit { + margin: auto; + width: max-content; + } + + .tosAgreement>span>span { + color: var(--yoroi-palette-primary-200); + } +} + +.back { + position: absolute; + top: 24px; + left: 24px; + cursor: pointer; } diff --git a/packages/yoroi-extension/app/components/profile/terms-of-use/TermsOfUseText.scss b/packages/yoroi-extension/app/components/profile/terms-of-use/TermsOfUseText.scss index 20b4c4ee10..6a59abb3f7 100644 --- a/packages/yoroi-extension/app/components/profile/terms-of-use/TermsOfUseText.scss +++ b/packages/yoroi-extension/app/components/profile/terms-of-use/TermsOfUseText.scss @@ -7,7 +7,8 @@ overflow: auto; } - h1, h2 { + h1, + h2 { font-weight: 500; font-size: 17px; margin-bottom: 11px; @@ -27,13 +28,13 @@ margin-left: 20px; } - p, li { + p, + li { font-weight: 400; font-size: 14px; letter-spacing: 0.5px; line-height: 1.38; margin-bottom: 11px; - } } @@ -41,24 +42,57 @@ color: var(--yoroi-terms-of-use-text-color); } -:global(.YoroiModern), :global(.YoroiRevamp) { +:global(.YoroiModern) { .terms { - h1, h2 { + h1, + h2 { font-size: 16px; } - + h1 { margin-top: 26px; } - + h2 { margin-top: 46px; } - - p, li { + + p, + li { color: var(--yoroi-terms-of-use-text-color); font-size: 13px; line-height: 1.54; } } } + +:global(.YoroiRevamp) { + .terms { + &.fixedHeight h1 { + margin-top: 26px; + } + + h1 { + text-align: center; + font-size: 18px; + font-weight: 500; + margin-top: 0px; + margin-bottom: 16px; + color: var(--yoroi-palette-common-black); + } + + h2 { + font-size: 16px; + font-weight: 500; + margin-top: 46px; + color: var(--yoroi-terms-of-use-text-color); + } + + p, + li { + color: var(--yoroi-terms-of-use-text-color); + font-size: 16px; + line-height: 24px; + } + } +} diff --git a/packages/yoroi-extension/app/components/settings/categories/SupportSettings.js b/packages/yoroi-extension/app/components/settings/categories/SupportSettings.js index 8445754f04..79247be96f 100644 --- a/packages/yoroi-extension/app/components/settings/categories/SupportSettings.js +++ b/packages/yoroi-extension/app/components/settings/categories/SupportSettings.js @@ -3,9 +3,8 @@ import { Component } from 'react'; import type { Node, ComponentType } from 'react'; import { observer } from 'mobx-react'; import { defineMessages, intlShape, FormattedMessage } from 'react-intl'; -import { Button } from '@mui/material'; +import { Box, Button, Typography } from '@mui/material'; import globalMessages from '../../../i18n/global-messages'; -import styles from './SupportSettings.scss'; import type { $npm$ReactIntl$IntlFormat } from 'react-intl'; import { withLayout } from '../../../styles/context/layout'; @@ -61,7 +60,6 @@ class SupportSettings extends Component { const faqLink = ( onExternalLinkClick(event)} > @@ -71,7 +69,6 @@ class SupportSettings extends Component { const supportRequestLink = ( onExternalLinkClick(event)} > @@ -80,45 +77,79 @@ class SupportSettings extends Component { ); const downloadLogsLink = ( - null} - className={styles.link} - onClick={onDownloadLogs} - > + null} onClick={onDownloadLogs}> {intl.formatMessage(globalMessages.downloadLogsLink)} ); - return ( -
-

{intl.formatMessage(messages.faqTitle)}

- -

- -

- -

{intl.formatMessage(messages.reportProblemTitle)}

- -

+ const sections = [ + { + title: messages.faqTitle, + text: , + }, + { + title: messages.reportProblemTitle, + text: ( -

- -

{intl.formatMessage(messages.logsTitle)}

- -

- -

+ ), + }, + { + title: messages.logsTitle, + text: , + }, + ]; + return ( + + {isRevampLayout && ( + + {intl.formatMessage(globalMessages.support)} + + )} + + + {sections.map(({ title, text }) => { + return ( + + + {intl.formatMessage(title)} + + + {text} + + + ); + })} + -
+ ); } } diff --git a/packages/yoroi-extension/app/components/settings/categories/SupportSettings.scss b/packages/yoroi-extension/app/components/settings/categories/SupportSettings.scss deleted file mode 100644 index 7dbbbafa46..0000000000 --- a/packages/yoroi-extension/app/components/settings/categories/SupportSettings.scss +++ /dev/null @@ -1,55 +0,0 @@ -@import '../../../themes/mixins/error-message'; -@import '../../../themes/mixins/underline'; - -.component { - padding-bottom: 10px; - - h1 { - color: var(--yoroi-support-settings-text); - font-weight: 500; - line-height: 1.38; - margin-bottom: 10px; - } - - h1:not(:first-child) { - padding-top: 10px; - } - - a, - p { - color: var(--yoroi-support-settings-text); - font-weight: 400; - font-size: 14px; - line-height: 19px; - } - - a { - color: var(--yoroi-support-settings-text); - } - - p { - margin-bottom: 10px; - } - - .link { - @include underline(var(--yoroi-palette-gray-800)); - } - - .link:focus { - outline: none; - } -} - -:global(.YoroiClassic) .component { - h1 { - font-size: 16px; - } -} - -:global(.YoroiModern) , :global(.YoroiRevamp) { - .component { - h1 { - font-size: 18px; - } - } -} diff --git a/packages/yoroi-extension/app/components/settings/categories/TermsOfUseSettings.js b/packages/yoroi-extension/app/components/settings/categories/TermsOfUseSettings.js index 12238416d5..711f74a36c 100644 --- a/packages/yoroi-extension/app/components/settings/categories/TermsOfUseSettings.js +++ b/packages/yoroi-extension/app/components/settings/categories/TermsOfUseSettings.js @@ -1,23 +1,33 @@ // @flow import { Component } from 'react'; -import type { Node } from 'react'; +import type { Node, ComponentType } from 'react'; import { observer } from 'mobx-react'; import TermsOfUseText from '../../profile/terms-of-use/TermsOfUseText'; -import styles from './TermsOfUseSettings.scss'; +import { Box } from '@mui/material'; +import { withLayout } from '../../../styles/context/layout'; +import type { InjectedLayoutProps } from '../../../styles/context/layout'; type Props = {| +localizedTermsOfUse: string, |}; @observer -export default class TermsOfUseSettings extends Component { +class TermsOfUseSettings extends Component { render(): Node { - const { localizedTermsOfUse } = this.props; + const { localizedTermsOfUse, isRevampLayout } = this.props; return ( -
+ -
+ ); } - } + +export default (withLayout(TermsOfUseSettings): ComponentType); diff --git a/packages/yoroi-extension/app/components/settings/categories/TermsOfUseSettings.scss b/packages/yoroi-extension/app/components/settings/categories/TermsOfUseSettings.scss deleted file mode 100644 index 381f62ca58..0000000000 --- a/packages/yoroi-extension/app/components/settings/categories/TermsOfUseSettings.scss +++ /dev/null @@ -1,5 +0,0 @@ -.component { - h1 { - margin-top: 0; - } -} diff --git a/packages/yoroi-extension/app/components/settings/categories/general-setting/AboutYoroiSettingsBlock.js b/packages/yoroi-extension/app/components/settings/categories/general-setting/AboutYoroiSettingsBlock.js index 3b80940629..4532edb93f 100644 --- a/packages/yoroi-extension/app/components/settings/categories/general-setting/AboutYoroiSettingsBlock.js +++ b/packages/yoroi-extension/app/components/settings/categories/general-setting/AboutYoroiSettingsBlock.js @@ -1,18 +1,18 @@ // @flow import { Component } from 'react'; -import type { Node } from 'react'; +import type { Node, ComponentType } from 'react'; import { defineMessages, intlShape } from 'react-intl'; import styles from './AboutYoroiSettingsBlock.scss'; import { observer } from 'mobx-react'; import GridFlexContainer from '../../../layout/GridFlexContainer'; -import { ReactComponent as githubSvg } from '../../../../assets/images/social/github.inline.svg'; -import { ReactComponent as youtubeSvg } from '../../../../assets/images/social/youtube.inline.svg'; -import { ReactComponent as telegramSvg } from '../../../../assets/images/social/telegram.inline.svg'; -import { ReactComponent as twitterSvg } from '../../../../assets/images/social/twitter.inline.svg'; -import { ReactComponent as yoroiSvg } from '../../../../assets/images/yoroi-logo-shape-white.inline.svg'; -import { ReactComponent as facebookSvg } from '../../../../assets/images/social/facebook.inline.svg'; -import { ReactComponent as mediumSvg } from '../../../../assets/images/social/medium.inline.svg'; +import { ReactComponent as githubSvg } from '../../../../assets/images/social/github.inline.svg'; +import { ReactComponent as youtubeSvg } from '../../../../assets/images/social/youtube.inline.svg'; +import { ReactComponent as telegramSvg } from '../../../../assets/images/social/telegram.inline.svg'; +import { ReactComponent as twitterSvg } from '../../../../assets/images/social/twitter.inline.svg'; +import { ReactComponent as yoroiSvg } from '../../../../assets/images/yoroi-logo-shape-white.inline.svg'; +import { ReactComponent as facebookSvg } from '../../../../assets/images/social/facebook.inline.svg'; +import { ReactComponent as mediumSvg } from '../../../../assets/images/social/medium.inline.svg'; import environment from '../../../../environment'; import LinkButton from '../../../widgets/LinkButton'; @@ -22,6 +22,9 @@ import ExplorableHash from '../../../widgets/hashWrappers/ExplorableHash'; import { handleExternalLinkClick } from '../../../../utils/routing'; import { PublicDeriver } from '../../../../api/ada/lib/storage/models/PublicDeriver'; import type { $npm$ReactIntl$IntlFormat } from 'react-intl'; +import { Box, Link, Typography } from '@mui/material'; +import { withLayout } from '../../../../styles/context/layout'; +import type { InjectedLayoutProps } from '../../../../styles/context/layout'; const messages = defineMessages({ aboutYoroiLabel: { @@ -66,11 +69,11 @@ const messages = defineMessages({ }, mainnet: { id: 'settings.general.aboutYoroi.network.mainnet', - defaultMessage: '!!!mainnet', + defaultMessage: '!!!Mainnet Network', }, testnet: { id: 'settings.general.aboutYoroi.network.testnet', - defaultMessage: '!!!testnet', + defaultMessage: '!!!Testnet Network', }, commitLabel: { id: 'settings.general.aboutYoroi.commitLabel', @@ -82,68 +85,93 @@ const messages = defineMessages({ }, }); -const socialMediaLinks = [{ - url: 'https://twitter.com/YoroiWallet', - svg: twitterSvg, - message: messages.aboutYoroiTwitter -}, { - svgClass: styles.yoroiLogo, - url: 'https://yoroi-wallet.com', - svg: yoroiSvg, - message: messages.aboutYoroiWebsite -}, { - url: 'https://www.facebook.com/Yoroi-wallet-399386000586822/', - svg: facebookSvg, - message: messages.aboutYoroiFacebook -}, { - url: 'https://www.youtube.com/channel/UCgFQ0hHuPO1QDcyP6t9KZTQ', - svg: youtubeSvg, - message: messages.aboutYoroiYoutube -}, { - url: 'https://t.me/emurgo', - svg: telegramSvg, - message: messages.aboutEmurgoTelegram -}, { - url: 'https://medium.com/@emurgo_io', - svg: mediumSvg, - message: messages.aboutYoroiMedium -}, { - url: 'https://github.com/Emurgo/yoroi-frontend', - svg: githubSvg, - message: messages.aboutYoroiGithub -}]; +const socialMediaLinks = [ + { + url: 'https://twitter.com/YoroiWallet', + svg: twitterSvg, + message: messages.aboutYoroiTwitter, + }, + { + svgClass: styles.yoroiLogo, + url: 'https://yoroi-wallet.com', + svg: yoroiSvg, + message: messages.aboutYoroiWebsite, + }, + { + url: 'https://www.facebook.com/Yoroi-wallet-399386000586822/', + svg: facebookSvg, + message: messages.aboutYoroiFacebook, + }, + { + url: 'https://www.youtube.com/channel/UCgFQ0hHuPO1QDcyP6t9KZTQ', + svg: youtubeSvg, + message: messages.aboutYoroiYoutube, + }, + { + url: 'https://t.me/emurgo', + svg: telegramSvg, + message: messages.aboutEmurgoTelegram, + }, + { + url: 'https://medium.com/@emurgo_io', + svg: mediumSvg, + message: messages.aboutYoroiMedium, + }, + { + url: 'https://github.com/Emurgo/yoroi-frontend', + svg: githubSvg, + message: messages.aboutYoroiGithub, + }, +]; const baseGithubUrl = 'https://github.com/Emurgo/yoroi-frontend/'; type Props = {| - wallet: null | PublicDeriver<> -|} + wallet: null | PublicDeriver<>, +|}; @observer -export default class AboutYoroiSettingsBlock extends Component { - static contextTypes: {|intl: $npm$ReactIntl$IntlFormat|} = { +class AboutYoroiSettingsBlock extends Component { + static contextTypes: {| intl: $npm$ReactIntl$IntlFormat |} = { intl: intlShape.isRequired, }; render(): Node { const { intl } = this.context; - const { wallet } = this.props; + const { wallet, isRevampLayout, renderLayoutComponent } = this.props; let network; if (wallet) { - const result = isTestnet(wallet.getParent().getNetworkInfo()) - network = result === true ? 'testnet' : 'mainnet' + const result = isTestnet(wallet.getParent().getNetworkInfo()); + network = result === true ? 'testnet' : 'mainnet'; } - return ( -
-

{intl.formatMessage(messages.aboutYoroiLabel)}

+ const classicLayout = ( + + + {intl.formatMessage(messages.aboutYoroiLabel)} + {network && ( -

- {intl.formatMessage(messages.networkLabel)}  - {intl.formatMessage(messages[network])} -

)} +

+ {intl.formatMessage(messages.networkLabel)}  + {intl.formatMessage(messages[network])} +

+ )}
{intl.formatMessage(messages.versionLabel)}  { placementTooltip="bottom" onExternalLinkClick={handleExternalLinkClick} > - - {environment.getVersion()} - + {environment.getVersion()}
@@ -167,12 +193,10 @@ export default class AboutYoroiSettingsBlock extends Component { placementTooltip="bottom-start" onExternalLinkClick={handleExternalLinkClick} > - - {environment.commit} - + {environment.commit}
- {!environment.isProduction() && + {!environment.isProduction() && (
{intl.formatMessage(messages.branchLabel)}  { placementTooltip="bottom-start" onExternalLinkClick={handleExternalLinkClick} > - - {environment.branch} - + {environment.branch}
- } + )}
{socialMediaLinks.map(link => ( @@ -200,9 +222,103 @@ export default class AboutYoroiSettingsBlock extends Component { ))}
-
+ + ); + + const revampLayout = ( + + + {intl.formatMessage(messages.aboutYoroiLabel)} + + + {network && ( + + )} + + + + + + {!environment.isProduction() && ( + + )} + +
+ + {socialMediaLinks.map(link => ( + + ))} + +
+
); - } + return renderLayoutComponent({ + CLASSIC: classicLayout, + REVAMP: revampLayout, + }); + } +} +function LabelWithValue({ + label, + value, + url, +}: {| + label: string, + value: string, + url?: string, +|}): Node { + return ( + + + {label} + + + {value} + + + ); } + +LabelWithValue.defaultProps = { + url: undefined, +}; + +export default (withLayout(AboutYoroiSettingsBlock): ComponentType); diff --git a/packages/yoroi-extension/app/components/settings/categories/general-setting/AboutYoroiSettingsBlock.scss b/packages/yoroi-extension/app/components/settings/categories/general-setting/AboutYoroiSettingsBlock.scss index 13b3ed28ac..4a379506a4 100644 --- a/packages/yoroi-extension/app/components/settings/categories/general-setting/AboutYoroiSettingsBlock.scss +++ b/packages/yoroi-extension/app/components/settings/categories/general-setting/AboutYoroiSettingsBlock.scss @@ -2,13 +2,6 @@ font-weight: 400; color: var(--yoroi-support-settings-text); - h2 { - color: var(--yoroi-support-settings-text); - font-weight: 500; - font-size: 18px; - line-height: 22px; - margin-bottom: 12px; - } .aboutLine { font-size: 14px; line-height: 22px; @@ -29,9 +22,7 @@ } } -.component, .aboutSocial { - border-top: 1px solid var(--yoroi-palette-gray-200); - padding-top: 30px; - margin-top: 32px; + margin-top: 40px; + margin-left: -13px; } diff --git a/packages/yoroi-extension/app/components/settings/categories/general-setting/ExplorerSettings.js b/packages/yoroi-extension/app/components/settings/categories/general-setting/ExplorerSettings.js index c56574b25d..da6de42cbf 100644 --- a/packages/yoroi-extension/app/components/settings/categories/general-setting/ExplorerSettings.js +++ b/packages/yoroi-extension/app/components/settings/categories/general-setting/ExplorerSettings.js @@ -1,11 +1,11 @@ // @flow import { Component } from 'react'; -import type { Node } from 'react'; +import type { Node, ComponentType } from 'react'; import { observer } from 'mobx-react'; import classNames from 'classnames'; import Select from '../../../common/Select'; -import { MenuItem } from '@mui/material'; -import { intlShape } from 'react-intl'; +import { Box, MenuItem, Typography } from '@mui/material'; +import { defineMessages, intlShape } from 'react-intl'; import ReactToolboxMobxForm from '../../../../utils/ReactToolboxMobxForm'; import LocalizableError from '../../../../i18n/LocalizableError'; import styles from './ExplorerSettings.scss'; @@ -13,28 +13,37 @@ import globalMessages from '../../../../i18n/global-messages'; import type { $npm$ReactIntl$IntlFormat } from 'react-intl'; import type { ExplorerRow } from '../../../../api/ada/lib/storage/database/explorers/tables'; import { SelectedExplorer } from '../../../../domain/SelectedExplorer'; +import { withLayout } from '../../../../styles/context/layout'; +import type { InjectedLayoutProps } from '../../../../styles/context/layout'; type Props = {| +explorers: $ReadOnlyArray<$ReadOnly>, +selectedExplorer: SelectedExplorer, - +onSelectExplorer: {| + +onSelectExplorer: ({| explorer: $ReadOnly, - |} => PossiblyAsync, + |}) => PossiblyAsync, +isSubmitting: boolean, +error?: ?LocalizableError, |}; +const messages = defineMessages({ + title: { + id: 'wallet.settings.blockchain.explorer.title', + defaultMessage: '!!!Explorer settings', + }, +}); + @observer -export default class ExplorerSettings extends Component { - static defaultProps: {|error: void|} = { - error: undefined +class ExplorerSettings extends Component { + static defaultProps: {| error: void |} = { + error: undefined, }; - static contextTypes: {|intl: $npm$ReactIntl$IntlFormat|} = { + static contextTypes: {| intl: $npm$ReactIntl$IntlFormat |} = { intl: intlShape.isRequired, }; - selectExplorer: $ReadOnly => Promise = async (explorer) => { + selectExplorer: ($ReadOnly) => Promise = async explorer => { await this.props.onSelectExplorer({ explorer }); }; @@ -43,12 +52,12 @@ export default class ExplorerSettings extends Component { explorerId: { label: this.context.intl.formatMessage(globalMessages.blockchainExplorer), value: this.props.selectedExplorer.selected, - } - } + }, + }, }); render(): Node { - const { isSubmitting, error } = this.props; + const { isSubmitting, error, isRevampLayout } = this.props; const { intl } = this.context; const { form } = this; const explorerId = form.$('explorerId'); @@ -63,22 +72,31 @@ export default class ExplorerSettings extends Component { return (
- - {error &&

{intl.formatMessage(error, error.values)}

} + {isRevampLayout && ( + + {intl.formatMessage(messages.title)} + + )} + + + {error &&

{intl.formatMessage(error, error.values)}

} +
); } } + +export default (withLayout(ExplorerSettings): ComponentType); diff --git a/packages/yoroi-extension/app/components/settings/categories/general-setting/GeneralSettings.js b/packages/yoroi-extension/app/components/settings/categories/general-setting/GeneralSettings.js index fcb70228f8..a23bef120d 100644 --- a/packages/yoroi-extension/app/components/settings/categories/general-setting/GeneralSettings.js +++ b/packages/yoroi-extension/app/components/settings/categories/general-setting/GeneralSettings.js @@ -1,11 +1,11 @@ // @flow import { Component } from 'react'; -import type { Node } from 'react'; +import type { Node, ComponentType } from 'react'; import { observer } from 'mobx-react'; import classNames from 'classnames'; import Select from '../../../common/Select'; -import { MenuItem, Typography } from '@mui/material'; -import { intlShape } from 'react-intl'; +import { Box, MenuItem, Typography } from '@mui/material'; +import { defineMessages, intlShape } from 'react-intl'; import ReactToolboxMobxForm from '../../../../utils/ReactToolboxMobxForm'; import LocalizableError from '../../../../i18n/LocalizableError'; import styles from './GeneralSettings.scss'; @@ -14,84 +14,114 @@ import FlagLabel from '../../../widgets/FlagLabel'; import { tier1Languages } from '../../../../config/languagesConfig'; import globalMessages, { listOfTranslators } from '../../../../i18n/global-messages'; import type { $npm$ReactIntl$IntlFormat } from 'react-intl'; +import { withLayout } from '../../../../styles/context/layout'; +import type { InjectedLayoutProps } from '../../../../styles/context/layout'; type Props = {| +languages: Array, +currentLocale: string, - +onSelectLanguage: {| locale: string |} => PossiblyAsync, + +onSelectLanguage: ({| locale: string |}) => PossiblyAsync, +isSubmitting: boolean, +error?: ?LocalizableError, |}; +const messages = defineMessages({ + languageLabel: { + id: 'wallet.settings.general.language', + defaultMessage: '!!!Language', + }, + languageSelectLabel: { + id: 'wallet.settings.general.revamp.languageSelectLabel', + defaultMessage: '!!!Select your language', + }, +}); + @observer -export default class GeneralSettings extends Component { - static defaultProps: {|error: void|} = { - error: undefined +class GeneralSettings extends Component { + static defaultProps: {| error: void |} = { + error: undefined, }; - static contextTypes: {|intl: $npm$ReactIntl$IntlFormat|} = { + static contextTypes: {| intl: $npm$ReactIntl$IntlFormat |} = { intl: intlShape.isRequired, }; - selectLanguage: string => Promise = async (locale) => { + selectLanguage: string => Promise = async locale => { await this.props.onSelectLanguage({ locale }); }; form: ReactToolboxMobxForm = new ReactToolboxMobxForm({ fields: { languageId: { - label: this.context.intl.formatMessage(globalMessages.languageSelectLabel), + label: this.context.intl.formatMessage( + this.props.isRevampLayout + ? messages.languageSelectLabel + : globalMessages.languageSelectLabel + ), value: this.props.currentLocale, - } - } + }, + }, }); render(): Node { - const { languages, isSubmitting, error } = this.props; + const { languages, isSubmitting, error, isRevampLayout } = this.props; const { intl } = this.context; const { form } = this; const languageId = form.$('languageId'); const languageOptions = languages.map(language => ({ value: language.value, label: intl.formatMessage(language.label), - svg: language.svg + svg: language.svg, })); const componentClassNames = classNames([styles.component, 'general']); return (
- - {error &&

{intl.formatMessage(error, error.values)}

} + + {error &&

{intl.formatMessage(error, error.values)}

} + - {!tier1Languages.includes(languageId.value) && + {!tier1Languages.includes(languageId.value) && (

{intl.formatMessage(globalMessages.languageSelectLabelInfo)}

- {intl.formatMessage(globalMessages.languageSelectInfo)} - {' '} - {listOfTranslators(intl.formatMessage(globalMessages.translationContributors), - intl.formatMessage(globalMessages.translationAcknowledgment))} + {intl.formatMessage(globalMessages.languageSelectInfo)}{' '} + {listOfTranslators( + intl.formatMessage(globalMessages.translationContributors), + intl.formatMessage(globalMessages.translationAcknowledgment) + )}

- } - + )}
); } } + +export default (withLayout(GeneralSettings): ComponentType); diff --git a/packages/yoroi-extension/app/components/settings/categories/general-setting/ThemeSettingsBlock.js b/packages/yoroi-extension/app/components/settings/categories/general-setting/ThemeSettingsBlock.js index f34bd334cf..9f26d14282 100644 --- a/packages/yoroi-extension/app/components/settings/categories/general-setting/ThemeSettingsBlock.js +++ b/packages/yoroi-extension/app/components/settings/categories/general-setting/ThemeSettingsBlock.js @@ -11,6 +11,8 @@ import type { $npm$ReactIntl$IntlFormat } from 'react-intl'; import globalMessages from '../../../../i18n/global-messages'; import { ReactComponent as YoroiModernTheme } from '../../../../assets/images/yoroi-modern-theme.inline.svg'; import { ReactComponent as YoroiClassicTheme } from '../../../../assets/images/yoroi-classic-theme.inline.svg'; +import ThemeToggler from '../../themeToggler'; +import environment from '../../../../environment'; const messages = defineMessages({ themeLabel: { @@ -55,19 +57,19 @@ const messages = defineMessages({ }, version: { id: 'settings.theme.version', - defaultMessage: '!!!Version' + defaultMessage: '!!!Version', }, currentVersion: { id: 'settings.theme.currentVersion', - defaultMessage: '!!!Yoroi current version' + defaultMessage: '!!!Yoroi old version', }, newVersion: { id: 'settings.theme.newVersion', - defaultMessage: '!!!Yoroi new version (beta)' + defaultMessage: '!!!Yoroi new version', }, selectColorTheme: { id: 'settings.theme.selectColorTheme', - defaultMessage: '!!!Select color theme for old version' + defaultMessage: '!!!Select color theme for old version', }, }); @@ -77,8 +79,8 @@ type Props = {| +onExternalLinkClick: MouseEvent => void, |}; -const NEW_THEME = THEMES.YOROI_REVAMP -const OLD_THEME = `${THEMES.YOROI_MODERN}-${THEMES.YOROI_CLASSIC}` +const NEW_THEME = THEMES.YOROI_REVAMP; +const OLD_THEME = `${THEMES.YOROI_MODERN}-${THEMES.YOROI_CLASSIC}`; @observer export default class ThemeSettingsBlock extends Component { static contextTypes: {| intl: $npm$ReactIntl$IntlFormat |} = { @@ -86,12 +88,9 @@ export default class ThemeSettingsBlock extends Component { }; render(): Node { - const { - currentTheme, - onSubmit, - onExternalLinkClick, - } = this.props; + const { currentTheme, onSubmit, onExternalLinkClick } = this.props; const { intl } = this.context; + const isRevampLayout = currentTheme === THEMES.YOROI_REVAMP; const blogLink = ( { ); return ( - - + + {intl.formatMessage(messages.version)} { - const theme = e.target.value === NEW_THEME ? NEW_THEME : THEMES.YOROI_MODERN - onSubmit(theme) + onChange={e => { + const theme = e.target.value === NEW_THEME ? NEW_THEME : THEMES.YOROI_MODERN; + onSubmit(theme); }} sx={{ display: 'flex', flexDirection: 'row', }} > + + } + label={intl.formatMessage(messages.newVersion)} + id="switchToNewVersionButton" + /> } + control={} label={intl.formatMessage(messages.currentVersion)} id="switchToOldVersionButton" sx={{ - marginRight: '20px' + marginRight: '20px', }} /> - } - label={intl.formatMessage(messages.newVersion)} - id="switchToNewVersionButton" - /> - { - currentTheme !== THEMES.YOROI_REVAMP && ( - - - - {intl.formatMessage(messages.selectColorTheme)} - - - - - - - - + {false && currentTheme === THEMES.YOROI_REVAMP && environment.isDev() && ( + + + + )} + {currentTheme !== THEMES.YOROI_REVAMP && ( + + + + {intl.formatMessage(messages.selectColorTheme)} + + + + + + + + - - { - onSubmit(e.target.value) + + { + onSubmit(e.target.value); + }} + > + - - - - - } label='Modern' /> + + - - - } label='classic' /> - - - + } + label="Modern" + /> + + + + } + label="classic" + /> + + - ) - } + + )} - ) + ); } -} \ No newline at end of file +} diff --git a/packages/yoroi-extension/app/components/settings/categories/general-setting/UnitOfAccountSettings.js b/packages/yoroi-extension/app/components/settings/categories/general-setting/UnitOfAccountSettings.js index 4ccd2781a1..bc81d3527c 100644 --- a/packages/yoroi-extension/app/components/settings/categories/general-setting/UnitOfAccountSettings.js +++ b/packages/yoroi-extension/app/components/settings/categories/general-setting/UnitOfAccountSettings.js @@ -1,6 +1,6 @@ // @flow import { Component } from 'react'; -import type { Node } from 'react'; +import type { Node, ComponentType } from 'react'; import { observer } from 'mobx-react'; import classNames from 'classnames'; import Select from '../../../common/Select'; @@ -15,6 +15,8 @@ import VerticalFlexContainer from '../../../layout/VerticalFlexContainer'; import LoadingSpinner from '../../../widgets/LoadingSpinner'; import globalMessages from '../../../../i18n/global-messages'; import type { $npm$ReactIntl$IntlFormat } from 'react-intl'; +import { withLayout } from '../../../../styles/context/layout'; +import type { InjectedLayoutProps } from '../../../../styles/context/layout'; const messages = defineMessages({ unitOfAccountTitle: { @@ -26,6 +28,11 @@ const messages = defineMessages({ defaultMessage: '!!!Note: coin price is approximate and may not match the price of any given trading platform. Any transactions based on these price approximates are done at your own risk.', }, + noteRevamp: { + id: 'settings.revamp.unitOfAccount.note', + defaultMessage: + '!!!Please note, that the coin price is approximate and may not match the price of any given trading platform. Any transactions based on this price approximates are done at your own risk', + }, lastUpdated: { id: 'settings.unitOfAccount.lastUpdated', defaultMessage: '!!!Last updated: {lastUpdated}', @@ -34,6 +41,10 @@ const messages = defineMessages({ id: 'settings.unitOfAccount.label', defaultMessage: '!!!Currency', }, + revampInputLabel: { + id: 'settings.unitOfAccount.revamp.label', + defaultMessage: '!!!Select currency', + }, }); type Props = {| @@ -43,6 +54,7 @@ type Props = {| value: string, label: string, svg: string, + name: string, ... }>, +currentValue: string, @@ -51,25 +63,27 @@ type Props = {| |}; @observer -export default class UnitOfAccountSettings extends Component { - static defaultProps: {|error: void|} = { - error: undefined +class UnitOfAccountSettings extends Component { + static defaultProps: {| error: void |} = { + error: undefined, }; - static contextTypes: {|intl: $npm$ReactIntl$IntlFormat|} = { + static contextTypes: {| intl: $npm$ReactIntl$IntlFormat |} = { intl: intlShape.isRequired, }; form: ReactToolboxMobxForm = new ReactToolboxMobxForm({ fields: { coinPriceCurrencyId: { - label: this.context.intl.formatMessage(messages.label), - } - } + label: this.context.intl.formatMessage( + this.props.isRevampLayout ? messages.revampInputLabel : messages.label + ), + }, + }, }); render(): Node { - const { currencies, error, currentValue, lastUpdatedTimestamp } = this.props; + const { currencies, error, currentValue, lastUpdatedTimestamp, isRevampLayout } = this.props; const { intl } = this.context; const { form } = this; const coinPriceCurrencyId = form.$('coinPriceCurrencyId'); @@ -106,57 +120,108 @@ export default class UnitOfAccountSettings extends Component { ); }; - const lastUpdated = lastUpdatedTimestamp != null - ? new Date(lastUpdatedTimestamp).toLocaleString() - : '-'; + const lastUpdated = + lastUpdatedTimestamp != null ? new Date(lastUpdatedTimestamp).toLocaleString() : '-'; - const dialog = this.props.isSubmitting - ? ( - - - - - - ) - : null; + const dialog = this.props.isSubmitting ? ( + + + + + + ) : null; return ( -
+ {dialog} -

+ {intl.formatMessage(messages.unitOfAccountTitle)} -

+ -

+ {!isRevampLayout && ( + <> + + + -

+ + + + + )} - - {error &&

{intl.formatMessage(error, error.values)}

} -
+ + + {isRevampLayout && ( + <> + + + + + + + + )} +
+ ); } } + +export default (withLayout(UnitOfAccountSettings): ComponentType); diff --git a/packages/yoroi-extension/app/components/settings/categories/general-setting/UnitOfAccountSettings.scss b/packages/yoroi-extension/app/components/settings/categories/general-setting/UnitOfAccountSettings.scss index bf0cca9978..fb9edb851c 100644 --- a/packages/yoroi-extension/app/components/settings/categories/general-setting/UnitOfAccountSettings.scss +++ b/packages/yoroi-extension/app/components/settings/categories/general-setting/UnitOfAccountSettings.scss @@ -1,30 +1,14 @@ @import '../../../../themes/mixins/error-message'; .component { - border-top: 1px solid var(--yoroi-palette-gray-200); - padding-top: 30px; - margin-bottom: 20px; - - .title { - color: var(--yoroi-support-settings-text); - font-weight: 500; - font-size: 18px; - line-height: 22px; - margin-bottom: 12px; - } - a, - p { + .text { color: var(--yoroi-support-settings-text); font-weight: 400; font-size: 14px; line-height: 22px; } - a { - color: var(--yoroi-support-settings-text); - } - - p { + .text { margin-bottom: 2px; } diff --git a/packages/yoroi-extension/app/components/settings/categories/general-setting/UriSettingsBlock.js b/packages/yoroi-extension/app/components/settings/categories/general-setting/UriSettingsBlock.js index 9eb2abcf3c..5720c6af86 100644 --- a/packages/yoroi-extension/app/components/settings/categories/general-setting/UriSettingsBlock.js +++ b/packages/yoroi-extension/app/components/settings/categories/general-setting/UriSettingsBlock.js @@ -2,9 +2,8 @@ import { Component } from 'react'; import type { Node, ComponentType } from 'react'; import { observer } from 'mobx-react'; -import { Button } from '@mui/material'; +import { Box, Button, Typography } from '@mui/material'; import { intlShape } from 'react-intl'; -import styles from './UriSettingsBlock.scss'; import globalMessages from '../../../../i18n/global-messages'; import { observable, runInAction } from 'mobx'; import type { $npm$ReactIntl$IntlFormat } from 'react-intl'; @@ -33,9 +32,23 @@ class UriSettingsBlock extends Component { const isDisabled = this.props.isFirefox && this.hasPressed; return ( -
-

{intl.formatMessage(globalMessages.uriSchemeLabel)}

-

{intl.formatMessage(globalMessages.uriExplanation)}

+ + + {intl.formatMessage(globalMessages.uriSchemeLabel)} + + + + {intl.formatMessage( + isRevampLayout ? globalMessages.uriExplanationRevamp : globalMessages.uriExplanation + )} + -
+ ); } } diff --git a/packages/yoroi-extension/app/components/settings/categories/general-setting/UriSettingsBlock.scss b/packages/yoroi-extension/app/components/settings/categories/general-setting/UriSettingsBlock.scss deleted file mode 100644 index e26ef668cd..0000000000 --- a/packages/yoroi-extension/app/components/settings/categories/general-setting/UriSettingsBlock.scss +++ /dev/null @@ -1,30 +0,0 @@ -@import '../../../../themes/mixins/underline'; - -.component { - border-top: 1px solid var(--yoroi-palette-gray-200); - padding-top: 24px; - padding-bottom: 24px; - - .title { - color: var(--yoroi-support-settings-text); - font-weight: 500; - font-size: 18px; - line-height: 22px; - margin-bottom: 12px; - } - - p { - color: var(--yoroi-support-settings-text); - font-size: 14px; - line-height: 22px; - } - - p button { - @include underline(var(--yoroi-support-settings-text)); - } - - p { - margin-bottom: 2px; - font-weight: 400; - } -} diff --git a/packages/yoroi-extension/app/components/settings/menu/SettingsMenu.js b/packages/yoroi-extension/app/components/settings/menu/SettingsMenu.js index 5a406cd655..197e782d39 100644 --- a/packages/yoroi-extension/app/components/settings/menu/SettingsMenu.js +++ b/packages/yoroi-extension/app/components/settings/menu/SettingsMenu.js @@ -1,6 +1,6 @@ // @flow import { Component } from 'react'; -import type { Node } from 'react'; +import type { Node, ComponentType } from 'react'; import { observer } from 'mobx-react'; import { defineMessages, intlShape } from 'react-intl'; import environmnent from '../../../environment'; @@ -8,8 +8,10 @@ import { ROUTES } from '../../../routes-config'; import globalMessages from '../../../i18n/global-messages'; import type { $npm$ReactIntl$IntlFormat } from 'react-intl'; import SubMenu from '../../topbar/SubMenu'; +import { withLayout } from '../../../styles/context/layout'; +import type { InjectedLayoutProps } from '../../../styles/context/layout'; -const messages = defineMessages({ +export const settingsMenuMessages: Object = defineMessages({ general: { id: 'settings.menu.general.link.label', defaultMessage: '!!!General', @@ -26,6 +28,10 @@ const messages = defineMessages({ id: 'settings.menu.externalStorage.link.label', defaultMessage: '!!!External Storage', }, + analytics: { + id: 'settings.menu.analytics.link.label', + defaultMessage: '!!!Analytics', + }, }); type Props = {| @@ -33,23 +39,23 @@ type Props = {| +onItemClick: string => void, |}; @observer -export default class SettingsMenu extends Component { +class SettingsMenu extends Component { static contextTypes: {| intl: $npm$ReactIntl$IntlFormat |} = { intl: intlShape.isRequired, }; render(): Node { const { intl } = this.context; - const { onItemClick, isActiveItem } = this.props; + const { onItemClick, isActiveItem, isRevampLayout } = this.props; const settingOptions: Array = [ { - label: intl.formatMessage(messages.general), + label: intl.formatMessage(settingsMenuMessages.general), route: ROUTES.SETTINGS.GENERAL, className: 'general', }, { - label: intl.formatMessage(messages.blockchain), + label: intl.formatMessage(settingsMenuMessages.blockchain), route: ROUTES.SETTINGS.BLOCKCHAIN, className: 'blockchain', }, @@ -59,12 +65,14 @@ export default class SettingsMenu extends Component { className: 'wallet', }, !environmnent.isProduction() && { - label: intl.formatMessage(messages.externalStorage), + label: intl.formatMessage(settingsMenuMessages.externalStorage), route: ROUTES.SETTINGS.EXTERNAL_STORAGE, className: 'externalStorage', }, { - label: intl.formatMessage(globalMessages.termsOfUse), + label: intl.formatMessage( + isRevampLayout ? globalMessages.termsOfService : globalMessages.termsOfUse + ), route: ROUTES.SETTINGS.TERMS_OF_USE, className: 'termsOfUse', }, @@ -74,10 +82,15 @@ export default class SettingsMenu extends Component { className: 'support', }, { - label: intl.formatMessage(messages.levelOfComplexity), + label: intl.formatMessage(settingsMenuMessages.levelOfComplexity), route: ROUTES.SETTINGS.LEVEL_OF_COMPLEXITY, className: 'levelOfComplexity', }, + { + label: intl.formatMessage(settingsMenuMessages.analytics), + route: ROUTES.SETTINGS.ANALYTICS, + className: 'analytics', + }, ]; return ( @@ -85,3 +98,5 @@ export default class SettingsMenu extends Component { ); } } + +export default (withLayout(SettingsMenu): ComponentType); diff --git a/packages/yoroi-extension/app/components/settings/themeToggler/index.js b/packages/yoroi-extension/app/components/settings/themeToggler/index.js new file mode 100644 index 0000000000..55895cee34 --- /dev/null +++ b/packages/yoroi-extension/app/components/settings/themeToggler/index.js @@ -0,0 +1,25 @@ +//@flow + +import { Box, Button } from '@mui/material'; +import { useState } from 'react'; +import { useThemeMode } from '../../../styles/context/mode'; +import { ReactComponent as IconSun } from '../../../assets/images/top-bar/sun.inline.svg'; +import { ReactComponent as IconMoon } from '../../../assets/images/top-bar/moon.inline.svg'; + +export default function ThemeToggler(): any { + const [mode, setMode] = useState(false); + const { toggleColorMode } = useThemeMode(); + + const toggle = () => { + setMode(md => !md); + toggleColorMode(); + }; + + return ( + + + + ); +} diff --git a/packages/yoroi-extension/app/components/topbar/BuySellAdaButton.js b/packages/yoroi-extension/app/components/topbar/BuySellAdaButton.js index 329e4f3ec4..3ed4b7bbb2 100644 --- a/packages/yoroi-extension/app/components/topbar/BuySellAdaButton.js +++ b/packages/yoroi-extension/app/components/topbar/BuySellAdaButton.js @@ -40,11 +40,10 @@ class BuySellAdaButton extends Component { const BuyAdaButtonRevamp = ( @@ -144,8 +146,8 @@ export default class NavWalletDetailsRevamp extends Component { onClick={onUpdateHideBalance} sx={{ bgcolor: 'primary.600', - width: '56px', - height: '54px', + width: '46px', + height: '46px', borderTopRightRadius: '6px', borderBottomRightRadius: '6px', borderTopLeftRadius: '0px', diff --git a/packages/yoroi-extension/app/components/topbar/NavWalletDetailsRevamp.scss b/packages/yoroi-extension/app/components/topbar/NavWalletDetailsRevamp.scss index e911a971c7..a63c14e38f 100644 --- a/packages/yoroi-extension/app/components/topbar/NavWalletDetailsRevamp.scss +++ b/packages/yoroi-extension/app/components/topbar/NavWalletDetailsRevamp.scss @@ -7,29 +7,25 @@ color: var(--yoroi-palette-gray-900); border: 1px solid var(--yoroi-palette-gray-300); border-radius: 8px; - min-width: 360px; - height: 56px; } .outerWrapper { display: flex; align-items: stretch; + justify-content: space-between; width: 100%; } .contentWrapper { display: flex; align-items: center; - width: 100%; - padding: 0px; - padding: 0px 16px; + padding: 0px 8px; } -.currency { +.plate { margin-right: 12px; display: flex; flex-shrink: 0; - border-radius: 50%; border: none; overflow: hidden; width: 32px; @@ -52,7 +48,6 @@ .name { font-size: 14px; line-height: 22px; - color: #242838; font-weight: 500; } @@ -61,7 +56,6 @@ font-size: 12px; line-height: 16px; letter-spacing: 0.2px; - color: #6b7384; } } @@ -78,9 +72,9 @@ display: flex; flex-direction: column; justify-content: center; - align-items: flex-end; + align-items: flex-start; text-align: left; - font-size: 16px; + font-size: 12px; line-height: 22px; width: 100%; margin-left: 24px; @@ -107,8 +101,22 @@ align-items: center; justify-content: flex-end; + &:first-child { + font-size: 14px; + } + + &:nth-child(1) { + font-size: 14px; + } + &:nth-child(2) { margin-top: -2px; + text-align: left; + display: flex; + align-items: center; + justify-content: flex-start; + font-size: 12px; + font-weight: 400; } } } diff --git a/packages/yoroi-extension/app/components/topbar/SideBarCategoryRevamp.js b/packages/yoroi-extension/app/components/topbar/SideBarCategoryRevamp.js index 80d52c7a23..2d8ed19baf 100644 --- a/packages/yoroi-extension/app/components/topbar/SideBarCategoryRevamp.js +++ b/packages/yoroi-extension/app/components/topbar/SideBarCategoryRevamp.js @@ -6,6 +6,7 @@ import { intlShape } from 'react-intl'; import { observer } from 'mobx-react'; import classNames from 'classnames'; import styles from './SideBarCategoryRevamp.scss'; +import { Typography } from '@mui/material'; type Props = {| +icon: string, @@ -43,7 +44,11 @@ export default class SideBarCategoryRevamp extends Component { - {label ? {intl.formatMessage(label)} : null} + {label ? ( + + {intl.formatMessage(label)} + + ) : null} ) : ( { - {label ? {intl.formatMessage(label)} : null} + {label ? {intl.formatMessage(label)} : null} ); } diff --git a/packages/yoroi-extension/app/components/topbar/Sidebar.js b/packages/yoroi-extension/app/components/topbar/Sidebar.js index c71a295f34..ab1c81f959 100644 --- a/packages/yoroi-extension/app/components/topbar/Sidebar.js +++ b/packages/yoroi-extension/app/components/topbar/Sidebar.js @@ -9,9 +9,9 @@ import classnames from 'classnames'; import { intlShape } from 'react-intl'; import type { $npm$ReactIntl$IntlFormat } from 'react-intl'; -import { ReactComponent as yoroiLogo } from '../../assets/images/sidebar/yoroi_logo.inline.svg'; -import { ReactComponent as yoroiLogoExpanded } from '../../assets/images/sidebar/yoroi_logo_expanded.inline.svg'; -import { ReactComponent as toggleIcon } from '../../assets/images/sidebar/open_sidebar.inline.svg'; +import { ReactComponent as yoroiLogo } from '../../assets/images/sidebar/yoroi-logo.inline.svg'; +import { ReactComponent as yoroiLogoExpanded } from '../../assets/images/sidebar/yoroi-logo-expanded.inline.svg'; +import { ReactComponent as toggleIcon } from '../../assets/images/sidebar/open-sidebar.inline.svg'; import globalMessages from '../../i18n/global-messages'; type Props = {| @@ -20,7 +20,7 @@ type Props = {| +isActiveCategory?: SidebarCategory => boolean, +onCategoryClicked?: SidebarCategory => void, +onToggleSidebar: void => Promise, - +isSidebarExpanded: boolean + +isSidebarExpanded: boolean, |}; @observer @@ -48,7 +48,7 @@ export default class Sidebar extends Component { isActiveCategory, onCategoryClicked, isSidebarExpanded, - onToggleSidebar + onToggleSidebar, } = this.props; const ToggleIcon = toggleIcon; @@ -62,33 +62,31 @@ export default class Sidebar extends Component { {isSidebarExpanded ? : }
- {categories ? categories.map(category => { - return ( - { - if (onCategoryClicked) { - onCategoryClicked(category); - } - }} - /> - ); - }) : null} + {categories + ? categories.map(category => { + return ( + { + if (onCategoryClicked) { + onCategoryClicked(category); + } + }} + /> + ); + }) + : null}
-
+
{intl.formatMessage(globalMessages.sidebarFaq)} @@ -98,14 +96,10 @@ export default class Sidebar extends Component { onClick={onToggleSidebar} className={classnames([ styles.toggleButton, - isSidebarExpanded ? styles.toggleActive : null + isSidebarExpanded ? styles.toggleActive : null, ])} > - + diff --git a/packages/yoroi-extension/app/components/topbar/SidebarRevamp.js b/packages/yoroi-extension/app/components/topbar/SidebarRevamp.js index 674013d98c..faf1acb664 100644 --- a/packages/yoroi-extension/app/components/topbar/SidebarRevamp.js +++ b/packages/yoroi-extension/app/components/topbar/SidebarRevamp.js @@ -1,13 +1,14 @@ // @flow import { Component } from 'react'; import type { Node } from 'react'; +import type { $npm$ReactIntl$IntlFormat } from 'react-intl'; +import type { SidebarCategoryRevamp } from '../../stores/stateless/sidebarCategories'; import { observer } from 'mobx-react'; +import { intlShape } from 'react-intl'; +import { Box, Link } from '@mui/material'; +import { ReactComponent as YoroiLogo } from '../../assets/images/sidebar/revamp/yoroi-logo.inline.svg'; import SideBarCategoryRevamp from './SideBarCategoryRevamp'; import styles from './SidebarRevamp.scss'; -import type { SidebarCategoryRevamp } from '../../stores/stateless/sidebarCategories'; -import { intlShape } from 'react-intl'; -import type { $npm$ReactIntl$IntlFormat } from 'react-intl'; -import { ReactComponent as YoroiLogo } from '../../assets/images/sidebar/yoroi_logo.inline.svg'; import globalMessages from '../../i18n/global-messages'; type Props = {| @@ -43,7 +44,7 @@ export default class SidebarRevamp extends Component { const { categories, isActiveCategory, onCategoryClicked, onLogoClick } = this.props; return ( - + + ); } } diff --git a/packages/yoroi-extension/app/components/topbar/SidebarRevamp.scss b/packages/yoroi-extension/app/components/topbar/SidebarRevamp.scss index 07b687a17a..b9048b9dc2 100644 --- a/packages/yoroi-extension/app/components/topbar/SidebarRevamp.scss +++ b/packages/yoroi-extension/app/components/topbar/SidebarRevamp.scss @@ -3,15 +3,14 @@ display: flex; flex-direction: column; align-items: center; - background: linear-gradient(30.09deg, #244abf 0%, #4760ff 100%); + width: 72px; + background-image: linear-gradient(30.09deg, #244abf 0%, #4760ff 176.73%); .faq { max-width: 47px; text-transform: uppercase; border-radius: 20px; - background: #1737A3; text-decoration: none; - color: #FFFFFF; font-weight: 400; font-size: 12px; padding: 14px 12px; @@ -22,10 +21,7 @@ text-align: center; margin: 0px 12px; margin-bottom: 32px; - &:hover { - background-color: #122770; - } - } + } } .header { @@ -42,12 +38,6 @@ bottom: 0; background: rgba(255, 255, 255, 0.5); } - & svg { - transform: scale(0.9); - } - & svg > path { - fill: white; - } } .categories { diff --git a/packages/yoroi-extension/app/components/topbar/SubMenu.js b/packages/yoroi-extension/app/components/topbar/SubMenu.js index 74b999de54..948540d64c 100644 --- a/packages/yoroi-extension/app/components/topbar/SubMenu.js +++ b/packages/yoroi-extension/app/components/topbar/SubMenu.js @@ -25,8 +25,8 @@ class SubMenu extends Component { const { onItemClick, isActiveItem, options } = this.props; return ( -
-
+