Untitled
unknown
plain_text
9 months ago
9.4 kB
6
Indexable
import React, { useState } from 'react';
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Leaf, TreePine, Recycle, PlaneTakeoff, Car, LightbulbOff, Smartphone } from "lucide-react";
import { Pie, PieChart } from "recharts";
import { useMetrics } from '@/hooks/useMetrics';
import { AppSidebar } from "@/components/app-sidebar";
import { SidebarInset, SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar";
import { Separator } from "@/components/ui/separator";
import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
} from "@/components/ui/breadcrumb";
import {
ChartConfig,
ChartContainer,
ChartTooltip,
ChartTooltipContent,
} from "@/components/ui/chart";
const timeOptions = [
{ value: "day", label: "Last 24 Hours" },
{ value: "week", label: "Last Week" },
{ value: "month", label: "Last Month" },
{ value: "year", label: "Last Year" },
];
const materialChartConfig = {
paper: {
label: "Paper",
color: "hsl(var(--chart-1))",
},
plastic: {
label: "Plastic",
color: "hsl(var(--chart-2))",
},
organic: {
label: "Organic",
color: "hsl(var(--chart-3))",
},
} satisfies ChartConfig;
export default function EnvironmentalImpact() {
const [selectedPeriod, setSelectedPeriod] = useState("month");
const { metrics, loading, error } = useMetrics();
const getPeriodMultiplier = (period) => {
switch (period) {
case 'day': return 1/30;
case 'week': return 1/4;
case 'year': return 12;
default: return 1; // month
}
};
const getAdjustedMetrics = (metrics, period) => {
if (!metrics) return null;
const multiplier = getPeriodMultiplier(period);
const { environmental_impact: impact } = metrics;
return {
co2_saved: impact.co2_saved * multiplier,
trees_saved: impact.trees_saved * multiplier,
paper_weight_recycled: impact.paper_weight_recycled * multiplier,
plastic_weight_recycled: impact.plastic_weight_recycled * multiplier,
organic_weight_processed: impact.organic_weight_processed * multiplier,
};
};
if (loading) return <div className="p-4">Loading...</div>;
if (error) return <div className="p-4">Error: {error}</div>;
if (!metrics) return null;
const impact = getAdjustedMetrics(metrics, selectedPeriod);
// Environmental equivalents calculations
const carKmAvoided = impact.co2_saved * 4; // Approx 250g CO2 per km
const flightsAvoided = Math.round(impact.co2_saved / 0.2); // Assuming 0.2kg CO2 per short flight
const phoneCharges = Math.round(impact.co2_saved * 1000); // Rough estimate for phone charges
const lightbulbHours = Math.round(impact.co2_saved * 100); // LED bulb hours equivalent
// Tree equivalents
const oxygenForPeople = Math.round(impact.trees_saved * 2); // People's oxygen needs per day
const paperSheetsSaved = Math.round(impact.trees_saved * 8333); // Sheets per tree approximation
const materialsData = [
{
name: "paper",
value: impact.paper_weight_recycled,
fill: "var(--color-paper)"
},
{
name: "plastic",
value: impact.plastic_weight_recycled,
fill: "var(--color-plastic)"
},
{
name: "organic",
value: impact.organic_weight_processed,
fill: "var(--color-organic)"
}
].filter(item => item.value > 0);
return (
<SidebarProvider>
<AppSidebar />
<SidebarInset>
<header className="flex shrink-0 items-center gap-2 border-b px-4 py-6">
<SidebarTrigger className="-ml-1" />
<Separator orientation="vertical" className="mr-2 h-4" />
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink href="/">Home</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbItem>
<BreadcrumbLink href="/impact">Environmental Impact</BreadcrumbLink>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
</header>
<main className="p-4 space-y-4">
<div className="flex justify-between items-center">
<h1 className="text-2xl font-bold">Environmental Impact</h1>
<Select value={selectedPeriod} onValueChange={setSelectedPeriod}>
<SelectTrigger className="w-[180px]">
<SelectValue placeholder="Select period" />
</SelectTrigger>
<SelectContent>
{timeOptions.map((option) => (
<SelectItem key={option.value} value={option.value}>
{option.label}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4">
{/* CO2 Saved Card */}
<Card className="xl:col-span-2">
<CardHeader className="pb-2">
<CardTitle className="flex items-center gap-2 text-lg">
<Leaf className="h-5 w-5 text-green-500" />
CO₂ Impact
</CardTitle>
</CardHeader>
<CardContent>
<div className="mt-2 space-y-4">
<div className="text-3xl font-bold text-green-500">
{impact.co2_saved.toFixed(2)} kg CO₂ saved
</div>
<div className="grid grid-cols-2 gap-4">
<div className="flex items-center gap-2 text-sm">
<Car className="h-4 w-4 text-blue-500" />
<span>{carKmAvoided.toFixed(1)} km of driving avoided</span>
</div>
<div className="flex items-center gap-2 text-sm">
<PlaneTakeoff className="h-4 w-4 text-blue-500" />
<span>Equal to {flightsAvoided} short flights</span>
</div>
<div className="flex items-center gap-2 text-sm">
<Smartphone className="h-4 w-4 text-blue-500" />
<span>{phoneCharges} phone charges saved</span>
</div>
<div className="flex items-center gap-2 text-sm">
<LightbulbOff className="h-4 w-4 text-blue-500" />
<span>{lightbulbHours} hours of LED bulb usage</span>
</div>
</div>
</div>
</CardContent>
</Card>
{/* Trees Saved Card */}
<Card>
<CardHeader className="pb-2">
<CardTitle className="flex items-center gap-2 text-lg">
<TreePine className="h-5 w-5 text-green-700" />
Tree Impact
</CardTitle>
</CardHeader>
<CardContent>
<div className="mt-2 space-y-4">
<div className="text-3xl font-bold text-green-700">
{impact.trees_saved.toFixed(3)} trees preserved
</div>
<div className="space-y-2">
<div className="text-sm">
⚡ Provides daily oxygen for {oxygenForPeople} people
</div>
<div className="text-sm">
📄 Saved {paperSheetsSaved.toLocaleString()} sheets of paper
</div>
</div>
</div>
</CardContent>
</Card>
{/* Materials Recycled Card */}
<Card className="xl:col-span-3">
<CardHeader className="pb-2">
<CardTitle className="flex items-center gap-2 text-lg">
<Recycle className="h-5 w-5 text-blue-500" />
Materials Recycled by Type
</CardTitle>
</CardHeader>
<CardContent>
<ChartContainer
config={materialChartConfig}
className="mx-auto h-[300px] w-full"
>
<PieChart>
<ChartTooltip
content={
<ChartTooltipContent
formatter={(value: number) => `${value.toFixed(2)} kg`}
/>
}
/>
<Pie
data={materialsData}
dataKey="value"
nameKey="name"
cx="50%"
cy="50%"
innerRadius={60}
outerRadius={120}
label={(entry) => `${materialChartConfig[entry.name].label}: ${entry.value.toFixed(2)}kg`}
labelLine={true}
/>
</PieChart>
</ChartContainer>
</CardContent>
</Card>
</div>
</main>
</SidebarInset>
</SidebarProvider>
);
}Editor is loading...
Leave a Comment