diff --git a/web/src/pages/Citizens.tsx b/web/src/pages/Citizens.tsx index f5fc89a4..ac67ec8a 100644 --- a/web/src/pages/Citizens.tsx +++ b/web/src/pages/Citizens.tsx @@ -3,15 +3,23 @@ import { useNavigate } from 'react-router-dom'; import { Card, CardContent } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; +import { Label } from '@/components/ui/label'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from '@/components/ui/dialog'; import { usePezkuwi } from '@/contexts/PezkuwiContext'; -import { useAuth } from '@/contexts/AuthContext'; import { useDashboard } from '@/contexts/DashboardContext'; -import { FileText, Building2, Home, Bell, ChevronLeft, ChevronRight, Upload, User, Sun, ShieldCheck } from 'lucide-react'; +import { FileText, Building2, Home, Bell, ChevronLeft, ChevronRight, Upload, User, Sun, ShieldCheck, Pencil } from 'lucide-react'; import { useToast } from '@/hooks/use-toast'; -// import { getCitizenSession } from '@pezkuwi/lib/citizenship-workflow'; import { getUserRoleCategories } from '@pezkuwi/lib/tiki'; -import { supabase } from '@/lib/supabase'; + +// LocalStorage key prefix for citizen profile data +const CITIZEN_PROFILE_KEY = 'citizen_profile_'; + +interface CitizenProfileData { + fullName: string; + fatherName: string; + location: string; + photoUrl: string | null; +} // Mock announcements data const announcements = [ @@ -37,12 +45,10 @@ const announcements = [ export default function Citizens() { const { selectedAccount } = usePezkuwi(); - const { user } = useAuth(); const navigate = useNavigate(); const { toast } = useToast(); - const { profile, nftDetails, citizenNumber, loading } = useDashboard(); + const { nftDetails, citizenNumber, loading } = useDashboard(); const [currentAnnouncementIndex, setCurrentAnnouncementIndex] = useState(0); - const [photoUrl, setPhotoUrl] = useState(null); const [uploadingPhoto, setUploadingPhoto] = useState(false); const fileInputRef = useRef(null); const [showGovDialog, setShowGovDialog] = useState(false); @@ -51,14 +57,67 @@ export default function Citizens() { const [isVerifying, setIsVerifying] = useState(false); const [dialogType, setDialogType] = useState<'gov' | 'citizens'>('gov'); + // Citizen profile from localStorage + const [citizenProfile, setCitizenProfile] = useState({ + fullName: '', + fatherName: '', + location: '', + photoUrl: null + }); + const [showEditModal, setShowEditModal] = useState(false); + const [editForm, setEditForm] = useState({ + fullName: '', + fatherName: '', + location: '', + photoUrl: null + }); + + // Load citizen profile from localStorage on mount useEffect(() => { - if (profile?.avatar_url) { - setPhotoUrl(profile.avatar_url); + if (selectedAccount?.address) { + const storageKey = CITIZEN_PROFILE_KEY + selectedAccount.address; + const savedProfile = localStorage.getItem(storageKey); + if (savedProfile) { + try { + const parsed = JSON.parse(savedProfile) as CitizenProfileData; + setCitizenProfile(parsed); + setEditForm(parsed); + } catch (e) { + console.error('Error parsing saved profile:', e); + } + } else { + // No saved profile - prompt user to fill in their info + setShowEditModal(true); + } } - }, [profile]); + }, [selectedAccount?.address]); + + // Save citizen profile to localStorage + const saveCitizenProfile = (data: CitizenProfileData) => { + if (selectedAccount?.address) { + const storageKey = CITIZEN_PROFILE_KEY + selectedAccount.address; + localStorage.setItem(storageKey, JSON.stringify(data)); + setCitizenProfile(data); + toast({ + title: "Profîl hat tomarkirin (Profile saved)", + description: "Zanyariyên we bi serkeftî hatin tomarkirin (Your information has been saved successfully)" + }); + } + }; const handlePhotoUpload = async (event: React.ChangeEvent) => { - if (!event.target.files || !event.target.files[0] || !user) return; + if (!event.target.files || !event.target.files[0]) { + return; + } + + if (!selectedAccount?.address) { + toast({ + title: "Cüzdan bağlı değil (Wallet not connected)", + description: "Ji kerema xwe wallet-ê xwe girêbide (Please connect your wallet)", + variant: "destructive" + }); + return; + } const file = event.target.files[0]; @@ -72,11 +131,11 @@ export default function Citizens() { return; } - // Validate file size (max 5MB) - if (file.size > 5 * 1024 * 1024) { + // Validate file size (max 2MB for localStorage) + if (file.size > 2 * 1024 * 1024) { toast({ title: "Dosya çok büyük (File too large)", - description: "Maksimum dosya boyutu 5MB (Maximum file size is 5MB)", + description: "Maksimum dosya boyutu 2MB (Maximum file size is 2MB)", variant: "destructive" }); return; @@ -86,44 +145,36 @@ export default function Citizens() { try { // Convert file to base64 data URL - const reader = new FileReader(); - reader.onloadend = async () => { - const dataUrl = reader.result as string; + const dataUrl = await new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onloadend = () => { + if (reader.result) { + resolve(reader.result as string); + } else { + reject(new Error('Failed to read file')); + } + }; + reader.onerror = () => reject(new Error('FileReader error')); + reader.readAsDataURL(file); + }); - // Update profile with data URL (for now - until storage bucket is created) - const { error: updateError } = await supabase - .from('profiles') - .update({ avatar_url: dataUrl }) - .eq('id', user.id); + // Save to localStorage with profile + const updatedProfile = { ...citizenProfile, photoUrl: dataUrl }; + saveCitizenProfile(updatedProfile); - if (updateError) throw updateError; - - setPhotoUrl(dataUrl); - setUploadingPhoto(false); - toast({ - title: "Fotoğraf yüklendi (Photo uploaded)", - description: "Profil fotoğrafınız başarıyla güncellendi (Your profile photo has been updated successfully)" - }); - }; - - reader.onerror = () => { - setUploadingPhoto(false); - toast({ - title: "Yükleme hatası (Upload error)", - description: "Fotoğraf okunamadı (Could not read photo)", - variant: "destructive" - }); - }; - - reader.readAsDataURL(file); - } catch (error) { - if (import.meta.env.DEV) console.error('Photo upload error:', error); - setUploadingPhoto(false); toast({ - title: "Yükleme hatası (Upload error)", - description: error instanceof Error ? error.message : "Fotoğraf yüklenemedi (Could not upload photo)", + title: "Wêne hat barkirin (Photo uploaded)", + description: "Wêneyê we bi serkeftî hat tomarkirin (Your photo has been saved successfully)" + }); + } catch (error) { + console.error('Photo upload error:', error); + toast({ + title: "Xeletiya barkirinê (Upload error)", + description: error instanceof Error ? error.message : "Wêne nehat barkirin (Could not upload photo)", variant: "destructive" }); + } finally { + setUploadingPhoto(false); } }; @@ -428,8 +479,8 @@ export default function Citizens() { {/* Photo Frame */}
- {photoUrl ? ( - Citizen Photo + {citizenProfile.photoUrl ? ( + Citizen Photo ) : (
@@ -467,23 +518,35 @@ export default function Citizens() {
{/* Middle Section - Personal Info */} -
+
+ {/* Edit Button */} + + {/* Name */}
Nav / Name
-
{profile?.full_name || 'N/A'}
+
{citizenProfile.fullName || 'Biguherîne...'}
{/* Father's Name */}
Navê Bav / Father's Name
-
{profile?.father_name || 'N/A'}
+
{citizenProfile.fatherName || 'Biguherîne...'}
{/* Location */}
Cih / Location
-
{profile?.location || 'N/A'}
+
{citizenProfile.location || 'Biguherîne...'}
@@ -628,6 +691,82 @@ export default function Citizens() {
+ + {/* Edit Profile Modal */} + + + + + Zanyariyên Kesane Biguherîne + + + Edit Your Personal Information + + +
+
+ + setEditForm({ ...editForm, fullName: e.target.value })} + className="border-2" + /> +
+ +
+ + setEditForm({ ...editForm, fatherName: e.target.value })} + className="border-2" + /> +
+ +
+ + setEditForm({ ...editForm, location: e.target.value })} + className="border-2" + /> +
+ +
+ + +
+
+
+
);