308 lines
10 KiB
JavaScript
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; |