Pull to refresh
35.17
Exolve
Конструктор омниканальных диалогов для бизнеса

Как сделать интерактивную панель для отправки SMS

Level of difficultyMedium
Reading time8 min
Views955

Сегодня разработаем панель, через которую сможем отправлять SMS сразу нескольким адресатам, получать их ответы и видеть статистику по отправленным сообщениям через календарь и график. Будем использовать Next.js, Shadcn для интерфейса и SMS API от МТС Exolve для отправки сообщений.

Архитектура приложения

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

Подготовка окружения

Разрабатывать будем на фулстек-фреймворке Next.js, который поддерживает серверный и клиентский код на React.js. Задача — создать компонент календаря и графика. Для этого мы обратимся к библиотеке Shadcn с готовыми компонентами, которые настроим под свои нужды. Основу слоя стилей Shadcn составляет Tailwind, и рекомендуется использовать его вместе с TypeScript. 

Если вы ещё не работали с TS — не страшно. Это просто язык статического анализа данных, и, разрабатывая на нём, можно всё так же писать на JS.

Переиспользуем код из другой статьи

В предыдущей статье (её полный код лежит на GitHub) мы уже создали часть нужной функциональности: отправку сообщений и запись данных в БД. Обратите внимание: ранее мы писали на JavaScript, а теперь будем на TypeScript. Главное — следите за расширением файлов, в целом ничего не меняется.

Разворачиваем приложение Next.js

Развернуть приложение Next.js можно с помощью документации на сайте https://nextjs.org. Но мы выбрали Shadcn, и эти ребята тесно сотрудничают с Next.js, поэтому предоставили возможность с помощью одной команды развернуть Next.js с Shadcn и настроить всё под себя. Перейдём в официальный источник https://ui.shadcn.com/docs/installation/next и воспользуемся командой, которая за нас всё сделает. Важно: выбирайте опцию с CSS-переменными и поддержкой TypeScript.

Копирование функциональности из прошлой статьи

Заходим в папку components и скачиваем файл SmsForm.js, переименовываем его в SmsForm.tsx, чтобы продолжить работать в TypeScript. Далее в папке api копируем файлы sendSms.js и messages.js и называем их sendSms.ts и messages.ts. Подключение к базе будет таким же, поэтому качаем в корне проекта файл db.js. Обратите внимание на пути подключения и настройте их под себя. После того как мы изменили расширение на ts, в скопированных файлах подсветятся ошибки TypeScript.

Сам TypeScript не вносит новой функциональности, а занимается только проверкой типов данных для лучшей отладки кода. Его можно настроить в конфигурационном файле tsconfig.json: указать, чтобы TS не подсвечивал ошибки или не проверял код. Также не забудьте скачать файл .env и заполнить его данными для подключения к БД, токеном авторизации МТС Exolve и SMS API для отправки сообщений. Если вы всё сделали правильно, то приложение уже может отправлять сообщения.

Компонент Calendar — календарь с сообщениями

Разработаем функциональность для компонента Calendar из Shadcn. Для начала нужно его скачать: находим в библиотеке и следуем инструкции по установке через CLI. Система сама добавит Calendar к нам в проект, а также все входящие в него компоненты Shadcn.

Не удивляйтесь, если в папке components появятся новые компоненты. Уже на этом этапе можно импортировать calendar на страницу и использовать, но мы так делать не будем, чтобы не захламлять код.

Инкапсулируем логику календаря, вынеся его в свой кастомный компонент. Создадим новый компонент в папке components и назовём его CalendarMessage.tsx. Обратите внимание: по соглашению между программистами для удобства желательно называть компоненты React с большой буквы, хоть и Shadcn по умолчанию именует их с маленькой. Это можно отредактировать в конфигурационном файле. Вот документация по его настройке: https://ui.shadcn.com/docs/components-json.

Логика работы календаря

