mirror of https://github.com/waku-org/waku-lab.git
chore: improvements
This commit is contained in:
parent
baa5145ff1
commit
da8b9c9790
|
@ -43,6 +43,7 @@
|
||||||
"@types/node": "^22.7.6",
|
"@types/node": "^22.7.6",
|
||||||
"@types/react": "^18.3.10",
|
"@types/react": "^18.3.10",
|
||||||
"@types/react-dom": "^18.3.0",
|
"@types/react-dom": "^18.3.0",
|
||||||
|
"@types/uuid": "^10.0.0",
|
||||||
"@vitejs/plugin-react": "^4.3.2",
|
"@vitejs/plugin-react": "^4.3.2",
|
||||||
"autoprefixer": "^10.4.20",
|
"autoprefixer": "^10.4.20",
|
||||||
"copy-webpack-plugin": "^11.0.0",
|
"copy-webpack-plugin": "^11.0.0",
|
||||||
|
@ -6610,6 +6611,13 @@
|
||||||
"integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==",
|
"integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/uuid": {
|
||||||
|
"version": "10.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz",
|
||||||
|
"integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@types/ws": {
|
"node_modules/@types/ws": {
|
||||||
"version": "8.5.13",
|
"version": "8.5.13",
|
||||||
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.13.tgz",
|
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.13.tgz",
|
||||||
|
|
|
@ -48,6 +48,7 @@
|
||||||
"@types/node": "^22.7.6",
|
"@types/node": "^22.7.6",
|
||||||
"@types/react": "^18.3.10",
|
"@types/react": "^18.3.10",
|
||||||
"@types/react-dom": "^18.3.0",
|
"@types/react-dom": "^18.3.0",
|
||||||
|
"@types/uuid": "^10.0.0",
|
||||||
"@vitejs/plugin-react": "^4.3.2",
|
"@vitejs/plugin-react": "^4.3.2",
|
||||||
"autoprefixer": "^10.4.20",
|
"autoprefixer": "^10.4.20",
|
||||||
"copy-webpack-plugin": "^11.0.0",
|
"copy-webpack-plugin": "^11.0.0",
|
||||||
|
|
|
@ -80,12 +80,13 @@ function App() {
|
||||||
return [...prevChains, message];
|
return [...prevChains, message];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
setWakuStatus(prev => ({ ...prev, store: 'success' }));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error processing message:", error);
|
console.error("Error processing message:", error);
|
||||||
|
// Update store status to error when query fails
|
||||||
|
setWakuStatus(prev => ({ ...prev, store: 'error' }));
|
||||||
// Continue processing other messages
|
// Continue processing other messages
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
setWakuStatus(prev => ({ ...prev, store: 'error' }));
|
setWakuStatus(prev => ({ ...prev, store: 'error' }));
|
||||||
|
|
|
@ -7,9 +7,8 @@ import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, Di
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Loader2 } from "lucide-react";
|
import { Loader2 } from "lucide-react";
|
||||||
import QRCode from '@/components/QRCode';
|
import QRCode from '@/components/QRCode';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
|
||||||
import { useWalletPrompt } from '@/hooks/useWalletPrompt';
|
import { useWalletPrompt } from '@/hooks/useWalletPrompt';
|
||||||
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
interface SignChainProps {
|
interface SignChainProps {
|
||||||
block: BlockPayload;
|
block: BlockPayload;
|
||||||
chainsData: BlockPayload[]; // Add this prop
|
chainsData: BlockPayload[]; // Add this prop
|
||||||
|
@ -25,6 +24,7 @@ const SignChain: React.FC<SignChainProps> = ({ block, chainsData, onSuccess }) =
|
||||||
const { data: ensName } = useEnsName({ address });
|
const { data: ensName } = useEnsName({ address });
|
||||||
const { node } = useWaku<LightNode>();
|
const { node } = useWaku<LightNode>();
|
||||||
const { ensureWalletConnected } = useWalletPrompt();
|
const { ensureWalletConnected } = useWalletPrompt();
|
||||||
|
const [isWalletPrompt, setIsWalletPrompt] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (address) {
|
if (address) {
|
||||||
|
@ -109,8 +109,13 @@ const SignChain: React.FC<SignChainProps> = ({ block, chainsData, onSuccess }) =
|
||||||
try {
|
try {
|
||||||
if (!address) {
|
if (!address) {
|
||||||
// If not connected, try to connect first
|
// If not connected, try to connect first
|
||||||
|
setIsWalletPrompt(true);
|
||||||
const connected = await ensureWalletConnected();
|
const connected = await ensureWalletConnected();
|
||||||
if (!connected) return;
|
setIsWalletPrompt(false);
|
||||||
|
if (!connected) {
|
||||||
|
setError('Please ensure your wallet is connected and the app is open.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if already signed
|
// Check if already signed
|
||||||
|
@ -119,6 +124,13 @@ const SignChain: React.FC<SignChainProps> = ({ block, chainsData, onSuccess }) =
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
|
||||||
|
if (isMobile && typeof window.ethereum === 'undefined') {
|
||||||
|
setError('Please ensure your wallet app is installed and open before signing.');
|
||||||
|
window.location.href = 'metamask:///';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Prepare the message
|
// Prepare the message
|
||||||
const message = `Sign Block:
|
const message = `Sign Block:
|
||||||
Chain UUID: ${block.chainUUID}
|
Chain UUID: ${block.chainUUID}
|
||||||
|
@ -133,8 +145,10 @@ Signed by: ${ensName || address}`;
|
||||||
signMessage({ message });
|
signMessage({ message });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error in sign flow:', error);
|
console.error('Error in sign flow:', error);
|
||||||
setError('Failed to initiate signing. Please try again.');
|
setError('Failed to initiate signing. Please ensure your wallet app is open and try again.');
|
||||||
setIsSigning(false);
|
setIsSigning(false);
|
||||||
|
} finally {
|
||||||
|
setIsWalletPrompt(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -161,15 +175,42 @@ Signed by: ${ensName || address}`;
|
||||||
</div>
|
</div>
|
||||||
<QRCode text={`${window.location.origin}/sign/${block.chainUUID}/${block.blockUUID}`} />
|
<QRCode text={`${window.location.origin}/sign/${block.chainUUID}/${block.blockUUID}`} />
|
||||||
</div>
|
</div>
|
||||||
{error && <p className="text-sm text-destructive">{error}</p>}
|
{(error || isWalletPrompt) && (
|
||||||
|
<div className="space-y-2">
|
||||||
|
{error && <p className="text-sm text-destructive">{error}</p>}
|
||||||
|
{isWalletPrompt && (
|
||||||
|
<div className="rounded-md bg-blue-50 p-4">
|
||||||
|
<p className="text-sm text-blue-700">
|
||||||
|
Attempting to connect to your wallet...
|
||||||
|
</p>
|
||||||
|
<p className="text-xs text-blue-600 mt-1">
|
||||||
|
If your wallet doesn't open automatically, please open it manually to approve the connection.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{/iPhone|iPad|iPod|Android/i.test(navigator.userAgent) && (
|
||||||
|
<p className="text-xs text-muted-foreground">
|
||||||
|
Tip: If your wallet doesn't open automatically, minimize this app and open your wallet manually before trying again.
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<DialogFooter>
|
<DialogFooter>
|
||||||
<Button variant="secondary" onClick={() => setIsOpen(false)}>Cancel</Button>
|
<Button variant="secondary" onClick={() => setIsOpen(false)}>Cancel</Button>
|
||||||
<Button onClick={handleSign} disabled={isSigning || alreadySigned}>
|
<Button
|
||||||
|
onClick={handleSign}
|
||||||
|
disabled={isSigning || alreadySigned || isWalletPrompt}
|
||||||
|
>
|
||||||
{isSigning ? (
|
{isSigning ? (
|
||||||
<>
|
<>
|
||||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||||
Signing...
|
Signing...
|
||||||
</>
|
</>
|
||||||
|
) : isWalletPrompt ? (
|
||||||
|
<>
|
||||||
|
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||||
|
Connecting...
|
||||||
|
</>
|
||||||
) : alreadySigned ? (
|
) : alreadySigned ? (
|
||||||
'Already Signed'
|
'Already Signed'
|
||||||
) : !address ? (
|
) : !address ? (
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Card } from "@/components/ui/card";
|
import { Card } from "@/components/ui/card";
|
||||||
import { Loader2, CheckCircle2, XCircle } from "lucide-react";
|
import { Loader2, CheckCircle2, XCircle } from "lucide-react";
|
||||||
import type { Status } from '@/App';
|
|
||||||
|
type Status = 'success' | 'error' | 'in-progress';
|
||||||
|
|
||||||
interface ConnectionStatusProps {
|
interface ConnectionStatusProps {
|
||||||
filter: Status;
|
filter: Status;
|
||||||
|
|
|
@ -82,30 +82,32 @@ const Header: React.FC<HeaderProps> = ({ wakuStatus }) => {
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div className="flex items-center gap-2 md:gap-4">
|
<div className="flex items-center gap-2 md:gap-4">
|
||||||
<div className="hidden md:flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
{!isWakuLoading && !wakuError && (
|
{!isWakuLoading && !wakuError && (
|
||||||
<>
|
<>
|
||||||
<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="hidden md:inline 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>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center space-x-1">
|
<div className="flex items-center space-x-1">
|
||||||
<span className="text-muted-foreground">Store:</span>
|
<span className="hidden md:inline 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>
|
||||||
|
<div className="flex items-center space-x-1">
|
||||||
|
<span className="hidden md:inline text-muted-foreground">Peers:</span>
|
||||||
|
{isWakuLoading ? (
|
||||||
|
<Loader2 className="h-4 w-4 animate-spin" />
|
||||||
|
) : wakuError ? (
|
||||||
|
<div className={`w-2 h-2 md:w-3 md:h-3 rounded-full bg-red-500`} />
|
||||||
|
) : (
|
||||||
|
<div className={`w-2 h-2 md:w-3 md:h-3 rounded-full ${connections > 0 ? "bg-green-500" : "bg-yellow-500"}`} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
{isWakuLoading ? (
|
|
||||||
<Loader2 className="h-4 w-4 animate-spin" />
|
|
||||||
) : wakuError ? (
|
|
||||||
<span className="text-xs text-red-500">Error</span>
|
|
||||||
) : (
|
|
||||||
<div className={`w-2 h-2 rounded-full ${connections > 0 ? "bg-green-500" : "bg-yellow-500"}`} />
|
|
||||||
)}
|
|
||||||
|
|
||||||
{isConnected ? (
|
{isConnected ? (
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<span className="text-xs md:text-sm text-muted-foreground truncate max-w-[80px] md:max-w-[120px]">
|
<span className="text-xs md:text-sm text-muted-foreground truncate max-w-[80px] md:max-w-[120px]">
|
||||||
|
|
|
@ -7,16 +7,33 @@ export function useWalletPrompt() {
|
||||||
const ensureWalletConnected = async () => {
|
const ensureWalletConnected = async () => {
|
||||||
if (!isConnected) {
|
if (!isConnected) {
|
||||||
try {
|
try {
|
||||||
// Find the first available connector (usually injected/metamask)
|
|
||||||
const connector = connectors[0]
|
const connector = connectors[0]
|
||||||
if (connector) {
|
if (connector) {
|
||||||
|
// Check if we're on iOS
|
||||||
|
const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent)
|
||||||
|
|
||||||
|
// If on iOS, try to open MetaMask first
|
||||||
|
if (isIOS) {
|
||||||
|
// Attempt to open MetaMask
|
||||||
|
window.location.href = 'metamask:///'
|
||||||
|
|
||||||
|
// Give a small delay before attempting connection
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1000))
|
||||||
|
}
|
||||||
|
|
||||||
await connect({ connector })
|
await connect({ connector })
|
||||||
|
|
||||||
|
// Wait a brief moment for the connection to be established
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1000))
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
// Wait a brief moment for the connection to be established
|
|
||||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
||||||
return true
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error connecting wallet:', error)
|
console.error('Error connecting wallet:', error)
|
||||||
|
// If connection fails, try to open MetaMask directly
|
||||||
|
if (typeof window.ethereum === 'undefined') {
|
||||||
|
// Redirect to MetaMask download page if not installed
|
||||||
|
window.open('https://metamask.io/download/', '_blank')
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue