Skip to content

Commit 7b90fbd

Browse files
committedJan 13, 2023
UI enhancement and adapt appointment module to match designs (openmrs#11)
* Update CI * Complete deployment changes
1 parent 1865df0 commit 7b90fbd

15 files changed

+280
-121
lines changed
 

‎.github/workflows/ci.yml

+81-62
Original file line numberDiff line numberDiff line change
@@ -236,14 +236,15 @@ jobs:
236236
password: ${{ secrets.DEPLOYER_PASSWORD }}
237237
data: '{ "service":"${{ env.ESM_NAME }}","url":"https://donaldkibet.fra1.digitaloceanspaces.com/${{ env.ESM_NAME }}/${{ env.TIMESTAMP }}_${{ github.sha }}/${{ env.JS_NAME }}" }'
238238
customHeaders: '{ "Accept": "application/json", "Content-Type": "application/json" }'
239+
239240

240-
deploy_patient_list_app:
241+
deploy_active_visits_app:
241242
runs-on: ubuntu-latest
242243

243244
env:
244-
DIR_NAME: "esm-patient-list-app"
245-
ESM_NAME: "@openmrs/esm-patient-list-app"
246-
JS_NAME: "openmrs-esm-patient-list-app.js"
245+
DIR_NAME: "esm-active-visits-app"
246+
ESM_NAME: "@openmrs/esm-active-visits-app"
247+
JS_NAME: "openmrs-esm-active-visits-app.js"
247248

248249
needs: build
249250

@@ -261,7 +262,6 @@ jobs:
261262
run: |
262263
mkdir -p dist/${{ env.ESM_NAME }}/${{ env.TIMESTAMP }}_${{ github.sha }}
263264
mv packages/${{ env.DIR_NAME }}/dist/*.* dist/${{ env.ESM_NAME }}/${{ env.TIMESTAMP }}_${{ github.sha }}/
264-
265265
- name: Publish to Digital Ocean
266266
uses: jakejarvis/s3-sync-action@master
267267
with:
@@ -272,7 +272,6 @@ jobs:
272272
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
273273
AWS_S3_ENDPOINT: ${{ secrets.AWS_S3_ENDPOINT }}
274274
SOURCE_DIR: "dist"
275-
276275
- name: Update Importmap
277276
uses: fjogeleit/http-request-action@master
278277
with:
@@ -283,13 +282,13 @@ jobs:
283282
data: '{ "service":"${{ env.ESM_NAME }}","url":"https://donaldkibet.fra1.digitaloceanspaces.com/${{ env.ESM_NAME }}/${{ env.TIMESTAMP }}_${{ github.sha }}/${{ env.JS_NAME }}" }'
284283
customHeaders: '{ "Accept": "application/json", "Content-Type": "application/json" }'
285284

286-
deploy_patient_registration_app:
285+
deploy_patient_search_app:
287286
runs-on: ubuntu-latest
288287

289288
env:
290-
DIR_NAME: "esm-patient-registration-app"
291-
ESM_NAME: "@openmrs/esm-patient-registration-app"
292-
JS_NAME: "openmrs-esm-patient-registration-app.js"
289+
DIR_NAME: "esm-patient-search-app"
290+
ESM_NAME: "@openmrs/esm-patient-search-app"
291+
JS_NAME: "openmrs-esm-patient-search-app.js"
293292

294293
needs: build
295294

@@ -328,74 +327,94 @@ jobs:
328327
password: ${{ secrets.DEPLOYER_PASSWORD }}
329328
data: '{ "service":"${{ env.ESM_NAME }}","url":"https://donaldkibet.fra1.digitaloceanspaces.com/${{ env.ESM_NAME }}/${{ env.TIMESTAMP }}_${{ github.sha }}/${{ env.JS_NAME }}" }'
330329
customHeaders: '{ "Accept": "application/json", "Content-Type": "application/json" }'
331-
332-
pre_release:
330+
deploy_patient_list_app:
333331
runs-on: ubuntu-latest
334332

333+
env:
334+
DIR_NAME: "esm-patient-list-app"
335+
ESM_NAME: "@openmrs/esm-patient-list-app"
336+
JS_NAME: "openmrs-esm-patient-list-app.js"
337+
335338
needs: build
336339

337340
if: ${{ github.event_name == 'push' }}
338341

339342
steps:
340-
- uses: actions/checkout@v3
341-
- name: Setup Node.js
342-
uses: actions/setup-node@v1
343-
with:
344-
node-version: "16.15"
345-
registry-url: "https://registry.npmjs.org"
346-
347-
- name: Cache dependencies
348-
id: cache
349-
uses: actions/cache@v3
343+
- name: Download Artifacts
344+
uses: actions/download-artifact@v2
345+
346+
- name: Compute Timestamp
347+
run: echo "TIMESTAMP=$(date +'%Y-%m-%d')" >> $GITHUB_ENV
348+
349+
- name: Prepare Directory
350+
shell: bash
351+
run: |
352+
mkdir -p dist/${{ env.ESM_NAME }}/${{ env.TIMESTAMP }}_${{ github.sha }}
353+
mv packages/${{ env.DIR_NAME }}/dist/*.* dist/${{ env.ESM_NAME }}/${{ env.TIMESTAMP }}_${{ github.sha }}/
354+
355+
- name: Publish to Digital Ocean
356+
uses: jakejarvis/s3-sync-action@master
350357
with:
351-
path: '**/node_modules'
352-
key: ${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}
353-
354-
- name: Install dependencies
355-
if: steps.cache.outputs.cache-hit != 'true'
356-
run: yarn install --immutable
357-
358-
- run: yarn lerna version "$(node -e "console.log(require('semver').inc(require('./lerna.json').version, 'patch'))")-pre.${{ github.run_number }}" --no-git-tag-version --no-push --yes
359-
- run: yarn turbo run build --color
360-
- run: git config user.email "info@openmrs.org" && git config user.name "OpenMRS CI"
361-
- run: git add . && git commit -m "Prerelease version" --no-verify
362-
- run: yarn run ci:prepublish
358+
args: --acl public-read --follow-symlinks --cache-control "max-age=31536000"
363359
env:
364-
NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }}
365-
- name: Upload Artifacts
366-
uses: actions/upload-artifact@v2
360+
AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }}
361+
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
362+
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
363+
AWS_S3_ENDPOINT: ${{ secrets.AWS_S3_ENDPOINT }}
364+
SOURCE_DIR: "dist"
365+
366+
- name: Update Importmap
367+
uses: fjogeleit/http-request-action@master
367368
with:
368-
name: packages
369-
path: |
370-
packages/**/dist
369+
url: http://${{ secrets.DEPLOYER_HOST }}/services?env=prod
370+
method: "PATCH"
371+
username: ${{ secrets.DEPLOYER_USERNAME }}
372+
password: ${{ secrets.DEPLOYER_PASSWORD }}
373+
data: '{ "service":"${{ env.ESM_NAME }}","url":"https://donaldkibet.fra1.digitaloceanspaces.com/${{ env.ESM_NAME }}/${{ env.TIMESTAMP }}_${{ github.sha }}/${{ env.JS_NAME }}" }'
374+
customHeaders: '{ "Accept": "application/json", "Content-Type": "application/json" }'
371375