Логика записи исходящих сообщений в БД у нас уже есть в файле api messages.ts. Нам остаётся «постучаться» к этому API, достать оттуда данные о SMS, отфильтровать по дате, выбранной в нашем календаре, и вывести через map все сообщения с помощью условного рендеринга под компонентом calendar. Обратите внимание, что мы преобразовываем дату к строке для сравнения, и не забывайте, что локаль даты может быть разной, как и часовой пояс. Внимательно следите за преобразованием и часовым поясом: эта статья лишь показывает пример реализации.

Содержимое CalendarMessage.tsx

Вставьте следующий код в компонент CalendarMessage.tsx:

import React, { useEffect, useState } from "react";
import { Calendar } from "./calendar";


// Определение интерфейса для объекта сообщения
interface Message {
  received_at: string; // Дата получения сообщения в формате строки
  sender_number: string; // Номер телефона отправителя
  recipient_numbers: string; // Строка с номерами получателей
  text: string; // Текст сообщения
}


const CalendarMessage: React.FC = () => {
  // Состояние для хранения текущей выбранной даты
  const [date, setDate] = useState<Date>(new Date());
  // Состояние для хранения списка сообщений
  const [messages, setMessages] = useState<Message[]>([]);


  // Эта функция для загрузки сообщений из API при монтировании компонента
  useEffect(() => {
    const getMessages = async () => {
      const res = await fetch("/api/messages");
      const data = await res.json();
      setMessages(data); // Сохранение полученных данных в состояние messages
    };
    getMessages();
  }, []);


  // Эта функция обрабатывает выбор даты в календаре
  const handleDateSelect = (newDate: Date | undefined) => {
    if (newDate) {
      setDate(newDate); // Обновление состояния date, если выбрана новая дата
    }
  };


  // Фильтрация сообщений по выбранной дате
  const filteredMessages = messages.filter((message) => {
    const messageDate = new Date(message.received_at).toDateString(); // Преобразование даты сообщения в строку
    return messageDate === date.toDateString(); // Сравнение даты сообщения с выбранной датой
  });


  // Рендер компонента
  return (
    <>
      <div className="w-full flex items-center justify-center">
        <Calendar
          mode="single" // Режим выбора одной даты
          selected={date} // Текущая выбранная дата
          onSelect={handleDateSelect} // Функция, вызываемая при выборе даты
          className="rounded-md border" // Классы стилей для календаря
        />
      </div>
      <div className="max-w-4xl mx-auto mt-10">
        <h2 className="text-lg font-semibold">
          Сообщения за {date.toLocaleDateString()}
        </h2>
        {filteredMessages.length > 0 ? (
          <ul>
            {filteredMessages.map((message, index) => (
              <li key={index} className="mb-2 p-2 border rounded">
                <p>
                  <strong>Номер отправителя:</strong> {message.sender_number}
                </p>
                <p>
                  <strong>Номера получателей:</strong>{" "}
                  {message.recipient_numbers}
                </p>
                <p>
                  <strong>Текст сообщения:</strong> {message.text}
                </p>
                <p>
                  <strong>Получено:</strong>{" "}
                  {new Date(message.received_at).toLocaleString()}
                </p>
              </li>
            ))}
          </ul>
        ) : (
          <p>Нет сообщений за этот день.</p> // Сообщение, если нет сообщений за выбранный день
        )}
      </div>
    </>
  );
};


export default CalendarMessage;

Остаётся импортировать этот компонент на главную страницу index.tsx.

Компонент Chart — график с отправленными SMS

Подобно установке календаря через Shadcn давайте установим компонент графика Chart. Так же вынесем логику графика в отдельный файл. Создадим в папке components компонент ChartMessage.tsx.

Логика работы графика для отображения количества SMS

Для реализации графика будем вновь использовать API messages.ts, чтобы достать данные с сообщениями. Запрограммируем график на отображение сегодняшней даты плюс два дня назад и два дня вперёд (вы можете указать любой диапазон и логику). Дальше мы должны получить данные по API: сравниваем их с датами в счётчике и при совпадении записываем в ячейку определённой даты количество сообщений. Не забывайте про часовой пояс! Рендерим компонент и наслаждаемся результатом.

Содержимое ChartMessage.tsx

Вставьте следующий код в компонент ChartMessage.tsx:

