diff --git a/atm.js b/atm.js new file mode 100644 index 0000000..8b3edfb --- /dev/null +++ b/atm.js @@ -0,0 +1,73 @@ +const person = new Person('John', 'Example', [new Account(1500, 'EUR', 1), new Account(-2500, 'EUR', 2)]); + +const atm = (() => { + // add person name + document.querySelector('.card-title').innerHTML = `${person.firstName} ${person.lastName}`; + + // list person accounts + const card = document.querySelector('.card-body'); + + for (let account of person.accounts) { + const paragraph = document.createElement('p'); + const paragraphText = document.createTextNode(`Account Number: ${account.number}, Balance: `); + + paragraph.appendChild(paragraphText); + + const span = document.createElement('span'); + span.id = 'account' + account.number; + span.innerText = account.balance; + + paragraph.appendChild(span); + + card.appendChild(paragraph); + } + + // progress bar handling + const container = document.querySelector('.container'); + const progress = document.querySelector('.progress'); + const button = document.querySelector('button'); + container.addEventListener('myEvent', (e) => { + progress.hidden = !e.detail.showProgress; + }); + + return { + withdrawMoney: function () { + const number = +document.querySelector('#number').value; + const amount = +document.querySelector('#amount').value; + + const event = new CustomEvent('myEvent', { + detail: { showProgress: true }, + bubbles: true + }); + + button.disabled = true; + button.dispatchEvent(event); + + if (number && amount) { + event.detail.showProgress = false; + + person.withdraw(number, amount).then(() => { + document.querySelector(`span#account${number}`).innerHTML = +document.querySelector(`span#account${number}`).innerHTML - amount; + + button.dispatchEvent(event); + button.disabled = false; + + }).catch((reason) => { + console.warn(reason); + button.dispatchEvent(event); + button.disabled = false; + }); + } + }, + onInputChange: function () { + const number = +document.querySelector('#number').value; + const amount = +document.querySelector('#amount').value; + + if (number > 0 && amount > 0) { + button.disabled = false; + } else { + button.disabled = true; + } + } + } +})(); \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..3044dfc --- /dev/null +++ b/index.html @@ -0,0 +1,59 @@ + + + + + + + + + + + + JS Training code + + + + + + + +
+

JS Training

+ + + +
+
+

+

Accounts:

+
+
+ +
+ + + + + + + +
+ +
+ + + + + + \ No newline at end of file diff --git a/main.js b/main.js new file mode 100644 index 0000000..b25c83f --- /dev/null +++ b/main.js @@ -0,0 +1,69 @@ +console.log('hello from main js'); + +class Account { + constructor(balance, currency, number) { + this.balance = balance; + this.currency = currency; + this.number = number; + }; +}; + +class Person { + constructor(firstName, lastName, accounts) { + this.firstName = firstName; + this.lastName = lastName; + this.accounts = accounts; + }; + + addAccount(account) { + this.accounts.push(account); + }; + + sayHello() { + return `Hi, my name is ${this.firstName} ${this.lastName} and I have ${this.accounts.length} bank account(s) with total balance ${this._calculateBalance()}`; + }; + + filterPositiveAccounts() { + return this.accounts.filter(account => account.balance > 0); + }; + + findAccount(accountNumber) { + return this.accounts.find(account => account.number === accountNumber); + }; + + withdraw(accountNumber, amount) { + const promise = new Promise((resolve, reject) => { + const foundAccount = this.findAccount(accountNumber); + + if (foundAccount && foundAccount.balance >= amount) { + setTimeout(() => { + foundAccount.balance = foundAccount.balance - amount; + resolve(`Operation successful, withdrawn ${amount} from account ${accountNumber}, remaining balance ${foundAccount.balance}`); + }, 3000); + } else if (!foundAccount) { + reject('Incorrect account number') + } else { + reject(`Not enough funds on account number ${accountNumber}`); + } + }); + + return promise; + }; + + _calculateBalance() { + let totalBalance = 0; + + for (let account of this.accounts) { + totalBalance = totalBalance + account.balance; + } + + return totalBalance; + }; +}; + +if (typeof module !== 'undefined') { + module.exports = { + Person: Person, + Account: Account + } +} diff --git a/main.spec.js b/main.spec.js new file mode 100644 index 0000000..31ceaee --- /dev/null +++ b/main.spec.js @@ -0,0 +1,94 @@ +describe('Person class tests', () => { + + const firstName = 'John'; + const lastName = 'Example'; + let person; + + beforeEach(() => { + person = new Person(firstName, lastName, [new Account(1500, 'EUR', 1234)]); + }); + + it('should initialize new person object', () => { + // given when then + expect(person.firstName).toBe(firstName); + expect(person.lastName).toBe(lastName); + expect(person.accounts.length).toBe(1); + expect(person.accounts[0].balance).toBe(1500); + expect(person.accounts[0].currency).toBe('EUR'); + expect(person.accounts[0].number).toBe(1234); + }); + + it('should add account', () => { + // given + const account = new Account(200, 'EUR', 9999); + + // when + person.addAccount(account); + + // then + expect(person.accounts.length).toBe(2); + expect(person.accounts[1]).toEqual(account); + }); + + it('should introduce itself', () => { + // given when then + expect(person.sayHello()).toBe('Hi, my name is John Example and I have 1 bank account(s) with total balance 1500'); + }); + + it('should filter accounts with positive balance', () => { + // given + const account = new Account(-100, 'PLN', 1010); + + // when + person.addAccount(account); + const positiveAccounts = person.filterPositiveAccounts(); + + // then + expect(positiveAccounts.length = 1); + expect(positiveAccounts[0].balance).toBeGreaterThanOrEqual(0); + }); + + it('should find account by its number', () => { + // given + const accountNumber = 1234; + + // when + const foundAccount = person.findAccount(accountNumber); + + // then + expect(foundAccount.number).toBe(accountNumber); + }); + + it('should withdraw money', (done) => { + // given when + const promise = person.withdraw(1234, 200); + + // then + promise.then(() => { + expect(person.accounts[0].balance).toBe(1300); + done(); + }); + }); + + it('should not withdraw money when account not found', (done) => { + // given when + const promise = person.withdraw(5, 2000); + + // then + promise.catch((reason) => { + expect(reason).toBe('Incorrect account number'); + done(); + }); + }); + + it('should not withdraw money when there is not enough money on the account', (done) => { + // given when + const promise = person.withdraw(1234, 20000); + + // then + promise.catch((reason) => { + expect(reason).toBe('Not enough funds on account number 1234'); + done(); + }); + }); +}); \ No newline at end of file diff --git a/package.json b/package.json index 505fe25..703a733 100644 --- a/package.json +++ b/package.json @@ -35,4 +35,4 @@ "dependencies": { "bootstrap": "^4.0.0" } -} +} \ No newline at end of file diff --git a/tests/main-node.spec.js b/tests/main-node.spec.js new file mode 100644 index 0000000..9ada06a --- /dev/null +++ b/tests/main-node.spec.js @@ -0,0 +1,28 @@ +const chai = require('chai'); +const expect = chai.expect; // we are using the "expect" style of Chai +const Person = require('../main.js').Person; +const Account = require('../main.js').Account; + + +describe('Person class tests', () => { + + let person; + const firstName = 'John'; + const lastName = 'Example'; + const accounts = [new Account(1500, 'EUR', 1234)]; + + + beforeEach(() => { + person = new Person(firstName, lastName, accounts); + }); + + it('should initialize new person object', () => { + // given when then + expect(person.firstName).to.equal(firstName); + expect(person.lastName).to.equal(lastName); + expect(person.accounts.length).to.equal(1); + expect(person.accounts[0].balance).to.equal(1500); + expect(person.accounts[0].currency).to.equal('EUR'); + expect(person.accounts[0].number).to.equal(1234); + }); +}); \ No newline at end of file