Sunteți pe pagina 1din 123

UNIVERSITATEA BUCUREȘTI

FACULTATEA DE INFORMATICĂ

LUCRARE DE LICENȚĂ

Aplicație pentru calcularea independenței financiare

Application for calculating financial independence

Coordonator științific: Absolvent:

Prof. dr. Florentin Ipate Avram Adrian-Constantin

2021
DECLARAȚIE PRIVIND ORIGINALITATEA ȘI RESPECTAREA

DREPTURILOR DE AUTOR

Prin prezenta, declar că Lucrarea de licență cu titlul ”Aplicație pentru calcularea


independenței financiare ” este scrisă de mine și nu a mai fost prezentată niciodată la o altă facultate
sau instituție de învatamânt superior din țară sau străinătate. De asemenea, declar că toate resursele
utilizate, inclusiv cele preluate de pe Internet, sunt indicate în lucrare, cu respectarea regulilor de
evitare a plagiatului:

∑ toate fragmentele reproduse exact sunt scrise între ghilimele și dețin referința
precisă a sursei;

∑ reformularea în cuvinte proprii a textelor scrise de către alți autori deține referința
precisă;

∑ codul sursă, imaginile, etc. preluate din proiecte open-source sau alte surse sunt
utilizate cu respectarea drepturilor de autor și dețin referințe precise;

∑ rezumarea ideilor altor autori precizează referința precisă la textul original.

Absolvent Avram Adrian-Constantin

___________________________
Rezumat
Educația stă la baza unei societăți sănătoase. Educația ne influențează viețile, comunitățile
și implicit, viitorul. Astfel, e important să dezvoltăm toate ramurile educației pentru o înflorire
grandioasă a viitoarelor generații.

Din nefericire, educația financiară a fost și încă este un subiect școlar neabordat în
majoritatea țărilor europene, inclusiv în România; iar acest lucru va avea un impact negativ asupra
generațiilor viitoare și asupra modului lor de a-și gestiona veniturile. Neexpunerea în mediului de
finanțe va afecta semnificativ felul în care un cetățean va interacționa cu sistemul bancar sau
mijloacele de contact cu instituțiile de investiții.

Aplicația pentru calcularea independenței financiare ofera oportunitatea celor dornici să


intre în contact cu domeniul financiar, un program interactiv cu toate funcționalitățile necesare unui
prim-contact cu domeniul de finanțe. Aplicația poate fi descarcată de pe Google Play pe telefonul
sau tableta personală, care rulează pe sistemul de operare android.

Utilizatorul are posibilitatea să-și fructifice cunoștiințele din domeniul financiar, prin
accesarea notificărilor pe care le va primi. De regulă, notificările îl vor redirecționa pe utilizator în
aplicație, într-o fereastră ce va conține o pagina a unui site de știri, cuprinzând informații importante
și de actualitate asupra unor evenimente ce au avut un impact economic; sau a unor blog-uri
interesante de unde utilizatorul să-și poată imbogăți cunoștiințele din domeniul de finanțe. De
asemenea, utilizatorul are posibilitatea să-și testeze cunoștiințele dobândite și prin intermediul
aplicației, acesta având posiblitatea de a-și efectua analize tehnice cu ajutorul graficelor puse la
dispoziție de către funcționalitățile programului, în urma cărora să-și efectueze predicții asupra
evoluției prețului unei acțiuni sau indice bursier; și să-și investească inteligent veniturile, în urma
analizelor făcute, într-o sursă de venit pe termen lung, prin intermediul functionalității prezente în
aceeastă pagină. Pe parcursul acestui proces îndelungat, utilizatorul va avea posibilitatea de a creea
notițe în legătură cu stadiul și evoluția unor analize economice făcute.

Pentru o gestionare cât mai bună a veniturilor, utilizatorului îi este oferită opțiunea de
limitator al cheltuielilor, astfel încât clientul aplicației să nu poată efectua tranzacții ce depășesc
suma limită stabilită de acesta, ori de cea stabilită prin intermediul aplicației; care prezice o sumă
limită convenabilă pentru salariul și veniturile sale bancare. In adaos, utilizatorul poate vedea un
grafic cu cheltuielile sale zilnice, pentru a observa fluctuația sumelor cheltuite zilnic.

Aplicația oferă clientului o interacțiune cât mai placută cu acesta, întrucât utilizatorului i se
oferă funcționalitățile de creare sau modificare a profilului și posibilitatea schimbării parolei sau
adresei de e-mail. De asemenea, acesta se poate autentifica prin intermediul platformei sociale
Facebook, preluând astfel anumite informații personale, pentru completarea automată a unor
informații din profilul utilizatorului.
Resume
Education is the foundation of a healthy society. Education influences our lives, our
communities and, implicitly, our future. Thus, it is important to develop all branches of education
for a grand flourishing of future generations.

Unfortunately, financial education has been and still is an unaddressed school subject in
most European countries, including Romania; and this will have a negative impact on future
generations, on their way of managing their income. Non-exposure in the financial environment
will significantly affect the way a citizen will interact with the banking system or the means of
contact with investment institutions.

The application for calculating financial independence offers the opportunity to those who
want to get in touch with the financial field, an interactive program with all the functionalities
necessary for a first contact with the finance field, which can be downloaded from Google Play on
your personal android tablet or phone.

The user has the possibility to use his knowledge in the financial field, by accessing the
notifications he will receive. Usually, the notifications will redirect the user in the application, in
an application window that will contain a page of a news site, containing important and current
information on some events and how they had an economic impact ; or interesting blogs where the
user can enrich their knowledge in the field of finance. Also, the user has the possibility to test the
acquired knowledge through the application, perform technical analyzes using graphs provided by
the program's functionalities; following which to make predictions about an action or stock market
index and to intelligibly invest, following the analyzes made, the incomes in a long-term income
source, through the functionality present in the same page with the graphs provided by the
application. During this long process, the user is offered the opportunity to create notes about the
stage and evolution of some economic analyzes made.

For a better management of revenues, the user is offered the option of limiting expenses, so
that the client of the application can not make transactions that exceed the limit set by him, or the
one set through the application, which predicts a convenient limit for his salary and bank account.
In addition, the user can see a graph with his daily expenses , to observe the fluctuation of the
amounts spent daily.
The application offers the client a pleasant interaction with him, as the user is offered the
functionalities of creating or modifying the profile and the possibility to change the password or e-
mail address. It can also be authenticated through the social platform Facebook, thus taking over
certain personal information, for the automatic completion of information from the user's profile.
Cuprins
I Introducere ....................................................................................................................................8

I.1 Tema proiectului .....................................................................................................................8


I.2 Ideea și scopul proiectului......................................................................................................8
I.3 Motivație .................................................................................................................................9
I.4 Starea actuală a domeniului și contribuții aduse ...................................................................10
I.5 Structura proiectului..............................................................................................................10
I.6 Structura lucrării....................................................................................................................11
II Preliminarii ................................................................................................................................12

II.1 Contextul proiectului ...........................................................................................................12


II.2 Noțiuni știintifice și tehnologice..........................................................................................12
III Arhitectura aplicației ................................................................................................................20

III.1 Descrierea arhitecturii și modulele funcționale ale sistemului ...........................................20


III.2 Arhitectura clientului..........................................................................................................21
III.2.1 Arhitectura codului React Native.................................................................................21
III.2.2 Arhitectura codului Redux ...........................................................................................23
III.3 Arhitectura server-ului Node.js ..........................................................................................30
III.4 Arhitectura contului de pe platforma Firebase ...................................................................32
IV Detalii de implementare ...........................................................................................................36

IV.1 Detalii de implementare ale codului client.........................................................................36


IV.1.1 Detaliile de implementare ale codului React Native ...................................................36
IV.1.2 Detaliile de implementare ale codului Redux..............................................................77
IV.2 Detalii de implementare a codului server...........................................................................91
IV.2.1 Detaliile de implementare ale codului Node.js............................................................91
V Manual de utilizare ..................................................................................................................104

VI. Concluzii ................................................................................................................................121

VI.1 Realizări............................................................................................................................121
VI.2 Dezvoltări ulterioare.........................................................................................................121
VI.3 Păreri personale ................................................................................................................121
VII Bibliografie ............................................................................................................................123
I Introducere

„Un popor needucat e un popor ușor de manipulat.”


(Imannuel Kant)

I.1 Tema proiectului


În cadrul lucrării de licență, am efectuat studii axate pe definiții, teoreme și demonstrații
ale soft-urilor de tip Fintech. Tema aplicației face referire atât la opțiunile și uneltele financiare
dispuse clientului pentru a accesa serviciile financiare, cât și la ideologiile din cadrul metodologiei
educației financiare. Tema se încadrează în lucrarea de tip aplicație software, întrucât în cadrul
lucrării am combinat caracteristici deja existente în mai multe aplicații ce aparțin de domeniul
fintech. Aplicația este menită să rezolve problema neclarității în cadrul utilizării unei aplicații
software fintech de către un utilizator neexperimentat în acest domeniu.

I.2 Ideea și scopul proiectului


Ideea proiectului este de a realiza o interacțiune strânsă între domeniul financiar și
utilizatori, prin intermediul unei aplicații ce oferă o experiență plăcută la utilizare, care cuprinde
toate funcționalitățile necesare unui începător pentru a-și dezvolta cunoștiințele referitoare în acest
domeniu și de a le pune în practică prin intermediul funcționalităților necesare pentru a putea investi
în acțiuni la bursă. În esență, scopul aplicației este acela de a educa financiar persoanele ce
conștientizează importanța acestui domeniu.

Ca precondiții, se presupune că utilizatorul a implinit vârsta de 14 ani, întrucât


aplicația va face legatură cu datele din card-ul său bancar, pentru a putea efectua tranzacții și
investiții cu ajutorul acestuia.[1]

În cadrul aplicației, utilizatorul va avea acces la toate funcționalitățile elementare pentru a-


și îmbogăți cunoștiințele din domeniul financiar și de a le pune în practică: accesul la grafice
detaliate riguros cu privire la cheltuielile sale zilnice, informații generale cu privire la rația dintre

1
Alpha Bank România SA , https://www.alphabank.ro/Portals/0/PDF/persoane-fizice/economii/alpha-dreams/termeni-si-conditii-
conturi-minori.pdf
cheltuieli și investiții sau cheltuieli și venitul total, înștiințarea utilizatorului asupra prețului actual
al unei acțiuni și fluctuația acestuia; dar și asupra profitului total obținut în cazul achiziționării unui
numar de actiuni. Pentru ca o persoană să poată deveni un utilizator al acestei aplicații, acesta
trebuie să se înregistreze și să se autentifice cu o adresă de e-mail și o parolă. În cadrul programului,
potențialul utilizator are la dispoziție metoda de a se autentifica prin intermediul unui cont recent
creat sau prin intermediul platformei sociale Facebook. După autentificare, utilizatorul va putea
efectua analize tehnice asupra evoluției prețului unei acțiuni, cu ajutorul graficelor expuse acestuia,
dar și prin informațiile atent selecționate de către dezvoltatorul aplicației, ce poate să le trimită
utilizatorului prin intermediul notificărilor, din serviciile de cloud la care are acces dezvoltatorul
aplicației. Pe lângă toate acestea, utilizatorul are la dispoziție o fereastră în care poate să investească
acțiuni la bursă, aplicația fiind conectată la un server al unei burse de valori; dar și o fereastră în
care poate să-și verifice tranzacțiile efectuate sau să-și gestioneze banii din conturile bancare,
programul fiind cuplat și cu un server al bancilor ce configurează pe un anumit card bancar. Pe
lânga toate aceste functionalități oferite în cadrul aplicației, clientul poate, de asemenea, să-și
adauge sau actualizeze datele din profil, precum adresa de e-mail sau salariul actual.

Prin funcționalitațile menționate, consider că audiența țintă a aplicației ( persoanele


incepătoare sau fără nici o cunoștință în domeniul financiar) poate avea o experiență placută în
primul lor pas în domeniul de finanțe, datorită simplității și selecției elementare de unelte financiare
prezente în program.

I.3 Motivație
Înca din liceu am fost pasionat de domeniul financiar, de cum îți poți investi inteligent
veniturile pentru a-ți maximiza profiturile sau de cum să-ți gestionezi salariul pentru a-ți putea
achiziționa dorințele materiale.

De asemenea, îmi doream ca aplicația mea sa aibă o folosință practică, aceasta


reprezentând un program necesar pentru a educa financiar utilizatorii. Astfel, am decis că o
aplicație Fintech ar combina cele doua dorințe ale mele într-un proiect de care să fiu mândru ca l-
am realizat. Mai mult decât atât, pentru realizarea aplicației am folosit tehnologiile pe care doresc
să lucrez în viitor.

9
I.4 Starea actuală a domeniului și contribuții aduse
Industria Fintech este în plin proces de dezvoltare. Din ce în ce mai multe operațiuni
bancare sau servicii financiare se automatizează pentru a oferi clienților, într-un timp util, soluții
la problemele întâmpinate în cadrul operațiunilor bancare și pentru a le furniza acestora o accesare
cât mai facilă a uneltelor financiare.

În prezent, sunt existente numeroase aplicații ce oferă acces la unelte și instrumente


financiare. Însa, pentru un utilizator neexperimentat, aceste aplicații îi pot debusola în utilizarea
acesteia sau în accesarea unui instrument financiar specific. Aplicația dezvoltată de mine are ca
scop îmbunatățirea relației dintre utilizatorii neexperimentați a aplicațiilor Fintech și serviciile
furnizate de instituțiile financiare. Totodată, comparativ cu celelalte aplicații prezente în piață,
programul dezvoltat de mine oferă o experiență lightweight persoanelor aflate în prim contact cu
domeniul fintech, prin numarul limitat și elementare de caracteristici prezente în aplicație, ce ofera
o utilizare ușor de accesat a acesteia, contribuind astfel la digitalizarea serviciilor financiare și la
creșterea audienței dornice pentru accesarea serviciilor financiare prin intermediul digital.

I.5 Structura proiectului


Proiectul a fost structurat în patru module cu functionalități diferite. Cele patru arii sunt:

Interfața clientului pe Android, respectiv IOS; care include toate elementele vizuale prin
care clientul interacționează cu aplicația (ferestre, butoane, liste).

Modulul de procesare a comenzilor date de către utilizator in client.

Modulul de comunicare client-server, care asigură o bună funcționare a aplicației cu


serverul dezvoltat de dezvoltatorii aplicației și cu cel extern (server-ul unei banci/ instituții
financiare).

Modulul de gestionare și actualizare a datelor folosind tehnologia Redux.

10
I.6 Structura lucrării
Capitolele acestei lucrări sunt structurate astfel: contextul și aspecte teoretice ale
proiectului, urmate de tehnologiile folosite la implementarea proiectului, cu detalierea celor
folosite în cadrul dezvoltării aplicației.

Urmează capitolul de explicitare al arhitecturii aplicației, în care sunt prezentate diferitele


module ale aplicației și interacțiunea dintre ele.

Capitolul detaliilor de implementare prezintă metodele de programare folosite, oferind spre


exemplificare porțiuni de cod explicate. În cadrul acestui capitol este descris modul în care un
utilizator se autentifică în aplicație, cum își modifică datele din profil și investește în acțiuni sau
efectuează tranzacții obișnuite. De asemenea, este descris modul în care utilizatorul gestionează
banii din conturile bancare proprii, primește notificări de la staff-ul aplicației și își scrie sau editează
notițe cu privire la informațiile esențiale și extrase din comunicatele primite prin intermediul
notificărilor. În adaos, sunt explicitate informațiile pe care clientul le primește, în timp real, asupra
sumelor din conturile sale bancare, totalul sumelor investite, fluctuația unei acțiuni și marja de
profit / pierdere în urmă investițiilor pentru o acțiune; precum și volumul de acțiuni deținut pentru
un anumit tip de indice bursier. Pe lângă toate acestea, sunt prezentate procesele în care atât server-
ul aplicației din Firebase, cât și server-ul dezvoltat în Node.js, prelucrează informațiile primite de
la client și returnează un răspuns.

În final, capitolul de utilizare al aplicației prezintă în detaliu aplicația și modalitatea de


utilizare al acesteia, prin secreenshot-uri și exempificari asupra capturilor de ecran atașate.

11
II Preliminarii
II.1 Contextul proiectului
Domeniul de finanțe poate părea un domeniu mult prea greu de înțeles pentru
anumite persoane, iar lipsa unei aplicații ușor de folosit care să-ți ofere o experiență plăcută la
utilizare poate conduce la lipsa sau pierderea de interes față de educația financiară.

Prin intermediul aplicației mele, doresc să contribui la educarea financiară a


populației prin accesul la informație, din interiorul aplicației; dar și prin aplicarea practică a
informațiilor dobândite, cu ajutorul uneltelor de investiții și gestionarea a veniturilor, prezente în
program.

II.2 Noțiuni știintifice și tehnologice


În cadrul studiului pentru lucrarea de licență, am analizat caracteristicile și uneltele necesare
pentru că un utilizator neexperimentat să aibă o experiență cât mai plăcută în cadrul utilizării
aplicației .

Tehnologia financiară (Fintech) este utilizată pentru a descrie tehnologia nouă care
urmărește îmbunătățirea și automatizarea livrării și utilizării serviciilor financiare. În esență,
fintech este utilizat pentru a ajută companiile, proprietarii de afaceri și consumatorii să își
gestioneze mai bine operațiunile financiare, procesele și viață, utilizând software specializat și
algoritmi care sunt utilizați pe computere și, din ce în ce mai mult, pe smartphone-uri. Fintech,
cuvântul, este o combinație de „tehnologie financiară”.

Când a apărut fintech-ul în secolul 21, termenul a fost inițial aplicat tehnologiei utilizate în
sistemele back-end ale instituțiilor financiare stabilite. De atunci, însă, a existat o trecere la servicii
mai mult orientate către consumator și, prin urmare, la o definiție mai orientată către consumator.
Fintech include acum diferite sectoare și industrii, cum ar fi educația, serviciile bancare cu
amănuntul, strângerea de fonduri și organizațiile nonprofit și managementul investițiilor.

Fintech descrie acum o varietate de activități financiare, cum ar fi transferuri de bani,


depunerea unui cec cu smartphone-ul persoanei, ocolirea unei sucursale bancare pentru a solicita
12
credit, strângerea de bani pentru înființarea unei afaceri sau gestionarea investițiilor; în general,
fără asistența unei persoane. Conform Indexului de adoptare Fintech din 2017 al EY, o treime din
consumatori utilizează cel puțin două sau mai multe servicii fintech, iar acei consumatori sunt tot
mai conștienți de fintech ca parte a vieții lor de zi cu zi.

Fintech include, de asemenea, dezvoltarea și utilizarea criptomonedelor, cum ar fi bitcoin.


În timp ce acel segment de fintech poate vedea cele mai multe titluri, banii mari se află în continuare
în industria bancară tradițională globală și în capitalizarea sa de piață de mai multe miliarde de
dolari.[2]

Numărul de aplicații mobile descărcate la nivel global a crescut de la 140 de milioane în


2016 la 220 de milioane în 2021 și se prevede ca această creștere să continue și în următorii ani.[3]
Cum aplicațiile mobile sunt din ce în ce mai cerute, m-am gândit să dezvolt o aplicație mobilă,
întrucât ar putea fii mult mai accesată decât o aplicație web. De asemenea, m-am gândit să folosesc
un framework hibrid, compatibil cu sistemele de operare Android și IOS pentru a reduce timpul de
lucru și costurile necesare în cazul dezvoltării separate a unei aplicații Android Nativ și IOS Nativ.
Am dorit ca aplicația mea să actualizeze informațiile în timp real cu privire la evoluția unui indice
bursier, profitul sau pierderile obținute și soldul din contul său bancar, pentru că utilizatorul să fie
la curent cu orice fluctuație apărută asupra prețului unei acțiuni. În urmă unei cercetări făcute pentru
a găsi un cadru de lucru potrivit că să-mi îndeplinească toate cerințele, am constatat că framework-
ul React Native și Flutter ar fi cele mai potrivite pentru aplicația pe care vreau să o dezvolt. Cum
eram deja familiar cu limbajul de programare Javascript[4], am decis să lucrez folosind framework-
ul React Native, deoarece acest cadru de lucru este compatibil cu JS. În urmă unei cercetări mai
amănunțite asupra acestui cadru de lucru, am constatat că ar fii mult mai optim, din punct de vedere
al timpului de lucru, să lucrez în Expo (un lanț de instrumente construit în jurul React Native pentru
a ajută dezvoltatorul să pornească mai rapid o aplicație).[5]

React Native este un cadru de aplicații mobile open-source creat de Facebook, Inc. Este
folosit pentru a dezvoltă aplicații pentru Android, Android TV, iOS, macOS, tvOS,

2
Julia Kagan, Financial Technology – Fintech, https://www.investopedia.com/terms/f/fintech.asp
3
Statista Research Department, https://www.statista.com/statistics/271644/worldwide-free-and-paid-mobile-app-store-downloads/
4
Javascript, https://www.javascript.com/
5
Expo, https://docs.expo.io/

13
Web, Windows și UWP, permițând dezvoltatorilor să utilizeze cadrul React împreună cu
capabilitățile platformei native.

În 2012, Mark Zuckerberg a comentat: „Cea mai mare greșeală pe care am făcut-o în calitate
de companie a fost să pariez prea mult pe HTML decât pe nativ”. Utilizarea HTML5 pentru
versiunea mobilă a Facebook a dus la o aplicație instabilă care a preluat datele încet. El a promis
că Facebook va oferi în curând o experiență mobilă mai bună.

În interiorul Facebook, Jordan Walke a găsit o modalitate de a genera elemente de interfață


pentru iOS dintr-un fir JavaScript de fundal, care a devenit baza pentru cadrul web React. Au decis
să organizeze un Hackathon intern pentru a perfecționa acest prototip și pentru a putea construi
aplicații native cu această tehnologie.

După luni de dezvoltare, Facebook a lansat prima versiune pentru configurația React
JavaScript în 2015. În timpul unei discuții tehnice, Christopher Chedeau a explicat că Facebook
folosea deja React Native în producție pentru aplicația de grup și aplicația lor pentru managerul de
anunțuri.

React Native combină cele mai bune parți ale dezvoltării native cu React, cea mai bună
librărie javascript pentru construirea interfețelor utilizator.

Primitivele React redau la interfața de utilizare a platformei native, ceea ce înseamnă că


aplicația folosește aceleași API-uri de platforma nativă pe care le fac alte aplicații.

Dezvoltatorii pot să creeze versiuni de componente specifice platformei, astfel încât o


singură bază de cod să poată partaja codul între platforme. Cu React Native, o echipă poate întreține
două platforme și poate împărtăși o tehnologie comună - React.

De asemenea, React Native oferă un set de bază de componente native agnostice ale
platformei, cum ar fi View, Text și Image, care se mapează direct la blocurile de construcție UI
native ale platformei.

În 2018, React Native a avut al doilea cel mai mare număr de colaboratori pentru orice
depozit din GitHub. Astăzi, React Native este susținut de contribuții de la persoane fizice și
companii din întreaga lume, inclusiv Callstack, Expo, Infinite Red, Microsoft și Software Mansion.

14
Comunitatea livrează întotdeauna noi proiecte interesante și explorează platforme dincolo
de Android și iOS cu repo-uri precum React Native Windows, React Native macOS și React Native
Web. [6]

Expo este un cadru și o platformă pentru aplicații universale React. Reprezintă un set de
instrumente și servicii construite în jurul platformelor native și native React care ajută la
dezvoltarea, construirea, implementarea și iterarea rapidă pe iOS, Android și aplicații web din
aceeași baza de cod JavaScript / TypeScript.[5]

În cadrul proiectului de licență, am utilizat cele două abordări ale construirii aplicațiilor cu
instrumentele Expo. Acestea sunt numite fluxuri de lucru „managed” și „bare”.

Un dezvoltator care folosește fluxul de lucru gestionat nu folosește Xcode sau Android
Studio, ci doar scrie cod JavaScript și gestionează configurația pentru lucruri precum pictograma
aplicației și ecranul splash prin app.json. SDK-ul Expo, expune un set din ce în ce mai cuprinzător
de API-uri care oferă puterea de a accesa capabilitățile dispozitivului precum camera, autentificarea
biometrică, sistemul de fișiere, haptica și așa mai departe.

În fluxul de lucru bare dezvoltatorul are control complet, împreuna cu complexitatea care
vine cu aceasta. Se poate utiliza majoritatea API-urilor în SDK Expo, dar serviciul de construire și
configurarea ușoară cu app.json / app.config.js nu sunt încă acceptate.[ 7]

Pe partea de server, am integrat două servere la două adrese diferite. Motivul pentru care
am folosit două servere este bine întemeiat: un server este responsabil cu menținerea integrității
datelor utilizatorilor, informațiile acestuia fiind stocate în server-ul de cloud al platformei Firebase.
Al doilea server folosit este construit și dezvoltat în Node.js. Acesta se prezintă că fiind server-ul
băncii sau instituției financiare, fiind cuplat cu serviciile aplicației. Este de înțeles faptul că o
aplicație ce dispune de o platforma de tranzacționare ce comunică cu un server al unei instituții
financiare pentru a afla prețul actual al unei acțiuni sau indice bursier, întrucât o aplicație privată
nu poate decide prețul actual al unei acțiuni. Programul comunică cu un server pentru a extrage
informațiile actuale asupra prețului unei acțiuni. De asemenea, o aplicație Fintech nu poate să

6
Wikipedia, https://en.wikipedia.org/wiki/React_Native
7
Expo, https://docs.expo.io/introduction/managed-vs-bare/

15
tranzacționeze în interiorul serverelor sale, ci face conexiunea cu serverele unei burse de
valori, pentru a efectua un contract de vânzare sau cumpărare al unui indice bursier.