372-
release:
376+
deploy_patient_registration_app:
373377
runs-on: ubuntu-latest
374378

379+
env:
380+
DIR_NAME: "esm-patient-registration-app"
381+
ESM_NAME: "@openmrs/esm-patient-registration-app"
382+
JS_NAME: "openmrs-esm-patient-registration-app.js"
383+
375384
needs: build
376385

377-
if: ${{ github.event_name == 'release' }}
386+
if: ${{ github.event_name == 'push' }}
378387

379388
steps:
380-
- uses: actions/checkout@v3
381-
- name: Setup Node.js
382-
uses: actions/setup-node@v3
383-
with:
384-
node-version: "16.15"
385-
registry-url: "https://registry.npmjs.org"
386-
387-
- name: Cache dependencies
388-
id: cache
389-
uses: actions/cache@v3
389+
- name: Download Artifacts
390+
uses: actions/download-artifact@v2
391+
392+
- name: Compute Timestamp
393+
run: echo "TIMESTAMP=$(date +'%Y-%m-%d')" >> $GITHUB_ENV
394+
395+
- name: Prepare Directory
396+
shell: bash
397+
run: |
398+
mkdir -p dist/${{ env.ESM_NAME }}/${{ env.TIMESTAMP }}_${{ github.sha }}
399+
mv packages/${{ env.DIR_NAME }}/dist/*.* dist/${{ env.ESM_NAME }}/${{ env.TIMESTAMP }}_${{ github.sha }}/
400+
401+
- name: Publish to Digital Ocean
402+
uses: jakejarvis/s3-sync-action@master
390403
with:
391-
path: '**/node_modules'
392-
key: ${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}
393-
394-
- name: Install dependencies
395-
if: steps.cache.outputs.cache-hit != 'true'
396-
run: yarn install --immutable
397-
398-
- run: yarn turbo run build --color
399-
- run: yarn run ci:publish
404+
args: --acl public-read --follow-symlinks --cache-control "max-age=31536000"
400405
env:
401-
NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }}
406+
AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }}
407+
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
408+
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
409+
AWS_S3_ENDPOINT: ${{ secrets.AWS_S3_ENDPOINT }}
410+
SOURCE_DIR: "dist"
411+
412+
- name: Update Importmap
413+
uses: fjogeleit/http-request-action@master
414+
with:
415+
url: http://${{ secrets.DEPLOYER_HOST }}/services?env=prod
416+
method: "PATCH"
417+
username: ${{ secrets.DEPLOYER_USERNAME }}
418+
password: ${{ secrets.DEPLOYER_PASSWORD }}
419+
data: '{ "service":"${{ env.ESM_NAME }}","url":"https://donaldkibet.fra1.digitaloceanspaces.com/${{ env.ESM_NAME }}/${{ env.TIMESTAMP }}_${{ github.sha }}/${{ env.JS_NAME }}" }'
420+
customHeaders: '{ "Accept": "application/json", "Content-Type": "application/json" }'

