← back to Norma

components/agents/OrgOnboarding.tsx

444 lines

'use client';

import { useState } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import {
  UserPlus, Building2, Globe, Mail, Phone, MapPin, Users, CheckCircle2,
  ChevronRight, Twitter, Linkedin, Facebook, Instagram, AlertCircle,
} from 'lucide-react';
import { useToast } from '../ToastProvider';

const ORG_TYPES = [
  { value: 'nonprofit', label: 'Nonprofit' },
  { value: 'advocacy', label: 'Advocacy' },
  { value: 'educational', label: 'Educational' },
  { value: 'government', label: 'Government' },
];

const KEY_ISSUES = [
  'Education', 'Student Loans', 'Workforce Development', 'Housing',
  'Healthcare', 'Economic Justice', 'Racial Equity', 'Climate',
  'Immigration', 'Voting Rights', 'Criminal Justice', 'Food Security',
  'Mental Health', 'Child Welfare', 'Disability Rights', 'Elder Care',
];

const FOCUS_POPULATIONS = [
  'Students', 'Veterans', 'Minorities', 'Low-Income',
  'Women', 'LGBTQ+', 'Immigrants', 'Seniors',
  'Youth', 'Rural Communities', 'Urban Communities', 'People with Disabilities',
];

const US_STATES = [
  'AL','AK','AZ','AR','CA','CO','CT','DE','FL','GA','HI','ID','IL','IN','IA','KS','KY',
  'LA','ME','MD','MA','MI','MN','MS','MO','MT','NE','NV','NH','NJ','NM','NY','NC','ND',
  'OH','OK','OR','PA','RI','SC','SD','TN','TX','UT','VT','VA','WA','WV','WI','WY','DC',
];

interface OnboardingProps {
  onNavigate: (tab: string) => void;
  onOrgChange: (id: string) => void;
}

