halcwb / genpres2 Goto Github PK
View Code? Open in Web Editor NEWEnable Safe and Efficient medication prescription, preparation and administration
Home Page: https://medicatieveiligensnel.nl
License: GNU General Public License v3.0
Enable Safe and Efficient medication prescription, preparation and administration
Home Page: https://medicatieveiligensnel.nl
License: GNU General Public License v3.0
Describe the bug
Example fentanyl is not split by dose type.
Also, take dose unit from qty_adj
When trying to update using paket update, this will move to net7, however, then the build fails.
Restrict the framework to net6 in the paket dependencies to prevent upgrade to net7.
Resolved in: a855b4e.
In a solution when the solvent quantity is zero, i.e. the medication cannot be further diluted. This is a special case that is not handled correctly currently. Need to resolve this.
Currently a multi component drug prescription is displayed like:
3 keer per dag 900 mg amoxicilline + 90 mg clavulaanzuur = 100 mg/kg/dag amoxicilline + 10 mg/kg/dag clavulaanzuur (95 - 110 mg/kg/dag)
Everything on a row. A better view is:
3 keer per dag 900 mg amoxicilline + = 100 mg/kg/dag (95 - 110 mg/kg/dag)
90 mg clavulaanzuur = 10 mg/kg/dag
I think this needs to be a column stack with each column a row stack of typography elements.
See current display code:
[<JSX.Component>]
let View (props:
{|
scenarios: Deferred<Types.ScenarioResult>
updateScenario: Types.ScenarioResult -> unit
selectOrder : (Types.Scenario * Shared.Types.Order option) -> unit
order: Deferred<(bool * string option * Order) option>
loadOrder: (string option * Order) -> unit
updateScenarioOrder : unit -> unit
localizationTerms : Deferred<string [] []>
|}) =
let context = React.useContext(Global.context)
let lang = context.Localization
let isMobile = Mui.Hooks.useMediaQuery "(max-width:1200px)"
let getTerm defVal term =
props.localizationTerms
|> Deferred.map (fun terms ->
Localization.getTerm terms lang term
|> Option.defaultValue defVal
)
|> Deferred.defaultValue defVal
let state, dispatch =
React.useElmish (
init props.order props.scenarios,
update props.scenarios props.updateScenario,
[| box props.order; box props.scenarios; box props.updateScenario; box props.selectOrder |]
)
let modalOpen, setModalOpen = React.useState(false)
let handleModalClose = fun () -> setModalOpen false
let select isLoading lbl selected dispatch xs =
Components.SimpleSelect.View({|
updateSelected = dispatch
label = lbl
selected = selected
values = xs
isLoading = isLoading
|})
let autoComplete isLoading lbl selected dispatch xs =
Components.Autocomplete.View({|
updateSelected = dispatch
label = lbl
selected = selected
values = xs
isLoading = isLoading
|})
let progress =
match props.scenarios with
| Resolved _ -> JSX.jsx $"<></>"
| _ ->
JSX.jsx
$"""
import CircularProgress from '@mui/material/CircularProgress';
<Box sx={ {| mt = 5; display = "flex"; p = 20 |} }>
<CircularProgress />
</Box>
"""
let typoGraphy (items : Types.TextItem[]) =
let print item =
match item with
| Normal s ->
JSX.jsx
$"""
<Typography color={Mui.Colors.Grey.``700``} display="inline">{s}</Typography>
"""
| Bold s ->
JSX.jsx
$"""
<Typography
color={Mui.Colors.BlueGrey.``700``}
display="inline"
>
<strong> {s} </strong>
</Typography>
"""
| Italic s ->
JSX.jsx
$"""
<Typography
color={Mui.Colors.Grey.``700``}
display="inline"
>
<strong> {s} </strong>
</Typography>
"""
JSX.jsx
$"""
import Typography from '@mui/material/Typography';
<Box display="inline" >
{items |> Array.map print |> unbox |> React.fragment}
</Box>
"""
let displayScenario med (sc : Types.Scenario) =
if med |> Option.isNone then JSX.jsx $"""<></>"""
else
let med =
med |> Option.defaultValue ""
|> fun s ->
if s.Contains(sc.Shape) then $"{s} {sc.DoseType}"
else
$"{s} {sc.Shape} {sc.DoseType}"
let ord =
sc.Order
let item icon prim sec =
JSX.jsx
$"""
<ListItem>
<ListItemIcon>
{icon}
</ListItemIcon>
<Box sx={ {| display="flex"; flexDirection="column" |} }>
{prim}
{sec |> typoGraphy}
</Box>
</ListItem>
"""
let content =
JSX.jsx
$"""
<React.Fragment>
<Typography variant="h6" >
{med}
</Typography>
<List sx={ {| width="100%"; maxWidth=800; bgcolor=Mui.Colors.Grey.``50`` |} }>
{
[|
item Mui.Icons.Notes (Terms.``Prescribe Prescription`` |> getTerm "Voorschrift") sc.Prescription
if sc.Preparation |> Array.length > 0 then
item Mui.Icons.Vaccines (Terms.``Prescribe Preparation`` |> getTerm "Bereiding") sc.Preparation
item Mui.Icons.MedicationLiquid (Terms.``Prescribe Administration`` |> getTerm "Toediening") sc.Administration
|]
|> unbox
|> React.fragment
}
</List>
</React.Fragment>
"""
JSX.jsx
$"""
import React from 'react';
import Card from '@mui/material/Card';
import CardActions from '@mui/material/CardActions';
import CardContent from '@mui/material/CardContent';
import Button from '@mui/material/Button';
import Typography from '@mui/material/Typography';
import Box from '@mui/material/Box';
import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import Divider from '@mui/material/Divider';
import ListItemText from '@mui/material/ListItemText';
import ListItemIcon from '@mui/material/ListItemIcon';
import Avatar from '@mui/material/Avatar';
import Typography from '@mui/material/Typography';
<Box sx={ {| mt=3; height="100%" |} } >
<Card sx={ {| minWidth = 275 |} }>
<CardContent>
{content}
{progress}
</CardContent>
<CardActions>
<Button
size="small"
onClick={fun () -> setModalOpen true; (sc, ord) |> props.selectOrder}
>{Terms.Edit |> getTerm "bewerken"}</Button>
</CardActions>
</Card>
</Box>
"""
let stackDirection =
if Mui.Hooks.useMediaQuery "(max-width:900px)" then "column" else "row"
let cards =
JSX.jsx
$"""
import CardContent from '@mui/material/CardContent';
import Typography from '@mui/material/Typography';
import Stack from '@mui/material/Stack';
<React.Fragment>
<Stack direction="column" spacing={3}>
<Typography sx={ {| fontSize=14 |} } color="text.secondary" gutterBottom>
{Terms.``Prescribe Scenarios`` |> getTerm "Medicatie scenario's"}
</Typography>
{
match props.scenarios with
| Resolved scrs -> false, scrs.Indication, scrs.Indications
| _ -> true, None, [||]
|> fun (isLoading, sel, items) ->
let lbl = (Terms.``Prescribe Indications`` |> getTerm "Indicaties")
if isMobile then
items
|> Array.map (fun s -> s, s)
|> select isLoading lbl sel (IndicationChange >> dispatch)
else
items
|> autoComplete isLoading lbl sel (IndicationChange >> dispatch)
}
<Stack direction={stackDirection} spacing={3} >
{
match props.scenarios with
| Resolved scrs -> false, scrs.Medication, scrs.Medications
| _ -> true, None, [||]
|> fun (isLoading, sel, items) ->
let lbl = (Terms.``Prescribe Medications`` |> getTerm "Medicatie")
if isMobile then
items
|> Array.map (fun s -> s, s)
|> select isLoading lbl sel (MedicationChange >> dispatch)
else
items
|> autoComplete isLoading lbl sel (MedicationChange >> dispatch)
}
{
match props.scenarios with
| Resolved scrs -> false, scrs.Route, scrs.Routes
| _ -> true, None, [||]
|> fun (isLoading, sel, items) ->
let lbl = (Terms.``Prescribe Routes`` |> getTerm "Routes")
if isMobile then
items
|> Array.map (fun s -> s, s)
|> select isLoading lbl sel (RouteChange >> dispatch)
else
items
|> autoComplete isLoading lbl sel (RouteChange >> dispatch)
}
{
match props.scenarios with
| Resolved scrs when scrs.Indication.IsSome &&
scrs.Medication.IsSome &&
scrs.Route.IsSome ->
(false, scrs.DoseType, scrs.DoseTypes)
|> fun (isLoading, sel, items) ->
let lbl = "Doseer types"
if isMobile then
items
|> Array.map (fun s -> s, s)
|> select isLoading lbl sel (DoseTypeChange >> dispatch)
else
items
|> autoComplete isLoading lbl sel (DoseTypeChange >> dispatch)
| _ -> JSX.jsx $"<></>"
}
<Box sx={ {| mt=2 |} }>
<Button variant="text" onClick={fun _ -> Clear |> dispatch } fullWidth startIcon={Mui.Icons.Delete} >
{Terms.Delete |> getTerm "Verwijder"}
</Button>
</Box>
</Stack>
<Stack direction="column" >
{
match props.scenarios with
| Resolved sc ->
sc.Medication,
sc.Scenarios
| _ -> None, [||]
|> fun (med, scs) ->
scs
|> Array.map (displayScenario med)
|> unbox |> React.fragment
}
</Stack>
</Stack>
</React.Fragment>
"""
let modalStyle =
{|
position="absolute"
top= "50%"
left= "50%"
transform= "translate(-50%, -50%)"
width= 400
bgcolor= "background.paper"
boxShadow= 24
|}
JSX.jsx
$"""
import Box from '@mui/material/Box';
import Modal from '@mui/material/Modal';
<div>
<Box sx={ {| height="100%" |} }>
{cards}
{progress}
</Box>
<Modal open={modalOpen} onClose={handleModalClose} >
<Box sx={modalStyle}>
{
Order.View {|
order = props.order
loadOrder = props.loadOrder
updateScenarioOrder = props.updateScenarioOrder
closeOrder = handleModalClose
localizationTerms = props.localizationTerms
|}
}
</Box>
</Modal>
</div>
"""
When running in development mode, i.e. use the vite server, png and svg files show up as images, however, when using the docker deployment, running with kestrel, these files are not rendered and sent to the browser as text/plain.
When multiple scenarios have to be calculated, this could be done in parallel in stead of sequential.
Should document special medication scenarios:
Probably a problem with a very large package-lock.json.
I had to:
Still slow, but may should remove all dependencies on MUI v4.
@MrBliz : is this something you can do?
Have to investigate
When a generic and shape is not correctly entered in a doserule, the products can't be found. There needs to be a check on that.
@MrBliz Currently we have some hand copied files for MUI5, but I noticed that in fact a complete port to material UI 5 already has been performed: https://github.com/ArtemyB/Feliz.MaterialUI/. Why not just use that lib?
Also, an even better solution would be to migrate to JSX, see: https://github.com/marcpiechura/JSX-Example. However, not in the current scope due to time limits.
Lists, seqs and arrays should have the same utility functions.
@MrBliz I think you can relatively easy merge the libsupdate branch. A couple of things to beware of:
Then you will have a full blown drug prescription system!
To distinguish between term neonates and preterm neonates but the latter for all preterms, a lower limit of GA should be able of exclusive zero (not shown as age in the printout).
When changing a weight or height, immediately an event is triggered such that if you type in 20, it triggers with "2" and the server responds to a weight of "2", which is not right ofcourse.
@MrBliz Is there a way to delay event triggering to make sure a number is entered completely? I think the right approach is to use a throttling mechanism, see: https://github.com/halcwb/PediatricRiskCalculator/blob/master/src/Client/Components/NumericInput.fs.
using Thoth.Elmish.Debouncer.
Probably there are some fable related libs hanging around that are not used/needed anymore. Need to clean up the solution by removing unnecessary libs.
Need to have a checkbox to signal whether the patient has a central venous line.
When a concentration is for example g/g, this gets simplified as a count. However, for concentrations this is not appropriate. It should still be printed out as g/g.
Maybe solve this in the order variable?
Note: introduce a percentage as a count unit.
Some products are made locally, so do not appear in the Z-index. Need to manually add these products.
When opening the GenPres demo page, the patient view doesn't fit on a mobile.
It seems the url parsing is not working anymore: http://genpres.nl/#pat?pg=el&by=2013&bm=2&bd=15&wt=34000. This should open the patient with age and weight set.
Posoconazol medication as an example. Also, interesting because of interactions.
Headername is now the field name, should be the headername using cards.
There is no patient reload when the patient changes with the relevant drugs.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.