-
Notifications
You must be signed in to change notification settings - Fork 99
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Re-add crew manifest, language menu, and tracked playtime TGUI interf…
…aces (#2530)
- Loading branch information
Showing
3 changed files
with
324 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,98 @@ | ||
import { classes } from 'common/react'; | ||
|
||
import { useBackend } from '../backend'; | ||
import { Icon, Section, Table, Tooltip } from '../components'; | ||
import { Window } from '../layouts'; | ||
|
||
const commandJobs = [ | ||
'Head of Personnel', | ||
'Head of Security', | ||
'Chief Engineer', | ||
'Research Director', | ||
'Chief Medical Officer', | ||
]; | ||
|
||
export const CrewManifest = (props) => { | ||
const { | ||
data: { manifest, positions }, | ||
} = useBackend(); | ||
|
||
return ( | ||
<Window | ||
title="Souls of the Wasteland" | ||
width={350} | ||
height={500} | ||
theme="mojavesun" | ||
> | ||
<Window.Content scrollable> | ||
{Object.entries(manifest).map(([dept, crew]) => ( | ||
<Section | ||
className={'CrewManifest--' + dept} | ||
key={dept} | ||
title={ | ||
dept + | ||
(dept !== 'Misc' | ||
? ` (${positions[dept].open} positions open)` | ||
: '') | ||
} | ||
> | ||
<Table> | ||
{Object.entries(crew).map(([crewIndex, crewMember]) => ( | ||
<Table.Row key={crewIndex}> | ||
<Table.Cell className={'CrewManifest__Cell'}> | ||
{crewMember.name} | ||
</Table.Cell> | ||
<Table.Cell | ||
className={classes([ | ||
'CrewManifest__Cell', | ||
'CrewManifest__Icons', | ||
])} | ||
collapsing | ||
> | ||
{positions[dept].exceptions.includes(crewMember.rank) && ( | ||
<Tooltip content="No position limit" position="bottom"> | ||
<Icon className="CrewManifest__Icon" name="infinity" /> | ||
</Tooltip> | ||
)} | ||
{crewMember.rank === 'Captain' && ( | ||
<Tooltip content="Captain" position="bottom"> | ||
<Icon | ||
className={classes([ | ||
'CrewManifest__Icon', | ||
'CrewManifest__Icon--Command', | ||
])} | ||
name="star" | ||
/> | ||
</Tooltip> | ||
)} | ||
{commandJobs.includes(crewMember.rank) && ( | ||
<Tooltip content="Member of command" position="bottom"> | ||
<Icon | ||
className={classes([ | ||
'CrewManifest__Icon', | ||
'CrewManifest__Icon--Command', | ||
'CrewManifest__Icon--Chevron', | ||
])} | ||
name="chevron-up" | ||
/> | ||
</Tooltip> | ||
)} | ||
</Table.Cell> | ||
<Table.Cell | ||
className={classes([ | ||
'CrewManifest__Cell', | ||
'CrewManifest__Cell--Rank', | ||
])} | ||
collapsing | ||
> | ||
{crewMember.rank} | ||
</Table.Cell> | ||
</Table.Row> | ||
))} | ||
</Table> | ||
</Section> | ||
))} | ||
</Window.Content> | ||
</Window> | ||
); | ||
}; |
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,111 @@ | ||
import { useBackend } from '../backend'; | ||
import { Button, LabeledList, Section } from '../components'; | ||
import { Window } from '../layouts'; | ||
|
||
export const LanguageMenu = (props) => { | ||
const { act, data } = useBackend(); | ||
const { | ||
admin_mode, | ||
is_living, | ||
omnitongue, | ||
languages = [], | ||
unknown_languages = [], | ||
} = data; | ||
return ( | ||
<Window title="Language Menu" width={700} height={600}> | ||
<Window.Content scrollable> | ||
<Section title="Known Languages"> | ||
<LabeledList> | ||
{languages.map((language) => ( | ||
<LabeledList.Item | ||
key={language.name} | ||
label={language.name} | ||
buttons={ | ||
<> | ||
{!!is_living && ( | ||
<Button | ||
content={ | ||
language.is_default | ||
? 'Default Language' | ||
: 'Select as Default' | ||
} | ||
disabled={!language.can_speak} | ||
selected={language.is_default} | ||
onClick={() => | ||
act('select_default', { | ||
language_name: language.name, | ||
}) | ||
} | ||
/> | ||
)} | ||
{!!admin_mode && ( | ||
<> | ||
<Button | ||
content="Grant" | ||
onClick={() => | ||
act('grant_language', { | ||
language_name: language.name, | ||
}) | ||
} | ||
/> | ||
<Button | ||
content="Remove" | ||
onClick={() => | ||
act('remove_language', { | ||
language_name: language.name, | ||
}) | ||
} | ||
/> | ||
</> | ||
)} | ||
</> | ||
} | ||
> | ||
{language.desc} Key: ,{language.key}{' '} | ||
{language.can_understand | ||
? 'Can understand.' | ||
: 'Cannot understand.'}{' '} | ||
{language.can_speak ? 'Can speak.' : 'Cannot speak.'} | ||
</LabeledList.Item> | ||
))} | ||
</LabeledList> | ||
</Section> | ||
{!!admin_mode && ( | ||
<Section | ||
title="Unknown Languages" | ||
buttons={ | ||
<Button | ||
content={'Omnitongue ' + (omnitongue ? 'Enabled' : 'Disabled')} | ||
selected={omnitongue} | ||
onClick={() => act('toggle_omnitongue')} | ||
/> | ||
} | ||
> | ||
<LabeledList> | ||
{unknown_languages.map((language) => ( | ||
<LabeledList.Item | ||
key={language.name} | ||
label={language.name} | ||
buttons={ | ||
<Button | ||
content="Grant" | ||
onClick={() => | ||
act('grant_language', { | ||
language_name: language.name, | ||
}) | ||
} | ||
/> | ||
} | ||
> | ||
{language.desc} Key: ,{language.key}{' '} | ||
{!!language.shadow && '(gained from mob)'}{' '} | ||
{language.can_speak ? 'Can speak.' : 'Cannot speak.'} | ||
</LabeledList.Item> | ||
))} | ||
</LabeledList> | ||
</Section> | ||
)} | ||
</Window.Content> | ||
</Window> | ||
); | ||
}; |
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,115 @@ | ||
import { sortBy } from 'common/collections'; | ||
|
||
import { useBackend } from '../backend'; | ||
import { Box, Button, Flex, ProgressBar, Section, Table } from '../components'; | ||
import { Window } from '../layouts'; | ||
|
||
const JOB_REPORT_MENU_FAIL_REASON_TRACKING_DISABLED = 1; | ||
const JOB_REPORT_MENU_FAIL_REASON_NO_RECORDS = 2; | ||
|
||
const sortByPlaytime = sortBy(([_, playtime]) => -playtime); | ||
|
||
const PlaytimeSection = (props) => { | ||
const { playtimes } = props; | ||
|
||
const sortedPlaytimes = sortByPlaytime(Object.entries(playtimes)).filter( | ||
(entry) => entry[1], | ||
); | ||
|
||
if (!sortedPlaytimes.length) { | ||
return 'No recorded playtime hours for this section.'; | ||
} | ||
|
||
const mostPlayed = sortedPlaytimes[0][1]; | ||
return ( | ||
<Table> | ||
{sortedPlaytimes.map(([jobName, playtime]) => { | ||
const ratio = playtime / mostPlayed; | ||
return ( | ||
<Table.Row key={jobName}> | ||
<Table.Cell | ||
collapsing | ||
p={0.5} | ||
style={{ | ||
'vertical-align': 'middle', | ||
}} | ||
> | ||
<Box align="right">{jobName}</Box> | ||
</Table.Cell> | ||
<Table.Cell> | ||
<ProgressBar maxValue={mostPlayed} value={playtime}> | ||
<Flex> | ||
<Flex.Item width={`${ratio * 100}%`} /> | ||
<Flex.Item> | ||
{(playtime / 60).toLocaleString(undefined, { | ||
minimumFractionDigits: 1, | ||
maximumFractionDigits: 1, | ||
})} | ||
h | ||
</Flex.Item> | ||
</Flex> | ||
</ProgressBar> | ||
</Table.Cell> | ||
</Table.Row> | ||
); | ||
})} | ||
</Table> | ||
); | ||
}; | ||
|
||
export const TrackedPlaytime = (props) => { | ||
const { act, data } = useBackend(); | ||
const { | ||
failReason, | ||
jobPlaytimes, | ||
specialPlaytimes, | ||
exemptStatus, | ||
isAdmin, | ||
livingTime, | ||
ghostTime, | ||
adminTime, | ||
} = data; | ||
return ( | ||
<Window title="Tracked Playtime" width={550} height={650}> | ||
<Window.Content scrollable> | ||
{(failReason && | ||
((failReason === JOB_REPORT_MENU_FAIL_REASON_TRACKING_DISABLED && ( | ||
<Box>This server has disabled tracking.</Box> | ||
)) || | ||
(failReason === JOB_REPORT_MENU_FAIL_REASON_NO_RECORDS && ( | ||
<Box>You have no records.</Box> | ||
)))) || ( | ||
<Box> | ||
<Section title="Total"> | ||
<PlaytimeSection | ||
playtimes={{ | ||
Ghost: ghostTime, | ||
Living: livingTime, | ||
Admin: adminTime, | ||
}} | ||
/> | ||
</Section> | ||
<Section | ||
title="Jobs" | ||
buttons={ | ||
!!isAdmin && ( | ||
<Button.Checkbox | ||
checked={!!exemptStatus} | ||
onClick={() => act('toggle_exempt')} | ||
> | ||
Job Playtime Exempt | ||
</Button.Checkbox> | ||
) | ||
} | ||
> | ||
<PlaytimeSection playtimes={jobPlaytimes} /> | ||
</Section> | ||
<Section title="Special"> | ||
<PlaytimeSection playtimes={specialPlaytimes} /> | ||
</Section> | ||
</Box> | ||
)} | ||
</Window.Content> | ||
</Window> | ||
); | ||
}; |