Firebase este o platforma dezvoltată de Google pentru crearea de aplicații mobile și web. A
fost inițial o companie independența fondată în 2011. În 2014, Google a achiziționat platforma și
este acum oferta lor emblematică pentru dezvoltarea aplicațiilor.

Realtime Database este o bază de date flexibilă și scalabila pentru dezvoltarea de


dispozitive mobile, web și de server de la Firebase și Google Cloud. Aceasta menține datele
sincronizate în aplicațiile clientului prin ascultători în timp real și oferă suport offline pentru mobil
și web, astfel încât dezvoltatorul să poată crea aplicații receptive care funcționează indiferent de
latența rețelei sau de conectivitatea la Internet.

Baza de date Firebase Realtime este o bază de date găzduită în cloud. Datele sunt stocate
că JSON și sincronizate în timp real cu fiecare client conectat, cu suport multiplatforma pentru iOS,
Android, Web și multe altele.[8]

Node.js este un mediu de execuție JavaScript de tip back-end open-source, cross-platform,


care rulează pe motorul V8 și execută cod JavaScript în afară unui browser web. Node.js permite
dezvoltatorilor să folosească JavaScript pentru a scrie instrumente de linie de comandă și pentru
scripturi de pe server- rularea de scripturi de pe server pentru a produce conținut dinamic al
aplicației înainte ca fereastra să fie trimisă în aplicația utilizatorului. În consecință, Node.js
reprezintă o paradigmă, unificând dezvoltarea aplicațiilor în jurul unui singur limbaj de
programare, mai degrabă decât a unor limbaje diferite pentru scripturile de pe partea de server și
partea de client.

Deși .js este extensia standard a numelui de fișier pentru codul JavaScript, numele
„Node.js” nu se referă la un anumit fișier în acest, ci este doar numele produsului. Node.js are o
arhitectură bazată pe evenimente capabile de I / O asincrone. Aceste opțiuni de proiectare vizează
optimizarea randamentului și scalabilitatii în aplicațiile cu multe operații de intrare/ieșire, precum
și pentru aplicațiile în timp real (de exemplu, programe de comunicare în timp real și jocuri de
browser).

8
Firebase, https://firebase.google.com/

16
Proiectul de dezvoltare distribuită Node.js a fost anterior guvernat de Fundația Node.js, și
a fuzionat acum cu Fundația JS pentru a formă Fundația OpenJS, care este facilitată de programul
de proiecte colaborative al Fundației Linux.

Utilizatorii corporativi ai software-ului Node.js includ GoDaddy, Groupon, IBM, LinkedIn,


Microsoft, Netflix, PayPal, Rakuten, SAP, Voxer, Walmart, Yahoo!, și Amazon Web Services.[9]

De asemenea, am dorit să mențin integritatea și managementul bun al datelor în cadrul


aplicației. După cercetări efectuate pentru a găsi un mod inteligibil de a gestiona datele din
aplicație, am constat că tehnologia Redux e cea mai potrivită pentru administrarea aplicației.

Redux este un container de stare previzibil pentru aplicațiile JavaScript.

Tehnologia Redux la scrierea de aplicații se comportă constant, rulează în medii diferite


(client, server și nativ) și sunt ușor de testat. În plus, oferă o experiență excelentă pentru
dezvoltatori, cum ar fi editarea codurilor live combinată cu un depanator de călătorie în timp.

Redux se poate utiliza împreună cu React sau cu orice altă bibliotecă de vizualizare. Este
mic (2 KB, inclusiv dependențe), dar are un ecosistem mare de suplimente disponibile.[10]

Redux Thunk middleware îmi permite să scriu creatori de acțiuni care returnează o funcție
în loc de o acțiune. Thunk-ul poate fi folosit pentru a întârzia expedierea unei acțiuni sau pentru a
expedia numai dacă este o anumită condiție. Funcția interioară primește metodele magazinului
dispatch și getState ca parametri.

Orice valoare returnată din funcția interioară va fi disponibilă ca valoare returnată a


expedierii în sine. Acest lucru este convenabil pentru orchestrarea unui flux de control asincron cu
creatorii de acțiune care se expediază reciproc și returnează promise-urile, ce se vor aștepta pentru
finalizarea reciprocă.[11]

Pentru comunicarea dintre client și server, am folosit tehnologia Axios, un client HTTP
bazat pe promisiuni pentru node.js și browser. Este izomorf (i.e. poate rula în browser și node.js cu

Wikipedia, Node.js, https://en.wikipedia.org/wiki/Node.js


9

10
Redux, Getting Started with Redux, https://redux.js.org/introduction/getting-started
11
Redux Thunk , https://www.npmjs.com/package/redux-thunk

17
aceeași bază de cod). Pe partea de server folosește modulul nativ http node.js, în timp ce pe client
folosește XMLHttpRequest. [12]

Din mai multe articole științifice studiate am preluat și analizat informații despre cum se
pot satisface toate necesitățile utilizatorului. Luând în calcul că audiența țintă este formată din
persoanele neexperimentate în domeniul Fintech, am preluat structura unui program ce îi oferă unui
utilizator o accesare cât mai facilă a aplicației.

Conform unui studiu elaborat în cadrul unui blog, publicat pe site-ul medium [13], design-
ul visual lasă o prima impresie crucială asupra vizitatorului. Un desing simplist, format inteligibil,
poate pune amprenta asupra părerii personale a utilizatorului asupra aplicației pe care o folosește.
Prima impresie e decisivă pentru utilizator, cu privire la dorința acestuia de a continuă utilizarea
acesteia sau de a o dezinstala din memoria telefonului. De asemenea, nuanțele de culori prezente
în aplicație joacă un rol psihologic important, întrucât utilizarea unui număr excesiv de culori în
cadrul aplicației poate avea un impact psihologic negativ asupra utilizatorului.

Conform unui alt studiu publicat de un important site financiar [14], utilizatorul începător
al unei aplicații Fintech trebuie să aibă un acces facil asupra instrumentelor prezente în aplicație,
întrucât abundență acestora îl pot obosi pe utilizatorul neexperimentat. Utilizatorul începător
trebuie să aibă acces la știri atent selecționate cu privire la evenimentele recente și de importanță
economică petrecute la nivel local sau global; precum și accesul la informații de actualitate cu
privire la noi reglementări din cadrul politicilor de funcționare al băncilor și instituțiilor financiare.
De asemenea, clientul ar trebui să aibă acces la informații legate de statusul conturilor sale bancare,
sumele și investițiile efectuate pe o perioada de timp aleasă de acesta. Pentru accesul și investiția
în acțiuni în cadrul unei burse de valori, utilizatorul începător nu trebuie să aibă o fereastră
supraîncărcată, întrucât îi poate afecta gândirea și decizia critică în cazul efectuării unor investiții
pe bursă. Limitarea la niște indicatori standard precum prețul actual al unei acțiuni, volumul de
acțiuni tranzacționat pentru un specific tip de stock, profitul și pierderile din urmă investițiilor
pentru un anumit indice bursier și redarea fluctuatiei prețului unei acțiuni sunt suficienți pentru un
utilizator aflat la început de drum în domeniul finanțelor. Astfel, balanța dintre starea emoțională

Axios, https://axios-http.com/docs/intro
12
13
Shanuj Mishra, Pleasant UX – Central to all conversions, https://medium.com/@shanuj1611/ux-key-to-digital-marketing-success-d1ace6b3829
14
Adam Fard, Fintech UX Design Trends in 2021, https://adamfard.com/blog/fintech-ux-trends

18
și muncă efectuată pentru a lua o decizie critică rămâne echilibrată. Este fundamental în domeniul
finanțelor luarea unei decizii neutre din punct de vedere emoțional.

19
III Arhitectura aplicației
III.1 Descrierea arhitecturii și modulele funcționale ale sistemului
În acest capitol voi evidenția arhitectura aplicației, ce se găsește pe Google Play sub
denumirea „Fintech Go”; prin detalierea principalelor module ale aplicației, precum și modul de
comunicare al acestora.

În ceea ce privește arhitectura aplicației, aceasta este de tip client-server, luând


modelul de referință OSI, în care primul participant este reprezentat de aplicația client și anume
aplicația React Native, iar cel de-al doilea este serverul localizat pe cloud în Firebase sau serverul
dezvoltat în Node.js. Stocarea datelor importante se face în baza de date a platformei Firebase,
Realtime Database, iar cele nesemnificative în memoria telefonului, folosind SQLite. Informațiile
externe, cu privire la evoluția piețelor de acțiuni, se stochează prin intermediul serverului Node.js
și tehnologiei pentru maparea datelor mongoose [15], într-o baza de date MongoDB.[16]

Managementul datelor în aplicație se realizează folosindu-se tehnologia Redux, oferind


programatorului un mediu facil de lucru.

Figura III.1 Arhitectura globală a sistemului

15
Mongoose, https://mongoosejs.com/
16
MongoDb, https://www.mongodb.com/

20
III.2 Arhitectura clientului
III.2.1 Arhitectura codului React Native
React Native oferă propriul strat de abstracție UI pe platformele iOS și Android. Componentele
React Native invocă vizualizările native, astfel încât dezvoltatorul să poată scrie interfață de
utilizare a aplicației smartphone cu JavaScript, în loc de Kotlin / Java sau Swift / Objective-C.

Această tehnologie este formată din patru secțiuni:

∑ Codul React pe care dezvoltatorul îl scrie.


∑ JavaScript care în cele din urmă este interpretat din codul pe care dezvoltatorul
l-a scris.
∑ Serie de elemente care sunt cunoscute sub numele de Bridge în mod colectiv.
∑ Latura nativă.

Figura III.2 Secțiunile principale ale cadrului de lucru React Native[17]

Aplicația React Native dezvoltată de mine este împachetată într-un container Redux, ce
deține întregul arbore de definire al aplicației.

Arhitectură clientului este reprezentată de un arbore, având la bază o componentă


funcțională ce se regăsește în codul aplicației sub denumirea de „AppNavigator”. Această
componentă este rădăcina aplicației și are trei ramuri care conduc spre trei navigatoare:
AuthNavigator, FinanceNavigator și StartupScreen.

17
Rahul Dubey, React Native Architecture, https://www.educba.com/react-native-architecture/

21
La rândul lor, fiecare container conține alte rute, reprezentând navigatori în cadrul
aplicației. În momentul deschiderii aplicației, execuția intră în cadrul componentei StartupScreen,
unde se încearcă logarea automată prin intermediul comunicării cu server-ul aflat în cloud-ul
platformei Firebase. Acest moment este decisiv pentru următoarea randare a codului, întrucât
programul determină pe care dintre cele două containere rămase (AuthNavigator și
FinanceNavigator) să îl parcurgă.

În cazul unei logări automate eșuate, execuția programului va ajunge în container-ul


AuthNavigator, urmând ca utilizatorul să se autentifice pentru a accesa serviciile dispuse de
aplicație (acestea aflându-se în interiorul containerului FinanceNavigator). Componenta
funcțională este formată la rândul ei din alte trei componente funcționale, ce redirecționează
utilizatorul către o fereastră specifică. Acestea se regăsesc în codul aplicației sub denumirea de
„Login”, „Register” și „UnsignedNewsWebView”.

În cazul unei logări automate realizată cu succes, se va parcurge container-ul


FinanceNavigator. În cazul acestui container, înălțimea arborelui este mai mare decât cea a
containerului AuthNavigator. Această componentă are 6 copii direcți: „Home”, „Portfolio”,
„Profile”, „Expenses”, „Bank Account” și „Settings”.

Navigatorul „Home” dispune doar de o singură fereastră, ce se regăsește sub același nume
cu numele navigatorului.

Navigatorul „Portfolio” are în componența sa tot o singură fereastră, aceasta regăsindu-se


în cod sub numele de „PortfolioOverview”. Navigatorul „Profile” este un navigator de tip stivă și
dispune de doi copii, redirecționând execuția programului către două componente funcționale de
tip fereastră, purtând numele de „Profile” și „UpdateProfile”.

Navigatorul „Expenses” este un navigator de file și are în componența sa tot doi copii
direcți, ce poartă numele de „Transactions” și „DoSavings”. Copiii direcți ai navigatorului
„Expenses” au la rândul lor alții copii direcți, în cadrul arborelui. Navigatorul cu numele
„Transactions” dispune de doi copii direcți, de tip fereastră. Aceștia se regăsesc în interiorul
componentei „Transactions” sub numele de „Transactions” și „NewTransaction”. Navigatorul
„DoSavings” are în componența sa patru componente funcționale de tip fereastră. Acestea poartă
numele de „Savings”, „Alert”, „Note” și „NoteDetails”.

22
Navigatorul „Bank Account” posedă două componente funcționale de tip fereastră, ce se
regăsesc în codul programului sub denumirea de „AccountsOverview” și „AddAccount”.

Ultimul navigator aflat în sertarul navigator FinanceNavigator poartă numele „Settings” și


dispune doar de o singură componentă funcțională, ce poartă numele „Settings”.

Pentru a se clarifica arhitectura aplicației și, implicit, arborele acesteia; am creat o diagramă
cu arborele aplicației folosindu-mă de aplicația web lucid.[18]

Figura III.3 Arborele de navigare al aplicației client

III.2.2 Arhitectura codului Redux


Am ales să folosesc tehnologia Redux pentru a-mi fii ușor de făcut teste în cadrul
aplicației și pentru a avea un management mai bun al datelor utilizate în interiorul programului.

După cum este de așteptat, toată aplicația dezvoltată utilizând React Native este
împachetată într-un container Redux, realizând astfel cuplajul cu aplicația în sine. Acest lucru este
necesar pentru a avea un singur state management pentru toată aplicația, dar și pentru o
funcționarea corespunzătoare a caracteristicilor Redux.

18
Lucid, https://lucid.app/

23
În cadrul directorului „store” se află toată implementarea functionalitatilor Redux.
Acest director este împărțit în 2 subdirectoare: „actions” și „reducers”.

În cadrul folder-ul „actions” sunt prezente fișiere ce cuprind funcții, care îndeplinesc
rolul de „action” în cadrul proceselor realizate de tehnologia Redux și sunt responsabile cu
procesarea informațiilor trimise din client și încărcarea acestora în containerul Redux. Pentru ca
datele trimise din client să fie înmagazinate în depozitul Redux, este necesar să ne folosim de
funcționalitatea „dispatch”, ce expediază datele primite de la aplicație către magazinul Redux.
Pentru ca expedierea și înmagazinarea datelor să fie realizate cu succes, dezvoltatorul trebuie să
specifice tipul acțiunii (ce va declanșa, ulterior, schimbarea unor anumite informații în cadrul
depozitului Redux) și încărcătura de date ce urmează a fii depozitată în container-ul Redux.

În cadrul folder-ului „reducers” sunt prezente fișiere ce conțin funcționalități, care


au rolul de a determina și executa comenzile primite din funcționalitățile prezente în cadrul folder-
ului „actions”. O funcționalitate a folderului „reducers” se numește reductor și este o funcție ce
determină informațiile prezente în aplicație. Aceasta se folosește de o funcție „action” prezentă
într-un fișier din cadrul folder-ului „actions” pentru a determina ce schimbări să efectueze în
depozitul Redux.

Majoritatea fișierelor din folder-ul „reducers” corespund unor fișiere din folder-ul
„actions”, având același nume. Tipurile de acțiuni sunt definite în fișierele din „actions” și sunt
importante în evidențele folder-ului „reducers”.

În cadrul funcțiilor actions, am folosit tehnologia Redux Thunk, pentru a observa dacă
actualizarea datelor este permisă în baza de date din Firebase, urmând că acestea să fie actualizate
și ulterior actualizate în cadrul aplicației, în magazinul Redux.

Informațiile din aplicație sunt înmagazinate în fișierele din cadrul folder-ului reducers.
Totalul de date prezent în program este partajat inteligibil în fragmente, ce definesc totalitatea
fișierelor prezente în folder-ul reducers.

Tipurile de acțiuni sunt importate din fișierele actions. Fiecare fișier are o lista de tipuri de
acțiuni pe care o primește de la un alt fișier, localizat în folderul „actions”.

24
Fiecare fișier are definită o variabilă numită „initialState”, ce cuprinde datele default,
existente până când vor fi modificate în urma declanșării acțiunilor.

Depozitul Redux este divizat în 9 fișiere, acestea conțînând totodată datele și funcțiile
reducer aferente acelor informații înmagazinate. Informațiile deținute de acesta provin dintr-un
server extern sau local din memoria telefonului. Aceste fișiere au următoarele denumiri, conținuturi
și aplicații:

∑ accounts.js: conține toate informațiile utilizatorului, aflate în obiectul investments din


cadrul bazei de date Realtime Database. Acest fișier este responsabil cu manipularea
datelor ce țin de conturile bancare ale utilizatorului și importă 4 tipuri de acțiuni:

- CREATE_ACCOUNT: acțiune ce declanșează crearea unui nou cont


bancar;

- SET_ACCOUNT: funcție declanșată la momentul extragerii informațiilor


de pe server (la deschiderea aplicației), și are rolul de a actualiza datele cu
privire la conturile bancare și sumele depuse în respectivele conturi;

- UPDATE_ACCOUNT: funcție ce declanșează actualizarea sumei dintr-un


cont bancar;

- DELETE_ACCOUNT: metodă ce trigger-uiește ștergerea unui cont bancar.


Acesta trebuie să aibă suma 0 în contul bancar pentru a putea fi șters.

∑ auth.js: funcțiile din cadrul acestui fișier se declanșează la momentul deschiderii


aplicației / autentificarii și deconectării din cadrul aplicatiei . În cadrul acestui fisier sunt
rețtinute detalii cu privire la id-ul utilizatorului, token-ul de acces în aplicație și
verificarea acțiunii de autoconectare în aplicație. Acest fișier de cod importă 3 tipuri de
acțiuni:

- AUTHENTICATE: acțiune declanșată în momentul autentificării cu succes


în cadrul aplicației;

25
- SET_DID_TRY_AL: acțiune declanșată în momentul intrării în aplicație.
Programul verifică dacă token-ul utilizatorului mai este încă valabil. În caz
afirmativ, îl va redirecționa pe utilizator în pagina „Home”;

- LOGOUT: acțiune declanșată în momentul în care utilizatorul se


deloghează din contul său curent.

∑ currency.js: acest fișier nu conține date extrase dintr-un server sau din memoria locală,
ci doar actualizează opțiunile utilizatorului, cu privire la valută afișată în aplicație.
Bineînțeles, se vor actualiza și sumele apărute în ecran, în raport cu valoarea
aproximativă a noii valute. Fișierul conține 3 acțiuni (RON,EUR,USD), ce declanșează
schimbarea valutei actuale cu cea aleasă de utilizator.
∑ deepProfile.js: conține toate informațiile utilizatorului, aflate în obiectul profile din
cadrul bazei de date Realtime Database. Fișierul dispune de 5 tipuri de acțiuni:

- CREATE_PROFILE: acțiune declanșată în momentul autentificarii cu


succes în cadrul aplicației. Se recuperează datele din server și sunt
actualizate în containerul Redux;

- SET_PROFILE: acțiune ce este declanșată de către utilizator, atunci când


acesta dorește să actualizeze niște date introduse greșit sau învechite;

- SET_PROFILE_PIC: acțiune ce declanșează actualizare pozei de profil;

- UPDATE_SPENDING_LIMITS: acțiunea ce declanșează actualizarea


sumei maxime permise de a fi cheltuită într-o zi;

- UPDATE_EMAIL: actualizare e-mail.

∑ Investments.js: conține toate informațiile utilizatorului, aflate în obiectul investments


din cadrul bazei de date Realtime Database. Fișierul dispune de 2 tipuri de acțiuni:

26
- SET_INVETMENTS: acțiune declanșată în momentul autentificării cu
succes în cadrul aplicației. Se recuperează datele din server și sunt
actualizate în containerul Redux.

- ADD_INVETMENTS: acțiunea este declanșată de către utilizator, atunci


când efectuează o nouă investiție în cadrul aplicației.

∑ mockFinanceData.js : conține datele trimise de client catre server și prelucrate în cadrul


serverului Node.js. Respectivele date se referă la portofoliul de investiții și datele
investițiilor (ce au fost prelucrate în cadrul serverului pentru a putea fii introduse în
graficele aplicației):

- SET_FINANCE_DATA: înmagazinează datele primite de la serverul


Node.js , cu privire la portofoliul de investiții al utilizatorului.

∑ news.js: conține tot istoricul cu privire la articolele și știrile accesate de către utilizator
prin intermediul notificărilor. Aceste date sunt reținute în memoria telefonului, întrucât
ar încarcă inutil memoria serverului (nu reprezintă niște date importante cu privire la
profilul utilizatorului). Notificările sunt salvate în memoria telefonului doar dacă
utilizatorul este autentificat; întrucât în urmă unui atac cibernetic, provocatorul ar putea
să încarce excesiv memoria telefonului unui utilizator. Acest fișier dispune de 2 tipuri
de acțiuni:

- SET_NEWS: acțiune declanșată în momentul autentificării cu succes în


cadrul aplicației. Se recuperează datele din memoria telefonului și sunt
actualizate în containerul Redux.

- ADD_NEWS: acțiunea este declanșată de către utilizator, atunci când


deschide o nouă notificare.

∑ notes.js: conține tot istoricul cu privire la notițele scrise și salvate de către utilizator.
Aceste date sunt reținute în memoria telefonului, întrucât ar încarcă inutil memoria

27
serverului și, de asemenea, au caracter personal. Acest fișier dispune de 2 tipuri de
acțiuni:

- SET_NOTES: acțiune declanșată în momentul autentificarii cu succes în


cadrul aplicației. Se recuperează datele din memoria telefonului și sunt
actualizate în containerul Redux.

- ADD_NOTES: acțiunea este declanșată de către utilizator, atunci când


inserează o nouă notiță.

∑ transactions.js: conține toate informațiile utilizatorului, aflate în obiectul transactions


din cadrul bazei de date Realtime Database. Fișierul dispune de 3 tipuri de
acțiuni:

- SET_INVETMENTS, SET_TRANSACTIOSN_TIMELINE: acțiune


declanșată în momentul autentificării cu succes în cadrul aplicației. Se
recuperează datele din server și sunt actualizate în containerul Redux.

- ADD_INVETMENTS: acțiunea este declanșată de către utilizator, atunci


când efectuează o nouă investiție în cadrul aplicației.

Datorită caracteristicilor consistent detaliate ale rețelei Redux, e posibil să nu se fii înțeles
anumite lucruri. De aceea, am rezumat toată arhitectură containerului Redux printr-o diagramă.

28
Figura III.4 Arhitectura codului Redux

29
III.3 Arhitectura server-ului Node.js
Server-ul dezvoltat în Node.js se prezintă că fiind server-ul unei instituții financiare
sau bancare. Clientul comunică cu server-ul folosind tehnologia Axios pentru a primii informații
de actualitate cu privire la prețul curent al unei acțiuni, dar și pentru a formata anumite date
personale ale utilizatorului, cu scopul de a le mapa cu ușurință în cadrul graficelor dispuse în
aplicație.

Pentru a furniza un mediu amiabil pentru schimbul de date dintre client și server,
am folosit tehnologia Express. Această tehnologie reprezintă un cadru flexibil de aplicații web
back-end pentru Node.js care furnizează un set robust de caracteristici pentru aplicațiile
mobile.[19]

În cadrul proiectului, am definit mai multe tipuri de URL-uri, în funcție de resursele


accesate. Acestea sunt formate prin concatenarea adresei gazdă cu ruta caracteristică a resursei
accesate:

- „./route/api/getUserData”: prin acest url se accesează o resursă folosind o metoda POST,


pentru a formata datele utilizatorului. Respectivele date se mapează pe formatul graficelor
prezente în aplicație. Clientul va trimite catre server datele necesare pentru a fii formatate.
- „./route/api/sendTransactionMoment”: prin acest url se accesează o resursă folosind o
metoda POST, pentru a-i ilustra inteligibil și în procente utilizatorului sumele cheltuite
zilnice, până în prezent.
- „./route/api/getAlertPrediction”: aceasta este o resursă accesibila printr-o metodă POST,
la care în momentul accesării sale din client, de către utilizator; consumatorul aplicației va
primi o predicție asupra sumei limite admise pe care o poate cheltui zilnic. Predicția e
stabilită în concordanță cu salariul și veniturile sale bancare, folosindu-se tehnica de
învațare automată.

În background-ul server-ului web rulează metoda „updateFinanceData”, care


actualizează constant prețurile acțiunilor.

19
Express , https://expressjs.com/

30
Toate datele ce sunt transmise între client și server trebuie să fie reprezentate în
format JSON, pentru a putea fii citite de către fiecare participant.

În urma accesării unei resurse de către client sau a unei actualizări automate a unei valori
în cadrul server-ului; tehnologia Mongoose se conectează cu serverul bazei de date MongoDB și
adaugă, actualizează sau șterge anumite informații din acest server.

Cum baza de date este de tip NoSQL, schema creeată cu ajutorul tehnologiei Mongoose
este non relațională. Schema este definită în format JSON și deține urmatoarele câmpuri:

∑ category : un string ce definește categoria / tipul unei acțiuni;


∑ variations : un vector de valori ce reprezintă istoricul valorilor unei acțiuni;
∑ totalShares : variabila ajutatoare de tip number, folosită pentru structurarea datelor
trimise din client.

Pentru a mă face înțeles cu privire la modul complet de funcționare al server-ului Node; am


creat o diagrama ce cuprinde arhitectura acestuia și conectarea sa cu server-ul MongoDB.

31
Figura III.5 Arhitectura serverului Node.js

III.4 Arhitectura contului de pe platforma Firebase


Dezvoltatorul aplicației are acces la toate serviciile Firebase necesare pentru o bună
funcționare ale aplicației mobile. Personal am ales serviciile de cloud de la Firebase, deoarece
dispun de o gama largă de opțiuni și servicii fără costuri.

În cadrul proiectului, am folosit numeroase servicii care m-au ajutat în testarea aplicației,
precum și în dezvoltarea acesteia.

