import { Button } from '@/components/ui'; import { DataTable } from '@/components/admin/DataTable.tsx'; import { SearchAndFilter } from '@/components/admin/SearchAndFilter.tsx'; import { useTranslation } from '@/hooks/useI18n.tsx'; import { useOrganizations } from '@/hooks/useOrganizations.ts'; import { Organization } from '@/types.ts'; import React, { useState, useMemo } from 'react'; import { useNavigate } from 'react-router-dom'; import { Plus, Download, Upload, CheckCircle, XCircle, Edit, Eye } from 'lucide-react'; import { useBulkVerifyOrganizations } from '@/hooks/api/useAdminAPI.ts'; import { useToast } from '@/hooks/useToast.ts'; const AdminOrganizationsPage = () => { const { t } = useTranslation(); const navigate = useNavigate(); const { organizations, updateOrganization } = useOrganizations(); const { success, error, warning } = useToast(); // Search and filter state const [searchTerm, setSearchTerm] = useState(''); const [filterValues, setFilterValues] = useState({ sector: '', type: '', verification: '', }); // Pagination state const [currentPage, setCurrentPage] = useState(1); const [pageSize, setPageSize] = useState(25); const [selectedRows, setSelectedRows] = useState>(new Set()); // Bulk operations const { mutate: bulkVerifyOrganizations, isPending: isBulkVerifying } = useBulkVerifyOrganizations(); // Filter organizations const filteredOrganizations = useMemo(() => { return organizations.filter((org) => { const matchesSearch = !searchTerm || org.Name?.toLowerCase().includes(searchTerm.toLowerCase()) || org.Description?.toLowerCase().includes(searchTerm.toLowerCase()) || org.Sector?.toLowerCase().includes(searchTerm.toLowerCase()); const matchesSector = !filterValues.sector || org.Sector === filterValues.sector; const matchesType = !filterValues.type || org.Type === filterValues.type; const matchesVerification = !filterValues.verification || (filterValues.verification === 'verified' && org.Verified) || (filterValues.verification === 'unverified' && !org.Verified) || (filterValues.verification === 'pending' && org.PendingVerification); return matchesSearch && matchesSector && matchesType && matchesVerification; }); }, [organizations, searchTerm, filterValues]); // Paginated data const paginatedData = useMemo(() => { const startIndex = (currentPage - 1) * pageSize; const endIndex = startIndex + pageSize; return filteredOrganizations.slice(startIndex, endIndex); }, [filteredOrganizations, currentPage, pageSize]); const totalPages = Math.ceil(filteredOrganizations.length / pageSize); // Table columns const columns = [ { key: 'logo', header: t('adminPage.orgTable.logo'), sortable: false, width: '80px', render: (org: Organization) => (
{org.Logo ? ( {org.Name} ) : (
{org.Name?.charAt(0).toUpperCase()}
)}
), }, { key: 'name', header: t('adminPage.orgTable.name'), sortable: true, render: (org: Organization) => (
{org.Name}
{org.Description?.slice(0, 50)}...
), }, { key: 'sector', header: t('adminPage.orgTable.sector'), sortable: true, render: (org: Organization) => org.Sector, }, { key: 'type', header: t('adminPage.orgTable.type'), sortable: true, render: (org: Organization) => org.Type, }, { key: 'needs_offers', header: t('adminPage.orgTable.needsOffers'), sortable: false, render: (org: Organization) => (
Needs: {org.Needs?.length || 0}
Offers: {org.Offers?.length || 0}
), }, { key: 'status', header: t('adminPage.orgTable.status'), sortable: true, render: (org: Organization) => (
{org.Verified ? ( {t('adminPage.orgTable.verified')} ) : org.PendingVerification ? ( {t('adminPage.orgTable.pending')} ) : ( {t('adminPage.orgTable.unverified')} )}
), }, { key: 'actions', header: t('adminPage.orgTable.actions'), sortable: false, render: (org: Organization) => (
), }, ]; // Bulk actions const handleBulkVerify = () => { const selectedIds = Array.from(selectedRows); if (selectedIds.length === 0) { warning(t('adminPage.orgTable.noSelection'), { title: t('adminPage.orgTable.selectOrgsFirst'), }); return; } bulkVerifyOrganizations(selectedIds, { onSuccess: () => { success(t('adminPage.orgTable.bulkVerifySuccess'), { title: t('adminPage.orgTable.bulkVerifySuccessDesc', { count: selectedIds.length }), }); setSelectedRows(new Set()); }, onError: () => { error(t('adminPage.orgTable.bulkVerifyError'), { title: t('adminPage.orgTable.bulkVerifyErrorDesc'), }); }, }); }; const handleExport = () => { // Export current filtered view const csvData = filteredOrganizations.map((org) => ({ Name: org.Name, Sector: org.Sector, Type: org.Type, Verified: org.Verified ? 'Yes' : 'No', CreatedAt: org.CreatedAt, })); const csvContent = [ Object.keys(csvData[0]).join(','), ...csvData.map((row) => Object.values(row).join(',')), ].join('\n'); const blob = new Blob([csvContent], { type: 'text/csv' }); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'organizations.csv'; a.click(); window.URL.revokeObjectURL(url); }; return (
{/* Header */}

{t('adminPage.organizations.title')}

{t('adminPage.organizations.subtitle')} ({filteredOrganizations.length}{' '} {t('adminPage.organizations.total')})

{/* Search and Filters */} {/* Bulk Actions */} {selectedRows.size > 0 && (
{selectedRows.size} {t('adminPage.organizations.selected')}
)} {/* Data Table */} org.ID} isLoading={false} selection={{ selectedRows, onSelectionChange: setSelectedRows, }} pagination={{ currentPage, totalPages, pageSize, totalItems: filteredOrganizations.length, onPageChange: setCurrentPage, onPageSizeChange: setPageSize, }} emptyMessage={t('adminPage.organizations.noOrganizations')} emptyDescription={t('adminPage.organizations.noOrganizationsDesc')} />
); }; export default AdminOrganizationsPage;