diff --git a/extension/e2e-tests/hideCollectible.test.ts b/extension/e2e-tests/hideCollectible.test.ts index 9c15dc83fb..64c7b00695 100644 --- a/extension/e2e-tests/hideCollectible.test.ts +++ b/extension/e2e-tests/hideCollectible.test.ts @@ -1,4 +1,4 @@ -import { test, expect, expectPageToHaveScreenshot } from "./test-fixtures"; +import { test, expect } from "./test-fixtures"; import { loginToTestAccount } from "./helpers/login"; import { stubAccountBalances, @@ -89,12 +89,6 @@ test("Hide and unhide a collectible", async ({ await expect(page.getByText("Stellar Frogs")).toBeVisible(); await expect(page.getByText("Soroban Domains")).toBeVisible(); - // Take a screenshot of the collectibles view - await expectPageToHaveScreenshot({ - page, - screenshot: "collectibles-view-before-hide.png", - }); - // Click on a collectible to open detail view const collectibleGrid = page.getByTestId("account-collection-grid").first(); await collectibleGrid.locator("div").first().click(); @@ -102,24 +96,12 @@ test("Hide and unhide a collectible", async ({ // Wait for detail view to open await expect(page.getByTestId("CollectibleDetail")).toBeVisible(); - // Take a screenshot of the collectible detail - await expectPageToHaveScreenshot({ - page, - screenshot: "collectible-detail-view.png", - }); - // Open the three-dot menu await page.getByTestId("CollectibleDetail__header__right-button").click(); // Wait for menu to be visible await expect(page.getByText("Hide collectible")).toBeVisible(); - // Take a screenshot of the menu with hide option - await expectPageToHaveScreenshot({ - page, - screenshot: "collectible-detail-hide-menu.png", - }); - // Click "Hide collectible" await page.getByText("Hide collectible").click(); @@ -130,12 +112,6 @@ test("Hide and unhide a collectible", async ({ await page.getByTestId("account-tabs-manage-btn-collectibles").click(); await expect(page.getByText("Hidden collectibles")).toBeVisible(); - // Take a screenshot of the manage dropdown - await expectPageToHaveScreenshot({ - page, - screenshot: "collectibles-manage-dropdown.png", - }); - // Click on hidden collectibles await page.getByTestId("hidden-collectibles-btn").click(); @@ -149,12 +125,6 @@ test("Hide and unhide a collectible", async ({ // Verify the hidden collectible is shown await expect(page.getByTestId("hidden-collectible-1")).toBeVisible(); - // Take a screenshot of the hidden collectibles view - await expectPageToHaveScreenshot({ - page, - screenshot: "hidden-collectibles-view.png", - }); - // Click on the hidden collectible to open detail await page.getByTestId("hidden-collectible-1").click(); @@ -167,12 +137,6 @@ test("Hide and unhide a collectible", async ({ // Verify "Show collectible" option is visible (not "Hide collectible") await expect(page.getByText("Show collectible")).toBeVisible(); - // Take a screenshot of the menu with show option - await expectPageToHaveScreenshot({ - page, - screenshot: "collectible-detail-show-menu.png", - }); - // Click "Show collectible" await page.getByText("Show collectible").click(); @@ -181,12 +145,6 @@ test("Hide and unhide a collectible", async ({ // Verify the empty state is now shown in hidden collectibles await expect(page.getByText("No hidden collectibles")).toBeVisible(); - - // Take a screenshot of empty hidden collectibles - await expectPageToHaveScreenshot({ - page, - screenshot: "hidden-collectibles-empty.png", - }); }); test("Hidden collectibles view shows empty state when no collectibles are hidden", async ({ diff --git a/extension/e2e-tests/hideCollectible.test.ts-snapshots/collectible-detail-hide-menu-chromium-darwin.png b/extension/e2e-tests/hideCollectible.test.ts-snapshots/collectible-detail-hide-menu-chromium-darwin.png deleted file mode 100644 index d06edbe438..0000000000 Binary files a/extension/e2e-tests/hideCollectible.test.ts-snapshots/collectible-detail-hide-menu-chromium-darwin.png and /dev/null differ diff --git a/extension/e2e-tests/hideCollectible.test.ts-snapshots/collectible-detail-show-menu-chromium-darwin.png b/extension/e2e-tests/hideCollectible.test.ts-snapshots/collectible-detail-show-menu-chromium-darwin.png deleted file mode 100644 index cae1d99b4d..0000000000 Binary files a/extension/e2e-tests/hideCollectible.test.ts-snapshots/collectible-detail-show-menu-chromium-darwin.png and /dev/null differ diff --git a/extension/e2e-tests/hideCollectible.test.ts-snapshots/collectible-detail-view-chromium-darwin.png b/extension/e2e-tests/hideCollectible.test.ts-snapshots/collectible-detail-view-chromium-darwin.png deleted file mode 100644 index a5bd0b3b4d..0000000000 Binary files a/extension/e2e-tests/hideCollectible.test.ts-snapshots/collectible-detail-view-chromium-darwin.png and /dev/null differ diff --git a/extension/e2e-tests/hideCollectible.test.ts-snapshots/collectibles-manage-dropdown-chromium-darwin.png b/extension/e2e-tests/hideCollectible.test.ts-snapshots/collectibles-manage-dropdown-chromium-darwin.png deleted file mode 100644 index 2ba492a1df..0000000000 Binary files a/extension/e2e-tests/hideCollectible.test.ts-snapshots/collectibles-manage-dropdown-chromium-darwin.png and /dev/null differ diff --git a/extension/e2e-tests/hideCollectible.test.ts-snapshots/collectibles-view-before-hide-chromium-darwin.png b/extension/e2e-tests/hideCollectible.test.ts-snapshots/collectibles-view-before-hide-chromium-darwin.png deleted file mode 100644 index a8a7a8f2a0..0000000000 Binary files a/extension/e2e-tests/hideCollectible.test.ts-snapshots/collectibles-view-before-hide-chromium-darwin.png and /dev/null differ diff --git a/extension/e2e-tests/hideCollectible.test.ts-snapshots/hidden-collectibles-empty-chromium-darwin.png b/extension/e2e-tests/hideCollectible.test.ts-snapshots/hidden-collectibles-empty-chromium-darwin.png deleted file mode 100644 index 71e0ebd01f..0000000000 Binary files a/extension/e2e-tests/hideCollectible.test.ts-snapshots/hidden-collectibles-empty-chromium-darwin.png and /dev/null differ diff --git a/extension/e2e-tests/hideCollectible.test.ts-snapshots/hidden-collectibles-view-chromium-darwin.png b/extension/e2e-tests/hideCollectible.test.ts-snapshots/hidden-collectibles-view-chromium-darwin.png deleted file mode 100644 index 2985fb898e..0000000000 Binary files a/extension/e2e-tests/hideCollectible.test.ts-snapshots/hidden-collectibles-view-chromium-darwin.png and /dev/null differ diff --git a/extension/playwright.config.ts b/extension/playwright.config.ts index 082ebcf795..3224775e10 100644 --- a/extension/playwright.config.ts +++ b/extension/playwright.config.ts @@ -37,10 +37,6 @@ export default defineConfig({ IS_PLAYWRIGHT: "true", }, }, - viewport: { - width: 1280, - height: 720, - }, }, /* Configure projects for major browsers */ diff --git a/extension/src/popup/components/__tests__/AccountCollectibles.test.tsx b/extension/src/popup/components/__tests__/AccountCollectibles.test.tsx index 3fb6e9cb09..871601867e 100644 --- a/extension/src/popup/components/__tests__/AccountCollectibles.test.tsx +++ b/extension/src/popup/components/__tests__/AccountCollectibles.test.tsx @@ -10,7 +10,15 @@ import { } from "@shared/constants/stellar"; import { ROUTES } from "popup/constants/routes"; +// Mock functions for hidden collectibles +const mockRefreshHiddenCollectibles = jest.fn().mockResolvedValue(undefined); +const mockIsCollectibleHidden = jest.fn().mockReturnValue(false); + describe("AccountCollectibles", () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + it("renders collectibles", async () => { render( { }, }} > - + , ); await waitFor(() => screen.getByTestId("account-collectibles")); @@ -156,7 +168,11 @@ describe("AccountCollectibles", () => { }, }} > - + , ); await waitFor(() => screen.getByTestId("account-collectibles")); @@ -202,6 +218,8 @@ describe("AccountCollectibles", () => { collections={[ { error: { collectionAddress: "test", errorMessage: "test" } }, ]} + refreshHiddenCollectibles={mockRefreshHiddenCollectibles} + isCollectibleHidden={mockIsCollectibleHidden} /> , ); @@ -317,7 +335,11 @@ describe("AccountCollectibles", () => { }, }} > - + , ); await waitFor(() => screen.getByTestId("account-collectibles")); diff --git a/extension/src/popup/components/account/AccountCollectibles/index.tsx b/extension/src/popup/components/account/AccountCollectibles/index.tsx index e00b4c7c21..9c9f365584 100644 --- a/extension/src/popup/components/account/AccountCollectibles/index.tsx +++ b/extension/src/popup/components/account/AccountCollectibles/index.tsx @@ -1,6 +1,5 @@ import React, { useState } from "react"; import { useTranslation } from "react-i18next"; -import { useSelector } from "react-redux"; import { Icon } from "@stellar/design-system"; import { Collection } from "@shared/api/types/types"; @@ -10,17 +9,42 @@ import { SheetContent, SheetTitle, } from "popup/basics/shadcn/Sheet"; -import { publicKeySelector } from "popup/ducks/accountServices"; -import { getUserCollections } from "popup/helpers/collectibles"; - import { CollectibleDetail, SelectedCollectible } from "../CollectibleDetail"; +import { CollectibleInfoImage } from "../CollectibleInfo"; import "./styles.scss"; -import { CollectibleInfoImage } from "../CollectibleInfo"; -const CollectionsList = ({ collections }: { collections: Collection[] }) => { - const [selectedCollectible, setSelectedCollectible] = - useState(null); +const CollectionsList = ({ + collections, + showHidden, + isCollectibleHidden, + onCloseCollectible, +}: { + collections: Collection[]; + showHidden: boolean; + isCollectibleHidden: (collectionAddress: string, tokenId: string) => boolean; + onCloseCollectible: () => void; +}) => { + const [isDetailOpen, setIsDetailOpen] = useState(false); + const [detailData, setDetailData] = useState( + null, + ); + + const handleOpenCollectible = (collectible: SelectedCollectible) => { + setDetailData(collectible); + setIsDetailOpen(true); + }; + + const handleCloseCollectible = () => { + setIsDetailOpen(false); + onCloseCollectible(); + }; + + const handleAnimationEnd = () => { + if (!isDetailOpen) { + setDetailData(null); + } + }; return ( <> @@ -30,7 +54,20 @@ const CollectionsList = ({ collections }: { collections: Collection[] }) => { return null; } - // render the collection we do have + // filter collectibles based on showHidden toggle + const collectiblesToShow = showHidden + ? collection.collectibles.filter((item) => + isCollectibleHidden(collection.address, item.tokenId), + ) + : collection.collectibles.filter( + (item) => !isCollectibleHidden(collection.address, item.tokenId), + ); + + // if no collectibles to show, don't render the collection + if (collectiblesToShow.length === 0) { + return null; + } + return (
{ className="AccountCollectibles__collection__header__count" data-testid="account-collection-count" > - {collection.collectibles.length} + {collectiblesToShow.length}
- {collection.collectibles.map((item) => ( - ( +
+ handleOpenCollectible({ + collectionAddress: collection.address, + tokenId: item.tokenId, + }) + } key={item.tokenId} > -
- setSelectedCollectible({ - collectionAddress: collection.address, - tokenId: item.tokenId, - }) - } - > - -
- e.preventDefault()} - > - - {item.tokenId} - - setSelectedCollectible(null)} - /> - - + +
))}
); })} + + {/* Sheet rendered outside the map to persist during close animation */} + { + if (!open) { + handleCloseCollectible(); + } + }} + > + e.preventDefault()} + onAnimationEnd={handleAnimationEnd} + > + + {detailData?.tokenId || ""} + + {detailData && ( + + )} + + ); }; interface AccountCollectiblesProps { collections: Collection[]; + refreshHiddenCollectibles: () => Promise; + isCollectibleHidden: (collectionAddress: string, tokenId: string) => boolean; onClickCollectible?: (selectedCollectible: SelectedCollectible) => void; } export const AccountCollectibles = ({ collections, + refreshHiddenCollectibles, + isCollectibleHidden, }: AccountCollectiblesProps) => { const { t } = useTranslation(); - const publicKey = useSelector(publicKeySelector); - const userCollections = getUserCollections({ - collections, - publicKey, - }); + // Check if there are any valid collections with collectibles + const hasValidCollections = collections.some((c) => c.collection && !c.error); return (
- {userCollections.length ? ( - + {hasValidCollections ? ( + ) : (
diff --git a/extension/src/popup/components/account/CollectibleDetail/index.tsx b/extension/src/popup/components/account/CollectibleDetail/index.tsx index 545c4db588..b2647ccca0 100644 --- a/extension/src/popup/components/account/CollectibleDetail/index.tsx +++ b/extension/src/popup/components/account/CollectibleDetail/index.tsx @@ -19,6 +19,8 @@ import { settingsNetworkDetailsSelector } from "popup/ducks/settings"; import { publicKeySelector } from "popup/ducks/accountServices"; import { collectionsSelector } from "popup/ducks/cache"; import { ROUTES } from "popup/constants/routes"; +import { changeCollectibleVisibility } from "@shared/api/internal"; +import { AssetVisibility } from "@shared/api/types/types"; import { useCollectibleDetail } from "./hooks/useCollectibleDetail"; import { @@ -37,7 +39,7 @@ export interface SelectedCollectible { export const CollectibleDetail = ({ selectedCollectible, handleItemClose, - isHidden, + isHidden = false, }: { selectedCollectible: SelectedCollectible; handleItemClose: () => void; @@ -97,6 +99,19 @@ export const CollectibleDetail = ({ navigateTo(ROUTES.sendPayment, navigate, queryParams); }; + const handleToggleCollectibleVisibility = async () => { + const collectibleKey = `${selectedCollectible.collectionAddress}:${selectedCollectible.tokenId}`; + await changeCollectibleVisibility({ + collectibleKey, + collectibleVisibility: isHidden + ? "visible" + : ("hidden" as AssetVisibility), + activePublicKey: publicKey || "", + }); + setIsPopoverOpen(false); + handleItemClose(); + }; + return (
@@ -143,12 +158,19 @@ export const CollectibleDetail = ({ {t("View on stellar.expert")}
- {/*
- +
+ {isHidden ? ( + + ) : ( + + )}
- {t("Hide collectible")} + {isHidden ? t("Show collectible") : t("Hide collectible")}
-
*/} +
@@ -158,11 +180,6 @@ export const CollectibleDetail = ({ ) : ( - {isHidden && ( - - {t("This collectible is hidden")} - - )}
+ {isHidden && ( + } + title={t("This collectible is hidden")} + /> + )}