diff --git a/packages/keychain/src/components/home.tsx b/packages/keychain/src/components/home.tsx index cc6527d066..d533abda3d 100644 --- a/packages/keychain/src/components/home.tsx +++ b/packages/keychain/src/components/home.tsx @@ -54,23 +54,37 @@ export function Home() { return ; } - // No controller, send to login - if (!controller) { + // Allow viewing certain pages without controller + const publicPaths = [ + "/account/", // Allow viewing any account inventory + ]; + const isPublicPath = publicPaths.some((path) => pathname.startsWith(path)); + + // No controller, send to login (unless on public path) + if (!controller && !isPublicPath) { return ; } - if (!upgrade.isSynced || isConfigLoading) { - // This is likely never observable in a real application but just in case. - return ; - } + // Skip upgrade checks if no controller (viewing public path) + if (controller) { + if (!upgrade.isSynced || isConfigLoading) { + // This is likely never observable in a real application but just in case. + return ; + } - if (upgrade.available) { - return ; + if (upgrade.available) { + return ; + } } return ( {(() => { + // If no controller and on public path, just show the outlet + if (!controller && isPublicPath) { + return ; + } + switch (context?.type) { case "connect": { // if no policies, we can connect immediately @@ -101,13 +115,13 @@ export function Home() { onConnect={() => { context.resolve({ code: ResponseCodes.SUCCESS, - address: controller.address(), + address: controller!.address(), }); }} onSkip={() => { context.resolve({ code: ResponseCodes.SUCCESS, - address: controller.address(), + address: controller!.address(), }); }} /> diff --git a/packages/keychain/src/components/inventory/collection/collection-asset.tsx b/packages/keychain/src/components/inventory/collection/collection-asset.tsx index 28ad3130b4..030ebd2bfe 100644 --- a/packages/keychain/src/components/inventory/collection/collection-asset.tsx +++ b/packages/keychain/src/components/inventory/collection/collection-asset.tsx @@ -39,12 +39,14 @@ import { useAccount } from "@/hooks/account"; import { useConnection, useControllerTheme } from "@/hooks/connection"; import { useNavigation } from "@/context/navigation"; import { createExecuteUrl } from "@/utils/connection/execute"; +import { useViewerAddress } from "@/hooks/viewer"; const OFFSET = 10; export function CollectionAsset() { const { chainId, project } = useConnection(); const account = useAccount(); + const { canPerformActions } = useViewerAddress(); const explorer = useExplorer(); const address = account?.address || ""; const [searchParams, setSearchParams] = useSearchParams(); @@ -305,66 +307,68 @@ export function CollectionAsset() { - -
- - - - - + {canPerformActions && ( + +
- - - - -
-
+ + + + + + + + + +
+
+ )} )} diff --git a/packages/keychain/src/components/inventory/collection/collection.tsx b/packages/keychain/src/components/inventory/collection/collection.tsx index e45f52e735..1b386021c4 100644 --- a/packages/keychain/src/components/inventory/collection/collection.tsx +++ b/packages/keychain/src/components/inventory/collection/collection.tsx @@ -26,6 +26,7 @@ import { useControllerTheme } from "@/hooks/connection"; import { useArcade } from "@/hooks/arcade"; import { EditionModel, GameModel } from "@cartridge/arcade"; import { useMarketplace } from "@/hooks/marketplace"; +import { useViewerAddress } from "@/hooks/viewer"; export function Collection() { const { games, editions } = useArcade(); @@ -33,6 +34,7 @@ export function Collection() { const { project } = useConnection(); const { collectionOrders: orders } = useMarketplace(); const theme = useControllerTheme(); + const { canPerformActions } = useViewerAddress(); const edition: EditionModel | undefined = useMemo(() => { return Object.values(editions).find( @@ -46,7 +48,9 @@ export function Collection() { const location = useLocation(); const [searchParams] = useSearchParams(); - const { collection, assets, status } = useCollection({ contractAddress }); + const { collection, assets, status } = useCollection({ + contractAddress, + }); // Use local state for selection instead of URL parameters const [selectedTokenIds, setSelectedTokenIds] = useState([]); @@ -119,23 +123,25 @@ export function Collection() { certified /> -
- -
- {selection - ? `${selectedTokenIds.length} Selected` - : "Select all"} + {canPerformActions && ( +
+ +
+ {selection + ? `${selectedTokenIds.length} Selected` + : "Select all"} +
-
+ )}
{assets.map((asset) => { @@ -150,7 +156,7 @@ export function Collection() { state={location.state} key={asset.tokenId} onClick={(e: React.MouseEvent) => { - if (selection) { + if (selection && canPerformActions) { e.preventDefault(); handleSelect(asset.tokenId); } @@ -165,10 +171,12 @@ export function Collection() { : `${asset.name} #${parseInt(BigInt(asset.tokenId).toString())}` } image={asset.imageUrl || placeholder} - selectable + selectable={canPerformActions} selected={isSelected} listingCount={listingCount} - onSelect={() => handleSelect(asset.tokenId)} + onSelect={() => + canPerformActions && handleSelect(asset.tokenId) + } className="rounded overflow-hidden" /> @@ -177,40 +185,42 @@ export function Collection() {
- -
- - - - - - -
-
+ + + + + +
+ + )} )} diff --git a/packages/keychain/src/components/inventory/token/token.tsx b/packages/keychain/src/components/inventory/token/token.tsx index d05498eda1..07f6e3b3d5 100644 --- a/packages/keychain/src/components/inventory/token/token.tsx +++ b/packages/keychain/src/components/inventory/token/token.tsx @@ -22,6 +22,7 @@ import { useCallback, useMemo } from "react"; import { useConnection } from "@/hooks/connection"; import { useVersion } from "@/hooks/version"; import { useNavigation } from "@/context/navigation"; +import { useViewerAddress } from "@/hooks/viewer"; export function Token() { const { address } = useParams<{ address: string }>(); @@ -38,6 +39,7 @@ function Credits() { // TODO: Get parent from keychain connection if needed const { navigate } = useNavigation(); const account = useAccount(); + const { canPerformActions } = useViewerAddress(); const username = account?.username || ""; const credit = useCreditBalance({ username, @@ -70,15 +72,17 @@ function Credits() { - - - + {canPerformActions && ( + + + + )} ); } @@ -112,15 +116,17 @@ const CreditsLoadingState = () => { function ERC20() { const { address } = useParams<{ address: string }>(); - const account = useAccount(); - const accountAddress = account?.address || ""; + const { address: profileAddress, canPerformActions } = useViewerAddress(); + const accountAddress = profileAddress || ""; const { controller } = useConnection(); const explorer = useExplorer(); const { transfers } = useData(); const { isControllerGte } = useVersion(); const chainId = constants.StarknetChainId.SN_MAIN; // Use mainnet as default - const { token } = useToken({ tokenAddress: address! }); + const { token } = useToken({ + tokenAddress: address!, + }); const [searchParams] = useSearchParams(); const compatibility = useMemo(() => { @@ -225,7 +231,7 @@ function ERC20() { - {compatibility && controller && ( + {compatibility && controller && canPerformActions && (