DevGang
Авторизоваться

Как добавить уведомления в реальном времени в ваше приложение

В современном цифровом мире, когда веб-сайты обрабатывают потоки данных в реальном времени, информирование пользователей об обновлениях путем отправки оповещений имеет решающее значение для удобства работы пользователей. Один из способов добиться этого — уведомления в приложении. Уведомления в приложении — это сообщения или оповещения, которые появляются на веб-сайте при доступе к нему в веб-браузере.

Рассмотрим веб-приложение, которое взаимодействует с сервером в ответ на запросы пользователей. Традиционный ответ сервера на запрос клиента обычно включает в себя отображение веб-страницы. Однако это не всегда так. Иногда ответ сервера несет важную информацию — новаторское обновление медицинского исследования медицинского приложения, уведомление о том, что ваш любимый ресторан готовит ваш заказ на еду, предупреждение о плановом обслуживании на веб-сайте вашего банка или даже неожиданное сообщение об ошибке.

В этих случаях уведомления в приложении обеспечивают прямую связь в реальном времени между клиентом и сервером, повышая удобство работы пользователя за счет предоставления своевременной информации и рекомендаций.

В этой статье мы собираемся создать приложение React, которое отправляет пользователям напоминание о перерывах в работе. Пользователи могут указать продолжительность своей работы и перерыва, и когда их рабочий сеанс будет завершен, приложение автоматически отправит уведомление, предлагая действия на запланированное время перерыва.

Мы начнем с настройки базового проекта React в Vite, будем использовать Ably для обеспечения связи в реальном времени между клиентом и сервером, использовать response-toastify для отображения уведомлений в браузере и отправлять системные уведомления с помощью Notifications API.

Следуйте инструкциям в этом посте, где вы найдете пошаговое руководство по созданию этого приложения, а если вы предпочитаете сразу перейти к готовому коду, посетите этот репозиторий Github.  

Начало работы с уведомлениями React в приложении

Предварительные условия

Прежде чем мы начнем, важно убедиться, что у нас установлены Tailwind CSS и Concurrently. Служебные классы CSS Tailwind будут использоваться для стилизации нашего проекта и не повлияют на функциональность. Одновременно позволит нам одновременно запускать наш интерфейс React и серверный файл на наших машинах. На данный момент достаточно знать цель, которой служит Concurrently. Далее в статье мы увидим, как заставить это работать.

Чтобы использовать Ably для отправки и получения уведомлений в реальном времени, нам понадобится учетная запись Ably. Зарегистрируйтесь здесь, создайте проект, следуя инструкциям, и получите ключ API. Вы можете найти свой ключ API на вкладке «API keys» вашего проекта. Если у вас есть какие-либо сомнения, вы можете следовать инструкциям здесь.
Поскольку мы не хотим раскрывать наши ключи API публично, мы также будем использовать dotenv для хранения ключей API в файле «.env».  

Понимание архитектуры приложения

Мы создаем приложение React, которое информирует пользователей с помощью уведомлений в приложении. Приложение имеет форму с двумя полями ввода чисел, позволяющую пользователям указать ожидаемую продолжительность рабочего времени и продолжительность перерыва. После отправки формы сервер выполняет поиск в нашей базе данных «Activity», которую пользователь может практиковать в указанное время перерыва. Эта «Activity» представляет собой предлагаемую здоровую задачу, которую пользователь может выполнить во время перерыва, например «walk» или «stretch». Серверная часть ищет подходящие занятия на основе введенной пользователем продолжительности перерыва. Полученная активность затем отправляется клиенту в режиме реального времени с помощью Ably Rest и отображается в браузере в виде уведомления.

Например, если пользователь вводит 60 минут для продолжительности рабочего времени и 10 минут для перерыва, серверная часть будет искать «Activity», которое можно завершить в течение 10 минут. Если база данных предлагает «walk», бэкенд отправляет эту рекомендацию клиенту в реальном времени с помощью Ably. Уведомление отображается на экране пользователя по истечении времени работы (60 минут).

