Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions apps/connect/src/components/create-space.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,14 @@ export function CreateSpace() {
};

return (
<>
<Input value={spaceName} onChange={(e) => setSpaceName(e.target.value)} />
<Button className="home-button" onClick={createSpace} disabled={isLoading}>
Create Space {isLoading ? <Spinner /> : null}
</Button>
</>
<div className="flex flex-col gap-2">
<span className="text-xs text-gray-500">Create a new space</span>
<div className="flex flex-row gap-2 items-center">
<Input value={spaceName} onChange={(e) => setSpaceName(e.target.value)} />
<Button className="home-button" onClick={createSpace} disabled={isLoading}>
Create Space {isLoading ? <Spinner /> : null}
</Button>
</div>
</div>
);
}
63 changes: 20 additions & 43 deletions apps/connect/src/components/spaces.tsx
Original file line number Diff line number Diff line change
@@ -1,53 +1,30 @@
import { useIdentityToken } from '@privy-io/react-auth';
import { useQuery } from '@tanstack/react-query';
import { useSpaces } from '@/hooks/use-spaces';

export function Spaces() {
const { identityToken } = useIdentityToken();

const { isPending, error, data } = useQuery<{
spaces: {
id: string;
name: string;
appIdentities: { address: string; appId: string }[];
keyBoxes: {
id: string;
ciphertext: string;
nonce: string;
authorPublicKey: string;
}[];
}[];
}>({
queryKey: ['spaces'],
queryFn: async () => {
if (!identityToken) return;
const response = await fetch(`${import.meta.env.VITE_HYPERGRAPH_SYNC_SERVER_ORIGIN}/connect/spaces`, {
headers: { 'privy-id-token': identityToken },
});
return await response.json();
},
});
const { isPending, error, data } = useSpaces();

if (isPending) return 'Loading spaces …';

if (error) return `An error has occurred: ${error.message}`;

return (
<>
{data.spaces.map((space) => (
<div key={space.id}>
<h2>
{space.name} ({space.id})
<br />
---------
<br />
{space.appIdentities.map((appIdentity) => (
<div key={appIdentity.address}>
{appIdentity.appId} ({appIdentity.address})
</div>
))}
</h2>
</div>
))}
</>
<div>
<h2 className="font-bold mb-2 mt-2">Spaces</h2>
<ul className="space-y-4">
{data.map((space) => (
<li key={space.id}>
<p>{space.name}</p>
<p className="text-xs text-gray-500 mt-2 mb-1">Apps with access to this space</p>
<ul>
{space.apps.map((app) => (
<li key={app.id} className="text-sm">
{app.name}
</li>
))}
</ul>
</li>
))}
</ul>
</div>
);
}
55 changes: 55 additions & 0 deletions apps/connect/src/hooks/use-spaces.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { getAppInfoByIds } from '@/lib/get-app-info-by-ids';
import { useIdentityToken } from '@privy-io/react-auth';
import { useQuery } from '@tanstack/react-query';

type SpaceData = {
id: string;
name: string;
appIdentities: { address: string; appId: string }[];
apps: { name: string; id: string }[];
keyBoxes: {
id: string;
ciphertext: string;
nonce: string;
authorPublicKey: string;
}[];
};

export const useSpaces = () => {
const { identityToken } = useIdentityToken();

return useQuery<SpaceData[]>({
queryKey: ['spaces'],
queryFn: async () => {
if (!identityToken) return [];
const response = await fetch(`${import.meta.env.VITE_HYPERGRAPH_SYNC_SERVER_ORIGIN}/connect/spaces`, {
headers: { 'privy-id-token': identityToken },
});
const data = await response.json();
const appIds = new Set<string>();
for (const space of data.spaces) {
for (const appIdentity of space.appIdentities) {
appIds.add(appIdentity.appId);
}
}
const appInfo = await getAppInfoByIds(Array.from(appIds));
const spaces = data.spaces.map((space: SpaceData) => {
const spaceAppIds = new Set<string>();
for (const appIdentity of space.appIdentities) {
spaceAppIds.add(appIdentity.appId);
}
return {
...space,
apps: Array.from(spaceAppIds).map((appId) => {
return {
// @ts-expect-error - need to improve appInfo typing
Copy link

Copilot AI Jun 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suppressing TypeScript errors with @ts-expect-error can hide real issues; consider refining the appInfo type definition to avoid the need for this comment.

Copilot uses AI. Check for mistakes.
name: appInfo[appId]?.name ?? 'Unknown',
id: appId,
};
}),
};
});
return spaces;
},
});
};
11 changes: 11 additions & 0 deletions apps/connect/src/lib/get-app-info-by-ids.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const apps = {
'93bb8907-085a-4a0e-83dd-62b0dc98e793': {
name: 'Todos',
},
};

export const getAppInfoByIds = async (appIds: string[]) => {
// sleep for 1 second
await new Promise((resolve) => setTimeout(resolve, 1000));
return apps;
Copy link

Copilot AI Jun 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getAppInfoByIds currently returns the entire apps object regardless of the appIds parameter; filter the output to include only requested IDs or document the intended behavior.

Suggested change
return apps;
const filteredApps = Object.fromEntries(
Object.entries(apps).filter(([id]) => appIds.includes(id))
);
return filteredApps;

Copilot uses AI. Check for mistakes.
};
Loading
Loading