VirtualDungeon/app/src/components/view/AssetUploader.tsx

117 lines
3.6 KiB
TypeScript

import * as Preact from 'preact';
import { useState, useEffect } from 'preact/hooks';
import './AssetUploader.sass';
import { Button } from '../input/Input';
import AssetUploadForm from './AssetUploadForm';
import { UploadData } from '../../../../common/DBStructs';
/**
* Handles uploading assets.
*/
export default function AssetUploader() {
const [ files, setFiles ] = useState<File[]>([]);
const [ filePreview, setFilePreview ] = useState<string>('');
const [ uploadStates, setUploadStates ] = useState<{ success: number; fail: number }>({ success: 0, fail: 0 });
const [ uploading, setUploading ] = useState<boolean>(false);
useEffect(() => {
if (files.length < 1) return;
let set = true;
setFilePreview('');
const reader = new FileReader();
reader.readAsDataURL(files[0]);
reader.onload = e => {
if (set) setFilePreview((e.target as any).result);
};
return () => set = false;
}, [ files ]);
const handleReset = () => {
setFiles([]);
setUploadStates({ success: 0, fail: 0 });
};
const handleFileSelect = (evt: any) => {
const newFiles = (Array.from((evt.target as HTMLInputElement).files ?? []) as File[])
.filter(f => f.type === 'image/png' || f.name.endsWith('.png'));
setFiles(newFiles);
};
const handleCancel = () => {
const newFiles = [ ...files ];
newFiles.splice(0, 1);
setFiles(newFiles);
setUploadStates(s => ({ ...s, fail: s.fail + 1 }));
};
const handleSubmit = async (data: UploadData) => {
if (uploading) return;
setUploading(true);
let formData = new FormData();
formData.append('file', files[0]);
formData.append('data', JSON.stringify(data));
const res = await fetch('/data/asset/upload',
{ method: 'POST', cache: 'no-cache', body: formData });
if (res.status === 200) {
setUploadStates(s => ({ ...s, success: s.success + 1 }));
}
else {
console.error(await res.text());
setUploadStates(s => ({ ...s, fail: s.fail + 1 }));
}
const newFiles = [ ...files ];
newFiles.splice(0, 1);
setFiles(newFiles);
setUploading(false);
};
return (
<div class='AssetUploader'>
{files.length === 0 && <Preact.Fragment>
{uploadStates.success + uploadStates.fail === 0 && <Preact.Fragment>
<div class='AssetUploader-UploadWrap'>
<input type='file' id='fileUpload' class='AssetUploader-Upload' accept='.png' multiple onChange={handleFileSelect} />
<label for='fileUpload' class='AssetUploader-UploadTitle'>Click or drag files here to upload!<br />
<small>(Tip: You can select multiple assets at once to batch-upload)</small></label>
</div>
<div class='AssetUploader-ActionBar'>
<Button label='Back to Assets' altLabel altColor to='../' />
</div>
</Preact.Fragment>}
{uploadStates.success + uploadStates.fail > 0 && <Preact.Fragment>
<div class='AssetUploader-ResultsCard'>
<p class='AssetUploader-ResultsStatus'>Uploaded {uploadStates.success} asset{uploadStates.success !== 1 ? 's' : ''}.</p>
<div class='AssetUploader-ActionBar'>
<Button label='Upload More' altLabel onClick={handleReset} />
<Button label='Back' altLabel altColor to='../' />
</div>
</div>
</Preact.Fragment>}
</Preact.Fragment>}
{/* {files.length > 1 && <div class='AssetUploader-Progress'>
<div class='AssetUploader-ProgressBar' style={{ width: current / files.length * 100 + '%'}} />
<p class='AssetUploader-ProgressText'>{`Asset ${current + 1} / ${files.length}`}</p>
</div>}*/}
{files.length !== 0 && <div>
<AssetUploadForm file={files[0]} preview={filePreview}
uploading={uploading} onCancel={handleCancel} onSubmit={handleSubmit}/>
</div>}
</div>
);
}