Skip to content

Commit 6ac81de

Browse files
chore(buddybook): enhancements (#105)
1 parent b0f2547 commit 6ac81de

File tree

6 files changed

+89
-32
lines changed

6 files changed

+89
-32
lines changed

examples/buddybook/src/App.tsx

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,14 @@ function App() {
5252

5353
if (isWakuLoading) {
5454
return (
55-
<div className="min-h-screen bg-background text-foreground flex justify-center items-center">
56-
<Loader2 className="h-8 w-8 animate-spin" />
55+
<div className="min-h-screen bg-background text-foreground">
56+
<div className="container mx-auto px-4 py-16 flex flex-col items-center justify-center space-y-4">
57+
<h1 className="text-2xl md:text-4xl font-bold">BuddyBook</h1>
58+
<div className="flex flex-col items-center space-y-2">
59+
<Loader2 className="h-8 w-8 animate-spin" />
60+
<p className="text-muted-foreground">Connecting to Waku's decentralized network...</p>
61+
</div>
62+
</div>
5763
</div>
5864
);
5965
}
@@ -63,8 +69,17 @@ function App() {
6369
try {
6470
setWakuStatus(prev => ({ ...prev, store: 'in-progress' }));
6571
setIsLoadingChains(true);
66-
const storeMessages = await getMessagesFromStore(node as LightNode)
67-
setChainsData(storeMessages)
72+
const messageGenerator = getMessagesFromStore(node as LightNode);
73+
74+
// Process messages as they arrive
75+
for await (const message of messageGenerator) {
76+
setChainsData(prevChains => {
77+
const blockExists = prevChains.some(block => block.blockUUID === message.blockUUID);
78+
if (blockExists) return prevChains;
79+
return [...prevChains, message];
80+
});
81+
}
82+
6883
setWakuStatus(prev => ({ ...prev, store: 'success' }));
6984
} catch (error) {
7085
console.error("Error fetching messages from store:", error);
@@ -117,7 +132,16 @@ function App() {
117132
<Route path="/create" element={<ChainCreationForm />} />
118133
<Route path="/view" element={<ChainList chainsData={chainsData} onChainUpdate={handleChainUpdate} isLoading={isLoadingChains} />} />
119134
<Route path="/" element={<Home />} />
120-
<Route path="/sign/:chainUUID/:blockUUID" element={<SignSharedChain chainsData={chainsData} onChainUpdate={handleChainUpdate} />} />
135+
<Route
136+
path="/sign/:chainUUID/:blockUUID"
137+
element={
138+
<SignSharedChain
139+
chainsData={chainsData}
140+
onChainUpdate={handleChainUpdate}
141+
isLoading={isLoadingChains}
142+
/>
143+
}
144+
/>
121145
<Route path="/telemetry" element={<TelemetryPage />} />
122146
<Route path="*" element={<Navigate to="/" replace />} />
123147
</Routes>

examples/buddybook/src/components/Chain/SignSharedChain.tsx

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@ import { BlockPayload } from '@/lib/waku';
44
import SignChain from './SignChain';
55
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
66
import { Button } from "@/components/ui/button";
7+
import { Loader2 } from "lucide-react";
78

89
interface SignSharedChainProps {
910
chainsData: BlockPayload[];
1011
onChainUpdate: (newBlock: BlockPayload) => void;
12+
isLoading: boolean;
1113
}
1214

13-
const SignSharedChain: React.FC<SignSharedChainProps> = ({ chainsData, onChainUpdate }) => {
15+
const SignSharedChain: React.FC<SignSharedChainProps> = ({ chainsData, onChainUpdate, isLoading }) => {
1416
const { chainUUID, blockUUID } = useParams();
1517
const [block, setBlock] = useState<BlockPayload | null>(null);
1618
const navigate = useNavigate();
@@ -22,6 +24,17 @@ const SignSharedChain: React.FC<SignSharedChainProps> = ({ chainsData, onChainUp
2224
}
2325
}, [chainsData, chainUUID, blockUUID]);
2426

27+
if (isLoading && !block) {
28+
return (
29+
<Card className="w-full max-w-md mx-auto">
30+
<CardContent className="flex flex-col items-center justify-center py-8 space-y-4">
31+
<Loader2 className="h-8 w-8 animate-spin" />
32+
<p className="text-sm text-muted-foreground">Looking for chain...</p>
33+
</CardContent>
34+
</Card>
35+
);
36+
}
37+
2538
if (!block) {
2639
return (
2740
<Card className="w-full max-w-md mx-auto">

examples/buddybook/src/components/Chain/View/ChainList.tsx

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -101,14 +101,18 @@ const ChainList: React.FC<ChainListProps> = ({ chainsData, onChainUpdate, isLoad
101101
return (
102102
<Card className="w-full max-w-4xl mx-auto">
103103
<CardHeader>
104-
<CardTitle>Existing Chains</CardTitle>
104+
<CardTitle>
105+
Existing Chains
106+
{isLoading && (
107+
<span className="ml-2 inline-flex items-center text-muted-foreground text-sm font-normal">
108+
<Loader2 className="h-4 w-4 animate-spin mr-2" />
109+
Loading more chains...
110+
</span>
111+
)}
112+
</CardTitle>
105113
</CardHeader>
106114
<CardContent>
107-
{isLoading ? (
108-
<div className="flex justify-center items-center h-32">
109-
<Loader2 className="h-8 w-8 animate-spin" />
110-
</div>
111-
) : rootBlocks.length === 0 ? (
115+
{rootBlocks.length === 0 && !isLoading ? (
112116
<p>No chains found.</p>
113117
) : (
114118
<ul className="space-y-4">

examples/buddybook/src/components/Header.tsx

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -93,14 +93,28 @@ const Header: React.FC<HeaderProps> = ({ wakuStatus }) => {
9393

9494
<div className="flex flex-wrap justify-center md:justify-end items-center gap-2 w-full md:w-auto">
9595
<div className="flex items-center space-x-2 text-xs md:text-sm">
96-
<div className="flex items-center space-x-1">
97-
<span className="text-muted-foreground">Filter:</span>
98-
<div className={`w-2 h-2 md:w-3 md:h-3 rounded-full ${getStatusColor(wakuStatus.filter)}`}></div>
99-
</div>
100-
<div className="flex items-center space-x-1">
101-
<span className="text-muted-foreground">Store:</span>
102-
<div className={`w-2 h-2 md:w-3 md:h-3 rounded-full ${getStatusColor(wakuStatus.store)}`}></div>
103-
</div>
96+
{isWakuLoading ? (
97+
<div className="flex items-center space-x-2">
98+
<Loader2 className="h-4 w-4 animate-spin" />
99+
<span className="text-muted-foreground">Connecting...</span>
100+
</div>
101+
) : wakuError ? (
102+
<span className="text-destructive">Network Error</span>
103+
) : (
104+
<>
105+
<div className="flex items-center space-x-1">
106+
<span className="text-muted-foreground">Filter:</span>
107+
<div className={`w-2 h-2 md:w-3 md:h-3 rounded-full ${getStatusColor(wakuStatus.filter)}`}></div>
108+
</div>
109+
<div className="flex items-center space-x-1">
110+
<span className="text-muted-foreground">Store:</span>
111+
<div className={`w-2 h-2 md:w-3 md:h-3 rounded-full ${getStatusColor(wakuStatus.store)}`}></div>
112+
</div>
113+
<span className="text-xs md:text-sm text-muted-foreground hidden md:inline">
114+
{connections > 0 ? `${connections} peer${connections === 1 ? '' : 's'}` : 'Connecting...'}
115+
</span>
116+
</>
117+
)}
104118
</div>
105119

106120
<div className="flex items-center space-x-2">

examples/buddybook/src/lib/waku.ts

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -65,18 +65,19 @@ export function createMessage({
6565
return { payload: payload };
6666
}
6767

68-
export async function getMessagesFromStore(node: LightNode) {
68+
export async function* getMessagesFromStore(node: LightNode) {
6969
console.time("getMessagesFromStore")
70-
const messages: BlockPayload[] = [];
71-
await node.store.queryWithOrderedCallback([decoder], async (message) => {
72-
console.log(message)
73-
if (!message.payload) return;
74-
const blockPayload = block.decode(message.payload) as unknown as BlockPayload;
75-
blockPayload.signatures = blockPayload.signatures.map(s => JSON.parse(s as unknown as string) as Signature);
76-
messages.push(blockPayload);
77-
})
70+
for await (const messagePromises of node.store.queryGenerator([decoder])) {
71+
const messages = await Promise.all(messagePromises);
72+
for (const message of messages) {
73+
console.log(message)
74+
if (!message?.payload) continue;
75+
const blockPayload = block.decode(message.payload) as unknown as BlockPayload;
76+
blockPayload.signatures = blockPayload.signatures.map(s => JSON.parse(s as unknown as string) as Signature);
77+
yield blockPayload;
78+
}
79+
}
7880
console.timeEnd("getMessagesFromStore")
79-
return messages;
8081
}
8182

8283
export async function subscribeToFilter(node: LightNode, callback: (message: BlockPayload) => void) {

examples/buddybook/tasks.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@
77
- [ ] landing page
88
- [ ] look into high initial loading times
99
- [ ] fix deployment/hosting
10-
- [ ] sign shared chain route should show spinner while waiting for the store query to resolve
11-
- [ ] create chain -> QR modal should have a sharable link instead of the object
10+
- [ x ] sign shared chain route should show spinner while waiting for the store query to resolve
11+
- [ x ] create chain -> QR modal should have a sharable link instead of the object
12+
- [ x ] store query should yield messages as they come in, instead of waiting for all of them to come in before displaying anything

0 commit comments

Comments
 (0)