import { Divider, IconButton, Input, Tooltip } from "@mui/joy"; import { includes } from "lodash-es"; import { useEffect, useState } from "react"; import { Link } from "react-router-dom"; import { showCommonDialog } from "@/components/Dialog/CommonDialog"; import Empty from "@/components/Empty"; import Icon from "@/components/Icon"; import MobileHeader from "@/components/MobileHeader"; import ResourceIcon from "@/components/ResourceIcon"; import { resourceServiceClient } from "@/grpcweb"; import useLoading from "@/hooks/useLoading"; import i18n from "@/i18n"; import { useMemoStore } from "@/store/v1"; import { Resource } from "@/types/proto/api/v2/resource_service"; import { useTranslate } from "@/utils/i18n"; function groupResourcesByDate(resources: Resource[]) { const tmp_resources: Resource[] = resources.slice(); tmp_resources.sort((a: Resource, b: Resource) => { const a_date = new Date(a.createTime as any); const b_date = new Date(b.createTime as any); return b_date.getTime() - a_date.getTime(); }); const grouped = new Map(); tmp_resources.forEach((item) => { const date = new Date(item.createTime as any); const year = date.getFullYear(); const month = date.getMonth() + 1; const timestamp = Date.UTC(year, month - 1, 1); if (!grouped.has(timestamp)) { grouped.set(timestamp, []); } grouped.get(timestamp)?.push(item); }); return grouped; } interface State { searchQuery: string; } const Resources = () => { const t = useTranslate(); const loadingState = useLoading(); const [state, setState] = useState({ searchQuery: "", }); const memoStore = useMemoStore(); const [resources, setResources] = useState([]); const filteredResources = resources.filter((resource: any) => includes(resource.filename, state.searchQuery)); const groupedResources = groupResourcesByDate(filteredResources.filter((resource: any) => resource.memoId)); const unusedResources = filteredResources.filter((resource: any) => !resource.memoId); useEffect(() => { resourceServiceClient.listResources({}).then(({ resources }) => { setResources(resources); loadingState.setFinish(); Promise.all(resources.map((resource: any) => (resource.memoId ? memoStore.getOrFetchMemoById(resource.memoId) : null))); }); }, []); const handleDeleteUnusedResources = () => { showCommonDialog({ title: "Delete all unused resources", content: "Are you sure to delete all unused resources? This action cannot be undone.", style: "warning", dialogName: "delete-unused-resources-dialog", onConfirm: async () => { for (const resource of unusedResources) { await resourceServiceClient.deleteResource({ id: resource.id }); } setResources(resources.filter((resource) => resource.memoId)); }, }); }; return (

{t("common.resources")}

} value={state.searchQuery} onChange={(e) => setState({ ...state, searchQuery: e.target.value })} />
{loadingState.isLoading ? (

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

) : ( <> {filteredResources.length === 0 ? (

{t("message.no-data")}

) : (
{Array.from(groupedResources.entries()).map(([timestamp, resources]) => { const date = new Date(timestamp); return (
{date.getFullYear()} {date.toLocaleString(i18n.language, { month: "short" })}
{resources.map((resource) => { const relatedMemo = resource.memoId ? memoStore.getMemoById(resource.memoId) : null; return (

{resource.filename}

{relatedMemo && ( #{relatedMemo.id} )}
); })}
); })} {unusedResources.length > 0 && ( <>
Unused resources ({unusedResources.length})
{unusedResources.map((resource) => { return (

{resource.filename}

); })}
)}
)} )}
); }; export default Resources;