338 lines
13 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useState, useEffect } from 'react';
import { X, FileText, Sprout, Beaker } from 'lucide-react';
import {Task, Plant, Fertilizer, Chemical, PlantTitles, TaskDraft} from '../types';
import { apiService } from '../services/api';
interface TaskFormProps {
isOpen: boolean;
onClose: () => void;
onSubmit: (task: TaskDraft) => void;
task?: Task;
}
const taskTypes = [
{ value: 'general', label: 'Общая', icon: FileText, color: 'bg-gray-100 text-gray-800' },
{ value: 'fertilizer', label: 'Внесение удобрений', icon: Sprout, color: 'bg-green-100 text-green-800' },
{ value: 'chemical', label: 'Применение химикатов', icon: Beaker, color: 'bg-red-100 text-red-800' },
{ value: 'watering', label: 'Полив', icon: FileText, color: 'bg-blue-100 text-blue-800' },
{ value: 'pruning', label: 'Обрезка', icon: FileText, color: 'bg-purple-100 text-purple-800' },
{ value: 'transplanting', label: 'Пересадка', icon: FileText, color: 'bg-orange-100 text-orange-800' },
{ value: 'harvesting', label: 'Сбор урожая', icon: FileText, color: 'bg-yellow-100 text-yellow-800' },
{ value: 'other', label: 'Другое', icon: FileText, color: 'bg-gray-100 text-gray-800' }
];
export default function TaskForm({ isOpen, onClose, onSubmit, task }: TaskFormProps) {
const [formData, setFormData] = useState({
plantId: '',
type: 'general',
title: '',
description: '',
deadline: '',
completed: false,
fertilizerId: '',
chemicalId: ''
});
const [plants, setPlants] = useState<Plant[]>([]);
const [fertilizers, setFertilizers] = useState<Fertilizer[]>([]);
const [chemicals, setChemicals] = useState<Chemical[]>([]);
const [selectedFertilizer, setSelectedFertilizer] = useState<Fertilizer | null>(null);
const [selectedChemical, setSelectedChemical] = useState<Chemical | null>(null);
useEffect(() => {
if (isOpen) {
loadData();
}
}, [isOpen]);
useEffect(() => {
if (task) {
setFormData({
plantId: task.plantId?.toString() || '',
type: task.type || 'general',
title: task.title,
description: task.description || '',
deadline: task.deadline.split('T')[0],
completed: task.completed,
fertilizerId: task.fertilizerId?.toString() || '',
chemicalId: task.chemicalId?.toString() || ''
});
} else {
setFormData({
plantId: '',
type: 'general',
title: '',
description: '',
deadline: '',
completed: false,
fertilizerId: '',
chemicalId: ''
});
}
}, [task]);
const loadData = async () => {
try {
const [plantsData, fertilizersData, chemicalsData] = await Promise.all([
apiService.getPlants(),
apiService.getFertilizers(),
apiService.getChemicals()
]);
setPlants(plantsData);
setFertilizers(fertilizersData);
setChemicals(chemicalsData);
} catch (error) {
console.error('Error loading data:', error);
}
};
useEffect(() => {
if (formData.fertilizerId) {
const fertilizer = fertilizers.find(f => f.id.toString() === formData.fertilizerId);
setSelectedFertilizer(fertilizer || null);
} else {
setSelectedFertilizer(null);
}
}, [formData.fertilizerId, fertilizers]);
useEffect(() => {
if (formData.chemicalId) {
const chemical = chemicals.find(c => c.id.toString() === formData.chemicalId);
setSelectedChemical(chemical || null);
} else {
setSelectedChemical(null);
}
}, [formData.chemicalId, chemicals]);
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
const taskData = {
...formData,
plantId: formData.plantId ? parseInt(formData.plantId) : undefined,
fertilizerId: formData.fertilizerId ? parseInt(formData.fertilizerId) : undefined,
chemicalId: formData.chemicalId ? parseInt(formData.chemicalId) : undefined
};
onSubmit(taskData);
onClose();
};
const handleTaskTypeChange = (taskType: string) => {
setFormData(prev => ({
...prev,
type: taskType,
fertilizerId: taskType !== 'fertilizer' ? '' : prev.fertilizerId,
chemicalId: taskType !== 'chemical' ? '' : prev.chemicalId
}));
};
if (!isOpen) return null;
const selectedTaskType = taskTypes.find(type => type.value === formData.type);
return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4 z-50">
<div className="bg-white rounded-lg shadow-xl w-full max-w-2xl max-h-[90vh] overflow-y-auto">
<div className="flex items-center justify-between p-6 border-b">
<h2 className="text-xl font-semibold text-gray-900">
{task ? 'Edit Task' : 'Create New Task'}
</h2>
<button
onClick={onClose}
className="text-gray-400 hover:text-gray-600 transition-colors"
>
<X className="w-6 h-6" />
</button>
</div>
<form onSubmit={handleSubmit} className="p-6 space-y-6">
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Task Title *
</label>
<input
type="text"
required
value={formData.title}
onChange={(e) => setFormData(prev => ({ ...prev, title: e.target.value }))}
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-green-500"
placeholder="Enter task title"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Type *
</label>
<select
required
value={formData.type}
onChange={(e) => handleTaskTypeChange(e.target.value)}
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-green-500"
>
{taskTypes.map(type => (
<option key={type.value} value={type.value}>
{type.label}
</option>
))}
</select>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Deadline *
</label>
<input
type="date"
required
value={formData.deadline}
onChange={(e) => setFormData(prev => ({ ...prev, deadline: e.target.value }))}
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-green-500"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Status
</label>
<div className="flex items-center">
<input
type="checkbox"
id="completed"
checked={formData.completed}
onChange={(e) => setFormData(prev => ({ ...prev, completed: e.target.checked }))}
className="h-4 w-4 text-green-600 focus:ring-green-500 border-gray-300 rounded"
/>
<label htmlFor="completed" className="ml-2 block text-sm text-gray-700">
Completed
</label>
</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Plant (Optional)
</label>
<select
value={formData.plantId}
onChange={(e) => setFormData(prev => ({ ...prev, plantId: e.target.value }))}
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-green-500"
>
<option value="">Выбор растения</option>
{plants.map(plant => (
<option key={plant.id} value={plant.id}>
{plant.variety} ({PlantTitles[plant.type]})
</option>
))}
</select>
</div>
</div>
{formData.type === 'fertilizer' && (
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Выбор удобрения
</label>
<select
value={formData.fertilizerId}
onChange={(e) => setFormData(prev => ({ ...prev, fertilizerId: e.target.value }))}
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-green-500"
>
<option value="">Выбор удобрения</option>
{fertilizers.map(fertilizer => (
<option key={fertilizer.id} value={fertilizer.id}>
{fertilizer.name} - {fertilizer.brand}
</option>
))}
</select>
{selectedFertilizer && (
<div className="mt-3 p-3 bg-green-50 rounded-md">
<h4 className="font-medium text-green-800 mb-2">Fertilizer Information</h4>
<div className="text-sm text-green-700 space-y-1">
<p><strong>NPK:</strong> {selectedFertilizer.npkRatio}</p>
<p><strong>Application Rate:</strong> {selectedFertilizer.applicationRate}</p>
<p><strong>Frequency:</strong> {selectedFertilizer.frequency}</p>
{selectedFertilizer.notes && (
<p><strong>Notes:</strong> {selectedFertilizer.notes}</p>
)}
</div>
</div>
)}
</div>
)}
{formData.type === 'chemical' && (
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Выбор химикатов
</label>
<select
value={formData.chemicalId}
onChange={(e) => setFormData(prev => ({ ...prev, chemicalId: e.target.value }))}
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-green-500"
>
<option value="">Выбор химикатов</option>
{chemicals.map(chemical => (
<option key={chemical.id} value={chemical.id}>
{chemical.name} - {chemical.brand}
</option>
))}
</select>
{selectedChemical && (
<div className="mt-3 p-3 bg-red-50 rounded-md">
<h4 className="font-medium text-red-800 mb-2">Chemical Information</h4>
<div className="text-sm text-red-700 space-y-1">
<p><strong>Active Ingredients:</strong> {selectedChemical.activeIngredient}</p>
<p><strong>Target Pests:</strong> {selectedChemical.targetPests}</p>
<p><strong>Application Rate:</strong> {selectedChemical.applicationMethod}</p>
{selectedChemical.safetyPeriod && (
<p className="bg-yellow-100 text-yellow-800 p-2 rounded">
<strong>Safety Period:</strong> {selectedChemical.safetyPeriod}
</p>
)}
{selectedChemical.notes && (
<p><strong>Notes:</strong> {selectedChemical.notes}</p>
)}
</div>
</div>
)}
</div>
)}
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Description
</label>
<textarea
value={formData.description}
onChange={(e) => setFormData(prev => ({ ...prev, description: e.target.value }))}
rows={4}
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-green-500"
placeholder="Enter task description"
/>
</div>
<div className="flex justify-end space-x-3 pt-4 border-t">
<button
type="button"
onClick={onClose}
className="px-4 py-2 text-gray-700 bg-gray-100 rounded-md hover:bg-gray-200 transition-colors"
>
Cancel
</button>
<button
type="submit"
className="px-4 py-2 bg-green-600 text-white rounded-md hover:bg-green-700 transition-colors"
>
{task ? 'Update Task' : 'Create Task'}
</button>
</div>
</form>
</div>
</div>
);
}