├── 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 | 
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 |
88 |
89 |
90 |
91 |
92 |
Request loan
93 |
98 |
99 |
100 |
101 |
102 |
Close account
103 |
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 |
--------------------------------------------------------------------------------