feat: Add NoteForm, ProjectForm, and ProjectTaskForm components

- Implemented NoteForm for adding notes to projects.
- Created ProjectForm for managing project details with contract selection.
- Developed ProjectTaskForm for adding tasks to projects, supporting both templates and custom tasks.

feat: Add ProjectTasksSection component

- Introduced ProjectTasksSection to display and manage tasks for a specific project.
- Includes functionality for adding, updating, and deleting tasks.

feat: Create TaskTemplateForm for managing task templates

- Added TaskTemplateForm for creating new task templates with required wait days.

feat: Implement UI components

- Created reusable UI components: Badge, Button, Card, Input, Loading, Navigation.
- Enhanced user experience with consistent styling and functionality.

feat: Set up database and queries

- Initialized SQLite database with tables for contracts, projects, tasks, project tasks, and notes.
- Implemented queries for managing contracts, projects, tasks, and notes.

chore: Add error handling and loading states

- Improved error handling in forms and data fetching.
- Added loading states for better user feedback during data operations.
This commit is contained in:
Chop
2025-06-02 22:07:05 +02:00
parent aa1eb99ce9
commit d0586f2876
43 changed files with 3272 additions and 137 deletions

View File

@@ -0,0 +1,111 @@
"use client";
import { useState, useEffect } from "react";
import { useRouter } from "next/navigation";
export default function ProjectForm({ initialData = null }) {
const [form, setForm] = useState({
contract_id: "",
project_name: "",
address: "",
plot: "",
district: "",
unit: "",
city: "",
investment_number: "",
finish_date: "",
wp: "",
contact: "",
notes: "",
...initialData,
});
const [contracts, setContracts] = useState([]);
const router = useRouter();
const isEdit = !!initialData;
useEffect(() => {
fetch("/api/contracts")
.then((res) => res.json())
.then(setContracts);
}, []);
function handleChange(e) {
setForm({ ...form, [e.target.name]: e.target.value });
}
async function handleSubmit(e) {
e.preventDefault();
const res = await fetch(
isEdit ? `/api/projects/${initialData.project_id}` : "/api/projects",
{
method: isEdit ? "PUT" : "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(form),
}
);
if (res.ok) {
router.push("/projects");
} else {
alert("Failed to save project.");
}
}
return (
<form onSubmit={handleSubmit} className="space-y-4">
{/* Contract Dropdown */}
<div>
<label className="block font-medium">Umowa</label>
<select
name="contract_id"
value={form.contract_id || ""}
onChange={handleChange}
className="border p-2 w-full"
required
>
<option value="">Wybierz umowę</option>
{contracts.map((contract) => (
<option key={contract.contract_id} value={contract.contract_id}>
{contract.contract_number} {contract.contract_name}
</option>
))}
</select>
</div>
{/* Other fields */}
{[
["project_name", "Nazwa projektu"],
["address", "Lokalizacja"],
["plot", "Działka"],
["district", "Obręb ewidencyjny"],
["unit", "Jednostka ewidencyjna"],
["city", "Miejscowość"],
["investment_number", "Numer inwestycjny"],
["finish_date", "Termin realizacji"],
["wp", "WP"],
["contact", "Dane kontaktowe"],
["notes", "Notatki"],
].map(([name, label]) => (
<div key={name}>
<label className="block font-medium">{label}</label>
<input
type={name === "finish_date" ? "date" : "text"}
name={name}
value={form[name] || ""}
onChange={handleChange}
className="border p-2 w-full"
/>
</div>
))}
<button
type="submit"
className="bg-blue-600 text-white px-4 py-2 rounded"
>
{isEdit ? "Update" : "Create"} Project
</button>
</form>
);
}