diff --git a/tgui/packages/tgui/interfaces/Biogenerator.tsx b/tgui/packages/tgui/interfaces/Biogenerator.tsx index 92efeadd5a0..24597404396 100644 --- a/tgui/packages/tgui/interfaces/Biogenerator.tsx +++ b/tgui/packages/tgui/interfaces/Biogenerator.tsx @@ -6,6 +6,7 @@ import { useBackend } from '../backend'; import { Box, Button, + Icon, LabeledList, NoticeBox, NumberInput, @@ -17,161 +18,75 @@ import { } from '../components'; import { Window } from '../layouts'; -type BiogeneratorData = { - processing: BooleanLike; +type Data = { beaker: BooleanLike; - reagent_color: string; - biomass: number; - max_visual_biomass: number; - can_process: BooleanLike; beakerCurrentVolume: number; beakerMaxVolume: number; - max_output: number; - efficiency: number; + biomass: number; + can_process: BooleanLike; categories: Category[]; + efficiency: number; + max_output: number; + max_visual_biomass: number; + processing: BooleanLike; + reagent_color: string; }; type Category = { - name: string; items: Design[]; + name: string; }; type Design = { - id: number; - name: string; - is_reagent: BooleanLike; - disable: BooleanLike; - cost: number; amount: number; + cost: number; + disable: BooleanLike; + id: string; + is_reagent: BooleanLike; + name: string; }; -export const Biogenerator = (props) => { - const { act, data } = useBackend(); - const { - processing, - beaker, - reagent_color, - biomass, - max_visual_biomass, - can_process, - beakerCurrentVolume, - beakerMaxVolume, - max_output, - efficiency, - categories, - } = data; +export function Biogenerator(props) { + const { data } = useBackend(); + const { beaker, beakerCurrentVolume, beakerMaxVolume, categories } = data; + const [selectedCategory, setSelectedCategory] = useState( data.categories[0]?.name, ); + const items = categories.find((category) => category.name === selectedCategory)?.items || []; + + const space = beaker ? beakerMaxVolume - beakerCurrentVolume : 1; + return ( -
- - act('activate')} - /> - } - > - - - {`${parseFloat(biomass.toFixed(2))} units`} - - - - {!!beaker && ( - act('eject')} - /> - } - > - - - {`${beakerCurrentVolume} of ${beakerMaxVolume} units`} - - - - )} - {!beaker && ( - - - No liquid container - - - )} - -
+
- {categories.map((category) => ( + {categories.map(({ name }) => ( setSelectedCategory(category.name)} + key={name} + selected={name === selectedCategory} + onClick={() => setSelectedCategory(name)} > - {category.name} + {name} ))} - +
- + {items.map((item) => ( + + ))}
@@ -179,67 +94,165 @@ export const Biogenerator = (props) => {
); +} + +function Controls() { + const { act, data } = useBackend(); + const { + beaker, + beakerCurrentVolume, + beakerMaxVolume, + biomass, + can_process, + max_visual_biomass, + processing, + reagent_color, + } = data; + + return ( +
+ + act('activate')} + > + Generate + + } + > + + + {`${parseFloat(biomass.toFixed(2))} units`} + + + + {!!beaker && ( + act('eject')} + > + Eject + + } + > + + + {`${beakerCurrentVolume} of ${beakerMaxVolume} units`} + + + + )} + {!beaker && ( + + + No liquid container + + + )} + +
+ ); +} + +type Props = { + item: Design; + space: number; }; -const ItemList = (props) => { - const { act } = useBackend(); - const items = props.items.map((item) => { - const [amount, setAmount] = useState( - item.is_reagent ? Math.min(Math.max(props.space, 1), 10) : 1, - ); - const disabled = - props.processing || - (item.is_reagent && !props.beaker) || - (item.is_reagent && props.space < amount) || - props.biomass < Math.ceil((item.cost * amount) / props.efficiency); - const max_possible = Math.floor( - (props.efficiency * props.biomass) / item.cost, - ); - const max_capacity = item.is_reagent ? props.space : props.max_output; - const max_amount = Math.max(1, Math.min(max_capacity, max_possible)); - return { - ...item, - disabled, - max_amount, - amount, - setAmount, - }; - }); - return items.map((item) => ( - +function Item(props: Props) { + const { item, space } = props; + const { cost, id, is_reagent, name } = item; + + const { act, data } = useBackend(); + const { biomass, beaker, efficiency, max_output, processing } = data; + + const minAmount = is_reagent ? Math.min(Math.max(space, 1), 10) : 1; + + const [amount, setAmount] = useState(minAmount); + + const disabled = + processing || + (is_reagent && !beaker) || + (is_reagent && space < amount) || + biomass < Math.ceil((cost * amount) / efficiency); + + const maxPossible = Math.floor((efficiency * biomass) / cost); + + const maxCapacity = is_reagent ? space : max_output; + const maxAmount = Math.max(1, Math.min(maxCapacity, maxPossible)); + + return ( + {' '} - {item.name} + {name} item.setAmount(value)} + maxValue={maxAmount} + onChange={(value) => setAmount(value)} /> - )); -}; + ); +}