From d84004c0a41a4e6657d115ba085aa72604f60dc4 Mon Sep 17 00:00:00 2001 From: Xavy Date: Tue, 24 Feb 2026 14:15:00 +0100 Subject: [PATCH] feat: Implement Stellar Freighter wallet integration with new navbar, login page, and updated ESLint configuration. --- app/login/page.tsx | 177 ++ components/navbar.tsx | 63 +- eslint.config.mjs | 8 + package-lock.json | 5637 ++++++++++++++++++++++++++++++++++++++--- package.json | 7 +- 5 files changed, 5506 insertions(+), 386 deletions(-) create mode 100644 app/login/page.tsx create mode 100644 eslint.config.mjs diff --git a/app/login/page.tsx b/app/login/page.tsx new file mode 100644 index 0000000..f026e13 --- /dev/null +++ b/app/login/page.tsx @@ -0,0 +1,177 @@ +'use client' + +import React, { useState, useEffect } from 'react' +import { isConnected, requestAccess, getAddress } from '@stellar/freighter-api' +import { Button } from '@/components/ui/button' +import { Wallet, LogOut, AlertCircle, Loader2, ArrowLeft } from 'lucide-react' +import Link from 'next/link' + +export default function LoginPage() { + const [address, setAddress] = useState(null) + const [isInitializing, setIsInitializing] = useState(true) + const [isConnecting, setIsConnecting] = useState(false) + const [error, setError] = useState(null) + + // Initialize session from local storage on mount + useEffect(() => { + const initSession = async () => { + try { + const savedAddress = localStorage.getItem('stellar_wallet_address') + if (savedAddress) { + // Verify if still connected + const connectedResponse = await isConnected() + if (connectedResponse.isConnected) { + setAddress(savedAddress) + } else { + localStorage.removeItem('stellar_wallet_address') + } + } + } catch (err) { + console.error('Failed to initialize wallet session:', err) + } finally { + setIsInitializing(false) + } + } + + // Slight delay to ensure Freighter extension is loaded + setTimeout(initSession, 500) + }, []) + + const handleConnect = async () => { + setError(null) + setIsConnecting(true) + try { + // Check if Freighter is installed + const connectedResponse = await isConnected() + if (connectedResponse.error && !connectedResponse.isConnected) { + throw new Error(connectedResponse.error.message || 'Freighter wallet not detected. Please install the extension.') + } + + // Request connection + const accessResponse = await requestAccess() + if (accessResponse.error) { + throw new Error(accessResponse.error.message || 'Connection request was rejected.') + } + + let walletAddress = accessResponse.address; + + // Fallback if address is missing but no error was caught + if (!walletAddress) { + const addressResponse = await getAddress() + if (addressResponse.error) { + throw new Error(addressResponse.error.message || 'Failed to retrieve wallet address.') + } + walletAddress = addressResponse.address + } + + if (walletAddress) { + setAddress(walletAddress) + localStorage.setItem('stellar_wallet_address', walletAddress) + } else { + throw new Error('Failed to retrieve wallet address from Freighter.') + } + } catch (err: any) { + console.error('Connection error:', err) + setError(err?.message || 'Unable to connect wallet. Please try again.') + } finally { + setIsConnecting(false) + } + } + + const handleDisconnect = () => { + setAddress(null) + localStorage.removeItem('stellar_wallet_address') + setError(null) + } + + const formatAddress = (addr: string) => { + if (!addr || addr.length <= 10) return addr; + return `${addr.substring(0, 5)}...${addr.substring(addr.length - 4)}` + } + + return ( +
+ {/* Back button */} +
+ +
+ + {/* Background decorations matching the app's aesthetic */} +
+
+ +
+
+
+ +
+ +
+

Connect Wallet

+

+ Connect your Stellar Freighter wallet to access your account securely. +

+
+ + {error && ( +
+ +

{error}

+
+ )} + + {isInitializing ? ( +
+ +
+ ) : address ? ( +
+
+ Connected + + {formatAddress(address)} + +
+ + +
+ ) : ( +
+ + +

+ By connecting a wallet, you agree to TaskChain's Terms of Service and Privacy Policy. +

+
+ )} +
+
+
+ ) +} diff --git a/components/navbar.tsx b/components/navbar.tsx index bbc991e..ec8820f 100644 --- a/components/navbar.tsx +++ b/components/navbar.tsx @@ -2,11 +2,24 @@ import Link from 'next/link' import { Button } from '@/components/ui/button' -import { Menu, X } from 'lucide-react' -import { useState } from 'react' +import { Menu, X, Wallet } from 'lucide-react' +import { useState, useEffect } from 'react' export function Navbar() { const [mobileMenuOpen, setMobileMenuOpen] = useState(false) + const [address, setAddress] = useState(null) + + useEffect(() => { + const savedAddress = localStorage.getItem('stellar_wallet_address') + if (savedAddress) { + setAddress(savedAddress) + } + }, []) + + const formatAddress = (addr: string) => { + if (!addr || addr.length <= 10) return addr; + return `${addr.substring(0, 5)}...${addr.substring(addr.length - 4)}` + } return (