Skip to content
Merged
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
108 changes: 108 additions & 0 deletions src/components/common/ConnectWalletCtaBanner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { useCallback, useEffect, useState } from 'react';
import { X, Wallet } from 'lucide-react';
import { useAccount, useConnect } from 'wagmi';
import { cn } from '@/lib/utils';

const DISMISS_KEY = 'connect-wallet-banner-dismissed';

function wasDismissed(): boolean {
try {
return sessionStorage.getItem(DISMISS_KEY) === 'true';
} catch {
return false;
}
}

function markDismissed(): void {
try {
sessionStorage.setItem(DISMISS_KEY, 'true');
} catch {
// sessionStorage unavailable – silently ignore
}
}

interface ConnectWalletCtaBannerProps {
className?: string;
}

const ConnectWalletCtaBanner: React.FC<ConnectWalletCtaBannerProps> = ({
className,
}) => {
const { isConnected } = useAccount();
const { connect, connectors, isPending } = useConnect();
const [dismissed, setDismissed] = useState(wasDismissed);

const visible = !isConnected && !dismissed;

useEffect(() => {
if (isConnected) {
setDismissed(false);
try {
sessionStorage.removeItem(DISMISS_KEY);
} catch {
// ignore
}
}
}, [isConnected]);

const handleDismiss = useCallback(() => {
setDismissed(true);
markDismissed();
}, []);

const handleConnect = useCallback(() => {
const primaryConnector = connectors[0];
if (primaryConnector) {
connect({ connector: primaryConnector });
}
}, [connect, connectors]);

if (!visible) {
return null;
}

return (
<div
role="status"
aria-label="Connect your wallet"
className={cn(
'w-full border-b border-blue-500/20 bg-gradient-to-r from-blue-600/10 via-blue-500/5 to-emerald-500/10',
className
)}
>
<div className="mx-auto flex max-w-5xl items-center justify-between gap-4 px-6 py-3">
<div className="flex items-center gap-3">
<div className="flex size-8 shrink-0 items-center justify-center rounded-full bg-blue-600/15">
<Wallet className="size-4 text-blue-400" />
</div>
<p className="font-jakarta text-sm font-medium text-gray-200">
Connect your Stellar wallet to buy creator keys and start
earning
</p>
</div>

<div className="flex shrink-0 items-center gap-2">
<button
type="button"
onClick={handleConnect}
disabled={isPending}
className="rounded-lg bg-blue-600 px-4 py-2 font-jakarta text-sm font-medium text-white transition-colors hover:bg-blue-700 disabled:cursor-not-allowed disabled:bg-blue-400"
>
{isPending ? 'Connecting...' : 'Connect Wallet'}
</button>

<button
type="button"
onClick={handleDismiss}
aria-label="Dismiss banner"
className="flex size-8 shrink-0 items-center justify-center rounded-md text-gray-400 transition-colors hover:bg-white/10 hover:text-gray-200"
>
<X className="size-4" />
</button>
</div>
</div>
</div>
);
};

export default ConnectWalletCtaBanner;
2 changes: 2 additions & 0 deletions src/pages/HomePage.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import ConnectWalletCtaBanner from '../components/common/ConnectWalletCtaBanner';
import FAQ from '../components/home/FAQ';
import Footer from '../components/home/Footer';
import Header from '../components/home/Header';
Expand All @@ -24,6 +25,7 @@ export default function HomePage() {
<Header />
<main>
<Hero />
<ConnectWalletCtaBanner />
<MarketOverview />
<CreatorSpotlight />
<TrendingLeaderboard />
Expand Down
6 changes: 6 additions & 0 deletions src/pages/__tests__/DocumentTitle.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ vi.mock('@/components/home/Hero', () => ({
vi.mock('@/components/home/CreatorSpotlight', () => ({
default: () => <section>Creator Spotlight</section>,
}));
vi.mock('@/components/home/MarketOverview', () => ({
default: () => <section>Market Overview</section>,
}));
vi.mock('@/components/home/TrendingLeaderboard', () => ({
default: () => <section>Trending Leaderboard</section>,
}));
Expand All @@ -25,6 +28,9 @@ vi.mock('@/components/home/FAQ', () => ({
vi.mock('@/components/home/Footer', () => ({
default: () => <footer>Footer</footer>,
}));
vi.mock('@/components/common/ConnectWalletCtaBanner', () => ({
default: () => null,
}));
vi.mock('@/components/common/ReferralLinkPanel', () => ({
default: () => <div>Referral Link Panel</div>,
}));
Expand Down
3 changes: 0 additions & 3 deletions src/utils/__tests__/slippageTolerance.utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ import {
computeMaxPriceStroops,
computeMinPriceStroops,
computeSlippageBounds,
computeSlippagePriceBounds,
validateSlippageTolerance,
MAX_SLIPPAGE_TOLERANCE_PERCENT,
} from '../slippageTolerance.utils';

describe('slippageTolerance.utils', () => {
Expand Down
Loading