‎packages/esm-appointments-app/src/appointment-forms/appointments-form.component.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,8 @@ const AppointmentForm: React.FC<AppointmentFormProps> = ({ appointment, patientU
8484
const { appointmentComments } = useConfig() as ConfigObject;
8585
const { appointmentStatuses } = useConfig() as ConfigObject;
8686
const { patient, isLoading } = usePatient(patientUuid ?? appointmentState.patientUuid);
87-
const locations = useLocations();
8887
const session = useSession();
88+
const locations = session?.sessionLocation ? [{ ...session?.sessionLocation }] : [];
8989
const { providers } = useProviders();
9090
const { services } = useServices();
9191
const [startDate, setStartDate] = useState(

‎packages/esm-appointments-app/src/appointments-calendar/appointments-calendar-list-view.component.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import AppointmentsHeader from '../appointments-header/appointments-header.compo
44
import CalendarHeader from './calendar-header.component';
55
import MonthlyCalendarView from './monthly-calendar-view.component';
66
import styles from './appointments-calendar-list-view.scss';
7+
import CommingSoon from '../empty-state/comming-soon.component';
78

89
interface AppointmentsCalendarListViewProps {}
910
type AppointmentsCalendarListView = 'daily' | 'weekly' | 'monthly';
@@ -15,6 +16,7 @@ const AppointmentsCalendarListView: React.FC<AppointmentsCalendarListViewProps>
1516
<AppointmentsHeader title={t('appointments', 'Appointments')} />
1617
<CalendarHeader onChangeView={setCalendarView} calendarView={calendarView} />
1718
{calendarView === 'monthly' && <MonthlyCalendarView type="monthly" events={events} />}
19+
{calendarView !== 'monthly' && <CommingSoon />}
1820
</div>
1921
);
2022
};

‎packages/esm-appointments-app/src/appointments-metrics/appointments-metrics.component.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,13 @@ const AppointmentsMetrics: React.FC = () => {
5050
}
5151
value={highestServiceLoad?.count ?? '--'}
5252
headerLabel={t('highestServiceVolume', 'High volume Service : {time}', { time: formattedStartDate })}
53-
view="highVolume"
53+
view=""
5454
/>
5555
<MetricsCard
5656
label={t('providers', 'Providers')}
5757
value={totalProviders}
5858
headerLabel={t('providersAvailableToday', 'Providers available : {time}', { time: formattedStartDate })}
59-
view="providers"
59+
view=""
6060
/>
6161
</div>
6262
</>

‎packages/esm-appointments-app/src/appointments-metrics/metrics-card.component.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ const MetricsCard: React.FC<MetricsCardProps> = ({ label, value, headerLabel, ch
4545
</div>
4646
{!isEmpty(count) && (
4747
<div className={styles.countGrid}>
48-
<span>Arrived</span>
49-
<span>Pending</span>
48+
<span>{t('arrived', 'Arrived')}</span>
49+
<span>{t('notArrived', 'Not arrived')}</span>
5050
<p style={{ color: '#319227' }}>{count.arrivedAppointments?.length}</p>
5151
<p style={{ color: '#da1e28' }}>{count.pendingAppointments?.length}</p>
5252
</div>

‎packages/esm-appointments-app/src/appointments-tabs/appointments-base-table.component.tsx

+19-6
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ import CancelAppointment from '../appointment-forms/cancel-appointment.component
3737
import dayjs from 'dayjs';
3838
import isToday from 'dayjs/plugin/isToday';
3939
import utc from 'dayjs/plugin/utc';
40+
import AppointmentButton from './appointments-button.component';
41+
import { useServiceQueues } from '../hooks/useServiceQueus';
4042
dayjs.extend(utc);
4143
dayjs.extend(isToday);
4244

@@ -45,13 +47,15 @@ interface AppointmentsBaseTableProps {
4547
isLoading: boolean;
4648
tableHeading: string;
4749
mutate?: () => void;
50+
visits: Array<any>;
4851
}
4952

5053
const AppointmentsBaseTable: React.FC<AppointmentsBaseTableProps> = ({
5154
appointments,
5255
isLoading,
5356
tableHeading,
5457
mutate,
58+
visits,
5559
}) => {
5660
const { t } = useTranslation();
5761
const { results, goTo, currentPage } = usePagination(appointments, 10);
@@ -64,6 +68,7 @@ const AppointmentsBaseTable: React.FC<AppointmentsBaseTableProps> = ({
6468
);
6569
};
6670

71+
const { isLoading: isLoadingQueueEntries, queueEntries } = useServiceQueues();
6772
const headerData = [
6873
{
6974
header: t('patientName', 'Patient name'),
@@ -86,7 +91,11 @@ const AppointmentsBaseTable: React.FC<AppointmentsBaseTableProps> = ({
8691
key: 'actions',
8792
},
8893
];
89-
94+
const patientQueueEntry = (patientUuid: string) => {
95+
const queryEntries = queueEntries.find((entry) => entry.queueEntry.patient.uuid === patientUuid);
96+
return ` ${queryEntries?.queueEntry?.status?.display ?? ''} ${queryEntries?.queueEntry?.queue?.display ?? ''}`;
97+
};
98+
const hasVisit = (patientUuid) => visits?.find((visit) => visit?.patient?.uuid === patientUuid)?.startDatetime;
9099
const rowData = results?.map((appointment, index) => ({
91100
id: `${index}`,
92101
patientName: {
@@ -103,7 +112,13 @@ const AppointmentsBaseTable: React.FC<AppointmentsBaseTableProps> = ({
103112
serviceType: appointment.serviceType,
104113
provider: appointment.provider,
105114
actions: (
106-
<>
115+
<div style={{ display: 'flex', alignItems: 'center' }}>
116+
{}
117+
{hasVisit(appointment.patientUuid) ? (
118+
patientQueueEntry(appointment.patientUuid)
119+
) : (
120+
<AppointmentButton patientUuid={appointment.patientUuid} appointment={appointment} />
121+
)}
107122
{(dayjs(appointment.dateTime).isAfter(dayjs()) || dayjs(appointment.dateTime).isToday()) && (
108123
<OverflowMenu size="sm" flipped>
109124
<OverflowMenuItem
@@ -126,7 +141,7 @@ const AppointmentsBaseTable: React.FC<AppointmentsBaseTableProps> = ({
126141
/>
127142
</OverflowMenu>
128143
)}
129-
</>
144+
</div>
130145
),
131146
}));
132147

@@ -190,9 +205,7 @@ const AppointmentsBaseTable: React.FC<AppointmentsBaseTableProps> = ({
190205
<React.Fragment key={row.id}>
191206
<TableExpandRow {...getRowProps({ row })}>
192207
{row.cells.map((cell) => (
193-
<TableCell className="cds--table-column-menu" key={cell.id}>
194-
{cell.value?.content ?? cell.value}
195-
</TableCell>
208+
<TableCell key={cell.id}>{cell.value?.content ?? cell.value}</TableCell>
196209
))}
197210
</TableExpandRow>
198211
{row.isExpanded && (
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import React from 'react';
2+
import { Button } from '@carbon/react';
3+
import { useTranslation } from 'react-i18next';
4+
import { launchOverlay } from '../hooks/useOverlay';
5+
import VisitForm from '../patient-queue/visit-form/visit-form.component';
6+
import { MappedAppointment } from '../types';
7+
import dayjs from 'dayjs';
8+
import isToday from 'dayjs/plugin/isToday';
9+
import utc from 'dayjs/plugin/utc';
10+
dayjs.extend(utc);
11+
dayjs.extend(isToday);
12+
13+
interface AppointmentButtonProps {
14+
patientUuid: string;
15+
appointment: MappedAppointment;
16+
}
17+
18+
const AppointmentButton: React.FC<AppointmentButtonProps> = ({ appointment, patientUuid }) => {
19+
const { t } = useTranslation();
20+
return (
21+
<>
22+
{(dayjs(appointment.dateTime).isAfter(dayjs()) || dayjs(appointment.dateTime).isToday()) && (
23+
<Button
24+
size="sm"
25+
kind="ghost"
26+
onClick={() =>
27+
launchOverlay(
28+
t('patientSearch', 'Patient search'),
29+
<VisitForm patientUuid={patientUuid} appointment={appointment} />,
30+
)
31+
}>
32+
{t('checkedIn', 'CheckedIn')}
33+
</Button>
34+
)}
35+
</>
36+
);
37+
};
38+
39+
export default AppointmentButton;

0 commit comments

Comments
 (0)
Failed to load comments.