Please use this identifier to cite or link to this item:
https://er.chdtu.edu.ua/handle/ChSTU/9889Full metadata record
| DC Field | Value | Language |
|---|---|---|
| dc.contributor.advisor | Прокопенко , Валентин Андрійович | - |
| dc.contributor.author | Воропай, Ярослав Євгенійович | - |
| dc.date.accessioned | 2026-07-27T11:47:23Z | - |
| dc.date.available | 2026-07-27T11:47:23Z | - |
| dc.date.issued | 2026-06-10 | - |
| dc.identifier.uri | https://er.chdtu.edu.ua/handle/ChSTU/9889 | - |
| dc.description.abstract | Кваліфікаційна робота присвячена розробці вебдодатку для обліку й аналізу особистих фінансів на базі React та Firebase. Актуальність теми зумовлена потребою у зручних цифрових інструментах контролю бюджету із синхронізацією даних у реальному часі. Метою роботи є проєктування та реалізація адаптивного вебзастосунку з інтуїтивним інтерфейсом, автоматичним оновленням курсів валют та візуалізацією статистики. Об’єктом роботи є технології розробки вебдодатків для фінансового аналізу. Предметом - застосування React та Firebase для реалізації фінансового вебпорталу. Практична значущість полягає у створенні готового застосунку з автентифікацією, фільтрацією витрат/доходів та інтерактивними діаграмами. У першому розділі розглянуто предметну область управління особистими фінансами та проаналізовано існуючі цифрові рішення. У другому розділі обґрунтовано вибір засобів розробки, зокрема React, Firebase та зовнішніх API. У третьому розділі описано практичну реалізацію вебдодатку: автентифікацію користувача, збереження даних у Firestore, фільтрацію фінансових записів, візуалізацію доходів і витрат та перевірку основних функцій системи. | uk_UA |
| dc.language.iso | uk | uk_UA |
| dc.subject | особисті фінанси | uk_UA |
| dc.subject | фінансовий аналіз | uk_UA |
| dc.subject | вебдодаток | uk_UA |
| dc.subject | React | uk_UA |
| dc.subject | Firebase | uk_UA |
| dc.subject | API Монобанк | uk_UA |
| dc.title | Web-додаток для відстежування та аналізу особистих фінансів | uk_UA |
| dc.type | Bachelor Thesis | uk_UA |
| Appears in Collections: | 126 Інформаційні системи та технології (Web-технології, web-дизайн) | |
Files in This Item:
| File | Description | Size | Format | |
|---|---|---|---|---|
| РЕП_БАК_Воропай _WEB-2211.pdf Restricted Access | 3.53 MB | Adobe PDF | View/Open Request a copy |
Items in DSpace are protected by copyright, with all rights reserved, unless otherwise indicated.
Extracted text
МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ
ЧЕРКАСЬКИЙ ДЕРЖАВНИЙ ТЕХНОЛОГІЧНИЙ УНІВЕРСИТЕТ
ФАКУЛЬТЕТ ІНФОРМАЦІЙНИХ ТЕХНОЛОГІЙ І СИСТЕМ
КАФЕДРА ІНФОРМАЦІЙНИХ ТЕХНОЛОГІЙ ПРОЕКТУВАННЯ
ПОЯСНЮВАЛЬНА ЗАПИСКА
до кваліфікаційної роботи бакалавра
на тему: «Web-додаток для відстежування та аналізу особистих фінансів»
Виконав (-ла): здобувач (-ка) першого
(бакалаврського) рівня вищої освіти
4 курсу, групи Web-2211
Спеціальності 126 Інформаційні системи та
технології
ОП «Web-технології, Web-дизайн»
Воропай Ярослав Євгенійович
Керівник: Phd (доктор філософії)
Прокопенко Валентин Андрійович
Рецензент: Директор ТОВ «Андерсенлаб» Алесін О.В.
Черкаси – 2026 року
Черкаський державний технологічний університет
Факультет ФІТІС
Кафедра Інформаційних технологій проєктування
Спеціальність 126 Інформаційні системи та технології
Освітня програма Web-технології Web-дизайн
ЗАТВЕРДЖУЮ:
Зав. Кафедрою _________ Прокопенко Т.О.
«___» _______________ 2026р.
ЗАВДАННЯ
НА КВАЛІФІКАЦІЙНУ РОБОТУ БАКАЛАВРА
Воропаю Ярославу Євгенійовичу
(прізвище, ім'я, по батькові)
1. Тема роботи Web-додаток для відстежування та аналізу особостих фінансів
керівник проєкту (роботи) Прокопенко.В.А.,асистент кафедри і.т.п
(прізвище, ім'я, по батькові, науковий ступінь, вчене звання)
затверджені наказом Черкаського державного технологічного університету від
«26» лютого 2026 року №60\04.
2. Строк подання здобувачем роботи 01.06.2026
3. Вихідні дані до роботи
Публікації, навчальні посібники та офіційна документація з розробки вебдодатків, управління особистими фінансами,
використання React, Firebase, Cloud Firestore, Firebase Authentication, JavaScript, HTML, CSS, API Монобанку та засобів
візуалізації даних.
4. Зміст розрахунково-пояснювальної записки (перелік питань, що їх належить розробити)
Вступ; 1. Аналіз предметної області та сучасних рішень; 2. Реалізація веб-розробки;; Висновки; Список використаних
джерел.
5. Перелік графічного матеріалу (з точним зазначенням обов'язкових креслень)
1) Порівняльна характеристика аналогів програм для реалізації роботи
6. Консультанти розділів роботи
Розділ Консультант Підпис, дата Підпис, дата
Завдання видав Завдання прийняв
7. Дата видачі завдання 15.02.2026
Керівник ____________________
(підпис)
Завдання прийняв до виконання ____________________
(підпис)
Календарний план
№ Назва етапів Строк виконання
з/п кваліфікаційної роботи етапів роботи Примітка
1 Підготовча стадія
1.1 Постановка задачі 15.02.2026 виконано
1.2 Підготовка завдання 20.02.2026 виконано
1.3 Погодження завдання 25.02.2026 виконано
1.4 Затвердження завдання 05.03.2026 виконано
2 Основна стадія
2.1 Підбір матеріалів 10.03.2026 виконано
2.2 Аналіз шляхів рішення
поставленої задачі 26.03.2026 виконано
2.3 Розрахунок основних
параметрів роботи 15.04.2026 виконано
2.4 Вибір кінцевого варіанту
проєктного рішення 28.04.2026 виконано
2.5 Оформлення первісної
редакції роботи 08.05.2026 виконано
3 Заключна стадія
Узгодження прийнятих
3.1 проєктних рішень 15.05.2026 виконано
з керівником
Оформлення
3.2 пояснювальної записки
роботи 18.05.2026 виконано
в кінцевій редакції
3.3 Затвердження роботи 01.06.2026
3.4 Рецензування роботи 03.06.2026
3.5 Захист роботи 10.06.2026
Студент дипломник _______________________ Воропай.Я.Є.
(підпис) (прізвище та ініціали)
Керівник роботи _______________________ Прокопенко.В.А
(підпис) (прізвище та ініціали)
АНОТАЦІЯ
Структура та обсяг роботи. Пояснювальна записка складається з 3 розділів,
викладена на 48 сторінках, містить 8 рисунків, 6 таблиць, 28 джерел.
Кваліфікаційна робота присвячена розробці вебдодатку для обліку й аналізу
особистих фінансів на базі React та Firebase. Актуальність теми зумовлена
потребою у зручних цифрових інструментах контролю бюджету із синхронізацією
даних у реальному часі.
Метою роботи є проєктування та реалізація адаптивного вебзастосунку з
інтуїтивним інтерфейсом, автоматичним оновленням курсів валют та візуалізацією
статистики.
Об’єктом роботи є технології розробки вебдодатків для фінансового аналізу.
Предметом - застосування React та Firebase для реалізації фінансового вебпорталу.
Практична значущість полягає у створенні готового застосунку з автентифікацією,
фільтрацією витрат/доходів та інтерактивними діаграмами.
У першому розділі розглянуто предметну область управління особистими
фінансами та проаналізовано існуючі цифрові рішення. У другому розділі
обґрунтовано вибір засобів розробки, зокрема React, Firebase та зовнішніх API. У
третьому розділі описано практичну реалізацію вебдодатку: автентифікацію
користувача, збереження даних у Firestore, фільтрацію фінансових записів,
візуалізацію доходів і витрат та перевірку основних функцій системи.
Ключові слова: особисті фінанси, вебдодаток, React, Firebase, API Монобанк,
фінансовий аналіз.
ABSTRACT
Structure and scope of the work. The explanatory note consists of 3 sections, is
presented on 48 pages, and contains 8 figures, 6 tables, and 28 references.
The qualification work is devoted to the development of a web application for
accounting and analyzing personal finances based on React and Firebase. The relevance
of the topic is determined by the need for convenient digital tools for budget control with
real-time data synchronization.
The purpose of the work is to design and implement an adaptive web application
with an intuitive interface, automatic updating of exchange rates, and visualization of
statistics.
The object of the work is the technologies for developing web applications for
financial analysis. The subject is the use of React and Firebase for the implementation of
a financial web portal. The practical significance lies in the creation of a ready-to-use
application with authentication, filtering of expenses/income, and interactive charts.
The first section considers the subject area of personal finance management and
analyzes existing digital solutions. The second section substantiates the choice of
development tools and describes the use of React, Firebase, and external APIs. The third
section presents the practical implementation of the web application, including user
authentication, data storage in Firestore, filtering of financial records, visualization of
income and expenses, and testing of the main functions.
Keywords: personal finance, web application, React, Firebase, Monobank API, financial
analysis.
ЗМІСТ
ВСТУП 4
РОЗДІЛ 1.АНАЛІЗ ПРЕДМЕТНОЇ ОБЛАСТІ УПРАВЛІННЯ ОСОБИСТИМИ ФІНАНСАМИ 6
1.1 Особисті фінанси як об’єкт автоматизації 6
1.2 Методи відстеження доходів і витрат 7
1.3 Аналіз існуючих рішень для управління особистими фінансами 9
1.4 Порівняльна характеристика аналогів 11
1.5 Постановка задачі 13
1.6 Висновки до розділу 1 14
РОЗДІЛ 2.ОБҐРУНТУВАННЯ ЗАСОБІВ РОЗРОБКИ ВЕБДОДАТКУ ДЛЯ ВІДСТЕЖЕННЯ
ОСОБИСТИХ ФІНАНСІВ 15
2.1 Загальні вимоги до програмної реалізації 15
2.2 Використання HTML, CSS та JavaScript 15
2.3 Обґрунтування вибору React 16
2.4 Використання Firebase для збереження даних та автентифікації 18
2.5 Використання API для отримання валютних курсів 19
2.6 Вимоги до безпеки та конфіденційності 20
2.7 Висновки до розділу 2 21
РОЗДІЛ 3.ПРОГРАМНА РЕАЛІЗАЦІЯ ТА ТЕСТУВАННЯ ВЕБДОДАТКУ 22
3.1 Вибір засобів реалізації вебдодатку 22
3.2 Структура проєкту 24
3.3 Реалізація автентифікації користувача 25
3.4 Реалізація роботи з Firebase та Firestore 29
3.5 Реалізація отримання валютних курсів 31
3.6 Реалізація вибору періоду та фільтрації даних 32
3.7 Реалізація основної логіки додатку 37
3.8 Реалізація графічного інтерфейсу користувача 42
3.9 Тестування вебдодатку 45
3.10 Порівняння розробленого вебдодатку з аналогами 48
3.11 Висновки до розділу 3 50
ВИСНОВКИ 51
СПИСОК ВИКОРИСТАНИХ ДЖЕРЕЛ 53
ВСТУП
У сучасних умовах управління особистими фінансами набуває дедалі
більшого значення. Зростання кількості щоденних витрат, поширення безготівкових
платежів, використання банківських карток, електронних сервісів та
онлайн-розрахунків призводять до того, що людині стає складніше контролювати
власний бюджет без спеціальних цифрових інструментів. Навіть за наявності
стабільного доходу відсутність системного обліку витрат може спричиняти
нераціональне використання коштів, труднощі з плануванням майбутніх покупок і
недостатній рівень заощаджень.
Одним із практичних способів вирішення цієї проблеми є використання
вебдодатків для обліку доходів і витрат. На відміну від паперових записів або
звичайних електронних таблиць, вебзастосунок дає змогу працювати з фінансовими
даними швидше, зручніше та наочніше. Користувач може вносити інформацію про
доходи й витрати, переглядати баланс, аналізувати структуру фінансових операцій
за категоріями, обирати потрібний період і отримувати візуальне подання даних у
вигляді діаграм. Такий підхід не лише спрощує облік, а й допомагає краще
оцінювати власну фінансову поведінку.
Актуальність теми кваліфікаційної роботи зумовлена потребою у створенні
доступного та зрозумілого вебдодатку, який дозволяє користувачеві вести облік
особистих фінансів без складних налаштувань і спеціальних знань. Існуючі сервіси
для управління фінансами мають достатньо широкий функціонал, однак частина з
них орієнтована переважно на іноземний ринок, має платні обмеження або є
надмірно складною для користувача, якому потрібен простий інструмент
щоденного фінансового контролю. Тому розробка власного вебдодатку для
відстеження та аналізу особистих фінансів є доцільною і практично значущою
задачею.[21; 27]
Метою кваліфікаційної роботи є проєктування та розробка вебдодатку для
відстеження й аналізу особистих фінансів із використанням сучасних
3
вебтехнологій, зокрема React та Firebase, що забезпечує можливість авторизації
користувача, збереження фінансових записів, перегляду доходів і витрат, фільтрації
даних за періодами та візуалізації фінансової інформації.
Для досягнення поставленої мети було поставлено такі завдання:
1. Проаналізувати предметну область управління особистими фінансами та
визначити основні потреби користувачів у процесі обліку доходів і витрат.
2. Розглянути існуючі цифрові рішення для контролю особистих фінансів,
визначити їх переваги, недоліки та функціональні особливості.
3. Обґрунтувати вибір технологій для реалізації вебдодатку, зокрема JavaScript,
React, Firebase, HTML, CSS та API для отримання валютних курсів.
4. Сформувати функціональні та нефункціональні вимоги до вебдодатку для
відстеження та аналізу особистих фінансів.
5. Спроєктувати структуру вебдодатку, визначити основні компоненти, логіку
взаємодії між ними та спосіб збереження даних користувача.
6. Реалізувати вебдодаток із можливістю автентифікації користувача, додавання
доходів і витрат, видалення записів, перегляду балансу, фільтрації за датами
та побудови діаграм.
7. Перевірити працездатність розробленого вебдодатку та оцінити
відповідність реалізованих функцій поставленим вимогам.
Об’єктом дослідження є процес розробки вебдодатків для обліку та аналізу
особистих фінансів.
Предметом дослідження є методи та засоби реалізації вебдодатку для відстеження
доходів, витрат і фінансового балансу користувача з використанням React та
Firebase.
4
РОЗДІЛ 1.АНАЛІЗ ПРЕДМЕТНОЇ ОБЛАСТІ УПРАВЛІННЯ ОСОБИСТИМИ
ФІНАНСАМИ
1.1 Особисті фінанси як об’єкт автоматизації
Управління особистими фінансами є важливою частиною повсякденного життя
людини. Воно охоплює облік доходів, контроль витрат, формування заощаджень,
планування майбутніх покупок, а також аналіз того, наскільки раціонально
використовуються наявні кошти. На практиці значна частина людей не веде
системного фінансового обліку, через що витрати часто оцінюються приблизно, а
реальна структура бюджету залишається незрозумілою.
Особисті фінанси можна розглядати як сукупність грошових надходжень і
витрат окремої людини або домогосподарства. До основних джерел доходів
належать заробітна плата, соціальні виплати, стипендії, пенсії, кошти від додаткової
зайнятості, фрілансу, оренди майна або інвестицій. Витрати, у свою чергу, можуть
бути обов’язковими та необов’язковими. До обов’язкових належать витрати на
житло, харчування, комунальні послуги, транспорт, зв’язок, навчання або
лікування. Необов’язкові витрати пов’язані з дозвіллям, подорожами, розвагами,
покупками, які не є першочерговими.
Окреме місце в системі особистих фінансів займають заощадження. Вони
дають змогу створити фінансовий резерв на випадок непередбачених обставин, а
також планувати більші витрати без залучення кредитних коштів. Якщо людина не
бачить повної картини своїх доходів і витрат, їй складніше оцінити, скільки коштів
можна відкладати щомісяця та які категорії витрат потребують перегляду.
Саме тому особисті фінанси доцільно розглядати як об’єкт автоматизації.
Автоматизований облік дозволяє не лише зберігати записи про доходи й витрати, а
й швидко отримувати узагальнену інформацію: загальний дохід, суму витрат,
залишок коштів, структуру витрат за категоріями та динаміку фінансових операцій
за певний період. Для користувача це важливо, оскільки фінансова інформація стає
5
не набором окремих записів, а зрозумілою картиною власного бюджету.
1.2 Методи відстеження доходів і витрат
Існує кілька поширених способів ведення особистого фінансового обліку.
Найпростішим є ручне записування доходів і витрат у зошиті або блокноті. Такий
спосіб не потребує технічних засобів і може бути зрозумілим будь-якому
користувачеві. Водночас він має очевидні недоліки: записи важко групувати,
підрахунки потрібно виконувати вручну, а аналіз за місяць або рік займає багато
часу. Крім того, під час ручного ведення обліку легко припуститися помилки або
втратити частину інформації.
Таблиця 1.1 - Порівняння методів використання
Метод Зручність Рівень Наочність Основні Основні
відстеженн використа автоматиза аналізу переваги недоліки
я ння ції
Ручне Низька Низький Низька Простота, Трудомістк
ведення не потребує ість,
записів спеціальни висока
х програм ймовірніст
ь помилок,
складність
аналізу
Електронні Середня Середній Середня Гнучкість, Потребує
таблиці можливіст навичок
ь роботи з
виконання таблицями,
розрахункі менш
в і зручне для
побудови щоденного
таблиць використа
ння
6
Вебдодатки Висока Високий Висока Швидке Залежність
та цифрові введення від
сервіси даних, інтернету,
автоматич можливі
ний питання
підрахунок конфіденці
, йності
візуалізаці
я, зручний
доступ
Більш зручним варіантом є використання електронних таблиць, наприклад
Microsoft Excel або Google Sheets. У таблицях можна створити власну структуру
обліку, використовувати формули, підраховувати підсумки, будувати діаграми.
Такий підхід є гнучким і підходить користувачам, які мають базові навички роботи
з таблицями. Проте електронні таблиці не завжди зручні для щоденного
використання. Їх потрібно налаштовувати вручну, а введення даних із мобільного
пристрою або швидкий перегляд статистики може бути менш комфортним, ніж у
спеціалізованому застосунку.
Сучаснішим підходом є використання мобільних або вебдодатків для
управління фінансами. Такі системи дозволяють додавати доходи й витрати через
зручні форми, зберігати дані в базі, автоматично підраховувати баланс, фільтрувати
записи за датою та категорією, а також показувати статистику у вигляді графіків чи
діаграм. Перевагою вебдодатку є те, що він не прив’язаний до конкретного
комп’ютера і може бути доступний із різних пристроїв через браузер.
Для теми цієї кваліфікаційної роботи найбільш доцільним є саме
веборієнтований підхід. Він дозволяє реалізувати особистий фінансовий кабінет
користувача, забезпечити автентифікацію, збереження даних у хмарній базі та
швидке відображення фінансової інформації в інтерфейсі. Такий формат є зручним
для користувача, який хоче вести облік без складних налаштувань і додаткового
програмного забезпечення.
7
1.3 Аналіз існуючих рішень для управління особистими фінансами
На ринку вже існує значна кількість сервісів для контролю особистих
фінансів. Їх аналіз є необхідним для того, щоб визначити функції, які доцільно
реалізувати у власному вебдодатку, а також врахувати недоліки наявних
рішень.Одним із відомих сервісів є Mint. Він орієнтований на автоматичне
завантаження фінансових операцій, створення бюджетів, перегляд витрат за
категоріями та моніторинг фінансового стану користувача. Його перевагою є
широкий набір функцій і зручна візуалізація даних. Водночас сервіс більше
орієнтований на іноземний ринок, а також може містити рекламні матеріали й
вимагати підключення до фінансових установ, що не завжди зручно або прийнятно
з погляду конфіденційності.
Рисунок 1.1 - Сайт Mint
Іншим популярним рішенням є YNAB. Його особливістю є підхід до
бюджетування, за якого кожна сума доходу має бути розподілена на конкретну мету
або категорію. Така логіка допомагає користувачеві краще планувати витрати та
формувати фінансову дисципліну. Проте цей сервіс є платним, а його методика
потребує певного часу на освоєння. Для користувача, якому потрібен простий облік
доходів і витрат, такий підхід може здатися надмірно складним.
8
Рисунок 1.2 - Сайт YNAB
PocketGuard також належить до сервісів управління особистими фінансами. Його
головна ідея полягає у визначенні суми коштів, які залишаються доступними після
врахування основних платежів. Такий підхід є зручним для швидкого контролю
залишку. Разом із тим безкоштовна версія має обмеження, а окремі функції
доступні лише після оплати.
Рисунок 1.3 - Сайт PocketGuard
Загалом аналіз існуючих рішень показує, що більшість сучасних фінансових
сервісів мають корисні можливості: облік доходів і витрат, категоризацію операцій,
побудову статистики, синхронізацію даних та інтеграцію із зовнішніми джерелами.
9
Водночас частина з них є платною, частина орієнтована на іноземні банківські
системи, а деякі мають перевантажений функціонал, який не завжди потрібен
звичайному користувачеві.[1; 2]
Для розроблюваного вебдодатку доцільно взяти за основу найбільш практичні
функції додавання доходів і витрат, перегляд загального балансу, фільтрацію за
періодом, відображення статистики у вигляді діаграм, а також отримання
актуальних валютних курсів. При цьому інтерфейс має залишатися простим, щоб
користувач міг швидко зрозуміти логіку роботи системи без додаткового навчання.
1.4 Порівняльна характеристика аналогів
Для зручності результати аналізу існуючих рішень можна подати у вигляді
порівняльної таблиці.
Таблиця 1.2 – Порівняльна характеристика сервісів для управління
особистими фінансами
Критерій Mint YNAB PocketGuard Розроблюван
ий вебдодаток
Облік доходів Передбачено Передбачено Передбачено Передбачено
Облік витрат Передбачено Передбачено Передбачено Передбачено
Категоризаці Є Є Є Є
я операцій
Візуалізація Є Є Є Передбачено
фінансових у вигляді
даних діаграм
Фільтрація за Є Є Є Передбачено
періодом
Отримання Обмежено Не є Обмежено Передбачено
валютних основною через API
курсів функцією Монобанку
Орієнтація на Низька Низька Низька Вища, з
українського урахуванням
користувача локального
10
API
Простота Висока Середня Висока Передбачено
використанн простий
я інтерфейс
Вартість Частково Платний Частково Безкоштовни
безкоштовни безкоштовни й у межах
й й розробленого
проєкту
Збереження Є Є Є через Firebase
даних у хмарі
На основі порівняння можна зробити висновок, що розроблюваний вебдодаток не
має на меті повністю замінити складні фінансові сервіси. Його призначення полягає
у створенні простого та доступного інструмента для особистого користування.
Основна увага приділяється тим функціям, які потрібні користувачеві найчастіше:
облік доходів, облік витрат, перегляд балансу, аналіз за категоріями та періодами.
1.5 Постановка задачі
Проведений аналіз предметної області та існуючих рішень показав, що для
повсякденного управління особистими фінансами користувачеві потрібен не
надмірно складний сервіс, а зрозумілий вебдодаток із базовими, але практично
корисними функціями. Такий застосунок має забезпечувати швидке внесення
фінансових операцій, збереження даних користувача, перегляд поточного стану
бюджету та наочний аналіз доходів і витрат.
У межах кваліфікаційної роботи необхідно розробити вебдодаток, який забезпечує:
1. автентифікацію користувача;
2. додавання записів про доходи;
3. додавання записів про витрати;
4. збереження фінансових даних у хмарній базі;
5. видалення раніше створених записів;
6. перегляд загального доходу, загальних витрат і балансу;
7. фільтрацію фінансових даних за роком, місяцем або днем;
11
8. візуалізацію структури доходів і витрат;
9. отримання актуальних курсів валют через зовнішній API;
10. роботу через браузер без встановлення додаткового програмного
забезпечення.
Розроблювана система повинна бути достатньо простою для щоденного
використання, але водночас мати таку структуру, яку можна буде розширювати в
майбутньому. Зокрема, надалі до неї можна додати фінансові цілі, експорт звітів,
нагадування, розширену аналітику або мобільну версію.
1.6 Висновки до розділу 1
У першому розділі розглянуто предметну область управління особистими
фінансами та визначено її значення для повсякденного контролю бюджету.
Встановлено, що облік доходів, витрат, заощаджень і балансу допомагає
користувачеві краще розуміти власний фінансовий стан, помічати зайві витрати та
планувати подальше використання коштів.
Було розглянуто основні способи відстеження фінансів: ручне ведення
записів, електронні таблиці та спеціалізовані цифрові сервіси. Традиційні способи є
простими й доступними, однак вони потребують більше часу та не завжди зручні
для аналізу. Вебдодатки в цьому випадку мають перевагу, оскільки дозволяють
швидше вносити записи, автоматично обробляти дані та подавати результати у
зрозумілій формі.
Також проаналізовано сервіси Mint, YNAB та PocketGuard. Вони мають
корисний функціонал, проте можуть бути платними, складними для швидкого
освоєння або недостатньо зручними для користувача, якому потрібен простий
інструмент щоденного обліку. Тому розробка власного вебдодатку для відстеження
та аналізу особистих фінансів є доцільною і може бути використана як основа для
подальшої практичної реалізації системи.
12
РОЗДІЛ 2.ОБҐРУНТУВАННЯ ЗАСОБІВ РОЗРОБКИ ВЕБДОДАТКУ ДЛЯ
ВІДСТЕЖЕННЯ ОСОБИСТИХ ФІНАНСІВ
2.1 Загальні вимоги до програмної реалізації
Розробка вебдодатку для відстеження особистих фінансів потребує вибору
таких технологій, які забезпечують зручну роботу з інтерфейсом, швидке
оновлення даних, можливість збереження інформації користувача та інтеграцію із
зовнішніми сервісами. Оскільки система передбачає роботу з персональними
фінансовими записами, важливими є також автентифікація користувача та
розмежування доступу до даних.
Вебдодаток має працювати через браузер, не потребувати встановлення
окремої програми та бути доступним на різних пристроях. Для цього інтерфейс
повинен бути адаптивним, а структура сторінки — зрозумілою. Користувач має
швидко виконувати основні дії: увійти в систему, додати дохід або витрату,
переглянути баланс, вибрати період і оцінити фінансову статистику[22] .
З технічної точки зору система повинна включати клієнтську частину, яка
відповідає за інтерфейс і взаємодію з користувачем, а також серверну або хмарну
частину, яка забезпечує зберігання даних та автентифікацію. Для реалізації такого
підходу було обрано JavaScript, React, HTML, CSS, Firebase та зовнішній API для
отримання валютних курсів.
2.2 Використання HTML, CSS та JavaScript
HTML і CSS є базовими технологіями для створення веб-інтерфейсу. HTML
використовується для формування структури сторінки: заголовків, форм, кнопок,
списків, блоків із фінансовими показниками та інших елементів. CSS відповідає за
зовнішній вигляд застосунку: розташування блоків, кольори, відступи, оформлення
кнопок, форм і діаграм.[4], [5]
Для фінансового вебдодатку зовнішній вигляд має велике значення, оскільки
користувач повинен швидко орієнтуватися в інформації. Якщо інтерфейс
перевантажений або незручний, навіть корисна функціональність буде сприйматися
13
гірше. Тому під час розробки потрібно забезпечити зрозумілу структуру: окремі
блоки для доходів, витрат, балансу, форми введення даних і зони статистики.
JavaScript використовується для реалізації логіки роботи додатку.[3] За його
допомогою можна обробляти введені користувачем дані, оновлювати стан
інтерфейсу, виконувати фільтрацію записів, працювати з масивами доходів і витрат,
надсилати запити до бази даних або зовнішнього API. У межах цієї роботи
JavaScript є основою для реалізації інтерактивності вебдодатку.
2.3 Обґрунтування вибору React
Для розробки інтерфейсу користувача було обрано бібліотеку React. Її
доцільність пояснюється тим, що вебдодаток для обліку фінансів складається з
багатьох повторюваних та взаємопов’язаних частин: форми додавання доходів,
форми додавання витрат, списків записів, блоку балансу, вибору періоду, діаграм,
заголовка та інших елементів. React дозволяє поділити інтерфейс на окремі
компоненти, кожен із яких виконує свою функцію.
Компонентний підхід полегшує розробку і подальшу підтримку системи.
Наприклад, компонент форми доходів можна змінювати окремо від компонента
діаграм, а компонент вибору дати - окремо від списків фінансових записів. Це
робить структуру проєкту більш зрозумілою та зменшує ризик помилок під час
внесення змін.[6]
Таблиця 2.1 - Порівняння засобів реалізації клієнтської частини вебдодатку
Критерій HTML, CSS, React Vue.js
JavaScript
Компонентний Реалізується Є основою Є основою
підхід вручну розробки розробки
Зручність роботи Обмежена, Висока, через Висока
зі станом потребує useState та
додаткового коду useEffect
Оновлення Можливе, але Реалізується Реалізується
інтерфейсу без складніше в зручно зручно
перезавантаженн реалізації
14
я сторінки
Підтримка форм і Потребує більшої Зручна реалізація Зручна реалізація
списків кількості ручного через компоненти
коду
Підтримка Можлива Широка Широка
діаграм і підтримка підтримка
сторонніх бібліотек
бібліотек
Зручність Середня Висока Висока
подальшого
розширення
Доцільність для Підходить для Найбільш Також підходить,
розробленого простих сторінок доцільний але не
вебдодатку варіант використовувавс
я в проєкт
Ще однією перевагою React є робота зі станом. У фінансовому додатку дані
постійно змінюються: користувач додає новий дохід, видаляє витрату, обирає інший
місяць, переглядає баланс. React дає змогу оновлювати інтерфейс без повного
перезавантаження сторінки. Завдяки цьому застосунок працює швидше і
сприймається користувачем як інтерактивний інструмент, а не як набір статичних
сторінок.
2.4 Використання Firebase для збереження даних та автентифікації
Для збереження фінансових даних і реалізації входу користувача було обрано
Firebase. Ця платформа надає готові сервіси, які спрощують розробку
вебзастосунків. У межах даної роботи важливими є два напрями: Firebase
Authentication та Cloud Firestore[12] .
15
Рисунок 2.1 - сайт Firebase
Firebase Authentication [10] використовується для автентифікації користувача.
Завдяки цьому можна реалізувати вхід через Google-акаунт без створення власної
складної системи реєстрації. Для фінансового додатку це важливо, оскільки дані
мають бути прив’язані до конкретного користувача. Після входу система може
визначати користувача за його унікальним ідентифікатором і відображати лише ті
записи, які належать саме йому.
Таблиця 2.2 - Використання сервісів Firebase у вебдодатку
Сервіс Firebase Призначення у Приклад використання
вебдодатку
Firebase Authentication Автентифікація Вхід користувача через
користувача Google-акаунт
Cloud Firestore Збереження фінансових Збереження доходів,
записів витрат і валютних
курсів
Firebase SDK Взаємодія додатку з Підключення бази
Firebase даних та функцій
автентифікації
Firebase Security Rules Обмеження доступу до Доступ лише для
даних авторизованого
користувача
16
Firebase Hosting Потенційне розгортання Публікація
вебдодатку вебзастосунку в мережі
Cloud Firestore використовується як хмарна база даних. У ній можуть
зберігатися записи про доходи, витрати та курси валют. Перевагою Firestore є те, що
дані доступні з різних пристроїв, а робота з ними може виконуватися без
розгортання окремого серверу. Для бакалаврської роботи такий підхід є доцільним,
оскільки дозволяє зосередитися на логіці вебдодатку, інтерфейсі та взаємодії
користувача з даними.
У структурі системи фінансові записи доцільно зберігати в окремих
колекціях, наприклад для доходів і витрат. Кожен запис повинен містити суму,
категорію, дату та ідентифікатор користувача. Наявність ідентифікатора
користувача дозволяє виконувати фільтрацію даних і не змішувати записи різних
користувачів.
2.5 Використання API для отримання валютних курсів
Додатковою функцією розроблюваного вебдодатку є відображення
актуальних валютних курсів. Для цього використовується зовнішній API. API
можна розглядати як механізм взаємодії між програмами, коли один сервіс надає
дані, а інший отримує їх у визначеному форматі.[9]
У межах цієї роботи API використовується для отримання курсів валют,
зокрема долара США та євро щодо гривні. Така функція є корисною, оскільки
користувачі часто здійснюють покупки, зберігають заощадження або планують
витрати з урахуванням валютного курсу. Автоматичне отримання курсів зменшує
потребу вручну шукати актуальну інформацію на сторонніх сайтах.
Використання API також робить додаток більш гнучким. Якщо в
майбутньому потрібно буде додати інші фінансові показники, наприклад курси
інших валют або додаткові аналітичні дані, архітектура із зовнішнім API дозволить
розширити функціональність без повної переробки системи.
2.6 Вимоги до безпеки та конфіденційності
17
Оскільки вебдодаток працює з фінансовими даними користувача, питання
безпеки є важливим навіть у межах навчального проєкту. Основна вимога полягає в
тому, щоб користувач бачив лише власні записи. Для цього кожен фінансовий запис
у базі даних повинен бути пов’язаний з ідентифікатором користувача, отриманим
після автентифікації.
Крім того, необхідно передбачити обробку ситуацій, коли користувач не
авторизований. У такому випадку система не повинна дозволяти перегляд або зміну
фінансових даних. Під час роботи з Firebase також доцільно використовувати
правила безпеки Firestore, які обмежують доступ до документів залежно від стану
автентифікації користувача [14], [15], [16], [17] .
На рівні інтерфейсу важливо уникати зайвого відображення службової
інформації, технічних помилок або даних, які не потрібні користувачеві.
Повідомлення про помилки мають бути зрозумілими, але не повинні розкривати
внутрішню структуру системи.
2.7 Висновки до розділу 2
У другому розділі було обґрунтовано вибір засобів розробки вебдодатку для
відстеження та аналізу особистих фінансів. Визначено, що для реалізації
інтерфейсу доцільно використовувати HTML, CSS та JavaScript, оскільки ці
технології забезпечують структуру, оформлення та інтерактивність вебсторінок.
Обґрунтовано використання React як основного інструменту для побудови
клієнтської частини. Компонентний підхід React відповідає структурі фінансового
вебдодатку, який складається з окремих функціональних блоків. Для збереження
даних та автентифікації користувача обрано Firebase, зокрема Firebase
Authentication і Cloud Firestore. Також розглянуто доцільність використання
зовнішнього API для отримання актуальних валютних курсів.
На основі проведеного обґрунтування визначено технологічну основу, яка
буде використана під час практичної реалізації вебдодатку в наступному розділі.
18
РОЗДІЛ 3.ПРОГРАМНА РЕАЛІЗАЦІЯ ТА ТЕСТУВАННЯ ВЕБДОДАТКУ
3.1 Вибір засобів реалізації вебдодатку
Для практичної реалізації вебдодатку для відстеження та аналізу особистих
фінансів було обрано набір технологій, які дозволяють створити зручний інтерфейс
користувача, забезпечити збереження фінансових даних, організувати
автентифікацію та реалізувати взаємодію із зовнішніми сервісами. Оскільки
розроблювана система призначена для щоденного використання, важливо було
обрати такі засоби, які забезпечують швидку роботу додатку, зрозумілу структуру
проєкту та можливість подальшого розширення функціоналу.
Основу клієнтської частини вебдодатку становить бібліотека React. Її
використання є доцільним, оскільки React дозволяє будувати інтерфейс із
незалежних компонентів. Для даного проєкту це має практичне значення, адже
вебдодаток складається з кількох окремих функціональних частин: форми
додавання доходів, форми додавання витрат, списку фінансових операцій, блоку
балансу, вибору періоду, відображення валютних курсів та діаграм. Кожен із цих
елементів може бути реалізований як окремий компонент, що спрощує розробку,
перевірку та подальше редагування коду.
Компонентний підхід також дає змогу зробити структуру проєкту більш
зрозумілою. Наприклад, зміни у формі додавання витрат не потребують переробки
блоку діаграм або компонента автентифікації. Це зменшує ризик помилок під час
доопрацювання вебдодатку та робить програмний код більш упорядкованим. Крім
того, React забезпечує швидке оновлення інтерфейсу без повного перезавантаження
сторінки, що є важливим для застосунку, у якому користувач постійно додає,
видаляє або фільтрує фінансові записи.
Для збереження даних і реалізації автентифікації користувача було
використано платформу Firebase. У межах розробленого вебдодатку Firebase
виконує дві основні функції: забезпечує вхід користувача через Google-акаунт та
зберігає фінансові
19
записи у хмарній базі даних Cloud Firestore. Такий підхід дозволяє не
створювати окремий сервер і не налаштовувати власну серверну інфраструктуру,
що є зручним рішенням для навчального проєкту та невеликого вебзастосунку.
Використання Firebase Authentication дозволяє пов’язати всі фінансові записи
з конкретним користувачем. Це важливо, оскільки дані про доходи, витрати та
баланс мають персональний характер і не повинні змішуватися з даними інших
користувачів. Після авторизації кожен запис може зберігатися разом з
ідентифікатором користувача, що надалі дає змогу отримувати з бази лише ті дані,
які належать поточному обліковому запису.
Cloud Firestore використовується для збереження інформації про доходи,
витрати та валютні курси. Його перевагою є можливість працювати з хмарною
базою даних без складного налаштування серверної частини. Для вебдодатку
особистих фінансів це зручно, оскільки користувач може зберігати свої записи, а
після повторного входу отримувати їх із бази даних. Крім того, така структура
дозволяє в майбутньому розширити функціональність системи, наприклад додати
фінансові цілі, історію змін або формування звітів.
Для отримання актуальних валютних курсів використано API Монобанку. Ця
функція є додатковою, проте вона підвищує практичну цінність вебдодатку.
Користувач може переглядати курси основних валют без переходу на сторонні
вебресурси. Це корисно для тих випадків, коли частина витрат, заощаджень або
планованих покупок пов’язана з іноземною валютою. Інтеграція з API також
демонструє можливість взаємодії розробленого додатку із зовнішніми сервісами.
Для візуального аналізу фінансових даних у вебдодатку використано засоби
побудови діаграм. Подання інформації лише у вигляді чисел не завжди є достатньо
зручним для користувача. Натомість діаграми дають змогу швидко оцінити
співвідношення доходів і витрат за категоріями та побачити, які напрями витрат
займають найбільшу частку в бюджеті. Це робить аналіз фінансів більш наочним і
зрозумілим.
20
Оформлення інтерфейсу реалізовано за допомогою CSS-файлів. Вони
відповідають за зовнішній вигляд сторінки, розташування блоків, кольори,
відступи, оформлення кнопок, форм і діаграм. Винесення стилів в окремі файли
дозволяє відокремити логіку роботи додатку від його візуального оформлення. Це
також полегшує подальше редагування дизайну без необхідності змінювати
основну програмну логіку.
Таким чином, обрані засоби реалізації відповідають поставленій задачі та
особливостям розроблюваного вебдодатку.[7] React забезпечує побудову
інтерактивного інтерфейсу, Firebase відповідає за автентифікацію та збереження
даних, Cloud Firestore використовується як хмарне сховище фінансових записів, API
Монобанку надає актуальні валютні дані, а CSS-файли формують зовнішній вигляд
системи. У сукупності ці технології дозволили реалізувати вебдодаток, придатний
для обліку, фільтрації та візуального аналізу особистих фінансів.
3.2 Структура проєкту
Практична частина роботи реалізована як React-проєкт із поділом на окремі
компоненти. Така структура спрощує підтримку системи, оскільки кожен файл
відповідає за конкретну частину функціоналу. Основні компоненти розміщено в
папці components, а стилі винесено в окремі CSS-файли.
До складу папки components входять такі основні файли:
1. Auth.js - компонент автентифікації користувача;
2. Balance.js - компонент відображення балансу;
3. CurrencyRates.js - компонент отримання та відображення валютних курсів;
4. ExpenseForm.js - форма додавання витрат;
5. ExpenseItem.js - елемент окремого запису витрат;
6. ExpenseList.js - список витрат;
7. Firebase.js - файл налаштування Firebase та функцій роботи з базою даних;
8. Header.js - заголовок вебдодатку;
9. IncomeForm.js - форма додавання доходів;
21
10. IncomeItem.js - елемент окремого запису доходу;
11. IncomeList.js - список доходів;
12. Month.js - компонент вибору періоду;
13. PiggyBank.js - компонент відображення накопичень.
Окремо створено CSS-файли для оформлення компонентів. Наприклад,
Balance.css використовується для стилізації блоку балансу, ExpenseForm.css - для
форми витрат, IncomeForm.css - для форми доходів, MonthGrid.css - для сітки
вибору періоду. Файл App.css містить загальні стилі додатку.
Головним компонентом є App.js, оскільки саме він об’єднує інші компоненти,
керує станами доходів і витрат, виконує фільтрацію та передає дані до компонентів
інтерфейсу. Файл index.js є точкою входу вебдодатку, через яку React виконує
рендеринг головного компонента у браузері.
3.3 Реалізація автентифікації користувача
Для роботи з особистими фінансовими даними необхідно було передбачити
автентифікацію користувача. У розробленому вебдодатку вона реалізована у
компоненті Auth.js за допомогою Firebase Authentication. Як спосіб входу
використано Google-акаунт, що спрощує процес авторизації для користувача і не
потребує створення окремої форми реєстрації [18].
Для того щоб дані про користувача були доступні в різних частинах додатку,
створено контекст автентифікації:
const AuthContext = createContext(null);
Використання контексту дозволяє передавати інформацію про поточного
користувача, стан завантаження та функцію виходу без дублювання коду в кожному
компоненті [19].
Компонент AuthProvider створює об’єкт автентифікації Firebase та зберігає
стан користувача:
export const AuthProvider = ({ children }) => {
const auth = getAuth(app);
22
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
Після запуску додатку виконується перевірка стану автентифікації. Якщо
користувач уже увійшов у систему, його дані записуються у стан user. Якщо
користувач не авторизований, виконується перенаправлення на сторінку входу
через Google [20]:
useEffect(() => {
const unsub = onAuthStateChanged(auth, async (maybeUser) => {
if (maybeUser) {
setUser(maybeUser);
setLoading(false);
} else {
try {
await signInWithRedirect(auth, googleAuthProvider);
} catch (e) {
console.error(e);
setLoading(false);
}
}
});
Після повернення користувача з Google-автентифікації система перевіряє результат
перенаправлення. Якщо авторизація виконана успішно, дані користувача
зберігаються в системі:
23
const checkRedirectResult = async () => {
try {
const result = await getRedirectResult(auth);
if (result) {
setUser(result.user);
}
} catch (e) {
console.error(e);
} finally {
setLoading(false);
}
};
Також передбачено функцію виходу із системи. Після її виконання користувач
виходить з облікового запису і повторно перенаправляється на сторінку
автентифікації:
const logout = async () => {
await signOut(auth);
await signInWithRedirect(auth, googleAuthProvider);
};
На завершення компонент передає дані через AuthContext.Provider Поки триває
перевірка стану входу, користувачу відображається повідомлення про
завантаження:
24
<AuthContext.Provider value={{ user, loading, logout }}>
{loading ? <>Завантаження...</> : children}
</AuthContext.Provider>
Таким чином, компонент Auth.js забезпечує контроль доступу до вебдодатку та
створює основу для збереження фінансових записів окремо для кожного
користувача.
3.4 Реалізація роботи з Firebase та Firestore
Збереження фінансових даних реалізовано за допомогою Cloud Firestore[11] . У
файлі Firebase.js налаштовується підключення до Firebase, автентифікація та
функції роботи з базою даних. Спочатку виконується ініціалізація Firebase-додатку:
export const app = initializeApp(firebaseConfig);
Після цього налаштовується Firebase Authentication і створюється провайдер для
входу через Google:
export const auth = getAuth(app);
export const googleAuthProvider = new GoogleAuthProvider()
Фінансові записи користувача зберігаються у двох основних колекціях:
dataMoneyIncome для доходів і dataMoneyExpense для витрат. Такий поділ є
зручним, оскільки доходи й витрати мають різне змістове призначення, але можуть
оброблятися за схожою логікою.
Для отримання доходів користувача використовується функція
getMoneyIncomeDBData [13]. У ній спочатку перевіряється наявність
авторизованого користувача. Далі формується запит до колекції dataMoneyIncome з
фільтрацією за uid:
async function getMoneyIncomeDBData() {
try {
const user = auth.currentUser;
if (!user) throw new Error("User not authenticated");
25
const moneyIncomeCol = collection(db, 'dataMoneyIncome');
const q = query(moneyIncomeCol, where('uid', '==', user.uid));
const incomeSnapshot = await getDocs(q);
const incomeList = incomeSnapshot.docs.map((doc) => ({
docId: doc.id,
data: doc.data()
}));
return incomeList;
} catch (error) {
console.error("Error getting money income data: ", error);
return [];
}
}
Фільтрація за uid є важливою, оскільки вона дозволяє отримувати лише ті
записи, які належать поточному користувачу. Отримані документи перетворюються
на масив об’єктів, де зберігається ідентифікатор документа та його дані. Це
потрібно для подальшого відображення і видалення записів.
Додавання нового доходу виконується функцією SetIncomeDBData. До
документа додаються дані доходу та ідентифікатор користувача:
async function SetIncomeDBData(incomeData) {
try {
const user = auth.currentUser;
if (!user) throw new Error("User not authenticated");
const moneyIncomeCol = collection(db, 'dataMoneyIncome');
await addDoc(moneyIncomeCol, { ...incomeData, uid: user.uid });
console.log("Data added successfully!");
26
} catch (error) {
console.error("Error adding data to money income collection: ", error);
}
}
Аналогічна логіка застосовується для роботи з витратами. Записи про витрати
зберігаються в окремій колекції, що дозволяє надалі окремо обробляти доходи та
витрати під час підрахунку балансу й побудови діаграм[24], [25] .
Окремо у Firebase.js реалізовано отримання валютних курсів із бази даних. Це
використовується як резервний варіант у випадку, якщо зовнішній API
недоступний:
async function getCurrencyRatesDBData() {
try {
const currencyRatesDoc = doc(db, 'CurrencyRates', documentId);
const ratesSnapshot = await getDoc(currencyRatesDoc);
if (ratesSnapshot.exists()) {
return ratesSnapshot.data();
} else {
console.log("No such document!");
return {};
}
} catch (error) {
console.error("Error getting currency rate data: ", error);
return {};
}}
У функціях роботи з Firebase передбачена обробка помилок. Якщо користувач не
авторизований або виникає помилка під час запиту до бази, вона фіксується в
консолі, а застосунок продовжує роботу без повного завершення.
27
3.5 Реалізація отримання валютних курсів
Для відображення актуальних валютних курсів використано компонент
CurrencyRates.js. Його призначення полягає в отриманні відкритих даних з API
Монобанку, відборі потрібних валютних пар і відображенні результату в інтерфейсі.
Запит до API виконується за допомогою бібліотеки Axios:
const response = await
axios.get('https://api.monobank.ua/bank/currency');
const currencyData = response.data;
Після отримання відповіді додаток має масив валютних курсів. Оскільки для
користувача найбільш практичними є курси долара США та євро щодо гривні,
виконується фільтрація даних:
const filteredRates = currencyData.filter(rate =>
(rate.currencyCodeA === 840 && rate.currencyCodeB === 980) ||
(rate.currencyCodeA === 978 && rate.currencyCodeB === 980)
);
Тут використовуються цифрові коди валют: 840 - долар США, 978 - євро, 980
- гривня. У результаті в інтерфейсі відображаються лише потрібні користувачеві
курси.
Після фільтрації отримані дані зберігаються у базі:
await SetCurrencyRatesDBData(filteredRates);
Це дозволяє використовувати останні збережені курси у випадку, коли API
тимчасово недоступний. Для цього в компоненті передбачено обробку помилки.
Якщо запит до API не виконується, система звертається до даних, які раніше були
збережені у Firebase:
} catch (error) {
setError(error.message);
setLoading(false);
const storedRates = await getCurrencyRatesDBData();
28
if (Object.keys(storedRates).length !== 0) {
setRates(storedRates);
} else {
console.error("Помилка отримання даних з бази даних.");
}
}
};
Отже, робота з валютними курсами реалізована не лише як прямий запит до
зовнішнього сервісу, а й із резервним механізмом використання збережених даних.
3.6 Реалізація вибору періоду та фільтрації даних
Для аналізу особистих фінансів важливо мати можливість переглядати записи
за конкретний період. У розробленому вебдодатку це реалізовано за допомогою
компонента Month.js та логіки фільтрації в App.js.
Компонент Month.js дозволяє користувачу вибрати рік, місяць, день або
режим перегляду «за весь час». Після кожної зміни вибору викликається функція
onDateChange, яка передає нові параметри до батьківського компонента:
useEffect(() => {
if (showAllTime || isAllTimeActive) {
onDateChange('за весь час');
} else {
onDateChange(year, selectedMonth + 1, selectedDay);
}
}, [year, selectedMonth, selectedDay, showAllTime, isAllTimeActive]);
Для зміни року передбачено окремі функції збільшення та зменшення значення:
const incrementYear = () => {
29
if (!showAllTime && !isAllTimeActive) {
setYear(prevYear => prevYear + 1);
}
};
const decrementYear = () => {
if (!showAllTime && !isAllTimeActive) {
setYear(prevYear => prevYear - 1);
}};
Кнопка перегляду «за весь час» скидає вибір конкретного місяця та активує
відповідний режим:
const handleShowAllTime = () => {
setShowAllTime(true);
setSelectedMonth(-1);
setViewMode('months');
setIsAllTimeActive(true);
};
Вибір місяця реалізовано через функцію handleMonthClick. Якщо користувач
натискає на місяць повторно, компонент переходить у режим вибору днів:
const handleMonthClick = (index) => {
const currentTime = new Date().getTime();
if (index === selectedMonth && currentTime - lastMonthClickTime < 300) {
30
setShowAllTime(false);
setViewMode('days');
} else {
setSelectedMonth(index);
setShowAllTime(false);
setViewMode('months');
setSelectedDay(null);
setIsAllTimeActive(false);
}
setLastMonthClickTime(currentTime);
};
Для вибору дня використовується функція handleDayClick:
const handleDayClick = (day) => {
const currentTime = new Date().getTime();
if (day === selectedDay && currentTime - lastDayClickTime < 300) {
setViewMode('months');
} else {
setSelectedDay(day);
}
setLastDayClickTime(currentTime);
};
31
Кількість днів у місяці визначається динамічно:
const getDaysInMonth = (year, month) => {
return new Date(year, month + 1, 0).getDate();
};
У компоненті App.js отримані значення періоду перетворюються у фільтр. Якщо
вибрано перегляд за весь час, відображаються всі записи. Якщо вибрано рік, місяць
або день, встановлюється відповідний тип фільтрації:
const handleDateChange = (year, month, day) => {
if (year === 'за весь час') {
setFilter({ type: 'all' });
} else if (month && day) {
setFilter({ type: 'day', year, month, day });
} else if (month) {
setFilter({ type: 'month', year, month });
} else {
setFilter({ type: 'year', year });
}
};
Фільтрація витрат виконується шляхом порівняння дати запису з активним
фільтром:
const filteredExpenses = expenses.filter(expense => {
if (filter.type === 'all') return true;
32
const expenseDate = new Date(expense.date);
if (filter.type === 'year') {
return expenseDate.getFullYear() === filter.year;
}
if (filter.type === 'month') {
return expenseDate.getFullYear() === filter.year && (expenseDate.getMonth() +
1) === filter.month;
}
if (filter.type === 'day') {
return expenseDate.getFullYear() === filter.year && (expenseDate.getMonth() +
1) === filter.month && expenseDate.getDate() === filter.day;
}
return true;
});
Такий підхід дозволяє користувачеві швидко переглядати фінансові записи за
потрібний період і робить аналіз витрат та доходів більш зручним.
3.7 Реалізація основної логіки додатку
Центральним елементом програмної реалізації вебдодатку є компонент
App.js, оскільки саме в ньому поєднується основна логіка роботи системи. Він
виконує роль головного контейнера, який об’єднує інші компоненти інтерфейсу,
забезпечує отримання даних із Firebase, передає їх до відповідних блоків сторінки
та реагує на дії користувача. Через цей компонент здійснюється керування
доходами, витратами, фільтрами, списками фінансових записів і відображенням
результатів у зручному для користувача вигляді.
33
У межах App.js реалізовано роботу з основними даними вебдодатку. Після
авторизації користувача компонент отримує з бази даних Firestore записи про
доходи та витрати, зберігає їх у стані застосунку, а потім передає до компонентів
списків, балансу та діаграм. Завдяки цьому користувач може бачити актуальну
інформацію про власні фінанси одразу після входу в систему.
Також у цьому компоненті реалізовано додавання нових фінансових записів.
Коли користувач вводить суму, категорію та дату доходу або витрати, відповідна
функція оновлює локальний стан додатку та зберігає запис у Firestore. Це дозволяє
одночасно оновити інтерфейс і забезпечити постійне збереження даних у хмарній
базі.
Окреме значення має логіка видалення записів. Якщо користувач помилково
додав дохід або витрату, він може видалити цей запис зі списку. Після цього
компонент повторно отримує оновлені дані з бази або змінює стан таким чином,
щоб в інтерфейсі відображалася вже актуальна інформація.Крім роботи з доходами
й витратами, App.js відповідає за фільтрацію фінансових даних.
Користувач може переглядати записи за весь час, за окремий рік, місяць або
день. Для цього у компоненті зберігається активний фільтр, який визначає, які саме
записи повинні бути показані в інтерфейсі.
На початку роботи компонента створюються змінні стану, які
використовуються для збереження доходів, витрат, ідентифікаторів документів у
базі даних, значення слайдера та поточного фільтра. Саме ці стани забезпечують
зв’язок між діями користувача, даними у Firebase та відображенням інформації на
сторінці.
const { user, loading } = useAuth() || {};
const [incomes, setIncomes] = useState([]);
const [incomesDocID, setIncomesDocID] = useState([]);
const [expenses, setExpenses] = useState([]);
34
const [sliderValue, setSliderValue] = useState(0);
const [filter, setFilter] = useState({ type: 'all' });
Після завантаження компонента виконується отримання даних із бази. Для цього
використовується useEffect, у якому окремо завантажуються доходи та витрати:
useEffect(() => {
const fetchIncomes = async () => {
try {
const incomeDocID = await getMoneyIncomeDBData();
const income = incomeDocID.map(({ docId, data }) => data);
setIncomesDocID(incomeDocID)
setIncomes(income);
} catch (error) {
console.error("Error fetching income: ", error);
}
};
const fetchExpenses = async () => {
try {
const expensesDocID = await getMoneyExpenseDBData();
const expenses = expensesDocID.map(({ docId, data }) => data);
setExpensesDocID(expensesDocID);
setExpenses(expenses);
35
} catch (error) {
console.error("Error fetching expenses: ", error);
}
};
fetchIncomes();
fetchExpenses();
}, []);
Додавання доходу виконується функцією addIncome. Вона оновлює локальний стан
і записує новий дохід у Firestore:
const addIncome = async (income) => {
setIncomes([...incomes, income]);
await SetIncomeDBData(income);
};
Додавання витрати працює за аналогічним принципом:
const addExpense = async (expense) => {
setExpenses([...expenses, expense]);
await SetExpenseDBData(expense);
};
Для видалення витрат використовується функція deleteExpense. Після видалення
документа з бази список витрат оновлюється:
const deleteExpense = async (expenseId) => {
36
await deleteExpenseDBData(expenseId);
const updatedExpenses = await getMoneyExpenseDBData();
const updatedExpensesData = updatedExpenses.map(({ docId, data }) => data);
setExpensesDocID(updatedExpenses);
setExpenses(updatedExpensesData);
};
Аналогічно реалізовано видалення доходів:
const deleteIncome = async (incomeId) => {
await deleteIncomeDBData(incomeId);
const updatedIncome = await getMoneyIncomeDBData();
const updatedIncomeData = updatedIncome.map(({ docId, data }) => data);
setIncomesDocID(updatedIncome)
setIncomes(updatedIncomeData);
};
Компонент App також перевіряє, чи користувач авторизований. Якщо триває
завантаження, відображається відповідне повідомлення. Якщо користувач увійшов
у систему, відкривається основний вміст додатку:
function App() {
const { user, loading } = useAuth() || {};
return (
<div>
37
{loading ? <p>Завантаження...</p> : (user ? <AppContent /> : <p>Ви не
увійшли в систему</p>)}
</div>
);
}
Для доступу до контексту автентифікації вся структура додатку обгортається у
AuthProvider:
export default function AppWithAuthProvider() {
return (
<AuthProvider>
<App />
</AuthProvider>
);
}
Отже, App.js виконує роль центрального компонента, який об’єднує
автентифікацію, роботу з базою даних, фільтрацію, форми введення та візуальне
відображення фінансових даних.
3.8 Реалізація графічного інтерфейсу користувача
Графічний інтерфейс вебдодатку побудований так, щоб користувач міг
швидко виконувати основні дії: переглядати баланс, додавати доходи й витрати,
обирати період, переглядати списки записів і аналізувати дані за допомогою
діаграм[26] .
38
Рисунок 3.1 - Головна сторінка сайту
У верхній частині сторінки розміщено шапку вебдодатку. У ній
відображається ім’я користувача, кнопка зміни облікового запису та елемент
керування періодом перегляду. Центральний заголовок показує, за який період
відображаються фінансові дані. Під заголовком розміщено інформаційні блоки із
загальним доходом, загальними витратами, балансом і накопиченнями. Такий блок
дозволяє швидко оцінити поточний фінансовий стан користувача.
Рисунок 3.2 - Інформаційний блок
Ліва частина інтерфейсу містить форми додавання доходів і витрат. У кожній
формі користувач вводить суму, обирає категорію та дату. Після натискання кнопки
додавання запис зберігається в базі даних і відображається в загальному списку.
39
У центральній частині сторінки відображаються списки доходів і витрат.
Кожен запис містить основні відомості про операцію та кнопку видалення. Це
дозволяє користувачеві швидко редагувати історію фінансових записів шляхом
видалення помилково внесених даних.
Рисунок 3.3 - Списки Доходів
Права частина сторінки призначена для візуального аналізу. Тут розміщуються
кругові діаграми, які показують розподіл доходів і витрат за категоріями. Графічне
подання [8] допомагає краще оцінити структуру фінансових операцій і побачити,
які категорії займають найбільшу частку.
40
Рисунок 3.4 - Діаграма витрат
3.9 Тестування вебдодатку
Після завершення програмної реалізації основних функцій вебдодатку було
проведено перевірку його працездатності. Метою тестування було визначити, чи
коректно працюють ключові можливості системи та чи відповідає розроблений
додаток поставленим функціональним вимогам.
Під час тестування перевірялися основні сценарії взаємодії користувача з
вебдодатком. Зокрема, було перевірено процес авторизації через Google-акаунт,
додавання записів про доходи та витрати, збереження цих записів у базі даних
Firestore, їх подальше відображення в інтерфейсі, видалення помилково внесених
даних, а також фільтрація фінансових записів за обраним періодом. Окрему увагу
було приділено перевірці правильності відображення балансу, загальної суми
41
доходів і витрат, а також побудові діаграм для візуального аналізу фінансової
інформації.
Також було перевірено роботу з зовнішнім сервісом отримання валютних
курсів. У межах цього етапу тестування оцінювалося, чи виконується запит до API
Монобанку, чи правильно відбираються потрібні валютні пари та чи
відображаються отримані значення в інтерфейсі вебдодатку. Це дозволило
переконатися, що додаток може працювати не лише з внутрішніми даними
користувача, а й із зовнішніми джерелами фінансової інформації.
Перевірка виконувалася шляхом послідовного проходження типових дій
користувача. Для кожного сценарію було визначено очікуваний результат, після чого
він порівнювався з фактичним результатом роботи вебдодатку. Такий підхід
дозволив оцінити стабільність основних функцій системи та виявити можливі
помилки в логіці роботи інтерфейсу, збереженні даних або фільтрації записів.
Результати проведеного функціонального тестування наведено в таблиці 3.1.
Таблиця 3.1 – Результати функціонального тестування вебдодатку
Тестовий сценарій Очікуваний Фактичний Статус
№ результат результат
1 Вхід користувача Користувач Авторизація Успішно
через успішно виконана
Google-акаунт авторизується
2 Додавання нового Запис Запис додано Успішно
доходу зберігається у
Firestore та
відображається
у списку
3 Додавання нової Запис Запис додано Успішно
витрати зберігається у
Firestore та
відображається
у списку
42
4 Видалення доходу Запис Запис Успішно
видаляється з видалено
бази та списку
5 Видалення витрати Запис Запис Успішно
видаляється з видалено
бази та списку
6 Вибір періоду «за Відображаються Дані Успішно
весь час» всі фінансові відображено
записи
7 Фільтрація за Відображаються Фільтрація Успішно
місяцем записи за працює
вибраний
місяць
8 Отримання Відображаються Курси Успішно
валютних курсів курси USD та отримано
EUR до UAH
9 Побудова діаграм Доходи й Діаграми Успішно
витрати побудовано
відображаються
графічно
10 Спроба доступу без Основний вміст Доступ Успішно
авторизації не обмежено
відкривається
без входу
За результатами тестування встановлено, що основні функції вебдодатку
працюють відповідно до поставлених вимог. Авторизація користувача виконується
коректно, фінансові записи зберігаються у базі даних із прив’язкою до користувача,
а фільтрація й візуалізація даних забезпечують зручний аналіз особистих фінансів.
Окремо було перевірено роботу з валютними курсами. У разі успішного
запиту до API Монобанку додаток отримує актуальні значення курсів. Якщо запит
не виконується, передбачено можливість використання раніше збережених даних із
Firebase.
3.10 Порівняння розробленого вебдодатку з аналогами
43
Після завершення розробки та перевірки працездатності вебдодатку було
проведено його порівняння з існуючими сервісами для управління особистими
фінансами. Такий етап є важливим, оскільки дозволяє оцінити не лише факт
реалізації основних функцій, а й практичну доцільність створеної системи
порівняно з уже наявними рішеннями.
Для порівняння було використано сервіси, розглянуті в першому розділі,
зокрема Mint, YNAB та PocketGuard. Вони мають подібне призначення, оскільки
також орієнтовані на облік доходів і витрат, перегляд фінансової інформації та
допомогу користувачеві в контролі особистого бюджету. Разом з тим ці сервіси
відрізняються за складністю, вартістю використання, набором функцій та
орієнтацією на певну аудиторію.
Метою порівняння є визначення сильних і слабких сторін розробленого
вебдодатку, а також встановлення його місця серед аналогічних програмних рішень.
Особлива увага приділялася тим критеріям, які є важливими саме для щоденного
використання: наявність обліку доходів і витрат, фільтрація за періодами,
візуалізація даних, хмарне збереження записів, простота інтерфейсу та можливість
отримання актуальних валютних курсів.
Розроблений вебдодаток не розглядається як повна заміна великих
комерційних фінансових платформ, однак він реалізує основні функції, необхідні
для базового контролю особистих фінансів. Його перевагою є простота
використання, відсутність зайвого функціонального перевантаження, збереження
даних у Firebase та інтеграція з API Монобанку, що робить систему більш
наближеною до потреб українського користувача.
Таблиця 3.2 – Порівняння розробленого вебдодатку з аналогами
Критерій Mint YNAB PocketGuard Розроблений
вебдодаток
Облік доходів Є Є Є Реалізовано
Облік витрат Є Є Є Реалізовано
44
Фільтрація за Є Є Є Реалізовано
періодом
Діаграми Є Є Є Реалізовано
доходів і
витрат
Авторизація Є Є Є Реалізовано
користувача через Google
Збереження Є Є Є Реалізовано
даних у хмарі через Firebase
Отримання Обмежено Не є Обмежено Реалізовано
валютних основною через API
курсів функцією Монобанку
Простота Висока Середня Висока Орієнтовано
інтерфейсу на просте
використанн
я
Вартість Частково Платний Частково Безкоштовни
використанн безкоштовни безкоштовни й у межах
я й й проєкту
Орієнтація на Низька Низька Низька Передбачено
українського використанн
користувача я локального
API
Порівняння показує, що розроблений вебдодаток не є повною заміною
складних комерційних фінансових сервісів, однак він реалізує основні функції,
необхідні для щоденного контролю особистих фінансів. Його перевагою є простота
інтерфейсу, використання Firebase для збереження даних, авторизація через Google
та інтеграція з API Монобанку для отримання валютних курсів.
3.11 Висновки до розділу 3
У третьому розділі було виконано програмну реалізацію вебдодатку для
відстеження та аналізу особистих фінансів. Описано структуру проєкту,
призначення основних компонентів React-застосунку та взаємодію між ними.
45
Реалізовано автентифікацію користувача за допомогою Firebase
Authentication. Це дозволило обмежити доступ до фінансових записів і забезпечити
прив’язку даних до конкретного користувача. Для збереження доходів, витрат і
валютних курсів використано Cloud Firestore.
У вебдодатку реалізовано додавання та видалення доходів і витрат, перегляд
балансу, вибір періоду, фільтрацію записів за датою, а також побудову діаграм для
візуального аналізу. Додатково реалізовано отримання актуальних курсів валют
через API Монобанку.
Проведене тестування підтвердило працездатність основних функцій
вебдодатку. Порівняння з аналогами показало, що розроблена система забезпечує
базові можливості для щоденного обліку особистих фінансів і може бути надалі
розширена новими функціями, зокрема експортом звітів, фінансовими цілями,
розширеною аналітикою або мобільною версією.
46
ВИСНОВКИ
У кваліфікаційній роботі було виконано проєктування та розробку вебдодатку для
відстеження й аналізу особистих фінансів. Розроблена система призначена для
зручного обліку доходів і витрат користувача, перегляду поточного балансу,
фільтрації фінансових записів за періодами та візуального аналізу фінансової
інформації. Для реалізації додатку використано React, Firebase, Cloud Firestore,
Firebase Authentication та API Монобанку.
У процесі виконання роботи було отримано такі результати:
1. Проаналізовано предметну область управління особистими фінансами.
Встановлено, що регулярний облік доходів, витрат і заощаджень допомагає
користувачеві краще контролювати власний бюджет, виявляти основні
напрями витрат і планувати подальше використання коштів.
2. Розглянуто існуючі цифрові рішення для управління фінансами, зокрема
Mint, YNAB та PocketGuard. Визначено, що такі сервіси мають широкий
функціонал, проте можуть бути платними, складними для швидкого освоєння
або недостатньо зручними для користувачів, яким потрібен простий
інструмент щоденного фінансового обліку.
3. Обґрунтовано вибір засобів розробки вебдодатку. Для побудови інтерфейсу
використано React, оскільки компонентний підхід дає змогу зручно
організувати структуру застосунку. Для автентифікації та збереження даних
обрано Firebase, що дозволило реалізувати вхід користувача через
Google-акаунт і зберігання фінансових записів у хмарній базі Firestore.
4. Спроєктовано структуру вебдодатку та визначено основні компоненти
системи. До складу застосунку увійшли компоненти для автентифікації,
відображення балансу, додавання доходів і витрат, перегляду списків
фінансових записів, вибору періоду, відображення валютних курсів та
побудови діаграм.
47
5. Реалізовано основні функціональні можливості вебдодатку. Користувач може
авторизуватися, додавати записи про доходи й витрати, видаляти помилково
внесені записи, переглядати загальний дохід, витрати, баланс і накопичення, а
також фільтрувати дані за роком, місяцем, днем або переглядати інформацію
за весь час.
6. Реалізовано інтеграцію з API Монобанку для отримання актуальних курсів
валют. Це розширює функціональність додатку та дозволяє користувачеві
отримувати додаткову фінансову інформацію без переходу на сторонні
ресурси.
7. Проведено перевірку працездатності розробленого вебдодатку. Тестування
показало, що основні функції системи працюють коректно: авторизація
виконується успішно, дані зберігаються у Firestore, записи додаються та
видаляються, фільтрація за періодами працює, а фінансова інформація
відображається у вигляді списків і діаграм.
Практичне значення роботи полягає у створенні вебдодатку, який може
використовуватися для щоденного контролю особистих фінансів. Розроблена
система має простий інтерфейс, не потребує встановлення додаткового
програмного забезпечення та забезпечує базові можливості для аналізу доходів і
витрат.
У подальшому вебдодаток може бути розширений. До перспектив розвитку
можна віднести додавання фінансових цілей, експорту звітів, нагадувань про
регулярні платежі, розширеної статистики, підтримки кількох валют, мобільної
версії та можливості спільного ведення бюджету для сім’ї або групи користувачів.
48
СПИСОК ВИКОРИСТАНИХ ДЖЕРЕЛ
1. Ynab. YNAB. URL: https://www.ynab.com/ (дата звернення: 26.05.2026).
2. PocketGuard: budgeting app & finance planner. PocketGuard | Your Personal
Money & Bill Organizer. URL: https://pocketguard.com/ (дата звернення:
26.05.2026).
3. JavaScript language overview - JavaScript | MDN. MDN Web Docs. URL:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Language_overview
(дата звернення: 26.05.2026).
4. Ukrainian W. Уроки від W3Schools українською онлайн. W3Schools
українською. Безплатні уроки онлайн для початківців, школярів та студентів.
URL: https://w3schoolsua.github.io/css/index.html#gsc.tab=0 (дата звернення:
26.05.2026).
5. CSS Приклади. Уроки для початківців. W3Schools українською. W3Schools
українською. Безплатні уроки онлайн для початківців, школярів та студентів.
URL: https://w3schoolsua.github.io/css/css_examples.html#gsc.tab=0 (дата
звернення: 26.05.2026).
6. Quick start – React. React. URL: https://react.dev/learn (дата звернення:
26.05.2026).
7. npm-start | npm docs. npm Docs. URL:
https://docs.npmjs.com/cli/v7/commands/npm-start (дата звернення: 26.05.2026).
8. Pie | react-chartjs-2. react-chartjs-2. URL:
https://react-chartjs-2.js.org/components/pie/ (дата звернення: 26.05.2026).
9. Monobank open API. API. URL:
https://api.monobank.ua/docs/index.html#tag/Publichni-dani (дата звернення:
26.05.2026).
10. Build documentation | Firebase documentation. Firebase. URL:
https://firebase.google.com/docs/build (дата звернення: 26.05.2026).
49
11. Get started with Cloud Firestore | Firebase. Firebase. URL:
https://firebase.google.com/docs/firestore/quickstart (дата звернення: 26.05.2026).
12. Manage databases | Firestore | Firebase. Firebase. URL:
https://firebase.google.com/docs/firestore/manage-databases (дата звернення:
26.05.2026).
13. Get data with Cloud Firestore | Firebase. Firebase. URL:
https://firebase.google.com/docs/firestore/query-data/get-data (дата звернення:
26.05.2026).
14. Get started with Firebase Security Rules. Firebase. URL:
https://firebase.google.com/docs/rules/get-started (дата звернення: 26.05.2026).
15. How Security Rules work | Firebase Security Rules. Firebase. URL:
https://firebase.google.com/docs/rules/rules-behavior (дата звернення:
26.05.2026).
16. Basic Security Rules | Firebase Security Rules. Firebase. URL:
https://firebase.google.com/docs/rules/basics#cloud-storage_2 (дата звернення:
26.05.2026).
17. Data validation | Firebase Security Rules. Firebase. URL:
https://firebase.google.com/docs/rules/data-validation (дата звернення:
26.05.2026).
18. Get started with Firebase Authentication on websites. Firebase. URL:
https://firebase.google.com/docs/auth/web/start (дата звернення: 26.05.2026).
19. Manage users in Firebase. Firebase. URL:
https://firebase.google.com/docs/auth/web/manage-users (дата звернення:
26.05.2026).
20. Authenticate using Google with JavaScript | Firebase. Firebase. URL:
https://firebase.google.com/docs/auth/web/google-signin (дата звернення:
26.05.2026).
50
21. Методичні рекомендації до підготовки кваліфікаційної роботи для здобувачів
освітнього ступеня «бакалавр» зі спеціальності 126 Інформаційні системи та
технології освітньої програми «Web-технології, Web-дизайн» усіх форм
навчання [Електронний ресурс] / упоряд.: Т.О. Прокопенко, Я.В. Тарасенко;
М-во освіти і науки України, Черкас. держ. технол. ун-т. Черкаси : ЧДТУ,
2021. 48 с.
22. Прокопенко Т.О., Ладанюк А.П. Інформаційні технології управління
організаційно-технологічними системами : монографія. Черкаси : Вертикаль,
видавець Кандич С.Г., 2015. 224 с.
23. Томашевський О.М., Цегелик Г.Г., Вітер М.Б., Дубук В.І. Інформаційні
технології та моделювання бізнес-процесів. Київ : Центр учбової літератури,
2012. 296 с.
24. Гайдаржи В.І., Ізварін І.В. Бази даних в інформаційних системах. Київ :
Університет «Україна», 2018. 418 с.
25. Харів Н.О. Бази даних та інформаційні системи : навчальний посібник. Рівне
: НУВГП, 2018. 127 с.
26. Трофименко О.Г., Козін О.Б., Задерейко О.В., Плачінда О.Є. Веб-технології та
веб-дизайн : навчальний посібник. Одеса : Фенікс, 2019. 284 с.
27. Буйницька О.П. Інформаційні технології та технічні засоби навчання :
навчальний посібник. Київ : Центр учбової літератури, 2018. 240 с.
28. Козловський А.В., Паночишин Ю.М., Погріщук Б.В. Комп’ютерна техніка та
інформаційні технології : навчальний посібник. Київ : Знання, 2017. 463 с
51
ДОДАТОК А
ЗАТВЕРДЖУЮ
завідувач кафедри ІТП
______________ Тетяна ПРОКОПЕНКО
«____» __________________2026 року
WEB-ДОДАТОК ДЛЯ ВІДСТЕЖУВАННЯ ТА АНАЛІЗУ
ОСОБИСТИХ ФІНАНСІВ
Специфікація
ЧДТУ 262205.003-01
Аркушів 2
Розробник ____________________ Воропай Я.Є.
(підпис)
Керівник ____________________ Прокопенко В.А.
(підпис)
Н. Контроль ____________________ Прокопенко Т.О.
(підпис)
2026
54
ДОДАТОК Б
Позначення Найменування Примітка
Документація
ЧДТУ 262205.003-01 12 01 Текст програми Додаток Г-Е
ЧДТУ 262205.003-01 34 01 Інструкція користувача Додаток Є
ЧДТУ 262205.003 ПЗ Пояснювальна записка Основний документ
55
Додаток В
ПРОГРАМНЕ ЗАБЕЗПЕЧЕННЯ
Web-додаток для відстежування та аналізу особистих фінансів
ТЕКСТ ПРОГРАМИ
ЧДТУ 262205.003-01 12 01
Аркушів 29
Розробник ________________ ВОРОПАЙ Я.Є.
(підпис)
Черкаси, 2026
56
ДОДАТОК Г
Текст програми компонента Auth.js
import React, { createContext, useContext, useState, useEffect } from "react";
import { signInWithPopup, onAuthStateChanged, signOut } from "firebase/auth";
import { auth, googleAuthProvider } from "./Firebase";
const AuthContext = createContext(null);
export const AuthProvider = ({ children }) => {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const unsub = onAuthStateChanged(auth, (maybeUser) => {
setUser(maybeUser);
setLoading(false);
});
return () => unsub();
}, []);
const login = async () => {
const result = await signInWithPopup(auth, googleAuthProvider);
setUser(result.user);
};
const logout = async () => {
57
await signOut(auth);
};
return (
<AuthContext.Provider value={{ user, loading, login, logout }}>
{loading ? <>Завантаження...</> : children}
</AuthContext.Provider>
);
};
export const useAuth = () => useContext(AuthContext);
58
ДОДАТОК Ґ
Текст програми компонента Firebase.js
import { initializeApp } from 'firebase/app';
import { getAuth, GoogleAuthProvider, onAuthStateChanged } from 'firebase/auth';
import { doc, getFirestore, collection, getDocs, addDoc, setDoc, getDoc, query, where,
deleteDoc } from 'firebase/firestore/lite';
const firebaseConfig = {
apiKey: "AIzaSyAl9lHxCUkmwBlkTYiIfNDic7dWm5gTytc",
authDomain: "persik-v-mazute.firebaseapp.com",
projectId: "persik-v-mazute",
storageBucket: "persik-v-mazute.firebasestorage.app",
messagingSenderId: "449805746563",
appId: "1:449805746563:web:d96ad5e0b48bd86f04f6b6",
measurementId: "G-8JFRQ3YTZE"
};
export const app = initializeApp(firebaseConfig);
export const db = getFirestore(app);
export const googleAuthProvider = new GoogleAuthProvider()
export const auth = getAuth(app);
function getCurrentUser() {
return new Promise((resolve) => {
59
if (auth.currentUser) {
resolve(auth.currentUser);
return;
}
const unsubscribe = onAuthStateChanged(auth, (user) => {
unsubscribe();
resolve(user);
});
});
}
async function getMoneyIncomeDBData() {
try {
const user = await getCurrentUser();
if (!user) throw new Error("User not authenticated");
const moneyIncomeCol = collection(db, 'dataMoneyIncome');
const q = query(moneyIncomeCol, where('uid', '==', user.uid));
const incomeSnapshot = await getDocs(q);
const incomeList = incomeSnapshot.docs.map((doc) => ({
docId: doc.id,
data: doc.data()
60
}));
return incomeList;
} catch (error) {
console.error("Error getting money income data: ", error);
return [];
}
}
async function SetIncomeDBData(incomeData) {
try {
const user = await getCurrentUser();
if (!user) throw new Error("User not authenticated");
const moneyIncomeCol = collection(db, 'dataMoneyIncome');
const docRef = await addDoc(moneyIncomeCol, { ...incomeData, uid: user.uid });
console.log("Data added successfully!");
return docRef.id;
} catch (error) {
console.error("Error adding data to money income collection: ", error);
}
}
async function getMoneyExpenseDBData() {
61
try {
const user = await getCurrentUser();
if (!user) throw new Error("User not authenticated");
const moneyExpenseCol = collection(db, 'dataMoneyExpense');
const q = query(moneyExpenseCol, where('uid', '==', user.uid));
const expenseSnapshot = await getDocs(q);
const expenseList = expenseSnapshot.docs.map((doc) => ({
docId: doc.id,
data: doc.data()
}));
return expenseList;
} catch (error) {
console.error("Error getting money expense data: ", error);
return [];
}
}
async function SetExpenseDBData(expenseData) {
try {
const user = await getCurrentUser();
if (!user) throw new Error("User not authenticated");
62
const moneyExpenseCol = collection(db, 'dataMoneyExpense');
const docRef = await addDoc(moneyExpenseCol, { ...expenseData, uid: user.uid });
console.log("Data added successfully!");
return docRef.id;
} catch (error) {
console.error("Error adding data to money expense collection: ", error);
}
}
const documentId = 'iWM8oDH1gDliulcQvmBd';
async function SetCurrencyRatesDBData(rateData) {
try {
const currencyRatesDoc = doc(db, 'CurrencyRates', documentId);
const filteredRates = rateData.map(rate => ({
currencyCodeA: rate.currencyCodeA,
currency: rate.currencyCodeA === 840 ? 'USD' : 'EUR',
rateBuy: rate.rateBuy,
rateSell: rate.rateSell
}));
const dataObject = {};
filteredRates.forEach((rate, index) => {
63
dataObject[index.toString()] = rate;
});
await setDoc(currencyRatesDoc, dataObject);
} catch (error) {
console.error("Помилка додавання даних до колекції курсів валют: ", error);
}
}
async function getCurrencyRatesDBData() {
try {
const currencyRatesDoc = doc(db, 'CurrencyRates', documentId);
const ratesSnapshot = await getDoc(currencyRatesDoc);
if (ratesSnapshot.exists()) {
return ratesSnapshot.data();
} else {
console.log("No such document!");
return {};
}
} catch (error) {
console.error("Error getting currency rate data: ", error);
return {};
64
}
}
async function deleteExpenseDBData(expenseId) {
try {
const user = await getCurrentUser();
if (!user) throw new Error("User not authenticated");
const expenseDoc = doc(db, 'dataMoneyExpense', expenseId);
await deleteDoc(expenseDoc);
console.log("Expense deleted successfully!");
} catch (error) {
console.error("Error deleting expense: ", error);
}
}
async function deleteIncomeDBData(incomeId) {
try {
const user = await getCurrentUser();
if (!user) throw new Error("User not authenticated");
const incomeDoc = doc(db, 'dataMoneyIncome', incomeId);
await deleteDoc(incomeDoc);
console.log("Income deleted successfully!");
65
} catch (error) {
console.error("Error deleting income: ", error);
}
}
export {
getMoneyIncomeDBData,
SetIncomeDBData,
getMoneyExpenseDBData,
SetExpenseDBData,
getCurrencyRatesDBData,
SetCurrencyRatesDBData,
deleteExpenseDBData,
deleteIncomeDBData
};
66
ДОДАТОК Д
Текст програми компонента App.js
import React, { useEffect, useState } from 'react';
import Balance from './components/Balance';
import IncomeForm from './components/IncomeForm';
import IncomeList from './components/IncomeList';
import ExpenseForm from './components/ExpenseForm';
import ExpenseList from './components/ExpenseList';
import Header from './components/Header';
import { Chart as ChartJS } from "chart.js/auto";
import { Doughnut, Pie } from "react-chartjs-2";
import { AuthProvider, useAuth } from "./components/Auth";
import { getMoneyIncomeDBData, SetIncomeDBData, getMoneyExpenseDBData,
SetExpenseDBData, deleteExpenseDBData,deleteIncomeDBData } from
"./components/Firebase";
import MonthGrid from "./components/Month";
import CurrencyRates from "./components/CurrencyRates";
import "./App.css";
import "./css/right_column.css"
import "./css/left_column.css"
const doughnutColors = [
67
'#FF6384', '#36A2EB', '#FFCE56', '#FF9F40',
'#4BC0C0', '#9966FF', '#FF6384', '#36A2EB',
'#FFCE56', '#FF9F40', '#4BC0C0', '#9966FF',
'#FF6384', '#36A2EB', '#FFCE56'
];
function AppContent() {
const { user, loading } = useAuth() || {};
const [incomes, setIncomes] = useState([]);
const [expenses, setExpenses] = useState([]);
const [sliderValue, setSliderValue] = useState(0);
const [filter, setFilter] = useState({ type: 'all' });
useEffect(() => {
const fetchIncomes = async () => {
try {
const incomeDocID = await getMoneyIncomeDBData();
const income = incomeDocID.map(({ docId, data }) => ({ ...data, docId }));
setIncomes(income);
} catch (error) {
console.error("Error fetching income: ", error);
}
68
};
const fetchExpenses = async () => {
try {
const expensesDocID = await getMoneyExpenseDBData();
const expenses = expensesDocID.map(({ docId, data }) => ({ ...data, docId })); //
Отримання даних без ID
setExpenses(expenses);
} catch (error) {
console.error("Error fetching expenses: ", error);
}
};
fetchIncomes();
fetchExpenses();
}, []);
const addIncome = async (income) => {
const docId = await SetIncomeDBData(income);
setIncomes([...incomes, { ...income, docId }]);
};
const addExpense = async (expense) => {
const docId = await SetExpenseDBData(expense);
setExpenses([...expenses, { ...expense, docId }]);
69
};
const handleSliderChange = (value) => {
setSliderValue(value);
};
const handleWithdraw = () => {
const updatedIncomes = incomes.map(income => ({
...income,
sliderValue: 0
}));
setIncomes(updatedIncomes);
};
const handleDateChange = (year, month, day) => {
if (year === 'за весь час') {
setFilter({ type: 'all' });
} else if (month && day) {
setFilter({ type: 'day', year, month, day });
} else if (month) {
setFilter({ type: 'month', year, month });
} else {
setFilter({ type: 'year', year });
70
}
};
const filteredIncomes = incomes.filter(income => {
if (filter.type === 'all') return true;
const incomeDate = new Date(income.date);
if (filter.type === 'year') {
return incomeDate.getFullYear() === filter.year;
}
if (filter.type === 'month') {
return incomeDate.getFullYear() === filter.year && (incomeDate.getMonth() + 1) ===
filter.month;
}
if (filter.type === 'day') {
return incomeDate.getFullYear() === filter.year && (incomeDate.getMonth() + 1) ===
filter.month && incomeDate.getDate() === filter.day;
}
return true;
});
const filteredIncomeTypeAmounts = filteredIncomes.reduce((acc, curr) => {
acc[curr.type] = (acc[curr.type] || 0) + curr.amount;
return acc;
71
}, {});
const filteredExpenses = expenses.filter(expense => {
if (filter.type === 'all') return true;
const expenseDate = new Date(expense.date);
if (filter.type === 'year') {
return expenseDate.getFullYear() === filter.year;
}
if (filter.type === 'month') {
return expenseDate.getFullYear() === filter.year && (expenseDate.getMonth() + 1) ===
filter.month;
}
if (filter.type === 'day') {
return expenseDate.getFullYear() === filter.year && (expenseDate.getMonth() + 1) ===
filter.month && expenseDate.getDate() === filter.day;
}
return true;
});
const filteredExpenseTypeAmounts = filteredExpenses.reduce((acc, curr) => {
acc[curr.type] = (acc[curr.type] || 0) + curr.amount;
return acc;
}, {});
72
const deleteExpense = async (expenseId) => {
await deleteExpenseDBData(expenseId);
const updatedExpenses = await getMoneyExpenseDBData();
const updatedExpensesData = updatedExpenses.map(({ docId, data }) => ({ ...data, docId
}));
setExpenses(updatedExpensesData);
};
const deleteIncome = async (incomeId) => {
await deleteIncomeDBData(incomeId);
const updatedIncome = await getMoneyIncomeDBData();
const updatedIncomeData = updatedIncome.map(({ docId, data }) => ({ ...data, docId
}));
setIncomes(updatedIncomeData);
};
const balanceIncome = filteredIncomes.reduce((acc, curr) => acc + curr.amount * ((100 -
curr.sliderValue) / 100).toFixed(2), 0);
const totalExpenses = filteredExpenses.reduce((acc, curr) => acc + curr.amount, 0);
const totalIncome = filteredIncomes.reduce((acc, curr) => acc + curr.amount, 0);
const savings = filteredIncomes.reduce((acc, curr) => acc + (curr.amount *
curr.sliderValue / 100), 0);
return (
<div>
73
<Header onDateChange={handleDateChange} />
<Balance
totalIncome={totalIncome}
totalExpenses={totalExpenses}
balanceIncome={balanceIncome}
savings={savings}
onWithdraw={handleWithdraw}
/>
<div className="container">
<div className="left-column">
<h2>Додати дохід</h2>
<div className="form-container-left">
<IncomeForm addIncome={addIncome} sliderValue={sliderValue}
onSliderChange={handleSliderChange} />
</div>
<h2>Додати витрати</h2>
<div className="form-container-left">
<ExpenseForm addExpense={addExpense} />
</div>
</div>
<div className="center-column">
74
<h2>Список доходів</h2>
<div className="list-container income-list-container">
<IncomeList incomes={filteredIncomes} onDelete={deleteIncome}/>
</div>
<h2>Список витрат</h2>
<div className="list-container income-list-container">
<ExpenseList expenses={filteredExpenses} onDelete={deleteExpense} />
</div>
</div>
<div className="right-column">
<h2>Діаграми</h2>
<div className="form-container">
<div style={{ width: '300px', height: '300px' }}>
<Pie
data={{
labels: Object.keys(filteredIncomeTypeAmounts),
datasets: [
{
label: "Income",
data: Object.values(filteredIncomes.reduce((acc, curr) =>
75
{
acc[curr.type] = (acc[curr.type] || 0) + curr.amount;
return acc;
}, {})),
backgroundColor: doughnutColors,
},
],
}}
/>
</div>
<div style={{ width: '300px', height: '300px' }}>
<Pie
data={{
labels: Object.keys(filteredExpenseTypeAmounts),
datasets: [
{
label: "Expense",
data: Object.values(filteredExpenses.reduce((acc, curr) => {
acc[curr.type] = (acc[curr.type] || 0) + curr.amount;
return acc;
76
}, {})),
backgroundColor: doughnutColors,
},
],
}}
/>
</div>
</div>
</div>
</div>
</div>
);
}
function App() {
const { user, loading, login } = useAuth() || {};
if (loading) {
return (
<div className="login-page">
<div className="login-loader">Завантаження...</div>
</div>
77
);
}
if (!user) {
return (
<main className="login-page">
<section className="login-panel" aria-label="Сторінка входу">
<div className="login-brand">
<div className="login-logo">UAH</div>
<span>Money Tracker</span>
</div>
<div className="login-copy">
<p className="login-eyebrow">Особисті фінанси</p>
<h1>Контролюй доходи, витрати й заощадження в одному місці</h1>
<p>
Увійди через Google, щоб синхронізувати записи та бачити свою фінансову картину
після кожного входу.
</p>
</div>
<button className="google-login-button" onClick={login}>
<span className="google-mark" aria-hidden="true">G</span>
Увійти через Google
78
</button>
</section>
</main>
);
}
return <AppContent />;
}
export default function AppWithAuthProvider() {
return (
<AuthProvider>
<App />
</AuthProvider>
);
}
79
ДОДАТОК Е
Текст програми компонента Month.js
import React, { useState, useEffect } from 'react';
import '../css/MonthGrid.css';
const months = ['січ', 'лют', 'бер', 'кві', 'тра', 'чер', 'лип', 'сер', 'вер', 'жов', 'лис', 'груд'];
export default function MonthGrid({ onDateChange }) {
const [year, setYear] = useState(2024);
const currentDate = new Date();
const currentMonthIndex = currentDate.getMonth();
const [selectedMonth, setSelectedMonth] = useState(-1);
const [selectedDay, setSelectedDay] = useState(null);
const [showAllTime, setShowAllTime] = useState('за весь час');
const [viewMode, setViewMode] = useState('months');
const [lastDayClickTime, setLastDayClickTime] = useState(null);
const [lastMonthClickTime, setLastMonthClickTime] = useState(null);
const [isAllTimeActive, setIsAllTimeActive] = useState(true);
useEffect(() => {
if (showAllTime || isAllTimeActive) {
onDateChange('за весь час');
} else {
onDateChange(year, selectedMonth + 1, selectedDay);
80
}
}, [year, selectedMonth, selectedDay, showAllTime, isAllTimeActive]);
const incrementYear = () => {
if (!showAllTime && !isAllTimeActive) {
setYear(prevYear => prevYear + 1);
}
};
const decrementYear = () => {
if (!showAllTime && !isAllTimeActive) {
setYear(prevYear => prevYear - 1);
}
};
const handleShowAllTime = () => {
setShowAllTime(true);
setSelectedMonth(-1);
setViewMode('months');
setIsAllTimeActive(true);
};
const handleMonthClick = (index) => {
const currentTime = new Date().getTime();
81
if (index === selectedMonth && currentTime - lastMonthClickTime < 300) {
setShowAllTime(false);
setViewMode('days');
} else {
setSelectedMonth(index);
setShowAllTime(false);
setViewMode('months');
setSelectedDay(null);
setIsAllTimeActive(false);
}
setLastMonthClickTime(currentTime);
};
const handleDayClick = (day) => {
const currentTime = new Date().getTime();
if (day === selectedDay && currentTime - lastDayClickTime < 300) {
setViewMode('months');
} else {
setSelectedDay(day);
}
setLastDayClickTime(currentTime);
82
};
const getDaysInMonth = (year, month) => {
return new Date(year, month + 1, 0).getDate();
};
const formatDate = () => {
if (showAllTime || year === 'за весь час') {
return 'За весь час';
} else if (selectedDay != null) {
return `${year}-${selectedMonth + 1 > 9 ? selectedMonth + 1 : '0' + (selectedMonth +
1)}-${selectedDay > 9 ? selectedDay : '0' + selectedDay}`;
} else {
return `${year}-${selectedMonth + 1 > 9 ? selectedMonth + 1 : '0' + (selectedMonth +
1)}`;
}
};
return (
<div className="year-month-container">
<div className="year-selector">
{viewMode !== 'year' && (<button onClick={decrementYear}
className="year-button">⬇</button>)}
{viewMode !== 'year' && (
83
<span className="year-display">
{year} р.
</span>
)}
{viewMode !== 'year' && (<button onClick={incrementYear}
className="year-button">⬆</button>)}
{viewMode !== 'year' && (
<button onClick={handleShowAllTime} className={`show-all-time-button
${showAllTime || isAllTimeActive ? 'selected' : ''}`}>
За весь час
</button>
)}
{/* {viewMode === 'year' && (
<span className="year-display">
{formatDate()}
</span>
)} */}
{viewMode === 'year' && (
<button onClick={() => setViewMode('months')} className="year-button">↓
Розгорнути</button>
)}
84
{viewMode === 'months' && (
<button onClick={() => setViewMode('year')} className="year-button">↑
Згорнути</button>
)}
{viewMode === 'days' && (
<button onClick={() => setViewMode('year')} className="year-button">↑
Згорнути</button>
)}
</div>
<div className="month-grid">
{viewMode === 'months' && months.map((month, index) => (
<button
key={index}
className={`month-button ${index === selectedMonth ? 'selected' : ''}`}
onClick={() => handleMonthClick(index)}
>
{month}
</button>
))}
{viewMode === 'days' && (
85
Array.from({ length: getDaysInMonth(year, selectedMonth) }, (_, i) => i + 1).map(day
=> (
<button
key={day}
className={`day-button ${day === selectedDay ? 'selected' : ''}`}
onClick={() => handleDayClick(day)}
>
{day}
</button>
))
)}
</div>
</div>
);
}
86
ДОДАТОК Є
Інструкція користувача
1. Відкрити вебдодаток у браузері.
2. Натиснути кнопку входу через Google-акаунт.
3. Після авторизації перейти до головної сторінки додатку.
4. Для додавання доходу заповнити форму “Додати дохід”: вказати суму,
категорію та дату, після чого натиснути кнопку додавання.
5. Для додавання витрати заповнити форму “Додати витрати”: вказати суму,
категорію та дату, після чого натиснути кнопку додавання.
6. Для перегляду фінансових записів використати списки доходів і витрат у
центральній частині сторінки.
7. Для фільтрації даних обрати потрібний період: рік, місяць, день або режим
“за весь час”.
8. Для видалення помилково внесеного запису натиснути кнопку видалення біля
відповідного доходу або витрати.
9. Для аналізу фінансової інформації переглянути блок балансу та діаграми
доходів і витрат.
10. Для перегляду валютних курсів скористатися відповідним блоком у
вебдодатку.
87