diff --git a/apps/names/tests/utils.ts b/apps/names/tests/utils.ts index da6e337c70..07d9dd5488 100644 --- a/apps/names/tests/utils.ts +++ b/apps/names/tests/utils.ts @@ -50,7 +50,6 @@ export async function createWallet(page: Page) { await page.getByText('Mnemonic', { exact: true }).click(); await page.getByTestId('password.input').fill('iotae2etests'); await page.getByTestId('password.confirmation').fill('iotae2etests'); - await page.getByText('I read and agree').click(); await page.getByRole('button', { name: /Create Wallet/ }).click(); await page.waitForURL(new RegExp(/accounts\/backup/)); diff --git a/apps/wallet/src/ui/app/components/accounts/ProtectAccountForm.tsx b/apps/wallet/src/ui/app/components/accounts/ProtectAccountForm.tsx index 4a6e798b82..ba91d08315 100644 --- a/apps/wallet/src/ui/app/components/accounts/ProtectAccountForm.tsx +++ b/apps/wallet/src/ui/app/components/accounts/ProtectAccountForm.tsx @@ -2,18 +2,16 @@ // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { ToS_LINK, useZodForm } from '@iota/core'; +import { useZodForm } from '@iota/core'; import { useEffect } from 'react'; import { type SubmitHandler } from 'react-hook-form'; import { useNavigate } from 'react-router-dom'; import { z } from 'zod'; import zxcvbn from 'zxcvbn'; import { parseAutoLock, useAutoLockMinutes } from '_hooks'; -import { CheckboxField } from '../../shared/forms/CheckboxField'; import { Form } from '../../shared/forms/Form'; import { AutoLockSelector, zodSchema } from './AutoLockSelector'; import { Button, ButtonHtmlType, ButtonType, Input, InputType } from '@iota/apps-ui-kit'; -import { ExternalLink } from '_components'; function addDot(str: string | undefined) { if (str && !str.endsWith('.')) { @@ -49,9 +47,6 @@ const formSchema = z path: ['confirmation'], message: "Passwords don't match", }), - acceptedTos: z.literal(true, { - errorMap: () => ({ message: 'Please accept Terms of Service to continue' }), - }), }) .merge(zodSchema); @@ -61,14 +56,12 @@ interface ProtectAccountFormProps { submitButtonText: string; cancelButtonText?: string; onSubmit: SubmitHandler; - hideToS?: boolean; } export function ProtectAccountForm({ submitButtonText, cancelButtonText, onSubmit, - hideToS, }: ProtectAccountFormProps) { const autoLock = useAutoLockMinutes(); const form = useZodForm({ @@ -76,7 +69,6 @@ export function ProtectAccountForm({ schema: formSchema, values: { password: { input: '', confirmation: '' }, - acceptedTos: !!hideToS, autoLock: parseAutoLock(autoLock.data || null), }, }); @@ -129,26 +121,6 @@ export function ProtectAccountForm({
- {hideToS ? null : ( - - - I read and agreed to the - - - Terms of Services - -
- } - /> - )} -
{cancelButtonText ? (
+ + + + ); +} diff --git a/apps/wallet/src/ui/app/components/menu/content/WalletSettingsMenuList.tsx b/apps/wallet/src/ui/app/components/menu/content/WalletSettingsMenuList.tsx index 111ce21ed8..b7b79985d2 100644 --- a/apps/wallet/src/ui/app/components/menu/content/WalletSettingsMenuList.tsx +++ b/apps/wallet/src/ui/app/components/menu/content/WalletSettingsMenuList.tsx @@ -18,6 +18,7 @@ import { Logout, Expand, Discord, + DataStack, SidePanel as SidePanelIcon, } from '@iota/apps-ui-icons'; import { @@ -35,6 +36,7 @@ import { ampli } from '_src/shared/analytics/ampli'; import { useTheme, getCustomNetwork, FAQ_LINK, ToS_LINK, DISCORD_SUPPORT_LINK } from '@iota/core'; import { useSidePanel } from '_src/ui/app/hooks/useSidePanel'; import { useSidePanelMutation } from '_src/ui/app/hooks/useSidePanelMutation'; +import { useMetricsEnabled } from '_src/ui/app/hooks/useMetricsEnabled'; import { SidePanel } from '_src/polyfills/sidepanel'; import { ExtensionViewType } from '_src/ui/app/redux/slices/app/appType'; import { openInNewTab } from '_src/shared/utils'; @@ -45,6 +47,7 @@ export function MenuList() { const networkUrl = useNextMenuUrl(true, '/network'); const autoLockUrl = useNextMenuUrl(true, '/auto-lock'); const themeUrl = useNextMenuUrl(true, '/theme'); + const metricsUrl = useNextMenuUrl(true, '/metrics'); const network = useAppSelector((state) => state.app.network); const networkConfig = network === Network.Custom ? getCustomNetwork() : getNetwork(network); const version = Browser.runtime.getManifest().version; @@ -52,6 +55,7 @@ export function MenuList() { const sidePanel = useSidePanel(); const sidePanelMutation = useSidePanelMutation(); const extensionType = useAppSelector((state) => state.app.extensionViewType); + const [hasAcceptedMetrics] = useMetricsEnabled(); // Logout const [isLogoutDialogOpen, setIsLogoutDialogOpen] = useState(false); @@ -79,6 +83,11 @@ export function MenuList() { function onThemeClick() { navigate(themeUrl); } + + function onMetricsClick() { + navigate(metricsUrl); + } + async function onSidePanelClick( _isToggled: boolean, event: React.ChangeEvent, @@ -120,6 +129,7 @@ export function MenuList() { const autoLockSubtitle = handleAutoLockSubtitle(); const themeSubtitle = themePreference.charAt(0).toUpperCase() + themePreference.slice(1); + const metricsSubtitle = `Metrics ${hasAcceptedMetrics ? 'enabled' : 'disabled'}`; const MENU_ITEMS = [ { title: 'Network', @@ -139,6 +149,12 @@ export function MenuList() { subtitle: themeSubtitle, onClick: onThemeClick, }, + { + title: 'Metrics', + icon: , + subtitle: metricsSubtitle, + onClick: onMetricsClick, + }, { title: 'Get Support', icon: , diff --git a/apps/wallet/src/ui/app/components/menu/content/index.tsx b/apps/wallet/src/ui/app/components/menu/content/index.tsx index c0b67da854..0de86768b4 100644 --- a/apps/wallet/src/ui/app/components/menu/content/index.tsx +++ b/apps/wallet/src/ui/app/components/menu/content/index.tsx @@ -17,6 +17,7 @@ import { AutoLockAccounts } from './AutoLockAccounts'; import { NetworkSettings } from './NetworkSettings'; import { MenuList } from './WalletSettingsMenuList'; import { ThemeSettings } from './ThemeSettings'; +import { MetricsSettings } from './MetricsSettings'; const CLOSE_KEY_CODES: string[] = ['Escape']; @@ -51,6 +52,7 @@ export function MenuContent() { } /> } /> } /> + } /> } /> diff --git a/apps/wallet/src/ui/app/hooks/useMetricsEnabled.ts b/apps/wallet/src/ui/app/hooks/useMetricsEnabled.ts new file mode 100644 index 0000000000..204d591e26 --- /dev/null +++ b/apps/wallet/src/ui/app/hooks/useMetricsEnabled.ts @@ -0,0 +1,21 @@ +// Copyright (c) 2026 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +import { useState } from 'react'; + +export const METRICS_STORAGE_KEY = 'metrics_enabled_iota-wallet'; +const DEFAULT_METRICS_ENABLED = true; + +export function useMetricsEnabled(): [boolean, (enabled: boolean) => void] { + const [isEnabled, setIsEnabled] = useState(() => { + const storedValue = localStorage.getItem(METRICS_STORAGE_KEY); + return storedValue ? JSON.parse(storedValue) : DEFAULT_METRICS_ENABLED; + }); + + const setMetricsEnabled = (enabled: boolean) => { + localStorage.setItem(METRICS_STORAGE_KEY, JSON.stringify(enabled)); + setIsEnabled(enabled); + }; + + return [isEnabled, setMetricsEnabled]; +} diff --git a/apps/wallet/src/ui/app/pages/accounts/WelcomePage.tsx b/apps/wallet/src/ui/app/pages/accounts/WelcomePage.tsx index 19917a306b..73f456ea19 100644 --- a/apps/wallet/src/ui/app/pages/accounts/WelcomePage.tsx +++ b/apps/wallet/src/ui/app/pages/accounts/WelcomePage.tsx @@ -9,7 +9,7 @@ import { Button, ButtonType } from '@iota/apps-ui-kit'; import { IotaLogoWeb } from '@iota/apps-ui-icons'; import GetStartedImage from '_assets/images/onboarding/get-started.png'; import GetStartedImageDark from '_assets/images/onboarding/get-started-darkmode.png'; -import { useTheme, Theme } from '@iota/core'; +import { useTheme, Theme, ToS_LINK } from '@iota/core'; import { AmpliSourceFlow } from '_src/shared/analytics'; export function WelcomePage() { @@ -22,34 +22,51 @@ export function WelcomePage() { return ( -
+
+ Get Started
- Get Started -

- Your Gateway to the IOTA Ecosystem -

-
-
- © IOTA Foundation {CURRENT_YEAR} +
+

+ Your Gateway to the IOTA Ecosystem +

+
diff --git a/apps/wallet/tests/utils/wallet.ts b/apps/wallet/tests/utils/wallet.ts index 13cc5571cd..185ada0137 100644 --- a/apps/wallet/tests/utils/wallet.ts +++ b/apps/wallet/tests/utils/wallet.ts @@ -15,7 +15,6 @@ export async function createWallet(page: Page, extensionUrl: string) { await page.getByText('Mnemonic', { exact: true }).click(); await page.getByTestId('password.input').fill(TESTS_PASSWORD); await page.getByTestId('password.confirmation').fill(TESTS_PASSWORD); - await page.getByText('I read and agree').click(); await page.getByRole('button', { name: /Create Wallet/ }).click(); await page.getByText('I saved my mnemonic').click(); await page.getByRole('button', { name: /Open Wallet/ }).click(); @@ -43,7 +42,6 @@ export async function importWallet(page: Page, extensionUrl: string, mnemonic: s await page.getByText('Add profile').click(); await page.getByTestId('password.input').fill(TESTS_PASSWORD); await page.getByTestId('password.confirmation').fill(TESTS_PASSWORD); - await page.getByText('I read and agree').click(); await page.getByRole('button', { name: /Create Wallet/ }).click(); await page.waitForURL(new RegExp(/^(?!.*protect-account).*$/)); @@ -106,9 +104,6 @@ export async function createPasskeyWallet( await page.getByTestId('password.input').fill(TESTS_PASSWORD); await page.getByTestId('password.confirmation').fill(TESTS_PASSWORD); - - await page.getByText('I read and agree').click(); - await page.getByRole('button', { name: /Create Wallet/ }).click(); await expect(page.getByText(username)).toBeVisible({ timeout: LONG_TIMEOUT }); @@ -128,8 +123,5 @@ export async function restorePasskeyAccount(page: Page) { await page.getByTestId('password.input').fill(TESTS_PASSWORD); await page.getByTestId('password.confirmation').fill(TESTS_PASSWORD); - - await page.getByText('I read and agree').click(); - await page.getByRole('button', { name: /Create Wallet/ }).click(); }