Другая форма позволяет пользователям вводить свое имя и сообщение, которым они, возможно, захотят поделиться с другими, использующими приложение. Затем сообщение отображается в виде уведомления во всех браузерах клиентов в режиме реального времени с помощью Ably.

Настройка базового проекта React с использованием Vite

Мы используем Vite, рекомендуемый сборщик для приложений React.
Начните с запуска следующей команды в своем терминале, которая создаст шаблон приложения React в каталоге, названном в честь имени проекта, которое вы указали в команде. В рамках этого руководства мы назовем наш проект «ably-react-notifications».

npm create vite@latest ably-react-notifications

Это побудит вас ответить на несколько вопросов, касающихся структуры и варианта. Мы выберем React и JavaScript соответственно.

После создания проекта перейдите в каталог проекта, запустив cd ably-react-notifications и установив зависимости проекта с помощью npm install команды, и, наконец, запустите приложение npm run dev, как предложено Vite, в вашем терминале.  

Настройка одновременного запуска клиента и сервера

После настройки проекта Vite создайте файл server.js в корневом каталоге вашего проекта. Мы добавим серверный код в server.js позже в этой статье. На данный момент нам просто нужен файл server.js, чтобы избежать ошибок при совместном запуске клиента и сервера с использованием пакета «Concurrently».

После создания файла server.js замените сценарий разработки в файле package.json на следующий, чтобы гарантировать одновременную работу App.jsx и server.js.

"dev": "concurrently \"vite\" \"node server.js\"",

На этом этапе структура каталогов вашего проекта должна выглядеть следующим образом.

└── ably-react-notifications/
    ├── public/
    │   └── vite.svg
    ├── src/
    │   ├── assets
    │   ├── App.css
    │   ├── App.jsx
    │   ├── index.css
    │   └── main.jsx
    ├── index.html
    ├── package-lock.json
    ├── package.json
    ├── server.js
    └── vite.config.js

Если вы настроили Tailwind CSS для стилизации, обычно у вас также будут файлы конфигурации Tailwind, такие как tailwind.config.js и postcss.config.js.

Использование Ably для получения уведомлений

Чтобы начать использовать Ably для отправки уведомлений в реальном времени, мы начнем с установки abilly-js, клиентской библиотеки JavaScript для Ably реального времени. Запустите следующую команду в каталоге вашего проекта, чтобы установить его:

npm install ably –-save

После установки пакета нам необходимо аутентифицировать нашего клиента для безопасной связи в реальном времени, используя ключ API нашего проекта. Если вы не знаете, как получить ключ API через панель управления Ably, это руководство содержит всю необходимую информацию.

Настройка конечной точки API токена аутентификации

Ably предоставляет два механизма аутентификации для обеспечения безопасной подписки и публикации сообщений. На стороне сервера рекомендуется использовать базовую аутентификацию. Однако клиентским приложениям рекомендуется интегрировать аутентификацию по токену, чтобы снизить риск раскрытия вашего ключа API Ably.

Мы добавляем аутентификацию по токену в наше приложение с помощью Ably REST SDK. В серверной части мы создаем новый клиент Ably REST с помощью нашего ключа API и добавляем конечную точку /auth со случайным идентификатором клиента, а также возможностями публикации и подписки. Мы передаем их как объект внутри функции createTokenRequest, предоставляемой Ably Rest SDK, которая затем создает новый токен для нашего клиентского запроса.

Мы создаем Express-сервер, поэтому сначала нам нужно будет установить его вместе с другими зависимостями. Запустите следующую команду в окне терминала:

npm install express cors dotenv body-parser
  • Express — это платформа приложений Node.js
  • Cors обеспечивает связь клиент-сервер с разных URL-адресов
  • Dotenv необходим для чтения секретного ключа API из файла .env
  • Body-парсер поможет прочитать тело HTTP-запроса

