Skip to content
This repository has been archived by the owner on Apr 1, 2024. It is now read-only.

19 - Sound notification for new messages #20

Merged
merged 4 commits into from
Nov 24, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"classnames": "^2.3.1",
"cross-env": "^7.0.3",
"framer-motion": "4.1.17",
"howler": "^2.2.4",
"i18next": "^21.2.4",
"i18next-browser-languagedetector": "^6.1.2",
"linkify-react": "^3.0.3",
Expand All @@ -40,6 +41,7 @@
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^10.4.9",
"@testing-library/user-event": "^7.2.1",
"@types/howler": "^2.2.11",
"@types/luxon": "^2.0.8",
"eslint": "8.15.0",
"eslint-config-airbnb": "^18.2.1",
Expand Down
10 changes: 5 additions & 5 deletions src/hooks/useGetActiveChats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@ const useGetActiveChats = (): void => {
const dispatch = useAppDispatch();

useEffect(() => {
const sseInstance = sse('cs-get-all-active-chats');

sseInstance.onMessage((data: Chat[]) => {
const onMessage = (data: Chat[]) => {
if (data !== undefined) {
dispatch(setActiveChats({ customerSupportId, data, checkNewMessages: true }));
}
});
};

const events = sse('cs-get-all-active-chats', onMessage);

return () => {
sseInstance.close();
events.close();
};
}, [customerSupportId, dispatch]);
};
Expand Down
12 changes: 8 additions & 4 deletions src/hooks/useGetNewMessages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,18 @@ const useGetNewMessages = (chatId: string | undefined): void => {

useEffect(() => {
if (!chatId || chatId === '-1' || !isAuthenticated || !selectedActiveChat) return undefined;
const sseInstance = sse(`cs-get-new-messages?chatId=${chatId}&lastRead=${lastReadMessageDate.split('+')[0]}`);

sseInstance.onMessage((data: MessageModel[]) => {
const onMessage = (data: MessageModel[]) => {
dispatch(addNewMessages(data));
});
};

const events = sse(
`cs-get-new-messages?chatId=${chatId}&lastRead=${lastReadMessageDate.split('+')[0]}`,
onMessage
);

return () => {
sseInstance.close();
events.close();
};
}, [isAuthenticated, dispatch, lastReadMessageDate, chatId, selectedActiveChat]);
};
Expand Down
11 changes: 5 additions & 6 deletions src/hooks/useNewMessageNotification.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
import { useEffect } from 'react';
import { useSelector } from 'react-redux';
import useSound from 'use-sound';
import { RootState, useAppDispatch } from '../store';
import { resetNewMessagesAmount } from '../slices/chats.slice';
import dingMp3 from '../static/ding.mp3';
import { useDing } from './useSound';

const useNewMessageNotification = (): void => {
const newMessagesAmount = useSelector((state: RootState) => state.chats.newMessagesAmount);
const [ding] = useSound(dingMp3);
const [ding] = useDing();
const dispatch = useAppDispatch();
const title = 'Bürokratt';

useEffect(() => {
const onVisibilityChange = () => {
document.title = title;
dispatch(resetNewMessagesAmount());
};

document.addEventListener('visibilitychange', onVisibilityChange);
document.addEventListener('visibilitychange', onVisibilityChange, false);

return () => {
document.removeEventListener('visibilitychange', onVisibilityChange);
Expand All @@ -26,8 +25,8 @@ const useNewMessageNotification = (): void => {

useEffect(() => {
if (newMessagesAmount === 0) return;
ding?.play();
document.title = `(${newMessagesAmount}) uus sõnum! - ${title}`;
ding();
}, [newMessagesAmount]);
};

Expand Down
30 changes: 30 additions & 0 deletions src/hooks/useSound.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { useEffect, useState } from 'react';
import { Howl } from 'howler';
import ding from '../static/ding.mp3';

export const useAudio = (audiosrc: string) => {
const [audio, setAudio] = useState<Howl | null>(null);

useEffect(() => {
const howl = new Howl({
src: audiosrc,
onloaderror: (soundId, error) => console.error(soundId, error),
onplayerror: (soundId, error) => {
console.error(soundId, error);
howl.once('unlock', () => howl.play());
},
});

setAudio(howl);

return () => {
howl.unload();
}
}, []);

return [audio] as const;
}

export const useDing = () => {
return useAudio(ding);
}
36 changes: 13 additions & 23 deletions src/services/sse.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,24 @@ import { RuuterResponse } from '../model/ruuter-response.model';

const ruuterUrl = window._env_.RUUTER_API_URL;

interface SseInstance {
onMessage: <T>(handleData: (data: T) => void) => void;
close: () => void;
}

const sse = (url: string): SseInstance => {
const sse = <T>(url: string, onMessage: (data: T) => void) => {
const eventSource = new EventSource(`${ruuterUrl}/sse/${url}`, { withCredentials: true });

const onMessage = <T>(handleData: (data: T) => void) => {
eventSource.onmessage = (event: MessageEvent) => {
const response = JSON.parse(event.data);
eventSource.onmessage = (event: MessageEvent) => {
const response = JSON.parse(event.data);

if (response.statusCodeValue === 200) {
const ruuterResponse = response.body as RuuterResponse;
if (ruuterResponse.data) handleData(Object.values(ruuterResponse.data)[0] as T);
}
};
};

const close = () => {
eventSource.close();
};
if (response.statusCodeValue === 200) {
const ruuterResponse = response.body as RuuterResponse;
if (ruuterResponse?.data)
onMessage(Object.values(ruuterResponse.data)[0] as T);
}
}

eventSource.onerror = () => {
eventSource.close();
};
console.error('SSE error');
}

return { onMessage, close };
};
return eventSource;
}

export default sse;