Home page; "all notifications"

This commit is contained in:
Philipp Heckel 2022-03-07 16:36:49 -05:00
parent 1d2f3f72e4
commit 5bed926323
5 changed files with 73 additions and 46 deletions

View file

@ -38,6 +38,14 @@ class SubscriptionManager {
async getNotifications(subscriptionId) { async getNotifications(subscriptionId) {
return db.notifications return db.notifications
.where({ subscriptionId: subscriptionId }) .where({ subscriptionId: subscriptionId })
.reverse()
.sortBy("time"); // Inefficient, but there is no other way (see docs)
}
async getAllNotifications() {
return db.notifications
.orderBy("time") // Efficient, see docs
.reverse()
.toArray(); .toArray();
} }

View file

@ -10,7 +10,6 @@ import connectionManager from "../app/ConnectionManager";
import Navigation from "./Navigation"; import Navigation from "./Navigation";
import ActionBar from "./ActionBar"; import ActionBar from "./ActionBar";
import notifier from "../app/Notifier"; import notifier from "../app/Notifier";
import NoTopics from "./NoTopics";
import Preferences from "./Preferences"; import Preferences from "./Preferences";
import {useLiveQuery} from "dexie-react-hooks"; import {useLiveQuery} from "dexie-react-hooks";
import poller from "../app/Poller"; import poller from "../app/Poller";
@ -56,7 +55,6 @@ const Root = () => {
}, [subscriptions, users]); // Dangle! }, [subscriptions, users]); // Dangle!
useEffect(() => { useEffect(() => {
console.log(`hello ${newNotificationsCount}`)
document.title = (newNotificationsCount > 0) ? `(${newNotificationsCount}) ntfy web` : "ntfy web"; document.title = (newNotificationsCount > 0) ? `(${newNotificationsCount}) ntfy web` : "ntfy web";
}, [newNotificationsCount]); }, [newNotificationsCount]);
@ -81,10 +79,10 @@ const Root = () => {
<Main> <Main>
<Toolbar/> <Toolbar/>
<Routes> <Routes>
<Route path="/" element={<NoTopics />} />
<Route path="settings" element={<Preferences />} /> <Route path="settings" element={<Preferences />} />
<Route path=":baseUrl/:topic" element={<Notifications subscription={selectedSubscription}/>} /> <Route path="/" element={<Notifications mode="all" subscriptions={subscriptions} />} />
<Route path=":topic" element={<Notifications subscription={selectedSubscription}/>} /> <Route path=":baseUrl/:topic" element={<Notifications mode="one" subscription={selectedSubscription}/>} />
<Route path=":topic" element={<Notifications mode="one" subscription={selectedSubscription}/>} />
</Routes> </Routes>
</Main> </Main>
</Box> </Box>

View file

@ -133,9 +133,10 @@ const SubscriptionList = (props) => {
const SubscriptionItem = (props) => { const SubscriptionItem = (props) => {
const navigate = useNavigate(); const navigate = useNavigate();
const subscription = props.subscription; const subscription = props.subscription;
const iconBadge = (subscription.new <= 99) ? subscription.new : "99+";
const icon = (subscription.state === ConnectionState.Connecting) const icon = (subscription.state === ConnectionState.Connecting)
? <CircularProgress size="24px"/> ? <CircularProgress size="24px"/>
: <Badge badgeContent={subscription.new} invisible={subscription.new === 0} color="primary"><ChatBubbleOutlineIcon/></Badge>; : <Badge badgeContent={iconBadge} invisible={subscription.new === 0} color="primary"><ChatBubbleOutlineIcon/></Badge>;
const label = (subscription.baseUrl === window.location.origin) const label = (subscription.baseUrl === window.location.origin)
? subscription.topic ? subscription.topic
: topicShortUrl(subscription.baseUrl, subscription.topic); : topicShortUrl(subscription.baseUrl, subscription.topic);

View file

@ -1,25 +0,0 @@
import {Link} from "@mui/material";
import Typography from "@mui/material/Typography";
import * as React from "react";
import {Paragraph, VerticallyCenteredContainer} from "./styles";
const NoTopics = (props) => {
return (
<VerticallyCenteredContainer maxWidth="xs">
<Typography variant="h5" align="center" sx={{ paddingBottom: 1 }}>
<img src="static/img/ntfy-outline.svg" height="64" width="64" alt="No topics"/><br />
It looks like you don't have any subscriptions yet.
</Typography>
<Paragraph>
Click the "Add subscription" link to create or subscribe to a topic. After that, you can send messages
via PUT or POST and you'll receive notifications here.
</Paragraph>
<Paragraph>
For more information, check out the <Link href="https://ntfy.sh" target="_blank" rel="noopener">website</Link> or
{" "}<Link href="https://ntfy.sh/docs" target="_blank" rel="noopener">documentation</Link>.
</Paragraph>
</VerticallyCenteredContainer>
);
};
export default NoTopics;

View file

@ -1,5 +1,5 @@
import Container from "@mui/material/Container"; import Container from "@mui/material/Container";
import {ButtonBase, CardActions, CardContent, Fade, Link, Modal, Stack} from "@mui/material"; import {ButtonBase, CardActions, CardContent, CircularProgress, Fade, Link, Modal, Stack} from "@mui/material";
import Card from "@mui/material/Card"; import Card from "@mui/material/Card";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import * as React from "react"; import * as React from "react";
@ -22,28 +22,43 @@ import Button from "@mui/material/Button";
import subscriptionManager from "../app/SubscriptionManager"; import subscriptionManager from "../app/SubscriptionManager";
const Notifications = (props) => { const Notifications = (props) => {
const subscription = props.subscription; if (props.mode === "all") {
if (!subscription) { return (props.subscriptions) ? <AllSubscriptions subscriptions={props.subscriptions}/> : <Loading/>;
return null;
} }
return <NotificationList subscription={subscription}/>; return (props.subscription) ? <SingleSubscription subscription={props.subscription}/> : <Loading/>;
}
const AllSubscriptions = () => {
const notifications = useLiveQuery(() => subscriptionManager.getAllNotifications(), []);
if (notifications === null || notifications === undefined) {
return <Loading/>;
} else if (notifications.length === 0) {
return <NoSubscriptions/>;
}
return <NotificationList notifications={notifications}/>;
}
const SingleSubscription = (props) => {
const subscription = props.subscription;
const notifications = useLiveQuery(() => subscriptionManager.getNotifications(subscription.id), [subscription]);
if (notifications === null || notifications === undefined) {
return <Loading/>;
} else if (notifications.length === 0) {
return <NoNotifications subscription={subscription}/>;
}
return <NotificationList notifications={notifications}/>;
} }
const NotificationList = (props) => { const NotificationList = (props) => {
const subscription = props.subscription; const sortedNotifications = props.notifications;
const notifications = useLiveQuery(() => subscriptionManager.getNotifications(subscription.id), [subscription]); /*const sortedNotifications = Array.from(props.notifications)
if (!notifications || notifications.length === 0) { .sort((a, b) => a.time < b.time ? 1 : -1);*/
return <NothingHereYet subscription={subscription}/>;
}
const sortedNotifications = Array.from(notifications)
.sort((a, b) => a.time < b.time ? 1 : -1);
return ( return (
<Container maxWidth="md" sx={{marginTop: 3, marginBottom: 3}}> <Container maxWidth="md" sx={{marginTop: 3, marginBottom: 3}}>
<Stack spacing={3}> <Stack spacing={3}>
{sortedNotifications.map(notification => {sortedNotifications.map(notification =>
<NotificationItem <NotificationItem
key={notification.id} key={notification.id}
subscriptionId={subscription.id}
notification={notification} notification={notification}
/>)} />)}
</Stack> </Stack>
@ -52,8 +67,8 @@ const NotificationList = (props) => {
} }
const NotificationItem = (props) => { const NotificationItem = (props) => {
const subscriptionId = props.subscriptionId;
const notification = props.notification; const notification = props.notification;
const subscriptionId = notification.subscriptionId;
const attachment = notification.attachment; const attachment = notification.attachment;
const date = formatShortDateTime(notification.time); const date = formatShortDateTime(notification.time);
const otherTags = unmatchedTags(notification.tags); const otherTags = unmatchedTags(notification.tags);
@ -250,7 +265,7 @@ const Icon = (props) => {
); );
} }
const NothingHereYet = (props) => { const NoNotifications = (props) => {
const shortUrl = topicShortUrl(props.subscription.baseUrl, props.subscription.topic); const shortUrl = topicShortUrl(props.subscription.baseUrl, props.subscription.topic);
return ( return (
<VerticallyCenteredContainer maxWidth="xs"> <VerticallyCenteredContainer maxWidth="xs">
@ -275,4 +290,34 @@ const NothingHereYet = (props) => {
); );
}; };
const NoSubscriptions = () => {
return (
<VerticallyCenteredContainer maxWidth="xs">
<Typography variant="h5" align="center" sx={{ paddingBottom: 1 }}>
<img src="/static/img/ntfy-outline.svg" height="64" width="64" alt="No topics"/><br />
It looks like you don't have any subscriptions yet.
</Typography>
<Paragraph>
Click the "Add subscription" link to create or subscribe to a topic. After that, you can send messages
via PUT or POST and you'll receive notifications here.
</Paragraph>
<Paragraph>
For more information, check out the <Link href="https://ntfy.sh" target="_blank" rel="noopener">website</Link> or
{" "}<Link href="https://ntfy.sh/docs" target="_blank" rel="noopener">documentation</Link>.
</Paragraph>
</VerticallyCenteredContainer>
);
};
const Loading = () => {
return (
<VerticallyCenteredContainer>
<Typography variant="h5" color="text.secondary" align="center" sx={{ paddingBottom: 1 }}>
<CircularProgress disableShrink sx={{marginBottom: 1}}/><br />
Loading notifications ...
</Typography>
</VerticallyCenteredContainer>
);
};
export default Notifications; export default Notifications;