Мы будем использовать наш ключ API в файле server.js для аутентификации. Чтобы сохранить ключ API в секрете, создайте файл .env в корневом каталоге и сохраните в нем ключ API, как показано ниже:

API_KEY = [YOUR_ABLY_API_KEY]

Доступ ко всему, что хранится внутри файла .env, можно получить с помощью process.env.SECRET_NAME команды. В нашем случае мы получаем доступ к API_KEY следующим образом:  

process.env.API_KEY

Добавьте следующий код в файл server.js, который мы создали в корневом каталоге проекта, чтобы добавить аутентификацию по токену.

const express = require("express");
const bodyParser = require("body-parser");
const fs = require("fs");
const Ably = require("ably");
const cors = require("cors");

const app = express();
require('dotenv').config();
app.use(bodyParser.json());
app.use(cors());

const client = new Ably.Rest(process.env.API_KEY);

app.get("/auth", (req, res) => {
  const tokenParams = {
    clientId: `anonymous-${Math.random().toString(36).substring(7)}`,
    capability: { '*': ['publish', 'subscribe'] } };
    client.auth.createTokenRequest(tokenParams, (err, token) => {
    if (err) {
      res.status(500).json({ error: "Failed to generate token request" });
    } else {
      res.setHeader("Content-Type", "application/json");
      res.send(JSON.stringify(token));
    }
  });
});

app.listen(3001, () => console.log("Server started on port 3001"));

В приведенном выше фрагменте кода мы сначала импортируем установленные зависимости в наш файл. Затем мы создаем клиент, используя Ably REST, предоставляя ему наш ключ API. Наконец, мы создаем конечную точку API /auth, которая генерирует токен.

Поскольку мы запускаем сервер с нашим интерфейсным приложением, мы обязательно столкнемся с ошибкой "ReferenceError: require is not Defined", которая часто встречается при использовании "require" в среде браузера. Чтобы избежать этой ошибки, добавьте "type": "commonjs" в файл package.json.

"type": "commonjs",
"scripts": {
	// Your scripts here
}

Перейдите по адресу http://localhost:3001/auth в своем браузере и убедитесь, что вы видите объект JSON с keyName, client id, timestamp, capability, nonce, и mac. Объект JSON должен выглядеть следующим образом:  

Публикация уведомления с сервера

Мы настроим наш клиент для отправки пользовательских данных на серверную часть, что позволит ему осуществлять поиск в базе данных. Для простоты мы добавим фиктивные данные в файл JSON, который будет служить нашим сервером для этого руководства. Создайте файл activity.json в корневом каталоге проекта со следующими данными:

{
  "activities": [
    {
      "name": "Stretching",
      "duration": 5
    },
    {
      "name": "Meditation",
      "duration": 10
    },
    {
      "name": "Walk",
      "duration": 15
    },
    {
      "name": "Deep Breathing",
      "duration": 7
    },
    {
      "name": "Snack Break",
      "duration": 20
    }
  ]
}

В файле server.js прочитайте и проанализируйте содержимое JSON, а затем, используя новый маршрут сервера, найдите и отправьте совпадающие данные клиенту:

const activitiesData = JSON.parse(fs.readFileSync("activities.json"));

app.post("/sendbreaktime", (req, res) => {
  const { duration } = req.body;

  const matchedActivity = activitiesData.activities.find(
    (activity) => activity.duration === Number(duration),
  );

  if (matchedActivity) {
    const channel = client.channels.get("activities");
    channel.publish("matched activity", matchedActivity);
    res.json({
      success: true,
      activity: matchedActivity,
    });
  } else {
    res.status(400).json({
      success: false,
      message: "No activity found for the specified duration",
    });
  }
});

Функция маршрута использует метод массива «find» для поиска соответствующего действия на основе продолжительности перерыва, предоставленной пользователем. Это совпадающее действие будет рекомендовано пользователю в качестве уведомления.

