-
Notifications
You must be signed in to change notification settings - Fork 189
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
(feat) O3-3018: Adding metric tiles to the refApp homepage. #1075
base: main
Are you sure you want to change the base?
Changes from 17 commits
b5e71d5
3a3f706
41b5fbe
5e30eec
c8fec9a
c0df520
5f5c033
a498561
80e7ab7
70b1138
d54bca9
91ca09b
f8a23de
85c7d8f
a52fb6d
afd8ef8
31b1421
f151e66
530e4cf
2dccd12
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import React from 'react'; | ||
import { Tile } from '@carbon/react'; | ||
import styles from '../homepage-tiles.scss'; | ||
import { useTranslation } from 'react-i18next'; | ||
import useActiveVisits from './active-visits-tile.resources'; | ||
|
||
const ActiveVisitsTile: React.FC = () => { | ||
const { data: activeVisitsData } = useActiveVisits(); | ||
|
||
const { t } = useTranslation(); | ||
return ( | ||
<React.Fragment> | ||
<Tile className={styles.tileContainer}> | ||
<div> | ||
<div className={styles.tileContent}> | ||
<div className={styles.tileHeader}> | ||
<header>{t('activeVisits', 'Active Visits')}</header> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we just move the className to the header and eliminate the need for the extra |
||
</div> | ||
<div className={styles.displayDetails}> | ||
<div className={styles.countLabel}>Patients</div> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add translation for |
||
<div className={styles.displayData}>{activeVisitsData?.length ?? 0}</div> | ||
</div> | ||
</div> | ||
</div> | ||
</Tile> | ||
</React.Fragment> | ||
); | ||
}; | ||
|
||
export default ActiveVisitsTile; |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,28 @@ | ||||||
import { openmrsFetch, useSession } from '@openmrs/esm-framework'; | ||||||
import useSWR from 'swr'; | ||||||
|
||||||
export default function useActiveVisits() { | ||||||
const session = useSession(); | ||||||
const sessionLocation = session?.sessionLocation?.uuid; | ||||||
|
||||||
const customRepresentation = 'custom:(uuid,startDatetime,stopDatetime)'; | ||||||
|
||||||
const getUrl = () => { | ||||||
let url = `/ws/rest/v1/visit?v=${customRepresentation}&`; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
let urlSearchParams = new URLSearchParams(); | ||||||
|
||||||
urlSearchParams.append('includeInactive', 'false'); | ||||||
urlSearchParams.append('totalCount', 'true'); | ||||||
urlSearchParams.append('location', `${sessionLocation}`); | ||||||
|
||||||
return url + urlSearchParams.toString(); | ||||||
}; | ||||||
|
||||||
const { data, error, isLoading } = useSWR<{ data: { results: any[]; totalCount: number } }>(getUrl, openmrsFetch); | ||||||
|
||||||
return { | ||||||
data: data?.data.results, | ||||||
error, | ||||||
isLoading, | ||||||
}; | ||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
@use '@carbon/type'; | ||
@use '@carbon/colors'; | ||
@import '~@openmrs/esm-styleguide/src/vars'; | ||
|
||
.tileContent { | ||
display: flex; | ||
flex-direction: column; | ||
align-items: space-between; | ||
} | ||
|
||
.tileContainer { | ||
background-color: white; | ||
border: 0.0625rem solid #e0e0e0; | ||
height: 7.875rem; | ||
padding: 1rem; | ||
margin: 0.5rem 0.5rem; | ||
} | ||
|
||
.tileHeader { | ||
font-size: 0.875rem; | ||
font-weight: 600; | ||
line-height: 1.28572; | ||
letter-spacing: 0.16px; | ||
color: #525252; | ||
} | ||
|
||
.displayDetails { | ||
margin-top: 1.5rem; | ||
} | ||
|
||
.displayData { | ||
font-size: 1.75rem; | ||
font-weight: 400; | ||
line-height: 1.28572; | ||
letter-spacing: 0; | ||
color: #161616; | ||
} | ||
|
||
.countLabel { | ||
@include type.type-style('label-01'); | ||
color: $text-02; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { ExtensionSlot } from '@openmrs/esm-framework'; | ||
import React from 'react'; | ||
import styles from './metrics-slot.scss'; | ||
|
||
const MetricsSlot = () => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This becomes tricky when we're adding tiles from other esms. Can we maintain this in the esm home? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My though process behind this:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is my understanding;
What am suggesting is this specific component defining the metrics-slot should be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Aah, I see what you mean! Which begs the question, where within There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The slot would move to the |
||
return <ExtensionSlot name="metrics-extension-slot" className={styles.extensionSlot} />; | ||
}; | ||
|
||
export default MetricsSlot; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
.extensionSlot { | ||
display: grid; | ||
grid-template-columns: 1fr 1fr 1fr; | ||
margin: 0 0.5rem; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import React from 'react'; | ||
import { Tile } from '@carbon/react'; | ||
import styles from '../homepage-tiles.scss'; | ||
import { useTranslation } from 'react-i18next'; | ||
import useTotalVisits from './total-visits-tile.resources'; | ||
|
||
const TotalVisitsTile: React.FC = () => { | ||
const { data: appointmentsData } = useTotalVisits(); | ||
|
||
const { t } = useTranslation(); | ||
|
||
return ( | ||
<React.Fragment> | ||
<Tile className={styles.tileContainer}> | ||
<div> | ||
<div className={styles.tileContent}> | ||
<div className={styles.tileHeader}> | ||
<header>{t('totalVisits', 'Total Visits Today')}</header> | ||
</div> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same comments apply to this component about cleaning this up |
||
<div className={styles.displayDetails}> | ||
<div className={styles.countLabel}>Patients</div> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Translations |
||
<div className={styles.displayData}>{appointmentsData?.length ?? 0}</div> | ||
</div> | ||
</div> | ||
</div> | ||
</Tile> | ||
</React.Fragment> | ||
); | ||
}; | ||
|
||
export default TotalVisitsTile; |
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,22 @@ | ||||||||||
import { openmrsFetch } from '@openmrs/esm-framework'; | ||||||||||
import useSWR from 'swr'; | ||||||||||
import dayjs from 'dayjs'; | ||||||||||
import { type Visit } from '../../types/index'; | ||||||||||
|
||||||||||
const useTotalVisits = () => { | ||||||||||
const omrsDateFormat = 'YYYY-MM-DDTHH:mm:ss.SSSZZ'; | ||||||||||
const currentVisitDate = dayjs(new Date().setHours(0, 0, 0, 0)).format(omrsDateFormat); | ||||||||||
const customRepresentation = 'custom:(uuid,startDatetime,stopDatetime)'; | ||||||||||
|
||||||||||
const visitsUrl = `/ws/rest/v1/visit?includeInactive=true&v=${customRepresentation}&fromStartDate=${dayjs( | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
currentVisitDate, | ||||||||||
).format('YYYY-MM-DD')}`; | ||||||||||
|
||||||||||
const { data, error, isLoading } = useSWR<{ data: { results: Visit[] } }>(visitsUrl, openmrsFetch); | ||||||||||
|
||||||||||
const responseData = data?.data.results; | ||||||||||
|
||||||||||
return { data: responseData, error, isLoading }; | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
}; | ||||||||||
|
||||||||||
export default useTotalVisits; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
import { type OpenmrsResource } from '@openmrs/esm-framework'; | ||
|
||
export interface SearchedPatient { | ||
patientId: number; | ||
uuid: string; | ||
|
@@ -26,3 +28,16 @@ export interface Identifier { | |
preferred: boolean; | ||
voided: boolean; | ||
} | ||
|
||
export interface Visit { | ||
uuid: string; | ||
display?: string; | ||
encounters: Array<OpenmrsResource>; | ||
patient?: OpenmrsResource; | ||
visitType: OpenmrsResource; | ||
location?: OpenmrsResource; | ||
startDatetime: string; | ||
stopDatetime?: string; | ||
attributes?: Array<OpenmrsResource>; | ||
[anythingElse: string]: any; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Was this a placeholder? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are you referring to: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's best not to have this. That forces us to confront any short-comings in the types instead of ignoring them... and if someone really needs to use a different property, there's always There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you for the clarity, will resolve this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's delete this |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import React from 'react'; | ||
import { Tile } from '@carbon/react'; | ||
import styles from './appointments-tile.scss'; | ||
import { useTranslation } from 'react-i18next'; | ||
import useAppointmentsData from './appointments-tile.resources'; | ||
|
||
const AppointmentsTile: React.FC = () => { | ||
const { data: appointmentsData } = useAppointmentsData(); | ||
|
||
const { t } = useTranslation(); | ||
|
||
return ( | ||
<React.Fragment> | ||
<Tile className={styles.tileContainer}> | ||
<div> | ||
<div className={styles.tileContent}> | ||
<div className={styles.tileHeader}> | ||
<header>{t('scheduledForToday', 'Scheduled For Today')}</header> | ||
</div> | ||
<div className={styles.displayDetails}> | ||
<div className={styles.countLabel}>Patients</div> | ||
<div className={styles.displayData}>{appointmentsData?.length ?? 0}</div> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same comments apply about cleaning this component |
||
</div> | ||
</div> | ||
</div> | ||
</Tile> | ||
</React.Fragment> | ||
); | ||
}; | ||
|
||
export default AppointmentsTile; |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,18 @@ | ||||||
import { openmrsFetch } from '@openmrs/esm-framework'; | ||||||
import useSWR from 'swr'; | ||||||
import dayjs from 'dayjs'; | ||||||
|
||||||
const useAppointmentsData = () => { | ||||||
const omrsDateFormat = 'YYYY-MM-DDTHH:mm:ss.SSSZZ'; | ||||||
const appointmentDate = dayjs(new Date().setHours(0, 0, 0, 0)).format(omrsDateFormat); | ||||||
|
||||||
const url = `ws/rest/v1/appointment/all?forDate=${appointmentDate}`; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
const { data, error, isLoading } = useSWR<{ data: Array<any> }>(url, openmrsFetch); | ||||||
|
||||||
const responseData = data?.data; | ||||||
|
||||||
return { data: responseData, error, isLoading }; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Was this intentional? Does There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On the initial render |
||||||
}; | ||||||
|
||||||
export default useAppointmentsData; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
@use '@carbon/type'; | ||
@use '@carbon/colors'; | ||
@import '~@openmrs/esm-styleguide/src/vars'; | ||
|
||
.tileContent { | ||
display: flex; | ||
flex-direction: column; | ||
align-items: space-between; | ||
} | ||
|
||
.tileContainer { | ||
background-color: white; | ||
border: 0.0625rem solid #e0e0e0; | ||
height: 7.875rem; | ||
padding: 1rem; | ||
margin: 0.5rem 0.5rem; | ||
} | ||
|
||
.tileHeader { | ||
font-size: 0.875rem; | ||
font-weight: 600; | ||
line-height: 1.28572; | ||
letter-spacing: 0.16px; | ||
color: #525252; | ||
} | ||
|
||
.displayDetails { | ||
margin-top: 1.5rem; | ||
} | ||
|
||
.displayData { | ||
font-size: 1.75rem; | ||
font-weight: 400; | ||
line-height: 1.28572; | ||
letter-spacing: 0; | ||
color: #161616; | ||
} | ||
|
||
.countLabel { | ||
@include type.type-style('label-01'); | ||
color: $text-02; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This tag seems redundant