import React, { useState } from 'react'; type DeadLoadItem = { category: string; description: string; multiplier: number; psfMax: number; psfMin: number; }; // Mock Data const ITEM_DB: Record = { Flooring: [ { category: 'Flooring', description: 'Carpet & pad', multiplier: 1, psfMax: 1.0, psfMin: 1.0 }, { category: 'Flooring', description: 'Ceramic tile', multiplier: 1, psfMax: 12.0, psfMin: 12.0 }, ], Topping: [ { category: 'Topping', description: 'Concrete regular per 1"', multiplier: 1, psfMax: 12.5, psfMin: 12.0 }, // 145pcf / 12 ~ 12 ], Decking: [ { category: 'Decking', description: 'Metal Floor deck - 2", 20ga', multiplier: 1, psfMax: 2.0, psfMin: 1.5 }, ], Framing: [ { category: 'Framing', description: 'Steel floor bms/joists & girders', multiplier: 1, psfMax: 8.0, psfMin: 5.0 }, ], Ceiling: [ { category: 'Ceiling', description: 'Suspended acoustical tile', multiplier: 1, psfMax: 1.8, psfMin: 1.0 }, ], Sprinklers: [ { category: 'Sprinklers', description: 'Sprinklers', multiplier: 1, psfMax: 2.0, psfMin: 0.0 }, // Wet 3.0? Screenshot uses 2.0 ], 'Mech & Elec': [ { category: 'Mech & Elec', description: 'Mech. & Elec.', multiplier: 1, psfMax: 2.0, psfMin: 0.0 }, ], Misc: [ { category: 'Misc', description: 'Misc.', multiplier: 1, psfMax: 0.5, psfMin: 0.0 }, ] }; const KLL_OPTIONS = [ { label: 'Interior columns', value: 4 }, { label: 'Exterior columns', value: 4 }, { label: 'Corner columns', value: 4 }, { label: 'Interior beams', value: 2 }, { label: 'Precast T', value: 1 }, // Often 1 or 2 check code { label: 'One-way slabs', value: 1 }, ]; export const FloorDesignLoadsSheet: React.FC = () => { // --- State --- const [selectedItems, setSelectedItems] = useState<{ [key: string]: DeadLoadItem | null }>({ Flooring: ITEM_DB.Flooring[0], Topping: ITEM_DB.Topping[0], Decking: ITEM_DB.Decking[0], Framing: ITEM_DB.Framing[0], Ceiling: ITEM_DB.Ceiling[0], Sprinklers: ITEM_DB.Sprinklers[0], 'Mech & Elec': ITEM_DB['Mech & Elec'][0], Misc: ITEM_DB.Misc[0], }); const [multipliers] = useState<{ [key: string]: number }>({ Topping: 3.5, // 3.5 inches? }); const [overrideDL, setOverrideDL] = useState({ enabled: true, value: 80.0, valueMin: 65.0 }); const [usePartitions, setUsePartitions] = useState(true); const [liveLoadUnreduced, setLiveLoadUnreduced] = useState(50.0); // Reduction State const [reduction1, setReduction1] = useState({ kll: 2, at: 300 }); const [reduction2, setReduction2] = useState({ kll: 4, at: 500 }); // --- Calculations --- // 1. Dead Load let dlMax = 0; let dlMin = 0; const rows = Object.keys(ITEM_DB); rows.forEach(key => { const item = selectedItems[key]; const mult = multipliers[key] || 1; if (item) { dlMax += item.psfMax * mult; dlMin += item.psfMin * mult; } }); const finalDL = overrideDL.enabled ? overrideDL.value : dlMax; // const finalDL_Min = overrideDL.enabled ? overrideDL.valueMin : dlMin; // 2. Live Load const partitions = usePartitions ? 15.0 : 0.0; const totalLL = liveLoadUnreduced + partitions; const totalLoad = finalDL + totalLL; // 3. Live Load Reduction (Standard) // L = Lo(0.25 + 15 / sqrt(Kll * At)) const calcReduced = (Lo: number, Kll: number, At: number, limitFactor: number) => { // Limits: // Not allowed if (Kll * At) < 400? ASCE 7-10 4.7.2: KllAt >= 400 for reduction. // If Kll*At < 400, no reduction allowed (Reduction Factor = 1.0) generally? usually checked. if (Kll * At < 400) return Lo; const multiplier = 0.25 + 15 / Math.sqrt(Kll * At); let L = Lo * multiplier; // Limits const minL = limitFactor * Lo; return Math.max(L, minL); }; const reduced1 = calcReduced(liveLoadUnreduced, reduction1.kll, reduction1.at, 0.5); // 1 floor const reduced2 = calcReduced(liveLoadUnreduced, reduction2.kll, reduction2.at, 0.4); // 2+ floors // 4. IBC Alternate // R = 0.08(A - 150) // R <= 40% (1 floor), R <= 60% (>=2 floors). // R <= 23.1(1 + D/Lo) const calcIBC = (Lo: number, At: number, DL: number, supportDescription: '1_floor' | '2_plus_floors') => { const R_area = 0.08 * (At - 150); const R_structure = 23.1 * (1 + DL / Lo); let maxR = 0; if (supportDescription === '1_floor') maxR = 40; else maxR = 60; // R is smallest of these const R = Math.max(0, Math.min(R_area, R_structure, maxR)); const L = Lo * (1 - R / 100); return { R, L }; }; // For IBC alternate, usually we check Tributary Area > 150. // Screenshot calculation for R=23.1(1+D/L) uses what DL? // "Actual DL" is 61.1, Override is 80.0. // R = 23.1 * (1 + 80 / 50) = 23.1 * (1 + 1.6) = 23.1 * 2.6 = 60.06 -> 60.1%. Matches screenshot. const ibc1 = calcIBC(liveLoadUnreduced, reduction1.at, finalDL, '1_floor'); const ibc2 = calcIBC(liveLoadUnreduced, reduction2.at, finalDL, '2_plus_floors'); const handleItemChange = (key: string, e: React.ChangeEvent) => { const selectedDescription = e.target.value; const selectedItem = ITEM_DB[key].find(item => item.description === selectedDescription); if (selectedItem) { setSelectedItems(prev => ({ ...prev, [key]: selectedItem })); } }; return (