Условный оператор проверяет, найдено ли подходящее действие. Если совпадение найдено, сервер подписывается на канал, используя экземпляр клиента, созданный в верхней части нашего файла server.js. Впоследствии он публикует уведомление с именем «matched activity», а тело этого уведомления содержит сведения о действии, найденном в файле данных.

Важно отметить, что при подписке на канал вы используете имя канала в хуке useChannel на стороне клиента и функции get на стороне сервера. Однако когда мы публикуем уведомление, мы указываем имя сообщения перед телом сообщения, которое в нашем случае является «matched activity».

На этом этапе структура каталогов вашего проекта должна выглядеть следующим образом.

└── ably-react-notifications/
    ├── public/
    │   └── vite.svg
    ├── src/
    │   ├── assets
    │   ├── App.css
    │   ├── App.jsx
    │   ├── index.css
    │   └── main.jsx
    ├── .env
    ├── activities.json
    ├── index.html
    ├── package-lock.json
    ├── package.json
    ├── server.js
    └── vite.config.js

Настройка провайдера Ably

На стороне клиента компонент соединяет наше приложение с Ably. Мы заворачиваем наш компонент в поставщике Ably, чтобы сделать Ably доступным во всем нашем приложении.

Импортируйте компонент и «Realtime» из Ably для подключения к Ably и настройки клиента для конечной точки API «/auth».

Переменная client настраивает наш интерфейс на конечную точку API «/auth», которая затем передается в качестве клиентской поддержки компоненту AblyProvider.

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import './index.css'
import { Realtime } from 'ably';
import { AblyProvider } from 'ably/react';
 
const client = new Realtime({authUrl: "http://127.0.0.1:3001/auth"})

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <AblyProvider client={client}>
    <App />
    </AblyProvider>
  </React.StrictMode>,
)

Найдите минутку и запустите npm run dev еще раз, чтобы проверить браузер и убедиться в отсутствии ошибок на этом этапе.  

Отображение уведомлений в браузере

Теперь, когда наш сервер настроен, наш следующий шаг — отобразить activities, отправляемые сервером нашим пользователям, в виде уведомлений. Чтобы добиться этого, мы сначала определим JSX для пользовательского интерфейса, а затем используем пользовательские данные для matchedActivity из activities.json. Наконец, мы используем Ably для подписки на выборку сервера matchedActivity из базы данных в реальном времени.

Сбор пользовательских данных в App.jsx и отправка их на server.js.
В нашем приложении нам нужно собирать пользовательские данные о продолжительности работы и перерывов. Мы достигаем этого, заменяя код App.jsx по умолчанию следующим:  

import { useState } from "react";

export const App = () => {
  const [breakTimeDuration, setBreakTimeDuration] = useState(0);
  const [workTimeDuration, setWorkTimeDuration] = useState(0);

  return (
    <div className="max-w-screen-xl mx-auto text-center">
      <h1 className="mt-4 max-w-lg text-3xl font-semibold leading-loose text-gray-900 mx-auto">
        Schedule your work and breaks!
      </h1>
      <div className="w-full px-2 m-auto md:w-2/5">
        <form className="my-10">
          <div className="mb-6">
            <label className="block mb-2 text-sm font-medium text-gray-900">
              Enter work time duration (in minutes):
            </label>
            <input
              className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
              type="number"
              value={workTimeDuration}
              onChange={(e) => setWorkTimeDuration(e.target.value)}
            />
          </div>
          <div className="mb-6">
            <label className="block mb-2 text-sm font-medium text-gray-900">
              Enter break time duration (in minutes):
            </label>
            <input
              className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
              type="number"
              value={breakTimeDuration}
              onChange={(e) => setBreakTimeDuration(e.target.value)}
            />
          </div>


          <button
            className="focus:outline-none text-white bg-purple-700 hover:bg-purple-800 focus:ring-4 focus:ring-purple-300 font-medium rounded-lg text-sm px-5 py-2.5"
            type="submit"
          >
            Set Schedule
          </button>
        </form>      
      </div>
    </div>
  )
}

