├── starter ├── icon.png ├── logo.png ├── Bankist-flowchart.png ├── newArrayMethods.js ├── index.html ├── style.css └── app.js └── README.md /starter/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Andrew-Tsegaye/bankist-app/HEAD/starter/icon.png -------------------------------------------------------------------------------- /starter/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Andrew-Tsegaye/bankist-app/HEAD/starter/logo.png -------------------------------------------------------------------------------- /starter/Bankist-flowchart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Andrew-Tsegaye/bankist-app/HEAD/starter/Bankist-flowchart.png -------------------------------------------------------------------------------- /starter/newArrayMethods.js: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////// 2 | /* -------- NEW ARRAY METHODS PRACTICE -------- */ 3 | 4 | const people = ['Hemi', 'Tuji', 'Keki']; 5 | 6 | // the with method 7 | /* 8 | const newPeople = people.with(2, 'Edu'); // <-- returns an array 9 | const peopleCopy = [...people]; 10 | peopleCopy[2] = 'New'; 11 | 12 | console.log('Original', people); 13 | console.log('New', newPeople); 14 | console.log('Copy', peopleCopy); 15 | */ 16 | 17 | // the toSorted method 18 | /* 19 | people.sort(); 20 | const sortedPeople = [...people].sort(); 21 | const toSortedPeople = people.toSorted(); 22 | 23 | console.log('Sorted', toSortedPeople); 24 | console.log('Original', people); 25 | */ 26 | 27 | // the toReversed method 28 | /* 29 | const reversedPeople = people.toReversed(); 30 | 31 | console.log('Reversed', reversedPeople); 32 | console.log('Original', people); 33 | */ 34 | 35 | // the toSpliced method 36 | /* 37 | people.splice(0, 1, 'Kaly'); // do NOT return new array instead it mutates the Original one 38 | 39 | const copy = people.toSpliced(0, 2, 'New'); 40 | 41 | console.log('Original', people); 42 | console.log('Copy', copy); 43 | */ 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Minimalist Bank App -> Bankist 2 | 3 | The Bankist App appears to be a simple, minimalist online banking application. It allows users to log in to their bank account and view their balance, transactions, and account details. The app also provides features for making transfers, deposits, and withdrawals, as well as the ability to lend money to other users. The interface is designed to be user-friendly and streamlined, offering only the essential features needed for managing one's finances. 4 | 5 | ![Bankist App](https://i.imgur.com/TWznvjA.png) 6 | 7 | ## Features 8 | 9 | - Ability to Login and Close account 10 | - Ability to transfer money 11 | - Ability to deposite and withdrawal money 12 | - Ability to sort cash transaction in order 13 | - Cross platform 14 | 15 | ### Testing the App Locally 16 | Once you've built the app, you may test it locally by running npm run preview command. 17 | 18 | ```bash 19 | $ npm run build 20 | $ npm run preview 21 | ``` 22 | 23 | ## Deployment 24 | 25 | If you setup JavaScript using vite you can deploy this project using 26 | 27 | ```bash 28 | $ npm run deploy 29 | ``` 30 | 31 | - Designed and developed by [Andrew-Tsegaye](https://www.github.com/Andrew-Tsegaye) 32 | -------------------------------------------------------------------------------- /starter/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 13 | 14 | 15 | Bankist 16 | 17 | 18 | 19 | 38 | 39 |
40 | 41 |
42 |
43 |

Current balance

44 |

45 | As of 05/03/2037 46 |

47 |
48 |

0000€

49 |
50 | 51 | 52 |
53 |
54 |
2 deposit
55 |
3 days ago
56 |
4 000€
57 |
58 |
59 |
60 | 1 withdrawal 61 |
62 |
24/01/2037
63 |
-378€
64 |
65 |
66 | 67 | 68 |
69 |

In

70 |

0000€

71 |

Out

72 |

0000€

73 |

Interest

74 |

0000€

75 | 76 |
77 | 78 | 79 |
80 |

Transfer money

81 |
82 | 83 | 84 | 85 | 86 | 87 |
88 |
89 | 90 | 91 |
92 |

Request loan

93 |
94 | 95 | 96 | 97 |
98 |
99 | 100 | 101 |
102 |

Close account

103 |
104 | 105 | 110 | 111 | 112 | 113 |
114 |
115 | 116 | 117 |

118 | You will be logged out in 05:00 119 |

