import { useState } from "react"; import type { components } from "../../reflector-api"; import { parseMaybeNonEmptyString } from "../../lib/utils"; type UpdateTranscript = components["schemas"]["UpdateTranscript"]; type GetTranscriptWithParticipants = components["schemas"]["GetTranscriptWithParticipants"]; type GetTranscriptTopic = components["schemas"]["GetTranscriptTopic"]; import { useTranscriptUpdate, useTranscriptParticipants, } from "../../lib/apiHooks"; import { Heading, IconButton, Input, Flex, Spacer, Spinner, Box, Text, } from "@chakra-ui/react"; import { LuPen, LuCopy, LuCheck, LuDownload, LuVideo } from "react-icons/lu"; import ShareAndPrivacy from "./shareAndPrivacy"; import { buildTranscriptWithTopics } from "./buildTranscriptWithTopics"; import { toaster } from "../../components/ui/toaster"; import { useAuth } from "../../lib/AuthProvider"; import { API_URL } from "../../lib/apiClient"; type TranscriptTitle = { title: string; transcriptId: string; onUpdate: (newTitle: string) => void; // share props transcript: GetTranscriptWithParticipants | null; topics: GetTranscriptTopic[] | null; finalSummaryElement: HTMLDivElement | null; // video props hasCloudVideo?: boolean; videoExpanded?: boolean; onVideoToggle?: () => void; videoNewBadge?: boolean; }; const TranscriptTitle = (props: TranscriptTitle) => { const [displayedTitle, setDisplayedTitle] = useState(props.title); const [preEditTitle, setPreEditTitle] = useState(props.title); const [isEditing, setIsEditing] = useState(false); const [downloading, setDownloading] = useState(false); const updateTranscriptMutation = useTranscriptUpdate(); const auth = useAuth(); const accessToken = auth.status === "authenticated" ? auth.accessToken : null; const userId = auth.status === "authenticated" ? auth.user?.id : null; const isOwner = !!(userId && userId === props.transcript?.user_id); const handleDownloadZip = async () => { if (!props.transcriptId || downloading) return; setDownloading(true); try { const headers: Record = {}; if (accessToken) { headers["Authorization"] = `Bearer ${accessToken}`; } const resp = await fetch( `${API_URL}/v1/transcripts/${props.transcriptId}/download/zip`, { headers }, ); if (!resp.ok) throw new Error("Download failed"); const blob = await resp.blob(); const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = `transcript_${props.transcriptId.split("-")[0]}.zip`; a.click(); URL.revokeObjectURL(url); } catch (err) { console.error("Failed to download zip:", err); } finally { setDownloading(false); } }; const participantsQuery = useTranscriptParticipants( props.transcript?.id ? parseMaybeNonEmptyString(props.transcript.id) : null, ); const updateTitle = async (newTitle: string, transcriptId: string) => { try { const requestBody: UpdateTranscript = { title: newTitle, }; await updateTranscriptMutation.mutateAsync({ params: { path: { transcript_id: transcriptId }, }, body: requestBody, }); props.onUpdate(newTitle); console.log("Updated transcript title:", newTitle); } catch (err) { console.error("Failed to update transcript:", err); // Revert title on error setDisplayedTitle(preEditTitle); } }; const handleTitleClick = () => { const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent); if (isMobile) { // Use prompt const newTitle = prompt("Please enter the new title:", displayedTitle); if (newTitle !== null) { setDisplayedTitle(newTitle); updateTitle(newTitle, props.transcriptId); } } else { setPreEditTitle(displayedTitle); setIsEditing(true); } }; const handleBlur = () => { if (displayedTitle !== preEditTitle) { updateTitle(displayedTitle, props.transcriptId); } setIsEditing(false); }; const handleChange = (e: React.ChangeEvent) => { setDisplayedTitle(e.target.value); }; const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === "Enter") { updateTitle(displayedTitle, props.transcriptId); setIsEditing(false); } else if (e.key === "Escape") { setDisplayedTitle(preEditTitle); setIsEditing(false); } }; return ( <> {isEditing ? ( ) : ( {displayedTitle} {props.transcript && props.topics && ( <> { const text = buildTranscriptWithTopics( props.topics || [], participantsQuery?.data || null, props.transcript?.title || null, ); if (!text) return; navigator.clipboard .writeText(text) .then(() => { toaster .create({ placement: "top", duration: 2500, render: () => (
Transcript copied
), }) .then(() => {}); }) .catch(() => {}); }} >
{isOwner && ( {downloading ? : } )} {props.hasCloudVideo && props.onVideoToggle && ( {props.videoNewBadge && ( new )} )} )}
)} ); }; export default TranscriptTitle;