Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/src/packages/frontend/app/notifications.tsx
Views: 687
/*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";78import {9CSS,10React,11redux,12useActions,13useMemo,14useTypedRedux,15} from "@cocalc/frontend/app-framework";16import { Icon } from "@cocalc/frontend/components";17import { unreachable } from "@cocalc/util/misc";18import { COLORS } from "@cocalc/util/theme";19import track from "@cocalc/frontend/user-tracking";20import { PageStyle, TOP_BAR_ELEMENT_CLASS } from "./top-nav-consts";21import { blur_active_element } from "./util";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");3940const count = useMemo(() => {41switch (type) {42case "bell":43return notify_count ?? 0;44case "notifications":45return mentions_store.get_unseen_size(mentions) ?? 0;46default:47unreachable(type);48return 0;49}50}, [type, notify_count, mentions]);5152const outer_style: CSS = {53padding: `${topPaddingIcons} ${sidePaddingIcons}`,54height: `${pageStyle.height}px`,55...(active ? { backgroundColor: COLORS.TOP_BAR.ACTIVE } : {}),56};5758const inner_style: CSS = {59cursor: "pointer",60position: "relative",61...(type === "notifications"62? { top: Math.floor(pageStyle.height / 10) + 1 } // bit offset to make room for the badge63: { top: 1 }),64};6566function onClick(e) {67e.preventDefault();68e.stopPropagation();6970switch (type) {71case "bell":72page_actions.toggle_show_file_use();73blur_active_element();74if (!active) {75track("top_nav", { name: "file_use" });76}77break;7879case "notifications":80page_actions.set_active_tab("notifications");8182// the idea of the following is to make sure the user sees immediately the most important notifications83if (count > 0) {84// mentions are more important, and this makes them shown to the user85redux.getActions("mentions").set_filter("unread");86} else if (news_unread > 0) {87// similar to the above, guide user towards seeing the news (if there are no mentions)88redux.getActions("mentions").set_filter("allNews");89}9091if (!active) {92track("top_nav", { name: "mentions" });93}94break;9596default:97unreachable(type);98}99}100101function renderBadge() {102switch (type) {103case "bell":104return (105<Badge106showZero107color={count == 0 ? COLORS.GRAY : undefined}108count={count}109className={count > 0 ? "smc-bell-notification" : ""}110/>111);112113case "notifications":114// only wiggle, if there are unread news – because they clear out automatically.115// mentions can be more long term, i.e. keep them unread until you mark them done.116const wiggle = news_unread > 0;117return (118<Badge119color={count == 0 ? COLORS.GRAY : undefined}120count={count}121size="small"122>123<Badge124color={news_unread == 0 ? COLORS.GRAY : ANTD_BLUE.primary}125count={news_unread}126showZero={false}127size="small"128offset={[newsBadgeOffset, 0]}129>130<Icon131style={{ fontSize: fontSizeIcons }}132className={wiggle ? "smc-bell-notification" : ""}133name="mail"134/>{" "}135</Badge>136</Badge>137);138139default:140unreachable(type);141}142}143144const className = TOP_BAR_ELEMENT_CLASS + (active ? " active" : "");145146return (147<div style={outer_style} onClick={onClick} className={className}>148<div style={inner_style}>{renderBadge()}</div>149</div>150);151});152153154