Funcționalitățile cloud utilizate în dezvoltarea aplicației sunt următoarele:

∑ Autentificare și managementul utilizatorilor;


∑ Trimiterea de notificări către utilizatori;
∑ Stocarea datelor utilizatorilor.

32
Serviciul de stocare în baza de date mi-a permis să observ în timp real modificările efectuate
în cadrul aplicației, ajutându-mă la depanarea erorilor apărute în timpul dezvoltării programului.
Serviciul de stocare al datelor afișează în timp real orice modificare apărută în baza de date. În
cadrul aplicației, am stocat următoarele date cu privire la fiecare utilizator înregistrat:

∑ Datele de autentificare, ce includ email-ul și parola criptată a utilizatorului;


∑ Obiectul accounts: sumele și denumirea fiecărui cont bancar;
∑ Obiectul investments: detalii cu privire la investițiile făcute pentru fiecare ordin în
parte, incluzând tipul acțiunii, numărul de acțiuni achizițtionate și prețul la care au
fost cumărate;
∑ Obiectul profiles: detalii cu privire la profilul utilizatorului. Acest câmp conține
detalii esențiale asupra consumatorului aplicației; precum numele, salariul, suma
totală din conturile sale bancare, adresa de e-mail și url-ul către poză de profil;
∑ Obiectul transactions: conțtine toate tranzacțiile efectuate în afara ariei de investiții
(cheltuieli personale). Acest obiect JSON conține informații asupra cheltuielilor
efectuate; precum suma cheltuită, data la care a avut loc tranzacția, titlul tranzacției
și momentul exact când suma a fost procesată din card.

În cadrul bazei de date, ce se regăsește în oferta Firebase sub denumirea „Realtime


Database”, datele sunt stocate ca obiecte JSON.

Pentru accesarea unei valori, clientul trebuie să facă un request la o adresă specifică
câmpului pe care dorește să-l manipuleze, în cadrul proiectului ce este cuplat cu aplicația curentă.

Pentru serviciile de autentificare și management al user-ilor, m-am folosit de Firebase Auth


REST API pentru a comunica cu serviciile oferite de platformă, stocate în cloud. Dintre cele
existente, am ales să mă folosesc de serviciile de înregistrare, logare, recuperare și resetare parolă
și de schimbare a parolei și a adresei de e-mail.

Cum Firebase este o platforma deținută de Google, m-am folosit de set-ul lor de instrumente
pentru a putea accesa serviciile prezentate în paragraful anterior.

Accesul la aceste servicii se realizează prin intermediul metodelor HTTP. Clientul


efectuează un request la o adresa deținută de Google, iar serverul îi trimite un răspuns cu privire la
statusul cererii sale. Pentru a accesa un serviciu, clientul trebuie să trimită un request de tip POST

33
care să includă un body, ce conține detalii referitoare la acțiunea ce urmează a fii declanșată în
cadrul serviciilor oferite de platformă. Datele trimise către server, în cadrul body-ului, trebuie să
fie în format JSON.

Forma generală al unui endpoint, pentru a accesa serviciile oferite de Firebase Auth REST
API, are următoarea structură:

https://identitytoolkit.googleapis.com/v1/accounts:${tipul_actiunii}?key={id_proiect}

Pentru a accesa serviciul de notificări oferite de platformă, a fost necesar să-mi fac upgrade
la contul de Firebase, întrucât acest serviciu este unul premium al aplicației. Din fericire, cererea
în plată se efectuează doar dacă se depășesc 1000 de notificări trimise, ceea ce nu a fost cazul în
stadiul de dezvoltare al aplicației.

În cadrul acestui serviciu, am putut testa funcționalitatea Firebase, precum și modul de


funcționare al caracteristicii native “push notifications” în cadrul aplicației. Serviciul a fost folosit
pentru a trimite noutăți și blog-uri interesante utilizatorilor. Pentru a se trimite corespunzător o
notificare, dezvoltatorul aplicației trebuie să introducă un titlu și mesaj sugestiv; dar și niște date
custom, reprezentate de 3 perechi de tip cheie-valoare. Pentru că programul să funcționeze în
parametrii normali, cheile trebuie să aibă denumirile „url”, „title” și „company”. Valorile acestor
chei au următoarele semnificații:

∑ url: adresa url la care va fi redirecționat utilizatorul în momentul accesări


notificării, în interiorul aplicației;
∑ title: titlul articolului sau paginii la care utilizatorul urmează să fie
redirecționat;
∑ company: denumirea companiei sau site-ului ce găzduiește respectivul
articol sau știre.

Pentru o înțelegere mai clară a tuturor functionalităților folosite și a datelor stocate în cloud,
precum și a modului de comunicare cu clientul, am realizat o diagramă ce conține arhitectura
sistemului de servicii Firebase folosite în cadrul aplicației.

34
Figura III.6 Arhitectura serviciilor folosite de pe platforma Firebase

35
IV Detalii de implementare
În continuare voi detalia codul implementat in cadrul proiectului; mai precis în structura
clientului și serverului. Cum am specificat și capitolul anterior, partea de Frontend este formată din
clientul compus de codul React Native și Redux; alegând varianta backendless pentru salvarea
datelor clientului, prin intermediul platformei Firebase. De asemenea, am creeat un API de bancă
cu care aplicația interacționează.

În acest capitol, voi descrie pe larg componentele prezentate în capitolul V (din cadrul
arhitecturii aplicației), descriind rolul acestora; dar și modul în care acestea comunica între ele.

IV.1 Detalii de implementare ale codului client


IV.1.1 Detaliile de implementare ale codului React Native

Cum am specificat și în arhitectura aplicației; la momentul deschiderii aplicației de către


utilizator, execuția codului va începe în cadrul fișierului StartupScreen.js.

În interiorul funcției „StartupScreen” se va verifica existența unui token folosit pentru


autoconectare. În cazul în care acesta nu există sau a expirat, utilizatorul va fi redirecționat către
pagina de autentificare. În cazul în care tokenul există și încă este disponibil, consumatorul
aplicației va fii redirecționat către pagină „Home”, autentificandu-se astfel în cadrul
aplicației. După încărcarea aplicației de pe telefonul mobil și, implicit, dispariția ecranului de
pronire; se va afișa o animație ce simbolizează prelucrarea informațiilor existente. Acest lucru îl
înștiințează pe utilizator că informațiile din cadrul aplicației se procesează.

În cazul unei autentificări eșuate, consumatorul aplicației va fii redirecționat către pagina
de autentificare, din cadrul fișierului „LoginScreen.js”. Tot pachetul de interfață returnat de funcția
ce randeaza această pagină este împachetat în interiorul obiectului „LinearGradient”, oferind astfel
un aspect plăcut background-ului paginii. Design-ul aplicației este predominant în culoarea
albastră, întrucât am observat prezența acestei culori în multe aplicații Fintech și, personal, îmi
oferă o senzație plăcută la utilizarea aplicației. Toate ferestrele aplicației conțin acest obiect,
dispunând de aceleași atribute și valori.

36
Datorită posibilității apariției unui bug din pricina mărimii ecranului, am împachetat tot
conținutul paginii într-un obiect „ScrollView”, permițând astfel acțiunea de scroll. Această
implementare este necesară pentru cazurile în care mărimea conținutului este mai mare decât
dimensiunile ecranului utilizatorului. Conținutul acestei ferestre este format din 2 input-uri, ce
simbolizează datele pe care utilizatorul trebuie să le introducă pentru a se putea autentifica. Acestea
sunt reprezentate prin e-mailul și parola utilizatorului. În cazul în care utilizatorul nu-și mai
amintește parola, acesta poate accesa funcționalitatea de recuperare a parolei. De asemenea
fereastra dispune de 3 butoane pentru autentificare și unul pentru înregistrare. Primul buton
comunică cu datele introduse de utilizator în input și la accesarea acestuia, clientul va comunica cu
serverul Firebase pentru a verifică existența unui user ce corespunde cu datele introduse de
consumatorul aplicației. Cel de-al doilea și al treilea buton permit autentificarea utilizatorului prin
intermediul platformei sociale Facebook, respectiv Google. Butonul pentru înregistrare va
redirecționa utilizatorul către o fereastră de înregistrare.

Stilizarea butoanelor se realizează în cadrul obiectului styles, creat cu ajutorul obiectului


„StyleSheet”, folosind metoda „create”. Acesta transformă variabila styles într-o variabilă utilă
pentru stilizarea componentelor din cadrul interfeței grafice. Pentru butoanele prezente în această
pagină, am definit campurile „buttonContainer” și „buttonLoginContainer” in cadrul obiectului
styles.Aceste obiecte conțin aspecte stilistice generale cu privire la dimensiunea și așezarea
butoanelor în pagină. Formatul butonului „Sign în with facebook” este format dintr-o componentă
nativă View, ce împachetează toate componentele specifice butonului de conectare cu Facebook,
precum și din componentele native Button și ActivityIndicator. Cele 2 componente prezentate
anterior oscilează în apariția acestora în cadrul ferestrei de autentificare, întrucât componenta
ActivityIndicator este activă în timpil procesării execuției, date la comandă de către utilizator prin
intermediul aplicației. În urmă opririi procesului de prelucrarea a comenzii date de utilizator,
animația furnizată de componentă ActivityIndicator devine pasivă iar componenta Button devine
din nou activă în cadrul paginii. Valoarea de adevăr a state-ului „fbLoading” activează starea activă
a componentei ActivityIndicator, în timp ce valoarea acesteia de fals dezactivează starea activă al
elementului.

37
Culoarea butonului este dată de variabila „primary”, din cadrul obiectului importat din
fișierul „Colors.js”, având valoarea „#0000B” (ce reprezintă culoarea albastru închis). Am ales să
definesc extern majoritatea culorilor folosite, întrucât la o strategie de marketing ce ar impune
schimbarea temei și design-ului unei aplicații; aceasta să se poată restructura în timp util, prin
schimbarea unor valori din cadrul unui singur fișier sursă, ce cuprinde variabile folosite pentru
design. Această tehnică permite actualizarea mai multor secțiuni de design din cadrul aplicației,
dintr-un singur fisier; reducând astfel timpul de lucru pentru restructurarea programului.

<View style={styles.buttonContainer}>
{fbLoading ? (
<ActivityIndicator size="small" color={Colors.primary} />
) : (
<Button
title="Sign in with Facebook"
color={Colors.facebook}
onPress={fbLogin}
/>
)}
</View>

Secvența de cod IV.1: structura codului implementat pentru definirea butonului ce face
legătura cu sistemul de autentificare, prin platforma Facebook

În cadrul interfeței, cele două input-uri sunt reprezentate stilistic, având un design plăcut
utilizatorului. Componentă custom „Input” este derivată din componentă nativă „TextInput”, ce
aparține de biblioteca React Native. Derivarea componentei „TextInput” și, implicit, crearea
funcției „input” ce returnează obiectul prezent în interfața grafică sunt definite în cadrul container-
ului „UI”, fișierul „Input.js”. Această delimitare față de fișierul „LoginScreen.js” ajută la
structurarea codului. Acest lucru oferă, în esență, un mediu de lucru facil programatorului. În cadrul
acestui obiect este prezent atât componentă funcțională „Input”, cât și reductorul „inputReducer”,
ce mă ajută la managementul state-urilor (în acest caz, stările reductorului fac referință la modul în
care utilizatorul interacționează cu formularul de login).

Pentru a oferi un design dinamic paginii, am creeat metoda „lostFocusHandler”. Această


metodă expediază acțiunea „INPUT_BLUR” către reducer-ul simulat local „inputReducer”. Prin
declanșarea acestei acțiuni, se va schimbă design-ul input-ului pe care este focusat utilizatorul. Am

38
ales să folosesc acest efect întrucât denotă un nivel de eleganță și profesionalism din partea
aplicației.

În cadrul componentei funcționale „Input” este prezentă o funcție hook „useEffect”, ce


îndeplinește rolul de a actualiza datele introduse de către utilizator. În această funcție, în cadrul
primului parametru se verifică în timp real veridicitatea datelor introduse de către consumatorul
aplicației. În interiorul obiectului din cadrul primului parametru este prezentă funcționalitatea
moștenită „onInputChange”, ce are rolul de a actualiza datele introduse de către utilizator.

Aceasta primește 3 parametri:

• id: tipul input-ului (în cazul de față, poate fi e-mailul sau parola);

• inputState.value: valoarea input-ului actual, stocată în reducer-ul creat local;

• inputState.valid: veridicitatea datelor introduse în inputul respectiv.

Funcția hooks primește 3 variabile în lista definită în parametrul al doilea, reprezentând


state-urile reductorului prezent local, respectiv funcția moștenită „onInputChange” .

useEffect(() => {
if (inputState.touched) {
onInputChange(id, inputState.value, inputState.isValid);
}
}, [inputState, onInputChange, id]);

Secvența de cod IV.2: funcția „useEffect” ce se autoapelează la orice schimbare a valorilor din
cadrul container-ului local Redux, precum și la redefinirea id-ului specific input-ului prezent în
componenta funcțională „LoginScreen”
În urma acestui apel, se va autoapela funcționalitatea „useCallBack” din cadrul funcției
„LoginScreen”. În genere, această funcție se apelează după efectul unei dependențe (în cazul
nostru, după apelul funcției „useEffect” din cadrul componenței funcționale „Input”). În urma
modificărilor efectuate în corpul metodei „useEffect”, se va apela metoda „inputChangeHandler”,
ce este la bază o funcție hook „useCallBack”. În cadrul acestei metode se vor actualiza valorile din
reducer-ul local „confirmReducer”, prezent în fișierul „LoginScreen.js”; prin intermediul acțiunii
„dispatchFormState”. Aceasta expediază către reductor datele și tipul acțiunii; urmând să se
modifice anumite informații din cadrul datelor înmagazinate în containerului simulat Redux. În
cadrul acestui acestui container, obiectul expediat va cuprinde informații cu privire la tipul acțiunii

39
ce va declanșa schimbarea unor date din interiorul magazinului Redux, precum și detalii referitoare
la statusul actual al unei intrări (valoarea sa, validitatea acestuia și id-ul respectivului). Valorile
acestui reductor local sunt folosite ulterior pentru a fii expediate către codul Redux.

const inputChangeHandler = useCallback(


(inputIdentifier, inputValue, inputValidity) => {
dispatchFormState({
type: LOGIN_INPUT_UPDATE,
value: inputValue,
isValid: inputValidity,
input: inputIdentifier,
});
},
[dispatchFormState]
);

Secvența de cod IV.3: implementarea funcției hook „useCallBack” din cadrul funcției
componente „LoginScreen”. Aceasta se autoapeleazaă în urma unui apel al funcției
useEffect, din cadrul componentei funcționale „Input”. Metoda primește ca element în
lista de track-ing a valorilor numai obiectul „dispatchFormState”, prezent și în corpul
funcției.

De asemenea, în componenta funcțională Redux este prezentă metoda


„textChangeHandler”, ce verifică veridicitatea datelor introduse de user. Aceste date sunt prezente
în cadrul fișierului „LoginScreen.js” și sunt transmise către funcția componentă din cadrul
fișierului prezentat anterior prin intermediul atributului props.

În esență, tot corpul formularului de autentificare este prezent în cadrul acestei funcții
componente. Pentru reprezentarea acestuia s-au folosit componentele native React Native „View”
(ce înglobează tot obiectul returnat de funcția componentă), „Text” și „TextInput”. Toate datele
înserate în corpurile „Text” și „TextInput” au fost preluate din atributul „props” al componentei
„Input”, prezente în componenta mamă.

Tot design-ul componentei funcționale a fost definit în obiectul „styles”, prezent în cadrul
aceluiași fișier. Stilul a fost atribuit interfaței grafice returnate de funcției componenta funcțtionala
“Input”. Bucata de design specifică unei anumite componente este atribuită acesteia prin

40
intermediul atributului „style”, aceasta primind un sub-obiect al obiectului principal „styles”,
specifică respectivei componente native.

În cele ce urmează, vreau să descriu toate atributele moștenite de componenta „Input” în


cadrul fișierului „LoginScreen.js”:

∑ props.initialValue: valoarea inițială a input-ului (care în majoritatea cazurilor,


este„”) prezentă în componenta dedicată introducerii adresei de e-mail sau a parolei;

∑ props.initiallyValid: validitatea input-ului în stare incipientă (în acest caz, ca și în


majoritatea celor prezente în cadrul aplicației, are valoarea fals);

∑ props.errorText: text-ul pe care componenta funcțională îl va afișa, în cazul în care


parola și e-mailul introdus nu au o structura specifică unei parole sau a unei adrese
de e-mail;

∑ alte proprietăți ce se vor mapa pe atributele componenței „TextInput”.

<View style={styles.formControl}>
<Text style={styles.label}>{props.label}</Text>
<TextInput
{...props}
style={styles.input}
value={inputState.value}
onChangeText={textChangeHandler}
onBlur={lostFocusHandler}
/>
{!inputState.isValid && inputState.touched && (
<View style={styles.errorContainer}>
<Text style={styles.errorText}>{props.errorText}</Text>
</View>
)}
</View>

Secvența de cod IV.4: obiectul returnat de componenta funcțională „Input”. Aceasta


conține toate caracteristicile necesare unui câmp de completare, pentru ca
utilizatorul să se autentifice.

41
La momentul accesării unui buton, o funcție manipulatoare asincronă din cadrul blocului
funcției componente va declanșa un apel la o funcționalitate a container-ului Redux. De exemplu,
în momentul în care utilizatorul apasă pe butonul regăsit în interfață sub numele de „Sign în with
Facebook”; acesta va fii redirecționat către metoda asincronă „fbLogin”. În cadrul acestei metode,
am folosit variabilele „error” și „fbLoading” , instanțiate în cadrul funcției componente cu valorile
null, respectiv false, folosindu-se funcția hook a librăriei React „useState”. Variabila „error” e
folosită în scop informativ; iar la modificarea valorii acestuia, va apărea o fereastră pop-up ce îl va
informa pe utilizator cu privire la erorile apărute în urmă proceselor efectuate în cadrul aplicației.
Acest efect se petrece la orice schimbare de valoare a variabilei „error”, în cadrul metodei
„useEffect”, deținută de librăria React. Pentru ca efectul să se producă numai la schimbarea valorii
stării „error”, a trebuit să introduc variabila în lista prezentă în cadrul celui de-al doilea parametru
al funcției „useEffect” (metoda „useEffect” se autoapeleaza la fiecare modificare a variabilelor din
lista dată în cel de-al doilea parametru al funcției ).

useEffect(() => {
if (error) {
Alert.alert("An Error Occurred!", error, [{ text: "Okay" }]);
}
}, [error]);

Secvența de cod IV.5: funcția „useEffect” ce se autoapelează la fiecare schimbare a


variabilei state „error”. Această metodă este implementată în majoritatea componentelor
funcționale și are rolul de a-l înștiinta pe utilizator cu privire la erorile apărute în cadrul
procesării informațiilor

În schimb, variabila „fbLoading” are rol stilistic (în momentul în care utilizatorul apasă pe
buton, design-ul acestuia dispare și se înlocuiește cu o animație de loading) și informativ, deoarece
îl informează pe utilizator că cererea lui este procesată.

Codul ce urmează a fii explicat se află într-o structura try/catch. În prima fază, în blocul try
se expediează acțiunea de autentificare prin platforma Facebook către funcția „fbLogin” din cadrul
codului Redux. Această funcție (împreună cu multe altele), a fost importată din codul Redux și
apelată prin intermediul obiectului „authActions”; acesta având atașate toate funcțiile actions
relatate la procesul de autentificare al utilizatorului. Bineînțeles, apelul a fost făcut în interiorul
metodei dispatch (creeată în interiorul funcției componente), pentru ca ulterior să se expedieze

42
obiectul returnat de către funcția „fbLogin”. Cum în cadrul obiectului s-au petrecut operații
asincrone , era necesar să fie pusă în așteptare apelul metodei dispatch, pentru a aștepta ca toate
procesele petrecute în interiorul obiectului să fie finalizate. În cazul în care nu au apărut erori în
timpul proceselor din codul Redux, utilizatorul va fii redirecționat în pagina „Home” a aplicației
de finanțe. În caz contrar, se apelează funcția „setFbLoading”, având parametrul false. Acest lucru
va declanșa procesul prin care animația de login va dispărea și va reapărea designul
butonului „Facebook Login” (prin resetarea valorii state-ului „fbLoading”). În cazul apariției unei
erori, se apelează funcția „setError”, primind ca parametru mesajul erorii. Acest apel va declanșa
metoda prezentată în secvența de cod 5, ilustrând o fereastră pop-up de atenționare către utilizator,
cu privire la eroarea apărută în cadrul codului Redux.

const fbLogin = async () => {

setError(null);
setFbLoading(true);
try {
await dispatch(authActions.fbLogin());
} catch (err) {
setError(err.message);
setFbLoading(false);
}
};

Secvența de cod IV.6: metoda ce manipulează acțiunea utilizatorului de a se conecta prin


intermediul Facebook. În cazul unei logări reușite prin intermediul codului Redux, utilizatorul va
fii redirecționat către pagina „Home”. Altfel, execuția va ieși din codul Redux și se va petrece în
interiorul blocului „catch”, prezent în codul React Native

Datorită numărului consistent de state-uri prezente în cadrul acestei ferestre, am simulat un


container Redux local, folosindu-mă de metoda hook „useReducer” a librăriei React. Aceasta
înmagazinează state-urile necesare pentru formularul de autentificare. Pentru construirea
containerului, s-a creeat variabila „formReducer”, care simulează componenta reductor din cadrul
codului Redux. Această funcție este formată din 2 parametrii (state și action). În cadrul
parametrului state, funcția va primi datele ce urmează a fii actualizate în interiorul containerului;
iar în variabila action se va defini tipul acțiunii ce va declanșa schimbarea anumitor date în cadrul
containerului simulat Redux. State-urile inițiale sunt definite în corpul componentei funcționale ce

43
randeaza pagina. Aceste state-uri incipiente sunt definite în blocul state, conțînând 3 obiecte:
„inputValues”, „inputValidities” și „formIsValid”. Primul obiect face referință la valorile introduse
ca input de către utilizator, acestea fiind formate din e-mailul și parola utilizatorului. Cel de-al
doilea obiect relatează autenticitatea datelor introduse de către utilizator; parola trebuind să conțină
minim 8 caractere, iar adresa de e-mail să aibă o structura corect definită. Al treilea obiect este
decisiv pentru accesarea funcționalităților din cadrul container-ului original Redux (cel ce
împachetează întreaga aplicație); întrucât acesta validează formularul și redirecționează
informațiile introduse de către utilizator spre funcțiile din cadrul codului redux. Întregul bloc state
este folosit pentru a defini variabilele constante „formState” și „dispatchFormState”, ce au rol de
accesare a state-urilor prezentate mai sus, respectiv de a expedia informații către containerul
„formReducer”, urmându-se a se schimba datele unor state-uri actuale. Pentru definirea acestor
variabile este nevoie să folosim funcția hook „useReducer” (pentru a cupla containerul Redudx
simulat „formReducer” cu componenta funcțională). Această metodă primește doi parametri:
primul este reprezentat de containerul simulat Redux la care facem referire (în cazul actual
„formReducer”); iar cel de-al doilea parametru face referire la blocul state ce va fii folosit pentru a
defini stările inițiale (în cazul de față, blocul state descris anterior).

const [formState, dispatchFormState] = useReducer(formReducer, {


inputValues: {
email: "",
password: "",
},
inputValidities: {
email: false,
password: false,
},
formIsValid: false,
});

Secvența de cod IV.7: definirea variabilelor ce fac conexiunea cu reductorul simulat


Redux „formReducer”, precum și determinarea stărilor inițiale

De asemenea, am simulat și un container Redux pentru a depozita state-urile folosite pentru


gestionarea tipurilor de modal implementate în cod, acestea având statusul de modal deschis sau
închis. Acest container a fost definit în variabilă exterioară „confirmReducer” și face legătura cu
componenta funcțională prin intermediul variabilelor „confirmState” și „dispatchConfirmState”.

44
În circumstanța în care utilizatorul nu are un cont înregistrat pe platforma Firebase
și nici nu dorește să se autentifice prin intermediul platformelor sociale Google sau Facebook,
acesta are opțiunea de a se înregistra prin intermediul ferestrei „RegisterScreen”. În urma accesării
butonului „Register” din cadrul paginii de autentificare, consumatorul aplicației va fii redirecționat
către pagina de înregistrare. Aidoma formularului de autentificare, utilizatorul trebuie să introducă
datele pentru a se putea înregistra; respectiv adresa de e-mail, parola și numele său complet.
Formularul de înregistrare are aceeași structura ca formularul de autentificare, având în plus câmpul
de introducere a numelui complet. În urma apăsării butonului de înregistare, se verifică eventualele
erori apărute în procesul de înregistrare a utilizatorului. În cazul în care procesul de verificare a
autenticității și integrității datelor introduse de către utilizator s-a încheiat cu succes, utilizatorului
i se va afișa o fereastră pop-up, prin intermediul căreia i se cere utilizatorului să introduca codul de
confirmare al înregistrării, primit prin adresa de e-mail. Fereastra este definită în cod prin
componenta nativă „Modal”. Variabila de stare „visibleModal” determină vizibilitatea Modal-ului
în cadrul paginii. Valoarea acesteia este de tip boolean și este modificată prin intermediul metodei
„setVisibleModal”. Design-ul modal-ului a fost realizat în cadrul fișierului „MyModal”, fiind situat
în folderul „components”, secțiunea „UI”. Acesta a fost importat în fișierul „RegisterScreen.js”
prin intermediul unui obiect, iar design-ul a fost atașat componentelor native (View, Test, Button
și TextInput) prezente în cadrul modal-ului prin intermediul atributului „style”.

În cadrul acestei ferestre, se cere utilizatorului să introducă codul de confirmare primit pe


