Skip to content

Commit

Permalink
Allow file upload to select same file after error (#4022)
Browse files Browse the repository at this point in the history
* Allow file upload to select same file after error

It fixes an error that occur when a user upload a file and have some connection or general error, if select the same file again it does not change.

* Update changelog entry

* Update workaround comment to include issue link

* Use correct dependency location
  • Loading branch information
alefesouza authored Mar 24, 2022
1 parent 3a6976a commit 4619c31
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 10 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: fix

Empty file input to allow the user to select the same file again if there's an error.
52 changes: 42 additions & 10 deletions client/components/file-upload/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,29 @@ export const FileUploadControl = ( {
/>
);

const handleButtonClick = (
event: React.MouseEvent< HTMLButtonElement >,
openFileDialog: () => void
) => {
// Get file input next to the button element and clear it's value,
// allowing to select the same file again in case of
// connection or general error or just need to select it again.
// This workaround is useful until we update @wordpress/components to a
// version the supports this: https://github.com/WordPress/gutenberg/issues/39267
const fileInput:
| HTMLInputElement
| null
| undefined = ( event.target as HTMLButtonElement )
.closest( '.components-form-file-upload' )
?.querySelector( 'input[type="file"]' );

if ( fileInput ) {
fileInput.value = '';
}

openFileDialog();
};

return (
<BaseControl
id={ `form-file-upload-base-control-${ field.key }` }
Expand All @@ -56,13 +79,6 @@ export const FileUploadControl = ( {
</DropZoneProvider>
<div className="file-upload">
<FormFileUpload
id={ `form-file-upload-${ field.key }` }
className={ isDone && ! hasError ? 'is-success' : '' }
isSecondary
isDestructive={ hasError }
isBusy={ isLoading }
disabled={ disabled || isLoading }
icon={ getIcon }
accept={ accept }
onChange={ (
event: React.ChangeEvent< HTMLInputElement >
Expand All @@ -72,9 +88,25 @@ export const FileUploadControl = ( {
( event.target.files || new FileList() )[ 0 ]
);
} }
>
{ __( 'Upload file', 'woocommerce-payments' ) }
</FormFileUpload>
render={ ( { openFileDialog } ) => (
<Button
id={ `form-file-upload-${ field.key }` }
className={
isDone && ! hasError ? 'is-success' : ''
}
isSecondary
isDestructive={ hasError }
isBusy={ isLoading }
disabled={ disabled || isLoading }
icon={ getIcon }
onClick={ (
event: React.MouseEvent< HTMLButtonElement >
) => handleButtonClick( event, openFileDialog ) }
>
{ __( 'Upload file', 'woocommerce-payments' ) }
</Button>
) }
></FormFileUpload>

{ hasError ? (
<FileUploadError error={ error } />
Expand Down
24 changes: 24 additions & 0 deletions client/components/file-upload/test/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/
import * as React from 'react';
import { render, fireEvent } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

/**
* Internal dependencies
Expand Down Expand Up @@ -87,6 +88,29 @@ describe( 'FileUploadControl', () => {
);
} );

test( 'triggers onFileChange two times when selecting the same file again', async () => {
const { container: control } = render(
<FileUploadControl { ...props } />
);

const file = new File( [ 'hello' ], 'hello.png', {
type: 'image/png',
} );

// Note: FormFileUpload does not associate file input with label so workaround is required to select it.
const input = control.querySelector( 'input[type="file"]' );
if ( input !== null ) {
await userEvent.upload( input, file );
await userEvent.upload( input, file );
}

expect( props.onFileChange ).toHaveBeenNthCalledWith(
2,
field.key,
file
);
} );

test( 'triggers onFileRemove', () => {
props.fileName = 'file.pdf';
props.isDone = true;
Expand Down

0 comments on commit 4619c31

Please sign in to comment.