164 lines
4.9 KiB
TypeScript
Raw Normal View History

2024-08-29 18:45:52 +02:00
import { Download, FilesIcon, ReceiptText, Star } from "lucide-react";
import { useEffect, useRef, useState } from "react";
import { PrettyBytes } from "../../utils/bytes.ts";
import { Dates } from "../../utils/dates.ts";
import "./Files.css";
import { ICON_SIZE, SIDE_DURATION } from "../../utils/constants.ts";
import {
ButtonIcon,
EmptyPlaceholder,
WebFileIcon,
2024-08-30 17:26:27 +02:00
} from "@codex-storage/marketplace-ui-components";
2024-08-29 18:45:52 +02:00
import { FileDetails } from "./FileDetails.tsx";
import { classnames } from "../../utils/classnames.ts";
import { FavoriteStorage } from "../../utils/favorite-storage.tsx";
import { useData } from "../../hooks/useData.tsx";
type StarIconProps = {
isFavorite: boolean;
};
function StarIcon({ isFavorite }: StarIconProps) {
if (isFavorite) {
return (
<Star size={ICON_SIZE} className="files-fileFavorite files-fileStar" />
);
}
return <Star size={ICON_SIZE} className="files-star" />;
}
export function Files() {
const files = useData();
const cid = useRef<string | null>("");
const [expanded, setExpanded] = useState(false);
const [favorites, setFavorites] = useState<string[]>([]);
const [selected, setSelected] = useState<"all" | "favorites">("all");
useEffect(() => {
FavoriteStorage.list().then((cids) => setFavorites(cids));
}, []);
const onClose = () => {
setExpanded(false);
setTimeout(() => {
cid.current = "";
}, SIDE_DURATION);
};
const onSelected = () =>
setSelected(selected === "all" ? "favorites" : "all");
const onDetails = (id: string) => {
cid.current = id;
setExpanded(true);
};
const onToggleFavorite = (cid: string) => {
if (favorites.includes(cid)) {
FavoriteStorage.delete(cid);
setFavorites(favorites.filter((c) => c !== cid));
} else {
FavoriteStorage.add(cid);
setFavorites([...favorites, cid]);
}
};
const items = [];
if (selected === "favorites") {
items.push(...files.filter((f) => favorites.includes(f.cid)));
} else {
items.push(...files);
}
const details = items.find((c) => c.cid === cid.current);
const url = import.meta.env.VITE_CODEX_API_URL + "/api/codex/v1/data/";
return (
<div className="files">
<div className="files-header">
<div className="files-title">Files</div>
<div className="files-headerTabs">
<div
className={classnames(
["files-headerTab"],
["files-headerTab--active", selected === "all"]
)}
onClick={onSelected}>
<FilesIcon size={"1rem"}></FilesIcon>
<span>All files</span>
</div>
<div
className={classnames(
["files-headerTab"],
["files-headerTab--active", selected === "favorites"]
)}
onClick={onSelected}>
<Star size={"1rem"}></Star>
<span>Favorites</span>
</div>
</div>
</div>
<div className="files-fileBody">
{items.length ? (
items.map((c) => (
<div className="files-file" key={c.cid}>
<div className="files-fileContent">
<div className="files-fileIcon">
<WebFileIcon type={c.mimetype} />
</div>
<div className="files-fileData">
<div>
<b>{c.name}</b>
<div>
<small className="files-fileMeta">
{PrettyBytes(c.manifest.datasetSize)} -{" "}
{Dates.format(c.uploadedAt).toString()} - ...
{c.cid.slice(-5)}
</small>
</div>
</div>
<div className="files-fileActions">
<ButtonIcon
variant="small"
onClick={() => window.open(url + c.cid, "_blank")}
Icon={() => <Download size={ICON_SIZE} />}></ButtonIcon>
<ButtonIcon
variant="small"
onClick={() => onToggleFavorite(c.cid)}
Icon={() => (
<StarIcon isFavorite={favorites.includes(c.cid)} />
)}></ButtonIcon>
<ButtonIcon
variant="small"
onClick={() => onDetails(c.cid)}
Icon={() => (
<ReceiptText size={ICON_SIZE} />
)}></ButtonIcon>
</div>
</div>
</div>
</div>
))
) : (
<div className="files-placeholder">
<EmptyPlaceholder
title="Nothing to show"
message="No data here yet. Start to upload files to see data here."
/>
</div>
)}
</div>
<FileDetails onClose={onClose} details={details} expanded={expanded} />
</div>
);
}