TitleNotifier.tsx 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. /**
  2. * This component is responsible for updating the title of the page when
  3. * different state changes occur.
  4. * If the stream live state changes, or chat messages come in while the
  5. * page is backgrounded, this component will update the title to reflect it. *
  6. * @component
  7. */
  8. import { FC, useEffect, useState } from 'react';
  9. import { useRecoilValue } from 'recoil';
  10. import Head from 'next/head';
  11. import { serverStatusState, chatMessagesAtom } from '../stores/ClientConfigStore';
  12. export type TitleNotifierProps = {
  13. name: string;
  14. };
  15. export const TitleNotifier: FC<TitleNotifierProps> = ({ name }) => {
  16. const chatMessages = useRecoilValue(chatMessagesAtom);
  17. const serverStatus = useRecoilValue(serverStatusState);
  18. const [backgrounded, setBackgrounded] = useState(false);
  19. const [title, setTitle] = useState(name);
  20. const { online, streamTitle } = serverStatus;
  21. const onBlur = () => {
  22. setBackgrounded(true);
  23. };
  24. const onFocus = () => {
  25. setBackgrounded(false);
  26. setTitle(name);
  27. };
  28. const listenForEvents = () => {
  29. // Listen for events that should update the title
  30. window.addEventListener('blur', onBlur);
  31. window.addEventListener('focus', onFocus);
  32. };
  33. const removeEvents = () => {
  34. window.removeEventListener('blur', onBlur);
  35. window.removeEventListener('focus', onFocus);
  36. };
  37. useEffect(() => {
  38. listenForEvents();
  39. setTitle(name);
  40. return () => {
  41. removeEvents();
  42. };
  43. }, [name]);
  44. useEffect(() => {
  45. if (!backgrounded || !online) {
  46. return;
  47. }
  48. // Only alert on real chat messages from people.
  49. const lastMessage = chatMessages.at(-1);
  50. if (!lastMessage || lastMessage.type !== 'CHAT') {
  51. return;
  52. }
  53. setTitle(`💬 :: ${name}`);
  54. }, [chatMessages, name]);
  55. useEffect(() => {
  56. if (navigator.mediaSession === undefined) {
  57. return;
  58. }
  59. navigator.mediaSession.metadata = new MediaMetadata({
  60. title: streamTitle,
  61. artist: name,
  62. artwork: [{ src: '/logo' }],
  63. });
  64. }, [name, streamTitle]);
  65. useEffect(() => {
  66. if (!backgrounded) {
  67. return;
  68. }
  69. if (online) {
  70. setTitle(` 🟢 :: ${name}`);
  71. } else if (!online) {
  72. setTitle(` 🔴 :: ${name}`);
  73. }
  74. }, [online, name]);
  75. return (
  76. <Head>
  77. <title>{title}</title>
  78. </Head>
  79. );
  80. };