diff --git a/client/src/components/App.js b/client/src/components/App.js index 12345fa04..e68fd59db 100644 --- a/client/src/components/App.js +++ b/client/src/components/App.js @@ -1,29 +1,21 @@ import React from 'react'; -import PropTypes from 'prop-types'; import { IntlProvider } from 'react-intl'; -import { connect } from 'react-redux'; -import { Router, Switch, Redirect } from 'react-router'; +import { Router, Switch, Route } from 'react-router'; import { createBrowserHistory } from 'history'; +import { ReactQueryConfigProvider } from 'react-query'; +import { ReactQueryDevtools } from 'react-query-devtools'; + import PrivateRoute from 'components/PrivateRoute'; import Authentication from 'components/Authentication'; import Dashboard from 'components/Dashboard/Dashboard'; -import { isAuthenticated } from 'store/authentication/authentication.reducer' -import { ReactQueryConfigProvider } from 'react-query'; -import { ReactQueryDevtools } from "react-query-devtools"; +import GlobalErrors from 'containers/GlobalErrors/GlobalErrors'; import messages from 'lang/en'; import 'style/App.scss'; -function App({ - isAuthorized, - locale, -}) { +function App({ locale }) { const history = createBrowserHistory(); - history.listen((location, action) => { - console.log(`new location via ${action}`, location); - }); - const queryConfig = { refetchAllOnWindowFocus: false, cacheTime: 10000, @@ -34,10 +26,18 @@ function App({
- - + + + + + + + + + +
@@ -49,10 +49,4 @@ App.defaultProps = { locale: 'en', }; -const mapStateToProps = (state) => { - return { - isAuthorized: isAuthenticated(state), - }; -}; - -export default connect(mapStateToProps)(App); \ No newline at end of file +export default App; diff --git a/client/src/components/Authentication.js b/client/src/components/Authentication.js index 84c534c8d..523b08f3f 100644 --- a/client/src/components/Authentication.js +++ b/client/src/components/Authentication.js @@ -2,22 +2,22 @@ import React from 'react'; import { Redirect, Route, Switch, Link } from 'react-router-dom'; import BodyClassName from 'react-body-classname'; import authenticationRoutes from 'routes/authentication'; -import { FormattedMessage as T, useIntl } from 'react-intl'; +import { FormattedMessage as T } from 'react-intl'; +import withAuthentication from 'containers/Authentication/withAuthentication'; +import { compose } from 'utils'; -export default function AuthenticationWrapper({ - isAuthenticated = false, - ...rest -}) { + +function AuthenticationWrapper({ isAuthorized = false, ...rest }) { const to = { pathname: '/homepage' }; return ( - - {isAuthenticated ? ( + <> + {isAuthorized ? ( ) : ( -
+
-
+
{authenticationRoutes.map((route, index) => ( )} - + ); } + +export default compose(withAuthentication)(AuthenticationWrapper); diff --git a/client/src/components/Dashboard/TopbarUser.js b/client/src/components/Dashboard/TopbarUser.js index fd197850a..f51bbf111 100644 --- a/client/src/components/Dashboard/TopbarUser.js +++ b/client/src/components/Dashboard/TopbarUser.js @@ -9,14 +9,13 @@ import { Popover } from '@blueprintjs/core'; import t from 'store/types'; -import { FormattedMessage as T, useIntl } from 'react-intl'; +import { FormattedMessage as T } from 'react-intl'; function DashboardTopbarUser({ logout }) { const history = useHistory(); const onClickLogout = useCallback(() => { logout(); - history.go('/auth/login'); }, [logout, history]); const userAvatarDropMenu = useMemo(() => ( diff --git a/client/src/components/PrivateRoute.js b/client/src/components/PrivateRoute.js index cfbf55815..90e7be2c8 100644 --- a/client/src/components/PrivateRoute.js +++ b/client/src/components/PrivateRoute.js @@ -1,37 +1,29 @@ import React from 'react'; import PropTypes from 'prop-types'; -import BodyClassName from 'react-body-classname'; -import { Route, Redirect } from 'react-router-dom'; +import BodyClassName from 'react-body-classname'; +import { Redirect } from 'react-router-dom'; +import withAuthentication from 'containers/Authentication/withAuthentication'; +import { compose } from 'utils'; -const propTypes = { - isAuthenticated: PropTypes.bool, - component: PropTypes.func.isRequired -}; function PrivateRoute({ component: Component, - isAuthenticated = false, + isAuthorized = false, ...rest }) { return ( - - isAuthenticated ? () : - ( - - )} - /> + {(isAuthorized) ? ( + + ) : ( + + )} ); } -PrivateRoute.propTypes = propTypes; - -export default PrivateRoute; \ No newline at end of file +export default compose(withAuthentication)(PrivateRoute); diff --git a/client/src/containers/Authentication/Login.js b/client/src/containers/Authentication/Login.js index fe6b47ce8..bfeebf862 100644 --- a/client/src/containers/Authentication/Login.js +++ b/client/src/containers/Authentication/Login.js @@ -66,7 +66,6 @@ function Login({ crediential: values.crediential, password: values.password, }).then(() => { - history.go('/homepage'); setSubmitting(false); }).catch((errors) => { const toastBuilders = []; diff --git a/client/src/containers/Authentication/withAuthentication.js b/client/src/containers/Authentication/withAuthentication.js new file mode 100644 index 000000000..0a311e70d --- /dev/null +++ b/client/src/containers/Authentication/withAuthentication.js @@ -0,0 +1,11 @@ +import { isAuthenticated } from 'store/authentication/authentication.reducer' +import { connect } from 'react-redux'; + + +const mapStateToProps = (state) => { + return { + isAuthorized: isAuthenticated(state), + }; +}; + +export default connect(mapStateToProps); \ No newline at end of file diff --git a/client/src/containers/GlobalErrors/GlobalErrors.js b/client/src/containers/GlobalErrors/GlobalErrors.js new file mode 100644 index 000000000..24f3606c7 --- /dev/null +++ b/client/src/containers/GlobalErrors/GlobalErrors.js @@ -0,0 +1,47 @@ +import { Intent } from '@blueprintjs/core'; +import { useIntl } from 'react-intl'; +import AppToaster from 'components/AppToaster'; + +import withGlobalErrors from './withGlobalErrors'; +import withGlobalErrorsActions from './withGlobalErrorsActions'; +import { compose } from 'utils'; + +let toastKeySessionExpired; +let toastKeySomethingWrong; + +function GlobalErrors({ + // #withGlobalErrors + globalErrors, + + // #withGlobalErrorsActions + globalErrorsSet, +}) { + const { formatMessage } = useIntl(); + + if (globalErrors.something_wrong) { + toastKeySessionExpired = AppToaster.show({ + message: formatMessage({ id: 'ops_something_went_wrong' }), + intent: Intent.DANGER, + onDismiss: () => { + globalErrorsSet({ something_wrong: false }); + } + }, toastKeySessionExpired); + } + + if (globalErrors.session_expired) { + toastKeySomethingWrong = AppToaster.show({ + message: formatMessage({ id: 'session_expired' }), + intent: Intent.DANGER, + onDismiss: () => { + globalErrorsSet({ session_expired: false }); + } + }, toastKeySomethingWrong); + } + + return null; +} + +export default compose( + withGlobalErrors, + withGlobalErrorsActions, +)(GlobalErrors); \ No newline at end of file diff --git a/client/src/containers/GlobalErrors/withGlobalErrors.js b/client/src/containers/GlobalErrors/withGlobalErrors.js new file mode 100644 index 000000000..1a3948e58 --- /dev/null +++ b/client/src/containers/GlobalErrors/withGlobalErrors.js @@ -0,0 +1,10 @@ +import { connect } from 'react-redux'; + + +const mapStateToProps = (state) => { + return { + globalErrors: state.globalErrors.data, + }; +}; + +export default connect(mapStateToProps); \ No newline at end of file diff --git a/client/src/containers/GlobalErrors/withGlobalErrorsActions.js b/client/src/containers/GlobalErrors/withGlobalErrorsActions.js new file mode 100644 index 000000000..caf923905 --- /dev/null +++ b/client/src/containers/GlobalErrors/withGlobalErrorsActions.js @@ -0,0 +1,9 @@ +import {connect} from 'react-redux'; +import { setGlobalErrors } from 'store/globalErrors/globalErrors.actions'; +import t from 'store/types'; + +export const mapDispatchToProps = (dispatch) => ({ + globalErrorsSet: (errors) => dispatch(setGlobalErrors(errors)), +}); + +export default connect(null, mapDispatchToProps); diff --git a/client/src/lang/en/index.js b/client/src/lang/en/index.js index 0d0e5a735..a16453658 100644 --- a/client/src/lang/en/index.js +++ b/client/src/lang/en/index.js @@ -1,14 +1,15 @@ export default { hello_world: 'Hello World', - 'email_or_phone_number': 'Email or phone number', + email_or_phone_number: 'Email or phone number', password: 'Password', login: 'Login', invalid_email_or_phone_number: 'Invalid email or phone number.', - 'required': 'Required', + required: 'Required', reset_password: 'Reset Password', - the_user_has_been_suspended_from_admin: 'The user has been suspended from the administrator.', + the_user_has_been_suspended_from_admin: + 'The user has been suspended from the administrator.', email_and_password_entered_did_not_match: - 'The email and password you entered did not match our records.', + 'The email and password you entered did not match our records.', field_name_must_be_number: 'field_name_must_be_number', name: 'Name', search: 'Search', @@ -34,9 +35,9 @@ export default { phone_number: 'Phone Number', you_email_address_is: 'You email address is', you_will_use_this_address_to_sign_in_to_bigcapital: - 'You will use this address to sign in to Bigcapital.', + 'You will use this address to sign in to Bigcapital.', signing_in_or_creating: - 'By signing in or creating an account, you agree with our', + 'By signing in or creating an account, you agree with our', terms_conditions: 'Terms & Conditions', and: 'and', privacy_statement: 'Privacy Statement', @@ -47,13 +48,15 @@ export default { organization_name: 'Organization Name', email: 'Email', register: 'Register', - password_successfully_updated: 'The Password for your account was successfully updated.', + password_successfully_updated: + 'The Password for your account was successfully updated.', choose_a_new_password: 'Choose a new password', you_remembered_your_password: 'You remembered your password ?', new_password: 'New Password', submit_new_password: 'Submit new password', reset_your_password: 'Reset Your Password', - we_ll_send_you_a_link_to_reset_your_password: 'Enter your email address and we’ll send you a link to reset your password.', + we_ll_send_you_a_link_to_reset_your_password: + 'Enter your email address and we’ll send you a link to reset your password.', send_password_reset_link: 'Send password reset link', return_to_log_in: 'Return to log in', sub_account: 'Sub account?', @@ -84,7 +87,8 @@ export default { new: 'New', new_category: 'New Category', invite_user: 'invite User', - your_access_to_your_team: 'Your teammate will get an email that gives them access to your team.', + your_access_to_your_team: + 'Your teammate will get an email that gives them access to your team.', invite: 'invite', count: 'Count', item_type: 'Item Type', @@ -137,7 +141,7 @@ export default { inactivate: 'Inactivate', activate: 'Activate', inactivate_account: 'Inactivate Account', - activate_account:'Activate Account', + activate_account: 'Activate Account', delete_account: 'Delete Account', code: 'Code', type: 'Type', @@ -169,164 +173,198 @@ export default { view_name: 'View Name', new_conditional: 'New Conditional', item: 'Item', - service_has_been_successful_created: '{service} {name} has been successfully created.', - service_has_been_successful_edited: '{service} {name} has been successfully edited.', + service_has_been_successful_created: + '{service} {name} has been successfully created.', + service_has_been_successful_edited: + '{service} {name} has been successfully edited.', you_are_about_permanently_delete_this_journal: `You're about to permanently delete this journal and all its transactions on accounts and attachments, and all of its data.

If you're not sure, you can archive this journal instead.`, - once_delete_these_accounts_you_will_not_able_restore_them: 'Once you delete these accounts, you won\'t be able to retrieve them later. Are you sure you want to delete them?', - once_delete_these_service_you_will_not_able_restore_it: 'Once you delete these {service}, you won\'t be able to retrieve them later. Are you sure you want to delete this {service}?', - you_could_not_delete_predefined_accounts: 'You could\'t delete predefined accounts.', - cannot_delete_account_has_associated_transactions: 'you could\'t not delete account that has associated transactions.', - the_account_has_been_successfully_inactivated: 'The account has been successfully inactivated.', - the_account_has_been_successfully_activated: 'The account has been successfully activated.', - the_account_has_been_successfully_deleted: 'The account has been successfully deleted.', - the_accounts_has_been_successfully_deleted: 'The accounts have been successfully deleted.', - are_sure_to_inactive_this_account: 'Are you sure you want to inactive this account? You will be able to activate it later', - are_sure_to_activate_this_account: 'Are you sure you want to activate this account? You will be able to inactivate it later', + once_delete_these_accounts_you_will_not_able_restore_them: + "Once you delete these accounts, you won't be able to retrieve them later. Are you sure you want to delete them?", + once_delete_these_service_you_will_not_able_restore_it: + "Once you delete these {service}, you won't be able to retrieve them later. Are you sure you want to delete this {service}?", + you_could_not_delete_predefined_accounts: + "You could't delete predefined accounts.", + cannot_delete_account_has_associated_transactions: + "you could't not delete account that has associated transactions.", + the_account_has_been_successfully_inactivated: + 'The account has been successfully inactivated.', + the_account_has_been_successfully_activated: + 'The account has been successfully activated.', + the_account_has_been_successfully_deleted: + 'The account has been successfully deleted.', + the_accounts_has_been_successfully_deleted: + 'The accounts have been successfully deleted.', + are_sure_to_inactive_this_account: + 'Are you sure you want to inactive this account? You will be able to activate it later', + are_sure_to_activate_this_account: + 'Are you sure you want to activate this account? You will be able to inactivate it later', once_delete_this_account_you_will_able_to_restore_it: `Once you delete this account, you won\'t be able to restore it later. Are you sure you want to delete this account?

If you're not sure, you can inactivate this account instead.`, - the_journal_has_been_successfully_created: 'The journal #{number} has been successfully created.', - the_journal_has_been_successfully_edited: 'The journal #{number} has been successfully edited.', + the_journal_has_been_successfully_created: + 'The journal #{number} has been successfully created.', + the_journal_has_been_successfully_edited: + 'The journal #{number} has been successfully edited.', credit: 'Credit', debit: 'Debit', once_delete_this_item_you_will_able_to_restore_it: `Once you delete this item, you won\'t be able to restore the item later. Are you sure you want to delete ?

If you're not sure, you can inactivate it instead.`, - the_item_has_been_successfully_deleted: 'The item has been successfully deleted.', - the_item_category_has_been_successfully_created: 'The item category has been successfully created.', - the_item_category_has_been_successfully_edited: 'The item category has been successfully edited.', - once_delete_these_views_you_will_not_able_restore_them: 'Once you delete the custom view, you won\'t be able to restore it later. Are you sure you want to delete this view?', - the_custom_view_has_been_successfully_deleted: 'The custom view has been successfully deleted.', - teammate_invited_to_organization_account: 'Your teammate has been invited to the organization account.', + the_item_has_been_successfully_deleted: + 'The item has been successfully deleted.', + the_item_category_has_been_successfully_created: + 'The item category has been successfully created.', + the_item_category_has_been_successfully_edited: + 'The item category has been successfully edited.', + once_delete_these_views_you_will_not_able_restore_them: + "Once you delete the custom view, you won't be able to restore it later. Are you sure you want to delete this view?", + the_custom_view_has_been_successfully_deleted: + 'The custom view has been successfully deleted.', + teammate_invited_to_organization_account: + 'Your teammate has been invited to the organization account.', select_account_type: 'Select account type', - menu:'Menu', - graph:'Graph', - map:'Map', - table:'Table', - nucleus:'Nucleus', - logout:'Logout', - the_expense_has_been_successfully_created: 'The expense has been successfully created.', - select_payment_account:'Select Payment Account', - select_expense_account:'Select Expense Account', - and:'And', - or:'OR', - select_a_comparator:'Select a comparator', - equals:'Equals', - not_equal:'Not Equal', - contain:'Contain', - not_contain:'Not Contain', - cash:'Cash', - accrual:'Accrual', - from:'From', - to:'To', - accounting_basis:'Accounting Basis:', - general:'General', - users:'Users', - currencies:'Currencies', - accountant:'Accountant', - accounts:'Accounts', - homepage:'Homepage', - items_list:'Items List', - new_item:'New Item', - items:'Items', - category_list:'Category List', - financial:'Financial', - accounts_chart:'Accounts Chart', - manual_journal:'Manual Journal', - make_journal:'Make Journal', - exchange_rate:'Exchange Rate', - banking:'Banking', - sales:'Sales', - purchases:'Purchases', - financial_reports:'Financial Reports', - balance_sheet:'Balance Sheet', - trial_balance_sheet:'Trial Balance Sheet', - journal:'Journal', - general_ledger:'General Ledger', - profit_loss_sheet:'Profit Loss Sheet', - expenses:'Expenses', - expenses_list:'Expenses List', - new_expenses:'New Expenses', - preferences:'Preferences', - auditing_system:'Auditing System', - all:'All', - organization:'Organization.', - check_your_email_for_a_link_to_reset: 'Check your email for a link to reset your password.If it doesn’t appear within a few minutes, check your spam folder.', - we_couldn_t_find_your_account_with_that_email:'We couldn\'t find your account with that email.', - select_parent_account:'Select Parent Account', - the_exchange_rate_has_been_successfully_edited:'The exchange rate has been successfully edited', - the_exchange_rate_has_been_successfully_created:'The exchange rate has been successfully created', - the_exchange_rate_has_been_successfully_deleted: 'The exchange rate has been successfully deleted.', - the_user_details_has_been_updated:'The user details has been updated', - the_category_has_been_successfully_created: 'The category has been successfully created.', - filters_applied:'filters applied', - the_expense_has_been_successfully_deleted: 'The expense has been successfully deleted.', - select_item_type:'Select Item Type', - service:'Service', - inventory:'Inventory', - non_inventory:'Non-Inventory', - select_category:'Select category', - select_account:'Select Account', - custom_fields:'Custom Fields', - the_currency_has_been_successfully_deleted:'The currency has been successfully deleted', - organization_industry:'Organization Industry', - business_location:'Business Location', - base_currency:'Base Currency', - fiscal_year:'Fiscal Year', - language:'Language', - time_zone:'Time Zone', - date_format:'Date Format', - edit_user:'Edit User', - edit_invite:'Edit Invite', - inactivate_user:'Inactivate User', - delete_user:'Delete User', - full_name:'Full Name', - the_user_has_been_successfully_inactivated: 'The user has been successfully inactivated.', - the_user_has_been_successfully_deleted: 'The user has been successfully deleted.', - customize_report:'Customize Report', - print:'Print', - export:'Export', - accounts_with_zero_balance:'Accounts with Zero Balance', - all_transactions:'All Transactions', - filter_accounts:'Filter Accounts', - calculate_report:'Calculate Report', - total:'Total', - specific_accounts:'Specific Accounts', - trans_num:'Trans. NUM', - journal_sheet:'Journal Sheet', - run_report:'Run Report', - num:'Num.', - acc_code:'Acc. Code', - display_report_columns:'Display report columns', - select_display_columns_by:'Select display columns by...', - credit_and_debit_not_equal:'credit and debit not equal', - the_currency_has_been_successfully_edited:'The currency has been successfully edited', - the_currency_has_been_successfully_created:'The currency has been successfully created', + menu: 'Menu', + graph: 'Graph', + map: 'Map', + table: 'Table', + nucleus: 'Nucleus', + logout: 'Logout', + the_expense_has_been_successfully_created: + 'The expense has been successfully created.', + select_payment_account: 'Select Payment Account', + select_expense_account: 'Select Expense Account', + and: 'And', + or: 'OR', + select_a_comparator: 'Select a comparator', + equals: 'Equals', + not_equal: 'Not Equal', + contain: 'Contain', + not_contain: 'Not Contain', + cash: 'Cash', + accrual: 'Accrual', + from: 'From', + to: 'To', + accounting_basis: 'Accounting Basis:', + general: 'General', + users: 'Users', + currencies: 'Currencies', + accountant: 'Accountant', + accounts: 'Accounts', + homepage: 'Homepage', + items_list: 'Items List', + new_item: 'New Item', + items: 'Items', + category_list: 'Category List', + financial: 'Financial', + accounts_chart: 'Accounts Chart', + manual_journal: 'Manual Journal', + make_journal: 'Make Journal', + exchange_rate: 'Exchange Rate', + banking: 'Banking', + sales: 'Sales', + purchases: 'Purchases', + financial_reports: 'Financial Reports', + balance_sheet: 'Balance Sheet', + trial_balance_sheet: 'Trial Balance Sheet', + journal: 'Journal', + general_ledger: 'General Ledger', + profit_loss_sheet: 'Profit Loss Sheet', + expenses: 'Expenses', + expenses_list: 'Expenses List', + new_expenses: 'New Expenses', + preferences: 'Preferences', + auditing_system: 'Auditing System', + all: 'All', + organization: 'Organization.', + check_your_email_for_a_link_to_reset: + 'Check your email for a link to reset your password.If it doesn’t appear within a few minutes, check your spam folder.', + we_couldn_t_find_your_account_with_that_email: + "We couldn't find your account with that email.", + select_parent_account: 'Select Parent Account', + the_exchange_rate_has_been_successfully_edited: + 'The exchange rate has been successfully edited', + the_exchange_rate_has_been_successfully_created: + 'The exchange rate has been successfully created', + the_exchange_rate_has_been_successfully_deleted: + 'The exchange rate has been successfully deleted.', + the_user_details_has_been_updated: 'The user details has been updated', + the_category_has_been_successfully_created: + 'The category has been successfully created.', + filters_applied: 'filters applied', + the_expense_has_been_successfully_deleted: + 'The expense has been successfully deleted.', + select_item_type: 'Select Item Type', + service: 'Service', + inventory: 'Inventory', + non_inventory: 'Non-Inventory', + select_category: 'Select category', + select_account: 'Select Account', + custom_fields: 'Custom Fields', + the_currency_has_been_successfully_deleted: + 'The currency has been successfully deleted', + organization_industry: 'Organization Industry', + business_location: 'Business Location', + base_currency: 'Base Currency', + fiscal_year: 'Fiscal Year', + language: 'Language', + time_zone: 'Time Zone', + date_format: 'Date Format', + edit_user: 'Edit User', + edit_invite: 'Edit Invite', + inactivate_user: 'Inactivate User', + delete_user: 'Delete User', + full_name: 'Full Name', + the_user_has_been_successfully_inactivated: + 'The user has been successfully inactivated.', + the_user_has_been_successfully_deleted: + 'The user has been successfully deleted.', + customize_report: 'Customize Report', + print: 'Print', + export: 'Export', + accounts_with_zero_balance: 'Accounts with Zero Balance', + all_transactions: 'All Transactions', + filter_accounts: 'Filter Accounts', + calculate_report: 'Calculate Report', + total: 'Total', + specific_accounts: 'Specific Accounts', + trans_num: 'Trans. NUM', + journal_sheet: 'Journal Sheet', + run_report: 'Run Report', + num: 'Num.', + acc_code: 'Acc. Code', + display_report_columns: 'Display report columns', + select_display_columns_by: 'Select display columns by...', + credit_and_debit_not_equal: 'credit and debit not equal', + the_currency_has_been_successfully_edited: + 'The currency has been successfully edited', + the_currency_has_been_successfully_created: + 'The currency has been successfully created', // Name Labels - expense_account_id :'Expense account', + expense_account_id: 'Expense account', payment_account_id: 'Payment account', currency_code_: 'Currency code', - publish:'Publish', - exchange_rate_:'Exchange rate', - journal_number_:'Journal number', + publish: 'Publish', + exchange_rate_: 'Exchange rate', + journal_number_: 'Journal number', first_name_: 'First name', - last_name_:'Last name', - phone_number_:'Phone number', - organization_name_:'Organization name', - confirm_password:'Confirm password', - crediential:'Email or Phone number', - account_type_id:'Account type', - account_name_:'Account name', - currency_name_:'Currency name', - cost_account_id:'Cost account', - sell_account_id:'Sell account', - item_type_:'Item type', - item_name_:'Item name', - organization_industry_:'Organization industry', - base_currency_:'Base currency', - date_format_:'Date format', - category_name_:'Category name', - view_name_:'View name', - the_items_has_been_successfully_deleted: 'The items have been successfully deleted.', - once_delete_these_items_you_will_not_able_restore_them: 'Once you delete these items, you won\'t be able to retrieve them later. Are you sure you want to delete them?', + last_name_: 'Last name', + phone_number_: 'Phone number', + organization_name_: 'Organization name', + confirm_password: 'Confirm password', + crediential: 'Email or Phone number', + account_type_id: 'Account type', + account_name_: 'Account name', + currency_name_: 'Currency name', + cost_account_id: 'Cost account', + sell_account_id: 'Sell account', + item_type_: 'Item type', + item_name_: 'Item name', + organization_industry_: 'Organization industry', + base_currency_: 'Base currency', + date_format_: 'Date format', + category_name_: 'Category name', + view_name_: 'View name', + the_items_has_been_successfully_deleted: + 'The items have been successfully deleted.', + once_delete_these_items_you_will_not_able_restore_them: + "Once you delete these items, you won't be able to retrieve them later. Are you sure you want to delete them?", + ops_something_went_wrong: 'Something went wrong! Please try again.', + session_expired: 'Session Expired!', }; - - - diff --git a/client/src/services/axios.js b/client/src/services/axios.js index 5ec987db0..f69dda9bd 100644 --- a/client/src/services/axios.js +++ b/client/src/services/axios.js @@ -1,8 +1,15 @@ import axios from 'axios'; +import React from 'react'; +import { Intent } from '@blueprintjs/core'; import store from 'store/createStore'; - +import { logout } from 'store/authentication/authentication.actions'; +import AppToaster from 'components/AppToaster'; +import { FormattedMessage as T, useIntl } from 'react-intl'; +import { setGlobalErrors } from 'store/globalErrors/globalErrors.actions'; const http = axios.create(); + + http.interceptors.request.use((request) => { const state = store.getState(); const { token, organization } = state.authentication; @@ -26,10 +33,11 @@ http.interceptors.response.use((response) => response, (error) => { const { status } = error.response; if (status >= 500) { - + store.dispatch(setGlobalErrors({ something_wrong: true })); } if (status === 401) { - + store.dispatch(setGlobalErrors({ session_expired: true })); + store.dispatch(logout()); } return Promise.reject(error); }); diff --git a/client/src/store/authentication/authentication.actions.js b/client/src/store/authentication/authentication.actions.js index 99580e12a..3e51d8a7e 100644 --- a/client/src/store/authentication/authentication.actions.js +++ b/client/src/store/authentication/authentication.actions.js @@ -26,6 +26,12 @@ export function login({ form }) { }); } +export const logout = () => { + return dispatch => dispatch({ + type: t.LOGOUT, + }); +}; + export const register = ({ form }) => { return (dispatch) => { return new Promise((resolve, reject) => { diff --git a/client/src/store/globalErrors/globalErrors.actions.js b/client/src/store/globalErrors/globalErrors.actions.js new file mode 100644 index 000000000..c4c7e6c55 --- /dev/null +++ b/client/src/store/globalErrors/globalErrors.actions.js @@ -0,0 +1,12 @@ + + +export const setGlobalErrors = (errors) => { + return dispatch => { + dispatch({ + type: 'GLOBAL_ERRORS_SET', + payload: { + errors, + }, + }); + } +} \ No newline at end of file diff --git a/client/src/store/globalErrors/globalErrors.reducer.js b/client/src/store/globalErrors/globalErrors.reducer.js new file mode 100644 index 000000000..7cd1194a1 --- /dev/null +++ b/client/src/store/globalErrors/globalErrors.reducer.js @@ -0,0 +1,17 @@ +import { createReducer } from '@reduxjs/toolkit'; +import t from 'store/types'; + +const initialState = { + data: {}, +}; + +export default createReducer(initialState, { + ['GLOBAL_ERRORS_SET']: (state, action) => { + const { errors } = action.payload; + + state.data = { + ...state.data, + ...errors, + }; + }, +}); diff --git a/client/src/store/reducers.js b/client/src/store/reducers.js index 326d421cd..f8851e793 100644 --- a/client/src/store/reducers.js +++ b/client/src/store/reducers.js @@ -16,6 +16,8 @@ import settings from './settings/settings.reducer'; import manualJournals from './manualJournals/manualJournals.reducers'; import globalSearch from './search/search.reducer'; import exchangeRates from './ExchangeRate/exchange.reducer' +import globalErrors from './globalErrors/globalErrors.reducer'; + export default combineReducers({ authentication, @@ -33,6 +35,6 @@ export default combineReducers({ itemCategories, settings, globalSearch, - exchangeRates - + exchangeRates, + globalErrors, });