diff --git a/package.json b/package.json
index 12cb0fd33..be4b25594 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "noharm-app",
- "version": "3.1.16",
+ "version": "3.1.17",
"private": true,
"dependencies": {
"@ckeditor/ckeditor5-build-classic": "^35.0.1",
diff --git a/public/index.html b/public/index.html
index 5a304be9f..eef22745e 100644
--- a/public/index.html
+++ b/public/index.html
@@ -99,6 +99,39 @@
+
+
diff --git a/src/components/DrugAlertLevelTag.jsx b/src/components/DrugAlertLevelTag.jsx
new file mode 100644
index 000000000..0b32075a7
--- /dev/null
+++ b/src/components/DrugAlertLevelTag.jsx
@@ -0,0 +1,96 @@
+import React from "react";
+import { useTranslation } from "react-i18next";
+
+import Tooltip from "components/Tooltip";
+import Badge from "components/Badge";
+import Tag from "components/Tag";
+
+export default function DrugAlertLevelTag({
+ levels,
+ count,
+ showDescription = false,
+ allergy = false,
+ onClick = () => {},
+}) {
+ const { t } = useTranslation();
+
+ const getAlertStyle = () => {
+ const defaultColor = {
+ background: "#7ebe9a",
+ borderColor: "#7ebe9a",
+ color: "#fff",
+ };
+
+ if (!levels.length) {
+ return defaultColor;
+ }
+
+ if (levels.indexOf("high") !== -1) {
+ return {
+ background: "#f44336",
+ borderColor: "#f44336",
+ color: "#fff",
+ };
+ }
+
+ if (levels.indexOf("medium") !== -1) {
+ return {
+ background: "#f57f17",
+ borderColor: "#f57f17",
+ color: "#fff",
+ };
+ }
+
+ if (levels.indexOf("low") !== -1) {
+ return {
+ background: "#ffc107",
+ borderColor: "#ffc107",
+ color: "#fff",
+ };
+ }
+ };
+
+ const getAlertDescription = () => {
+ if (!levels.length) {
+ return "-";
+ }
+
+ if (levels.indexOf("high") !== -1) {
+ return "Alto";
+ }
+
+ if (levels.indexOf("medium") !== -1) {
+ return "Médio";
+ }
+
+ if (levels.indexOf("low") !== -1) {
+ return "Baixo";
+ }
+ };
+
+ return (
+
+
+ onClick()}
+ >
+ {showDescription ? getAlertDescription() : count}
+
+
+
+ );
+}
diff --git a/src/components/Forms/ClinicalNotes/util/templates.js b/src/components/Forms/ClinicalNotes/util/templates.js
index 8a22c300e..e56ef08b3 100644
--- a/src/components/Forms/ClinicalNotes/util/templates.js
+++ b/src/components/Forms/ClinicalNotes/util/templates.js
@@ -346,11 +346,11 @@ export const alertsTemplate = (prescription) => {
let alerts = [];
list.forEach((i) => {
- if (i.alerts && i.alerts.length) {
+ if (i.alertsComplete && i.alertsComplete.length) {
const tpl = `
Medicamento: ${i.drug}
Alertas:
- -- ${i.alerts.join("\r\n -- ")}
+ -- ${i.alertsComplete.map((a) => a.text).join("\r\n -- ")}
`;
alerts = [...alerts, tpl];
}
diff --git a/src/components/Layout/index.jsx b/src/components/Layout/index.jsx
index 25d6c5968..f3090bb7a 100644
--- a/src/components/Layout/index.jsx
+++ b/src/components/Layout/index.jsx
@@ -139,6 +139,9 @@ const Me = ({
const ErrorFallback = ({ error, resetErrorBoundary }) => {
console.error(error);
+ if (window.cwr) {
+ window.cwr("recordError", error);
+ }
return (
- {t("alerts.alergy")}
+ {t("drugAlertType.allergy")}
-
- {t("alerts.max_dose")}
+ {t("drugAlertType.maxDose")}
-
-
- {t("alerts.duplicate")}
+
+ {t("drugAlertType.dm")}
-
-
- {t("alerts.exam")}
+
+ {t("drugAlertType.dt")}
-
-
- {t("alerts.y")}
+
+ {t("drugAlertType.liver")}
-
-
- {t("alerts.isl")}
+
+ {t("drugAlertType.iy")}
-
-
- {t("alerts.interaction")}
+
+ {t("drugAlertType.it")}
-
-
- {t("alerts.tube")}
+
+ {t("drugAlertType.ira")}
+
+
+ {t("drugAlertType.sl")}
-
- {t("alerts.elderly")}
+ {t("drugAlertType.elderly")}
+
+
+ {t("drugAlertType.kidney")}
+
+
+ {t("drugAlertType.platelets")}
+
+
+ {t("drugAlertType.rx")}
+
+
+ {t("drugAlertType.tube")}
-
- {t("alerts.time")}
+ {t("drugAlertType.maxTime")}
diff --git a/src/components/Prioritization/Util/index.js b/src/components/Prioritization/Util/index.js
index 3da715aad..342a2b51e 100644
--- a/src/components/Prioritization/Util/index.js
+++ b/src/components/Prioritization/Util/index.js
@@ -126,7 +126,8 @@ export const filterList = (list, filter) => {
newList = newList.filter(
(i) =>
i.namePatient.toLowerCase().includes(filter.searchKey) ||
- `${i.admissionNumber}`.includes(filter.searchKey)
+ `${i.admissionNumber}`.includes(filter.searchKey) ||
+ `${i.idPatient}`.includes(filter.searchKey)
);
}
diff --git a/src/components/References/Relation/columns.jsx b/src/components/References/Relation/columns.jsx
index 656f50500..b74814e78 100644
--- a/src/components/References/Relation/columns.jsx
+++ b/src/components/References/Relation/columns.jsx
@@ -56,6 +56,51 @@ const columns = (security) => [
),
},
+ {
+ title: "Nível",
+ render: (entry, record) => {
+ switch (record.level) {
+ case "low":
+ return (
+
+ Baixo
+
+ );
+ case "medium":
+ return (
+
+ Médio
+
+ );
+ case "high":
+ return (
+
+ Alto
+
+ );
+ default:
+ return record.level;
+ }
+ },
+ },
{
title: "Ações",
key: "operations",
diff --git a/src/components/References/Relation/index.jsx b/src/components/References/Relation/index.jsx
index c1547b811..f5613ceae 100644
--- a/src/components/References/Relation/index.jsx
+++ b/src/components/References/Relation/index.jsx
@@ -159,6 +159,33 @@ export default function Relation({
/>
+ {relation.item.editable && (
+
+
+
+ Nível:
+
+
+
+
+
+
+ )}
{relation.item.editable && (
diff --git a/src/components/Screening/AlertCard/index.jsx b/src/components/Screening/AlertCard/index.jsx
index ae709b2e1..f98fd7079 100644
--- a/src/components/Screening/AlertCard/index.jsx
+++ b/src/components/Screening/AlertCard/index.jsx
@@ -1,4 +1,5 @@
-import React from "react";
+import React, { useState } from "react";
+import { useDispatch } from "react-redux";
import { useTranslation } from "react-i18next";
import {
ForkOutlined,
@@ -9,6 +10,13 @@ import {
import CustomIcon from "components/Icon";
import PrescriptionCard from "components/PrescriptionCard";
import Tooltip from "components/Tooltip";
+import DefaultModal from "components/Modal";
+import Button from "components/Button";
+import AlertListReport from "features/reports/AlertListReport/AlertListReport";
+import {
+ setInitialFilters,
+ setReportData,
+} from "features/reports/AlertListReport/AlertListReportSlice";
import { AlertContainer } from "./index.style";
@@ -17,51 +25,62 @@ export const getAlerts = (stats, t) => [
label: t("alerts.y"),
icon: () => ,
value: stats.inc + stats.isl,
+ filters: { typeList: ["iy", "sl"] },
},
{
label: t("alerts.interaction"),
icon: () => ,
value: stats.int,
+ filters: { typeList: ["it"] },
},
{
label: t("alerts.max_dose"),
icon: () => ,
value: stats.maxDose,
+ filters: { typeList: ["maxDose"] },
},
{
label: t("alerts.exam"),
icon: () => ,
value: stats.exams,
+ filters: { typeList: ["liver", "kidney", "platelets"] },
},
{
label: t("alerts.time"),
icon: () => ,
value: stats.maxTime,
+ filters: { typeList: ["time"] },
},
{
label: t("alerts.elderly"),
icon: () => ,
value: stats.elderly,
+ filters: { typeList: ["elderly"] },
},
{
label: t("alerts.alergy"),
icon: () => ,
- value: stats.allergy,
+ value: stats.allergy + (stats?.interactions?.rx || 0),
+ filters: { typeList: ["allergy", "rx"] },
},
{
label: t("alerts.tube"),
icon: () => ,
value: stats.tube,
+ filters: { typeList: ["tube"] },
},
{
label: t("alerts.duplicate"),
icon: () => ,
value: stats.dup,
+ filters: { typeList: ["dm", "dt"] },
},
];
-export default function AlertCard({ stats }) {
+export default function AlertCard({ stats, prescription }) {
const { t } = useTranslation();
+ const dispatch = useDispatch();
+ const [modal, setModal] = useState(false);
if (!stats) {
return null;
@@ -69,22 +88,46 @@ export default function AlertCard({ stats }) {
const alerts = getAlerts(stats, t);
+ const openModal = (filters = {}) => {
+ dispatch(setInitialFilters(filters));
+ dispatch(setReportData(prescription.alertsList));
+ setModal(true);
+ };
+
return (
-
{t("tableHeader.alerts")}
+
+ {t("tableHeader.alerts")}
+
+
{alerts.map((a) => (
- 0 ? "alert" : ""}>
+
0 ? "alert" : ""}
+ onClick={() => openModal(a.filters)}
+ >
{a.icon()} {a.value}
))}
+ setModal(false)}
+ width={"min(1440px, 100%)"}
+ footer={null}
+ style={{ top: "10px", height: "100vh" }}
+ >
+
+
);
}
diff --git a/src/components/Screening/AlertCard/index.style.jsx b/src/components/Screening/AlertCard/index.style.jsx
index 870496604..6026c9a52 100644
--- a/src/components/Screening/AlertCard/index.style.jsx
+++ b/src/components/Screening/AlertCard/index.style.jsx
@@ -23,6 +23,7 @@ export const AlertContainer = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
+ cursor: pointer;
@media only screen and (min-width: 1515px) {
font-size: 16px;
diff --git a/src/components/Screening/Patient/index.jsx b/src/components/Screening/Patient/index.jsx
index 36898b15d..e4460959d 100644
--- a/src/components/Screening/Patient/index.jsx
+++ b/src/components/Screening/Patient/index.jsx
@@ -115,7 +115,7 @@ export default function Patient({
justifyContent: "space-between",
}}
>
-
+
{hasClinicalNotes && (
span {
+ .panel-header-description {
padding-left: 15px;
- }
- .p-number {
- padding-right: 10px;
- }
+ div > span {
+ padding-left: 15px;
+ }
- a {
- color: rgba(0, 0, 0, 0.65);
- text-decoration: none;
- }
+ .p-number {
+ padding-right: 10px;
+ }
- a:hover {
- text-decoration: underline;
- }
+ a {
+ color: rgba(0, 0, 0, 0.65);
+ text-decoration: none;
+ }
- .title {
- font-size: 16px;
- }
+ a:hover {
+ text-decoration: underline;
+ }
- .subtitle {
- opacity: 0.6;
- }
+ .title {
+ font-size: 16px;
+ }
- .expired {
- color: rgb(207, 19, 34);
+ .subtitle {
+ opacity: 0.6;
+ }
+
+ .expired {
+ color: rgb(207, 19, 34);
+ }
}
`;
@@ -100,6 +104,8 @@ export const PrescriptionCollapse = styled(Collapse)`
transition: background 0.3s linear;
.ant-collapse-header {
+ align-items: center;
+
.panel-header {
transition: transform 0.3s cubic-bezier(0.33, 1, 0.68, 1);
}
@@ -244,3 +250,47 @@ export const InterventionListContainer = styled.div`
margin-top: 15px;
}
`;
+
+export const DrugAlertsCollapse = styled(Collapse)`
+ border: 1px solid #ffccc7 !important;
+ background: #fff2f0;
+
+ .ant-collapse-item {
+ &.high {
+ .tag {
+ background: #f44336;
+ border-color: #f44336;
+ color: #fff;
+ }
+ }
+
+ &.medium {
+ .tag {
+ background: #f57f17;
+ border-color: #f57f17;
+ color: #fff;
+ }
+ }
+
+ &.low {
+ .tag {
+ background: #ffc107;
+ border-color: #ffc107;
+ color: #fff;
+ }
+ }
+
+ .ant-collapse-header {
+ align-items: center;
+ padding: 12px 10px;
+ }
+ }
+
+ .ant-collapse-content.ant-collapse-content-active {
+ padding-top: 0;
+
+ .ant-collapse-content-box {
+ padding-left: 35px;
+ }
+ }
+`;
diff --git a/src/components/Screening/PrescriptionDrug/PrescriptionDrugList.jsx b/src/components/Screening/PrescriptionDrug/PrescriptionDrugList.jsx
index 68bdf9007..2f4c5086e 100644
--- a/src/components/Screening/PrescriptionDrug/PrescriptionDrugList.jsx
+++ b/src/components/Screening/PrescriptionDrug/PrescriptionDrugList.jsx
@@ -16,6 +16,7 @@ import {
import { filterInterventionByPrescriptionDrug } from "utils/transformers/intervention";
import SecurityService from "services/security";
import FeatureService from "services/features";
+import DrugAlertLevelTag from "components/DrugAlertLevelTag";
import {
PrescriptionCollapse,
@@ -70,8 +71,12 @@ export const rowClassName = (record, bag) => {
classes.push("checked");
}
+ if (!record.checked && record.drug) {
+ classes.push("new-item");
+ }
+
if (record.whiteList && !record.total) {
- classes.push("checked");
+ classes.push("whitelist");
}
if (bag.interventions) {
@@ -246,59 +251,95 @@ export default function PrescriptionDrugList({
);
};
- const panelHeader = (ds) => (
-
-
-
- {t("prescriptionDrugList.panelPrescription")}
-
- # {ds.key}
-
-
-
-
-
- {t("prescriptionDrugList.panelIssueDate")}:
- {format(new Date(headers[ds.key].date), "dd/MM/yyyy HH:mm")}
-
-
+ const panelHeader = (ds) => {
+ const isChecked = headers[ds.key].status === "s";
+ const source = isEmpty(ds.value) ? null : ds.value[0].source;
+ let summary = null;
+ if (headers[ds.key] && headers[ds.key][summarySourceToType(source)]) {
+ summary = headers[ds.key][summarySourceToType(source)];
+ }
+
+ return (
+
+
+ {!isChecked && summary && summary.alerts > 0 && (
+
+ )}
+
+
+
+
+ {t("prescriptionDrugList.panelPrescription")}
+
+ # {ds.key}
+
+
+
+
+
+ {t("prescriptionDrugList.panelIssueDate")}:{" "}
+
+ {format(new Date(headers[ds.key].date), "dd/MM/yyyy HH:mm")}
+
+
+ {t("prescriptionDrugList.panelValidUntil")}:{" "}
+
+
+ {headers[ds.key].expire
+ ? format(new Date(headers[ds.key].expire), "dd/MM/yyyy HH:mm")
+ : " - "}
+
+
+
+ {t("prescriptionDrugList.panelBed")}:
+
+ {headers[ds.key].bed}
+
+
+
+ {t("prescriptionDrugList.panelPrescriber")}:{" "}
+
+ {headers[ds.key].prescriber}
+
+
+
+
+ );
+ };
+
+ const groupHeader = (dt, headerSummary) => {
+ return (
+
+ {!headerSummary.checked &&
+ headerSummary &&
+ headerSummary.summary.alerts > 0 && (
+
+ )}
+
{t("prescriptionDrugList.panelValidUntil")}:
-
- {headers[ds.key].expire
- ? format(new Date(headers[ds.key].expire), "dd/MM/yyyy HH:mm")
- : " - "}
+
+ {format(parseISO(dt), "dd/MM/yyyy")}
-
- {t("prescriptionDrugList.panelBed")}:
-
- {headers[ds.key].bed}
-
-
-
- {t("prescriptionDrugList.panelPrescriber")}:
- {headers[ds.key].prescriber}
-
-
-
- );
-
- const groupHeader = (dt) => (
-
-
- {t("prescriptionDrugList.panelValidUntil")}:
-
- {format(parseISO(dt), "dd/MM/yyyy")}
-
-
-
- );
+
+ );
+ };
const summarySourceToType = (s) => {
switch (sourceToStoreType(s)) {
@@ -306,6 +347,10 @@ export default function PrescriptionDrugList({
return "drugs";
case "solution":
+ if (featureService.hasDisableSolutionTab()) {
+ return "drugs";
+ }
+
return "solutions";
case "procedure":
return "procedures";
@@ -429,12 +474,13 @@ export default function PrescriptionDrugList({
const aggSummary = (currentData, addData) => {
const baseData = currentData || {
alerts: 0,
- alergy: 0,
+ allergy: 0,
interventions: 0,
np: 0,
am: 0,
av: 0,
controlled: 0,
+ alertLevel: [],
};
if (isEmpty(addData)) {
@@ -443,7 +489,11 @@ export default function PrescriptionDrugList({
const aggData = {};
Object.keys(baseData).forEach((k) => {
- aggData[k] = baseData[k] + addData[k];
+ if (k === "alertLevel") {
+ aggData[k] = [...baseData[k], addData[k]];
+ } else {
+ aggData[k] = baseData[k] + addData[k];
+ }
});
return aggData;
@@ -486,7 +536,7 @@ export default function PrescriptionDrugList({
const getCollapseItems = (g) => [
{
key: "1",
- label: groupHeader(g),
+ label: groupHeader(g, groups[g]),
extra: groupSummary(groups[g]),
className: groups[g].checked ? "checked" : "",
children: list(groups[g].ids),
diff --git a/src/components/Screening/PrescriptionDrug/components/DrugAlerts.jsx b/src/components/Screening/PrescriptionDrug/components/DrugAlerts.jsx
new file mode 100644
index 000000000..93e12933d
--- /dev/null
+++ b/src/components/Screening/PrescriptionDrug/components/DrugAlerts.jsx
@@ -0,0 +1,158 @@
+import React, { useState, useEffect } from "react";
+import { useTranslation } from "react-i18next";
+import { Alert, Tag } from "antd";
+import {
+ PlusOutlined,
+ MinusOutlined,
+ CloseCircleFilled,
+} from "@ant-design/icons";
+
+import RichTextView from "components/RichTextView";
+import Button from "components/Button";
+import Tooltip from "components/Tooltip";
+import { DrugAlertsCollapse } from "../PrescriptionDrug.style";
+
+export default function DrugAlerts({ alerts, disableGroups }) {
+ const { t } = useTranslation();
+ const [activeKey, setActiveKey] = useState([]);
+
+ useEffect(() => {
+ if (alerts && alerts.length > 0) {
+ const levels = alerts.map((a) => a.level);
+
+ if (levels.indexOf("medium") !== -1) {
+ setActiveKey(["medium"]);
+ }
+
+ if (levels.indexOf("high") !== -1) {
+ setActiveKey(["high"]);
+ }
+ }
+ }, [alerts]);
+
+ if (alerts == null || alerts.length === 0) {
+ return null;
+ }
+
+ const activeKeyChange = (keys) => {
+ setActiveKey(keys);
+ };
+
+ const toggleAll = (groups) => {
+ if (activeKey.length) {
+ setActiveKey([]);
+ } else {
+ setActiveKey(Object.keys(groups));
+ }
+ };
+
+ const drugAlertTitle = (type, group) => {
+ return (
+
+ <>
+ {group.length}
+ {t(`drugAlertType.${type}`)}
+ >
+
+ );
+ };
+
+ const getIconColor = (type) => {
+ switch (type) {
+ case "high":
+ return "#f44336";
+ case "medium":
+ return "#f57f17";
+ case "low":
+ return "#ffc107";
+ default:
+ return "#f44336";
+ }
+ };
+
+ const groups = {};
+ alerts.forEach((a) => {
+ let type = a.level;
+
+ if (!groups.hasOwnProperty(type)) {
+ groups[type] = [a];
+ } else {
+ groups[type].push(a);
+ }
+ });
+
+ const items = [];
+
+ ["high", "medium", "low"].forEach((type) => {
+ if (groups[type]) {
+ items.push({
+ key: type,
+ label: drugAlertTitle(type, groups[type]),
+ className: type,
+ children: (
+ <>
+ {groups[type].map((item, index) => (
+ }
+ style={{ marginTop: "5px", background: "#fff" }}
+ showIcon
+ icon={
+
+ }
+ />
+ ))}
+ >
+ ),
+ });
+ }
+ });
+
+ if (disableGroups) {
+ return (
+ <>
+ {alerts.map((item, index) => (
+ }
+ style={{ marginTop: "5px" }}
+ showIcon
+ />
+ ))}
+ >
+ );
+ }
+
+ return (
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/components/Screening/PrescriptionDrug/components/Filters.jsx b/src/components/Screening/PrescriptionDrug/components/Filters.jsx
index ba5ab206a..8f97e7388 100644
--- a/src/components/Screening/PrescriptionDrug/components/Filters.jsx
+++ b/src/components/Screening/PrescriptionDrug/components/Filters.jsx
@@ -15,6 +15,7 @@ import {
setPrescriptionListOrder,
savePreferences,
} from "features/preferences/PreferencesSlice";
+import DrugAlertTypeEnum from "models/DrugAlertTypeEnum";
import { ToolBox } from "../PrescriptionDrug.style";
@@ -31,6 +32,42 @@ export default function Filters({ showPrescriptionOrder }) {
const filterOptions = () => {
const items = [
+ {
+ key: "alertsLevelGroup",
+ label: t(`prescriptionDrugFilters.alertsLevelGroup`),
+ children: [
+ {
+ key: "alertsAll_level",
+ label: t(`prescriptionDrugFilters.alertsAll`),
+ },
+ {
+ key: "alertsHigh",
+ label: t(`prescriptionDrugFilters.alertsHigh`),
+ },
+ {
+ key: "alertsMedium",
+ label: t(`prescriptionDrugFilters.alertsMedium`),
+ },
+ {
+ key: "alertsLow",
+ label: t(`prescriptionDrugFilters.alertsLow`),
+ },
+ ],
+ },
+ {
+ key: "alertsTypeGroup",
+ label: t(`prescriptionDrugFilters.alertsTypeGroup`),
+ children: [
+ {
+ key: "alertsAll_type",
+ label: t(`prescriptionDrugFilters.alertsAll`),
+ },
+ ...DrugAlertTypeEnum.getAlertTypes(t).map((a) => ({
+ key: `drugAlertType.${a.id}`,
+ label: a.label,
+ })),
+ ],
+ },
{
key: "hv",
label: t(`prescriptionDrugFilters.hv`),
@@ -39,14 +76,12 @@ export default function Filters({ showPrescriptionOrder }) {
key: "am",
label: t(`prescriptionDrugFilters.am`),
},
+
{
key: "active",
label: t(`prescriptionDrugFilters.active`),
},
- {
- key: "alerts",
- label: t(`prescriptionDrugFilters.alerts`),
- },
+
{
key: "withValidation",
label: t(`prescriptionDrugFilters.withValidation`),
@@ -98,7 +133,7 @@ export default function Filters({ showPrescriptionOrder }) {
closable
onClose={() => handleFilterClick({ key: i })}
>
- {t(`prescriptionDrugFilters.${i}`)}
+ {t(i.split(".").length > 1 ? i : `prescriptionDrugFilters.${i}`)}
))}
diff --git a/src/components/Screening/PrescriptionDrug/components/PanelAction.jsx b/src/components/Screening/PrescriptionDrug/components/PanelAction.jsx
index 3dbf3d4ac..ffbe12f18 100644
--- a/src/components/Screening/PrescriptionDrug/components/PanelAction.jsx
+++ b/src/components/Screening/PrescriptionDrug/components/PanelAction.jsx
@@ -1,4 +1,5 @@
import React from "react";
+import { useDispatch } from "react-redux";
import { useTranslation } from "react-i18next";
import {
LinkOutlined,
@@ -10,14 +11,13 @@ import {
CopyOutlined,
} from "@ant-design/icons";
-import Badge from "components/Badge";
import Dropdown from "components/Dropdown";
import Tooltip from "components/Tooltip";
import Button from "components/Button";
-import Tag from "components/Tag";
import notification from "components/notification";
import { sourceToStoreType } from "utils/transformers/prescriptions";
import { getErrorMessageFromException } from "utils/errorHandler";
+import { setCheckSummary } from "features/prescription/PrescriptionSlice";
const PanelAction = ({
id,
@@ -31,6 +31,7 @@ const PanelAction = ({
hasPrescriptionEdit,
}) => {
const { t } = useTranslation();
+ const dispatch = useDispatch();
const summarySourceToType = (s) => {
switch (sourceToStoreType(s)) {
@@ -71,25 +72,6 @@ const PanelAction = ({
const summaryTags = (summary) => {
const tags = [];
- if (summary.alerts) {
- tags.push(
-
-
-
- {summary.alerts}
-
-
-
- );
- }
-
if (summary.interventions) {
tags.push(
{
- checkScreening(id, status)
- .then(() => {
- notification.success({
- message:
- status === "s"
- ? "Checagem efetuada com sucesso!"
- : "Checagem desfeita com sucesso!",
- });
- })
- .catch((err) => {
- notification.error({
- message: t("error.title"),
- description: getErrorMessageFromException(err, t),
+ if (status === "s") {
+ dispatch(
+ setCheckSummary({
+ idPrescription: id,
+ agg: false,
+ })
+ );
+ } else {
+ checkScreening(id, status)
+ .then(() => {
+ notification.success({
+ message:
+ status === "s"
+ ? "Checagem efetuada com sucesso!"
+ : "Checagem desfeita com sucesso!",
+ });
+ })
+ .catch((err) => {
+ notification.error({
+ message: t("error.title"),
+ description: getErrorMessageFromException(err, t),
+ });
});
- });
+ }
};
const handleMenuClick = ({ key, domEvent }) => {
diff --git a/src/components/Screening/PrescriptionDrug/components/PresmedTags.jsx b/src/components/Screening/PrescriptionDrug/components/PresmedTags.jsx
index 866c46778..e09c60394 100644
--- a/src/components/Screening/PrescriptionDrug/components/PresmedTags.jsx
+++ b/src/components/Screening/PrescriptionDrug/components/PresmedTags.jsx
@@ -9,15 +9,11 @@ import {
import { useSelector } from "react-redux";
import {
WarningOutlined,
- CheckOutlined,
- FormOutlined,
- StopOutlined,
MessageOutlined,
HourglassOutlined,
CalendarOutlined,
} from "@ant-design/icons";
-import Badge from "components/Badge";
import Tooltip from "components/Tooltip";
import Tag from "components/Tag";
@@ -50,16 +46,6 @@ function PresmedTags({ prescription, bag }) {
return (
- bag.handleRowExpand(prescription)}
- >
- {prescription.checked && (
-
-
-
- )}
-
bag.handleRowExpand(prescription)}
@@ -71,16 +57,6 @@ function PresmedTags({ prescription, bag }) {
)}
- bag.handleRowExpand(prescription)}
- >
- {prescription.prevNotes && prescription.prevNotes !== "None" && (
-
-
-
- )}
-
bag.handleRowExpand(prescription)}
@@ -99,16 +75,6 @@ function PresmedTags({ prescription, bag }) {
)}
- bag.handleRowExpand(prescription)}
- >
- {prescription.suspended && (
-
-
-
- )}
-
{hasExpireInfo && (
<>
)}
- bag.handleRowExpand(prescription)}
- >
- {!isEmpty(prescription.alerts) && (
-
-
-
- {prescription.alerts.length}
-
-
-
- )}
-
);
}
diff --git a/src/components/Screening/ScreeningActions/index.jsx b/src/components/Screening/ScreeningActions/index.jsx
index 1b0950bd6..6b5e3327a 100644
--- a/src/components/Screening/ScreeningActions/index.jsx
+++ b/src/components/Screening/ScreeningActions/index.jsx
@@ -6,6 +6,8 @@ import { FloatButton } from "antd";
import FormPatientModal from "containers/Forms/Patient";
import { shouldUpdatePrescription } from "features/serverActions/ServerActionsSlice";
import InterventionOutcome from "features/intervention/InterventionOutcome/InterventionOutcome";
+import CheckSummary from "features/prescription/CheckSummary/CheckSummary";
+import SecurityService from "services/security";
import { ScreeningFloatButtonGroup } from "../index.style";
@@ -14,8 +16,12 @@ export default function ScreeningActions({
prescription,
setModalVisibility,
patientEditVisible,
+ roles,
+ checkScreening,
+ interventions,
}) {
const dispatch = useDispatch();
+ const security = SecurityService(roles);
const afterSavePatient = () => {
dispatch(
@@ -56,6 +62,14 @@ export default function ScreeningActions({
afterSavePatient={afterSavePatient}
/>
+
+
>
);
}
diff --git a/src/components/Screening/columns.jsx b/src/components/Screening/columns.jsx
index 20f603290..702d913fc 100644
--- a/src/components/Screening/columns.jsx
+++ b/src/components/Screening/columns.jsx
@@ -9,6 +9,8 @@ import {
CaretDownOutlined,
FormOutlined,
CalculatorOutlined,
+ CheckCircleOutlined,
+ StopOutlined,
} from "@ant-design/icons";
import { Button as AntButton } from "antd";
@@ -20,16 +22,17 @@ import Descriptions from "components/Descriptions";
import Tag from "components/Tag";
import { createSlug } from "utils/transformers/utils";
import Dropdown from "components/Dropdown";
-import Alert from "components/Alert";
import RichTextView from "components/RichTextView";
import InterventionStatus from "models/InterventionStatus";
import { SelectMultiline } from "components/Inputs";
import { filterInterventionByPrescriptionDrug } from "utils/transformers/intervention";
import { setSelectedIntervention as setSelectedInterventionOutcome } from "features/intervention/InterventionOutcome/InterventionOutcomeSlice";
+import DrugAlertLevelTag from "components/DrugAlertLevelTag";
import { PeriodTags } from "./index.style";
import SolutionCalculator from "./PrescriptionDrug/components/SolutionCalculator";
import PresmedTags from "./PrescriptionDrug/components/PresmedTags";
+import DrugAlerts from "./PrescriptionDrug/components/DrugAlerts";
import { InterventionView } from "./Intervention/columns";
import DrugForm from "./Form";
@@ -333,7 +336,8 @@ const NestedTableContainer = styled.div`
.ant-descriptions-item-label {
font-weight: 600;
color: #2e3c5a;
- width: 20%;
+ width: 15%;
+ text-align: right;
}
`;
@@ -359,26 +363,6 @@ const periodDates = (dates) => {
);
};
-const showAlerts = (alerts) => {
- if (alerts == null || alerts.length === 0) {
- return "--";
- }
-
- return (
- <>
- {alerts.map((item, index) => (
- }
- style={{ marginTop: "5px" }}
- showIcon
- />
- ))}
- >
- );
-};
-
const periodDatesList = (dates) => {
if (dates == null || dates.length === 0) {
return "";
@@ -472,12 +456,15 @@ export const expandedRowRender = (bag) => (record) => {
className={`${record.source} ${record.groupRow ? "group" : ""}`}
>
- {!isEmpty(record.alerts) && (
+ {!isEmpty(record.alertsComplete) && (
- {showAlerts(record.alerts)}
+
)}
{bag.security.hasPresmedForm() && bag.formTemplate && (
@@ -791,25 +778,89 @@ const drugInfo = (bag) => [
{
key: "idPrescriptionDrug",
dataIndex: "score",
- width: 20,
+ width: 85,
align: "center",
- render: (entry, { score, near, total, emptyRow }) => {
- if (total || emptyRow) {
+ render: (entry, prescription) => {
+ if (prescription.total || prescription.emptyRow) {
return "";
}
return (
-
-
- {score}
-
-
+ a.level)
+ : []
+ }
+ count={prescription.alertsComplete?.length}
+ allergy={prescription.allergy}
+ onClick={() => bag.handleRowExpand(prescription)}
+ />
+
+ bag.handleRowExpand(prescription)}
+ >
+ {prescription.score}
+
+
+ {prescription.suspensionDate ? (
+
+
+
+ ) : (
+ <>
+ {prescription.checked && (
+
+
+
+ )}
+ {!prescription.checked && (
+
+
+
+ )}
+ >
+ )}
+
);
},
},
@@ -922,8 +973,8 @@ const frequencyAndTime = (bag) => [
{
title: bag.t("tableHeader.time"),
dataIndex: "time",
- ellipsis: bag.condensed,
- align: bag.condensed ? "left" : "center",
+ ellipsis: true,
+ align: "left",
width: 100,
render: (text, prescription) => {
return {prescription.time};
diff --git a/src/components/Screening/index.jsx b/src/components/Screening/index.jsx
index 45242260f..d5cea01f0 100644
--- a/src/components/Screening/index.jsx
+++ b/src/components/Screening/index.jsx
@@ -12,6 +12,8 @@ import Tag from "components/Tag";
import notification from "components/notification";
import Dropdown from "components/Dropdown";
import Menu from "components/Menu";
+import FeatureService from "services/features";
+import SecurityService from "services/security";
import PrescriptionList from "containers/Screening/PrescriptionDrug/PrescriptionList";
import SolutionList from "containers/Screening/PrescriptionDrug/SolutionList";
@@ -39,9 +41,9 @@ export default function Screening({
content,
error,
selectPrescriptionDrug,
- security,
interventions,
- featureService,
+ roles,
+ features,
}) {
const params = useParams();
const id = params?.slug;
@@ -49,6 +51,8 @@ export default function Screening({
content;
const { t } = useTranslation();
+ const security = SecurityService(roles);
+ const featureService = FeatureService(features);
// show message if has error
useEffect(() => {
diff --git a/src/components/ScreeningList/columns.jsx b/src/components/ScreeningList/columns.jsx
index 10ea650ec..045c5581e 100644
--- a/src/components/ScreeningList/columns.jsx
+++ b/src/components/ScreeningList/columns.jsx
@@ -1,16 +1,12 @@
import React from "react";
import styled from "styled-components/macro";
-import {
- CheckOutlined,
- SearchOutlined,
- LoadingOutlined,
-} from "@ant-design/icons";
+import { SearchOutlined, LoadingOutlined } from "@ant-design/icons";
-import { Link, BasicButton } from "components/Button";
+import { Link } from "components/Button";
import { InfoIcon } from "components/Icon";
import Tooltip from "components/Tooltip";
import Table from "components/Table";
-import PopConfirm from "components/PopConfirm";
+import Tag from "components/Tag";
const setDataIndex = (list) =>
list.map(({ key, ...column }) => ({
@@ -59,10 +55,6 @@ const ActionsBox = styled.div`
}
`;
-const CheckedBox = styled.span`
- padding: 5px 15px;
-`;
-
const NestedTableContainer = styled.div`
margin-top: 5px;
margin-bottom: 35px;
@@ -77,42 +69,8 @@ const ScreeningActions = ({
prioritizationType,
t,
}) => {
- const checkAction = () => checkScreening(idPrescription, "s");
-
- const isDisabled =
- check.idPrescription !== idPrescription && check.isChecking;
- const isChecking =
- check.idPrescription === idPrescription && check.isChecking;
- const isChecked = status === "s";
-
return (
- {!isChecked && (
-
-
-
-
-
-
-
- )}
- {isChecked && (
-
-
-
-
-
- )}
{
),
className: `gtm-th-idade ${oddClass(index++)}`,
key: "age",
- width: 30,
+ width: 40,
align: "center",
sortDirections,
sorter: (a, b) => a.birthdays - b.birthdays,
@@ -450,7 +408,8 @@ const columns = (sortedInfo, filteredInfo, t) => {
filteredValue: filteredInfo.searchKey || null,
onFilter: (value, record) =>
record.namePatient.toLowerCase().includes(value) ||
- `${record.admissionNumber}` === value,
+ `${record.admissionNumber}`.includes(value) ||
+ `${record.idPatient}`.includes(value),
sortDirections,
sorter: (a, b) => Date.parse(a.date) - Date.parse(b.date),
sortOrder: sortedInfo.columnKey === "date" && sortedInfo.order,
@@ -464,10 +423,43 @@ const columns = (sortedInfo, filteredInfo, t) => {
title: t("screeningList.prescriptionRisk"),
children: setDataIndex(prescriptionRiskColumns),
},
+ {
+ title: t("labels.status"),
+ key: "status",
+ width: 0,
+ align: "center",
+ render: (text, prescription) => {
+ if (prescription.status === "s") {
+ return (
+
+ Checada
+
+ );
+ }
+
+ if (prescription.status !== "s") {
+ return (
+ <>
+ {prescription.isBeingEvaluated ? (
+
+
+ Em análise
+
+
+ ) : (
+
+ Pendente
+
+ )}
+ >
+ );
+ }
+ },
+ },
{
title: t("screeningList.actions"),
key: "operations",
- width: 70,
+ width: 10,
align: "center",
filteredValue: filteredInfo.status || null,
onFilter: (value, record) => record.status === value,
diff --git a/src/components/Table.jsx b/src/components/Table.jsx
index 17ee1cd20..d727a562f 100644
--- a/src/components/Table.jsx
+++ b/src/components/Table.jsx
@@ -19,11 +19,19 @@ const Table = styled(AntTable)`
padding: 5px;
}
+ .ant-table-tbody > tr > td {
+ color: rgba(0, 0, 0, 0.65);
+ }
+
.ant-table-thead > tr > th,
.ant-table-thead > tr > td {
background: transparent;
}
+ .ant-table-expand-icon-col {
+ width: 35px;
+ }
+
.ant-table-column-title {
color: ${get("colors.primary")};
font-weight: ${get("weight.semiBold")};
@@ -62,18 +70,18 @@ const Table = styled(AntTable)`
}
&.red {
- background-color: #e46666;
+ background-color: #f44336;
color: #fff;
}
&.orange {
- background-color: #e67e22;
+ background-color: #f57f17;
color: #fff;
}
&.yellow {
- background-color: #e4da66;
- color: #000;
+ background-color: #ffc107;
+ color: #fff;
}
&.green {
@@ -123,11 +131,53 @@ const Table = styled(AntTable)`
opacity: 0.45;
text-decoration: line-through;
}
+
+ .score-container {
+ transition: opacity 0.3s linear;
+ opacity: 0;
+ }
+
+ &:hover {
+ .score-container {
+ opacity: 1;
+ }
+ }
}
.checked {
+ td:not(:nth-child(1)) {
+ opacity: 0.75;
+ }
+ }
+
+ .new-item {
+ td:not(:nth-child(1)) {
+ font-weight: 500;
+
+ a {
+ font-weight: 500;
+ }
+ }
+ }
+
+ .whitelist {
+ .score-container {
+ transition: opacity 0.3s linear;
+ opacity: 0;
+ }
+
td:not(:nth-child(1)) {
opacity: 0.45;
+
+ a {
+ opacity: 0.45;
+ }
+ }
+
+ &:hover {
+ .score-container {
+ opacity: 1;
+ }
}
}
@@ -289,7 +339,7 @@ const Table = styled(AntTable)`
.summary-row {
td:not(:first-child) {
- opacity: 0.2;
+ opacity: 0.45;
}
td {
diff --git a/src/containers/Screening/PageHeader.jsx b/src/containers/Screening/PageHeader.jsx
index 811a1af96..31f963a5d 100644
--- a/src/containers/Screening/PageHeader.jsx
+++ b/src/containers/Screening/PageHeader.jsx
@@ -1,15 +1,12 @@
import { connect } from "react-redux";
import { bindActionCreators } from "redux";
-import security from "services/security";
-
import {
checkScreeningThunk,
reviewPatientThunk,
incrementClinicalNotesThunk,
} from "store/ducks/prescriptions/thunk";
import PageHeader from "pages/Screening/PageHeader";
-import FeatureService from "services/features";
const mapStateToProps = ({ prescriptions, user }) => ({
prescription: {
@@ -19,8 +16,8 @@ const mapStateToProps = ({ prescriptions, user }) => ({
content: prescriptions.single.data,
},
userId: user.account.userId,
- security: security(user.account.roles),
- featureService: FeatureService(user.account.features),
+ roles: user.account.roles,
+ features: user.account.features,
});
const mapDispatchToProps = (dispatch) =>
bindActionCreators(
diff --git a/src/containers/Screening/ScreeningActions.jsx b/src/containers/Screening/ScreeningActions.jsx
index faf60966f..ff121abce 100644
--- a/src/containers/Screening/ScreeningActions.jsx
+++ b/src/containers/Screening/ScreeningActions.jsx
@@ -4,21 +4,22 @@ import { bindActionCreators } from "redux";
import {
fetchScreeningThunk,
setModalVisibilityThunk,
+ checkScreeningThunk,
} from "store/ducks/prescriptions/thunk";
import ScreeningActions from "components/Screening/ScreeningActions";
-import security from "services/security";
-import FeatureService from "services/features";
const mapStateToProps = ({ prescriptions, user }) => ({
prescription: prescriptions.single.data,
- security: security(user.account.roles),
- featureService: FeatureService(user.account.features),
patientEditVisible: prescriptions.single.actions.modalVisibility.patientEdit,
+ roles: user.account.roles,
+ features: user.account.features,
+ interventions: prescriptions.single.intervention.list,
});
const mapDispatchToProps = (dispatch) =>
bindActionCreators(
{
fetchScreening: fetchScreeningThunk,
+ checkScreening: checkScreeningThunk,
setModalVisibility: setModalVisibilityThunk,
},
dispatch
diff --git a/src/containers/Screening/index.jsx b/src/containers/Screening/index.jsx
index 27de9802e..54ec6b96c 100644
--- a/src/containers/Screening/index.jsx
+++ b/src/containers/Screening/index.jsx
@@ -4,8 +4,6 @@ import { bindActionCreators } from "redux";
import { fetchScreeningThunk } from "store/ducks/prescriptions/thunk";
import { selectPrescriptionDrugThunk } from "store/ducks/prescriptionDrugs/thunk";
-import security from "services/security";
-import FeatureService from "services/features";
import Screening from "components/Screening";
const mapStateToProps = ({ prescriptions, user }) => ({
@@ -14,8 +12,8 @@ const mapStateToProps = ({ prescriptions, user }) => ({
isFetching: prescriptions.single.isFetching,
content: prescriptions.single.data,
interventions: prescriptions.single.intervention.list,
- security: security(user.account.roles),
- featureService: FeatureService(user.account.features),
+ roles: user.account.roles,
+ features: user.account.features,
});
const mapDispatchToProps = (dispatch) =>
bindActionCreators(
diff --git a/src/features/intervention/InterventionOutcome/Form/InterventionOutcomeForm.jsx b/src/features/intervention/InterventionOutcome/Form/InterventionOutcomeForm.jsx
index 38f7ed1de..83956616c 100644
--- a/src/features/intervention/InterventionOutcome/Form/InterventionOutcomeForm.jsx
+++ b/src/features/intervention/InterventionOutcome/Form/InterventionOutcomeForm.jsx
@@ -133,7 +133,7 @@ export default function InterventionOutcomeForm() {
return "error";
}
- if (!Big(values[source][f]).eq(Big(original.item[f]))) {
+ if (!Big(values[source][f] || 0).eq(Big(original.item[f] || 0))) {
return "warning";
}
diff --git a/src/features/prescription/CheckSummary/CheckSummary.jsx b/src/features/prescription/CheckSummary/CheckSummary.jsx
new file mode 100644
index 000000000..cca084512
--- /dev/null
+++ b/src/features/prescription/CheckSummary/CheckSummary.jsx
@@ -0,0 +1,344 @@
+import React, { useState } from "react";
+import { useDispatch, useSelector } from "react-redux";
+import { Alert, Tag } from "antd";
+import { Formik } from "formik";
+import * as Yup from "yup";
+import { useTranslation } from "react-i18next";
+import {
+ ExclamationCircleFilled,
+ CheckOutlined,
+ WarningOutlined,
+} from "@ant-design/icons";
+
+import RichTextView from "components/RichTextView";
+import Tooltip from "components/Tooltip";
+import DefaultModal from "components/Modal";
+import Heading from "components/Heading";
+import { Checkbox } from "components/Inputs";
+import notification from "components/notification";
+import { getErrorMessageFromException } from "utils/errorHandler";
+import { formatDate } from "utils/date";
+import { setCheckSummary } from "../PrescriptionSlice";
+
+import { Form } from "styles/Form.style";
+import { DrugAlertsCollapse } from "components/Screening/PrescriptionDrug/PrescriptionDrug.style";
+
+export default function CheckSummary({
+ hasCpoe,
+ checkScreening,
+ headers,
+ alerts,
+ interventions,
+}) {
+ const dispatch = useDispatch();
+ const prescription = useSelector(
+ (state) => state.prescriptionv2.checkSummary.prescription
+ );
+ const { t } = useTranslation();
+ const [loading, setLoading] = useState(false);
+
+ const validationSchema = Yup.object().shape({
+ accept: Yup.boolean().oneOf(
+ [true],
+ "Você precisa aceitar para confirmar a checagem"
+ ),
+ });
+
+ if (!prescription) {
+ return null;
+ }
+
+ let highRiskAlerts = [];
+
+ if (alerts && alerts.length) {
+ if (prescription.agg) {
+ highRiskAlerts = alerts.filter((a) => a.level === "high");
+ } else {
+ highRiskAlerts = alerts.filter(
+ (a) =>
+ a.level === "high" && a.idPrescription === prescription.idPrescription
+ );
+ }
+ }
+
+ const initialValues = {
+ accept: highRiskAlerts.length > 0 ? false : true,
+ };
+
+ const onCancel = () => {
+ setLoading(false);
+ dispatch(setCheckSummary(null));
+ };
+
+ const getHeader = (item) => {
+ return (
+
+ );
+ };
+
+ const getExtra = (item) => {
+ return (
+
+
+
+ {" "}
+ {item.dose}{" "}
+ {item.measureUnit?.label
+ ? item.measureUnit.label
+ : item.measureUnit.value}
+
+
+
+
+ {item.frequency?.label
+ ? item.frequency.label
+ : item.frequency.value}
+
+
+
+ {item.route}
+
+
+ );
+ };
+
+ const onSave = () => {
+ setLoading(true);
+ const auditAlerts = highRiskAlerts.map(({ idPrescriptionDrug, type }) => ({
+ idPrescriptionDrug,
+ type,
+ }));
+
+ checkScreening(prescription.idPrescription, "s", {
+ alerts: auditAlerts,
+ })
+ .then(() => {
+ setLoading(false);
+ dispatch(setCheckSummary(null));
+ notification.success({
+ message: "Checagem efetuada com sucesso!",
+ });
+ })
+ .catch((err) => {
+ setLoading(false);
+ console.error("error", err);
+ notification.error({
+ message: t("error.title"),
+ description: getErrorMessageFromException(err, t),
+ });
+ });
+ };
+
+ const groups = {};
+ highRiskAlerts.forEach((a) => {
+ if (groups[a.idPrescriptionDrug]) {
+ groups[a.idPrescriptionDrug]["alerts"].push(a);
+ } else {
+ groups[a.idPrescriptionDrug] = {
+ ...a,
+ alerts: [a],
+ };
+ }
+ });
+
+ const dateGroups = {};
+ if (prescription?.agg && !hasCpoe) {
+ Object.keys(groups).forEach((g) => {
+ const dt = groups[g].expire
+ ? groups[g].expire.substr(0, 10)
+ : groups[g].date.substr(0, 10);
+
+ if (dateGroups[dt]) {
+ dateGroups[dt].push(groups[g]);
+ } else {
+ dateGroups[dt] = [groups[g]];
+ }
+ });
+ } else {
+ dateGroups["uniq"] = [];
+ Object.keys(groups).forEach((g) => {
+ dateGroups["uniq"].push(groups[g]);
+ });
+ }
+
+ const AlertStatus = ({ idPrescription, idPrescriptionDrug }) => {
+ const header = headers[idPrescription];
+ const intervention = interventions.find(
+ (i) => i.id === idPrescriptionDrug && i.status !== "0"
+ );
+
+ return (
+ <>
+ {header && header.status === "s" && (
+
+ {" "}
+ {header.user ? <>Checado por {header.user}> : <>Checado>}
+
+ )}
+ {intervention && (
+
+ {" "}
+ {intervention.user ? (
+ <>Intervenção registrada por {intervention.user}>
+ ) : (
+ <>Intervenção registrada>
+ )}
+
+ )}
+ >
+ );
+ };
+
+ const getItemsByGroup = (g) => {
+ return {
+ key: g.idPrescriptionDrug,
+ label: getHeader(g),
+ extra: getExtra(g),
+ children: (
+ <>
+ {g.alerts.map((a, index) => (
+ }
+ style={{ marginTop: "5px", background: "#fff" }}
+ showIcon
+ />
+ ))}
+
+ >
+ ),
+ };
+ };
+
+ return (
+
+ {({ handleSubmit, errors, values, setFieldValue }) => (
+ 0 ? 900 : 350}
+ centered
+ destroyOnClose
+ onCancel={() => onCancel()}
+ onOk={handleSubmit}
+ okText="Confirmar"
+ cancelText={t("actions.cancel")}
+ confirmLoading={loading}
+ okButtonProps={{
+ disabled: loading,
+ }}
+ cancelButtonProps={{
+ disabled: loading,
+ }}
+ maskClosable={false}
+ >
+
+
+ {" "}
+ Confirmar a checagem
+
+
+ {highRiskAlerts.length > 0 && (
+ <>
+
+ Revise os alertas de Nível Alto e confirme para
+ finalizar a checagem.
+
+
+
+ >
+ )}
+
+ )}
+
+ );
+}
diff --git a/src/features/prescription/PrescriptionSlice.js b/src/features/prescription/PrescriptionSlice.js
index 567f94d18..243f4674e 100644
--- a/src/features/prescription/PrescriptionSlice.js
+++ b/src/features/prescription/PrescriptionSlice.js
@@ -9,6 +9,9 @@ const initialState = {
data: {},
active: false,
},
+ checkSummary: {
+ prescription: null,
+ },
filters: [],
};
@@ -35,6 +38,9 @@ const prescriptionSlice = createSlice({
setPrescriptionFilters(state, action) {
state.filters = action.payload;
},
+ setCheckSummary(state, action) {
+ state.checkSummary.prescription = action.payload;
+ },
},
extraReducers(builder) {
builder
@@ -51,6 +57,7 @@ const prescriptionSlice = createSlice({
},
});
-export const { reset, setPrescriptionFilters } = prescriptionSlice.actions;
+export const { reset, setPrescriptionFilters, setCheckSummary } =
+ prescriptionSlice.actions;
export default prescriptionSlice.reducer;
diff --git a/src/features/reports/AlertListReport/AlertList/AlertList.jsx b/src/features/reports/AlertListReport/AlertList/AlertList.jsx
new file mode 100644
index 000000000..b1ded081b
--- /dev/null
+++ b/src/features/reports/AlertListReport/AlertList/AlertList.jsx
@@ -0,0 +1,149 @@
+import React, { useState } from "react";
+import { useSelector } from "react-redux";
+import { useTranslation } from "react-i18next";
+import { Descriptions, Alert } from "antd";
+
+import { CardTable } from "components/Table";
+import DrugAlertLevelTag from "components/DrugAlertLevelTag";
+import RichTextView from "components/RichTextView";
+import { formatDateTime } from "utils/date";
+
+export default function AlertList() {
+ const { t } = useTranslation();
+ const [expandedRows, setExpandedRows] = useState([]);
+ const datasource = useSelector(
+ (state) => state.reportsArea.alertList.filtered.result.list
+ );
+
+ const updateExpandedRows = (list, key) => {
+ if (list.includes(key)) {
+ return list.filter((i) => i !== key);
+ }
+
+ return [...list, key];
+ };
+
+ const handleRowExpand = (record) => {
+ setExpandedRows(updateExpandedRows(expandedRows, record.rowKey));
+ };
+
+ const toggleExpansion = () => {
+ if (expandedRows.length) {
+ setExpandedRows([]);
+ } else {
+ setExpandedRows(datasource.map((i) => i.rowKey));
+ }
+ };
+
+ const ExpandColumn = ({ expand }) => {
+ return (
+
+
+
+ );
+ };
+
+ const columns = [
+ {
+ title: "Nível",
+ align: "center",
+ render: (_, record) => {
+ return (
+
+ );
+ },
+ },
+ {
+ title: "Medicamento",
+ render: (_, record) => record.drugName,
+ },
+
+ {
+ title: "Tipo",
+ render: (_, record) => t(`drugAlertType.${record.type}`),
+ },
+ ];
+
+ return (
+ <>
+ (
+
+ {datasource.length} registro(s)
+
+ )}
+ expandable={{
+ expandedRowRender: (record) => ,
+ onExpand: (expanded, record) => handleRowExpand(record),
+ expandedRowKeys: expandedRows,
+ }}
+ onRow={(record) => {
+ return {
+ onClick: (event) => {
+ handleRowExpand(record);
+ },
+ };
+ }}
+ columnTitle={}
+ size="small"
+ pagination={{ showSizeChanger: true }}
+ />
+ >
+ );
+}
+
+const ExpandedRow = ({ record }) => {
+ const items = [
+ {
+ label: "Dose",
+ span: 3,
+ children: `${record.dose} ${record.measureUnit?.label || "-"}`,
+ },
+ {
+ label: "Frequência",
+ span: 3,
+ children: `${record.frequency?.label || "-"}`,
+ },
+ {
+ label: "Via",
+ span: 3,
+ children: `${record.route || "-"}`,
+ },
+ {
+ label: "Vigência",
+ span: 3,
+ children: `${
+ record.expire
+ ? formatDateTime(record.expire)
+ : "Manter até segunda ordem"
+ }`,
+ },
+ {
+ label: "Alerta",
+ span: 3,
+ children: (
+ }
+ showIcon
+ />
+ ),
+ },
+ ];
+
+ return ;
+};
diff --git a/src/features/reports/AlertListReport/AlertListReport.jsx b/src/features/reports/AlertListReport/AlertListReport.jsx
new file mode 100644
index 000000000..e40a7751f
--- /dev/null
+++ b/src/features/reports/AlertListReport/AlertListReport.jsx
@@ -0,0 +1,100 @@
+import React, { useRef } from "react";
+import { useSelector } from "react-redux";
+import { Row, Col, Space, Spin } from "antd";
+
+import { PageHeader } from "styles/PageHeader.style";
+import {
+ ReportContainer,
+ ReportHeader,
+ ReportFilterContainer,
+ ReportPrintDescriptions,
+} from "styles/Report.style";
+import Filter from "./Filter/Filter";
+import { ReactComponent as Brand } from "assets/noHarm-horizontal.svg";
+import { filtersToDescription } from "utils/report";
+import AlertList from "./AlertList/AlertList";
+
+export default function AlertListReport({ prescription }) {
+ const status = useSelector((state) => state.reportsArea.alertList.status);
+ const filteredStatus = useSelector(
+ (state) => state.reportsArea.alertList.filtered.status
+ );
+ const filters = useSelector((state) => state.reportsArea.alertList.filters);
+ const printRef = useRef(null);
+ const isLoading = status === "loading" || filteredStatus === "loading";
+ const filtersConfig = {
+ drugList: {
+ label: "Medicamento",
+ type: "list",
+ },
+ typeList: {
+ label: "Tipo",
+ type: "list",
+ },
+ levelList: {
+ label: "Nível",
+ type: "list",
+ },
+ };
+
+ return (
+ <>
+
+
+
Relatório: Alertas
+
+
+
+
+
+
+
+
+ Relatório: Alertas
+
+
+
+
+
+
+
+
+
+
+ : {prescription.admissionNumber}
+
+
+ : {prescription.namePatient}
+
+
+ : {prescription.birthdateFormat}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ *A quantidade de alertas de interação e duplicidade é maior no
+ relatório, pois o alerta é contabilizado nas duas direções da interação.
+
+ >
+ );
+}
diff --git a/src/features/reports/AlertListReport/AlertListReportSlice.js b/src/features/reports/AlertListReport/AlertListReportSlice.js
new file mode 100644
index 000000000..912fda253
--- /dev/null
+++ b/src/features/reports/AlertListReport/AlertListReportSlice.js
@@ -0,0 +1,58 @@
+import { createSlice } from "@reduxjs/toolkit";
+
+import { getUniqList } from "utils/report";
+
+const initialState = {
+ status: "idle",
+ error: null,
+ list: [],
+ filters: {},
+ filtered: {
+ status: "idle",
+ error: null,
+ result: {
+ list: [],
+ },
+ },
+ filterData: {
+ drugs: [],
+ },
+ initialFilters: {},
+};
+
+const alertListReportSlice = createSlice({
+ name: "alertListReport",
+ initialState,
+ reducers: {
+ reset() {
+ return initialState;
+ },
+ setInitialFilters(state, action) {
+ state.initialFilters = action.payload;
+ },
+ setFilters(state, action) {
+ state.filters = action.payload;
+ },
+ setFilteredStatus(state, action) {
+ state.filtered.status = action.payload;
+ },
+ setFilteredResult(state, action) {
+ state.filtered.result = action.payload;
+ },
+ setReportData(state, action) {
+ state.list = action.payload;
+ state.filterData.drugs = getUniqList(action.payload, "drugName");
+ },
+ },
+});
+
+export const {
+ reset,
+ setFilters,
+ setFilteredResult,
+ setFilteredStatus,
+ setReportData,
+ setInitialFilters,
+} = alertListReportSlice.actions;
+
+export default alertListReportSlice.reducer;
diff --git a/src/features/reports/AlertListReport/Filter/Filter.jsx b/src/features/reports/AlertListReport/Filter/Filter.jsx
new file mode 100644
index 000000000..d191f497b
--- /dev/null
+++ b/src/features/reports/AlertListReport/Filter/Filter.jsx
@@ -0,0 +1,94 @@
+import React, { useEffect } from "react";
+import { useDispatch, useSelector } from "react-redux";
+import { FloatButton, Spin } from "antd";
+import { MenuOutlined, PrinterOutlined } from "@ant-design/icons";
+import { useReactToPrint } from "react-to-print";
+
+import { FloatButtonGroup } from "components/FloatButton";
+import AdvancedFilter from "components/AdvancedFilter";
+import {
+ setFilteredStatus,
+ setFilteredResult,
+ setFilters,
+} from "../AlertListReportSlice";
+import { getReportData } from "../transformers";
+import MainFilters from "./MainFilters";
+import { onBeforePrint, onAfterPrint } from "utils/report";
+
+export default function Filter({ printRef }) {
+ const dispatch = useDispatch();
+ const isFetching =
+ useSelector((state) => state.reportsArea.alertList.status) === "loading";
+ const datasource = useSelector((state) => state.reportsArea.alertList.list);
+ const initialFilters = useSelector(
+ (state) => state.reportsArea.alertList.initialFilters
+ );
+ const handlePrint = useReactToPrint({
+ content: () => printRef.current,
+ onBeforeGetContent: onBeforePrint,
+ onAfterPrint: onAfterPrint,
+ });
+ const initialValues = {
+ levelList: [],
+ drugList: [],
+ typeList: [],
+ ...initialFilters,
+ };
+
+ useEffect(() => {
+ search({
+ ...initialValues,
+ });
+ }, []); //eslint-disable-line
+
+ const search = async (params, forceDs) => {
+ let ds = [];
+ if (!forceDs) {
+ ds = datasource;
+ }
+
+ dispatch(setFilteredStatus("loading"));
+ dispatch(setFilters(params));
+ const reportData = getReportData(forceDs || ds, params);
+ dispatch(setFilteredResult(reportData));
+
+ setTimeout(() => {
+ dispatch(setFilteredStatus("succeeded"));
+ }, 500);
+ };
+
+ return (
+
+
+ {!isFetching && (
+ }
+ onSearch={search}
+ loading={isFetching}
+ skipFilterList={["dateRange", "segmentList", "departmentList"]}
+ />
+ )}
+
+ {!isFetching && (
+ }
+ tooltip="Menu"
+ style={{ bottom: 25 }}
+ >
+ }
+ onClick={handlePrint}
+ tooltip="Imprimir"
+ />
+
+ )}
+
+
+ );
+}
diff --git a/src/features/reports/AlertListReport/Filter/MainFilters.jsx b/src/features/reports/AlertListReport/Filter/MainFilters.jsx
new file mode 100644
index 000000000..1ee13af0f
--- /dev/null
+++ b/src/features/reports/AlertListReport/Filter/MainFilters.jsx
@@ -0,0 +1,99 @@
+import React, { useContext } from "react";
+import { useSelector } from "react-redux";
+import { useTranslation } from "react-i18next";
+
+import { Select } from "components/Inputs";
+import Heading from "components/Heading";
+import { Col } from "components/Grid";
+import { AdvancedFilterContext } from "components/AdvancedFilter";
+import DrugAlertTypeEnum from "models/DrugAlertTypeEnum";
+import DrugAlertLevelTag from "components/DrugAlertLevelTag";
+
+export default function MainFilters() {
+ const { t } = useTranslation();
+ const drugs = useSelector(
+ (state) => state.reportsArea.alertList.filterData.drugs
+ );
+
+ const status = useSelector((state) => state.reportsArea.alertList.status);
+ const { values, setFieldValue } = useContext(AdvancedFilterContext);
+
+ return (
+ <>
+
+
+ Nível:
+
+
+
+
+
+ Medicamento:
+
+
+
+
+
+
+ Tipo:
+
+
+
+ >
+ );
+}
diff --git a/src/features/reports/AlertListReport/transformers.js b/src/features/reports/AlertListReport/transformers.js
new file mode 100644
index 000000000..52c5bab53
--- /dev/null
+++ b/src/features/reports/AlertListReport/transformers.js
@@ -0,0 +1,42 @@
+import { exportCSV } from "utils/report";
+
+const filterDatasource = (datasource, filters) => {
+ return datasource
+ .filter((i) => {
+ if (filters.drugList.length) {
+ return filters.drugList.indexOf(i.drugName) !== -1;
+ }
+
+ return true;
+ })
+ .filter((i) => {
+ if (filters.levelList.length) {
+ return filters.levelList.indexOf(i.level) !== -1;
+ }
+
+ return true;
+ })
+ .filter((i) => {
+ if (filters.typeList.length) {
+ return filters.typeList.indexOf(i.type) !== -1;
+ }
+
+ return true;
+ });
+};
+
+export const getReportData = (datasource, filters) => {
+ const filteredList = filterDatasource(datasource, filters);
+
+ const reportData = {
+ list: filteredList,
+ };
+
+ return reportData;
+};
+
+export const filterAndExportCSV = (datasource, filters, t) => {
+ const items = filterDatasource(datasource, filters);
+
+ return exportCSV(items, t);
+};
diff --git a/src/features/userAdmin/UserAdminSlice.js b/src/features/userAdmin/UserAdminSlice.js
index 506237574..4894c8dab 100644
--- a/src/features/userAdmin/UserAdminSlice.js
+++ b/src/features/userAdmin/UserAdminSlice.js
@@ -68,7 +68,6 @@ const userAdminSlice = createSlice({
state.single.status = "succeeded";
const item = action.payload.data.data;
- console.log("item", item);
const index = state.list.findIndex((i) => i.id === item.id);
if (index !== -1) {
diff --git a/src/lib/withAuth.jsx b/src/lib/withAuth.jsx
index 31e80b4d0..cdfa88515 100644
--- a/src/lib/withAuth.jsx
+++ b/src/lib/withAuth.jsx
@@ -41,6 +41,16 @@ const AuthHandler = ({
return ;
}
+ try {
+ if (window.cwr) {
+ window.cwr("addSessionAttributes", {
+ schema: localStorage.getItem("schema"),
+ });
+ }
+ } catch (ex) {
+ console.error("cwr set schema error");
+ }
+
return ;
};
diff --git a/src/models/DrugAlertTypeEnum.js b/src/models/DrugAlertTypeEnum.js
new file mode 100644
index 000000000..63b3d83a7
--- /dev/null
+++ b/src/models/DrugAlertTypeEnum.js
@@ -0,0 +1,85 @@
+export default class DrugAlertTypeEnum {
+ static ALLERGY = "allergy";
+ static MAX_DOSE = "maxDose";
+ static DM = "dm";
+ static DT = "dt";
+ static LIVER = "liver";
+ static IY = "iy";
+ static IT = "it";
+ static IRA = "ira";
+ static SL = "sl";
+ static ELDERLY = "elderly";
+ static KIDNEY = "kidney";
+ static PLATELETS = "platelets";
+ static RX = "rx";
+ static TUBE = "tube";
+ static MAX_TIME = "maxTime";
+
+ static getAlertTypes = (t) => {
+ const types = [
+ {
+ id: DrugAlertTypeEnum.ALLERGY,
+ label: t(`drugAlertType.${DrugAlertTypeEnum.ALLERGY}`),
+ },
+ {
+ id: DrugAlertTypeEnum.MAX_DOSE,
+ label: t(`drugAlertType.${DrugAlertTypeEnum.MAX_DOSE}`),
+ },
+ {
+ id: DrugAlertTypeEnum.DM,
+ label: t(`drugAlertType.${DrugAlertTypeEnum.DM}`),
+ },
+ {
+ id: DrugAlertTypeEnum.DT,
+ label: t(`drugAlertType.${DrugAlertTypeEnum.DT}`),
+ },
+ {
+ id: DrugAlertTypeEnum.LIVER,
+ label: t(`drugAlertType.${DrugAlertTypeEnum.LIVER}`),
+ },
+ {
+ id: DrugAlertTypeEnum.IY,
+ label: t(`drugAlertType.${DrugAlertTypeEnum.IY}`),
+ },
+ {
+ id: DrugAlertTypeEnum.IT,
+ label: t(`drugAlertType.${DrugAlertTypeEnum.IT}`),
+ },
+
+ {
+ id: DrugAlertTypeEnum.IRA,
+ label: t(`drugAlertType.${DrugAlertTypeEnum.IRA}`),
+ },
+ {
+ id: DrugAlertTypeEnum.SL,
+ label: t(`drugAlertType.${DrugAlertTypeEnum.SL}`),
+ },
+ {
+ id: DrugAlertTypeEnum.ELDERLY,
+ label: t(`drugAlertType.${DrugAlertTypeEnum.ELDERLY}`),
+ },
+ {
+ id: DrugAlertTypeEnum.KIDNEY,
+ label: t(`drugAlertType.${DrugAlertTypeEnum.KIDNEY}`),
+ },
+ {
+ id: DrugAlertTypeEnum.PLATELETS,
+ label: t(`drugAlertType.${DrugAlertTypeEnum.PLATELETS}`),
+ },
+ {
+ id: DrugAlertTypeEnum.RX,
+ label: t(`drugAlertType.${DrugAlertTypeEnum.RX}`),
+ },
+ {
+ id: DrugAlertTypeEnum.TUBE,
+ label: t(`drugAlertType.${DrugAlertTypeEnum.TUBE}`),
+ },
+ {
+ id: DrugAlertTypeEnum.MAX_TIME,
+ label: t(`drugAlertType.${DrugAlertTypeEnum.MAX_TIME}`),
+ },
+ ];
+
+ return types.sort((a, b) => `${a?.label}`.localeCompare(`${b?.label}`));
+ };
+}
diff --git a/src/models/Feature.js b/src/models/Feature.js
index 260b02081..a0ca70160 100644
--- a/src/models/Feature.js
+++ b/src/models/Feature.js
@@ -10,6 +10,7 @@ export default class Feature {
static PATIENT_REVISION = "PATIENT_REVISION";
static INTERVENTION_V2 = "INTERVENTION_V2";
static AUTHORIZATION_SEGMENT = "AUTHORIZATION_SEGMENT";
+ static DISABLE_ALERT_GROUPS = "DISABLE_ALERT_GROUPS";
static getFeatures(t) {
return [
@@ -62,18 +63,18 @@ export default class Feature {
label: t(`features.${Feature.PATIENT_REVISION}`),
description: t(`featuresDescription.${Feature.PATIENT_REVISION}`),
},
- {
- id: Feature.INTERVENTION_V2,
- label: "Intervenções V2",
- description:
- "A nova versão de intervenções possibilita o novo relatório de farmacoeconomia. Será liberado para todos usuários em 01/07/24",
- },
{
id: Feature.AUTHORIZATION_SEGMENT,
label: "Autorização por Segmento",
description:
"Quando ativado, o usuário só conseguirá efetuar ações em segmentos onde tiver autorização. As autorizações são concedidas no cadastro do usuário.",
},
+ {
+ id: Feature.DISABLE_ALERT_GROUPS,
+ label: "Desabilita agrupamento de alertas",
+ description:
+ "Esta feature faz com que o agrupamento de alertas na tela de prescrição seja desativado, voltando ao modo de visualização antigo.",
+ },
];
}
}
diff --git a/src/pages/Screening/PageHeader.jsx b/src/pages/Screening/PageHeader.jsx
index 30b960d16..54269db25 100644
--- a/src/pages/Screening/PageHeader.jsx
+++ b/src/pages/Screening/PageHeader.jsx
@@ -1,6 +1,7 @@
import styled from "styled-components/macro";
import React, { useState, useEffect } from "react";
+import { useDispatch } from "react-redux";
import { useTranslation } from "react-i18next";
import { useParams } from "react-router-dom";
import {
@@ -30,6 +31,9 @@ import ClinicalNotesCustomForm from "containers/Forms/ClinicalNotes/CustomForm";
import FormClinicalAlert from "containers/Forms/ClinicalAlert";
import { getErrorMessageFromException } from "utils/errorHandler";
import pageTimer from "utils/pageTimer";
+import FeatureService from "services/features";
+import SecurityService from "services/security";
+import { setCheckSummary } from "features/prescription/PrescriptionSlice";
import { ScreeningHeader } from "components/Screening/index.style";
@@ -58,10 +62,11 @@ export default function PageHeader({
checkScreening,
reviewPatient,
incrementClinicalNotes,
- security,
- featureService,
userId,
+ roles,
+ features,
}) {
+ const dispatch = useDispatch();
const params = useParams();
const id = params?.slug;
const { isChecking } = prescription.check;
@@ -83,6 +88,8 @@ export default function PageHeader({
delay: 150,
config: config.slow,
});
+ const security = SecurityService(roles);
+ const featureService = FeatureService(features);
useEffect(() => {
if (!window.noharm) {
@@ -157,6 +164,24 @@ export default function PageHeader({
notification.success({ message: "Número da prescrição copiado!" });
};
+ const confirmCheckPrescription = (id) => {
+ let highRiskAlerts = [];
+ if (
+ prescription?.content?.alertsList &&
+ prescription.content.alertsList.length
+ ) {
+ highRiskAlerts = prescription.content.alertsList.filter(
+ (a) => a.level === "high"
+ );
+ }
+
+ if (highRiskAlerts.length > 0) {
+ dispatch(setCheckSummary(prescription.content));
+ } else {
+ setPrescriptionStatus(id, "s");
+ }
+ };
+
const setPrescriptionStatus = (id, status) => {
checkScreening(id, status)
.then(() => {
@@ -315,7 +340,7 @@ export default function PageHeader({
type="primary gtm-bt-check"
icon={}
ghost
- onClick={() => setPrescriptionStatus(id, "s")}
+ onClick={() => confirmCheckPrescription(id)}
loading={isChecking}
style={{ marginRight: "5px" }}
>
diff --git a/src/services/features.js b/src/services/features.js
index b08dfb702..0ee9e278a 100644
--- a/src/services/features.js
+++ b/src/services/features.js
@@ -41,14 +41,14 @@ const FeaturesService = (features) => {
return hasFeature(Feature.PATIENT_REVISION);
};
- const hasInterventionV2 = () => {
- return hasFeature(Feature.INTERVENTION_V2);
- };
-
const hasAuthorizationSegment = () => {
return hasFeature(Feature.AUTHORIZATION_SEGMENT);
};
+ const hasDisableAlertGroups = () => {
+ return hasFeature(Feature.DISABLE_ALERT_GROUPS);
+ };
+
return {
hasFeature,
hasMicromedex,
@@ -59,8 +59,8 @@ const FeaturesService = (features) => {
hasDisableSolutionTab,
hasClinicalNotesNewFormat,
hasPatientRevision,
- hasInterventionV2,
hasAuthorizationSegment,
+ hasDisableAlertGroups,
};
};
diff --git a/src/store/ducks/index.js b/src/store/ducks/index.js
index d53ef026a..27599a86c 100644
--- a/src/store/ducks/index.js
+++ b/src/store/ducks/index.js
@@ -50,6 +50,7 @@ import reportPrescriptionAuditReport from "features/reports/PrescriptionAuditRep
import reportEconomyReport from "features/reports/EconomyReport/EconomyReportSlice";
import reportCultureReport from "features/reports/CultureReport/CultureReportSlice";
import reportAntimicrobialHistoryReport from "features/reports/AntimicrobialHistoryReport/AntimicrobialHistoryReportSlice";
+import reportAlertListReport from "features/reports/AlertListReport/AlertListReportSlice";
const adminReducers = combineReducers({
interventionReason: adminInterventionReasonReducer,
@@ -73,6 +74,7 @@ const reportReducers = combineReducers({
economy: reportEconomyReport,
culture: reportCultureReport,
antimicrobialHistory: reportAntimicrobialHistoryReport,
+ alertList: reportAlertListReport,
reports: reports,
});
diff --git a/src/store/ducks/prescriptions/index.js b/src/store/ducks/prescriptions/index.js
index a586427e1..7c995d7e1 100644
--- a/src/store/ducks/prescriptions/index.js
+++ b/src/store/ducks/prescriptions/index.js
@@ -157,7 +157,6 @@ const setModalVisibility = (state = INITIAL_STATE, { modalKey, visible }) => ({
});
const removeNotes = (state = INITIAL_STATE, { id, notesType }) => {
- console.log("remove notes thunk");
let listAttr;
if (notesType === "allergy") {
listAttr = "notesAllergies";
@@ -308,7 +307,7 @@ const checkSuccess = (state = INITIAL_STATE, { success }) => {
let prescriptionStatus = success.newStatus;
const headers = state.single.data.headers
- ? { ...state.single.data.headers }
+ ? JSON.parse(JSON.stringify(state.single.data.headers))
: null;
if (!isEmpty(headers)) {
@@ -316,7 +315,7 @@ const checkSuccess = (state = INITIAL_STATE, { success }) => {
if (headers[i.idPrescription]) {
headers[i.idPrescription].status = i.status;
headers[i.idPrescription].user = success.user;
- headers[i.idPrescription].user = success.userId;
+ //headers[i.idPrescription].user = success.userId;
}
});
diff --git a/src/store/ducks/prescriptions/thunk.js b/src/store/ducks/prescriptions/thunk.js
index 502a83560..b6160bb83 100644
--- a/src/store/ducks/prescriptions/thunk.js
+++ b/src/store/ducks/prescriptions/thunk.js
@@ -183,7 +183,8 @@ export const fetchScreeningThunk =
};
export const checkScreeningThunk =
- (idPrescription, status) => async (dispatch, getState) => {
+ (idPrescription, status, params = {}) =>
+ async (dispatch, getState) => {
return new Promise(async (resolve, reject) => {
dispatch(prescriptionsCheckStart(idPrescription));
@@ -192,6 +193,7 @@ export const checkScreeningThunk =
idPrescription,
status,
evaluationTime: window.noharm?.pageTimer?.getCurrentTime(),
+ alerts: params?.alerts,
})
.catch(errorHandler);
diff --git a/src/store/ducks/reset.js b/src/store/ducks/reset.js
index 940c616ba..c7019cdc8 100644
--- a/src/store/ducks/reset.js
+++ b/src/store/ducks/reset.js
@@ -42,6 +42,7 @@ import { reset as prescriptionAuditReportReset } from "features/reports/Prescrip
import { reset as economyReportReset } from "features/reports/EconomyReport/EconomyReportSlice";
import { reset as cultureReportReset } from "features/reports/CultureReport/CultureReportSlice";
import { reset as antimicrobialHistoryReportReset } from "features/reports/AntimicrobialHistoryReport/AntimicrobialHistoryReportSlice";
+import { reset as alertListReportReset } from "features/reports/AlertListReport/AlertListReportSlice";
const { clinicalNotesReset } = ClinicalNotesCreators;
const { departmentsReset } = DepartmentsCreators;
@@ -99,4 +100,5 @@ export const resetReduxState = (dispatch) => {
dispatch(economyReportReset());
dispatch(cultureReportReset());
dispatch(antimicrobialHistoryReportReset());
+ dispatch(alertListReportReset());
};
diff --git a/src/styles/Form.style.jsx b/src/styles/Form.style.jsx
index 9c1579601..570b02b44 100644
--- a/src/styles/Form.style.jsx
+++ b/src/styles/Form.style.jsx
@@ -89,6 +89,12 @@ export const Form = styled.form`
border-radius: 5px;
}
+ .form-input-checkbox-single {
+ padding: 1rem;
+ background: #fafafa;
+ border-radius: 5px;
+ }
+
.form-action {
display: flex;
justify-content: flex-end;
diff --git a/src/styles/base.css b/src/styles/base.css
index 094dcf53d..ae722eee9 100644
--- a/src/styles/base.css
+++ b/src/styles/base.css
@@ -36,6 +36,22 @@
}
}
+.custom-scroll-danger {
+ &::-webkit-scrollbar {
+ -webkit-appearance: none;
+ width: 15px;
+ background-color: rgba(0, 0, 0, 0.1);
+ border-radius: 4px;
+ }
+
+ &::-webkit-scrollbar-thumb {
+ border-radius: 4px;
+ border: 1px solid #fff;
+ background-color: #ffccc7;
+ -webkit-box-shadow: 0 0 1px rgba(255, 255, 255, 0.5);
+ }
+}
+
@keyframes flickerAnimation {
0% {
opacity: 0.5;
diff --git a/src/translations/en.json b/src/translations/en.json
index 3b1970086..a2a3784b4 100644
--- a/src/translations/en.json
+++ b/src/translations/en.json
@@ -415,7 +415,13 @@
},
"prescriptionDrugFilters": {
- "alerts": "Has alerts",
+ "alerts": "Alerts",
+ "alertsAll": "Alerts: All",
+ "alertsHigh": "Alerts: High",
+ "alertsMedium": "Alerts: Medium",
+ "alertsLow": "Alerts: Low",
+ "alertsTypeGroup": "Alerts by Type",
+ "alertsLevelGroup": "Alerts by Risk",
"diff": "Not evaluated",
"am": "Antimicrobial",
"hv": "High vigilance",
@@ -634,11 +640,12 @@
"endEconomyDate": "ECONOMY DATE END",
"economyValue": "ECONOMY VALUE",
"dose": "DOSE",
- "frequency": "FREQUENCIA",
- "measureUnit": "UNIDADE MEDIDA",
- "route": "VIA",
- "prescriptionExpirationDate": "VIGENCIA",
- "suspensionDate": "DATA SUSPENSAO"
+ "frequency": "FREQUENCY",
+ "measureUnit": "MEASURE UNIT",
+ "route": "ROUTE",
+ "prescriptionExpirationDate": "EXPIRE DATE",
+ "suspensionDate": "SUSPENSION DATE",
+ "observation": "OBSERVATION"
},
"reportcsvCulture": {
@@ -722,5 +729,30 @@
"whiteList": "No validations",
"chemo": "Chemotherapy",
"dialyzable": "Dialyzable"
+ },
+
+ "drugAlertType": {
+ "allergy": "Allergy",
+ "maxDose": "Max dose",
+ "dm": "Drug duplicity",
+ "dt": "Therapeutic duplicity",
+ "liver": "Hepatotoxic",
+ "iy": "Y incompatibility",
+ "it": "Drug interaction",
+ "ira": "Risk of Acute Renal Failure",
+ "sl": "Solution incompatibility",
+ "elderly": "Potentially inappropriate medication for the elderly",
+ "kidney": "Nephrotoxic",
+ "platelets": "Platelets",
+ "rx": "Cross reactivity",
+ "tube": "Probe",
+ "maxTime": "Treatment time",
+
+ "exams": "Lab results x Drugs",
+ "duplicity": "Duplicity",
+ "group_pregnant_lactating": "Pregnant or Lactating",
+ "high": "Alerts: High",
+ "medium": "Alerts: Medium",
+ "low": "Alerts: Low"
}
}
diff --git a/src/translations/pt.json b/src/translations/pt.json
index ab1aa4b05..2827397a6 100644
--- a/src/translations/pt.json
+++ b/src/translations/pt.json
@@ -415,12 +415,20 @@
},
"prescriptionDrugFilters": {
- "alerts": "Com alertas",
+ "alerts": "Alertas",
+ "alertsAll": "Alertas: Todos",
+ "alertsHigh": "Alertas: Nível Alto",
+ "alertsMedium": "Alertas: Nível Médio",
+ "alertsLow": "Alertas: Nível Baixo",
+ "alertsTypeGroup": "Alertas por Tipo",
+ "alertsLevelGroup": "Alertas por Nível",
"diff": "Diferentes",
"am": "Antimicrobianos",
"hv": "Alta vigilância",
"active": "Ativos",
- "withValidation": "Com validação"
+ "withValidation": "Com validação",
+ "alertsAll_type": "Alertas: todos",
+ "alertsAll_level": "Alertas: todos"
},
"interventionForm": {
@@ -642,7 +650,8 @@
"measureUnit": "UNIDADE MEDIDA",
"route": "VIA",
"prescriptionExpirationDate": "VIGENCIA",
- "suspensionDate": "DATA SUSPENSAO"
+ "suspensionDate": "DATA SUSPENSAO",
+ "observation": "OBSERVACAO"
},
"reportcsvCulture": {
@@ -728,5 +737,27 @@
"whiteList": "Sem validação",
"chemo": "Quimioterápico",
"dialyzable": "Dialisável"
+ },
+
+ "drugAlertType": {
+ "allergy": "Alergia",
+ "maxDose": "Dose máxima ou de alerta",
+ "dm": "Duplicidade Medicamentosa",
+ "dt": "Duplicidade Terapêutica",
+ "liver": "Ajuste Hepático",
+ "iy": "Incompatibilidade em Y",
+ "it": "Interação Medicamentosa",
+ "ira": "IRA (Risco)",
+ "sl": "ISL Incompatibilidade em Solução",
+ "elderly": "Medicamento potencialmente inapropriado para idosos",
+ "kidney": "Ajuste Renal",
+ "platelets": "Plaquetas",
+ "rx": "Reatividade Cruzada",
+ "tube": "Sonda",
+ "maxTime": "Tempo de tratamento",
+
+ "high": "Alertas Nível Alto",
+ "medium": "Alertas Nível Médio",
+ "low": "Alertas Nível Baixo"
}
}
diff --git a/src/utils/report.js b/src/utils/report.js
index e4deea171..7b33ae1f2 100644
--- a/src/utils/report.js
+++ b/src/utils/report.js
@@ -78,6 +78,13 @@ export const filtersToDescription = (filters, filtersConfig) => {
export const exportCSV = (datasource, t, namespace = "reportcsv") => {
const replacer = (key, value) => (value === null ? "" : value);
+ const stringify = (value) => {
+ if (Array.isArray(value)) {
+ return `"${JSON.stringify(value, replacer).replaceAll('"', "")}"`;
+ }
+
+ return JSON.stringify(value, replacer);
+ };
const header = Object.keys(datasource[0]);
const headerNames = Object.keys(datasource[0]).map((k) =>
t(`${namespace}.${k}`)
@@ -85,9 +92,7 @@ export const exportCSV = (datasource, t, namespace = "reportcsv") => {
const csv = [
headerNames.join(","),
...datasource.map((row) =>
- header
- .map((fieldName) => JSON.stringify(row[fieldName], replacer))
- .join(",")
+ header.map((fieldName) => stringify(row[fieldName])).join(",")
),
].join("\r\n");
diff --git a/src/utils/transformers/prescriptionDrugs.js b/src/utils/transformers/prescriptionDrugs.js
index 5cf57dcc2..b21e42184 100644
--- a/src/utils/transformers/prescriptionDrugs.js
+++ b/src/utils/transformers/prescriptionDrugs.js
@@ -156,39 +156,76 @@ const sortPrescriptionDrugs = (items) => {
.concat(whitelistItems);
};
+const hasAlertLevel = (alerts, level) => {
+ if (alerts && alerts.length) {
+ return alerts.findIndex((a) => a.level === level) !== -1;
+ }
+
+ return false;
+};
+
+const hasAlertType = (alerts, type) => {
+ if (alerts && alerts.length) {
+ return alerts.findIndex((a) => a.type === type) !== -1;
+ }
+
+ return false;
+};
+
export const filterPrescriptionDrugs = (items, headers, filters) => {
if (filters && filters.length && items) {
return items.filter((i) => {
- let show = true;
+ let show = false;
- if (filters.indexOf("alerts") !== -1) {
- show = show && i.alerts && i.alerts.length;
+ if (
+ filters.indexOf("alertsAll_level") !== -1 ||
+ filters.indexOf("alertsAll_type") !== -1
+ ) {
+ show = show || (i.alertsComplete && i.alertsComplete.length > 0);
+ }
+
+ if (filters.indexOf("alertsHigh") !== -1) {
+ show = show || hasAlertLevel(i.alertsComplete, "high");
+ }
+
+ if (filters.indexOf("alertsMedium") !== -1) {
+ show = show || hasAlertLevel(i.alertsComplete, "medium");
+ }
+
+ if (filters.indexOf("alertsLow") !== -1) {
+ show = show || hasAlertLevel(i.alertsComplete, "low");
}
if (filters.indexOf("diff") !== -1) {
- show = show && !i.checked;
+ show = show || !i.checked;
}
if (filters.indexOf("am") !== -1) {
- show = show && i.am;
+ show = show || i.am;
}
if (filters.indexOf("hv") !== -1) {
- show = show && i.av;
+ show = show || i.av;
}
if (filters.indexOf("withValidation") !== -1) {
- show = show && !i.whiteList;
+ show = show || !i.whiteList;
}
if (filters.indexOf("active") !== -1) {
- show = show && !i.suspended;
+ show = show || !i.suspended;
- if (i.cpoe && headers[i.cpoe]) {
- show = show && isActive(headers[i.cpoe]);
+ if (i.cpoe || headers[i.cpoe]) {
+ show = show || isActive(headers[i.cpoe]);
}
}
+ filters.forEach((f) => {
+ if (f.indexOf("drugAlertType.") !== -1) {
+ show = show || hasAlertType(i.alertsComplete, f.split(".")[1]);
+ }
+ });
+
return show;
});
}
diff --git a/src/utils/transformers/prescriptions.js b/src/utils/transformers/prescriptions.js
index 02e3ba13f..332d00e15 100644
--- a/src/utils/transformers/prescriptions.js
+++ b/src/utils/transformers/prescriptions.js
@@ -200,6 +200,31 @@ export const transformPrescription = ({
return count;
};
+ const alerts = [];
+
+ if (prescription || solution || procedures) {
+ const allItems = [...prescription, ...solution, ...procedures];
+ allItems.forEach((i) => {
+ if (i.alertsComplete && i.alertsComplete.length) {
+ const drugAlerts = i.alertsComplete.map((a, index) => ({
+ ...a,
+ idPrescription: i.idPrescription,
+ cpoe: i.cpoe, // idPrescription when cpoe **refactor
+ drugName: i.drug,
+ date: item?.headers[i.idPrescription]?.date,
+ expire: item?.headers[i.idPrescription]?.expire,
+ dose: i.dose,
+ doseconv: i.doseconv,
+ measureUnit: i.measureUnit,
+ frequency: i.frequency,
+ route: i.route,
+ rowKey: `${a.idPrescriptionDrug}-${a.key}-${a.type}-${index}`,
+ }));
+ alerts.push(...drugAlerts);
+ }
+ });
+ }
+
return {
...item,
daysAgo,
@@ -248,6 +273,7 @@ export const transformPrescription = ({
proceduresCount: countList(proceduresList),
dietCount: countList(dietList),
uniqueDrugs: getUniqueDrugs(prescription, solution, procedures),
+ alertsList: alerts,
};
};
diff --git a/tests/prescription/intervention.spec.ts b/tests/prescription/intervention.spec.ts
index 6dda11433..5c7677f40 100644
--- a/tests/prescription/intervention.spec.ts
+++ b/tests/prescription/intervention.spec.ts
@@ -8,7 +8,7 @@ test("add intervention", async ({ page }) => {
.click();
await page.getByText("Paciente 99").click();
await page
- .getByRole("row", { name: "Expandir linha 1 BISACODIL 5 mg" })
+ .getByRole("row", { name: "Expandir linha 0 1 BISACODIL" })
.getByRole("button")
.nth(1)
.click();
@@ -21,8 +21,9 @@ test("add intervention", async ({ page }) => {
await page.getByRole("textbox").click();
await page.getByRole("textbox").fill("teste");
await page.getByRole("button", { name: "Salvar" }).click();
+
await page
- .getByRole("row", { name: "Expandir linha 1 BISACODIL 5 mg" })
+ .getByRole("row", { name: "Expandir linha 0 1 BISACODIL 5 mg" })
.getByRole("button")
.nth(1)
.click();
@@ -36,7 +37,7 @@ test("add multiple interventions and rollback", async ({ page }) => {
// click intervention button
await page
- .getByRole("row", { name: "Expandir linha 0 ENALAPRIL 20 mg" })
+ .getByRole("row", { name: "Expandir linha 0 0 ENALAPRIL" })
.getByRole("button")
.nth(1)
.click();
@@ -53,7 +54,7 @@ test("add multiple interventions and rollback", async ({ page }) => {
// click intervention button
await page
- .getByRole("row", { name: "Expandir linha 0 ENALAPRIL 20 mg" })
+ .getByRole("row", { name: "Expandir linha 0 0 ENALAPRIL" })
.getByRole("button")
.nth(1)
.click();
@@ -76,7 +77,7 @@ test("add multiple interventions and rollback", async ({ page }) => {
//check created interventions
await page
- .getByRole("row", { name: "Expandir linha 0 ENALAPRIL 20 mg" })
+ .getByRole("row", { name: "Expandir linha 0 0 ENALAPRIL" })
.getByRole("button")
.nth(1)
.click();
@@ -91,14 +92,14 @@ test("add multiple interventions and rollback", async ({ page }) => {
await page.locator(".ant-modal-confirm-btns button").first().click();
await page
- .getByRole("row", { name: "Expandir linha 0 ENALAPRIL 20 mg" })
+ .getByRole("row", { name: "Expandir linha 0 0 ENALAPRIL 20 mg" })
.getByRole("button")
.nth(1)
.click();
await page.getByText("Pendente", { exact: true }).click();
await page.getByRole("button", { name: "rollback" }).click();
await page
- .getByRole("row", { name: "Expandir linha 0 ENALAPRIL 20 mg" })
+ .getByRole("row", { name: "Expandir linha 0 0 ENALAPRIL 20 mg" })
.getByRole("button")
.nth(1)
.click();
diff --git a/tests/prescription/interventionOutcome.spec.ts b/tests/prescription/interventionOutcome.spec.ts
index f03919040..6576415cb 100644
--- a/tests/prescription/interventionOutcome.spec.ts
+++ b/tests/prescription/interventionOutcome.spec.ts
@@ -8,7 +8,7 @@ test("outcome: suspension", async ({ page }) => {
.click();
await page.getByText("Paciente 99").click();
await page
- .getByRole("row", { name: "Expandir linha 1 BISACODIL 5 mg" })
+ .getByRole("row", { name: "Expandir linha 0 1 BISACODIL 5 mg" })
.getByRole("button")
.nth(1)
.click();
@@ -100,7 +100,7 @@ test("outcome: substitution", async ({ page }) => {
.click();
await page.getByText("Paciente 99").click();
await page
- .getByRole("row", { name: "Expandir linha 0 ENALAPRIL 20" })
+ .getByRole("row", { name: "Expandir linha 0 0 ENALAPRIL 20" })
.getByRole("button")
.nth(1)
.click();