adresa de e-mail, pentru a certifica adresa de e-mail cu care s-a înregistrat. În cazul introducerii
codului corect, se va expedia o acțiune către codul Redux, pentru a se certifica adresa de e-mail a
utilizatorului. În caz contrar, consumatorului aplicației i se va afișa o fereastră de atenționare, prin
care îl înștiințează pe utilizator de faptul că codul introdus de acesta este greșit.

45
<Modal visible={visibleModal}
onDismiss={() => {
setVisibleModal(false);}}
style={{
margin: 0,
justifyContent: "center",
alignItems: "center", }} >
<View style={stylesModal.modalContainer}>
<Text style={{ fontSize: 24,fontWeight: "bold",textAlign: "center
",}} >
Please enter the code received via email to verify your
account
</Text>
<View style={stylesModal.textContainer}>
<TextInput
style={stylesModal.input}
placeholder="Verification code"
id="verifCode"
label="Verification code"
keyboardType="default"
required
minLength={5}
autoCapitalize="none"
errorText="Please enter a valid verification code."
onChangeText={(text) => {
setVerifCode(text);}}/>
</View>
<View style={styles.confirmButton}>
<Button title="Confirm verification code "
onPress={confirmHandler}/>
</View>
<View style={{ position: "absolute", top: 0, right: 0 }}>
<Button style={{ opacity: 0.93 }} title="Close pop-up"
onPress={() => {setVisibleModal(false);}}/>
</View>
</View>
</Modal>

Secvența de cod IV.8: componenta „Modal” definește o fereastră pop-up, prin care i se cere
utilizatorului să introducă codul primit prin e-mail pentru a-și confirma înregistrarea

Odată ce utilizatorul s-a autentificat în aplicația „Fintech Go”, acesta va fii redirecționat în
fereastra „Home”. În cadrul acestei pagini, utilizatorului i se vor afișa informații cu privire la
cheltuilelile sale zilnice (afișate într-un grafic) precum și detalii cu privire la valoarea sa netă.

46
Aceasta valoare se calculează prin însumarea sumelor deținute de utilizator în conturile sale
bancare și valoarea investițiilor sale în prezent. De asemenea, i se ilustrează sumele totale cheltuite
și suma totală investită până în prezent.

Pagina are un design similar cu ferestrele „Login” și „Screen”, utilizandu-se componenta


„LinearGradient” pentru stilizarea paginii. De asemenea, culoarea predominantă în pagină rămâne
albastru.

Pentru determinarea valorilor nete ale utilizatorului, precum și sumele totale cheltuite și
investite până în prezent, a fost necesar să recuperăm datele din server, ce cuprind istoricul
tranzacțiilor și investițiilor efectuate până în prezent. De asemenea, a fost nevoie să recuperăm
datele cu privire la soldul din conturile sale bancare.

Mai mult decât atât, a fost necesară importarea funcției ajutătoare „getFinanceData”,
folosită pentru a calcula totalul din conturile sale bancare, dar și pentru a socoti totalul cheltuielilor
efectuate până în prezent. Am ales să definesc această metodă externă, întrucât aș supraîncarcă
pagina „Home.js” cu codul implementat pentru a efectua aceste calculele. Pentru extragerea
informațiilor cu privire la istoricul investițiilor și tranzacțiilor efectuate până în prezent, a trebuit
să accesez depozitul Redux, unde erau stocate aceste date. Pentru a avea acces la ele, m-am folosit
de funcția hook „useSelector”, existentă în cadrul librăriei „React Redux”. După ce am preluat
datele din containerul Redux, am calculat sumele totale cheltuite în cadrul investițiilor și
tranzacțiilor folosindu-mă de funcțiile Javascript „map” și „reduce” Metodă „map” preia din
obiectul unei tranzacții sau investiții suma cheltuită; în timp ce „reduce” însumează toate sumele
cheltuite în cadrul obiectelor destinate tranzacțiilor, respectiv investițiilor. Sumele calculate sunt
ulterior returnate de către metodă.

47
export default getFinanceData = () => {
let totalBankAccounts = useSelector((state) => state.accounts.accounts);
let totalExpenditure = useSelector(
(state) => state.transactions.transactions
);
totalBankAccounts = totalBankAccounts
.map((el) => el.amount)
.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
totalExpenditure = totalExpenditure
.map((el) => el.amount)
.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
return { totalBankAccounts, totalExpenditure };
};
Secvența de cod IV.9: implementarea metodei prin care se calculează sumele totale
cheltuite de către utilizator, în cadrul investițiilor și tranzacțiilor efectuate

De asemenea, m-am folosit de metoda „getPortfolioData” pentru a comunica cu server-ul


Node.js și pentru a determina valoarea netă a utilizatorului. Serverul, reprezentat ca fiind un API
al băncii, calculează în timp real pierderile sau câștigurile obținute până în prezent, bazându-se pe
valoarea actuală al prețului unei acțiuni. Întrucât valoarea netă a unui consumator al aplicației
reprezintă totalul dintre sumele din conturile bancare și valorile acțiunilor sale, a fost necesară
comunicarea cu serverul pentru aflarea în timp real al valorii sale nete. Această funcție se află în
același fișier cu metoda prezentată anterior, „getFinanceData”. Funcția primește parametrii
„dispatch” și „getState” (folosiți pentru comunicarea cu codul Redux. Corpul metodei este înfășurat
în funcția javascript „setTimeout”, ce întârzie executarea funcției. Am ales să folosesc această
metodă întrucât apăreau complicații în momentul randării paginii. Oferind acest delay, pagina se
reîncarcă prin executarea în serie a mai multor operațiuni din cadrul paginii. În cadrul acestei funcții
se preia din containerul Redux lista de obiectele ce conțin istoricul tututor investițiilor făcute de
utilizator până în prezent. Lista de obiecte este ulterior transmisă server-ului băncii prin intermediul
tehnologiei de comunicare Axios, prezentată în capitolul III. Cu ajutorul tehnologiei axios se

48
trimite un request către server, ce este reprezentat printr-o metodă POST, având url-ul format din
string-ul definit în fișierul „env.js” și importat în fișierul actual prin obiectul „ENV”; și locația
accesării resursei: „convertToPortfolioData”. În corpul funcției este atașată variabila
„investments”, ce conține istoricul tuturor tranzacțiilor. În urma procesării datelor în cadrul server-
ului și primirii unui răspuns, execuția programului poate continuă pe 2 căi: prima va conduce către
expedierea datelor primite (ce constau în datele primite de la client, dar reformatate pentru a fi
utilizate în cadrul graficelor și în scop de cercetare) de la server spre Redux, având tipul acțiunii
„SET_FINANCE_DATA”; în timp ce pe a doua cale va intra în blocul „catch”, afișând eroarea în
consola dezvoltatorului pentru a o putea trata. Această metodă se autoapelează la fiecare secundă,
astfel încât utilizatorul să știe în timp real valoarea sa netă.

export const getPortfolioData = () => {


return async (dispatch, getState) => {
setTimeout(() => {
let investments = getState().investments.investments;
axios.post(`${ENV.REACT_APP_API_URL}/convertToPortfolioData`, {
investments}).then((res) => {
dispatch({type: SET_FINANCE_DATA,
portfolio: res.data.mockTypeInvestments,
investmentsData: res.data.investmentsData,});
}).catch((err) => {
console.log(err.message);
return false;});
dispatch({ type: "NO_EXECUTION" });
}, 1000);};};
Secvența de cod IV.10: implementarea metodei prin care sunt extrase datele din containerul
Redux, cu privire la investițiile făcute. Aceste informații sunt trimise către server, pentru a fii
formatate și stocate în cadrul depozitului Redux

Pentru a ilustra grafic în interfață sumele cheltuite de utilizator zilnic, m-am folosit de
componentă „LineChart”, situată în librăria integrată manual „react-native-chart-kit”. Aceasta
conține o serie de parametrii necesari ca să poată fii ilustrată cu succes:

49
∑ data: setul de date pe care îl va afișa în interiorul graficului;

∑ width/height: lungimea, respectiv înălțimea graficului. Aceasta are lungimea egală


cu dimensiunea ecranului telefonului iar înălțimea de 220;

∑ chartConfig: contine detalii cu privire la stilul diagramei. Detaliile cu stilul chart-


ului au fost implementate în fișierul „Styles.js” și importate în fișierul „Home.js”.
Am ales această abordare pentru a putea împărtăși design-ul diagramei și cu alte
componente funcționale. Acest atribut conține detalii de design; precum culoarea
de background, variația culorilor în diagramă, culoarea etichetei și a text-ului
prezent în diagramă; precum și culoarea și forma punctelor din interiorul diagramei.

<LineChart
data={{
datasets: [{ data: lineChartDataset }],}}
width={Dimensions.get("window").width}
height={220}
chartConfig={chartConfig}
bezier
style={{ marginVertical: 5, borderBottomRadius: 15 }}/>
Secvența de cod IV.11 : implementarea diagramei „LineChart” în cadrul paginii „Home”

50
export const chartConfig = {
backgroundColor: "#e26a00",
backgroundGradientFrom: "#4682B4",
backgroundGradientTo: "#87CEFA",
borderRadius: 10,
color: (opacity = 1) => `white`,
labelColor: (opacity = 1) => `white`,
style: { borderBottomRadius: 16 },
propsForDots: { r: "6", strokeWidth: "2", stroke: "#191970" },
}
Secvența de cod IV.12 : implementarea obiectului exportat din fișierul mamă „Styles.js” și
importat în cadrul paginii Home. Acesta este folosit pentru stilizarea componentei „Linechart”,
definită în program ca și în secvența de cod postată anterior

Utilizatorul are două opțiuni de a accesa sertarul de meniu: fie prin glisarea la
dreapta, fie prin apăsarea butonului „Menu”. Acest buton este disponibil în fiecare fereastră
principală a aplicației. Butonul „Menu” este definit în cadrul funcției ce definește opțiunile
ferestrei. Această funcție se denumește screenOptions și va fii (împreună cu funcția componentă
HomeScreen”) exportată către meniul de navigație al aplicației. În cadrul funcției „screenOptions”
sunt prezente variabila „headerTitle” ce redă titlul paginii („Homepage”) și variabila „headerLeft”,
ce este prezentată ca fiind o funcție ce returnează un obiect JSX, simbolizând o icoană în formă de
meniu. Aceasta este localizată în partea din stânga a header-ului paginii. Pentru stilizarea icoanei,
am folosit componentele native „HeaderButtons” și „Item” prezente în librăria „react-navigation-
header-buttons”. Pentru stilizarea butonului, am creat o funcție ce returnează un obiect JSX,
prezentă în fișierul „HeaderButton.js”. Aceasta a fost importată în cadrul fișierului „Home.js” și
definește componenta butonului. Are mărimea de „23” și culoarea specifică sistemului de operare
unui design de produs IOS sau Android. Cum aplicațiile IOS au de regulă fundalul alb și scrisul
colorat, icoana va avea culoara specifică variabilelei „primary”, definită în fișierul unde sunt
depozitate culorile aplicației. Dacă utilizatorul accesează aplicația printr-un dispozitiv Android,
atunci culoarea icoanei va fii albă. Un alt aspect ce ține cont de tipul sistemului de operare al
telefonului este modelul icoanei alese: pe un dispozitiv android, se va folosi o icoană „md-menu”;
în timp ce pe un dispozitiv IOS se va folosi „ios-menu”. Pentru determinarea sistemului de operare

51
se va folosi obiectul nativ „Platform.OS”. Funcția „screenOptions” are un parametru, ce este folosit
pentru a putea efectua o tranziție între două ferestre. Odată ce utilizatorul va apăsa pe icoana de
meniu, se va afișa pe jumătatea stângă a ecranului meniul de sertar. Cum am precizat și anterior,
această acțiune poate fi efectuată și prin glisarea la dreapta.

export const screenOptions = (navData) => {


return {
headerTitle: "Homepage",
headerLeft: () => (
<HeaderButtons HeaderButtonComponent={HeaderButton}>
<Item
title="Menu"
iconName={Platform.OS === "android" ? "md-menu" : "ios-menu"}
onPress={() => {
navData.navigation.toggleDrawer();
}}
/>
</HeaderButtons>
),
};
};
Secvența de cod IV.13: implementarea functionalității prin care utilizatorul poate accesa sertarul
de meniu, prin apăsarea iconiței de meniu aflate în partea stangă a barei de acțiuni

În fișierul „FinanceNavigator.js” este definit sistemul de navigare sertar. În acest


fișier se determină accesul caracteristicii native de cameră (ce are rol de actualizare a pozei de
profil), întregul arbore de navigație al aplicației; precum și funcționalitatea de deconectare din
aplicație. Intregul arbore de navigare al programului se definește prin importarea tuturor
componentelor funcționale de tip fereastră și opțiunile ferestrelor aferente fiecărei pagini; precum
și prin structurarea acestora în cadrul navigatorilor de tip stivă, respectiv de file (așa cum au fost
organizate în Figura III.3). De asemenea, se definește design-ul pentru opțiunile de navigare din
cadrul navigatorului sertar în variabila „defaultNavOptions”. Font-ul scrisului este de tip „open-

52
sans-bold”, iar culorile background-ului și scrisului sunt definite în concordanță cu sistemul de
operare al telefonului (exact ca și în definirea butonului de deschidere al meniului). Așa cum am
precizat și în capitolul anterior, navigatorul principal sertar are 6 copii direcți, ce conduc către alte
navigatoare, acestea conducând la randul lor catre alte navigatoare sau un punct final, reprezentat
de o pagină în aplicație.

Componenta funcțională „FinanceNavigator” returnează un obiect JSX ce redă


interfața grafică a navigatorului principal al aplicației. În momentul accesări sale, se afișează o
animație de loading, până sunt recuperate datele din server, cu privire la informatiile din profilul
utilizatorului. Containerul ce conține copii navigatorului dispune de 3 atribute: „drawerStyle”
(folosit pentru stilizarea sertarului „FinanceDrawerNavigator”), „drawerContent” (conținutul
navigatorului sertar) și „drawerContentOptions” (stilul fiecărei componente navigator din cadrul
rutei principale „FinanceDrawerNavigator”). Stilul asignat atributului „drawerStyle” este format
dintr-un obiect, importat din fișierul „Styles.js”. În cadrul atributului „drawerContent” este prezent
întregul obiect JSX ce reprezintă interfața grafică a navigatorului. În cadrul acestui obiect, sunt
definite funcționalitatea de cameră, de navigare în cadrul aplicației și de deconectare din aplicație.

În prima parte a navigatorului (reprezentată de conținutul primului View secundar al


obiectului returnat de funcția „FinanceNavigator”) este prezentă fotografia de profil a
utilizatorului; precum și funcționalitatea de cameră, prin utilizarea căreia consumatorul aplicației
își actualizează imaginea de profil. Aceste caracteristici sunt redate utilizatorului prin componenta
nativă „Image” (în cadrul căreia se vede fotografia de profil a utilizatorului) și prin componenta
custom „ImgPicker” (ce îndeplinește funcționalitatea nativă de cameră). Stilul imaginii de profil
este preluată tot din fișierul „Styles.js”; url-ul imaginii fiind recuperat din cadrul serverului
„Realtime Database”. Componenta custom „ImgPicker” este importată din fișierul
„NavigationMethod.js” și primește în cadrul atributului „onImageTaken” metoda manipulativă
„updateProfilePictureHandler”. Această funcție se ocupă cu actualizarea fotografiei de profil,
expediind acțiunea către metoda „updateProfilePicture” din cadrul codului Redux.

În interiorul componentei funcționale „ImgPicker” din cadrul fișierului


„NavigationMethods” se verifică permisiunile aplicației de a accesa camera telefonului. Prin
intermediul obiectului „Permissions”, importat din librăria integrată manual „expo-permissions”,
aplicația cere consimțământul utilizatorului pentru a accesa serviciul de cameră al aplicației. În

53
cazul în care utilizatorul nu-și dă consimțământul, cererea acestuia de a-și actualiza fotografia de
profil va fi respinsă.

const verifyPermissions = async () => {


const result = await Permissions.askAsync(Permissions.CAMERA);
if (result.status !== "granted") {
Alert.alert(
"Insufficient permissions!",
"You need to grant camera permissions to use this app.",
[{ text: "Okay" }]
);
return false;
}
return true;
};
Secvența de cod IV.14: implementarea metodei asincrone „verifyPermission”, ce verifică
permisiunea aplicației de a accesa funcționalitatea nativă de cameră

În caz afirmativ, prin intermediul metodei „newProfilePic” și, implicit, a obiectului


„ImagePicker” importat din librăria „expo-image-picker”, aplicația va comunica cu serviciul de
camera al telefonului și se va deschide camera utilizatorului; permițând astfel consumatorului
aplicației de a actualiza fotografia de profil. Fotografia făcută va avea un aspect de 9:9, având o
calitate puțin inferioară de 0.5, pentru a nu stoca în depozitul serverului un bloc mare de memorie.
Camera telefonului se va deschide la apelarea cu success a metodei asincrone
„launchCameraAsync”. Atât metoda „newProfilePic”, cât și cea ilustrată în secvență de cod
anterioară sunt asincrone, întrucât execuția trebuie să aștepte până la confirmarea utilizatorului,
respectiv până la efectuarea fotografiei de către acesta. Ulterior, utilizatorul va fii avertizat cu
privire la acțiunea de schimbare a pozei de profil. În cazul în care își dă consimțământul cu privire
la schimbarea fotografiei, funcția preluată din componenta funcțională „FinanceNavigator” se va
apela prin intermediul atributului ce o definește, „onImageTaken”. Aceasta va expedia datele cu
privire la noua imagine de profil către codul Redux.

54
const newProfilePic = async () => {
const hasPermission = await verifyPermissions();
if (!hasPermission) {
console.log("Not permission");
return;
}
const image = await ImagePicker.launchCameraAsync({
allowsEditing: true,
aspect: [9, 9],
quality: 0.5,
});
Alert.alert(
"Update profile picture!",
"Are you sure you want to update your profile picture?",
[
{
text: "Okay",
onPress: () => {
props.onImageTaken(image);
},
},
{ text: "Cancel", onPress: () => {} },
]
);
};
Secvența de cod IV.15: implementarea metodei asincrone „newProfilePic”, ce verifică
permisiunea aplicației de a accesa camera, activează funcționalitatea de cameră în cadrul
aplicației și trimite, la consimțământul utilizatorului, datele cu privire la noua fotografie de
profil către codul Redux

55
Funcționalitatea de schimbare a imaginii de profil se realizează prin intermediul obiectului
JSX returnat de metoda „ImgPicker”, în momentul în care utilizatorul apasă pe componenta nativă
„TouchableNativeFeedback”.

A doua funcționalitate prezentă în cadrul corpului navigatorului sertar este cea de navigare
către alte rute. Aceasta se află în interiorul celei de-a două componente native „View” și conține
rutele ce duc către navigatorii copii ai rutei principale „FinanceDrawerNavigator”. Toți copiii
navigatorului sertar sunt introduse ca elemente props în cadrul componentei „DrawerItemList”,
importată din biblioteca integrată manual „@react-navigation/drawer”. Întrucât i-am enumerat și
detaliat în capitolul anterior, nu o să mă axez pe prezentarea acestora.

Cea de-a treia funcționalitate existentă în corpul navigatorului este cea de


deconectare din cadrul aplicației. Această funcție se declanșează la apăsarea butonului „Logout”.
În momentul apăsării acestuia, codul React Native va expedia către codul Redux obiectul returnat
de către funcția Middleware „logout” (apelată cu ajutorul obiectului „authActions”; ce cuprinde
totalitatea funcțiilor folosite în codul Redux pentru autentificare). Metoda middleware „logout”
este plasată în cadrul fișierului „Auth.js” din containerul „actions”.

56
<View style={{

flex: 1,
paddingTop: 20,
opacity: 1, }}>
<SafeAreaView forceInset={{ top: "always", horizontal: "never" }}>
<View
style={{flex: 1,justifyContent: "center",alignItems: "center",marginTop: 100,}}>
<Image
style={imageProfileStyle}
source={{ uri: profile.profilePic }}
accessibilityLabel="label"/>
<ImgPicker onImageTaken={updateProfilePictureHandler} />
<Text style={{ fontSize: 30, fontFamily: "open-sans" }}>
{profile.userName}
</Text>
</View>
<View style={{ marginTop: 100 }}>
<DrawerItemList {...props} />
<View style={{ marginTop: "5%" }}>
<Button
title="Logout"
color={Colors.primary}
onPress={() => {
dispatch(authActions.logout());}}/>
</View>
</View>
</SafeAreaView>
</View>
Secvența de cod IV.16: obiectul returnat de componenta functională „FinanceNavigator”, ce
definește interfața graficaă a navigatorului principal, cuprinzând cele trei funcționalități
prezentate anterior

57
Întrucât ar fi redundant să exemplific fiecare navigator copil în parte, îmi propun să detaliez
un singur navigator, deoarece multe detalii și specificații s-ar asemăna cu celelalte navigatoare
prezente în interiorul rutei principale „FinanceDrawerNavigator”.

Navigatorul „Expenses” înglobează componenta „ExpensesNavigator” care, la rândul ei,


conține două navigatoare de tip stivă. Primul copil apare sub numele de „Transactions” și oferă
suport de navigație către ferestrele dedicate creeri, respectiv vizualizării istoricului de tranzacții; în
timp ce al doilea copil „DoSavings” furnizează opțiunea de navigare către fereastra ce conține un
meniu cu funcționalitățile necesare pentru a face economii, respectiv prin limitarea bugetului de
cheltuieli zilnice și prin posibilitatea utilizatorului de a-și crea notițe cu privire la modul de
gestionare a banilor. În cadrul navigatorului de file „ExpensesNavigator” am stilizat butoanele de
navigație către navigatoarele stivă „Transactions” și „DoSavings” prin intermediul atributului
screenOptions. Acest atribut primește o funcție, ce determină icoana simbolică pentru navigatorul
„Transactions”, respectiv „DoSavings”, prin intermediul obiectului „tabBarIcon”. Icoana
navigatorului „Transactions”, respectiv „DoSavings” este definită cu ajutorul componentei
„Ionicons”, ce este importată din librăria integrată manual „react-native-vector-icons/Ionicons”.
Culoarea acesteia este albastrul pentru ambele tipuri de navigatoare și ambele tipuri de sisteme de
operare: Android și IOS. Însă, tipul icoanei diferă în funcție de mai multe circumstanțe.

În primul rând, o icoană ce conduce către ruta cu numele „Transactions” poate fi de două
tipuri: „ios-cash” și „ios-cash-outline”. Tipul icoanei se decide în funcție de starea actuală a rutei.
Dacă aplicația este deschisă în cadrul rutei „Transactions”, atunci aceasta va fii de tipul „ios-cash”,
altfel „ios-cash-outline”. Analog cu ruta „DoSavings”, aceasta poate fi de două tipuri: „ios-card”
și „ios-card-outline”. Circumstanțele în care este definit un tip sunt aidoma cu cele ale rutei
„Transactions”.

În cadrul atributului tabBarOptions se definește design-ul unui navigator de file. Culoarea


background-ului este definită într-un obiect din fișierul „Colors.js” și importată în fișierul actual,
fiind atașată obiectului „style”, câmpul „backgroundColors”. Înălțimea navigatorului este de 65px.
În momentul în care navigatorul este activ, titlul navigatorului are culoare neagră; în caz contrar,
are culoarea gri.

Icoana navigatorului „Expenses” din cadrul navigatorului principal este definită cu ajutorul
componenței „Ionicons”, ce este importată din librăria integrată manual „react-native-vector-

58
icons/Ionicons”. Tipul icoanei diferă, din nou, de sistemul de operare al telefonului. Dacă celularul
rulează pe Android, atunci Icoana va avea tipul „md-cart”, altfel „ios-cart”. Mărimea acesteia este
de 23 iar culoarea albastră.

59
export const ExpensesNavigator=()=> {

return (
<ExpensesTabNavigator.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ focused, color, size }) => {
let iconName;
if (route.name === "Transactions") {
iconName = focused ? "ios-cash" : "ios-cash-outline";
} else if (route.name === "DoSavings") {
iconName = focused ? "ios-card" : "ios-card-outline";}
return <Ionicons name={iconName} size={40} color="blue" />;},
})}
tabBarOptions={{
style: { backgroundColor: Colors.navigationColor, height: 65 },
activeTintColor: "black",
inactiveTintColor: "gray",
}}>
<ExpensesTabNavigator.Screen
name="Transactions"
component={NewTransactionNavigator}/>
<ExpensesTabNavigator.Screen
name="DoSavings"
component={SavingsNavigator}/>
</ExpensesTabNavigator.Navigator>
);
}
Secvența de cod IV.17: implementarea metodei „ExpensesNavigator”, ce returnează un obiect
care definește atât componenta navigatorului Expenses, cât și stilizarea componentelor copii ale
acestuia

60
De asemenea, navigatorul „ExpensesNavigator” are legătură cu alte 2 rute: „Transactions”
și „DoSavings”. În cadrul rutei „Transactions”, se regăsesc 2 pagini, împachetate într-un navigator
de tip stivă. Aceste pagini fac referire la istoricul tranzacțiilor efectuate de către utilizator, respectiv
la solicitarea acestuia de a efectua o nouă tranzacție. Fiecare obiect fereastră al navigatorului din
cadrul rutei „Transactions” și „DoSavings” are atașat un nume de rută către aceasta, componenta
fereastră (făcând referire la componentă funcțională ce returnează obiectul redat în interfața
grafică) și opțiunile paginii din cadrul barei de acțiuni. Rutele navigatorului stivă „Transactions”
sunt „Transactions” și „NewTransactions”. Prima rută conduce execuția programului către pagina
„Transactions”, implementată în fișierul „Transactions.js” din cadrul containerului „Expenses” și
importată împreună cu opțiunile paginii în cadrul fișierului actual, „FinanceNavigator.js”. Analog,
pagina „NewTransactions” este implementată în fișierul cu același nume, din cadrul aceluiași
container cu fișierul „Transactions.js” și importată în fișierul „FinanceNavigator”. Asemănător,
navigatorul „DoSavings” conține patru rute către ferestre din cadrul aplicației, fiind integrate în
cadrul containerului asociat navigatorului „DoSavings” prin intermediul obiectelor de tip
fereastră.

