Files
pezkuwi-telegram-miniapp/src/sections/Rewards.tsx
T
pezkuwichain c35c538678 fix: LP staking logout issue and Kurdish text correction
- Replace window.location.reload() with onClose() in LPStakingModal
- Fix Turkish word "ise" to Kurdish "be" in Rewards score formula
2026-02-07 02:07:37 +03:00

722 lines
31 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Rewards Section - Referral System
* Uses real blockchain data from ReferralContext
*/
import { useState, useEffect, useCallback } from 'react';
import {
Gift,
Users,
Trophy,
Copy,
Check,
Share2,
RefreshCw,
Star,
TrendingUp,
Award,
Zap,
Coins,
Shield,
Target,
Sparkles,
GraduationCap,
} from 'lucide-react';
import { cn, formatAddress } from '@/lib/utils';
import { useTelegram } from '@/hooks/useTelegram';
import { useAuth } from '@/contexts/AuthContext';
import { useReferral } from '@/contexts/ReferralContext';
import { useWallet } from '@/contexts/WalletContext';
import { SocialLinks } from '@/components/SocialLinks';
import {
getAllScoresWithFallback,
getFrontendStakingScore,
formatStakedAmount,
getScoreColor,
getScoreRating,
type FrontendTrustScoreResult,
type FrontendStakingScoreResult,
} from '@/lib/scores';
// Activity tracking constants
const ACTIVITY_STORAGE_KEY = 'pezkuwi_last_active';
const ACTIVITY_DURATION_MS = 24 * 60 * 60 * 1000; // 24 hours
export function RewardsSection() {
const { hapticImpact, hapticNotification, shareUrl, showAlert } = useTelegram();
const { user: authUser } = useAuth();
const { stats, myReferrals, loading, refreshStats } = useReferral();
const { isConnected, address, api, peopleApi } = useWallet();
const [copied, setCopied] = useState(false);
const [activeTab, setActiveTab] = useState<'overview' | 'referrals' | 'scores'>('overview');
const [isActive, setIsActive] = useState(false);
const [timeRemaining, setTimeRemaining] = useState<string | null>(null);
const [userScores, setUserScores] = useState<
(FrontendTrustScoreResult & { isFromFrontend: boolean }) | null
>(null);
const [stakingDetails, setStakingDetails] = useState<FrontendStakingScoreResult | null>(null);
const [scoresLoading, setScoresLoading] = useState(false);
// Check activity status
const checkActivityStatus = useCallback(() => {
const lastActive = localStorage.getItem(ACTIVITY_STORAGE_KEY);
if (lastActive) {
const lastActiveTime = parseInt(lastActive, 10);
const now = Date.now();
const elapsed = now - lastActiveTime;
if (elapsed < ACTIVITY_DURATION_MS) {
setIsActive(true);
const remaining = ACTIVITY_DURATION_MS - elapsed;
const hours = Math.floor(remaining / (60 * 60 * 1000));
const minutes = Math.floor((remaining % (60 * 60 * 1000)) / (60 * 1000));
setTimeRemaining(`${hours}s ${minutes}d`);
} else {
setIsActive(false);
setTimeRemaining(null);
}
} else {
setIsActive(false);
setTimeRemaining(null);
}
}, []);
// Check activity status on mount and every minute
useEffect(() => {
// Run check after a microtask to avoid synchronous setState in effect
const timeoutId = setTimeout(checkActivityStatus, 0);
const interval = setInterval(checkActivityStatus, 60000);
return () => {
clearTimeout(timeoutId);
clearInterval(interval);
};
}, [checkActivityStatus]);
// Fetch user scores when on scores tab
const fetchUserScores = useCallback(async () => {
if (!address) {
setUserScores(null);
setStakingDetails(null);
return;
}
setScoresLoading(true);
try {
const [scores, staking] = await Promise.all([
getAllScoresWithFallback(peopleApi, api, address),
api ? getFrontendStakingScore(api, address) : Promise.resolve(null),
]);
setUserScores(scores);
setStakingDetails(staking);
} catch (err) {
console.error('Error fetching scores:', err);
} finally {
setScoresLoading(false);
}
}, [api, peopleApi, address]);
// Fetch scores when tab changes to scores or on initial load
useEffect(() => {
if (activeTab === 'scores' && address) {
fetchUserScores();
}
}, [activeTab, address, fetchUserScores]);
const handleActivate = () => {
hapticNotification('success');
localStorage.setItem(ACTIVITY_STORAGE_KEY, Date.now().toString());
setIsActive(true);
setTimeRemaining('24s 0d');
showAlert('Tu niha aktîv î! 24 saet paşê dîsa bikirtîne.');
};
// Telegram referral link (for sharing) - use authenticated user ID
const referralLink = authUser?.telegram_id
? `https://t.me/pezkuwichain_bot?start=ref_${authUser.telegram_id}`
: 'https://t.me/pezkuwichain_bot';
const handleCopy = async () => {
try {
await window.navigator.clipboard.writeText(referralLink);
setCopied(true);
hapticNotification('success');
setTimeout(() => setCopied(false), 2000);
} catch {
showAlert('Kopî bû');
}
};
const handleShare = () => {
hapticImpact('medium');
shareUrl(
referralLink,
'Pezkuwichain - Dewleta Dîjîtal a Kurd! Bi lînka min ve tev li me bibe:'
);
};
const handleRefresh = () => {
hapticImpact('medium');
refreshStats();
};
// Calculate points per referral based on position
const getPointsForPosition = (position: number): number => {
if (position <= 10) return 10;
if (position <= 50) return 5;
if (position <= 100) return 4;
return 0;
};
if (!isConnected) {
return (
<div className="flex flex-col h-full items-center justify-center p-8 text-center">
<Gift className="w-16 h-16 text-purple-400 mb-4" />
<h2 className="text-xl font-semibold mb-2">Xelat - Referral System</h2>
<p className="text-muted-foreground mb-4">
Ji bo dîtina referral û xelatên xwe, berî her tiştî cîzdanê xwe girêde.
</p>
</div>
);
}
return (
<div className="flex flex-col h-full">
{/* Header */}
<header className="flex-shrink-0 px-4 py-3 border-b border-border bg-background/80 backdrop-blur-sm safe-area-top">
<div className="flex items-center justify-between mb-3">
<div className="flex items-center gap-2">
<div className="w-8 h-8 rounded-lg bg-purple-500/20 flex items-center justify-center">
<Gift className="w-4 h-4 text-purple-400" />
</div>
<h1 className="text-lg font-semibold">Xelat</h1>
</div>
<button
onClick={handleRefresh}
disabled={loading}
className="p-2 rounded-lg hover:bg-secondary"
>
<RefreshCw
className={`w-5 h-5 text-muted-foreground ${loading ? 'animate-spin' : ''}`}
/>
</button>
</div>
{/* Tabs */}
<div className="flex gap-1 bg-secondary/50 rounded-lg p-1">
{[
{ id: 'overview' as const, label: 'Geşbîn' },
{ id: 'referrals' as const, label: 'Referral' },
{ id: 'scores' as const, label: 'Xal' },
].map(({ id, label }) => (
<button
key={id}
onClick={() => {
hapticImpact('light');
setActiveTab(id);
}}
className={cn(
'flex-1 py-2 rounded-md text-sm transition-colors',
activeTab === id
? 'bg-background text-foreground shadow-sm'
: 'text-muted-foreground'
)}
>
{label}
</button>
))}
</div>
</header>
<div className="flex-1 overflow-y-auto hide-scrollbar">
{/* Overview Tab */}
{activeTab === 'overview' && (
<div className="p-4 space-y-4">
{loading ? (
<div className="grid grid-cols-2 gap-3">
{[1, 2, 3, 4].map((i) => (
<div key={i} className="bg-secondary/50 rounded-xl p-4 animate-pulse">
<div className="h-4 bg-secondary rounded w-1/2 mb-2" />
<div className="h-6 bg-secondary rounded w-3/4" />
</div>
))}
</div>
) : (
<>
{/* Score Card */}
<div className="bg-gradient-to-br from-purple-600 to-pink-600 rounded-2xl p-4 text-white">
<div className="flex items-center justify-between mb-4">
<div>
<p className="text-purple-100 text-sm">Pûana Referral</p>
<p className="text-4xl font-bold">{stats?.referralScore ?? 0}</p>
</div>
<div className="w-16 h-16 rounded-full bg-white/20 flex items-center justify-center">
<Trophy className="w-8 h-8" />
</div>
</div>
<div className="flex items-center gap-2 text-sm text-purple-100">
<TrendingUp className="w-4 h-4" />
<span>Max pûan: 500</span>
</div>
</div>
{/* Refer More Card */}
<div className="bg-gradient-to-r from-amber-500/20 to-orange-500/20 border border-amber-500/30 rounded-xl p-4">
<div className="flex items-start gap-3">
<div className="w-10 h-10 rounded-full bg-amber-500/30 flex items-center justify-center flex-shrink-0">
<Coins className="w-5 h-5 text-amber-400" />
</div>
<div>
<h4 className="font-semibold text-amber-100 mb-1">
زیاتر ڕیفەر بکە، زیاتر قازانج بکە!
</h4>
<p className="text-sm text-amber-200/80">
هەر کەسێک بهێنیت، HEZ و PEZ وەک خەڵات وەردەگریت. زیاتر ڕیفەر = زیاتر خەڵات!
</p>
</div>
</div>
</div>
{/* Stats Grid */}
<div className="grid grid-cols-2 gap-3">
<div className="bg-secondary/30 rounded-xl p-4 border border-border/50">
<div className="flex items-center gap-2 mb-2">
<Users className="w-4 h-4 text-green-400" />
<span className="text-xs text-muted-foreground">Referral</span>
</div>
<p className="text-2xl font-bold text-foreground">
{stats?.referralCount ?? 0}
</p>
<p className="text-xs text-muted-foreground">KYC pejirandî</p>
</div>
<div className="bg-secondary/30 rounded-xl p-4 border border-border/50">
<div className="flex items-center gap-2 mb-2">
<Award className="w-4 h-4 text-blue-400" />
<span className="text-xs text-muted-foreground">Referrer</span>
</div>
{stats?.whoInvitedMe ? (
<p className="text-sm font-mono text-foreground truncate">
{formatAddress(stats.whoInvitedMe, 6)}
</p>
) : (
<p className="text-sm text-muted-foreground">Tune</p>
)}
<p className="text-xs text-muted-foreground">Min vexwand</p>
</div>
</div>
{/* Pending Referral Notification */}
{stats?.pendingReferral && (
<div className="bg-blue-900/20 border border-blue-600/30 rounded-xl p-4">
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-full bg-blue-600/30 flex items-center justify-center">
<Award className="w-5 h-5 text-blue-400" />
</div>
<div className="flex-1">
<div className="text-white font-semibold">Referral li bendê</div>
<div className="text-sm text-blue-300">
KYC temam bike ji bo pejirandina referral ji{' '}
<span className="font-mono">
{formatAddress(stats.pendingReferral, 6)}
</span>
</div>
</div>
</div>
</div>
)}
{/* Invite Card */}
<div className="bg-secondary/30 rounded-xl p-4 border border-border/50">
<h3 className="font-medium text-foreground mb-3 flex items-center gap-2">
<Share2 className="w-4 h-4 text-primary" />
Hevalên xwe vexwîne
</h3>
<div className="bg-background rounded-lg p-3 mb-3">
<p className="text-xs text-muted-foreground mb-1">Lînka te</p>
<code className="text-sm text-foreground break-all">{referralLink}</code>
</div>
<div className="flex gap-2">
<button
onClick={handleCopy}
className={cn(
'flex-1 flex items-center justify-center gap-2 py-2.5 rounded-lg text-sm font-medium transition-colors',
copied
? 'bg-green-500/20 text-green-400'
: 'bg-secondary hover:bg-secondary/80'
)}
>
{copied ? <Check className="w-4 h-4" /> : <Copy className="w-4 h-4" />}
{copied ? 'Kopî bû!' : 'Kopî bike'}
</button>
<button
onClick={handleShare}
className="flex-1 flex items-center justify-center gap-2 py-2.5 bg-primary rounded-lg text-primary-foreground text-sm font-medium"
>
<Share2 className="w-4 h-4" />
Parve bike
</button>
</div>
</div>
{/* Score System */}
<div className="bg-secondary/30 rounded-xl p-4 border border-border/50">
<h3 className="font-medium text-foreground mb-3 flex items-center gap-2">
<Star className="w-4 h-4 text-yellow-400" />
Sîstema pûanan
</h3>
<div className="space-y-2 text-sm">
<div className="flex justify-between py-2 border-b border-border/30">
<span className="text-muted-foreground">1-10 referral</span>
<span className="text-green-400 font-medium">×10 pûan</span>
</div>
<div className="flex justify-between py-2 border-b border-border/30">
<span className="text-muted-foreground">11-50 referral</span>
<span className="text-green-400 font-medium">100 + ×5</span>
</div>
<div className="flex justify-between py-2 border-b border-border/30">
<span className="text-muted-foreground">51-100 referral</span>
<span className="text-green-400 font-medium">300 + ×4</span>
</div>
<div className="flex justify-between py-2">
<span className="text-muted-foreground">101+ referral</span>
<span className="text-yellow-400 font-medium">500 (Max)</span>
</div>
</div>
</div>
{/* I am Active Button */}
<div className="bg-secondary/30 rounded-xl p-4 border border-border/50">
<div className="flex items-center justify-between mb-3">
<div className="flex items-center gap-2">
<Zap
className={cn('w-5 h-5', isActive ? 'text-green-400' : 'text-gray-400')}
/>
<div>
<h3 className="font-medium text-foreground">Rewşa Aktîvbûnê</h3>
{isActive && timeRemaining && (
<p className="text-xs text-green-400">Dem: {timeRemaining} maye</p>
)}
</div>
</div>
<div
className={cn(
'px-2 py-1 rounded-full text-xs font-medium',
isActive ? 'bg-green-500/20 text-green-400' : 'bg-red-500/20 text-red-400'
)}
>
{isActive ? 'Aktîv' : 'Ne Aktîv'}
</div>
</div>
<p className="text-sm text-muted-foreground mb-3">
Her 24 saet carekê bikirtîne da ku aktîv bimînî û xelatên zêdetir qezenc bikî!
</p>
<button
onClick={handleActivate}
disabled={isActive}
className={cn(
'w-full py-3 rounded-lg font-medium flex items-center justify-center gap-2 transition-all',
isActive
? 'bg-green-500/20 text-green-400 cursor-not-allowed'
: 'bg-gradient-to-r from-green-500 to-emerald-600 text-white hover:opacity-90'
)}
>
<Zap className="w-5 h-5" />
{isActive ? 'Tu Aktîv î!' : 'Ez Aktîv im!'}
</button>
</div>
{/* Social Links */}
<SocialLinks />
</>
)}
</div>
)}
{/* Referrals Tab */}
{activeTab === 'referrals' && (
<div className="p-4 space-y-4">
{/* Refer More Card */}
<div className="bg-gradient-to-r from-amber-500/20 to-orange-500/20 border border-amber-500/30 rounded-xl p-4">
<div className="flex items-start gap-3">
<div className="w-10 h-10 rounded-full bg-amber-500/30 flex items-center justify-center flex-shrink-0">
<Coins className="w-5 h-5 text-amber-400" />
</div>
<div>
<h4 className="font-semibold text-amber-100 mb-1">
زیاتر ڕیفەر بکە، زیاتر قازانج بکە!
</h4>
<p className="text-sm text-amber-200/80">
هەر کەسێک بهێنیت، HEZ و PEZ وەک خەڵات وەردەگریت. زیاتر ڕیفەر = زیاتر خەڵات!
</p>
</div>
</div>
</div>
{/* I am Active Button */}
<div className="bg-secondary/30 rounded-xl p-4 border border-border/50">
<div className="flex items-center justify-between mb-3">
<div className="flex items-center gap-2">
<Zap className={cn('w-5 h-5', isActive ? 'text-green-400' : 'text-gray-400')} />
<div>
<h3 className="font-medium text-foreground">Rewşa Aktîvbûnê</h3>
{isActive && timeRemaining && (
<p className="text-xs text-green-400">Dem: {timeRemaining} maye</p>
)}
</div>
</div>
<div
className={cn(
'px-2 py-1 rounded-full text-xs font-medium',
isActive ? 'bg-green-500/20 text-green-400' : 'bg-red-500/20 text-red-400'
)}
>
{isActive ? 'Aktîv' : 'Ne Aktîv'}
</div>
</div>
<button
onClick={handleActivate}
disabled={isActive}
className={cn(
'w-full py-3 rounded-lg font-medium flex items-center justify-center gap-2 transition-all',
isActive
? 'bg-green-500/20 text-green-400 cursor-not-allowed'
: 'bg-gradient-to-r from-green-500 to-emerald-600 text-white hover:opacity-90'
)}
>
<Zap className="w-5 h-5" />
{isActive ? 'Tu Aktîv î!' : 'Ez Aktîv im!'}
</button>
</div>
{loading ? (
<div className="space-y-3">
{[1, 2, 3, 4, 5].map((i) => (
<div key={i} className="bg-secondary/50 rounded-xl p-4 animate-pulse">
<div className="h-4 bg-secondary rounded w-2/3" />
</div>
))}
</div>
) : myReferrals.length > 0 ? (
<div className="space-y-3">
<div className="text-sm text-muted-foreground mb-2">
{myReferrals.length} referral (KYC pejirandî)
</div>
{myReferrals.map((referralAddress, index) => (
<div
key={referralAddress}
className="bg-secondary/30 rounded-xl p-4 border border-border/50 flex items-center gap-3"
>
<div className="w-10 h-10 rounded-full bg-green-500/20 flex items-center justify-center text-sm font-bold text-green-400">
{index + 1}
</div>
<div className="flex-1 min-w-0">
<code className="text-sm text-foreground">
{formatAddress(referralAddress, 8)}
</code>
<p className="text-xs text-green-400">KYC Pejirandî</p>
</div>
<div className="text-right">
<span className="text-green-400 text-sm font-medium">
+{getPointsForPosition(index + 1)} pûan
</span>
</div>
</div>
))}
</div>
) : (
<div className="flex flex-col items-center justify-center py-12 text-center">
<Users className="w-12 h-12 text-muted-foreground mb-4" />
<p className="text-muted-foreground">Hêj referralên te tune ne</p>
<p className="text-sm text-muted-foreground mt-1">Lînka xwe parve bike!</p>
<button
onClick={handleShare}
className="mt-4 flex items-center gap-2 px-4 py-2 bg-primary rounded-lg text-primary-foreground text-sm font-medium"
>
<Share2 className="w-4 h-4" />
Parve bike
</button>
</div>
)}
</div>
)}
{/* Scores Tab */}
{activeTab === 'scores' && (
<div className="p-4 space-y-4">
{scoresLoading ? (
<div className="space-y-4">
{[1, 2, 3, 4].map((i) => (
<div key={i} className="bg-secondary/50 rounded-xl p-4 animate-pulse">
<div className="h-6 bg-secondary rounded w-1/2 mb-2" />
<div className="h-8 bg-secondary rounded w-1/3" />
</div>
))}
</div>
) : (
<>
{/* Trust Score - Main Card */}
<div className="bg-gradient-to-br from-purple-600 to-indigo-600 rounded-2xl p-5 text-white">
<div className="flex items-center justify-between mb-4">
<div>
<p className="text-purple-100 text-sm flex items-center gap-2">
<Shield className="w-4 h-4" />
Pûana Pêbaweriyê (Trust)
</p>
<p
className={cn(
'text-5xl font-bold mt-1',
getScoreColor(userScores?.trustScore || 0)
)}
>
{userScores?.trustScore ?? 0}
</p>
</div>
<div className="w-16 h-16 rounded-full bg-white/20 flex items-center justify-center">
<Trophy className="w-8 h-8" />
</div>
</div>
<div className="flex items-center justify-between text-sm">
<span className="text-purple-100">
Rêze: {getScoreRating(userScores?.trustScore || 0)}
</span>
{userScores?.isCitizen && (
<span className="bg-green-500/30 text-green-200 px-2 py-1 rounded-full text-xs">
Welatî
</span>
)}
</div>
</div>
{/* Score Components Grid */}
<div className="grid grid-cols-2 gap-3">
{/* Staking Score */}
<div className="bg-secondary/30 rounded-xl p-4 border border-border/50">
<div className="flex items-center gap-2 mb-2">
<Target className="w-4 h-4 text-blue-400" />
<span className="text-xs text-muted-foreground">Staking</span>
</div>
<p className="text-2xl font-bold text-blue-400">
{userScores?.stakingScore ?? 0}
</p>
{stakingDetails && stakingDetails.stakedAmount > 0n && (
<p className="text-xs text-muted-foreground mt-1">
{formatStakedAmount(stakingDetails.stakedAmount)} HEZ
</p>
)}
</div>
{/* Referral Score */}
<div className="bg-secondary/30 rounded-xl p-4 border border-border/50">
<div className="flex items-center gap-2 mb-2">
<Users className="w-4 h-4 text-green-400" />
<span className="text-xs text-muted-foreground">Referral</span>
</div>
<p className="text-2xl font-bold text-green-400">
{userScores?.referralScore ?? 0}
</p>
<p className="text-xs text-muted-foreground mt-1">
{stats?.referralCount ?? 0} kes
</p>
</div>
{/* Tiki Score */}
<div className="bg-secondary/30 rounded-xl p-4 border border-border/50">
<div className="flex items-center gap-2 mb-2">
<Sparkles className="w-4 h-4 text-yellow-400" />
<span className="text-xs text-muted-foreground">Tiki</span>
</div>
<p className="text-2xl font-bold text-yellow-400">
{userScores?.tikiScore ?? 0}
</p>
<p className="text-xs text-muted-foreground mt-1">Rola NFT</p>
</div>
{/* Perwerde Score */}
<div className="bg-secondary/30 rounded-xl p-4 border border-border/50">
<div className="flex items-center gap-2 mb-2">
<GraduationCap className="w-4 h-4 text-pink-400" />
<span className="text-xs text-muted-foreground">Perwerde</span>
</div>
<p className="text-2xl font-bold text-pink-400">
{userScores?.perwerdeScore ?? 0}
</p>
<p className="text-xs text-muted-foreground mt-1">Xwendin</p>
</div>
</div>
{/* Staking Details Card */}
{stakingDetails && stakingDetails.stakedAmount > 0n && (
<div className="bg-secondary/30 rounded-xl p-4 border border-border/50">
<h3 className="font-medium text-foreground mb-3 flex items-center gap-2">
<TrendingUp className="w-4 h-4 text-blue-400" />
Staking Hûrgelan
</h3>
<div className="space-y-2 text-sm">
<div className="flex justify-between py-2 border-b border-border/30">
<span className="text-muted-foreground">HEZ Staked</span>
<span className="text-foreground font-medium">
{formatStakedAmount(stakingDetails.stakedAmount)} HEZ
</span>
</div>
<div className="flex justify-between py-2 border-b border-border/30">
<span className="text-muted-foreground">Demjimêr</span>
<span className="text-foreground font-medium">
{stakingDetails.monthsStaked} meh
</span>
</div>
<div className="flex justify-between py-2 border-b border-border/30">
<span className="text-muted-foreground">Pir Zêdeker</span>
<span className="text-foreground font-medium">
{stakingDetails.timeMultiplier}x
</span>
</div>
<div className="flex justify-between py-2">
<span className="text-muted-foreground">Nominasyon</span>
<span className="text-foreground font-medium">
{stakingDetails.nominationsCount}
</span>
</div>
</div>
</div>
)}
{/* Score Formula Info */}
<div className="bg-secondary/30 rounded-xl p-4 border border-border/50">
<h3 className="font-medium text-foreground mb-3 flex items-center gap-2">
<Star className="w-4 h-4 text-yellow-400" />
Formûla Pûanê
</h3>
<div className="text-sm text-muted-foreground space-y-2">
<p>Trust = (Staking × Weighted Sum) / 100</p>
<p className="text-xs">
Weighted Sum = Staking×100 + Referral×300 + Perwerde×300 + Tiki×300
</p>
<div className="mt-3 p-2 bg-yellow-500/10 rounded-lg border border-yellow-500/20">
<p className="text-yellow-300 text-xs">
Staking 0 be, Trust pûan 0 dibe. Berî her tiştî stake bike!
</p>
</div>
</div>
</div>
{/* Refresh Button */}
<button
onClick={fetchUserScores}
disabled={scoresLoading}
className="w-full py-3 bg-primary rounded-lg text-primary-foreground font-medium flex items-center justify-center gap-2"
>
<RefreshCw className={cn('w-4 h-4', scoresLoading && 'animate-spin')} />
Pûanan Nûve Bike
</button>
</>
)}
</div>
)}
</div>
</div>
);
}