44/////////////////////////////////////////////////
55// BANKIST APP
66
7- // Data
7+ // DIFFERENT DATA! Contains movement dates, currency and locale
8+
89const account1 = {
910 owner : 'Jonas Schmedtmann' ,
10- movements : [ 200 , 450 , - 400 , 3000 , - 650 , - 130 , 70 , 1300 ] ,
11+ movements : [ 200 , 455.23 , - 306.5 , 25000 , - 642.21 , - 133.9 , 79.97 , 1300 ] ,
1112 interestRate : 1.2 , // %
1213 pin : 1111 ,
14+
15+ movementsDates : [
16+ '2019-11-18T21:31:17.178Z' ,
17+ '2019-12-23T07:42:02.383Z' ,
18+ '2020-01-28T09:15:04.904Z' ,
19+ '2020-04-01T10:17:24.185Z' ,
20+ '2020-05-08T14:11:59.604Z' ,
21+ '2020-05-27T17:01:17.194Z' ,
22+ '2020-07-11T23:36:17.929Z' ,
23+ '2020-07-12T10:51:36.790Z' ,
24+ ] ,
25+ currency : 'EUR' ,
26+ locale : 'pt-PT' , // de-DE
1327} ;
1428
1529const account2 = {
1630 owner : 'Jessica Davis' ,
1731 movements : [ 5000 , 3400 , - 150 , - 790 , - 3210 , - 1000 , 8500 , - 30 ] ,
1832 interestRate : 1.5 ,
1933 pin : 2222 ,
20- } ;
21-
22- const account3 = {
23- owner : 'Steven Thomas Williams' ,
24- movements : [ 200 , - 200 , 340 , - 300 , - 20 , 50 , 400 , - 460 ] ,
25- interestRate : 0.7 ,
26- pin : 3333 ,
27- } ;
2834
29- const account4 = {
30- owner : 'Sarah Smith' ,
31- movements : [ 430 , 1000 , 700 , 50 , 90 ] ,
32- interestRate : 1 ,
33- pin : 4444 ,
35+ movementsDates : [
36+ '2019-11-01T13:15:33.035Z' ,
37+ '2019-11-30T09:48:16.867Z' ,
38+ '2019-12-25T06:04:23.907Z' ,
39+ '2020-01-25T14:18:46.235Z' ,
40+ '2020-02-05T16:33:06.386Z' ,
41+ '2020-04-10T14:43:26.374Z' ,
42+ '2023-12-18T18:49:59.371Z' ,
43+ '2023-12-21T12:01:20.894Z' ,
44+ ] ,
45+ currency : 'USD' ,
46+ locale : 'en-US' ,
3447} ;
3548
36- const accounts = [ account1 , account2 , account3 , account4 ] ;
49+ const accounts = [ account1 , account2 ] ;
3750
3851// Elements
3952const labelWelcome = document . querySelector ( '.welcome' ) ;
@@ -65,26 +78,167 @@ const inputClosePin = document.querySelector('.form__input--pin');
6578/////////////////////////////////////////////////
6679// LECTURES
6780
81+ const minToLogOut = 5 ;
82+
83+ let sorted = false ;
84+ let currencyOptions = { } ;
85+ let currAccount , currMinute , logout , time , timer ;
86+
6887const currencies = new Map ( [
6988 [ 'USD' , 'United States dollar' ] ,
7089 [ 'EUR' , 'Euro' ] ,
7190 [ 'GBP' , 'Pound sterling' ] ,
7291] ) ;
7392
93+ const labelDateOptions = {
94+ year : 'numeric' ,
95+ month : 'long' ,
96+ day : 'numeric' ,
97+ weekday : 'long' ,
98+ hour : 'numeric' ,
99+ minute : 'numeric'
100+ } ;
101+
102+ const movDateOptions = {
103+ year : 'numeric' ,
104+ month : 'numeric' ,
105+ day : 'numeric'
106+ } ;
107+
108+ const getLocaleDate = ( date , locale , options ) => new Intl . DateTimeFormat ( locale , options ) . format ( date ) ;
109+
110+ const getCurrencyOptions = ( acc ) =>
111+ {
112+ currencyOptions . style = 'currency' ;
113+ currencyOptions . currency = acc . currency ;
114+ } ;
115+
116+ const getLocaleNumber = ( acc , number ) => new Intl . NumberFormat ( acc . locale , currencyOptions ) . format ( number ) ; ;
117+
118+ const getDaysDiff = ( date1 , date2 ) => Math . round ( Math . abs ( date2 - date1 ) / ( 1000 * 60 * 60 * 24 ) ) ;
119+
120+ const formatMovDate = date =>
121+ {
122+ console . log ( date ) ;
123+
124+ const now = new Date ( ) ;
125+ const daysDiff = getDaysDiff ( now , date ) ;
126+ console . log ( daysDiff ) ;
127+
128+ if ( daysDiff <= 1 ) return daysDiff === 0 ? 'Today' : 'Yesterday' ;
129+ else if ( daysDiff <= 7 ) return `${ daysDiff } days ago` ;
130+
131+ return getLocaleDate ( date , currAccount . locale , movDateOptions ) ;
132+ } ;
133+
74134const createUsernames = accounts =>
75135 accounts . forEach ( account =>
76136 account . username = account . owner . toLowerCase ( ) . split ( ' ' ) . map ( name => name [ 0 ] ) . join ( '' ) ) ;
77137createUsernames ( accounts ) ;
78- console . log ( accounts ) ;
138+
139+ const updateLabelContent = ( ) =>
140+ {
141+ const now = new Date ( ) ;
142+ labelDate . textContent = getLocaleDate ( now , currAccount . locale , labelDateOptions ) ;
143+ } ;
79144
80145const updateUI = ( ) =>
81146{
82- displayMovements ( currAccount . movements ) ;
147+ updateLabelContent ( ) ;
148+
149+ currMinute = setInterval ( updateLabelContent ( ) , 1000 * 60 ) ;
150+
151+ displayMovements ( currAccount ) ;
83152 calcDisplayBalance ( currAccount . movements ) ;
84153 calcDisplaySummary ( currAccount . movements ) ;
85154} ;
86155
87- let currAccount ;
156+ const clearUI = ( ) =>
157+ {
158+ containerApp . style . opacity = 0 ;
159+ labelWelcome . textContent = 'Log in to get started' ;
160+ } ;
161+
162+ const displayMovements = ( acc , sort = false ) =>
163+ {
164+ containerMovements . innerHTML = '' ;
165+
166+ const dates = acc . movementsDates ;
167+ const temp = dates . slice ( ) ;
168+ const datesIndices = Array . from ( { length : dates . length } , ( _ , i ) => i ) ;
169+ const movs = sort ? acc . movements . slice ( ) . sort ( ( a , b ) => a - b ) : acc . movements ;
170+ sort ? datesIndices . sort ( ( a , b ) => acc . movements [ a ] - acc . movements [ b ] ) : datesIndices ;
171+
172+ console . log ( dates ) ;
173+
174+ let i = 0 ;
175+ for ( let index of datesIndices )
176+ dates [ i ++ ] = temp [ index ] ;
177+
178+ movs . forEach ( ( mov , i ) =>
179+ {
180+ const type = mov > 0 ? 'deposit' : 'withdrawal' ;
181+
182+ console . log ( dates [ i ] ) ;
183+ const dateFormatted = formatMovDate ( new Date ( dates [ i ] ) ) ;
184+ const movFormatted = getLocaleNumber ( acc , mov ) ;
185+
186+ const html = `
187+ <div class="movements__row">
188+ <div class="movements__type movements__type--${ type } ">${ i + 1 } ${ type } </div>
189+ <div class="movements__date">${ dateFormatted } </div>
190+ <div class="movements__value">${ movFormatted } </div>
191+ </div>
192+ ` ;
193+
194+ containerMovements . insertAdjacentHTML ( 'afterbegin' , html ) ;
195+ } ) ;
196+ } ;
197+
198+ const calcDisplayBalance = movements =>
199+ {
200+ const balance = movements . reduce ( ( acc , mov ) => acc + mov , 0 ) ;
201+
202+ currAccount . balance = balance ;
203+ labelBalance . textContent = `${ getLocaleNumber ( currAccount , balance ) } ` ;
204+ } ;
205+
206+ const calcDisplaySummary = movements =>
207+ {
208+ const income = movements . filter ( mov => mov > 0 ) . reduce ( ( acc , mov ) => acc + mov , 0 ) ;
209+ const outcome = movements . filter ( mov => mov < 0 ) . reduce ( ( acc , mov ) => acc + mov , 0 ) ;
210+ const interest = movements . filter ( mov => mov > 0 )
211+ . map ( mov => mov * currAccount . interestRate / 100 )
212+ . filter ( mov => mov >= 1 )
213+ . reduce ( ( acc , mov ) => acc + mov , 0 ) ;
214+
215+ labelSumIn . textContent = `${ getLocaleNumber ( currAccount , income ) } ` ;
216+ labelSumOut . textContent = `${ getLocaleNumber ( currAccount , Math . abs ( outcome ) ) } ` ;
217+ labelSumInterest . textContent = `${ getLocaleNumber ( currAccount , interest ) } ` ;
218+ } ;
219+
220+ const tick = ( ) =>
221+ {
222+ const min = String ( Math . trunc ( time / 60 ) ) . padStart ( 2 , '0' ) ;
223+ const sec = String ( time % 60 ) . padStart ( 2 , '0' ) ;
224+
225+ labelTimer . textContent = `${ min } :${ sec } ` ;
226+
227+ if ( time === 0 )
228+ {
229+ clearInterval ( timer ) ;
230+ clearUI ( ) ;
231+ }
232+ time -- ;
233+ } ;
234+
235+ const startTimer = ( ) =>
236+ {
237+ time = minToLogOut * 60 ;
238+
239+ tick ( ) ;
240+ timer = setInterval ( tick , 1000 ) ;
241+ } ;
88242
89243btnLogin . addEventListener ( 'click' , event =>
90244{
@@ -95,7 +249,12 @@ btnLogin.addEventListener('click', event =>
95249 if ( currAccount ?. pin !== Number ( inputLoginPin . value ) )
96250 return ;
97251
252+ if ( currMinute ) clearInterval ( currMinute ) ;
253+ if ( timer ) clearInterval ( timer ) ;
254+ startTimer ( ) ;
255+
98256 labelWelcome . textContent = `Welcome back, ${ currAccount . owner . split ( ' ' ) [ 0 ] } ` ;
257+ getCurrencyOptions ( currAccount ) ;
99258
100259 containerApp . style . opacity = 1 ;
101260
@@ -146,10 +305,18 @@ btnTransfer.addEventListener('click', event =>
146305 if ( ! toAccount )
147306 return ;
148307
308+ clearInterval ( timer ) ;
309+ startTimer ( ) ;
310+
149311 if ( currAccount . balance >= amount && toAccount ?. username !== currAccount . username )
150312 {
151- currAccount . movements . push ( - 1 * amount ) ;
152- toAccount . movements . push ( amount ) ;
313+ const now = new Date ( ) . toISOString ( ) ;
314+
315+ currAccount . movements . push ( - amount . toFixed ( 2 ) ) ;
316+ currAccount . movementsDates . push ( now ) ;
317+
318+ toAccount . movements . push ( + amount . toFixed ( 2 ) ) ;
319+ toAccount . movementsDates . push ( now ) ;
153320 updateUI ( ) ;
154321
155322 console . log ( 'Transfer Valid' ) ;
@@ -160,11 +327,15 @@ btnLoan.addEventListener('click', event =>
160327{
161328 event . preventDefault ( ) ;
162329
163- const amount = Number ( inputLoanAmount . value ) ;
330+ clearInterval ( timer ) ;
331+ startTimer ( ) ;
332+
333+ const amount = Math . round ( inputLoanAmount . value ) ;
164334
165335 if ( amount > 0 && currAccount . movements . some ( mov => mov >= amount * 0.1 ) )
166336 {
167337 currAccount . movements . push ( amount ) ;
338+ currAccount . movementsDates . push ( new Date ( ) . toISOString ( ) ) ;
168339
169340 inputLoanAmount . value = '' ;
170341 updateUI ( ) ;
@@ -177,72 +348,32 @@ btnClose.addEventListener('click', event =>
177348{
178349 event . preventDefault ( ) ;
179350
351+ clearInterval ( timer ) ;
352+ startTimer ( ) ;
353+
180354 if ( currAccount . username === inputCloseUsername . value && currAccount . pin === Number ( inputClosePin . value ) )
181355 {
182356 const index = accounts . findIndex ( acc => acc . username === currAccount . username ) ;
183357 accounts . splice ( index , 1 ) ;
184358
185359 inputCloseUsername . value = inputClosePin . value = '' ;
186- containerApp . style . opacity = 0 ;
187-
188- labelBalance . textContent = 'Log in to get started' ;
360+ clearUI ( ) ;
189361
190362 console . log ( 'Account Deleted' ) ;
191363 }
192364} ) ;
193365
194- let sorted = false ;
195366
196367btnSort . addEventListener ( 'click' , event =>
197368{
198369 event . preventDefault ( ) ;
199- sorted = ! sorted ;
200- displayMovements ( currAccount . movements , sorted ) ;
201- } ) ;
202-
203- const displayMovements = ( movements , sort = false ) =>
204- {
205- containerMovements . innerHTML = '' ;
206370
207- const movs = sort ? movements . slice ( ) . sort ( ( a , b ) => a - b ) : movements ;
371+ clearInterval ( timer ) ;
372+ startTimer ( ) ;
208373
209- movs . forEach ( ( mov , i ) =>
210- {
211- const type = mov > 0 ? 'deposit' : 'withdrawal' ;
212-
213- const html = `
214- <div class="movements__row">
215- <div class="movements__type movements__type--${ type } ">${ i + 1 } ${ type } </div>
216- <div class="movements__value">${ mov } €</div>
217- </div>
218- ` ;
219- // <div class="movements__date">3 days ago</div>
220-
221- containerMovements . insertAdjacentHTML ( 'afterbegin' , html ) ;
222- } ) ;
223- } ;
224-
225- const calcDisplayBalance = movements =>
226- {
227- const balance = movements . reduce ( ( acc , mov ) => acc + mov , 0 ) ;
228-
229- currAccount . balance = balance ;
230- labelBalance . textContent = `${ balance } €` ;
231- } ;
232-
233- const calcDisplaySummary = movements =>
234- {
235- const income = movements . filter ( mov => mov > 0 ) . reduce ( ( acc , mov ) => acc + mov , 0 ) ;
236- const outcome = movements . filter ( mov => mov < 0 ) . reduce ( ( acc , mov ) => acc + mov , 0 ) ;
237- const interest = movements . filter ( mov => mov > 0 )
238- . map ( mov => mov * currAccount . interestRate / 100 )
239- . filter ( mov => mov >= 1 )
240- . reduce ( ( acc , mov ) => acc + mov , 0 ) ;
241-
242- labelSumIn . textContent = `${ income } €` ;
243- labelSumOut . textContent = `${ Math . abs ( outcome ) } €` ;
244- labelSumInterest . textContent = `${ interest } €` ;
245- } ;
374+ sorted = ! sorted ;
375+ displayMovements ( currAccount , sorted ) ;
376+ } ) ;
246377
247378const overallBalance = accounts . flatMap ( acc => acc . movements ) . reduce ( ( acc , curr ) => acc += curr , 0 ) ;
248379console . log ( `Overall Balance: ${ overallBalance } ` ) ;
0 commit comments