better medical records

This commit is contained in:
Contrabang
2022-12-02 23:33:52 -05:00
parent 658a632c44
commit 095525dc19
12 changed files with 356 additions and 170 deletions
+1
View File
@@ -39,6 +39,7 @@ GLOBAL_LIST_INIT(diseases, subtypesof(/datum/disease))
var/spread_flags = AIRBORNE
//Fluff
var/medical_name // Used for identification of viruses in the Medical Records Virus Database
var/form = "Virus"
var/name = "No disease"
var/desc = ""
+1
View File
@@ -1,5 +1,6 @@
/datum/disease/cold9
name = "The Cold"
medical_name = "ICE9 Cold"
max_stages = 3
spread_text = "On contact"
spread_flags = CONTACT_GENERAL
+1
View File
@@ -48,6 +48,7 @@
/datum/disease/kingstons_advanced //this used to be directly a subtype of kingstons, which sounds nice, but it ment that it would *turn you into a tarjaran always and have normal kingstons stage act* Don't make virusus subtypes unless the base virus does nothing.
name = "Advanced Kingstons Syndrome"
medical_name = "Advanced Kingstons Syndrome"
max_stages = 4
spread_text = "Airborne"
cure_text = "Plasma"
+22 -6
View File
@@ -78,7 +78,7 @@
/obj/machinery/computer/med_data/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "MedicalRecords", "Medical Records", 800, 380, master_ui, state)
ui = new(user, src, ui_key, "MedicalRecords", "Medical Records", 800, 800, master_ui, state)
ui.open()
ui.set_autoupdate(FALSE)
@@ -96,7 +96,13 @@
var/list/records = list()
data["records"] = records
for(var/datum/data/record/R in sortRecord(GLOB.data_core.general))
records[++records.len] = list("ref" = "\ref[R]", "id" = R.fields["id"], "name" = R.fields["name"])
records[++records.len] = list(
"ref" = "\ref[R]",
"name" = R.fields["name"],
"id" = R.fields["id"],
"rank" = R.fields["rank"],
"p_stat" = R.fields["p_stat"],
"m_stat" = R.fields["m_stat"])
if(MED_DATA_RECORD)
var/list/general = list()
data["general"] = general
@@ -127,14 +133,14 @@
fields[++fields.len] = MED_FIELD("Blood Type", active2.fields["blood_type"], "blood_type", FALSE)
fields[++fields.len] = MED_FIELD("DNA", active2.fields["b_dna"], "b_dna", TRUE)
fields[++fields.len] = MED_FIELD("Minor Disabilities", active2.fields["mi_dis"], "mi_dis", FALSE)
fields[++fields.len] = MED_FIELD("Details", active2.fields["mi_dis_d"], "mi_dis_d", TRUE)
fields[++fields.len] = MED_FIELD("Details", active2.fields["mi_dis_d"], "mi_dis_d", FALSE)
fields[++fields.len] = MED_FIELD("Major Disabilities", active2.fields["ma_dis"], "ma_dis", FALSE)
fields[++fields.len] = MED_FIELD("Details", active2.fields["ma_dis_d"], "ma_dis_d", TRUE)
fields[++fields.len] = MED_FIELD("Allergies", active2.fields["alg"], "alg", FALSE)
fields[++fields.len] = MED_FIELD("Details", active2.fields["alg_d"], "alg_d", TRUE)
fields[++fields.len] = MED_FIELD("Details", active2.fields["alg_d"], "alg_d", FALSE)
fields[++fields.len] = MED_FIELD("Current Diseases", active2.fields["cdi"], "cdi", FALSE)
fields[++fields.len] = MED_FIELD("Details", active2.fields["cdi_d"], "cdi_d", TRUE)
fields[++fields.len] = MED_FIELD("Important Notes", active2.fields["notes"], "notes", TRUE)
fields[++fields.len] = MED_FIELD("Important Notes", active2.fields["notes"], "notes", FALSE)
if(!active2.fields["comments"] || !islist(active2.fields["comments"]))
active2.fields["comments"] = list()
medical["comments"] = active2.fields["comments"]
@@ -149,7 +155,15 @@
continue
if(!DS.desc)
continue
data["virus"] += list(list("name" = DS.name, "D" = D))
if(DS.medical_name)
DS.name = "[DS.medical_name] ([DS.name])"
var/list/payload = list(
"name" = DS.name,
"max_stages" = "[DS.max_stages]", // This needs to be a string for sorting
"severity" = DS.severity,
"D" = D)
data["virus"] += list(payload)
qdel(DS)
if(MED_DATA_MEDBOT)
data["medbots"] = list()
for(var/mob/living/simple_animal/bot/medbot/M in GLOB.bots_list)
@@ -214,6 +228,8 @@
return
var/datum/disease/D = new type(0)
if(D.medical_name)
D.name = "[D.medical_name] ([D.name])"
var/list/payload = list(
name = D.name,
max_stages = D.max_stages,
@@ -16,6 +16,7 @@ import { TableCell } from '../components/Table';
import { Window } from '../layouts';
import { LoginInfo } from './common/LoginInfo';
import { LoginScreen } from './common/LoginScreen';
import { SortButton } from './common/SortButton';
export const AccountsUplinkTerminal = (properties, context) => {
const { act, data } = useBackend(context);
@@ -173,33 +174,6 @@ const DepartmentAccountsList = (properties, context) => {
);
};
const SortButton = (properties, context) => {
const [sortId, setSortId] = useLocalState(context, 'sortId', 'name');
const [sortOrder, setSortOrder] = useLocalState(context, 'sortOrder', true);
const { id, children } = properties;
return (
<Table.Cell>
<Button
color={sortId !== id && 'transparent'}
width="100%"
onClick={() => {
if (sortId === id) {
setSortOrder(!sortOrder);
} else {
setSortId(id);
setSortOrder(true);
}
}}
>
{children}
{sortId === id && (
<Icon name={sortOrder ? 'sort-up' : 'sort-down'} ml="0.25rem;" />
)}
</Button>
</Table.Cell>
);
};
const AccountsActions = (properties, context) => {
const { act, data } = useBackend(context);
const { is_printing } = data;
+249 -106
View File
@@ -1,31 +1,42 @@
import { createSearch } from 'common/string';
import { Fragment } from 'inferno';
import { useBackend } from '../backend';
import { useBackend, useLocalState } from '../backend';
import {
Box,
Button,
Collapsible,
Icon,
Input,
LabeledList,
Section,
Tabs,
Flex,
Table
} from '../components';
import {
ComplexModal,
modalOpen,
modalRegisterBodyOverride,
} from '../interfaces/common/ComplexModal';
import { FlexItem } from '../components/Flex';
import { Window } from '../layouts';
import { LoginInfo } from './common/LoginInfo';
import { LoginScreen } from './common/LoginScreen';
import { TemporaryNotice } from './common/TemporaryNotice';
import { SortButton } from './common/SortButton';
const severities = {
'Minor': 'good',
'Medium': 'average',
'Minor': 'lightgray',
'Medium': 'good',
'Harmful': 'average',
'Dangerous!': 'bad',
'Harmful': 'bad',
'BIOHAZARD THREAT!': 'bad',
'BIOHAZARD THREAT!': 'darkred',
};
const medStatusStyles = {
'*Deceased*': 'deceased',
'*SSD*': 'ssd',
'Physically Unfit': 'physically_unfit',
'Disabled': 'disabled',
};
const doEdit = (context, field) => {
@@ -109,27 +120,77 @@ export const MedicalRecords = (_properties, context) => {
const MedicalRecordsList = (_properties, context) => {
const { act, data } = useBackend(context);
const { records } = data;
const [searchText, setSearchText] = useLocalState(context, 'searchText', '');
const [sortId, _setSortId] = useLocalState(context, 'sortId', 'name');
const [sortOrder, _setSortOrder] = useLocalState(context, 'sortOrder', true);
return (
<Fragment>
<Input
fluid
placeholder="Search by Name, DNA, or ID"
onChange={(_event, value) => act('search', { t1: value })}
/>
<Box mt="0.5rem">
{records.map((record, i) => (
<Fragment key={i}>
<Button
icon="user"
mb="0.5rem"
content={record.id + ': ' + record.name}
onClick={() => act('d_rec', { d_rec: record.ref })}
/>
<br />
</Fragment>
))}
</Box>
</Fragment>
<Flex direction="column" height="100%">
<Flex>
<FlexItem>
<Button
content="Manage Records"
icon="wrench"
ml="0.25rem"
onClick={() => act('screen', { screen: 3 })}
/>
</FlexItem>
<FlexItem grow="1" ml="0.5rem">
<Input
placeholder="Search by Name, ID, Physical Status, or Mental Status"
width="100%"
onInput={(e, value) => setSearchText(value)}
/>
</FlexItem>
</Flex>
<Section flexGrow="1" mt="0.5rem">
<Table className="MedicalRecords__list">
<Table.Row bold>
<SortButton id="name">Name</SortButton>
<SortButton id="id">ID</SortButton>
<SortButton id="rank">Assignment</SortButton>
<SortButton id="p_stat">Patient Status</SortButton>
<SortButton id="m_stat">Mental Status</SortButton>
</Table.Row>
{records
.filter(
createSearch(searchText, (record) => {
return (
record.name +
'|' +
record.id +
'|' +
record.rank +
'|' +
record.p_stat +
'|' +
record.m_stat
);
})
)
.sort((a, b) => {
const i = sortOrder ? 1 : -1;
return a[sortId].localeCompare(b[sortId]) * i;
})
.map((record) => (
<Table.Row
key={record.id}
className={
'MedicalRecords__listRow--' + medStatusStyles[record.p_stat]
}
onClick={() => act('d_rec', { d_rec: record.ref })}
>
<Table.Cell>
<Icon name="user" /> {record.name}
</Table.Cell>
<Table.Cell>{record.id}</Table.Cell>
<Table.Cell>{record.rank}</Table.Cell>
<Table.Cell>{record.p_stat}</Table.Cell>
<Table.Cell>{record.m_stat}</Table.Cell>
</Table.Row>
))}
</Table>
</Section>
</Flex>
);
};
@@ -160,36 +221,35 @@ const MedicalRecordsView = (_properties, context) => {
const { medical, printing } = data;
return (
<Fragment>
<Section title="General Data" level={2} mt="-6px">
<Section
title="General Data"
level={2}
mt="-6px"
buttons={
<Button
icon={printing ? 'spinner' : 'print'}
disabled={printing}
iconSpin={!!printing}
content="Print Entry"
ml="0.5rem"
onClick={() => act('print_p')}
/>
}>
<MedicalRecordsViewGeneral />
</Section>
<Section title="Medical Data" level={2}>
<Section
title="Medical Data"
level={2}
buttons={
<Button.Confirm
icon="trash"
disabled={!!medical.empty}
content="Delete Medical Record"
onClick={() => act('del_r')}
/>
}>
<MedicalRecordsViewMedical />
</Section>
<Section title="Actions" level={2}>
<Button.Confirm
icon="trash"
disabled={!!medical.empty}
content="Delete Medical Record"
color="bad"
onClick={() => act('del_r')}
/>
<Button
icon={printing ? 'spinner' : 'print'}
disabled={printing}
iconSpin={!!printing}
content="Print Entry"
ml="0.5rem"
onClick={() => act('print_p')}
/>
<br />
<Button
icon="arrow-left"
content="Back"
mt="0.5rem"
onClick={() => act('screen', { screen: 2 })}
/>
</Section>
</Fragment>
);
};
@@ -277,7 +337,16 @@ const MedicalRecordsViewMedical = (_properties, context) => {
</LabeledList.Item>
))}
</LabeledList>
<Section title="Comments/Log" level={2}>
<Section
title="Comments/Log"
level={2}
buttons={
<Button
icon="comment"
content="Add Entry"
onClick={() => modalOpen(context, 'add_c')}
/>
}>
{medical.comments.length === 0 ? (
<Box color="label">No comments found.</Box>
) : (
@@ -297,15 +366,6 @@ const MedicalRecordsViewMedical = (_properties, context) => {
</Box>
))
)}
<Button
icon="comment-medical"
content="Add Entry"
color="good"
mt="0.5rem"
mb="0"
onClick={() => modalOpen(context, 'add_c')}
/>
</Section>
</Fragment>
);
@@ -314,59 +374,134 @@ const MedicalRecordsViewMedical = (_properties, context) => {
const MedicalRecordsViruses = (_properties, context) => {
const { act, data } = useBackend(context);
const { virus } = data;
virus.sort((a, b) => (a.name > b.name ? 1 : -1));
return virus.map((vir, i) => (
<Fragment key={i}>
<Button
icon="flask"
content={vir.name}
mb="0.5rem"
onClick={() => act('vir', { vir: vir.D })}
/>
<br />
</Fragment>
));
const [searchText, setSearchText] = useLocalState(context, 'searchText', '');
const [sortId, _setSortId] = useLocalState(context, 'sortId', 'name');
const [sortOrder, _setSortOrder] = useLocalState(context, 'sortOrder', true);
return(
<Flex direction="column" height="100%">
<Flex>
<FlexItem grow="1" ml="0.5rem">
<Input
placeholder="Search by Name, Max Stages, or Severity"
width="100%"
onInput={(e, value) => setSearchText(value)}
/>
</FlexItem>
</Flex>
<Section flexGrow="1" mt="0.5rem">
<Table className="MedicalRecords__list">
<Table.Row bold>
<SortButton id="name">Name</SortButton>
<SortButton id="max_stages">Max Stages</SortButton>
<SortButton id="severity">Severity</SortButton>
</Table.Row>
{virus
.filter(
createSearch(searchText, (vir) => {
return (
vir.name +
'|' +
vir.max_stages +
'|' +
vir.severity
);
})
)
.sort((a, b) => {
const i = sortOrder ? 1 : -1;
return a[sortId].localeCompare(b[sortId]) * i;
})
.map((vir) => (
<Table.Row
key={vir.id}
className={
'MedicalRecords__listVirus--' + vir.severity
}
onClick={() => act('vir', { vir: vir.D })}
>
<Table.Cell>
<Icon name="virus" /> {vir.name}
</Table.Cell>
<Table.Cell>{vir.max_stages}</Table.Cell>
<Table.Cell
color = {severities[vir.severity]}
>
{vir.severity}
</Table.Cell>
</Table.Row>
))}
</Table>
</Section>
</Flex>
)
// virus.sort((a, b) => (a.name > b.name ? 1 : -1));
// // here
// return virus.map((vir, i) => (
// <Fragment key={i}>
// <Button
// icon="flask"
// content={vir.name}
// mb="0.5rem"
// onClick={() => act('vir', { vir: vir.D })}
// />
// <br />
// </Fragment>
// ));
};
const MedicalRecordsMedbots = (_properties, context) => {
const { data } = useBackend(context);
const { act, data } = useBackend(context);
const { medbots } = data;
if (medbots.length === 0) {
return <Box color="label">There are no Medbots.</Box>;
}
return medbots.map((medbot, i) => (
<Collapsible key={i} open title={medbot.name}>
<Box px="0.5rem">
<LabeledList>
<LabeledList.Item label="Location">
{medbot.area || 'Unknown'} ({medbot.x}, {medbot.y})
</LabeledList.Item>
<LabeledList.Item label="Status">
{medbot.on ? (
<Fragment>
<Box color="good">Online</Box>
<Box mt="0.5rem">
return(
<Flex direction="column" height="100%">
<Section flexGrow="1" mt="0.5rem">
<Table className="MedicalRecords__list">
<Table.Row bold>
<Table.Cell>Name</Table.Cell>
<Table.Cell>Area</Table.Cell>
<Table.Cell>Status</Table.Cell>
<Table.Cell>Chemicals</Table.Cell>
</Table.Row>
{medbots
.map((medbot) => (
<Table.Row
key={medbot.id}
className={
'MedicalRecords__listMedbot--' + medbot.on
}
>
<Table.Cell>
<Icon name="medical" /> {medbot.name}
</Table.Cell>
<Table.Cell>{medbot.area || 'Unknown'} ({medbot.x}, {medbot.y})</Table.Cell>
<Table.Cell>{medbot.on ? (
<Box color="good">Online</Box>
) : (
<Box color="average">Offline</Box>
)}
</Table.Cell>
<Table.Cell>
{medbot.use_beaker
? 'Reservoir: ' +
medbot.total_volume +
'/' +
medbot.maximum_volume
: 'Using internal synthesizer.'}
</Box>
</Fragment>
) : (
<Box color="average">Offline</Box>
)}
</LabeledList.Item>
</LabeledList>
</Box>
</Collapsible>
));
: 'Using internal synthesizer'}
</Table.Cell>
</Table.Row>
))}
</Table>
</Section>
</Flex>
);
};
const MedicalRecordsNavigation = (_properties, context) => {
const { act, data } = useBackend(context);
const { screen } = data;
const { screen, general } = data;
return (
<Tabs>
<Tabs.Tab
@@ -390,13 +525,21 @@ const MedicalRecordsNavigation = (_properties, context) => {
<Icon name="plus-square" />
Medbot Tracking
</Tabs.Tab>
<Tabs.Tab
selected={screen === 3}
onClick={() => act('screen', { screen: 3 })}
>
<Icon name="wrench" />
Record Maintenance
</Tabs.Tab>
{screen === 3 && (
<Tabs.Tab
selected={screen === 3}
>
<Icon name="wrench" />
Record Maintenance
</Tabs.Tab>
)}
{screen === 4 && general && !general.empty && (
<Tabs.Tab
selected={screen === 4}>
<Icon name="file" />
Record: {general.fields[0].value}
</Tabs.Tab>
)}
</Tabs>
);
};
@@ -18,6 +18,7 @@ import { ComplexModal, modalOpen } from './common/ComplexModal';
import { LoginInfo } from './common/LoginInfo';
import { LoginScreen } from './common/LoginScreen';
import { TemporaryNotice } from './common/TemporaryNotice';
import { SortButton } from './common/SortButton';
const statusStyles = {
'*Execute*': 'execute',
@@ -161,33 +162,6 @@ const SecurityRecordsPageList = (properties, context) => {
);
};
const SortButton = (properties, context) => {
const [sortId, setSortId] = useLocalState(context, 'sortId', 'name');
const [sortOrder, setSortOrder] = useLocalState(context, 'sortOrder', true);
const { id, children } = properties;
return (
<Table.Cell>
<Button
color={sortId !== id && 'transparent'}
width="100%"
onClick={() => {
if (sortId === id) {
setSortOrder(!sortOrder);
} else {
setSortId(id);
setSortOrder(true);
}
}}
>
{children}
{sortId === id && (
<Icon name={sortOrder ? 'sort-up' : 'sort-down'} ml="0.25rem;" />
)}
</Button>
</Table.Cell>
);
};
const SecurityRecordsActions = (properties, context) => {
const { act, data } = useBackend(context);
const { isPrinting } = data;
@@ -0,0 +1,33 @@
import { useLocalState } from '../../backend';
import {
Button,
Icon,
Table,
} from '../../components';
export const SortButton = (properties, context) => {
const [sortId, setSortId] = useLocalState(context, 'sortId', 'name');
const [sortOrder, setSortOrder] = useLocalState(context, 'sortOrder', true);
const { id, children } = properties;
return (
<Table.Cell>
<Button
color={sortId !== id && 'transparent'}
width="100%"
onClick={() => {
if (sortId === id) {
setSortOrder(!sortOrder);
} else {
setSortId(id);
setSortOrder(true);
}
}}
>
{children}
{sortId === id && (
<Icon name={sortOrder ? 'sort-up' : 'sort-down'} ml="0.25rem;" />
)}
</Button>
</Table.Cell>
);
};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,42 @@
@use '../base.scss';
@use '../colors.scss';
@use '../functions.scss' as *;
.MedicalRecords__list {
tr > td {
text-align: center;
}
tr:not(:first-child) {
height: 24px;
line-height: 24px;
cursor: pointer;
transition: background-color 50ms;
&:hover,
&:focus {
background-color: rgba(base.$color-bg, 1);
}
}
}
.MedicalRecords__listRow--deceased {
background-color: colors.bg(#890e26);
}
.MedicalRecords__listRow--ssd {
background-color: colors.bg(#008091);
}
.MedicalRecords__listRow--physically_unfit {
background-color: colors.bg(#b38f00);
}
.MedicalRecords__listRow--disabled {
background-color: colors.bg(#251496);
}
.MedicalRecords__listMedbot--0 {
background-color: colors.bg(#321717);
}
+1
View File
@@ -55,6 +55,7 @@
@include meta.load-css('./interfaces/Roulette.scss');
@include meta.load-css('./interfaces/Safe.scss');
@include meta.load-css('./interfaces/SecurityRecords.scss');
@include meta.load-css('./interfaces/MedicalRecords.scss');
// Layouts
@include meta.load-css('./layouts/Layout.scss');