144 lines
No EOL
5.2 KiB
JavaScript
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; |