Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
163 changes: 118 additions & 45 deletions components/connectWallet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,89 +5,150 @@ import type React from "react";
import Image from "next/image";
import { useState, useEffect } from "react";
import { MdClose } from "react-icons/md";
import { useConnect, useAccount } from "@starknet-react/core";
import { useStellarWallet } from "@/contexts/stellar-wallet-context";
import {
FREIGHTER_ID,
xBULL_ID,
ALBEDO_ID,
LOBSTR_ID,
HANA_ID,
} from "@creit.tech/stellar-wallets-kit";

interface ConnectModalProps {
isModalOpen: boolean;
setIsModalOpen: (isModalOpen: boolean) => void;
}

interface StellarWallet {
id: string;
name: string;
icon: string;
installUrl?: string;
}

// Stellar wallet configurations
const STELLAR_WALLETS: StellarWallet[] = [
{
id: FREIGHTER_ID,
name: "Freighter",
icon: "/wallets/freighter.svg",
installUrl:
"https://chrome.google.com/webstore/detail/freighter/bcacfldlkkdogcmkkibnjlakofdplcbk",
},
{
id: xBULL_ID,
name: "xBull",
icon: "/wallets/xbull.svg",
installUrl: "https://xbull.app/",
},
{
id: ALBEDO_ID,
name: "Albedo",
icon: "/wallets/albedo.svg",
installUrl: "https://albedo.link/",
},
{
id: LOBSTR_ID,
name: "Lobstr",
icon: "/wallets/lobstr.svg",
installUrl: "https://lobstr.co/",
},
{
id: HANA_ID,
name: "Hana",
icon: "/wallets/hana.svg",
installUrl: "https://hanawallet.io/",
},
];

export default function ConnectWalletModal({
isModalOpen,
setIsModalOpen,
}: ConnectModalProps) {
const { connect, connectors } = useConnect();
const { isConnected, status } = useAccount();
const { isConnected, isConnecting, error, connectWallet } =
useStellarWallet();

const [selectedWallet, setSelectedWallet] = useState(connectors?.[0] || null);
const [isConnecting, setIsConnecting] = useState(false);
const [selectedWallet, setSelectedWallet] = useState<string | null>(null);
const [connectionError, setConnectionError] = useState<string | null>(null);

// Close modal when wallet connects successfully
useEffect(() => {
if (isConnected && isModalOpen) {
setIsModalOpen(false);
setIsConnecting(false);
setSelectedWallet(null);
setConnectionError(null);
}
}, [isConnected, isModalOpen, setIsModalOpen]);

// Handle connection status changes
// Update connection error from context
useEffect(() => {
if (status === "connecting") {
setIsConnecting(true);
setConnectionError(null);
} else if (status === "disconnected" && isConnecting) {
// Braavos (and some wallets) briefly hit "disconnected" during the
// popup/handshake before landing on "connected". Debounce so that
// a transient disconnect doesn't look like a failure.
const timer = setTimeout(() => {
setIsConnecting(false);
setConnectionError("Connection failed. Please try again.");
console.log("[ConnectWalletModal] Disconnected, resetting state");
}, 2000);
return () => clearTimeout(timer);
if (error) {
setConnectionError(error);
}
}, [status, isConnecting]);
}, [error]);

const handleOverlayClick = () => {
if (!isConnecting) {
setIsModalOpen(false);
setConnectionError(null);
setSelectedWallet(null);
}
};

const handleModalClick = (e: React.MouseEvent) => {
e.stopPropagation();
};

