mirror of
https://github.com/waku-org/js-waku-lab.git
synced 2025-01-13 10:34:23 +00:00
chore(buddybook): enhancements (#105)
This commit is contained in:
parent
b0f2547732
commit
6ac81de93c
@ -52,8 +52,14 @@ function App() {
|
|||||||
|
|
||||||
if (isWakuLoading) {
|
if (isWakuLoading) {
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-background text-foreground flex justify-center items-center">
|
<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" />
|
<Loader2 className="h-8 w-8 animate-spin" />
|
||||||
|
<p className="text-muted-foreground">Connecting to Waku's decentralized network...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -63,8 +69,17 @@ function App() {
|
|||||||
try {
|
try {
|
||||||
setWakuStatus(prev => ({ ...prev, store: 'in-progress' }));
|
setWakuStatus(prev => ({ ...prev, store: 'in-progress' }));
|
||||||
setIsLoadingChains(true);
|
setIsLoadingChains(true);
|
||||||
const storeMessages = await getMessagesFromStore(node as LightNode)
|
const messageGenerator = getMessagesFromStore(node as LightNode);
|
||||||
setChainsData(storeMessages)
|
|
||||||
|
// 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' }));
|
setWakuStatus(prev => ({ ...prev, store: 'success' }));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching messages from store:", error);
|
console.error("Error fetching messages from store:", error);
|
||||||
@ -117,7 +132,16 @@ function App() {
|
|||||||
<Route path="/create" element={<ChainCreationForm />} />
|
<Route path="/create" element={<ChainCreationForm />} />
|
||||||
<Route path="/view" element={<ChainList chainsData={chainsData} onChainUpdate={handleChainUpdate} isLoading={isLoadingChains} />} />
|
<Route path="/view" element={<ChainList chainsData={chainsData} onChainUpdate={handleChainUpdate} isLoading={isLoadingChains} />} />
|
||||||
<Route path="/" element={<Home />} />
|
<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="/telemetry" element={<TelemetryPage />} />
|
||||||
<Route path="*" element={<Navigate to="/" replace />} />
|
<Route path="*" element={<Navigate to="/" replace />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
|
@ -4,13 +4,15 @@ import { BlockPayload } from '@/lib/waku';
|
|||||||
import SignChain from './SignChain';
|
import SignChain from './SignChain';
|
||||||
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
|
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { Loader2 } from "lucide-react";
|
||||||
|
|
||||||
interface SignSharedChainProps {
|
interface SignSharedChainProps {
|
||||||
chainsData: BlockPayload[];
|
chainsData: BlockPayload[];
|
||||||
onChainUpdate: (newBlock: BlockPayload) => void;
|
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 { chainUUID, blockUUID } = useParams();
|
||||||
const [block, setBlock] = useState<BlockPayload | null>(null);
|
const [block, setBlock] = useState<BlockPayload | null>(null);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@ -22,6 +24,17 @@ const SignSharedChain: React.FC<SignSharedChainProps> = ({ chainsData, onChainUp
|
|||||||
}
|
}
|
||||||
}, [chainsData, chainUUID, blockUUID]);
|
}, [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) {
|
if (!block) {
|
||||||
return (
|
return (
|
||||||
<Card className="w-full max-w-md mx-auto">
|
<Card className="w-full max-w-md mx-auto">
|
||||||
|
@ -101,14 +101,18 @@ const ChainList: React.FC<ChainListProps> = ({ chainsData, onChainUpdate, isLoad
|
|||||||
return (
|
return (
|
||||||
<Card className="w-full max-w-4xl mx-auto">
|
<Card className="w-full max-w-4xl mx-auto">
|
||||||
<CardHeader>
|
<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>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
{isLoading ? (
|
{rootBlocks.length === 0 && !isLoading ? (
|
||||||
<div className="flex justify-center items-center h-32">
|
|
||||||
<Loader2 className="h-8 w-8 animate-spin" />
|
|
||||||
</div>
|
|
||||||
) : rootBlocks.length === 0 ? (
|
|
||||||
<p>No chains found.</p>
|
<p>No chains found.</p>
|
||||||
) : (
|
) : (
|
||||||
<ul className="space-y-4">
|
<ul className="space-y-4">
|
||||||
|
@ -93,6 +93,15 @@ 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 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-2 text-xs md:text-sm">
|
||||||
|
{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">
|
<div className="flex items-center space-x-1">
|
||||||
<span className="text-muted-foreground">Filter:</span>
|
<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 className={`w-2 h-2 md:w-3 md:h-3 rounded-full ${getStatusColor(wakuStatus.filter)}`}></div>
|
||||||
@ -101,6 +110,11 @@ const Header: React.FC<HeaderProps> = ({ wakuStatus }) => {
|
|||||||
<span className="text-muted-foreground">Store:</span>
|
<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 className={`w-2 h-2 md:w-3 md:h-3 rounded-full ${getStatusColor(wakuStatus.store)}`}></div>
|
||||||
</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>
|
||||||
|
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
|
@ -65,18 +65,19 @@ export function createMessage({
|
|||||||
return { payload: payload };
|
return { payload: payload };
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getMessagesFromStore(node: LightNode) {
|
export async function* getMessagesFromStore(node: LightNode) {
|
||||||
console.time("getMessagesFromStore")
|
console.time("getMessagesFromStore")
|
||||||
const messages: BlockPayload[] = [];
|
for await (const messagePromises of node.store.queryGenerator([decoder])) {
|
||||||
await node.store.queryWithOrderedCallback([decoder], async (message) => {
|
const messages = await Promise.all(messagePromises);
|
||||||
|
for (const message of messages) {
|
||||||
console.log(message)
|
console.log(message)
|
||||||
if (!message.payload) return;
|
if (!message?.payload) continue;
|
||||||
const blockPayload = block.decode(message.payload) as unknown as BlockPayload;
|
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);
|
blockPayload.signatures = blockPayload.signatures.map(s => JSON.parse(s as unknown as string) as Signature);
|
||||||
messages.push(blockPayload);
|
yield blockPayload;
|
||||||
})
|
}
|
||||||
|
}
|
||||||
console.timeEnd("getMessagesFromStore")
|
console.timeEnd("getMessagesFromStore")
|
||||||
return messages;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function subscribeToFilter(node: LightNode, callback: (message: BlockPayload) => void) {
|
export async function subscribeToFilter(node: LightNode, callback: (message: BlockPayload) => void) {
|
||||||
|
@ -7,5 +7,6 @@
|
|||||||
- [ ] landing page
|
- [ ] landing page
|
||||||
- [ ] look into high initial loading times
|
- [ ] look into high initial loading times
|
||||||
- [ ] fix deployment/hosting
|
- [ ] fix deployment/hosting
|
||||||
- [ ] sign shared chain route should show spinner while waiting for the store query to resolve
|
- [ x ] 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 ] 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
|
Loading…
x
Reference in New Issue
Block a user