Untitled
unknown
plain_text
9 months ago
5.2 kB
7
Indexable
"use client"
import React, { useEffect, useState } from 'react';
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card";
import { TreePine, Leaf, Trophy, Unlock } from "lucide-react";
import { Progress } from "@/components/ui/progress";
interface TreeVisualizationProps {
impact: {
co2_saved: number;
trees_saved: number;
};
}
const SingleTree = ({ scale }: { scale: number }) => {
if (scale === 0) return null;
return (
<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;
useEffect(() => {
const isMaxed = impact.trees_saved >= maxTrees;
const totalTrees = Math.floor(impact.trees_saved);
const partialTreeScale = isMaxed ? 100 : (impact.trees_saved % 1) * 100;
let newTreeStates: number[] = [];
// Add full trees
for (let i = 0; i < Math.min(totalTrees, maxTrees); i++) {
newTreeStates.push(100);
}
// Add partial tree if there's room and not maxed
if (!isMaxed && 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 = Math.min((impact.trees_saved / maxTrees) * 100, 100);
const isMaxed = impact.trees_saved >= maxTrees;
return (
<>
<CardHeader className="items-center pb-2">
<CardTitle className="flex items-center justify-between w-full">
<div className="flex items-center gap-2">
<TreePine className="h-5 w-5 text-green-700" />
Your Impact Forest
</div>
{isMaxed && <Unlock className="h-5 w-5 text-primary" />}
</CardTitle>
<CardDescription>Watch your forest grow with your impact</CardDescription>
</CardHeader>
<CardContent className={`flex flex-col items-center space-y-4 transition-all duration-200 ${
isMaxed
? 'dark:bg-gradient-to-br dark:from-primary/10 dark:to-primary/5 ' +
'bg-gradient-to-br from-primary/20 to-background border-primary/50 ' +
'shadow-lg shadow-primary/5 rounded-lg'
: ''
}`}>
<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.round(totalProgress)}%</span>
</div>
<Progress value={totalProgress} 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>
{isMaxed && (
<div className="flex items-center gap-2 text-primary font-medium">
<Trophy className="h-5 w-5" />
Maximum Forest Size Reached!
</div>
)}
</CardContent>
</>
);
};
export default TreeVisualization;Editor is loading...
Leave a Comment