export default App;

В приведенном выше коде мы используем хук useState для хранения значений workTimeDuration и breakTimeDuration, которые пользователь вводит в поля ввода. В JSX есть <h1> элемент для заголовка и элемент <form> для полей ввода. Мы привязываем наши состояния к соответствующим полям ввода, используя свойство «value». Событие onChange устанавливает состояния, равные тому, что пользователь вводит в поля ввода, чтобы отслеживать это.  

Далее нам нужно отправить пользовательские данные на наш сервер. Мы можем добиться этого, определив функцию handleSubmit и передав ее в качестве обработчика события onSubmit в нашей форме.

Функция handleSubmit отправляет POST-запрос в конечную точку /sendbreaktime с breakTimeDuration в качестве тела запроса. Этот запрос обрабатывается нашим файлом server.js в конечной точке API /sendbreaktime для запуска уведомления. Добавьте следующую функцию handleSubmit в файл App.jsx:

function handleSubmit(e) {
  e.preventDefault();
  fetch("http://127.0.0.1:3001/sendbreaktime", {
    method: "POST",
    headers: {
      "Content-Type": "application/json;charset=utf-8",
    },
    body: JSON.stringify({
      duration: breakTimeDuration,
    }),
  })
  .then((response) => {
    response.json();
  })
  .catch((error) => {
    console.error("Error sending break time data:", error);
  });
}

Теперь мы можем передать это в событие onSubmit формы, просто добавив следующий код в тег открытия формы:

<form className="my-10" onSubmit={handleSubmit}>

После внесения этих изменений обновите приложение. Введите случайное число в поле ввода рабочего времени и введите «10» в поле ввода продолжительности перерыва. Затем отправьте форму. Уведомление вы не увидите, поскольку мы еще не позаботились о его отображении, но и приложение не сломается. Если вы введете значение, которого нет в нашем файле activities.json, вы, скорее всего, столкнетесь с ошибкой «400 — неверный запрос» в вашей консоли, поскольку сервер не сможет найти соответствующее действие.

Использование useChannel для подписки на уведомление в App.jsx

Теперь, когда клиент готов отправлять необходимые данные на сервер, а сервер настроен для отправки соответствующего действия клиенту, нам нужно отобразить его на стороне клиента.

Ably предоставляет хук useChannel, который позволяет вам подписаться на канал и получать от него сообщения в реальном времени. Этот хук принимает имя канала и функцию обратного вызова, которая определяет, как вы хотите обрабатывать сообщения, полученные по этому каналу. Важно отметить, что тот же экземпляр канала, созданный с помощью перехватчика useChannel, также может использоваться для публикации сообщений по каналу.

Этот хук упрощает процесс подписки и взаимодействия с каналами, упрощая реализацию связи в реальном времени и отображение уведомлений в вашем веб-приложении.

Сначала мы импортируем хук useChannel в наш файл App.jsx.

import { useChannel } from "ably/react";

Затем мы создаем новое состояние под названием «activity» для хранения активности, которую мы получаем через Ably REST.

const [activity, setActivity] = useState("");

Наконец, мы используем хук useChannel для подписки на канал “activities“, который будет получать соответствующую активность с сервера. Этот хук позволяет нам установить состояние “activity“ с полученными данными:

const { channel } = useChannel("activities", (matchedActivity) => {
  setActivity(matchedActivity);
});

Наш клиент теперь эффективно прослушивает любые уведомления, отправленные сервером в канале “activities“. Однако, поскольку мы еще не реализовали логику для отображения уведомлений в браузере, мы не сможем их увидеть на данном этапе. Вы можете использовать журналы консоли, чтобы увидеть это в действии.

Добавление функции совместного использования целей в App.jsx

