Commit cb86531b authored by Florent Chehab's avatar Florent Chehab

fix(currencyConversion): no more crash when currency is unknown

* Updated utils functions for currency conversion and getting symbol
* Updated its used in the app

Fixes #76
parent e283b5d6
Pipeline #37127 passed with stages
in 5 minutes and 18 seconds
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
// Inspired by : https://github.com/mui-org/material-ui/blob/master/docs/src/pages/page-layout-examples/blog/Markdown.js // Inspired by : https://github.com/mui-org/material-ui/blob/master/docs/src/pages/page-layout-examples/blog/Markdown.js
import React, { Component } from "react"; import React, { Component } from "react";
import { connect } from "react-redux";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import ReactMarkdown from "react-markdown"; import ReactMarkdown from "react-markdown";
...@@ -126,7 +125,7 @@ const ListItemRenderer = (props, classes) => ( ...@@ -126,7 +125,7 @@ const ListItemRenderer = (props, classes) => (
const CodeRenderer = (props) => ( const CodeRenderer = (props) => (
// className={classes.code} would be override by typography variant // className={classes.code} would be override by typography variant
<Typography variant={"body2"} component='code' style={{fontFamily: "monospace"}}> <Typography variant={"body2"} component='code' style={{ fontFamily: "monospace" }}>
{props.value} {props.value}
</Typography> </Typography>
); );
...@@ -187,7 +186,6 @@ const renderers = { ...@@ -187,7 +186,6 @@ const renderers = {
* *
* A custom tag for currency was adde: `:100.2CHF:` would be understood as `100 CHF (~88€)` for instance. * A custom tag for currency was adde: `:100.2CHF:` would be understood as `100 CHF (~88€)` for instance.
* *
* NB: We don't make use of Custom Component for API since currencies should be loaded at app startup.
* We don't need to fetch them here. * We don't need to fetch them here.
* *
* @class Markdown * @class Markdown
...@@ -210,14 +208,18 @@ class Markdown extends Component { ...@@ -210,14 +208,18 @@ class Markdown extends Component {
if (!el.isMoney) { if (!el.isMoney) {
compiled += el.text; compiled += el.text;
} else { } else {
const { amount, currency } = el, const { amount, currency } = el;
{ currencies } = this.props;
if (currency === "EUR") { if (currency === "EUR") {
compiled += `${amount}€`; compiled += `${amount}€`;
} else { } else {
const converted = convertAmountToEur(amount, currency, currencies); const converted = convertAmountToEur(amount, currency);
compiled += `${amount}${currency} [*(≈ ${converted}€)*](https://www.xe.com/currencyconverter/convert/?Amount=${amount}&From=${currency}&To=EUR)`; // add money converted information in markdown format compiled += `${amount}${currency} `;
if (converted === null) {
compiled += `*(\`${currency}\` n'a pas été reconnue comme le code d'une monnaie ; nous n'avons pas pu procéder à une conversion automatique)*`;
} else {
compiled += `[*(≈ ${converted}€)*](https://www.xe.com/currencyconverter/convert/?Amount=${amount}&From=${currency}&To=EUR)`; // add money converted information in markdown format
}
} }
} }
}); });
...@@ -238,12 +240,7 @@ class Markdown extends Component { ...@@ -238,12 +240,7 @@ class Markdown extends Component {
} }
Markdown.propTypes = { Markdown.propTypes = {
currencies: PropTypes.array.isRequired,
source: PropTypes.string source: PropTypes.string
}; };
const mapStateToPropsTextRenderer = (state) => ({ export default Markdown;
currencies: state.api.currenciesAll.readSucceeded.data,
});
export default connect(mapStateToPropsTextRenderer)(Markdown);
...@@ -53,6 +53,7 @@ Les objectifs de ce service sont : ...@@ -53,6 +53,7 @@ Les objectifs de ce service sont :
## Autre fun feature ## Autre fun feature
You can format money: \`:100CHF:\` => :100CHF: You can format money: \`:100CHF:\` => :100CHF:
You can format money: \`:100LSD:\` => :100LSD:
`; `;
......
...@@ -4,6 +4,7 @@ import withStyles from "@material-ui/core/styles/withStyles"; ...@@ -4,6 +4,7 @@ import withStyles from "@material-ui/core/styles/withStyles";
import Markdown from "../../../common/Markdown"; import Markdown from "../../../common/Markdown";
import moneyConversion from "../../../../utils/convertAmountToEur"; import moneyConversion from "../../../../utils/convertAmountToEur";
import getCurrencySymbol from "../../../../utils/getCurrencySymbol";
import Typography from "@material-ui/core/Typography"; import Typography from "@material-ui/core/Typography";
const styles = theme => { const styles = theme => {
...@@ -52,20 +53,12 @@ class Scholarship extends React.Component { ...@@ -52,20 +53,12 @@ class Scholarship extends React.Component {
} }
getSymbol() { getSymbol() {
const { currencies, currency } = this.props; return getCurrencySymbol(this.props.currency);
const currencyInfo = currencies.find(c => c.id == currency);
const { symbol } = currencyInfo;
if (symbol) {
return symbol;
} else {
return " " + currency;
}
} }
convertAmountToEur(amount) { convertAmountToEur(amount) {
const { currency, currencies } = this.props; const { currency } = this.props;
return moneyConversion(amount, currency, currencies); return moneyConversion(amount, currency);
} }
getAmounts() { getAmounts() {
...@@ -78,11 +71,19 @@ class Scholarship extends React.Component { ...@@ -78,11 +71,19 @@ class Scholarship extends React.Component {
} }
getConvertedAmounts() { getConvertedAmounts() {
const { amountMin, amountMax } = this.props; const { amountMin, amountMax, currency } = this.props,
convertedMin = this.convertAmountToEur(amountMin);
// we only need for errors in conversion on min.
// They share the same currency, so if one fails, the other will too.
if (convertedMin === null) {
return `Monnaie non reconnue: ${currency}`;
}
if (amountMax != null && amountMax != amountMin) { if (amountMax != null && amountMax != amountMin) {
return `${this.convertAmountToEur(amountMin)}€ – ${this.convertAmountToEur(amountMax)}€`; return `${convertedMin}€ – ${this.convertAmountToEur(amountMax)}€`;
} else { } else {
return `${this.convertAmountToEur(amountMin)}€`; return `${convertedMin}€`;
} }
} }
......
import { getLatestReadDataFromStore } from "../redux/api/utils";
// For optimization
let allCurrencies = undefined;
/** /**
* Function for converting money amounts to euros. * Function for converting money amounts to euros.
* *
* @export * @export
* @param {number} amount * @param {number} amount
* @param {string} currency * @param {string} currencyStr
* @param {Array[string]} currencies * @returns {number} or null if no matching currency could be found
* @returns {number}
*/ */
export default function convertAmountToEur(amount, currency, currencies) { export default function convertAmountToEur(amount, currencyStr) {
if (currency === "EUR") { if (currencyStr === "EUR") {
return amount; return amount;
} }
const rate = currencies.find(c => c.id == currency).one_EUR_in_this_currency; // a bit of optimization, will be useful if this function is used a lot
return Math.trunc(amount / rate); if (typeof allCurrencies === "undefined") {
allCurrencies = new Map();
const currencies = getLatestReadDataFromStore("currenciesAll");
if (currencies.length === 0) {
// To use this function, you need to have currencies loaded in the store. Make sure the currencies are loaded in the backend.
// Also, make sure not use this function before we have the currencies loaded :)
throw new Error("Currencies in the store are empty see code for more info.");
}
currencies.forEach(c => allCurrencies.set(c.id, c.one_EUR_in_this_currency));
}
if (allCurrencies.has(currencyStr)) {
return Math.trunc(amount / allCurrencies.get(currencyStr));
} else {
return null;
}
} }
import { getLatestReadDataFromStore } from "../redux/api/utils";
// For optimization
let currenciesSymbols = undefined;
/**
* Function to get the symbol associated with a currency.
* If no symbol is found, currencyStr is returned itsself.
*
* @export
* @param {string} currencyStr
* @returns
*/
export default function getCurrencySymbol(currencyStr) {
if (currencyStr === "EUR") {
return "";
}
// a bit of optimization, will be useful if this function is used a lot
if (typeof currenciesSymbols === "undefined") {
currenciesSymbols = new Map();
const currencies = getLatestReadDataFromStore("currenciesAll");
if (currencies.length === 0) {
// To use this function, you need to have currencies loaded in the store. Make sure the currencies are loaded in the backend.
// Also, make sure not use this function before we have the currencies loaded :)
throw new Error("Currencies in the store are empty see code for more info.");
}
currenciesSymbols = new Map();
currencies
.filter(c => c.symbol !== "") // We keep only the currencies with a symbol
.forEach(c => currenciesSymbols.set(c.id, c.symbol));
}
if (currenciesSymbols.has(currencyStr)) {
return currenciesSymbols.get(currencyStr);
} else {
return " " + currencyStr;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment