Files
pwap/web/src/pages/Citizens.tsx
T
pezkuwichain 4f683538d3 feat: complete i18n support for all components (6 languages)
Add full internationalization across 127+ components and pages.
790+ translation keys in en, tr, kmr, ckb, ar, fa locales.
Remove duplicate keys and delete unused .json locale files.
2026-02-22 04:48:20 +03:00

761 lines
31 KiB
TypeScript

import { useEffect, useState, useRef } from 'react';
import { useNavigate } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
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 { useDashboard } from '@/contexts/DashboardContext';
import { FileText, Building2, Home, Bell, ChevronLeft, ChevronRight, Upload, User, Sun, ShieldCheck, Pencil } from 'lucide-react';
import { useToast } from '@/hooks/use-toast';
import { getUserRoleCategories } from '@pezkuwi/lib/tiki';
// 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 = [
{
id: 1,
title: "Bijî Azadiya Kurdistanê! (Long Live Free Kurdistan!)",
description: "Bi serkeftina sîstema me ya dijîtal, em gaveke din li pêşiya azadiya xwe datînin. (With the success of our digital system, we take another step towards our freedom.)",
date: "2025-01-19"
},
{
id: 2,
title: "Daxuyaniya Nû ya Hikûmetê (New Government Announcement)",
description: "Pergalên nû yên xizmetguzariya dijîtal ji bo hemû welatiyan aktîv bûn. (New digital service systems have been activated for all citizens.)",
date: "2025-01-18"
},
{
id: 3,
title: "Civîna Giştî ya Welatiyên (Citizens General Assembly)",
description: "Civîna mehane ya welatiyên di 25ê vê mehê de pêk tê. Beşdarî bibin! (Monthly citizens assembly takes place on the 25th of this month. Participate!)",
date: "2025-01-17"
}
];
export default function Citizens() {
const { selectedAccount } = usePezkuwi();
const navigate = useNavigate();
const { toast } = useToast();
const { t } = useTranslation();
const { nftDetails, citizenNumber, loading } = useDashboard();
const [currentAnnouncementIndex, setCurrentAnnouncementIndex] = useState(0);
const [uploadingPhoto, setUploadingPhoto] = useState(false);
const fileInputRef = useRef<HTMLInputElement>(null);
const [showGovDialog, setShowGovDialog] = useState(false);
const [showCitizensDialog, setShowCitizensDialog] = useState(false);
const [citizenNumberInput, setCitizenNumberInput] = useState('');
const [isVerifying, setIsVerifying] = useState(false);
const [dialogType, setDialogType] = useState<'gov' | 'citizens'>('gov');
// Citizen profile from localStorage
const [citizenProfile, setCitizenProfile] = useState<CitizenProfileData>({
fullName: '',
fatherName: '',
location: '',
photoUrl: null
});
const [showEditModal, setShowEditModal] = useState(false);
const [editForm, setEditForm] = useState<CitizenProfileData>({
fullName: '',
fatherName: '',
location: '',
photoUrl: null
});
// Load citizen profile from localStorage on mount
useEffect(() => {
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);
}
}
}, [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: t('citizens.profileSaved'),
description: t('citizens.profileSavedDesc')
});
}
};
const handlePhotoUpload = async (event: React.ChangeEvent<HTMLInputElement>) => {
if (!event.target.files || !event.target.files[0]) {
return;
}
if (!selectedAccount?.address) {
toast({
title: t('citizens.walletNotConnected'),
description: t('citizens.connectWallet'),
variant: "destructive"
});
return;
}
const file = event.target.files[0];
// Validate file type
if (!file.type.startsWith('image/')) {
toast({
title: t('citizens.fileError'),
description: t('citizens.uploadImageOnly'),
variant: "destructive"
});
return;
}
// Validate file size (max 2MB for localStorage)
if (file.size > 2 * 1024 * 1024) {
toast({
title: t('citizens.fileTooLarge'),
description: t('citizens.maxFileSize'),
variant: "destructive"
});
return;
}
setUploadingPhoto(true);
try {
// Convert file to base64 data URL
const dataUrl = await new Promise<string>((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);
});
// Save to localStorage with profile
const updatedProfile = { ...citizenProfile, photoUrl: dataUrl };
saveCitizenProfile(updatedProfile);
toast({
title: t('citizens.photoUploaded'),
description: t('citizens.photoUploadedDesc')
});
} catch (error) {
console.error('Photo upload error:', error);
toast({
title: t('citizens.uploadError'),
description: error instanceof Error ? error.message : t('citizens.couldNotUpload'),
variant: "destructive"
});
} finally {
setUploadingPhoto(false);
}
};
// Handle case where no wallet is connected
if (!selectedAccount && !loading) {
return (
<div className="min-h-screen bg-gradient-to-br from-green-700 via-white to-red-600 flex items-center justify-center">
<Card className="bg-white/90 backdrop-blur max-w-md">
<CardContent className="pt-6">
<div className="text-center space-y-4">
<p className="text-xl font-bold text-red-700">{t('citizens.connectWalletMsg')}</p>
<Button
onClick={() => navigate('/')}
className="bg-red-600 hover:bg-red-700 text-white"
>
<Home className="mr-2 h-4 w-4" />
{t('citizens.backToHome')}
</Button>
</div>
</CardContent>
</Card>
</div>
);
}
const handleCitizensIssue = () => {
// Check if user has Tiki NFT
if (!nftDetails.citizenNFT) {
toast({
title: t('citizens.noAccess'),
description: t('citizens.noAccessDesc'),
variant: "destructive"
});
return;
}
// Show citizen number verification dialog for Citizens Issues
setDialogType('citizens');
setShowCitizensDialog(true);
};
const handleGovEntrance = () => {
// Check if user has Tiki NFT
if (!nftDetails.citizenNFT) {
toast({
title: t('citizens.noAccess'),
description: t('citizens.noAccessDesc'),
variant: "destructive"
});
return;
}
// Navigate directly - GovernmentEntrance will handle verification
navigate('/citizens/government');
};
const handleVerifyCitizenNumber = () => {
setIsVerifying(true);
// Construct the full citizen number format: #42-0-123456
const actualCitizenNumber = nftDetails.citizenNFT
? `#${nftDetails.citizenNFT.collectionId}-${nftDetails.citizenNFT.itemId}-${citizenNumber}`
: '';
// Clean and compare
const inputCleaned = citizenNumberInput.trim().toUpperCase();
if (inputCleaned === actualCitizenNumber.toUpperCase()) {
setShowGovDialog(false);
setShowCitizensDialog(false);
setCitizenNumberInput('');
if (dialogType === 'gov') {
toast({
title: t('citizens.authSuccess'),
description: t('citizens.govAuthDesc'),
});
navigate('/citizens/government');
} else {
toast({
title: t('citizens.authSuccess'),
description: t('citizens.citizenAuthDesc'),
});
navigate('/citizens/issues');
}
} else {
toast({
title: t('citizens.wrongNumber'),
description: t('citizens.wrongNumberDesc'),
variant: "destructive"
});
}
setIsVerifying(false);
};
const nextAnnouncement = () => {
setCurrentAnnouncementIndex((prev) => (prev + 1) % announcements.length);
};
const prevAnnouncement = () => {
setCurrentAnnouncementIndex((prev) => (prev - 1 + announcements.length) % announcements.length);
};
if (loading) {
return (
<div className="min-h-screen bg-gradient-to-br from-green-700 via-white to-red-600 flex items-center justify-center">
<Card className="bg-white/90 backdrop-blur">
<CardContent className="pt-6">
<div className="flex items-center space-x-4">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-red-600"></div>
<p className="text-gray-700 font-medium">{t('citizens.loading')}</p>
</div>
</CardContent>
</Card>
</div>
);
}
// Get role categories for display
const roleCategories = getUserRoleCategories(nftDetails.roleNFTs) || {
government: [],
citizen: [],
business: [],
judicial: []
};
if (import.meta.env.DEV) console.log('Role categories:', roleCategories);
const currentAnnouncement = announcements[currentAnnouncementIndex];
return (
<div className="min-h-screen bg-gradient-to-br from-green-700 via-white to-red-600">
<div className="container mx-auto px-4 py-8">
{/* Back Button */}
<div className="mb-6">
<Button
onClick={() => navigate('/')}
variant="outline"
className="bg-red-600 hover:bg-red-700 border-yellow-400 border-2 text-white font-semibold shadow-lg"
>
<Home className="mr-2 h-4 w-4" />
{t('citizens.backToHome')}
</Button>
</div>
{/* Title Section */}
<div className="text-center mb-8">
<h1 className="text-5xl md:text-6xl font-bold text-red-700 mb-3 drop-shadow-lg">
{t('citizens.portalTitle')}
</h1>
<p className="text-xl text-gray-800 font-semibold drop-shadow-md">
{t('citizens.digitalKurdistan')}
</p>
</div>
{/* Announcements Widget - Modern Carousel */}
<div className="max-w-4xl mx-auto mb-8">
<div className="relative bg-gradient-to-r from-red-600 via-red-500 to-yellow-500 rounded-3xl shadow-xl overflow-hidden">
<div className="absolute inset-0 bg-black/10"></div>
<div className="relative p-8">
<div className="flex items-center justify-between">
<button
onClick={prevAnnouncement}
className="z-10 text-white/80 hover:text-white transition-all hover:scale-110"
>
<ChevronLeft className="h-8 w-8" />
</button>
<div className="flex-1 text-center px-6">
<div className="flex items-center justify-center mb-3">
<Bell className="h-7 w-7 text-white mr-3 animate-pulse" />
<h3 className="text-3xl font-bold text-white">{t('citizens.announcements')}</h3>
</div>
<h4 className="text-xl font-bold text-white mb-3">{currentAnnouncement.title}</h4>
<p className="text-white/90 text-base leading-relaxed max-w-2xl mx-auto">{currentAnnouncement.description}</p>
<p className="text-white/70 text-sm mt-3">{currentAnnouncement.date}</p>
{/* Modern dots indicator */}
<div className="flex justify-center gap-3 mt-5">
{announcements.map((_, idx) => (
<button
key={idx}
onClick={() => setCurrentAnnouncementIndex(idx)}
className={`h-2.5 rounded-full transition-all duration-300 ${
idx === currentAnnouncementIndex
? 'bg-white w-8'
: 'bg-white/40 w-2.5 hover:bg-white/60'
}`}
/>
))}
</div>
</div>
<button
onClick={nextAnnouncement}
className="z-10 text-white/80 hover:text-white transition-all hover:scale-110"
>
<ChevronRight className="h-8 w-8" />
</button>
</div>
</div>
</div>
</div>
{/* Main Entrance Cards - Grid with exactly 2 cards */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 max-w-5xl mx-auto mb-12">
{/* LEFT: Citizens Issues */}
<Card
className="bg-white/95 backdrop-blur border-4 border-purple-400 hover:border-purple-600 transition-all shadow-2xl cursor-pointer group hover:scale-105"
onClick={handleCitizensIssue}
>
<CardContent className="p-8 flex flex-col items-center justify-center min-h-[300px]">
<div className="mb-6">
<div className="bg-purple-500 w-24 h-24 rounded-2xl flex items-center justify-center group-hover:scale-110 transition-transform shadow-xl">
<FileText className="h-12 w-12 text-white" />
</div>
</div>
<h2 className="text-3xl font-bold text-purple-700 mb-2 text-center">
{t('citizens.citizenIssues')}
</h2>
</CardContent>
</Card>
{/* RIGHT: Gov Entrance */}
<Card
className="bg-white/95 backdrop-blur border-4 border-green-400 hover:border-green-600 transition-all shadow-2xl cursor-pointer group hover:scale-105"
onClick={handleGovEntrance}
>
<CardContent className="p-8 flex flex-col items-center justify-center min-h-[300px]">
<div className="mb-6">
<div className="bg-green-600 w-24 h-24 rounded-2xl flex items-center justify-center group-hover:scale-110 transition-transform shadow-xl">
<Building2 className="h-12 w-12 text-white" />
</div>
</div>
<h2 className="text-3xl font-bold text-green-700 mb-2 text-center">
{t('citizens.govEntrance')}
</h2>
</CardContent>
</Card>
</div>
{/* Digital Citizen ID Card - Pure HTML/CSS Design */}
<div className="max-w-2xl mx-auto">
<div
className="relative rounded-2xl overflow-hidden shadow-2xl"
style={{
background: 'linear-gradient(135deg, #166534 0%, #16a34a 15%, #ffffff 35%, #ffffff 65%, #dc2626 85%, #991b1b 100%)',
aspectRatio: '1.586/1'
}}
>
{/* Security Pattern Overlay */}
<div
className="absolute inset-0 opacity-[0.03]"
style={{
backgroundImage: `repeating-linear-gradient(
45deg,
transparent,
transparent 10px,
#000 10px,
#000 11px
)`
}}
/>
{/* Top Header Band */}
<div className="absolute top-0 left-0 right-0 bg-gradient-to-r from-green-800 via-green-700 to-green-800 py-3 px-4">
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
{/* Sun Symbol */}
<div className="relative">
<Sun className="h-8 w-8 text-yellow-400 drop-shadow-lg" />
<div className="absolute inset-0 animate-pulse">
<Sun className="h-8 w-8 text-yellow-300 opacity-50" />
</div>
</div>
<div>
<div className="text-white font-bold text-sm tracking-wider">KOMARÎ KURDISTAN</div>
<div className="text-green-200 text-[10px] tracking-wide">REPUBLIC OF KURDISTAN</div>
</div>
</div>
<div className="text-right">
<div className="text-yellow-400 font-bold text-xs">NASNAMEYA DÎJÎTAL</div>
<div className="text-green-200 text-[10px]">DIGITAL IDENTITY CARD</div>
</div>
</div>
</div>
{/* Main Content Area */}
<div className="absolute top-16 bottom-10 left-0 right-0 px-5 flex flex-col sm:flex-row">
{/* Left Section - Photo */}
<div className="w-1/4 flex flex-col items-center justify-center">
<div className="relative w-full aspect-[3/4] max-w-[120px] group">
{/* Photo Frame */}
<div className="absolute inset-0 bg-gradient-to-br from-green-600 to-red-600 rounded-lg p-[2px]">
<div className="w-full h-full bg-white rounded-lg overflow-hidden flex items-center justify-center">
{citizenProfile.photoUrl ? (
<img src={citizenProfile.photoUrl} alt="Citizen Photo" className="w-full h-full object-cover" />
) : (
<div className="w-full h-full bg-gray-100 flex items-center justify-center">
<User className="w-12 h-12 text-gray-300" />
</div>
)}
</div>
</div>
{/* Upload Overlay */}
<div className="absolute inset-0 bg-black/60 opacity-0 group-hover:opacity-100 transition-opacity rounded-lg flex items-center justify-center">
<Button
size="sm"
variant="ghost"
onClick={() => fileInputRef.current?.click()}
disabled={uploadingPhoto}
className="text-white text-xs px-2 py-1 h-auto hover:bg-white/20"
>
{uploadingPhoto ? (
<div className="animate-spin h-4 w-4 border-2 border-white rounded-full border-t-transparent" />
) : (
<>
<Upload className="h-4 w-4 mr-1" />
{t('citizens.upload')}
</>
)}
</Button>
</div>
<input
ref={fileInputRef}
type="file"
accept="image/*"
className="hidden"
onChange={handlePhotoUpload}
/>
</div>
</div>
{/* Middle Section - Personal Info */}
<div className="flex-1 px-4 flex flex-col justify-center space-y-3 relative">
{/* Edit Button */}
<button
onClick={() => {
setEditForm(citizenProfile);
setShowEditModal(true);
}}
className="absolute -top-2 right-0 bg-white/90 hover:bg-white rounded-full p-1.5 shadow-md transition-colors"
title={t('citizens.editProfile')}
>
<Pencil className="h-3 w-3 text-gray-600" />
</button>
{/* Name */}
<div className="bg-white/80 backdrop-blur-sm rounded-lg px-3 py-2 border-l-4 border-green-600 shadow-sm">
<div className="text-[10px] text-gray-500 uppercase tracking-wider font-medium">{t('citizens.nameLabel')}</div>
<div className="text-sm font-bold text-gray-800 truncate">{citizenProfile.fullName || '...'}</div>
</div>
{/* Father's Name */}
<div className="bg-white/80 backdrop-blur-sm rounded-lg px-3 py-2 border-l-4 border-yellow-500 shadow-sm">
<div className="text-[10px] text-gray-500 uppercase tracking-wider font-medium">{t('citizens.fatherNameLabel')}</div>
<div className="text-sm font-bold text-gray-800 truncate">{citizenProfile.fatherName || '...'}</div>
</div>
{/* Location */}
<div className="bg-white/80 backdrop-blur-sm rounded-lg px-3 py-2 border-l-4 border-red-600 shadow-sm">
<div className="text-[10px] text-gray-500 uppercase tracking-wider font-medium">{t('citizens.locationLabel')}</div>
<div className="text-sm font-bold text-gray-800 truncate">{citizenProfile.location || '...'}</div>
</div>
</div>
{/* Right Section - NFT & ID Numbers */}
<div className="w-full sm:w-1/4 flex flex-row sm:flex-col justify-center items-center gap-2 sm:space-y-2 mt-2 sm:mt-0">
{/* NFT Badge */}
<div className="bg-gradient-to-br from-green-700 to-green-900 rounded-xl p-2 sm:p-3 text-center shadow-lg flex-1 sm:w-full sm:max-w-[110px]">
<div className="text-[8px] sm:text-[9px] text-green-200 font-medium uppercase tracking-wider">NFT ID</div>
<div className="text-white font-bold text-xs sm:text-sm mt-1">
{nftDetails.citizenNFT ? `#${nftDetails.citizenNFT.collectionId}-${nftDetails.citizenNFT.itemId}` : 'N/A'}
</div>
</div>
{/* Citizen Number Badge */}
<div className="bg-gradient-to-br from-red-700 to-red-900 rounded-xl p-2 sm:p-3 text-center shadow-lg flex-1 sm:w-full sm:max-w-[110px]">
<div className="text-[8px] sm:text-[9px] text-red-200 font-medium uppercase tracking-wider">Hejmara Welatî</div>
<div className="text-[7px] sm:text-[8px] text-red-300 mb-1">Citizen No</div>
<div className="text-white font-bold text-[10px] sm:text-[11px]">
{nftDetails.citizenNFT ? `#${nftDetails.citizenNFT.collectionId}-${nftDetails.citizenNFT.itemId}-${citizenNumber}` : 'N/A'}
</div>
</div>
{/* Verified Badge */}
<div className="flex items-center gap-1 bg-white/90 rounded-full px-2 py-1 shadow">
<ShieldCheck className="h-3 w-3 text-green-600" />
<span className="text-[8px] sm:text-[9px] font-semibold text-green-700">VERIFIED</span>
</div>
</div>
</div>
{/* Bottom Footer Band */}
<div className="absolute bottom-0 left-0 right-0 bg-gradient-to-r from-red-800 via-red-700 to-red-800 py-2 px-4">
<div className="flex items-center justify-between text-[9px]">
<div className="text-red-200">
<span className="font-medium">Blockchain:</span> Pezkuwichain People
</div>
<div className="text-yellow-400 font-bold tracking-wider">
BIJÎ KURDISTAN
</div>
<div className="text-red-200">
<span className="font-medium">Type:</span> Welati NFT
</div>
</div>
</div>
{/* Corner Decorations */}
<div className="absolute top-14 left-2 w-6 h-6 border-l-2 border-t-2 border-green-600/30 rounded-tl-lg" />
<div className="absolute top-14 right-2 w-6 h-6 border-r-2 border-t-2 border-red-600/30 rounded-tr-lg" />
<div className="absolute bottom-8 left-2 w-6 h-6 border-l-2 border-b-2 border-green-600/30 rounded-bl-lg" />
<div className="absolute bottom-8 right-2 w-6 h-6 border-r-2 border-b-2 border-red-600/30 rounded-br-lg" />
</div>
</div>
{/* Government Entrance - Citizen Number Verification Dialog */}
<Dialog open={showGovDialog} onOpenChange={setShowGovDialog}>
<DialogContent className="sm:max-w-md bg-gradient-to-br from-green-700 via-white to-red-600">
<DialogHeader>
<DialogTitle className="text-center text-2xl font-bold text-red-700">
<div className="flex items-center justify-center mb-4">
<Sun className="h-16 w-16 text-yellow-500 animate-spin" style={{ animationDuration: '8s' }} />
</div>
{t('citizens.govDialogTitle')}
</DialogTitle>
<DialogDescription className="text-center text-gray-700 font-medium">
{t('citizens.enterCitizenNumber')}
</DialogDescription>
</DialogHeader>
<div className="space-y-4 py-4">
<div className="space-y-2">
<label className="text-sm font-semibold text-gray-800">
{t('citizens.citizenNumberLabel')}
</label>
<Input
type="text"
placeholder="#42-0-123456"
value={citizenNumberInput}
onChange={(e) => setCitizenNumberInput(e.target.value)}
className="text-center font-mono text-lg border-2 border-green-400"
onKeyDown={(e) => {
if (e.key === 'Enter' && !isVerifying) {
handleVerifyCitizenNumber();
}
}}
/>
</div>
<Button
onClick={handleVerifyCitizenNumber}
disabled={isVerifying || !citizenNumberInput.trim()}
className="w-full bg-green-600 hover:bg-green-700 text-white font-bold py-3"
>
<ShieldCheck className="mr-2 h-5 w-5" />
{isVerifying ? t('citizens.verifying') : t('citizens.enter')}
</Button>
</div>
</DialogContent>
</Dialog>
{/* Citizens Issues - Citizen Number Verification Dialog */}
<Dialog open={showCitizensDialog} onOpenChange={setShowCitizensDialog}>
<DialogContent className="sm:max-w-md bg-gradient-to-br from-green-700 via-white to-red-600">
<DialogHeader>
<DialogTitle className="text-center text-2xl font-bold text-purple-700">
<div className="flex items-center justify-center mb-4">
<Sun className="h-16 w-16 text-yellow-500 animate-spin" style={{ animationDuration: '8s' }} />
</div>
{t('citizens.citizenDialogTitle')}
</DialogTitle>
<DialogDescription className="text-center text-gray-700 font-medium">
{t('citizens.enterCitizenNumber')}
</DialogDescription>
</DialogHeader>
<div className="space-y-4 py-4">
<div className="space-y-2">
<label className="text-sm font-semibold text-gray-800">
{t('citizens.citizenNumberLabel')}
</label>
<Input
type="text"
placeholder="#42-0-123456"
value={citizenNumberInput}
onChange={(e) => setCitizenNumberInput(e.target.value)}
className="text-center font-mono text-lg border-2 border-purple-400"
onKeyDown={(e) => {
if (e.key === 'Enter' && !isVerifying) {
handleVerifyCitizenNumber();
}
}}
/>
</div>
<Button
onClick={handleVerifyCitizenNumber}
disabled={isVerifying || !citizenNumberInput.trim()}
className="w-full bg-purple-600 hover:bg-purple-700 text-white font-bold py-3"
>
<ShieldCheck className="mr-2 h-5 w-5" />
{isVerifying ? t('citizens.verifying') : t('citizens.enter')}
</Button>
</div>
</DialogContent>
</Dialog>
{/* Edit Profile Modal */}
<Dialog open={showEditModal} onOpenChange={setShowEditModal}>
<DialogContent className="sm:max-w-md">
<DialogHeader>
<DialogTitle className="text-center text-xl font-bold text-gray-800">
{t('citizens.editProfile')}
</DialogTitle>
</DialogHeader>
<div className="space-y-4 py-4">
<div className="space-y-2">
<Label htmlFor="edit-name" className="text-sm font-medium">
{t('citizens.nameLabel')}
</Label>
<Input
id="edit-name"
type="text"
placeholder={t('citizens.namePlaceholder')}
value={editForm.fullName}
onChange={(e) => setEditForm({ ...editForm, fullName: e.target.value })}
className="border-2"
/>
</div>
<div className="space-y-2">
<Label htmlFor="edit-father" className="text-sm font-medium">
{t('citizens.fatherNameLabel')}
</Label>
<Input
id="edit-father"
type="text"
placeholder={t('citizens.fatherNamePlaceholder')}
value={editForm.fatherName}
onChange={(e) => setEditForm({ ...editForm, fatherName: e.target.value })}
className="border-2"
/>
</div>
<div className="space-y-2">
<Label htmlFor="edit-location" className="text-sm font-medium">
{t('citizens.locationLabel')}
</Label>
<Input
id="edit-location"
type="text"
placeholder={t('citizens.locationPlaceholder')}
value={editForm.location}
onChange={(e) => setEditForm({ ...editForm, location: e.target.value })}
className="border-2"
/>
</div>
<div className="flex gap-2 pt-4">
<Button
variant="outline"
onClick={() => setShowEditModal(false)}
className="flex-1"
>
{t('common.cancel')}
</Button>
<Button
onClick={() => {
saveCitizenProfile(editForm);
setShowEditModal(false);
}}
className="flex-1 bg-green-600 hover:bg-green-700"
>
{t('citizens.save')}
</Button>
</div>
</div>
</DialogContent>
</Dialog>
</div>
</div>
);
}