1 {fromCurrency} =
-
+
+ {popoverRecalcConfirm ? (
+
+ {exchangeRateField}
+
+ ) : (
+ exchangeRateField
+ )}
{toCurrency}
@@ -34,7 +158,7 @@ export function ExchangeRateInputGroup({
}
const ExchangeRateField = styled(FMoneyInputGroup)`
- max-width: 75px;
+ max-width: 85px;
`;
const ExchangeRateSideIcon = styled.div`
@@ -57,3 +181,8 @@ const ExchangeFlagIcon = styled(FlagIcon)`
margin-left: 5px;
display: inline-block;
`;
+
+const PopoverContent = styled('div')`
+ padding: 20px;
+ width: 300px;
+`;
diff --git a/packages/webapp/src/constants/dialogs.ts b/packages/webapp/src/constants/dialogs.ts
index 115c25af2..e9c82bdd4 100644
--- a/packages/webapp/src/constants/dialogs.ts
+++ b/packages/webapp/src/constants/dialogs.ts
@@ -48,4 +48,5 @@ export enum DialogsName {
ProjectBillableEntriesForm = 'project-billable-entries',
InvoiceNumberSettings = 'InvoiceNumberSettings',
TaxRateForm = 'tax-rate-form',
+ InvoiceExchangeRateChangeNotice = 'InvoiceExchangeRateChangeNotice'
}
diff --git a/packages/webapp/src/containers/AlertsContainer/registered.tsx b/packages/webapp/src/containers/AlertsContainer/registered.tsx
index 417583f60..d68666253 100644
--- a/packages/webapp/src/containers/AlertsContainer/registered.tsx
+++ b/packages/webapp/src/containers/AlertsContainer/registered.tsx
@@ -12,7 +12,6 @@ import PaymentMadesAlerts from '@/containers/Purchases/PaymentMades/PaymentMades
import CustomersAlerts from '@/containers/Customers/CustomersAlerts';
import VendorsAlerts from '@/containers/Vendors/VendorsAlerts';
import ManualJournalsAlerts from '@/containers/Accounting/JournalsLanding/ManualJournalsAlerts';
-import ExchangeRatesAlerts from '@/containers/ExchangeRates/ExchangeRatesAlerts';
import ExpensesAlerts from '@/containers/Expenses/ExpensesAlerts';
import AccountTransactionsAlerts from '@/containers/CashFlow/AccountTransactions/AccountTransactionsAlerts';
import UsersAlerts from '@/containers/Preferences/Users/UsersAlerts';
@@ -41,7 +40,6 @@ export default [
...CustomersAlerts,
...VendorsAlerts,
...ManualJournalsAlerts,
- ...ExchangeRatesAlerts,
...ExpensesAlerts,
...AccountTransactionsAlerts,
...UsersAlerts,
@@ -54,5 +52,5 @@ export default [
...WarehousesTransfersAlerts,
...BranchesAlerts,
...ProjectAlerts,
- ...TaxRatesAlerts
+ ...TaxRatesAlerts,
];
diff --git a/packages/webapp/src/containers/Dialogs/ExchangeRateFormDialog/ExchangeRateForm.schema.tsx b/packages/webapp/src/containers/Dialogs/ExchangeRateFormDialog/ExchangeRateForm.schema.tsx
deleted file mode 100644
index 7ff0ff63d..000000000
--- a/packages/webapp/src/containers/Dialogs/ExchangeRateFormDialog/ExchangeRateForm.schema.tsx
+++ /dev/null
@@ -1,19 +0,0 @@
-// @ts-nocheck
-import * as Yup from 'yup';
-import intl from 'react-intl-universal';
-import { DATATYPES_LENGTH } from '@/constants/dataTypes';
-
-const Schema = Yup.object().shape({
- exchange_rate: Yup.number()
- .required()
- .label(intl.get('exchange_rate_')),
- currency_code: Yup.string()
- .max(3)
- .required(intl.get('currency_code_')),
- date: Yup.date()
- .required()
- .label(intl.get('date')),
-});
-
-export const CreateExchangeRateFormSchema = Schema;
-export const EditExchangeRateFormSchema = Schema;
diff --git a/packages/webapp/src/containers/Dialogs/ExchangeRateFormDialog/ExchangeRateForm.tsx b/packages/webapp/src/containers/Dialogs/ExchangeRateFormDialog/ExchangeRateForm.tsx
deleted file mode 100644
index b0cb40518..000000000
--- a/packages/webapp/src/containers/Dialogs/ExchangeRateFormDialog/ExchangeRateForm.tsx
+++ /dev/null
@@ -1,114 +0,0 @@
-// @ts-nocheck
-import React, { useMemo } from 'react';
-import intl from 'react-intl-universal';
-import moment from 'moment';
-import { Intent } from '@blueprintjs/core';
-import { Formik } from 'formik';
-import { AppToaster } from '@/components';
-import {
- CreateExchangeRateFormSchema,
- EditExchangeRateFormSchema,
-} from './ExchangeRateForm.schema';
-import ExchangeRateFormContent from './ExchangeRateFormContent';
-import { useExchangeRateFromContext } from './ExchangeRateFormProvider';
-import withDialogActions from '@/containers/Dialog/withDialogActions';
-
-import { compose, transformToForm } from '@/utils';
-
-const defaultInitialValues = {
- exchange_rate: '',
- currency_code: '',
- date: moment(new Date()).format('YYYY-MM-DD'),
-};
-
-/**
- * Exchange rate form.
- */
-function ExchangeRateForm({
- // #withDialogActions
- closeDialog,
-}) {
- const {
- createExchangeRateMutate,
- editExchangeRateMutate,
- isNewMode,
- dialogName,
- exchangeRate,
- } = useExchangeRateFromContext();
-
- // Form validation schema in create and edit mode.
- const validationSchema = isNewMode
- ? CreateExchangeRateFormSchema
- : EditExchangeRateFormSchema;
- const initialValues = useMemo(
- () => ({
- ...defaultInitialValues,
- ...transformToForm(exchangeRate, defaultInitialValues),
- }),
- [],
- );
-
- // Transformers response errors.
- const transformErrors = (errors, { setErrors }) => {
- if (
- errors.find((error) => error.type === 'EXCHANGE.RATE.DATE.PERIOD.DEFINED')
- ) {
- setErrors({
- exchange_rate: intl.get(
- 'there_is_exchange_rate_in_this_date_with_the_same_currency',
- ),
- });
- }
- };
-
- // Handle the form submit.
- const handleFormSubmit = (values, { setSubmitting, setErrors }) => {
- setSubmitting(true);
-
- // Handle close the dialog after success response.
- const afterSubmit = () => {
- closeDialog(dialogName);
- };
- const onSuccess = ({ response }) => {
- AppToaster.show({
- message: intl.get(
- !isNewMode
- ? 'the_exchange_rate_has_been_edited_successfully'
- : 'the_exchange_rate_has_been_created_successfully',
- ),
- intent: Intent.SUCCESS,
- });
- afterSubmit(response);
- };
- // Handle the response error.
- const onError = (error) => {
- const {
- response: {
- data: { errors },
- },
- } = error;
-
- transformErrors(errors, { setErrors });
- setSubmitting(false);
- };
- if (isNewMode) {
- createExchangeRateMutate(values).then(onSuccess).catch(onError);
- } else {
- editExchangeRateMutate([exchangeRate.id, values])
- .then(onSuccess)
- .catch(onError);
- }
- };
-
- return (
-
-
-
- );
-}
-
-export default compose(withDialogActions)(ExchangeRateForm);
diff --git a/packages/webapp/src/containers/Dialogs/ExchangeRateFormDialog/ExchangeRateFormContent.tsx b/packages/webapp/src/containers/Dialogs/ExchangeRateFormDialog/ExchangeRateFormContent.tsx
deleted file mode 100644
index 07ecc1ebc..000000000
--- a/packages/webapp/src/containers/Dialogs/ExchangeRateFormDialog/ExchangeRateFormContent.tsx
+++ /dev/null
@@ -1,14 +0,0 @@
-// @ts-nocheck
-import React from 'react';
-import { Form } from 'formik';
-import ExchangeRateFormFields from './ExchangeRateFormFields';
-import ExchangeRateFormFooter from './ExchangeRateFormFooter';
-
-export default function ExchangeRateFormContent() {
- return (
-
- );
-}
diff --git a/packages/webapp/src/containers/Dialogs/ExchangeRateFormDialog/ExchangeRateFormDialogContent.tsx b/packages/webapp/src/containers/Dialogs/ExchangeRateFormDialog/ExchangeRateFormDialogContent.tsx
deleted file mode 100644
index 2cad6e0c3..000000000
--- a/packages/webapp/src/containers/Dialogs/ExchangeRateFormDialog/ExchangeRateFormDialogContent.tsx
+++ /dev/null
@@ -1,27 +0,0 @@
-// @ts-nocheck
-import React from 'react';
-
-import ExchangeRateForm from './ExchangeRateForm';
-import { ExchangeRateFormProvider } from './ExchangeRateFormProvider';
-
-import '@/style/pages/ExchangeRate/ExchangeRateDialog.scss';
-
-/**
- * Exchange rate form content.
- */
-export default function ExchangeRateFormDialogContent({
- // #ownProp
- action,
- exchangeRateId,
- dialogName,
-}) {
- return (
-
-
-
- );
-}
diff --git a/packages/webapp/src/containers/Dialogs/ExchangeRateFormDialog/ExchangeRateFormFields.tsx b/packages/webapp/src/containers/Dialogs/ExchangeRateFormDialog/ExchangeRateFormFields.tsx
deleted file mode 100644
index 58c3eb262..000000000
--- a/packages/webapp/src/containers/Dialogs/ExchangeRateFormDialog/ExchangeRateFormFields.tsx
+++ /dev/null
@@ -1,89 +0,0 @@
-// @ts-nocheck
-import React from 'react';
-import { Classes, FormGroup, InputGroup, Position } from '@blueprintjs/core';
-import { FastField } from 'formik';
-import { DateInput } from '@blueprintjs/datetime';
-import { FormattedMessage as T } from '@/components';
-import classNames from 'classnames';
-import {
- momentFormatter,
- tansformDateValue,
- handleDateChange,
- inputIntent,
-} from '@/utils';
-import {
- ErrorMessage,
- FieldRequiredHint,
- CurrencySelectList,
-} from '@/components';
-import { useExchangeRateFromContext } from './ExchangeRateFormProvider';
-
-
-export default function ExchangeRateFormFields() {
- const { action, currencies } = useExchangeRateFromContext();
-
- return (
-
- {/* ----------- Date ----------- */}
-
- {({ form, field: { value }, meta: { error, touched } }) => (
- }
- labelInfo={FieldRequiredHint}
- className={classNames('form-group--select-list', Classes.FILL)}
- intent={inputIntent({ error, touched })}
- helperText={}
- inline={true}
- >
- {
- form.setFieldValue('date', formattedDate);
- })}
- popoverProps={{ position: Position.BOTTOM, minimal: true }}
- disabled={action === 'edit'}
- />
-
- )}
-
- {/* ----------- Currency Code ----------- */}
-
- {({ form, field: { value }, meta: { error, touched } }) => (
- }
- labelInfo={}
- className={classNames('form-group--currency', Classes.FILL)}
- intent={inputIntent({ error, touched })}
- helperText={}
- inline={true}
- >
- {
- form.setFieldValue('currency_code', currency_code);
- }}
- disabled={action === 'edit'}
- />
-
- )}
-
-
- {/*------------ Exchange Rate -----------*/}
-
- {({ form, field, meta: { error, touched } }) => (
- }
- labelInfo={}
- intent={inputIntent({ error, touched })}
- helperText={}
- inline={true}
- >
-
-
- )}
-
-
- );
-}
diff --git a/packages/webapp/src/containers/Dialogs/ExchangeRateFormDialog/ExchangeRateFormFooter.tsx b/packages/webapp/src/containers/Dialogs/ExchangeRateFormDialog/ExchangeRateFormFooter.tsx
deleted file mode 100644
index ef66f7674..000000000
--- a/packages/webapp/src/containers/Dialogs/ExchangeRateFormDialog/ExchangeRateFormFooter.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-// @ts-nocheck
-import React from 'react';
-import { useFormikContext } from 'formik';
-
-import { Button, Classes, Intent } from '@blueprintjs/core';
-import { FormattedMessage as T } from '@/components';
-import { useExchangeRateFromContext } from './ExchangeRateFormProvider';
-import withDialogActions from '@/containers/Dialog/withDialogActions';
-import { compose } from '@/utils';
-
-function ExchangeRateFormFooter({
- // #withDialogActions
- closeDialog,
-}) {
- const { isSubmitting } = useFormikContext();
- const { dialogName, action } = useExchangeRateFromContext();
-
- const handleClose = () => {
- closeDialog(dialogName);
- };
-
- return (
-
-
-
-
-
-
- );
-}
-
-export default compose(withDialogActions)(ExchangeRateFormFooter);
diff --git a/packages/webapp/src/containers/Dialogs/ExchangeRateFormDialog/ExchangeRateFormProvider.tsx b/packages/webapp/src/containers/Dialogs/ExchangeRateFormDialog/ExchangeRateFormProvider.tsx
deleted file mode 100644
index 90bdf8e96..000000000
--- a/packages/webapp/src/containers/Dialogs/ExchangeRateFormDialog/ExchangeRateFormProvider.tsx
+++ /dev/null
@@ -1,53 +0,0 @@
-// @ts-nocheck
-import React, { createContext, useContext } from 'react';
-import {
- useCreateExchangeRate,
- useEdiExchangeRate,
- useCurrencies,
- useExchangeRates,
-} from '@/hooks/query';
-import { DialogContent } from '@/components';
-
-const ExchangeRateFormContext = createContext();
-
-/**
- * Exchange rate Form page provider.
- */
-function ExchangeRateFormProvider({
- exchangeRate,
- action,
- dialogName,
- ...props
-}) {
- // Create and edit exchange rate mutations.
- const { mutateAsync: createExchangeRateMutate } = useCreateExchangeRate();
- const { mutateAsync: editExchangeRateMutate } = useEdiExchangeRate();
-
- // Load Currencies list.
- const { data: currencies, isFetching: isCurrenciesLoading } = useCurrencies();
- const { isFetching: isExchangeRatesLoading } = useExchangeRates();
-
- const isNewMode = !exchangeRate;
-
- // Provider state.
- const provider = {
- createExchangeRateMutate,
- editExchangeRateMutate,
- dialogName,
- exchangeRate,
- action,
- currencies,
- isExchangeRatesLoading,
- isNewMode,
- };
-
- return (
-
-
-
- );
-}
-
-const useExchangeRateFromContext = () => useContext(ExchangeRateFormContext);
-
-export { ExchangeRateFormProvider, useExchangeRateFromContext };
diff --git a/packages/webapp/src/containers/Dialogs/ExchangeRateFormDialog/index.tsx b/packages/webapp/src/containers/Dialogs/ExchangeRateFormDialog/index.tsx
deleted file mode 100644
index 3bbc71954..000000000
--- a/packages/webapp/src/containers/Dialogs/ExchangeRateFormDialog/index.tsx
+++ /dev/null
@@ -1,45 +0,0 @@
-// @ts-nocheck
-import React, { lazy } from 'react';
-import { Dialog, DialogSuspense, FormattedMessage as T } from '@/components';
-import withDialogRedux from '@/components/DialogReduxConnect';
-import { compose } from '@/utils';
-
-const ExchangeRateFormDialogContent = lazy(
- () => import('./ExchangeRateFormDialogContent'),
-);
-
-/**
- * Exchange rate form dialog.
- */
-function ExchangeRateFormDialog({
- dialogName,
- payload = { action: '', id: null, exchangeRate: '' },
- isOpen,
-}) {
- return (
-
- ) : (
-
- )
- }
- className={'dialog--exchangeRate-form'}
- isOpen={isOpen}
- autoFocus={true}
- canEscapeKeyClose={true}
- >
-
-
-
-
- );
-}
-
-export default compose(withDialogRedux())(ExchangeRateFormDialog);
diff --git a/packages/webapp/src/containers/ExchangeRates/ExchangeRateActionsBar.tsx b/packages/webapp/src/containers/ExchangeRates/ExchangeRateActionsBar.tsx
deleted file mode 100644
index e2fadd8b4..000000000
--- a/packages/webapp/src/containers/ExchangeRates/ExchangeRateActionsBar.tsx
+++ /dev/null
@@ -1,147 +0,0 @@
-// @ts-nocheck
-import React, { useCallback, useState, useMemo } from 'react';
-import intl from 'react-intl-universal';
-import classNames from 'classnames';
-import {
- NavbarGroup,
- NavbarDivider,
- Button,
- Classes,
- Intent,
- Popover,
- Position,
- PopoverInteractionKind,
- Alignment,
-} from '@blueprintjs/core';
-import {
- Icon,
- If,
- DashboardActionsBar,
- FormattedMessage as T,
-} from '@/components';
-import { connect } from 'react-redux';
-
-import { useRefreshExchangeRate } from '@/hooks/query/exchangeRates';
-import withDialogActions from '@/containers/Dialog/withDialogActions';
-import withResourceDetail from '@/containers/Resources/withResourceDetails';
-import withExchangeRatesActions from './withExchangeRatesActions';
-import { compose } from '@/utils';
-
-/**
- * Exchange rate actions bar.
- */
-function ExchangeRateActionsBar({
- // #withDialogActions.
- openDialog,
-
- // #withResourceDetail
- resourceFields,
-
- //#withExchangeRatesActions
- addExchangeRatesTableQueries,
-
- // #ownProps
- selectedRows = [],
- onDeleteExchangeRate,
- onFilterChanged,
- onBulkDelete,
-}) {
- const [filterCount, setFilterCount] = useState(0);
-
- const onClickNewExchangeRate = () => {
- openDialog('exchangeRate-form', {});
- };
-
- // Exchange rates refresh action.
- const { refresh } = useRefreshExchangeRate();
-
- // Handle click a refresh sale estimates
- const handleRefreshBtnClick = () => {
- refresh();
- };
-
- const hasSelectedRows = useMemo(
- () => selectedRows.length > 0,
- [selectedRows],
- );
-
- const handelBulkDelete = useCallback(() => {
- onBulkDelete && onBulkDelete(selectedRows.map((r) => r.id));
- }, [onBulkDelete, selectedRows]);
-
- return (
-
-
- }
- text={}
- onClick={onClickNewExchangeRate}
- />
-
-
-
-
- ) : (
- `${filterCount} ${intl.get('filters_applied')}`
- )
- }
- icon={}
- />
-
-
-
- }
- text={}
- intent={Intent.DANGER}
- onClick={handelBulkDelete}
- />
-
-
- }
- text={}
- />
- }
- text={}
- />
-
-
- }
- onClick={handleRefreshBtnClick}
- />
-
-
- );
-}
-
-const mapStateToProps = (state, props) => ({
- resourceName: '',
-});
-
-const withExchangeRateActionBar = connect(mapStateToProps);
-
-export default compose(
- withExchangeRateActionBar,
- withDialogActions,
- withResourceDetail(({ resourceFields }) => ({
- resourceFields,
- })),
- withExchangeRatesActions,
-)(ExchangeRateActionsBar);
diff --git a/packages/webapp/src/containers/ExchangeRates/ExchangeRateTable.tsx b/packages/webapp/src/containers/ExchangeRates/ExchangeRateTable.tsx
deleted file mode 100644
index f595a26f5..000000000
--- a/packages/webapp/src/containers/ExchangeRates/ExchangeRateTable.tsx
+++ /dev/null
@@ -1,110 +0,0 @@
-// @ts-nocheck
-import React, { useCallback } from 'react';
-
-import {
- DataTable,
- TableSkeletonRows,
- TableSkeletonHeader,
-} from '@/components';
-
-import { useExchangeRatesContext } from './ExchangeRatesProvider';
-import { useExchangeRatesTableColumns, ActionMenuList } from './components';
-
-import withExchangeRates from './withExchangeRates';
-import withExchangeRatesActions from './withExchangeRatesActions';
-
-import withDialogActions from '@/containers/Dialog/withDialogActions';
-import withAlertActions from '@/containers/Alert/withAlertActions';
-import { compose } from '@/utils';
-
-/**
- * Exchange rates table.
- */
-function ExchangeRateTable({
- // #ownProps
- tableProps,
-
- // #withDialogActions.
- openDialog,
-
- // #withAlertActions
- openAlert,
-
- // #withExchangeRatesActions
- setExchangeRateTableState,
-
- // #withExchangeRates
- exchangeRatesTableState,
-}) {
- const {
- isExchangeRatesFetching,
- isExchangeRatesLoading,
-
- exchangesRates,
- pagination,
- } = useExchangeRatesContext();
-
- // Table columns.
- const columns = useExchangeRatesTableColumns();
-
- // Handle delete exchange rate.
- const handleDeleteExchangeRate = ({ id }) => {
- openAlert('exchange-rate-delete', { exchangeRateId: id });
- };
-
- // Handle Edit exchange rate.
- const handelEditExchangeRate = (exchangeRate) => {
- openDialog('exchangeRate-form', {
- action: 'edit',
- exchangeRate: exchangeRate,
- });
- };
-
- const handleFetchData = useCallback(
- ({ pageSize, pageIndex, sortBy }) => {
- setExchangeRateTableState({
- pageIndex,
- pageSize,
- sortBy,
- });
- },
- [setExchangeRateTableState],
- );
-
- return (
-
- );
-}
-
-export default compose(
- withDialogActions,
- withAlertActions,
- withExchangeRates(({ exchangeRatesTableState }) => ({
- exchangeRatesTableState,
- })),
- withExchangeRatesActions,
-)(ExchangeRateTable);
diff --git a/packages/webapp/src/containers/ExchangeRates/ExchangeRatesAlerts.tsx b/packages/webapp/src/containers/ExchangeRates/ExchangeRatesAlerts.tsx
deleted file mode 100644
index 7ebae78c7..000000000
--- a/packages/webapp/src/containers/ExchangeRates/ExchangeRatesAlerts.tsx
+++ /dev/null
@@ -1,10 +0,0 @@
-// @ts-nocheck
-import React from 'react';
-
-const ExchangeRateDeleteAlert = React.lazy(
- () => import('@/containers/Alerts/ExchangeRates/ExchangeRateDeleteAlert'),
-);
-
-export default [
- { name: 'exchange-rate-delete', component: ExchangeRateDeleteAlert },
-];
diff --git a/packages/webapp/src/containers/ExchangeRates/ExchangeRatesList.tsx b/packages/webapp/src/containers/ExchangeRates/ExchangeRatesList.tsx
deleted file mode 100644
index 3f4b75ce2..000000000
--- a/packages/webapp/src/containers/ExchangeRates/ExchangeRatesList.tsx
+++ /dev/null
@@ -1,38 +0,0 @@
-// @ts-nocheck
-import React from 'react';
-
-import { DashboardContentTable, DashboardPageContent } from '@/components';
-
-import ExchangeRateTable from './ExchangeRateTable';
-import ExchangeRateActionsBar from './ExchangeRateActionsBar';
-
-import { ExchangeRatesProvider } from './ExchangeRatesProvider';
-import { transformTableStateToQuery, compose } from '@/utils';
-import withExchangeRates from './withExchangeRates';
-
-/**
- * Exchange Rates list.
- */
-function ExchangeRatesList({
- // #withExchangeRates
- exchangeRatesTableState,
-}) {
- return (
-
-
-
-
-
-
-
-
-
- );
-}
-export default compose(
- withExchangeRates(({ exchangeRatesTableState }) => ({
- exchangeRatesTableState,
- })),
-)(ExchangeRatesList);
diff --git a/packages/webapp/src/containers/ExchangeRates/ExchangeRatesProvider.tsx b/packages/webapp/src/containers/ExchangeRates/ExchangeRatesProvider.tsx
deleted file mode 100644
index 8d1175cdc..000000000
--- a/packages/webapp/src/containers/ExchangeRates/ExchangeRatesProvider.tsx
+++ /dev/null
@@ -1,42 +0,0 @@
-// @ts-nocheck
-import React, { createContext } from 'react';
-import { transformTableQueryToParams } from '@/utils';
-
-import { DashboardInsider } from '@/components';
-import { useExchangeRates } from '@/hooks/query';
-
-const ExchangesRatesContext = createContext();
-
-/**
- * Exchanges rates list provider.
- */
-function ExchangeRatesProvider({ query, ...props }) {
- const {
- data: { exchangesRates, pagination, filterMeta },
- isFetching: isExchangeRatesFetching,
- isLoading: isExchangeRatesLoading,
- } = useExchangeRates(
- {
- ...transformTableQueryToParams(query),
- },
- { keepPreviousData: true },
- );
-
- const state = {
- isExchangeRatesFetching,
- isExchangeRatesLoading,
-
- exchangesRates,
- pagination,
- };
-
- return (
-
-
-
- );
-}
-
-const useExchangeRatesContext = () => React.useContext(ExchangesRatesContext);
-
-export { ExchangeRatesProvider, useExchangeRatesContext };
diff --git a/packages/webapp/src/containers/ExchangeRates/components.tsx b/packages/webapp/src/containers/ExchangeRates/components.tsx
deleted file mode 100644
index 2bf08f2f0..000000000
--- a/packages/webapp/src/containers/ExchangeRates/components.tsx
+++ /dev/null
@@ -1,91 +0,0 @@
-// @ts-nocheck
-import React, { useMemo } from 'react';
-import moment from 'moment';
-import intl from 'react-intl-universal';
-import {
- Menu,
- Popover,
- Button,
- Position,
- MenuItem,
- MenuDivider,
- Intent,
-} from '@blueprintjs/core';
-import { Icon, Money } from '@/components';
-import { safeCallback } from '@/utils';
-
-/**
- * Row actions menu list.
- */
-export function ActionMenuList({
- row: { original },
- payload: { onEditExchangeRate, onDeleteExchangeRate },
-}) {
- return (
-
- );
-}
-
-/**
- * Table actions cell.
- */
-export function TableActionsCell(props) {
- return (
- }
- position={Position.RIGHT_TOP}
- >
- } />
-
- );
-}
-
-export function useExchangeRatesTableColumns() {
- return useMemo(
- () => [
- {
- id: 'date',
- Header: intl.get('date'),
- accessor: (r) => moment(r.date).format('YYYY MMM DD'),
- width: 150,
- },
- {
- id: 'currency_code',
- Header: intl.get('currency_code'),
- accessor: 'currency_code',
- className: 'currency_code',
- width: 150,
- },
- {
- id: 'exchange_rate',
- Header: intl.get('exchange_rate'),
- accessor: (r) => (
-
- ),
- className: 'exchange_rate',
- width: 150,
- },
- {
- id: 'actions',
- Header: '',
- Cell: TableActionsCell,
- className: 'actions',
- width: 50,
- },
- ],
- [],
- );
-}
diff --git a/packages/webapp/src/containers/ExchangeRates/withExchangeRateDetail.tsx b/packages/webapp/src/containers/ExchangeRates/withExchangeRateDetail.tsx
deleted file mode 100644
index dc787259d..000000000
--- a/packages/webapp/src/containers/ExchangeRates/withExchangeRateDetail.tsx
+++ /dev/null
@@ -1,9 +0,0 @@
-// @ts-nocheck
-import { connect } from 'react-redux';
-import { getExchangeRateById } from '@/store/ExchangeRate/exchange.selector';
-
-const mapStateToProps = (state, props) => ({
- exchangeRate: getExchangeRateById(state, props),
-});
-
-export default connect(mapStateToProps);
diff --git a/packages/webapp/src/containers/ExchangeRates/withExchangeRates.tsx b/packages/webapp/src/containers/ExchangeRates/withExchangeRates.tsx
deleted file mode 100644
index 5636c5c25..000000000
--- a/packages/webapp/src/containers/ExchangeRates/withExchangeRates.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-// @ts-nocheck
-import { connect } from 'react-redux';
-import { getExchangeRatesTableStateFactory } from '@/store/ExchangeRate/exchange.selector';
-
-export default (mapState) => {
- const getExchangeRatesTableState = getExchangeRatesTableStateFactory();
-
- const mapStateToProps = (state, props) => {
- const mapped = {
- exchangeRatesTableState: getExchangeRatesTableState(state, props),
- };
- return mapState ? mapState(mapped, state, props) : mapped;
- };
-
- return connect(mapStateToProps);
-};
diff --git a/packages/webapp/src/containers/ExchangeRates/withExchangeRatesActions.tsx b/packages/webapp/src/containers/ExchangeRates/withExchangeRatesActions.tsx
deleted file mode 100644
index 86ddd4453..000000000
--- a/packages/webapp/src/containers/ExchangeRates/withExchangeRatesActions.tsx
+++ /dev/null
@@ -1,10 +0,0 @@
-// @ts-nocheck
-import { connect } from 'react-redux';
-import { setExchangeRateTableState } from '@/store/ExchangeRate/exchange.actions';
-
-export const mapDispatchToProps = (dispatch) => ({
- setExchangeRateTableState: (queries) =>
- dispatch(setExchangeRateTableState(queries)),
-});
-
-export default connect(null, mapDispatchToProps);
diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/Dialogs/InvoiceExchangeRateChangeDialog.tsx b/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/Dialogs/InvoiceExchangeRateChangeDialog.tsx
new file mode 100644
index 000000000..00a86b326
--- /dev/null
+++ b/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/Dialogs/InvoiceExchangeRateChangeDialog.tsx
@@ -0,0 +1,63 @@
+// @ts-nocheck
+import { Dialog, DialogSuspense, FormattedMessage as T } from '@/components';
+import withDialogRedux from '@/components/DialogReduxConnect';
+import withDialogActions from '@/containers/Dialog/withDialogActions';
+import { compose } from '@/utils';
+import { Button, Classes, Intent } from '@blueprintjs/core';
+
+/**
+ * Invoice number dialog.
+ */
+function InvoiceExchangeRateChangeDialog({
+ dialogName,
+ payload: { initialFormValues },
+ isOpen,
+ onConfirm,
+ // #withDialogActions
+ closeDialog,
+}) {
+ const handleConfirm = () => {
+ closeDialog(dialogName);
+ };
+
+ return (
+
+ );
+}
+
+export default compose(
+ withDialogRedux(),
+ withDialogActions,
+)(InvoiceExchangeRateChangeDialog);
diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/Dialogs/index.ts b/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/Dialogs/index.ts
new file mode 100644
index 000000000..cda7f24dc
--- /dev/null
+++ b/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/Dialogs/index.ts
@@ -0,0 +1,16 @@
+// @ts-nocheck
+import { DialogsName } from '@/constants/dialogs';
+import React from 'react';
+
+const InvoiceExchangeRateChangeAlert = React.lazy(
+ () => import('./InvoiceExchangeRateChangeDialog'),
+);
+
+const Dialogs = [
+ {
+ name: DialogsName.InvoiceExchangeRateChangeNotice,
+ component: InvoiceExchangeRateChangeAlert,
+ },
+];
+
+export default Dialogs;
diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/InvoiceForm.tsx b/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/InvoiceForm.tsx
index a8463619b..7a975551d 100644
--- a/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/InvoiceForm.tsx
+++ b/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/InvoiceForm.tsx
@@ -34,7 +34,7 @@ import {
transformValueToRequest,
resetFormState,
} from './utils';
-import { InvoiceNoSyncSettingsToForm } from './components';
+import { InvoiceExchangeRateSync, InvoiceNoSyncSettingsToForm } from './components';
/**
* Invoice form.
@@ -180,6 +180,7 @@ function InvoiceForm({
{/*---------- Effects ----------*/}
+
diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/InvoiceFormHeaderFields.tsx b/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/InvoiceFormHeaderFields.tsx
index 8697e52bc..51ba306fa 100644
--- a/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/InvoiceFormHeaderFields.tsx
+++ b/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/InvoiceFormHeaderFields.tsx
@@ -23,7 +23,10 @@ import {
handleDateChange,
} from '@/utils';
import { CLASSES } from '@/constants/classes';
-import { customerNameFieldShouldUpdate } from './utils';
+import {
+ customerNameFieldShouldUpdate,
+ useInvoiceEntriesOnExchangeRateChange,
+} from './utils';
import { useInvoiceFormContext } from './InvoiceFormProvider';
import {
@@ -36,6 +39,7 @@ import {
ProjectBillableEntriesLink,
} from '@/containers/Projects/components';
import { Features } from '@/constants';
+import { useCurrentOrganization } from '@/hooks/state';
/**
* Invoice form header fields.
@@ -161,8 +165,29 @@ export default function InvoiceFormHeaderFields() {
* @returns {React.ReactNode}
*/
function InvoiceFormCustomerSelect() {
- const { customers } = useInvoiceFormContext();
const { values, setFieldValue } = useFormikContext();
+ const { customers, setAutoExRateCurrency } = useInvoiceFormContext();
+ const currentComapny = useCurrentOrganization();
+ const composeEntriesOnExChange = useInvoiceEntriesOnExchangeRateChange();
+
+ // Handles the customer item change.
+ const handleItemChange = (customer) => {
+ setAutoExRateCurrency(null);
+
+ // If the customer id has changed change the customer id and currency code.
+ if (values.customer_id !== customer.id) {
+ setFieldValue('customer_id', customer.id);
+ setFieldValue('currency_code', customer?.currency_code);
+ }
+ // If the customer's currency code is the same the base currency.
+ if (customer?.currency_code === currentComapny.base_currency) {
+ setFieldValue('exchange_rate', '1');
+ setFieldValue('entries', composeEntriesOnExChange(values.exchange_rate, 1));
+ } else {
+ // Sets the currency code to fetch auto-exchange rate.
+ setAutoExRateCurrency(customer?.currency_code);
+ }
+ };
return (
}
- onItemChange={(customer) => {
- setFieldValue('customer_id', customer.id);
- setFieldValue('currency_code', customer?.currency_code);
- }}
+ onItemChange={handleItemChange}
allowCreate={true}
fastField={true}
shouldUpdate={customerNameFieldShouldUpdate}
diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/InvoiceFormProvider.tsx b/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/InvoiceFormProvider.tsx
index fd1b3b0b2..1969abd61 100644
--- a/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/InvoiceFormProvider.tsx
+++ b/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/InvoiceFormProvider.tsx
@@ -3,7 +3,7 @@ import React, { createContext, useState } from 'react';
import { isEmpty, pick } from 'lodash';
import { useLocation } from 'react-router-dom';
import { Features } from '@/constants';
-import { useFeatureCan } from '@/hooks/state';
+import { useCurrentOrganization, useFeatureCan } from '@/hooks/state';
import { DashboardInsider } from '@/components/Dashboard';
import { transformToEditForm, ITEMS_FILTER_ROLES_QUERY } from './utils';
import {
@@ -16,6 +16,7 @@ import {
useEditInvoice,
useSettingsInvoices,
useEstimate,
+ useExchangeRate,
} from '@/hooks/query';
import { useProjects } from '@/containers/Projects/hooks';
import { useTaxRates } from '@/hooks/query/taxRates';
@@ -93,6 +94,18 @@ function InvoiceFormProvider({ invoiceId, baseCurrency, ...props }) {
// Handle fetching settings.
const { isLoading: isSettingsLoading } = useSettingsInvoices();
+ const [autoExRateCurrency, setAutoExRateCurrency] = useState('');
+ const currentOrganization = useCurrentOrganization();
+
+ // Retrieves the exchange rate.
+ const { data: autoExchangeRate, isLoading: isAutoExchangeRateLoading } =
+ useExchangeRate(autoExRateCurrency, currentOrganization.base_currency, {
+ enabled: Boolean(currentOrganization.base_currency && autoExRateCurrency),
+ refetchOnWindowFocus: false,
+ staleTime: Infinity,
+ cacheTime: Infinity,
+ });
+
// Create and edit invoice mutations.
const { mutateAsync: createInvoiceMutate } = useCreateInvoice();
const { mutateAsync: editInvoiceMutate } = useEditInvoice();
@@ -119,6 +132,7 @@ function InvoiceFormProvider({ invoiceId, baseCurrency, ...props }) {
warehouses,
projects,
taxRates,
+ autoExchangeRate,
isInvoiceLoading,
isItemsLoading,
@@ -135,6 +149,10 @@ function InvoiceFormProvider({ invoiceId, baseCurrency, ...props }) {
editInvoiceMutate,
setSubmitPayload,
isNewMode,
+
+ autoExRateCurrency,
+ setAutoExRateCurrency,
+ isAutoExchangeRateLoading,
};
return (
diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/components.tsx b/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/components.tsx
index 0020a7e8d..e25b389d7 100644
--- a/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/components.tsx
+++ b/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/components.tsx
@@ -1,23 +1,53 @@
// @ts-nocheck
-import React from 'react';
+import { useEffect, useRef } from 'react';
import intl from 'react-intl-universal';
import * as R from 'ramda';
import { Button } from '@blueprintjs/core';
import { useFormikContext } from 'formik';
import { ExchangeRateInputGroup } from '@/components';
import { useCurrentOrganization } from '@/hooks/state';
-import { useInvoiceIsForeignCustomer } from './utils';
+import {
+ useInvoiceEntriesOnExchangeRateChange,
+ useInvoiceIsForeignCustomer,
+ useInvoiceTotal,
+} from './utils';
import withSettings from '@/containers/Settings/withSettings';
import { useUpdateEffect } from '@/hooks';
import { transactionNumber } from '@/utils';
+import { useInvoiceFormContext } from './InvoiceFormProvider';
+import withDialogActions from '@/containers/Dialog/withDialogActions';
+import { DialogsName } from '@/constants/dialogs';
+
+/**
+ * Re-calculate the item entries prices based on the old exchange rate.
+ * @param {InvoiceExchangeRateInputFieldRoot} Component
+ * @returns {JSX.Element}
+ */
+const withExchangeRateItemEntriesPriceRecalc = (Component) => (props) => {
+ const { setFieldValue } = useFormikContext();
+ const composeChangeExRate = useInvoiceEntriesOnExchangeRateChange();
+
+ return (
+ {
+ setFieldValue(
+ 'entries',
+ composeChangeExRate(oldExchangeRate, exchangeRate),
+ );
+ }}
+ {...props}
+ />
+ );
+};
/**
* Invoice exchange rate input field.
* @returns {JSX.Element}
*/
-export function InvoiceExchangeRateInputField({ ...props }) {
+const InvoiceExchangeRateInputFieldRoot = ({ ...props }) => {
const currentOrganization = useCurrentOrganization();
const { values } = useFormikContext();
+ const { isAutoExchangeRateLoading } = useInvoiceFormContext();
const isForeignCustomer = useInvoiceIsForeignCustomer();
@@ -27,12 +57,22 @@ export function InvoiceExchangeRateInputField({ ...props }) {
}
return (
);
-}
+};
+
+/**
+ * Invoice exchange rate input field.
+ * @returns {JSX.Element}
+ */
+export const InvoiceExchangeRateInputField = R.compose(
+ withExchangeRateItemEntriesPriceRecalc,
+)(InvoiceExchangeRateInputFieldRoot);
/**
* Invoice project select.
@@ -66,3 +106,42 @@ export const InvoiceNoSyncSettingsToForm = R.compose(
return null;
});
+
+/**
+ * Syncs the fetched real-time exchange rate to the form.
+ * @returns {JSX.Element}
+ */
+export const InvoiceExchangeRateSync = R.compose(withDialogActions)(
+ ({ openDialog }) => {
+ const { setFieldValue, values } = useFormikContext();
+ const { autoExRateCurrency, autoExchangeRate } = useInvoiceFormContext();
+ const composeEntriesOnExChange = useInvoiceEntriesOnExchangeRateChange();
+
+ const total = useInvoiceTotal();
+ const timeout = useRef();
+
+ // Sync the fetched real-time exchanage rate to the form.
+ useEffect(() => {
+ if (autoExchangeRate?.exchange_rate && autoExRateCurrency) {
+ setFieldValue('exchange_rate', autoExchangeRate?.exchange_rate + '');
+ setFieldValue(
+ 'entries',
+ composeEntriesOnExChange(
+ values.exchange_rate,
+ autoExchangeRate?.exchange_rate,
+ ),
+ );
+ // If the total bigger then zero show alert to the user after adjusting entries.
+ if (total > 0) {
+ clearTimeout(timeout.current);
+ timeout.current = setTimeout(() => {
+ openDialog(DialogsName.InvoiceExchangeRateChange);
+ }, 500);
+ }
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [autoExchangeRate?.exchange_rate, autoExRateCurrency]);
+
+ return null;
+ },
+);
diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/utils.tsx b/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/utils.tsx
index 4186cbc63..b059a48fa 100644
--- a/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/utils.tsx
+++ b/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/utils.tsx
@@ -5,7 +5,7 @@ import intl from 'react-intl-universal';
import moment from 'moment';
import * as R from 'ramda';
import { Intent } from '@blueprintjs/core';
-import { omit, first, sumBy } from 'lodash';
+import { omit, first, sumBy, round } from 'lodash';
import {
compose,
transformToForm,
@@ -57,7 +57,7 @@ export const defaultInvoice = {
reference_no: '',
invoice_message: '',
terms_conditions: '',
- exchange_rate: 1,
+ exchange_rate: '1',
currency_code: '',
branch_id: '',
warehouse_id: '',
@@ -398,3 +398,85 @@ export const useIsInvoiceTaxExclusive = () => {
return values.inclusive_exclusive_tax === TaxType.Exclusive;
};
+
+/**
+ * Convert the given rate to the local currency.
+ * @param {number} rate
+ * @param {number} exchangeRate
+ * @returns {number}
+ */
+export const convertToForeignCurrency = (
+ rate: number,
+ exchangeRate: number,
+) => {
+ return rate * exchangeRate;
+};
+
+/**
+ * Converts the given rate to the base currency.
+ * @param {number} rate
+ * @param {number} exchangeRate
+ * @returns {number}
+ */
+export const covertToBaseCurrency = (rate: number, exchangeRate: number) => {
+ return rate / exchangeRate;
+};
+
+/**
+ * Reverts the given rate from the old exchange rate and covert it to the new
+ * currency based on the given new exchange rate.
+ * @param {number} rate -
+ * @param {number} oldExchangeRate - Old exchange rate.
+ * @param {number} newExchangeRate - New exchange rate.
+ * @returns {number}
+ */
+const revertAndConvertExchangeRate = (
+ rate: number,
+ oldExchangeRate: number,
+ newExchangeRate: number,
+) => {
+ const oldValue = convertToForeignCurrency(rate, oldExchangeRate);
+ const newValue = covertToBaseCurrency(oldValue, newExchangeRate);
+
+ return round(newValue, 3);
+};
+
+/**
+ * Assign the new item entry rate after converting to the new exchange rate.
+ * @params {number} oldExchangeRate -
+ * @params {number} newExchangeRate -
+ * @params {IItemEntry} entries -
+ */
+const assignRateRevertAndCovertExchangeRate = R.curry(
+ (oldExchangeRate: number, newExchangeRate: number, entries: IItemEntry[]) => {
+ return entries.map((entry) => ({
+ ...entry,
+ rate: revertAndConvertExchangeRate(
+ entry.rate,
+ oldExchangeRate,
+ newExchangeRate,
+ ),
+ }));
+ },
+);
+
+/**
+ * Compose invoice entries on exchange rate change.
+ * @returns {(oldExchangeRate: number, newExchangeRate: number) => IItemEntry[]}
+ */
+export const useInvoiceEntriesOnExchangeRateChange = () => {
+ const {
+ values: { entries },
+ } = useFormikContext();
+
+ return React.useMemo(() => {
+ return R.curry((oldExchangeRate: number, newExchangeRate: number) => {
+ return R.compose(
+ // Updates entries total.
+ updateItemsEntriesTotal,
+ // Assign a new rate of the given new exchange rate from the old exchange rate.
+ assignRateRevertAndCovertExchangeRate(oldExchangeRate, newExchangeRate),
+ )(entries);
+ });
+ }, [entries]);
+};
diff --git a/packages/webapp/src/hooks/query/exchangeRates.tsx b/packages/webapp/src/hooks/query/exchangeRates.tsx
index f38b66737..b861d7c7d 100644
--- a/packages/webapp/src/hooks/query/exchangeRates.tsx
+++ b/packages/webapp/src/hooks/query/exchangeRates.tsx
@@ -1,102 +1,29 @@
// @ts-nocheck
-import { useMutation, useQueryClient } from 'react-query';
-import { defaultTo } from 'lodash';
-import { useQueryTenant } from '../useQueryRequest';
-import { transformPagination } from '@/utils';
-import useApiRequest from '../useRequest';
+import { useQuery } from 'react-query';
+import QUERY_TYPES from './types';
-const defaultPagination = {
- pageSize: 20,
- page: 0,
- pagesCount: 0,
-};
-/**
- * Creates a new exchange rate.
- */
-export function useCreateExchangeRate(props) {
- const queryClient = useQueryClient();
- const apiRequest = useApiRequest();
-
- return useMutation((values) => apiRequest.post('exchange_rates', values), {
- onSuccess: () => {
- queryClient.invalidateQueries('EXCHANGES_RATES');
- },
- ...props,
- });
+function getRandomItemFromArray(arr) {
+ const randomIndex = Math.floor(Math.random() * arr.length);
+ return arr[randomIndex];
}
/**
- * Edits the exchange rate.
+ * Retrieves tax rates.
+ * @param {number} customerId - Customer id.
*/
-export function useEdiExchangeRate(props) {
- const queryClient = useQueryClient();
- const apiRequest = useApiRequest();
-
- return useMutation(
- ([id, values]) => apiRequest.post(`exchange_rates/${id}`, values),
- {
- onSuccess: () => {
- queryClient.invalidateQueries('EXCHANGES_RATES');
- },
- ...props,
- },
- );
-}
-
-/**
- * Deletes the exchange rate.
- */
-export function useDeleteExchangeRate(props) {
- const queryClient = useQueryClient();
- const apiRequest = useApiRequest();
-
- return useMutation((id) => apiRequest.delete(`exchange_rates/${id}`), {
- onSuccess: () => {
- queryClient.invalidateQueries('EXCHANGES_RATES');
- },
- ...props,
- });
-}
-
-/**
- * Retrieve the exchange rate list.
- */
-export function useExchangeRates(query, props) {
- const apiRequest = useApiRequest();
-
- const states = useQueryTenant(
- ['EXCHANGES_RATES', query],
- () => apiRequest.get('exchange_rates', { params: query }),
- {
- select: (res) => ({
- exchangesRates: res.data.exchange_rates.results,
- pagination: transformPagination(res.data.exchange_rates.pagination),
- filterMeta: res.data.filter_meta,
+export function useExchangeRate(
+ fromCurrency: string,
+ toCurrency: string,
+ props,
+) {
+ return useQuery(
+ [QUERY_TYPES.EXCHANGE_RATE, fromCurrency, toCurrency],
+ () =>
+ Promise.resolve({
+ from_currency: fromCurrency,
+ to_currency: toCurrency,
+ exchange_rate: getRandomItemFromArray([4.231, 2.231]),
}),
- ...props,
- },
+ props,
);
-
- return {
- ...states,
- data: defaultTo(states.data, {
- exchangesRates: [],
- pagination: {
- page: 1,
- pageSize: 20,
- total: 0,
- },
- filterMeta: {},
- }),
- };
-}
-
-export function useRefreshExchangeRate() {
- const queryClient = useQueryClient();
-
- return {
- refresh: () => {
- queryClient.invalidateQueries('EXCHANGES_RATES');
- },
- };
}
diff --git a/packages/webapp/src/hooks/query/types.tsx b/packages/webapp/src/hooks/query/types.tsx
index c0173cab7..fbce84ae3 100644
--- a/packages/webapp/src/hooks/query/types.tsx
+++ b/packages/webapp/src/hooks/query/types.tsx
@@ -32,7 +32,7 @@ const FINANCIAL_REPORTS = {
REALIZED_GAIN_OR_LOSS: 'REALIZED_GAIN_OR_LOSS',
UNREALIZED_GAIN_OR_LOSS: 'UNREALIZED_GAIN_OR_LOSS',
PROJECT_PROFITABILITY_SUMMARY: 'PROJECT_PROFITABILITY_SUMMARY',
- SALES_TAX_LIABILITY_SUMMARY: 'SALES_TAX_LIABILITY_SUMMARY'
+ SALES_TAX_LIABILITY_SUMMARY: 'SALES_TAX_LIABILITY_SUMMARY',
};
const BILLS = {
@@ -222,12 +222,17 @@ const DASHBOARD = {
};
const ORGANIZATION = {
- ORGANIZATION_MUTATE_BASE_CURRENCY_ABILITIES: 'ORGANIZATION_MUTATE_BASE_CURRENCY_ABILITIES',
+ ORGANIZATION_MUTATE_BASE_CURRENCY_ABILITIES:
+ 'ORGANIZATION_MUTATE_BASE_CURRENCY_ABILITIES',
};
export const TAX_RATES = {
TAX_RATES: 'TAX_RATES',
-}
+};
+
+export const EXCHANGE_RATE = {
+ EXCHANGE_RATE: 'EXCHANGE_RATE',
+};
export default {
...Authentication,
@@ -262,5 +267,6 @@ export default {
...BRANCHES,
...DASHBOARD,
...ORGANIZATION,
- ...TAX_RATES
+ ...TAX_RATES,
+ ...EXCHANGE_RATE,
};
diff --git a/packages/webapp/src/routes/dashboard.tsx b/packages/webapp/src/routes/dashboard.tsx
index 5193c63f8..c1137bc5b 100644
--- a/packages/webapp/src/routes/dashboard.tsx
+++ b/packages/webapp/src/routes/dashboard.tsx
@@ -473,16 +473,6 @@ export const getDashboardRoutes = () => [
pageTitle: intl.get('all_financial_reports'),
subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
},
- // Exchange Rates
- // {
- // path: `/exchange-rates`,
- // component: lazy(
- // () => import('@/containers/ExchangeRates/ExchangeRatesList'),
- // ),
- // breadcrumb: intl.get('exchange_rates_list'),
- // pageTitle: intl.get('exchange_rates_list'),
- // subscriptionActive: [SUBSCRIPTION_TYPE.MAIN],
- // },
// Expenses.
{
path: `/expenses/new`,