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 { Check, AlertCircle, ArrowLeft, Loader2, Globe2, TreePine, Waves, Factory, Wind, X } from 'lucide-react';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import { createOffsetOrder, getPortfolios } from '../api/wrenClient'; 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 // Calculate offset cost using the portfolio price
const offsetCost = monetaryAmount || (portfolio ? tons * (portfolio.pricePerTon || 18) : 0); const offsetCost = monetaryAmount || (portfolio ? tons * (portfolio.pricePerTon || 18) : 0);
// Completely simplified project selection handler // Robust project click handler with multiple fallbacks
const handleProjectClick = (project: OffsetProject, e: React.MouseEvent) => { const handleProjectClick = useCallback((project: OffsetProject, e?: React.MouseEvent) => {
if (e) {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
}
console.log('Opening project details for:', project.name); console.log('Opening project details for:', project.name);
setSelectedProject(project); 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 // Simple lightbox close handler
const handleCloseLightbox = () => { const handleCloseLightbox = () => {
@ -343,56 +351,96 @@ export function OffsetOrder({ tons, monetaryAmount, onBack, calculatorType }: Pr
animate={{ opacity: 1 }} animate={{ opacity: 1 }}
transition={{ duration: 0.5, delay: 0.3 }} transition={{ duration: 0.5, delay: 0.3 }}
> >
{portfolio.projects.map((project) => ( {portfolio.projects.map((project, index) => (
<div <motion.div
key={project.id} key={project.id || `project-${index}`}
className="bg-gray-50 rounded-lg p-4 hover:shadow-lg transition-all cursor-pointer border border-gray-200 hover:border-blue-300" className="bg-white rounded-lg p-6 shadow-md hover:shadow-xl transition-all border border-gray-200 hover:border-blue-400 relative group"
onClick={(e) => handleProjectClick(project, e)} initial={{ opacity: 0, y: 20 }}
role="button" animate={{ opacity: 1, y: 0 }}
tabIndex={0} transition={{ duration: 0.3, delay: index * 0.1 }}
style={{ whileHover={{ scale: 1.02 }}
userSelect: 'none',
WebkitUserSelect: 'none',
msUserSelect: 'none',
MozUserSelect: 'none'
}}
> >
<div className="flex items-center justify-between mb-3"> {/* Header with title and percentage */}
<div className="flex items-center space-x-2"> <div className="flex items-center justify-between mb-4">
<div className="flex items-center space-x-3">
<ProjectTypeIcon project={project} /> <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> </div>
{project.percentage && ( {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)}% {(project.percentage * 100).toFixed(1)}%
</span> </span>
)} )}
</div> </div>
{/* Project image */}
{project.imageUrl && ( {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 <img
src={project.imageUrl} src={project.imageUrl}
alt={project.name} alt={project.name}
className="absolute inset-0 w-full h-full object-cover transition-transform duration-300 hover:scale-110" className="w-full h-full object-cover transition-transform duration-300 group-hover:scale-105"
style={{ pointerEvents: 'none' }}
/> />
<div className="absolute inset-0 bg-gradient-to-t from-black/20 to-transparent opacity-0 group-hover:opacity-100 transition-opacity" />
</div> </div>
)} )}
<p className="text-sm text-gray-600 mb-3">
{/* Description */}
<p className="text-gray-600 mb-4 leading-relaxed">
{project.shortDescription || project.description} {project.shortDescription || project.description}
</p> </p>
<div className="space-y-1 text-sm mt-3">
<div className="flex justify-between"> {/* Price info */}
<span className="text-gray-500">Price per ton:</span> <div className="bg-gray-50 p-3 rounded-lg mb-4">
<span className="text-gray-900 font-medium"> <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)} ${project.pricePerTon.toFixed(2)}
</span> </span>
</div> </div>
</div> </div>
<div className="mt-3 text-center">
<span className="text-xs text-blue-600 font-medium">👆 Click for details</span> {/* Click button - Primary call to action */}
</div> <button
</div> 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> </motion.div>
)} )}