feat(upload): allow adding more files before starting (#293)

pull/295/head
Alex Kern 5 months ago committed by GitHub
parent dc56fba614
commit ce3a27b69c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -16,6 +16,7 @@ import { getFileName } from '../fs'
import TitleText from '../components/TitleText' import TitleText from '../components/TitleText'
import { pluralize } from '../utils/pluralize' import { pluralize } from '../utils/pluralize'
import TermsAcceptance from '../components/TermsAcceptance' import TermsAcceptance from '../components/TermsAcceptance'
import AddFilesButton from '../components/AddFilesButton'
function PageWrapper({ children }: { children: React.ReactNode }): JSX.Element { function PageWrapper({ children }: { children: React.ReactNode }): JSX.Element {
return ( return (
@ -59,6 +60,7 @@ function ConfirmUploadState({
onCancel, onCancel,
onStart, onStart,
onRemoveFile, onRemoveFile,
onAddFiles,
}: { }: {
uploadedFiles: UploadedFile[] uploadedFiles: UploadedFile[]
password: string password: string
@ -66,6 +68,7 @@ function ConfirmUploadState({
onCancel: () => void onCancel: () => void
onStart: () => void onStart: () => void
onRemoveFile: (index: number) => void onRemoveFile: (index: number) => void
onAddFiles: (files: UploadedFile[]) => void
}): JSX.Element { }): JSX.Element {
const fileListData = useUploaderFileListData(uploadedFiles) const fileListData = useUploaderFileListData(uploadedFiles)
return ( return (
@ -75,6 +78,9 @@ function ConfirmUploadState({
{pluralize(uploadedFiles.length, 'file', 'files')}. {pluralize(uploadedFiles.length, 'file', 'files')}.
</TitleText> </TitleText>
<UploadFileList files={fileListData} onRemove={onRemoveFile} /> <UploadFileList files={fileListData} onRemove={onRemoveFile} />
<div className="flex justify-end w-full">
<AddFilesButton onAdd={onAddFiles} />
</div>
<PasswordField value={password} onChange={onChangePassword} /> <PasswordField value={password} onChange={onChangePassword} />
<div className="flex space-x-4"> <div className="flex space-x-4">
<CancelButton onClick={onCancel} /> <CancelButton onClick={onCancel} />
@ -137,6 +143,10 @@ export default function UploadPage(): JSX.Element {
setUploadedFiles((fs) => fs.filter((_, i) => i !== index)) setUploadedFiles((fs) => fs.filter((_, i) => i !== index))
}, []) }, [])
const handleAddFiles = useCallback((files: UploadedFile[]) => {
setUploadedFiles((fs) => [...fs, ...files])
}, [])
if (!uploadedFiles.length) { if (!uploadedFiles.length) {
return <InitialState onDrop={handleDrop} /> return <InitialState onDrop={handleDrop} />
} }
@ -150,6 +160,7 @@ export default function UploadPage(): JSX.Element {
onCancel={handleCancel} onCancel={handleCancel}
onStart={handleStart} onStart={handleStart}
onRemoveFile={handleRemoveFile} onRemoveFile={handleRemoveFile}
onAddFiles={handleAddFiles}
/> />
) )
} }

@ -0,0 +1,45 @@
import React, { useRef, useCallback, JSX } from 'react'
import { UploadedFile } from '../types'
export default function AddFilesButton({
onAdd,
}: {
onAdd: (files: UploadedFile[]) => void
}): JSX.Element {
const fileInputRef = useRef<HTMLInputElement>(null)
const handleClick = useCallback(() => {
fileInputRef.current?.click()
}, [])
const handleChange = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => {
if (e.target.files) {
onAdd(Array.from(e.target.files) as UploadedFile[])
e.target.value = ''
}
},
[onAdd],
)
return (
<>
<input
id="add-files-input"
type="file"
ref={fileInputRef}
className="hidden"
multiple
onChange={handleChange}
/>
<button
id="add-files-button"
type="button"
onClick={handleClick}
className="block cursor-pointer relative py-3 px-6 text-base font-bold text-stone-700 dark:text-stone-200 bg-white dark:bg-stone-800 border-2 border-stone-700 dark:border-stone-700 rounded-lg transition-all duration-300 ease-in-out outline-none hover:shadow-md active:shadow-inner focus:shadow-outline"
>
Add more files
</button>
</>
)
}

@ -0,0 +1,17 @@
/// <reference types="@playwright/test" />
import { test, expect } from '@playwright/test'
import { createTestFile, uploadFile, addFile } from './helpers'
test('user can add more files before starting upload', async ({ page }) => {
const file1 = createTestFile('first.txt', 'A')
const file2 = createTestFile('second.txt', 'B')
await uploadFile(page, file1)
// Add another file using the add files button
await addFile(page, file2)
// Both files should be listed
await expect(page.getByText(file1.name)).toBeVisible()
await expect(page.getByText(file2.name)).toBeVisible()
})

@ -66,6 +66,33 @@ export async function uploadFile(
) )
} }
export async function addFile(
page: Page,
testFile: TestFile,
): Promise<void> {
await page.evaluate(
({ testContent, testFileName }) => {
const input = document.querySelector(
'#add-files-input',
) as HTMLInputElement
if (input) {
const file = new File([testContent], testFileName, {
type: 'text/plain',
})
const dataTransfer = new DataTransfer()
dataTransfer.items.add(file)
input.files = dataTransfer.files
const event = new Event('change', { bubbles: true })
input.dispatchEvent(event)
}
},
{ testContent: testFile.content, testFileName: testFile.name },
)
await expect(page.getByText(testFile.name)).toBeVisible({ timeout: 5000 })
}
export async function startUpload(page: Page): Promise<string> { export async function startUpload(page: Page): Promise<string> {
// Start sharing // Start sharing
await page.locator('#start-button').click() await page.locator('#start-button').click()

Loading…
Cancel
Save