Add progress notifications

pull/1405/head
LASER-Yi 4 years ago
parent d5112d365c
commit 4513c4f676

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

@ -36,6 +36,8 @@ export const SITE_INITIALIZED = "SITE_SYSTEM_INITIALIZED";
export const SITE_INITIALIZE_FAILED = "SITE_INITIALIZE_FAILED"; export const SITE_INITIALIZE_FAILED = "SITE_INITIALIZE_FAILED";
export const SITE_NOTIFICATIONS_ADD = "SITE_NOTIFICATIONS_ADD"; export const SITE_NOTIFICATIONS_ADD = "SITE_NOTIFICATIONS_ADD";
export const SITE_NOTIFICATIONS_REMOVE = "SITE_NOTIFICATIONS_REMOVE"; 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_SIDEBAR_UPDATE = "SITE_SIDEBAR_UPDATE";
export const SITE_BADGE_UPDATE = "SITE_BADGE_UPDATE"; export const SITE_BADGE_UPDATE = "SITE_BADGE_UPDATE";
export const SITE_OFFLINE_UPDATE = "SITE_OFFLINE_UPDATE"; export const SITE_OFFLINE_UPDATE = "SITE_OFFLINE_UPDATE";

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

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

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

@ -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 { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { capitalize } from "lodash"; import { capitalize } from "lodash";
import React, { FunctionComponent, useCallback, useMemo } from "react"; import React, { FunctionComponent, useCallback, useMemo } from "react";
import { Toast } from "react-bootstrap"; import { ProgressBar, Toast } from "react-bootstrap";
import { useTimeoutWhen } from "rooks"; import { useTimeoutWhen } from "rooks";
import { siteRemoveNotifications } from "../../@redux/actions"; import {
siteRemoveNotifications,
siteRemoveProgress,
} from "../../@redux/actions";
import { useReduxAction, useReduxStore } from "../../@redux/hooks/base"; import { useReduxAction, useReduxStore } from "../../@redux/hooks/base";
import "./style.scss"; import "./style.scss";
export interface NotificationContainerProps {} export interface NotificationContainerProps {}
const NotificationContainer: FunctionComponent<NotificationContainerProps> = () => { const NotificationContainer: FunctionComponent<NotificationContainerProps> = () => {
const list = useReduxStore((s) => s.site.notifications); const { progress, notifications } = useReduxStore((s) => s.site);
const items = useMemo( const items = useMemo(() => {
() => const progressItems = progress.map((v) => (
list.map((v) => ( <ProgressToast key={v.id} {...v}></ProgressToast>
<NotificationToast key={v.id} {...v}></NotificationToast> ));
)),
[list] const notificationItems = notifications.map((v) => (
); <NotificationToast key={v.id} {...v}></NotificationToast>
));
return [...progressItems, ...notificationItems];
}, [notifications, progress]);
return ( return (
<div className="alert-container"> <div className="alert-container">
<div className="toast-container">{items}</div> <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; export default NotificationContainer;

Loading…
Cancel
Save