- Seitenansicht (/projects/:projectId/print): tabular cover page, board overview with supply structure and power sums, one plan per board with a repeating title block; PDF via the browser print dialog with named @page rules (A4 portrait cover, A4/A3 landscape plans, page x of y). - Distribution-board info card (board number, location, fed-from, remark) in the board edit dialog, persisted through the additively extended distribution-board.update command (migration 0008, snapshot schema 6, legacy subtree commands normalized). - Global document logo upload (PNG/JPEG/SVG, max 2 MB) outside project revisions and snapshots. - fed-from stays free text; the overview hierarchy and cumulated sums are preliminary until the feed link is modeled. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
110 lines
3.3 KiB
TypeScript
110 lines
3.3 KiB
TypeScript
"use client";
|
|
|
|
import {
|
|
distributionBoardInfoFieldLabels,
|
|
distributionBoardInfoFieldMaxLengths,
|
|
distributionBoardInfoFields,
|
|
type DistributionBoardInfoField,
|
|
} from "../../shared/constants/distribution-board";
|
|
import type { DistributionBoardInfoDto } from "../types";
|
|
|
|
export type DistributionBoardInfoDraft = Record<DistributionBoardInfoField, string>;
|
|
|
|
const placeholders: Record<DistributionBoardInfoField, string> = {
|
|
boardNumber: "z. B. UV 1.1",
|
|
location: "z. B. Raum 003 Technik",
|
|
fedFrom: "z. B. HV 0.1 oder HAK / Zähleranlage",
|
|
remark: "",
|
|
};
|
|
|
|
export function toDistributionBoardInfoDraft(
|
|
info: DistributionBoardInfoDto
|
|
): DistributionBoardInfoDraft {
|
|
return {
|
|
boardNumber: info.boardNumber ?? "",
|
|
location: info.location ?? "",
|
|
fedFrom: info.fedFrom ?? "",
|
|
remark: info.remark ?? "",
|
|
};
|
|
}
|
|
|
|
export function fromDistributionBoardInfoDraft(
|
|
draft: DistributionBoardInfoDraft
|
|
): DistributionBoardInfoDto {
|
|
const value = (field: DistributionBoardInfoField) =>
|
|
draft[field].trim() ? draft[field].trim() : null;
|
|
return {
|
|
boardNumber: value("boardNumber"),
|
|
location: value("location"),
|
|
fedFrom: value("fedFrom"),
|
|
remark: value("remark"),
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Descriptive board data used by the print view title block. The values are
|
|
* local planning values; a later Revit import may prefill them only through
|
|
* an explicit, previewed decision.
|
|
*/
|
|
export function DistributionBoardInfoCard({
|
|
draft,
|
|
onChange,
|
|
}: {
|
|
draft: DistributionBoardInfoDraft;
|
|
onChange: (draft: DistributionBoardInfoDraft) => void;
|
|
}) {
|
|
return (
|
|
<section
|
|
aria-labelledby="distribution-board-info-heading"
|
|
className="card"
|
|
>
|
|
<div className="card-header" id="distribution-board-info-heading">
|
|
Infokarte
|
|
</div>
|
|
<div className="card-body row g-3">
|
|
{distributionBoardInfoFields.map((field) => (
|
|
<div
|
|
className={field === "remark" ? "col-12" : "col-12 col-md-6"}
|
|
key={field}
|
|
>
|
|
<label
|
|
className="form-label"
|
|
htmlFor={`distribution-board-info-${field}`}
|
|
>
|
|
{distributionBoardInfoFieldLabels[field]}
|
|
</label>
|
|
{field === "remark" ? (
|
|
<textarea
|
|
className="form-control"
|
|
id={`distribution-board-info-${field}`}
|
|
maxLength={distributionBoardInfoFieldMaxLengths[field]}
|
|
onChange={(event) =>
|
|
onChange({ ...draft, [field]: event.target.value })
|
|
}
|
|
rows={2}
|
|
value={draft[field]}
|
|
/>
|
|
) : (
|
|
<input
|
|
className="form-control"
|
|
id={`distribution-board-info-${field}`}
|
|
maxLength={distributionBoardInfoFieldMaxLengths[field]}
|
|
onChange={(event) =>
|
|
onChange({ ...draft, [field]: event.target.value })
|
|
}
|
|
placeholder={placeholders[field]}
|
|
value={draft[field]}
|
|
/>
|
|
)}
|
|
{field === "fedFrom" ? (
|
|
<div className="form-text">
|
|
Vorerst Freitext. Die logische Verknüpfung mit dem
|
|
speisenden Verteiler folgt.
|
|
</div>
|
|
) : null}
|
|
</div>
|
|
))}
|
|
</div>
|
|
</section>
|
|
);
|
|
}
|