From eca89a779cbc2b265aa5f048a57757d839f9d912 Mon Sep 17 00:00:00 2001 From: Nada Date: Thu, 7 Sep 2023 13:28:38 +0400 Subject: [PATCH 1/4] refactor: order details confirm modal, fileuploader refactoring --- .../__test__/file-uploader-component.spec.js | 66 --------------- .../file-uploader-component.spec.tsx | 81 +++++++++++++++++++ ...ponent.jsx => file-uploader-component.tsx} | 66 +++++++++------ .../{index.js => index.ts} | 2 +- ...s => order-details-confirm-modal.spec.tsx} | 40 +++++---- .../{index.js => index.ts} | 3 +- .../order-details-confirm-modal.scss | 0 ...al.jsx => order-details-confirm-modal.tsx} | 67 +++++++-------- packages/p2p/src/utils/file-uploader.js | 2 + 9 files changed, 176 insertions(+), 151 deletions(-) delete mode 100644 packages/p2p/src/components/file-uploader-component/__test__/file-uploader-component.spec.js create mode 100644 packages/p2p/src/components/file-uploader-component/__tests__/file-uploader-component.spec.tsx rename packages/p2p/src/components/file-uploader-component/{file-uploader-component.jsx => file-uploader-component.tsx} (52%) rename packages/p2p/src/components/file-uploader-component/{index.js => index.ts} (54%) rename packages/p2p/src/components/modal-manager/modals/order-details-confirm-modal/__tests__/{order-details-confirm-modal.spec.js => order-details-confirm-modal.spec.tsx} (79%) rename packages/p2p/src/components/modal-manager/modals/order-details-confirm-modal/{index.js => index.ts} (67%) rename packages/p2p/src/components/{order-details => modal-manager/modals/order-details-confirm-modal}/order-details-confirm-modal.scss (100%) rename packages/p2p/src/components/modal-manager/modals/order-details-confirm-modal/{order-details-confirm-modal.jsx => order-details-confirm-modal.tsx} (67%) diff --git a/packages/p2p/src/components/file-uploader-component/__test__/file-uploader-component.spec.js b/packages/p2p/src/components/file-uploader-component/__test__/file-uploader-component.spec.js deleted file mode 100644 index 61acb889991e..000000000000 --- a/packages/p2p/src/components/file-uploader-component/__test__/file-uploader-component.spec.js +++ /dev/null @@ -1,66 +0,0 @@ -import React from 'react'; -import { render, screen, fireEvent, waitFor } from '@testing-library/react'; -import { isMobile, isDesktop } from '@deriv/shared'; -import FileUploaderComponent from '../file-uploader-component'; - -jest.mock('@deriv/shared', () => ({ - ...jest.requireActual('@deriv/shared'), - isDesktop: jest.fn(), - isMobile: jest.fn(), - compressImageFiles: jest.fn(() => Promise.resolve([{ path: 'hello.pdf' }])), - readFiles: jest.fn(), -})); - -jest.mock('@binary-com/binary-document-uploader'); - -describe('', () => { - beforeEach(() => { - isDesktop.mockReturnValue(true); - isMobile.mockReturnValue(false); - jest.clearAllMocks(); - }); - - const file = new File(['hello'], 'hello.png', { type: 'image/png' }); - const props = { - accept: 'image/pdf, image/png', - filename_limit: 26, - max_size: 2097152, - multiple: false, - onDropAccepted: jest.fn(), - onDropRejected: jest.fn(), - validation_error_message: null, - onClickClose: jest.fn(), - upload_message: 'upload here', - value: [], - }; - - it('should render FileUploaderComponent component in desktop mode', async () => { - render(); - expect(screen.getByText('upload here')).toBeInTheDocument(); - }); - - it('should upload supported file', async () => { - props.value = [file]; - render(); - const input = screen.getByTestId('dt_file_upload_input'); - fireEvent.change(input, { target: { files: [file] } }); - await waitFor(() => { - expect(input.files[0]).toBe(file); - expect(input.files).toHaveLength(1); - }); - expect(screen.getByText('hello.png')).toBeInTheDocument(); - }); - - it('should show error message when unsupported file is uploaded', async () => { - props.validation_error_message = 'error'; - render(); - - const unsupported_file = new File(['hello'], 'hello.html', { type: 'html' }); - const input = screen.getByTestId('dt_file_upload_input'); - fireEvent.change(input, { target: { files: [unsupported_file] } }); - - await waitFor(() => { - expect(screen.getByText('error')).toBeInTheDocument(); - }); - }); -}); diff --git a/packages/p2p/src/components/file-uploader-component/__tests__/file-uploader-component.spec.tsx b/packages/p2p/src/components/file-uploader-component/__tests__/file-uploader-component.spec.tsx new file mode 100644 index 000000000000..5b5226c27299 --- /dev/null +++ b/packages/p2p/src/components/file-uploader-component/__tests__/file-uploader-component.spec.tsx @@ -0,0 +1,81 @@ +import React from 'react'; +import { render, screen, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { StoreProvider, mockStore } from '@deriv/stores'; +import FileUploaderComponent from '../file-uploader-component'; + +describe('', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + const file = new File(['hello'], 'hello.png', { type: 'image/png' }); + const props = { + accept: 'image/pdf, image/png', + filename_limit: 26, + hover_message: 'drop here', + max_size: 2097152, + multiple: false, + setDocumentFile: jest.fn(), + validation_error_message: null, + upload_message: 'upload here', + value: [], + }; + + it('should render FileUploaderComponent component in desktop mode', async () => { + render(, { + wrapper: ({ children }) => {children}, + }); + expect(screen.getByText('upload here')).toBeInTheDocument(); + }); + + it('should upload supported file', async () => { + const new_props = { + ...props, + value: [file], + }; + render(, { + wrapper: ({ children }) => {children}, + }); + const input: HTMLInputElement = screen.getByTestId('dt_file_upload_input'); + userEvent.upload(input, file); + await waitFor(() => { + expect(input.files?.[0]).toBe(file); + expect(input.files).toHaveLength(1); + }); + expect(props.setDocumentFile).toHaveBeenCalledWith({ files: [file], error_message: null }); + expect(screen.getByText('hello.png')).toBeInTheDocument(); + }); + + it('should show error message when unsupported file is uploaded', async () => { + const new_props = { ...props, validation_error_message: 'error' }; + render(, { + wrapper: ({ children }) => {children}, + }); + + const unsupported_file = new File(['hello'], 'hello.html', { type: 'html' }); + const input = screen.getByTestId('dt_file_upload_input'); + userEvent.upload(input, unsupported_file); + + await waitFor(() => { + expect(screen.getByText('error')).toBeInTheDocument(); + }); + }); + it('should handle remove File', async () => { + const new_props = { ...props, validation_error_message: 'error' }; + render(, { + wrapper: ({ children }) => {children}, + }); + + const input: HTMLInputElement = screen.getByTestId('dt_file_upload_input'); + userEvent.upload(input, file); + await waitFor(() => { + expect(input.files?.[0]).toBe(file); + expect(input.files).toHaveLength(1); + }); + const remove_icon = screen.getByTestId('dt_remove_file_icon'); + expect(remove_icon).toBeInTheDocument(); + userEvent.click(remove_icon); + expect(props.setDocumentFile).toHaveBeenCalledWith({ files: [], error_message: null }); + }); +}); diff --git a/packages/p2p/src/components/file-uploader-component/file-uploader-component.jsx b/packages/p2p/src/components/file-uploader-component/file-uploader-component.tsx similarity index 52% rename from packages/p2p/src/components/file-uploader-component/file-uploader-component.jsx rename to packages/p2p/src/components/file-uploader-component/file-uploader-component.tsx index 7b0db19725f4..dfbd64071cc1 100644 --- a/packages/p2p/src/components/file-uploader-component/file-uploader-component.jsx +++ b/packages/p2p/src/components/file-uploader-component/file-uploader-component.tsx @@ -1,32 +1,64 @@ import React from 'react'; -import PropTypes from 'prop-types'; import { FileDropzone, Icon, Text } from '@deriv/components'; -import { isMobile } from '@deriv/shared'; +import { TFile } from '@deriv/shared'; +import { useStore } from '@deriv/stores'; import { localize } from 'Components/i18next'; +import { getErrorMessage } from 'Utils/file-uploader'; + +type TDocumentFile = { + files: TFile[]; + error_message: string | null; +}; + +type TFileUploaderComponentProps = { + accept: string; + hover_message: string; + max_size: number; + multiple?: boolean; + setDocumentFile: React.Dispatch>; + upload_message: string; + validation_error_message: string | null; + value: File[]; +}; const FileUploaderComponent = ({ accept, hover_message, max_size, multiple = false, - onClickClose, - onDropAccepted, - onDropRejected, + setDocumentFile, upload_message, validation_error_message, value, -}) => { +}: TFileUploaderComponentProps) => { + const { + ui: { is_mobile }, + } = useStore(); const getUploadMessage = () => { return ( <> - + {upload_message} ); }; + const handleAcceptedFiles = (files: TFile[]) => { + if (files.length > 0) { + setDocumentFile({ files, error_message: null }); + } + }; + + const removeFile = () => { + setDocumentFile({ files: [], error_message: null }); + }; + + const handleRejectedFiles = (files: TFile[]) => { + setDocumentFile({ files, error_message: getErrorMessage(files) }); + }; + return (
@@ -46,7 +78,7 @@ const FileUploaderComponent = ({ @@ -55,18 +87,4 @@ const FileUploaderComponent = ({ ); }; -FileUploaderComponent.propTypes = { - accept: PropTypes.string, - hover_message: PropTypes.string, - error_messages: PropTypes.string, - max_size: PropTypes.number, - multiple: PropTypes.bool, - upload_message: PropTypes.string, - onClickClose: PropTypes.func, - onDropAccepted: PropTypes.func, - onDropRejected: PropTypes.func, - validation_error_message: PropTypes.string, - value: PropTypes.arrayOf(PropTypes.instanceOf(File)), -}; - export default FileUploaderComponent; diff --git a/packages/p2p/src/components/file-uploader-component/index.js b/packages/p2p/src/components/file-uploader-component/index.ts similarity index 54% rename from packages/p2p/src/components/file-uploader-component/index.js rename to packages/p2p/src/components/file-uploader-component/index.ts index 3d3e6ed215c8..d2d1d530cfaf 100644 --- a/packages/p2p/src/components/file-uploader-component/index.js +++ b/packages/p2p/src/components/file-uploader-component/index.ts @@ -1,4 +1,4 @@ -import FileUploaderComponent from './file-uploader-component.jsx'; +import FileUploaderComponent from './file-uploader-component'; import './file-uploader-component.scss'; export default FileUploaderComponent; diff --git a/packages/p2p/src/components/modal-manager/modals/order-details-confirm-modal/__tests__/order-details-confirm-modal.spec.js b/packages/p2p/src/components/modal-manager/modals/order-details-confirm-modal/__tests__/order-details-confirm-modal.spec.tsx similarity index 79% rename from packages/p2p/src/components/modal-manager/modals/order-details-confirm-modal/__tests__/order-details-confirm-modal.spec.js rename to packages/p2p/src/components/modal-manager/modals/order-details-confirm-modal/__tests__/order-details-confirm-modal.spec.tsx index bc179c6219d4..8d4a93df85e7 100644 --- a/packages/p2p/src/components/modal-manager/modals/order-details-confirm-modal/__tests__/order-details-confirm-modal.spec.js +++ b/packages/p2p/src/components/modal-manager/modals/order-details-confirm-modal/__tests__/order-details-confirm-modal.spec.tsx @@ -1,8 +1,10 @@ import React from 'react'; import { fireEvent, render, screen, waitFor } from '@testing-library/react'; -import { useStores } from 'Stores'; -import OrderDetailsConfirmModal from '../order-details-confirm-modal.jsx'; +import { StoreProvider, mockStore } from '@deriv/stores'; import { useModalManagerContext } from 'Components/modal-manager/modal-manager-context'; +import { useStores } from 'Stores'; +import OrderDetailsConfirmModal from '../order-details-confirm-modal'; +import userEvent from '@testing-library/user-event'; const el_modal = document.createElement('div'); @@ -11,18 +13,6 @@ jest.mock('Utils/websocket', () => ({ requestWS: jest.fn().mockResolvedValue({ error: { message: 'P2P Error' } }), })); -jest.mock('@sendbird/chat', () => ({ - SendbirdChat: jest.fn().mockReturnValue({}), -})); - -jest.mock('@sendbird/chat/groupChannel', () => ({ - SendbirdChat: jest.fn().mockReturnValue({}), -})); - -jest.mock('@sendbird/chat/message', () => ({ - SendbirdChat: jest.fn().mockReturnValue({}), -})); - jest.mock('Stores', () => ({ ...jest.requireActual('Stores'), useStores: jest.fn().mockReturnValue({ @@ -63,7 +53,9 @@ describe('', () => { }); it('should render the modal', () => { - render(); + render(, { + wrapper: ({ children }) => {children}, + }); expect(screen.getByText('Payment confirmation')).toBeInTheDocument(); expect( @@ -78,11 +70,13 @@ describe('', () => { it('should handle GoBack Click', () => { const { hideModal } = useModalManagerContext(); - render(); + render(, { + wrapper: ({ children }) => {children}, + }); const cancel_button = screen.getByRole('button', { name: 'Go Back' }); expect(cancel_button).toBeInTheDocument(); - fireEvent.click(cancel_button); + userEvent.click(cancel_button); expect(hideModal).toHaveBeenCalled(); }); it('should send a request when confirm button is clicked', async () => { @@ -90,19 +84,21 @@ describe('', () => { const { hideModal } = useModalManagerContext(); const { confirmOrderRequest, order_information } = order_store; - render(); + render(, { + wrapper: ({ children }) => {children}, + }); const file = new File(['hello'], 'hello.png', { type: 'image/png' }); - const input = screen.getByTestId('dt_file_upload_input'); - fireEvent.change(input, { target: { files: [file] } }); + const input: HTMLInputElement = screen.getByTestId('dt_file_upload_input'); + userEvent.upload(input, file); await waitFor(() => { - expect(input.files[0]).toBe(file); + expect(input.files?.[0]).toBe(file); expect(input.files).toHaveLength(1); }); const confirm_button = screen.getByRole('button', { name: 'Confirm' }); expect(confirm_button).toBeInTheDocument(); expect(confirm_button).toBeEnabled(); - fireEvent.click(confirm_button); + userEvent.click(confirm_button); await waitFor(() => { expect(sendbird_store.sendFile).toHaveBeenCalled(); expect(confirmOrderRequest).toHaveBeenCalledWith(order_information.id, true); diff --git a/packages/p2p/src/components/modal-manager/modals/order-details-confirm-modal/index.js b/packages/p2p/src/components/modal-manager/modals/order-details-confirm-modal/index.ts similarity index 67% rename from packages/p2p/src/components/modal-manager/modals/order-details-confirm-modal/index.js rename to packages/p2p/src/components/modal-manager/modals/order-details-confirm-modal/index.ts index 75cf94729d7c..b00158058072 100644 --- a/packages/p2p/src/components/modal-manager/modals/order-details-confirm-modal/index.js +++ b/packages/p2p/src/components/modal-manager/modals/order-details-confirm-modal/index.ts @@ -1,3 +1,4 @@ -import OrderDetailsConfirmModal from './order-details-confirm-modal.jsx'; +import OrderDetailsConfirmModal from './order-details-confirm-modal'; +import './order-details-confirm-modal.scss'; export default OrderDetailsConfirmModal; diff --git a/packages/p2p/src/components/order-details/order-details-confirm-modal.scss b/packages/p2p/src/components/modal-manager/modals/order-details-confirm-modal/order-details-confirm-modal.scss similarity index 100% rename from packages/p2p/src/components/order-details/order-details-confirm-modal.scss rename to packages/p2p/src/components/modal-manager/modals/order-details-confirm-modal/order-details-confirm-modal.scss diff --git a/packages/p2p/src/components/modal-manager/modals/order-details-confirm-modal/order-details-confirm-modal.jsx b/packages/p2p/src/components/modal-manager/modals/order-details-confirm-modal/order-details-confirm-modal.tsx similarity index 67% rename from packages/p2p/src/components/modal-manager/modals/order-details-confirm-modal/order-details-confirm-modal.jsx rename to packages/p2p/src/components/modal-manager/modals/order-details-confirm-modal/order-details-confirm-modal.tsx index e991b26444aa..660bd68c6f34 100644 --- a/packages/p2p/src/components/modal-manager/modals/order-details-confirm-modal/order-details-confirm-modal.jsx +++ b/packages/p2p/src/components/modal-manager/modals/order-details-confirm-modal/order-details-confirm-modal.tsx @@ -1,38 +1,36 @@ import React from 'react'; import { useStores } from 'Stores'; import { Button, Modal, Text } from '@deriv/components'; -import { isMobile, formatMoney } from '@deriv/shared'; +import { formatMoney, TFile } from '@deriv/shared'; +import { observer, useStore } from '@deriv/stores'; import { localize } from '@deriv/translations'; import FileUploaderComponent from 'Components/file-uploader-component'; +//Todo: change the below line when changing the base branch import FormError from 'Components/form/error.jsx'; import { Localize } from 'Components/i18next'; import { useModalManagerContext } from 'Components/modal-manager/modal-manager-context'; -import { getErrorMessage, max_pot_file_size } from 'Utils/file-uploader'; +import { accepted_file_types, max_pot_file_size } from 'Utils/file-uploader'; import { removeTrailingZeros, roundOffDecimal, setDecimalPlaces } from 'Utils/format-value'; -import 'Components/order-details/order-details-confirm-modal.scss'; + +type TDocumentFile = { + files: TFile[]; + error_message: string | null; +}; const OrderDetailsConfirmModal = () => { const { hideModal, is_modal_open } = useModalManagerContext(); const { order_details_store, order_store, sendbird_store } = useStores(); - const { amount_display, local_currency, other_user_details, rate, id } = order_store.order_information; - const [document_file, setDocumentFile] = React.useState({ files: [], error_message: null }); - - const handleAcceptedFiles = files => { - if (files.length > 0) { - setDocumentFile({ files, error_message: null }); - } - }; - - const removeFile = () => { - setDocumentFile({ files: [], error_message: null }); - }; - - const handleRejectedFiles = files => { - setDocumentFile({ files, error_message: getErrorMessage(files) }); - }; + const { + ui: { is_mobile }, + } = useStore(); + const { error_message } = order_details_store; + const { confirmOrderRequest, order_information } = order_store; + const { sendFile } = sendbird_store; + const { amount_display, local_currency, other_user_details, rate, id } = order_information ?? {}; + const [document_file, setDocumentFile] = React.useState({ files: [], error_message: null }); const display_payment_amount = removeTrailingZeros( - formatMoney(local_currency, amount_display * roundOffDecimal(rate, setDecimalPlaces(rate, 6)), true) + formatMoney(local_currency, amount_display * Number(roundOffDecimal(rate, setDecimalPlaces(rate, 6))), true) ); return ( @@ -41,12 +39,11 @@ const OrderDetailsConfirmModal = () => { className='order-details-confirm-modal' is_open={is_modal_open} toggleModal={hideModal} - has_close_icon renderTitle={() => ( @@ -55,7 +52,7 @@ const OrderDetailsConfirmModal = () => { width='44rem' > - + { - {order_details_store.error_message && } + {error_message && }
From 82b2fba5534fb1887e36bf35ecc1e34d3be0de8b Mon Sep 17 00:00:00 2001 From: Nada Date: Fri, 8 Sep 2023 12:48:22 +0400 Subject: [PATCH 3/4] fix: changed destructuring, moved nested component out --- .../file-uploader-component.tsx | 33 ++++++++++--------- .../order-details-confirm-modal.tsx | 7 ++-- packages/p2p/src/stores/sendbird-store.ts | 1 + 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/packages/p2p/src/components/file-uploader-component/file-uploader-component.tsx b/packages/p2p/src/components/file-uploader-component/file-uploader-component.tsx index d73d69ce7726..adb82202f5e6 100644 --- a/packages/p2p/src/components/file-uploader-component/file-uploader-component.tsx +++ b/packages/p2p/src/components/file-uploader-component/file-uploader-component.tsx @@ -21,6 +21,23 @@ type TFileUploaderComponentProps = { value: File[]; }; +type TUploadMessageProps = { + upload_message: string; +}; + +const UploadMessage = ({ upload_message }: TUploadMessageProps) => { + const { ui } = useStore(); + const { is_mobile } = ui; + return ( + + + + {upload_message} + + + ); +}; + const FileUploaderComponent = ({ accept, hover_message, @@ -31,20 +48,6 @@ const FileUploaderComponent = ({ validation_error_message, value, }: TFileUploaderComponentProps) => { - const { - ui: { is_mobile }, - } = useStore(); - const getUploadMessage = () => { - return ( - <> - - - {upload_message} - - - ); - }; - const handleAcceptedFiles = (files: TFile[]) => { if (files.length > 0) { setDocumentFile({ files, error_message: null }); @@ -67,7 +70,7 @@ const FileUploaderComponent = ({ filename_limit={26} hover_message={hover_message} max_size={max_size} - message={getUploadMessage()} + message={} multiple={multiple} onDropAccepted={handleAcceptedFiles} onDropRejected={handleRejectedFiles} diff --git a/packages/p2p/src/components/modal-manager/modals/order-details-confirm-modal/order-details-confirm-modal.tsx b/packages/p2p/src/components/modal-manager/modals/order-details-confirm-modal/order-details-confirm-modal.tsx index 660bd68c6f34..af3d0d9e8c07 100644 --- a/packages/p2p/src/components/modal-manager/modals/order-details-confirm-modal/order-details-confirm-modal.tsx +++ b/packages/p2p/src/components/modal-manager/modals/order-details-confirm-modal/order-details-confirm-modal.tsx @@ -5,7 +5,7 @@ import { formatMoney, TFile } from '@deriv/shared'; import { observer, useStore } from '@deriv/stores'; import { localize } from '@deriv/translations'; import FileUploaderComponent from 'Components/file-uploader-component'; -//Todo: change the below line when changing the base branch +//TODO: update the below line before merging to feature branch "p2p-modal-test" branch import FormError from 'Components/form/error.jsx'; import { Localize } from 'Components/i18next'; import { useModalManagerContext } from 'Components/modal-manager/modal-manager-context'; @@ -20,9 +20,8 @@ type TDocumentFile = { const OrderDetailsConfirmModal = () => { const { hideModal, is_modal_open } = useModalManagerContext(); const { order_details_store, order_store, sendbird_store } = useStores(); - const { - ui: { is_mobile }, - } = useStore(); + const { ui } = useStore(); + const { is_mobile } = ui; const { error_message } = order_details_store; const { confirmOrderRequest, order_information } = order_store; const { sendFile } = sendbird_store; diff --git a/packages/p2p/src/stores/sendbird-store.ts b/packages/p2p/src/stores/sendbird-store.ts index 6f906a4aa3b2..94b1068d5053 100644 --- a/packages/p2p/src/stores/sendbird-store.ts +++ b/packages/p2p/src/stores/sendbird-store.ts @@ -49,6 +49,7 @@ export default class SendbirdStore extends BaseStore { addChannelMessage: action.bound, createChatForNewOrder: action.bound, replaceChannelMessage: action.bound, + sendFile: action.bound, setActiveChatChannel: action.bound, setChatChannelUrl: action.bound, setChatInfo: action.bound, From 845f5a56298fa2d2cfb2d070b4fbdfa95d74b48c Mon Sep 17 00:00:00 2001 From: Nada Date: Fri, 8 Sep 2023 15:27:40 +0400 Subject: [PATCH 4/4] fix: import reorder --- .../order-details-confirm-modal.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/p2p/src/components/modal-manager/modals/order-details-confirm-modal/order-details-confirm-modal.tsx b/packages/p2p/src/components/modal-manager/modals/order-details-confirm-modal/order-details-confirm-modal.tsx index af3d0d9e8c07..a127a9ff7bd8 100644 --- a/packages/p2p/src/components/modal-manager/modals/order-details-confirm-modal/order-details-confirm-modal.tsx +++ b/packages/p2p/src/components/modal-manager/modals/order-details-confirm-modal/order-details-confirm-modal.tsx @@ -1,14 +1,14 @@ import React from 'react'; -import { useStores } from 'Stores'; import { Button, Modal, Text } from '@deriv/components'; import { formatMoney, TFile } from '@deriv/shared'; import { observer, useStore } from '@deriv/stores'; import { localize } from '@deriv/translations'; -import FileUploaderComponent from 'Components/file-uploader-component'; //TODO: update the below line before merging to feature branch "p2p-modal-test" branch import FormError from 'Components/form/error.jsx'; +import FileUploaderComponent from 'Components/file-uploader-component'; import { Localize } from 'Components/i18next'; import { useModalManagerContext } from 'Components/modal-manager/modal-manager-context'; +import { useStores } from 'Stores'; import { accepted_file_types, max_pot_file_size } from 'Utils/file-uploader'; import { removeTrailingZeros, roundOffDecimal, setDecimalPlaces } from 'Utils/format-value';