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
54 changes: 54 additions & 0 deletions apps/events/src/components/InboxCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { useExternalAccountInbox } from '@graphprotocol/hypergraph-react';
import { useState } from 'react';

interface InboxCardProps {
accountId: string;
inboxId: string;
}

export function InboxCard({ accountId, inboxId }: InboxCardProps) {
const [message, setMessage] = useState('');
const { loading, error, sendMessage, isPublic, authPolicy } = useExternalAccountInbox(accountId, inboxId);

const handleSendMessage = async () => {
if (!message.trim()) return;

try {
await sendMessage(message.trim());
setMessage(''); // Clear the input after sending
} catch (err) {
console.error('Failed to send message:', err);
}
};

return (
<div className="p-4 border rounded">
<h2 className="text-lg mb-2">Inbox: {inboxId}</h2>
<div className="text-sm text-muted-foreground mb-4">
<div>{isPublic ? 'Public' : 'Private'} inbox</div>
<div>Auth Policy: {authPolicy}</div>
</div>

<div className="flex gap-2">
<input
type="text"
value={message}
onChange={(e) => setMessage(e.target.value)}
placeholder="Type a message..."
className="flex-1 px-3 py-2 border rounded"
disabled={loading}
/>
<button
type="button"
onClick={handleSendMessage}
className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 disabled:opacity-50"
disabled={loading || !message.trim()}
>
Send
</button>
</div>

{error && <div className="text-red-500 mt-2">{error.message}</div>}
</div>
);
}
71 changes: 71 additions & 0 deletions apps/events/src/components/SpaceChat.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { useOwnSpaceInbox } from '@graphprotocol/hypergraph-react';
import { useState } from 'react';
import { Button } from './ui/button';

interface SpaceChatProps {
spaceId: string;
}

export function SpaceChat({ spaceId }: SpaceChatProps) {
const [message, setMessage] = useState('');

// This will create the inbox if it doesn't exist, or use the first inbox in the space
const { messages, error, sendMessage, loading } = useOwnSpaceInbox({
spaceId,
autoCreate: true,
});

if (loading) {
return <div>Creating space chat...</div>;
}

const handleSendMessage = async () => {
if (!message.trim()) return;

try {
await sendMessage(message.trim());
setMessage(''); // Clear the input after sending
} catch (err) {
console.error('Failed to send message:', err);
}
};

return (
<div className="mt-8">
<h3 className="text-xl font-bold mb-4">Space Chat</h3>

<div className="border rounded-lg p-4">
{/* Messages */}
<div className="space-y-4 mb-4 max-h-[400px] overflow-y-auto">
{messages?.map((msg) => (
<div key={msg.id} className="bg-muted p-3 rounded">
<div className="text-sm text-muted-foreground mb-1">
<div>From: {msg.authorAccountId?.substring(0, 6) || 'Anonymous'}</div>
<div>{new Date(msg.createdAt).toLocaleString()}</div>
</div>
<div>{msg.plaintext}</div>
</div>
))}
{messages?.length === 0 && <div className="text-center text-muted-foreground py-4">No messages yet</div>}
</div>

{/* Input */}
<div className="flex gap-2">
<input
type="text"
value={message}
onChange={(e) => setMessage(e.target.value)}
placeholder="Type a message..."
className="flex-1 px-3 py-2 border rounded"
disabled={loading}
/>
<Button onClick={handleSendMessage} disabled={loading || !message.trim()}>
Send
</Button>
</div>

{error && <div className="text-red-500 mt-2">{error.message}</div>}
</div>
</div>
);
}
64 changes: 62 additions & 2 deletions apps/events/src/routeTree.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import { Route as rootRoute } from './routes/__root'
import { Route as IndexImport } from './routes/index'
import { Route as SpaceSpaceIdImport } from './routes/space/$spaceId'
import { Route as SettingsExportWalletImport } from './routes/settings/export-wallet'
import { Route as FriendsAccountIdImport } from './routes/friends/$accountId'
import { Route as AccountInboxInboxIdImport } from './routes/account-inbox/$inboxId'

