improve list view

This commit is contained in:
Sara
2023-12-06 17:12:10 +01:00
parent 6fe61cd5e3
commit 5ef7dc0a76
4 changed files with 180 additions and 71 deletions

View File

@@ -6,81 +6,176 @@ import { Title } from "../../lib/textComponents";
import Pagination from "./pagination";
import Link from "next/link";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faGear } from "@fortawesome/free-solid-svg-icons";
import {
faCheck,
faGear,
faMicrophone,
faStar,
faTrash,
faX,
} from "@fortawesome/free-solid-svg-icons";
import useTranscriptList from "../transcripts/useTranscriptList";
import { formatTime } from "../../lib/time";
import getApi from "../../api";
import { useError } from "../../(errors)/errorContext";
export default function TranscriptBrowser() {
const [page, setPage] = useState<number>(1);
const { loading, response } = useTranscriptList(page);
const { loading, response, refetch } = useTranscriptList(page);
const [transcriptToDeleteId, setTranscriptToDeleteId] = useState("");
const [deletionLoading, setDeletionLoading] = useState(false);
const [deletedItems, setDeletedItems] = useState<string[]>([]);
const api = getApi();
const { setError } = useError();
return (
<div className="grid grid-rows-layout-topbar gap-2 lg:gap-4 h-full max-h-full">
<div className="flex flex-row gap-2 items-center">
<Title className="mb-5 mt-5 flex-1">Past transcripts</Title>
<Pagination
page={page}
setPage={setPage}
total={response?.total || 0}
size={response?.size || 0}
if (loading && !response)
return (
<div className="h-full flex flex-col items-center justify-center">
<FontAwesomeIcon
icon={faGear}
className="animate-spin-slow h-14 w-14 md:h-20 md:w-20 text-gray-400"
/>
</div>
);
{loading && (
<div className="full-screen flex flex-col items-center justify-center">
<FontAwesomeIcon
icon={faGear}
className="animate-spin-slow h-14 w-14 md:h-20 md:w-20"
if (!loading && !response)
return (
<div className="text-gray-500">
No transcripts found, but you can&nbsp;
<Link href="/transcripts/new" className="underline">
record a meeting
</Link>
&nbsp;to get started.
</div>
);
const handleDelete =
(id: string) => (e: React.MouseEvent<HTMLButtonElement>) => {
e.stopPropagation();
e.preventDefault();
setTranscriptToDeleteId(id);
};
const deleteTranscript = () => (e: React.MouseEvent<HTMLButtonElement>) => {
e.stopPropagation();
e.preventDefault();
if (!deletionLoading) {
api
?.v1TranscriptDelete({ transcriptId: transcriptToDeleteId })
.then(() => {
setDeletionLoading(false);
setDeletedItems([...deletedItems, transcriptToDeleteId]);
setTranscriptToDeleteId("");
refetch();
})
.catch((err) => {
setDeletionLoading(false);
setError(err, "There was an error deleting the transcript");
});
}
};
const cancelDelete = (e: React.MouseEvent<HTMLButtonElement>) => {
e.stopPropagation();
e.preventDefault();
setTranscriptToDeleteId("");
};
return (
<div className="w-full flex flex-col items-center justify-center flex-grow">
<div className="max-w-5xl h-full">
<div className="flex flex-row gap-2 items-center">
<Title className="mb-5 mt-5 flex-1">Past transcripts</Title>
<Pagination
page={page}
setPage={setPage}
total={response?.total || 0}
size={response?.size || 0}
/>
</div>
)}
{!loading && !response && (
<div className="text-gray-500">
No transcripts found, but you can&nbsp;
<Link href="/transcripts/new" className="underline">
record a meeting
</Link>
&nbsp;to get started.
</div>
)}
<div /** center and max 900px wide */ className="overflow-y-scroll">
<div className="grid grid-cols-1 gap-2 lg:gap-4 h-full mx-auto max-w-[900px]">
{response?.items.map((item: GetTranscript) => (
<div
key={item.id}
className="flex flex-col bg-blue-400/20 rounded-lg md:rounded-xl p-2 md:px-4"
>
<div className="flex flex-col">
<div className="flex flex-row gap-2 items-start">
<Link
href={`/transcripts/${item.id}`}
className="text-1xl flex-1 pl-0 hover:underline focus-within:underline underline-offset-2 decoration-[.5px] font-light px-2"
>
{item.title || item.name}
</Link>
<div className="grid grid-cols-1 gap-2 lg:gap-4 h-full">
{response?.items
.filter((item) => !deletedItems.includes(item.id))
.map((item: GetTranscript) => (
<Link
key={item.id}
href={`/transcripts/${item.id}`}
className="flex flex-col bg-blue-400/20 rounded-lg md:rounded-xl p-2 md:px-4"
>
<div className="flex flex-col">
<div className="flex flex-row gap-2 items-start">
<h2 className="text-1xl font-semibold flex-1">
{item.title || item.name}
</h2>
{item.locked ? (
<div className="inline-block bg-red-500 text-white px-2 py-1 rounded-full text-xs font-semibold">
Locked
</div>
) : (
<></>
)}
{item.locked && (
<div className="inline-block bg-red-500 text-white px-2 py-1 rounded-full text-xs font-semibold">
Locked
</div>
)}
{item.source_language ? (
<div className="inline-block bg-blue-500 text-white px-2 py-1 rounded-full text-xs font-semibold">
{item.source_language}
{item.status == "ended" && (
<FontAwesomeIcon
icon={faCheck}
className="mt-1 text-green-500"
/>
)}
{item.status == "error" && (
<FontAwesomeIcon
icon={faX}
className="mt-1 text-red-500"
/>
)}
{item.status == "idle" && (
<FontAwesomeIcon
icon={faStar}
className="mt-1 text-yellow-500"
/>
)}
{item.status == "processing" && (
<FontAwesomeIcon
icon={faGear}
className="mt-1 text-grey-500"
/>
)}
{item.status == "recording" && (
<FontAwesomeIcon
icon={faMicrophone}
className="mt-1 text-blue-500"
/>
)}
{item.sourceLanguage && (
<div className="inline-block bg-blue-500 text-white px-2 py-1 rounded-full text-xs font-semibold">
{item.sourceLanguage}
</div>
)}
</div>
<div className="flex flex-row gap-2 items-start">
<div className="text-xs text-gray-700 flex-1">
{new Date(item.createdAt).toLocaleDateString("en-US")}
{"\u00A0"}-{"\u00A0"}
{formatTime(Math.floor(item.duration))}
<div className="text-sm">{item.shortSummary}</div>
</div>
) : (
<></>
)}
{item.status !== "ended" && (
<button
className="self-end p-2"
disabled={deletionLoading}
onClick={handleDelete(item.id)}
>
<FontAwesomeIcon icon={faTrash}></FontAwesomeIcon>
</button>
)}
<dialog open={transcriptToDeleteId == item.id}>
<p>Are you sure you want to delete {item.title} ?</p>
<p>This action is not reversible.</p>
<button onClick={cancelDelete}>Cancel</button>
<button onClick={deleteTranscript()}>Confirm</button>
</dialog>
</div>
</div>
<div className="text-xs text-gray-700">
{new Date(item.created_at).toLocaleDateString("en-US")}
</div>
<div className="text-sm">{item.short_summary}</div>
</div>
</div>
))}
</Link>
))}
</div>
</div>
</div>