Adds first version of the app. Local storage only.

This commit is contained in:
2026-09-01 14:44:49 -05:00
commit 9710f1ee5a
44 changed files with 5865 additions and 0 deletions
+76
View File
@@ -0,0 +1,76 @@
import { allCableTypes } from './project'
import type { Device, Project } from './types'
export interface BomCableLine {
cableTypeId: string
cableTypeName: string
unit: string
count: number
/** Sum of user-entered distances; connections with no distance are excluded. */
totalLength: number
connectionsMissingLength: number
}
export interface BomDeviceLine {
key: string
name: string
category: string
manufacturer?: string
model?: string
count: number
}
export interface Bom {
cables: BomCableLine[]
devices: BomDeviceLine[]
}
function deviceGroupKey(device: Device): string {
return device.templateId ?? `${device.category}:${device.manufacturer ?? ''}:${device.model ?? device.name}`
}
export function computeBom(project: Project): Bom {
const cableTypes = new Map(allCableTypes(project).map((ct) => [ct.id, ct]))
const cableLines = new Map<string, BomCableLine>()
for (const connection of project.connections) {
const cableType = cableTypes.get(connection.cableTypeId)
const name = cableType?.name ?? 'Unknown Cable'
const unit = cableType?.unit ?? 'ft'
const existing = cableLines.get(connection.cableTypeId) ?? {
cableTypeId: connection.cableTypeId,
cableTypeName: name,
unit,
count: 0,
totalLength: 0,
connectionsMissingLength: 0,
}
existing.count += 1
if (typeof connection.distance === 'number' && !Number.isNaN(connection.distance)) {
existing.totalLength += connection.distance
} else {
existing.connectionsMissingLength += 1
}
cableLines.set(connection.cableTypeId, existing)
}
const deviceLines = new Map<string, BomDeviceLine>()
for (const device of project.devices) {
const key = deviceGroupKey(device)
const existing = deviceLines.get(key) ?? {
key,
name: device.name,
category: device.category,
manufacturer: device.manufacturer,
model: device.model,
count: 0,
}
existing.count += 1
deviceLines.set(key, existing)
}
return {
cables: [...cableLines.values()].sort((a, b) => a.cableTypeName.localeCompare(b.cableTypeName)),
devices: [...deviceLines.values()].sort((a, b) => a.name.localeCompare(b.name)),
}
}