diff --git a/e2e/specs/stateless/wrapName.spec.ts b/e2e/specs/stateless/wrapName.spec.ts index 44a64ac7a..8279829b8 100644 --- a/e2e/specs/stateless/wrapName.spec.ts +++ b/e2e/specs/stateless/wrapName.spec.ts @@ -48,6 +48,9 @@ test('should not show wrap notification if the name is already wrapped', async ( await page.waitForTimeout(3000) await expect(morePage.wrapButton).not.toBeVisible() + + await expect(morePage.pccStatus).toBeVisible() + await expect(morePage.nameWrapperStatus).toHaveText('Wrapped') }) test('should show wrap button on unwrapped name', async ({ login, makeName, makePageObject }) => { @@ -255,7 +258,7 @@ test('should calculate needed steps without localstorage', async ({ await login.connect() await page.pause() - await expect(page.getByTestId('name-details-text-wrapper')).toContainText('unwrapped') + await expect(page.getByTestId('namewrapper-status')).toContainText('Unwrapped') await morePage.wrapButton.click() await page.pause() @@ -291,8 +294,187 @@ test('should calculate needed steps without localstorage', async ({ await transactionModal.introButton.click() await transactionModal.confirm() await transactionModal.complete() - await expect(page.getByTestId('name-details-text-wrapper')).not.toContainText('unwrapped') + await expect(page.getByTestId('namewrapper-status')).not.toContainText('Unwrapped') await profilePage.goto(subname) await expect(profilePage.record('text', 'description')).toHaveText('test') }) + +test('Wrapped, emancipated, 2LD', async ({ login, makeName, makePageObject }) => { + const name = await makeName({ + label: 'wrapped', + type: 'wrapped', + owner: 'user', + }) + + const morePage = makePageObject('MorePage') + await morePage.goto(name) + + await login.connect() + + await expect(morePage.wrapButton).not.toBeVisible() + await expect(morePage.unwrapButton).toBeVisible() + await expect(morePage.nameWrapperStatus).toContainText('Wrapped') + await expect(morePage.pccStatus).toContainText('Not parent-controllable') + await expect(morePage.nameWrapperCheckIcon).toBeVisible() + await expect(morePage.npcIcon).toBeVisible() +}) + +test('Wrapped, locked, 2LD', async ({ login, makeName, makePageObject }) => { + const name = await makeName({ + label: 'wrapped', + type: 'wrapped', + owner: 'user', + fuses: { + named: ['CANNOT_UNWRAP'], + }, + }) + + const morePage = makePageObject('MorePage') + await morePage.goto(name) + + await login.connect() + + await expect(morePage.wrapButton).not.toBeVisible() + await expect(morePage.unwrapButtonDisabled).toBeVisible() + await expect(morePage.nameWrapperStatus).toContainText('Wrapped') + await expect(morePage.pccStatus).toContainText('Not parent-controllable') + await expect(morePage.nameWrapperLockIcon).toBeVisible() + await expect(morePage.npcIcon).toBeVisible() +}) + +test('Wrapped, not-emancipated (PCC), 3LD', async ({ login, makeName, makePageObject }) => { + const name = await makeName({ + label: 'wrapped', + type: 'wrapped', + owner: 'user', + subnames: [ + { + label: 'test', + owner: 'user', + }, + ], + }) + + const morePage = makePageObject('MorePage') + await morePage.goto(`test.${name}`) + + await login.connect() + + await expect(morePage.unwrapButton).toBeVisible() + await expect(morePage.nameWrapperStatus).toContainText('Wrapped') + await expect(morePage.pccStatus).toContainText('Parent-controllable') + await expect(morePage.nameWrapperCheckIcon).toBeVisible() + await expect(morePage.nameWrapperLockIcon).not.toBeVisible() + await expect(morePage.pccIcon).toBeVisible() + await expect(morePage.nameWrapperLockIcon).not.toBeVisible() +}) + +test('Wrapped, emancipated(NPC), 3LD', async ({ login, makeName, makePageObject }) => { + const name = await makeName({ + label: 'wrapped', + type: 'wrapped', + owner: 'user', + fuses: { + named: ['CANNOT_UNWRAP'], + }, + subnames: [ + { + label: 'test', + owner: 'user', + fuses: { + parent: { + named: ['PARENT_CANNOT_CONTROL'], + }, + }, + }, + ], + }) + + const morePage = makePageObject('MorePage') + await morePage.goto(`test.${name}`) + + await login.connect() + + await expect(morePage.unwrapButton).toBeVisible() + await expect(morePage.nameWrapperStatus).toContainText('Wrapped') + await expect(morePage.pccStatus).toContainText('Not parent-controllable') + await expect(morePage.nameWrapperCheckIcon).toBeVisible() + await expect(morePage.npcIcon).toBeVisible() + await expect(morePage.nameWrapperLockIcon).not.toBeVisible() +}) + +test('Wrapped, emancipated(NPC), Locked, 3LD', async ({ login, makeName, makePageObject }) => { + const name = await makeName({ + label: 'wrapped', + type: 'wrapped', + owner: 'user', + fuses: { + named: ['CANNOT_UNWRAP'], + }, + subnames: [ + { + label: 'test', + owner: 'user', + fuses: { + parent: { + named: ['PARENT_CANNOT_CONTROL'], + }, + child: { + named: ['CANNOT_UNWRAP'], + }, + }, + }, + ], + }) + + const morePage = makePageObject('MorePage') + await morePage.goto(`test.${name}`) + + await login.connect() + + await expect(morePage.nameWrapperStatus).toContainText('Wrapped') + await expect(morePage.pccStatus).toContainText('Not parent-controllable') + await expect(morePage.nameWrapperLockIcon).toBeVisible() + await expect(morePage.npcIcon).toBeVisible() + await expect(morePage.unwrapButtonDisabled).toBeVisible() +}) + +test('Wrapped, emancipated(NPC), 3LD Manager', async ({ login, makeName, makePageObject }) => { + const name = await makeName({ + label: 'wrapped', + type: 'wrapped', + owner: 'user2', + fuses: { + named: ['CANNOT_UNWRAP'], + }, + subnames: [ + { + label: 'test', + owner: 'user', + fuses: { + parent: { + named: ['PARENT_CANNOT_CONTROL'], + }, + }, + }, + ], + }) + + const morePage = makePageObject('MorePage') + const transactionModal = makePageObject('TransactionModal') + await morePage.goto(`test.${name}`) + + await login.connect() + + await expect(morePage.unwrapButton).toBeVisible() + await expect(morePage.nameWrapperStatus).toContainText('Wrapped') + await expect(morePage.pccStatus).toContainText('Not parent-controllable') + await expect(morePage.nameWrapperCheckIcon).toBeVisible() + await expect(morePage.npcIcon).toBeVisible() + await expect(morePage.nameWrapperLockIcon).not.toBeVisible() + + await morePage.unwrapButton.click() + await transactionModal.autoComplete() + await expect(morePage.wrapButton).toBeVisible() +}) diff --git a/playwright/pageObjects/morePage.ts b/playwright/pageObjects/morePage.ts index c29f50bbb..1e39d0d83 100644 --- a/playwright/pageObjects/morePage.ts +++ b/playwright/pageObjects/morePage.ts @@ -20,6 +20,20 @@ export class MorePage { readonly unwrapButton: Locator + readonly pccStatus: Locator + + readonly nameWrapperStatus: Locator + + readonly unwrapButtonDisabled: Locator + + readonly nameWrapperLockIcon: Locator + + readonly nameWrapperCheckIcon: Locator + + readonly npcIcon: Locator + + readonly pccIcon: Locator + constructor(page: Page) { this.page = page this.getSendNameButton = this.page.getByTestId('send-name-button') @@ -30,6 +44,13 @@ export class MorePage { this.resolver = this.page.getByTestId('name-details-text') this.wrapButton = this.page.getByTestId('wrap-name-btn') this.unwrapButton = this.page.getByTestId('unwrap-name-btn') + this.pccStatus = this.page.getByTestId('pcc-status') + this.nameWrapperStatus = this.page.getByTestId('namewrapper-status') + this.unwrapButtonDisabled = this.page.getByTestId('cannot-unwrap-disabled-button') + this.nameWrapperLockIcon = this.page.getByTestId('namewrapper-lock-icon') + this.nameWrapperCheckIcon = this.page.getByTestId('namewrapper-check-icon') + this.npcIcon = this.page.getByTestId('npc-icon') + this.pccIcon = this.page.getByTestId('pcc-icon') } async goto(name: string) { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 11053683f..d9af9e0a5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -442,33 +442,6 @@ importers: specifier: ^1.0.0-pre.53 version: 1.0.0-pre.53 - .yalc/@ensdomains/thorin: - dependencies: - clsx: - specifier: ^1.1.1 - version: 1.2.1 - focus-visible: - specifier: ^5.2.0 - version: 5.2.0 - lodash: - specifier: ^4.17.21 - version: 4.17.21 - react: - specifier: ^18.2.0 - version: 18.3.1 - react-dom: - specifier: ^18.2.0 - version: 18.3.1(react@18.3.1) - react-transition-state: - specifier: ^2.1.1 - version: 2.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - styled-components: - specifier: ^5.3.6 - version: 5.3.11(@babel/core@7.24.6)(react-dom@18.3.1(react@18.3.1))(react-is@18.3.1)(react@18.3.1) - ts-pattern: - specifier: ^4.3.0 - version: 4.3.0 - packages: '@adobe/css-tools@4.3.3': @@ -8313,12 +8286,6 @@ packages: react: ^18.2.0 react-dom: ^18.2.0 - react-transition-state@2.1.1: - resolution: {integrity: sha512-kQx5g1FVu9knoz1T1WkapjUgFz08qQ/g1OmuWGi3/AoEFfS0kStxrPlZx81urjCXdz2d+1DqLpU6TyLW/Ro04Q==} - peerDependencies: - react: ^18.2.0 - react-dom: ^18.2.0 - react-universal-interface@0.6.2: resolution: {integrity: sha512-dg8yXdcQmvgR13RIlZbTRQOoUrDciFVoSBZILwjE2LFISxZZ8loVJKAkuzswl5js8BHda79bIb2b84ehU8IjXw==} peerDependencies: @@ -10496,10 +10463,10 @@ snapshots: '@babel/helpers': 7.24.6 '@babel/parser': 7.24.6 '@babel/template': 7.24.6 - '@babel/traverse': 7.24.6 + '@babel/traverse': 7.24.6(supports-color@5.5.0) '@babel/types': 7.24.6 convert-source-map: 2.0.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4(supports-color@5.5.0) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -11657,21 +11624,6 @@ snapshots: '@babel/parser': 7.25.3 '@babel/types': 7.25.2 - '@babel/traverse@7.24.6': - dependencies: - '@babel/code-frame': 7.24.6 - '@babel/generator': 7.24.6 - '@babel/helper-environment-visitor': 7.24.6 - '@babel/helper-function-name': 7.24.6 - '@babel/helper-hoist-variables': 7.24.6 - '@babel/helper-split-export-declaration': 7.24.6 - '@babel/parser': 7.24.6 - '@babel/types': 7.24.6 - debug: 4.3.4(supports-color@8.1.1) - globals: 11.12.0 - transitivePeerDependencies: - - supports-color - '@babel/traverse@7.24.6(supports-color@5.5.0)': dependencies: '@babel/code-frame': 7.24.6 @@ -12071,7 +12023,7 @@ snapshots: '@eslint/eslintrc@2.1.4': dependencies: ajv: 6.12.6 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4(supports-color@5.5.0) espree: 9.6.1 globals: 13.24.0 ignore: 5.3.1 @@ -12394,7 +12346,7 @@ snapshots: '@humanwhocodes/config-array@0.11.14': dependencies: '@humanwhocodes/object-schema': 2.0.3 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4(supports-color@5.5.0) minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -12408,7 +12360,7 @@ snapshots: '@babel/core': 7.24.6 '@babel/generator': 7.24.6 '@babel/parser': 7.24.6 - '@babel/traverse': 7.24.6 + '@babel/traverse': 7.24.6(supports-color@5.5.0) '@babel/types': 7.24.6 prettier: 3.0.3 semver: 7.6.2 @@ -12708,7 +12660,7 @@ snapshots: dependencies: '@ethereumjs/tx': 4.2.0 '@types/debug': 4.1.12 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4(supports-color@5.5.0) semver: 7.6.2 superstruct: 1.0.4 transitivePeerDependencies: @@ -12720,7 +12672,7 @@ snapshots: '@noble/hashes': 1.4.0 '@scure/base': 1.1.6 '@types/debug': 4.1.12 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4(supports-color@5.5.0) pony-cause: 2.1.11 semver: 7.6.2 superstruct: 1.0.4 @@ -12797,7 +12749,7 @@ snapshots: '@open-draft/until': 1.0.3 '@types/debug': 4.1.12 '@xmldom/xmldom': 0.8.10 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4(supports-color@5.5.0) headers-polyfill: 3.2.5 outvariant: 1.4.2 strict-event-emitter: 0.2.8 @@ -13067,7 +13019,7 @@ snapshots: '@puppeteer/browsers@2.2.3': dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4(supports-color@5.5.0) extract-zip: 2.0.1 progress: 2.0.3 proxy-agent: 6.4.0 @@ -13968,7 +13920,7 @@ snapshots: '@truffle/contract-schema@3.4.16': dependencies: ajv: 6.12.6 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4(supports-color@5.5.0) transitivePeerDependencies: - supports-color @@ -13981,7 +13933,7 @@ snapshots: '@truffle/error': 0.2.2 '@truffle/interface-adapter': 0.5.37(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10) bignumber.js: 7.2.1 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4(supports-color@5.5.0) ethers: 4.0.49 web3: 1.10.0(bufferutil@4.0.8)(encoding@0.1.13)(utf-8-validate@5.0.10) web3-core-helpers: 1.10.0 @@ -14000,7 +13952,7 @@ snapshots: '@trufflesuite/chromafi': 3.0.0 bn.js: 5.2.1 chalk: 2.4.2 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4(supports-color@5.5.0) highlightjs-solidity: 2.0.6 transitivePeerDependencies: - supports-color @@ -14276,7 +14228,7 @@ snapshots: '@typescript-eslint/type-utils': 6.21.0(eslint@8.50.0)(typescript@5.4.5) '@typescript-eslint/utils': 6.21.0(eslint@8.50.0)(typescript@5.4.5) '@typescript-eslint/visitor-keys': 6.21.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4(supports-color@5.5.0) eslint: 8.50.0 graphemer: 1.4.0 ignore: 5.3.1 @@ -14294,7 +14246,7 @@ snapshots: '@typescript-eslint/types': 6.21.0 '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.4.5) '@typescript-eslint/visitor-keys': 6.21.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4(supports-color@5.5.0) eslint: 8.50.0 optionalDependencies: typescript: 5.4.5 @@ -14320,7 +14272,7 @@ snapshots: dependencies: '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.4.5) '@typescript-eslint/utils': 6.21.0(eslint@8.50.0)(typescript@5.4.5) - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4(supports-color@5.5.0) eslint: 8.50.0 ts-api-utils: 1.3.0(typescript@5.4.5) optionalDependencies: @@ -14338,7 +14290,7 @@ snapshots: dependencies: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4(supports-color@5.5.0) globby: 11.1.0 is-glob: 4.0.3 semver: 7.6.2 @@ -14352,7 +14304,7 @@ snapshots: dependencies: '@typescript-eslint/types': 6.21.0 '@typescript-eslint/visitor-keys': 6.21.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4(supports-color@5.5.0) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 @@ -14367,7 +14319,7 @@ snapshots: dependencies: '@typescript-eslint/types': 7.10.0 '@typescript-eslint/visitor-keys': 7.10.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4(supports-color@5.5.0) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.4 @@ -15030,7 +14982,7 @@ snapshots: agent-base@7.1.1: dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4(supports-color@5.5.0) transitivePeerDependencies: - supports-color @@ -15335,17 +15287,6 @@ snapshots: transitivePeerDependencies: - '@babel/core' - babel-plugin-styled-components@2.1.4(@babel/core@7.24.6)(styled-components@5.3.11(@babel/core@7.24.6)(react-dom@18.3.1(react@18.3.1))(react-is@18.3.1)(react@18.3.1)): - dependencies: - '@babel/helper-annotate-as-pure': 7.24.6 - '@babel/helper-module-imports': 7.24.6 - '@babel/plugin-syntax-jsx': 7.24.6(@babel/core@7.24.6) - lodash: 4.17.21 - picomatch: 2.3.1 - styled-components: 5.3.11(@babel/core@7.24.6)(react-dom@18.3.1(react@18.3.1))(react-is@18.3.1)(react@18.3.1) - transitivePeerDependencies: - - '@babel/core' - babel-plugin-transform-flow-enums@0.0.2(@babel/core@7.24.6): dependencies: '@babel/plugin-syntax-flow': 7.24.7(@babel/core@7.24.6) @@ -16760,7 +16701,7 @@ snapshots: eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.50.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.50.0): dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4(supports-color@5.5.0) enhanced-resolve: 5.16.1 eslint: 8.50.0 eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.50.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.50.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.50.0))(eslint@8.50.0) @@ -16912,7 +16853,7 @@ snapshots: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4(supports-color@5.5.0) doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 @@ -17420,7 +17361,7 @@ snapshots: follow-redirects@1.15.6(debug@4.3.4): optionalDependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4(supports-color@5.5.0) for-each@0.3.3: dependencies: @@ -17799,7 +17740,7 @@ snapshots: axios: 0.21.4(debug@4.3.4) chalk: 4.1.2 chokidar: 3.6.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4(supports-color@5.5.0) enquirer: 2.4.1 ethers: 5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10) form-data: 4.0.0 @@ -17832,7 +17773,7 @@ snapshots: chalk: 2.4.2 chokidar: 3.6.0 ci-info: 2.0.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4(supports-color@5.5.0) enquirer: 2.4.1 env-paths: 2.2.1 ethereum-cryptography: 1.2.0 @@ -17990,7 +17931,7 @@ snapshots: http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.1 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4(supports-color@5.5.0) transitivePeerDependencies: - supports-color @@ -18015,14 +17956,14 @@ snapshots: https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4(supports-color@5.5.0) transitivePeerDependencies: - supports-color https-proxy-agent@7.0.4: dependencies: agent-base: 7.1.1 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4(supports-color@5.5.0) transitivePeerDependencies: - supports-color @@ -20141,7 +20082,7 @@ snapshots: dependencies: '@puppeteer/browsers': 2.2.3 chromium-bidi: 0.5.19(devtools-protocol@0.0.1286932) - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4(supports-color@5.5.0) devtools-protocol: 0.0.1286932 ws: 8.17.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) transitivePeerDependencies: @@ -20389,11 +20330,6 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - react-transition-state@2.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-universal-interface@0.6.2(react@18.3.1)(tslib@2.6.2): dependencies: react: 18.3.1 @@ -21298,24 +21234,6 @@ snapshots: transitivePeerDependencies: - '@babel/core' - styled-components@5.3.11(@babel/core@7.24.6)(react-dom@18.3.1(react@18.3.1))(react-is@18.3.1)(react@18.3.1): - dependencies: - '@babel/helper-module-imports': 7.24.6 - '@babel/traverse': 7.24.6(supports-color@5.5.0) - '@emotion/is-prop-valid': 1.2.2 - '@emotion/stylis': 0.8.5 - '@emotion/unitless': 0.7.5 - babel-plugin-styled-components: 2.1.4(@babel/core@7.24.6)(styled-components@5.3.11(@babel/core@7.24.6)(react-dom@18.3.1(react@18.3.1))(react-is@18.3.1)(react@18.3.1)) - css-to-react-native: 3.2.0 - hoist-non-react-statics: 3.3.2 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-is: 18.3.1 - shallowequal: 1.1.0 - supports-color: 5.5.0 - transitivePeerDependencies: - - '@babel/core' - styled-jsx@5.1.1(@babel/core@7.24.6)(react@18.3.1): dependencies: client-only: 0.0.1 @@ -21358,7 +21276,7 @@ snapshots: stylelint-processor-styled-components@1.10.0: dependencies: '@babel/parser': 7.24.6 - '@babel/traverse': 7.24.6 + '@babel/traverse': 7.24.6(supports-color@5.5.0) micromatch: 4.0.7 postcss: 7.0.39 transitivePeerDependencies: @@ -21389,7 +21307,7 @@ snapshots: colord: 2.9.3 cosmiconfig: 7.1.0 css-functions-list: 3.2.2 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.4(supports-color@5.5.0) fast-glob: 3.3.2 fastest-levenshtein: 1.0.16 file-entry-cache: 6.0.1 diff --git a/public/locales/en/profile.json b/public/locales/en/profile.json index 7e8a11f42..2e85a2b20 100644 --- a/public/locales/en/profile.json +++ b/public/locales/en/profile.json @@ -305,13 +305,19 @@ "hex": "hex", "decimal": "decimal", "wrapper": "wrapper", + "nameWrapper": "Name Wrapper", + "unwrappedText": " Wrapping your name gives it new features and functionality, however some functionality on your name will change. Please make sure you understand these changes before wrapping your name.", "wrapName": "Wrap Name", - "unwrap": "Unwrap", + "unwrap": "Unwrap Name", + "unwrapWarning": "This name has revoked the permissions needed for this action.", + "tooltip": "The Name Wrapper enables additional functionality on ENS names.", "status": { - "unwrapped": "unwrapped", - "wrapped": "wrapped", - "emancipated": "wrapped, emancipated", - "locked": "wrapped, locked" + "unwrapped": "Unwrapped", + "wrapped": "Wrapped" + }, + "pcc": { + "controllable": "Parent-controllable", + "not-controllable": "Not parent-controllable" } }, "misc": { diff --git a/src/components/@molecules/DisabledButtonWithTooltip.tsx b/src/components/@molecules/DisabledButtonWithTooltip.tsx index b79034645..897dfe690 100644 --- a/src/components/@molecules/DisabledButtonWithTooltip.tsx +++ b/src/components/@molecules/DisabledButtonWithTooltip.tsx @@ -59,6 +59,7 @@ export const DisabledButtonWithTooltip = ({ data-testid={buttonId} width={buttonWidth} loading={loading} + disabled > {buttonText} diff --git a/src/components/@molecules/QuestionTooltip/QuestionTooltip.tsx b/src/components/@molecules/QuestionTooltip/QuestionTooltip.tsx index 6367d11ab..615bbe769 100644 --- a/src/components/@molecules/QuestionTooltip/QuestionTooltip.tsx +++ b/src/components/@molecules/QuestionTooltip/QuestionTooltip.tsx @@ -10,6 +10,8 @@ const IconWrapper = styled.div( height: ${theme.space[4]}; color: ${theme.colors.indigo}; + cursor: pointer; + svg { display: block; } diff --git a/src/components/pages/profile/[name]/tabs/MoreTab/MoreTab.test.tsx b/src/components/pages/profile/[name]/tabs/MoreTab/MoreTab.test.tsx index 67e045be0..5759e5d44 100644 --- a/src/components/pages/profile/[name]/tabs/MoreTab/MoreTab.test.tsx +++ b/src/components/pages/profile/[name]/tabs/MoreTab/MoreTab.test.tsx @@ -59,9 +59,5 @@ describe('MoreTab', () => { renderHelper({ name: 'test', isWrapped: false, ownerData: {} as any }) expect(screen.getByText('Token')).toBeVisible() }) - it('should not show token section if ownerData is undefined', () => { - renderHelper({ name: 'test', isWrapped: false }) - expect(screen.queryByText('Token')).not.toBeInTheDocument() - }) }) }) diff --git a/src/components/pages/profile/[name]/tabs/MoreTab/MoreTab.tsx b/src/components/pages/profile/[name]/tabs/MoreTab/MoreTab.tsx index 566ed4783..38b1b570e 100644 --- a/src/components/pages/profile/[name]/tabs/MoreTab/MoreTab.tsx +++ b/src/components/pages/profile/[name]/tabs/MoreTab/MoreTab.tsx @@ -1,9 +1,12 @@ import styled, { css } from 'styled-components' +import { useAccount } from 'wagmi' import { CacheableComponent } from '@app/components/@atoms/CacheableComponent' import type { useAbilities } from '@app/hooks/abilities/useAbilities' +import { useIsOffchainName } from '@app/hooks/ensjs/dns/useIsOffchainName' import { useNameDetails } from '@app/hooks/useNameDetails' +import { NameWrapper } from './NameWrapper' import Resolver from './Resolver' import Token from './Token/Token' @@ -28,16 +31,27 @@ type Props = { const MoreTab = ({ name, nameDetails, abilities }: Props) => { const { canBeWrapped, ownerData, wrapperData, isWrapped, isCachedData, profile } = nameDetails + const { isConnected, address } = useAccount() + + const isOffchainImport = useIsOffchainName({ + name, + enabled: nameDetails.registrationStatus === 'imported', + }) + return ( - {ownerData && ( - + {(isConnected || isWrapped) && !isOffchainImport && ( + )} ({ default: () =>
})) +vi.mock('./Token/UnwrapButton', () => ({ default: () =>
})) + +describe('NameWrapper', () => { + it('should show wrapped status for unwrapped name', () => { + const name = 'nick.eth' + render( + , + ) + expect(screen.getByTestId('namewrapper-status')).toHaveTextContent( + 'tabs.more.token.status.unwrapped', + ) + }) + it('should show wrapped status for wrapped name', () => { + const name = 'nick.eth' + render( + , + ) + expect(screen.getByTestId('namewrapper-status')).toHaveTextContent( + 'tabs.more.token.status.wrapped', + ) + }) + it('should show wrap button if unwrapped', () => { + const name = 'nick.eth' + render( + , + ) + expect(screen.getByTestId('wrap-button')).toBeVisible() + }) + it('should show unwrap button if wrapped', () => { + const name = 'nick.eth' + render( + , + ) + expect(screen.queryByTestId('unwrap-button')).toBeInTheDocument() + expect(screen.getByTestId('unwrap-button')).toBeVisible() + }) + it('should not show unwrap button if wrapped but not owned', () => { + const name = 'nick.eth' + render( + , + ) + expect(screen.queryByTestId('unwrap-button')).not.toBeInTheDocument() + }) + it('should not show unwrap button if wrapped but disconnected', () => { + const name = 'nick.eth' + render( + , + ) + expect(screen.queryByTestId('unwrap-button')).not.toBeInTheDocument() + }) + it('should show lock icon and disable unwrap button if name is locked', () => { + const name = 'nick.eth' + render( + , + ) + expect(screen.getByTestId('cannot-unwrap-disabled-button')).toBeDisabled() + expect(screen.getByTestId('namewrapper-lock-icon')).toBeVisible() + }) + it('should show PCC record for wrapped names', () => { + render( + , + ) + expect(screen.getByTestId('pcc-status')).toHaveTextContent('tabs.more.token.pcc.controllable') + }) + it('should show PCC for emancipated names', () => { + render( + , + ) + + expect(screen.getByTestId('pcc-status')).toHaveTextContent( + 'tabs.more.token.pcc.not-controllable', + ) + }) + it('should show PCC record for wrapped names when disconnected', () => { + render( + , + ) + expect(screen.getByTestId('pcc-status')).toHaveTextContent('tabs.more.token.pcc.controllable') + }) + it('should show PCC for emancipated names when disconnected', () => { + render( + , + ) + + expect(screen.getByTestId('pcc-status')).toHaveTextContent( + 'tabs.more.token.pcc.not-controllable', + ) + }) +}) diff --git a/src/components/pages/profile/[name]/tabs/MoreTab/NameWrapper.tsx b/src/components/pages/profile/[name]/tabs/MoreTab/NameWrapper.tsx new file mode 100644 index 000000000..cdc89595f --- /dev/null +++ b/src/components/pages/profile/[name]/tabs/MoreTab/NameWrapper.tsx @@ -0,0 +1,192 @@ +import { useTranslation } from 'react-i18next' +import styled, { css } from 'styled-components' +import { match, P } from 'ts-pattern' +import { Address } from 'viem' + +import { GetOwnerReturnType, GetWrapperDataReturnType } from '@ensdomains/ensjs/public' +import { AlertSVG, CheckSVG, LockSVG, mq, Typography } from '@ensdomains/thorin' + +import { cacheableComponentStyles } from '@app/components/@atoms/CacheableComponent' +import { DisabledButtonWithTooltip } from '@app/components/@molecules/DisabledButtonWithTooltip' +import { QuestionTooltip } from '@app/components/@molecules/QuestionTooltip/QuestionTooltip' +import type { NameWrapperState } from '@app/hooks/fuses/useFusesStates' +import type { Profile } from '@app/types' + +import { TabWrapper } from '../../../TabWrapper' +import UnwrapButton from './Token/UnwrapButton' +import WrapButton from './Token/WrapButton' + +type Props = { + name: string + isWrapped: boolean + canBeWrapped: boolean + ownerData?: GetOwnerReturnType + wrapperData?: GetWrapperDataReturnType + profile?: Profile + address?: Address +} + +const Container = styled(TabWrapper)( + cacheableComponentStyles, + ({ theme }) => css` + width: 100%; + display: flex; + flex-direction: column; + align-items: stretch; + justify-content: center; + gap: ${theme.space['4']}; + + padding: ${theme.space['4']}; + + ${mq.sm.min(css` + padding: ${theme.space['6']}; + `)} + `, +) + +const TwoRows = styled.div( + ({ theme }) => css` + display: flex; + flex-direction: row; + gap: ${theme.space['4']}; + justify-content: space-between; + `, +) + +const Record = styled.div( + ({ theme }) => css` + padding: ${theme.space[3]}; + background: ${theme.colors.greenSurface}; + border-radius: ${theme.radii.input}; + width: ${theme.space.full}; + font-weight: ${theme.fontWeights.bold}; + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + + & > svg { + color: ${theme.colors.green}; + } + `, +) + +const ParentControlRecord = styled(Record)<{ $isPCC: boolean }>( + ({ theme, $isPCC }) => css` + background: ${$isPCC ? theme.colors.greenSurface : theme.colors.yellowSurface}; + & > svg { + color: ${$isPCC ? theme.colors.green : theme.colors.yellow}; + } + `, +) + +const HeaderContainer = styled.div` + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; +` + +const Header = styled.div( + ({ theme }) => css` + display: flex; + align-items: center; + gap: ${theme.space[2]}; + `, +) + +const getFuseStateFromWrapperData = (wrapperData?: GetWrapperDataReturnType): NameWrapperState => + match(wrapperData) + .with(P.nullish, () => 'unwrapped' as const) + .with({ fuses: { child: { CANNOT_UNWRAP: true } } }, () => 'locked' as const) + .with({ fuses: { parent: { PARENT_CANNOT_CONTROL: true } } }, () => 'emancipated' as const) + .otherwise(() => 'wrapped') + +export const NameWrapper = ({ + name, + isWrapped, + ownerData, + wrapperData, + canBeWrapped: _canBeWrapped, + profile, + address, +}: Props) => { + const { t } = useTranslation('profile') + + const status = getFuseStateFromWrapperData(wrapperData) + + const isManager = ownerData?.owner === address + const isRegistrant = ownerData?.registrant === address + + const isOwned = ownerData?.ownershipLevel === 'registrar' ? isRegistrant : isManager + + const isButtonDisplayed = isOwned && !!address + + const canBeWrapped = _canBeWrapped && !!address && isOwned + + const isPCC = !!wrapperData?.fuses?.parent?.PARENT_CANNOT_CONTROL + + return ( + + +
+ {t('tabs.more.token.nameWrapper')} + +
+ + {match({ isButtonDisplayed, isWrapped, status }) + .with({ isButtonDisplayed: true, isWrapped: true, status: 'locked' }, () => ( + + )) + .with({ isButtonDisplayed: true, isWrapped: true }, () => ( + + )) + .with({ isButtonDisplayed: true, isWrapped: false }, () => ( + + )) + .with({ isButtonDisplayed: false, isWrapped: false }, () => null) + .otherwise(() => null)} +
+ + {match({ ownedAndCanWrap: isOwned && canBeWrapped, isWrapped }) + .with({ ownedAndCanWrap: true }, () => <>{t('tabs.more.token.unwrappedText')}) + .with({ ownedAndCanWrap: false, isWrapped: true }, () => ( + + + {t('tabs.more.token.status.wrapped')} + {status === 'locked' ? ( + + ) : ( + + )} + + + {isPCC ? ( + <> + {t('tabs.more.token.pcc.not-controllable')} + + ) : ( + <> + {t('tabs.more.token.pcc.controllable')} + + )} + + + )) + .with({ ownedAndCanWrap: false, isWrapped: false }, () => ( + + + {t('tabs.more.token.status.unwrapped')} + + + )) + .otherwise(() => null)} +
+ ) +} diff --git a/src/components/pages/profile/[name]/tabs/MoreTab/Token/BaseWrapButton.tsx b/src/components/pages/profile/[name]/tabs/MoreTab/Token/BaseWrapButton.tsx index 2e2cecd5c..b6afcd266 100644 --- a/src/components/pages/profile/[name]/tabs/MoreTab/Token/BaseWrapButton.tsx +++ b/src/components/pages/profile/[name]/tabs/MoreTab/Token/BaseWrapButton.tsx @@ -12,8 +12,8 @@ const StyledWrapButton = styled(Button)( `, ) -const BaseWrapButton = forwardRef( - ({ children, ...props }: ComponentProps, ref) => { +const BaseWrapButton = forwardRef>( + ({ children, ...props }, ref) => { return ( {children} diff --git a/src/components/pages/profile/[name]/tabs/MoreTab/Token/Token.test.tsx b/src/components/pages/profile/[name]/tabs/MoreTab/Token/Token.test.tsx index 9aedeb83b..814488630 100644 --- a/src/components/pages/profile/[name]/tabs/MoreTab/Token/Token.test.tsx +++ b/src/components/pages/profile/[name]/tabs/MoreTab/Token/Token.test.tsx @@ -8,7 +8,7 @@ import { useContractAddress } from '@app/hooks/chain/useContractAddress' import { useParentBasicName } from '@app/hooks/useParentBasicName' import { useBreakpoint } from '@app/utils/BreakpointProvider' -import { makeMockUseWrapperDataData } from '../../../../../../../../test/mock/makeMockUseWrapperDataData.ts' +import { makeMockUseWrapperDataData } from '@root/test/mock/makeMockUseWrapperDataData.ts' import Token from './Token' vi.mock('@app/hooks/useParentBasicName') @@ -36,66 +36,6 @@ mockUseParentBasicName.mockImplementation(() => { }) describe('Token', () => { - it('should show wrapped status for unwrapped name', () => { - const name = 'nick.eth' - render( - , - ) - expect(screen.getByTestId('name-details-text-tabs.more.token.wrapper')).toHaveTextContent( - 'tabs.more.token.status.unwrapped', - ) - }) - it('should show wrapped status for wrapped name', () => { - const name = 'nick.eth' - render( - , - ) - expect(screen.getByTestId('name-details-text-tabs.more.token.wrapper')).toHaveTextContent( - 'tabs.more.token.status.wrapped', - ) - }) - it('should show wrapped status for emancipated name', () => { - const name = 'nick.eth' - render( - , - ) - expect(screen.getByTestId('name-details-text-tabs.more.token.wrapper')).toHaveTextContent( - 'tabs.more.token.status.emancipated', - ) - }) - it('should show wrapped status for locked name', () => { - const name = 'nick.eth' - render( - , - ) - expect(screen.getByTestId('name-details-text-tabs.more.token.wrapper')).toHaveTextContent( - 'tabs.more.token.status.locked', - ) - }) - it('should show wrap button if unwrapped', () => { - const name = 'nick.eth' - render() - expect(screen.getByTestId('wrap-button')).toBeVisible() - }) - it('should show unwrap button if wrapped', () => { - const name = 'nick.eth' - render( - , - ) - expect(screen.getByTestId('unwrap-button')).toBeVisible() - }) describe('tokenids', () => { it('should not show tokenid section for unwrapped non .eth 2ld', () => { const name = 'sub.nick.eth' diff --git a/src/components/pages/profile/[name]/tabs/MoreTab/Token/Token.tsx b/src/components/pages/profile/[name]/tabs/MoreTab/Token/Token.tsx index 1ef167c13..95d72bf51 100644 --- a/src/components/pages/profile/[name]/tabs/MoreTab/Token/Token.tsx +++ b/src/components/pages/profile/[name]/tabs/MoreTab/Token/Token.tsx @@ -1,9 +1,7 @@ import { useTranslation } from 'react-i18next' import styled, { css } from 'styled-components' -import { match, P } from 'ts-pattern' import { labelhash, namehash } from 'viem' -import { GetOwnerReturnType, GetWrapperDataReturnType } from '@ensdomains/ensjs/public' import { mq, Tag, Typography } from '@ensdomains/thorin' import { CacheableComponent } from '@app/components/@atoms/CacheableComponent' @@ -12,21 +10,13 @@ import { Outlink } from '@app/components/Outlink' import RecordItem from '@app/components/RecordItem' import { useChainName } from '@app/hooks/chain/useChainName' import { useContractAddress } from '@app/hooks/chain/useContractAddress' -import { NameWrapperState } from '@app/hooks/fuses/useFusesStates' -import { Profile } from '@app/types' import { checkETH2LDFromName, makeEtherscanLink } from '@app/utils/utils' import { TabWrapper } from '../../../../TabWrapper' -import UnwrapButton from './UnwrapButton' -import WrapButton from './WrapButton' type Props = { name: string isWrapped: boolean - canBeWrapped: boolean - ownerData?: GetOwnerReturnType - wrapperData?: GetWrapperDataReturnType - profile: Profile | undefined } const Container = styled(TabWrapper)( @@ -114,21 +104,13 @@ const NftBox = styled(NFTWithPlaceholder)( `, ) -const getFuseStateFromWrapperData = (wrapperData?: GetWrapperDataReturnType): NameWrapperState => - match(wrapperData) - .with(P.nullish, () => 'unwrapped' as const) - .with({ fuses: { child: { CANNOT_UNWRAP: true } } }, () => 'locked' as const) - .with({ fuses: { parent: { PARENT_CANNOT_CONTROL: true } } }, () => 'emancipated' as const) - .otherwise(() => 'wrapped') - -const Token = ({ name, isWrapped, canBeWrapped, ownerData, wrapperData, profile }: Props) => { +const Token = ({ name, isWrapped }: Props) => { const { t } = useTranslation('profile') const networkName = useChainName() const nameWrapperAddress = useContractAddress({ contract: 'ensNameWrapper' }) const registrarAddress = useContractAddress({ contract: 'ensBaseRegistrarImplementation' }) - const status: NameWrapperState = getFuseStateFromWrapperData(wrapperData) const is2ldEth = checkETH2LDFromName(name) const hex = isWrapped ? namehash(name) : labelhash(name.split('.')[0]) @@ -162,23 +144,6 @@ const Token = ({ name, isWrapped, canBeWrapped, ownerData, wrapperData, profile )} - - - {isWrapped ? ( - - ) : ( - - )} - ) } diff --git a/src/components/pages/profile/[name]/tabs/MoreTab/Token/UnwrapButton.tsx b/src/components/pages/profile/[name]/tabs/MoreTab/Token/UnwrapButton.tsx index 50846324a..fedbb1c7e 100644 --- a/src/components/pages/profile/[name]/tabs/MoreTab/Token/UnwrapButton.tsx +++ b/src/components/pages/profile/[name]/tabs/MoreTab/Token/UnwrapButton.tsx @@ -13,9 +13,10 @@ type Props = { name: string ownerData: GetOwnerReturnType | undefined status: NameWrapperState + disabled?: boolean } -const UnwrapButton = ({ name, ownerData, status }: Props) => { +const UnwrapButton = ({ name, ownerData, status, disabled }: Props) => { const { t } = useTranslation('profile') const { address } = useAccountSafely() @@ -31,7 +32,7 @@ const UnwrapButton = ({ name, ownerData, status }: Props) => { if (!canBeUnwrapped) return null return ( - + {t('tabs.more.token.unwrap')} ) diff --git a/src/components/pages/profile/[name]/tabs/MoreTab/Token/WrapButton.test.tsx b/src/components/pages/profile/[name]/tabs/MoreTab/Token/WrapButton.test.tsx index bbfb1a9be..f6577caed 100644 --- a/src/components/pages/profile/[name]/tabs/MoreTab/Token/WrapButton.test.tsx +++ b/src/components/pages/profile/[name]/tabs/MoreTab/Token/WrapButton.test.tsx @@ -65,6 +65,8 @@ describe('WrapButton', () => { canBeWrapped ownerData={{ owner: '0x123' } as any} profile={{ resolverAddress: '0x456' } as any} + isManager={false} + isRegistrant={false} />, ) expect(screen.getByTestId('wrap-name-btn')).toBeVisible() @@ -77,8 +79,7 @@ describe('WrapButton', () => { name="test123.eth" canBeWrapped={false} ownerData={{ owner: '0x123' } as any} - profile={{ resolverAddress: '0x456' } as any} - />, + profile={{ resolverAddress: '0x456' } as any} isManager={false} isRegistrant={false} />, ) expect(screen.queryByTestId('wrap-name-btn')).toBeNull() }) @@ -89,8 +90,7 @@ describe('WrapButton', () => { name="test123.eth" canBeWrapped ownerData={{ owner: '0x123' } as any} - profile={{ resolverAddress: '0x456' } as any} - />, + profile={{ resolverAddress: '0x456' } as any} isManager={false} isRegistrant={false} />, ) screen.getByTestId('wrap-name-btn').click() expect(mockCreateTransactionFlow).toHaveBeenCalled() @@ -104,25 +104,22 @@ describe('WrapButton', () => { name="test123.eth" canBeWrapped ownerData={{ owner: '0x123' } as any} - profile={ - { - resolverAddress: '0x456', - records: { - coinTypes: [ - { - key: 'coin1', - }, - { - key: 'coin2', - }, - ], - }, - } as any - } - />, + profile={{ + resolverAddress: '0x456', + records: { + coinTypes: [ + { + key: 'coin1', + }, + { + key: 'coin2', + }, + ], + }, + } as any} isManager={true} isRegistrant={false} />, ) screen.getByTestId('wrap-name-btn').click() - const args = mockCreateTransactionFlow.mock.lastCall + const args = mockCreateTransactionFlow.mock.lastCall! expect(args[0]).toBe('wrapName-test123.eth') expect(args[1].transactions[0].name).toEqual('migrateProfile') @@ -136,25 +133,22 @@ describe('WrapButton', () => { name="test123.eth" canBeWrapped ownerData={{ owner: '0x123' } as any} - profile={ - { - resolverAddress: '0x231b0Ee14048e9dCcD1d247744d114a4EB5E8E63', - records: { - coinTypes: [ - { - key: 'coin1', - }, - { - key: 'coin2', - }, - ], - }, - } as any - } - />, + profile={{ + resolverAddress: '0x231b0Ee14048e9dCcD1d247744d114a4EB5E8E63', + records: { + coinTypes: [ + { + key: 'coin1', + }, + { + key: 'coin2', + }, + ], + }, + } as any} isManager={false} isRegistrant={false} />, ) screen.getByTestId('wrap-name-btn').click() - const args = mockCreateTransactionFlow.mock.lastCall + const args = mockCreateTransactionFlow.mock.lastCall! expect(args[0]).toBe('wrapName-test123.eth') expect(args[1].transactions[0].name).toEqual('wrapName') @@ -167,16 +161,13 @@ describe('WrapButton', () => { name="test123.eth" canBeWrapped ownerData={{ owner: '0x123' } as any} - profile={ - { - resolverAddress: '0x456', - records: {}, - } as any - } - />, + profile={{ + resolverAddress: '0x456', + records: {}, + } as any} isManager={false} isRegistrant={false} />, ) screen.getByTestId('wrap-name-btn').click() - const args = mockCreateTransactionFlow.mock.lastCall + const args = mockCreateTransactionFlow.mock.lastCall! expect(args[0]).toBe('wrapName-test123.eth') expect(args[1].transactions[0].name).toEqual('wrapName') @@ -191,25 +182,22 @@ describe('WrapButton', () => { name="test123.eth" canBeWrapped ownerData={{ ownershipLevel: 'registrar', owner: '0x124', registrant: '0x123' }} - profile={ - { - resolverAddress: '0x456', - records: { - coinTypes: [ - { - key: 'coin1', - }, - { - key: 'coin2', - }, - ], - }, - } as any - } - />, + profile={{ + resolverAddress: '0x456', + records: { + coinTypes: [ + { + key: 'coin1', + }, + { + key: 'coin2', + }, + ], + }, + } as any} isManager={false} isRegistrant={true} />, ) screen.getByTestId('wrap-name-btn').click() - const args = mockCreateTransactionFlow.mock.lastCall + const args = mockCreateTransactionFlow.mock.lastCall! expect(args[0]).toBe('wrapName-test123.eth') expect(args[1].transactions[0].name).toEqual('wrapName') @@ -223,25 +211,22 @@ describe('WrapButton', () => { name="test123.eth" canBeWrapped ownerData={{ ownershipLevel: 'registrar', owner: '0x124', registrant: '0x123' }} - profile={ - { - resolverAddress: '0x231b0Ee14048e9dCcD1d247744d114a4EB5E8E63', - records: { - coinTypes: [ - { - key: 'coin1', - }, - { - key: 'coin2', - }, - ], - }, - } as any - } - />, + profile={{ + resolverAddress: '0x231b0Ee14048e9dCcD1d247744d114a4EB5E8E63', + records: { + coinTypes: [ + { + key: 'coin1', + }, + { + key: 'coin2', + }, + ], + }, + } as any} isManager={false} isRegistrant={false} />, ) screen.getByTestId('wrap-name-btn').click() - const args = mockCreateTransactionFlow.mock.lastCall + const args = mockCreateTransactionFlow.mock.lastCall! expect(args[0]).toBe('wrapName-test123.eth') expect(args[1].transactions[0].name).toEqual('wrapName') @@ -259,16 +244,13 @@ describe('WrapButton', () => { name="sub.test123.eth" canBeWrapped ownerData={{ owner: '0x123' } as any} - profile={ - { - resolverAddress: '0x456', - records: {}, - } as any - } - />, + profile={{ + resolverAddress: '0x456', + records: {}, + } as any} isManager={true} isRegistrant={false} />, ) screen.getByTestId('wrap-name-btn').click() - const args = mockCreateTransactionFlow.mock.lastCall + const args = mockCreateTransactionFlow.mock.lastCall! expect(args[0]).toBe('wrapName-sub.test123.eth') expect(args[1].transactions[0].name).toEqual('approveNameWrapper') @@ -286,16 +268,13 @@ describe('WrapButton', () => { name="sub.test123.eth" canBeWrapped ownerData={{ owner: '0x123' } as any} - profile={ - { - resolverAddress: '0x456', - records: {}, - } as any - } - />, + profile={{ + resolverAddress: '0x456', + records: {}, + } as any} isManager={false} isRegistrant={false} />, ) screen.getByTestId('wrap-name-btn').click() - const args = mockCreateTransactionFlow.mock.lastCall + const args = mockCreateTransactionFlow.mock.lastCall! expect(args[0]).toBe('wrapName-sub.test123.eth') expect(args[1].transactions[0].name).toEqual('wrapName') @@ -311,25 +290,22 @@ describe('WrapButton', () => { name="sub.test123.eth" canBeWrapped ownerData={{ owner: '0x123' } as any} - profile={ - { - resolverAddress: '0x456', - records: { - coinTypes: [ - { - key: 'coin1', - }, - { - key: 'coin2', - }, - ], - }, - } as any - } - />, + profile={{ + resolverAddress: '0x456', + records: { + coinTypes: [ + { + key: 'coin1', + }, + { + key: 'coin2', + }, + ], + }, + } as any} isManager={true} isRegistrant={false} />, ) screen.getByTestId('wrap-name-btn').click() - const args = mockCreateTransactionFlow.mock.lastCall + const args = mockCreateTransactionFlow.mock.lastCall! expect(args[0]).toBe('wrapName-sub.test123.eth') expect(args[1].transactions[0].name).toEqual('migrateProfile') @@ -345,8 +321,7 @@ describe('WrapButton', () => { name="test123.eth" canBeWrapped ownerData={{ owner: '0x123' } as any} - profile={{ resolverAddress: '0x456' } as any} - />, + profile={{ resolverAddress: '0x456' } as any} isManager={false} isRegistrant={false} />, ) screen.getByTestId('wrap-name-btn').click() expect(mockResumeTransactionFlow).toHaveBeenCalled() @@ -366,14 +341,13 @@ describe('WrapButton', () => { name="[b2fd3233fdc544d81e84c93822934ddd9b599f056b6a7f84f4de29378bf1cb15].test123.eth" canBeWrapped ownerData={{ owner: '0x123' } as any} - profile={{ resolverAddress: '0x456', records: {} } as any} - />, + profile={{ resolverAddress: '0x456', records: {} } as any} isManager={true} isRegistrant={false} />, ) screen.getByTestId('wrap-name-btn').click() expect(mockCreateTransactionFlow).not.toHaveBeenCalled() expect(mockShowDataInput).toHaveBeenCalled() - const args = mockShowDataInput.mock.lastCall + const args = mockShowDataInput.mock.lastCall! expect(args[0]).toBe( // eslint-disable-next-line no-restricted-syntax 'wrapName-[b2fd3233fdc544d81e84c93822934ddd9b599f056b6a7f84f4de29378bf1cb15].test123.eth', @@ -400,8 +374,7 @@ describe('WrapButton', () => { name="sub.test123.eth" canBeWrapped ownerData={{ owner: '0x123', ownershipLevel: 'registrar', registrant: '0x123' } as any} - profile={{ resolverAddress: '0x456' } as any} - />, + profile={{ resolverAddress: '0x456' } as any} isManager={false} isRegistrant={false} />, ) expect( mockUseWrapperApprovedForAll.mock.calls[mockUseWrapperApprovedForAll.mock.calls.length - 1], diff --git a/src/components/pages/profile/[name]/tabs/MoreTab/Token/WrapButton.tsx b/src/components/pages/profile/[name]/tabs/MoreTab/Token/WrapButton.tsx index 8762e8d44..f442f69b7 100644 --- a/src/components/pages/profile/[name]/tabs/MoreTab/Token/WrapButton.tsx +++ b/src/components/pages/profile/[name]/tabs/MoreTab/Token/WrapButton.tsx @@ -20,9 +20,11 @@ type Props = { canBeWrapped: boolean ownerData: GetOwnerReturnType | undefined profile: Profile | undefined + isManager: boolean + isRegistrant: boolean } -const WrapButton = ({ name, ownerData, profile, canBeWrapped }: Props) => { +const WrapButton = ({ name, ownerData, profile, canBeWrapped, isManager, isRegistrant }: Props) => { const { t } = useTranslation('profile') const { data: hasGraphError, isLoading: hasGraphErrorLoading } = useHasGraphError() @@ -30,23 +32,16 @@ const WrapButton = ({ name, ownerData, profile, canBeWrapped }: Props) => { const resolverStatus = useResolverStatus({ name }) const hasOwnerData = !!ownerData - const isManager = ownerData?.owner === address - const isRegistrant = ownerData?.registrant === address const shouldMigrate = !resolverStatus.data?.isMigratedProfileEqual && !resolverStatus.data?.isNameWrapperAware const resolverAddress = profile?.resolverAddress - const _canBeWrapped = - canBeWrapped && - !!address && - (ownerData?.ownershipLevel === 'registrar' ? isRegistrant : isManager) - const isSubname = name.split('.').length > 2 const { data: approvedForAll, isLoading: isApprovalLoading } = useWrapperApprovedForAll({ address: address!, isSubname, - canBeWrapped: _canBeWrapped, + canBeWrapped, }) const { createTransactionFlow, resumeTransactionFlow, getResumable, usePreparedDataInput } = @@ -106,7 +101,7 @@ const WrapButton = ({ name, ownerData, profile, canBeWrapped }: Props) => { const isLoading = isApprovalLoading || resolverStatus.isLoading || hasGraphErrorLoading - if (!_canBeWrapped || hasGraphError) return null + if (!canBeWrapped || hasGraphError) return null return (