This commit is contained in:
Matt 2025-06-03 17:07:59 +02:00
parent af3abb2afd
commit 1f2e0e8222

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react';
import React, { useState, useEffect, useCallback } from 'react';
import { Check, AlertCircle, ArrowLeft, Loader2, Globe2, TreePine, Waves, Factory, Wind, X } from 'lucide-react';
import { motion } from 'framer-motion';
import { createOffsetOrder, getPortfolios } from '../api/wrenClient';
@ -128,13 +128,21 @@ export function OffsetOrder({ tons, monetaryAmount, onBack, calculatorType }: Pr
// Calculate offset cost using the portfolio price
const offsetCost = monetaryAmount || (portfolio ? tons * (portfolio.pricePerTon || 18) : 0);
// Completely simplified project selection handler
const handleProjectClick = (project: OffsetProject, e: React.MouseEvent) => {
// Robust project click handler with multiple fallbacks
const handleProjectClick = useCallback((project: OffsetProject, e?: React.MouseEvent) => {
if (e) {
e.preventDefault();
e.stopPropagation();
}
console.log('Opening project details for:', project.name);
setSelectedProject(project);
};
}, []);
// Additional handler for direct button clicks
const handleProjectButtonClick = useCallback((project: OffsetProject) => {
console.log('Button click - Opening project details for:', project.name);
setSelectedProject(project);
}, []);
// Simple lightbox close handler
const handleCloseLightbox = () => {
@ -343,56 +351,96 @@ export function OffsetOrder({ tons, monetaryAmount, onBack, calculatorType }: Pr
animate={{ opacity: 1 }}
transition={{ duration: 0.5, delay: 0.3 }}
>
{portfolio.projects.map((project) => (
<div
key={project.id}
className="bg-gray-50 rounded-lg p-4 hover:shadow-lg transition-all cursor-pointer border border-gray-200 hover:border-blue-300"
onClick={(e) => handleProjectClick(project, e)}
role="button"
tabIndex={0}
style={{
userSelect: 'none',
WebkitUserSelect: 'none',
msUserSelect: 'none',
MozUserSelect: 'none'
}}
{portfolio.projects.map((project, index) => (
<motion.div
key={project.id || `project-${index}`}
className="bg-white rounded-lg p-6 shadow-md hover:shadow-xl transition-all border border-gray-200 hover:border-blue-400 relative group"
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3, delay: index * 0.1 }}
whileHover={{ scale: 1.02 }}
>
<div className="flex items-center justify-between mb-3">
<div className="flex items-center space-x-2">
{/* Header with title and percentage */}
<div className="flex items-center justify-between mb-4">
<div className="flex items-center space-x-3">
<ProjectTypeIcon project={project} />
<h4 className="font-semibold text-gray-900">{project.name}</h4>
<h4 className="font-bold text-gray-900 text-lg">{project.name}</h4>
</div>
{project.percentage && (
<span className="text-sm text-gray-600 font-medium">
<span className="text-sm bg-blue-100 text-blue-800 font-medium px-3 py-1 rounded-full">
{(project.percentage * 100).toFixed(1)}%
</span>
)}
</div>
{/* Project image */}
{project.imageUrl && (
<div className="relative h-32 mb-3 rounded-lg overflow-hidden">
<div className="relative h-40 mb-4 rounded-lg overflow-hidden">
<img
src={project.imageUrl}
alt={project.name}
className="absolute inset-0 w-full h-full object-cover transition-transform duration-300 hover:scale-110"
style={{ pointerEvents: 'none' }}
className="w-full h-full object-cover transition-transform duration-300 group-hover:scale-105"
/>
<div className="absolute inset-0 bg-gradient-to-t from-black/20 to-transparent opacity-0 group-hover:opacity-100 transition-opacity" />
</div>
)}
<p className="text-sm text-gray-600 mb-3">
{/* Description */}
<p className="text-gray-600 mb-4 leading-relaxed">
{project.shortDescription || project.description}
</p>
<div className="space-y-1 text-sm mt-3">
<div className="flex justify-between">
<span className="text-gray-500">Price per ton:</span>
<span className="text-gray-900 font-medium">
{/* Price info */}
<div className="bg-gray-50 p-3 rounded-lg mb-4">
<div className="flex justify-between items-center">
<span className="text-gray-600 font-medium">Price per ton:</span>
<span className="text-gray-900 font-bold text-lg">
${project.pricePerTon.toFixed(2)}
</span>
</div>
</div>
<div className="mt-3 text-center">
<span className="text-xs text-blue-600 font-medium">👆 Click for details</span>
</div>
</div>
{/* Click button - Primary call to action */}
<button
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
handleProjectButtonClick(project);
}}
className="w-full bg-blue-600 hover:bg-blue-700 text-white font-semibold py-3 px-4 rounded-lg transition-colors duration-200 flex items-center justify-center space-x-2 group-hover:scale-105 transform transition-transform"
onMouseDown={(e) => e.preventDefault()}
onTouchStart={(e) => e.preventDefault()}
>
<span>View Project Details</span>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
</svg>
</button>
{/* Fallback click area - covers entire card */}
<div
className="absolute inset-0 cursor-pointer z-10"
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
handleProjectClick(project, e);
}}
onTouchEnd={(e) => {
e.preventDefault();
e.stopPropagation();
handleProjectClick(project);
}}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
handleProjectClick(project);
}
}}
role="button"
tabIndex={0}
aria-label={`View details for ${project.name}`}
/>
</motion.div>
))}
</motion.div>
)}