61
const NewTransactionStackNavigator = createStackNavigator();
export const NewTransactionNavigator = () => {
return (
<NewTransactionStackNavigator.Navigator screenOptions={defaultNavOptions}>
<ExpensesStackNavigator.Screen
name="Transactions"
component={TransactionsScreen}
options={transactionsOptions}
/>
<NewTransactionStackNavigator.Screen
name="NewTransaction"
component={NewTransactionScreen}
options={newTransactionOptions}
/>
</NewTransactionStackNavigator.Navigator>
);
};
Secvența de cod IV.18: instantierea metodei „NewTransactionStackNavigator” ca un navigator
de tip stivă, precum și definirea rutelor acestuia (Transactions și NewTransactions) în cadrul
obiectului returnat de această funcție

Dintre toate ferestrele importate în fișierul „StartupScreen.js”, fereastra


„NewsWebScreen” este prezentă în două rute ale programului. În cadrul acestei ferestre este afișată
o pagină web, în interiorul aplicației. Această pagină este accesată în momentul în care utilizatorul
primește o notificare, redirectionându-l pe acesta într-o pagină web a unui site financiar. Cele două
rute în care aceasta componentă funcțtională este prezentă sunt „UnsignedNewsWebView”, din
cadrul navigatorului stivă folosit pentru autentificare; și „SignedNewsWebView”, aflată în
interiorul navigatorului „DoResearch”. Singura diferență dintre rutele care fac referință la acest
obiect este că în cadrul paginii aferente rutei din navigatorul pentru autentificare nu există bară de
acțiuni. Acest lucru se datorează faptului că utilizatorul nefiind autentificat, acesta nu poate accesa
serviciile aplicației.

62
În cadrul paginii „Transaction”, prezentate anterior, se află istoricul tuturor tranzacțiilor.
Cu ajutorul functionalităților „useDispatch” și „useSelector” din cadrul librăriei „react-redux” se
recuperează datele din server cu privire la tranzacțiile efectuate de utilizator până în prezent, prin
intermediul funcției „useEffect”; și se extrag aceste informații ce au fost stocate în interiorul
depozitului Redux. De asemenea, se extrage din containerul Redux informația cu privire la valuta
pe care utilizatorul a dorit să o folosească în cadrul aplicației. Datele cu privire la fiecare tranzacție
efectuate sunt afișate corespunzător, în interiorul componentei native „FlatList” prezente în
obiectul returnat de componenta funcțională „Transaction”. Aceasta furnizează o lista de obiecte
derulabile, ce cuprinde totalitatea tranzacțiilor efectuate. Componenta nativă „FlatList” oferă
eficiență de timp în cazul unui istoric lung de tranzacții, întrucât oferă serviciul de afișare dinamică
a datelor.[20]

Această componentă nativă primește trei atribute: „data” (ce cuprinde lista de date
care se vor randa în interfață), „keyExtractor” (cheia unică a unui obiect din lista, definind
unicitatea obiectului) și „renderItem” (codul JSX care definește modul în care un obiect din lista
de date va fii redat in interfața grafică).

Atributului „data” îi este asignat lista de tranzacții efectuate până în prezent.


Atributul „keyExtractor” este definit prin id-ul corespunzător fiecărei tranzacții; în timp ce atributul
„renderItem” are o definire mai complexă, definindu-se printr-o funcție ce returnează un obiect
JSX. Codul JSX al atributului „renderItem” este format din componenta custom „PlaceItem”,
implementată în fișierul „ListItem” și importată în fișierul prezent. Această componentă custom
este folosita și la afișarea notițelor scrise de utilizator. Componenta aceasta are la rândul ei 3
atribute, având următoarele nume și roluri:

∑ title: compania la care s-a efectuat tranzacția;


∑ amount: suma tranzacționată;
∑ dateTime: data la care s-a efectuat tranzacția.

20
Nimra Saad,What is FlatList and how to use FlatList in React Native, https://www.folio3.com/mobile/blog/what-is-flatlist-and-how-to-use-
flatlist-in-react-native/

63
<FlatList
data={transactions}
keyExtractor={(item) => item.id}
renderItem={(itemData) => (
<PlaceItem
title={itemData.item.title}
amount={
(parseInt(itemData.item.amount) / currency.rate)
.toFixed(0)
.toString() + currency.currency
}
dateTime={itemData.item.dateTime}
></PlaceItem>
)}
/>
Secvența de cod IV.19: structura componentei native „FlatList”; folosită pentru redarea în mod
dinamic a tuturor tranzacțiilor efectuate de utilizator

Prin intermediul ferestrei „Transactions” se poate efectua navigarea către fereastra


„NewTransaction”, pentru a efectua o nouă tranzacție în cadrul aplicației. Funcționalitatea de
navigare către această fereastră se face prin intermediul apăsării pe icoana „md-add” sau „ios-
add”, aflate în partea dreapta a barei de acțiuni.

În cadrul rutei „DoSavings”, prezentată în cadrul descrierii navigatorului


„ExpensesNavigator”, este definită o stivă de pagini, ce au rolul de a-l ajuta pe utilizator în a-și
gestiona veniturile și a face economii. Prima pagină a rutei se prezintă că fiind fereastră de meniu;
în cadrul navigatorului „DoSavings”. Prin intermediul acesteia, utilizatorul accesează una dintre
funcționalitățile dispuse în cadrul navigatorului stivă „DoSavings”. Ruta care conduce către
componenta funcțională „Alert” are rolul de a-i limita sumele cheltuite zilnice; în timp ce rutele
care conduc către componentele funcționale ce definesc paginile „Note”, respectiv „NoteDetails”
alcătuiesc un jurnal cu planurile de economie ale consumatorului aplicației.

64
Fereastra „Alert” dispune de două posibilități pentru utilizator de a-și seta un maxim de
cheltuieli zilnic. Prima este manuală, suma fiind aleasă de către consumatorul aplicației. A doua
este recomandată de aplicație, întrucât clientul comunica cu API-ul băncii pentru a primii o valoare
aproximativă admisă pe care utilizatorul să o cheltuie. Predicția acestei sume este calculată pe baza
salariului și valorii nete a utilizatorului utilizându-se tehnica de învățare automată. Programul din
cadrul server-ului băncii (reprezentată prin serverul Node.js) determină o predicție bazată pe
istoricul sumelor cheltuite zilnic de către investitorii de succes, ce au colaborat cu banca sau
instituția financiară.

Toate notițele afișate în fereastra „Note” (în același stil în care au fost afișate și istoricul
tranzacțiilor, folosindu-se componenta nativă „FlatList” și cea custom „PlaceItem) au atașate două
funcționalități: de ștergere, prin apăsarea butonului „Delete”, atașat unui obiect din cadrul listei de
elemente; dar și de editare a unui item. Cea de-a doua funcționalitate se declanșează în momentul
în care autorul apasă pe un anumit item din listă, redirecționând utilizatorul către ruta
„NoteDetails”, primind ca parametru id-ul notiței alese.

În cadrul rutei „NoteDetails” se află fereastra folosită pentru editarea, respectiv crearea unei
noi notițe. Inițial, se verifică prin parametrul „props” dacă există un parametru al unei rute cu
numele de „noteId”. În caz afirmativ, e de înțeles că pagina a fost accesată folosindu-se de un item
al listei „FlatList”, descrise în paragraful anterior. Astfel, se va cauta în containerul Redux notița
cu respectivul id, folosindu-se funcția hook „useSelector” și metoda javascript „find” (folosită
pentru a caută un obiect , prin intermediul unui câmp al acestuia). Odată găsită, se vor umple
câmpurile de editare „Title” și „Text” ale componentelor „Input” cu datele notiței; aceasta urmând
să fie modificate. În cazul în care nu există un parametru props cu numele de „noteId”, utilizatorul
va fii redirecționat către aceeași pagină, dar cu câmpurile necompletate.

În momentul confirmării editării sau creerii unei notițe, se verifică dacă câmpurile „Title”
și „Text” sunt completate. În caz afirmativ, se verifică dacă a existat parametrul „noteId”, provenit
din urmărirea unei rute. În situația în care a existat acest parametru, se va expedia obiectul returnat
de metoda „refreshNote”, urmând ca datele notiței existente să fie actualizate. În caz contrar, se va
expedia obiectul returnat de funcția „addNote”, rezultând în crearea unei noi notițe cu datele
introduse de către consumatorul aplicației. În cazul în care câmpurile nu au fost completate, i se va
afișa o eroarea utilizatorului cu privire la necompletarea unor câmpuri. De asemenea, utilizatorul

65
va fii înștiințat prin intermediul unei ferestre pop-up, dacă prelucrarea comenzii sale nu a putut fii
realizată cu succes. În situația în care toate procesele s-au realizat cu succes, utilizatorul va fii
redirecționat către pagina precedentă, adică „Notes”.

În cadrul paginii „Profile” se află informații generale cu privire la profilul utilizatorului:


numele și prenumele, salariul (în valută curentă), adresa de e-mail și data de naștere. Aceste date
sunt preluate din codul Redux la redarea paginii. În cazul în care utilizatorul a introdus incorect
data de naștere sau salariul sau a fost modificat, acesta poate să-și actualizeze informațiile, apăsând
pe iconița „md-menu” sau „ios-menu”, aflată în partea dreapta a barei de acțiuni. Odată apăsată,
utilizatorul va fii redirecționat către ruta „UpdateProfile”, ce afișează o fereastră unde utilizatorul
își poate actualiza datele specificate mai sus.

În fișierul ce cuprinde ruta „UpdateProfile” este construit un reducer, folosit la


managementul state-urilor. Aceste stări sunt utilizate pentru integrarea și validarea câmpurilor ale
formularului de editare a datelor de profil. Acesta stochează datele introduse de utilizator, cu privire
la salariul sau și data sa de naștere. În urma confirmării datelor, acestea sunt expediate către codul
Redux, urmând că aceste date să fie actualizate în cadrul platformei Firebase și a depozitului Redux.
Pentru selectarea datei m-am folosit de componenta nativă „DatePicker”, importată din librăria
„react-native-community/datetimepicker”.

În interiorul stivei navigator „Bank accounts” sunt prezente două rute: „AccountOverview”
și „AddAccount”. Ruta „AccountOverview” conduce execuția programului către componenta
funcțională „AccountsOverview”, ce redă lista cu sumele din fiecare cont bancar deschis.
Utilizatorul poate să transfere o suma de bani dintr-o banca în altă, utilizându-se de butonul
„Withdraw” pentru a expedia bani din contul curent, respectiv „Deposit” pentru a depozita bani în
respectivul cont. Acest transfer se face exclusiv prin intermediul contului bancar principal
(„BCR”). Pentru a se transfera o sumă de bani între două conturi bancare secundare, expeditorul
trebuie mai întâi să expedieze suma dorită către contul „BCR”, urmând ca apoi să-i transfere către
banca receptoare. Pentru a putea închide un cont bancar , acesta trebuie să aibă în depozit suma 0.
Întrucât contul de la banca „BCR” este cel principal, acesta nu poate fii închis sub nici o
circumstanță. Pentru a deschide un nou cont bancar, utilizatorul trebuie să apese pe butonul situat
în baza paginii „LinkBankAccount”.

66
Acesta recuperează datele din server cu privire la conturile bancare deschise și le redă în
cadrul interfeței grafice prin intermediul componentei native „FlatList”. Fiecare item al listei de
date ale componentei „FlatList” este identificat prin id-ul contului bancar. Itemele listei, ce
reprezintă conturile bancare deschise, sunt redate în interfața grafică prin intermediul componentei
funcționale „PlaceBank”. Această componentă este implementată în cadrul fișierului
„BankItem.js”, situat în container-ul „components” și importată în fișierul actual. Am folosit
această tehnică de import a componentelor prezente în interfața grafică redată de componenta
funcțională „AccountsOverview” pentru a nu supraîncărca pagina de cod a fișierului
„AccountsOverview.js”. Componenta „PlaceBank” primește ca atribute titlul băncii, suma (în
valuta aleasă de utlizator) din cadrul contului bancar, funcționalitatea „onDeposit” , „onWithdraw”
și „onDelete”. Toate datele și funcționalitățile componentei „PlaceBank” primite ca atribute în
cadrul componentei „AccountsOverview” sunt accesate prin parametrul props. La accesarea
metodei „onDeposit” se va activa modalul „visibleDepositModal”. Acest modal îi cere
utilizatorului să introducă suma pe care dorește s-o depoziteze în cadrul contului selectat. Suma
minimă pentru depozitare este 10000; astfel dacă introduce o suma mai mică, i se va afișa o
atenționare. În cazul în care condiția se respectă, se expediază către codul Redux obiectul returnat
de funcția updateAccount, importată din codul „Redux”. Aceasta primește că parametrii id-ul
băncii în care se dorește a se depozita bani , precum și suma depusă. În cazul unei erori ale
serverului sau a uneia apărute din greșeala utilizatorului, prin faptul că a încercat să depoziteze o
suma de bani mai mare decât cea existentă în contul principal; aceasta va fi tratată în cadrul blocului
„catch”, fiind ulterior afișată într-o fereastră pop-up utilizatorului. În cazul unui proces efectuat cu
succes, se va actualiza lista de conturi bancare, închizându-se totodată modalul curent. Metoda
„onWithdraw”, prin care se scot bani dintr-un cont bancar funcționează pe același principiu.
Singura diferență este că utilizatorul poate efectua o greșeală, prin încercarea de a transfera o suma
de bani mai mare decât cea existentă în contul curent. Prin metoda „onDelete” se închide un cont
bancar curent. Obiectul returnat de componenta „BankItem” este compus din componenta nativă
„TouchableNativeFeedback” (ce împachetează întreg codul JSX al componenței), View, Text,
Button și „FontAwesome” (icoană importată din librăria „@expo/vector-icons”, ce are forma unei
instituții bancare). Design-ul componentei „BankItem” este plasat pe trei rânduri: în primele două
se specifică titlul băncii, respectiv suma deținută la banca specifică; iar pe cel de-al treilea rând
sunt situate funcționalitățile contului bancar, ce pot fi accesate prin intermediul butoanelor ce

67
declanșează apelarea metodelor prezentate anterior: „onDeposit”, „onWithdraw” și „onDelete”.
Cum contul din banca „BCR” este cel principal, am ales să dezactivez funcționalitățile din cadrul
acestui cont, deoarece acest cont bancar este un intermediar între conturile secundare ale
consumatorului aplicației. Butoanele „Deposit”, „Withdraw” și „Delete” sunt situate pe același
rând, în interiorul unei componente native View. Stilul acestei componente este redată prin obiectul
stilistic „infoContainer”, ce ține de obiectul principal folosit pentru stilizare „styles”. Pentru ca
butoanele să fie redate în linie, a trebuit să atribui câmpului „flexDirection” din cadrul obiectului
„infoContainer” valoarea „row” (valoarea acestui câmp fiind „column” by default).

<TouchableNativeFeedback onPress={props.onSelect} style={styles.bankItem}>


<View style={styles.infoContainer}>
<View style={styles.inlineTitle}>
<FontAwesome name="bank" size={30} color="black" />
<Text style={styles.title}>{props.title}</Text>
</View>
<Text style={styles.content}>{props.amount}</Text>
{props.onDeposit && (
<View style={styles.inlineButtons}>
{props.title !== "BCR" && (
<Button title="Deposit" onPress={props.onDeposit} />
)}
{amountOnlyNumber != 0 && props.title !== "BCR" && (
<Button title="Withdraw" onPress={props.onWithdraw} />
)}
{amountOnlyNumber == 0 && props.title !== "BCR" && (
<Button title="Delete" onPress={props.onDelete} />
)}
</View>
)}
</View>
<View style={styles.actions}>{props.children}</View>
</TouchableNativeFeedback>
Secventa de cod IV.20: structura codului implementat pentru definirea componentei native
„PlaceBank”, ce afișează în mod etic datele utilizatorului cu privire la un cont bancar deschis

În situația în care utilizatorul dorește să deschidă un nou cont bancar, acesta trebuie să
acceseze butonul „Link Bank Account”. În momentul accesări sale, consumatorul aplicației va fi
redirecționat către componenta funcțională „AddAccount”, ce redă pagina cu posibilele bănci unde
utilizatorul și-ar putea deschide cont bancar. Listele cu băncile disponibile sunt listate folosindu-se

68
componentele „FlatList” și „BankItem”, așa cum sunt descrise și prezentate pentru componenta
funcțională prezentată anterior. Aplicația permite deschiderea unui singur cont bancar per bancă.
Astfel, odată ce un cont este deschis, respectiva bancă nu va mai apărea în lista de conturi din
cadrul paginii „AddAccount”. Suma minimă necesară pentru a deschide un cont este de 10000,
această fiind preluată din contul principal „BCR”. De asemenea, odată ce un cont este închis,
utilizatorul are posibilitatea de a-l redeschide în cadrul paginii.
Navigatorul stivă „Settings” conține doar fereastra „Settings”, ce este redată prin
componenta funcțională care poartă același nume. În cadrul acestei pagini i se oferă utilizatorului
opțiunile de schimbare a adresei de e-mail, respectiv parolă; precum și schimbarea valutei prezente
în cadrul aplicației. În cazul modificării parolei, respectiv a adresei de e-mail; este necesară
confirmarea modificării datelor prin e-mail. La fiecare cerere de modificare, componenta
funcțională comunica cu codul Redux, pentru a actualiza datele utilizatorului atât în cadrul
serverului, cât și în interiorul depozitului Redux. În urma efectuării unei schimbări cu succes,
utilizatorul va fi înștiințat cu privire la succesul comenzii sale, printr-un compartiment în care este
precizat faptul că execuția comenzii sale a reușit. Afișarea pentru o scurtă durată a acestui
compartiment se realizează folosindu-se obiectul „ToastAndroid”, importat din biblioteca „react-
native”.
Navigatorul „Portfolio” are în componența sa doi copii: ruta care îi poartă numele și
navigatorul stivă „DoResearch”. Navigatorul „Portfolio” conține la rândul ei o singură rută, ce
redirecționează aplicația către fereastra cu numele „PortfolioOverview”.
Componenta funcțională „PortfolioOverview” redă pagina cu același nume și se află în
interiorul fișierului „PortfolioOverview.js”, situat în containerul „Portfolio”. Această pagină are un
conținut consistent și se prezintă că fiind platforma de pe care utilizatorul poate efectua investiții
în cadrul bursei de valori.
Numărul de stări, respectiv de date recuperate din codul Redux este unul consistent. Pe
lângă variabilele comune folosite pentru afișarea erorilor sau a animației de loading, mai sunt și
cele ce îndeplinesc rolul de suport în interfață, în cadrul afișării informațiilor din interiorul
modalelor; dar și în transmiterea unei execuții în cadrul platformei către codul Redux. În cadrul
acestei pagini, se recuperează din serverul platformei Firebase, prin intermediul codului Redux;
datele cu privire la istoricul investițiilor făcute de utilizator, tranzacțiile și conturile bancare ale
acestuia. Metodele ce recuperează aceste date din cadrul serverului sunt implementate în codul

69
Redux și importate în fișierul curent. Acestea poartă numele sugestive „fetchAccounts”,
„fetchTransactions” și „fetchInvestments”. De asemenea, se depozitează în codul Redux datele
investițiilor utilizatorului, formatate și prelucrate în cadrul API-ului serverului Node.js, astfel încât
să scutească clientul din a executa anumite calcule ce ar ocupa spațiu în cod și ar maximiza mărimea
aplicației. Metoda ce efectuează aceste procese se cheamă „getPortfolioData”; și este implementată
în cadrul codului Redux, secțiunea „actions”. Nu o să detaliez implementarea acestei
funcționalități, întrucât am descris-o și în cadrul unei alte pagini în care am folosit-o, mai exact în
cadrul ferestrei „Home” .
În continuare, vreau să detaliez stările existente în cadrul acestei pagini, întrucât pot apărea
neînțelegeri în cadrul explicării codului și metodelor existente în fișier datorită numărului
consistent al acestora:
o visibleBuyModal/visibleSellModal: variabile booleene, folosite pentru activarea
modalului prin care se vând/cumpără acțiuni;
o isLoading: variabilă booleana, folosită pentru afișarea animației de loading, la
apăsarea unui buton;
o error: variabilă prin care se salvează eroarea primită de la codul Redux, urmând să
fie afișată pe ecran, prin intermediul unei ferestre pop-up;
o countOperation: variabilă folosită pentru recuperarea noilor date din codul Redux;
necesare în redarea paginii, după o investiție efectuată;
o category: variabilă folosită pentru a selecta categoria de acțiuni, pentru care se va
deschide un modal ; în cadrul căruia se vor efectua acțiuni de vânzare/cumpărare;
o modalShareValue: înștiințează utilizatorul cu privire la cheltuiala totală suportată
de acesta, pentru cumpărarea unei cantități de acțiuni;
o portfolioData: datele cu privire la investițiile utilizatorului, formatate în Node.js,
pentru a fii mapate în cadrul atributelor diagramelor prezente în pagină;
o investmentsData: lista de obiecte ce conține istoricul investițiilor utilizatorului;
o totalInvestments: suma totală investită.
În cadrul acestei ferestre, se afișează informații fundamentale cu privire la soldul din
conturile sale bancare, suma totală investită, precum și rația dintre soldul conturilor sale bancare și
suma totală investită; dar și rația dintre soldul total al conturilor bancare și suma totală

70
tranzacționată în afară sistemului de investiții. Aceste informații sunt necesare pentru a înștiința
utilizatorul cu privire la modul în care a gestionat veniturile.
De asemenea, în partea de sus a paginii este ilustrată o diagramă rotundă, ce este împărțită
și reprezentată în „felii”. Fiecare „felie” conține un procentaj, reprezentat prin raportul dintre
numărul de acțiuni deținute pentru o categorie de acțtiuni, în cadrul acelei „felii” și numărul total
de acțiuni deținute. Mai mult decât atât, în dreapta diagramei este afișată o legendă, în care se
specifică numărul de acțiuni deținute în cadrul fiecărei „felii”. Componenta nativă folosită pentru
această reprezentare se numește „PieChart” și este importată din cadrul librăriei „react-native-
chart-kit”. În atributul „data” a componentei „PieChart” se asignează lista cu toate obiectele ce vor
fi inserate în grafic. Aceste date sunt preluate din cadrul serverului Node.js. Întrucât apăreau erori
în cadrul sincronizării preluării datelor din cadrul serverului băncii și redarea acestora prin
intermediul componentei „PieChart”; am asignat variabilei „portfolioData” mock data, pentru a
putea rula componenta „PieChart”. Fiecare obiect trebuie să includă numele indicelui bursier
respectiv, cantitatea de acțiuni deținute în cadrul acelui indice, culoarea „Feliei” ce va fii creată în
cadrul diagramei; culoarea și mărimea scrisului din cadrul legendei diagramei rotunde. „Feliile”
descrise anterior se formează în baza atributului „accesor”. Acest atribut primește câmpul, prezent
în fiecare obiect, prin care se face partajarea ariei diagramei pentru fiecare categorie de acțiuni
deținută.
Întrucât conținutul paginii este foarte întins, acesta nu putea fii redat întreg pentru mărimea
niciunui tip de telefon, soluția fiind de a folosi o componentă ce împachetează întregul obiect JSX
și redă conținutul paginii. Inițial, am folosit un ScrollView ce îngloba întregul conținut al paginii.
Cum aveam nevoie și de componenta nativă „FlatList” pentru a afișa fiecare obiect ce cuprinde
graficul de fluctuație al unei acțiuni, valoarea actuală a unei acțiuni și profiturile dobîndite din
cadrul investițiilor în cadrul acelui indice bursier; nu puteam folosi componenta „ScrollView”,
întrucât aș folosi în cadrul aceeași ferestre două componente cu funcționalitatea „scroll”; ceea ce
este o tehnică greșită de definire a interfeței grafice. De aceea, am instantiat o variabilă ce conține
partea de incipit a paginii (respectiv diagramă rotundă prezentată anterior, cu design-ul aferent) și
am asignat-o atributului „ListHeaderComponente” al componentei „ScrollView”. Astfel, în afară
de componenta „View” ce împachetează tot cuprinsul ferestrei, conținutul interfeței grafice este
introdus în component „ListView”. Fiecare obiect al listei prezintă informații cu privire la
categoriile de acțiuni în care investitorul poate investi, precum și actele de vânzare/ cumpărare în

71
cadrul respectivului indice bursier. Tot acest conținut este redat prin intermediul componentei
custom „MarketItem”, definită în exterior și importată în cadrul paginii. Aceasta primește
următoarele atribute, fiind accesate în cadrul fișierului în care este definită prin intermediul
parametrului props. Aceste atribute au următoarele denumiri și specificații:
o profit: profitul obținut de către investitor în cadrul unei acțiunii;
o amount: numărul total de acțiuni achiziționate;
o category: categoria de acțiuni la care graficul face referire;
o chartData: fluctuația indicelui bursier;
o onBuy: funcționalitatea prin care un investitor poate achiziționa acțiuni, în cadrul
aplicației;
o onSell: funcționalitatea prin care un investitor poate vinde acțiuni, în cadrul aplicației.

