Files
turftracker/frontend/src/pages/Dashboard/Dashboard.js
2025-08-21 07:43:43 -05:00

308 lines
10 KiB
JavaScript

import React from 'react';
import { Link } from 'react-router-dom';
import {
MapIcon,
WrenchScrewdriverIcon,
BeakerIcon,
CalendarDaysIcon,
ClockIcon,
CloudIcon,
PlusIcon,
} from '@heroicons/react/24/outline';
import { useAuth } from '../../hooks/useAuth';
const Dashboard = () => {
const { user } = useAuth();
const quickActions = [
{
name: 'Add Property',
href: '/properties',
icon: MapIcon,
description: 'Set up a new lawn area',
color: 'bg-blue-500',
},
{
name: 'Plan Application',
href: '/applications/plan',
icon: CalendarDaysIcon,
description: 'Schedule a treatment',
color: 'bg-green-500',
},
{
name: 'Add Equipment',
href: '/equipment',
icon: WrenchScrewdriverIcon,
description: 'Register new equipment',
color: 'bg-purple-500',
},
{
name: 'Log Application',
href: '/applications/log',
icon: ClockIcon,
description: 'Record completed work',
color: 'bg-orange-500',
},
];
const stats = [
{
name: 'Properties',
value: '3',
change: '+1',
changeType: 'positive',
icon: MapIcon,
},
{
name: 'This Month\'s Applications',
value: '12',
change: '+4',
changeType: 'positive',
icon: CalendarDaysIcon,
},
{
name: 'Equipment Items',
value: '8',
change: '+2',
changeType: 'positive',
icon: WrenchScrewdriverIcon,
},
{
name: 'Products Used',
value: '15',
change: '+3',
changeType: 'positive',
icon: BeakerIcon,
},
];
const recentActivity = [
{
id: 1,
type: 'application',
title: 'Applied fertilizer to Front Yard',
property: 'Main Property',
date: '2 hours ago',
status: 'completed',
},
{
id: 2,
type: 'plan',
title: 'Scheduled weed control treatment',
property: 'Back Yard',
date: 'Tomorrow at 9:00 AM',
status: 'planned',
},
{
id: 3,
type: 'equipment',
title: 'Added new broadcast spreader',
property: null,
date: '3 days ago',
status: 'completed',
},
];
const upcomingTasks = [
{
id: 1,
title: 'Pre-emergent herbicide application',
property: 'Main Property - Front Yard',
date: 'March 15, 2024',
weather: 'Partly cloudy, 65°F',
priority: 'high',
},
{
id: 2,
title: 'Spring fertilizer application',
property: 'Side Property - Back Lawn',
date: 'March 20, 2024',
weather: 'Sunny, 72°F',
priority: 'medium',
},
];
return (
<div className="p-6 max-w-7xl mx-auto">
{/* Header */}
<div className="mb-8">
<h1 className="text-3xl font-bold text-gray-900">
Welcome back, {user?.firstName}!
</h1>
<p className="mt-2 text-gray-600">
Here's what's happening with your lawn care today.
</p>
</div>
{/* Stats Grid */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
{stats.map((stat) => (
<div key={stat.name} className="card">
<div className="flex items-center">
<div className="flex-shrink-0">
<stat.icon className="h-8 w-8 text-gray-400" />
</div>
<div className="ml-4 flex-1">
<p className="text-sm font-medium text-gray-500">{stat.name}</p>
<div className="flex items-baseline">
<p className="text-2xl font-semibold text-gray-900">{stat.value}</p>
<span className={`ml-2 text-sm font-medium ${
stat.changeType === 'positive' ? 'text-green-600' : 'text-red-600'
}`}>
{stat.change}
</span>
</div>
</div>
</div>
</div>
))}
</div>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
{/* Quick Actions */}
<div className="lg:col-span-1">
<div className="card">
<div className="card-header">
<h3 className="text-lg font-medium text-gray-900">Quick Actions</h3>
<p className="text-sm text-gray-500">Get started with common tasks</p>
</div>
<div className="space-y-3">
{quickActions.map((action) => (
<Link
key={action.name}
to={action.href}
className="flex items-center p-3 rounded-lg border border-gray-200 hover:border-gray-300 hover:shadow-sm transition-all duration-200"
>
<div className={`flex-shrink-0 p-2 rounded-lg ${action.color}`}>
<action.icon className="h-5 w-5 text-white" />
</div>
<div className="ml-3 flex-1">
<p className="text-sm font-medium text-gray-900">{action.name}</p>
<p className="text-xs text-gray-500">{action.description}</p>
</div>
<PlusIcon className="h-4 w-4 text-gray-400" />
</Link>
))}
</div>
</div>
</div>
{/* Recent Activity & Upcoming Tasks */}
<div className="lg:col-span-2 space-y-8">
{/* Recent Activity */}
<div className="card">
<div className="card-header">
<h3 className="text-lg font-medium text-gray-900">Recent Activity</h3>
<Link
to="/history"
className="text-sm text-primary-600 hover:text-primary-500"
>
View all
</Link>
</div>
<div className="space-y-4">
{recentActivity.map((activity) => (
<div key={activity.id} className="flex items-start space-x-3">
<div className={`flex-shrink-0 p-1 rounded-full ${
activity.status === 'completed' ? 'bg-green-100' : 'bg-blue-100'
}`}>
<div className={`h-2 w-2 rounded-full ${
activity.status === 'completed' ? 'bg-green-600' : 'bg-blue-600'
}`} />
</div>
<div className="flex-1 min-w-0">
<p className="text-sm text-gray-900">{activity.title}</p>
{activity.property && (
<p className="text-xs text-gray-500">{activity.property}</p>
)}
<p className="text-xs text-gray-400">{activity.date}</p>
</div>
</div>
))}
</div>
</div>
{/* Upcoming Tasks */}
<div className="card">
<div className="card-header">
<h3 className="text-lg font-medium text-gray-900">Upcoming Tasks</h3>
<Link
to="/applications"
className="text-sm text-primary-600 hover:text-primary-500"
>
View all
</Link>
</div>
<div className="space-y-4">
{upcomingTasks.map((task) => (
<div key={task.id} className="border border-gray-200 rounded-lg p-4">
<div className="flex items-start justify-between">
<div className="flex-1">
<h4 className="text-sm font-medium text-gray-900">{task.title}</h4>
<p className="text-xs text-gray-500 mt-1">{task.property}</p>
<div className="flex items-center mt-2 space-x-4">
<span className="text-xs text-gray-500">{task.date}</span>
<div className="flex items-center space-x-1">
<CloudIcon className="h-3 w-3 text-gray-400" />
<span className="text-xs text-gray-500">{task.weather}</span>
</div>
</div>
</div>
<span className={`inline-flex items-center px-2 py-1 rounded-full text-xs font-medium ${
task.priority === 'high'
? 'bg-red-100 text-red-800'
: task.priority === 'medium'
? 'bg-yellow-100 text-yellow-800'
: 'bg-green-100 text-green-800'
}`}>
{task.priority}
</span>
</div>
</div>
))}
</div>
</div>
</div>
</div>
{/* Weather Widget */}
<div className="mt-8">
<div className="card">
<div className="flex items-center justify-between mb-4">
<h3 className="text-lg font-medium text-gray-900">Today's Weather</h3>
<Link
to="/weather"
className="text-sm text-primary-600 hover:text-primary-500"
>
Detailed forecast
</Link>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
<div className="flex items-center space-x-3">
<CloudIcon className="h-8 w-8 text-blue-500" />
<div>
<p className="text-2xl font-semibold text-gray-900">72°F</p>
<p className="text-sm text-gray-500">Partly cloudy</p>
</div>
</div>
<div className="flex items-center justify-between">
<span className="text-sm text-gray-500">Wind:</span>
<span className="text-sm font-medium text-gray-900">5 mph</span>
</div>
<div className="flex items-center justify-between">
<span className="text-sm text-gray-500">Humidity:</span>
<span className="text-sm font-medium text-gray-900">45%</span>
</div>
</div>
<div className="mt-4 p-3 bg-green-50 rounded-lg">
<p className="text-sm text-green-800">
Good conditions for lawn applications today
</p>
</div>
</div>
</div>
</div>
);
};
export default Dashboard;