289 lines
8.6 KiB
JavaScript
289 lines
8.6 KiB
JavaScript
"use client";
|
||
|
||
import { useState, useEffect } from "react";
|
||
import { useRouter } from "next/navigation";
|
||
import { Card, CardHeader, CardContent } from "@/components/ui/Card";
|
||
import Button from "@/components/ui/Button";
|
||
import { Input } from "@/components/ui/Input";
|
||
import PageContainer from "@/components/ui/PageContainer";
|
||
import PageHeader from "@/components/ui/PageHeader";
|
||
import { useTranslation } from "@/lib/i18n";
|
||
|
||
export default function NewTaskSetPage() {
|
||
const { t } = useTranslation();
|
||
const router = useRouter();
|
||
const [taskTemplates, setTaskTemplates] = useState([]);
|
||
const [formData, setFormData] = useState({
|
||
name: "",
|
||
description: "",
|
||
task_category: "design",
|
||
selectedTemplates: []
|
||
});
|
||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||
|
||
useEffect(() => {
|
||
// Fetch available task templates
|
||
const fetchTemplates = async () => {
|
||
try {
|
||
const response = await fetch('/api/tasks/templates');
|
||
if (response.ok) {
|
||
const data = await response.json();
|
||
setTaskTemplates(data);
|
||
}
|
||
} catch (error) {
|
||
console.error('Error fetching templates:', error);
|
||
}
|
||
};
|
||
|
||
fetchTemplates();
|
||
}, []);
|
||
|
||
const handleSubmit = async (e) => {
|
||
e.preventDefault();
|
||
|
||
if (!formData.name.trim()) {
|
||
alert("Nazwa zestawu jest wymagana");
|
||
return;
|
||
}
|
||
|
||
if (formData.selectedTemplates.length === 0) {
|
||
alert("Wybierz przynajmniej jeden szablon zadania");
|
||
return;
|
||
}
|
||
|
||
setIsSubmitting(true);
|
||
|
||
try {
|
||
// Create the task set
|
||
const createResponse = await fetch('/api/task-sets', {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({
|
||
name: formData.name.trim(),
|
||
description: formData.description.trim(),
|
||
task_category: formData.task_category
|
||
})
|
||
});
|
||
|
||
if (!createResponse.ok) {
|
||
throw new Error('Failed to create task set');
|
||
}
|
||
|
||
const { id: setId } = await createResponse.json();
|
||
|
||
// Add templates to the set
|
||
const templatesData = {
|
||
templates: formData.selectedTemplates.map((templateId, index) => ({
|
||
task_id: templateId,
|
||
sort_order: index
|
||
}))
|
||
};
|
||
|
||
const updateResponse = await fetch(`/api/task-sets/${setId}`, {
|
||
method: 'PUT',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify(templatesData)
|
||
});
|
||
|
||
if (!updateResponse.ok) {
|
||
throw new Error('Failed to add templates to task set');
|
||
}
|
||
|
||
router.push('/task-sets');
|
||
} catch (error) {
|
||
console.error('Error creating task set:', error);
|
||
alert('Wystąpił błąd podczas tworzenia zestawu zadań');
|
||
} finally {
|
||
setIsSubmitting(false);
|
||
}
|
||
};
|
||
|
||
const toggleTemplate = (templateId) => {
|
||
setFormData(prev => ({
|
||
...prev,
|
||
selectedTemplates: prev.selectedTemplates.includes(templateId)
|
||
? prev.selectedTemplates.filter(id => id !== templateId)
|
||
: [...prev.selectedTemplates, templateId]
|
||
}));
|
||
};
|
||
|
||
const moveTemplate = (fromIndex, toIndex) => {
|
||
const newSelected = [...formData.selectedTemplates];
|
||
const [moved] = newSelected.splice(fromIndex, 1);
|
||
newSelected.splice(toIndex, 0, moved);
|
||
|
||
setFormData(prev => ({
|
||
...prev,
|
||
selectedTemplates: newSelected
|
||
}));
|
||
};
|
||
|
||
return (
|
||
<PageContainer>
|
||
<PageHeader
|
||
title="Nowy zestaw zadań"
|
||
description="Utwórz nowy zestaw zadań z szablonów"
|
||
/>
|
||
|
||
<form onSubmit={handleSubmit} className="max-w-4xl">
|
||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||
{/* Basic info */}
|
||
<Card>
|
||
<CardHeader>
|
||
<h3 className="text-lg font-semibold">Informacje podstawowe</h3>
|
||
</CardHeader>
|
||
<CardContent className="space-y-4">
|
||
<div>
|
||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||
Nazwa zestawu *
|
||
</label>
|
||
<Input
|
||
type="text"
|
||
value={formData.name}
|
||
onChange={(e) => setFormData(prev => ({ ...prev, name: e.target.value }))}
|
||
placeholder="np. Standardowe zadania projektowe"
|
||
required
|
||
/>
|
||
</div>
|
||
|
||
<div>
|
||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||
Opis
|
||
</label>
|
||
<Input
|
||
type="text"
|
||
value={formData.description}
|
||
onChange={(e) => setFormData(prev => ({ ...prev, description: e.target.value }))}
|
||
placeholder="Opcjonalny opis zestawu"
|
||
/>
|
||
</div>
|
||
|
||
<div>
|
||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||
Kategoria zadań *
|
||
</label>
|
||
<select
|
||
value={formData.task_category}
|
||
onChange={(e) => setFormData(prev => ({ ...prev, task_category: e.target.value }))}
|
||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||
required
|
||
>
|
||
<option value="design">Zadania projektowe</option>
|
||
<option value="construction">Zadania budowlane</option>
|
||
</select>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
|
||
{/* Template selection */}
|
||
<Card>
|
||
<CardHeader>
|
||
<h3 className="text-lg font-semibold">Wybrane szablony zadań</h3>
|
||
<p className="text-sm text-gray-600">
|
||
Wybrano: {formData.selectedTemplates.length} szablonów
|
||
</p>
|
||
</CardHeader>
|
||
<CardContent>
|
||
{formData.selectedTemplates.length > 0 ? (
|
||
<div className="space-y-2">
|
||
{formData.selectedTemplates.map((templateId, index) => {
|
||
const template = taskTemplates.find(t => t.task_id === templateId);
|
||
return (
|
||
<div key={templateId} className="flex items-center justify-between p-2 bg-gray-50 rounded">
|
||
<div className="flex items-center space-x-2">
|
||
<span className="text-sm font-medium text-gray-600">{index + 1}.</span>
|
||
<span className="text-sm">{template?.name || 'Nieznany szablon'}</span>
|
||
</div>
|
||
<div className="flex space-x-1">
|
||
<button
|
||
type="button"
|
||
onClick={() => index > 0 && moveTemplate(index, index - 1)}
|
||
className="text-gray-400 hover:text-gray-600"
|
||
disabled={index === 0}
|
||
>
|
||
↑
|
||
</button>
|
||
<button
|
||
type="button"
|
||
onClick={() => index < formData.selectedTemplates.length - 1 && moveTemplate(index, index + 1)}
|
||
className="text-gray-400 hover:text-gray-600"
|
||
disabled={index === formData.selectedTemplates.length - 1}
|
||
>
|
||
↓
|
||
</button>
|
||
<button
|
||
type="button"
|
||
onClick={() => toggleTemplate(templateId)}
|
||
className="text-red-400 hover:text-red-600"
|
||
>
|
||
×
|
||
</button>
|
||
</div>
|
||
</div>
|
||
);
|
||
})}
|
||
</div>
|
||
) : (
|
||
<p className="text-gray-500 text-sm">Brak wybranych szablonów</p>
|
||
)}
|
||
</CardContent>
|
||
</Card>
|
||
</div>
|
||
|
||
{/* Available templates */}
|
||
<Card className="mt-6">
|
||
<CardHeader>
|
||
<h3 className="text-lg font-semibold">Dostępne szablony zadań</h3>
|
||
<p className="text-sm text-gray-600">
|
||
Wybierz szablony, które chcesz dodać do zestawu
|
||
</p>
|
||
</CardHeader>
|
||
<CardContent>
|
||
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||
{taskTemplates.map((template) => (
|
||
<label key={template.task_id} className="flex items-center space-x-2 p-2 hover:bg-gray-50 rounded cursor-pointer">
|
||
<input
|
||
type="checkbox"
|
||
checked={formData.selectedTemplates.includes(template.task_id)}
|
||
onChange={() => toggleTemplate(template.task_id)}
|
||
className="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded"
|
||
/>
|
||
<div className="flex-1">
|
||
<div className="font-medium text-sm">{template.name}</div>
|
||
{template.description && (
|
||
<div className="text-xs text-gray-600">{template.description}</div>
|
||
)}
|
||
</div>
|
||
</label>
|
||
))}
|
||
</div>
|
||
{taskTemplates.length === 0 && (
|
||
<p className="text-gray-500 text-sm text-center py-4">
|
||
Brak dostępnych szablonów zadań. Najpierw utwórz szablony w zakładce "Szablony zadań".
|
||
</p>
|
||
)}
|
||
</CardContent>
|
||
</Card>
|
||
|
||
{/* Actions */}
|
||
<div className="flex justify-end space-x-4 mt-6">
|
||
<Button
|
||
type="button"
|
||
variant="secondary"
|
||
onClick={() => router.back()}
|
||
disabled={isSubmitting}
|
||
>
|
||
Anuluj
|
||
</Button>
|
||
<Button
|
||
type="submit"
|
||
variant="primary"
|
||
disabled={isSubmitting}
|
||
>
|
||
{isSubmitting ? "Tworzenie..." : "Utwórz zestaw"}
|
||
</Button>
|
||
</div>
|
||
</form>
|
||
</PageContainer>
|
||
);
|
||
} |