Path: blob/master/src/packages/frontend/app/notifications.tsx
1496 views
/*1* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.2* License: MS-RSL – see LICENSE.md for details3*/45import { blue as ANTD_BLUE } from "@ant-design/colors";6import { Badge } from "antd";7import {8CSS,9React,10redux,11useActions,12useTypedRedux,13} from "@cocalc/frontend/app-framework";14import { Icon } from "@cocalc/frontend/components";15import { unreachable } from "@cocalc/util/misc";16import { COLORS } from "@cocalc/util/theme";17import track from "@cocalc/frontend/user-tracking";18import { PageStyle, TOP_BAR_ELEMENT_CLASS } from "./top-nav-consts";19import { blur_active_element } from "./util";20import { useEffect, useMemo } from "react";21import { set_window_title } from "@cocalc/frontend/browser";2223interface Props {24type: "bell" | "notifications";25active: boolean;26pageStyle: PageStyle;27}2829export const Notification: React.FC<Props> = React.memo((props: Props) => {30const { active, type, pageStyle } = props;31const { topPaddingIcons, sidePaddingIcons, fontSizeIcons } = pageStyle;32const newsBadgeOffset = `-${fontSizeIcons}`;33const page_actions = useActions("page");3435const mentions_store = redux.getStore("mentions");36const mentions = useTypedRedux("mentions", "mentions");37const notify_count = useTypedRedux("file_use", "notify_count");38const news_unread = useTypedRedux("news", "unread");39const unread_message_count =40useTypedRedux("account", "unread_message_count") ?? 0;4142const count = useMemo(() => {43switch (type) {44case "bell":45return notify_count ?? 0;46case "notifications":47return mentions_store.getUnreadSize() ?? 0;48default:49unreachable(type);50return 0;51}52}, [type, notify_count, mentions]);5354useEffect(() => {55set_window_title();56}, [count, news_unread]);5758const outer_style: CSS = {59padding: `${topPaddingIcons} ${sidePaddingIcons}`,60height: `${pageStyle.height}px`,61...(active ? { backgroundColor: COLORS.TOP_BAR.ACTIVE } : {}),62};6364const inner_style: CSS = {65cursor: "pointer",66position: "relative",67...(type === "notifications"68? { top: Math.floor(pageStyle.height / 10) + 1 } // bit offset to make room for the badge69: { top: 1 }),70};7172function onClick(e) {73e.preventDefault();74e.stopPropagation();7576switch (type) {77case "bell":78page_actions.toggle_show_file_use();79blur_active_element();80if (!active) {81track("top_nav", { name: "file_use" });82}83break;8485case "notifications":86page_actions.set_active_tab("notifications");87if (!active) {88track("top_nav", { name: "mentions" });89}90break;9192default:93unreachable(type);94}95}9697function renderBadge() {98switch (type) {99case "bell":100return (101<Badge102showZero103color={count == 0 ? COLORS.GRAY : undefined}104count={count}105className={count > 0 ? "smc-bell-notification" : ""}106/>107);108109case "notifications":110// only wiggle, if there are unread news – because they clear out automatically.111// mentions can be more long term, i.e. keep them unread until you mark them done.112const wiggle = news_unread > 0 || unread_message_count > 0;113return (114<Badge115color={unread_message_count == 0 ? COLORS.GRAY : "green"}116count={unread_message_count}117size="small"118showZero={false}119offset={[0, `${fontSizeIcons}`]}120>121<Badge122color={count == 0 ? COLORS.GRAY : undefined}123count={count}124size="small"125>126<Badge127color={news_unread == 0 ? COLORS.GRAY : ANTD_BLUE.primary}128count={news_unread}129showZero={false}130size="small"131offset={[newsBadgeOffset, 0]}132>133<Icon134style={{ fontSize: fontSizeIcons }}135className={wiggle ? "smc-bell-notification" : ""}136name="mail"137/>{" "}138</Badge>139</Badge>140</Badge>141);142143default:144unreachable(type);145}146}147148const className = TOP_BAR_ELEMENT_CLASS + (active ? " active" : "");149150return (151<div style={outer_style} onClick={onClick} className={className}>152<div style={inner_style}>{renderBadge()}</div>153</div>154);155});156157158