- default
+ Room Ownership
- default
+ The person who created the room is the room owner and has special privileges, like the ability to lock and unlock the room. If the owner leaves the room, the second person to join assumes ownership. If they leave, the third person becomes owner, and so on. The room owner has a star icon next to their username in the participants dropdown.
- default
+ Lock Room
- default
+ If you are the room owner, you can lock and unlock the room by clicking the lock icon in the nav bar. When a room is locked, no other participants will be able to join.
- default
+ Slash Commands
- default
+ The following slash commands are available:
-
@@ -123,7 +139,7 @@ exports[`Settings component should display 1`] = `
- default
+ changes username
-
@@ -131,7 +147,7 @@ exports[`Settings component should display 1`] = `
- default
+ performs an action
-
@@ -139,7 +155,7 @@ exports[`Settings component should display 1`] = `
- default
+ clears your message history
-
@@ -147,7 +163,7 @@ exports[`Settings component should display 1`] = `
- default
+ lists all commands
diff --git a/client/src/components/Settings/index.js b/client/src/components/Settings/index.js
index 50b27c5..e3b2397 100644
--- a/client/src/components/Settings/index.js
+++ b/client/src/components/Settings/index.js
@@ -11,6 +11,10 @@ class Settings extends Component {
this.props.toggleSoundEnabled(!this.props.soundIsEnabled)
}
+ handleNotificationToggle() {
+ this.props.toggleNotificationEnabled(!this.props.notificationIsEnabled)
+ }
+
handleLanguageChange(evt) {
const language = evt.target.value;
Cookie.set('language', language);
@@ -21,7 +25,7 @@ class Settings extends Component {
return (
+
@@ -78,6 +89,8 @@ class Settings extends Component {
Settings.propTypes = {
soundIsEnabled: PropTypes.bool.isRequired,
toggleSoundEnabled: PropTypes.func.isRequired,
+ notificationIsEnabled: PropTypes.bool.isRequired,
+ toggleNotificationEnabled: PropTypes.func.isRequired,
roomId: PropTypes.string.isRequired,
setLanguage: PropTypes.func.isRequired,
translations: PropTypes.object.isRequired,
diff --git a/client/src/i18n/de.json b/client/src/i18n/de.json
index f1cac6c..b4ceaf7 100644
--- a/client/src/i18n/de.json
+++ b/client/src/i18n/de.json
@@ -22,6 +22,8 @@
"slashCommandsHeader": "Slash-Befehle",
"slashCommandsText": "Die folgenden Schrägstrichbefehle sind verfügbar:",
"sound": "Klingen",
+ "newMessageNotification": "New message notification",
+ "desktopNotification": "Desktop Notification",
"typePlaceholder": "Tippen Sie hier",
"unlockedRoom": "{username} hat den Raum freigeschaltet",
"userJoined": "{username} ist beigetreten",
@@ -30,4 +32,4 @@
"welcomeHeader": "Willkommen bei Darkwire v2.0",
"welcomeModalCTA": "OK",
"helpTranslate": "Hilf uns, Darkwire zu übersetzen!"
-}
\ No newline at end of file
+}
diff --git a/client/src/i18n/en.json b/client/src/i18n/en.json
index 4664147..4a8d107 100644
--- a/client/src/i18n/en.json
+++ b/client/src/i18n/en.json
@@ -25,14 +25,11 @@
"lockRoomText": "If you are the room owner, you can lock and unlock the room by clicking the lock icon in the nav bar. When a room is locked, no other participants will be able to join.",
"slashCommandsHeader": "Slash Commands",
"slashCommandsText": "The following slash commands are available:",
- "slashCommandsBullets": [
- "changes username",
- "performs an action",
- "clears your message history",
- "lists all commands"
- ],
+ "slashCommandsBullets": ["changes username", "performs an action", "clears your message history", "lists all commands"],
"sound": "Sound",
+ "newMessageNotification": "New message notification",
+ "desktopNotification": "Desktop Notification",
"welcomeModalCTA": "Ok",
"lockedRoomHeader": "This room is locked",
"helpTranslate": "Help us translate Darkwire!"
-}
\ No newline at end of file
+}
diff --git a/client/src/i18n/fr.json b/client/src/i18n/fr.json
index 33b4e13..c0a56d0 100644
--- a/client/src/i18n/fr.json
+++ b/client/src/i18n/fr.json
@@ -25,13 +25,10 @@
"lockRoomText": "Si vous êtes le propriétaire du salon, vous pouvez le verrouiller et le déverrouiller en cliquant sur l'icône de cadenas située dans la barre de navigation. Quand un salon est verrouillé, aucun autre participant ne peut rejoindre.",
"slashCommandsHeader": "Commandes",
"slashCommandsText": "Les commandes suivantes sont disponibles :",
- "slashCommandsBullets": [
- "changer de pseudo",
- "effectuer une action",
- "effacer votre historique de messages",
- "lister toutes les commandes"
- ],
+ "slashCommandsBullets": ["changer de pseudo", "effectuer une action", "effacer votre historique de messages", "lister toutes les commandes"],
"sound": "Son",
+ "newMessageNotification": "Notification lors d'un nouveau message",
+ "desktopNotification": "Notification Système",
"welcomeModalCTA": "Ok",
"lockedRoomHeader": "Ce salon est verrouillé",
"helpTranslate": "Aidez-nous à traduire Darkwire!"
diff --git a/client/src/i18n/it.json b/client/src/i18n/it.json
index 14d0f02..37a768f 100644
--- a/client/src/i18n/it.json
+++ b/client/src/i18n/it.json
@@ -22,6 +22,8 @@
"slashCommandsHeader": "Comandi",
"slashCommandsText": "Sono disponibili i seguenti comandi:",
"sound": "Suono",
+ "newMessageNotification": "New message notification",
+ "desktopNotification": "Desktop Notification",
"typePlaceholder": "Digitare qui",
"unlockedRoom": "{username} ha aperto la stanza",
"userJoined": "{username} si è unito",
diff --git a/client/src/i18n/nl.json b/client/src/i18n/nl.json
index e363e41..04e7121 100644
--- a/client/src/i18n/nl.json
+++ b/client/src/i18n/nl.json
@@ -22,6 +22,8 @@
"slashCommandsHeader": "Slash-opdrachten",
"slashCommandsText": "De volgende slash-opdrachten zijn beschikbaar:",
"sound": "Geluid",
+ "newMessageNotification": "New message notification",
+ "desktopNotification": "Desktop Notification",
"typePlaceholder": "Typ hier",
"unlockedRoom": "{username} heeft de kamer ontgrendeld",
"userJoined": "{username} is lid geworden",
@@ -30,4 +32,4 @@
"welcomeHeader": "Welkom bij Darkwire v2.0",
"welcomeModalCTA": "OK",
"helpTranslate": "Help ons Darkwire te vertalen!"
-}
\ No newline at end of file
+}
diff --git a/client/src/i18n/oc.json b/client/src/i18n/oc.json
index 98b3833..c78d2f9 100644
--- a/client/src/i18n/oc.json
+++ b/client/src/i18n/oc.json
@@ -25,13 +25,10 @@
"lockRoomText": "Se sètz lo proprietari de la sala, podètz clavar e desclavar en clicar l’icòna del cadenat de la barra de navigacion. Quand una sala es clavada, cap de participant pòt pas la rejónher .",
"slashCommandsHeader": "Comandas",
"slashCommandsText": "Las comandas seguentas son disponiblas :",
- "slashCommandsBullets": [
- "càmbia d’escais-nom",
- "realiza una accion",
- "escafa l’istoric de conversacion",
- "lista totas las comandas"
- ],
+ "slashCommandsBullets": ["càmbia d’escais-nom", "realiza una accion", "escafa l’istoric de conversacion", "lista totas las comandas"],
"sound": "Son",
+ "newMessageNotification": "New message notification",
+ "desktopNotification": "Desktop Notification",
"welcomeModalCTA": "D’acòrdi",
"lockedRoomHeader": "Aquesta sala es clavada",
"helpTranslate": "Ajudatz-nos a traduire Darkwire !"
diff --git a/client/src/i18n/zh-CN.json b/client/src/i18n/zh-CN.json
index 9af9261..e76aa07 100644
--- a/client/src/i18n/zh-CN.json
+++ b/client/src/i18n/zh-CN.json
@@ -22,6 +22,8 @@
"slashCommandsHeader": "斜线命令",
"slashCommandsText": "可以使用以下斜杠命令:",
"sound": "声音",
+ "newMessageNotification": "New message notification",
+ "desktopNotification": "Desktop Notification",
"typePlaceholder": "在此输入",
"unlockedRoom": "{username} 解锁了房间",
"userJoined": "{username} 已加入",
@@ -30,4 +32,4 @@
"welcomeHeader": "欢迎来到Darkwire v2.0",
"welcomeModalCTA": "好",
"helpTranslate": "帮助我们翻译Darkwire"
-}
\ No newline at end of file
+}
diff --git a/client/src/reducers/app.js b/client/src/reducers/app.js
index 557b812..2328dcf 100644
--- a/client/src/reducers/app.js
+++ b/client/src/reducers/app.js
@@ -1,5 +1,5 @@
import Cookie from 'js-cookie';
-import {getTranslations} from 'i18n';
+import { getTranslations } from 'i18n';
const language = Cookie.get('language') || navigator.language || 'en';
@@ -9,6 +9,7 @@ const initialState = {
windowIsFocused: true,
unreadMessageCount: 0,
soundIsEnabled: true,
+ notificationIsEnabled: true,
socketConnected: false,
language,
translations: getTranslations(language)
@@ -47,6 +48,11 @@ const app = (state = initialState, action) => {
...state,
soundIsEnabled: action.payload,
}
+ case 'TOGGLE_NOTIFICATION_ENABLED':
+ return {
+ ...state,
+ notificationIsEnabled: action.payload,
+ }
case 'TOGGLE_SOCKET_CONNECTED':
return {
...state,
diff --git a/client/src/reducers/app.test.js b/client/src/reducers/app.test.js
index 3177f90..b737067 100644
--- a/client/src/reducers/app.test.js
+++ b/client/src/reducers/app.test.js
@@ -14,6 +14,7 @@ describe('App reducer', () => {
modalComponent: null,
scrolledToBottom: true,
socketConnected: false,
+ notificationIsEnabled: true,
soundIsEnabled: true,
translations: { path: 'test' },
unreadMessageCount: 0,
diff --git a/client/src/utils/notifications.js b/client/src/utils/notifications.js
new file mode 100644
index 0000000..220176a
--- /dev/null
+++ b/client/src/utils/notifications.js
@@ -0,0 +1,50 @@
+import beepFile from 'audio/beep.mp3'
+
+
+const showNotification = (title, message, avatarUrl) => {
+ const notifBody = {
+ body: message,
+ tag: 'darkwire',
+ silent: true, // we play our own sounds
+ };
+
+ const notification = new Notification(title, notifBody);
+ const handleVisibilityChange = () => {
+ if (document.visibilityState === 'visible') {
+ // The tab has become visible so clear the now-stale Notification.
+ notification.close();
+ document.removeEventListener('visibilitychange', handleVisibilityChange);
+ }
+ };
+ // Focus window on click
+ notification.onclick = function () {
+ window.focus();
+ notification.close();
+ };
+ document.addEventListener('visibilitychange', handleVisibilityChange);
+};
+
+export const notify = (title, content) => {
+ if (!('Notification' in window)) {
+ alert('This browser does not support desktop notification');
+ }
+ // Let's check whether notification permissions have already been granted
+ else if (Notification.permission === 'granted') {
+ // If it's okay let's create a notification
+ showNotification(title, content);
+ }
+
+ // Otherwise, we need to ask the user for permission
+ else if (Notification.permission !== 'denied') {
+ Notification.requestPermission().then(function (permission) {
+ // If the user accepts, let's create a notification
+ if (permission === 'granted') {
+ showNotification(title, content);
+ }
+ });
+ }
+};
+
+export const beep = (window.Audio && new window.Audio(beepFile)) || { play: () => { }}
+
+export default { notify, beep };