export default function OrgOnboarding({ onNavigate, onOrgChange }: OnboardingProps) {
  const { addToast } = useToast();
  const [submitting, setSubmitting] = useState(false);
  const [submitted, setSubmitted] = useState(false);
  const [newOrgName, setNewOrgName] = useState('');
  const [errors, setErrors] = useState<Record<string, string>>({});

  // Form state
  const [form, setForm] = useState({
    name: '',
    ein: '',
    type: 'nonprofit',
    mission: '',
    key_issues: [] as string[],
    focus_populations: [] as string[],
    city: '',
    state: '',
    zip: '',
    website: '',
    email: '',
    phone: '',
    executive_director: '',
    twitter: '',
    facebook: '',
    instagram: '',
    linkedin: '',
  });

  function updateField(field: string, value: string) {
    setForm(prev => ({ ...prev, [field]: value }));
    if (errors[field]) setErrors(prev => { const n = { ...prev }; delete n[field]; return n; });
  }

  function toggleArrayItem(field: 'key_issues' | 'focus_populations', item: string) {
    setForm(prev => ({
      ...prev,
      [field]: prev[field].includes(item)
        ? prev[field].filter(i => i !== item)
        : [...prev[field], item],
    }));
  }

  function validate(): boolean {
    const errs: Record<string, string> = {};
    if (!form.name.trim()) errs.name = 'Organization name is required';
    if (!form.email.trim()) errs.email = 'Contact email is required';
    if (form.email && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(form.email)) errs.email = 'Invalid email format';
    if (form.key_issues.length === 0) errs.key_issues = 'Select at least one issue';
    setErrors(errs);
    return Object.keys(errs).length === 0;
  }

  async function handleSubmit() {
    if (!validate()) return;
    setSubmitting(true);

    try {
      const payload = {
        name: form.name.trim(),
        ein: form.ein.trim() || null,
        type: form.type,
        mission: form.mission.trim() || null,
        key_issues: form.key_issues,
        focus_populations: form.focus_populations,
        city: form.city.trim() || null,
        state: form.state || null,
        zip: form.zip.trim() || null,
        website: form.website.trim() || null,
        email: form.email.trim(),
        phone: form.phone.trim() || null,
        executive_director: form.executive_director.trim() || null,
        social_media: {
          twitter: form.twitter.trim() || null,
          facebook: form.facebook.trim() || null,
          instagram: form.instagram.trim() || null,
          linkedin: form.linkedin.trim() || null,
        },
      };

      const res = await fetch('/api/agents/org/register', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(payload),
      });

      if (!res.ok) {
        const data = await res.json();
        throw new Error(data.error || 'Registration failed');
      }

      const data = await res.json();
      setNewOrgName(form.name);
      setSubmitted(true);
      if (data.id) onOrgChange(data.id);
      addToast('Organization registered successfully', 'success');
    } catch (err) {
      addToast((err as Error).message || 'Failed to register organization', 'error');
    }
    setSubmitting(false);
  }

  if (submitted) {
    return (
      <div style={{ padding: 24, maxWidth: 700, margin: '0 auto' }}>
        <motion.div
          initial={{ opacity: 0, scale: 0.95 }}
          animate={{ opacity: 1, scale: 1 }}
          transition={{ duration: 0.3 }}
        >
          <div className="card" style={{ padding: 40, textAlign: 'center' }}>
            <div style={{
              width: 64, height: 64, borderRadius: 16, margin: '0 auto 20px',
              backgroundColor: 'rgba(34,197,94,0.15)',
              display: 'flex', alignItems: 'center', justifyContent: 'center',
            }}>
              <CheckCircle2 size={32} style={{ color: '#22c55e' }} />
            </div>
            <h2 style={{ fontSize: 24, fontWeight: 700, color: 'var(--color-text)', margin: '0 0 8px' }}>
              Your Agent Toolkit is Ready
            </h2>
            <p style={{ fontSize: 14, color: 'var(--color-text-secondary)', margin: '0 0 28px' }}>
              <strong>{newOrgName}</strong> has been registered. Explore your AI-powered advocacy tools.
            </p>
            <div style={{
              display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(200px, 1fr))',
              gap: 12, marginBottom: 20,
            }}>
              {[
                { tab: 'agent-petition', label: 'Petition Builder', icon: '📋' },
                { tab: 'agent-grants', label: 'Grant Finder', icon: '🔍' },
                { tab: 'agent-advocacy', label: 'Advocacy Toolkit', icon: '🎯' },
                { tab: 'agent-hub', label: 'Agent Hub', icon: '🤖' },
              ].map(tool => (
                <button
                  key={tool.tab}
                  className="btn btn-secondary"
                  onClick={() => onNavigate(tool.tab)}
                  style={{ justifyContent: 'flex-start', gap: 8 }}
                >
                  <span>{tool.icon}</span>
                  {tool.label}
                  <ChevronRight size={14} style={{ marginLeft: 'auto' }} />
                </button>
              ))}
            </div>
          </div>
        </motion.div>
      </div>
    );
  }

  return (
    <div style={{ padding: 24, maxWidth: 800, margin: '0 auto' }}>
      {/* Header */}
      <div style={{ marginBottom: 24 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 12, marginBottom: 8 }}>
          <div style={{
            width: 40, height: 40, borderRadius: 12,
            backgroundColor: 'rgba(34,197,94,0.12)',
            display: 'flex', alignItems: 'center', justifyContent: 'center',
          }}>
            <UserPlus size={20} style={{ color: '#22c55e' }} />
          </div>
          <div>
            <h1 style={{ fontSize: 22, fontWeight: 700, color: 'var(--color-text)', margin: 0 }}>
              Organization Onboarding
            </h1>
            <p style={{ fontSize: 13, color: 'var(--color-text-muted)', margin: 0 }}>
              Register your nonprofit to access AI-powered advocacy tools
            </p>
          </div>
        </div>
      </div>

      {/* Form */}
      <div style={{ display: 'flex', flexDirection: 'column', gap: 20 }}>

        {/* Basic Info */}
        <div className="card" style={{ padding: 20 }}>
          <h3 style={{ fontSize: 14, fontWeight: 600, color: 'var(--color-text)', margin: '0 0 16px', display: 'flex', alignItems: 'center', gap: 8 }}>
            <Building2 size={16} style={{ color: 'var(--color-primary)' }} />
            Organization Details
          </h3>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
            <div style={{ gridColumn: '1 / -1' }}>
              <label style={{ fontSize: 12, fontWeight: 600, color: 'var(--color-text-secondary)', display: 'block', marginBottom: 4 }}>
                Organization Name *
              </label>
              <input
                className="input"
                value={form.name}
                onChange={e => updateField('name', e.target.value)}
                placeholder="e.g., Your Organization Name"
              />
              {errors.name && <span style={{ fontSize: 11, color: 'var(--color-error)', marginTop: 2, display: 'flex', alignItems: 'center', gap: 4 }}><AlertCircle size={11} />{errors.name}</span>}
            </div>
            <div>
              <label style={{ fontSize: 12, fontWeight: 600, color: 'var(--color-text-secondary)', display: 'block', marginBottom: 4 }}>
                EIN (Tax ID)
              </label>
              <input
                className="input"
                value={form.ein}
                onChange={e => updateField('ein', e.target.value)}
                placeholder="XX-XXXXXXX"
              />
            </div>
            <div>
              <label style={{ fontSize: 12, fontWeight: 600, color: 'var(--color-text-secondary)', display: 'block', marginBottom: 4 }}>
                Organization Type
              </label>
              <select
                className="input"
                value={form.type}
                onChange={e => updateField('type', e.target.value)}
                style={{ cursor: 'pointer' }}
              >
                {ORG_TYPES.map(t => <option key={t.value} value={t.value}>{t.label}</option>)}
              </select>
            </div>
            <div style={{ gridColumn: '1 / -1' }}>
              <label style={{ fontSize: 12, fontWeight: 600, color: 'var(--color-text-secondary)', display: 'block', marginBottom: 4 }}>
                Mission Statement
              </label>
              <textarea
                className="input"
                value={form.mission}
                onChange={e => updateField('mission', e.target.value)}
                placeholder="Briefly describe your organization's mission..."
                rows={3}
                style={{ resize: 'vertical', fontFamily: 'inherit' }}
              />
            </div>
            <div>
              <label style={{ fontSize: 12, fontWeight: 600, color: 'var(--color-text-secondary)', display: 'block', marginBottom: 4 }}>
                Executive Director
              </label>
              <input
                className="input"
                value={form.executive_director}
                onChange={e => updateField('executive_director', e.target.value)}
                placeholder="Full name"
              />
            </div>
          </div>
        </div>

        {/* Key Issues */}
        <div className="card" style={{ padding: 20 }}>
          <h3 style={{ fontSize: 14, fontWeight: 600, color: 'var(--color-text)', margin: '0 0 4px', display: 'flex', alignItems: 'center', gap: 8 }}>
            <Users size={16} style={{ color: '#f59e0b' }} />
            Key Issues & Focus Populations
          </h3>
          <p style={{ fontSize: 12, color: 'var(--color-text-muted)', margin: '0 0 14px' }}>
            Select all that apply to your organization.
          </p>

          <label style={{ fontSize: 12, fontWeight: 600, color: 'var(--color-text-secondary)', display: 'block', marginBottom: 8 }}>
            Key Issues *
          </label>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, marginBottom: 16 }}>
            {KEY_ISSUES.map(issue => {
              const selected = form.key_issues.includes(issue);
              return (
                <button
                  key={issue}
                  type="button"
                  onClick={() => toggleArrayItem('key_issues', issue)}
                  style={{
                    padding: '5px 12px', borderRadius: 20, border: '1px solid',
                    borderColor: selected ? 'var(--color-primary)' : 'var(--color-border)',
                    backgroundColor: selected ? 'rgba(16,185,129,0.15)' : 'transparent',
                    color: selected ? '#34d399' : 'var(--color-text-secondary)',
                    fontSize: 12, fontWeight: 500, cursor: 'pointer',
                    transition: 'all 0.15s',
                  }}
                >
                  {issue}
                </button>
              );
            })}
          </div>
          {errors.key_issues && <span style={{ fontSize: 11, color: 'var(--color-error)', display: 'flex', alignItems: 'center', gap: 4, marginBottom: 12 }}><AlertCircle size={11} />{errors.key_issues}</span>}

          <label style={{ fontSize: 12, fontWeight: 600, color: 'var(--color-text-secondary)', display: 'block', marginBottom: 8 }}>
            Focus Populations
          </label>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
            {FOCUS_POPULATIONS.map(pop => {
              const selected = form.focus_populations.includes(pop);
              return (
                <button
                  key={pop}
                  type="button"
                  onClick={() => toggleArrayItem('focus_populations', pop)}
                  style={{
                    padding: '5px 12px', borderRadius: 20, border: '1px solid',
                    borderColor: selected ? '#8b5cf6' : 'var(--color-border)',
                    backgroundColor: selected ? 'rgba(139,92,246,0.15)' : 'transparent',
                    color: selected ? '#a78bfa' : 'var(--color-text-secondary)',
                    fontSize: 12, fontWeight: 500, cursor: 'pointer',
                    transition: 'all 0.15s',
                  }}
                >
                  {pop}
                </button>
              );
            })}
          </div>
        </div>

        {/* Contact Info */}
        <div className="card" style={{ padding: 20 }}>
          <h3 style={{ fontSize: 14, fontWeight: 600, color: 'var(--color-text)', margin: '0 0 16px', display: 'flex', alignItems: 'center', gap: 8 }}>
            <MapPin size={16} style={{ color: '#22c55e' }} />
            Contact Information
          </h3>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 12 }}>
            <div>
              <label style={{ fontSize: 12, fontWeight: 600, color: 'var(--color-text-secondary)', display: 'block', marginBottom: 4 }}>City</label>
              <input className="input" value={form.city} onChange={e => updateField('city', e.target.value)} placeholder="City" />
            </div>
            <div>
              <label style={{ fontSize: 12, fontWeight: 600, color: 'var(--color-text-secondary)', display: 'block', marginBottom: 4 }}>State</label>
              <select className="input" value={form.state} onChange={e => updateField('state', e.target.value)} style={{ cursor: 'pointer' }}>
                <option value="">Select</option>
                {US_STATES.map(s => <option key={s} value={s}>{s}</option>)}
              </select>
            </div>
            <div>
              <label style={{ fontSize: 12, fontWeight: 600, color: 'var(--color-text-secondary)', display: 'block', marginBottom: 4 }}>ZIP</label>
              <input className="input" value={form.zip} onChange={e => updateField('zip', e.target.value)} placeholder="ZIP Code" />
            </div>
            <div>
              <label style={{ fontSize: 12, fontWeight: 600, color: 'var(--color-text-secondary)', display: 'block', marginBottom: 4 }}>Email *</label>
              <input className="input" type="email" value={form.email} onChange={e => updateField('email', e.target.value)} placeholder="contact@org.com" />
              {errors.email && <span style={{ fontSize: 11, color: 'var(--color-error)', marginTop: 2, display: 'flex', alignItems: 'center', gap: 4 }}><AlertCircle size={11} />{errors.email}</span>}
            </div>
            <div>
              <label style={{ fontSize: 12, fontWeight: 600, color: 'var(--color-text-secondary)', display: 'block', marginBottom: 4 }}>Phone</label>
              <input className="input" value={form.phone} onChange={e => updateField('phone', e.target.value)} placeholder="(555) 123-4567" />
            </div>
            <div>
              <label style={{ fontSize: 12, fontWeight: 600, color: 'var(--color-text-secondary)', display: 'block', marginBottom: 4 }}>Website</label>
              <input className="input" value={form.website} onChange={e => updateField('website', e.target.value)} placeholder="https://www.org.com" />
            </div>
          </div>
        </div>

        {/* Social Media */}
        <div className="card" style={{ padding: 20 }}>
          <h3 style={{ fontSize: 14, fontWeight: 600, color: 'var(--color-text)', margin: '0 0 16px', display: 'flex', alignItems: 'center', gap: 8 }}>
            <Globe size={16} style={{ color: '#6366f1' }} />
            Social Media Links
          </h3>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              <Twitter size={16} style={{ color: '#34d399', flexShrink: 0 }} />
              <input className="input" value={form.twitter} onChange={e => updateField('twitter', e.target.value)} placeholder="https://twitter.com/yourorg" />
            </div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              <Facebook size={16} style={{ color: '#34d399', flexShrink: 0 }} />
              <input className="input" value={form.facebook} onChange={e => updateField('facebook', e.target.value)} placeholder="https://facebook.com/yourorg" />
            </div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              <Instagram size={16} style={{ color: '#e879f9', flexShrink: 0 }} />
              <input className="input" value={form.instagram} onChange={e => updateField('instagram', e.target.value)} placeholder="https://instagram.com/yourorg" />
            </div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              <Linkedin size={16} style={{ color: '#34d399', flexShrink: 0 }} />
              <input className="input" value={form.linkedin} onChange={e => updateField('linkedin', e.target.value)} placeholder="https://linkedin.com/company/yourorg" />
            </div>
          </div>
        </div>

        {/* Submit */}
        <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 12 }}>
          <button className="btn btn-ghost" onClick={() => onNavigate('agent-hub')}>
            Cancel
          </button>
          <button
            className="btn btn-primary btn-lg"
            onClick={handleSubmit}
            disabled={submitting}
          >
            {submitting ? (
              <>
                <span className="spinner" style={{ width: 16, height: 16 }} />
                Registering...
              </>
            ) : (
              <>
                <UserPlus size={16} />
                Register Organization
              </>
            )}
          </button>
        </div>
      </div>
    </div>
  );
}