import React, { useMemo, useState } from „react“;
import { motion } from „framer-motion“;
import { PieChart, Pie, Cell, ResponsiveContainer, Tooltip, BarChart, Bar, XAxis, YAxis, Legend, CartesianGrid } from „recharts“;
import { Bike, Bus, Leaf, PlugZap, Droplets, Flame, Home, Car, ShoppingBag, Soup, Waves, Wallet, Settings2, Plus, RefreshCw } from „lucide-react“;
// shadcn/ui
import { Card, CardContent, CardHeader, CardTitle } from „@/components/ui/card“;
import { Button } from „@/components/ui/button“;
import { Input } from „@/components/ui/input“;
import { Label } from „@/components/ui/label“;
import { Slider } from „@/components/ui/slider“;
import { Switch } from „@/components/ui/switch“;
import { Tabs, TabsContent, TabsList, TabsTrigger } from „@/components/ui/tabs“;
import { Separator } from „@/components/ui/separator“;
import { Badge } from „@/components/ui/badge“;
// ––––––––
// Помощни типове и данни
// ––––––––
type LineItem = {
key: string;
label: string;
icon?: React.ReactNode;
monthly: number; // базов разход в лева (лв.)
category: string;
editable?: boolean;
};
type Action = {
key: string;
label: string;
desc: string;
enabled: boolean;
intensity?: number; // 0..100 (%), ако е с плъзгач
};
const CURRENCY = „лв.“;
const COLORS = [
„#0ea5e9“,
„#22c55e“,
„#eab308“,
„#f97316“,
„#a855f7“,
„#ef4444“,
„#14b8a6“,
„#94a3b8“,
];
// Предефинирани сценарии (примерни стойности – редактират се от потребителя)
const PRESETS: Record
= {
„Сам човек в голям град“: [
{ key: „rent“, label: „Наем/Кредит“, category: „Дом“, monthly: 1200, icon: },
{ key: „electricity“, label: „Електроенергия“, category: „Комунални“, monthly: 140, icon: },
{ key: „heating“, label: „Отопление/Газ“, category: „Комунални“, monthly: 160, icon: },
{ key: „water“, label: „Вода“, category: „Комунални“, monthly: 35, icon: },
{ key: „internet“, label: „Интернет/ТВ“, category: „Комуникации“, monthly: 45, icon: },
{ key: „mobile“, label: „Мобилен план“, category: „Комуникации“, monthly: 30, icon: },
{ key: „fuel“, label: „Гориво/Паркиране“, category: „Транспорт“, monthly: 260, icon: },
{ key: „public“, label: „Обществен транспорт“, category: „Транспорт“, monthly: 60, icon: },
{ key: „bike“, label: „Поддръжка велосипед/тротинетка“, category: „Транспорт“, monthly: 15, icon: },
{ key: „groceries“, label: „Храна – магазин“, category: „Храна“, monthly: 420, icon: },
{ key: „eatingout“, label: „Храна навън/кафета“, category: „Храна“, monthly: 180, icon: },
{ key: „clothes“, label: „Дрехи/лични“, category: „Пазаруване“, monthly: 120, icon: },
{ key: „household“, label: „Дом/консумативи“, category: „Пазаруване“, monthly: 90, icon: },
{ key: „subs“, label: „Абонаменти/стрийминг/софтуер“, category: „Забавления“, monthly: 40, icon: },
{ key: „leisure“, label: „Свободно време/събития“, category: „Забавления“, monthly: 120, icon: },
{ key: „health“, label: „Здраве/лекарства“, category: „Здраве“, monthly: 60, icon: },
],
„Двама възрастни“: [
{ key: „rent“, label: „Наем/Кредит“, category: „Дом“, monthly: 1600, icon: },
{ key: „electricity“, label: „Електроенергия“, category: „Комунални“, monthly: 190, icon: },
{ key: „heating“, label: „Отопление/Газ“, category: „Комунални“, monthly: 210, icon: },
{ key: „water“, label: „Вода“, category: „Комунални“, monthly: 50, icon: },
{ key: „internet“, label: „Интернет/ТВ“, category: „Комуникации“, monthly: 55, icon: },
{ key: „mobile“, label: „Мобилни планове (2)“, category: „Комуникации“, monthly: 60, icon: },
{ key: „fuel“, label: „Гориво/Паркиране“, category: „Транспорт“, monthly: 340, icon: },
{ key: „public“, label: „Обществен транспорт“, category: „Транспорт“, monthly: 100, icon: },
{ key: „bike“, label: „Поддръжка велосипеди“, category: „Транспорт“, monthly: 20, icon: },
{ key: „groceries“, label: „Храна – магазин“, category: „Храна“, monthly: 650, icon: },
{ key: „eatingout“, label: „Храна навън/кафета“, category: „Храна“, monthly: 260, icon: },
{ key: „clothes“, label: „Дрехи/лични“, category: „Пазаруване“, monthly: 200, icon: },
{ key: „household“, label: „Дом/консумативи“, category: „Пазаруване“, monthly: 140, icon: },
{ key: „subs“, label: „Абонаменти/стрийминг/софтуер“, category: „Забавления“, monthly: 60, icon: },
{ key: „leisure“, label: „Свободно време/събития“, category: „Забавления“, monthly: 200, icon: },
{ key: „health“, label: „Здраве/лекарства“, category: „Здраве“, monthly: 100, icon: },
],
„Семейство с дете“: [
{ key: „rent“, label: „Наем/Кредит“, category: „Дом“, monthly: 1800, icon: },
{ key: „electricity“, label: „Електроенергия“, category: „Комунални“, monthly: 210, icon: },
{ key: „heating“, label: „Отопление/Газ“, category: „Комунални“, monthly: 240, icon: },
{ key: „water“, label: „Вода“, category: „Комунални“, monthly: 65, icon: },
{ key: „internet“, label: „Интернет/ТВ“, category: „Комуникации“, monthly: 55, icon: },
{ key: „mobile“, label: „Мобилни планове (2-3)“, category: „Комуникации“, monthly: 80, icon: },
{ key: „fuel“, label: „Гориво/Паркиране“, category: „Транспорт“, monthly: 420, icon: },
{ key: „public“, label: „Обществен транспорт“, category: „Транспорт“, monthly: 120, icon: },
{ key: „bike“, label: „Поддръжка велосипеди/детски“, category: „Транспорт“, monthly: 25, icon: },
{ key: „groceries“, label: „Храна – магазин“, category: „Храна“, monthly: 900, icon: },
{ key: „eatingout“, label: „Храна навън/кафета“, category: „Храна“, monthly: 320, icon: },
{ key: „clothes“, label: „Дрехи/лични“, category: „Пазаруване“, monthly: 260, icon: },
{ key: „household“, label: „Дом/консумативи (вкл. бебешки)“, category: „Пазаруване“, monthly: 220, icon: },
{ key: „subs“, label: „Абонаменти/стрийминг/софтуер“, category: „Забавления“, monthly: 70, icon: },
{ key: „leisure“, label: „Свободно време/събития“, category: „Забавления“, monthly: 260, icon: },
{ key: „health“, label: „Здраве/лекарства“, category: „Здраве“, monthly: 140, icon: },
],
};
// Еко-действия: дефинираме кои редове засягат и как (процент намаление)
const ACTION_RULES: Record = {
energy_saving: { affects: [„electricity“], maxPct: 25 },
heat_down: { affects: [„heating“], maxPct: 15 },
water_saving: { affects: [„water“], maxPct: 20 },
transit_shift: { affects: [„fuel“], maxPct: 90 },
bike_commute: { affects: [„fuel“], maxPct: 40 },
eat_plant: { affects: [„groceries“, „eatingout“], maxPct: 20 },
zero_waste: { affects: [„household“], maxPct: 25 },
thrifting: { affects: [„clothes“], maxPct: 50 },
subs_trim: { affects: [„subs“], maxPct: 60 },
dine_less: { affects: [„eatingout“], maxPct: 70 },
wfh: { affects: [„fuel“, „eatingout“], maxPct: 40 },
};
const DEFAULT_ACTIONS: Action[] = [
{ key: „energy_saving“, label: „Енергийно-ефективни навици (LED, изключване на уреди)“, desc: „Намалява електроенергията“, enabled: true, intensity: 60 },
{ key: „heat_down“, label: „Термостат -1 до -2°C“, desc: „Намалява отоплението“, enabled: false, intensity: 40 },
{ key: „water_saving“, label: „Пестене на вода (перлатори, кратък душ)“, desc: „Намалява водата“, enabled: true, intensity: 40 },
{ key: „transit_shift“, label: „Повече обществен транспорт“, desc: „Малко/никакво гориво“, enabled: false, intensity: 30 },
{ key: „bike_commute“, label: „Колоездене/пеша за близки дистанции“, desc: „Още по-малко гориво“, enabled: true, intensity: 40 },
{ key: „wfh“, label: „Работа от вкъщи няколко дни“, desc: „По-малко гориво и обяд навън“, enabled: false, intensity: 30 },
{ key: „eat_plant“, label: „Повече растителна храна“, desc: „Намалява храната и навън“, enabled: true, intensity: 25 },
{ key: „dine_less“, label: „По-рядко хранене навън“, desc: „Намалява разхода навън“, enabled: false, intensity: 30 },
{ key: „zero_waste“, label: „Нулеви отпадъци/насипни продукти“, desc: „Намалява консумативи“, enabled: true, intensity: 30 },
{ key: „thrifting“, label: „Втора употреба/ремонт на дрехи“, desc: „Намалява дрехи“, enabled: true, intensity: 50 },
{ key: „subs_trim“, label: „Оптимизация на абонаменти“, desc: „Намалява абонаменти“, enabled: true, intensity: 50 },
];
function formatCurrency(x: number) {
return `${x.toFixed(0)} ${CURRENCY}`;
}
export default function EcoSavingsCalculatorBG() {
const [items, setItems] = useState(PRESETS[„Сам човек в голям град“]);
const [actions, setActions] = useState(DEFAULT_ACTIONS);
const [customName, setCustomName] = useState(„“);
const [customValue, setCustomValue] = useState(„“);
const [customCategory, setCustomCategory] = useState(„Други“);
const [preset, setPreset] = useState(„Сам човек в голям град“);
const categories = useMemo(
() => Array.from(new Set(items.map((i) => i.category))),
[items]
);
const baseTotal = useMemo(
() => items.reduce((sum, i) => sum + i.monthly, 0),
[items]
);
const savingsByAction = useMemo(() => {
const map: Record = {};
actions.forEach((a) => {
if (!a.enabled) return;
const rule = ACTION_RULES[a.key];
if (!rule) return;
const pct = ((a.intensity ?? 0) / 100) * rule.maxPct; // реално прилаган процент
rule.affects.forEach((k) => {
const line = items.find((it) => it.key === k);
if (!line) return;
const save = (line.monthly * pct) / 100;
map[k] = (map[k] || 0) + save;
});
});
return map; // по ключ на ред
}, [actions, items]);
const ecoItems = useMemo(() => {
return items.map((i) => ({
…i,
monthly: Math.max(0, i.monthly – (savingsByAction[i.key] || 0)),
}));
}, [items, savingsByAction]);
const ecoTotal = useMemo(
() => ecoItems.reduce((sum, i) => sum + i.monthly, 0),
[ecoItems]
);
const totalSavings = Math.max(0, baseTotal – ecoTotal);
function applyPreset(name: string) {
setPreset(name);
setItems(PRESETS[name].map((x) => ({ …x })));
}
function updateItem(key: string, value: number) {
setItems((prev) => prev.map((i) => (i.key === key ? { …i, monthly: value } : i)));
}
function addCustomItem() {
const v = Number(customValue);
if (!customName || isNaN(v)) return;
const newItem: LineItem = {
key: `${Date.now()}`,
label: customName,
category: customCategory || „Други“,
monthly: Math.max(0, v),
editable: true,
};
setItems((prev) => […prev, newItem]);
setCustomName(„“);
setCustomValue(„“);
}
function resetActions() {
setActions(DEFAULT_ACTIONS.map((a) => ({ …a })));
}
const chartData = useMemo(() => {
const byCatBase: Record = {};
const byCatEco: Record = {};
items.forEach((i) => (byCatBase[i.category] = (byCatBase[i.category] || 0) + i.monthly));
ecoItems.forEach((i) => (byCatEco[i.category] = (byCatEco[i.category] || 0) + i.monthly));
return categories.map((c) => ({ category: c, „База“: byCatBase[c] || 0, „Еко“: byCatEco[c] || 0 }));
}, [items, ecoItems, categories]);
const pieData = useMemo(() => {
return [
{ name: „Базов бюджет“, value: baseTotal },
{ name: „Еко бюджет“, value: ecoTotal },
{ name: „Спестявания“, value: totalSavings },
];
}, [baseTotal, ecoTotal, totalSavings]);
return (
Еко Спестявания: колко можете да спестите месечно?
Настройте реалните си разходи и включете природосъобразни навици. Калкулаторът ще изчисли
потенциалните спестявания на месечна и годишна база.
{/* Лява колона: Настройки и разходи */}
1) Базови разходи
{categories.map((c) => (
{c}
))}
{categories.map((c) => (
{items.filter((i) => i.category === c).map((it) => (
))}
))}
2) Еко-действия
Включете навици и настройки. Плъзгачът управлява интензитета (реален ефект до максималния процент).
{actions.map((a, idx) => (
setActions((prev) => prev.map((x) => x.key === a.key ? { …x, enabled: v } : x))} />
{a.label}
{a.desc} · до {ACTION_RULES[a.key].maxPct}%
setActions((prev) => prev.map((x) => x.key === a.key ? { …x, intensity: v[0] } : x))}
/>
))}
Забележка: Процентите са ориентировъчни и зависят от жилище, навици и градска среда. Всички стойности са напълно редактиратеми.