72
<FlatList
data={investmentsData}
keyExtractor={(item) => item.category}
ListHeaderComponent={listHeaderComponent}
renderItem={(itemData) => (
<MarketItem
profit={
((itemData.item.variations[
itemData.item.variations.length - 1
] *
itemData.item.totalShares) /
itemData.item.totalInvestments
).toFixed(2) * 100}
amount={itemData.item.totalShares}
category={itemData.item.category}
chartData={itemData.item.variations}
onBuy={() => {
buyFundsHandler(
itemData.item.category,
itemData.item.variations[
itemData.item.variations.length - 1]);}}
onSell={() => {
sellFundsHandler(
itemData.item.category,
itemData.item.variations[
itemData.item.variations.length - 1]);}}/>)}/>
Secvența de cod IV.21: structura codului implementat pentru definirea componentei
native „FlatList”, ce conține partea incipientă a paginii (diagrama unicaă „PieChart” ce
cuprinde informatii generale cu privire la investitiile facute de consumatorul aplicatției); precum
și lista de obiecte ce afișează detalii despre fiecare acțiune în parte, precum și butoanele ce
declanșează acțiunea de vânzare sau cumpărare a unei acțiuni, prin intermediul aplicației

În cadrul componentei native „MarketItem” am definit mai multe variabile ce m-au ajutat
la ilustrarea convenabilă a datelor unei acțiuni. Acestea au următoarele denumiri și specificații:
o currentValue: valoarea curentă a unei acțiuni;
o prevValue: valoare antecedentă a unei acțiuni. A fost definită această valoare pentru
a o compara cu cea curentă și a determina dacă prețul unei acțiuni a crescut sau a
scăzut;
o marketData: datele cu privire la fluctuația unei acțiuni;

73
o tableHead/tableBody: capetele de tabel, respectiv corpul tabelei; ce prezintă în
interfața grafică informații generale asupra unei categorii de acțiuni, precum
numărul de acțiuni deținute, profitul sau pierderile obținute și valoarea curentă a
acțiunii.

În interiorul componentei native m-am folosit de metoda „currentShareValue” pentru a


ilustra sugestiv fluctuația prețului unei acțiuni. În cazul în care prețul unei acțiuni a crescut,
valoarea curentă a acestuia va fi afișată în culoarea verde; iar în dreapta prețului va apărea o icoană
în formă de săgeata în sus, de aceeași culoare. În caz contrar, valoarea acestuia va fi ilustrată în
culoarea roșie; iar în dreapta prețului va apărea icoană în formă de săgeata în jos. Icoana este
definită prin componenta nativă „Entypo”, provenită din librăria „@expo/vector-icons”.

const currentShareValue = () =>


(prevValue > currentValue && (
<View style={styles.inlineContent}>
<Text style={styles.contentDown}> {currentValue}</Text>
<Entypo name="arrow-long-down" size={24} color="red" />
</View>
)) || (
<View style={styles.inlineContent}>
<Text style={styles.contentUp}> {currentValue}</Text>
<Entypo name="arrow-long-up" size={24} color="green" />
</View>);
Secvența de cod IV.22: metoda „currentShareValue”, folosită pentru a ilustra sugestiv, în
cadrul interfeței, evoluția prețului unei acțiuni

De asemenea, m-am folosit de obiectul „profit” pentru a ilustra sugestiv câștigurile sau
pierderile obținute în cadrul unei categorii de acțiuni, dar și pentru a corecta anumite cazuri de
excepție, precum împărțirea la 0 în cazul în care investitorul nu a efectuat nicio investiție în cadrul
unei categorii de acțiuni specifice și tratarea erorii „NaN”. Profitul va fi ilustrat în procentaj,
folosindu-se culoarea sugestivă verde, în timp ce pierderile vor fi afișate în procente, în culoarea
roșie.

74
const profit = () =>
(props.profit > 100 && (
<View style={styles.inlineContent}>
<Text style={styles.contentUp}>
+{props.profit == Infinity ? 0 : props.profit - 100}%
</Text>
</View>))
||
(<View style={styles.inlineContent}>
<Text style={styles.contentDown}>
-{props.profit.toString() === 'NaN' ? 0 :100- props.profit }%
</Text>
</View>);
Secvența de cod IV.23: metoda „profit”, folosită pentru a ilustra sugestiv ,în cadrul
interfețe , câștigurile sau pierderile obținute în cadrul unei categorii de acțiuni, precum și
tratarea unor cazuri de excepție

Toată interfața grafică a componentei „MarketItem” este înfășurată într-o componentă


nativă „View”. Aceasta curpinde trei părți: în prima parte este definit un tabel cu informațiile
generale despre starea unei acțiuni și acțiunile deținute de către investitor în cadrul acesteia, în ce-
a de-a doua este implementată diagrama propriu-zisă (ce cuprinde istoricul valorilor respectivei
acțiuni); iar în partea a treia sunt prezente butoanele in-line, folosite pentru cumpărarea și vânzarea
de acțiuni.

Pentru a ilustra tabelul, m-am folosit de componentele native „Table”, „Row”,


„TableWrapper” și „Cell”. În continuare voi detalia specificațiile și rolurile acestora :

∑ Table: împachetează întreaga structură a tabelului;


∑ Row: definește prima linie a structurii, respectiv capul de tabel. Această
linie cuprinde toate șirurile prezente în variabila „tableHead”, descrisă
mai sus.
∑ TableWrapper: prin intermediul listei „tableBody”, specificate mai sus,
se mapează fiecare item din listă pe componenta nativă
„TableWrapper”. Astfel , se formează un rând în cadrul tabelului
(rândul conțînând datele cu privire la informațiile generale ale unei
acțiuni, reținute în variabilă „rowData”, descrise mai sus);

75
∑ Cell: definește conținutul prezent în cadrul unei celule, respectiv o
informație cu privire la statutul actual al unui indice bursier.

<View style={styles.container}>
<Table borderStyle={{ borderColor: "transparent" }}>
<Row
data={tableHead}
style={styles.head}
textStyle={styles.text}
/>
{tableBody.map((rowData, index) => (
<TableWrapper key={index} style={styles.row}>
{rowData.map((cellData, cellIndex) => (
<Cell
key={cellIndex}
data={cellIndex === 3 && currentShareValue() || (cellIndex ==
= 2 && profit())|| cellData}
textStyle={styles.text}
/>))}
</TableWrapper> ))}
</Table>
</View>
Secvența de cod IV.24: componenta nativă „View”, ce împachetează tabelul în care sunt
afișate informații generale cu privire la starea unei acțiuni; precum și a numărului de acțiuni
deținute de investitor și a profiturilor / pierderilor obținute de pe urma acestora

Pentru a ilustra diagrama cu fluctuația m-am folosit de componenta nativă „LineChart”.


Componenta primește dataset-ul „marketData”, ce cuprinde istoricul valorilor unei acțiuni și le
ilustrează grafic. Acest lucru îl ajută pe utilizator să realizeze analize tehnice și să efectueze
predicții, pe baza istoricul valorilor acțiunii, despre cum ar putea evolua prețul acțiunii în viitor.
Întrucât am afișat o secvență de cod asemănătoare cu implementarea codului pentru o diagramă
„LineChart” în cadrul paginii Home, doresc să nu postez un cod similar.

În esență, am detaliat structurile principale prezente în cadrul codului React Native. Am


preferat să nu postez sau să detaliez părți de cod similare, întrucât aș furniza o cantitate
semnificativă de informație redundantă .

76
IV.1.2 Detaliile de implementare ale codului Redux

În această secțiune doresc să postez și să prezint implementarea codului Redux. Întrucât


container-ul „reducers” a fost amplu detaliat în Arhitectura codului redux, consider că ar fii
redundant să îl redescriu în cadrul acestui subcapitol. Așadar, doresc să mă axez prin prezentarea
codului implementat numai în containerul „actions”; deoarece conține implementări de cod
importante, cu privire la procesarea și stocarea datelor atât în cadrul serverului Firebase, cât și în
interiorul depozitului Redux.

În cadrul fișierului „accounts.js” din interiorul containerului „actions” sunt prezente


metodele „fetchAccounts”, „addAccount”, „updateAccount”, „openFirstAccount” și
„deleteAccount”, folosite pentru gestionarea conturilor bancare ale utilizatorului. Aceste metode
au fost utilizate și menționate în cadrul codului React Native, însă nu au fost descrise. Prin acest
subcapitol doresc să detaliez fiecare funcționalitate thunk care a fost expusă în cadrul codului React
Native. Am ales să folosesc middleware-ul Redux Thunk pentru ca metodele create să returneze o
funcție, nu doar o acțiune. Acest lucru îmi permite o expediere întârziată a acțiunii către „reducer”,
incluzând lucrul cu promise-uri. În cadrul funcționalităților asincrone, lucrul cu promise-uri este
fundamental, astfel încât datele modificate în cadrul codului „React Native” să fie actualizate atât
în cadrul serverului, cât și al depozitului Redux.

În interiorul acestui fișier, prima metoda apelată va fii „openFirstAccount”, în momentul


înregistrării. Funcționalitatea creează contul bancar principal, de la banca „BCR”, și îl stochează
atât în depozitul Redux, cât și în serverul de pe platforma Firebase. Funcția primește doi
parametri: numele băncii la care se va deschide contul (în cazul acestei funcții, banca „BCR”) și
suma depusă (valoare generată aleatoriu, în momentul înregistrării unui nou utilizator).

Datorită folosirii tehnologiei Redux Thunk, această funcție returnează o funcție asincronă
mijlocie, având ca parametrii două funcționalități Redux: „dispatch” și „getState”. Aceste metode
oferă suport în declanșarea cu întârziere a unor acțiuni către reductorul Redux, precum și în
extragerea de date din interiorul containerului Redux, pentru a fii prelucrate în interiorul funcției
thunk. Metoda „getState” a fost folosită pentru a extrage din depozitul Redux token-ul cu care
utilizatorul s-a autentificat, respectiv id-ul acestuia. Cu aceste date se permite accesul și calea către
crearea primului cont bancar al utilizatorului, la
adresa „hostname/users/${userId}/accounts.json?auth=${token}”. Request-ul este trimis

77
folosindu-se metoda „POST”, având în conținutul body-ului numele băncii și suma depusă. În cazul
în care serverul trimite un răspuns negativ cu privire la procesarea cererii clientului, această eroare
va fii redirecționată în afară funcției, fiind preluată și tratată în interiorul blocului „catch” din codul
React Native, de unde a fost apelată. În caz contrar, se va prelua răspunsul oferit de server.
Răspunsul se rezumă la blocul de date trimis , la care se adaugă un id de acces al acestuia, în cadrul
serverului. Toate datele primite, inclusiv id-ul, sunt stocate într-un obiect, în cadrul rezervei Redux.
export const openFirstAccount = (bank, amount) => {
return async (dispatch, getState) => {
const token = getState().auth.token;
const userId = getState().auth.userId;
const response = await fetch(`https://first-rn-app-4c8c9-default-
rtdb.firebaseio.com/users/${userId}/accounts.json?auth=${token}`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
bank: bank,
amount: amount,
}),});
if (!response.ok) {
console.log(response.toString());
throw new Error("Something went wrong!");}
const resData = await response.json();
dispatch({
type: OPEN_FIRST_ACCOUNT,
accountData: {
id: resData.name,
bank,
amount,
}, });};};
Secvența de cod IV.25: metoda „openFirstAccount” ce returnează o funcție thunk, care
se ocupă cu salvarea primului cont bancar al utilizatorului în cadrul serverului, cât și cu
depozitarea acestor date în interiorul rezervei Redux

Funcționalitatea „addAccount” are un grad de complexitate mai ridicat, întrucât în cadrul


acesteia se actualizează niște date folosindu-se metoda „PATCH”, dar se și creează altele noi
folosindu-se metoda „POST”. Această funcție are 2 parametri: bank (numele băncii la care se va
deschide noul cont bancar) și amount (suma care va fi depusă în respectivul cont). Ca și în

78
detalierea anterioară, metoda returnează o funcție thunk, având parametrii „dispatch” și „getState”.
Pe lângă „token” și „userId”, funcția thunk extrage din depozitul Redux și obiectul ce reține
detaliile despre contul bancar intermediar, aparținut de banca BCR. Inițial, se verifică dacă suma
ce va fi transferată din contul bancar BCR este suficient de mare pentru a acoperi suma pe care
utilizatorul dorește să o integreze în noul cont bancar. În cazul unui eșec, metoda va arunca un caz
de excepție, ce va fi preluat în blocul „catch” din structura „try/catch” prezentă în codul React
Native, acolo unde a fost apelată această metodă. În caz unei reușite, se va creea noul cont bancar
în cadrul bazei de date „Realtime Database”; urmând să se actualizeze fondurile rămase din contul
bancar principal.

export const addAccount = (bank, amount) => {

return async (dispatch, getState) => {


const userId = getState().auth.userId;
const token = getState().auth.token;
const mainBank = getState().accounts.accounts.find(
(account) => account.bank === mainBankName);
if (mainBank.amount < amount)
throw new Error("Insufficient funds in your main bank account");
const response = await fetch(
`https://first-rn-app-4c8c9-default-
rtdb.firebaseio.com/users/${userId}/accounts.json?auth=${token}`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
bank: bank,
amount: amount,
}),});
if (!response.ok) {
throw new Error("Something went wrong!");}
const resData = await response.json();
Secvența de cod IV.26: prima parte de implementare de cod a metodei „addAccount. În
cadrul acestei părți se extrag datele din depozitul Redux cu prvirie la datele de autentificare ale
utilizatorului, precum și obiectul ce definește contul bancar al băncii principale. Se verifică dacă
există suficiente fonduri în contul principal pentru a creea noul cont bancar, urmând ca acest
cont sa se creeze și integreze în serverul dispus de platforma Firbease.

79
În cazul în care serverul reușește să creeze noul cont bancar, se calculează restul sumei
rămase în contul BCR, urmând ca aceasta să fie actualizată în cadrul serverului la adresa
„hostname/users/${userId}/accounts/${accountId}.json?auth=${token}”. Dacă și această
actualizare a datelor în cadrul serverului a avut loc cu succes, datele urmează să fie și ele actualizate
în cadrul depozitului Redux, prin expedierea unui obiect ce conține tipul acțiunii
„CREATE_ACCOUNT”, precum și datele ce urmează a fii stocate, aflate în câmpul „accountData”
(id-ul noului cont creat, numele băncii și suma depusă).

const remainedFundsMainBank = parseInt(mainBank.amount) - parseInt(amount);


const updateMainBankAcc = await fetch(`https://first-rn-app-4c8c9-default-
rtdb.firebaseio.com/users/${userId}/accounts/${accountId}/${mainBank.id}.json?aut
h=${token}`,
{
method: "PATCH",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
amount: remainedFundsMainBank,
}),});
if (!updateMainBankAcc.ok) {
throw new Error("Something went wrong!");}
dispatch({
type: CREATE_ACCOUNT,
accountData: {
id: resData.name,
bank,
amount,
},});};};
Secvența de cod IV.27: a doua parte de implementare de cod a metodei „addAccount”. În cadrul
acestei părți se calculează suma rămasă în codul bancar principal și se actualizează în cadrul
serverului. În cazul unei actualizări cu succes, se poate creea noul cont bancar secundar

În cadrul fișierului „auth.js” din interiorul containerului „actions” sunt prezente metodele
„setDidTryAL”, „authenticate”, „changeEmail”, „changePassword” „recoverPassword”,
„resetPassword”, „fbLogin”, „login”, „signUp” și „logOut” și sunt folosite pentru gestionarea
contului utilizatorului.

În momentul în care consumatorul accesează pentru prima oară aplicația, e evident că acesta
trebuie să se înregistreze. Prin urmare, prima funcționalitate care va fi accesată va fi „signUp”.
80
Aceasta primește ca parametri e-mailul utilizatorului, parola cu care va accesa contul de utilizator
și numele; iar după caz va mai primi și url-ul către poză de profil și data nașterii.

Se instantiază variabilele „salary” și „bankAccount” cu niște valori aproximative


convenabile. Această metoda returnează o funcție thunk, ce conține parametrul „dispatch”. În
interiorul acestei funcții, se verifică veridicitatea parolei. În cazul în care parola nu are o lungime
minimă de 8 caractere și nu conține minim o litera mică, una mare și o cifra atunci funcția va arunca
o eroare. În caz contrar, prin intermediul funcției asincrone fetch, se definește variabila „response”,
ce așteaptă răspunsul acesteia. Funcția fetch trimite un request către server, folosind metoda
„POST”. În interiorul body-ului request-ului se specifică e-mailul și parola cu care utilizatorul se
va putea autentifica.

81
export const signup = (email, password, userName, profilePic, birthday) => {
let salary=Math.floor(Math.random()*10000)+1000;
let bankAccount = Math.floor(Math.random() * 1000000) + 100000;
return async (dispatch) => {
let message;
if (
!(/[a-z]+/.test(password) &&/[A-
Z]+/.test(password) &&/\d+/.test(password) &&password.length >= 8)
) {message =
"Your password needs Upper and lower case letters, numbers and a minimum 8 ch
ars";
throw new Error(message);
}
const response = await fetch(
"https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=AIzaSyDKDyRv
Ja4zncRbMWQaPtYHkVik6uIHKCc",
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email: email,
password: password,
returnSecureToken: true,
}),});
Secvența de cod IV.28: prima parte a implementării de cod a metodei „signup”. În cadrul acestei
părți se determină aleator salariul și suma totală deținută în contul bancar, se verifică
corectitudinea parolei introduse de către utilizator și se trimite un request folosindu-se metoda
„POST” către server, pentru a crea contul utilizatorului

În cazul unui eșec al înregistrării, funcția va returna o eroare. În situația în care înregistrarea
user-ului a fost efectuată cu succes, se va depozita profilul acestuia în cadrul stocului Redux,
conținând toate detaliile primite ca parametrii, folosindu-se tipul de acțiune
„CREATE_PROFILE”. De asemenea, se va expedia în cadrul funcției o altă funcție thunk. Aceasta
poartă denumirea „authenticate” și primește că parametrii obiectul primit ca răspuns în urma
înregistrării. Acesta conține id-ul utilizatorului, id-ul token-ului de acces în cadrul aplicației și
termenul de valabilitate a token-ului de acces. Aceste date sunt salvate în containerul Redux. De
asemenea, prin metoda „saveDataToStorage” am simulat funcționalitatea web „Cookie”, prin
intermediul obiectului „AsyncStorage”. Acesta creează item-ul „userData”, având că parametrii

82
datele primite de la server. Cu ajutorul acestui item (care rămâne activ și la închiderea aplicației)
se va putea efectua operația de autoconectare la redeschiderea aplicației.

if (!response.ok) {
const errorResData = await response.json();
const errorId = errorResData.error.message;
message = "Something went wrong!";
if (errorId === "EMAIL_EXISTS") {
message = "This email exists already!";}
throw new Error(errorId);}
const resData = await response.json();
dispatch({
type: CREATE_PROFILE,
profileData: {
email: email,
salary: salary,
bankAccount: bankAccount,
name: userName,
profilePic: profilePic,
birthday: birthday,
spendingLimits:'Infinity'},});
dispatch(
authenticate(
resData.localId,
resData.idToken,
parseInt(resData.expiresIn) * 1000));
const expirationDate = new Date(
new Date().getTime() + parseInt(resData.expiresIn) * 1000);
saveDataToStorage(resData.idToken, resData.localId, expirationDate);
Secvența de cod IV.29: a doua parte implementare de cod pentru metoda „signup”. În cadrul
acestei părți se tratează erorile apărute în cazul unei înregistrări eșuate. În cazul unei
înregistrări reușite, se creează profilul utilizatorului în interiorul codului Redux. Se salvează
datele folosite pentru autentificarea utilizatorului și se creează un „cookie” simulat pentru
operația de autologin în cadrul aplicației

Dacă totul a decurs cu succes, va fi creat și profilul utilizatorului în cadrul serverului,


folosindu-se metoda post. În cele din urmă, se va creea primul cont bancar al utilizatorului,
depunându-se suma generată aleator anterior.

83
const response2 = await fetch(
`https://first-rn-app-4c8c9-default-
rtdb.firebaseio.com/users/${resData.localId}/profiles.json?auth=${resData.idToken
}`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email: email,
salary: salary,
bankAccount: bankAccount,
userName: userName ? userName : "",
profilePic: profilePic ? profilePic : "",
birthday: birthday ? birthday : "",
spendingLimits: "Infinity",
}),
}
);
if (!response2.ok) {
throw new Error("Something went wrong in profile!");
}
dispatch(accountActions.openFirstAccount("BCR", bankAccount));
Secvența de cod IV.30: a treia parte implementare de cod pentru metoda „signup”. În
cadrul acestei părți se creează profilul user-ului în cadrul serverului. În cazul apariției unei
erori, aceasta va fi preluată în locația de unde a fost apelată. Daca totul a decurs cum trebuie, se
vor depozita în containerul Redux detaliile cu privire la contul bancar principa .

Multe dintre aspectele detaliate la metoda „SignUp” se aplică și la metoda „login”. Această
funcționalitate returnează o funcție thunk, ce are ca parametru metoda „dispatch”. Se trimite un
request folosindu-se metoda „POST” către serviciul Google de conectare, conținând în obiectul
body e-mail-ul și parola introdusă de către utilizator în cadrul interfeței grafice. În cazul apariției
unei erori, aceasta va fi tratată în codul React Native, unde a fost apelată.

84
export const login = (email, password) => {
return async (dispatch) => {
const response = await fetch(
"https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=
AIzaSyDKDyRvJa4zncRbMWQaPtYHkVik6uIHKCc",
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email: email,
password: password,
returnSecureToken: true,
}),
}
);

if (!response.ok) {
const errorResData = await response.json();
const errorId = errorResData.error.message;
let message = "Something went wrong!";
if (errorId === "EMAIL_NOT_FOUND") {
message = "This email could not be found!";
} else if (errorId === "INVALID_PASSWORD") {
message = "This password is not valid!";
}
throw new Error(message);
}
Secvența de cod IV.31: prima parte a implementării de cod a metodei „login”. În cadrul acestei
părți se trimite un request folosindu-se metoda „POST” către server, pentru a primi ca răspuns
un token de autentificare în cadrul aplicației. De asemenea, sunt tratate posibilele erori apărute
în cadrul acestui proces

În caz contrar, se vor recupera datele din server cu privire la profilul utilizatorului, urmând
să se depoziteze în magazinul Redux datele de autentificare ale utilizatorului și să se creeze un
„cookie” ce permite operația de autologin la redeschiderea aplicației.

85
const resData = await response.json();
dispatch(fetchProfile());
const expirationDate = new Date(
new Date().getTime() + parseInt(resData.expiresIn) * 1000
);
saveDataToStorage(resData.idToken, resData.localId, expirationDate);
dispatch(
authenticate(
resData.localId,
resData.idToken,
parseInt(resData.expiresIn) * 1000
)
);
};
};
Secvența de cod IV.32: a doua parte a implementării de cod a metodei „login”. În cadrul acestei
părți se preia raspunsul primit de la server, ce conține datele cu privire la autentificarea
utilizatorului; se salvează în depozitul Redux și se creează cookie-ul de autentificare prin
intermediul metodei „saveDataToStorage”

Funcția „fbLogin” permite autentificarea utilizatorului prin platforma Facebook. Aceasta


returnează o funcție „thunk”, ce efectuează toate procesele necesare pentru ca utilizatorul să se
conecteze prin această modalitate. Pentru inițializarea și cuplarea aplicației cu serviciile cloud
dezvoltate de Facebook m-am folosit de obiectul „Facebook”, importat din librăria „Facebook”.
Prin acest obiect, efectuez inițializarea conexiunii dintre aplicație și serverul de cloud folosindu-
mă de metoda „initializeAsync” a obiectului „Facebook”. Ulterior, prin intermediul aceluias obiect,
se încearcă conectarea la serverul Facebook în interiorul aplicației. Întrucât sunt necesare
extragerea unor date personale din profilul utilizatorului de pe Facebook (precum e-mail-ul și poză
de profil), este necesar să cerem permisia de colectare a acestor informații. Pentru a obține aceste
permisiuni, se va folosi metodă „logInWIthReadPermissionAsync” a obiectului „Facebook”.
Aceasta va primi ca parametru un obiect, ce conține câmpul „permissions”. Pentru a colecta datele
precizate anterior, trebuie să introducem în lista ce definește câmpul „permissions” șirurile
„public_profile”, respectiv „e-mail”. În cazul unor permisiunii oferite cu succes, se vor colecta
aceste date, prin intermediul unui request către serverul Facebook. În acest request va trebui să
specificam token-ul de acces, primit în urma apelarii funcției „logInWithReadPermissionAsync”,
precum și datele pe care dorim să le colectăm (în cazul nostru: id-ul, numele, url-ul către poză de

86
profil și e-mailul). Aceste date vor fii folosite pentru înregistrarea sau autentificarea
consumatorului aplicației.

