All files / pages Finance.jsx

44.44% Statements 16/36
75% Branches 15/20
25% Functions 4/16
64% Lines 16/25

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123                1x             1x           14x 14x 14x 14x 14x 14x   14x   14x       14x         14x   14x                                                                                     56x   4x                               1x                                        
import { useState } from "react"
import Navigation from "../components/Navigation"
import FinanceDashboard from "../components/finance/FinanceDashboard"
import TransactionList from "../components/finance/TransactionList"
import FinanceAnalytics from "../components/finance/FinanceAnalytics"
import CategoriesManager from "../components/finance/CategoriesManager"
import AddTransactionModal from "../components/finance/AddTransactionModal"
 
const tabs = [
  { key: "dashboard", label: "Обзор", icon: "📊" },
  { key: "transactions", label: "Транзакции", icon: "📋" },
  { key: "analytics", label: "Аналитика", icon: "📈" },
  { key: "categories", label: "Категории", icon: "🏷️" },
]
 
const MONTH_NAMES = [
  "Январь", "Февраль", "Март", "Апрель", "Май", "Июнь",
  "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь",
]
 
export default function Finance() {
  const now = new Date()
  const [activeTab, setActiveTab] = useState("dashboard")
  const [showAdd, setShowAdd] = useState(false)
  const [refreshKey, setRefreshKey] = useState(0)
  const [month, setMonth] = useState(now.getMonth() + 1)
  const [year, setYear] = useState(now.getFullYear())
 
  const refresh = () => setRefreshKey((k) => k + 1)
 
  const prevMonth = () => {
    if (month === 1) { setMonth(12); setYear(y => y - 1) }
    else setMonth(m => m - 1)
  }
  const nextMonth = () => {
    if (month === 12) { setMonth(1); setYear(y => y + 1) }
    else setMonth(m => m + 1)
  }
 
  const isCurrentMonth = month === now.getMonth() + 1 && year === now.getFullYear()
 
  return (
    <div className="min-h-screen bg-surface-50 dark:bg-gray-950 gradient-mesh pb-24">
      <header className="bg-white/70 dark:bg-gray-900/70 backdrop-blur-xl border-b border-gray-100/50 dark:border-gray-800 sticky top-0 z-10">
        <div className="max-w-lg mx-auto px-4 py-4 flex items-center justify-between">
          <div>
            <h1 className="text-xl font-display font-bold text-gray-900 dark:text-white">
              💰 Финансы
            </h1>
          </div>
          <button
            onClick={() => setShowAdd(true)}
            className="w-10 h-10 rounded-xl bg-primary-500 text-white flex items-center justify-center text-xl shadow-lg hover:bg-primary-600 transition"
          >
            +
          </button>
        </div>
 
        {/* Month Switcher */}
        <div className="max-w-lg mx-auto px-4 pb-3">
          <div className="flex items-center justify-center gap-4">
            <button
              onClick={prevMonth}
              className="w-8 h-8 rounded-lg bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-400 flex items-center justify-center hover:bg-gray-200 dark:hover:bg-gray-700 transition text-sm font-bold"
            >
              ←
            </button>
            <button
              onClick={() => { setMonth(now.getMonth() + 1); setYear(now.getFullYear()) }}
              className={"text-sm font-semibold min-w-[140px] text-center " + (isCurrentMonth ? "text-gray-900 dark:text-white" : "text-primary-600 dark:text-primary-400")}
            >
              {MONTH_NAMES[month - 1]} {year}
            </button>
            <button
              onClick={nextMonth}
              className="w-8 h-8 rounded-lg bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-400 flex items-center justify-center hover:bg-gray-200 dark:hover:bg-gray-700 transition text-sm font-bold"
            >
              →
            </button>
          </div>
        </div>
 
        <div className="max-w-lg mx-auto px-4 pb-3 flex gap-1.5 overflow-x-auto scrollbar-hide">
          {tabs.map((t) => (
            <button
              key={t.key}
              onClick={() => setActiveTab(t.key)}
              className={`flex-1 min-w-0 py-2 rounded-xl text-xs sm:text-sm font-semibold transition whitespace-nowrap px-2 ${
                activeTab === t.key
                  ? "bg-primary-500 text-white"
                  : "bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-400"
              }`}
            >
              {t.icon} {t.label}
            </button>
          ))}
        </div>
      </header>
 
      <div className="max-w-lg mx-auto px-4 py-6">
        {activeTab === "dashboard" && <FinanceDashboard key={refreshKey + "-" + month + "-" + year} month={month} year={year} />}
        {activeTab === "transactions" && (
          <TransactionList key={refreshKey + "-" + month + "-" + year} month={month} year={year} onAdd={() => setShowAdd(true)} />
        )}
        {activeTab === "analytics" && <FinanceAnalytics key={refreshKey + "-" + month + "-" + year} month={month} year={year} />}
        {activeTab === "categories" && <CategoriesManager refreshKey={refreshKey} />}
      </div>
 
      {showAdd && (
        <AddTransactionModal
          onClose={() => setShowAdd(false)}
          onSaved={() => {
            setShowAdd(false)
            refresh()
          }}
        />
      )}
 
      <Navigation />
    </div>
  )
}