"use client" import { useState, useEffect } from "react" import { useParams } from "next/navigation" import { Button } from "@/components/ui/button" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" import { Textarea } from "@/components/ui/textarea" import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog" import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from "@/components/ui/alert-dialog" import { Plus, Edit, Trash2, ArrowLeft, User, Upload, X } from "lucide-react" import Link from "next/link" import Image from "next/image" import { AuthGuard } from "@/components/auth-guard" import { useAuth } from "@/hooks/use-auth" import apiClient from "@/lib/api-client" import { API_CONFIG } from "@/lib/config" import { useToast } from "@/hooks/use-toast" interface VoteEvent { id: string title: string description: string start_date: string end_date: string is_active: boolean is_voting_open: boolean } interface Candidate { id: string vote_event_id: string name: string image_url: string description: string created_at: string updated_at: string } interface CandidateFormData { name: string description: string image_url: string } function CandidateManagementContent() { const { user, logout } = useAuth() const { toast } = useToast() const params = useParams() const eventId = params.eventId as string const [event, setEvent] = useState(null) const [candidates, setCandidates] = useState([]) const [loading, setLoading] = useState(true) const [formData, setFormData] = useState({ name: "", description: "", image_url: "" }) const [editingCandidate, setEditingCandidate] = useState(null) const [isDialogOpen, setIsDialogOpen] = useState(false) const [submitting, setSubmitting] = useState(false) const [uploadingImage, setUploadingImage] = useState(false) const [imageFile, setImageFile] = useState(null) const [imagePreview, setImagePreview] = useState("") useEffect(() => { if (eventId) { fetchEventDetails() fetchCandidates() } }, [eventId]) const fetchEventDetails = async () => { try { const response = await apiClient.get(`${API_CONFIG.ENDPOINTS.VOTE_EVENTS}/${eventId}`) if (response.data.success) { setEvent(response.data.data) } } catch (error) { console.error('Error fetching event details:', error) toast({ title: "Error", description: "Failed to fetch event details", variant: "destructive" }) } } const fetchCandidates = async () => { try { setLoading(true) const response = await apiClient.get(`${API_CONFIG.ENDPOINTS.VOTE_EVENTS}/${eventId}/candidates`) if (response.data.success) { setCandidates(response.data.data.candidates || []) } } catch (error) { console.error('Error fetching candidates:', error) toast({ title: "Error", description: "Failed to fetch candidates", variant: "destructive" }) } finally { setLoading(false) } } const handleImageChange = (e: React.ChangeEvent) => { const file = e.target.files?.[0] if (file) { // Validate file type const validTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/webp'] if (!validTypes.includes(file.type)) { toast({ title: "Invalid File Type", description: "Please select a valid image file (JPEG, PNG, GIF, WebP)", variant: "destructive" }) return } // Validate file size (max 5MB) const maxSize = 5 * 1024 * 1024 // 5MB if (file.size > maxSize) { toast({ title: "File Too Large", description: "Please select an image smaller than 5MB", variant: "destructive" }) return } setImageFile(file) const reader = new FileReader() reader.onloadend = () => { setImagePreview(reader.result as string) } reader.readAsDataURL(file) } } const uploadImage = async (file: File): Promise => { const formData = new FormData() formData.append('file', file) formData.append('type', file.type) try { const response = await apiClient.post(API_CONFIG.ENDPOINTS.FILES, formData, { headers: { 'Content-Type': 'multipart/form-data' } }) if (response.data.success) { return response.data.data.url } else { throw new Error('Upload failed') } } catch (error) { console.error('Error uploading image:', error) throw new Error('Failed to upload image') } } const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() setSubmitting(true) try { let imageUrl = formData.image_url // Upload new image if selected if (imageFile) { setUploadingImage(true) try { imageUrl = await uploadImage(imageFile) } catch (uploadError) { setUploadingImage(false) throw uploadError } setUploadingImage(false) } const payload = { vote_event_id: eventId, name: formData.name, image_url: imageUrl, description: formData.description } if (editingCandidate) { // Update existing candidate await apiClient.put(`${API_CONFIG.ENDPOINTS.CANDIDATES}/${editingCandidate.id}`, payload) toast({ title: "Success", description: "Candidate updated successfully" }) } else { // Create new candidate await apiClient.post(API_CONFIG.ENDPOINTS.CANDIDATES, payload) toast({ title: "Success", description: "Candidate created successfully" }) } setIsDialogOpen(false) resetForm() fetchCandidates() } catch (error) { console.error('Error saving candidate:', error) toast({ title: "Error", description: editingCandidate ? "Failed to update candidate" : "Failed to create candidate", variant: "destructive" }) } finally { setSubmitting(false) } } const handleEdit = (candidate: Candidate) => { setEditingCandidate(candidate) setFormData({ name: candidate.name, description: candidate.description, image_url: candidate.image_url }) setImagePreview(candidate.image_url) setIsDialogOpen(true) } const handleDelete = async (candidateId: string) => { try { await apiClient.delete(`${API_CONFIG.ENDPOINTS.CANDIDATES}/${candidateId}`) toast({ title: "Success", description: "Candidate deleted successfully" }) fetchCandidates() } catch (error) { console.error('Error deleting candidate:', error) toast({ title: "Error", description: "Failed to delete candidate", variant: "destructive" }) } } const resetForm = () => { setFormData({ name: "", description: "", image_url: "" }) setEditingCandidate(null) setImageFile(null) setImagePreview("") setUploadingImage(false) } const removeImage = () => { setImageFile(null) setImagePreview("") setFormData({ ...formData, image_url: "" }) } return (
METI - New & Renewable Energy

Candidate Management

{event && (

{event.title}

)}
Welcome, {user?.username || 'Admin'}
{/* Header with Create Button */}

Candidates

Manage candidates for this voting event

{editingCandidate ? 'Edit Candidate' : 'Add New Candidate'} {editingCandidate ? 'Update the candidate details below.' : 'Fill in the details to add a new candidate.'}
setFormData({ ...formData, name: e.target.value })} placeholder="Enter candidate name" required />