-
+
+
+
@@ -15,11 +33,90 @@
import Currency from '@/components/CurrencyConverter/components/Currency.vue';
import CurrencyRatio from '@/components/CurrencyConverter/components/CurrencyRatio.vue';
+/* eslint-disable max-len */
+/* eslint-disable prefer-destructuring */
+
export default {
name: 'CurrencyConverter',
components: {
Currency,
CurrencyRatio,
},
+ props: {
+ currencies: {
+ type: Array,
+ },
+ },
+ data() {
+ return {
+ firstCurrency: this.currencies[0],
+ secondCurrency: this.currencies[1],
+ firstCurrencyAmount: 1,
+ secondCurrencyAmount: 0,
+ firstAgainstSecondCurrency: 0,
+ secondAgainstFirstCurrency: 0,
+ firstCurrencyCausedChange: false,
+ secondCurrencyCausedChange: false,
+ };
+ },
+ methods: {
+ async setCurrencyRates() {
+ if (this.firstCurrency === this.secondCurrency) {
+ this.firstAgainstSecondCurrency = 1;
+ this.secondAgainstFirstCurrency = 1;
+ return;
+ }
+ const rates = await this.$store.getters.getRates;
+ if (!rates[this.firstCurrency] && !rates[this.secondCurrency]) {
+ await this.$store.dispatch('fetchRate', this.firstCurrency);
+ await this.$store.dispatch('fetchRate', this.secondCurrency);
+ }
+ if (rates[this.firstCurrency]) {
+ this.firstAgainstSecondCurrency = rates[this.firstCurrency].rates[this.secondCurrency];
+ this.secondAgainstFirstCurrency = 1 / this.firstAgainstSecondCurrency;
+ } else {
+ this.secondAgainstFirstCurrency = rates[this.secondCurrency].rates[this.firstCurrency];
+ this.firstAgainstSecondCurrency = 1 / this.secondAgainstFirstCurrency;
+ }
+ },
+ async firstCurrencyChanged(...args) {
+ this.firstCurrency = args[0];
+ await this.setCurrencyRates();
+ this.setSecondCurrencyAmount();
+ this.secondCurrencyCausedChange = false;
+ this.firstCurrencyCausedChange = true;
+ },
+ async firstCurrencyAmountChanged(...args) {
+ const newAmount = args[0];
+ this.secondCurrencyCausedChange = false;
+ this.firstCurrencyCausedChange = true;
+ this.firstCurrencyAmount = parseFloat(newAmount);
+ this.setSecondCurrencyAmount();
+ },
+ setSecondCurrencyAmount() {
+ this.secondCurrencyAmount = parseFloat((this.firstCurrencyAmount * this.firstAgainstSecondCurrency).toFixed(2));
+ },
+ async secondCurrencyChanged(...args) {
+ this.secondCurrency = args[0];
+ await this.setCurrencyRates();
+ this.setFirstCurrencyAmount();
+ this.firstCurrencyCausedChange = false;
+ this.secondCurrencyCausedChange = true;
+ },
+ async secondCurrencyAmountChanged(...args) {
+ const newAmount = args[0];
+ this.firstCurrencyCausedChange = false;
+ this.secondCurrencyCausedChange = true;
+ this.secondCurrencyAmount = parseFloat(newAmount);
+ this.setFirstCurrencyAmount();
+ },
+ setFirstCurrencyAmount() {
+ this.firstCurrencyAmount = parseFloat((this.secondCurrencyAmount * this.secondAgainstFirstCurrency).toFixed(2));
+ },
+ },
+ async beforeMount() {
+ await this.setCurrencyRates();
+ this.setSecondCurrencyAmount();
+ },
};
diff --git a/src/components/CurrencyConverter/components/Currency.vue b/src/components/CurrencyConverter/components/Currency.vue
index 06dfc1f..a50f310 100644
--- a/src/components/CurrencyConverter/components/Currency.vue
+++ b/src/components/CurrencyConverter/components/Currency.vue
@@ -1,10 +1,18 @@
-
+
+
+ class="ml-4"
+ :options="currencies"
+ :startingOption="currency"
+ :optionImages="currencyImages"
+ :optionDescriptions="currencyNames"
+ @save-single-choice="updateCurrencyType">
@@ -12,6 +20,39 @@
diff --git a/src/components/CurrencyConverter/components/CurrencyRatio.vue b/src/components/CurrencyConverter/components/CurrencyRatio.vue
index f4a6c45..1ab92b8 100644
--- a/src/components/CurrencyConverter/components/CurrencyRatio.vue
+++ b/src/components/CurrencyConverter/components/CurrencyRatio.vue
@@ -1,5 +1,29 @@
-
-
1 EUR = 1.22 USD
+
+
1 {{firstCurrency}} = {{ratioFormatted}} {{secondCurrency}}
+
+
diff --git a/src/components/shared/Dropdown.vue b/src/components/shared/Dropdown.vue
index 693f463..4250a0e 100644
--- a/src/components/shared/Dropdown.vue
+++ b/src/components/shared/Dropdown.vue
@@ -1,23 +1,26 @@
-
+
{{ currentOption }}
▼
▲
-
-
- {{option}}
-
+
+
+
![]()
+
{{option}}
+
{{optionDescriptions[option]}}
+
+
+
diff --git a/src/components/shared/TextInput.vue b/src/components/shared/TextInput.vue
index 973078d..8631339 100644
--- a/src/components/shared/TextInput.vue
+++ b/src/components/shared/TextInput.vue
@@ -1,11 +1,64 @@
+
-
+
+
+
diff --git a/src/main.js b/src/main.js
index 3621783..c87b864 100644
--- a/src/main.js
+++ b/src/main.js
@@ -1,4 +1,5 @@
import Vue from 'vue';
+import Axios from 'axios';
import App from './App.vue';
import router from './router';
import store from './store';
@@ -6,6 +7,8 @@ import './assets/tailwind.css';
Vue.config.productionTip = false;
+Vue.prototype.$http = Axios;
+
new Vue({
router,
store,
diff --git a/src/router/index.js b/src/router/index.js
index 41d2d27..b129fea 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -1,6 +1,7 @@
import Vue from 'vue';
import VueRouter from 'vue-router';
import Home from '../views/Home.vue';
+import PageNotFound from '../views/PageNotFound.vue';
Vue.use(VueRouter);
@@ -10,6 +11,11 @@ const routes = [
name: 'Home',
component: Home,
},
+ {
+ path: '*',
+ name: 'PageNotFound',
+ component: PageNotFound,
+ },
];
const router = new VueRouter({
diff --git a/src/store/index.js b/src/store/index.js
index 9ea7685..bb01dc7 100644
--- a/src/store/index.js
+++ b/src/store/index.js
@@ -1,9 +1,11 @@
import Vue from 'vue';
import Vuex from 'vuex';
+import CurrencyExchange from './modules/CurrencyExchange';
Vue.use(Vuex);
export default new Vuex.Store({
+ strict: true,
state: {
},
mutations: {
@@ -11,5 +13,6 @@ export default new Vuex.Store({
actions: {
},
modules: {
+ CurrencyExchange,
},
});
diff --git a/src/store/modules/CurrencyExchange.js b/src/store/modules/CurrencyExchange.js
new file mode 100644
index 0000000..6263eb6
--- /dev/null
+++ b/src/store/modules/CurrencyExchange.js
@@ -0,0 +1,33 @@
+import Axios from 'axios';
+
+/* eslint-disable */
+
+const state = {
+ rates: {},
+};
+
+const getters = {
+ getRates(state) {
+ return state.rates;
+ },
+};
+
+const mutations = {
+ fetchRate(state, { currency, exchangeRate }) {
+ state.rates[currency] = exchangeRate;
+ },
+};
+
+const actions = {
+ async fetchRate(state, currency) {
+ const response = await Axios.get(process.env.VUE_APP_EXCHANGE_RATES_API + currency);
+ await state.commit('fetchRate', { currency, exchangeRate: response.data });
+ },
+};
+
+export default {
+ state,
+ getters,
+ mutations,
+ actions,
+};
diff --git a/src/views/Home.vue b/src/views/Home.vue
index 37ac11b..1605601 100644
--- a/src/views/Home.vue
+++ b/src/views/Home.vue
@@ -1,26 +1,41 @@
-
+
-
+
Currency converter
-
Bidirectional conversion & multiple value pairs
+
Bidirectional conversion
+
&
+
Multiple value pairs
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
diff --git a/src/views/PageNotFound.vue b/src/views/PageNotFound.vue
new file mode 100644
index 0000000..184e447
--- /dev/null
+++ b/src/views/PageNotFound.vue
@@ -0,0 +1,9 @@
+
+
+ 404
+ Page not found
+
+ Go to currency converter
+
+
+
diff --git a/yarn.lock b/yarn.lock
index 0070b88..6c831bd 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2283,6 +2283,13 @@ aws4@^1.8.0:
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59"
integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==
+axios@^0.21.1:
+ version "0.21.1"
+ resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8"
+ integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==
+ dependencies:
+ follow-redirects "^1.10.0"
+
babel-code-frame@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
@@ -5074,7 +5081,7 @@ flush-write-stream@^1.0.0:
inherits "^2.0.3"
readable-stream "^2.3.6"
-follow-redirects@^1.0.0:
+follow-redirects@^1.0.0, follow-redirects@^1.10.0:
version "1.13.2"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.2.tgz#dd73c8effc12728ba5cf4259d760ea5fb83e3147"
integrity sha512-6mPTgLxYm3r6Bkkg0vNM0HTjfGrOEtsfbhagQvbxDEsEkpNhw582upBaoRZylzen6krEmxXJgt9Ju6HiI4O7BA==