Can attach file to movement
This commit is contained in:
97
moneymgr_web/src/widgets/forms/UploadFileButton.tsx
Normal file
97
moneymgr_web/src/widgets/forms/UploadFileButton.tsx
Normal file
@ -0,0 +1,97 @@
|
||||
import { Button, IconButton, Tooltip, Typography } from "@mui/material";
|
||||
import UploadFileIcon from "@mui/icons-material/UploadFile";
|
||||
import { ServerApi } from "../../api/ServerApi";
|
||||
import React from "react";
|
||||
import { FileApi, UploadedFile } from "../../api/FileApi";
|
||||
import { useAlert } from "../../hooks/context_providers/AlertDialogProvider";
|
||||
import { useLoadingMessage } from "../../hooks/context_providers/LoadingMessageProvider";
|
||||
import { useSnackbar } from "../../hooks/context_providers/SnackbarProvider";
|
||||
|
||||
// https://medium.com/@dprincecoder/creating-a-drag-and-drop-file-upload-component-in-react-a-step-by-step-guide-4d93b6cc21e0
|
||||
|
||||
export function UploadFileButton(p: {
|
||||
onUploaded: (file: UploadedFile) => void;
|
||||
label: string;
|
||||
tooltip: string;
|
||||
}): React.ReactElement {
|
||||
const alert = useAlert();
|
||||
const loadingMessage = useLoadingMessage();
|
||||
const snackbar = useSnackbar();
|
||||
|
||||
const fileInput = React.useRef<HTMLInputElement>(null);
|
||||
|
||||
const [dragActive, setDragActive] = React.useState(false);
|
||||
|
||||
const forceFileSelect = () => fileInput.current?.click();
|
||||
|
||||
const dragEnter = () => {
|
||||
setDragActive(true);
|
||||
};
|
||||
const dragLeave = () => {
|
||||
setDragActive(false);
|
||||
};
|
||||
|
||||
const handleUpload = async (file: File[]) => {
|
||||
if (file.length < 1) return;
|
||||
|
||||
try {
|
||||
loadingMessage.show("Uploading file...");
|
||||
|
||||
const result = await FileApi.UploadFile(file[0]);
|
||||
|
||||
snackbar("The file was successfully uploaded!");
|
||||
|
||||
p.onUploaded(result);
|
||||
} catch (e) {
|
||||
console.error("Failed to upload file!", e);
|
||||
alert(`Failed to upload file! ${e}`);
|
||||
} finally {
|
||||
loadingMessage.hide();
|
||||
}
|
||||
};
|
||||
|
||||
const handleDrop = (ev: React.DragEvent) => {
|
||||
ev.preventDefault();
|
||||
handleUpload([...ev.dataTransfer.files]);
|
||||
};
|
||||
|
||||
const handlefileChange = (ev: React.ChangeEvent) => {
|
||||
ev.preventDefault();
|
||||
if ((fileInput.current?.files?.length ?? 0) > 0) {
|
||||
handleUpload([...fileInput.current?.files!]);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
title={p.tooltip}
|
||||
onDrop={handleDrop}
|
||||
onDragOver={(event) => event.preventDefault()}
|
||||
onDragEnter={dragEnter}
|
||||
onDragLeave={dragLeave}
|
||||
>
|
||||
<Button
|
||||
size="small"
|
||||
startIcon={<UploadFileIcon fontSize="small" />}
|
||||
variant={dragActive ? "outlined" : "text"}
|
||||
onClick={forceFileSelect}
|
||||
>
|
||||
<input
|
||||
ref={fileInput}
|
||||
type="file"
|
||||
accept={ServerApi.Config.constraints.file_allowed_types.join(",")}
|
||||
style={{
|
||||
border: "0",
|
||||
height: "1px",
|
||||
width: "1px",
|
||||
padding: "0px",
|
||||
position: "absolute",
|
||||
clipPath: "inset(50%)",
|
||||
}}
|
||||
onChange={handlefileChange}
|
||||
/>
|
||||
<Typography variant="caption">{p.label}</Typography>
|
||||
</Button>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
Reference in New Issue
Block a user