import { useState, useMemo } from 'react'
import { SUBSTANCES, COMBINATIONS } from '../engine/knowledgebaseData.js'
// ── Helpers ──────────────────────────────────────────────────────────────────
const ROLE_FILTERS = ['All', 'Fuels', 'Oxidisers', 'Monopropellants']
const SUBCATEGORY_FILTERS = ['Cryogenic', 'Storable', 'Hypergolic', 'Green', 'Solid', 'Hybrid']
function roleBadgeClass(role) {
if (role === 'fuel') return 'bg-blue-900 text-blue-200 border border-blue-700'
if (role === 'oxidiser') return 'bg-orange-900 text-orange-200 border border-orange-700'
return 'bg-yellow-900 text-yellow-200 border border-yellow-700'
}
function roleLabel(role) {
if (role === 'fuel') return 'FUEL'
if (role === 'oxidiser') return 'OXIDISER'
return 'MONOPROPELLANT'
}
function subcategoryBadgeClass(sub) {
const map = {
Cryogenic: 'bg-cyan-900 text-cyan-200 border border-cyan-700',
Storable: 'bg-slate-700 text-slate-200 border border-slate-500',
Hypergolic: 'bg-red-900 text-red-200 border border-red-700',
Green: 'bg-green-900 text-green-200 border border-green-700',
Solid: 'bg-amber-900 text-amber-200 border border-amber-700',
Hybrid: 'bg-purple-900 text-purple-200 border border-purple-700',
}
return map[sub] ?? 'bg-slate-700 text-slate-200 border border-slate-500'
}
function PropRow({ label, value }) {
if (value === null || value === undefined) return null
return (
{label}
{value}
)
}
// ── Main page ────────────────────────────────────────────────────────────────
export default function KnowledgebaseFuelsPage() {
const [search, setSearch] = useState('')
const [roleFilter, setRoleFilter] = useState('All')
const [subcatFilter, setSubcatFilter] = useState(null)
const [selectedId, setSelectedId] = useState(SUBSTANCES[0].id)
// Filtered list
const filtered = useMemo(() => {
const q = search.toLowerCase()
return SUBSTANCES.filter(s => {
if (q && !s.name.toLowerCase().includes(q) && !s.symbol.toLowerCase().includes(q) && !s.formula.toLowerCase().includes(q)) return false
if (roleFilter === 'Fuels' && s.role !== 'fuel') return false
if (roleFilter === 'Oxidisers' && s.role !== 'oxidiser') return false
if (roleFilter === 'Monopropellants' && s.role !== 'monopropellant') return false
if (subcatFilter && s.subcategory !== subcatFilter) return false
return true
})
}, [search, roleFilter, subcatFilter])
const selected = SUBSTANCES.find(s => s.id === selectedId) ?? SUBSTANCES[0]
// Combinations for the selected substance
const combinations = useMemo(() => {
if (selected.role === 'monopropellant') return []
return COMBINATIONS.filter(c =>
(selected.role === 'fuel' && c.fuelId === selected.id) ||
(selected.role === 'oxidiser' && c.oxidiserId === selected.id)
)
}, [selected])
// Get partner substance for each combination
function getPartner(combo) {
const partnerId = selected.role === 'fuel' ? combo.oxidiserId : combo.fuelId
return SUBSTANCES.find(s => s.id === partnerId)
}
// Ensure selected item is still in filtered list; if not, show first filtered
const effectiveSelected =
filtered.find(s => s.id === selectedId)
? selected
: (filtered[0] ?? selected)
return (
{/* ── Left panel ────────────────────────────────────────────────────── */}
{/* Search */}
setSearch(e.target.value)}
className="w-full px-3 py-1.5 rounded-md bg-slate-800 border border-slate-600 text-sm text-slate-100 placeholder-slate-500 focus:outline-none focus:border-blue-500"
/>
{/* Role filter pills */}
{ROLE_FILTERS.map(r => (
))}
{/* Subcategory filter pills */}
{SUBCATEGORY_FILTERS.map(sc => (
))}
{/* Substance list */}
{filtered.length === 0 && (
No substances match your filters.
)}
{filtered.map(s => (
))}
{/* ── Right panel ───────────────────────────────────────────────────── */}
)
}
// ── Substance detail view ────────────────────────────────────────────────────
function SubstanceDetail({ substance: s, combinations, getPartner }) {
return (
{/* Header */}
{s.name}
{s.symbol}
{roleLabel(s.role)}
{s.subcategory}
{/* Description */}
{s.description}
{/* Technical specs */}
Technical Specifications
{s.catalyticIsp != null && (
)}
{/* Engine examples */}
{s.engineExamples?.length > 0 && (
Engine / Motor Examples
{s.engineExamples.join(', ')}
)}
{/* Combinations */}
{s.role !== 'monopropellant' && (
Bipropellant Combinations
{combinations.length === 0 ? (
No combination data available for this substance.
) : (
{combinations.map((combo, i) => {
const partner = getPartner(combo)
const partnerLabel = s.role === 'fuel'
? `with ${partner?.name ?? combo.oxidiserId} (oxidiser)`
: `with ${partner?.name ?? combo.fuelId} (fuel)`
return (
{partnerLabel}
{combo.energeticCategory}
{combo.isHypergolic && (
Hypergolic
)}
{combo.notes && (
{combo.notes}
)}
{combo.engines?.length > 0 && (
Engines:
{combo.engines.join(', ')}
)}
)
})}
)}
)}
)
}
function Stat({ label, value }) {
return (
)
}