184 lines
5.2 KiB
TypeScript
Executable File
184 lines
5.2 KiB
TypeScript
Executable File
import React, { useState, useEffect, useCallback, Fragment } from "react";
|
|
import { FaExclamation, FaCheck } from "react-icons/fa";
|
|
import { useTranslation } from "react-i18next";
|
|
import {
|
|
Progress,
|
|
Label,
|
|
ProgressClassNameContract,
|
|
Hypertext,
|
|
} from "@microsoft/fast-components-react-msft";
|
|
import manageJss, { ComponentStyles } from "@microsoft/fast-jss-manager-react";
|
|
import {
|
|
DropzoneUploadClassNameContract,
|
|
DropzoneUploadProps,
|
|
} from "./DropzoneUpload.props";
|
|
import {
|
|
neutralForegroundRest,
|
|
DesignSystem,
|
|
neutralLayerCard,
|
|
applyAcrylicMaterial,
|
|
applyElevation,
|
|
ElevationMultiplier,
|
|
backgroundColor,
|
|
} from "@microsoft/fast-components-styles-msft";
|
|
import { parseColorHexRGBA } from "@microsoft/fast-colors";
|
|
import { ProgressIcon } from "../../_DesignSystem";
|
|
import axios from "../../_interceptedAxios";
|
|
|
|
const DropzoneUploadStyles: ComponentStyles<
|
|
DropzoneUploadClassNameContract,
|
|
DesignSystem
|
|
> = {
|
|
dropzoneUpload: {
|
|
position: "relative",
|
|
overflow: "hidden",
|
|
width: "200px",
|
|
height: "200px",
|
|
background: neutralLayerCard,
|
|
...applyElevation(ElevationMultiplier.e5),
|
|
"&:hover > footer": {
|
|
transform: "translateY(0%)",
|
|
},
|
|
},
|
|
dropzoneUpload_image: {
|
|
objectFit: "contain",
|
|
},
|
|
dropzoneUpload_details: {
|
|
position: "absolute",
|
|
bottom: "0",
|
|
left: "0",
|
|
width: "100%",
|
|
padding: "10px 50px 10px 10px",
|
|
boxSizing: "border-box",
|
|
display: "flex",
|
|
textAlign: "left",
|
|
lineBreak: "anywhere",
|
|
transform: "translateY(100%)",
|
|
transition: "transform .15s",
|
|
minHeight: "57px",
|
|
...applyAcrylicMaterial("#000000", 0.8),
|
|
background: des => parseColorHexRGBA(backgroundColor(des) + "cc").toStringWebRGBA(),
|
|
"&.focus-visible, &:focus-within": {
|
|
transform: "translateY(0%)",
|
|
},
|
|
},
|
|
dropzoneUpload_progress: {
|
|
position: "absolute",
|
|
bottom: "10px",
|
|
right: "10px",
|
|
},
|
|
dropzoneUpload_error: {
|
|
lineBreak: "initial",
|
|
},
|
|
dropzoneUploadIcon: {
|
|
fontSize: "4em",
|
|
color: neutralForegroundRest,
|
|
},
|
|
};
|
|
|
|
const ProgressStyles: ComponentStyles<ProgressClassNameContract, DesignSystem> = {
|
|
progress_circularSVG__container: {
|
|
...applyElevation(ElevationMultiplier.e8),
|
|
borderRadius: "50%",
|
|
},
|
|
progress_circularSVG__control: {},
|
|
progress_circularSVG__page: {},
|
|
};
|
|
|
|
const DropzoneUpload = (props: DropzoneUploadProps) => {
|
|
const { t } = useTranslation("dashboard");
|
|
const [errorMessage, setErrorMessage] = useState("");
|
|
const [progress, setProgress] = useState(0);
|
|
const [resData, setResData] = useState({ id: null, file_url: null });
|
|
|
|
const onUploadProgress = (prog: ProgressEvent) =>
|
|
setProgress(Math.round((prog.loaded * 100) / prog.total));
|
|
|
|
const uploadFile = useCallback(async () => {
|
|
const formData = new FormData();
|
|
formData.set("data", props.file);
|
|
|
|
try {
|
|
const res = await axios.post(window.location.origin + "/api/upload.php", formData, {
|
|
onUploadProgress,
|
|
});
|
|
setResData(res.data);
|
|
} catch (err) {
|
|
console.log("An error happened!\n", err);
|
|
setErrorMessage(err.i18n ? t(err.i18n) : err.message || "Unknkown Error!");
|
|
return null;
|
|
}
|
|
}, [props.file, t]);
|
|
|
|
// onMount
|
|
useEffect(() => {
|
|
console.log("updated!");
|
|
if (props.rejected) {
|
|
let savedTimeout = setTimeout(props.onRemoveRequest, 6000);
|
|
return () => clearTimeout(savedTimeout);
|
|
}
|
|
|
|
// Uploading process
|
|
if (resData.id || errorMessage) return () => {};
|
|
uploadFile();
|
|
return () => {};
|
|
}, [errorMessage, props.onRemoveRequest, props.rejected, resData.id, uploadFile]);
|
|
|
|
return (
|
|
<div className={props.managedClasses.dropzoneUpload}>
|
|
{!props.rejected && props.preview && (
|
|
<img
|
|
src={props.preview}
|
|
alt={props.file.name}
|
|
className={props.managedClasses.dropzoneUpload_image}
|
|
width="200"
|
|
height="200"
|
|
/>
|
|
)}
|
|
<footer className={props.managedClasses.dropzoneUpload_details} tabIndex={0}>
|
|
<Label
|
|
className={
|
|
props.rejected || errorMessage || resData.id
|
|
? props.managedClasses.dropzoneUpload_error
|
|
: ""
|
|
}
|
|
tabIndex={-1}
|
|
>
|
|
{props.rejected ? (
|
|
t("upload.error.unsupported")
|
|
) : errorMessage ? (
|
|
errorMessage
|
|
) : resData.id ? (
|
|
<Fragment>
|
|
{t("upload.finished", { filename: resData.id })}
|
|
<br />
|
|
<Hypertext href={resData.file_url} target="_">
|
|
{t("upload.visit")}
|
|
</Hypertext>
|
|
</Fragment>
|
|
) : (
|
|
props.file.name
|
|
)}
|
|
</Label>
|
|
</footer>
|
|
<div className={props.managedClasses.dropzoneUpload_progress}>
|
|
{props.rejected || errorMessage.length > 0 ? (
|
|
<ProgressIcon icon={FaExclamation} />
|
|
) : progress === 100 ? (
|
|
<ProgressIcon icon={FaCheck} />
|
|
) : (
|
|
<Progress
|
|
jssStyleSheet={ProgressStyles}
|
|
circular={true}
|
|
minValue={0}
|
|
maxValue={100}
|
|
value={progress}
|
|
/>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default manageJss(DropzoneUploadStyles)(DropzoneUpload);
|