Чтобы реализовать функцию, которая позволяет клиентам делиться своими целями с другими в нашем приложении React, нам нужно добавить новый <form> элемент в наш файл App.jsx. Нам понадобится хук useState для хранения пользовательских данных, как мы это делали в форме продолжительности рабочего времени.

Начните с добавления двух новых состояний с именами «message» и «userName», используя хук «useState»:

const [message, setMessage] = useState("");
const [userName, setUserName] = useState("");

Затем добавьте новую форму в файл App.jsx под формой продолжительности рабочего перерыва.

<form className="my-10">
  <p className="tracking-tighter text-gray-500 md:text-lg mb-2">
    Wanna share your goals with others?
  </p>
  <div className="mb-6">
    <label className="block mb-2 text-sm font-medium text-gray-900">
      Name
    </label>
    <input className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"  type="text" value={userName} onChange={(e) => setUserName(e.target.value)} />
  </div>
  <div className="mb-6">
    <label className="block mb-2 text-sm font-medium text-gray-900">
      Message
    </label>
    <input className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5" type="text" value={message} onChange={(e) => setMessage(e.target.value)} />
  </div>
  <button className="focus:outline-none text-white bg-purple-700 hover:bg-purple-800 focus:ring-4 focus:ring-purple-300 font-medium rounded-lg text-sm px-5 py-2.5" type="submit">
    Submit
  </button>
</form>

Затем мы создаем еще один экземпляр useChannel с именем messagesChannel, чтобы подписаться на сообщение, отправленное клиентом, и сохранить его в состоянии message. Этот экземпляр обеспечит связь между клиентами в реальном времени, подписавшись на канал messages и сохранив его в состоянии message.

Когда пользователь отправляет форму с помощью функции handleMessageSubmit, данные сообщения, включая имя пользователя и сообщение цели, публикуются в messagesChannel.

const { channel: messagesChannel } = useChannel("messages", (message) => {
  setMessage(message)
});

Теперь мы определяем функцию handleMessgeSubmit, которая использует экземпляр messagesChannel перехватчика useChannel для публикации userName и message по каналу messages.

function handleMessageSubmit(e) {
  e.preventDefault();
  messagesChannel.publish("message", {
    name: userName,
    message: message,
  });
  setMessage("");
  setUserName("");
};

Теперь мы можем передать это в событие onSubmit формы, просто добавив следующий код в тег открытия формы:

<form className="my-10" onSubmit={handleMessageSubmit}>

Интерфейс приложения будет выглядеть так, как показано на скриншоте ниже. Стилизация может различаться в зависимости от того, использовали ли вы Tailwind CSS.

Использование react-toastify для реализации компонента уведомлений

На данный момент мы сохранили уведомления, отправленные сервером и клиентом, в соответствующих состояниях. Однако мы пока не отображаем их в виде уведомлений браузеру. Для этого мы можем использовать библиотеку компонентов тостов. В этом уроке мы используем «react-toastify» для отображения уведомлений.

Для начала мы устанавливаем «react-toastify» в наш проект.

npm install react-toastify

Далее импортируем необходимые компоненты и стили для «react-toastify» в App.jsx:

