713 lines
44 KiB
JavaScript
713 lines
44 KiB
JavaScript
import React, { useState, useEffect } from 'react';
|
|
import { Head, router, Link } from '@inertiajs/react';
|
|
import AdminLayout from '@/Layouts/AdminLayout';
|
|
import {
|
|
Search,
|
|
Filter,
|
|
Download,
|
|
Users,
|
|
Mail,
|
|
MapPin,
|
|
Calendar,
|
|
CheckCircle,
|
|
Clock,
|
|
XCircle,
|
|
ExternalLink,
|
|
MoreVertical,
|
|
BadgeDollarSign,
|
|
ShieldAlert,
|
|
TrendingUp,
|
|
AlertOctagon,
|
|
Award,
|
|
Edit2,
|
|
Trash2,
|
|
Check,
|
|
Phone,
|
|
ShieldCheck
|
|
} from 'lucide-react';
|
|
import {
|
|
Table,
|
|
TableBody,
|
|
TableCell,
|
|
TableHead,
|
|
TableHeader,
|
|
TableRow,
|
|
} from '@/components/ui/table';
|
|
import {
|
|
DropdownMenu,
|
|
DropdownMenuContent,
|
|
DropdownMenuItem,
|
|
DropdownMenuLabel,
|
|
DropdownMenuSeparator,
|
|
DropdownMenuTrigger,
|
|
} from "@/components/ui/dropdown-menu";
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
} from "@/components/ui/dialog";
|
|
import { Badge } from '@/components/ui/badge';
|
|
|
|
export default function SponsorsIndex({ sponsors, filters = {} }) {
|
|
const [searchTerm, setSearchTerm] = useState(filters.search || '');
|
|
const [statusFilter, setStatusFilter] = useState(filters.status || 'All');
|
|
const [locationFilter, setLocationFilter] = useState(filters.location || 'All');
|
|
const [sortField, setSortField] = useState(filters.sort_field || 'created_at');
|
|
const [sortOrder, setSortOrder] = useState(filters.sort_order || 'desc');
|
|
|
|
const [selectedSponsor, setSelectedSponsor] = useState(null);
|
|
const [isDetailsOpen, setIsDetailsOpen] = useState(false);
|
|
const [isEditOpen, setIsEditOpen] = useState(false);
|
|
const [editForm, setEditForm] = useState({
|
|
id: '',
|
|
full_name: '',
|
|
email: '',
|
|
mobile: '',
|
|
city: '',
|
|
nationality: '',
|
|
address: '',
|
|
subscription_plan: 'premium',
|
|
subscription_status: 'active'
|
|
});
|
|
|
|
// Handle search/filter queries
|
|
const triggerSearch = (searchVal, statusVal, locationVal, sortF, sortO) => {
|
|
router.get('/admin/employers', {
|
|
search: searchVal,
|
|
status: statusVal,
|
|
location: locationVal,
|
|
sort_field: sortF,
|
|
sort_order: sortO
|
|
}, {
|
|
preserveState: true,
|
|
preserveScroll: true,
|
|
replace: true
|
|
});
|
|
};
|
|
|
|
useEffect(() => {
|
|
const delayDebounceFn = setTimeout(() => {
|
|
if (searchTerm !== (filters.search || '')) {
|
|
triggerSearch(searchTerm, statusFilter, locationFilter, sortField, sortOrder);
|
|
}
|
|
}, 500);
|
|
|
|
return () => clearTimeout(delayDebounceFn);
|
|
}, [searchTerm]);
|
|
|
|
const handleFilterChange = (status, location) => {
|
|
setStatusFilter(status);
|
|
setLocationFilter(location);
|
|
triggerSearch(searchTerm, status, location, sortField, sortOrder);
|
|
};
|
|
|
|
const handleSort = (field) => {
|
|
const order = sortField === field && sortOrder === 'desc' ? 'asc' : 'desc';
|
|
setSortField(field);
|
|
setSortOrder(order);
|
|
triggerSearch(searchTerm, statusFilter, locationFilter, field, order);
|
|
};
|
|
|
|
const handleApprove = (id) => {
|
|
router.post(`/admin/employers/${id}/verify`, {}, {
|
|
onSuccess: () => {
|
|
setIsDetailsOpen(false);
|
|
}
|
|
});
|
|
};
|
|
|
|
const handleSuspend = (id) => {
|
|
router.post(`/admin/employers/${id}/suspend`, {}, {
|
|
onSuccess: () => {
|
|
setIsDetailsOpen(false);
|
|
}
|
|
});
|
|
};
|
|
|
|
const handleActivate = (id) => {
|
|
router.post(`/admin/employers/${id}/activate`, {}, {
|
|
onSuccess: () => {
|
|
setIsDetailsOpen(false);
|
|
}
|
|
});
|
|
};
|
|
|
|
const handleDelete = (id) => {
|
|
if (confirm('Are you absolutely sure you want to permanently delete this sponsor registry?')) {
|
|
router.delete(`/admin/employers/${id}`);
|
|
}
|
|
};
|
|
|
|
const handleEditClick = (sponsor) => {
|
|
setEditForm({
|
|
id: sponsor.id,
|
|
full_name: sponsor.full_name,
|
|
email: sponsor.email,
|
|
mobile: sponsor.mobile,
|
|
city: sponsor.city || 'Dubai',
|
|
nationality: sponsor.nationality || '',
|
|
address: sponsor.address || '',
|
|
subscription_plan: sponsor.subscription_plan || 'premium',
|
|
subscription_status: sponsor.subscription_status || 'active'
|
|
});
|
|
setIsEditOpen(true);
|
|
};
|
|
|
|
const handleEditSubmit = (e) => {
|
|
e.preventDefault();
|
|
router.post(`/admin/employers/${editForm.id}/update`, editForm, {
|
|
onSuccess: () => {
|
|
setIsEditOpen(false);
|
|
}
|
|
});
|
|
};
|
|
|
|
const viewDetails = (sponsor) => {
|
|
setSelectedSponsor(sponsor);
|
|
setIsDetailsOpen(true);
|
|
};
|
|
|
|
return (
|
|
<AdminLayout title="Sponsor Registry & Moderation">
|
|
<Head title="Sponsor Management" />
|
|
|
|
<div className="space-y-6 font-sans">
|
|
{/* Statistics Ribbons */}
|
|
<div className="grid grid-cols-1 md:grid-cols-4 gap-5">
|
|
<div className="bg-white p-5 rounded-2xl border border-slate-200 shadow-sm flex items-center justify-between">
|
|
<div>
|
|
<span className="text-[10px] font-black text-slate-400 uppercase tracking-widest block mb-1">Total Sponsors</span>
|
|
<h3 className="text-2xl font-black text-slate-900">{sponsors.total || 0}</h3>
|
|
</div>
|
|
<div className="p-3 bg-teal-50 rounded-xl">
|
|
<Users className="w-6 h-6 text-teal-600" />
|
|
</div>
|
|
</div>
|
|
<div className="bg-white p-5 rounded-2xl border border-slate-200 shadow-sm flex items-center justify-between">
|
|
<div>
|
|
<span className="text-[10px] font-black text-slate-400 uppercase tracking-widest block mb-1">Active Passes</span>
|
|
<h3 className="text-2xl font-black text-blue-600">
|
|
{sponsors.data.filter(s => s.subscription_status === 'active').length}
|
|
</h3>
|
|
</div>
|
|
<div className="p-3 bg-blue-50 rounded-xl">
|
|
<BadgeDollarSign className="w-6 h-6 text-blue-600" />
|
|
</div>
|
|
</div>
|
|
<div className="bg-white p-5 rounded-2xl border border-slate-200 shadow-sm flex items-center justify-between">
|
|
<div>
|
|
<span className="text-[10px] font-black text-slate-400 uppercase tracking-widest block mb-1">Pending Vetting</span>
|
|
<h3 className="text-2xl font-black text-amber-500">
|
|
{sponsors.data.filter(s => !s.is_verified).length}
|
|
</h3>
|
|
</div>
|
|
<div className="p-3 bg-amber-50 rounded-xl">
|
|
<Clock className="w-6 h-6 text-amber-500" />
|
|
</div>
|
|
</div>
|
|
<div className="bg-white p-5 rounded-2xl border border-slate-200 shadow-sm flex items-center justify-between">
|
|
<div>
|
|
<span className="text-[10px] font-black text-slate-400 uppercase tracking-widest block mb-1">Suspended Registry</span>
|
|
<h3 className="text-2xl font-black text-rose-600">
|
|
{sponsors.data.filter(s => s.status === 'suspended').length}
|
|
</h3>
|
|
</div>
|
|
<div className="p-3 bg-rose-50 rounded-xl">
|
|
<ShieldAlert className="w-6 h-6 text-rose-600" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Search and Filters */}
|
|
<div className="flex flex-col lg:flex-row lg:items-center justify-between gap-4">
|
|
<div className="flex flex-1 items-center space-x-3">
|
|
<div className="relative flex-1 max-w-md">
|
|
<Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-400" />
|
|
<input
|
|
type="text"
|
|
placeholder="Search by name, email, or mobile..."
|
|
className="w-full pl-10 pr-4 py-2.5 bg-white border border-slate-200 rounded-xl text-sm font-medium focus:ring-4 focus:ring-teal-500/10 outline-none transition-all"
|
|
value={searchTerm}
|
|
onChange={e => setSearchTerm(e.target.value)}
|
|
/>
|
|
</div>
|
|
|
|
<div className="flex items-center space-x-2">
|
|
<select
|
|
className="px-4 py-2.5 bg-white border border-slate-200 rounded-xl text-xs font-bold text-slate-600 outline-none focus:ring-2 focus:ring-teal-500/10 transition-all cursor-pointer"
|
|
value={statusFilter}
|
|
onChange={e => handleFilterChange(e.target.value, locationFilter)}
|
|
>
|
|
<option value="All">All Statuses</option>
|
|
<option value="Active">Active</option>
|
|
<option value="Inactive">Inactive</option>
|
|
<option value="Suspended">Suspended</option>
|
|
</select>
|
|
|
|
<select
|
|
className="px-4 py-2.5 bg-white border border-slate-200 rounded-xl text-xs font-bold text-slate-600 outline-none focus:ring-2 focus:ring-teal-500/10 transition-all cursor-pointer"
|
|
value={locationFilter}
|
|
onChange={e => handleFilterChange(statusFilter, e.target.value)}
|
|
>
|
|
<option value="All">All Locations</option>
|
|
<option value="Dubai">Dubai</option>
|
|
<option value="Abu Dhabi">Abu Dhabi</option>
|
|
<option value="Sharjah">Sharjah</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Dynamic Sponsors Table */}
|
|
<div className="bg-white rounded-2xl border border-slate-200 shadow-sm overflow-hidden">
|
|
<Table>
|
|
<TableHeader>
|
|
<TableRow className="bg-slate-50/50 hover:bg-slate-50/50">
|
|
<TableHead onClick={() => handleSort('full_name')} className="font-bold text-slate-500 text-[10px] uppercase tracking-widest h-14 pl-8 cursor-pointer select-none">
|
|
Sponsor Info {sortField === 'full_name' && (sortOrder === 'desc' ? '↓' : '↑')}
|
|
</TableHead>
|
|
<TableHead onClick={() => handleSort('city')} className="font-bold text-slate-500 text-[10px] uppercase tracking-widest h-14 cursor-pointer select-none">
|
|
Location {sortField === 'city' && (sortOrder === 'desc' ? '↓' : '↑')}
|
|
</TableHead>
|
|
<TableHead className="font-bold text-slate-500 text-[10px] uppercase tracking-widest h-14">Subscription Plan</TableHead>
|
|
<TableHead className="font-bold text-slate-500 text-[10px] uppercase tracking-widest h-14">Verification Status</TableHead>
|
|
<TableHead onClick={() => handleSort('status')} className="font-bold text-slate-500 text-[10px] uppercase tracking-widest h-14 cursor-pointer select-none">
|
|
Status {sortField === 'status' && (sortOrder === 'desc' ? '↓' : '↑')}
|
|
</TableHead>
|
|
<TableHead className="font-bold text-slate-500 text-[10px] uppercase tracking-widest h-14 text-right pr-8">Action</TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
{sponsors.data.length > 0 ? (
|
|
sponsors.data.map((sponsor) => (
|
|
<TableRow key={sponsor.id} className="hover:bg-slate-50/50 transition-colors">
|
|
<TableCell className="py-5 pl-8">
|
|
<div className="flex items-center space-x-4">
|
|
<div className="w-10 h-10 rounded-xl bg-[#0F6E56]/10 text-[#0F6E56] flex items-center justify-center border border-[#0F6E56]/20 font-bold text-sm">
|
|
{sponsor.full_name.charAt(0)}
|
|
</div>
|
|
<div>
|
|
<h4 className="text-sm font-bold text-slate-900 leading-none mb-1">{sponsor.full_name}</h4>
|
|
<p className="text-xs text-slate-500 font-medium">{sponsor.email}</p>
|
|
<p className="text-[10px] text-slate-400 font-medium">{sponsor.mobile}</p>
|
|
</div>
|
|
</div>
|
|
</TableCell>
|
|
<TableCell>
|
|
<div className="flex items-center space-x-2 text-slate-600">
|
|
<MapPin className="w-3.5 h-3.5 text-slate-400" />
|
|
<span className="text-xs font-bold">{sponsor.city || 'Dubai'}</span>
|
|
</div>
|
|
</TableCell>
|
|
<TableCell>
|
|
<div className="flex flex-col space-y-1">
|
|
<span className={`px-2 py-0.5 rounded-lg text-[10px] font-black uppercase tracking-tight w-max ${
|
|
sponsor.subscription_plan ? 'bg-blue-50 text-blue-600 border border-blue-100' : 'bg-slate-100 text-slate-500'
|
|
}`}>
|
|
{sponsor.subscription_plan ? `${sponsor.subscription_plan} Pass` : 'No Plan'}
|
|
</span>
|
|
<span className={`text-[9px] font-bold ${
|
|
sponsor.subscription_status === 'active' ? 'text-emerald-600' : 'text-slate-400'
|
|
}`}>
|
|
Status: {sponsor.subscription_status.toUpperCase()}
|
|
</span>
|
|
</div>
|
|
</TableCell>
|
|
<TableCell>
|
|
<div className="flex items-center space-x-1.5">
|
|
{sponsor.is_verified ? (
|
|
<>
|
|
<ShieldCheck className="w-4 h-4 text-emerald-500" />
|
|
<span className="text-xs font-bold text-emerald-600">OTP Verified</span>
|
|
</>
|
|
) : (
|
|
<>
|
|
<Clock className="w-4 h-4 text-amber-500" />
|
|
<span className="text-xs font-bold text-amber-600">Unverified</span>
|
|
</>
|
|
)}
|
|
</div>
|
|
</TableCell>
|
|
<TableCell>
|
|
<div className="flex items-center space-x-2">
|
|
{sponsor.status === 'active' && <CheckCircle className="w-4 h-4 text-emerald-500" />}
|
|
{sponsor.status === 'inactive' && <Clock className="w-4 h-4 text-amber-500" />}
|
|
{sponsor.status === 'suspended' && <XCircle className="w-4 h-4 text-rose-500" />}
|
|
<span className={`text-[10px] font-black uppercase tracking-widest ${
|
|
sponsor.status === 'active' ? 'text-emerald-600' :
|
|
sponsor.status === 'inactive' ? 'text-amber-600' : 'text-rose-600'
|
|
}`}>
|
|
{sponsor.status}
|
|
</span>
|
|
</div>
|
|
</TableCell>
|
|
<TableCell className="text-right pr-8">
|
|
<div className="flex items-center justify-end space-x-1">
|
|
<button
|
|
onClick={() => viewDetails(sponsor)}
|
|
className="p-2 hover:bg-slate-100 rounded-lg text-[#0F6E56] font-bold"
|
|
title="View Details"
|
|
>
|
|
<ExternalLink className="w-4.5 h-4.5" />
|
|
</button>
|
|
<DropdownMenu>
|
|
<DropdownMenuTrigger asChild>
|
|
<button className="p-2 text-slate-400 hover:text-slate-900 hover:bg-slate-50 rounded-lg transition-all outline-none">
|
|
<MoreVertical className="w-5 h-5" />
|
|
</button>
|
|
</DropdownMenuTrigger>
|
|
<DropdownMenuContent align="end" className="w-48 p-2 rounded-xl">
|
|
<DropdownMenuLabel className="text-[9px] font-black text-slate-400 uppercase tracking-widest px-2 py-2">Quick Actions</DropdownMenuLabel>
|
|
<DropdownMenuSeparator />
|
|
<DropdownMenuItem
|
|
className="p-3 rounded-lg focus:bg-blue-50 cursor-pointer text-blue-600 font-bold"
|
|
onClick={() => handleEditClick(sponsor)}
|
|
>
|
|
<div className="flex items-center space-x-3">
|
|
<Edit2 className="w-4 h-4" />
|
|
<span className="text-xs font-bold">Edit Registry</span>
|
|
</div>
|
|
</DropdownMenuItem>
|
|
{!sponsor.is_verified && (
|
|
<DropdownMenuItem className="p-3 rounded-lg focus:bg-emerald-50 cursor-pointer text-emerald-600 font-bold" onClick={() => handleApprove(sponsor.id)}>
|
|
<div className="flex items-center space-x-3">
|
|
<CheckCircle className="w-4 h-4" />
|
|
<span className="text-xs font-bold">Approve / Verify</span>
|
|
</div>
|
|
</DropdownMenuItem>
|
|
)}
|
|
{sponsor.status === 'active' ? (
|
|
<DropdownMenuItem
|
|
onClick={() => handleSuspend(sponsor.id)}
|
|
className="p-3 rounded-lg focus:bg-rose-50 cursor-pointer text-rose-600 font-bold"
|
|
>
|
|
<div className="flex items-center space-x-3">
|
|
<XCircle className="w-4 h-4" />
|
|
<span className="text-xs font-bold">Suspend Sponsor</span>
|
|
</div>
|
|
</DropdownMenuItem>
|
|
) : (
|
|
<DropdownMenuItem
|
|
onClick={() => handleActivate(sponsor.id)}
|
|
className="p-3 rounded-lg focus:bg-emerald-50 cursor-pointer text-emerald-600 font-bold"
|
|
>
|
|
<div className="flex items-center space-x-3">
|
|
<CheckCircle className="w-4 h-4" />
|
|
<span className="text-xs font-bold">Activate Sponsor</span>
|
|
</div>
|
|
</DropdownMenuItem>
|
|
)}
|
|
<DropdownMenuSeparator />
|
|
<DropdownMenuItem
|
|
onClick={() => handleDelete(sponsor.id)}
|
|
className="p-3 rounded-lg focus:bg-red-50 cursor-pointer text-red-600 font-bold animate-pulse"
|
|
>
|
|
<div className="flex items-center space-x-3">
|
|
<Trash2 className="w-4 h-4" />
|
|
<span className="text-xs font-bold">Delete Sponsor</span>
|
|
</div>
|
|
</DropdownMenuItem>
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
</div>
|
|
</TableCell>
|
|
</TableRow>
|
|
))
|
|
) : (
|
|
<TableRow>
|
|
<TableCell colSpan={6} className="py-12 text-center text-slate-400 font-semibold text-sm">
|
|
No registered sponsors match the active search/filters criteria.
|
|
</TableCell>
|
|
</TableRow>
|
|
)}
|
|
</TableBody>
|
|
</Table>
|
|
|
|
{/* Pagination */}
|
|
{sponsors.last_page > 1 && (
|
|
<div className="p-5 border-t border-slate-100 flex items-center justify-between bg-slate-50/50">
|
|
<span className="text-xs text-slate-500 font-bold">
|
|
Showing page {sponsors.current_page} of {sponsors.last_page}
|
|
</span>
|
|
<div className="flex items-center space-x-2">
|
|
<Link
|
|
href={sponsors.prev_page_url || '#'}
|
|
only={['sponsors']}
|
|
preserveScroll
|
|
className={`px-4 py-2 bg-white border border-slate-200 rounded-xl text-xs font-bold text-slate-700 shadow-xs hover:bg-slate-50 transition-colors ${
|
|
!sponsors.prev_page_url && 'opacity-50 pointer-events-none'
|
|
}`}
|
|
>
|
|
Previous
|
|
</Link>
|
|
<Link
|
|
href={sponsors.next_page_url || '#'}
|
|
only={['sponsors']}
|
|
preserveScroll
|
|
className={`px-4 py-2 bg-white border border-slate-200 rounded-xl text-xs font-bold text-slate-700 shadow-xs hover:bg-slate-50 transition-colors ${
|
|
!sponsors.next_page_url && 'opacity-50 pointer-events-none'
|
|
}`}
|
|
>
|
|
Next
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Advanced Sponsor Detail Modal */}
|
|
<Dialog open={isDetailsOpen} onOpenChange={setIsDetailsOpen}>
|
|
<DialogContent className="sm:max-w-4xl w-full bg-white p-0 overflow-hidden rounded-[24px] border-none shadow-2xl font-sans max-h-[85vh] flex flex-col">
|
|
<div className="bg-gradient-to-r from-[#0F6E56] to-[#085041] p-6 text-white relative flex-shrink-0">
|
|
<div className="relative z-10 flex items-center space-x-4">
|
|
<div className="w-14 h-14 rounded-2xl bg-white/10 backdrop-blur-md flex items-center justify-center border border-white/20 font-black text-xl">
|
|
{selectedSponsor?.full_name.charAt(0)}
|
|
</div>
|
|
<div>
|
|
<h2 className="text-2xl font-black tracking-tight">{selectedSponsor?.full_name}</h2>
|
|
<p className="text-teal-100/80 text-xs font-semibold mt-1">📍 {selectedSponsor?.city || 'Dubai'} • Registered {new Date(selectedSponsor?.created_at).toLocaleDateString()}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="p-6 space-y-6 overflow-y-auto flex-1 bg-slate-50/50">
|
|
{/* Vetting info */}
|
|
<div className="bg-white p-5 border border-slate-200 rounded-2xl shadow-sm space-y-4">
|
|
<div className="flex items-center justify-between border-b border-slate-100 pb-2">
|
|
<h3 className="text-xs font-black text-slate-700 uppercase tracking-widest flex items-center gap-1.5">
|
|
<Award className="w-4.5 h-4.5 text-[#0F6E56]" />
|
|
<span>UAE Sponsor Vetting Dossier</span>
|
|
</h3>
|
|
<Badge className="bg-teal-50 text-[#0F6E56] border-none font-black text-[9px] uppercase px-3 py-1 rounded-lg">
|
|
Sponsor ID: SPN-{selectedSponsor?.id}
|
|
</Badge>
|
|
</div>
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<div className="text-xs font-bold text-slate-600 space-y-3">
|
|
<div className="flex items-center gap-2 text-slate-800">
|
|
<Mail className="w-4 h-4 text-slate-400" />
|
|
<span>Email: {selectedSponsor?.email}</span>
|
|
</div>
|
|
<div className="flex items-center gap-2 text-slate-800">
|
|
<Phone className="w-4 h-4 text-slate-400" />
|
|
<span>Mobile: {selectedSponsor?.mobile}</span>
|
|
</div>
|
|
{selectedSponsor?.address && (
|
|
<div className="flex items-center gap-2 text-slate-800">
|
|
<MapPin className="w-4 h-4 text-slate-400" />
|
|
<span>Address: {selectedSponsor?.address}</span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
<div className="text-xs font-bold text-slate-600 space-y-3">
|
|
<div>OTP Verification: {selectedSponsor?.is_verified ? 'Passed' : 'Pending'}</div>
|
|
{selectedSponsor?.otp_verified_at && (
|
|
<div>Verified At: {new Date(selectedSponsor.otp_verified_at).toLocaleString()}</div>
|
|
)}
|
|
<div>Nationality: {selectedSponsor?.nationality || 'N/A'}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Subscription monitoring */}
|
|
<div className="bg-white p-5 border border-slate-200 rounded-2xl shadow-sm space-y-3">
|
|
<h3 className="text-xs font-black text-slate-700 uppercase tracking-widest flex items-center gap-1.5 border-b border-slate-100 pb-2">
|
|
<BadgeDollarSign className="w-4.5 h-4.5 text-blue-600" />
|
|
<span>Premium Subscription Status</span>
|
|
</h3>
|
|
<div className="grid grid-cols-2 gap-4 text-xs font-bold text-slate-700">
|
|
<div>
|
|
<span className="text-[9px] text-slate-400 uppercase tracking-widest block font-black mb-1">Active Plan</span>
|
|
<span className="text-sm font-black text-blue-700 bg-blue-50 px-2.5 py-1 rounded-lg border border-blue-100/50 w-fit block capitalize">
|
|
{selectedSponsor?.subscription_plan || 'No Active Plan'}
|
|
</span>
|
|
</div>
|
|
<div>
|
|
<span className="text-[9px] text-slate-400 uppercase tracking-widest block font-black mb-1">Payment Status</span>
|
|
<span className="inline-flex items-center text-slate-800 bg-slate-100 px-2.5 py-1 rounded-lg border border-slate-200/50 capitalize">
|
|
{selectedSponsor?.payment_status}
|
|
</span>
|
|
</div>
|
|
{selectedSponsor?.subscription_start_date && (
|
|
<div>
|
|
<span className="text-[9px] text-slate-400 uppercase tracking-widest block font-black mb-1">Start Date</span>
|
|
<span className="font-mono text-slate-600">{new Date(selectedSponsor.subscription_start_date).toLocaleDateString()}</span>
|
|
</div>
|
|
)}
|
|
{selectedSponsor?.subscription_end_date && (
|
|
<div>
|
|
<span className="text-[9px] text-slate-400 uppercase tracking-widest block font-black mb-1">Expiry Date</span>
|
|
<span className="font-mono text-slate-600">{new Date(selectedSponsor.subscription_end_date).toLocaleDateString()}</span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="p-6 border-t border-slate-100 bg-slate-50 flex items-center justify-between flex-shrink-0">
|
|
<div className="flex items-center space-x-2">
|
|
<span className="text-[10px] font-black text-slate-400 uppercase tracking-widest">Sponsor Verification Action:</span>
|
|
{!selectedSponsor?.is_verified ? (
|
|
<button
|
|
onClick={() => handleApprove(selectedSponsor.id)}
|
|
className="px-4 py-2.5 bg-emerald-600 text-white rounded-xl text-[10px] font-black uppercase tracking-widest shadow-md shadow-emerald-600/10 hover:bg-emerald-500 transition-colors"
|
|
>
|
|
Verify Sponsor OTP
|
|
</button>
|
|
) : (
|
|
<Badge className="bg-emerald-100 text-emerald-800 border-none font-black uppercase text-[9px] px-3 py-1.5 rounded-lg shadow-sm">
|
|
OTP Verified
|
|
</Badge>
|
|
)}
|
|
</div>
|
|
|
|
<div className="flex items-center space-x-3">
|
|
{selectedSponsor?.status !== 'suspended' ? (
|
|
<button
|
|
onClick={() => handleSuspend(selectedSponsor.id)}
|
|
className="px-4 py-2.5 bg-red-600 text-white rounded-xl text-[10px] font-black uppercase tracking-widest shadow-md shadow-red-600/10 hover:bg-red-700 transition-all"
|
|
>
|
|
Suspend Sponsor
|
|
</button>
|
|
) : (
|
|
<button
|
|
onClick={() => handleActivate(selectedSponsor.id)}
|
|
className="px-4 py-2.5 bg-slate-900 text-white rounded-xl text-[10px] font-black uppercase tracking-widest hover:bg-slate-800 transition-colors"
|
|
>
|
|
Activate Registry
|
|
</button>
|
|
)}
|
|
<button
|
|
onClick={() => setIsDetailsOpen(false)}
|
|
className="px-5 py-2.5 bg-slate-200 text-slate-700 rounded-xl text-[10px] font-black uppercase tracking-widest hover:bg-slate-300 transition-colors"
|
|
>
|
|
Close Details
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</DialogContent>
|
|
</Dialog>
|
|
|
|
{/* Sponsor Edit Dialog */}
|
|
<Dialog open={isEditOpen} onOpenChange={setIsEditOpen}>
|
|
<DialogContent className="sm:max-w-xl w-full bg-white p-6 rounded-[24px] font-sans">
|
|
<DialogHeader>
|
|
<DialogTitle className="text-lg font-black text-slate-800 uppercase tracking-wide">Edit Sponsor Registry Details</DialogTitle>
|
|
</DialogHeader>
|
|
<form onSubmit={handleEditSubmit} className="space-y-4 mt-4">
|
|
<div className="space-y-1">
|
|
<label className="text-[10px] font-black text-slate-400 uppercase tracking-widest">Full Name</label>
|
|
<input
|
|
type="text"
|
|
className="w-full px-4 py-2.5 border border-slate-200 rounded-xl text-sm font-semibold focus:ring-4 focus:ring-teal-500/10 outline-none"
|
|
value={editForm.full_name}
|
|
onChange={e => setEditForm({ ...editForm, full_name: e.target.value })}
|
|
required
|
|
/>
|
|
</div>
|
|
<div className="grid grid-cols-2 gap-4">
|
|
<div className="space-y-1">
|
|
<label className="text-[10px] font-black text-slate-400 uppercase tracking-widest">Email Address</label>
|
|
<input
|
|
type="email"
|
|
className="w-full px-4 py-2.5 border border-slate-200 rounded-xl text-sm font-semibold focus:ring-4 focus:ring-teal-500/10 outline-none"
|
|
value={editForm.email}
|
|
onChange={e => setEditForm({ ...editForm, email: e.target.value })}
|
|
required
|
|
/>
|
|
</div>
|
|
<div className="space-y-1">
|
|
<label className="text-[10px] font-black text-slate-400 uppercase tracking-widest">Mobile Number</label>
|
|
<input
|
|
type="text"
|
|
className="w-full px-4 py-2.5 border border-slate-200 rounded-xl text-sm font-semibold focus:ring-4 focus:ring-teal-500/10 outline-none"
|
|
value={editForm.mobile}
|
|
onChange={e => setEditForm({ ...editForm, mobile: e.target.value })}
|
|
required
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div className="grid grid-cols-2 gap-4">
|
|
<div className="space-y-1">
|
|
<label className="text-[10px] font-black text-slate-400 uppercase tracking-widest">City</label>
|
|
<select
|
|
className="w-full px-4 py-2.5 border border-slate-200 rounded-xl text-sm font-semibold focus:ring-4 focus:ring-teal-500/10 outline-none"
|
|
value={editForm.city}
|
|
onChange={e => setEditForm({ ...editForm, city: e.target.value })}
|
|
>
|
|
<option value="Dubai">Dubai</option>
|
|
<option value="Abu Dhabi">Abu Dhabi</option>
|
|
<option value="Sharjah">Sharjah</option>
|
|
</select>
|
|
</div>
|
|
<div className="space-y-1">
|
|
<label className="text-[10px] font-black text-slate-400 uppercase tracking-widest">Nationality</label>
|
|
<input
|
|
type="text"
|
|
className="w-full px-4 py-2.5 border border-slate-200 rounded-xl text-sm font-semibold focus:ring-4 focus:ring-teal-500/10 outline-none"
|
|
value={editForm.nationality}
|
|
onChange={e => setEditForm({ ...editForm, nationality: e.target.value })}
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div className="space-y-1">
|
|
<label className="text-[10px] font-black text-slate-400 uppercase tracking-widest">Address</label>
|
|
<input
|
|
type="text"
|
|
className="w-full px-4 py-2.5 border border-slate-200 rounded-xl text-sm font-semibold focus:ring-4 focus:ring-teal-500/10 outline-none"
|
|
value={editForm.address}
|
|
onChange={e => setEditForm({ ...editForm, address: e.target.value })}
|
|
/>
|
|
</div>
|
|
<div className="grid grid-cols-2 gap-4 border-t border-slate-100 pt-3">
|
|
<div className="space-y-1">
|
|
<label className="text-[10px] font-black text-slate-400 uppercase tracking-widest">Subscription Plan</label>
|
|
<select
|
|
className="w-full px-4 py-2.5 border border-slate-200 rounded-xl text-sm font-semibold focus:ring-4 focus:ring-teal-500/10 outline-none"
|
|
value={editForm.subscription_plan}
|
|
onChange={e => setEditForm({ ...editForm, subscription_plan: e.target.value })}
|
|
>
|
|
<option value="basic">Basic Search</option>
|
|
<option value="premium">Premium Pass</option>
|
|
<option value="vip">VIP Concierge</option>
|
|
<option value="">No Active Plan</option>
|
|
</select>
|
|
</div>
|
|
<div className="space-y-1">
|
|
<label className="text-[10px] font-black text-slate-400 uppercase tracking-widest">Subscription Status</label>
|
|
<select
|
|
className="w-full px-4 py-2.5 border border-slate-200 rounded-xl text-sm font-semibold focus:ring-4 focus:ring-teal-500/10 outline-none"
|
|
value={editForm.subscription_status}
|
|
onChange={e => setEditForm({ ...editForm, subscription_status: e.target.value })}
|
|
>
|
|
<option value="active">Active</option>
|
|
<option value="expired">Expired</option>
|
|
<option value="none">None</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex items-center justify-end space-x-3 pt-4 border-t border-slate-100">
|
|
<button
|
|
type="button"
|
|
onClick={() => setIsEditOpen(false)}
|
|
className="px-4 py-2 bg-slate-100 text-slate-600 rounded-xl text-xs font-bold hover:bg-slate-200"
|
|
>
|
|
Cancel
|
|
</button>
|
|
<button
|
|
type="submit"
|
|
className="px-5 py-2.5 bg-[#0F6E56] text-white rounded-xl text-xs font-black uppercase tracking-wider"
|
|
>
|
|
Save Registry
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</DialogContent>
|
|
</Dialog>
|
|
</AdminLayout>
|
|
);
|
|
}
|