import copy from "copy-to-clipboard"; import { useCallback, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import useLoading from "../hooks/useLoading"; import { resourceService } from "../services"; import Dropdown from "./common/Dropdown"; import { generateDialog } from "./Dialog"; import { showCommonDialog } from "./Dialog/CommonDialog"; import showPreviewImageDialog from "./PreviewImageDialog"; import Icon from "./Icon"; import toastHelper from "./Toast"; import "../less/resources-dialog.less"; import * as utils from "../helpers/utils"; type Props = DialogProps; interface State { resources: Resource[]; isUploadingResource: boolean; } const ResourcesDialog: React.FC = (props: Props) => { const { destroy } = props; const { t } = useTranslation(); const loadingState = useLoading(); const [state, setState] = useState({ resources: [], isUploadingResource: false, }); useEffect(() => { fetchResources() .catch((error) => { console.error(error); toastHelper.error(error.response.data.message); }) .finally(() => { loadingState.setFinish(); }); }, []); const fetchResources = async () => { const data = await resourceService.getResourceList(); setState({ ...state, resources: data, }); }; const handleUploadFileBtnClick = async () => { if (state.isUploadingResource) { return; } const inputEl = document.createElement("input"); inputEl.style.position = "fixed"; inputEl.style.top = "-100vh"; inputEl.style.left = "-100vw"; document.body.appendChild(inputEl); inputEl.type = "file"; inputEl.multiple = true; inputEl.accept = "*"; inputEl.onchange = async () => { if (!inputEl.files || inputEl.files.length === 0) { return; } setState({ ...state, isUploadingResource: true, }); for (const file of inputEl.files) { try { await resourceService.upload(file); } catch (error: any) { console.error(error); toastHelper.error(error.response.data.message); } finally { setState({ ...state, isUploadingResource: false, }); } } document.body.removeChild(inputEl); await fetchResources(); }; inputEl.click(); }; const handlPreviewBtnClick = (resource: Resource) => { const resourceUrl = `${window.location.origin}/o/r/${resource.id}/${resource.filename}`; if (resource.type.startsWith("image")) { showPreviewImageDialog(resourceUrl); } else { window.open(resourceUrl); } }; const handleCopyResourceLinkBtnClick = (resource: Resource) => { copy(`${window.location.origin}/o/r/${resource.id}/${resource.filename}`); toastHelper.success("Succeed to copy resource link to clipboard"); }; const handleDeleteResourceBtnClick = (resource: Resource) => { let warningText = t("resources.warning-text"); if (resource.linkedMemoAmount > 0) { warningText = warningText + `\n${t("resources.linked-amount")}: ${resource.linkedMemoAmount}`; } showCommonDialog({ title: t("resources.delete-resource"), content: warningText, style: "warning", onConfirm: async () => { await resourceService.deleteResourceById(resource.id); await fetchResources(); }, }); }; const handleResourceNameOrTypeMouseEnter = useCallback((event: React.MouseEvent, nameOrType: string) => { const tempDiv = document.createElement("div"); tempDiv.className = "usage-detail-container pop-up"; const bounding = utils.getElementBounding(event.target as HTMLElement); tempDiv.style.left = bounding.left + "px"; tempDiv.style.top = bounding.top - 2 + "px"; tempDiv.innerHTML = `${nameOrType}`; document.body.appendChild(tempDiv); }, []); const handleResourceNameOrTypeMouseLeave = useCallback(() => { document.body.querySelectorAll("div.usage-detail-container.pop-up").forEach((node) => node.remove()); }, []); return ( <>

🌄 {t("sidebar.resources")}

handleUploadFileBtnClick()}>
{t("resources.upload")}
{loadingState.isLoading ? (

{t("resources.fetching-data")}

) : (
ID NAME TYPE
{state.resources.length === 0 ? (

{t("resources.no-resources")}

) : ( state.resources.map((resource) => (
{resource.id} handleResourceNameOrTypeMouseEnter(e, resource.filename)} onMouseLeave={handleResourceNameOrTypeMouseLeave} > {resource.filename} handleResourceNameOrTypeMouseEnter(e, resource.type)} onMouseLeave={handleResourceNameOrTypeMouseLeave} > {resource.type}
} />
)) )}
)}
); }; export default function showResourcesDialog() { generateDialog( { className: "resources-dialog", }, ResourcesDialog, {} ); }