Add optional room areas

This commit is contained in:
Julian Appel 2026-09-27 20:00:03 +02:00
parent a6500e2b26
commit dce31ee143
26 changed files with 3669 additions and 78 deletions

View file

@ -18,6 +18,19 @@ type FloorLike = Pick<FloorDto, "id" | "name"> & {
buildingId?: string | null;
};
type RoomLike = Pick<RoomDto, "floorId">;
type RoomAreaLike = Pick<RoomDto, "floorId" | "areaM2">;
export interface RoomAreaSummary {
areaM2: number;
roomCount: number;
missingAreaCount: number;
}
export interface StructureAreaSummaries {
total: RoomAreaSummary;
byBuilding: Map<string | null, RoomAreaSummary>;
byFloor: Map<string | null, RoomAreaSummary>;
}
export interface FloorGroup<TFloor extends FloorLike = FloorLike> {
/** null for floors without (known) building. */
@ -262,6 +275,59 @@ export function countRoomsByFloor(
return counts;
}
/**
* Sums only known room areas and counts missing values separately. Rooms with
* no known floor/building are grouped under null for the corresponding UI
* entries "Ohne Etage" and "Ohne Gebäude".
*/
export function summarizeRoomAreas(
rooms: ReadonlyArray<RoomAreaLike>,
floors: ReadonlyArray<FloorLike>,
buildings: ReadonlyArray<BuildingLike>
): StructureAreaSummaries {
const buildingIds = toIdSet(buildings);
const floorsById = new Map(floors.map((floor) => [floor.id, floor]));
const byBuilding = new Map<string | null, RoomAreaSummary>();
const byFloor = new Map<string | null, RoomAreaSummary>();
const total = emptyAreaSummary();
for (const room of rooms) {
const floor = room.floorId === null ? undefined : floorsById.get(room.floorId);
const floorId = floor?.id ?? null;
const buildingId = floor
? resolveFloorBuildingId(floor, buildingIds)
: null;
addRoomArea(total, room.areaM2);
addRoomArea(summaryFor(byFloor, floorId), room.areaM2);
addRoomArea(summaryFor(byBuilding, buildingId), room.areaM2);
}
return { total, byBuilding, byFloor };
}
function emptyAreaSummary(): RoomAreaSummary {
return { areaM2: 0, roomCount: 0, missingAreaCount: 0 };
}
function summaryFor(
summaries: Map<string | null, RoomAreaSummary>,
key: string | null
) {
const existing = summaries.get(key);
if (existing) return existing;
const created = emptyAreaSummary();
summaries.set(key, created);
return created;
}
function addRoomArea(summary: RoomAreaSummary, areaM2: number | null) {
summary.roomCount += 1;
if (areaM2 === null) {
summary.missingAreaCount += 1;
} else {
summary.areaM2 += areaM2;
}
}
/** "EG · Haus A", "EG" (floor without building) or "Ohne Etage". */
export function describeRoomLocation(
room: RoomLike,