From 26acbbc810534598a1ae1541c647290b322fb90c Mon Sep 17 00:00:00 2001 From: aovantsev Date: Fri, 3 Oct 2025 16:15:08 +0300 Subject: [PATCH] final fix --- frontend/src/App.tsx | 47 ++-- frontend/src/components/CounterCard.tsx | 11 +- frontend/src/components/CounterDetail.tsx | 252 ++++++++---------- .../src/components/CreateCounterModal.tsx | 4 +- frontend/src/components/Dashboard.tsx | 20 +- frontend/src/contexts/CountersContext.tsx | 41 +++ frontend/src/hooks/useCounters.tsx | 189 ++++++++----- frontend/src/types/index.ts | 7 +- 8 files changed, 323 insertions(+), 248 deletions(-) create mode 100644 frontend/src/contexts/CountersContext.tsx diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index fad9baa..2370fa7 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom'; import { AuthProvider } from './hooks/useAuth'; +import { CountersProvider } from './contexts/CountersContext'; import { ProtectedRoute } from './components/ProtectedRoute'; import { Layout } from './components/Layout'; import { Login } from './components/Login'; @@ -12,28 +13,30 @@ import './App.css'; function App() { return ( - -
- - } /> - } /> - - - - } /> - } /> - } /> - - - - } - /> - -
-
+ + +
+ + } /> + } /> + + + + } /> + } /> + } /> + + + + } + /> + +
+
+
); } diff --git a/frontend/src/components/CounterCard.tsx b/frontend/src/components/CounterCard.tsx index 97c8370..ecab3ea 100644 --- a/frontend/src/components/CounterCard.tsx +++ b/frontend/src/components/CounterCard.tsx @@ -1,22 +1,23 @@ import React, { useState } from 'react'; import { Link } from 'react-router-dom'; -import { useCounters } from '../hooks/useCounters'; import { CounterWithStats } from '../types'; import { Plus, Minus, Edit, Trash2, MoreVertical } from 'lucide-react'; interface CounterCardProps { counter: CounterWithStats; + onIncrement: (id: number | string, value: number) => Promise; + onDelete: (id: number | string) => Promise; } -export const CounterCard: React.FC = ({ counter }) => { - const { incrementCounter, deleteCounter } = useCounters(); +export const CounterCard: React.FC = ({ counter, onIncrement, onDelete }) => { const [isLoading, setIsLoading] = useState(false); const [showMenu, setShowMenu] = useState(false); const handleIncrement = async (value: number) => { setIsLoading(true); try { - await incrementCounter(counter.id, value); + await onIncrement(counter.id, value); + console.log('Counter incremented:', counter.id, value); } catch (error) { console.error('Failed to increment counter:', error); } finally { @@ -27,7 +28,7 @@ export const CounterCard: React.FC = ({ counter }) => { const handleDelete = async () => { if (window.confirm('Are you sure you want to delete this counter?')) { try { - await deleteCounter(counter.id); + await onDelete(counter.id); } catch (error) { console.error('Failed to delete counter:', error); } diff --git a/frontend/src/components/CounterDetail.tsx b/frontend/src/components/CounterDetail.tsx index ac47b55..8b20679 100644 --- a/frontend/src/components/CounterDetail.tsx +++ b/frontend/src/components/CounterDetail.tsx @@ -1,9 +1,8 @@ -import React, { useState, useEffect, useCallback } from 'react'; +import React, { useState, useEffect } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; -import { useCounters } from '../hooks/useCounters'; +import { useCountersContext } from '../contexts/CountersContext'; import { useAuth } from '../hooks/useAuth'; -import { CounterWithStats, CounterEntry } from '../types'; -import { countersAPI } from '../services/api'; +import { CounterEntry } from '../types'; import { ArrowLeft, Plus, Minus, Trash2, Calendar } from 'lucide-react'; import { format } from 'date-fns'; @@ -11,91 +10,35 @@ export const CounterDetail: React.FC = () => { const { id } = useParams<{ id: string }>(); const navigate = useNavigate(); const { isAuthenticated } = useAuth(); - const { incrementCounter, deleteCounter } = useCounters(); + const { counters, incrementCounter, deleteCounter, getCounterEntries } = useCountersContext(); - const [counter, setCounter] = useState(null); + // Get the current counter from the useCounters hook + const counter = counters.find(c => c.id.toString() === id) || null; const [entries, setEntries] = useState([]); const [isLoading, setIsLoading] = useState(true); const [isIncrementing, setIsIncrementing] = useState(false); const [error, setError] = useState(null); - const loadCounterData = useCallback(async () => { - if (!id) return; - - setIsLoading(true); - setError(null); - - try { - if (isAuthenticated) { - // Load from API - const [counterResponse, entriesResponse] = await Promise.all([ - countersAPI.getCounter(parseInt(id)), - countersAPI.getCounterEntries(parseInt(id)) - ]); - setCounter(counterResponse.data); - setEntries(entriesResponse.data); - } else { - // Load from localStorage - const counters = JSON.parse(localStorage.getItem('anonymous_counters') || '[]'); - const foundCounter = counters.find((c: any) => c.id === id); - if (foundCounter) { - // Convert to CounterWithStats format - const today = new Date().toISOString().split('T')[0]; - const counterWithStats: CounterWithStats = { - id: parseInt(foundCounter.id), - name: foundCounter.name, - description: foundCounter.description, - created_at: foundCounter.created_at, - updated_at: foundCounter.updated_at, - total_value: foundCounter.total_value, - today_value: foundCounter.entries[today] || 0, - week_value: Object.entries(foundCounter.entries) - .filter(([date]) => { - const entryDate = new Date(date); - const weekAgo = new Date(); - weekAgo.setDate(weekAgo.getDate() - 7); - return entryDate >= weekAgo; - }) - .reduce((sum, [, value]) => sum + (value as number), 0), - month_value: Object.entries(foundCounter.entries) - .filter(([date]) => { - const entryDate = new Date(date); - const monthAgo = new Date(); - monthAgo.setMonth(monthAgo.getMonth() - 1); - return entryDate >= monthAgo; - }) - .reduce((sum, [, value]) => sum + (value as number), 0), - entry_count: Object.values(foundCounter.entries).reduce((sum: number, value: unknown) => sum + Math.abs(value as number), 0), - }; - setCounter(counterWithStats); - - // Convert entries to CounterEntry format - const counterEntries: CounterEntry[] = Object.entries(foundCounter.entries) - .map(([date, value]) => ({ - id: Math.random(), // Generate random ID for display - counter_id: parseInt(foundCounter.id), - value: value as number, - date: date, - created_at: new Date().toISOString(), - })) - .sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()); - setEntries(counterEntries); - } else { - setError('Counter not found'); - } - } - } catch (err: any) { - setError(err.response?.data?.error || 'Failed to load counter'); - } finally { - setIsLoading(false); - } - }, [id, isAuthenticated]); - + // Load entries when component mounts or counter changes useEffect(() => { - if (id) { - loadCounterData(); - } - }, [id, loadCounterData]); + const loadEntries = async () => { + if (!id || !counter) return; + + setIsLoading(true); + setError(null); + + try { + const counterEntries = await getCounterEntries(id); + setEntries(counterEntries); + } catch (err: any) { + setError(err.message || 'Failed to load counter entries'); + } finally { + setIsLoading(false); + } + }; + + loadEntries(); + }, [id, counter, getCounterEntries]); const handleIncrement = async (value: number) => { if (!counter) return; @@ -103,8 +46,8 @@ export const CounterDetail: React.FC = () => { setIsIncrementing(true); try { await incrementCounter(counter.id, value); - // Reload data to get updated values - await loadCounterData(); + console.log('Counter incremented:', counter.id, value); + // Entries will be reloaded automatically when counter changes } catch (error) { console.error('Failed to increment counter:', error); } finally { @@ -150,68 +93,100 @@ export const CounterDetail: React.FC = () => { return (
{/* Header */} -
- -
-

{counter.name}

- {counter.description && ( -

{counter.description}

- )} -
-
+
+
+
+

{counter.name}

+ {counter.description && ( +

{counter.description}

+ )} +
+
+ + +
+ + {/* Stats Cards */} +
+
+
+

Total Value

+

{counter.total_value}

+
+
+ +
+
+

Today

+

{counter.today_value}

+
+
+ +
+
+

This Week

+

{counter.week_value}

+
+
+ +
+
+

This Month

+

{counter.month_value}

+
- {/* Counter Value and Controls */} -
-
- {counter.total_value} -
-
Total Count
- -
+ {/* Increment Controls */} +
+

Quick Actions

+
+ + + + + -
-
- - {/* Stats Grid */} -
-
-
{counter.today_value}
-
Today
-
-
-
{counter.week_value}
-
This Week
-
-
-
{counter.month_value}
-
This Month
@@ -234,17 +209,14 @@ export const CounterDetail: React.FC = () => { className="flex justify-between items-center py-2 px-4 bg-gray-50 rounded-lg" >
-
0 ? 'bg-green-500' : 'bg-red-500' - }`} /> - +
{format(new Date(entry.date), 'MMM dd, yyyy')} - +
-
0 ? 'text-green-600' : 'text-red-600' - }`}> - {entry.value > 0 ? '+' : ''}{entry.value} +
+ = 0 ? 'text-green-600' : 'text-red-600'}`}> + {entry.value > 0 ? '+' : ''}{entry.value} +
))} @@ -253,4 +225,4 @@ export const CounterDetail: React.FC = () => {
); -}; +}; \ No newline at end of file diff --git a/frontend/src/components/CreateCounterModal.tsx b/frontend/src/components/CreateCounterModal.tsx index 549e37c..b0a9650 100644 --- a/frontend/src/components/CreateCounterModal.tsx +++ b/frontend/src/components/CreateCounterModal.tsx @@ -1,6 +1,6 @@ import React, { useState } from 'react'; import { useForm } from 'react-hook-form'; -import { useCounters } from '../hooks/useCounters'; +import { useCountersContext } from '../contexts/CountersContext'; import { CreateCounterRequest } from '../types'; import { X } from 'lucide-react'; @@ -9,7 +9,7 @@ interface CreateCounterModalProps { } export const CreateCounterModal: React.FC = ({ onClose }) => { - const { createCounter } = useCounters(); + const { createCounter } = useCountersContext(); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); diff --git a/frontend/src/components/Dashboard.tsx b/frontend/src/components/Dashboard.tsx index 2be3583..13b754b 100644 --- a/frontend/src/components/Dashboard.tsx +++ b/frontend/src/components/Dashboard.tsx @@ -1,12 +1,13 @@ -import React, { useState } from 'react'; -import { useCounters } from '../hooks/useCounters'; +import React, { useState, useEffect } from 'react'; +import { useCountersContext } from '../contexts/CountersContext'; import { useAuth } from '../hooks/useAuth'; import { CreateCounterModal } from './CreateCounterModal'; import { CounterCard } from './CounterCard'; import { Plus, Search, TrendingUp, Calendar, Clock } from 'lucide-react'; export const Dashboard: React.FC = () => { - const { counters, isLoading, error, searchCounters } = useCounters(); + console.log('Dashboard: Component rendering...'); + const { counters, isLoading, error, searchCounters, version, incrementCounter, deleteCounter } = useCountersContext(); const { isAuthenticated } = useAuth(); const [showCreateModal, setShowCreateModal] = useState(false); const [searchQuery, setSearchQuery] = useState(''); @@ -16,6 +17,11 @@ export const Dashboard: React.FC = () => { searchCounters(query); }; + useEffect(() => { + console.log('Dashboard: Counters changed:', counters, 'version:', version); + }, [counters, version]); + + console.log('Dashboard: Current counters:', counters, 'version:', version); const totalCounters = counters?.length || 0; const totalValue = counters?.reduce((sum, counter) => sum + counter.total_value, 0) || 0; const todayValue = counters?.reduce((sum, counter) => sum + counter.today_value, 0) || 0; @@ -41,6 +47,7 @@ export const Dashboard: React.FC = () => { }

+