Skip to content

Commit 43f30ce

Browse files
Add support for showing desktop notifications.
1 parent b70d647 commit 43f30ce

File tree

3 files changed

+123
-2
lines changed

3 files changed

+123
-2
lines changed
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { useEffect, useState } from 'react';
2+
import { UserNotification } from '../api';
3+
import * as engineer from '../icons/engineer_blu.jpg';
4+
5+
export const DesktopNotifications = ({
6+
notifications,
7+
isLoading
8+
}: {
9+
notifications?: UserNotification[];
10+
isLoading: boolean;
11+
}) => {
12+
const [newest, setNewest] = useState<number>();
13+
14+
useEffect(() => {
15+
if (isLoading || notifications == null) {
16+
return;
17+
}
18+
19+
// Track the newest one we get on initial load so we are only showing items that are newer.
20+
if (newest == null) {
21+
setNewest(notifications.length > 0 ? notifications[0].person_notification_id : 0);
22+
return;
23+
}
24+
25+
notifications
26+
.filter((n) => n.person_notification_id > newest)
27+
.map((n) => {
28+
setNewest(n.person_notification_id);
29+
new Notification('New Notification Received', {
30+
body: n.message,
31+
// timestamp: Math.floor(n.created_on.getTime()), chrome only
32+
silent: true,
33+
lang: 'en-US',
34+
icon: engineer.default
35+
});
36+
});
37+
}, [isLoading, newest, notifications]);
38+
39+
return <></>;
40+
};

frontend/src/component/TopBar.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ import { useColourModeCtx } from '../hooks/useColourModeCtx.ts';
5858
import steamLogo from '../icons/steam_login_sm.png';
5959
import { tf2Fonts } from '../theme';
6060
import { generateOIDCLink } from '../util/auth/generateOIDCLink.ts';
61+
import { DesktopNotifications } from './DesktopNotifications.tsx';
6162
import RouterLink from './RouterLink.tsx';
6263
import { VCenterBox } from './VCenterBox.tsx';
6364

@@ -74,9 +75,10 @@ export const TopBar = () => {
7475
const { data: notifications, isLoading } = useQuery({
7576
queryKey: ['notifications'],
7677
queryFn: async () => {
77-
return await apiGetNotifications();
78+
return (await apiGetNotifications()) ?? [];
7879
},
7980
refetchInterval: 60 * 1000,
81+
refetchIntervalInBackground: true,
8082
refetchOnWindowFocus: true
8183
});
8284

@@ -491,6 +493,7 @@ export const TopBar = () => {
491493
</Box>
492494
</Toolbar>
493495
</Container>
496+
<DesktopNotifications notifications={notifications} isLoading={isLoading} />
494497
</AppBar>
495498
);
496499
};

frontend/src/routes/_auth.settings.tsx

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
1-
import { useState } from 'react';
1+
import { useMemo, useState } from 'react';
22
import { useModal } from '@ebay/nice-modal-react';
33
import CableIcon from '@mui/icons-material/Cable';
44
import ConstructionIcon from '@mui/icons-material/Construction';
55
import DeleteIcon from '@mui/icons-material/Delete';
66
import ForumIcon from '@mui/icons-material/Forum';
77
import LoginIcon from '@mui/icons-material/Login';
8+
import NotificationsActiveIcon from '@mui/icons-material/NotificationsActive';
89
import SettingsIcon from '@mui/icons-material/Settings';
910
import SettingsInputComponentIcon from '@mui/icons-material/SettingsInputComponent';
1011
import SportsEsportsIcon from '@mui/icons-material/SportsEsports';
1112
import Avatar from '@mui/material/Avatar';
1213
import Box from '@mui/material/Box';
1314
import Button from '@mui/material/Button';
1415
import Link from '@mui/material/Link';
16+
import List from '@mui/material/List';
17+
import ListItemText from '@mui/material/ListItemText';
1518
import Stack from '@mui/material/Stack';
19+
import Tooltip from '@mui/material/Tooltip';
1620
import Typography from '@mui/material/Typography';
1721
import Grid from '@mui/material/Unstable_Grid2';
1822
import { useForm } from '@tanstack/react-form';
@@ -167,6 +171,12 @@ const GeneralSection = ({
167171
settings: PersonSettings;
168172
mutate: (s: PersonSettings) => void;
169173
}) => {
174+
const [notifPerms, setNotifPerms] = useState(Notification.permission);
175+
176+
const notificationsSupported = useMemo(() => {
177+
return 'Notification' in window;
178+
}, []);
179+
170180
const { Field, Subscribe, handleSubmit, reset } = useForm({
171181
onSubmit: async ({ value }) => {
172182
mutate({ ...settings, ...value });
@@ -177,6 +187,10 @@ const GeneralSection = ({
177187
}
178188
});
179189

190+
const togglePerms = async () => {
191+
setNotifPerms(await Notification.requestPermission());
192+
};
193+
180194
return (
181195
<TabSection
182196
tab={'general'}
@@ -192,6 +206,70 @@ const GeneralSection = ({
192206
}}
193207
>
194208
<Grid container spacing={2}>
209+
{notificationsSupported && (
210+
<Grid xs={12}>
211+
<div>
212+
<Grid container spacing={1}>
213+
<Grid md={6} xs={12}>
214+
<Stack spacing={1}>
215+
<Typography>Show desktop notifications?</Typography>
216+
{notifPerms != 'granted' ? (
217+
<Button
218+
variant={'contained'}
219+
color={'success'}
220+
onClick={togglePerms}
221+
startIcon={<NotificationsActiveIcon />}
222+
>
223+
Enable Desktop Notifications
224+
</Button>
225+
) : (
226+
<Tooltip
227+
title={
228+
'Please see the links to the right for instructions on how to disable'
229+
}
230+
>
231+
<span>
232+
<Button
233+
disabled={true}
234+
variant={'contained'}
235+
color={'success'}
236+
onClick={togglePerms}
237+
startIcon={<NotificationsActiveIcon />}
238+
>
239+
Desktop Notifications Enabled
240+
</Button>
241+
</span>
242+
</Tooltip>
243+
)}
244+
</Stack>
245+
</Grid>
246+
<Grid md={6} xs={12}>
247+
<Typography>How to disable notifications: </Typography>
248+
<List>
249+
<ListItemText>
250+
<Link
251+
href={
252+
'https://support.google.com/chrome/answer/114662?sjid=2540186662959230327-NC&visit_id=638611827496769425-656746251&rd=1'
253+
}
254+
>
255+
Google Chrome
256+
</Link>
257+
</ListItemText>
258+
<ListItemText>
259+
<Link
260+
href={
261+
'https://support.mozilla.org/en-US/kb/push-notifications-firefox'
262+
}
263+
>
264+
Mozilla Firefox
265+
</Link>
266+
</ListItemText>
267+
</List>
268+
</Grid>
269+
</Grid>
270+
</div>
271+
</Grid>
272+
)}
195273
<Grid xs={12}>
196274
<Field
197275
name={'stats_hidden'}

0 commit comments

Comments
 (0)