-
Notifications
You must be signed in to change notification settings - Fork 67
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[MIRROR] [no gbp] Fixes cargo express console (#2145)
* [no gbp] Fixes cargo express console (#82843) Cargo express console does not send amounts by name Fixed and touched up the express console a bit ![Screenshot 2024-04-22 195254](https://github.com/tgstation/tgstation/assets/42397676/c099cdc0-6b4d-4348-9b5b-f9d4cc325d0b) Bug fix (no issue yet) :cl: fix: Cargo express console fixed: No more bluescreen /:cl: * [no gbp] Fixes cargo express console --------- Co-authored-by: Jeremiah <[email protected]> Co-authored-by: Mal <[email protected]>
- Loading branch information
1 parent
df3285b
commit d7089ca
Showing
2 changed files
with
296 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,238 @@ | ||
import { sortBy } from 'common/collections'; | ||
import { useMemo } from 'react'; | ||
|
||
import { useBackend, useSharedState } from '../../backend'; | ||
import { | ||
Button, | ||
Icon, | ||
Input, | ||
Section, | ||
Stack, | ||
Table, | ||
Tabs, | ||
Tooltip, | ||
} from '../../components'; | ||
import { formatMoney } from '../../format'; | ||
import { CargoCartButtons } from './CargoButtons'; | ||
import { searchForSupplies } from './helpers'; | ||
import { CargoData, Supply, SupplyCategory } from './types'; | ||
|
||
type Props = { | ||
express?: boolean; | ||
}; | ||
|
||
export function CargoCatalog(props: Props) { | ||
const { express } = props; | ||
const { act, data } = useBackend<CargoData>(); | ||
const { self_paid } = data; | ||
|
||
const supplies = Object.values(data.supplies); | ||
|
||
const [activeSupplyName, setActiveSupplyName] = useSharedState( | ||
'supply', | ||
supplies[0]?.name, | ||
); | ||
|
||
const [searchText, setSearchText] = useSharedState('search_text', ''); | ||
|
||
const packs = useMemo(() => { | ||
let fetched: Supply[] | undefined; | ||
|
||
if (activeSupplyName === 'search_results') { | ||
fetched = searchForSupplies(supplies, searchText); | ||
} else { | ||
fetched = supplies.find( | ||
(supply) => supply.name === activeSupplyName, | ||
)?.packs; | ||
} | ||
|
||
if (!fetched) return []; | ||
|
||
fetched = sortBy(fetched, (pack: Supply) => pack.name); | ||
|
||
return fetched; | ||
}, [activeSupplyName, supplies, searchText]); | ||
|
||
return ( | ||
<Section | ||
fill | ||
title="Catalog" | ||
buttons={ | ||
!express && ( | ||
<> | ||
<CargoCartButtons /> | ||
<Button | ||
color={self_paid ? 'caution' : 'transparent'} | ||
icon={self_paid ? 'check-square-o' : 'square-o'} | ||
ml={2} | ||
onClick={() => act('toggleprivate')} | ||
tooltip="Use your own funds to purchase items." | ||
> | ||
Buy Privately | ||
</Button> | ||
</> | ||
) | ||
} | ||
> | ||
<Stack fill> | ||
<Stack.Item grow> | ||
<CatalogTabs | ||
activeSupplyName={activeSupplyName} | ||
categories={supplies} | ||
searchText={searchText} | ||
setActiveSupplyName={setActiveSupplyName} | ||
setSearchText={setSearchText} | ||
/> | ||
</Stack.Item> | ||
<Stack.Divider /> | ||
<Stack.Item grow={express ? 2 : 3}> | ||
<CatalogList packs={packs} /> | ||
</Stack.Item> | ||
</Stack> | ||
</Section> | ||
); | ||
} | ||
|
||
type CatalogTabsProps = { | ||
activeSupplyName: string; | ||
categories: SupplyCategory[]; | ||
searchText: string; | ||
setActiveSupplyName: (name: string) => void; | ||
setSearchText: (text: string) => void; | ||
}; | ||
|
||
function CatalogTabs(props: CatalogTabsProps) { | ||
const { | ||
activeSupplyName, | ||
categories, | ||
searchText, | ||
setActiveSupplyName, | ||
setSearchText, | ||
} = props; | ||
|
||
const sorted = sortBy(categories, (supply) => supply.name); | ||
|
||
return ( | ||
<Tabs vertical> | ||
<Tabs.Tab | ||
key="search_results" | ||
selected={activeSupplyName === 'search_results'} | ||
> | ||
<Stack align="center"> | ||
<Stack.Item> | ||
<Icon name="search" /> | ||
</Stack.Item> | ||
<Stack.Item grow> | ||
<Input | ||
fluid | ||
placeholder="Search..." | ||
value={searchText} | ||
onInput={(e, value) => { | ||
if (value === searchText) { | ||
return; | ||
} | ||
|
||
if (value.length) { | ||
// Start showing results | ||
setActiveSupplyName('search_results'); | ||
} else if (activeSupplyName === 'search_results') { | ||
// return to normal category | ||
setActiveSupplyName(sorted[0]?.name); | ||
} | ||
setSearchText(value); | ||
}} | ||
/> | ||
</Stack.Item> | ||
</Stack> | ||
</Tabs.Tab> | ||
|
||
{sorted.map((supply) => ( | ||
<Tabs.Tab | ||
className="candystripe" | ||
color={supply.name === activeSupplyName ? 'green' : undefined} | ||
key={supply.name} | ||
selected={supply.name === activeSupplyName} | ||
onClick={() => { | ||
setActiveSupplyName(supply.name); | ||
setSearchText(''); | ||
}} | ||
> | ||
<div style={{ display: 'flex', justifyContent: 'space-between' }}> | ||
<span>{supply.name}</span> | ||
<span> {supply.packs.length}</span> | ||
</div> | ||
</Tabs.Tab> | ||
))} | ||
</Tabs> | ||
); | ||
} | ||
|
||
type CatalogListProps = { | ||
packs: SupplyCategory['packs']; | ||
}; | ||
|
||
function CatalogList(props: CatalogListProps) { | ||
const { act, data } = useBackend<CargoData>(); | ||
const { amount_by_name = {}, max_order, self_paid, app_cost } = data; | ||
const { packs = [] } = props; | ||
|
||
return ( | ||
<Section fill scrollable> | ||
<Table> | ||
{packs.map((pack) => { | ||
let color = ''; | ||
const digits = Math.floor(Math.log10(pack.cost) + 1); | ||
if (self_paid) { | ||
color = 'caution'; | ||
} else if (digits >= 5 && digits <= 6) { | ||
color = 'yellow'; | ||
} else if (digits > 6) { | ||
color = 'bad'; | ||
} | ||
|
||
return ( | ||
<Table.Row key={pack.name} className="candystripe"> | ||
<Table.Cell color="label">{pack.name}</Table.Cell> | ||
<Table.Cell collapsing> | ||
{!!pack.small_item && ( | ||
<Tooltip content="Small Item"> | ||
<Icon color="purple" name="compress-alt" /> | ||
</Tooltip> | ||
)} | ||
</Table.Cell> | ||
<Table.Cell collapsing> | ||
{!!pack.access && ( | ||
<Tooltip content="Restricted"> | ||
<Icon color="average" name="lock" /> | ||
</Tooltip> | ||
)} | ||
</Table.Cell> | ||
<Table.Cell collapsing textAlign="right"> | ||
<Button | ||
color={color} | ||
tooltip={pack.desc} | ||
tooltipPosition="left" | ||
disabled={(amount_by_name[pack.name] || 0) >= max_order} | ||
onClick={() => | ||
act('add', { | ||
id: pack.id, | ||
}) | ||
} | ||
minWidth={5} | ||
mb={0.5} | ||
> | ||
{formatMoney( | ||
(self_paid && !pack.goody) || app_cost | ||
? Math.round(pack.cost * 1.1) | ||
: pack.cost, | ||
)}{' '} | ||
cr | ||
</Button> | ||
</Table.Cell> | ||
</Table.Row> | ||
); | ||
})} | ||
</Table> | ||
</Section> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import { BooleanLike } from 'common/react'; | ||
|
||
export type CargoData = { | ||
amount_by_name: Record<string, number> | undefined; | ||
app_cost?: number; | ||
away: BooleanLike; | ||
can_approve_requests: BooleanLike; | ||
can_send: BooleanLike; | ||
cart: CartEntry[]; | ||
department: string; | ||
docked: BooleanLike; | ||
grocery: number; | ||
loan_dispatched: BooleanLike; | ||
loan: BooleanLike; | ||
location: string; | ||
max_order: number; | ||
message: string; | ||
points: number; | ||
requests: Request[]; | ||
requestonly: BooleanLike; | ||
self_paid: BooleanLike; | ||
supplies: Record<string, SupplyCategory>; | ||
}; | ||
|
||
export type SupplyCategory = { | ||
name: string; | ||
packs: Supply[]; | ||
}; | ||
|
||
export type Supply = { | ||
access: BooleanLike; | ||
cost: number; | ||
desc: string; | ||
goody: BooleanLike; | ||
id: string; | ||
name: string; | ||
small_item: BooleanLike; | ||
}; | ||
|
||
type CartEntry = { | ||
amount: number; | ||
can_be_cancelled: BooleanLike; | ||
cost_type: string; | ||
cost: number; | ||
dep_order: BooleanLike; | ||
id: string; | ||
object: string; | ||
orderer: string; | ||
paid: BooleanLike; | ||
}; | ||
|
||
type Request = { | ||
cost: number; | ||
id: string; | ||
object: string; | ||
orderer: string; | ||
reason: string; | ||
}; |