Spaces:
Sleeping
Sleeping
| 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; |