chore(buddybook): enhancements (#105)

This commit is contained in:
Danish Arora 2024-10-29 15:41:00 +05:30 committed by GitHub
parent b0f2547732
commit 6ac81de93c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 89 additions and 32 deletions

View File

@ -52,8 +52,14 @@ function App() {
if (isWakuLoading) {
return (
<div className="min-h-screen bg-background text-foreground flex justify-center items-center">
<Loader2 className="h-8 w-8 animate-spin" />
<div className="min-h-screen bg-background text-foreground">
<div className="container mx-auto px-4 py-16 flex flex-col items-center justify-center space-y-4">
<h1 className="text-2xl md:text-4xl font-bold">BuddyBook</h1>
<div className="flex flex-col items-center space-y-2">
<Loader2 className="h-8 w-8 animate-spin" />
<p className="text-muted-foreground">Connecting to Waku's decentralized network...</p>
</div>
</div>
</div>
);
}
@ -63,8 +69,17 @@ function App() {
try {
setWakuStatus(prev => ({ ...prev, store: 'in-progress' }));
setIsLoadingChains(true);
const storeMessages = await getMessagesFromStore(node as LightNode)
setChainsData(storeMessages)
const messageGenerator = getMessagesFromStore(node as LightNode);
// Process messages as they arrive
for await (const message of messageGenerator) {
setChainsData(prevChains => {
const blockExists = prevChains.some(block => block.blockUUID === message.blockUUID);
if (blockExists) return prevChains;
return [...prevChains, message];
});
}
setWakuStatus(prev => ({ ...prev, store: 'success' }));
} catch (error) {
console.error("Error fetching messages from store:", error);
@ -117,7 +132,16 @@ function App() {
<Route path="/create" element={<ChainCreationForm />} />
<Route path="/view" element={<ChainList chainsData={chainsData} onChainUpdate={handleChainUpdate} isLoading={isLoadingChains} />} />
<Route path="/" element={<Home />} />
<Route path="/sign/:chainUUID/:blockUUID" element={<SignSharedChain chainsData={chainsData} onChainUpdate={handleChainUpdate} />} />
<Route
path="/sign/:chainUUID/:blockUUID"
element={
<SignSharedChain
chainsData={chainsData}
onChainUpdate={handleChainUpdate}
isLoading={isLoadingChains}
/>
}
/>
<Route path="/telemetry" element={<TelemetryPage />} />
<Route path="*" element={<Navigate to="/" replace />} />
</Routes>

View File

@ -4,13 +4,15 @@ import { BlockPayload } from '@/lib/waku';
import SignChain from './SignChain';
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Loader2 } from "lucide-react";
interface SignSharedChainProps {
chainsData: BlockPayload[];
onChainUpdate: (newBlock: BlockPayload) => void;
isLoading: boolean;
}
const SignSharedChain: React.FC<SignSharedChainProps> = ({ chainsData, onChainUpdate }) => {
const SignSharedChain: React.FC<SignSharedChainProps> = ({ chainsData, onChainUpdate, isLoading }) => {
const { chainUUID, blockUUID } = useParams();
const [block, setBlock] = useState<BlockPayload | null>(null);
const navigate = useNavigate();
@ -22,6 +24,17 @@ const SignSharedChain: React.FC<SignSharedChainProps> = ({ chainsData, onChainUp
}
}, [chainsData, chainUUID, blockUUID]);
if (isLoading && !block) {
return (
<Card className="w-full max-w-md mx-auto">
<CardContent className="flex flex-col items-center justify-center py-8 space-y-4">
<Loader2 className="h-8 w-8 animate-spin" />
<p className="text-sm text-muted-foreground">Looking for chain...</p>
</CardContent>
</Card>
);
}
if (!block) {
return (
<Card className="w-full max-w-md mx-auto">

View File

@ -101,14 +101,18 @@ const ChainList: React.FC<ChainListProps> = ({ chainsData, onChainUpdate, isLoad
return (
<Card className="w-full max-w-4xl mx-auto">
<CardHeader>
<CardTitle>Existing Chains</CardTitle>
<CardTitle>
Existing Chains
{isLoading && (
<span className="ml-2 inline-flex items-center text-muted-foreground text-sm font-normal">
<Loader2 className="h-4 w-4 animate-spin mr-2" />
Loading more chains...
</span>
)}
</CardTitle>
</CardHeader>
<CardContent>
{isLoading ? (
<div className="flex justify-center items-center h-32">
<Loader2 className="h-8 w-8 animate-spin" />
</div>
) : rootBlocks.length === 0 ? (
{rootBlocks.length === 0 && !isLoading ? (
<p>No chains found.</p>
) : (
<ul className="space-y-4">

View File

@ -93,14 +93,28 @@ const Header: React.FC<HeaderProps> = ({ wakuStatus }) => {
<div className="flex flex-wrap justify-center md:justify-end items-center gap-2 w-full md:w-auto">
<div className="flex items-center space-x-2 text-xs md:text-sm">
<div className="flex items-center space-x-1">
<span className="text-muted-foreground">Filter:</span>
<div className={`w-2 h-2 md:w-3 md:h-3 rounded-full ${getStatusColor(wakuStatus.filter)}`}></div>
</div>
<div className="flex items-center space-x-1">
<span className="text-muted-foreground">Store:</span>
<div className={`w-2 h-2 md:w-3 md:h-3 rounded-full ${getStatusColor(wakuStatus.store)}`}></div>
</div>
{isWakuLoading ? (
<div className="flex items-center space-x-2">
<Loader2 className="h-4 w-4 animate-spin" />
<span className="text-muted-foreground">Connecting...</span>
</div>
) : wakuError ? (
<span className="text-destructive">Network Error</span>
) : (
<>
<div className="flex items-center space-x-1">
<span className="text-muted-foreground">Filter:</span>
<div className={`w-2 h-2 md:w-3 md:h-3 rounded-full ${getStatusColor(wakuStatus.filter)}`}></div>
</div>
<div className="flex items-center space-x-1">
<span className="text-muted-foreground">Store:</span>
<div className={`w-2 h-2 md:w-3 md:h-3 rounded-full ${getStatusColor(wakuStatus.store)}`}></div>
</div>
<span className="text-xs md:text-sm text-muted-foreground hidden md:inline">
{connections > 0 ? `${connections} peer${connections === 1 ? '' : 's'}` : 'Connecting...'}
</span>
</>
)}
</div>
<div className="flex items-center space-x-2">

View File

@ -65,18 +65,19 @@ export function createMessage({
return { payload: payload };
}
export async function getMessagesFromStore(node: LightNode) {
export async function* getMessagesFromStore(node: LightNode) {
console.time("getMessagesFromStore")
const messages: BlockPayload[] = [];
await node.store.queryWithOrderedCallback([decoder], async (message) => {
console.log(message)
if (!message.payload) return;
const blockPayload = block.decode(message.payload) as unknown as BlockPayload;
blockPayload.signatures = blockPayload.signatures.map(s => JSON.parse(s as unknown as string) as Signature);
messages.push(blockPayload);
})
for await (const messagePromises of node.store.queryGenerator([decoder])) {
const messages = await Promise.all(messagePromises);
for (const message of messages) {
console.log(message)
if (!message?.payload) continue;
const blockPayload = block.decode(message.payload) as unknown as BlockPayload;
blockPayload.signatures = blockPayload.signatures.map(s => JSON.parse(s as unknown as string) as Signature);
yield blockPayload;
}
}
console.timeEnd("getMessagesFromStore")
return messages;
}
export async function subscribeToFilter(node: LightNode, callback: (message: BlockPayload) => void) {

View File

@ -7,5 +7,6 @@
- [ ] landing page
- [ ] look into high initial loading times
- [ ] fix deployment/hosting
- [ ] sign shared chain route should show spinner while waiting for the store query to resolve
- [ ] create chain -> QR modal should have a sharable link instead of the object
- [ x ] sign shared chain route should show spinner while waiting for the store query to resolve
- [ x ] create chain -> QR modal should have a sharable link instead of the object
- [ x ] store query should yield messages as they come in, instead of waiting for all of them to come in before displaying anything