Notifications
One-on-One Chat
Add a red dot in src/components/contact.jsx:
@@ -4,6 +4,7 @@ import "./Contact.css";
const Contact = (props) => {
return (
<div className="contact" onClick={props.onClick}>
+ {props.notify && <div className="notify-dot"></div>}
<div className="name truncate">{props.username}</div>
<div className="last-message truncate">
{props.message || "[no messages]"}
Add red dot's styles in src/components/Contact.css:
@@ -5,6 +5,7 @@
border-bottom: solid 1px var(--theme-color);
text-align: left;
cursor: pointer;
+ position: relative;
}
.name {
@@ -28,3 +29,13 @@
overflow: hidden;
text-overflow: ellipsis;
}
+
+.notify-dot {
+ position: absolute;
+ top: 8px;
+ right: 8px;
+ width: 8px;
+ height: 8px;
+ background-color: orangered;
+ border-radius: 50%;
+}
Add a new state contactNotifications
to remember the contacts that need red dots.
Changes in src/App.js:
@@ -31,6 +31,7 @@ function App() {
const [groups, setGroups] = useState([]);
const [contactMessages, setContactMessages] = useState({});
const [groupMessages, setGroupMessages] = useState({});
+ const [contactNotifications, setContactNotifications] = useState({});
const [pickedContact, setPickedContact] = useState(null);
const [typedContent, setTypedContent] = useState("");
const resultEndRef = useRef(null);
@@ -53,6 +54,9 @@ function App() {
const newMessages = [...oldMessages, entry];
return { ...cm, [from]: newMessages };
});
+ setContactNotifications((cn) => {
+ return { ...cn, [from]: true };
+ });
});
socket.on("create-group", (data) => {
const { name, id } = data;
@@ -145,6 +149,11 @@ function App() {
}
return "";
};
+ const readMessage = (id) => {
+ setContactNotifications((cn) => {
+ return { ...cn, [id]: false };
+ });
+ };
return (
<>
<div className="app">
@@ -197,8 +206,16 @@ function App() {
key={e.sid}
username={e.emoji + " " + e.name}
message={lastMessage(contactMessages[e.sid])}
+ notify={
+ e.sid !== pickedContact?.sid &&
+ contactNotifications[e.sid]
+ }
onClick={() => {
setPickedContact(e);
+ if (pickedContact) {
+ readMessage(pickedContact.sid);
+ }
+ readMessage(e.sid);
}}
/>
))}
Group Chat
Add a red dot in src/components/group.jsx:
@@ -4,6 +4,7 @@ import "./Contact.css";
const Group = (props) => {
return (
<div className="contact" onClick={props.onClick}>
+ {props.notify && <div className="notify-dot"></div>}
<div className="name truncate">{props.name}</div>
<div className="last-message truncate">
{props.message || "[no messages]"}
- Add a new state
groupNotifications
to remember the groups that need red dots. - Add red dots for tabs:
Chat
andGroups
. When you're in one tab, the other tab would show a red dot if it gets any new message.
Changes in src/App.js:
@@ -32,6 +32,7 @@ function App() {
const [contactMessages, setContactMessages] = useState({});
const [groupMessages, setGroupMessages] = useState({});
const [contactNotifications, setContactNotifications] = useState({});
+ const [groupNotifications, setGroupNotifications] = useState({});
const [pickedContact, setPickedContact] = useState(null);
const [typedContent, setTypedContent] = useState("");
const resultEndRef = useRef(null);
@@ -73,6 +74,9 @@ function App() {
const newMessages = [...oldMessages, entry];
return { ...gm, [roomId]: newMessages };
});
+ setGroupNotifications((gn) => {
+ return { ...gn, [roomId]: true };
+ });
});
socket.emit("user-join", user);
setConn(socket);
@@ -150,9 +154,24 @@ function App() {
return "";
};
const readMessage = (id) => {
- setContactNotifications((cn) => {
- return { ...cn, [id]: false };
- });
+ if (isGroupChatting) {
+ setGroupNotifications((gn) => {
+ return { ...gn, [id]: false };
+ });
+ } else {
+ setContactNotifications((cn) => {
+ return { ...cn, [id]: false };
+ });
+ }
+ };
+ const shouldNotify = () => {
+ if (isGroupChatting) {
+ // Notify for Chat Tab
+ return Object.values(contactNotifications).some((e) => e === true);
+ } else {
+ // Notify for Groups Tab
+ return Object.values(groupNotifications).some((e) => e === true);
+ }
};
return (
<>
@@ -174,6 +193,9 @@ function App() {
setPickedContact(null);
}}
>
+ {isGroupChatting && shouldNotify() && (
+ <span className="notify-dot"></span>
+ )}
Chat
</span>
<span
@@ -185,6 +207,9 @@ function App() {
setPickedContact(null);
}}
>
+ {!isGroupChatting && shouldNotify() && (
+ <span className="notify-dot"></span>
+ )}
Groups
</span>
</div>
@@ -196,8 +221,15 @@ function App() {
key={e.id}
name={e.name}
message={lastMessage(groupMessages[e.id])}
+ notify={
+ e.id !== pickedContact?.id && groupNotifications[e.id]
+ }
onClick={() => {
setPickedContact(e);
+ if (pickedContact) {
+ readMessage(pickedContact.id);
+ }
+ readMessage(e.id);
}}
/>
))
Tune styles in src/App.css:
@@ -28,6 +28,12 @@ body {
background-color: var(--secondary-color);
padding: 5px 12px;
cursor: pointer;
+ position: relative;
+
+ .notify-dot {
+ top: 4px;
+ right: 4px;
+ }
}
.left-seg {
Avoid red dots for the current conversation
Changes in src/app.js:
@@ -92,6 +92,20 @@ function App() {
resultEndRef.current?.scrollIntoView({ behavior: "smooth" });
}, [contactMessages, groupMessages, pickedContact]);
+ useEffect(() => {
+ // Avoid red dots for the current conversation
+ if (!pickedContact) return;
+ if (isGroupChatting) {
+ setGroupNotifications((gn) => {
+ return { ...gn, [pickedContact.id]: false };
+ });
+ } else {
+ setContactNotifications((cn) => {
+ return { ...cn, [pickedContact.sid]: false };
+ });
+ }
+ }, [contactMessages, groupMessages, pickedContact, isGroupChatting]);
+
const login = (emoji, name) => {
setUser({ emoji, name });
setLogged(true);
@@ -226,9 +240,6 @@ function App() {
}
onClick={() => {
setPickedContact(e);
- if (pickedContact) {
- readMessage(pickedContact.id);
- }
readMessage(e.id);
}}
/>
@@ -244,9 +255,6 @@ function App() {
}
onClick={() => {
setPickedContact(e);
- if (pickedContact) {
- readMessage(pickedContact.sid);
- }
readMessage(e.sid);
}}
/>
We use useEffect
to watch changes in contactMessages
and groupMessages
, then turn off the red dots accordingly.