Navbar

REACT DEVELOPMENT STANDARDS - AI PROMPT

CRITICAL REQUIREMENTS - ERROR HANDLING, CHANGE LOGS, AND SIMPLICITY ARE MANDATORY

BROWSER STORAGE RESTRICTION: NEVER use localStorage, sessionStorage, or ANY browser storage APIs in React components. These APIs are NOT supported in Claude.ai artifacts and will cause components to fail. Use React state (useState, useReducer) for ALL data storage.

REACT ERROR HANDLING REQUIREMENTS (NON-NEGOTIABLE):

REACT COMPONENT STRUCTURE REQUIREMENTS:

FILE ORGANIZATION - AUDIENCE-BASED STRUCTURE:

Organize by audience/purpose, NOT by technical type:
src/
├── audiences/
│   ├── landowners/          # Stories, financial projections, land value
│   │   ├── LandownerStory.jsx
│   │   ├── ROICalculator.jsx
│   │   └── LandValueWidget.jsx
│   ├── politicians/         # Policy frameworks, economic impact
│   │   ├── EconomicImpact.jsx
│   │   ├── PolicyFramework.jsx
│   │   └── CommunityBenefits.jsx
│   ├── financial/           # Investment models, risk assessments
│   │   ├── PortfolioReturns.jsx
│   │   ├── RiskAssessment.jsx
│   │   └── FinancialProjections.jsx
│   ├── technical/           # Engineering specs, implementation
│   │   ├── TechSpecs.jsx
│   │   ├── DataCenterDetails.jsx
│   │   └── RoboticsTimeline.jsx
│   └── workers/             # Job transformation stories
│       ├── WorkerStories.jsx
│       ├── TrainingPrograms.jsx
│       └── EquityDistribution.jsx
├── shared/
│   ├── components/          # Reusable UI pieces
│   │   ├── DataTable.jsx    # For HUD data, housing authorities
│   │   ├── SortableWidget.jsx
│   │   ├── ErrorBoundary.jsx
│   │   └── LoadingSpinner.jsx
│   ├── data/               # Static data and constants
│   │   ├── sampleData.js   # Example datasets for development
│   │   ├── constants.js    # Fixed values, API endpoints
│   │   └── mockData.js     # Mock data for testing
│   └── utils/              # Helper functions
│       ├── formatters.js   # Data formatting utilities
│       ├── validators.js   # Input validation
│       └── apiHelpers.js   # Future API integration helpers
└── App.jsx                 # Main application component

REACT COMPONENT CHANGE LOG TEMPLATE:

/*
CHANGE LOG
File: /src/audiences/landowners/ROICalculator.jsx
Document Type: React Functional Component
Purpose: Interactive ROI calculator for landowner equity returns
Props: { landValue: number, acreage: number }
State: Local calculation state using useState
Dependencies: React, shared/utils/formatters.js
Version History:
2025-05-31 v1.1 - Added error handling for invalid inputs
2025-05-31 v1.0 - Initial creation with basic ROI calculation
*/

REACT ERROR BOUNDARY TEMPLATE - USE FOR ALL MAJOR SECTIONS:

/*
CHANGE LOG
File: /src/shared/components/ErrorBoundary.jsx
Document Type: React Error Boundary Component
Purpose: Catch and handle React component errors gracefully
Dependencies: React
*/

import React from 'react';

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false, error: null };
  }

  static getDerivedStateFromError(error) {
    console.error('ERROR: ErrorBoundary caught error:', error);
    return { hasError: true, error };
  }

  componentDidCatch(error, errorInfo) {
    console.error('ERROR: ErrorBoundary details:', error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      return (
        <div style="padding: 20px; border: 1px solid red;">
          <h3>Something went wrong</h3>
          <p>{this.props.fallbackMessage || 'Please try refreshing the page.'}</p>
        </div>
      );
    }

    return this.props.children;
  }
}

export default ErrorBoundary;

FUNCTIONAL COMPONENT TEMPLATE - SHORT & TEXT EDITOR FRIENDLY:

/*
CHANGE LOG
File: /src/audiences/[audience]/ComponentName.jsx
Document Type: React Functional Component
Purpose: Brief description of component purpose
Props: { prop1: type, prop2: type }
State: Description of state management
Dependencies: List key imports
Lines: Keep under 200, max 300
Version History:
2025-05-31 v1.0 - Initial creation
*/

import React, { useState, useEffect } from 'react';

const ComponentName = ({ prop1, prop2 }) => {
  // 1. State (keep minimal)
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

  // 2. Input validation
  useEffect(() => {
    if (!prop1) {
      console.error('ERROR: ComponentName - Missing required prop1');
      setError('Missing required data');
      return;
    }
    
    console.log('DEBUG: ComponentName - Starting load');
    loadData();
  }, [prop1, prop2]);

  // 3. Simple data loading
  const loadData = async () => {
    try {
      setLoading(true);
      setError(null);
      
      // Simple processing - if complex, move to separate file
      const result = processSimpleData(prop1, prop2);
      
      setData(result);
      console.log('DEBUG: ComponentName - Success');
      
    } catch (err) {
      console.error('ERROR: ComponentName - Failed:', err);
      setError('Loading failed');
    } finally {
      setLoading(false);
    }
  };

  // 4. Simple helper (if complex, move to utils/ folder)
  const processSimpleData = (input1, input2) => {
    return { processed: true, input1, input2 };
  };

  // 5. Simple render - all states handled
  if (error) {
    return (
      <div className="p-4 border border-red-300 bg-red-50">
        <p className="text-red-700">Error: {error}</p>
      </div>
    );
  }

  if (loading) return <div className="p-4">Loading...</div>;
  if (!data) return <div className="p-4">No data</div>;

  return (
    <div className="p-4">
      <h3 className="text-lg font-semibold mb-2">Component Title</h3>
      <p className="text-gray-700">{data.input1}</p>
    </div>
  );
};