const handleWalletClick = async (wallet: (typeof connectors)[0]) => {
const handleWalletClick = async (wallet: StellarWallet) => {
if (isConnecting) {
return;
}

try {
setSelectedWallet(wallet);
setIsConnecting(true);
setSelectedWallet(wallet.id);
setConnectionError(null);

await connect({ connector: wallet });
await connectWallet(wallet.id);
} catch (err) {
console.error("[ConnectWalletModal] Connection error:", err);
const errorMessage =
err instanceof Error ? err.message : "Failed to connect wallet";

// The AuthProvider will automatically detect and store the active connector
} catch (error) {
console.error("[ConnectWalletModal] Connection error:", error);
setConnectionError("Failed to connect wallet. Please try again.");
setIsConnecting(false);
// Check if wallet is not installed
if (
errorMessage.includes("not installed") ||
errorMessage.includes("not found") ||
errorMessage.includes("not available")
) {
setConnectionError(
`${wallet.name} is not installed. Please install it first.`
);
} else if (
errorMessage.includes("rejected") ||
errorMessage.includes("denied")
) {
setConnectionError("Connection rejected. Please try again.");
} else {
setConnectionError(errorMessage);
}

setSelectedWallet(null);
}
};

const handleCloseModal = () => {
if (!isConnecting) {
setIsModalOpen(false);
setConnectionError(null);
setSelectedWallet(null);
}
};

const getInstallLink = (walletId: string) => {
const wallet = STELLAR_WALLETS.find(w => w.id === walletId);
return wallet?.installUrl;
};

return (
<div
className={`fixed inset-0 bg-black/40 z-50 flex items-center justify-center px-4 ${
Expand Down Expand Up @@ -128,34 +189,46 @@ export default function ConnectWalletModal({
<p className="text-red-400 text-sm text-center">
{connectionError}
</p>
{connectionError.includes("not installed") && selectedWallet && (
<a
href={getInstallLink(selectedWallet)}
target="_blank"
rel="noopener noreferrer"
className="block mt-2 text-center text-blue-400 hover:text-blue-300 text-sm underline"
>
Install Wallet
</a>
)}
</div>
)}

{/* Wallet List */}
<div className="flex flex-row gap-[7px] rounded-[20px] bg-[#FFFFFF1A] p-[10px] justify-center mb-4">
{connectors.map(wallet => (
<div className="flex flex-row gap-[7px] rounded-[20px] bg-[#FFFFFF1A] p-[10px] justify-center mb-4 flex-wrap">
{STELLAR_WALLETS.map(wallet => (
<div key={wallet.id} onClick={() => handleWalletClick(wallet)}>
<button
className={`w-[80px] h-[80px] bg-[#1D2027] rounded-[16px] flex items-center justify-center p-3 text-white transition-all duration-200 ${
isConnecting && selectedWallet?.id === wallet.id
className={`w-[80px] h-[80px] bg-[#1D2027] rounded-[16px] flex flex-col items-center justify-center p-2 text-white transition-all duration-200 ${
isConnecting && selectedWallet === wallet.id
? "bg-[#393B3D] opacity-75 cursor-not-allowed animate-pulse"
: isConnecting
? "opacity-50 cursor-not-allowed"
: "hover:bg-[#393B3D] cursor-pointer"
}`}
disabled={isConnecting}
title={wallet.name}
>
<Image
src={
typeof wallet.icon === "object"
? wallet.icon.dark || wallet.icon.light
: wallet.icon
}
alt={wallet.name || "Unknown Wallet"}
height={40}
width={40}
className="object-contain"
/>
<div className="w-10 h-10 mb-1 flex items-center justify-center">
<Image
src={wallet.icon}
alt={wallet.name}
height={40}
width={40}
className="object-contain"
/>
</div>
<span className="text-xs text-center truncate w-full">
{wallet.name}
</span>
</button>
</div>
))}
Expand Down
12 changes: 6 additions & 6 deletions components/explore/ProfileModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { motion } from "framer-motion";
import { ChevronLeft } from "lucide-react";
import { MdClose } from "react-icons/md";
import { useRouter } from "next/navigation";
import { useAccount } from "@starknet-react/core";
import { useStellarWallet } from "@/contexts/stellar-wallet-context";
import SimpleLoader from "@/components/ui/loader/simple-loader";

interface ProfileModalProps {
Expand Down Expand Up @@ -40,7 +40,7 @@ export default function ProfileModal({

// Router and wallet
const router = useRouter();
const { address } = useAccount();
const { publicKey } = useStellarWallet();

// Verification code state
const [verificationCode, setVerificationCode] = useState([
Expand Down Expand Up @@ -82,12 +82,12 @@ export default function ProfileModal({
setIsLoading(true);

try {
console.log("ProfileModal: Registering user with wallet:", address);
console.log("ProfileModal: Registering user with wallet:", publicKey);

const formData = {
username: displayName,
email: email,
wallet: address,
wallet: publicKey,
bio: bio || undefined,
};

Expand All @@ -109,11 +109,11 @@ export default function ProfileModal({
console.log("ProfileModal: Registration successful");

// Store wallet and username in localStorage for persistence
localStorage.setItem("wallet", address || "");
localStorage.setItem("wallet", publicKey || "");
localStorage.setItem("username", displayName);

// Also store in sessionStorage for redundancy
sessionStorage.setItem("wallet", address || "");
sessionStorage.setItem("wallet", publicKey || "");
sessionStorage.setItem("username", displayName);

// Skip verification for now and go straight to success
Expand Down
32 changes: 3 additions & 29 deletions components/providers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,9 @@
import type React from "react";
import { useEffect } from "react";
import { SWRConfig } from "swr";
import { sepolia, mainnet } from "@starknet-react/chains";
import {
StarknetConfig,
publicProvider,
argent,
braavos,
useInjectedConnectors,
voyager,
} from "@starknet-react/core";
import { AuthProvider } from "./auth/auth-provider";

import { ThemeProvider } from "@/contexts/theme-context";
import { StellarWalletProvider } from "@/contexts/stellar-wallet-context";

// Create a stable cache instance outside the component to ensure proper cache sharing
const swrCache = new Map();
Expand All @@ -39,17 +30,6 @@ function StarknetKeyCleanup({ children }: { children: React.ReactNode }) {
}

export function Providers({ children }: { children: React.ReactNode }) {
const { connectors } = useInjectedConnectors({
// Recommended connectors for StarkNet

recommended: [argent(), braavos()],
// Include all injected connectors
includeRecommended: "always",
// Order of connectors

order: "alphabetical",
});

return (
<SWRConfig
value={{
Expand All @@ -63,17 +43,11 @@ export function Providers({ children }: { children: React.ReactNode }) {
}}
>
<StarknetKeyCleanup>
<StarknetConfig
chains={[mainnet, sepolia]}
provider={publicProvider()}
connectors={connectors}
explorer={voyager}
autoConnect={true}
>
<StellarWalletProvider>
<ThemeProvider>
<AuthProvider>{children}</AuthProvider>
</ThemeProvider>
</StarknetConfig>
</StellarWalletProvider>
</StarknetKeyCleanup>
</SWRConfig>
);
Expand Down
Loading