import { ToastContainer, toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";

Не забудьте включить CSS для правильного оформления.

Функция handleActivityNotification использует функцию setTimeout для отображения всплывающего уведомления об успехе после истечения времени работы.

Затем мы используем хук useEffect для запуска функции handleActivityNotification при каждом изменении состояний activity и workTimeDuration. Чтобы импортировать хук useEffect из React, измените код, в котором вы импортируете хук useState в верхней части вашего App.jsx, на следующий:

import { useState, useEffect } from "react";

Toast принимает сообщение, которое мы хотим отобразить как уведомление, и объект для настройки параметров уведомлений. Свойство объекта position указывает позицию в браузере, где мы хотим отображать уведомление, а autoClose указывает период времени, по истечении которого уведомление исчезает.

Чтобы настроить цвет всплывающих сообщений, мы можем использовать всплывающие уведомления, чтобы указать тип уведомления. Мы можем выбирать между успехом, ошибкой, предупреждением и информацией в соответствии с нашими предпочтениями.

function handleActivityNotification() {
  setTimeout(
    () => {
      toast.success(
        `After all the ${workTimeDuration} minutes of hard work, your body deserves a ${activity.data.duration} minutes ${activity.data.name}`,
        {
          position: "top-right",
          autoClose: 3000,
        },
      );
    },
    workTimeDuration * 60 * 1000,
  );
}

useEffect(() => {
  if (activity && workTimeDuration > 0) {
    handleActivityNotification();
  }
}, [activity, workTimeDuration]);

Нам не нужно ждать, чтобы отобразить уведомления клиента, как это было с уведомлениями сервера. Поэтому мы напрямую вызываем функцию toast внутри экземпляра messagesChannel хука useChannel.

<CustomToast /> компонент позволяет нам настраивать всплывающие сообщения, мы использовали его, чтобы выделить userName жирным шрифтом в уведомлении.

Всплывающее сообщение без какого-либо эмиттера отображает уведомление в пользовательском стиле.

const CustomToast = ({ sender, message }) => (
  <div>
    <strong>{sender}:</strong> {message}
  </div>
);

const { channel: messagesChannel} = useChannel("messages", (message) => {
  toast(
    <CustomToast sender={message.data.name} message={message.data.message} />,
    {
      position: "top-right",
      autoClose: 3000,
    },
  );
});

  Наконец, мы добавляем <ToastContainer /> компонент в конец нашего JSX, внутри самого внешнего <div/> тега, чтобы всплывающие сообщения могли отображаться в браузере.  

<ToastContainer />

На этом этапе протестируйте свое приложение, чтобы убедиться, что все работает должным образом. Введите продолжительность рабочего времени и продолжительность перерыва в первой форме. Обязательно введите продолжительность перерыва, указанную в нашем файле activities.json.

После отправки формы по истечении рабочего времени вы должны увидеть уведомление, как показано на снимке экрана, прикрепленном ниже.

Проверьте форму обмена целями, введя имя и сообщение. Вы должны увидеть сообщение в виде уведомления с именем в вашем браузере.

Вы также можете протестировать его в разных браузерах или устройствах, чтобы увидеть, как несколько клиентов могут одновременно использовать одни и те же цели. То, как это будет выглядеть, будет похоже на скриншот ниже.

Использование API уведомлений для запуска уведомлений

API уведомлений — это API браузера, который позволяет веб-приложениям отображать уведомления системного уровня пользователям на их устройствах. Некоторые пользователи не предпочитают, чтобы уведомления отображались на их экранах. Однако наше приложение использует уведомления для обмена информацией между клиентом и сервером.

Чтобы сообщить пользователю, что наше приложение будет отображать уведомления на его экранах, мы будем использовать API уведомлений. API уведомлений может отправлять уведомления, даже если веб-приложение не находится на переднем плане и не используется активно. Однако для этого требуется, чтобы веб-браузер был открыт и приложение было загружено.

Чтобы использовать API уведомлений. начнем с импорта «bellImage» в «App.jsx», который мы будем использовать в качестве значка уведомления. Используемый образ можно найти в репозитории проекта на GitHub здесь. При желании вы можете использовать любое изображение по вашему выбору.

import bellImage from './assets/bell.png';

Затем определите функцию с именем showSystemNotification, которая позволит нам отображать уведомления системного уровня.

function showSystemNotification() {
  if (“Notification” in window) {
    if (Notification.permission === "granted") {
      let notification = new Notification("Need your attention", {
        body: "This site uses notifications for the best user experience. Thank you for understanding",
        icon: bellImage,
      });
    } else if (Notification.permission !== "denied") {
      Notification.requestPermission().then((permission) => {
        if (permission === "granted") {
          let notification = new Notification("Need your attention", {
            body: "This site uses notifications for the best user experience. Thank you for understanding",
            icon: bellImage,
          });
        } else if (permission === "denied") {
          alert("This site uses notifications for the best user experience. Thank you for understanding");
        }
      });
    } else {
      alert("This site uses notifications for the best user experience. Thank you for understanding");
    }
  } else {
    alert("This site uses notifications for the best user experience. Thank you for understanding");
  }
}

Сначала он проверяет, доступен ли объект Notification в окне. Это используется для определения того, поддерживает ли браузер API уведомлений.

Если объект Notification доступен, он проверяет статус разрешения с помощью Notification.permission.

Если разрешение granted, оно создает новое уведомление с использованием нового конструктора уведомлений. Уведомление включает в себя заголовок (“Need your attention”), основной текст (“This site uses notifications for the best user experience. Thank you for understanding”) и значок.

Если разрешение не denied, но и не granted, оно запрашивает разрешение у пользователя с помощью Notification.requestPermission(). Он обрабатывает ответ на разрешение в блоке then. Если разрешение предоставлено, создается уведомление; в случае отказа отображается предупреждение, информирующее пользователя об уведомлениях в нашем приложении.

Если в разрешении denied с самого начала или если браузер не поддерживает API уведомлений, он отображает одно и то же предупреждающее сообщение, объясняющее важность уведомлений для взаимодействия с пользователем.

Наконец, добавьте перехватчик useEffect для запуска функции showSystemNotification при монтировании компонента. Это означает, что логика уведомлений запустится сразу после загрузки компонента.

useEffect(() => showSystemNotification(), []);

Перезапустите приложение и проверьте, отображает ли оно уведомление в правом нижнем углу экрана или предупреждающее сообщение в зависимости от разрешения вашего браузера на уведомления.

Использование API уведомлений для отображения уведомлений Ably

Всплывающие уведомления можно увидеть только тогда, когда наше приложение активно в браузере. Однако мы хотим, чтобы наши пользователи оставались в курсе, даже если они свернули наше приложение или переключились на другую вкладку во время работы. API уведомлений отображает уведомления, даже если приложение свернуто, поскольку оно отправляет уведомления в операционную систему, которая отображает их на экране пользователя.

Для этого в нашей функции handleActivityNotification мы добавляем условный оператор, проверяющий, предоставлены ли разрешения на уведомления. Если разрешение предоставлено, наше приложение отправляет пользователю активность в виде системного уведомления. В случаях, когда разрешение не было предоставлено, мы возвращаемся к использованию «react-toastify» для отображения уведомления в нашем приложении.

function handleActivityNotification() {
  setTimeout(
    () => {
      if(“Notification” in window && Notification.permission === "granted") {
        let notification = new Notification(`${activity.data.name}`, {
          body: `After all the ${workTimeDuration} minutes of hardwork, your body deserves a ${activity.data.duration} minutes ${activity.data.name}`,
          icon: bellImage
        })
      } else {
        toast.success(
          `After all the ${workTimeDuration} minutes of hardwork, your body deserves a ${activity.data.duration} minutes ${activity.data.name}`,
          {
            position: "top-right",
            autoClose: 3000,
          },
        );
      }
    },
    workTimeDuration * 60 * 1000,
  );
}

Заключение

В этом руководстве рассмотрен процесс реализации уведомлений внутри приложения в React. Мы рассмотрели все аспекты этой реализации: от настройки поставщика Ably и аутентификации до отображения уведомлений в реальном времени в нашем приложении с помощью react-toastify.

Кроме того, мы изучили, как API уведомлений можно использовать для отправки уведомлений на уровне системы нашим пользователям. Мы также продемонстрировали его интеграцию в наше приложение, сделав его более информативным и интересным, а также интегрировали его в наше приложение.

Источник:

#JavaScript #React
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

В этом месте могла бы быть ваша реклама

Разместить рекламу