export default ComponentName;

// TOTAL LINES: ~70 (well under 200 limit)
// IF APPROACHING 200 LINES: Split into multiple files

TAILWIND CSS STANDARDS - PROFESSIONAL & ACCESSIBLE:

TAILWIND COMPONENT EXAMPLE - PROFESSIONAL DATA TABLE:

const DataTable = ({ data, columns, onSort }) => {
  return (
    <div className="overflow-x-auto">
      <table className="min-w-full bg-white border border-gray-200">
        <thead className="bg-gray-50">
          <tr>
            {columns.map(col => (
              <th 
                key={col.key}
                className="px-4 py-2 text-left text-sm font-medium text-gray-900 border-b border-gray-200 hover:bg-gray-100 cursor-pointer"
                onClick={() => onSort(col.key)}
              >
                {col.label}
              </th>
            ))}
          </tr>
        </thead>
        <tbody>
          {data.map((row, index) => (
            <tr key={index} className="hover:bg-gray-50">
              {columns.map(col => (
                <td key={col.key} className="px-4 py-2 text-sm text-gray-700 border-b border-gray-100">
                  {row[col.key]}
                </td>
              ))}
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
};

DATA INTEGRATION STRATEGY - STATIC TO DYNAMIC:

Phase 1: Static Presentation (Current Need)

Phase 2: Data Integration (Future - HUD, Housing Authorities)

EXAMPLE: SIMPLE HOUSING AUTHORITY WIDGET (UNDER 200 LINES):

/*
File: /src/shared/components/HousingAuthorityTable.jsx
Purpose: Sortable table for housing authority data
Props: { authorities: array }
Lines: ~150 (well under limit)
*/

import React, { useState } from 'react';

const HousingAuthorityTable = ({ authorities = [] }) => {
  const [sortField, setSortField] = useState('name');
  const [sortDirection, setSortDirection] = useState('asc');
  const [sizeFilter, setSizeFilter] = useState('all');

  // Simple sorting
  const sortedData = [...authorities]
    .filter(auth => sizeFilter === 'all' || auth.size === sizeFilter)
    .sort((a, b) => {
      const aVal = a[sortField];
      const bVal = b[sortField];
      const direction = sortDirection === 'asc' ? 1 : -1;
      return aVal < bVal ? -direction : direction;
    });

  const handleSort = (field) => {
    setSortDirection(sortField === field && sortDirection === 'asc' ? 'desc' : 'asc');
    setSortField(field);
  };

  if (!authorities.length) {
    return <div className="p-4">No housing authorities data available</div>;
  }

  return (
    <div className="w-full">
      {/* Simple filter */}
      <div className="mb-4">
        <select 
          value={sizeFilter} 
          onChange={(e) => setSizeFilter(e.target.value)}
          className="border border-gray-300 rounded px-3 py-1"
        >
          <option value="all">All Sizes</option>
          <option value="small">Small</option>
          <option value="medium">Medium</option>
          <option value="large">Large</option>
        </select>
      </div>

      {/* Simple table */}
      <table className="w-full border border-gray-200">
        <thead className="bg-gray-50">
          <tr>
            <th onClick={() => handleSort('name')} 
                className="p-2 text-left cursor-pointer hover:bg-gray-100">
              Name {sortField === 'name' ? (sortDirection === 'asc' ? '↑' : '↓') : ''}
            </th>
            <th onClick={() => handleSort('state')} 
                className="p-2 text-left cursor-pointer hover:bg-gray-100">
              State {sortField === 'state' ? (sortDirection === 'asc' ? '↑' : '↓') : ''}
            </th>
            <th onClick={() => handleSort('units')} 
                className="p-2 text-left cursor-pointer hover:bg-gray-100">
              Units {sortField === 'units' ? (sortDirection === 'asc' ? '↑' : '↓') : ''}
            </th>
            <th onClick={() => handleSort('hudRating')} 
                className="p-2 text-left cursor-pointer hover:bg-gray-100">
              HUD Rating {sortField === 'hudRating' ? (sortDirection === 'asc' ? '↑' : '↓') : ''}
            </th>
          </tr>
        </thead>
        <tbody>
          {sortedData.map((auth, index) => (
            <tr key={auth.id || index} className="border-b hover:bg-gray-50">
              <td className="p-2">{auth.name}</td>
              <td className="p-2">{auth.state}</td>
              <td className="p-2">{auth.units?.toLocaleString()}</td>
              <td className="p-2">{auth.hudRating}</td>
            </tr>
          ))}
        </tbody>
      </table>
      
      <p className="mt-2 text-sm text-gray-600">
        Showing {sortedData.length} of {authorities.length} authorities
      </p>
    </div>
  );
};

export default HousingAuthorityTable;

// TOTAL: ~80 lines - Perfect for text editor editing

SIMPLICITY PRINCIPLE FOR REACT (CRITICAL FOR TEXT EDITOR WORKFLOW):

INTEGRATION WITH EXISTING PYTHON BACKEND:

REMINDERS: