122 lines
3.6 KiB
TypeScript
Executable File
122 lines
3.6 KiB
TypeScript
Executable File
import React, { useState, useContext } from "react";
|
|
import {
|
|
FVSidebarDescEditorProps,
|
|
FVSidebarDescEditorClassNameContract,
|
|
} from "./FVSidebarDescEditor.props";
|
|
import { DesignSystem } from "@microsoft/fast-components-styles-msft";
|
|
import manageJss, { ComponentStyles } from "@microsoft/fast-jss-manager-react";
|
|
import {
|
|
TextAction,
|
|
Progress,
|
|
ProgressClassNameContract,
|
|
} from "@microsoft/fast-components-react-msft";
|
|
import { FaCheck, FaExclamationTriangle } from "react-icons/fa";
|
|
import axios from "../../../_interceptedAxios";
|
|
import { useToasts } from "../../../_DesignSystem";
|
|
import { useTranslation } from "react-i18next";
|
|
import { SidebarData } from "./FVSidebarContext";
|
|
|
|
const styles: ComponentStyles<FVSidebarDescEditorClassNameContract, DesignSystem> = {
|
|
"@keyframes fadeAway": {
|
|
from: { opacity: "1" },
|
|
to: { opacity: "0" },
|
|
},
|
|
fv_sidebar_descEditor: {
|
|
marginTop: "5px",
|
|
},
|
|
fv_sidebar_descEditor_check: {
|
|
animationName: "fadeAway",
|
|
animationDuration: "5s",
|
|
animationDelay: "2s",
|
|
animationFillMode: "forwards",
|
|
animationTimingFunction: "linear",
|
|
},
|
|
};
|
|
|
|
const progressStyles: ComponentStyles<ProgressClassNameContract, DesignSystem> = {
|
|
progress_circularSVG__container: {
|
|
width: "auto",
|
|
height: "auto",
|
|
},
|
|
progress_circularSVG__control: {},
|
|
progress_circularSVG__page: {},
|
|
};
|
|
|
|
const FVSidebarDescEditor: React.ComponentType<FVSidebarDescEditorProps> = ({
|
|
managedClasses,
|
|
fileData,
|
|
}) => {
|
|
const { addToast } = useToasts();
|
|
const { t } = useTranslation("common");
|
|
const { setFileTitle, fileTitle } = useContext(SidebarData);
|
|
const [loadingState, setLoadingState] = useState<
|
|
"loading" | "success" | "error" | null
|
|
>(null);
|
|
|
|
const onFocus = () => loadingState !== "error" && setLoadingState(null);
|
|
|
|
/**
|
|
* Saves changes to title if user leaves the input element.
|
|
*/
|
|
const onBlur: React.FocusEventHandler<HTMLInputElement> = async ({ currentTarget }) => {
|
|
let { value } = currentTarget;
|
|
value = value.trim();
|
|
|
|
// Avoid saving the same
|
|
if (value === fileTitle) return;
|
|
|
|
// If the request takes too long, <Progress/> should appear
|
|
const deferredLoading = setTimeout(() => setLoadingState("loading"), 500);
|
|
|
|
try {
|
|
await axios.post(window.location.origin + "/api/edit.php", {
|
|
selection: fileData.id,
|
|
value,
|
|
action: "editTitle",
|
|
});
|
|
|
|
clearTimeout(deferredLoading);
|
|
setLoadingState("success");
|
|
setFileTitle(value);
|
|
} catch (err) {
|
|
clearTimeout(deferredLoading);
|
|
setLoadingState("error");
|
|
addToast(t(err.i18n, err.message), {
|
|
appearance: "error",
|
|
title: t("error.requestGeneric") + ":",
|
|
});
|
|
console.log(`${t("error.requestGeneric")}:\n`, `(${err.code}) - ${err.message}`);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<TextAction
|
|
className={managedClasses.fv_sidebar_descEditor}
|
|
name="description"
|
|
placeholder={"-"}
|
|
defaultValue={!fileTitle || fileTitle === "untitled" ? "" : fileTitle}
|
|
onBlur={onBlur}
|
|
onFocus={onFocus}
|
|
maxLength={255}
|
|
afterGlyph={name =>
|
|
loadingState === "loading" ? (
|
|
<Progress
|
|
className={name}
|
|
circular={true}
|
|
minValue={0}
|
|
maxValue={100}
|
|
value={0}
|
|
jssStyleSheet={progressStyles}
|
|
/>
|
|
) : loadingState === "success" ? (
|
|
<FaCheck className={name + " " + managedClasses.fv_sidebar_descEditor_check} />
|
|
) : (
|
|
loadingState === "error" && <FaExclamationTriangle className={name} />
|
|
)
|
|
}
|
|
/>
|
|
);
|
|
};
|
|
|
|
export default manageJss(styles)(FVSidebarDescEditor);
|