Merge pull request #6 from edewit/alerts

initial version of the alert system
This commit is contained in:
Stan Silvert 2020-08-07 15:25:55 -04:00 committed by GitHub
commit a77b63fab1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 130 additions and 2 deletions

View file

@ -1,14 +1,22 @@
import React, { useContext } from 'react'; import React, { useContext } from 'react';
import {
Page,
PageSection,
Button,
AlertVariant,
} from '@patternfly/react-core';
import { ClientList } from './clients/ClientList'; import { ClientList } from './clients/ClientList';
import { DataLoader } from './components/data-loader/DataLoader'; import { DataLoader } from './components/data-loader/DataLoader';
import { HttpClientContext } from './http-service/HttpClientContext'; import { HttpClientContext } from './http-service/HttpClientContext';
import { Client } from './clients/client-model'; import { Client } from './clients/client-model';
import { Page, PageSection } from '@patternfly/react-core';
import { Header } from './PageHeader'; import { Header } from './PageHeader';
import { PageNav } from './PageNav'; import { PageNav } from './PageNav';
import { AlertPanel } from './components/alert/AlertPanel';
import { useAlerts, withAlerts } from './components/alert/Alerts';
export const App = () => { const AppComponent = () => {
const [alerts, add, hide] = useAlerts();
const httpClient = useContext(HttpClientContext); const httpClient = useContext(HttpClientContext);
const loader = async () => { const loader = async () => {
@ -19,10 +27,18 @@ export const App = () => {
return ( return (
<Page header={<Header />} sidebar={<PageNav />}> <Page header={<Header />} sidebar={<PageNav />}>
<PageSection> <PageSection>
<AlertPanel alerts={alerts} onCloseAlert={hide} />
<DataLoader loader={loader}> <DataLoader loader={loader}>
{(clients) => <ClientList clients={clients} />} {(clients) => <ClientList clients={clients} />}
</DataLoader> </DataLoader>
<Button
onClick={() => add('Crazy stuff happened', AlertVariant.danger)}
>
Click
</Button>
</PageSection> </PageSection>
</Page> </Page>
); );
}; };
export const App = withAlerts(AppComponent);

View file

@ -0,0 +1,40 @@
import React from 'react';
import {
AlertGroup,
Alert,
AlertActionCloseButton,
AlertVariant,
} from '@patternfly/react-core';
export type AlertType = {
key: number;
message: string;
variant: AlertVariant;
};
type AlertPanelProps = {
alerts: AlertType[];
onCloseAlert: (key: number) => void;
};
export function AlertPanel({ alerts, onCloseAlert }: AlertPanelProps) {
return (
<AlertGroup isToast>
{alerts.map(({ key, variant, message }) => (
<Alert
isLiveRegion
variant={AlertVariant[variant]}
title={message}
actionClose={
<AlertActionCloseButton
title={message}
variantLabel={`${variant} alert`}
onClose={() => onCloseAlert(key)}
/>
}
key={key}
/>
))}
</AlertGroup>
);
}

View file

@ -0,0 +1,48 @@
import React, {
useState,
FunctionComponent,
useContext,
Dispatch,
SetStateAction,
} from 'react';
import { AlertType } from './AlertPanel';
import { AlertVariant } from '@patternfly/react-core';
const AlertsContext = React.createContext<
[AlertType[], Dispatch<SetStateAction<AlertType[]>>] | undefined
>(undefined);
export function withAlerts(WrappedComponent: FunctionComponent) {
return function (props: any) {
const state = useState<AlertType[]>([]);
return (
<AlertsContext.Provider value={state}>
<WrappedComponent {...props} />
</AlertsContext.Provider>
);
};
}
export function useAlerts(): [
AlertType[],
(message: string, type: AlertVariant) => void,
(key: number) => void
] {
const createId = () => new Date().getTime();
const [alerts, setAlerts] = useContext(AlertsContext)!;
const hideAlert = (key: number) => {
setAlerts([...alerts.filter((el) => el.key !== key)]);
};
const add = (message: string, type: AlertVariant) => {
const key = createId();
setAlerts([...alerts, { key, message, variant: type }]);
if (type !== AlertVariant.danger) {
setTimeout(() => hideAlert(key), 8000);
}
};
return [alerts, add, hideAlert];
}

View file

@ -0,0 +1,24 @@
import React from 'react';
import { AlertVariant, Button } from '@patternfly/react-core';
import { storiesOf } from '@storybook/react';
import { AlertPanel } from '../src/components/alert/AlertPanel';
import { withAlerts, useAlerts } from '../src/components/alert/Alerts';
storiesOf('Alert Panel', module)
.add('api', () => <AlertPanel alerts={[{ key: 1, message: 'Hello', variant: AlertVariant.default }]} onCloseAlert={() => { }} />)
.add('add alert', () => {
const Comp = () => {
const [alerts, add, hide] = useAlerts();
return (
<>
<AlertPanel alerts={alerts} onCloseAlert={hide} />
<Button onClick={() => add('Hello', AlertVariant.default)}>Add</Button>
</>
);
}
const WrapperComponent = withAlerts(Comp);
return (
<WrapperComponent/>
);
});