mirror of
https://github.com/morpheus65535/bazarr.git
synced 2025-03-09 21:36:45 +08:00
Rewrite notification system
This commit is contained in:
parent
28ad20de88
commit
a417f35856
8 changed files with 33 additions and 43 deletions
|
@ -19,7 +19,7 @@ export const bootstrap = createCallbackAction(
|
|||
() => siteInitializationFailed()
|
||||
);
|
||||
|
||||
// TODO: Override error message
|
||||
// TODO: Override error messages
|
||||
export const siteInitializationFailed = createAction(SITE_INITIALIZE_FAILED);
|
||||
|
||||
const siteInitialized = createAction(SITE_INITIALIZED);
|
||||
|
@ -37,7 +37,7 @@ export const siteAddNotifications = createAction(
|
|||
|
||||
export const siteRemoveNotifications = createAction(
|
||||
SITE_NOTIFICATIONS_REMOVE,
|
||||
(date: Date[]) => date
|
||||
(id: string) => id
|
||||
);
|
||||
|
||||
export const siteChangeSidebar = createAction(
|
||||
|
|
|
@ -1,26 +1,21 @@
|
|||
import { useCallback, useEffect } from "react";
|
||||
import { useSystemSettings } from ".";
|
||||
import {
|
||||
siteAddNotifications,
|
||||
siteChangeSidebar,
|
||||
siteRemoveNotifications,
|
||||
} from "../actions";
|
||||
import { siteAddNotifications, siteChangeSidebar } from "../actions";
|
||||
import { useReduxAction, useReduxStore } from "./base";
|
||||
|
||||
export function useNotification(timeout: number = 5000) {
|
||||
export function useNotification(id: string, timeout: number = 5000) {
|
||||
const add = useReduxAction(siteAddNotifications);
|
||||
const remove = useReduxAction(siteRemoveNotifications);
|
||||
|
||||
return useCallback(
|
||||
(msg: Omit<ReduxStore.Notification, "timestamp">) => {
|
||||
const error: ReduxStore.Notification = {
|
||||
(msg: Omit<ReduxStore.Notification, "id" | "timeout">) => {
|
||||
const notification: ReduxStore.Notification = {
|
||||
...msg,
|
||||
timestamp: new Date(),
|
||||
id,
|
||||
timeout,
|
||||
};
|
||||
add([error]);
|
||||
setTimeout(() => remove([error.timestamp]), timeout);
|
||||
add([notification]);
|
||||
},
|
||||
[add, remove, timeout]
|
||||
[add, timeout, id]
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { differenceWith } from "lodash";
|
||||
import { remove, uniqBy } from "lodash";
|
||||
import { Action, handleActions } from "redux-actions";
|
||||
import apis from "../../apis";
|
||||
import {
|
||||
|
@ -36,16 +36,16 @@ const reducer = handleActions<ReduxStore.Site, any>(
|
|||
state,
|
||||
action: Action<ReduxStore.Notification[]>
|
||||
) => {
|
||||
const alerts = [...state.notifications, ...action.payload];
|
||||
return { ...state, notifications: alerts };
|
||||
},
|
||||
[SITE_NOTIFICATIONS_REMOVE]: (state, action: Action<Date[]>) => {
|
||||
const alerts = differenceWith(
|
||||
state.notifications,
|
||||
action.payload,
|
||||
(n, t) => n.timestamp === t
|
||||
const notifications = uniqBy(
|
||||
[...action.payload, ...state.notifications],
|
||||
(n) => n.id
|
||||
);
|
||||
return { ...state, notifications: alerts };
|
||||
return { ...state, notifications };
|
||||
},
|
||||
[SITE_NOTIFICATIONS_REMOVE]: (state, action: Action<string>) => {
|
||||
const notifications = [...state.notifications];
|
||||
remove(notifications, (n) => n.id === action.payload);
|
||||
return { ...state, notifications };
|
||||
},
|
||||
[SITE_SIDEBAR_UPDATE]: (state, action: Action<string>) => {
|
||||
return {
|
||||
|
|
3
frontend/src/@redux/redux.d.ts
vendored
3
frontend/src/@redux/redux.d.ts
vendored
|
@ -8,8 +8,9 @@ interface ReduxStore {
|
|||
namespace ReduxStore {
|
||||
interface Notification {
|
||||
type: "error" | "warning" | "info";
|
||||
id: string;
|
||||
message: string;
|
||||
timestamp: Date;
|
||||
timeout: number;
|
||||
}
|
||||
|
||||
interface Site {
|
||||
|
|
|
@ -7,7 +7,6 @@ import {
|
|||
seriesUpdateList,
|
||||
siteAddNotifications,
|
||||
siteInitializationFailed,
|
||||
siteRemoveNotifications,
|
||||
siteUpdateOffline,
|
||||
systemUpdateLanguagesAll,
|
||||
systemUpdateSettings,
|
||||
|
@ -50,16 +49,11 @@ export function createDefaultReducer(): SocketIO.Reducer[] {
|
|||
const notifications = msg.map<ReduxStore.Notification>((message) => ({
|
||||
message,
|
||||
type: "info",
|
||||
timestamp: new Date(),
|
||||
id: "backend-message",
|
||||
timeout: 5 * 1000,
|
||||
}));
|
||||
|
||||
reduxStore.dispatch(siteAddNotifications(notifications));
|
||||
|
||||
const ts = notifications.map((n) => n.timestamp);
|
||||
setTimeout(
|
||||
() => reduxStore.dispatch(siteRemoveNotifications(ts)),
|
||||
5000
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
|
|
@ -25,7 +25,7 @@ interface Props {}
|
|||
const App: FunctionComponent<Props> = () => {
|
||||
const { initialized, auth } = useReduxStore((s) => s.site);
|
||||
|
||||
const notify = useNotification(10 * 1000);
|
||||
const notify = useNotification("has-update", 10 * 1000);
|
||||
|
||||
// Has any update?
|
||||
const hasUpdate = useHasUpdateInject();
|
||||
|
|
|
@ -3,6 +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 { useTimeoutWhen } from "rooks";
|
||||
import { siteRemoveNotifications } from "../../@redux/actions";
|
||||
import { useReduxAction, useReduxStore } from "../../@redux/hooks/base";
|
||||
import "./style.scss";
|
||||
|
@ -15,10 +16,7 @@ const NotificationContainer: FunctionComponent<NotificationContainerProps> = ()
|
|||
const items = useMemo(
|
||||
() =>
|
||||
list.map((v) => (
|
||||
<NotificationToast
|
||||
key={v.timestamp.getTime()}
|
||||
{...v}
|
||||
></NotificationToast>
|
||||
<NotificationToast key={v.id} {...v}></NotificationToast>
|
||||
)),
|
||||
[list]
|
||||
);
|
||||
|
@ -32,14 +30,16 @@ const NotificationContainer: FunctionComponent<NotificationContainerProps> = ()
|
|||
type MessageHolderProps = ReduxStore.Notification & {};
|
||||
|
||||
const NotificationToast: FunctionComponent<MessageHolderProps> = (props) => {
|
||||
const { message, type, timestamp } = props;
|
||||
const { message, type, id, timeout } = props;
|
||||
const removeNotification = useReduxAction(siteRemoveNotifications);
|
||||
|
||||
const remove = useCallback(() => removeNotification([timestamp]), [
|
||||
const remove = useCallback(() => removeNotification(id), [
|
||||
removeNotification,
|
||||
timestamp,
|
||||
id,
|
||||
]);
|
||||
|
||||
useTimeoutWhen(remove, timeout);
|
||||
|
||||
return (
|
||||
<Toast onClose={remove} animation={false}>
|
||||
<Toast.Header>
|
||||
|
|
|
@ -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();
|
||||
const onError = useNotification("async-loading");
|
||||
|
||||
useEffect(() => {
|
||||
if (!state.updating && state.error !== undefined && !missing) {
|
||||
|
|
Loading…
Reference in a new issue