Untitled
"use client" import React, { useEffect, useState } from 'react'; import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"; import { TreePine, Leaf, Trophy } from "lucide-react"; import { Progress } from "@/components/ui/progress"; import { Alert, AlertDescription } from "@/components/ui/alert"; interface TreeVisualizationProps { impact: { co2_saved: number; trees_saved: number; }; } const SingleTree = ({ scale }: { scale: number }) => ( <svg viewBox="0 0 100 100" className="w-full h-full transform transition-all duration-1000" style={{ transform: `scale(${0.5 + (scale * 0.5) / 100})` }} > <path d="M45 90 L55 90 L53 60 L47 60 Z" fill="#8B4513" className="transition-all duration-1000" style={{ transform: `scaleY(${0.8 + (scale * 0.2) / 100})`, transformOrigin: 'center bottom' }} /> <g className="transition-all duration-1000"> <path d="M20 60 L80 60 L50 30 Z" fill="#2F855A" opacity={scale >= 20 ? "1" : "0"} className="transition-all duration-500" /> <path d="M25 45 L75 45 L50 20 Z" fill="#276749" opacity={scale >= 50 ? "1" : "0"} className="transition-all duration-500" /> <path d="M30 30 L70 30 L50 10 Z" fill="#22543D" opacity={scale >= 80 ? "1" : "0"} className="transition-all duration-500" /> {scale >= 95 && ( <> <circle cx="35" cy="50" r="2" fill="#48BB78" /> <circle cx="65" cy="50" r="2" fill="#48BB78" /> <circle cx="50" cy="25" r="2" fill="#48BB78" /> </> )} </g> </svg> ); const TreeVisualization: React.FC<TreeVisualizationProps> = ({ impact }) => { const [treeStates, setTreeStates] = useState<number[]>([]); const maxTrees = 5; const treeThreshold = 1; // CO2 saved needed for one full tree useEffect(() => { const totalTrees = Math.floor(impact.trees_saved); const partialTreeScale = (impact.trees_saved % 1) * 100; let newTreeStates: number[] = []; // Add full trees for (let i = 0; i < Math.min(totalTrees, maxTrees - 1); i++) { newTreeStates.push(100); } // Add partial tree if there's room if (newTreeStates.length < maxTrees) { newTreeStates.push(partialTreeScale); } // Pad with empty trees if needed while (newTreeStates.length < maxTrees) { newTreeStates.push(0); } setTreeStates(newTreeStates.slice(0, maxTrees)); }, [impact.trees_saved]); const totalProgress = (impact.trees_saved / maxTrees) * 100; return ( <> <CardHeader className="items-center pb-2"> <CardTitle className="flex items-center gap-2"> <TreePine className="h-5 w-5 text-green-700" /> Your Impact Forest </CardTitle> <CardDescription>Watch your forest grow with your impact</CardDescription> </CardHeader> <CardContent className="flex flex-col items-center space-y-4"> <div className="grid grid-cols-5 gap-2 w-full h-48"> {treeStates.map((scale, index) => ( <div key={index} className="relative flex items-center justify-center"> <SingleTree scale={scale} /> </div> ))} </div> <div className="w-full space-y-2"> <div className="flex justify-between text-sm"> <span>Forest Growth Progress</span> <span>{Math.min(Math.round(totalProgress), 100)}%</span> </div> <Progress value={Math.min(totalProgress, 100)} className="h-2" /> </div> <div className="grid grid-cols-2 gap-4 text-sm text-muted-foreground"> <div className="flex items-center gap-2"> <Leaf className="h-4 w-4 text-green-500" /> <span>{impact.co2_saved.toFixed(2)} kg CO₂ saved</span> </div> <div className="flex items-center gap-2"> <TreePine className="h-4 w-4 text-green-700" /> <span>{impact.trees_saved.toFixed(3)} trees preserved</span> </div> </div> {impact.trees_saved >= maxTrees && ( <Alert className="bg-green-50 border-green-200"> <Trophy className="h-4 w-4 text-green-600" /> <AlertDescription className="text-green-800"> 🎉 Maximum forest size reached! Amazing work on your environmental impact! </AlertDescription> </Alert> )} </CardContent> </> ); }; export default TreeVisualization;
Leave a Comment