Merge pull request #6 from edewit/alerts
initial version of the alert system
This commit is contained in:
commit
a77b63fab1
4 changed files with 130 additions and 2 deletions
20
src/App.tsx
20
src/App.tsx
|
@ -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);
|
||||||
|
|
40
src/components/alert/AlertPanel.tsx
Normal file
40
src/components/alert/AlertPanel.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
}
|
48
src/components/alert/Alerts.tsx
Normal file
48
src/components/alert/Alerts.tsx
Normal 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];
|
||||||
|
}
|
24
stories/5-AlertPanel.stories.js
Normal file
24
stories/5-AlertPanel.stories.js
Normal 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/>
|
||||||
|
);
|
||||||
|
});
|
Loading…
Reference in a new issue