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 ? 'Изменение работы' : 'Создание новой работы'}
</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">
Наименование работы *
</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">
Тип *
</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">
Крайний срок *
</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">
Статус
</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">
Завершена
</label>
</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Растение (не обязательно)
</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>Заметки:</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>Заметки:</strong> {selectedChemical.notes}</p>
)}
</div>
</div>
)}
</div>
)}
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Описание
</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"
>
Отмена
</button>
<button
type="submit"
className="px-4 py-2 bg-green-600 text-white rounded-md hover:bg-green-700 transition-colors"
>
{task ? 'Изменить' : 'Создать'}
</button>
</div>
</form>
</div>
</div>
);
}