diff --git a/app/controllers/panel_controller.rb b/app/controllers/panel_controller.rb index b1e8b08b704..c4fac828968 100644 --- a/app/controllers/panel_controller.rb +++ b/app/controllers/panel_controller.rb @@ -22,6 +22,10 @@ def index panel_details = User.panel_list[@panel_id.to_sym] @pages = panel_details[:pages] @title = panel_details[:name] + # This awkward mapping is necessary because `panel_notifications` returns callables + # which compute the value _if needed_. The point is to reduce workload, not every time + # that `User.panel_notifications` is called should trigger an actual computation. + @notifications = User.panel_notifications.slice(*@pages).transform_values(&:call) end def generate_db_token diff --git a/app/models/user.rb b/app/models/user.rb index 706790fcf14..dd9f619a164 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -643,6 +643,12 @@ def self.panel_pages ].index_with { |panel_page| panel_page.to_s.underscore.dasherize } end + def self.panel_notifications + { + self.panel_pages[:approveAvatars] => lambda { User.where.not(pending_avatar: nil).count }, + } + end + def self.panel_list panel_pages = User.panel_pages { diff --git a/app/views/panel/index.html.erb b/app/views/panel/index.html.erb index f8780b049e4..13576a1f667 100644 --- a/app/views/panel/index.html.erb +++ b/app/views/panel/index.html.erb @@ -3,4 +3,5 @@ loggedInUserId: current_user.id, heading: @title, pages: @pages, + pageNotifications: @notifications, }) %> diff --git a/app/webpacker/components/Panel/PanelTemplate.jsx b/app/webpacker/components/Panel/PanelTemplate.jsx index 53285620bad..f421ccfba3f 100644 --- a/app/webpacker/components/Panel/PanelTemplate.jsx +++ b/app/webpacker/components/Panel/PanelTemplate.jsx @@ -2,13 +2,18 @@ import React from 'react'; import { Container, Dropdown, - Grid, Header, Icon, Menu, Segment, + Grid, Header, Icon, Label, Menu, Segment, } from 'semantic-ui-react'; import useHash from '../../lib/hooks/useHash'; import ConfirmProvider from '../../lib/providers/ConfirmProvider'; import PanelPages from './PanelPages'; -export default function PanelTemplate({ heading, pages, loggedInUserId }) { +export default function PanelTemplate({ + heading, + pages, + pageNotifications, + loggedInUserId, +}) { const [hash, setHash] = useHash(); const SelectedComponent = React.useMemo(() => { @@ -28,9 +33,10 @@ export default function PanelTemplate({ heading, pages, loggedInUserId }) { const menuOptions = React.useMemo(() => (pages.map( (page) => ({ id: page, + notification: pageNotifications?.[page], ...PanelPages[page], }), - )), [pages]); + )), [pages, pageNotifications]); return ( @@ -48,6 +54,11 @@ export default function PanelTemplate({ heading, pages, loggedInUserId }) { )} > {!menuOption.component && } + {menuOption.notification !== undefined && ( + + )} {menuOption.name} ))} @@ -65,6 +76,7 @@ export default function PanelTemplate({ heading, pages, loggedInUserId }) { text: menuOption.name, value: menuOption.id, icon: !menuOption.component && 'external alternate', + label: menuOption.notification && ({ color: 'red', content: menuOption.notification }), }))} value={hash} onChange={(_, { value }) => setHash(value)}