All first todos completed
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
"use client";
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import { useParams } from "next/navigation";
|
||||
import { FormEvent, useEffect, useMemo, useState } from "react";
|
||||
import {
|
||||
copyGlobalDeviceToProject,
|
||||
copyProjectDeviceToGlobal,
|
||||
createDistributionBoard,
|
||||
createFloor,
|
||||
createProjectDevice,
|
||||
@@ -11,6 +13,7 @@ import {
|
||||
deleteProjectDevice,
|
||||
listDistributionBoards,
|
||||
listFloors,
|
||||
listGlobalDevices,
|
||||
listProjectDevices,
|
||||
listProjects,
|
||||
listRooms,
|
||||
@@ -21,6 +24,7 @@ import type {
|
||||
CreateProjectDeviceInput,
|
||||
DistributionBoardDto,
|
||||
FloorDto,
|
||||
GlobalDeviceDto,
|
||||
ProjectDeviceDto,
|
||||
ProjectDto,
|
||||
RoomDto,
|
||||
@@ -28,6 +32,7 @@ import type {
|
||||
|
||||
const emptyProjectDevice: CreateProjectDeviceInput = {
|
||||
name: "",
|
||||
displayName: "",
|
||||
category: "",
|
||||
quantity: 1,
|
||||
installedPowerPerUnitKw: 0.1,
|
||||
@@ -54,6 +59,7 @@ export default function ProjectDetailPage() {
|
||||
const [floors, setFloors] = useState<FloorDto[]>([]);
|
||||
const [rooms, setRooms] = useState<RoomDto[]>([]);
|
||||
const [projectDevices, setProjectDevices] = useState<ProjectDeviceDto[]>([]);
|
||||
const [globalDevices, setGlobalDevices] = useState<GlobalDeviceDto[]>([]);
|
||||
const [boardName, setBoardName] = useState("");
|
||||
const [floorName, setFloorName] = useState("");
|
||||
const [roomNumber, setRoomNumber] = useState("");
|
||||
@@ -63,6 +69,7 @@ export default function ProjectDetailPage() {
|
||||
const [threePhaseVoltageV, setThreePhaseVoltageV] = useState("400");
|
||||
const [projectDeviceForm, setProjectDeviceForm] = useState<Record<string, string>>({
|
||||
name: "",
|
||||
displayName: "",
|
||||
category: "",
|
||||
quantity: "1",
|
||||
installedPowerPerUnitKw: "0.1",
|
||||
@@ -72,6 +79,7 @@ export default function ProjectDetailPage() {
|
||||
powerFactor: "1",
|
||||
note: "",
|
||||
});
|
||||
const [selectedGlobalDeviceId, setSelectedGlobalDeviceId] = useState("");
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
|
||||
@@ -89,8 +97,9 @@ export default function ProjectDetailPage() {
|
||||
listFloors(projectId),
|
||||
listRooms(projectId),
|
||||
listProjectDevices(projectId),
|
||||
listGlobalDevices(),
|
||||
])
|
||||
.then(([projects, distributionBoards, loadedFloors, loadedRooms, loadedProjectDevices]) => {
|
||||
.then(([projects, distributionBoards, loadedFloors, loadedRooms, loadedProjectDevices, loadedGlobalDevices]) => {
|
||||
const currentProject = projects.find((item) => item.id === projectId) ?? null;
|
||||
setProject(currentProject);
|
||||
if (currentProject) {
|
||||
@@ -101,6 +110,7 @@ export default function ProjectDetailPage() {
|
||||
setFloors(loadedFloors);
|
||||
setRooms(loadedRooms);
|
||||
setProjectDevices(loadedProjectDevices);
|
||||
setGlobalDevices(loadedGlobalDevices);
|
||||
setError(null);
|
||||
})
|
||||
.catch((err: unknown) =>
|
||||
@@ -201,6 +211,7 @@ export default function ProjectDetailPage() {
|
||||
|
||||
const payload: CreateProjectDeviceInput = {
|
||||
name: projectDeviceForm.name.trim(),
|
||||
displayName: projectDeviceForm.displayName.trim() || projectDeviceForm.name.trim(),
|
||||
category: projectDeviceForm.category.trim() || undefined,
|
||||
quantity: Number(projectDeviceForm.quantity),
|
||||
installedPowerPerUnitKw: Number(projectDeviceForm.installedPowerPerUnitKw),
|
||||
@@ -218,6 +229,7 @@ export default function ProjectDetailPage() {
|
||||
setProjectDevices((current) => [...current, created]);
|
||||
setProjectDeviceForm({
|
||||
name: emptyProjectDevice.name,
|
||||
displayName: emptyProjectDevice.displayName,
|
||||
category: emptyProjectDevice.category ?? "",
|
||||
quantity: String(emptyProjectDevice.quantity),
|
||||
installedPowerPerUnitKw: String(emptyProjectDevice.installedPowerPerUnitKw),
|
||||
@@ -252,7 +264,7 @@ export default function ProjectDetailPage() {
|
||||
|
||||
async function handleQuickUpdateProjectDevice(
|
||||
device: ProjectDeviceDto,
|
||||
key: "name" | "category",
|
||||
key: "name" | "displayName" | "category",
|
||||
value: string
|
||||
) {
|
||||
if (!projectId) {
|
||||
@@ -261,6 +273,7 @@ export default function ProjectDetailPage() {
|
||||
|
||||
const payload: CreateProjectDeviceInput = {
|
||||
name: key === "name" ? value : device.name,
|
||||
displayName: key === "displayName" ? value : device.displayName,
|
||||
category: key === "category" ? value : device.category ?? undefined,
|
||||
quantity: device.quantity,
|
||||
installedPowerPerUnitKw: device.installedPowerPerUnitKw,
|
||||
@@ -279,6 +292,40 @@ export default function ProjectDetailPage() {
|
||||
}
|
||||
}
|
||||
|
||||
async function handleCopyGlobalToProject() {
|
||||
if (!projectId || !selectedGlobalDeviceId) {
|
||||
return;
|
||||
}
|
||||
|
||||
setIsSaving(true);
|
||||
setError(null);
|
||||
try {
|
||||
const created = await copyGlobalDeviceToProject(projectId, selectedGlobalDeviceId);
|
||||
setProjectDevices((current) => [...current, created]);
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : "Globales Gerät konnte nicht ins Projekt kopiert werden.");
|
||||
} finally {
|
||||
setIsSaving(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleCopyProjectToGlobal(projectDeviceId: string) {
|
||||
if (!projectId) {
|
||||
return;
|
||||
}
|
||||
|
||||
setIsSaving(true);
|
||||
setError(null);
|
||||
try {
|
||||
const created = await copyProjectDeviceToGlobal(projectId, projectDeviceId);
|
||||
setGlobalDevices((current) => [...current, created]);
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : "Projektgerät konnte nicht global kopiert werden.");
|
||||
} finally {
|
||||
setIsSaving(false);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<main className="container py-4">
|
||||
<div className="d-flex justify-content-between align-items-center mb-3">
|
||||
@@ -512,14 +559,24 @@ export default function ProjectDetailPage() {
|
||||
<div className="col-12 col-md-3">
|
||||
<input
|
||||
className="form-control"
|
||||
placeholder="Bezeichnung"
|
||||
placeholder="Interner Name"
|
||||
value={projectDeviceForm.name}
|
||||
onChange={(event) =>
|
||||
setProjectDeviceForm((current) => ({ ...current, name: event.target.value }))
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-6 col-md-2">
|
||||
<div className="col-12 col-md-3">
|
||||
<input
|
||||
className="form-control"
|
||||
placeholder="Anzeigename"
|
||||
value={projectDeviceForm.displayName}
|
||||
onChange={(event) =>
|
||||
setProjectDeviceForm((current) => ({ ...current, displayName: event.target.value }))
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-6 col-md-1">
|
||||
<input
|
||||
className="form-control"
|
||||
placeholder="Kategorie"
|
||||
@@ -540,7 +597,7 @@ export default function ProjectDetailPage() {
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-6 col-md-2">
|
||||
<div className="col-6 col-md-1">
|
||||
<input
|
||||
className="form-control"
|
||||
type="number"
|
||||
@@ -586,17 +643,40 @@ export default function ProjectDetailPage() {
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
<div className="input-group mt-3">
|
||||
<select
|
||||
className="form-select"
|
||||
value={selectedGlobalDeviceId}
|
||||
onChange={(event) => setSelectedGlobalDeviceId(event.target.value)}
|
||||
>
|
||||
<option value="">Globales Gerät auswählen</option>
|
||||
{globalDevices.map((device) => (
|
||||
<option key={device.id} value={device.id}>
|
||||
{device.displayName}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<button
|
||||
className="btn btn-outline-primary"
|
||||
type="button"
|
||||
onClick={handleCopyGlobalToProject}
|
||||
disabled={!selectedGlobalDeviceId || isSaving}
|
||||
>
|
||||
Nach Projekt kopieren
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="table-responsive">
|
||||
<table className="table table-sm table-striped align-middle mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Bezeichnung</th>
|
||||
<th>Interner Name</th>
|
||||
<th>Anzeigename</th>
|
||||
<th>Kategorie</th>
|
||||
<th>Anzahl</th>
|
||||
<th>Leistung je Stück [kW]</th>
|
||||
<th>GZF</th>
|
||||
<th>Aktion</th>
|
||||
<th>Aktionen</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -613,6 +693,17 @@ export default function ProjectDetailPage() {
|
||||
}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<input
|
||||
className="form-control form-control-sm"
|
||||
defaultValue={device.displayName}
|
||||
onBlur={(event) =>
|
||||
event.target.value !== device.displayName
|
||||
? handleQuickUpdateProjectDevice(device, "displayName", event.target.value)
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<input
|
||||
className="form-control form-control-sm"
|
||||
@@ -628,19 +719,30 @@ export default function ProjectDetailPage() {
|
||||
<td>{device.installedPowerPerUnitKw}</td>
|
||||
<td>{device.demandFactor}</td>
|
||||
<td>
|
||||
<button
|
||||
className="btn btn-sm btn-outline-danger"
|
||||
type="button"
|
||||
onClick={() => handleDeleteProjectDevice(device.id)}
|
||||
>
|
||||
Löschen
|
||||
</button>
|
||||
<div className="btn-group btn-group-sm">
|
||||
<button
|
||||
className="btn btn-outline-secondary"
|
||||
type="button"
|
||||
onClick={() => handleCopyProjectToGlobal(device.id)}
|
||||
disabled={isSaving}
|
||||
>
|
||||
Nach global kopieren
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-outline-danger"
|
||||
type="button"
|
||||
onClick={() => handleDeleteProjectDevice(device.id)}
|
||||
disabled={isSaving}
|
||||
>
|
||||
Löschen
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
{!projectDevices.length ? (
|
||||
<tr>
|
||||
<td colSpan={6} className="text-center text-secondary py-4">
|
||||
<td colSpan={7} className="text-center text-secondary py-4">
|
||||
Noch keine Projektgeräte vorhanden.
|
||||
</td>
|
||||
</tr>
|
||||
@@ -658,3 +760,5 @@ export default function ProjectDetailPage() {
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user