Skip to content

Commit

Permalink
[MIRROR] Cargo ui refactor -> TS (#2135)
Browse files Browse the repository at this point in the history
Cargo ui refactor -> TS

Co-authored-by: Jeremiah <[email protected]>
  • Loading branch information
2 people authored and StealsThePRs committed Apr 23, 2024
1 parent df3285b commit 3010052
Show file tree
Hide file tree
Showing 11 changed files with 879 additions and 15 deletions.
41 changes: 41 additions & 0 deletions tgui/packages/common/type-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* Helps visualize highly complex ui data on the fly.
* @example
* ```tsx
* const { data } = useBackend<CargoData>();
* logger.log(getShallowTypes(data));
* ```
*/
export function getShallowTypes(
data: Record<string, any>,
): Record<string, any> {
const output = {};

for (const key in data) {
if (Array.isArray(data[key])) {
const arr: any[] = data[key];

// Return the first array item if it exists
if (data[key].length > 0) {
output[key] = arr[0];
continue;
}

output[key] = 'emptyarray';
} else if (typeof data[key] === 'object' && data[key] !== null) {
// Please inspect it further and make a new type for it
output[key] = 'object (inspect) || Record<string, any>';
} else if (typeof data[key] === 'number') {
const num = Number(data[key]);

// 0 and 1 could be booleans from byond
if (num === 1 || num === 0) {
output[key] = `${num}, BooleanLike?`;
continue;
}
output[key] = data[key];
}
}

return output;
}
39 changes: 39 additions & 0 deletions tgui/packages/tgui/interfaces/Cargo/CargoButtons.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { useBackend } from '../../backend';
import { Box, Button } from '../../components';
import { formatMoney } from '../../format';
import { CargoData } from './types';

export function CargoCartButtons(props) {
const { act, data } = useBackend<CargoData>();
const { cart = [], requestonly, can_send, can_approve_requests } = data;

let total = 0;
let amount = 0;
for (let i = 0; i < cart.length; i++) {
amount += cart[i].amount;
total += cart[i].cost;
}

const canClear =
!requestonly && !!can_send && !!can_approve_requests && cart.length > 0;

return (
<>
<Box inline mx={1}>
{amount === 0 && 'Cart is empty'}
{amount === 1 && '1 item'}
{amount >= 2 && amount + ' items'}{' '}
{total > 0 && `(${formatMoney(total)} cr)`}
</Box>

<Button
disabled={!canClear}
icon="times"
color="transparent"
onClick={() => act('clear')}
>
Clear
</Button>
</>
);
}
130 changes: 130 additions & 0 deletions tgui/packages/tgui/interfaces/Cargo/CargoCart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import { useBackend } from '../../backend';
import {
Button,
Icon,
Input,
NoticeBox,
RestrictedInput,
Section,
Stack,
Table,
} from '../../components';
import { formatMoney } from '../../format';
import { CargoCartButtons } from './CargoButtons';
import { CargoData } from './types';

export function CargoCart(props) {
const { act, data } = useBackend<CargoData>();
const { requestonly, away, cart = [], docked, location } = data;

const sendable = !away && !!docked;

return (
<Stack fill vertical>
<Stack.Item grow>
<Section fill scrollable title="Cart" buttons={<CargoCartButtons />}>
<CheckoutItems />
</Section>
</Stack.Item>
<Stack.Item>
{cart.length > 0 && !requestonly && (
<Section align="right">
<Stack fill align="center">
<Stack.Item grow>
{!sendable && <Icon color="blue" name="toolbox" spin />}
</Stack.Item>
<Stack.Item>
<Button
color="green"
disabled={!sendable}
onClick={() => act('send')}
px={2}
py={1}
tooltip={sendable ? '' : `Shuttle is at ${location}`}
>
Confirm the order
</Button>
</Stack.Item>
</Stack>
</Section>
)}
</Stack.Item>
</Stack>
);
}

function CheckoutItems(props) {
const { act, data } = useBackend<CargoData>();
const { amount_by_name, can_send, cart = [], max_order } = data;

if (cart.length === 0) {
return <NoticeBox>Nothing in cart</NoticeBox>;
}

return (
<Table>
<Table.Row header color="gray">
<Table.Cell collapsing>ID</Table.Cell>
<Table.Cell>Supply Type</Table.Cell>
<Table.Cell>Amount</Table.Cell>
<Table.Cell collapsing />
<Table.Cell collapsing textAlign="right">
Cost
</Table.Cell>
</Table.Row>

{cart.map((entry) => (
<Table.Row className="candystripe" key={entry.id}>
<Table.Cell collapsing color="label">
#{entry.id}
</Table.Cell>
<Table.Cell>{entry.object}</Table.Cell>

<Table.Cell width={11}>
{can_send && entry.can_be_cancelled ? (
<RestrictedInput
width={5}
minValue={0}
maxValue={max_order}
value={entry.amount}
onEnter={(e, value) =>
act('modify', {
order_name: entry.object,
amount: value,
})
}
/>
) : (
<Input width="40px" value={entry.amount} disabled />
)}

{!!can_send && !!entry.can_be_cancelled && (
<>
<Button
icon="plus"
disabled={amount_by_name[entry.object] >= max_order}
onClick={() =>
act('add_by_name', { order_name: entry.object })
}
/>
<Button
icon="minus"
onClick={() => act('remove', { order_name: entry.object })}
/>
</>
)}
</Table.Cell>

<Table.Cell collapsing color="average">
{!!entry.paid && <b>[Private x {entry.paid}]</b>}
{!!entry.dep_order && <b>[Department x {entry.dep_order}]</b>}
</Table.Cell>

<Table.Cell collapsing color="gold" textAlign="right">
{formatMoney(entry.cost)} {entry.cost_type}
</Table.Cell>
</Table.Row>
))}
</Table>
);
}
Loading

0 comments on commit 3010052

Please sign in to comment.