Files
reflector/www/app/transcripts/dashboard.tsx
2023-08-29 21:22:05 +07:00

123 lines
3.8 KiB
TypeScript

import React, { useState, useEffect } from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
faChevronRight,
faChevronDown,
} from "@fortawesome/free-solid-svg-icons";
import { formatTime } from "../lib/time";
import ScrollToBottom from "./scrollToBottom";
import DisconnectedIndicator from "./disconnectedIndicator";
import LiveTrancription from "./liveTranscription";
import FinalSummary from "./finalSummary";
import { Topic, FinalSummary as FinalSummaryType } from "./webSocketTypes";
type DashboardProps = {
transcriptionText: string;
finalSummary: FinalSummaryType;
topics: Topic[];
disconnected: boolean;
useActiveTopic: [
Topic | null,
React.Dispatch<React.SetStateAction<Topic | null>>,
];
};
export function Dashboard({
transcriptionText,
finalSummary,
topics,
disconnected,
useActiveTopic,
}: DashboardProps) {
const [activeTopic, setActiveTopic] = useActiveTopic;
const [autoscrollEnabled, setAutoscrollEnabled] = useState<boolean>(true);
useEffect(() => {
if (autoscrollEnabled) scrollToBottom();
}, [topics.length]);
const scrollToBottom = () => {
const topicsDiv = document.getElementById("topics-div");
if (!topicsDiv)
console.error("Could not find topics div to scroll to bottom");
else topicsDiv.scrollTop = topicsDiv.scrollHeight;
};
const handleScroll = (e) => {
const bottom =
e.target.scrollHeight - e.target.scrollTop === e.target.clientHeight;
if (!bottom && autoscrollEnabled) {
setAutoscrollEnabled(false);
} else if (bottom && !autoscrollEnabled) {
setAutoscrollEnabled(true);
}
};
return (
<>
<div className="relative h-[60svh] w-3/4 flex flex-col">
<div className="text-center pb-1 pt-4">
<h1 className="text-2xl font-bold text-blue-500">Meeting Notes</h1>
</div>
<ScrollToBottom
visible={!autoscrollEnabled}
hasFinalSummary={finalSummary ? true : false}
handleScrollBottom={scrollToBottom}
/>
<div
id="topics-div"
className="py-2 overflow-y-auto"
onScroll={handleScroll}
>
{topics.map((item, index) => (
<div key={index} className="border-b-2 py-2 hover:bg-[#8ec5fc30]">
<div
className="flex justify-between items-center cursor-pointer px-4"
onClick={() =>
setActiveTopic(activeTopic?.id == item.id ? null : item)
}
>
<div className="flex justify-between items-center">
<span className="font-light text-slate-500 pr-1">
[{formatTime(item.timestamp)}]
</span>{" "}
<span className="pr-1">{item.title}</span>
<FontAwesomeIcon
className={`transform transition-transform duration-200`}
icon={
activeTopic?.id == item.id
? faChevronDown
: faChevronRight
}
/>
</div>
</div>
{activeTopic?.id == item.id && (
<div className="p-2 mt-2 -mb-2 bg-slate-50 rounded">
{item.transcript}
</div>
)}
</div>
))}
{topics.length === 0 && (
<div className="text-center text-gray-500">
Discussion topics will appear here after you start recording. It
may take up to 5 minutes of conversation for the first topic to
appear.
</div>
)}
</div>
{finalSummary.summary && <FinalSummary text={finalSummary.summary} />}
</div>
{disconnected && <DisconnectedIndicator />}
<LiveTrancription text={transcriptionText} />
</>
);
}