Skip to content
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

Open
wants to merge 20 commits into
base: main
Choose a base branch
from

Conversation

arodidev
Copy link
Contributor

@arodidev arodidev commented Apr 2, 2024

Requirements

  • This PR has a title that briefly describes the work done including the ticket number. If there is a ticket, make sure your PR title includes a conventional commit label. See existing PR titles for inspiration.
  • My work conforms to the OpenMRS 3.0 Styleguide and design documentation.
  • My work includes tests or is validated by existing tests.

Summary

This PR introduces metric tiles to the refApp homepage that track three key reporting metrics:

  1. Active visits.
  2. Total visits for the day.
  3. Patient appointments scheduled for the day.

The metric tiles are loaded into the metrics-extension-slot created within this monorepo in a bid to give more control over positioning of the tiles within a parent container, thus negating the need to add a display: flex property to the extension slots within the homepage. This extension is then loaded into the home-dashboard-slot within openmrs-esm-home.

This PR together with the homepage dashboard header PR should complete the initial phase of the home dashboard revamp.

Screenshots

Screen.Recording.2024-04-16.at.11.51.58.mov

Related Issue

Other

@pirupius
Copy link
Member

@arodidev some quick design comments as i look at the code. Are u able to add a video showing the responsiveness? There is also some discrepancy with the text styling for example the word Patients seems to be bold which doesn't match this guideline https://zeroheight.com/23a080e38/p/8358ed-page-header

Copy link
Member

@pirupius pirupius left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @arodidev for the work on this. I've left some early clean up comments

Comment on lines 18 to 20
urlSearchParams.append('includeInactive', 'false');
urlSearchParams.append('totalCount', 'true');
urlSearchParams.append('location', `${sessionLocation}`);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a use case for this? Is this tied to other data within the home screen that has a search functionality or is this purely a way to chain params to the url?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Majorly chaining params together, although I am not sure I fully understand your question, but it is tied to sessionLocation from the home page.

import { ExtensionSlot } from '@openmrs/esm-framework';
import React from 'react';

const MetricsSlot = () => {
Copy link
Member

Choose a reason for hiding this comment

The 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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My though process behind this:

  • We need a way to manage the parent container of the metric tiles that does not rely on openmrs-esm-home since that slot should be totally generic and agnostic of whatever is loaded into it.
  • This works since the different tiles reside within different esms (esm-active-visits-app, esm-appointments-app) but need to live inside a single container for the purposes of uniformity of styling/ alignment, and also so that they are loaded into the extension slot within openmrs-esm-home as a single unit instead of three individual tiles.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is my understanding;

  • This component(MetricSlot) introduces the Metrics slot which is specific to the home.
  • Different esm can then define tiles that are attached to this slot.

What am suggesting is this specific component defining the metrics-slot should be esm-home and patient-management let alone the esm-visits-app. It's not a tied to the visits esm and implementers who decide not to include the esm-visits in the importmap would have this. But implementations that have esm-home should be able to take advantage of the metrics-tiles-slot

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aah, I see what you mean! Which begs the question, where within patient-management would you suggest I define this? Could there be a way to represent this logic independent of any of the modules? I hope my understanding of what you said was correct.

packages/esm-active-visits-app/src/routes.json Outdated Show resolved Hide resolved
startDatetime: string;
stopDatetime?: string;
attributes?: Array<OpenmrsResource>;
[anythingElse: string]: any;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this a placeholder?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you referring to: [anythingElse: string]: any;?
If so then this was just a contingency.

Copy link
Member

Choose a reason for hiding this comment

The 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 (visit as any).prop = value as a work-around.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the clarity, will resolve this.

packages/esm-active-visits-app/src/types/index.ts Outdated Show resolved Hide resolved
packages/esm-appointments-app/src/routes.json Outdated Show resolved Hide resolved
@arodidev
Copy link
Contributor Author

Thanks @arodidev for the work on this. I've left some early clean up comments

Will get to work on these, thank you for your review.

@arodidev arodidev requested a review from pirupius April 16, 2024 14:01
Copy link
Member

@pirupius pirupius left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @arodidev for the continuous work on this. I've left some more todo's to clean this up

return (
<React.Fragment>
<Tile className={styles.tileContainer}>
<div>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This tag seems redundant

Comment on lines 16 to 17
<div className={styles.tileHeader}>
<header>{t('activeVisits', 'Active Visits')}</header>
Copy link
Member

Choose a reason for hiding this comment

The 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

<header>{t('activeVisits', 'Active Visits')}</header>
</div>
<div className={styles.displayDetails}>
<div className={styles.countLabel}>Patients</div>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add translation for Patients

const customRepresentation = 'custom:(uuid,startDatetime,stopDatetime)';

const getUrl = () => {
let url = `/ws/rest/v1/visit?v=${customRepresentation}&`;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let url = `/ws/rest/v1/visit?v=${customRepresentation}&`;
let url = `${restBaseUrl}/visit?v=${customRepresentation}&`;

Comment on lines 15 to 19
<div>
<div className={styles.tileContent}>
<div className={styles.tileHeader}>
<header>{t('totalVisits', 'Total Visits Today')}</header>
</div>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comments apply to this component about cleaning this up

Comment on lines 17 to 19
const responseData = data?.data.results;

return { data: responseData, error, isLoading };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const responseData = data?.data.results;
return { data: responseData, error, isLoading };
return { data: data?.data.results, error, isLoading };

startDatetime: string;
stopDatetime?: string;
attributes?: Array<OpenmrsResource>;
[anythingElse: string]: any;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's delete this

Comment on lines 15 to 22
<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>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comments apply about cleaning this component

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}`;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const url = `ws/rest/v1/appointment/all?forDate=${appointmentDate}`;
const url = `${restBaseUrl}/appointment/all?forDate=${appointmentDate}`;

Comment on lines 13 to 15
const responseData = data?.data;

return { data: responseData, error, isLoading };
Copy link
Member

@pirupius pirupius Apr 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this intentional? Does data?.data have the necessary information to be displayed or do u have to chain results like the rest

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the initial render data.data will throw an error because the network request hasn't been fulfilled yet.

@arodidev arodidev requested a review from pirupius April 16, 2024 18:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants