Skip to content

Commit

Permalink
(feat) Add a page header (#212)
Browse files Browse the repository at this point in the history
* (feat) Add a page header

* Remove breadcrumbs registration

* Update svg illustration
  • Loading branch information
denniskigen authored Dec 18, 2023
1 parent 4f5ef97 commit a47074d
Show file tree
Hide file tree
Showing 15 changed files with 235 additions and 59 deletions.
33 changes: 18 additions & 15 deletions src/components/dashboard/dashboard.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import { useClobdata } from '../../hooks/useClobdata';
import { useForms } from '../../hooks/useForms';
import EmptyState from '../empty-state/empty-state.component';
import ErrorState from '../error-state/error-state.component';
import Header from '../header/header.component';
import styles from './dashboard.scss';

type Mutator = KeyedMutator<{
Expand Down Expand Up @@ -436,24 +437,26 @@ const Dashboard: React.FC = () => {
const { error, forms, isLoading, isValidating, mutate } = useForms();

return (
<div className={styles.container}>
<h3 className={styles.heading}>{t('formBuilder', 'Form Builder')}</h3>
{(() => {
if (error) {
return <ErrorState error={error} />;
}
<main>
<Header title={t('home', 'Home')} />
<div className={styles.container}>
{(() => {
if (error) {
return <ErrorState error={error} />;
}

if (isLoading) {
return <DataTableSkeleton role="progressbar" />;
}
if (isLoading) {
return <DataTableSkeleton role="progressbar" />;
}

if (forms.length === 0) {
return <EmptyState />;
}
if (forms.length === 0) {
return <EmptyState />;
}

return <FormsList forms={forms} isValidating={isValidating} mutate={mutate} t={t} />;
})()}
</div>
return <FormsList forms={forms} isValidating={isValidating} mutate={mutate} t={t} />;
})()}
</div>
</main>
);
};

Expand Down
8 changes: 2 additions & 6 deletions src/components/dashboard/dashboard.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
@use "@carbon/type";

.container {
padding: 2rem;
padding: 1rem;
background-color: colors.$gray-10;
}

Expand Down Expand Up @@ -68,10 +68,6 @@
}
}

.heading {
margin-bottom: 1.5rem;
}

.toolbar {
position: relative;
display: flex;
Expand Down Expand Up @@ -150,7 +146,7 @@
}

.warningMessage {
margin: 1.5rem 0;
margin: 1rem 0;
}

.spinner {
Expand Down
4 changes: 2 additions & 2 deletions src/components/dashboard/dashboard.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ describe('Dashboard', () => {

await waitForLoadingToFinish();

expect(screen.getByRole('heading', { name: /form builder/i })).toBeInTheDocument();
expect(screen.getByText(/form builder/i)).toBeInTheDocument();
expect(screen.getByRole('heading', { name: /forms/i })).toBeInTheDocument();
expect(screen.getByTitle(/empty data illustration/i)).toBeInTheDocument();
expect(screen.getByText(/there are no forms to display/i)).toBeInTheDocument();
Expand Down Expand Up @@ -142,7 +142,7 @@ describe('Dashboard', () => {

await waitForLoadingToFinish();

expect(screen.getByRole('heading', { name: /form builder/i })).toBeInTheDocument();
expect(screen.getByText(/form builder/i)).toBeInTheDocument();
expect(screen.getByRole('combobox', { name: /filter by/i })).toBeInTheDocument();
expect(screen.getByRole('button', { name: /create a new form/i })).toBeInTheDocument();
expect(screen.getByRole('button', { name: /edit schema/i })).toBeInTheDocument();
Expand Down
28 changes: 23 additions & 5 deletions src/components/form-editor/form-editor.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,21 @@ import {
TabPanels,
TabPanel,
} from '@carbon/react';
import { Download } from '@carbon/react/icons';
import { ArrowLeft, Download } from '@carbon/react/icons';
import { useParams } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { ExtensionSlot } from '@openmrs/esm-framework';
import type { OHRIFormSchema } from '@openmrs/openmrs-form-engine-lib';
import type { Schema } from '../../types';
import { useClobdata } from '../../hooks/useClobdata';
import { useForm } from '../../hooks/useForm';
import ActionButtons from '../action-buttons/action-buttons.component';
import AuditDetails from '../audit-details/audit-details.component';
import FormRenderer from '../form-renderer/form-renderer.component';
import Header from '../header/header.component';
import InteractiveBuilder from '../interactive-builder/interactive-builder.component';
import SchemaEditor from '../schema-editor/schema-editor.component';
import styles from './form-editor.scss';
import { ConfigurableLink } from '@openmrs/esm-framework';

interface ErrorProps {
error: Error;
Expand Down Expand Up @@ -240,9 +241,8 @@ const FormEditor: React.FC = () => {

return (
<>
<div className={styles.breadcrumbsContainer}>
<ExtensionSlot name="breadcrumbs-slot" />
</div>
<Header title={t('schemaEditor', 'Schema editor')} />
<BackButton />
<div className={styles.container}>
{showDraftSchemaModal && <DraftSchemaModal />}
<Grid className={styles.grid}>
Expand Down Expand Up @@ -334,4 +334,22 @@ const FormEditor: React.FC = () => {
);
};

function BackButton() {
const { t } = useTranslation();

return (
<div className={styles.backButton}>
<ConfigurableLink to={window.getOpenmrsSpaBase() + 'form-builder'}>
<Button
kind="ghost"
renderIcon={(props) => <ArrowLeft size={24} {...props} />}
iconDescription="Return to dashboard"
>
<span>{t('backToDashboard', 'Back to dashboard')}</span>
</Button>
</ConfigurableLink>
</div>
);
}

export default FormEditor;
33 changes: 27 additions & 6 deletions src/components/form-editor/form-editor.scss
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,6 @@
flex-direction: column;
}

.breadcrumbsContainer {
nav {
background-color: colors.$white-0;
}
}

.grid {
margin-left: 0;
margin-right: 0;
Expand Down Expand Up @@ -72,3 +66,30 @@
padding: 0.75rem;
}

.backButton {
margin-left: layout.$spacing-05;
padding: layout.$spacing-03 0;
max-width: fit-content;

a {
text-decoration: none;
}

button {
display: flex;
padding-left: 0 !important;

svg {
order: 1;
margin: 0 layout.$spacing-03;
}

span {
order: 2;
}
}
}

button {
padding-block-start: 0.5rem;
}
43 changes: 43 additions & 0 deletions src/components/header/header.component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import { Calendar, Location, UserFollow } from '@carbon/react/icons';
import { formatDate, useSession } from '@openmrs/esm-framework';
import Illustration from './illo.component';
import styles from './header.scss';

interface HeaderProps {
title: string;
}

const Header: React.FC<HeaderProps> = ({ title }) => {
const { t } = useTranslation();
const session = useSession();
const location = session?.sessionLocation?.display;

return (
<div className={styles.header}>
<div className={styles['left-justified-items']}>
<Illustration />
<div className={styles['page-labels']}>
<p>{t('formBuilder', 'Form builder')}</p>
<p className={styles['page-name']}>{title}</p>
</div>
</div>
<div className={styles['right-justified-items']}>
<div className={styles.userContainer}>
<p>{session?.user?.person?.display}</p>
<UserFollow size={16} className={styles.userIcon} />
</div>
<div className={styles['date-and-location']}>
<Location size={16} />
<span className={styles.value}>{location}</span>
<span className={styles.middot}>&middot;</span>
<Calendar size={16} />
<span className={styles.value}>{formatDate(new Date(), { mode: 'standard' })}</span>
</div>
</div>
</div>
);
};

export default Header;
67 changes: 67 additions & 0 deletions src/components/header/header.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
@use '@carbon/layout';
@use '@carbon/type';
@import '~@openmrs/esm-styleguide/src/vars';

.header {
@include type.type-style('body-compact-02');
color: $text-02;
height: layout.$spacing-12;
background-color: $ui-02;
border-bottom: 1px solid $ui-03;
display: flex;
justify-content: space-between;
padding: layout.$spacing-05;
}

.left-justified-items {
display: flex;
flex-direction: row;
align-items: center;
cursor: pointer;
align-items: center;
}

.right-justified-items {
@include type.type-style('body-compact-02');
color: $text-02;
display: flex;
flex-direction: column;
justify-content: space-between;
}

.page-name {
@include type.type-style('heading-04');
}

.page-labels {
margin: layout.$spacing-03;

p:first-of-type {
margin-bottom: layout.$spacing-02;
}
}

.date-and-location {
display: flex;
justify-content: flex-end;
align-items: center;
}

.userContainer {
display: flex;
align-items: center;
justify-content: flex-end;
gap: layout.$spacing-05;
}

.value {
margin-left: layout.$spacing-02;
}

.middot {
margin: 0 layout.$spacing-03;
}

.view {
@include type.type-style('label-01');
}
34 changes: 34 additions & 0 deletions src/components/header/illo.component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React from 'react';

const Illustration: React.FC = () => {
return (
<svg
height="64"
width="64"
viewBox="0 0 32 32"
xmlns="http://www.w3.org/2000/svg"
xmlSpace="preserve"
fill-rule="evenodd"
clipRule="evenodd"
strokeLinejoin="round"
strokeMiterlimit="2"
>
<path
d="M27 31.36H8a.36.36 0 0 1-.36-.36v-1.64H6a.36.36 0 0 1-.36-.36v-1.64H5a.36.36 0 0 1-.36-.36V3A.36.36 0 0 1 5 2.64h4.64V2a.36.36 0 0 1 .36-.36h1.64V1A.36.36 0 0 1 12 .64h4a.36.36 0 0 1 .36.36v.64H18a.36.36 0 0 1 .36.36v.64H23a.36.36 0 0 1 .36.36v1.64H25a.36.36 0 0 1 .36.36v1.64H27a.36.36 0 0 1 .36.36v24a.36.36 0 0 1-.36.36Z"
fill="#d2e5e5"
/>
<path d="M8.36 30.64h18.28V7.36h-1.28V29a.36.36 0 0 1-.36.36H8.36v1.28Z" fill="#8abab8" />
<path
d="M5.36 26.64h17.28V3.36h-4.28V4a.36.36 0 0 1-.36.36h-8A.36.36 0 0 1 9.64 4v-.64H5.36v23.28Z"
fill="#8abab8"
/>
<path fill="#fff" d="M7.5 12.64h13v.72h-13zM7.5 8.64h13v.72h-13zM7.5 20.64h13v.72h-13zM7.5 16.64h13v.72h-13z" />
<path
d="M10.36 3.64h7.28V2.36H16a.36.36 0 0 1-.36-.36v-.64h-3.28V2a.36.36 0 0 1-.36.36h-1.64v1.28ZM6.36 28.64h18.28V5.36h-1.28V27a.36.36 0 0 1-.36.36H6.36v1.28Z"
fill="#8abab8"
/>
</svg>
);
};

export default Illustration;
20 changes: 1 addition & 19 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { defineConfigSchema, getAsyncLifecycle, registerBreadcrumbs } from '@openmrs/esm-framework';
import { defineConfigSchema, getAsyncLifecycle } from '@openmrs/esm-framework';
import { configSchema } from './config-schema';

const moduleName = '@openmrs/esm-form-builder-app';
Expand All @@ -19,22 +19,4 @@ export const systemAdministrationFormBuilderCardLink = getAsyncLifecycle(

export function startupApp() {
defineConfigSchema(moduleName, configSchema);

registerBreadcrumbs([
{
path: `${window.spaBase}/form-builder`,
title: 'Form Builder',
parent: `${window.spaBase}/home`,
},
{
path: `${window.spaBase}/form-builder/new`,
title: 'Form Editor',
parent: `${window.spaBase}/form-builder`,
},
{
path: `${window.spaBase}/form-builder/edit/:uuid`,
title: 'Form Editor',
parent: `${window.spaBase}/form-builder`,
},
]);
}
Loading

0 comments on commit a47074d

Please sign in to comment.