Skip to content

Commit

Permalink
Add support for showing desktop notifications.
Browse files Browse the repository at this point in the history
  • Loading branch information
leighmacdonald committed Sep 6, 2024
1 parent b70d647 commit 225a2bb
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 2 deletions.
40 changes: 40 additions & 0 deletions frontend/src/component/DesktopNotifications.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { useEffect, useState } from 'react';
import { UserNotification } from '../api';
import * as engineer from '../icons/engineer_blu.jpg';

export const DesktopNotifications = ({
notifications,
isLoading
}: {
notifications?: UserNotification[];
isLoading: boolean;
}) => {
const [newest, setNewest] = useState<number>();

useEffect(() => {
if (isLoading || notifications == null) {
return;
}

// Track the newest one we get on initial load so we are only showing items that are newer.
if (newest == null) {
setNewest(notifications.length > 0 ? notifications[0].person_notification_id : 0);
return;
}

notifications
.filter((n) => n.person_notification_id > newest)
.map((n) => {
setNewest(n.person_notification_id);
new Notification('New Notification Received', {
body: n.message,
// timestamp: Math.floor(n.created_on.getTime()), chrome only
silent: true,
lang: 'en-US',
icon: engineer.default
});
});
}, [isLoading, newest, notifications]);

return <></>;
};
5 changes: 4 additions & 1 deletion frontend/src/component/TopBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ import { useColourModeCtx } from '../hooks/useColourModeCtx.ts';
import steamLogo from '../icons/steam_login_sm.png';
import { tf2Fonts } from '../theme';
import { generateOIDCLink } from '../util/auth/generateOIDCLink.ts';
import { DesktopNotifications } from './DesktopNotifications.tsx';
import RouterLink from './RouterLink.tsx';
import { VCenterBox } from './VCenterBox.tsx';

Expand All @@ -74,9 +75,10 @@ export const TopBar = () => {
const { data: notifications, isLoading } = useQuery({
queryKey: ['notifications'],
queryFn: async () => {
return await apiGetNotifications();
return (await apiGetNotifications()) ?? [];
},
refetchInterval: 60 * 1000,
refetchIntervalInBackground: true,
refetchOnWindowFocus: true
});

Expand Down Expand Up @@ -491,6 +493,7 @@ export const TopBar = () => {
</Box>
</Toolbar>
</Container>
<DesktopNotifications notifications={notifications} isLoading={isLoading} />
</AppBar>
);
};
80 changes: 79 additions & 1 deletion frontend/src/routes/_auth.settings.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
import { useState } from 'react';
import { useMemo, useState } from 'react';
import { useModal } from '@ebay/nice-modal-react';
import CableIcon from '@mui/icons-material/Cable';
import ConstructionIcon from '@mui/icons-material/Construction';
import DeleteIcon from '@mui/icons-material/Delete';
import ForumIcon from '@mui/icons-material/Forum';
import LoginIcon from '@mui/icons-material/Login';
import NotificationsActiveIcon from '@mui/icons-material/NotificationsActive';
import SettingsIcon from '@mui/icons-material/Settings';
import SettingsInputComponentIcon from '@mui/icons-material/SettingsInputComponent';
import SportsEsportsIcon from '@mui/icons-material/SportsEsports';
import Avatar from '@mui/material/Avatar';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
import Link from '@mui/material/Link';
import List from '@mui/material/List';
import ListItemText from '@mui/material/ListItemText';
import Stack from '@mui/material/Stack';
import Tooltip from '@mui/material/Tooltip';
import Typography from '@mui/material/Typography';
import Grid from '@mui/material/Unstable_Grid2';
import { useForm } from '@tanstack/react-form';
Expand Down Expand Up @@ -167,6 +171,12 @@ const GeneralSection = ({
settings: PersonSettings;
mutate: (s: PersonSettings) => void;
}) => {
const [notifPerms, setNotifPerms] = useState(Notification.permission);

const notificationsSupported = useMemo(() => {
return 'Notification' in window;
}, []);

const { Field, Subscribe, handleSubmit, reset } = useForm({
onSubmit: async ({ value }) => {
mutate({ ...settings, ...value });
Expand All @@ -177,6 +187,10 @@ const GeneralSection = ({
}
});

const togglePerms = async () => {
setNotifPerms(await Notification.requestPermission());
};

return (
<TabSection
tab={'general'}
Expand All @@ -192,6 +206,70 @@ const GeneralSection = ({
}}
>
<Grid container spacing={2}>
{notificationsSupported && (
<Grid xs={12}>
<div>
<Grid container spacing={1}>
<Grid md={6} xs={12}>
<Stack spacing={1}>
<Typography>Show desktop notifications?</Typography>
{notifPerms != 'granted' ? (
<Button
variant={'contained'}
color={'success'}
onClick={togglePerms}
startIcon={<NotificationsActiveIcon />}
>
Enable Desktop Notifications
</Button>
) : (
<Tooltip
title={
'Please see the links to the right for instructions on how to disable'
}
>
<span>
<Button
disabled={true}
variant={'contained'}
color={'success'}
onClick={togglePerms}
startIcon={<NotificationsActiveIcon />}
>
Desktop Notifications Enabled
</Button>
</span>
</Tooltip>
)}
</Stack>
</Grid>
<Grid md={6} xs={12}>
<Typography>How to disable notifications: </Typography>
<List>
<ListItemText>
<Link
href={
'https://support.google.com/chrome/answer/114662?sjid=2540186662959230327-NC&visit_id=638611827496769425-656746251&rd=1'
}
>
Google Chrome
</Link>
</ListItemText>
<ListItemText>
<Link
href={
'https://support.mozilla.org/en-US/kb/push-notifications-firefox'
}
>
Mozilla Firefox
</Link>
</ListItemText>
</List>
</Grid>
</Grid>
</div>
</Grid>
)}
<Grid xs={12}>
<Field
name={'stats_hidden'}
Expand Down

0 comments on commit 225a2bb

Please sign in to comment.