diff --git a/src/renderer/components/hooks.js b/src/renderer/components/hooks.js
index 1fbcc970..814adf65 100644
--- a/src/renderer/components/hooks.js
+++ b/src/renderer/components/hooks.js
@@ -108,3 +108,28 @@ export const useEmitter = key => {
return services.emitters[key]
}, [key, services])
}
+
+/**
+ * Track the number of pending invitations (invited:* keys in the store).
+ * Re-counts on every batch event that touches invited keys.
+ */
+export const useInvitationCount = () => {
+ const { store } = useServices()
+ const [count, setCount] = React.useState(0)
+
+ React.useEffect(() => {
+ if (!store) return
+
+ const recount = () => store.keys('invited').then(keys => setCount(keys.length))
+ recount()
+
+ const handler = ({ operations }) => {
+ if (operations.some(op => op.key && op.key.startsWith('invited:'))) recount()
+ }
+
+ store.on('batch', handler)
+ return () => store.off('batch', handler)
+ }, [store])
+
+ return count
+}
diff --git a/src/renderer/components/sidebar/ScopeSwitcher.css b/src/renderer/components/sidebar/ScopeSwitcher.css
index 92d1a0f8..32575c30 100644
--- a/src/renderer/components/sidebar/ScopeSwitcher.css
+++ b/src/renderer/components/sidebar/ScopeSwitcher.css
@@ -64,6 +64,24 @@
opacity: 1;
}
+.a74a-badge {
+ position: absolute;
+ top: 4px;
+ right: 4px;
+ min-width: 16px;
+ height: 16px;
+ padding: 0 4px;
+ border-radius: 8px;
+ background: #e9746c;
+ color: white;
+ font-size: 10px;
+ font-weight: 600;
+ line-height: 16px;
+ text-align: center;
+ pointer-events: none;
+ box-sizing: border-box;
+}
+
.a74a-breadcrumb {
display: flex;
flex-direction: column;
diff --git a/src/renderer/components/sidebar/ScopeSwitcher.js b/src/renderer/components/sidebar/ScopeSwitcher.js
index ce8642c3..1389c885 100644
--- a/src/renderer/components/sidebar/ScopeSwitcher.js
+++ b/src/renderer/components/sidebar/ScopeSwitcher.js
@@ -2,7 +2,7 @@ import * as R from 'ramda'
import React from 'react'
import PropTypes from 'prop-types'
import * as mdi from '@mdi/js'
-import { useMemento } from '../hooks'
+import { useMemento, useInvitationCount } from '../hooks'
import { defaultSearch } from './state'
import * as ID from '../../ids'
import { Tooltip } from 'react-tooltip'
@@ -99,6 +99,11 @@ const ScopeSwitch = props => {
<>
+ {props.badge > 0 && (
+
+ {props.badge > 99 ? '99+' : props.badge}
+
+ )}
>
@@ -112,6 +117,7 @@ ScopeSwitch.propTypes = {
label: PropTypes.string.isRequired,
scope: PropTypes.string.isRequired,
toolTip: PropTypes.string,
+ badge: PropTypes.number,
onScopeClick: PropTypes.func
}
@@ -120,12 +126,15 @@ ScopeSwitch.propTypes = {
* Vertical column of scope icons
*/
export const ScopeSwitcher = ({ onScopeClick }) => {
+ const invitationCount = useInvitationCount()
+
const defaultSwitches = Object.entries(SCOPES).map(([scope, label]) =>
)