Spaces:
Sleeping
Sleeping
File size: 9,285 Bytes
ad08f08 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | import React, { useState, useEffect } from 'react';
const DirectoryPage = () => {
const [organizations, setOrganizations] = useState([]);
const [loading, setLoading] = useState(true);
const [searchTerm, setSearchTerm] = useState('');
const [sectorFilter, setSectorFilter] = useState('All');
useEffect(() => {
// In a real app, this would fetch from an API
// For demo purposes, we'll use mock data
const mockOrganizations = [
{
id: 1,
name: 'Global Food Rescue Initiative',
sector: 'NGO',
country: 'International',
description: 'Non-profit organization focused on reducing food waste through redistribution networks.',
expertise: ['Food Recovery', 'Logistics', 'Volunteer Management'],
projects: 42
},
{
id: 2,
name: 'AgriTech Solutions Ltd',
sector: 'Private',
country: 'Netherlands',
description: 'Technology company developing smart cold chain solutions for perishable goods.',
expertise: ['Cold Chain Technology', 'IoT Sensors', 'Data Analytics'],
projects: 18
},
{
id: 3,
name: 'Sustainable Agriculture Research Institute',
sector: 'Academic',
country: 'United States',
description: 'Research institution studying post-harvest loss reduction techniques.',
expertise: ['Research', 'Post-harvest Technology', 'Training'],
projects: 27
},
{
id: 4,
name: 'Ministry of Agriculture and Food Security',
sector: 'Government',
country: 'Kenya',
description: 'Government agency implementing national food loss reduction programs.',
expertise: ['Policy Development', 'Program Implementation', 'Farmer Support'],
projects: 15
},
{
id: 5,
name: 'Circular Economy Food Partners',
sector: 'NGO',
country: 'Germany',
description: 'Organization promoting circular economy approaches to food systems.',
expertise: ['Circular Economy', 'Composting', 'Waste Valorization'],
projects: 33
},
{
id: 6,
name: 'Farm to Market Logistics Co.',
sector: 'Private',
country: 'Brazil',
description: 'Logistics company specializing in transportation of perishable agricultural products.',
expertise: ['Transportation', 'Cold Chain Logistics', 'Supply Chain'],
projects: 29
}
];
setTimeout(() => {
setOrganizations(mockOrganizations);
setLoading(false);
}, 500);
}, []);
const sectors = ['All', ...new Set(organizations.map(org => org.sector))];
const filteredOrganizations = organizations.filter(org => {
const matchesSearch = org.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
org.description.toLowerCase().includes(searchTerm.toLowerCase()) ||
org.expertise.some(exp => exp.toLowerCase().includes(searchTerm.toLowerCase()));
const matchesSector = sectorFilter === 'All' || org.sector === sectorFilter;
return matchesSearch && matchesSector;
});
if (loading) {
return (
<div className="py-16 bg-gradient-to-br from-gray-50 to-gray-100 dark:from-gray-800 dark:to-gray-900 transition-colors duration-300 min-h-screen">
<div className="container mx-auto px-4">
<h2 className="text-3xl font-bold mb-8 text-gray-800 dark:text-white drop-shadow bg-gradient-to-r from-bio-green to-bio-blue bg-clip-text text-transparent">Stakeholder Directory</h2>
<div className="flex justify-center">
<div className="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-bio-green"></div>
</div>
</div>
</div>
);
}
return (
<div className="py-16 bg-gradient-to-br from-gray-50 to-gray-100 dark:from-gray-800 dark:to-gray-900 transition-colors duration-300 min-h-screen">
<div className="container mx-auto px-4">
<h2 className="text-3xl font-bold mb-8 text-gray-800 dark:text-white drop-shadow bg-gradient-to-r from-bio-green to-bio-blue bg-clip-text text-transparent">Stakeholder Directory</h2>
<div className="mb-8 bg-white dark:bg-gray-700 rounded-2xl shadow-lg p-6 border border-gray-100 dark:border-gray-600 bg-gradient-to-br from-white to-gray-100 dark:from-gray-700 dark:to-gray-800">
<div className="flex flex-col md:flex-row gap-4">
<div className="flex-grow">
<input
type="text"
placeholder="Search organizations..."
className="w-full px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-bio-green focus:border-transparent dark:bg-gray-600 dark:text-white drop-shadow bg-gradient-to-r from-white to-gray-50 dark:from-gray-600 dark:to-gray-700"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
</div>
<div className="w-full md:w-48">
<select
className="w-full px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-bio-green focus:border-transparent dark:bg-gray-600 dark:text-white drop-shadow bg-gradient-to-r from-white to-gray-50 dark:from-gray-600 dark:to-gray-700"
value={sectorFilter}
onChange={(e) => setSectorFilter(e.target.value)}
>
{sectors.map(sector => (
<option key={sector} value={sector}>{sector}</option>
))}
</select>
</div>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{filteredOrganizations.map((org) => (
<div key={org.id} className="bg-white dark:bg-gray-700 rounded-2xl shadow-lg overflow-hidden hover:shadow-xl transition-all duration-300 transform hover:-translate-y-1 border border-gray-100 dark:border-gray-600 bg-gradient-to-br from-white to-gray-100 dark:from-gray-700 dark:to-gray-800">
<div className="p-6">
<div className="flex justify-between items-start mb-4">
<h3 className="text-xl font-bold text-gray-800 dark:text-white drop-shadow bg-gradient-to-r from-gray-800 to-gray-600 bg-clip-text text-transparent dark:from-white dark:to-gray-300">{org.name}</h3>
<span className="inline-block px-3 py-1 text-xs font-semibold text-bio-purple bg-purple-100 dark:bg-purple-900/30 dark:text-purple-300 rounded-full drop-shadow bg-gradient-to-r from-purple-100 to-purple-200 dark:from-purple-900/30 dark:to-purple-800/30">
{org.sector}
</span>
</div>
<div className="mb-4">
<span className="text-sm text-gray-500 dark:text-gray-400 drop-shadow">{org.country}</span>
</div>
<p className="text-gray-600 dark:text-gray-300 mb-4 drop-shadow">{org.description}</p>
<div className="mb-4">
<h4 className="font-semibold text-gray-800 dark:text-white mb-2 drop-shadow bg-gradient-to-r from-gray-800 to-gray-600 bg-clip-text text-transparent dark:from-white dark:to-gray-300">Expertise:</h4>
<div className="flex flex-wrap gap-2">
{org.expertise.map((exp, index) => (
<span key={index} className="px-2 py-1 text-xs bg-gray-200 dark:bg-gray-600 text-gray-700 dark:text-gray-300 rounded-full drop-shadow bg-gradient-to-r from-gray-200 to-gray-300 dark:from-gray-600 dark:to-gray-700">
{exp}
</span>
))}
</div>
</div>
<div className="flex justify-between items-center">
<span className="text-sm text-gray-500 dark:text-gray-400 drop-shadow">{org.projects} projects</span>
<button className="bg-gradient-to-r from-bio-purple to-purple-500 text-white px-4 py-2 rounded-lg hover:from-purple-500 hover:to-purple-600 transition shadow-md hover:shadow-lg drop-shadow">
Contact
</button>
</div>
</div>
</div>
))}
</div>
{filteredOrganizations.length === 0 && (
<div className="text-center py-12 bg-white dark:bg-gray-700 rounded-2xl shadow-lg bg-gradient-to-br from-white to-gray-100 dark:from-gray-700 dark:to-gray-800">
<p className="text-gray-600 dark:text-gray-400 drop-shadow">No organizations found matching your criteria.</p>
<button
className="mt-4 text-bio-purple dark:text-purple-400 hover:underline drop-shadow bg-gradient-to-r from-bio-purple to-purple-500 bg-clip-text text-transparent"
onClick={() => {
setSearchTerm('');
setSectorFilter('All');
}}
>
Clear filters
</button>
</div>
)}
</div>
</div>
);
};
export default DirectoryPage; |