import React, { useState, useEffect } from "react";
import { Bar, BarChart, CartesianGrid, XAxis, Tooltip } from "recharts";
import { ChartContainer } from "@/components/ui/chart";


// Типы для сообщений и данных графика
interface Message {
  id: number;
  received_at: string;
}


interface ChartData {
  time: string; // дата в формате YYYY-MM-DD
  sms: number; // количество сообщений
}


// Конфигурация графика
const chartConfig = {
  sms: {
    label: "sms",
    color: "#2563eb",
  },
};


const ChartMessage: React.FC = () => {
  // Состояние для данных графика
  const [chartData, setChartData] = useState<ChartData[]>([]);


  // Получение данных при монтировании компонента
  useEffect(() => {
    const fetchData = async (): Promise<void> => {
      try {
        const response = await fetch("/api/messages");
        if (!response.ok) {
          throw new Error(`Error fetching messages: ${response.statusText}`);
        }
        const data: Message[] = await response.json();
        updateChartData(data);
      } catch (error) {
        console.error("Error fetching messages:", error);
      }
    };
    fetchData();
  }, []);


  // Функция для обновления данных графика
  const updateChartData = (data: Message[]): void => {
    const today = new Date();
    const counts: Record<string, number> = {};


    // Генерация диапазона дат для графика
    for (let i = -2; i <= 2; i++) {
      const date = new Date(today);
      date.setDate(date.getDate() + i);
      const dateString = date.toISOString().split("T")[0]; // Преобразование даты в строку YYYY-MM-DD
      counts[dateString] = 0; // Инициализация счетчика для каждой даты
    }


    // Подсчет количества сообщений по датам
    data.forEach((msg) => {
      const msgDate = msg.received_at.split("T")[0];
      if (counts.hasOwnProperty(msgDate)) {
        counts[msgDate]++;
      }
    });


    // Создание данных для графика из счетчиков
    const newChartData: ChartData[] = Object.keys(counts).map((key) => ({
      time: key,
      sms: counts[key],
    }));


    setChartData(newChartData);
  };


  // Отрисовка компонента
  return (
    <div className="max-w-4xl mx-auto mt-10">
      <ChartContainer config={chartConfig} className="h-[200px] w-full">
        <BarChart accessibilityLayer data={chartData}>
          <CartesianGrid vertical={false} />
          <XAxis dataKey="time" />
          <Tooltip />
          <Bar dataKey="sms" fill={chartConfig.sms.color} radius={4} />
        </BarChart>
      </ChartContainer>
    </div>
  );
};


export default ChartMessage;

Остаётся импортировать его на главную страницу index.tsx.

Результат

Над дизайном вы при желании поработаете сами, а основные функции мы добавили вместе — можно рассылать SMS и просматривать, что и в каком количестве было отправлено. Мы разместили весь код на GitHub.

Подводные камни компонента Chart

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

Второй подводный камень — часовой пояс. База данных может иметь часовой пояс и преобразовывать даты по-своему. Можно следить за этим и устанавливать везде равные часовые пояса или преобразовывать дату во время выполнения кода. В компоненте календаря удалось вывести дату как строку, но в компоненте графика это оказалось сложнее: пришлось преобразовывать внутри. Как следствие, компонент календаря и компонент графика выводят сообщения в разных часовых поясах. Для продуктивной среды такой вариант не совсем подойдёт, а вот в качестве статьи очень даже.

Заключение

В статье реализована функциональность работы с абонентом через API-платформу МТС Exolve — это надёжный способ интеграции. В сочетании с готовыми компонентами задача становится вполне подъёмной. Тщательно планируйте логику работы приложения, задавайте ему стили и архитектуру, и у вас всё получится. Также не забывайте про правильную настройку и обработку даты. А если вы ещё не знаете TypeScript, то самое время его изучить — язык не сложный, а пользы от него предостаточно.

Tags:
Hubs:
Total votes 9: ↑9 and ↓0+9
Comments0

Articles

Information

Website
exolve.ru
Registered
Founded
Employees
501–1,000 employees