// Create Virtual Routes

Expand Down Expand Up @@ -47,6 +49,18 @@ const SettingsExportWalletRoute = SettingsExportWalletImport.update({
getParentRoute: () => rootRoute,
} as any)

const FriendsAccountIdRoute = FriendsAccountIdImport.update({
id: '/friends/$accountId',
path: '/friends/$accountId',
getParentRoute: () => rootRoute,
} as any)

const AccountInboxInboxIdRoute = AccountInboxInboxIdImport.update({
id: '/account-inbox/$inboxId',
path: '/account-inbox/$inboxId',
getParentRoute: () => rootRoute,
} as any)

// Populate the FileRoutesByPath interface

declare module '@tanstack/react-router' {
Expand All @@ -65,6 +79,20 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof LoginLazyImport
parentRoute: typeof rootRoute
}
'/account-inbox/$inboxId': {
id: '/account-inbox/$inboxId'
path: '/account-inbox/$inboxId'
fullPath: '/account-inbox/$inboxId'
preLoaderRoute: typeof AccountInboxInboxIdImport
parentRoute: typeof rootRoute
}
'/friends/$accountId': {
id: '/friends/$accountId'
path: '/friends/$accountId'
fullPath: '/friends/$accountId'
preLoaderRoute: typeof FriendsAccountIdImport
parentRoute: typeof rootRoute
}
'/settings/export-wallet': {
id: '/settings/export-wallet'
path: '/settings/export-wallet'
Expand All @@ -87,13 +115,17 @@ declare module '@tanstack/react-router' {
export interface FileRoutesByFullPath {
'/': typeof IndexRoute
'/login': typeof LoginLazyRoute
'/account-inbox/$inboxId': typeof AccountInboxInboxIdRoute
'/friends/$accountId': typeof FriendsAccountIdRoute
'/settings/export-wallet': typeof SettingsExportWalletRoute
'/space/$spaceId': typeof SpaceSpaceIdRoute
}

export interface FileRoutesByTo {
'/': typeof IndexRoute
'/login': typeof LoginLazyRoute
'/account-inbox/$inboxId': typeof AccountInboxInboxIdRoute
'/friends/$accountId': typeof FriendsAccountIdRoute
'/settings/export-wallet': typeof SettingsExportWalletRoute
'/space/$spaceId': typeof SpaceSpaceIdRoute
}
Expand All @@ -102,19 +134,35 @@ export interface FileRoutesById {
__root__: typeof rootRoute
'/': typeof IndexRoute
'/login': typeof LoginLazyRoute
'/account-inbox/$inboxId': typeof AccountInboxInboxIdRoute
'/friends/$accountId': typeof FriendsAccountIdRoute
'/settings/export-wallet': typeof SettingsExportWalletRoute
'/space/$spaceId': typeof SpaceSpaceIdRoute
}

export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
fullPaths: '/' | '/login' | '/settings/export-wallet' | '/space/$spaceId'
fullPaths:
| '/'
| '/login'
| '/account-inbox/$inboxId'
| '/friends/$accountId'
| '/settings/export-wallet'
| '/space/$spaceId'
fileRoutesByTo: FileRoutesByTo
to: '/' | '/login' | '/settings/export-wallet' | '/space/$spaceId'
to:
| '/'
| '/login'
| '/account-inbox/$inboxId'
| '/friends/$accountId'
| '/settings/export-wallet'
| '/space/$spaceId'
id:
| '__root__'
| '/'
| '/login'
| '/account-inbox/$inboxId'
| '/friends/$accountId'
| '/settings/export-wallet'
| '/space/$spaceId'
fileRoutesById: FileRoutesById
Expand All @@ -123,13 +171,17 @@ export interface FileRouteTypes {
export interface RootRouteChildren {
IndexRoute: typeof IndexRoute
LoginLazyRoute: typeof LoginLazyRoute
AccountInboxInboxIdRoute: typeof AccountInboxInboxIdRoute
FriendsAccountIdRoute: typeof FriendsAccountIdRoute
SettingsExportWalletRoute: typeof SettingsExportWalletRoute
SpaceSpaceIdRoute: typeof SpaceSpaceIdRoute
}

const rootRouteChildren: RootRouteChildren = {
IndexRoute: IndexRoute,
LoginLazyRoute: LoginLazyRoute,
AccountInboxInboxIdRoute: AccountInboxInboxIdRoute,
FriendsAccountIdRoute: FriendsAccountIdRoute,
SettingsExportWalletRoute: SettingsExportWalletRoute,
SpaceSpaceIdRoute: SpaceSpaceIdRoute,
}
Expand All @@ -146,6 +198,8 @@ export const routeTree = rootRoute
"children": [
"/",
"/login",
"/account-inbox/$inboxId",
"/friends/$accountId",
"/settings/export-wallet",
"/space/$spaceId"
]
Expand All @@ -156,6 +210,12 @@ export const routeTree = rootRoute
"/login": {
"filePath": "login.lazy.tsx"
},
"/account-inbox/$inboxId": {
"filePath": "account-inbox/$inboxId.tsx"
},
"/friends/$accountId": {
"filePath": "friends/$accountId.tsx"
},
"/settings/export-wallet": {
"filePath": "settings/export-wallet.tsx"
},
Expand Down
50 changes: 50 additions & 0 deletions apps/events/src/routes/account-inbox/$inboxId.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { useHypergraphAuth, useOwnAccountInbox } from '@graphprotocol/hypergraph-react';
import { createFileRoute } from '@tanstack/react-router';

export const Route = createFileRoute('/account-inbox/$inboxId')({
component: RouteComponent,
});

function RouteComponent() {
const { inboxId } = Route.useParams();
const { identity } = useHypergraphAuth();

// Ensure we have an authenticated user
if (!identity?.accountId) {
return <div>Please login to view your inbox</div>;
}

const { messages, loading, error } = useOwnAccountInbox(inboxId);

if (loading) {
return <div>Loading inbox messages...</div>;
}

if (error) {
return <div>Error: {error.message}</div>;
}

if (!messages) {
return <div>Inbox not found</div>;
}

return (
<div className="max-w-3xl mx-auto p-6">
<h1 className="text-2xl font-bold mb-6">Inbox Messages</h1>
<div className="space-y-4">
{messages.map((message) => (
<div key={message.id} className="bg-card rounded-lg p-4 shadow-sm border">
<div className="text-lg mb-2">{message.plaintext}</div>
<div className="space-y-1 text-sm text-muted-foreground">
<div className="message-time">{new Date(message.createdAt).toLocaleString()}</div>
{message.authorAccountId && <div>From: {message.authorAccountId}</div>}
</div>
</div>
))}
{messages.length === 0 && (
<div className="text-center py-8 text-muted-foreground">No messages in this inbox</div>
)}
</div>
</div>
);
}
36 changes: 36 additions & 0 deletions apps/events/src/routes/friends/$accountId.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { usePublicAccountInboxes } from '@graphprotocol/hypergraph-react';
import { createFileRoute } from '@tanstack/react-router';
import { InboxCard } from '../../components/InboxCard';

export const Route = createFileRoute('/friends/$accountId')({
component: RouteComponent,
});

function RouteComponent() {
const { accountId } = Route.useParams();
const { publicInboxes, loading, error } = usePublicAccountInboxes(accountId);

if (loading) {
return <div>Loading...</div>;
}

if (error) {
return <div>Error: {error.message}</div>;
}

if (publicInboxes.length === 0) {
return <div>No public inboxes found</div>;
}

return (
<div className="p-4">
<h1 className="text-2xl mb-4">Friend's Public Inboxes: {accountId}</h1>

<div className="space-y-6">
{publicInboxes.map((inbox: { inboxId: string }) => (
<InboxCard key={inbox.inboxId} accountId={accountId} inboxId={inbox.inboxId} />
))}
</div>
</div>
);
}
Loading
Loading