Skip to content

Commit

Permalink
fix(Forms): add support for sessionStorageId in Field.Upload (#4424)
Browse files Browse the repository at this point in the history
In this PR #4339 we did not render the stored files.
This time, we do support rendering the file names stored in the session
storage. The test dedicated to session storage got aligned.

---------

Co-authored-by: Anders <[email protected]>
  • Loading branch information
tujoworker and langz authored Dec 26, 2024
1 parent 74423d6 commit a8dfc52
Show file tree
Hide file tree
Showing 9 changed files with 222 additions and 26 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { Flex } from '@dnb/eufemia/src'
import ComponentBox from '../../../../../../../shared/tags/ComponentBox'
import { Field, Form, Tools } from '@dnb/eufemia/src/extensions/forms'
import {
Field,
Form,
Tools,
Value,
} from '@dnb/eufemia/src/extensions/forms'
import { createMockFile } from '../../../../../../../docs/uilib/components/upload/Examples'
import useUpload from '@dnb/eufemia/src/components/upload/useUpload'
import { UploadValue } from '@dnb/eufemia/src/extensions/forms/Field/Upload'
Expand Down Expand Up @@ -252,3 +257,27 @@ export const WithAsyncOnFileClick = () => {
</ComponentBox>
)
}

export function SessionStorage() {
return (
<ComponentBox>
<Form.Handler sessionStorageId="documents">
<Flex.Stack>
<Form.Card>
<Field.Upload path="/documents" />
<Value.Upload
path="/documents"
label="Uploaded files"
placeholder="No files uploaded."
variant="ol"
showEmpty
/>
</Form.Card>

<Form.SubmitButton />
<Tools.Log />
</Flex.Stack>
</Form.Handler>
</ComponentBox>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ import * as Examples from './Examples'

<Examples.Customized />

### Session storage support

The `sessionStorageId` property can be used to store the files in the session storage so they persist between page reloads.

<Examples.SessionStorage />

### With asynchronous file handler

The `fileHandler` property supports an asynchronous function, and can be used for handling/validating files asynchronously, like to upload files to a virus checker and display errors based on the outcome:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,3 +160,9 @@ function MyForm() {
)
}
```

### Persist files in session storage

The `sessionStorageId` property can be used to store the files in the session storage so they persist between page reloads.

But the persisted files only render the file name, and not the file itself. The file blob will be lost during the serialization process.
39 changes: 33 additions & 6 deletions packages/dnb-eufemia/src/extensions/forms/Field/Upload/Upload.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,22 @@ function UploadComponent(props: Props) {
[formsTr.errorRequired]
)

const fromInput = useCallback((value: UploadValue) => {
value.forEach((item, index) => {
value[index] = item

// Store the name in the value, to support session storage (serialization)
value[index]['name'] = item['name'] || item.file?.name
})

return value
}, [])

const preparedProps = {
errorMessages,
validateRequired,
fromInput,
toInput: transformFiles,
...props,
}

Expand Down Expand Up @@ -128,11 +141,7 @@ function UploadComponent(props: Props) {
}, [files])

useEffect(() => {
// Files stored in session storage will not have a property (due to serialization).
const hasInvalidFiles = value?.some(({ file }) => !file?.name)
if (!hasInvalidFiles) {
setFiles(value)
}
setFiles(value)
}, [setFiles, value])

const handleChangeAsync = useCallback(
Expand Down Expand Up @@ -173,7 +182,7 @@ function UploadComponent(props: Props) {
handleChange(existingFiles)
}
},
[files, setFiles, fileHandler, handleChange]
[setFiles, fileHandler, handleChange]
)

const changeHandler = useCallback(
Expand Down Expand Up @@ -241,3 +250,21 @@ function UploadComponent(props: Props) {
export default UploadComponent

UploadComponent._supportsSpacingProps = true

export function transformFiles(value: UploadValue) {
if (Array.isArray(value)) {
if (value.length === 0) {
return undefined
}

value.map((item) => {
if (item?.file && !(item.file instanceof File)) {
// To support session storage, we recreated the file blob.
item['file'] = new File([], item['name'])
}
return item
})
}

return value
}
Original file line number Diff line number Diff line change
Expand Up @@ -207,11 +207,13 @@ describe('Field.Upload', () => {
file: file1,
id: expect.any(String),
exists: expect.any(Boolean),
name: 'fileName-1.png',
},
{
file: file2,
id: expect.any(String),
exists: expect.any(Boolean),
name: 'fileName-2.png',
},
],
},
Expand Down Expand Up @@ -256,6 +258,7 @@ describe('Field.Upload', () => {
file: file1,
exists: false,
id: expect.anything(),
name: 'fileName-1.png',
},
{
errorMessage: nbShared.Upload.errorLargeFile.replace(
Expand All @@ -265,6 +268,7 @@ describe('Field.Upload', () => {
file: file2,
exists: false,
id: expect.anything(),
name: 'fileName-2.png',
},
],
},
Expand All @@ -276,6 +280,7 @@ describe('Field.Upload', () => {
file: file1,
exists: false,
id: expect.anything(),
name: 'fileName-1.png',
},
{
errorMessage: nbShared.Upload.errorLargeFile.replace(
Expand All @@ -285,6 +290,7 @@ describe('Field.Upload', () => {
file: file2,
exists: false,
id: expect.anything(),
name: 'fileName-2.png',
},
])

Expand All @@ -310,6 +316,7 @@ describe('Field.Upload', () => {
file: file1,
exists: false,
id: expect.anything(),
name: 'fileName-1.png',
},
],
},
Expand Down Expand Up @@ -353,6 +360,7 @@ describe('Field.Upload', () => {
exists: false,
file: file1,
id: expect.any(String),
name: 'fileName-1.png',
}),
],
},
Expand Down Expand Up @@ -399,6 +407,7 @@ describe('Field.Upload', () => {
exists: false,
file: file1,
id: expect.any(String),
name: 'fileName-1.png',
}),
],
},
Expand Down Expand Up @@ -468,6 +477,7 @@ describe('Field.Upload', () => {
file: file1,
exists: false,
id: expect.anything(),
name: 'fileName-1.png',
},
],
},
Expand Down Expand Up @@ -734,6 +744,7 @@ describe('Field.Upload', () => {
file: file1,
exists: false,
id: expect.anything(),
name: 'fileName-1.png',
},
],
},
Expand Down Expand Up @@ -1475,7 +1486,7 @@ describe('Field.Upload', () => {
})
})

it('should not set files from session storage if they are invalid', async () => {
it('should recreate files from session storage', async () => {
const file = createMockFile('fileName.png', 100, 'image/png')

const { unmount } = render(
Expand Down Expand Up @@ -1517,15 +1528,16 @@ describe('Field.Upload', () => {
expect(dataContext.internalDataRef.current.myFiles).toEqual([
{
exists: false,
file: {},
file: new File([], 'fileName.png'),
id: expect.any(String),
name: 'fileName.png',
},
])
const [title] = Array.from(document.querySelectorAll('p'))
expect(title).toHaveTextContent(nbShared.Upload.title)
expect(
document.querySelectorAll('.dnb-upload__file-cell').length
).toBe(0)
).toBe(1)
})

describe('transformIn and transformOut', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Field, Form, Tools } from '../../..'
import { Field, Form, Tools, Value } from '../../..'
import { Flex } from '../../../../../components'
import { UploadFileNative } from '../../../../../components/Upload'
import { createRequest } from '../../../Form/Handler/stories/FormHandler.stories'
Expand Down Expand Up @@ -216,8 +216,6 @@ export function TransformInAndOut() {
>
<Flex.Stack>
<Field.Upload
label="Label"
placeholder="This is a Field"
path="/documents"
transformIn={transformIn}
transformOut={transformOut}
Expand All @@ -233,3 +231,25 @@ export function TransformInAndOut() {
</Form.Handler>
)
}

export function SessionStorage() {
return (
<Form.Handler sessionStorageId="documents">
<Flex.Stack>
<Form.Card>
<Field.Upload path="/documents" />
<Value.Upload
path="/documents"
label="Uploaded files"
placeholder="No files uploaded."
variant="ol"
showEmpty
/>
</Form.Card>

<Form.SubmitButton />
<Tools.Log />
</Flex.Stack>
</Form.Handler>
)
}
23 changes: 19 additions & 4 deletions packages/dnb-eufemia/src/extensions/forms/Value/Upload/Upload.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ import ListFormat, {
import type { UploadFile } from '../../../../components/upload/types'
import { getFileIcon } from '../../../../components/upload/UploadFileListCell'
import { BYTES_IN_A_MEGA_BYTE } from '../../../../components/upload/UploadVerify'
import { Props as FieldUploadProps } from '../../Field/Upload/Upload'
import {
Props as FieldUploadProps,
transformFiles,
} from '../../Field/Upload/Upload'
import { format } from '../../../../components/number-format/NumberUtils'
import { UploadFileLink } from '../../../../components/upload/UploadFileListLink'
import { isAsync } from '../../../../shared/helpers/isAsync'
Expand All @@ -21,8 +24,12 @@ export type Props = ValueProps<Array<UploadFile>> &
}

function Upload(props: Props) {
const preparedProps = {
fromExternal: transformFiles,
...props,
}

const {
path,
value,
format,
className,
Expand All @@ -32,7 +39,7 @@ function Upload(props: Props) {
displaySize = false,
onFileClick,
...rest
} = useValueProps(props)
} = useValueProps(preparedProps)

const list = useMemo(() => {
const valueToUse =
Expand Down Expand Up @@ -62,7 +69,15 @@ function Upload(props: Props) {
/>
)
}
}, [path, value, variant, listType])
}, [
value,
download,
displaySize,
onFileClick,
format,
variant,
listType,
])

return (
<ValueBlock
Expand Down
Loading

0 comments on commit a8dfc52

Please sign in to comment.