diff --git a/packages/browser-wallet/src/assets/svgX/code.svg b/packages/browser-wallet/src/assets/svgX/code.svg
new file mode 100644
index 000000000..175f796f9
--- /dev/null
+++ b/packages/browser-wallet/src/assets/svgX/code.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/browser-wallet/src/popup/popupX/constants/routes.ts b/packages/browser-wallet/src/popup/popupX/constants/routes.ts
index 4342f3748..2e3258e94 100644
--- a/packages/browser-wallet/src/popup/popupX/constants/routes.ts
+++ b/packages/browser-wallet/src/popup/popupX/constants/routes.ts
@@ -90,6 +90,15 @@ export const relativeRoutes = {
},
token: {
path: 'token',
+ ccd: {
+ path: 'ccd',
+ },
+ details: {
+ path: ':contractIndex',
+ raw: {
+ path: 'raw',
+ },
+ },
},
submittedTransaction: {
path: 'submitted/:transactionHash',
@@ -157,6 +166,15 @@ export const relativeRoutes = {
},
},
},
+ nft: {
+ path: 'nft',
+ details: {
+ path: ':contractIndex/:id/details',
+ raw: {
+ path: 'raw',
+ },
+ },
+ },
/** Routes related to staking for the currently selected account */
earn: {
path: 'earn',
diff --git a/packages/browser-wallet/src/popup/popupX/page-layouts/MainLayout/Header/components/MenuTiles.tsx b/packages/browser-wallet/src/popup/popupX/page-layouts/MainLayout/Header/components/MenuTiles.tsx
index 386503bd0..0430413e2 100644
--- a/packages/browser-wallet/src/popup/popupX/page-layouts/MainLayout/Header/components/MenuTiles.tsx
+++ b/packages/browser-wallet/src/popup/popupX/page-layouts/MainLayout/Header/components/MenuTiles.tsx
@@ -9,6 +9,7 @@ import LinkSimple from '@assets/svgX/link-simple-horizontal.svg';
import Info from '@assets/svgX/info2.svg';
import Restore from '@assets/svgX/arrow-counter-clock.svg';
import Eye from '@assets/svgX/eye.svg';
+import NFT from '@assets/svgX/cube-focus.svg';
import IconButton from '@popup/shared/IconButton';
import Text from '@popup/popupX/shared/Text';
import { Link } from 'react-router-dom';
@@ -101,6 +102,12 @@ export default function MenuTiles({ menuOpen, setMenuOpen }: MenuTilesProps) {
{t('oldUI')}
+
+
+
+ {t('nft')}
+
+
);
diff --git a/packages/browser-wallet/src/popup/popupX/page-layouts/MainLayout/Header/i18n/en.ts b/packages/browser-wallet/src/popup/popupX/page-layouts/MainLayout/Header/i18n/en.ts
index 71ead420c..09cbbd344 100644
--- a/packages/browser-wallet/src/popup/popupX/page-layouts/MainLayout/Header/i18n/en.ts
+++ b/packages/browser-wallet/src/popup/popupX/page-layouts/MainLayout/Header/i18n/en.ts
@@ -10,6 +10,7 @@ const t = {
about: 'About',
restore: 'Restore',
oldUI: 'Old UI',
+ nft: 'NFT',
},
accountSelector: {
sortAsc: 'Sort A-Z',
diff --git a/packages/browser-wallet/src/popup/popupX/pages/MainPage/MainPage.tsx b/packages/browser-wallet/src/popup/popupX/pages/MainPage/MainPage.tsx
index f1900613a..b0ee063d5 100644
--- a/packages/browser-wallet/src/popup/popupX/pages/MainPage/MainPage.tsx
+++ b/packages/browser-wallet/src/popup/popupX/pages/MainPage/MainPage.tsx
@@ -4,7 +4,7 @@ import { useTranslation } from 'react-i18next';
import { useAtomValue } from 'jotai';
import { displayAsCcd } from 'wallet-common-helpers';
import { AccountInfoType, Ratio } from '@concordium/web-sdk';
-import { relativeRoutes } from '@popup/popupX/constants/routes';
+import { absoluteRoutes, relativeRoutes } from '@popup/popupX/constants/routes';
import Img from '@popup/shared/Img';
import { WalletCredential } from '@shared/storage/types';
import { useAccountInfo } from '@popup/shared/AccountInfoListenerContext';
@@ -122,7 +122,9 @@ function MainPage({ credential }: MainPageProps) {
const navToReceive = () => nav(relativeRoutes.home.receive.path);
const navToTransactionLog = () =>
nav(relativeRoutes.home.transactionLog.path.replace(':account', credential.address));
- const navToTokenDetails = () => nav(relativeRoutes.home.token.path);
+ const navToTokenDetails = (contractIndex: string) => {
+ return nav(absoluteRoutes.home.token.details.path.replace(':contractIndex', contractIndex));
+ };
const navToManageToken = () => nav(relativeRoutes.home.manageTokenList.path);
const chainParameters = useBlockChainParameters();
@@ -151,7 +153,7 @@ function MainPage({ credential }: MainPageProps) {
nav(`${relativeRoutes.home.token.path}/ccd`)}
+ onClick={() => nav(`${absoluteRoutes.home.token.ccd.path}`)}
thumbnail={}
symbol="CCD"
staked={isStaked}
@@ -161,7 +163,7 @@ function MainPage({ credential }: MainPageProps) {
/>
{tokens.map((token) => (
navToTokenDetails()}
+ onClick={() => navToTokenDetails(token.contractIndex)}
key={`${token.contractIndex}.${token.id}`}
thumbnail={token.metadata.thumbnail?.url || ''}
symbol={token.metadata.symbol || ''}
diff --git a/packages/browser-wallet/src/popup/popupX/pages/Nft/Nft.scss b/packages/browser-wallet/src/popup/popupX/pages/Nft/Nft.scss
new file mode 100644
index 000000000..6683037c9
--- /dev/null
+++ b/packages/browser-wallet/src/popup/popupX/pages/Nft/Nft.scss
@@ -0,0 +1,87 @@
+.nft-x {
+ .owner {
+ display: flex;
+ justify-content: space-between;
+
+ .label__main {
+ color: $color-white;
+ }
+ }
+
+ &__list {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-between;
+ gap: rem(7px);
+ margin-top: rem(8px);
+
+ &_item {
+ display: flex;
+ flex-direction: column;
+ width: rem(160px);
+ height: rem(192px);
+ padding: rem(8px) rem(8px) rem(16px) rem(8px);
+ border: unset;
+ border-radius: rem(12px);
+ background-color: $color-transaction-bg;
+
+ &-img {
+ width: 100%;
+ border-radius: rem(8px);
+ }
+
+ .text__main_regular {
+ width: 100%;
+ margin-top: rem(8px);
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ text-align: left;
+ }
+ }
+ }
+}
+
+.nft-details-x {
+ .page__top_side {
+ .button__icon {
+ svg {
+ height: rem(16px);
+ width: rem(16px);
+ }
+
+ &:last-of-type {
+ svg path {
+ fill: $color-red-attention;
+ }
+ }
+ }
+ }
+
+ .info-row {
+ display: flex;
+ justify-content: space-between;
+ padding: rem(4px) 0;
+ border-bottom: 1px solid $color-grey-3;
+
+ &:nth-child(3) {
+ border-bottom: unset;
+ }
+
+ .capture__main_small:last-child {
+ color: $color-white;
+ }
+ }
+
+ .details-img {
+ margin-top: rem(12px);
+ margin-bottom: rem(16px);
+ border-radius: rem(16px);
+ }
+}
+
+.nft-raw-x {
+ .row.details .capture__main_small:first-child {
+ text-transform: capitalize;
+ }
+}
diff --git a/packages/browser-wallet/src/popup/popupX/pages/Nft/Nft.tsx b/packages/browser-wallet/src/popup/popupX/pages/Nft/Nft.tsx
new file mode 100644
index 000000000..f6110af61
--- /dev/null
+++ b/packages/browser-wallet/src/popup/popupX/pages/Nft/Nft.tsx
@@ -0,0 +1,66 @@
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import Page from '@popup/popupX/shared/Page';
+import Text from '@popup/popupX/shared/Text';
+import Button from '@popup/popupX/shared/Button';
+import { displayNameAndSplitAddress, useSelectedCredential } from '@popup/shared/utils/account-helpers';
+import Img from '@popup/shared/Img';
+import { WalletCredential } from '@shared/storage/types';
+import { useFlattenedAccountTokens } from '@popup/pages/Account/Tokens/utils';
+import { getMetadataUnique } from '@shared/utils/token-helpers';
+import { useNavigate } from 'react-router-dom';
+import { relativeRoutes } from '@popup/popupX/constants/routes';
+
+function useFilteredTokens(account: WalletCredential, unique: boolean) {
+ const tokens = useFlattenedAccountTokens(account);
+ return tokens.filter((t) => getMetadataUnique(t.metadata) === unique);
+}
+
+function NftList({ account }: { account: WalletCredential }) {
+ const tokens = useFilteredTokens(account, true);
+ const nav = useNavigate();
+ const navToDetails = (contractIndex: string, id: string) =>
+ nav(relativeRoutes.settings.nft.details.path.replace(':contractIndex', contractIndex).replace(':id', id));
+
+ return (
+
+ {tokens.map(({ contractIndex, id, metadata }) => (
+
navToDetails(contractIndex, id)}
+ className="nft-x__list_item"
+ >
+
+ {metadata.name}
+
+ ))}
+
+ );
+}
+
+export default function Nft() {
+ const { t } = useTranslation('x', { keyPrefix: 'nft' });
+ const account = useSelectedCredential();
+
+ if (account === undefined) {
+ return null;
+ }
+
+ return (
+
+
+
+
+ {t('owned')}
+ {t('on', { value: displayNameAndSplitAddress(account) })}
+
+
+
+
+ );
+}
diff --git a/packages/browser-wallet/src/popup/popupX/pages/Nft/NftDetails.tsx b/packages/browser-wallet/src/popup/popupX/pages/Nft/NftDetails.tsx
new file mode 100644
index 000000000..67cc4ee79
--- /dev/null
+++ b/packages/browser-wallet/src/popup/popupX/pages/Nft/NftDetails.tsx
@@ -0,0 +1,90 @@
+import React from 'react';
+import Page from '@popup/popupX/shared/Page';
+import { useTranslation } from 'react-i18next';
+import { useNavigate, useParams } from 'react-router-dom';
+import { withSelectedCredential } from '@popup/popupX/shared/utils/hoc';
+import { WalletCredential } from '@shared/storage/types';
+import { useFlattenedAccountTokens } from '@popup/pages/Account/Tokens/utils';
+import Button from '@popup/popupX/shared/Button';
+import Code from '@assets/svgX/code.svg';
+import EyeSlash from '@assets/svgX/eye-slash.svg';
+import Text from '@popup/popupX/shared/Text';
+import Img from '@popup/shared/Img';
+import { contractBalancesFamily, removeTokenFromCurrentAccountAtom } from '@popup/store/token';
+import { useAtomValue } from 'jotai';
+import { useUpdateAtom } from 'jotai/utils';
+import { relativeRoutes } from '@popup/popupX/constants/routes';
+
+const SUB_INDEX = '0';
+
+type Params = {
+ contractIndex: string;
+ id: string;
+};
+
+function useSelectedToken(credential: WalletCredential) {
+ const { contractIndex, id } = useParams();
+ const token = useFlattenedAccountTokens(credential).find((t) => t.contractIndex === contractIndex && t.id === id);
+ return token;
+}
+
+function useRemoveToken() {
+ const { contractIndex, id } = useParams();
+ const nav = useNavigate();
+ const removeToken = useUpdateAtom(removeTokenFromCurrentAccountAtom);
+ if (!contractIndex || !id) return () => {};
+
+ return () => {
+ removeToken({ contractIndex, tokenId: id });
+ nav(-1);
+ };
+}
+
+type InfoRowProps = {
+ title: string;
+ value?: string;
+};
+
+function InfoRow({ title, value }: InfoRowProps) {
+ return (
+
+ {title}
+ {value}
+
+ );
+}
+
+function NftDetails({ credential }: { credential: WalletCredential }) {
+ const nav = useNavigate();
+ const { t } = useTranslation('x', { keyPrefix: 'nft' });
+ const token = useSelectedToken(credential);
+ const removeToken = useRemoveToken();
+ const { contractIndex, id, metadata } = token || { id: '', contractIndex: '' };
+ const balancesAtom = contractBalancesFamily(credential?.address ?? '', token?.contractIndex ?? '');
+ const balance = useAtomValue(balancesAtom)[id];
+
+ const navToRaw = () => nav(relativeRoutes.settings.nft.details.raw.path);
+
+ return (
+
+
+ } onClick={navToRaw} />
+ } onClick={removeToken} />
+
+
+
+
+
+
+ {metadata?.description}
+
+
+ );
+}
+
+export default withSelectedCredential(NftDetails);
diff --git a/packages/browser-wallet/src/popup/popupX/pages/Nft/NftRaw.tsx b/packages/browser-wallet/src/popup/popupX/pages/Nft/NftRaw.tsx
new file mode 100644
index 000000000..3492af4d1
--- /dev/null
+++ b/packages/browser-wallet/src/popup/popupX/pages/Nft/NftRaw.tsx
@@ -0,0 +1,48 @@
+import React from 'react';
+import Page from '@popup/popupX/shared/Page';
+import { WalletCredential } from '@shared/storage/types';
+import { useParams } from 'react-router-dom';
+import { useFlattenedAccountTokens } from '@popup/pages/Account/Tokens/utils';
+import { withSelectedCredential } from '@popup/popupX/shared/utils/hoc';
+import { useTranslation } from 'react-i18next';
+import Button from '@popup/popupX/shared/Button';
+import Copy from '@assets/svgX/copy.svg';
+import { copyToClipboard } from '@popup/popupX/shared/utils/helpers';
+import Card from '@popup/popupX/shared/Card';
+
+type Params = {
+ contractIndex: string;
+ id: string;
+};
+
+function useSelectedToken(credential: WalletCredential) {
+ const { contractIndex, id } = useParams();
+ const token = useFlattenedAccountTokens(credential).find((t) => t.contractIndex === contractIndex && t.id === id);
+ return token;
+}
+
+function NftRaw({ credential }: { credential: WalletCredential }) {
+ const { t } = useTranslation('x', { keyPrefix: 'nft' });
+ const token = useSelectedToken(credential);
+ const metadata = token?.metadata || {};
+
+ return (
+
+
+ }
+ onClick={() => copyToClipboard(JSON.stringify(token?.metadata, null, 2))}
+ />
+
+
+
+ {Object.entries(metadata).map(([k, v]) => (
+
+ ))}
+
+
+
+ );
+}
+
+export default withSelectedCredential(NftRaw);
diff --git a/packages/browser-wallet/src/popup/popupX/pages/Nft/i18n/en.ts b/packages/browser-wallet/src/popup/popupX/pages/Nft/i18n/en.ts
new file mode 100644
index 000000000..a0f9b060f
--- /dev/null
+++ b/packages/browser-wallet/src/popup/popupX/pages/Nft/i18n/en.ts
@@ -0,0 +1,13 @@
+const t = {
+ nft: 'NFT',
+ owned: 'Owned by me',
+ on: 'on {{value}}',
+ ownership: 'Ownership',
+ contract: 'Contract index, subindex',
+ tokenId: 'TokenID',
+ unownedUnique: 'Not owned',
+ ownedUnique: 'Owned',
+ rawMetadata: 'Raw Metadata',
+};
+
+export default t;
diff --git a/packages/browser-wallet/src/popup/popupX/pages/Nft/index.ts b/packages/browser-wallet/src/popup/popupX/pages/Nft/index.ts
new file mode 100644
index 000000000..297e7f451
--- /dev/null
+++ b/packages/browser-wallet/src/popup/popupX/pages/Nft/index.ts
@@ -0,0 +1,3 @@
+export { default as Nft } from './Nft';
+export { default as NftDetails } from './NftDetails';
+export { default as NftRaw } from './NftRaw';
diff --git a/packages/browser-wallet/src/popup/popupX/pages/TokenDetails/TokenDetails.scss b/packages/browser-wallet/src/popup/popupX/pages/TokenDetails/TokenDetails.scss
index 43a295273..dcbd201eb 100644
--- a/packages/browser-wallet/src/popup/popupX/pages/TokenDetails/TokenDetails.scss
+++ b/packages/browser-wallet/src/popup/popupX/pages/TokenDetails/TokenDetails.scss
@@ -38,10 +38,12 @@
}
.button__icon.text {
- margin-top: rem(12px);
+ margin-top: rem(24px);
align-self: flex-start;
&:last-child {
+ margin-top: rem(12px);
+
.label__main {
color: $color-red-attention;
}
diff --git a/packages/browser-wallet/src/popup/popupX/pages/TokenDetails/TokenDetails.tsx b/packages/browser-wallet/src/popup/popupX/pages/TokenDetails/TokenDetails.tsx
index 62eaf30cb..70cabb7f3 100644
--- a/packages/browser-wallet/src/popup/popupX/pages/TokenDetails/TokenDetails.tsx
+++ b/packages/browser-wallet/src/popup/popupX/pages/TokenDetails/TokenDetails.tsx
@@ -1,27 +1,57 @@
import React from 'react';
-import { useNavigate } from 'react-router-dom';
-import Arrow from '@assets/svgX/arrow-right.svg';
-import FileText from '@assets/svgX/file-text.svg';
-import Notebook from '@assets/svgX/notebook.svg';
-import Eye from '@assets/svgX/eye-slash.svg';
+import { useNavigate, useParams } from 'react-router-dom';
import { relativeRoutes } from '@popup/popupX/constants/routes';
import Page from '@popup/popupX/shared/Page';
import Text from '@popup/popupX/shared/Text';
import Button from '@popup/popupX/shared/Button';
import { useTranslation } from 'react-i18next';
import Card from '@popup/popupX/shared/Card';
+import { withSelectedCredential } from '@popup/popupX/shared/utils/hoc';
+import { useFlattenedAccountTokens } from '@popup/pages/Account/Tokens/utils';
+import { contractBalancesFamily, removeTokenFromCurrentAccountAtom } from '@popup/store/token';
+import { useAtomValue } from 'jotai';
+import { addThousandSeparators, integerToFractional, pipe } from 'wallet-common-helpers';
+import { getMetadataDecimals, trunctateSymbol } from '@shared/utils/token-helpers';
+import { useUpdateAtom } from 'jotai/utils';
+import { WalletCredential } from '@shared/storage/types';
+import Arrow from '@assets/svgX/arrow-right.svg';
+import FileText from '@assets/svgX/file-text.svg';
+import Notebook from '@assets/svgX/notebook.svg';
+import Eye from '@assets/svgX/eye-slash.svg';
+
+const SUB_INDEX = '0';
-export default function TokenDetails() {
+type Params = {
+ contractIndex: string;
+};
+
+function TokenDetails({ credential }: { credential: WalletCredential }) {
const { t } = useTranslation('x', { keyPrefix: 'tokenDetails' });
+ const { contractIndex = '' } = useParams();
+ const tokenDetails = useFlattenedAccountTokens(credential).find((token) => token.contractIndex === contractIndex);
+ const { id, metadata } = tokenDetails || { id: '', metadata: {} };
+ const balancesAtom = contractBalancesFamily(credential?.address ?? '', tokenDetails?.contractIndex ?? '');
+ const balance = useAtomValue(balancesAtom)[id];
+ const renderBalance = pipe(integerToFractional(getMetadataDecimals(metadata)), addThousandSeparators);
+ const remove = useUpdateAtom(removeTokenFromCurrentAccountAtom);
+
const nav = useNavigate();
const navToSend = () => nav(`../${relativeRoutes.home.send.path}`);
const navToReceive = () => nav(`../${relativeRoutes.home.receive.path}`);
const navToTransactionLog = () => nav(`../${relativeRoutes.home.transactionLog.path}`);
+ const navToRaw = () => nav(relativeRoutes.home.token.details.raw.path);
+ const removeToken = () => {
+ remove({ contractIndex, tokenId: id });
+ nav(-1);
+ };
+
return (
- 5500 CCd
+
+ {renderBalance(balance)} {trunctateSymbol(metadata.symbol || '')}
+
}
@@ -37,16 +67,15 @@ export default function TokenDetails() {
/>
-
-
-
+
+
+
- } label={t('showRawMetadata')} />
- } label={t('hideToken')} />
+ } label={t('showRawMetadata')} onClick={navToRaw} />
+ } label={t('hideToken')} onClick={removeToken} />
);
}
+
+export default withSelectedCredential(TokenDetails);
diff --git a/packages/browser-wallet/src/popup/popupX/pages/TokenDetails/TokenRaw.tsx b/packages/browser-wallet/src/popup/popupX/pages/TokenDetails/TokenRaw.tsx
new file mode 100644
index 000000000..9a3de7e4e
--- /dev/null
+++ b/packages/browser-wallet/src/popup/popupX/pages/TokenDetails/TokenRaw.tsx
@@ -0,0 +1,47 @@
+import React from 'react';
+import Page from '@popup/popupX/shared/Page';
+import { WalletCredential } from '@shared/storage/types';
+import { useParams } from 'react-router-dom';
+import { useFlattenedAccountTokens } from '@popup/pages/Account/Tokens/utils';
+import { withSelectedCredential } from '@popup/popupX/shared/utils/hoc';
+import { useTranslation } from 'react-i18next';
+import Button from '@popup/popupX/shared/Button';
+import Copy from '@assets/svgX/copy.svg';
+import { copyToClipboard } from '@popup/popupX/shared/utils/helpers';
+import Card from '@popup/popupX/shared/Card';
+
+type Params = {
+ contractIndex: string;
+};
+
+function useSelectedToken(credential: WalletCredential) {
+ const { contractIndex } = useParams();
+ const token = useFlattenedAccountTokens(credential).find((t) => t.contractIndex === contractIndex);
+ return token;
+}
+
+function TokenRaw({ credential }: { credential: WalletCredential }) {
+ const { t } = useTranslation('x', { keyPrefix: 'tokenDetails' });
+ const token = useSelectedToken(credential);
+ const metadata = token?.metadata || {};
+
+ return (
+
+
+ }
+ onClick={() => copyToClipboard(JSON.stringify(token?.metadata, null, 2))}
+ />
+
+
+
+ {Object.entries(metadata).map(([k, v]) => (
+
+ ))}
+
+
+
+ );
+}
+
+export default withSelectedCredential(TokenRaw);
diff --git a/packages/browser-wallet/src/popup/popupX/pages/TokenDetails/i18n/en.ts b/packages/browser-wallet/src/popup/popupX/pages/TokenDetails/i18n/en.ts
index b0b27eca3..3d48c69d3 100644
--- a/packages/browser-wallet/src/popup/popupX/pages/TokenDetails/i18n/en.ts
+++ b/packages/browser-wallet/src/popup/popupX/pages/TokenDetails/i18n/en.ts
@@ -12,6 +12,7 @@ const t = {
delegated: 'Delegated',
validated: 'Validated',
cooldown: 'Cooldown',
+ rawMetadata: 'Raw Metadata',
ccdDescription:
'CCD is the native token of the Concordium blockchain. Its main use cases are the payment of transaction fees, the payment for the execution of smart contracts, payments between users, payments for commercial transactions, staking, and the rewards offered to node operators.',
};
diff --git a/packages/browser-wallet/src/popup/popupX/pages/TokenDetails/index.ts b/packages/browser-wallet/src/popup/popupX/pages/TokenDetails/index.ts
index 4b95f01ea..187a4a0c1 100644
--- a/packages/browser-wallet/src/popup/popupX/pages/TokenDetails/index.ts
+++ b/packages/browser-wallet/src/popup/popupX/pages/TokenDetails/index.ts
@@ -1,2 +1,3 @@
export { default as TokenDetails } from './TokenDetails';
export { default as TokenDetailsCcd } from './TokenDetailsCcd';
+export { default as TokenRaw } from './TokenRaw';
diff --git a/packages/browser-wallet/src/popup/popupX/shell/Routes.tsx b/packages/browser-wallet/src/popup/popupX/shell/Routes.tsx
index 0843b0d42..0569b5efb 100644
--- a/packages/browser-wallet/src/popup/popupX/shell/Routes.tsx
+++ b/packages/browser-wallet/src/popup/popupX/shell/Routes.tsx
@@ -7,7 +7,7 @@ import { SendConfirm, SendFunds } from '@popup/popupX/pages/SendFunds';
import ReceiveFunds from '@popup/popupX/pages/ReceiveFunds';
import TransactionLog from '@popup/popupX/pages/TransactionLog';
import TransactionDetails from '@popup/popupX/pages/TransactionDetails';
-import { TokenDetails, TokenDetailsCcd } from '@popup/popupX/pages/TokenDetails';
+import { TokenDetails, TokenDetailsCcd, TokenRaw } from '@popup/popupX/pages/TokenDetails';
import IdCards from '@popup/popupX/pages/IdCards';
import Accounts from '@popup/popupX/pages/Accounts';
import SeedPhrase from 'src/popup/popupX/pages/SeedPhrase';
@@ -27,6 +27,7 @@ import { MessagePromptHandlersType } from '@popup/shared/utils/message-prompt-ha
import ConnectionRequest from '@popup/popupX/pages/prompts/ConnectionRequest';
import ExternalRequestLayout from '@popup/popupX/page-layouts/ExternalRequestLayout';
import { ManageTokenList, AddToken } from '@popup/popupX/pages/ManageTokens';
+import { Nft, NftDetails, NftRaw } from 'src/popup/popupX/pages/Nft';
import { DelegationResult } from '../pages/EarningRewards/Delegator/Result';
import SubmittedTransaction from '../pages/SubmittedTransaction';
import { DelegatorIntro } from '../pages/EarningRewards/Delegator/Intro';
@@ -65,8 +66,13 @@ export default function Routes({ messagePromptHandlers }: { messagePromptHandler
path={relativeRoutes.home.transactionLog.details.path}
/>
- } path={relativeRoutes.home.token.path} />
- } path={`${relativeRoutes.home.token.path}/ccd`} />
+
+ } path={`${relativeRoutes.home.token.ccd.path}`} />
+
+ } />
+ } path={`${relativeRoutes.home.token.details.raw.path}`} />
+
+
}
path={`${relativeRoutes.home.submittedTransaction.path}`}
@@ -101,6 +107,13 @@ export default function Routes({ messagePromptHandlers }: { messagePromptHandler
} path={relativeRoutes.settings.restore.result.path} />
} path={relativeRoutes.settings.about.path} />
+
+ } />
+
+ } />
+ } path={relativeRoutes.settings.nft.details.raw.path} />
+
+
} />
diff --git a/packages/browser-wallet/src/popup/popupX/styles/_elements.scss b/packages/browser-wallet/src/popup/popupX/styles/_elements.scss
index e050cfae5..3c5997b2b 100644
--- a/packages/browser-wallet/src/popup/popupX/styles/_elements.scss
+++ b/packages/browser-wallet/src/popup/popupX/styles/_elements.scss
@@ -17,6 +17,7 @@
@import '../pages/ManageTokens/ManageTokens';
@import '../pages/SendFunds/SendFunds';
@import '../pages/TransactionDetails/TransactionDetails';
+@import '../pages/Nft/Nft';
@import '../pages/EarningRewards/EarningRewards';
@import '../pages/EarningRewards/AccountCooldowns/AccountCooldowns';
@import '../pages/EarningRewards/Validator/Intro/ValidatorIntro';
diff --git a/packages/browser-wallet/src/popup/shell/i18n/locales/en.ts b/packages/browser-wallet/src/popup/shell/i18n/locales/en.ts
index 17eea29b8..661424548 100644
--- a/packages/browser-wallet/src/popup/shell/i18n/locales/en.ts
+++ b/packages/browser-wallet/src/popup/shell/i18n/locales/en.ts
@@ -50,6 +50,7 @@ import earn from '@popup/popupX/pages/EarningRewards/i18n/en';
import mangeTokens from '@popup/popupX/pages/ManageTokens/i18n/en';
import connectionRequestX from '@popup/popupX/pages/prompts/ConnectionRequest/i18n/en';
import submittedTransaction from '@popup/popupX/pages/SubmittedTransaction/i18n/en';
+import nft from '@popup/popupX/pages/Nft/i18n/en';
const t = {
shared,
@@ -103,6 +104,7 @@ const t = {
mangeTokens,
prompts: { connectionRequestX },
submittedTransaction,
+ nft,
},
};