Files
panel/src/app/task-sets/new/page.js

289 lines
8.6 KiB
JavaScript
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.

"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>
);
}