diff --git a/web/src/App.js b/web/src/App.js
index d8c1c21..b75e643 100644
--- a/web/src/App.js
+++ b/web/src/App.js
@@ -3,44 +3,56 @@ import Container from '@mui/material/Container';
import Typography from '@mui/material/Typography';
import Box from '@mui/material/Box';
import Link from '@mui/material/Link';
-import {useState} from "react";
+import {useEffect, useState} from "react";
import Subscription from './Subscription';
import WsConnection from './WsConnection';
-function SubscriptionList(props) {
+const SubscriptionList = (props) => {
+ const subscriptions = props.subscriptions;
return (
- {props.subscriptions.map(subscription =>
- )}
+ {Object.keys(subscriptions).map(id =>
+ props.handleSubscriptionClick(id)}
+ />)
+ }
);
}
-function SubscriptionItem(props) {
+const SubscriptionItem = (props) => {
const subscription = props.subscription;
return (
-
-
{subscription.shortUrl()}
-
+ <>
+
+ {subscription.shortUrl()}
+
+ >
);
}
-function NotificationList(props) {
+const NotificationList = (props) => {
return (
- {props.notifications.map(notification =>
)}
-
{props.timestamp}
-
{props.message}
+ {props.notifications.map(notification =>
+
)}
);
}
const NotificationItem = (props) => {
+ const notification = props.notification;
return (
-
-
{props.time}
-
{props.message}
-
+ <>
+ {notification.time}
+ {notification.message}
+ >
);
}
@@ -67,20 +79,23 @@ const SubscriptionAddForm = (props) => {
}
const App = () => {
- const [state, setState] = useState({
- subscriptions: [],
- });
- const notifications = [
- {id: "qGrfmhp3vK", times: 1645193395, message: "Message 1"},
- {id: "m4YYjfxwyT", times: 1645193428, message: "Message 2"}
- ];
- const addSubscription = (newSubscription) => {
- const connection = new WsConnection(newSubscription.wsUrl());
+ const [subscriptions, setSubscriptions] = useState({});
+ const [selectedSubscription, setSelectedSubscription] = useState(null);
+ const [connections, setConnections] = useState({});
+ const subscriptionChanged = (subscription) => {
+ setSubscriptions(prev => ({...prev, [subscription.id]: subscription})); // Fake-replace
+ };
+ const addSubscription = (subscription) => {
+ const connection = new WsConnection(subscription, subscriptionChanged);
+ setSubscriptions(prev => ({...prev, [subscription.id]: subscription}));
+ setConnections(prev => ({...prev, [connection.id]: connection}));
connection.start();
- setState(prevState => ({
- subscriptions: [...prevState.subscriptions, newSubscription],
- }));
- }
+ };
+ const handleSubscriptionClick = (subscriptionId) => {
+ console.log(`handleSubscriptionClick ${subscriptionId}`)
+ setSelectedSubscription(subscriptions[subscriptionId]);
+ };
+ const notifications = (selectedSubscription !== null) ? selectedSubscription.notifications : [];
return (
@@ -88,7 +103,11 @@ const App = () => {
ntfy
-
+
diff --git a/web/src/Subscription.js b/web/src/Subscription.js
index 7b517d4..1222ee2 100644
--- a/web/src/Subscription.js
+++ b/web/src/Subscription.js
@@ -1,15 +1,26 @@
import {topicUrl, shortTopicUrl, topicUrlWs} from './utils';
export default class Subscription {
- url = '';
+ id = '';
baseUrl = '';
topic = '';
notifications = [];
+ lastActive = null;
constructor(baseUrl, topic) {
- this.url = topicUrl(baseUrl, topic);
+ this.id = topicUrl(baseUrl, topic);
this.baseUrl = baseUrl;
this.topic = topic;
}
+ addNotification(notification) {
+ if (notification.time === null) {
+ return;
+ }
+ this.notifications.push(notification);
+ this.lastActive = notification.time;
+ }
+ url() {
+ return this.id;
+ }
wsUrl() {
return topicUrlWs(this.baseUrl, this.topic);
}
diff --git a/web/src/WsConnection.js b/web/src/WsConnection.js
index c9d7eb3..4e9dfaf 100644
--- a/web/src/WsConnection.js
+++ b/web/src/WsConnection.js
@@ -1,28 +1,47 @@
export default class WsConnection {
- constructor(url) {
- this.url = url;
+ id = '';
+ constructor(subscription, onNotification) {
+ this.id = subscription.id;
+ this.subscription = subscription;
+ this.onNotification = onNotification;
this.ws = null;
}
start() {
- const socket = new WebSocket(this.url);
- socket.onopen = function(e) {
- console.log(this.url, "[open] Connection established");
+ const socket = new WebSocket(this.subscription.wsUrl());
+ socket.onopen = (event) => {
+ console.log(this.id, "[open] Connection established");
+ }
+ socket.onmessage = (event) => {
+ console.log(this.id, `[message] Data received from server: ${event.data}`);
+ try {
+ const data = JSON.parse(event.data);
+ const relevantAndValid =
+ data.event === 'message' &&
+ 'id' in data &&
+ 'time' in data &&
+ 'message' in data;
+ if (!relevantAndValid) {
+ return;
+ }
+ console.log('adding')
+ this.subscription.addNotification(data);
+ this.onNotification(this.subscription);
+ } catch (e) {
+ console.log(this.id, `[message] Error handling message: ${e}`);
+ }
};
- socket.onmessage = function(event) {
- console.log(this.url, `[message] Data received from server: ${event.data}`);
- };
- socket.onclose = function(event) {
+ socket.onclose = (event) => {
if (event.wasClean) {
- console.log(this.url, `[close] Connection closed cleanly, code=${event.code} reason=${event.reason}`);
+ console.log(this.id, `[close] Connection closed cleanly, code=${event.code} reason=${event.reason}`);
} else {
- console.log(this.url, `[close] Connection died`);
+ console.log(this.id, `[close] Connection died`);
// e.g. server process killed or network down
// event.code is usually 1006 in this case
}
};
- socket.onerror = function(error) {
- console.log(this.url, `[error] ${error.message}`);
+ socket.onerror = (event) => {
+ console.log(this.id, `[error] ${event.message}`);
};
this.ws = socket;
}