You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
filepizza/src/app/page.tsx

176 lines
4.7 KiB
TypeScript

'use client'
import React, { JSX, useCallback, useState } from 'react'
import WebRTCPeerProvider from '../components/WebRTCProvider'
import DropZone from '../components/DropZone'
import UploadFileList from '../components/UploadFileList'
import Uploader from '../components/Uploader'
import PasswordField from '../components/PasswordField'
import StartButton from '../components/StartButton'
import { UploadedFile } from '../types'
import Spinner from '../components/Spinner'
import Wordmark from '../components/Wordmark'
import CancelButton from '../components/CancelButton'
import { useMemo } from 'react'
import { getFileName } from '../fs'
import TitleText from '../components/TitleText'
import { pluralize } from '../utils/pluralize'
import TermsAcceptance from '../components/TermsAcceptance'
import AddFilesButton from '../components/AddFilesButton'
function PageWrapper({ children }: { children: React.ReactNode }): JSX.Element {
return (
<div className="flex flex-col items-center space-y-5 py-10 max-w-2xl mx-auto px-4">
<Spinner direction="up" />
<Wordmark />
{children}
</div>
)
}
function InitialState({
onDrop,
}: {
onDrop: (files: UploadedFile[]) => void
}): JSX.Element {
return (
<PageWrapper>
<div className="flex flex-col items-center space-y-1 max-w-md">
<TitleText>Peer-to-peer file transfers in your browser.</TitleText>
</div>
<DropZone onDrop={onDrop} />
<TermsAcceptance />
</PageWrapper>
)
}
function useUploaderFileListData(uploadedFiles: UploadedFile[]) {
return useMemo(() => {
return uploadedFiles.map((item) => ({
fileName: getFileName(item),
type: item.type,
}))
}, [uploadedFiles])
}
function ConfirmUploadState({
uploadedFiles,
password,
onChangePassword,
onCancel,
onStart,
onRemoveFile,
onAddFiles,
}: {
uploadedFiles: UploadedFile[]
password: string
onChangePassword: (pw: string) => void
onCancel: () => void
onStart: () => void
onRemoveFile: (index: number) => void
onAddFiles: (files: UploadedFile[]) => void
}): JSX.Element {
const fileListData = useUploaderFileListData(uploadedFiles)
return (
<PageWrapper>
<TitleText>
You are about to start uploading{' '}
{pluralize(uploadedFiles.length, 'file', 'files')}.
</TitleText>
<UploadFileList files={fileListData} onRemove={onRemoveFile} />
<div className="flex justify-end w-full">
<AddFilesButton onAdd={onAddFiles} />
</div>
<PasswordField value={password} onChange={onChangePassword} />
<div className="flex space-x-4">
<CancelButton onClick={onCancel} />
<StartButton onClick={onStart} />
</div>
</PageWrapper>
)
}
function UploadingState({
uploadedFiles,
password,
onStop,
}: {
uploadedFiles: UploadedFile[]
password: string
onStop: () => void
}): JSX.Element {
const fileListData = useUploaderFileListData(uploadedFiles)
return (
<PageWrapper>
<TitleText>
You are uploading {pluralize(uploadedFiles.length, 'file', 'files')}.
</TitleText>
<UploadFileList files={fileListData} />
<WebRTCPeerProvider>
<Uploader files={uploadedFiles} password={password} onStop={onStop} />
</WebRTCPeerProvider>
</PageWrapper>
)
}
export default function UploadPage(): JSX.Element {
const [uploadedFiles, setUploadedFiles] = useState<UploadedFile[]>([])
const [password, setPassword] = useState('')
const [uploading, setUploading] = useState(false)
const handleDrop = useCallback((files: UploadedFile[]): void => {
setUploadedFiles(files)
}, [])
const handleChangePassword = useCallback((pw: string) => {
setPassword(pw)
}, [])
const handleStart = useCallback(() => {
setUploading(true)
}, [])
const handleStop = useCallback(() => {
setUploading(false)
}, [])
const handleCancel = useCallback(() => {
setUploadedFiles([])
setUploading(false)
}, [])
const handleRemoveFile = useCallback((index: number) => {
setUploadedFiles((fs) => fs.filter((_, i) => i !== index))
}, [])
const handleAddFiles = useCallback((files: UploadedFile[]) => {
setUploadedFiles((fs) => [...fs, ...files])
}, [])
if (!uploadedFiles.length) {
return <InitialState onDrop={handleDrop} />
}
if (!uploading) {
return (
<ConfirmUploadState
uploadedFiles={uploadedFiles}
password={password}
onChangePassword={handleChangePassword}
onCancel={handleCancel}
onStart={handleStart}
onRemoveFile={handleRemoveFile}
onAddFiles={handleAddFiles}
/>
)
}
return (
<UploadingState
uploadedFiles={uploadedFiles}
password={password}
onStop={handleStop}
/>
)
}