← back to Sdcc Awards

cypressaward/frontend/app/nonprofits/page.tsx

323 lines

'use client'

import { useEffect, useState } from 'react'
import { supabase } from '@/lib/supabase'

interface NonProfit {
  id: number
  name: string
  category: string
  location: string
  mission: string
  rating: string
  website: string
  source: string
}

export default function NonProfitsPage() {
  const [nonprofits, setNonprofits] = useState<NonProfit[]>([])
  const [loading, setLoading] = useState(true)
  const [selectedOrg, setSelectedOrg] = useState<NonProfit | null>(null)
  const [showModal, setShowModal] = useState(false)
  const [showRegisterForm, setShowRegisterForm] = useState(false)

  useEffect(() => {
    fetchNonprofits()
  }, [])

  async function fetchNonprofits() {
    try {
      const { data, error } = await supabase
        .from('scraped_nonprofits')
        .select('*')
        .order('name', { ascending: true })
        .limit(100)

      if (error) throw error
      setNonprofits(data || [])
    } catch (error) {
      console.error('Error fetching nonprofits:', error)
    } finally {
      setLoading(false)
    }
  }

  function openModal(org: NonProfit) {
    setSelectedOrg(org)
    setShowModal(true)
  }

  function closeModal() {
    setShowModal(false)
    setSelectedOrg(null)
  }

  async function handleRegisterSubmit(e: React.FormEvent<HTMLFormElement>) {
    e.preventDefault()
    const formData = new FormData(e.currentTarget)
    
    const newOrg = {
      name: formData.get('name') as string,
      category: formData.get('category') as string,
      location: formData.get('location') as string,
      mission: formData.get('mission') as string,
      rating: 'Pending Review',
      website: formData.get('website') as string,
      source: 'User Submission',
      data_type: 'nonprofit',
      hash: Math.random().toString(36).substring(7)
    }

    try {
      const { error } = await supabase
        .from('scraped_nonprofits')
        .insert([newOrg])

      if (!error) {
        alert('Organization registered successfully!')
        setShowRegisterForm(false)
        fetchNonprofits()
      }
    } catch (error) {
      console.error('Error registering nonprofit:', error)
      alert('Error registering organization')
    }
  }

  return (
    <div className="min-h-screen bg-gray-50 py-8">
      <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
        <div className="bg-white shadow-xl rounded-lg">
          <div className="px-6 py-4 border-b border-gray-200 flex justify-between items-center">
            <div>
              <h1 className="text-3xl font-bold text-gray-900">Non-Profit Organizations</h1>
              <p className="text-gray-600 mt-2">Legal aid and advocacy organizations</p>
            </div>
            <button
              onClick={() => setShowRegisterForm(true)}
              className="px-4 py-2 bg-green-600 text-white rounded-md hover:bg-green-700 transition font-medium"
            >
              Register Nonprofit
            </button>
          </div>

          {loading ? (
            <div className="flex justify-center py-12">
              <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600"></div>
            </div>
          ) : (
            <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 p-6">
              {nonprofits.map((org) => (
                <div key={org.id} className="bg-white border border-gray-200 rounded-lg shadow-sm hover:shadow-lg transition">
                  <div className="p-6">
                    <div className="mb-4">
                      <span className="inline-block px-3 py-1 text-xs font-semibold text-green-800 bg-green-100 rounded-full">
                        {org.category}
                      </span>
                      {org.rating && (
                        <span className="ml-2 inline-block px-3 py-1 text-xs font-semibold text-blue-800 bg-blue-100 rounded-full">
                          {org.rating}
                        </span>
                      )}
                    </div>
                    <h3 className="text-lg font-bold text-gray-900 mb-2">
                      {org.name}
                    </h3>
                    <p className="text-sm text-gray-600 mb-2">
                      <span className="font-semibold">Location:</span> {org.location}
                    </p>
                    <p className="text-gray-700 text-sm line-clamp-3 mb-4">
                      {org.mission}
                    </p>
                    <div className="flex gap-2">
                      <button
                        onClick={() => openModal(org)}
                        className="flex-1 px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition text-sm font-medium"
                      >
                        View Details
                      </button>
                      {org.website && (
                        <a
                          href={org.website}
                          target="_blank"
                          rel="noopener noreferrer"
                          className="flex-1 px-4 py-2 bg-green-600 text-white rounded-md hover:bg-green-700 transition text-sm font-medium text-center"
                        >
                          Visit Site
                        </a>
                      )}
                    </div>
                  </div>
                </div>
              ))}
            </div>
          )}
        </div>
      </div>

      {/* Details Modal */}
      {showModal && selectedOrg && (
        <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4 z-50">
          <div className="bg-white rounded-lg max-w-2xl w-full max-h-[90vh] overflow-y-auto">
            <div className="p-6">
              <div className="flex justify-between items-start mb-4">
                <h2 className="text-2xl font-bold text-gray-900">{selectedOrg.name}</h2>
                <button
                  onClick={closeModal}
                  className="text-gray-400 hover:text-gray-600"
                >
                  <svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
                  </svg>
                </button>
              </div>
              <div className="space-y-4">
                <div>
                  <h3 className="font-semibold text-gray-700">Category</h3>
                  <p className="text-gray-900">{selectedOrg.category}</p>
                </div>
                <div>
                  <h3 className="font-semibold text-gray-700">Location</h3>
                  <p className="text-gray-900">{selectedOrg.location}</p>
                </div>
                <div>
                  <h3 className="font-semibold text-gray-700">Mission</h3>
                  <p className="text-gray-900">{selectedOrg.mission}</p>
                </div>
                <div>
                  <h3 className="font-semibold text-gray-700">Rating</h3>
                  <p className="text-gray-900">{selectedOrg.rating}</p>
                </div>
                <div>
                  <h3 className="font-semibold text-gray-700">Source</h3>
                  <p className="text-gray-900">{selectedOrg.source}</p>
                </div>
              </div>
              <div className="mt-6 flex gap-3">
                {selectedOrg.website && (
                  <a
                    href={selectedOrg.website}
                    target="_blank"
                    rel="noopener noreferrer"
                    className="flex-1 px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition text-center font-medium"
                  >
                    Visit Website
                  </a>
                )}
                <button
                  onClick={closeModal}
                  className="flex-1 px-4 py-2 bg-gray-200 text-gray-800 rounded-md hover:bg-gray-300 transition font-medium"
                >
                  Close
                </button>
              </div>
            </div>
          </div>
        </div>
      )}

      {/* Register Form Modal */}
      {showRegisterForm && (
        <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4 z-50">
          <div className="bg-white rounded-lg max-w-2xl w-full max-h-[90vh] overflow-y-auto">
            <div className="p-6">
              <div className="flex justify-between items-start mb-4">
                <h2 className="text-2xl font-bold text-gray-900">Register Nonprofit Organization</h2>
                <button
                  onClick={() => setShowRegisterForm(false)}
                  className="text-gray-400 hover:text-gray-600"
                >
                  <svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
                  </svg>
                </button>
              </div>
              <form onSubmit={handleRegisterSubmit} className="space-y-4">
                <div>
                  <label className="block text-sm font-medium text-gray-700 mb-1">
                    Organization Name *
                  </label>
                  <input
                    type="text"
                    name="name"
                    required
                    className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
                  />
                </div>
                <div>
                  <label className="block text-sm font-medium text-gray-700 mb-1">
                    Category *
                  </label>
                  <select
                    name="category"
                    required
                    className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
                  >
                    <option value="">Select a category</option>
                    <option value="Legal Aid">Legal Aid</option>
                    <option value="Civil Rights">Civil Rights</option>
                    <option value="Criminal Justice Reform">Criminal Justice Reform</option>
                    <option value="Immigration Law">Immigration Law</option>
                    <option value="Student Advocacy">Student Advocacy</option>
                    <option value="Environmental Law">Environmental Law</option>
                    <option value="Consumer Protection">Consumer Protection</option>
                    <option value="Other">Other</option>
                  </select>
                </div>
                <div>
                  <label className="block text-sm font-medium text-gray-700 mb-1">
                    Location *
                  </label>
                  <input
                    type="text"
                    name="location"
                    required
                    placeholder="City, State"
                    className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
                  />
                </div>
                <div>
                  <label className="block text-sm font-medium text-gray-700 mb-1">
                    Mission Statement *
                  </label>
                  <textarea
                    name="mission"
                    required
                    rows={4}
                    className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
                  />
                </div>
                <div>
                  <label className="block text-sm font-medium text-gray-700 mb-1">
                    Website
                  </label>
                  <input
                    type="url"
                    name="website"
                    placeholder="https://example.org"
                    className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
                  />
                </div>
                <div className="flex gap-3 pt-4">
                  <button
                    type="submit"
                    className="flex-1 px-4 py-2 bg-green-600 text-white rounded-md hover:bg-green-700 transition font-medium"
                  >
                    Register Organization
                  </button>
                  <button
                    type="button"
                    onClick={() => setShowRegisterForm(false)}
                    className="flex-1 px-4 py-2 bg-gray-200 text-gray-800 rounded-md hover:bg-gray-300 transition font-medium"
                  >
                    Cancel
                  </button>
                </div>
              </form>
            </div>
          </div>
        </div>
      )}
    </div>
  )
}