Commit 460bae71 authored by Nicolas Frandeboeuf's avatar Nicolas Frandeboeuf Committed by Benjamin Bouvier
Browse files

Toast'em all

parent 7025a9fc
......@@ -11,7 +11,7 @@ export default class ChartComponent extends React.Component {
}
redraw() {
alert('not yet implemented');
window.alert('not yet implemented');
}
componentDidUpdate() {
......
......@@ -3,7 +3,7 @@ import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import PropTypes from 'prop-types';
import { NONE_CATEGORY_ID, translate as $t, generateColor } from '../../helpers';
import { NONE_CATEGORY_ID, translate as $t, generateColor, notify } from '../../helpers';
import { get, actions } from '../../store';
import FuzzyOrNativeSelect from '../ui/fuzzy-or-native-select';
......@@ -62,7 +62,7 @@ const Export = connect(
});
props.onChange(category.id);
} catch (err) {
alert(`Error when creating a category: ${err.toString()}`);
notify.error($t('client.category.creation_error', { error: err.toString() }));
}
}
};
......
......@@ -3,7 +3,7 @@ import { connect } from 'react-redux';
// Global variables
import { get, actions } from '../../../store';
import { translate as $t } from '../../../helpers';
import { translate as $t, notify } from '../../../helpers';
class ImportModule extends React.Component {
state = {
......@@ -48,9 +48,9 @@ class ImportModule extends React.Component {
json = JSON.parse(fileEvent.target.result);
} catch (err) {
if (err instanceof SyntaxError) {
alert($t('client.settings.import_invalid_json'));
notify.error($t('client.settings.import_invalid_json'));
} else {
alert(`Unexpected error: ${err.message}`);
notify.error($t('client.general.unexpected_error', { error: err.message }));
}
}
......@@ -62,13 +62,13 @@ class ImportModule extends React.Component {
// Note this works also with older import formats, which
// didn't let you encrypt an export.
if (!json.encrypted) {
alert($t('client.settings.error_decrypt_non_encrypted'));
notify.error($t('client.settings.error_decrypt_non_encrypted'));
return;
}
this.props.importInstanceWithPassword(data, this.refPassword.current.value);
} else {
if (json.encrypted) {
alert($t('client.settings.error_non_decrypt_encrypted'));
notify.error($t('client.settings.error_non_decrypt_encrypted'));
return;
}
this.props.importInstanceWithoutPassword(data);
......
......@@ -2,7 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { translate as $t } from '../../../helpers';
import { translate as $t, notify } from '../../../helpers';
import { get } from '../../../store';
import PasswordInput from '../../ui/password-input';
......@@ -83,7 +83,7 @@ class CustomBankField extends React.Component {
break;
default:
alert($t('client.settings.unknown_field_type'));
notify.error($t('client.settings.unknown_field_type'));
}
// The "cols-with-label" css class is active only within modals.
......
import React from 'react';
import { connect } from 'react-redux';
import { translate as $t } from '../../../helpers';
import { translate as $t, notify } from '../../../helpers';
import { get, actions } from '../../../store';
import { registerModal } from '../../ui/modal';
......@@ -58,7 +58,7 @@ class LogsSection extends React.PureComponent {
document.execCommand('copy');
selection.removeAllRanges();
window.alert($t('client.settings.logs.copied'));
notify.success($t('client.settings.logs.copied'));
};
componentDidMount() {
......
/* eslint no-console: 0 */
import errors from '../shared/errors.json';
import { translate as $t } from './helpers';
import { translate as $t, notify } from './helpers';
export function get(name) {
if (typeof errors[name] !== 'undefined') {
......@@ -49,5 +49,5 @@ export function genericErrorHandler(err) {
msg += $t('client.sync.unknown_error');
}
alert(`${msg}\n\n${$t('client.general.see_developers_console')}`);
notify.error(`${msg}\n\n${$t('client.general.see_developers_console')}`);
}
......@@ -3,6 +3,7 @@
*/
/* eslint no-console: 0 */
import { toast } from 'react-toastify';
import {
maybeHas as maybeHas_,
......@@ -49,7 +50,7 @@ export function assert(x, wat) {
if (!x) {
let text = `Assertion error: ${wat ? wat : ''}\n${new Error().stack}`;
if (ASSERTS) {
alert(text);
window.alert(text);
console.error(text);
}
return false;
......@@ -197,3 +198,8 @@ export function computeIsSmallScreen(width = null) {
}
return actualWidth <= SMALL_SCREEN_MAX_WIDTH;
}
export const notify = {
success: msg => toast.success(msg),
error: msg => toast.error(msg, { autoClose: false })
};
......@@ -4,6 +4,7 @@ import { BrowserRouter, Route, Switch, Link, Redirect } from 'react-router-dom';
import { connect, Provider } from 'react-redux';
import PropTypes from 'prop-types';
import throttle from 'lodash.throttle';
import { ToastContainer } from 'react-toastify';
// Global variables
import { get, init, rx, actions } from './store';
......@@ -164,6 +165,8 @@ class BaseApp extends React.Component {
</Switch>
</div>
</main>
<ToastContainer />
</ErrorReporter>
);
};
......@@ -275,6 +278,6 @@ export default function runKresus() {
debug(err);
errMessage = `\n${err.shortMessage || JSON.stringify(err)}`;
}
alert(`Error when starting the app:${errMessage}\nCheck the console.`);
window.alert(`Error when starting the app:${errMessage}\nCheck the console.`);
});
}
......@@ -12,7 +12,8 @@ import {
UNKNOWN_ACCOUNT_TYPE,
displayLabel,
shouldIncludeInBalance,
shouldIncludeInOutstandingSum
shouldIncludeInOutstandingSum,
notify
} from '../helpers';
import { Account, Access, Alert, Bank, Operation } from '../models';
......@@ -530,25 +531,25 @@ export function setDefaultAccountId(accountId) {
function handleFirstSyncError(err) {
switch (err.code) {
case Errors.EXPIRED_PASSWORD:
alert($t('client.sync.expired_password'));
notify.error($t('client.sync.expired_password'));
break;
case Errors.INVALID_PARAMETERS:
alert($t('client.sync.invalid_parameters', { content: err.content || '?' }));
notify.error($t('client.sync.invalid_parameters', { content: err.content || '?' }));
break;
case Errors.INVALID_PASSWORD:
alert($t('client.sync.first_time_wrong_password'));
notify.error($t('client.sync.first_time_wrong_password'));
break;
case Errors.NO_ACCOUNTS:
alert($t('client.sync.no_accounts'));
notify.error($t('client.sync.no_accounts'));
break;
case Errors.UNKNOWN_MODULE:
alert($t('client.sync.unknown_module'));
notify.error($t('client.sync.unknown_module'));
break;
case Errors.ACTION_NEEDED:
alert($t('client.sync.action_needed'));
notify.error($t('client.sync.action_needed'));
break;
case Errors.AUTH_METHOD_NYI:
alert($t('client.sync.auth_method_nyi'));
notify.error($t('client.sync.auth_method_nyi'));
break;
default:
genericErrorHandler(err);
......@@ -560,10 +561,10 @@ function handleFirstSyncError(err) {
function handleSyncError(err) {
switch (err.code) {
case Errors.INVALID_PASSWORD:
alert($t('client.sync.wrong_password'));
notify.error($t('client.sync.wrong_password'));
break;
case Errors.NO_PASSWORD:
alert($t('client.sync.no_password'));
notify.error($t('client.sync.no_password'));
break;
default:
handleFirstSyncError(err);
......
......@@ -3,7 +3,7 @@ import moment from 'moment';
import DefaultSettings from '../../shared/default-settings';
import { assert, setupTranslator, translate as $t } from '../helpers';
import { assert, setupTranslator, translate as $t, notify } from '../helpers';
import * as backend from './backend';
import { createReducerFromMap, fillOutcomeHandlers, SUCCESS, FAIL } from './helpers';
......@@ -328,7 +328,7 @@ function reduceGetWeboobVersion(state, action) {
if (typeof action.isInstalled === 'boolean') {
if (!action.isInstalled) {
window.alert($t('client.sync.weboob_not_installed'));
notify.error($t('client.sync.weboob_not_installed'));
}
stateUpdates.map['weboob-installed'] = action.isInstalled.toString();
}
......@@ -338,7 +338,7 @@ function reduceGetWeboobVersion(state, action) {
if (status === FAIL) {
if (action.error.code === Errors.WEBOOB_NOT_INSTALLED) {
window.alert($t('client.sync.weboob_not_installed'));
notify.error($t('client.sync.weboob_not_installed'));
return u({ map: { 'weboob-installed': 'false' } }, state);
}
......
......@@ -12,7 +12,7 @@ import {
UPDATE_MODAL
} from './actions';
import { translate as $t, computeIsSmallScreen } from '../helpers';
import { translate as $t, computeIsSmallScreen, notify } from '../helpers';
import { get as getErrorCode, genericErrorHandler } from '../errors';
// Basic action creators
......@@ -147,12 +147,15 @@ function reduceUpdateWeboob(state, action) {
let { status } = action;
if (status === SUCCESS) {
notify.success($t('client.settings.update_weboob_success'));
return u({ updatingWeboob: false }, state);
}
if (status === FAIL) {
if (action.error && typeof action.error.message === 'string') {
alert(`Error when updating weboob: ${action.error.message}`);
notify.error(
$t('client.settings.emails.update_weboob_error', { error: action.error.message })
);
}
return u({ updatingWeboob: false }, state);
......@@ -165,12 +168,15 @@ function reduceSendTestEmail(state, action) {
let { status } = action;
if (status === SUCCESS) {
notify.success($t('client.settings.emails.send_test_email_success'));
return u({ sendingTestEmail: false }, state);
}
if (status === FAIL) {
if (action.error && typeof action.error.message === 'string') {
alert(`Error when trying to send test email: ${action.error.message}`);
notify.error(
$t('client.settings.emails.send_test_email_error', { error: action.error.message })
);
}
return u({ sendingTestEmail: false }, state);
......@@ -187,7 +193,7 @@ function reduceExportInstance(state, action) {
}
if (status === FAIL) {
alert(action.error && action.error.message);
notify.error(action.error && action.error.message);
return u({ isExporting: false }, state);
}
......@@ -240,10 +246,10 @@ function reduceImport(state, action) {
let { error } = action;
switch (error.errCode) {
case getErrorCode('INVALID_ENCRYPTED_EXPORT'):
alert($t('client.settings.invalid_encrypted_export'));
notify.error($t('client.settings.invalid_encrypted_export'));
break;
case getErrorCode('INVALID_PASSWORD_JSON_EXPORT'):
alert($t('client.settings.invalid_password_json_export'));
notify.error($t('client.settings.invalid_password_json_export'));
break;
default:
genericErrorHandler(error);
......
......@@ -53,7 +53,8 @@
"replace_with_info": "You can attach them to an existing category with the dropdown below (by default, these transactions will not have a category set anymore).",
"budget_migration": "The attached budgets will also be migrated to the chosen category (unless there already are budgets attached).",
"replace_with": "Replace with",
"label": "Label"
"label": "Label",
"creation_error": "Error when creating a category: %{error}"
},
"defaultcategories": {
"groceries": "Groceries",
......@@ -146,6 +147,7 @@
"shown": "Shown",
"plus": "Plus",
"minus": "Minus",
"unexpected_error": "Unexpected error: %{error}",
"network_error": "A network error happened. Are you sure your Internet connection is correctly configured and working?",
"json_parse_error": "Impossible to parse the response from the server. Either the connection timed out, or there is something wrong with the endpoint. Please contact your local administrator or somebody from the Kresus team.",
"see_developers_console": "Please refer to the developers' console for more information.",
......@@ -261,6 +263,8 @@
"weboob_version": "Weboob's version",
"weboob_description": "Weboob is the underlying tool used by Kresus to fetch your bank data. This tool's modules (one module per bank) sometimes require to be updated in order to follow the evolutions of the banks' websites.",
"update_weboob": "Update weboob",
"update_weboob_success": "Weboob was successfully updated",
"update_weboob_error": "Error when updating weboob: %{error}",
"go_update_weboob": "Fire the update!",
"update_weboob_help": "This will update Weboob without reinstalling it from scratch. This should be done as a first step, in case fetching transactions doesn't work anymore.",
"export_instance": "Export Kresus instance",
......@@ -341,6 +345,8 @@
"monthly": "monthly",
"send_to": "Recipient's email address",
"send_test_email": "Send test email",
"send_test_email_success": "The test email was successfully sent",
"send_test_email_error": "Error when trying to send test email: %{error}",
"emails_not_enabled": "Emails haven't been enabled by your administrator. Thus, it is not possible to set any email reports or alerts at this time.",
"limit_is_empty": "Please enter a threshold value."
},
......
......@@ -53,7 +53,8 @@
"replace_with_info": "Vous pouvez les réaffecter à une catégorie existante à l'aide du menu déroulant ci-dessous (sinon, ces opérations n'auront plus de catégorie).",
"budget_migration": "Les budgets attachés seront également migrés vers cette catégorie (à moins que des budgets y soient déjà attachés).",
"replace_with": "Remplacer par",
"label": "Libellé"
"label": "Libellé",
"creation_error": "Erreur lors de la création d'une catégorie : %{error}"
},
"defaultcategories": {
"groceries": "Courses",
......@@ -146,6 +147,7 @@
"shown": "Affiché",
"plus": "Plus",
"minus": "Moins",
"unexpected_error": "Erreur inattendue : %{error}",
"network_error": "Une erreur réseau s'est produite. Êtes-vous sûr·e d'avoir correctement configuré votre connexion Internet et d'être actuellement connecté ?",
"json_parse_error": "Impossible d'analyser le contenu de la réponse serveur. Soit la connexion n'arrive pas à aboutir (timeout), soit l'URL distante n'envoie pas les bonnes informations. Merci de prévenir votre administrateur ou l'équipe de Kresus.",
"see_developers_console": "Veuillez vous référer à la console développeurs pour plus d'informations.",
......@@ -261,6 +263,8 @@
"weboob_version": "Version de Weboob",
"weboob_description": "Weboob est l'outil qu'utilise Kresus pour récupérer vos données bancaires. Les modules de cet outil (un module par banque) requièrent parfois d'être mis à jour afin de suivre les évolutions des sites web des banques.",
"update_weboob": "Mettre Weboob à jour",
"update_weboob_success": "Weboob a bien été mis à jour",
"update_weboob_error": "Une erreur est survenue lors de la mise à jour de weboob : %{error}",
"go_update_weboob": "Lancer la mise à jour",
"update_weboob_help": "Cette procédure va mettre à jour Weboob sans le réinstaller entièrement. Cela peut prendre quelques minutes, durant lesquelles vous ne pourrez pas importer vos comptes et opérations. À utiliser quand mettre à jour ne synchronise plus vos opérations !",
"export_instance": "Exporter l'instance",
......@@ -341,6 +345,8 @@
"monthly": "tous les mois",
"send_to": "Envoyer à l'adresse email",
"send_test_email": "Envoyer un email de test",
"send_test_email_success": "L'email de test a bien été envoyé",
"send_test_email_error": "Une erreur est survenue lors de l'envoi de l'email de test : %{error}",
"emails_not_enabled": "Les emails n'ont pas été activés par votre administrateur : il n'est donc pas possible d'envoyer des rapports emails ou des alertes pour le moment.",
"limit_is_empty": "La valeur de seuil est obligatoire."
},
......
......@@ -28,6 +28,7 @@ let entry = {
'./node_modules/c3/c3.css',
'./node_modules/flatpickr/dist/themes/light.css',
'./node_modules/primer-tooltips/build/build.css',
'./node_modules/react-toastify/dist/ReactToastify.min.css',
'./client/css/base.css',
'./client/init.js'
]
......
Supports Markdown
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