Add progress notifications

This commit is contained in:
LASER-Yi 2021-05-09 16:41:19 +08:00
parent d5112d365c
commit 4513c4f676
6 changed files with 98 additions and 12 deletions

View File

@ -8,6 +8,8 @@ import {
SITE_NOTIFICATIONS_ADD,
SITE_NOTIFICATIONS_REMOVE,
SITE_OFFLINE_UPDATE,
SITE_PROGRESS_ADD,
SITE_PROGRESS_REMOVE,
SITE_SIDEBAR_UPDATE,
} from "../constants";
import { createAsyncAction, createCallbackAction } from "./factory";
@ -32,7 +34,7 @@ export const badgeUpdateAll = createAsyncAction(SITE_BADGE_UPDATE, () =>
export const siteAddNotifications = createAction(
SITE_NOTIFICATIONS_ADD,
(err: ReduxStore.Notification[]) => err
(notification: ReduxStore.Notification[]) => notification
);
export const siteRemoveNotifications = createAction(
@ -40,6 +42,16 @@ export const siteRemoveNotifications = createAction(
(id: string) => id
);
export const siteAddProgress = createAction(
SITE_PROGRESS_ADD,
(progress: ReduxStore.Progress[]) => progress
);
export const siteRemoveProgress = createAction(
SITE_PROGRESS_REMOVE,
(id: string) => id
);
export const siteChangeSidebar = createAction(
SITE_SIDEBAR_UPDATE,
(id: string) => id

View File

@ -36,6 +36,8 @@ 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_PROGRESS_ADD = "SITE_PROGRESS_ADD";
export const SITE_PROGRESS_REMOVE = "SITE_PROGRESS_REMOVE";
export const SITE_SIDEBAR_UPDATE = "SITE_SIDEBAR_UPDATE";
export const SITE_BADGE_UPDATE = "SITE_BADGE_UPDATE";
export const SITE_OFFLINE_UPDATE = "SITE_OFFLINE_UPDATE";

View File

@ -9,6 +9,8 @@ import {
SITE_NOTIFICATIONS_ADD,
SITE_NOTIFICATIONS_REMOVE,
SITE_OFFLINE_UPDATE,
SITE_PROGRESS_ADD,
SITE_PROGRESS_REMOVE,
SITE_SIDEBAR_UPDATE,
} from "../constants";
import { AsyncAction } from "../types";
@ -47,6 +49,18 @@ const reducer = handleActions<ReduxStore.Site, any>(
remove(notifications, (n) => n.id === action.payload);
return { ...state, notifications };
},
[SITE_PROGRESS_ADD]: (state, action: Action<ReduxStore.Progress[]>) => {
const progress = uniqBy(
[...action.payload, ...state.progress],
(n) => n.id
);
return { ...state, progress };
},
[SITE_PROGRESS_REMOVE]: (state, action: Action<string>) => {
const progress = [...state.progress];
remove(progress, (n) => n.id === action.payload);
return { ...state, progress };
},
[SITE_SIDEBAR_UPDATE]: (state, action: Action<string>) => {
return {
...state,
@ -70,6 +84,7 @@ const reducer = handleActions<ReduxStore.Site, any>(
{
initialized: false,
auth: true,
progress: [],
notifications: [],
sidebar: "",
badges: {

View File

@ -13,10 +13,18 @@ namespace ReduxStore {
timeout: number;
}
interface Progress {
id: string;
name: string;
value: number;
count: number;
}
interface Site {
// Initialization state or error message
initialized: boolean | string;
auth: boolean;
progress: Progress[];
notifications: Notification[];
sidebar: string;
badges: Badge;

View File

@ -37,4 +37,8 @@ namespace SocketIO {
EventType,
OptionalRecord<ActionType, any[]>
>;
namespace CustomEvent {
type Progress = ReduxStore.Progress;
}
}

View File

@ -1,25 +1,35 @@
import { faExclamationTriangle } from "@fortawesome/free-solid-svg-icons";
import {
faExclamationTriangle,
faPaperPlane,
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { capitalize } from "lodash";
import React, { FunctionComponent, useCallback, useMemo } from "react";
import { Toast } from "react-bootstrap";
import { ProgressBar, Toast } from "react-bootstrap";
import { useTimeoutWhen } from "rooks";
import { siteRemoveNotifications } from "../../@redux/actions";
import {
siteRemoveNotifications,
siteRemoveProgress,
} from "../../@redux/actions";
import { useReduxAction, useReduxStore } from "../../@redux/hooks/base";
import "./style.scss";
export interface NotificationContainerProps {}
const NotificationContainer: FunctionComponent<NotificationContainerProps> = () => {
const list = useReduxStore((s) => s.site.notifications);
const { progress, notifications } = useReduxStore((s) => s.site);
const items = useMemo(
() =>
list.map((v) => (
<NotificationToast key={v.id} {...v}></NotificationToast>
)),
[list]
);
const items = useMemo(() => {
const progressItems = progress.map((v) => (
<ProgressToast key={v.id} {...v}></ProgressToast>
));
const notificationItems = notifications.map((v) => (
<NotificationToast key={v.id} {...v}></NotificationToast>
));
return [...progressItems, ...notificationItems];
}, [notifications, progress]);
return (
<div className="alert-container">
<div className="toast-container">{items}</div>
@ -54,4 +64,39 @@ const NotificationToast: FunctionComponent<MessageHolderProps> = (props) => {
);
};
type ProgressHolderProps = ReduxStore.Progress & {};
const ProgressToast: FunctionComponent<ProgressHolderProps> = ({
id,
name,
value,
count,
}) => {
const removeProgress = useReduxAction(siteRemoveProgress);
const remove = useCallback(() => removeProgress(id), [removeProgress, id]);
// TODO: Auto remove
return (
<Toast onClose={remove}>
<Toast.Body>
<div className="mb-2 mt-1">
<FontAwesomeIcon
className="mr-2"
icon={faPaperPlane}
></FontAwesomeIcon>
<span>{name}</span>
</div>
<ProgressBar
className="my-1"
animated
now={value / count}
max={1}
label={`${value}/${count}`}
></ProgressBar>
</Toast.Body>
</Toast>
);
};
export default NotificationContainer;