🔀 Merge pull request #35 from Ayush272002/metamask_button

🚑️ Fixing Metamask Connection Button!
This commit is contained in:
Sid
2024-10-26 23:48:53 +01:00
committed by GitHub
4 changed files with 135 additions and 107 deletions

View File

@@ -62,7 +62,7 @@ const fetchEvents = (): Event[] => {
const EventsPage: React.FC = () => { const EventsPage: React.FC = () => {
const [events, setEvents] = useState<Event[]>([]); const [events, setEvents] = useState<Event[]>([]);
const [filteredEvents, setFilteredEvents] = useState<Event[]>([]); const [filteredEvents, setFilteredEvents] = useState<Event[]>([]);
const [searchQuery, setSearchQuery] = useState<string>(""); const [searchQuery, setSearchQuery] = useState<string>('');
const [hoveredEventId, setHoveredEventId] = useState<number | null>(null); const [hoveredEventId, setHoveredEventId] = useState<number | null>(null);
const [sortOption, setSortOption] = useState<string>(''); const [sortOption, setSortOption] = useState<string>('');
const [filterOptions, setFilterOptions] = useState<string[]>([]); const [filterOptions, setFilterOptions] = useState<string[]>([]);
@@ -81,14 +81,16 @@ const EventsPage: React.FC = () => {
}, []); }, []);
const SearchBox = () => { const SearchBox = () => {
setSearchQuery(useSearchParams().get("q") || ""); setSearchQuery(useSearchParams().get('q') || '');
return <input return (
type="text" <input
placeholder="Search events..." type="text"
value={searchQuery} placeholder="Search events..."
onChange={(e) => setSearchQuery(e.target.value)} value={searchQuery}
className="search-bar mt-4 p-2 border border-gray-300 rounded w-full max-w-md" onChange={(e) => setSearchQuery(e.target.value)}
/> className="search-bar mt-4 p-2 border border-gray-300 rounded w-full max-w-md"
/>
);
}; };
useEffect(() => { useEffect(() => {
@@ -177,16 +179,18 @@ const EventsPage: React.FC = () => {
<div className="relative z-20 container mx-auto p-4 pt-16"> <div className="relative z-20 container mx-auto p-4 pt-16">
<div className="mb-6"> <div className="mb-6">
<Suspense fallback={ <Suspense
<input fallback={
type="text" <input
placeholder="Search events..." type="text"
disabled={true} placeholder="Search events..."
value="loading..." disabled={true}
onChange={(e) => setSearchQuery(e.target.value)} value="loading..."
className="search-bar mt-4 p-2 border border-gray-300 rounded w-full max-w-md" onChange={(e) => setSearchQuery(e.target.value)}
/> className="search-bar mt-4 p-2 border border-gray-300 rounded w-full max-w-md"
}> />
}
>
<SearchBox /> <SearchBox />
</Suspense> </Suspense>
<div className="flex mt-4 space-x-4"> <div className="flex mt-4 space-x-4">

View File

@@ -1,44 +1,51 @@
'use client'; 'use client';
import React from 'react'; import React from 'react';
import { import {
Card, Card,
CardHeader, CardHeader,
CardFooter, CardFooter,
CardTitle, CardTitle,
CardDescription, CardDescription,
CardContent, CardContent,
} from '@/components/ui/card'; } from '@/components/ui/card';
interface props { interface props {
name: string; name: string;
description: string; description: string;
location: string; location: string;
eventStartDate: number; eventStartDate: number;
eventHost: string; eventHost: string;
imageURL: string | null; imageURL: string | null;
} }
const FeaturedEvent = ({ const FeaturedEvent = ({
name, description, location, eventStartDate, eventHost, imageURL name,
description,
location,
eventStartDate,
eventHost,
imageURL,
}: props) => { }: props) => {
return <Card> return (
<CardHeader> <Card>
{imageURL && <img src={imageURL} alt={name}></img>} <CardHeader>
<CardTitle> {imageURL && <img src={imageURL} alt={name}></img>}
{name} <CardTitle>{name}</CardTitle>
</CardTitle> <CardDescription>
<CardDescription> {location}
{location}<br /> <br />
{new Date(eventStartDate*1000).toLocaleString()} {new Date(eventStartDate * 1000).toLocaleString()}
</CardDescription> </CardDescription>
</CardHeader> </CardHeader>
<CardContent> <CardContent>{description}</CardContent>
{description} <CardFooter>
</CardContent> <i>
<CardFooter> Host: {eventHost.substring(0, 8)}...
<i>Host: {eventHost.substring(0, 8)}...{eventHost.substring(eventHost.length-3)}</i> {eventHost.substring(eventHost.length - 3)}
</CardFooter> </i>
</CardFooter>
</Card> </Card>
} );
};
export default FeaturedEvent; export default FeaturedEvent;

View File

@@ -1,7 +1,7 @@
'use client'; 'use client';
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { useSDK, MetaMaskProvider } from '@metamask/sdk-react'; import { WalletIcon } from 'lucide-react';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { import {
Popover, Popover,
@@ -9,54 +9,87 @@ import {
PopoverTrigger, PopoverTrigger,
} from '@/components/ui/popover'; } from '@/components/ui/popover';
function WalletIcon(props: React.SVGProps<SVGSVGElement>) { declare global {
return ( interface Window {
<svg ethereum?: {
{...props} isMetaMask?: boolean;
xmlns="http://www.w3.org/2000/svg" request: (request: {
width="24" method: string;
height="24" params?: Array<unknown>; // Use `unknown` instead of `any`
viewBox="0 0 24 24" }) => Promise<unknown>; // Specify a more accurate return type if possible
fill="none" };
stroke="currentColor" }
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M21 12V7H5a2 2 0 0 1 0-4h14v4" />
<path d="M3 5v14a2 2 0 0 0 2 2h16v-5" />
<path d="M18 12a2 2 0 0 0 0 4h4v-4Z" />
</svg>
);
}
function formatAddress(address: string | undefined): string {
if (!address) return '';
return `${address.slice(0, 6)}...${address.slice(-4)}`;
} }
function MetaMaskConnect() { function MetaMaskConnect() {
const { sdk, connected, connecting, account } = useSDK(); const [isConnected, setIsConnected] = useState<boolean>(false);
const [isConnected, setIsConnected] = useState(false); const [account, setAccount] = useState<string | null>(null);
// Initial check on load
useEffect(() => { useEffect(() => {
setIsConnected(connected); const checkConnection = async () => {
}, [connected]); if (typeof window !== 'undefined' && window.ethereum) {
try {
// Check if there are any accounts already connected
const accounts = (await window.ethereum.request({
method: 'eth_accounts',
})) as string[];
if (accounts && accounts.length > 0) {
setIsConnected(true);
setAccount(accounts[0]);
localStorage.setItem('isConnected', JSON.stringify(true));
localStorage.setItem('account', accounts[0]);
} else {
// No connected accounts found; check `localStorage`
const storedIsConnected = JSON.parse(
localStorage.getItem('isConnected') || 'false'
);
const storedAccount = localStorage.getItem('account') || null;
setIsConnected(storedIsConnected);
setAccount(storedAccount);
}
} catch (error) {
console.error('Error checking MetaMask connection:', error);
}
}
};
checkConnection();
}, []);
// Update localStorage whenever connection state changes
useEffect(() => {
if (typeof window !== 'undefined') {
localStorage.setItem('isConnected', JSON.stringify(isConnected));
localStorage.setItem('account', account || '');
}
}, [isConnected, account]);
const connect = async () => { const connect = async () => {
try { try {
await sdk?.connect(); const accounts = (await window.ethereum?.request({
setIsConnected(true); method: 'eth_requestAccounts',
} catch (err) { })) as string[];
console.warn(`No accounts found`, err); if (accounts && accounts.length > 0) {
setIsConnected(true);
setAccount(accounts[0]);
localStorage.setItem('isConnected', JSON.stringify(true));
localStorage.setItem('account', accounts[0]);
}
} catch (error) {
console.error('MetaMask connection failed:', error);
} }
}; };
const disconnect = () => { const disconnect = async () => {
if (sdk) { setIsConnected(false);
sdk.terminate(); setAccount(null);
setIsConnected(false); localStorage.setItem('isConnected', JSON.stringify(false));
} localStorage.removeItem('account');
await window.ethereum?.request({
method: 'wallet_revokePermissions',
params: [{ eth_accounts: {} }],
});
}; };
return ( return (
@@ -65,7 +98,7 @@ function MetaMaskConnect() {
<Popover> <Popover>
<PopoverTrigger asChild> <PopoverTrigger asChild>
<Button variant="link" className="text-white"> <Button variant="link" className="text-white">
{formatAddress(account)} {account && `${account.slice(0, 6)}...${account.slice(-4)}`}
</Button> </Button>
</PopoverTrigger> </PopoverTrigger>
<PopoverContent className="w-44"> <PopoverContent className="w-44">
@@ -80,7 +113,6 @@ function MetaMaskConnect() {
</Popover> </Popover>
) : ( ) : (
<Button <Button
disabled={connecting}
onClick={connect} onClick={connect}
className="bg-light-purple bg-opacity-75 hover:bg-purple border-0 hover:border-0" className="bg-light-purple bg-opacity-75 hover:bg-purple border-0 hover:border-0"
> >
@@ -91,18 +123,4 @@ function MetaMaskConnect() {
); );
} }
export default function MetaMaskConnectWrapper() { export default MetaMaskConnect;
return (
<MetaMaskProvider
debug={false}
sdkOptions={{
dappMetadata: {
name: 'My dApp',
url: typeof window !== 'undefined' ? window.location.href : '',
},
}}
>
<MetaMaskConnect />
</MetaMaskProvider>
);
}

View File

@@ -33,7 +33,6 @@ export const buyHandler = async (
return; return;
} }
// @ts-expect-error: window.ethereum might not match ExternalProvider exactly
const provider = new ethers.providers.Web3Provider(window.ethereum); const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner(); const signer = provider.getSigner();
const contract = getContract().connect(signer); const contract = getContract().connect(signer);