fix(striker-ui): split file upload and edit; make file info reusable

main
Tsu-ba-me 3 years ago
parent 6b69213bc3
commit d46ec7b02f
  1. 101
      striker-ui/components/Files/FileInfo.tsx
  2. 96
      striker-ui/components/Files/FileUploadInfo.tsx
  3. 14
      striker-ui/components/Files/Files.tsx
  4. 11
      striker-ui/lib/consts/UPLOAD_FILE_TYPES.ts
  5. 1
      striker-ui/types/UploadFileTypes.d.ts

@ -1,96 +1,63 @@
import { useEffect, useRef } from 'react';
import {
Box,
Button,
Checkbox,
FormControl,
FormControlLabel,
Input,
InputLabel,
MenuItem,
Select,
TextField,
} from '@mui/material';
import { BodyText } from '../Text';
import { UPLOAD_FILE_TYPES_ARRAY } from '../../lib/consts/UPLOAD_FILE_TYPES';
type FileInfoProps = {
anvilList: {
fileName: string;
fileType: string;
fileSyncAnvilList: {
anvilName: string;
anvilDescription: string;
anvilUUID: string;
isSync: boolean;
}[];
isShowSelectFileOnStart?: boolean;
};
const FILE_TYPE_LIST = {
iso: 'ISO (optical disc)',
other: 'Other file type',
script: 'Script (program)',
};
// Used to solve react/require-default-params AND ensure linting works within the function component.
const FILE_INFO_DEFAULT_PROPS = { isShowSelectFileOnStart: false };
const FileInfo = ({
anvilList,
isShowSelectFileOnStart = FILE_INFO_DEFAULT_PROPS.isShowSelectFileOnStart,
fileName,
fileType,
fileSyncAnvilList,
}: FileInfoProps): JSX.Element => {
const selectFileRef = useRef<HTMLInputElement>();
const openFilePicker = () => {
selectFileRef.current?.click();
};
useEffect(() => {
if (isShowSelectFileOnStart) {
openFilePicker();
}
}, [isShowSelectFileOnStart]);
return (
<form encType="multipart/form-data">
<Box sx={{ display: 'flex', flexDirection: 'column' }}>
<InputLabel htmlFor="select-file">
<Input
id="select-file"
ref={selectFileRef}
sx={{ display: 'none' }}
type="file"
/>
</InputLabel>
<Box
sx={{ alignItems: 'center', display: 'flex', flexDirection: 'row' }}
>
<TextField id="file-name" label="File name" sx={{ flexGrow: 1 }} />
<Button onClick={openFilePicker} sx={{ textTransform: 'none' }}>
<BodyText text="Browse" />
</Button>
</Box>
<Select id="file-type" label="File type" value="other">
{Object.entries(FILE_TYPE_LIST).map(
([fileType, fileTypeDisplayString]) => {
return (
<MenuItem key={fileType} value={fileType}>
{fileTypeDisplayString}
</MenuItem>
);
},
)}
</Select>
{anvilList.map(({ anvilName, anvilDescription, anvilUUID }) => {
<FormControl>
<TextField
defaultValue={fileName}
id="file-name"
label="File name"
sx={{ flexGrow: 1 }}
/>
<Select defaultValue={fileType} id="file-type" label="File type">
{UPLOAD_FILE_TYPES_ARRAY.map(
([fileTypeKey, [, fileTypeDisplayString]]) => {
return (
<MenuItem key={fileTypeKey} value={fileTypeKey}>
{fileTypeDisplayString}
</MenuItem>
);
},
)}
</Select>
{fileSyncAnvilList.map(
({ anvilName, anvilDescription, anvilUUID, isSync }) => {
return (
<FormControlLabel
control={<Checkbox />}
control={<Checkbox checked={isSync} />}
key={anvilUUID}
label={`${anvilName}: ${anvilDescription}`}
value={`${anvilUUID}-sync`}
/>
);
})}
</Box>
</form>
},
)}
</FormControl>
);
};
FileInfo.defaultProps = FILE_INFO_DEFAULT_PROPS;
export default FileInfo;

@ -0,0 +1,96 @@
import { ChangeEventHandler, useEffect, useRef, useState } from 'react';
import { Box, Button, Input, InputLabel } from '@mui/material';
import EventEmitter from 'events';
import { UPLOAD_FILE_TYPES } from '../../lib/consts/UPLOAD_FILE_TYPES';
import FileInfo from './FileInfo';
import { BodyText } from '../Text';
type FileUploadInfoProps = {
openFilePickerEventEmitter?: EventEmitter;
};
const FILE_UPLOAD_INFO_DEFAULT_PROPS = {
openFilePickerEventEmitter: undefined,
};
const FileUploadInfo = ({
openFilePickerEventEmitter,
}: FileUploadInfoProps = FILE_UPLOAD_INFO_DEFAULT_PROPS): JSX.Element => {
const selectFileRef = useRef<HTMLInputElement>();
const [selectedFileList, setSelectedFileList] = useState<File[]>([]);
const convertMIMETypeToFileTypeKey = (
fileMIMEType: string,
): UploadFileTypes => {
const fileTypesIterator = UPLOAD_FILE_TYPES.entries();
let fileType: UploadFileTypes | undefined;
do {
const fileTypesResult = fileTypesIterator.next();
if (fileTypesResult.value) {
const [fileTypeKey, [mimeTypeToUse]] = fileTypesResult.value;
if (fileMIMEType === mimeTypeToUse) {
fileType = fileTypeKey;
}
} else {
fileType = 'other';
}
} while (!fileType);
return fileType;
};
const autocompleteAfterSelectFile: ChangeEventHandler<HTMLInputElement> = ({
target: { files },
}) => {
if (files) {
setSelectedFileList(Array.from(files));
}
};
useEffect(() => {
openFilePickerEventEmitter?.addListener('open', () => {
selectFileRef.current?.click();
});
}, [openFilePickerEventEmitter]);
return (
<form encType="multipart/form-data">
<Box sx={{ display: 'flex', flexDirection: 'column' }}>
<InputLabel htmlFor="select-file">
<Input
id="select-file"
inputProps={{ multiple: true }}
onChange={autocompleteAfterSelectFile}
ref={selectFileRef}
sx={{ display: 'none' }}
type="file"
/>
</InputLabel>
{selectedFileList.map((file: File) => (
<FileInfo
fileName={file.name}
fileType={convertMIMETypeToFileTypeKey(file.type)}
fileSyncAnvilList={[]}
key={file.name}
/>
))}
{selectedFileList.length > 0 && (
<Button sx={{ textTransform: 'none' }}>
<BodyText text="Upload" />
</Button>
)}
</Box>
</form>
);
};
FileUploadInfo.defaultProps = FILE_UPLOAD_INFO_DEFAULT_PROPS;
export default FileUploadInfo;

@ -1,7 +1,7 @@
import { useState } from 'react';
import { Box, IconButton } from '@mui/material';
import AddIcon from '@mui/icons-material/Add';
import { styled } from '@mui/material/styles';
import EventEmitter from 'events';
import ICON_BUTTON_STYLE from '../../lib/consts/ICON_BUTTON_STYLE';
@ -9,8 +9,8 @@ import { Panel } from '../Panels';
import PeriodicFetch from '../../lib/fetchers/periodicFetch';
import Spinner from '../Spinner';
import { HeaderText } from '../Text';
import FileInfo from './FileInfo';
import FileList from './FileList';
import FileUploadInfo from './FileUploadInfo';
const PREFIX = 'Files';
@ -28,14 +28,14 @@ const StyledDiv = styled('div')(() => ({
}));
const Files = (): JSX.Element => {
const [isShowUploadForm, setIsShowUploadForm] = useState<boolean>(false);
const openFilePickerEventEmitter: EventEmitter = new EventEmitter();
const { data: fileList, isLoading } = PeriodicFetch(
`${process.env.NEXT_PUBLIC_API_URL?.replace('/cgi-bin', '/api')}/files`,
);
const onAddFileButtonClick = () => {
setIsShowUploadForm(!isShowUploadForm);
openFilePickerEventEmitter.emit('open');
};
return (
@ -54,9 +54,9 @@ const Files = (): JSX.Element => {
</IconButton>
</Box>
</Box>
{isShowUploadForm && (
<FileInfo anvilList={[]} isShowSelectFileOnStart />
)}
<FileUploadInfo
openFilePickerEventEmitter={openFilePickerEventEmitter}
/>
{isLoading ? <Spinner /> : <FileList list={fileList} />}
</StyledDiv>
</Panel>

@ -0,0 +1,11 @@
export const UPLOAD_FILE_TYPES_ARRAY: ReadonlyArray<
[UploadFileTypes, [string, string]]
> = [
['iso', ['application/x-cd-image', 'ISO (optical disc)']],
['other', ['text/plain', 'Other file type']],
['script', ['text/plain', 'Script (program)']],
];
export const UPLOAD_FILE_TYPES: ReadonlyMap<
UploadFileTypes,
[string, string]
> = new Map(UPLOAD_FILE_TYPES_ARRAY);

@ -0,0 +1 @@
declare type UploadFileTypes = 'iso' | 'other' | 'script';
Loading…
Cancel
Save