120 |
121 | 122 | 125 | 126 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /starter/style.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Use this CSS to learn some intersting techniques, 3 | * in case you're wondering how I built the UI. 4 | * Have fun! 😁 5 | */ 6 | 7 | * { 8 | margin: 0; 9 | padding: 0; 10 | box-sizing: inherit; 11 | } 12 | 13 | html { 14 | font-size: 62.5%; 15 | box-sizing: border-box; 16 | } 17 | 18 | html::-webkit-scrollbar-track { 19 | --webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3); 20 | border-radius: 10px; 21 | background-color: #f5f5f5; 22 | } 23 | 24 | html::-webkit-scrollbar { 25 | width: 7px; 26 | background-color: #f5f5f5; 27 | } 28 | 29 | html::-webkit-scrollbar-thumb { 30 | border-radius: 20px; 31 | --webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3); 32 | background-color: #555; 33 | } 34 | 35 | body { 36 | font-family: 'Poppins', sans-serif; 37 | color: #444; 38 | background-color: #f3f3f3; 39 | height: 100vh; 40 | padding: 2rem; 41 | } 42 | 43 | nav { 44 | display: flex; 45 | justify-content: space-between; 46 | align-items: center; 47 | padding: 0 2rem; 48 | } 49 | 50 | .welcome { 51 | font-size: 1.9rem; 52 | font-weight: 500; 53 | } 54 | 55 | .logo { 56 | height: 5.25rem; 57 | } 58 | 59 | .login { 60 | display: flex; 61 | } 62 | 63 | .login__input { 64 | border: none; 65 | padding: 0.5rem 2rem; 66 | font-size: 1.6rem; 67 | font-family: inherit; 68 | text-align: center; 69 | width: 12rem; 70 | border-radius: 10rem; 71 | margin-right: 1rem; 72 | color: inherit; 73 | border: 1px solid #fff; 74 | transition: all 0.3s; 75 | } 76 | 77 | .login__input:focus { 78 | outline: none; 79 | border: 1px solid #ccc; 80 | } 81 | 82 | .login__input::placeholder { 83 | color: #bbb; 84 | } 85 | 86 | .login__btn { 87 | border: none; 88 | background: none; 89 | font-size: 2.2rem; 90 | color: inherit; 91 | cursor: pointer; 92 | transition: all 0.3s; 93 | } 94 | 95 | .login__btn:hover, 96 | .login__btn:focus, 97 | .btn--sort:hover, 98 | .btn--sort:focus { 99 | outline: none; 100 | color: #777; 101 | } 102 | 103 | /* MAIN */ 104 | .app { 105 | position: relative; 106 | max-width: 100rem; 107 | margin: 4rem auto; 108 | display: grid; 109 | grid-template-columns: 4fr 3fr; 110 | grid-template-rows: auto repeat(3, 15rem) auto; 111 | gap: 2rem; 112 | 113 | /* NOTE This creates the fade in/out anumation */ 114 | opacity: 0; 115 | transition: all 1s; 116 | } 117 | 118 | .balance { 119 | grid-column: 1 / span 2; 120 | display: flex; 121 | align-items: flex-end; 122 | justify-content: space-between; 123 | margin-bottom: 2rem; 124 | } 125 | 126 | .balance__label { 127 | font-size: 2.2rem; 128 | font-weight: 500; 129 | margin-bottom: -0.2rem; 130 | } 131 | 132 | .balance__date { 133 | font-size: 1.4rem; 134 | color: #888; 135 | } 136 | 137 | .balance__value { 138 | font-size: 4.5rem; 139 | font-weight: 400; 140 | } 141 | 142 | /* MOVEMENTS */ 143 | .movements { 144 | grid-row: 2 / span 3; 145 | background-color: #fff; 146 | border-radius: 1rem; 147 | overflow: scroll; 148 | overflow-x: hidden; 149 | } 150 | 151 | #style-1::-webkit-scrollbar-track { 152 | --webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3); 153 | border-radius: 10px; 154 | background-color: #f5f5f5; 155 | } 156 | 157 | #style-1::-webkit-scrollbar { 158 | width: 7px; 159 | background-color: #f5f5f5; 160 | } 161 | 162 | #style-1::-webkit-scrollbar-thumb { 163 | border-radius: 20px; 164 | --webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3); 165 | background-color: #555; 166 | } 167 | 168 | .movements__row { 169 | padding: 2.25rem 4rem; 170 | display: flex; 171 | align-items: center; 172 | border-bottom: 1px solid #eee; 173 | } 174 | 175 | .movements__type { 176 | font-size: 1.1rem; 177 | text-transform: uppercase; 178 | font-weight: 500; 179 | color: #fff; 180 | padding: 0.1rem 1rem; 181 | border-radius: 10rem; 182 | margin-right: 2rem; 183 | } 184 | 185 | .movements__date { 186 | font-size: 1.1rem; 187 | text-transform: uppercase; 188 | font-weight: 500; 189 | color: #666; 190 | } 191 | 192 | .movements__type--deposit { 193 | background-image: linear-gradient(to top left, #39b385, #9be15d); 194 | } 195 | 196 | .movements__type--withdrawal { 197 | background-image: linear-gradient(to top left, #e52a5a, #ff585f); 198 | } 199 | 200 | .movements__value { 201 | font-size: 1.7rem; 202 | margin-left: auto; 203 | } 204 | 205 | /* SUMMARY */ 206 | .summary { 207 | grid-row: 5 / 6; 208 | display: flex; 209 | align-items: baseline; 210 | padding: 0 0.3rem; 211 | margin-top: 1rem; 212 | } 213 | 214 | .summary__label { 215 | font-size: 1.2rem; 216 | font-weight: 500; 217 | text-transform: uppercase; 218 | margin-right: 0.8rem; 219 | } 220 | 221 | .summary__value { 222 | font-size: 2.2rem; 223 | margin-right: 2.5rem; 224 | } 225 | 226 | .summary__value--in, 227 | .summary__value--interest { 228 | color: #66c873; 229 | } 230 | 231 | .summary__value--out { 232 | color: #f5465d; 233 | } 234 | 235 | .btn--sort { 236 | margin-left: auto; 237 | border: none; 238 | background: none; 239 | font-size: 1.3rem; 240 | font-weight: 500; 241 | cursor: pointer; 242 | } 243 | 244 | .btn--sort:active { 245 | color: hotpink; 246 | } 247 | 248 | /* OPERATIONS */ 249 | .operation { 250 | border-radius: 1rem; 251 | padding: 3rem 4rem; 252 | color: #333; 253 | } 254 | 255 | .operation--transfer { 256 | background-image: linear-gradient(to top left, #ffb003, #ffcb03); 257 | } 258 | 259 | .operation--loan { 260 | background-image: linear-gradient(to top left, #39b385, #9be15d); 261 | } 262 | 263 | .operation--close { 264 | background-image: linear-gradient(to top left, #e52a5a, #ff585f); 265 | } 266 | 267 | h2 { 268 | margin-bottom: 1.5rem; 269 | font-size: 1.7rem; 270 | font-weight: 600; 271 | color: #333; 272 | } 273 | 274 | .form { 275 | display: grid; 276 | grid-template-columns: 2.5fr 2.5fr 1fr; 277 | grid-template-rows: auto auto; 278 | gap: 0.4rem 1rem; 279 | } 280 | 281 | /* Exceptions for interst */ 282 | .form.form--loan { 283 | grid-template-columns: 2.5fr 1fr 2.5fr; 284 | } 285 | .form__label--loan { 286 | grid-row: 2; 287 | } 288 | /* End exceptions */ 289 | 290 | .form__input { 291 | width: 100%; 292 | border: none; 293 | background-color: rgba(255, 255, 255, 0.4); 294 | font-family: inherit; 295 | font-size: 1.5rem; 296 | text-align: center; 297 | color: #333; 298 | padding: 0.3rem 1rem; 299 | border-radius: 0.7rem; 300 | transition: all 0.3s; 301 | } 302 | 303 | .form__input:focus { 304 | outline: none; 305 | background-color: rgba(255, 255, 255, 0.6); 306 | } 307 | 308 | .form__label { 309 | font-size: 1.3rem; 310 | text-align: center; 311 | } 312 | 313 | .form__btn { 314 | border: none; 315 | border-radius: 0.7rem; 316 | font-size: 1.8rem; 317 | background-color: #fff; 318 | cursor: pointer; 319 | transition: all 0.3s; 320 | } 321 | 322 | .form__btn:focus { 323 | outline: none; 324 | background-color: rgba(255, 255, 255, 0.8); 325 | } 326 | 327 | .logout-timer { 328 | padding: 0 0.3rem; 329 | margin-top: 1.9rem; 330 | text-align: right; 331 | font-size: 1.25rem; 332 | } 333 | 334 | .timer { 335 | font-weight: 600; 336 | } 337 | -------------------------------------------------------------------------------- /starter/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | ///////////////////////////////////////////////// 4 | ///////////////////////////////////////////////// 5 | // BANKIST APP 6 | 7 | ///////////////////////////////////////////////// 8 | // Data 9 | 10 | // DIFFERENT DATA! Contains movement dates, currency and locale 11 | 12 | const account1 = { 13 | owner: 'Andrew Tsegaye', 14 | movements: [200, 455.23, -306.5, 25000, -642.21, -133.9, 79.97, 1300], 15 | interestRate: 1.2, // % 16 | pin: 1111, 17 | 18 | movementsDates: [ 19 | '2020-02-05T16:33:06.386Z', 20 | '2020-04-10T14:43:26.374Z', 21 | '2021-06-22T18:49:59.371Z', 22 | '2021-06-25T12:01:20.894Z', 23 | '2021-07-26T12:01:20.894Z', 24 | '2022-10-29T12:29:35.462Z', 25 | '2022-11-01T12:29:35.462Z', 26 | '2022-11-03T12:29:35.462Z', 27 | ], 28 | currency: 'EUR', 29 | locale: 'pt-PT', // de-DE 30 | }; 31 | 32 | const account2 = { 33 | owner: 'Kaleb Tsegaye', 34 | movements: [5000, 3400, -150, -790, -3210, -1000, 8500, -30], 35 | interestRate: 1.5, 36 | pin: 2222, 37 | 38 | movementsDates: [ 39 | '2020-02-05T16:33:06.386Z', 40 | '2020-04-10T14:43:26.374Z', 41 | '2021-06-22T18:49:59.371Z', 42 | '2021-06-25T12:01:20.894Z', 43 | '2021-07-26T12:01:20.894Z', 44 | '2022-10-29T12:29:35.462Z', 45 | '2022-11-02T12:29:35.462Z', 46 | '2022-11-03T12:29:35.462Z', 47 | ], 48 | currency: 'USD', 49 | locale: 'en-US', 50 | }; 51 | 52 | const accounts = [account1, account2]; 53 | 54 | ///////////////////////////////////////////////// 55 | // Elements 56 | const labelWelcome = document.querySelector('.welcome'); 57 | const labelDate = document.querySelector('.date'); 58 | const labelBalance = document.querySelector('.balance__value'); 59 | const labelSumIn = document.querySelector('.summary__value--in'); 60 | const labelSumOut = document.querySelector('.summary__value--out'); 61 | const labelSumInterest = document.querySelector('.summary__value--interest'); 62 | const labelTimer = document.querySelector('.timer'); 63 | 64 | const containerApp = document.querySelector('.app'); 65 | const containerMovements = document.querySelector('.movements'); 66 | 67 | const btnLogin = document.querySelector('.login__btn'); 68 | const btnTransfer = document.querySelector('.form__btn--transfer'); 69 | const btnLoan = document.querySelector('.form__btn--loan'); 70 | const btnClose = document.querySelector('.form__btn--close'); 71 | const btnSort = document.querySelector('.btn--sort'); 72 | 73 | const inputLoginUsername = document.querySelector('.login__input--user'); 74 | const inputLoginPin = document.querySelector('.login__input--pin'); 75 | const inputTransferTo = document.querySelector('.form__input--to'); 76 | const inputTransferAmount = document.querySelector('.form__input--amount'); 77 | const inputLoanAmount = document.querySelector('.form__input--loan-amount'); 78 | const inputCloseUsername = document.querySelector('.form__input--user'); 79 | const inputClosePin = document.querySelector('.form__input--pin'); 80 | 81 | ///////////////////////////////////////////////// 82 | // Functions 83 | 84 | const formatMovementsDay = function (date, locale) { 85 | const calcDaysPassed = (date1, date2) => 86 | Math.round(Math.abs((date2 - date1) / (1000 * 60 * 60 * 24))); 87 | 88 | const daysPassed = calcDaysPassed(new Date(), date); 89 | 90 | if (daysPassed === 0) return 'Today'; 91 | if (daysPassed === 1) return 'Yesterday'; 92 | if (daysPassed <= 7) return `${daysPassed} days ago`; 93 | // const day = `${date.getDate()}`.padStart(2, 0); 94 | // const month = `${date.getMonth()}`.padStart(2, 0); 95 | // const year = date.getFullYear(); 96 | // return `${day}/${month}/${year}`; 97 | // day = `${date.toLocaleDateString('en-US', options)}`, 98 | return new Intl.DateTimeFormat(locale).format(date); 99 | }; 100 | 101 | const formattedCur = function (value, locale, currency) { 102 | return new Intl.NumberFormat(locale, { 103 | style: 'currency', 104 | currency: currency, 105 | }).format(value); 106 | }; 107 | 108 | const displayMovements = function (acc, sort = false) { 109 | containerMovements.innerHTML = ''; 110 | 111 | const movs = sort 112 | ? acc.movements.slice().sort((a, b) => a - b) 113 | : acc.movements; 114 | 115 | movs.forEach(function (mov, i) { 116 | const type = mov > 0 ? 'deposit' : 'withdrawal'; 117 | 118 | // const options = { weekday: 'long' }; 119 | const date = new Date(acc.movementsDates[i]); 120 | const displayDate = formatMovementsDay(date, acc.locale); 121 | 122 | const formattedMov = formattedCur(mov, acc.locale, acc.currency); 123 | 124 | const html = ` 125 |
126 |
${i + 1} ${type}
127 |
${displayDate}
128 |
${formattedMov}
129 |
130 | `; 131 | 132 | containerMovements.insertAdjacentHTML('afterbegin', html); 133 | }); 134 | }; 135 | 136 | const calcDisplayBalance = function (acc) { 137 | acc.balance = acc.movements.reduce((acc, mov) => acc + mov, 0); 138 | labelBalance.textContent = formattedCur( 139 | acc.balance, 140 | acc.locale, 141 | acc.currency 142 | ); 143 | }; 144 | 145 | const calcDisplaySummary = function (acc) { 146 | const incomes = acc.movements 147 | .filter(mov => mov > 0) 148 | .reduce((acc, mov) => acc + mov, 0); 149 | labelSumIn.textContent = formattedCur( 150 | Math.abs(incomes), 151 | acc.locale, 152 | acc.currency 153 | ); 154 | 155 | const out = acc.movements 156 | .filter(mov => mov < 0) 157 | .reduce((acc, mov) => acc + mov, 0); 158 | labelSumOut.textContent = formattedCur( 159 | Math.abs(out), 160 | acc.locale, 161 | acc.currency 162 | ); 163 | 164 | const interest = acc.movements 165 | .filter(mov => mov > 0) 166 | .map(deposit => (deposit * acc.interestRate) / 100) 167 | .filter((int, i, arr) => { 168 | // console.log(arr); 169 | return int >= 1; 170 | }) 171 | .reduce((acc, int) => acc + int, 0); 172 | labelSumInterest.textContent = formattedCur( 173 | Math.abs(interest), 174 | acc.locale, 175 | acc.currency 176 | ); 177 | }; 178 | 179 | const createUsernames = function (accs) { 180 | accs.forEach(function (acc) { 181 | acc.username = acc.owner 182 | .toLowerCase() 183 | .split(' ') 184 | .map(name => name[0]) 185 | .join(''); 186 | }); 187 | }; 188 | createUsernames(accounts); 189 | 190 | const updateUI = function (acc) { 191 | // Display movements 192 | displayMovements(acc); 193 | 194 | // Display balance 195 | calcDisplayBalance(acc); 196 | 197 | // Display summary 198 | calcDisplaySummary(acc); 199 | }; 200 | 201 | const startLogOutTimer = function () { 202 | // Set time to 5 minutes 203 | let time = 120; 204 | 205 | const tick = function () { 206 | const min = String(Math.trunc(time / 60)).padStart(2, 0); 207 | const sec = String(time % 60).padStart(2, 0); 208 | 209 | // In each call, print the remaining time to UI 210 | labelTimer.textContent = `${min}:${sec}`; 211 | 212 | // When 0 seconds, stop timer and log out user 213 | if (time === 0) { 214 | clearInterval(timer); 215 | labelWelcome.textContent = 'Login to get started'; 216 | containerApp.style.opacity = 0; 217 | } 218 | 219 | // Decrease 1 second 220 | time--; 221 | }; 222 | tick(); 223 | // Call the timer every second 224 | const timer = setInterval(tick, 1000); 225 | return timer; 226 | }; 227 | 228 | /////////////////////////////////////// 229 | // Event handlers 230 | let currentAccount, timer; 231 | 232 | // Fake account login 233 | // currentAccount = account1; 234 | // updateUI(currentAccount); 235 | // containerApp.style.opacity = 100; 236 | 237 | btnLogin.addEventListener('click', function (e) { 238 | // Prevent form from submitting 239 | e.preventDefault(); 240 | 241 | currentAccount = accounts.find( 242 | acc => acc.username === inputLoginUsername.value 243 | ); 244 | console.log(currentAccount); 245 | 246 | if (currentAccount?.pin === +inputLoginPin.value) { 247 | // Display UI and message 248 | labelWelcome.textContent = `Welcome back, ${ 249 | currentAccount.owner.split(' ')[0] 250 | }`; 251 | containerApp.style.opacity = 100; 252 | 253 | // Show date and time 254 | const now = new Date(); 255 | const options = { 256 | hour: 'numeric', 257 | minute: 'numeric', 258 | day: 'numeric', 259 | month: 'numeric', 260 | year: 'numeric', 261 | // weekday: 'long', 262 | }; 263 | // const locale = navigator.language; <--* 'en-US' takes language of the browser 264 | // console.log(locale); 265 | 266 | // Display date 267 | labelDate.textContent = new Intl.DateTimeFormat( 268 | currentAccount.locale, 269 | options 270 | ).format(now); 271 | 272 | // Clear input fields 273 | inputLoginUsername.value = inputLoginPin.value = ''; 274 | inputLoginPin.blur(); 275 | 276 | // Timer 277 | if (timer) clearInterval(timer); 278 | timer = startLogOutTimer(); 279 | 280 | // Update UI 281 | updateUI(currentAccount); 282 | } 283 | }); 284 | 285 | btnTransfer.addEventListener('click', function (e) { 286 | e.preventDefault(); 287 | const amount = +inputTransferAmount.value; 288 | const receiverAcc = accounts.find( 289 | acc => acc.username === inputTransferTo.value 290 | ); 291 | inputTransferAmount.value = inputTransferTo.value = ''; 292 | 293 | if ( 294 | amount > 0 && 295 | receiverAcc && 296 | currentAccount.balance >= amount && 297 | receiverAcc?.username !== currentAccount.username 298 | ) { 299 | // Doing the transfer 300 | currentAccount.movements.push(-amount); 301 | receiverAcc.movements.push(amount * 0.99); 302 | 303 | // Add transfer date 304 | currentAccount.movementsDates.push(new Date().toISOString()); 305 | receiverAcc.movementsDates.push(new Date().toISOString()); 306 | 307 | // Update UI 308 | updateUI(currentAccount); 309 | 310 | // Reset timer 311 | clearInterval(timer); 312 | timer = startLogOutTimer(); 313 | } 314 | }); 315 | 316 | btnLoan.addEventListener('click', function (e) { 317 | e.preventDefault(); 318 | 319 | const amount = Math.floor(inputLoanAmount.value); 320 | 321 | if (amount > 0 && currentAccount.movements.some(mov => mov >= amount * 0.1)) { 322 | setTimeout(() => { 323 | // Add movement 324 | currentAccount.movements.push(amount); 325 | 326 | // Add loan date 327 | currentAccount.movementsDates.push(new Date().toISOString()); 328 | 329 | // Update UI 330 | updateUI(currentAccount); 331 | }, 2500); 332 | } 333 | inputLoanAmount.value = ''; 334 | 335 | // Reset timer 336 | clearInterval(timer); 337 | timer = startLogOutTimer(); 338 | }); 339 | 340 | btnClose.addEventListener('click', function (e) { 341 | e.preventDefault(); 342 | 343 | if ( 344 | inputCloseUsername.value === currentAccount.username && 345 | +inputClosePin.value === currentAccount.pin 346 | ) { 347 | const index = accounts.findIndex( 348 | acc => acc.username === currentAccount.username 349 | ); 350 | console.log(index); 351 | // .indexOf(23) 352 | 353 | // Delete account 354 | accounts.splice(index, 1); 355 | 356 | // Hide UI 357 | containerApp.style.opacity = 0; 358 | } 359 | 360 | inputCloseUsername.value = inputClosePin.value = ''; 361 | }); 362 | 363 | let sorted = false; 364 | btnSort.addEventListener('click', function (e) { 365 | e.preventDefault(); 366 | displayMovements(currentAccount, !sorted); 367 | sorted = !sorted; 368 | }); 369 | 370 | ///////////////////////////////////////////////// 371 | ///////////////////////////////////////////////// 372 | // LECTURES 373 | 374 | ///////////////////////////////////////////////// 375 | /* -----*----- === Converting and Checking Numbers === ----*------ */ 376 | /* 377 | console.log(24 === 24.0); 378 | 379 | // Base 10 - 0 to 9. 1/10 = 0.1. 3/10 = 3.3333333 380 | // Binary 2 - 0 1 381 | console.log(0.2 + 0.1); 382 | console.log(0.2 + 0.1 === 0.3); 383 | 384 | // Conversion 385 | console.log(Number('23')); 386 | console.log(+'23'); 387 | 388 | // Parsing 389 | console.log(Number.parseInt('30px', 10)); 390 | console.log(Number.parseInt('e20', 10)); 391 | 392 | console.log(Number.parseInt(' 2.5rem ')); 393 | console.log(Number.parseFloat(' 2.5rem ')); 394 | 395 | // console.log(parseFloat(' 2.5rem ')); 396 | 397 | // Check if value is NaN 398 | console.log(Number.isNaN(20)); 399 | console.log(Number.isNaN('20')); 400 | console.log(Number.isNaN(+'20px')); 401 | console.log(Number.isNaN(23 / 0)); 402 | 403 | // Checking if value is number 404 | console.log(Number.isFinite(20)); 405 | console.log(Number.isFinite('20')); 406 | console.log(Number.isFinite(+'20X')); 407 | console.log(Number.isFinite(23 / 0)); 408 | 409 | console.log(Number.isInteger(23)); 410 | console.log(Number.isInteger(23.0)); 411 | console.log(Number.isInteger(23 / 0)); 412 | */ 413 | 414 | ///////////////////////////////////////////////// 415 | /* -----*----- === Math and Rounding === ----*------ */ 416 | /* 417 | console.log(Math.sqrt(25)); 418 | console.log(25 ** (1 / 2)); 419 | console.log(8 ** (1 / 3)); 420 | 421 | console.log(Math.max(5, 18, 23, 11, 2)); 422 | console.log(Math.max(5, 18, '23', 11, 2)); 423 | console.log(Math.max(5, 18, '23px', 11, 2)); 424 | 425 | console.log(Math.min(5, 18, 23, 11, 2)); 426 | 427 | console.log(Math.PI * Number.parseFloat('10px') ** 2); 428 | 429 | console.log(Math.trunc(Math.random() * 6) + 1); 430 | 431 | // Crearting a random number b/n min and max both inclusive 432 | const randomInt = (min, max) => 433 | Math.floor(Math.random() * (max - min) + 1 + min); 434 | // 0...1 -> 0...(max - min) -> min...max 435 | // console.log(randomInt(10, 20)); 436 | 437 | // Rounding Integers 438 | console.log('--Rounding Integers--'); 439 | 440 | console.log(Math.round(23.3)); 441 | console.log(Math.round(23.9)); 442 | 443 | console.log(Math.ceil(23.3)); 444 | console.log(Math.ceil(23.9)); 445 | 446 | console.log(Math.floor(23.3)); 447 | console.log(Math.floor('23.9')); 448 | 449 | console.log(Math.trunc(23.3)); 450 | 451 | console.log(Math.trunc(-23.3)); 452 | console.log(Math.floor(-23.3)); 453 | 454 | // Rounding Decimals 455 | console.log((2.7).toFixed(0)); // always converts to string 456 | console.log((2.7).toFixed(3)); // adds zeros until its decimal become three 457 | 458 | console.log((2.345).toFixed(2)); 459 | console.log(+(2.345).toFixed(2)); 460 | */ 461 | 462 | ///////////////////////////////////////////////// 463 | /* -----*----- === The Remainder Operator === ----*------ */ 464 | /* 465 | console.log(5 % 2); 466 | console.log(5 / 2); // 5 = 2 * 2 + 1 467 | 468 | console.log(8 % 3); 469 | console.log(8 / 3); // 8 = 2 * 3 + 2 470 | 471 | console.log(6 % 2); 472 | console.log(6 / 2); 473 | 474 | console.log(7 % 2); 475 | console.log(7 / 2); 476 | 477 | const isEven = n => n % 2 === 0; 478 | console.log(isEven(70987)); 479 | 480 | labelBalance.addEventListener('click', function () { 481 | [...document.querySelectorAll('.movements__row')].forEach((el, i) => { 482 | // 0, 2, 4, 6 483 | if (i % 2 === 0) el.style.backgroundColor = 'orangered'; 484 | // 0, 3, 6, 9 485 | if (i % 3 === 0) el.style.backgroundColor = 'blue'; 486 | }); 487 | }); 488 | */ 489 | 490 | ///////////////////////////////////////////////// 491 | /* -----*----- === Working with BigInt === ----*------ */ 492 | /* 493 | console.log(2 ** 53 - 1); 494 | console.log(Number.MAX_SAFE_INTEGER); 495 | console.log(2 ** 53 + 1); 496 | console.log(2 ** 53 + 2); 497 | console.log(2 ** 53 + 3); 498 | console.log(2 ** 53 + 4); 499 | 500 | // BigInt 501 | console.log(5685321156432174245575632395929404237576941n); 502 | console.log(BigInt(568532115)); 503 | // console.log(Math.sqrt(19n)); 504 | 505 | // Operations 506 | console.log(1000n + 1000n); 507 | console.log(43629774071493247140598723947136519743n * 1000n); 508 | const num = 23; 509 | 510 | console.log(huge * BigInt(num)); 511 | 512 | // Exceptions 513 | console.log(20n > 15); 514 | console.log(20n === 20); 515 | console.log(typeof 20n); 516 | console.log(20n == '20'); 517 | 518 | console.log(huge + ' is REALLY big!!!'); 519 | 520 | // Divisions 521 | console.log(10n / 3n); 522 | console.log(10 / 3); 523 | */ 524 | 525 | ///////////////////////////////////////////////// 526 | /* -----*----- === Creating Dates === ----*------ */ 527 | /* 528 | // Create a Date 529 | /* 530 | const now = new Date(); 531 | 532 | console.log(now); 533 | 534 | console.log(new Date('Oct 31 2022 18:45:42')); 535 | console.log(new Date('October 22, 2015')); 536 | console.log(new Date(account1.movementsDates[0])); 537 | 538 | console.log(new Date(2037, 10, 19, 15, 23, 5)); 539 | console.log(new Date(2022, 10, 31)); 540 | 541 | console.log(new Date(0)); 542 | console.log(new Date(3 * 24 * 60 * 60 * 1000)); 543 | 544 | // working with dates 545 | const future = new Date(2037, 10, 19, 15, 23); 546 | console.log(future); 547 | console.log(future.getFullYear()); 548 | console.log(future.getMonth()); 549 | console.log(future.getDate()); 550 | console.log(future.getDay()); 551 | console.log(future.getHours()); 552 | console.log(future.getMinutes()); 553 | console.log(future.toISOString()); 554 | console.log(future.getTime()); 555 | 556 | console.log(new Date(2142285780000)); 557 | 558 | console.log(Date.now()); 559 | console.log(new Date(1667270064128)); 560 | 561 | future.setFullYear(2040); 562 | console.log(future); 563 | */ 564 | 565 | ///////////////////////////////////////////////// 566 | /* -----*----- === Numeric Separators === ----*------ */ 567 | /* 568 | // 287,460,000,000 569 | const diameter = 287_460_000_000; 570 | console.log(diameter); 571 | 572 | const price = 345_99; 573 | console.log(price); 574 | 575 | const transferFee1 = 15_00; 576 | const transferFee2 = 1_500; 577 | 578 | const PI = 3.14_15; 579 | console.log(PI); 580 | 581 | console.log(Number('23_000')); 582 | console.log(parseInt('230_30')); 583 | */ 584 | 585 | ///////////////////////////////////////////////// 586 | /* -----*----- === Operation with Dates === ----*------ */ 587 | /* 588 | const future = new Date(2037, 10, 19, 15, 23); 589 | console.log(+future); 590 | 591 | const calcDaysPassed = (date1, date2) => 592 | Math.abs((date2 - date1) / (1000 * 60 * 60 * 24)); 593 | 594 | const days1 = calcDaysPassed(new Date(2037, 3, 4), new Date(2037, 3, 14)); 595 | console.log(days1); 596 | */ 597 | 598 | ///////////////////////////////////////////////// 599 | /* -----*----- === Internationalizing Numbers (Intl) === ----*------ */ 600 | /* 601 | const num = 3884764.23; 602 | 603 | const options = { 604 | style: 'currency', 605 | unit: 'celsius', 606 | currency: 'EUR', 607 | useGrouping: false, 608 | }; 609 | 610 | console.log('US: ', new Intl.NumberFormat('en-US', options).format(num)); 611 | console.log('Germany: ', new Intl.NumberFormat('de-DE', options).format(num)); 612 | console.log('Syria: ', new Intl.NumberFormat('ar-SY', options).format(num)); 613 | console.log( 614 | navigator.language, 615 | new Intl.NumberFormat(navigator.language, options).format(num) 616 | ); 617 | */ 618 | 619 | ///////////////////////////////////////////////// 620 | /* -----*----- === Timers: setTimeut and setTimeInterval === ----*------ */ 621 | /* 622 | // --- setTimeout schedules a time to do something --- // 623 | const ingredients = ['olives', 'spinach']; 624 | const pizzaTimer = setTimeout( 625 | (ing1, ing2) => 626 | console.log(`Here is your pizz 🍕 with ${ing1} and ${ing2} ingredients`), 627 | 3000, 628 | ...ingredients 629 | ); 630 | console.log('waiting...'); 631 | 632 | if (ingredients.includes('spinach')) clearTimeout(pizzaTimer); 633 | 634 | // --- setTimeInterval keeps running forever --- // 635 | setInterval(function () { 636 | const now = new Date(); 637 | const hours = now.getHours(); 638 | const minutes = now.getMinutes(); 639 | const seconds = now.getSeconds(); 640 | console.log(`${hours}:${minutes}:${seconds}`); 641 | }, 1000); 642 | */ 643 | --------------------------------------------------------------------------------