packages/core: add consumer side to AlertApi and use for AlertDialog + friends

This commit is contained in:
Patrik Oldsberg
2020-05-25 21:51:06 +02:00
parent 6d3f745b4b
commit 9be7870a34
4 changed files with 26 additions and 27 deletions
+2 -2
View File
@@ -19,7 +19,7 @@ import React, { FC } from 'react';
import { BrowserRouter as Router } from 'react-router-dom';
import Root from './components/Root';
import * as plugins from './plugins';
import apis, { alertApiForwarder } from './apis';
import apis from './apis';
const app = createApp({
apis,
@@ -31,7 +31,7 @@ const AppComponent = app.getRootComponent();
const App: FC<{}> = () => (
<AppProvider>
<AlertDisplay forwarder={alertApiForwarder} />
<AlertDisplay />
<OAuthRequestDialog />
<Router>
<Root>
@@ -14,6 +14,7 @@
* limitations under the License.
*/
import { createApiRef } from '../ApiRef';
import { Observable } from '../../types';
export type AlertMessage = {
message: string;
@@ -30,6 +31,11 @@ export type AlertApi = {
* Post an alert for handling by the application.
*/
post(alert: AlertMessage): void;
/**
* Observe alerts posted by other parts of the application.
*/
alert$(): Observable<AlertMessage>;
};
export const alertApiRef = createApiRef<AlertApi>({
@@ -14,22 +14,17 @@
* limitations under the License.
*/
import { AlertApi, AlertMessage } from '../../../';
type SubscriberFunc = (message: AlertMessage) => void;
type Unsubscribe = () => void;
import { PublishSubject } from './lib';
import { Observable } from '../../types';
export class AlertApiForwarder implements AlertApi {
private readonly subscribers = new Set<SubscriberFunc>();
private readonly subject = new PublishSubject<AlertMessage>();
post(alert: AlertMessage) {
this.subscribers.forEach(subscriber => subscriber(alert));
this.subject.next(alert);
}
subscribe(func: SubscriberFunc): Unsubscribe {
this.subscribers.add(func);
return () => {
this.subscribers.delete(func);
};
alert$(): Observable<AlertMessage> {
return this.subject;
}
}
@@ -15,25 +15,27 @@
*/
import React, { FC, useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { Snackbar, IconButton } from '@material-ui/core';
import CloseIcon from '@material-ui/icons/Close';
import { Alert } from '@material-ui/lab';
import { AlertApiForwarder, AlertMessage } from '../../api';
import { AlertMessage, useApi, alertApiRef } from '../../api';
type Props = {
forwarder: AlertApiForwarder;
};
type Props = {};
// TODO: improve on this and promote to a shared component for use by all apps.
export const AlertDisplay: FC<Props> = ({ forwarder }) => {
export const AlertDisplay: FC<Props> = () => {
const [messages, setMessages] = useState<Array<AlertMessage>>([]);
const alertApi = useApi(alertApiRef);
useEffect(() => {
return forwarder.subscribe((message: AlertMessage) =>
setMessages(msgs => msgs.concat(message)),
);
}, [forwarder]);
const subscription = alertApi
.alert$()
.subscribe(message => setMessages(msgs => msgs.concat(message)));
return () => {
subscription.unsubscribe();
};
}, [alertApi]);
if (messages.length === 0) {
return null;
@@ -69,7 +71,3 @@ export const AlertDisplay: FC<Props> = ({ forwarder }) => {
</Snackbar>
);
};
AlertDisplay.propTypes = {
forwarder: PropTypes.instanceOf(AlertApiForwarder).isRequired,
};