- Node.js (версия 18 или выше)
- npm или yarn
-
Клонируйте репозиторий
git clone <url-репозитория> cd analytics-service
-
Установите зависимости
npm install
-
Запустите проект в режиме разработки
npm run dev
-
Откройте браузер Приложение будет доступно по адресу:
http://localhost:5173
- React - основная библиотека
- TypeScript - типизация
- Vite - сборщик
- react-router-dom - навигация
- Zustand - управление состоянием
- CSS Modules - стилизация
src/
├── api/ # Запросы к API
│ ├── getGeneratedFile.ts # Получение сгенерированного файла
│ └── postFile.ts # Загрузка файла на сервер для получения агрегированных данных
│
├── assets/ # Статические ресурсы (иконки, изображения)
│
├── components/ # Переиспользуемые UI-компоненты
│
├── features/ # Бизнес-логика
│ ├── aggregation/ # Логика, связанная с агрегацией данных
│ │ ├── AggregationSelectors.ts # Селекторы для доступа к данным агрегации из стора
│ │ ├── useAggregatedFields.ts # Хук для получения и обработки агрегированных полей
│ │ └── types.ts # Типы для модуля агрегации
│ ├── fileUploader/ # Логика загрузки и обработки файлов
│ │ ├── aggregateFile.ts # Функция для агрегации данных из файла
│ │ ├── handleClear.ts # Очистка состояния загрузчика
│ │ ├── handleFileChange.ts # Обработка выбора файла
│ └── generateFile/ # Логика для генерации файлов
│ ├── generateFile.ts # Функция для генерации нового файла
│ └── types.ts # Типы для модуля генерации
│
├── functions/ # Вспомогательные функции
│ ├── dayToDate.ts # Конвертация дня в дату
│ └── transformAggregationData.ts # Трансформация данных агрегации
│
├── pages/ # Страницы приложения. Каждая страница — это отдельный модуль, который содержит в себе все необходимые для работы компоненты и утилиты.
│ ├── CsvAnalytic/ # Страница, где происходит анализ CSV
│ ├── CsvGenerator/ # Страница для генерации нового CSV
│ └── History/ # Страница с историей операций
│
├── store/ # Хранилища состояния (Zustand)
│ ├── aggregationStore.ts # Хранит результаты агрегации
│ ├── fileStore.ts # Отвечает за состояние загружаемого файла
│ ├── generateFileStore.ts # Отвечает за состояние генерации файла
│ └── historyStore.ts # Хранит историю операций
│
└── types/ # Глобальные типы TypeScript
- Главная (
/) - анализ CSV файлов - Генератор (
/generator/) - создание CSV файлов - История (
/history/) - история операций
Далее я немного подробнее опишу наиболее значимые, на мой взгляд, файлы проекта, чтобы тебе, проверяющий, было комфортнее ориентироваться в происходящем.
Центральный компонент для загрузки файлов. Он управляет всем процессом: от выбора файла до отправки на сервер и отображения результата.
- Состояния: Использует
fileStore(Zustand) для отслеживания статуса (INITIAL,UPLOADING,ADDED,LOADING,SUCCESS,ERROR). - Drag & Drop: Реализует функциональность перетаскивания файла с помощью утилит из
./utils/DragAndDrop.ts. - Отображение: В зависимости от текущего статуса, рендерит либо кнопку загрузки, либо лоадер, либо компонент
ActionResultButtonс результатом. - Отправка: По клику на кнопку "Отправить" вызывает функцию
aggregateFile, которая инициирует процесс загрузки и обработки файла на бэкенде.
Этот компонент отображает результат действия с файлом (например, успешная загрузка или ошибка) и предоставляет кнопку для отмены или сброса состояния. Он используется как в FileUploader, так и в FileGenerator для унификации UI после завершения операции.
В зависимости от контекста (загрузка или генерация), кнопка сброса либо очищает <input type="file"> через handleClear, либо меняет состояние в generateFileStore.
Это кастомный хук, который собирает воедино все данные, полученные после агрегации. Он подписывается на aggregationStore через хуки-селекторы (useTotalSpend, useBigSpend и т.д.) и форматирует их в виде массива объектов. Каждый объект содержит name (ключ из объекта), title (человекочитаемое название) и value (значение метрики).
Такая структура позволяет легко отрисовывать результаты агрегации в компоненте AggregationResult, не загромождая его логикой получения и форматирования данных.
Ключевая функция, отвечающая за бизнес-логику обработки файла.
- Устанавливает статус
LOADINGвfileStore. - Отправляет файл на бэкенд с помощью
postFile. - Обрабатывает стриминг-ответ:
- Читает ответ сервера по частям (
ReadableStream). - Каждую полученную строку парсит как JSON.
- Каждую распарсенную метрику записывает в
aggregationStoreс помощьюsetResult.
- Читает ответ сервера по частям (
- Проверяет полноту данных: После завершения стрима убеждается, что все необходимые поля были получены от бэкенда. Это не было обязательным условием в домашнем задании, но я реализовала. Благодаря этому, если залить например пустой csv файл, выведется ошибка!
- Устанавливает финальный статус (
SUCCESSилиERROR). - Записывает результат в
historyStore, чтобы операция сохранилась в истории.
Функция для генерации и скачивания нового CSV-файла.
- Устанавливает статус
LOADINGвgenerateFileStore. - Отправляет запрос на бэкенд через
getGeneratedFile. - Обрабатывает ответ: Если ответ успешный, данные преобразуются и файл скачивается.
- Устанавливает финальный статус (
SUCCESSилиERROR).
Для сохранения между сессиями истории операций используется localStorage. Это реализовано с помощью мидлвара persist из библиотеки zustand.
- Автоматическое сохранение: Любое изменение в
historyStore(добавление нового элемента, удаление или полная очистка) автоматически сохраняется вlocalStorageпод ключомaggregationHistory. - Восстановление состояния: При инициализации приложения
historyStoreавтоматически подгружает сохраненные данные изlocalStorage, восстанавливая состояние истории с предыдущей сессии.