export const fbLogin = () => {


return async (dispatch) => {
try {
await Facebook.initializeAsync({
appId: "845294616345396",});
const { type, token } = await Facebook.logInWithReadPermissionsAsync({
permissions: ["public_profile", "email"],
});

if (type === "success") {


const response = await fetch(
`https://graph.facebook.com/me?access_token=${token}&fields=id,name,pic
ture,email`
);
const fbData = await response.json();
Secvența de cod IV.33: prima parte a implementării de cod a metodei „fbLogin”. În cadrul
acestei părți se inițializează conexiunea aplicației cu serverul Facebook. De asemenea, se cere
permisiunea aplicației de a colecta datele personale ale contului de utilizator de pe Facebook. În
cazul unei permisii acceptate, se colectează datele utilizatorului, mai exact id-ul utilizatorului de
pe Facebook, numele, poza de profil si e-mailul acestuia

Pentru a decide care dintre operațiile de înregistrare sau autentificare se va efectua, am


decis să introduc metodele „signup” și „login” într-un bloc „try/catch”.

Metoda „signup” este plasată în structura „try”, pe când „login” este apelată din cadrul
structurii „catch”. În cazul în care metoda signup nu emite nici o eroare, înseamnă că adresa de e-
mail furnizată pentru înregistrare nu apare în baza de date a serverului, deci se va efectua o
înregistrare. În caz contrar, metoda signup va emite o eroare cu privire la înregistrarea user-ului.
Dacă acest utilizator are deja un cont creat pe adresa de e-mail a facebook-ului, serverul va
transmite un mesaj de eroare, în care se specifică că există deja un e-mail pentru respectivul request.
În acest caz, execuția se va continua în interiorul blocului „catch”, unde se va încerca autentificarea
utilizatorului. De asemenea, se vor trata și cazurile de excepție, în care utilizatorul nu oferă accesul
aplicației de a i se colecta datele sau în situația în care a existat o eroare în cadrul serverului
Facebook.

87
try {
await dispatch(signup(fbData.email, fbData.name + fbData.id,fbData.name
,fbData.picture.data.url,null));

} catch(err) {
console.log(err.message);
await dispatch(login(fbData.email, fbData.name + fbData.id));
}
} else {
console.log("login failed");
}
} catch ({ message }) {
alert(`Facebook Login Error: ${message}`);
}
};
};
Secvența de cod IV.34: a doua parte a implementării de cod a metodei „fbLogin”. În cadrul
acestei părți se încearcă înregistrarea utilizatorului. În cazul în care această acțiune a avut loc
cu eșec, înseamnă că serverul Firebase a emis o posibilă eroare cu privire la existența adresei de
e-mail. În acest caz, se va efectua operația de autentificare a consumatorului aplicației. De
asemenea, sunt tratate și cazurile de exceptie, în care utilizatorul nu oferă acces la colectarea
datelor sale de pe Facebook; sau în care există o eroare în interiorul serverelor Facebook

Fișierul „notes.js” conține toate funcționalitățile Redux necesare pentru manipularea


notițelor create de utilizator. Funcționalitățile acestui fișier, precum și a fișierului „news” au o
structură diferită față de majoritatea funcționalităților prezente în containerul „actions”; întrucât
funcțiile thunk din cadrul acestui fișier comunică cu o bază de date SQLite creată local pentru
recuperarea datelor din memoria telefonului mobil. Întrucât structura codului este foarte similară
între funcționalitățile prezente, o să detaliez doar o singură metodă prezentă în acest fișier.

Funcția „addNote” dispune de doi parametri: „content” și „title”. Aceștia conțin datele cu
privire la titlul și conținutul introdus de utilizator pentru a crea o nouă notiță. Aceasta returnează o
funcție thunk, ce are întreg corpul funcției înfășurat într-un bloc „try/catch”. Prin intermediul
acestei metode thunk se apelează metoda „insertNote” (implementată în fișierul „db.js” din cadrul
containerului „helpers” și importată în fișierul „notes.js”) și se așteaptă inserarea notiței în cadrul

88
bazei de date SQLite „graduationProject.db”, prin intermediul variabilei „db” (inițializată în același
fișier cu metoda „insertNote”) .

În cazul unei acțiuni reușite, se va depozita în codul Redux detaliile notiței. Acestea sunt
reprezentate de titlul acesteia, conținutul și id-ul unic determinat de baza de date SQLite, în cadrul
funcției „insertNote”. În caz contrar, eroarea va fi preluată în codul „catch”, fiind ulterior trimisă
în exterior și tratată în codul React Native.

export const addNote = (content,title) => {


return async (dispatch) => {
try {
const dbResult = await insertNote(content,title);
console.log(dbResult);
dispatch({
type: ADD_NOTE,
noteData: {
id: dbResult.insertId,

title:title,
content:content
},
});
} catch (err) {
console.log(err);
throw err;}};
};
Secvența de cod IV.35: implementarea metodei „addNote”. În cadrul acestei metode se încearcă
salvarea în memoria internă a telefonului o nouă notiță, prin intermediul funcției asincrone
„insertNote”. În cazul unei inserări eșuate, eroarea va fi preluată în blocul „catch” a metodei,
fiind ulterior preluată și tratată în codul React Nativ . În caz contrar, se vor depozita datele
notiței în codul Redux.

Funcția „insertNote” primește ca parametrii valorile primite ca parametru de către funcția


„addNote”: „content” și „title”. Întrucât comanda de introducere a unor date în cadrul unei baze de
date este asincronă, am creat un obiect „Promise”. Acesta are ca parametrii două valori: „resolve”,
ce reprezintă o funcție care se va apela dacă obiectul Promise a efectuat operațiunile în cadrul său
cu succes și „reject”, ce simbolizează o metodă care se va apela dacă operațiile efectuate în cadrul
obiectului „Promise” nu au fost finalizate cu succes. În interiorul acestei funții are loc procesul de

89
înserare a unei notițe în cadrul bazei de date. Prin intermediul variabilei „db” descrise anterior, se
creează o nouă tranzacție; cu ajutorul căreia se va putea executa codul SQL necesar pentru
introducerea notiței în DB. Prin metoda „transaction” a variabilei „db” se returnează o funcție ce
primește ca parametru o valoare (în cazul nostru, este denumită „tx”), cu care se poate executa cod
SQL. Executarea codului SQL se face prin intermediul obiectului, cu ajutorul metodei
„executeSql”. Aceasta metoda primește patru parametri:
∑ Codul SQL ce urmează a fii executat (în cazul de față: „INSERT INTO notes
(content,value) VALUES (?,?);”
∑ Lista de valori introduse în cadrul codului SQL (pentru funcția actuală: “content” si
“value”);
∑ Funcția ce se va executa în cazul unei execuții reușite. Pentru metoda actuală funcția
conține doi parametri. Primul este nesemnificativ, însă cu ajutorul celui de-al doilea
putem furniza un răspuns pozitiv în cadrul obiectului Promise-ului creat, prin apelarea
metodei „resolve”; având că parametru răspunsul primit în urma execuției cu succes
a codului SQL;
∑ Funcția ce se va executa în cazul unei execuții eșuate. Pentru metoda actuală, funcția
conține doi parametri. Primul este nesemnificativ, însă cu ajutorul celui de-al doilea
putem furniza eroarea apărută în cadrul obiectului Promise-ului creat, prin apelarea
metodei „reject”; având ca parametru eroarea primită în urmă execuției fără succes a
codului SQL.

90
export const insertNote = (content, title) => {
const promise = new Promise((resolve, reject) => {
db.transaction((tx) => {
tx.executeSql(
`INSERT INTO notes (content,title) VALUES (?, ?);`,
[content, title],
(_, result) => {
resolve(result);
},
(_, err) => {
reject(err);
}
);
});
});
return promise;
};
Secvența de cod IV.36: implementarea metodei „addNote”. În cadrul acestei funcții se creeaza
un obiect Promise, folosit pentru execuția asincronă de inserarea a unei notițe în baza de date.
Parametrii funcției „resolve” și „reject” sunt decisivi în determinarea unui răspuns pozitiv sau
negativ din partea promise-ului creat

IV.2 Detalii de implementare a codului server

În cadrul aplicației am folosit două servere: unul backendless, furnizat de platforma


Firebase și unul dezvoltat de mine, în Node.js. În mediul Firebase sunt stocate și furnizate toate
serviciile necesare clientului; în timp ce mediul Node.js se prezintă că fiind un API al unei instituții
financiare, ce comunica cu aplicația client.

IV.2.1 Detaliile de implementare ale codului Node.js

Serverul Node.js cuprinde trei sectoare importante, implementate în trei containere diferite.
În containerul „helpers” se realizează conexiunea serverului node cu baza de date „MongoDb”

91
folosindu-se tehnologia mongoose. În interiorul folder-ului „models”, în fișierul
„mockFinanceData” este definită schema bazei de date, folosindu-se tot tehnologia mongoose.
Ultimul sector (și cel mai consistent) este definit și implementat în containerul „route”. În interiorul
acestui folder sunt definite toate router-ele și procesele ce au loc în cadrul acestora, precum și
anumire metode adiacente ce rulează în fundal.

În cadrul fișierului „server.js” sunt importate și apelate funcționalitățile serverului.


Totodată, inițializarea și pornirea serverului se realizează cu ajutorul funcționalităților prezente în
acest fișier. Se instantiază obiectul „express”, folosit pentru a defini variabila „app”. Prin
intermediul acestei variabile se construiește întregul sistem al serverului. M-am folosit de obiectul
„cors” pentru a permite efectuarea de request-uri în cadrul serverului, în stadiul de dezvoltare al
aplicației. Prin intermediul obiectului „app” și „cors” se construiește originea serverului (având
aceeași adresa cu clientul, pentru a nu încalcă politică SOP). De asemenea, se face conectarea cu
serverul MongoDb. Ulterior, se furnizează accesul la metodele HTTP, header-urilor și originii,
pentru a se putea desfășura comunicarea între client și server.

92
const express = require("express");
const cors = require("cors");
const app = express();
const cookieParser = require("cookie-parser");
require("dotenv").config({
path: "./config.env",
});
app.use(express.static("public"));
if (process.env.NODE_ENV === "development") {
app.use(
cors({
origin: process.env.CLIENT_URL,
credentials: true,
}));
}
const connectDB = require("./helpers/db");
connectDB();
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.setHeader('Access-Control-Allow-
Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-
With, Content- Type, Accept");
next();
});
Secvența de cod IV.37: configurarea serverului Node.js. Se instantiază variabila app folosită la
construirea sistemului serverului, se precizează locația unde sunt definite variabilele de mediu,
se definește originea serverului în stagiul de dezvoltare al acestuia, se face conexiunea cu baza
de date MongoDb și se furnizează accesul la funcționalitățile elementare pentru comunicarea cu
clientul

De asemenea, sunt importate rutele și procesele ce se efectuează în cadrul acestora. Acestea


sunt atașate API-ului, prin intermediul obiectului „app”, folosindu-se metoda „use”. De altfel, este
atașată și o funcție, ce întoarce statusul „404” în cazul în care adresa la care a dorit să ajungă
utilizatorul nu este una validă. În cele din urmă, prin intermediul metodei „listen” a obiectului
„app” se pornește serverul, fiind valabil pentru accesarea de resurse în cadrul acestuia. În
background-ul serverului rulează metoda „updateFinanceData”, prezentă la adresa

93
„./route/api/getUserData” și apelată prin intermediul obiectului „getUserData”. Aceasta
actualizează în mod constant valorile acțiunilor și indicilor bursieri.

În cadrul fișierului „config.env” sunt stocate toate variabilele de mediu, ce sunt folosite
pentru construirea sistemului serverului. Acestea sunt accesate în cadrul serverului prin structura
„process.env”, inclusă în fiecare fișier Javascript în mod implicit.

Așa cum am precizat și la începutul capitolului în containerul „helpers”, fișierul „db.js”


realizează conexiunea serverului node cu baza de date „MongoDb”, folosindu-se tehnologia
mongoose. Se definește metoda „connectDb”, ce returnează o funcție asincronă, în interiorul căreia
se apelează funcția asincronă „connect” a obiectului „mongoose”. Aceasta primește ca parametrii
url-ul la care să se deschidă serverul bazei de date și un obiect ce conține configurația bazei de
date. Prin intermediul instrucțiunii „module.exports” se exportă metoda „connectDb”; fiind ulterior
importată în cadrul fișierului „Server.js”.

În containerul „models”, fișierul „mockFinanceData” este instantiată variabila


„fundsSchema” prin intermediul obiectului mongoose, folosindu-se metoda „Schema”. Această
metodă primește doi parametri: un obiect ce definește schema creeată iar cel de-al doilea determină
configurația schemei. În cadrul primului obiect sunt prezente câmpurile „category”, „variations” și
„totalShares”. Doresc să nu le exemplific, întrucât le-am detaliat în cadrul capitolului „Arhitectura
aplicației”. În cadrul celui de-al doilea parametru se află un obiect, ce conține câmpul „timeStamps”
setat pe valoarea „true”. În acest fel, putem urmări orice eveniment petrecut în cadrul bazei de
date. În cele din urmă se creează modelul „Funds”, bazat pe această schemă și se exportă.

În containerul „route” sunt implementate toate rutele serverului, precum și procesele care
se desfășoară în interiorul acestora.

În cadrul rutei „/convertPortfolioData”, accesată prin metoda „post”, este definită o metodă
ce primește doi parametrii: „req” și „res”. În cadrul obiectului req se preiau datele trimise din client,
urmând să fie prelucrate în cadrul funcției. Serverul îi răspunde cererii clientului prin intermediul
parametrului „res”.

În cadrul acestei funcții, se preia din corpul requestului trimis de client istoricul
investitiiilor sale. Acestea sunt formatate astfel încât să fie atașabile diagramelor prezente în
ferestrele aplicației. Se importă schema aplicației definită în cadrul fișierului „mockFinanceData”

94
sub constanta „FinanceData”. Acest obiect conține o serie de funcționalități folosite pentru a accesa
sau modifica date în cadrul bazei de date MongoDB. Întrucât aplicația este destinată persoanelor
neexperimentate, am decis ca utilizatorii să poată investi în 3 domenii fundamentale. Am ales să
nu creez o gamă variată de opțiuni de investiții, întrucât aș derută utilizatorii nefamiliarizați cu
acest domeniu. Prin urmare, consumatorii aplicației pot să investească în „Real Estate”,
criptomonede și în acțiuni. Întrucât codul implementat pentru formatarea datelor este similar între
cele 3 categorii de investiții, o să aleg să detaliez structura codului a unei singure categorii.

Prin intermediul obiectului „FinanceData” se apelează funcția asincronă „findOne”, ce


accesează istoricul valorilor din cadrul categoriei „Stocks”, din interiorul bazei de date. Ulterior,
prin metoda „exec”, se definește o funcție ce conține parametrul „portfolio”. Acest parametru
conține istoricul tuturor tranzacțiilor, însă urmează să fie completate și alte câmpuri cu date
provenite de la utilizator, în interiorul funcției „exec”. Câmpurile și datele ce se definesc în
interiorul acestei funcționalități sunt următoarele următoarele:

∑ totalShares: acest câmp nu conține date din baza de date. Acesta este folosit pentru
definirea obiectului ce conține o parte din datele care urmează să fie transmise către client.
Acest sector definește numărul de acțiuni pe care utilizatorul le are în cadrul respectivei
categorii. Pentru a determina numărul acestora, m-am folosit de metoda „numOfShares”.
Aceasta funcție primește ca parametrii categoria de acțiuni curentă și istoricul investițiilor.
În interiorul acestei funcții, se filtrează investițiile și se extrag doar acelea ce țin de
categoria dată că parametru. Ulterior, se extrage din lista de obiecte ce conțin respectivele
investiții numărul de acțiuni cumpărate. Adunându-se toate acțiunile cumpărate din
fiecare obiect, se determină numărul de acțiuni cumpărate în total. De asemenea, se
calculează suma totală investită.
∑ totalInvestments: câmpul cuprinde suma totală investită, în cadrul categoriei de investiții
„Stocks”. Pentru a calcula această sumă, m-am folosit de funcțiile Javascript „filter”,
„map” și „reduce”. Acestea au fost folosite pentru următoarele scopuri:
- filter: filtrarea categoriilor de acțiuni, ce aparțin de categoria „Stocks”;
- map: extragerea numărului de acțiuni, precum și a valorii la care acestea
au fost achiziționate. Pentru a se calcula suma investită în cadrul acestui

95
obiect, se înmulțește numărul de acțiuni achiziționate cu valoarea la care
acestea au fost cumpărate.
- reduce: metoda folosită pentru însumarea tuturor valorilor determinate
în cadrul funcției map, pentru fiecare obiect.

