2025-05-26 21:55:49 +02:00

214 lines
9.8 KiB
TypeScript

import React, { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { ShoppingEvent } from '../types';
import { shoppingEventApi } from '../services/api';
const Dashboard: React.FC = () => {
const navigate = useNavigate();
const [recentEvents, setRecentEvents] = useState<ShoppingEvent[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetchRecentEvents();
}, []);
const fetchRecentEvents = async () => {
try {
setLoading(true);
const response = await shoppingEventApi.getAll();
// Get the 3 most recent events
const recent = response.data
.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime())
.slice(0, 3);
setRecentEvents(recent);
} catch (error) {
console.error('Error fetching recent events:', error);
} finally {
setLoading(false);
}
};
return (
<div className="space-y-6">
<div>
<h1 className="text-2xl font-bold text-gray-900">Dashboard</h1>
<p className="text-gray-600">Welcome to your product tracker!</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
{/* Stats Cards */}
<div className="bg-white rounded-lg shadow p-6">
<div className="flex items-center">
<div className="p-2 bg-blue-100 rounded-md">
<svg className="w-6 h-6 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M16 11V7a4 4 0 00-8 0v4M5 9h14l1 12H4L5 9z" />
</svg>
</div>
<div className="ml-4">
<p className="text-sm font-medium text-gray-600">Total Shopping Events</p>
<p className="text-2xl font-semibold text-gray-900">-</p>
</div>
</div>
</div>
<div className="bg-white rounded-lg shadow p-6">
<div className="flex items-center">
<div className="p-2 bg-green-100 rounded-md">
<svg className="w-6 h-6 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1" />
</svg>
</div>
<div className="ml-4">
<p className="text-sm font-medium text-gray-600">Total Spent</p>
<p className="text-2xl font-semibold text-gray-900">$-</p>
</div>
</div>
</div>
<div className="bg-white rounded-lg shadow p-6">
<div className="flex items-center">
<div className="p-2 bg-yellow-100 rounded-md">
<svg className="w-6 h-6 text-yellow-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4" />
</svg>
</div>
<div className="ml-4">
<p className="text-sm font-medium text-gray-600">Unique Items</p>
<p className="text-2xl font-semibold text-gray-900">-</p>
</div>
</div>
</div>
<div className="bg-white rounded-lg shadow p-6">
<div className="flex items-center">
<div className="p-2 bg-purple-100 rounded-md">
<svg className="w-6 h-6 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" />
</svg>
</div>
<div className="ml-4">
<p className="text-sm font-medium text-gray-600">Shops Visited</p>
<p className="text-2xl font-semibold text-gray-900">-</p>
</div>
</div>
</div>
</div>
{/* Quick Actions */}
<div className="bg-white rounded-lg shadow">
<div className="px-6 py-4 border-b border-gray-200">
<h2 className="text-lg font-medium text-gray-900">Quick Actions</h2>
</div>
<div className="p-6">
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<button
onClick={() => navigate('/shopping-events/new')}
className="flex items-center p-4 border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors"
>
<div className="p-2 bg-blue-100 rounded-md mr-3">
<svg className="w-5 h-5 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
</svg>
</div>
<div>
<p className="font-medium text-gray-900">Add New Event</p>
<p className="text-sm text-gray-600">Record a new shopping event</p>
</div>
</button>
<button
onClick={() => navigate('/products?add=true')}
className="flex items-center p-4 border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors"
>
<div className="p-2 bg-green-100 rounded-md mr-3">
<svg className="w-5 h-5 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4" />
</svg>
</div>
<div>
<p className="font-medium text-gray-900">Add Product</p>
<p className="text-sm text-gray-600">Add a new product item</p>
</div>
</button>
<button
onClick={() => navigate('/shops?add=true')}
className="flex items-center p-4 border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors"
>
<div className="p-2 bg-purple-100 rounded-md mr-3">
<svg className="w-5 h-5 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" />
</svg>
</div>
<div>
<p className="font-medium text-gray-900">Add Shop</p>
<p className="text-sm text-gray-600">Register a new shop</p>
</div>
</button>
</div>
</div>
</div>
{/* Recent Activity */}
<div className="bg-white rounded-lg shadow">
<div className="px-6 py-4 border-b border-gray-200">
<h2 className="text-lg font-medium text-gray-900">Recent Shopping Events</h2>
</div>
<div className="p-6">
{loading ? (
<div className="flex justify-center items-center py-8">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-500"></div>
</div>
) : recentEvents.length === 0 ? (
<div className="text-center py-8">
<svg className="mx-auto h-12 w-12 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 48 48">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4" />
</svg>
<h3 className="mt-2 text-sm font-medium text-gray-900">No shopping events yet</h3>
<p className="mt-1 text-sm text-gray-500">Get started by adding your first event!</p>
</div>
) : (
<div className="space-y-4">
{recentEvents.map((event) => (
<div key={event.id} className="border border-gray-200 rounded-lg p-4 hover:bg-gray-50 transition-colors">
<div className="flex justify-between items-start">
<div className="flex-1">
<div className="flex items-center space-x-2">
<h4 className="font-medium text-gray-900">{event.shop.name}</h4>
<span className="text-sm text-gray-500"></span>
<span className="text-sm text-gray-500">{event.shop.city}</span>
</div>
<p className="text-sm text-gray-600 mt-1">
{new Date(event.date).toLocaleDateString()}
</p>
{event.products.length > 0 && (
<p className="text-sm text-gray-500 mt-1">
{event.products.length} item{event.products.length !== 1 ? 's' : ''}
</p>
)}
</div>
<div className="text-right">
{event.total_amount && (
<p className="font-semibold text-green-600">
${event.total_amount.toFixed(2)}
</p>
)}
<button
onClick={() => navigate('/shopping-events')}
className="text-sm text-blue-600 hover:text-blue-800 mt-1"
>
View all
</button>
</div>
</div>
</div>
))}
</div>
)}
</div>
</div>
</div>
);
};
export default Dashboard;