mirror of https://github.com/morpheus65535/bazarr
Add Socket.IO event which is used for showing notifications in UI
This commit is contained in:
parent
08712ec5ba
commit
24cb712ad7
|
@ -7,7 +7,6 @@ import {
|
|||
SITE_NEED_AUTH,
|
||||
SITE_NOTIFICATIONS_ADD,
|
||||
SITE_NOTIFICATIONS_REMOVE,
|
||||
SITE_NOTIFICATIONS_REMOVE_BY_TIMESTAMP,
|
||||
SITE_OFFLINE_UPDATE,
|
||||
SITE_SIDEBAR_UPDATE,
|
||||
} from "../constants";
|
||||
|
@ -30,19 +29,14 @@ export const badgeUpdateAll = createAsyncAction(SITE_BADGE_UPDATE, () =>
|
|||
BadgesApi.all()
|
||||
);
|
||||
|
||||
export const siteAddNotification = createAction(
|
||||
export const siteAddNotifications = createAction(
|
||||
SITE_NOTIFICATIONS_ADD,
|
||||
(err: ReduxStore.Notification) => err
|
||||
(err: ReduxStore.Notification[]) => err
|
||||
);
|
||||
|
||||
export const siteRemoveNotification = createAction(
|
||||
export const siteRemoveNotifications = createAction(
|
||||
SITE_NOTIFICATIONS_REMOVE,
|
||||
(id: string) => id
|
||||
);
|
||||
|
||||
export const siteRemoveNotificationByTime = createAction(
|
||||
SITE_NOTIFICATIONS_REMOVE_BY_TIMESTAMP,
|
||||
(date: Date) => date
|
||||
(date: Date[]) => date
|
||||
);
|
||||
|
||||
export const siteChangeSidebar = createAction(
|
||||
|
|
|
@ -36,8 +36,6 @@ export const SITE_INITIALIZED = "SITE_SYSTEM_INITIALIZED";
|
|||
export const SITE_INITIALIZE_FAILED = "SITE_INITIALIZE_FAILED";
|
||||
export const SITE_NOTIFICATIONS_ADD = "SITE_NOTIFICATIONS_ADD";
|
||||
export const SITE_NOTIFICATIONS_REMOVE = "SITE_NOTIFICATIONS_REMOVE";
|
||||
export const SITE_NOTIFICATIONS_REMOVE_BY_TIMESTAMP =
|
||||
"SITE_NOTIFICATIONS_REMOVE_BY_TIMESTAMP";
|
||||
export const SITE_SIDEBAR_UPDATE = "SITE_SIDEBAR_UPDATE";
|
||||
export const SITE_BADGE_UPDATE = "SITE_BADGE_UPDATE";
|
||||
export const SITE_OFFLINE_UPDATE = "SITE_OFFLINE_UPDATE";
|
||||
|
|
|
@ -1,27 +1,26 @@
|
|||
import { useCallback, useEffect } from "react";
|
||||
import { useSystemSettings } from ".";
|
||||
import {
|
||||
siteAddNotification,
|
||||
siteAddNotifications,
|
||||
siteChangeSidebar,
|
||||
siteRemoveNotificationByTime,
|
||||
siteRemoveNotifications,
|
||||
} from "../actions";
|
||||
import { useReduxAction, useReduxStore } from "./base";
|
||||
|
||||
export function useNotification(id: string, sec: number = 5) {
|
||||
const add = useReduxAction(siteAddNotification);
|
||||
const remove = useReduxAction(siteRemoveNotificationByTime);
|
||||
export function useNotification(timeout: number = 5000) {
|
||||
const add = useReduxAction(siteAddNotifications);
|
||||
const remove = useReduxAction(siteRemoveNotifications);
|
||||
|
||||
return useCallback(
|
||||
(msg: Omit<ReduxStore.Notification, "id" | "timestamp">) => {
|
||||
(msg: Omit<ReduxStore.Notification, "timestamp">) => {
|
||||
const error: ReduxStore.Notification = {
|
||||
...msg,
|
||||
id,
|
||||
timestamp: new Date(),
|
||||
};
|
||||
add(error);
|
||||
setTimeout(() => remove(error.timestamp), sec * 1000);
|
||||
add([error]);
|
||||
setTimeout(() => remove([error.timestamp]), timeout);
|
||||
},
|
||||
[add, remove, sec, id]
|
||||
[add, remove, timeout]
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { differenceWith } from "lodash";
|
||||
import { Action, handleActions } from "redux-actions";
|
||||
import apis from "../../apis";
|
||||
import {
|
||||
|
@ -7,7 +8,6 @@ import {
|
|||
SITE_NEED_AUTH,
|
||||
SITE_NOTIFICATIONS_ADD,
|
||||
SITE_NOTIFICATIONS_REMOVE,
|
||||
SITE_NOTIFICATIONS_REMOVE_BY_TIMESTAMP,
|
||||
SITE_OFFLINE_UPDATE,
|
||||
SITE_SIDEBAR_UPDATE,
|
||||
} from "../constants";
|
||||
|
@ -34,21 +34,16 @@ const reducer = handleActions<ReduxStore.Site, any>(
|
|||
}),
|
||||
[SITE_NOTIFICATIONS_ADD]: (
|
||||
state,
|
||||
action: Action<ReduxStore.Notification>
|
||||
action: Action<ReduxStore.Notification[]>
|
||||
) => {
|
||||
const alerts = [
|
||||
...state.notifications.filter((v) => v.id !== action.payload.id),
|
||||
const alerts = [...state.notifications, ...action.payload];
|
||||
return { ...state, notifications: alerts };
|
||||
},
|
||||
[SITE_NOTIFICATIONS_REMOVE]: (state, action: Action<Date[]>) => {
|
||||
const alerts = differenceWith(
|
||||
state.notifications,
|
||||
action.payload,
|
||||
];
|
||||
return { ...state, notifications: alerts };
|
||||
},
|
||||
[SITE_NOTIFICATIONS_REMOVE]: (state, action: Action<string>) => {
|
||||
const alerts = state.notifications.filter((v) => v.id !== action.payload);
|
||||
return { ...state, notifications: alerts };
|
||||
},
|
||||
[SITE_NOTIFICATIONS_REMOVE_BY_TIMESTAMP]: (state, action: Action<Date>) => {
|
||||
const alerts = state.notifications.filter(
|
||||
(v) => v.timestamp !== action.payload
|
||||
(n, t) => n.timestamp === t
|
||||
);
|
||||
return { ...state, notifications: alerts };
|
||||
},
|
||||
|
|
|
@ -10,7 +10,6 @@ namespace ReduxStore {
|
|||
type: "error" | "warning" | "info";
|
||||
message: string;
|
||||
timestamp: Date;
|
||||
id: string;
|
||||
}
|
||||
|
||||
interface Site {
|
||||
|
|
|
@ -5,6 +5,8 @@ import {
|
|||
movieUpdateList,
|
||||
seriesDeleteItems,
|
||||
seriesUpdateList,
|
||||
siteAddNotifications,
|
||||
siteRemoveNotifications,
|
||||
siteUpdateOffline,
|
||||
systemUpdateLanguagesAll,
|
||||
systemUpdateSettings,
|
||||
|
@ -29,6 +31,26 @@ export function createDefaultReducer(): SocketIO.Reducer[] {
|
|||
key: "disconnect",
|
||||
any: () => reduxStore.dispatch(siteUpdateOffline(true)),
|
||||
},
|
||||
{
|
||||
key: "message",
|
||||
update: (msg?: string[]) => {
|
||||
if (msg) {
|
||||
const notifications = msg.map<ReduxStore.Notification>((message) => ({
|
||||
message,
|
||||
type: "info",
|
||||
timestamp: new Date(),
|
||||
}));
|
||||
|
||||
reduxStore.dispatch(siteAddNotifications(notifications));
|
||||
|
||||
const ts = notifications.map((n) => n.timestamp);
|
||||
setTimeout(
|
||||
() => reduxStore.dispatch(siteRemoveNotifications(ts)),
|
||||
5000
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "series",
|
||||
update: bindToReduxStore(seriesUpdateList),
|
||||
|
|
|
@ -25,7 +25,7 @@ interface Props {}
|
|||
const App: FunctionComponent<Props> = () => {
|
||||
const { initialized, auth } = useReduxStore((s) => s.site);
|
||||
|
||||
const notify = useNotification("has-update", 10);
|
||||
const notify = useNotification(10 * 1000);
|
||||
|
||||
// Has any update?
|
||||
const hasUpdate = useHasUpdateInject();
|
||||
|
|
|
@ -3,7 +3,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|||
import { capitalize } from "lodash";
|
||||
import React, { FunctionComponent, useCallback, useMemo } from "react";
|
||||
import { Toast } from "react-bootstrap";
|
||||
import { siteRemoveNotification } from "../../@redux/actions";
|
||||
import { siteRemoveNotifications } from "../../@redux/actions";
|
||||
import { useReduxAction, useReduxStore } from "../../@redux/hooks/base";
|
||||
import "./style.scss";
|
||||
|
||||
|
@ -14,8 +14,11 @@ const NotificationContainer: FunctionComponent<NotificationContainerProps> = ()
|
|||
|
||||
const items = useMemo(
|
||||
() =>
|
||||
list.map((v, idx) => (
|
||||
<NotificationToast key={v.id} {...v}></NotificationToast>
|
||||
list.map((v) => (
|
||||
<NotificationToast
|
||||
key={v.timestamp.getTime()}
|
||||
{...v}
|
||||
></NotificationToast>
|
||||
)),
|
||||
[list]
|
||||
);
|
||||
|
@ -29,12 +32,12 @@ const NotificationContainer: FunctionComponent<NotificationContainerProps> = ()
|
|||
type MessageHolderProps = ReduxStore.Notification & {};
|
||||
|
||||
const NotificationToast: FunctionComponent<MessageHolderProps> = (props) => {
|
||||
const { message, id, type } = props;
|
||||
const removeNotification = useReduxAction(siteRemoveNotification);
|
||||
const { message, type, timestamp } = props;
|
||||
const removeNotification = useReduxAction(siteRemoveNotifications);
|
||||
|
||||
const remove = useCallback(() => removeNotification(id), [
|
||||
const remove = useCallback(() => removeNotification([timestamp]), [
|
||||
removeNotification,
|
||||
id,
|
||||
timestamp,
|
||||
]);
|
||||
|
||||
return (
|
||||
|
|
|
@ -48,7 +48,7 @@ export function AsyncStateOverlay<T>(props: AsyncStateOverlayProps<T>) {
|
|||
const { exist, state, children } = props;
|
||||
const missing = exist ? !exist(state.data) : !defaultExist(state.data);
|
||||
|
||||
const onError = useNotification("async-overlay");
|
||||
const onError = useNotification();
|
||||
|
||||
useEffect(() => {
|
||||
if (!state.updating && state.error !== undefined && !missing) {
|
||||
|
|
Loading…
Reference in New Issue