diff --git a/packages/ripple-ui-forms/src/components/RplFormFile/RplFormFile.css b/packages/ripple-ui-forms/src/components/RplFormFile/RplFormFile.css index 15bf2bd56..7176fb217 100644 --- a/packages/ripple-ui-forms/src/components/RplFormFile/RplFormFile.css +++ b/packages/ripple-ui-forms/src/components/RplFormFile/RplFormFile.css @@ -175,7 +175,7 @@ } .rpl-form-file__item--pending .rpl-form-file__icon-status { - animation: rpl-file-spin calc(var(--rpl-motion-speed-10) * 2) linear infinite; + animation: rpl-file-spin calc(var(--rpl-motion-speed-10) * 3) linear infinite; } .rpl-form-file__item-error { diff --git a/packages/ripple-ui-forms/src/components/RplFormFile/RplFormFile.cy.ts b/packages/ripple-ui-forms/src/components/RplFormFile/RplFormFile.cy.ts index a958a950e..62ba6da74 100644 --- a/packages/ripple-ui-forms/src/components/RplFormFile/RplFormFile.cy.ts +++ b/packages/ripple-ui-forms/src/components/RplFormFile/RplFormFile.cy.ts @@ -56,8 +56,8 @@ const upload = (options?: { }) => { let { ref = null, status = 'success', error = null } = options || {} - return cy.stub().callsFake((id: string, file: File) => { - const _ref = ref ? `${ref}-${file.name.toLowerCase()}` : id + return cy.stub().callsFake((file: File, options: { id: string }) => { + const _ref = ref ? `${ref}-${file.name.toLowerCase()}` : options.id return Promise.resolve({ ref: _ref, status, error }) }) @@ -125,7 +125,7 @@ describe('RplFormFile', () => { 'accept', 'image/jpeg,image/png,.jpg,.png' ) - cy.get(_.requirements).should('contain', 'Accepted file types: JPG, PNG') + cy.get(_.requirements).should('contain', 'Accepted file types: JPG or PNG') select([file('Test 1.png', 'image/png'), file('Test 2.txt', 'text/plain')]) @@ -137,10 +137,7 @@ describe('RplFormFile', () => { cy.get(_.items) .eq(1) - .should( - 'contain', - 'File is not in a supported format, please remove this file and select a JPG, PNG' - ) + .should('contain', 'The selected file must be a JPG or PNG') .should('have.attr', 'data-status', 'invalid') expect(handleUpload).to.not.have.been.calledOnce @@ -158,7 +155,7 @@ describe('RplFormFile', () => { cy.get(_.input).should('have.attr', 'accept', '.jpg,.png,.gif') cy.get(_.requirements).should( 'contain', - 'Accepted file types: JPG, PNG, GIF' + 'Accepted file types: JPG, PNG or GIF' ) select([ @@ -178,10 +175,7 @@ describe('RplFormFile', () => { .should('have.length', 2) .should('contain', 'Test 3.txt') .should('contain', 'Test 4.webp') - .should( - 'contain', - 'File is not in a supported format, please remove this file and select a JPG, PNG, GIF' - ) + .should('contain', 'The selected file must be a JPG, PNG or GIF') expect(handleUpload).to.not.have.been.calledTwice }) @@ -258,12 +252,7 @@ describe('RplFormFile', () => { select(file('Test.txt')) - cy.get(_.items) - .eq(0) - .should( - 'contain', - 'File is not in a supported format, please remove this file and select a PNG' - ) + cy.get(_.items).eq(0).should('contain', 'The selected file must be a PNG') cy.then(() => expect(handleUpload).not.to.have.been.called) }) @@ -311,7 +300,7 @@ describe('RplFormFile', () => { ) ) - cy.get(_.items).eq(0).should('contain', 'File is too large') + cy.get(_.items).eq(0).should('contain', 'The selected file must be smaller') cy.then(() => expect(handleUpload).not.to.have.been.called) }) diff --git a/packages/ripple-ui-forms/src/components/RplFormFile/RplFormFile.stories.ts b/packages/ripple-ui-forms/src/components/RplFormFile/RplFormFile.stories.ts index 636d2aa81..436c7f87e 100644 --- a/packages/ripple-ui-forms/src/components/RplFormFile/RplFormFile.stories.ts +++ b/packages/ripple-ui-forms/src/components/RplFormFile/RplFormFile.stories.ts @@ -12,8 +12,8 @@ const createMockUploadHandler = ( status: string = 'success' ) => { return ( - id: string, file: File, + options: { id: string }, onUpdate: (complete: number) => void ): Promise<{ ref?: string; status: string; error?: string }> => { const randomSpeed = Math.random() * 15 + 1 @@ -30,10 +30,10 @@ const createMockUploadHandler = ( const statuses = { error: { status: 'error', - error: 'Failed to upload file to server' + error: 'The selected file could not be uploaded – try again' }, success: { - ref: id + '_success', + ref: `${options.id}_success`, status: 'success' } } diff --git a/packages/ripple-ui-forms/src/components/RplFormFile/RplFormFile.vue b/packages/ripple-ui-forms/src/components/RplFormFile/RplFormFile.vue index 3224a7099..973c33071 100644 --- a/packages/ripple-ui-forms/src/components/RplFormFile/RplFormFile.vue +++ b/packages/ripple-ui-forms/src/components/RplFormFile/RplFormFile.vue @@ -49,8 +49,8 @@ interface Props { placeholderOver?: string onChange?: (value: FileItem[]) => void handleUpload?: ( - id: string, file: File, + options: { id: string; fieldId: string; formId: string }, onUpdate: (complete: number | boolean) => void ) => Promise<{ id: string; status: FileStatus; error?: string }> } @@ -165,9 +165,14 @@ const acceptedTypes = computed(() => { const acceptedExtensions = computed(() => { const { extensions } = parsedAllowedTypes.value - return extensions.length - ? extensions.map((ext) => ext.toUpperCase()).join(', ') - : null + if (!extensions.length) { + return null + } + + return new Intl.ListFormat('en-AU', { + style: 'long', + type: 'disjunction' + }).format(extensions.map((ext) => ext.toUpperCase())) }) // Helpers @@ -232,11 +237,11 @@ const isValidType = (file: File): boolean => { const validateFile = (file: File) => { if (!isValidType(file)) { - return `File is not in a supported format, please remove this file and select a ${acceptedExtensions.value}` + return `The selected file must be a ${acceptedExtensions.value}` } if (props.maxSize && getFileSize(file.size) > props.maxSize) { - return `File is too large, please remove this file and select a file less than ${props.maxSize} MB` + return `The selected file must be smaller than ${props.maxSize} MB` } return null @@ -250,12 +255,18 @@ const uploadFile = async (item: FileItem): Promise => { return { id: item.id, status: FileStatus.error, - error: 'Sorry file cannot be uploaded at this time.' + error: 'Sorry file cannot be uploaded at this time' } } try { - return await props.handleUpload(item.id, item.file, (complete: number) => { + const options = { + id: item.id, + formId: form?.id, + fieldId: props.id + } + + return await props.handleUpload(item.file, options, (complete: number) => { const index = internalFiles.value.findIndex((f) => f.id === item.id) if (index !== -1) { @@ -266,7 +277,7 @@ const uploadFile = async (item: FileItem): Promise => { return { id: item.id, status: FileStatus.error, - error: 'Error uploading file' + error: 'The selected file could not be uploaded – try again' } } } @@ -550,7 +561,7 @@ watch(