From 7f0adfddcd4112bcbd958d58ec86b7796725c1c1 Mon Sep 17 00:00:00 2001 From: Nik Graf Date: Fri, 11 Jul 2025 18:19:15 +0200 Subject: [PATCH] add selection for private spaces in connect --- apps/connect/src/components/SpacesCard.tsx | 118 +++++++++++++-------- apps/connect/src/routes/authenticate.tsx | 39 ++++--- 2 files changed, 90 insertions(+), 67 deletions(-) diff --git a/apps/connect/src/components/SpacesCard.tsx b/apps/connect/src/components/SpacesCard.tsx index f716dc7f..ff3d0b11 100644 --- a/apps/connect/src/components/SpacesCard.tsx +++ b/apps/connect/src/components/SpacesCard.tsx @@ -7,9 +7,20 @@ import { Popover } from '@base-ui-components/react/popover'; interface SpacesCardProps extends Omit, 'children'> { spaces: (PublicSpaceData | PrivateSpaceData)[]; status?: 'loading' | { error: boolean | string } | undefined; + selected?: Set; + onSelected?: (spaceId: string, selected: boolean) => void; + currentAppId?: string; } -export function SpacesCard({ spaces, status, className, ...props }: SpacesCardProps) { +export function SpacesCard({ + spaces, + status, + selected, + onSelected, + currentAppId, + className, + ...props +}: SpacesCardProps) { const error = typeof status === 'object' && 'error' in status ? typeof status.error === 'boolean' @@ -59,53 +70,68 @@ export function SpacesCard({ spaces, status, className, ...props }: SpacesCardPr } return (
    - {spaces.map((space) => ( -
  • - - - {space.name || space.id} - - - - - - - - {!('apps' in space) ? ( - Public space - ) : space.apps.length === 0 ? ( - - No app has access to this private space - - ) : ( - <> + {spaces.map((space) => { + // Determine if space is selected + const isPublicSpace = !('apps' in space); + const isSelected = isPublicSpace ? true : (selected?.has(space.id) ?? false); + const isDisabled = + !isPublicSpace && 'apps' in space && space.apps.some((app) => app.id === currentAppId); + + return ( +
  • + + { + if (!isDisabled && onSelected) { + onSelected(space.id, !isSelected); + } + }} + > + {space.name || space.id} + + + + + + + + {!('apps' in space) ? ( + Public space + ) : space.apps.length === 0 ? ( - Apps with access to this private space + No app has access to this private space - -
      - {space.apps.map((app) => ( -
    • {app.name || app.id}
    • - ))} -
    -
    - - )} -
    -
    -
    -
    -
  • - ))} + ) : ( + <> + + Apps with access to this private space + + +
      + {space.apps.map((app) => ( +
    • {app.name || app.id}
    • + ))} +
    +
    + + )} + + + + + + ); + })}
); })()} diff --git a/apps/connect/src/routes/authenticate.tsx b/apps/connect/src/routes/authenticate.tsx index fe85ef86..cc849b15 100644 --- a/apps/connect/src/routes/authenticate.tsx +++ b/apps/connect/src/routes/authenticate.tsx @@ -11,7 +11,7 @@ import { createStore } from '@xstate/store'; import { useSelector } from '@xstate/store/react'; import { Effect, Schema } from 'effect'; import { TriangleAlert } from 'lucide-react'; -import { useEffect } from 'react'; +import { useEffect, useState } from 'react'; import { createWalletClient, custom } from 'viem'; import { privateKeyToAccount } from 'viem/accounts'; @@ -140,6 +140,7 @@ function AuthenticateComponent() { const embeddedWallet = wallets.find((wallet) => wallet.walletClientType === 'privy') || wallets[0]; const state = useSelector(componentStore, (state) => state.context); + const [selectedPrivateSpaces, setSelectedPrivateSpaces] = useState>(new Set()); const { isPending: privateSpacesPending, error: privateSpacesError, data: privateSpacesData } = usePrivateSpaces(); const { @@ -148,25 +149,6 @@ function AuthenticateComponent() { data: publicSpacesData, } = usePublicSpaces(`${Graph.TESTNET_API_ORIGIN}/graphql`); - const selectedPrivateSpaces = new Set(); - const selectedPublicSpaces = new Set(); - - const handlePrivateSpaceToggle = (spaceId: string, checked: boolean) => { - if (checked) { - selectedPrivateSpaces.add(spaceId); - } else { - selectedPrivateSpaces.delete(spaceId); - } - }; - - const handlePublicSpaceToggle = (spaceId: string, checked: boolean) => { - if (checked) { - selectedPublicSpaces.add(spaceId); - } else { - selectedPublicSpaces.delete(spaceId); - } - }; - useEffect(() => { const run = async () => { if (!identityToken || !accountAddress || !keys || !embeddedWallet) { @@ -247,7 +229,7 @@ function AuthenticateComponent() { const privateSpacesInput = privateSpacesData ? privateSpacesData - // .filter((space) => selectedPrivateSpaces.has(space.id)) + .filter((space) => selectedPrivateSpaces.has(space.id)) .map((space) => { // TODO: currently without checking we assume all keyboxes exists and we don't create any - we should check if the keyboxes exist and create them if they don't if (space.appIdentities.some((spaceAppIdentity) => spaceAppIdentity.address === appIdentity.address)) @@ -518,6 +500,18 @@ function AuthenticateComponent() { }); }; + const handleSpaceSelection = (spaceId: string, selected: boolean) => { + setSelectedPrivateSpaces((prev) => { + const newSet = new Set(prev); + if (selected) { + newSet.add(spaceId); + } else { + newSet.delete(spaceId); + } + return newSet; + }); + }; + return (
{(() => { @@ -587,6 +581,9 @@ function AuthenticateComponent() { ? { error: privateSpacesError.message } : undefined } + selected={selectedPrivateSpaces} + onSelected={handleSpaceSelection} + currentAppId={state.appInfo?.appId} className="lg:absolute lg:inset-0" />