FinanceData.findOne({
category: "Stocks",
}).exec((err, portfolio) => {
if (portfolio) {
portfolio.totalShares = numOfShares("Stocks", investments);
portfolio.totalInvestments = investments
.filter((ie) => ie.title === "Stocks")
.map((ie) => ie.amount * ie.shareValue)
.reduce((acc, cval) => acc + cval, 0);
Secvența de cod IV.38: extragerea datelor categoriei de investiții „Stocks” din baza de date
MongoDb și completarea acestora cu datele primite de la client către server

În cele din urmă, se definește prin variabila „stocks” tot corpul de date ce va fi integrat în
cadrul listei „currentFundsValue”. Parametrului „stocks” i se vor asigna valorile definite în obiectul
portfolio; respectiv „variations” (istoricul valorilor categoriei de investiții „Stocks”), „category”
(în cazul prezentat, categoria de investiții „Stocks), „totalInvestments” (totalitatea sumelor
investite în categoria „Stocks”), „totalShares” (numărul total de acțiuni achiziționate) și
„currentValue” (valoarea curentă a acțiunii; această e reprezentată prin ultima valoare a istoricului
de valori a categoriei de investiții).

Obiectul „currentFundsValue” conține informațiile prezentate mai sus, dar pentru fiecare
categorie de investiții: „Stocks”, „Real Estates” și „Crypto”. Acest obiect va fi trimis ca răspuns
către server, conținând analize tehnice ce-l vor ajuta pe utilizator să facă investiții. Tot prin
intermediul acestui obiect, se definește parametrul „mockTypeInvestments”. Variabila este
reprezentată printr-o listă, ce conține trei obiecte. Obiectele, configurația și formatul necesar pentru
definirea diagramei „PieChart”, din cadrul ferestrei „PortfolioOverview” a aplicației client. Fiecare
obiect conține următoarele câmpuri și date:

o name: numele categoriei;

96
o volume: câmp folosit pentru partajarea ariei ocupate în cadrul diagramei
„PieChart”. Conține numărul total de acțiuni deținute în cadrul unei
cateogrii de investiții;
o color: culoarea ariei ocupate de o categorie de investiții, în diagrama
„PieChart”;
o legendFontColor/legendFontSize: mărimea scrisului, respectiv culoarea
legendei diagramei, pentru o categorie de acțiuni. Se afișează numărul
de acțiuni deținute.

În cele din urmă, se trimit ca răspuns către client prin intermediul parametrulului „res”, un
obiect ce conține variabilele „mockTypeInvestments” (transmis prin câmpul ce are acleasi nume)
și „currentFundsValue” (asignat câmpului investmentsData).

Metoda „updateFinanceData” rulează în background-ul serverului și actualizează constant


valorile categoriilor de investiții. Această actualizare constantă se petrece deoarece întregul cod al
aplicației este împachetat în cadrul unui obiect al funcției javascript „setInterval”. Aceasta primește
ca parametrii structura codului care se dorește să se execute în ciclul și intervalul de timp la care
această acțiune să se repete.

Similar cu cazul funcției prezentate anterior, se extrag datele pentru fiecare categorie de
acțiuni din cadrul serverului MongoDb. Ulterior, se actualizează istoricul fiecărei categorii de
acțiuni prin introducerea în listei de valori antecedente a indicelui bursier, valoarea curentă a
categoriei de investiții. Înserarea noii valori a unei categori de acțiuni se face în cadrul parametrului
„variations” (ce conține istoricul valorilor) prin funcționalitatea Javascript „push”. Funcția
primește ca parametru noua valoare ce va fi înserată în listă. În cazul de față, această valoare este
o deviație a celei mai recente valori prezente în listă.

Deviația acestei valori se face în cadrul metodei „newStockValue”. Această funcție conține
parametrul „lastValue”, ce definește ultima valoare din lista „variations”, prezentată în paragraful
anterior. Am simulat noua valoare a unei categorii de acțiuni folosindu-mă de metodele obiectului
javascript „Math”, mai exact „random” și „floor”. Cu ajutorul funcției „random” am determinat,
prin intermediul variabilei „plusOrMinus” dacă prețul unui indice bursier scade sau crește; iar cu
ajutorul funcției „floor” am convertit noua valoare determinată a categoriei de acțiuni într-un număr
natural.

97
function newStockValue(lastValue){
var plusOrMinus = Math.random() < 0.5 ? -1 : 1;
return lastValue+Math.floor(lastValue*Math.floor(Math.random() * 10)*plusOrMinu
s/100)
}
Secvența de cod IV.39: determinarea noii valori a unei categorii de investiții , deviată din cea
mai recentă valoare a indicelui bursier

Ulterior, se va încerca salvarea noii listei în cadrul bazei de date. În situația unei operațiuni
de salvare eșuate, se va afișa în consola dezvoltatorului cauzele erorii apărute.

FinanceData.findOne({
category: "Real Estate",
}).exec((err, portfolio) => {
if (portfolio) {
portfolio.variations.push(
newStockValue(portfolio.variations[portfolio.variations.length - 1])
);
portfolio.save((err, user) => {
if (err) {
console.log(err);
}
});
Secvența de cod IV.40: actualizarea istoricului de valori a categoriei de acțiuni „Real Estate”

Ruta „/getAlertPrediction” este implementată în cadrul fișierului „getAlertPredict.js” și este


accesată prin metoda „post”. Pentru această ruta este definit un manipulant de cerere, ce primește
doi parametrii: „req” și „res”. În cadrul acestui manipulant m-am folosit de mai multe
funcționalități prezente în containerul „node-modules”. Acestea au următoarele denumiri și ocupă
următoarele roluri:

∑ express: modul folosit în contextul construirii și definirii rutei


„/getAlertPrediction”. Funcționalitatea de router a acestui modul a fost integrată
prin variabila „router”.
∑ fs: modul folosit pentru accesarea fișierelor din sistem, integrat prin
variabila globală „fs”.

98
∑ csv-parser: modul folosit pentru parsarea fișierelor de tip .csv, integrat prin
variabila „csv”.
∑ @tensorflow/tfjs [21]: o biblioteca Javascript folosită pentru instruirea și
implementarea metodelor de învățare automată, integrată în cod prin variabila „tf”.

În cadrul obiectului req se preiau datele trimise din client, urmând să fie prelucrate în cadrul
funcției. Serverul îi răspunde cererii clientului prin intermediul parametrului „res”. Cererea către
această rută este făcută în cadrul ferestrei „Alert” a clientului. Această cerere este făcută la
preferință utilizatorului, atunci când dorește să-și seteze o suma maximă permisă de a fi cheltuită
zilnic, recomandată de o instituție financiară. Pentru determinarea acestei sume, se va folosi tehnica
de învățare automată. Se vor extrage din istoricul investitorilor de succes salariile și suma medie
zilnică cheltuite de aceștia, precum și sumele din conturile sale bancare. Aceste date vor fi folosite
ca date de antrenare pentru algoritmii folosiți în învățarea automată. Ulterior, algoritmul va efectua
o predicție pentru suma maximă permisă de a fi cheltuită zilnic, primind ca date folosite pentru
predicție salariul și sumele din conturile bancare ale utilizatorului ce a accesat acest serviciu al
băncii.

Datele preluate din corpul cererii sunt „bankAccounts” (suma totală deținută de utilizator)
și „salary”. Se instantiază variabilele „trainData” și „trainResult” cu o listă vidă. Se utilizează
obiectul „fs” pentru citirea datelor tuturor investitorilor ce au avut contact cu această instituție
financiară, respectiv pentru prelucrarea acestor informații și furnizarea unui răspuns către client.
Obiectul este format din patru părți, reprezentate prin patru funcții și înglobează toate procesele
efectuate în cadrul metodei principale a rutei:

∑ createReadStream: cu ajutorul acestei metode, se creează un cititor pentru


fișierul „reportingUserData.csv” , aflat în containerul „helpers”;
∑ pipe: prin intermediul acestei funcții se permite analizarea datelor din fișierul
în format „.csv”;
∑ .on „datA”: sunt citite datele din fiecare linie din fișierul cu extensia „.csv”.
Aceste date sunt reprezentate pentru fiecare investitor, conținând următoarele
informații: sumele din conturile bancare, salariul, suma medie cheltuită de aceștia

21
Tensorflow, https://www.tensorflow.org/js

99
și decidabilitatea dacă acest investitor a avut succes. Ulterior, se integrează în
datele de antrenare informațiile investitorilor de succes. Datele de antrenare sunt
introduse în lista „trainData” și sunt reprezentate de suma totală din conturile
bancare și salariul investitorului. Rezultatele datelor de antrenare sunt inserate în
lista „trainResult”. Etichetele datelor de antrenare reprezintă suma medie cheltuită
de aceștia.
router.post('/getAlertPrediction',async (req,res)=>{
const {bankAccounts,salary}=req.body;
let trainData=[];
let trainResult=[];
await fs.createReadStream("./helpers/reportingUsersData.csv")
.pipe(csv())
.on("data", (row) => {
if(row.Succeeded=='YES'){
trainData.push([parseInt(row.Bank_Accounts),parseInt(row.Salary
)]);
trainResult.push([parseInt(row.Daily_Expenses)]);
}
})
Secvența de cod IV.41: definirea rutei „/getAlertPrediction” și al manipulantului cererii. Se
citesc din corpul cererii datele folosite pentru a face predicția utilizatorului și se instantiază
variabilele ce vor conține datele de antrenare, respectiv etichetele acestora. Se definește un
cititor pentru fișierul ce conține lista cu investitorii de succes și se folosește analizorul csv pentru
a putea citi datele din fișier, ce vor fi ulterior prelucrate în metoda „on(„data”,..). În cadrul
acestei metode se verifică dacă utilizatorul a fost unul de succes, avand campul „Succeded” setat
pe valoarea „YES”. In caz afirmativ, sunt introduse în datele de antrenare salariul și suma din
conturile sale bancare, iar în etichetele de antrenare suma medie cheltuită de acesta. Metoda se
autoapelează până când sunt parcurse toate liniile din fișier, respectiv toată lista de investitori.

∑ .on „end”: această metodă este apelată odată ce toate liniile din cadrul
fișierului „reportingUserData.csv” au fost citite în cadrul programului. Ulterior, sunt
create tensoarele bidimensionale, utilizate pentru a instrui modelul ce va fii creat.
Acestea sunt definite în variabilele „xs” (conținutul datelor de antrenare) și „ys”
(conținutul etichetelor datelor de antrenare) prin intermediul obiectului „tf”,
folosindu-se metoda „tensor2d”, ce primește ca parametru lista cu datele de
antrenare.

100
Ulterior, se construiește în interiorul metodei „getModel” modelul de antrenare, bazându-
se pe structura datelor de antrenare.

Metoda „getModel” deține 3 parametrii:

- inputUnit: numărul de unități (neuroni) folosiți în stratul de intrare. Am decis ca numărul


acestora să fie egal cu lungimea vectorului „trainData”.
- inputShape: forma datelor de intrare. Întrucât vectorul „trainData” este 2-dimensional;
valoarea parametrului inputShape va fi 2.
- outputUnit: numărul de unități folosiți în stratul de ieșire. Întrucât eticheta fiecărei date de
antrenare este formată dintr-o singură valoare (suma medie cheltuită de investitor), această
variabilă va avea valoarea 1.

Întrucât fiecare pereche de date de antrenare corespunde unei singure etichete (în cadrul
definirii modelului, datele de intrare/ieșire ale unui investitor nu interferează cu datele altuia), am
ales să definesc un model secvențial. Modelul este creat prin intermediul „tf”, folosindu-se de
metoda „sequential”. Acesta este format din 2 straturi: de intrare și de ieșire. Ambele straturi sunt
definite prin apelarea metodei „dense” din cadrul intrucțiunii „tf.layers.dense” și primesc ca
parametru un obiect, ce definește arhitectura stratului.

Obiectul aferent primului strat deține trei câmpuri, având următoarele roluri:

- units: definit prin valoarea parametrului „inputUnits”, îndeplinește rolul descris în


cadrul detalierii acestui parametru.
- inputShape: definit prin valoarea parametrului „inputShapes”, îndeplinește rolul
descris în cadrul detalierii acestui parametru.
- activation: transformă datele de intrare în cadrul stratului de intrare; astfel încât
acestea să aibă niște valori convenabile în momentul în care acestea ajung în stratul
de ieșire. Pentru a reduce semnificativ zgomotul produs în cadrul procesării datelor,
am ales funcția de activare sigmoid, întrucât mapează valorile datelor de intrare în
intervalul (0,1 .

Obiectul aferent celui de-al doilea strat, respectiv stratul de ieșire, conține numai câmpul
units. Acesta este definit prin valoarea parametrului „outputUnits”, ce îndeplinește rolul descris în
cadrul detalierii acestui parametru.

101
Ulterior, modelul este compilat și salvat. În interiorul metodei ce compilează și salvează acest
model este definit un obiect ce conține două câmpuri:

o loss: câmpul în care se introduce modul de calculare a marjei de eroare. Această


marjă este determinată prin diferența în absolut a valorii prezise de model și eticheta specifică
unor date de antrenare. Am ales să folosesc funcția de pierdere „MeanSquaredError”, întrucât
datele de antrenare sunt foarte divergente (salariul și sumele deținute în conturile bancare de
investitori pot diferi foarte mult de la un întreprinzător la altul) și limitate, este necesară o
penalizare severă a marjelor de eroare consistente.
o Optimizer: câmpul în care se introduce un tip de algoritm, folosit pentru a susține
reducerea marjelor de eroare apărute în urmă predicțiilor făcute de model.

Într-un final, funcția „getModel” returnează modelul construit cu specificațiile detaliate mai
sus.

const getModel=(inputUnit,inputShape,outputUnit)=>{

const model=tf.sequential();
model.add(tf.layers.dense({
units: inputUnit,
inputShape: [inputShape],
activation: "sigmoid",}));
model.add(tf.layers.dense({
units: outputUnit,
}));
model.compile({
loss:'meanSquaredError',
optimizer:'sgd'});
return model
}
Secvența de cod IV.42 : definirea metodei „getModel”, ce determină arhitectura unui
model secvențial, format din două straturi: unul de intrare și unul de ieșire
Modelul returnat de această metodă este reținut în variabilA „model”, aflată în interiorul
request handler-ului. Modelul va fi instruit cu ajutorul funcției „fit”, care primește ca parametrii
tensorul de intrare „xs” și cel de ieșire „ys”; precum și numărul de epoci prin care se va repeta
procesul de antrenare al datelor (în cazul de față, numărul de epoci parcurse în cadrul algoritmului
este de 1000). În cadrul acestui proces, se va instrui modelul astfel încât să se potrivească predicțiile
acestuia cu datele din tensorul de ieșire „ys”, pe baza tensorului de intrare „xs”. Odată ce modelul

102
a fost instruit, acesta va încerca să facă o predicție asupra sumei limite de cheltuit admise, pe baza
salariului și suma totală din conturile sale bancare. Predicția se va face prin intermediul variabilei
„model”, folosindu-se metoda „predict” ce primește ca parametru un tensor bidimensional care
conține datele utilizatorului, specificate mai sus. Rezultatul predicției va fi transmis în format JSON
către client prin intermediul parametrului „res”.

.on("end", () => {
console.log("CSV file successfully processed");
const xs=tf.tensor2d(trainData);
const ys=tf.tensor2d(trainResult);
const model=getModel(trainData.length,trainData[0].length,trainResult.len
gth);
model.fit(xs,ys,{
epochs:1000
}).then(()=>{
const dataToPredict = tf.tensor2d([[bankAccounts, salary]]);
const prediction=model.predict(dataToPredict);
prediction.print();
let predictionResult=parseInt(prediction.dataSync()[0]);
return res.json({predictionResult});
})
});})
Secvența de cod IV.43: funcția „.on(„end”...) se apelează odată ce tot fisierul „.csv” a fost
parcurs, linie cu linie. Ulterior, se definesc tensoarele de intrare, respectiv de ieșire. Se definește
modelul folosindu-se metoda descrisă în secvența de cod anterioară și se instruiește cu ajutorul
tensoarelor specificate anterior, în 1000 de epoci. Odată ce modelul este antrenat, se creează
tensorul de intrare „dataToPredict”; ce conține datele utilizatorului pe baza cărora modelul va
încerca să facă o predicție asupra sumei maxime permise a fi cheltuită într-o zi. În cele din urmă,
suma prezisă este trimisă către client în format JSON prin parametrul „res”.

103
V Manual de utilizare
La rularea aplicației se afișează utilizatorului ecranul numit „SplashScreen”, în care se află
amplasată pe interfața grafică sigla pozei de profil în cadrul contului meu de Teams. În urma
încărcării aplicației, se verifică în memoria locală dacă există salvat un jeton de autentificare
valabil.

Figura V.1 Ecranul afișat în timpul încărcării aplicației

104
În cazul inexistenței unui jeton de autentificare sau unul expirat, utilizatorul va fi
redirecționat către pagina de autentificare. Acesta are posibilitatea de a se autentifica prin
intermediul unui cont creat anterior sau prin intermediul platformei Facebook. În cazul în care
consumatorul aplicației nu are un cont creat, dar nici nu vrea să se autentifice prin intermediul
platformei sociale; acesta are posibilitatea de a-și crea un cont, prin intermediul ferestrei de
înregistrare. Această fereastră poate fi accesată prin apăsarea butonului „Sign Up”.

În cazul în care utilizatorul dorește să-și creeze un nou cont, acesta va accesa pagina de
înregistrare, prin apăsarea butonului „Sign Up” din cadrul ferestrei de autentificare.

Figura V.2 Fereastra prin


intermediul căreia se efectuează
autentificarea în cadrul paginii

Consumatorul aplicației va trebui să-și introducă numele, adresa de e-mail personală și


parola cu care se va autentifica în cadrul paginii. Ulterior, se va afișa o fereastră pop-up, în care i

105
se va cere utilizatorului să introducă codul de confirmare a contului, trimis prin adresa de e-mail
introdusă de către utilizator. Odată confirmat codul, utilizatorul va fi redirecționat către pagina
principală.

Figura V.3 Fereastra prin intermediul Figura V.4 Fereastră pop-up prin care
căreia se efectuează înregistrarea se cere confirmarea contului prin codul
noului utilizator trimis către adresa de e-mail introdusă
de către consumatorul aplicației. În
urma introducerii codului corect,
utilizatorul va fii redirecționat către
pagina principală a aplicației

106
Figura V.5 Fereastra principală, în Figura V.6 Meniul de navigație al
care i se ilustrează utilizatorului aplicației, accesibil prin glisarea spre
informațiile generale cu privire la dreapta a ecranului
activitatea sa în segmentul financiar

Odată ce utilizatorul este autentificat, acesta va fi redirecționat către pagina principală. În


cadrul acesteia, se afișează cheltuielile sale zilnice, precum și informații generale despre activitatea
sa: suma totală deținută în conturile bancare, suma totală investită și suma totală cheltuită pentru
diverse tranzacții. Pentru a accesa meniul de navigație, utilizatorul trebuie să gliseze spre dreapta
ecranului.

Mai întâi de toate, în interiorul meniului de navigație utilizatorul poate să-și schimbe poza
de profil, apasând pe butonul verde aflat în dreapta fotografiei de profil. Aplicația îi va cere
utilizatorului să-i ofere permisiunea de a accesa funcționalitatea de camera a telefonului. Ulterior,
îl va înștiința pe utilizator dacă este decis să schimbe fotografia de profil.

107
Figura V.7 Prin apăsarea Figura V.8 În urma efectuării
butonului verde, situat în dreapta fotografiei, utilizatorul este
fotografiei de profil, se va putea avertizat dacă este decis să-și
activa camera și să se actualizeze schimbe fotografia de profil
poza de profil; în cazul în care
utilizatorul oferă permisiunea
aplicației de a accesa camera
telefonului

Accesând navigatorul „Profile” prin intermediul meniului de navigare, utilizatorul va fi


redirecționat către pagina de profil a acestuia. Fereastra conține detalii despre utilizator, precum
numele, dată de naștere, salariul și e-mailul acestuia. În cazul în care salariul utilizatorului a fost
actualizat sau au fost introduse niște date greșite cu privire la data de naștere sau salariul acestuia,
aceste date pot să fie modificate prin intermediul ferestrei de editare a profilului. Aceasta este
accesibilă din pagina de profil prin intermediul icoanei situate în partea dreapta a barei de acțiuni.

108
Figura V.9 Pagina de profil a Figura V.10 Fereastra de editare a
utilizatorului,ce cuprinde informații datelor din profil. Odată modificate,
generale despre identitatea acestuia. datele se salvează prin apăsarea iconiței
Editarea profilului se poate face prin marcată prin sageată
apăsarea icoanei marcată prin sageată

109
Accesând navigatorul „Portfolio” prin intermediul meniului de navigare, utilizatorul va fi
redirecționat către platforma de trading oferită de aplicație, situată în navigatorul copil „Portfolio”.
În cadrul acesteia, se va afișa portofoliul utilizatorului, precum și analize tehnice ce-l ajută pe
investitor în a face investiții de succes. Totodată, se vor afișa și diagrame în care se arată evoluția
prețului unui indice bursier.

Figura V.11 Prezentarea unor Figura V.12 Fereastra pop-up


analize tehnice cu privire la un indice deschisă în cadrul paginii
bursier. Cu ajutorul butoanelor „Buy” „PortfolioOverview”, în momentul în
și „SELL” utilizatorul poate cumpăra, care utilizatorul dorește să cumpere sau
respectiv vinde acțiuni să vândă acțiuni. Utilizatorului îi este
precizată suma totală ce va fi investită
pentru numarul de acțiuni pe care
dorește să le achiziționeze

Având toate aceste date, utilizatorul poate să cumpere și să vândă inteligent acțiuni, astfel
încât să-și maximizeze profiturile. Cumpărarea sau vânzarea de acțiuni se realizează prin butoanele

110
„BUY”, respectiv „SELL”; prezente pentru fiecare indice bursier ce poate fii tranzacționat prin
intermediul aplicației.

Figura V.13 Platforma de


investiții oferită de aplicație.
Utilizatorul poate observa, în
prima parte a ecranului, detalii
generale cu privire la portofoliul
acestuia de investitor.

Navigatorul copil „DoResearch” al navigatorului „Portfolio” poate fii accesat prin apăsarea
pe butonul „DoResearch”, aflat în josul paginii. În cadrul acestei ferestre, utilizatorul poate observa
toate știrile și blogurile recomandate de către dezvoltatorul aplicației. Acestea sunt salvate odată
ce utilizatorul accesează o notificare, conducându-l pe consumatorul aplicației către pagina web a
știrei sau blogului recomandat, în cadrul aplicației.

111
Figura V.14 Dezvoltatorul Figura V.15 Odata ce Figura V.16 O notificare
trimite notificări catre știri sau utilizatorul a accesat o accesată va rămâne
blog-uri interesante prin notificare, acesta va fi salvată în cadrul paginii
intermediul platformei redirectionat către o “All News”. Aceasta poate
Firebase. Odată ce utilizatorul fereastră a aplicației. În fi accesată din nou, prin
accesează o notificare (fie în cadrul acesteia, apăsarea pe interfața
background, fie în foreground), consumatorului aplicației i grafică corespunzătoare
acesta va fi redirecționat în se va afișa conținutul blog- știrei pe care
aplicație; într-o fereastră în ului sau știrei existente la o consumatorul aplicației
care i se va ilustra respectiva adresa web. dorește să o recitească.
știre. Această pagină este
prezentă în același
navigator de stivă cu
fereastra anterioară:
“DoResearch”.

112
Accesând navigatorul „Expenses” prin intermediul meniului de navigare, utilizatorul va fi
redirecționat către primul navigator copil, „Transactions”. Acest navigator conține 2 ferestre: prima
ilustrează istoricul tranzacțiilor, iar prin intermediul celei de-a două se poate efectua o nouă
tranzacție. Fereastra principală este cea care ilustrează istoricul tranzacțiilor. Accesarea celei de-a
doua ferestre se face prin apăsarea pe iconița situată în partea dreapta a barei de acțiuni, prezentă
în fereastra principală.

Figura V.17 Fereastra ce conține istoricul Figura V.18 Fereastra prin intermediul
tranzacțiilor utilizatorului. Pentru a efectua o căreia utilizatorului i se permite să
nouă tranzacție, acesta trebuie să navigheze efectueze o nouă tranzacție. Acesta
către pagina de efectuare a tranzacțiilor. trebuie să introducă numele item-ului
Navigarea se face prin apăsarea butonului cumpărat, precum și costul acestuia.
marcat prin săgeata de culoare albastru Pentru a salva tranzacția, consumatorul
deschis. Pentru a naviga către navigatorul de aplicației trebuie să apese pe iconița
file „DoSavings”, acesta trebuie să apese pe situată în partea dreaptă a barei de
iconița marcată prin săgeata de culoare acțiuni
albastru închis.

113
Cel de-al doilea navigator copil poate fi accesat prin intermediul butonului aflat în partea
dreapta a meniului de navigație al navigatorului „Expenses”. Acest navigator poartă denumirea
„DoSavings” în cadrul interfeței și conține modalități prin care utilizatorul este ajutat să-și
gestioneze veniturile. La accesarea acestui navigator, consumatorul aplicației va fi redirecționat
către meniul navigatorului „DoSavings”. Acest meniu conține opțiuni, care să-l ajute pe utilizator
să-și gestioneze inteligibil veniturile: setarea unei suma maxime permise de a fi cheltuită zilnic și
funcționalitatea de a crea notițe, alcătuind un jurnal al cheltuielilor sale.

Figura V.19 Fereastră ce conține meniul principal al navigatorului „DoSavings”.


Prin intermediul acestuia, utilizatorul poate accesa funcționalități
care îl ajută în a-și gestiona veniturile

Utilizatorul poate accesa funcționalitatea de a vizualiza, respectiv a scrie notițe prin


apăsarea butonului „Write some notes”, prezent în meniul principal. Similar cu cazul navigatorului
„Transactions”, sunt prezente două ferestre: în prima pagină se afișează notițele scrise și salvate de
către utilizator; iar prin intermediul celei de-a doua se pot scrie și salva notițe noi. De asemenea,

114
utilizatorul poate șterge anumite notițe, în cazul în care informațiile salvate în cadrul acestora nu
mai sunt folositoare.

Figura V.20 Fereastra ce conține Figura V.21 Pagina prin


istoricul notițelor scrise și salvate intermediul căreia un utilizator
de utilizator. Utilizatorul are poate crea o nouă notiță. Acesta
posibilitatea de a șterge o notiță trebuie să specifice titlul și textul
prin apăsarea butonului notiței. Pentru a salva notița , acesta
„DELETE” trebuie să apese pe icoana existenta
în partea dreaptă a berei de acțiuni

Revenind în meniul principal „DoSavings”, regăsim butonul „Consuming Alert”. Odată


accesat, aplicația va fi redirecționată către pagina ce oferă funcționalitatea de limitare a sumelor
cheltuite zilnic. În cadrul acesteia, utilizatorul are două opțiuni de setare a acestei sume. Opțiunea
recomandată este prin intermediul API-ului băncii, care furnizează o sumă limită aproximativă, în
concordanță cu salariul și suma totală din conturile bancare ale utilizatorului. Această opțiune este

115
accesată prin intermediul butonului „Default Limitation”. Cea de-a doua opțiune este de a-și seta
manual utilizatorul o sumă maximă admisă, decisă de acesta.

Figura V.22 Fereastra ce conține optiunile de


setare a sumei maxime permise a fi cheltuită
zilnic.Aceasta poate fi determinată de catre API-ul
băncii sau de către utilizator. În cazul în care
consumatorul aplicației dorește să introducă
manual o sumă limită admisă, se va afișa o
fereastra pop-up, prin care i se cere utilizatorului
să introducă suma dorită de el.

Accesând navigatorul „Bank Accounts” prin intermediul meniului de navigare, utilizatorul


va fi redirecționat către pagina ce conține soldurile din toate conturile bancare deschise de client.
În cadrul acestei ferestre, autorul poate să transfere bani dintr-un cont bancar în altul prin
intermediul contului bancar principal, asociat băncii BCR; folosindu-se butoanele „Deposit”
(pentru a se depozita bani în contul curent) și „Withdraw” (pentru a se retrage o suma de bani din
contul curent, fiind ulterior depozitată în contul băncii BCR). În momentul accesării uneia dintre
aceste butoane, se va afișa o fereastră pop-up. În cadrul acestei ferestre utilizatorul trebuie să
introducă suma pe care dorește să o depoziteze/retragă.

116
Utilizatorul are opțiunea de a deschide un cont bancar aferent unei alte bănci. Pentru a putea
efectua această operațiune, acesta trebuie să acceseze butonul situat în josul paginii „Link bank
account”. În urmă apăsării acestui buton, utilizatorul va fi redirecționat către fereastra ce îi permite
deschiderea unui nou cont bancar. Acesta poate să aleagă să deschidă un cont bancar la o varietate
de bănci naționale și internaționale; însă nu poate deschide mai mult de un cont bancar la o anumită
bancă. Odată ce a accesat o opțiune de deschidere a unui cont la o bancă valabilă (prin apăsarea
item-ului aferent unui titlu de bancă), utilizatorului i se va afișa o fereastră pop-up. În cadrul acestei
ferestre utilizatorul va trebui să specifice suma pe care o va depunde în acel cont bancar. Cum
multe băncii au restricții privind suma minimă admisă pentru a deschide un cont bancar, am
specificat în cadrul ferestrei pop-up că pentru a deschide un nou cont este necesar să fie depusă o
suma minimă de 10000 RON.

117
Figura V.23 Fereastra ce conține toate Figura V.24 Fereastra ce conține toate
conturile bancare deschise. Depozitarea și băncile la care autorul își poate deschide un
retragerea unei sume dintr-un cont cont bancar. Odată deschis în cadrul unei
secundar se face prin intermediul contului banci, aceasta va dispărea din lista băncilor
asociat băncii BCR. Întrucât contul BCR valabile pentru deschiderea unui cont.
este un cont bancar intermediar, acesta nu Pentru a se deschide un cont bancar în
poate efectua operațiuni de retragere sau cadrul unei bănci, autorul trebuie să apese
depozitare. pe interfața unei banci. Ulterior, se va
deschide o fereastră pop-up, în care i se cere
utilizatorului să introducă o sumă (minim
10000) pentru a se deschide noul cont
bancar cu suma depozitată în acesta. Suma
va fi retrasă din contul bancar principal ce
aparține de banca BCR.

118
Accesând navigatorul „Settings” prin intermediul meniului de navigare, utilizatorul va fi
redirecționat către pagina de setări. Aceasta conține un meniu de opțiuni, ce permit schimbarea
valutei actuale sau datelor de autentificare. Pentru schimbarea valutei actuale se va afișa un mesaj
de tip alertă, în interiorul căruia utilizatorul are posibilitatea de a-și schimba valuta actuală în
moneda RON, EUR sau USD.

Figura V.25 Fereastra ce Figura V.26 La apăsarea Figura V.27 La apăsarea


conține opțiunile butonului „Change butonului „Change email”
utilizatorului de a-și schimba currency” din cadrul sau „Change password”,
datele de conectare, precum meniului, se va deschide o se va afișa o fereastră pop-
și valuta folosită pentru fereastra pop-up. Prin up, prin care i se cere
ilustrarea valorilor în cadrul intermediul acesteia, utilizatorului să introducă
aplicației. utilizatorul își poate noua sa adresă de e-mail,
schimba valuta curentă. respectiv noua parolă.
Ulterior, se va actualiza
fereastra pop-up, cerându-
se utilizatorului să
confirme actiunea sa; prin
introducerea unui cod de
confirmare primit prin
adresa de e-mail actuală.

119
Figura V.28 La apăsarea pe
butonul marcat prin săgeata
albastră, aflat în interiorul
navigatorului principal,
utilizatorul se deconectează din
cadrul aplicației.

120
VI. Concluzii
VI.1 Realizări
Aplicația dezvoltată reprezintă un curs practic, prin care persoanele dornice să-și
investească timpul în a-și aprofunda cunoștințele în educația financiară au la dispoziție o aplicație
interactivă, ușor de accesat și de înțeles; datorită prezenței stricte a unor funcționalități și unelte
financiare elementare. Prin intermediul acestei aplicații utilizatorul are acces la funcționalități
precum limitator de cheltuieli zilnice și crearea unui jurnal, pentru a-l ajuta să-și gestioneze
veniturile și să-și facă planuri inteligente de investiții. De asemenea, consumatorului aplicației i se
furnizează un număr suficient de date tehnice de factură economică, astfel încât să poată efectua
analize tehnice care îl pot ajuta să efectueze investiții de succes; fără să fie copleșit de un număr
consistent de informații. În cele din urmă, acestuia i se furnizează o platforma de tranzacționare,
prin care utilizatorul începător poate efectua investiții în cadrul unei burse de valori sau a unei
instituții financiare. Astfel, utilizatorul va putea învăța practic cum să-și gestioneze emoțiile pentru
a face investiții raționale.

VI.2 Dezvoltări ulterioare


În momentul actual, utilizatorul poate accesa pagina sa de profil , pentru a putea observa
datele sale personale. Însă, acesta nu poate accesa profilurile altor utilizatori, pentru a putea
împărtăși cunoștințe și idei cu aceștia. O posibilă direcție de dezvoltare a aplicației pe viitor ar fi
implementarea unei rețele sociale, prin care utilizatorii să-și poată partaja portofolile de investiții
ale acestora, precum și anumite date personale scrise în jurnal sau păreri personale cu privire la
fluctuația unui indice bursier sau a unor evenimente petrecute, ce au avut un impact economic.

VI.3 Păreri personale


Eu sunt foarte mulțumit de proiectul pe care l-am realizat, deoarece am putut dezvolta un
program folositor persoanelor ce vor să-și îmbunătățească educația financiară; dar și pentru că am
dezvoltat o aplicație ce mi-a permis să-mi dezvolt cunoștințele din domeniul finanțelor prin

121
cercetările efectuate în cadrul lucrării de licență, dar și cele de programare prin construirea
aplicației.

Am fost, de asemenea, motivat să lucrez la acest proiect, întrucât am avut ocazia să-mi
dezvolt cunoștiințele pe tehnologiile cu care doresc să lucrez în continuare; dar și să-mi satisfac
pasiunea de a crea propria platformă de tranzacționare la bursă, în cadrul unei aplicații Fintech.

122
VII Bibliografie
[1] Alpha Bank România SA, https://www.alphabank.ro/Portals/0/PDF/persoane-
fizice/economii/alpha-dreams/termeni-si-conditii-conturi-minori.pdf
[2] Julia Kagan, Financial Technology – Fintech,
https://www.investopedia.com/terms/f/fintech.asp
[3] Statista Research Department, https://www.statista.com/statistics/271644/worldwide-
free-and-paid-mobile-app-store-downloads/
[4] Javascript, https://www.javascript.com/
[5] Expo, https://docs.expo.io/
[6] Wikipedia, https://en.wikipedia.org/wiki/React_Native
[7] Expo, https://docs.expo.io/introduction/managed-vs-bare/
[8] Firebase, https://firebase.google.com/
[9] Wikipedia, Node.js, https://en.wikipedia.org/wiki/Node.js
[10] Redux, Getting Started with Redux, https://redux.js.org/introduction/getting-started
[11] Redux Thunk , https://www.npmjs.com/package/redux-thunk
[12] Axios, https://axios-http.com/docs/intro
[13] Shanuj Mishra, Pleasant UX – Central to all conversions,
https://medium.com/@shanuj1611/ux-key-to-digital-marketing-success-d1ace6b3829
[14] Adam Fard, Fintech UX Design Trends in 2021, https://adamfard.com/blog/fintech-ux-
trends
[15] Mongoose, https://mongoosejs.com/
[16] MongoDb, https://www.mongodb.com/
[17] Rahul Dubey, React Native Architecture, https://www.educba.com/react-native-
architecture/
[18] Lucid, https://lucid.app/
[19] Express, https://expressjs.com/
[20] Nimra Saad, What is FlatList and how to use FlatList in React Native,
https://www.folio3.com/mobile/blog/what-is-flatlist-and-how-to-use-flatlist-in-react-
native/
[21] Tensorflow, https://www.tensorflow.org/js

123

S-ar putea să vă placă și