feat: Add project type and status fields to project forms and views, including database migrations
This commit is contained in:
@@ -12,8 +12,8 @@ import { differenceInCalendarDays, parseISO } from "date-fns";
|
|||||||
import PageContainer from "@/components/ui/PageContainer";
|
import PageContainer from "@/components/ui/PageContainer";
|
||||||
import PageHeader from "@/components/ui/PageHeader";
|
import PageHeader from "@/components/ui/PageHeader";
|
||||||
|
|
||||||
export default async function ProjectViewPage({ params }) {
|
export default function ProjectViewPage({ params }) {
|
||||||
const { id } = await params;
|
const { id } = params;
|
||||||
const project = getProjectWithContract(id);
|
const project = getProjectWithContract(id);
|
||||||
const notes = getNotesForProject(id);
|
const notes = getNotesForProject(id);
|
||||||
const daysRemaining = differenceInCalendarDays(
|
const daysRemaining = differenceInCalendarDays(
|
||||||
@@ -141,6 +141,36 @@ export default async function ProjectViewPage({ params }) {
|
|||||||
<p className="text-gray-900">{project.notes}</p>
|
<p className="text-gray-900">{project.notes}</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
<div>
|
||||||
|
<span className="text-sm font-medium text-gray-500">
|
||||||
|
Typ projektu
|
||||||
|
</span>
|
||||||
|
<p className="text-gray-900">
|
||||||
|
{project.project_type === "design"
|
||||||
|
? "Projektowanie"
|
||||||
|
: project.project_type === "construction"
|
||||||
|
? "Realizacja"
|
||||||
|
: project.project_type === "design+construction"
|
||||||
|
? "Projektowanie + Realizacja"
|
||||||
|
: "-"}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span className="text-sm font-medium text-gray-500">
|
||||||
|
Status projektu
|
||||||
|
</span>
|
||||||
|
<p className="text-gray-900">
|
||||||
|
{project.project_status === "registered"
|
||||||
|
? "Zarejestrowany"
|
||||||
|
: project.project_status === "in_progress_design"
|
||||||
|
? "W realizacji (projektowanie)"
|
||||||
|
: project.project_status === "in_progress_construction"
|
||||||
|
? "W realizacji (realizacja)"
|
||||||
|
: project.project_status === "fulfilled"
|
||||||
|
? "Zakończony"
|
||||||
|
: "-"}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
<Card>
|
<Card>
|
||||||
|
|||||||
@@ -192,6 +192,26 @@ export default function ProjectListPage() {
|
|||||||
<div className="col-span-1 text-sm text-gray-600 truncate">
|
<div className="col-span-1 text-sm text-gray-600 truncate">
|
||||||
{project.finish_date || "N/A"}
|
{project.finish_date || "N/A"}
|
||||||
</div>
|
</div>
|
||||||
|
<div className="col-span-1 text-sm text-gray-600 truncate">
|
||||||
|
{project.project_type === "design"
|
||||||
|
? "Projektowanie"
|
||||||
|
: project.project_type === "construction"
|
||||||
|
? "Realizacja"
|
||||||
|
: project.project_type === "design+construction"
|
||||||
|
? "Projektowanie + Realizacja"
|
||||||
|
: "-"}
|
||||||
|
</div>
|
||||||
|
<div className="col-span-1 text-sm text-gray-600 truncate">
|
||||||
|
{project.project_status === "registered"
|
||||||
|
? "Zarejestrowany"
|
||||||
|
: project.project_status === "in_progress_design"
|
||||||
|
? "W realizacji (projektowanie)"
|
||||||
|
: project.project_status === "in_progress_construction"
|
||||||
|
? "W realizacji (realizacja)"
|
||||||
|
: project.project_status === "fulfilled"
|
||||||
|
? "Zakończony"
|
||||||
|
: "-"}
|
||||||
|
</div>
|
||||||
<div className="col-span-1">
|
<div className="col-span-1">
|
||||||
<Link href={`/projects/${project.project_id}`}>
|
<Link href={`/projects/${project.project_id}`}>
|
||||||
<Button variant="outline" size="sm">
|
<Button variant="outline" size="sm">
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ export default function ProjectForm({ initialData = null }) {
|
|||||||
wp: "",
|
wp: "",
|
||||||
contact: "",
|
contact: "",
|
||||||
notes: "",
|
notes: "",
|
||||||
|
project_type: initialData?.project_type || "design",
|
||||||
|
// project_status is not included in the form for creation or editing
|
||||||
...initialData,
|
...initialData,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -74,6 +76,24 @@ export default function ProjectForm({ initialData = null }) {
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Project Type Dropdown */}
|
||||||
|
<div>
|
||||||
|
<label className="block font-medium">Typ projektu</label>
|
||||||
|
<select
|
||||||
|
name="project_type"
|
||||||
|
value={form.project_type}
|
||||||
|
onChange={handleChange}
|
||||||
|
className="border p-2 w-full"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
<option value="design">Projektowanie</option>
|
||||||
|
<option value="construction">Realizacja</option>
|
||||||
|
<option value="design+construction">
|
||||||
|
Projektowanie + Realizacja
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Other fields */}
|
{/* Other fields */}
|
||||||
{[
|
{[
|
||||||
["project_name", "Nazwa projektu"],
|
["project_name", "Nazwa projektu"],
|
||||||
|
|||||||
38
src/components/ProjectStatusDropdown.js
Normal file
38
src/components/ProjectStatusDropdown.js
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
export default function ProjectStatusDropdown({ project, onStatusChange }) {
|
||||||
|
const [status, setStatus] = useState(project.project_status);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
|
const handleChange = async (e) => {
|
||||||
|
const newStatus = e.target.value;
|
||||||
|
setStatus(newStatus);
|
||||||
|
setLoading(true);
|
||||||
|
await fetch(`/api/projects/${project.project_id}`, {
|
||||||
|
method: "PUT",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify({ ...project, project_status: newStatus }),
|
||||||
|
});
|
||||||
|
setLoading(false);
|
||||||
|
if (onStatusChange) onStatusChange(newStatus);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<select
|
||||||
|
name="project_status"
|
||||||
|
value={status}
|
||||||
|
onChange={handleChange}
|
||||||
|
className="ml-2 border p-1 rounded"
|
||||||
|
disabled={loading}
|
||||||
|
>
|
||||||
|
<option value="registered">Zarejestrowany</option>
|
||||||
|
<option value="in_progress_design">W realizacji (projektowanie)</option>
|
||||||
|
<option value="in_progress_construction">
|
||||||
|
W realizacji (realizacja)
|
||||||
|
</option>
|
||||||
|
<option value="fulfilled">Zakończony</option>
|
||||||
|
</select>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -30,6 +30,8 @@ export default function initializeDatabase() {
|
|||||||
wp TEXT,
|
wp TEXT,
|
||||||
contact TEXT,
|
contact TEXT,
|
||||||
notes TEXT,
|
notes TEXT,
|
||||||
|
project_type TEXT CHECK(project_type IN ('design', 'construction', 'design+construction')) DEFAULT 'design',
|
||||||
|
project_status TEXT CHECK(project_status IN ('registered', 'in_progress_design', 'in_progress_construction', 'fulfilled')) DEFAULT 'registered',
|
||||||
FOREIGN KEY (contract_id) REFERENCES contracts(contract_id)
|
FOREIGN KEY (contract_id) REFERENCES contracts(contract_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -98,4 +100,22 @@ export default function initializeDatabase() {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Column already exists, ignore error
|
// Column already exists, ignore error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Migration: Add project_type column to projects table
|
||||||
|
try {
|
||||||
|
db.exec(`
|
||||||
|
ALTER TABLE projects ADD COLUMN project_type TEXT CHECK(project_type IN ('design', 'construction', 'design+construction')) DEFAULT 'design';
|
||||||
|
`);
|
||||||
|
} catch (e) {
|
||||||
|
// Column already exists, ignore error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Migration: Add project_status column to projects table
|
||||||
|
try {
|
||||||
|
db.exec(`
|
||||||
|
ALTER TABLE projects ADD COLUMN project_status TEXT CHECK(project_status IN ('registered', 'in_progress_design', 'in_progress_construction', 'fulfilled')) DEFAULT 'registered';
|
||||||
|
`);
|
||||||
|
} catch (e) {
|
||||||
|
// Column already exists, ignore error
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ export function createProject(data) {
|
|||||||
const stmt = db.prepare(`
|
const stmt = db.prepare(`
|
||||||
INSERT INTO projects (
|
INSERT INTO projects (
|
||||||
contract_id, project_name, project_number, address, plot, district, unit, city, investment_number, finish_date,
|
contract_id, project_name, project_number, address, plot, district, unit, city, investment_number, finish_date,
|
||||||
wp, contact, notes
|
wp, contact, notes, project_type, project_status
|
||||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
`);
|
`);
|
||||||
stmt.run(
|
stmt.run(
|
||||||
data.contract_id,
|
data.contract_id,
|
||||||
@@ -58,7 +58,9 @@ export function createProject(data) {
|
|||||||
data.finish_date,
|
data.finish_date,
|
||||||
data.wp,
|
data.wp,
|
||||||
data.contact,
|
data.contact,
|
||||||
data.notes
|
data.notes,
|
||||||
|
data.project_type || "design",
|
||||||
|
data.project_status || "registered"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +68,7 @@ export function updateProject(id, data) {
|
|||||||
const stmt = db.prepare(`
|
const stmt = db.prepare(`
|
||||||
UPDATE projects SET
|
UPDATE projects SET
|
||||||
contract_id = ?, project_name = ?, project_number = ?, address = ?, plot = ?, district = ?, unit = ?, city = ?,
|
contract_id = ?, project_name = ?, project_number = ?, address = ?, plot = ?, district = ?, unit = ?, city = ?,
|
||||||
investment_number = ?, finish_date = ?, wp = ?, contact = ?, notes = ?
|
investment_number = ?, finish_date = ?, wp = ?, contact = ?, notes = ?, project_type = ?, project_status = ?
|
||||||
WHERE project_id = ?
|
WHERE project_id = ?
|
||||||
`);
|
`);
|
||||||
stmt.run(
|
stmt.run(
|
||||||
@@ -83,6 +85,8 @@ export function updateProject(id, data) {
|
|||||||
data.wp,
|
data.wp,
|
||||||
data.contact,
|
data.contact,
|
||||||
data.notes,
|
data.notes,
|
||||||
|
data.project_type || "design",
|
||||||
|
data.project_status || "registered",
|
||||||
id
|
id
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user