aethex-us/contribute/src/components/PassportModal.jsx

144 lines
No EOL
5.2 KiB
JavaScript

import React, { useEffect, useState } from 'react';
import { motion } from 'framer-motion';
import { X, Copy, Check, Loader2 } from 'lucide-react';
import { QRCode } from 'react-qrcode-logo';
import AeThexLogo from './AeThexLogo';
import { useAuth } from '@/contexts/SupabaseAuthContext';
import { supabase } from '@/lib/customSupabaseClient';
import toast from 'react-hot-toast';
const backdropVariants = {
visible: { opacity: 1 },
hidden: { opacity: 0 }
};
const modalVariants = {
hidden: { opacity: 0, scale: 0.9, y: 50 },
visible: {
opacity: 1,
scale: 1,
y: 0,
transition: { type: 'spring', damping: 25, stiffness: 200 }
},
exit: {
opacity: 0,
scale: 0.9,
y: 50,
transition: { duration: 0.2 }
}
};
const PassportModal = ({ onClose }) => {
const { user } = useAuth();
const [profile, setProfile] = useState(null);
const [loading, setLoading] = useState(true);
const [copied, setCopied] = useState(false);
useEffect(() => {
const fetchProfile = async () => {
if (user) {
setLoading(true);
const { data, error } = await supabase
.from('profiles')
.select('username, avatar_url, aethex_passport_id, created_at')
.eq('id', user.id)
.single();
if (error) {
console.error('Error fetching profile:', error);
toast.error("Failed to load Passport data.");
} else {
setProfile(data);
}
setLoading(false);
}
};
fetchProfile();
}, [user]);
const handleCopy = () => {
if (profile?.aethex_passport_id) {
navigator.clipboard.writeText(profile.aethex_passport_id);
setCopied(true);
toast.success("Passport ID Copied!");
setTimeout(() => setCopied(false), 2000);
}
};
return (
<motion.div
variants={backdropVariants}
initial="hidden"
animate="visible"
exit="hidden"
className="fixed inset-0 bg-black/80 backdrop-blur-sm z-50 flex items-center justify-center p-4"
onClick={onClose}
>
<motion.div
variants={modalVariants}
className="relative bg-gray-900 rounded-2xl border border-primary/20 w-full max-w-sm shadow-2xl shadow-primary/10 overflow-hidden"
onClick={(e) => e.stopPropagation()}
>
<button
onClick={onClose}
className="absolute top-4 right-4 z-20 bg-black/50 hover:bg-black/70 text-white p-2 rounded-full transition-colors"
>
<X className="w-5 h-5" />
</button>
<div className="relative p-8 bg-grid-pattern">
<div className="absolute inset-0 bg-gradient-to-b from-transparent to-gray-900"></div>
<div className="relative z-10 flex flex-col items-center text-center">
<img
src={profile?.avatar_url || 'https://i.pravatar.cc/150?u=a042581f4e29026704d'}
alt="User Avatar"
className="w-24 h-24 rounded-full object-cover border-4 border-primary shadow-lg"
/>
<h2 className="text-2xl font-bold text-white mt-4">{profile?.username || 'Loading...'}</h2>
<p className="text-sm text-gray-400">{user?.email}</p>
</div>
</div>
<div className="p-8">
{loading ? (
<div className="flex justify-center items-center h-48">
<Loader2 className="w-8 h-8 text-primary animate-spin" />
</div>
) : (
<div className="flex flex-col items-center space-y-6">
<div className="bg-white p-3 rounded-lg shadow-md">
<QRCode
value={profile?.aethex_passport_id || 'no-id'}
size={150}
logoImage="/aethex-icon.svg"
logoWidth={40}
logoHeight={40}
qrStyle="dots"
eyeRadius={5}
/>
</div>
<div className="text-center w-full">
<p className="text-xs text-gray-500 uppercase font-semibold">Passport ID</p>
<div className="flex items-center justify-center mt-1 bg-gray-800 rounded-lg px-3 py-2 border border-gray-700">
<p className="text-sm text-primary font-mono truncate">{profile?.aethex_passport_id}</p>
<button onClick={handleCopy} className="ml-3 text-gray-400 hover:text-white">
{copied ? <Check className="w-4 h-4 text-green-500"/> : <Copy className="w-4 h-4" />}
</button>
</div>
</div>
<div className="text-center">
<p className="text-xs text-gray-500 uppercase font-semibold">Member Since</p>
<p className="text-sm text-white mt-1">{profile ? new Date(profile.created_at).toLocaleDateString() : '...'}</p>
</div>
</div>
)}
</div>
<div className="bg-gray-900/50 px-8 py-4 border-t border-gray-800 flex justify-center items-center">
<AeThexLogo />
</div>
</motion.div>
</motion.div>
);
};
export default PassportModal;