@pucp-gidis-hiisc/esm-fua-app 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/116.js +1 -0
- package/dist/116.js.map +1 -0
- package/dist/123.js +2 -0
- package/dist/123.js.map +1 -0
- package/dist/191.js +1 -0
- package/dist/191.js.map +1 -0
- package/dist/194.js +1 -0
- package/dist/194.js.map +1 -0
- package/dist/276.js +2 -0
- package/dist/{556.js.LICENSE.txt → 276.js.LICENSE.txt} +1 -11
- package/dist/276.js.map +1 -0
- package/dist/300.js +1 -1
- package/dist/31.js +1 -0
- package/dist/31.js.map +1 -0
- package/dist/322.js +1 -0
- package/dist/322.js.map +1 -0
- package/dist/336.js +1 -1
- package/dist/336.js.map +1 -1
- package/dist/372.js +1 -1
- package/dist/372.js.map +1 -1
- package/dist/397.js +1 -0
- package/dist/397.js.map +1 -0
- package/dist/41.js +1 -1
- package/dist/41.js.map +1 -1
- package/dist/457.js +1 -1
- package/dist/457.js.map +1 -1
- package/dist/464.js +1 -1
- package/dist/464.js.map +1 -1
- package/dist/470.js +1 -1
- package/dist/470.js.map +1 -1
- package/dist/495.js +2 -1
- package/dist/495.js.LICENSE.txt +9 -0
- package/dist/495.js.map +1 -1
- package/dist/51.js +2 -0
- package/dist/{main.js.LICENSE.txt → 51.js.LICENSE.txt} +18 -3
- package/dist/51.js.map +1 -0
- package/dist/661.js +1 -0
- package/dist/661.js.map +1 -0
- package/dist/69.js +1 -0
- package/dist/69.js.map +1 -0
- package/dist/745.js +1 -0
- package/dist/745.js.map +1 -0
- package/dist/794.js +1 -0
- package/dist/794.js.map +1 -0
- package/dist/810.js +1 -0
- package/dist/810.js.map +1 -0
- package/dist/876.js +1 -2
- package/dist/876.js.map +1 -1
- package/dist/89.js +1 -1
- package/dist/89.js.map +1 -1
- package/dist/913.js +1 -1
- package/dist/913.js.LICENSE.txt +3 -3
- package/dist/913.js.map +1 -1
- package/dist/932.js +1 -0
- package/dist/932.js.map +1 -0
- package/dist/964.js +1 -0
- package/dist/964.js.map +1 -0
- package/dist/99.js +1 -1
- package/dist/main.js +1 -2
- package/dist/main.js.map +1 -1
- package/dist/pucp-gidis-hiisc-esm-fua-app.js +1 -1
- package/dist/pucp-gidis-hiisc-esm-fua-app.js.buildmanifest.json +368 -101
- package/dist/pucp-gidis-hiisc-esm-fua-app.js.map +1 -1
- package/dist/routes.json +1 -1
- package/package.json +4 -2
- package/src/components/fua-html-viewer.component.tsx +81 -0
- package/src/components/fua-html-viewer.scss +44 -0
- package/src/components/summary-tiles/summary-tile.component.tsx +35 -0
- package/src/components/summary-tiles/summary-tiles.scss +64 -0
- package/src/config-schema.ts +15 -53
- package/src/declarations.d.ts +4 -6
- package/src/fua/fua-date-range-picker.component.tsx +38 -0
- package/src/fua/fua-date-range-picker.scss +15 -0
- package/src/fua/fua-header.scss +68 -0
- package/src/fua/{case-management-header.tsx → fua-header.tsx} +6 -6
- package/src/fua/{case-management-illustration.tsx → fua-illustration.tsx} +3 -3
- package/src/fua/fua-request-table.scss +80 -128
- package/src/fua/fuaRequestTable.tsx +148 -101
- package/src/fua-dashboard.component.tsx +25 -0
- package/src/fua-dashboard.scss +35 -0
- package/src/fua-tabs/data-table-extensions/all-fua-requests-table.extension.tsx +8 -0
- package/src/fua-tabs/data-table-extensions/completed-fua-requests-table.extension.tsx +8 -0
- package/src/fua-tabs/data-table-extensions/declined-fua-requests-table.extension.tsx +8 -0
- package/src/fua-tabs/data-table-extensions/in-progress-fua-requests-table.extension.tsx +8 -0
- package/src/fua-tabs/fua-tabs.component.tsx +74 -0
- package/src/fua-tabs/fua-tabs.scss +65 -0
- package/src/fua-tiles/all-fua-requests-tile.component.tsx +20 -0
- package/src/fua-tiles/completed-fua-requests-tile.component.tsx +19 -0
- package/src/fua-tiles/fua-summary-tiles.component.tsx +46 -0
- package/src/fua-tiles/fua-summary-tiles.scss +16 -0
- package/src/fua-tiles/in-progress-fua-requests-tile.component.tsx +20 -0
- package/src/fua-viewer-page/fua-viewer-page.component.tsx +90 -0
- package/src/fua-viewer-page/fua-viewer-page.scss +82 -0
- package/src/hooks/useFuaRequests.ts +93 -26
- package/src/index.ts +82 -7
- package/src/root.component.tsx +8 -0
- package/src/routes.json +94 -10
- package/src/types/index.ts +4 -0
- package/src/workspaces/fua-viewer.workspace.tsx +20 -0
- package/translations/en.json +15 -1
- package/translations/es.json +15 -1
- package/.turbo/turbo-build.log +0 -43
- package/.turbo/turbo-extract-translations.log +0 -11
- package/.turbo/turbo-lint.log +0 -14
- package/dist/144.js +0 -2
- package/dist/144.js.LICENSE.txt +0 -19
- package/dist/144.js.map +0 -1
- package/dist/466.js +0 -1
- package/dist/466.js.map +0 -1
- package/dist/556.js +0 -2
- package/dist/556.js.map +0 -1
- package/dist/596.js +0 -2
- package/dist/596.js.LICENSE.txt +0 -30
- package/dist/596.js.map +0 -1
- package/dist/790.js +0 -1
- package/dist/790.js.map +0 -1
- package/src/root.scss +0 -102
- /package/dist/{876.js.LICENSE.txt → 123.js.LICENSE.txt} +0 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { useTranslation } from 'react-i18next';
|
|
3
|
+
import { type AssignedExtension, Extension, useAssignedExtensions } from '@openmrs/esm-framework';
|
|
4
|
+
import { ComponentContext } from '@openmrs/esm-framework/src/internal';
|
|
5
|
+
import styles from './fua-tabs.scss';
|
|
6
|
+
|
|
7
|
+
const fuaPanelSlot = 'fua-panels-slot';
|
|
8
|
+
|
|
9
|
+
const FuaOrdersTabs: React.FC = () => {
|
|
10
|
+
const { t } = useTranslation();
|
|
11
|
+
const [selectedTab, setSelectedTab] = useState(0);
|
|
12
|
+
const tabExtensions = useAssignedExtensions(fuaPanelSlot) as AssignedExtension[];
|
|
13
|
+
|
|
14
|
+
const filteredExtensions = tabExtensions.filter((extension) => Object.keys(extension.meta).length > 0);
|
|
15
|
+
|
|
16
|
+
if (filteredExtensions.length === 0) {
|
|
17
|
+
return (
|
|
18
|
+
<div style={{ padding: '20px' }}>
|
|
19
|
+
<p>No tab extensions found</p>
|
|
20
|
+
</div>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<div className={styles.customTabsContainer}>
|
|
26
|
+
{/* Tab buttons */}
|
|
27
|
+
<div className={styles.customTabList}>
|
|
28
|
+
{filteredExtensions.map((extension, index) => {
|
|
29
|
+
const { name, title } = extension.meta;
|
|
30
|
+
return (
|
|
31
|
+
<button
|
|
32
|
+
key={index}
|
|
33
|
+
className={`${styles.customTab} ${selectedTab === index ? styles.customTabActive : ''}`}
|
|
34
|
+
onClick={() => setSelectedTab(index)}
|
|
35
|
+
aria-selected={selectedTab === index}
|
|
36
|
+
>
|
|
37
|
+
{t(title, {
|
|
38
|
+
ns: extension.moduleName,
|
|
39
|
+
defaultValue: title,
|
|
40
|
+
})}
|
|
41
|
+
</button>
|
|
42
|
+
);
|
|
43
|
+
})}
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
{/* Tab panels */}
|
|
47
|
+
<div className={styles.customTabPanels}>
|
|
48
|
+
{filteredExtensions.map((extension, index) => {
|
|
49
|
+
if (selectedTab !== index) return null;
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<div key={index} className={styles.customTabPanel}>
|
|
53
|
+
<ComponentContext.Provider
|
|
54
|
+
value={{
|
|
55
|
+
moduleName: extension.moduleName,
|
|
56
|
+
featureName: 'fua',
|
|
57
|
+
extension: {
|
|
58
|
+
extensionId: extension.id,
|
|
59
|
+
extensionSlotName: fuaPanelSlot,
|
|
60
|
+
extensionSlotModuleName: extension.moduleName,
|
|
61
|
+
},
|
|
62
|
+
}}
|
|
63
|
+
>
|
|
64
|
+
<Extension />
|
|
65
|
+
</ComponentContext.Provider>
|
|
66
|
+
</div>
|
|
67
|
+
);
|
|
68
|
+
})}
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export default FuaOrdersTabs;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
@use '@carbon/styles/scss/spacing';
|
|
2
|
+
@use '@carbon/styles/scss/type';
|
|
3
|
+
|
|
4
|
+
.customTabsContainer {
|
|
5
|
+
background-color: var(--cds-layer-01);
|
|
6
|
+
margin: 0;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.customTabList {
|
|
10
|
+
display: flex;
|
|
11
|
+
border-bottom: 1px solid var(--cds-border-subtle-01);
|
|
12
|
+
padding-left: spacing.$spacing-05;
|
|
13
|
+
background-color: var(--cds-layer-01);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.customTab {
|
|
17
|
+
@include type.type-style('body-compact-01');
|
|
18
|
+
|
|
19
|
+
padding: spacing.$spacing-04 spacing.$spacing-05;
|
|
20
|
+
min-width: 8.875rem;
|
|
21
|
+
background: transparent;
|
|
22
|
+
border: none;
|
|
23
|
+
border-bottom: 2px solid transparent;
|
|
24
|
+
color: var(--cds-text-secondary);
|
|
25
|
+
cursor: pointer;
|
|
26
|
+
transition: all 0.11s cubic-bezier(0.2, 0, 0.38, 0.9);
|
|
27
|
+
|
|
28
|
+
&:hover {
|
|
29
|
+
background-color: var(--cds-layer-hover-01);
|
|
30
|
+
color: var(--cds-text-primary);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
&:focus {
|
|
34
|
+
outline: 2px solid var(--cds-focus);
|
|
35
|
+
outline-offset: -2px;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.customTabActive {
|
|
40
|
+
color: var(--cds-text-primary);
|
|
41
|
+
border-bottom-color: var(--cds-border-interactive);
|
|
42
|
+
font-weight: 600;
|
|
43
|
+
|
|
44
|
+
&:hover {
|
|
45
|
+
border-bottom-color: var(--cds-border-interactive);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.customTabPanels {
|
|
50
|
+
padding: spacing.$spacing-05;
|
|
51
|
+
background-color: var(--cds-layer-01);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.customTabPanel {
|
|
55
|
+
animation: fadeIn 0.15s ease-in;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@keyframes fadeIn {
|
|
59
|
+
from {
|
|
60
|
+
opacity: 0;
|
|
61
|
+
}
|
|
62
|
+
to {
|
|
63
|
+
opacity: 1;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useTranslation } from 'react-i18next';
|
|
3
|
+
import { useFuaRequests } from '../hooks/useFuaRequests';
|
|
4
|
+
import FuaSummaryTile from '../components/summary-tiles/summary-tile.component';
|
|
5
|
+
|
|
6
|
+
const AllFuaRequestsTile = () => {
|
|
7
|
+
const { t } = useTranslation();
|
|
8
|
+
|
|
9
|
+
const { fuaOrders } = useFuaRequests({ newOrdersOnly: true });
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<FuaSummaryTile
|
|
13
|
+
label={t('orders', 'Orders')}
|
|
14
|
+
value={fuaOrders?.length}
|
|
15
|
+
headerLabel={t('testsOrdered', 'Tests ordered')}
|
|
16
|
+
/>
|
|
17
|
+
);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export default AllFuaRequestsTile;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useTranslation } from 'react-i18next';
|
|
3
|
+
import { useFuaRequests } from '../hooks/useFuaRequests';
|
|
4
|
+
import FuaSummaryTile from '../components/summary-tiles/summary-tile.component';
|
|
5
|
+
|
|
6
|
+
const CompletedFuaRequestsTile = () => {
|
|
7
|
+
const { t } = useTranslation();
|
|
8
|
+
const { fuaOrders } = useFuaRequests({ status: 'COMPLETED', excludeCanceled: false });
|
|
9
|
+
|
|
10
|
+
return (
|
|
11
|
+
<FuaSummaryTile
|
|
12
|
+
label={t('completed', 'Completed')}
|
|
13
|
+
value={fuaOrders?.length}
|
|
14
|
+
headerLabel={t('results', 'Results')}
|
|
15
|
+
/>
|
|
16
|
+
);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export default CompletedFuaRequestsTile;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useTranslation } from 'react-i18next';
|
|
3
|
+
import { type AssignedExtension, useAssignedExtensions, Extension, useConfig } from '@openmrs/esm-framework';
|
|
4
|
+
import { ComponentContext } from '@openmrs/esm-framework/src/internal';
|
|
5
|
+
import styles from './fua-summary-tiles.scss';
|
|
6
|
+
import { type Config } from '../config-schema';
|
|
7
|
+
|
|
8
|
+
const FuaSummaryTiles: React.FC = () => {
|
|
9
|
+
const { t } = useTranslation();
|
|
10
|
+
const { enableReviewingLabResultsBeforeApproval } = useConfig<Config>();
|
|
11
|
+
const fuaTileSlot = 'fua-tiles-slot';
|
|
12
|
+
const tilesExtensions = useAssignedExtensions(fuaTileSlot) as AssignedExtension[];
|
|
13
|
+
|
|
14
|
+
const filteredExtensions = tilesExtensions
|
|
15
|
+
.filter((extension) => Object.keys(extension.meta).length > 0)
|
|
16
|
+
.filter((extension) => {
|
|
17
|
+
if (extension.name === 'pending-review-list-tile-component') {
|
|
18
|
+
return enableReviewingLabResultsBeforeApproval === true;
|
|
19
|
+
}
|
|
20
|
+
return true;
|
|
21
|
+
});
|
|
22
|
+
return (
|
|
23
|
+
<div className={styles.cardContainer}>
|
|
24
|
+
{filteredExtensions.map((extension, index) => {
|
|
25
|
+
return (
|
|
26
|
+
<ComponentContext.Provider
|
|
27
|
+
key={extension.id}
|
|
28
|
+
value={{
|
|
29
|
+
moduleName: extension.moduleName,
|
|
30
|
+
featureName: 'fua',
|
|
31
|
+
extension: {
|
|
32
|
+
extensionId: extension.id,
|
|
33
|
+
extensionSlotName: fuaTileSlot,
|
|
34
|
+
extensionSlotModuleName: extension.moduleName,
|
|
35
|
+
},
|
|
36
|
+
}}
|
|
37
|
+
>
|
|
38
|
+
<Extension />
|
|
39
|
+
</ComponentContext.Provider>
|
|
40
|
+
);
|
|
41
|
+
})}
|
|
42
|
+
</div>
|
|
43
|
+
);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export default FuaSummaryTiles;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
@use '@carbon/layout';
|
|
2
|
+
@use '@carbon/type';
|
|
3
|
+
@use '@openmrs/esm-styleguide/src/vars' as *;
|
|
4
|
+
|
|
5
|
+
.cardContainer {
|
|
6
|
+
background-color: $ui-02;
|
|
7
|
+
display: flex;
|
|
8
|
+
flex-wrap: wrap;
|
|
9
|
+
padding: layout.$spacing-03;
|
|
10
|
+
gap: 0 layout.$spacing-01;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.cardContainer>div {
|
|
14
|
+
flex: 1 1 300px;
|
|
15
|
+
box-sizing: border-box;
|
|
16
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useTranslation } from 'react-i18next';
|
|
3
|
+
import { useFuaRequests } from '../hooks/useFuaRequests';
|
|
4
|
+
import FuaSummaryTile from '../components/summary-tiles/summary-tile.component';
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
const InProgressFuaRequestsTile = () => {
|
|
8
|
+
const { t } = useTranslation();
|
|
9
|
+
const { fuaOrders } = useFuaRequests({ status: 'IN_PROGRESS' });
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<FuaSummaryTile
|
|
13
|
+
label={t('inProgress', 'In progress')}
|
|
14
|
+
value={fuaOrders?.length}
|
|
15
|
+
headerLabel={t('worklist', 'Ex-Worklist')}
|
|
16
|
+
/>
|
|
17
|
+
);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export default InProgressFuaRequestsTile;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
|
+
import { useConfig, showSnackbar } from '@openmrs/esm-framework';
|
|
3
|
+
import { InlineLoading } from '@carbon/react';
|
|
4
|
+
import type { Config } from '../config-schema';
|
|
5
|
+
import styles from './fua-viewer-page.scss';
|
|
6
|
+
|
|
7
|
+
const FuaViewerPage: React.FC = () => {
|
|
8
|
+
const config = useConfig<Config>();
|
|
9
|
+
const endpoint = config.fuaGeneratorEndpoint;
|
|
10
|
+
const [htmlContent, setHtmlContent] = useState<string>('');
|
|
11
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
12
|
+
const [error, setError] = useState<string | null>(null);
|
|
13
|
+
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
const fetchHtml = async () => {
|
|
16
|
+
try {
|
|
17
|
+
setIsLoading(true);
|
|
18
|
+
setError(null);
|
|
19
|
+
|
|
20
|
+
const response = await fetch(endpoint);
|
|
21
|
+
|
|
22
|
+
if (!response.ok) {
|
|
23
|
+
throw new Error(`Error al cargar el contenido: ${response.status} ${response.statusText}`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const html = await response.text();
|
|
27
|
+
setHtmlContent(html);
|
|
28
|
+
} catch (err) {
|
|
29
|
+
const errorMessage = err instanceof Error ? err.message : 'Error desconocido al cargar el contenido';
|
|
30
|
+
setError(errorMessage);
|
|
31
|
+
console.error('Error fetching FUA HTML:', err);
|
|
32
|
+
showSnackbar({
|
|
33
|
+
title: 'Error al cargar FUA',
|
|
34
|
+
subtitle: errorMessage,
|
|
35
|
+
kind: 'error',
|
|
36
|
+
});
|
|
37
|
+
} finally {
|
|
38
|
+
setIsLoading(false);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
fetchHtml();
|
|
43
|
+
}, [endpoint]);
|
|
44
|
+
|
|
45
|
+
if (isLoading) {
|
|
46
|
+
return (
|
|
47
|
+
<div className={styles.loadingContainer}>
|
|
48
|
+
<InlineLoading description="Cargando visor de FUA..." />
|
|
49
|
+
</div>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (error) {
|
|
54
|
+
return (
|
|
55
|
+
<div className={styles.errorContainer}>
|
|
56
|
+
<h3>⚠️ Error al cargar el visor de FUA</h3>
|
|
57
|
+
<p>{error}</p>
|
|
58
|
+
<details>
|
|
59
|
+
<summary>Información técnica</summary>
|
|
60
|
+
<p><strong>Endpoint:</strong> {endpoint}</p>
|
|
61
|
+
<p><strong>Posibles causas:</strong></p>
|
|
62
|
+
<ul>
|
|
63
|
+
<li>El servidor no está respondiendo</li>
|
|
64
|
+
<li>Políticas CORS bloqueando la conexión</li>
|
|
65
|
+
<li>El endpoint configurado es incorrecto</li>
|
|
66
|
+
</ul>
|
|
67
|
+
<p><strong>Soluciones:</strong></p>
|
|
68
|
+
<ul>
|
|
69
|
+
<li>Verifica que el servidor esté funcionando</li>
|
|
70
|
+
<li>Prueba el endpoint directamente en tu navegador</li>
|
|
71
|
+
<li>Contacta al administrador del sistema</li>
|
|
72
|
+
</ul>
|
|
73
|
+
</details>
|
|
74
|
+
</div>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<div className={styles.pageContainer}>
|
|
80
|
+
<iframe
|
|
81
|
+
srcDoc={htmlContent}
|
|
82
|
+
title="Visor de FUA"
|
|
83
|
+
className={styles.fullIframe}
|
|
84
|
+
sandbox="allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox allow-forms"
|
|
85
|
+
/>
|
|
86
|
+
</div>
|
|
87
|
+
);
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export default FuaViewerPage;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
@use '@carbon/styles/scss/spacing';
|
|
2
|
+
@use '@carbon/styles/scss/type';
|
|
3
|
+
|
|
4
|
+
.pageContainer {
|
|
5
|
+
width: 100%;
|
|
6
|
+
height: 100vh;
|
|
7
|
+
margin: 0;
|
|
8
|
+
padding: 0;
|
|
9
|
+
overflow: hidden;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.fullIframe {
|
|
13
|
+
width: 100%;
|
|
14
|
+
height: 100%;
|
|
15
|
+
border: none;
|
|
16
|
+
margin: 0;
|
|
17
|
+
padding: 0;
|
|
18
|
+
display: block;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.loadingContainer {
|
|
22
|
+
display: flex;
|
|
23
|
+
justify-content: center;
|
|
24
|
+
align-items: center;
|
|
25
|
+
height: 100vh;
|
|
26
|
+
padding: spacing.$spacing-05;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.errorContainer {
|
|
30
|
+
display: flex;
|
|
31
|
+
flex-direction: column;
|
|
32
|
+
justify-content: center;
|
|
33
|
+
align-items: center;
|
|
34
|
+
height: 100vh;
|
|
35
|
+
padding: spacing.$spacing-07;
|
|
36
|
+
text-align: center;
|
|
37
|
+
max-width: 800px;
|
|
38
|
+
margin: 0 auto;
|
|
39
|
+
|
|
40
|
+
h3 {
|
|
41
|
+
@include type.type-style('heading-03');
|
|
42
|
+
color: #da1e28;
|
|
43
|
+
margin-bottom: spacing.$spacing-05;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
p {
|
|
47
|
+
@include type.type-style('body-01');
|
|
48
|
+
color: #525252;
|
|
49
|
+
margin-bottom: spacing.$spacing-03;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
details {
|
|
53
|
+
margin-top: spacing.$spacing-05;
|
|
54
|
+
text-align: left;
|
|
55
|
+
width: 100%;
|
|
56
|
+
background-color: #f4f4f4;
|
|
57
|
+
padding: spacing.$spacing-05;
|
|
58
|
+
border-radius: 4px;
|
|
59
|
+
border-left: 3px solid #da1e28;
|
|
60
|
+
|
|
61
|
+
summary {
|
|
62
|
+
@include type.type-style('label-01');
|
|
63
|
+
cursor: pointer;
|
|
64
|
+
font-weight: 600;
|
|
65
|
+
margin-bottom: spacing.$spacing-03;
|
|
66
|
+
|
|
67
|
+
&:hover {
|
|
68
|
+
color: #0f62fe;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
ul {
|
|
73
|
+
margin-left: spacing.$spacing-05;
|
|
74
|
+
margin-top: spacing.$spacing-03;
|
|
75
|
+
|
|
76
|
+
li {
|
|
77
|
+
@include type.type-style('body-compact-01');
|
|
78
|
+
margin-bottom: spacing.$spacing-02;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import dayjs from 'dayjs';
|
|
2
|
+
import useSWR from 'swr';
|
|
3
|
+
import { openmrsFetch, useAppContext } from '@openmrs/esm-framework';
|
|
3
4
|
import { ModuleFuaRestURL } from '../constant';
|
|
4
5
|
|
|
5
6
|
export interface FuaEstado {
|
|
@@ -19,30 +20,96 @@ export interface FuaRequest {
|
|
|
19
20
|
fechaActualizacion: number;
|
|
20
21
|
}
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
23
|
+
export interface DateFilterContext {
|
|
24
|
+
dateRange: [Date, Date];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const useFuaRequestsDefaultParams: UseFuaRequestsParams = {
|
|
28
|
+
status: null,
|
|
29
|
+
newOrdersOnly: false,
|
|
30
|
+
excludeCanceled: true,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export interface UseFuaRequestsParams {
|
|
34
|
+
status: string | null;
|
|
35
|
+
newOrdersOnly: boolean;
|
|
36
|
+
excludeCanceled: boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Custom hook for retrieving FUA requests based on the specified status.
|
|
41
|
+
*
|
|
42
|
+
* @param status - The status of the requests to retrieve
|
|
43
|
+
* @param excludeCanceled - Whether to exclude canceled requests
|
|
44
|
+
* @param newOrdersOnly - Whether to retrieve only new orders
|
|
45
|
+
*/
|
|
46
|
+
export function useFuaRequests(params: Partial<UseFuaRequestsParams> = useFuaRequestsDefaultParams) {
|
|
47
|
+
const { status, newOrdersOnly, excludeCanceled } = { ...useFuaRequestsDefaultParams, ...params };
|
|
48
|
+
const { dateRange } = useAppContext<DateFilterContext>('fua-date-filter') ?? {
|
|
49
|
+
dateRange: [dayjs().startOf('day').toDate(), new Date()],
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
let url = `${ModuleFuaRestURL}/list`;
|
|
53
|
+
const queryParams: string[] = [];
|
|
54
|
+
|
|
55
|
+
if (status) {
|
|
56
|
+
queryParams.push(`status=${status}`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (excludeCanceled) {
|
|
60
|
+
queryParams.push('excludeCanceled=true');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (dateRange) {
|
|
64
|
+
queryParams.push(`startDate=${dateRange.at(0).toISOString()}`);
|
|
65
|
+
queryParams.push(`endDate=${dateRange.at(1).toISOString()}`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (queryParams.length > 0) {
|
|
69
|
+
url = `${url}?${queryParams.join('&')}`;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const { data, error, mutate, isLoading, isValidating } = useSWR<{ data: Array<FuaRequest> }>(
|
|
73
|
+
url,
|
|
74
|
+
openmrsFetch,
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
// openmrsFetch returns { data: T }, so we access data.data to get the array
|
|
78
|
+
const allOrders = data?.data ?? [];
|
|
79
|
+
|
|
80
|
+
const filteredOrders = allOrders.filter(
|
|
81
|
+
(order) => !newOrdersOnly || (order?.fuaEstado === null || order?.fuaEstado === undefined),
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
fuaOrders: filteredOrders,
|
|
86
|
+
isLoading,
|
|
87
|
+
isError: error,
|
|
88
|
+
mutate,
|
|
89
|
+
isValidating,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function setFuaEstado(fuaRequestId: string, estadoId: number, abortController: AbortController) {
|
|
94
|
+
return openmrsFetch(`${ModuleFuaRestURL}/${fuaRequestId}/estado`, {
|
|
95
|
+
method: 'POST',
|
|
96
|
+
headers: {
|
|
97
|
+
'Content-Type': 'application/json',
|
|
98
|
+
},
|
|
99
|
+
signal: abortController.signal,
|
|
100
|
+
body: { estadoId },
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function cancelFuaRequest(fuaRequestId: string, comment: string, abortController: AbortController) {
|
|
105
|
+
return openmrsFetch(`${ModuleFuaRestURL}/${fuaRequestId}/cancel`, {
|
|
106
|
+
method: 'POST',
|
|
107
|
+
headers: {
|
|
108
|
+
'Content-Type': 'application/json',
|
|
109
|
+
},
|
|
110
|
+
signal: abortController.signal,
|
|
111
|
+
body: { comment },
|
|
112
|
+
});
|
|
46
113
|
}
|
|
47
114
|
|
|
48
115
|
export default useFuaRequests;
|
package/src/index.ts
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import { defineConfigSchema, getAsyncLifecycle, getSyncLifecycle } from '@openmrs/esm-framework';
|
|
2
|
-
import { createDashboardLink } from '@openmrs/esm-patient-common-lib';
|
|
3
2
|
import { configSchema } from './config-schema';
|
|
4
3
|
import { createLeftPanelLink } from './left-panel-link.component';
|
|
5
|
-
import
|
|
6
|
-
import { FuaRequestDashboardMeta } from './dashboard.meta';
|
|
4
|
+
import rootComponent from './root.component';
|
|
7
5
|
|
|
8
6
|
export const importTranslation = require.context('../translations', false, /.json$/, 'lazy');
|
|
9
7
|
|
|
10
8
|
const moduleName = '@pucp-gidis-hiisc/esm-fua-app';
|
|
9
|
+
|
|
11
10
|
const options = {
|
|
12
|
-
featureName: '
|
|
11
|
+
featureName: 'fua',
|
|
13
12
|
moduleName,
|
|
14
13
|
};
|
|
15
14
|
|
|
@@ -21,7 +20,83 @@ export function startupApp(): void {
|
|
|
21
20
|
}
|
|
22
21
|
|
|
23
22
|
// ================================================================================
|
|
24
|
-
//
|
|
23
|
+
// ROOT COMPONENT
|
|
24
|
+
// ================================================================================
|
|
25
|
+
export const root = getSyncLifecycle(rootComponent, options);
|
|
26
|
+
|
|
27
|
+
// ================================================================================
|
|
28
|
+
// DASHBOARD LINK
|
|
29
|
+
// ================================================================================
|
|
30
|
+
export const fuaDashboardLink = getSyncLifecycle(
|
|
31
|
+
createLeftPanelLink({
|
|
32
|
+
name: 'fua-request',
|
|
33
|
+
title: 'Formato Único de Atención',
|
|
34
|
+
}),
|
|
35
|
+
options,
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
// ================================================================================
|
|
40
|
+
// TILES
|
|
41
|
+
// ================================================================================
|
|
42
|
+
export const allFuaRequestsTile = getAsyncLifecycle(
|
|
43
|
+
() => import('./fua-tiles/all-fua-requests-tile.component'),
|
|
44
|
+
options,
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
export const inProgressFuaRequestsTile = getAsyncLifecycle(
|
|
48
|
+
() => import('./fua-tiles/in-progress-fua-requests-tile.component'),
|
|
49
|
+
options,
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
export const completedFuaRequestsTile = getAsyncLifecycle(
|
|
53
|
+
() => import('./fua-tiles/completed-fua-requests-tile.component'),
|
|
54
|
+
options,
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
// ================================================================================
|
|
58
|
+
// TABLES/TABS
|
|
59
|
+
// ================================================================================
|
|
60
|
+
export const allFuaRequestsTable = getAsyncLifecycle(
|
|
61
|
+
() => import('./fua-tabs/data-table-extensions/all-fua-requests-table.extension'),
|
|
62
|
+
options,
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
export const inProgressFuaRequestsTable = getAsyncLifecycle(
|
|
66
|
+
() => import('./fua-tabs/data-table-extensions/in-progress-fua-requests-table.extension'),
|
|
67
|
+
options,
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
export const completedFuaRequestsTable = getAsyncLifecycle(
|
|
71
|
+
() => import('./fua-tabs/data-table-extensions/completed-fua-requests-table.extension'),
|
|
72
|
+
options,
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
export const declinedFuaRequestsTable = getAsyncLifecycle(
|
|
76
|
+
() => import('./fua-tabs/data-table-extensions/declined-fua-requests-table.extension'),
|
|
77
|
+
options,
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
// ================================================================================
|
|
81
|
+
// HTML VIEWER
|
|
82
|
+
// ================================================================================
|
|
83
|
+
export const fuaHtmlViewer = getAsyncLifecycle(
|
|
84
|
+
() => import('./components/fua-html-viewer.component'),
|
|
85
|
+
options,
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
// ================================================================================
|
|
89
|
+
// WORKSPACES
|
|
90
|
+
// ================================================================================
|
|
91
|
+
export const fuaViewerWorkspace = getAsyncLifecycle(
|
|
92
|
+
() => import('./workspaces/fua-viewer.workspace'),
|
|
93
|
+
options,
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
// ================================================================================
|
|
97
|
+
// FUA VIEWER PAGE
|
|
25
98
|
// ================================================================================
|
|
26
|
-
export const
|
|
27
|
-
|
|
99
|
+
export const fuaViewerPage = getAsyncLifecycle(
|
|
100
|
+
() => import('./fua-viewer-page/fua-viewer-page.component'),
|
|
101
|
+
options,
|
|
102
|
+
);
|