Documente Academic
Documente Profesional
Documente Cultură
FACULTATEA DE INFORMATICĂ
LUCRARE DE LICENȚĂ
2021
DECLARAȚIE PRIVIND ORIGINALITATEA ȘI RESPECTAREA
DREPTURILOR DE AUTOR
∑ 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;
___________________________
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.
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
VI.1 Realizări............................................................................................................................121
VI.2 Dezvoltări ulterioare.........................................................................................................121
VI.3 Păreri personale ................................................................................................................121
VII Bibliografie ............................................................................................................................123
I Introducere
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.
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.
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.
Interfața clientului pe Android, respectiv IOS; care include toate elementele vizuale prin
care clientul interacționează cu aplicația (ferestre, butoane, liste).
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.
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ă.
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.
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ă.
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.
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.
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]
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.
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.
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
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.
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.
Aplicația React Native dezvoltată de mine este împachetată într-un container Redux, ce
deține întregul arbore de definire al aplicației.
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ă.
Navigatorul „Home” dispune doar de o singură fereastră, ce se regăsește sub același nume
cu numele navigatorului.
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”.
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]
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.
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:
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”;
∑ 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:
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.
∑ 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:
∑ 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:
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]
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:
31
Figura III.5 Arhitectura serverului Node.js
În cadrul proiectului, am folosit numeroase servicii care m-au ajutat în testarea aplicației,
precum și în dezvoltarea acesteia.
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:
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ă.
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.
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.
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.
Î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.
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).
38
ales să folosesc acest efect întrucât denotă un nivel de eleganță și profesionalism din partea
aplicației.
• id: tipul input-ului (în cazul de față, poate fi e-mailul sau parola);
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.
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.
Î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.
<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>
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]);
Î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.
setError(null);
setFbLoading(true);
try {
await dispatch(authActions.fbLogin());
} catch (err) {
setError(err.message);
setFbLoading(false);
}
};
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).
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”.
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.
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
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ă.
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;
<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.
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.
53
cazul în care utilizatorul nu-și dă consimțământul, cererea acestuia de a-și actualiza fotografia de
profil va fi respinsă.
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.
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”.
Î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”.
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
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ă).
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
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 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).
Î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.
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
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
76
IV.1.2 Detaliile de implementare ale codului Redux
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
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.
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ă).
Î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.
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
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”
86
profil și e-mailul). Aceste date vor fii folosite pentru înregistrarea sau autentificarea
consumatorului aplicației.
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
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.
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.
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
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.
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
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.
Î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.
∑ 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:
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).
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”
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:
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.
Î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:
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:
Î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.
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.
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
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
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.
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.
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.
114
utilizatorul poate șterge anumite notițe, în cazul în care informațiile salvate în cadrul acestora nu
mai sunt folositoare.
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.
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.
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.
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