Floor Design Loads

{/* Left Column */}
{rows.map(key => { const item = selectedItems[key]; return ( ) })}
Items Description Multiple psf (max) psf (min)
{item?.description} {multipliers[key] ?
x {multipliers[key].toFixed(1)}
: ''}
{(item!.psfMax * (multipliers[key] || 1)).toFixed(1)} {(item!.psfMin * (multipliers[key] || 1)).toFixed(1)}
Actual Dead Load {dlMax.toFixed(1)} {dlMin.toFixed(1)}
setOverrideDL({ ...overrideDL, enabled: true })} /> setOverrideDL({ ...overrideDL, value: parseFloat(e.target.value) })} style={{ width: '60px', color: 'red', fontWeight: 'bold' }} /> setOverrideDL({ ...overrideDL, valueMin: parseFloat(e.target.value) })} style={{ width: '60px', color: 'red', fontWeight: 'bold' }} />
{partitions.toFixed(1)} 0.0
Live Load setLiveLoadUnreduced(parseFloat(e.target.value))} style={{ width: '50px', background: 'transparent', border: 'none', textAlign: 'center', textDecoration: 'underline' }} /> 0.0
Total Live Load {totalLL.toFixed(1)} 0.0
Total Load {totalLoad.toFixed(1)} {dlMin.toFixed(1)}
{/* Standard Reduction */}
FLOOR LIVE LOAD REDUCTION (not including partitions)
NOTE: Not allowed for assembly occupancy or LL>100psf or passenger car garages, except may reduce members supporting 2 or more floors & non-assembly 20%.
L = Lo(0.25+15/√(KLLAT))
Unreduced design live load: Lo = {liveLoadUnreduced} psf
{/* Member & 1 Floor */}
Floor member & 1 floor cols KLL =
{reduction1.kll}
Tributary Area AT =
setReduction1({ ...reduction1, at: parseFloat(e.target.value) })} style={{ width: '80px', color: 'red' }} />
sf
Reduced live load: L =
{reduced1.toFixed(1)} psf
{/* Cols 2 or more floors */}
Columns (2 or more floors) KLL =
{reduction2.kll}
Tributary Area AT =
setReduction2({ ...reduction2, at: parseFloat(e.target.value) })} style={{ width: '80px', color: 'red' }} />
sf
Reduced live load: L =
{reduced2.toFixed(1)} psf
{/* Right Column: IBC Alternate */}
Edit default weights
IBC alternate procedure
Smallest of:
R = .08%(SF - 150)
R = 23.1(1+D/L) = {ibc1.R.toFixed(1)}%
R = 40% member supports 1 floor
R = 60% member supports ≥2 floors
R = {ibc1.R.toFixed(1)}%
Reduced live load: L = {ibc1.L.toFixed(1)} psf
R = {ibc2.R.toFixed(1)}%
Reduced live load: L = {ibc2.L.toFixed(1)} psf
); };