From bce8fa73edc0020891a937ba2c7ba98ce6a4a458 Mon Sep 17 00:00:00 2001 From: Sara Date: Fri, 12 Jan 2024 14:57:41 +0100 Subject: [PATCH 01/15] fix regions --- www/app/[domain]/transcripts/player.tsx | 15 ++++++--------- www/app/[domain]/transcripts/recorder.tsx | 7 +------ www/app/lib/custom-plugins/regions.ts | 18 ------------------ www/app/styles/recorder.js | 1 - 4 files changed, 7 insertions(+), 34 deletions(-) delete mode 100644 www/app/lib/custom-plugins/regions.ts diff --git a/www/app/[domain]/transcripts/player.tsx b/www/app/[domain]/transcripts/player.tsx index 632dfd8a..c8ffd5ea 100644 --- a/www/app/[domain]/transcripts/player.tsx +++ b/www/app/[domain]/transcripts/player.tsx @@ -1,7 +1,7 @@ import React, { useRef, useEffect, useState } from "react"; import WaveSurfer from "wavesurfer.js"; -import CustomRegionsPlugin from "../../lib/custom-plugins/regions"; +import RegionsPlugin from "wavesurfer.js/dist/plugins/regions.esm.js"; import { formatTime } from "../../lib/time"; import { Topic } from "./webSocketTypes"; @@ -24,9 +24,7 @@ export default function Player(props: PlayerProps) { const [wavesurfer, setWavesurfer] = useState(null); const [isPlaying, setIsPlaying] = useState(false); const [currentTime, setCurrentTime] = useState(0); - const [waveRegions, setWaveRegions] = useState( - null, - ); + const [waveRegions, setWaveRegions] = useState(null); const [activeTopic, setActiveTopic] = props.useActiveTopic; const topicsRef = useRef(props.topics); // Waveform setup @@ -39,12 +37,13 @@ export default function Player(props: PlayerProps) { // This is not ideal, but it works for now. const _wavesurfer = WaveSurfer.create({ container: waveformRef.current, - peaks: props.waveform, + peaks: props.waveform.data, hideScrollbar: true, autoCenter: true, barWidth: 2, height: "auto", - duration: props.mediaDuration, + duration: Math.floor(props.mediaDuration / 1000), + media: props.media, ...waveSurferStyles.player, }); @@ -64,12 +63,10 @@ export default function Player(props: PlayerProps) { }); _wavesurfer.on("timeupdate", setCurrentTime); - setWaveRegions(_wavesurfer.registerPlugin(CustomRegionsPlugin.create())); + setWaveRegions(_wavesurfer.registerPlugin(RegionsPlugin.create())); _wavesurfer.toggleInteraction(true); - _wavesurfer.setMediaElement(props.media); - setWavesurfer(_wavesurfer); return () => { diff --git a/www/app/[domain]/transcripts/recorder.tsx b/www/app/[domain]/transcripts/recorder.tsx index 562f6a76..8ab6d9c1 100644 --- a/www/app/[domain]/transcripts/recorder.tsx +++ b/www/app/[domain]/transcripts/recorder.tsx @@ -1,8 +1,7 @@ import React, { useRef, useEffect, useState } from "react"; import WaveSurfer from "wavesurfer.js"; -import RecordPlugin from "../../lib/custom-plugins/record"; -import CustomRegionsPlugin from "../../lib/custom-plugins/regions"; +import RecordPlugin from "wavesurfer.js/dist/plugins/record.esm.js"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faMicrophone } from "@fortawesome/free-solid-svg-icons"; @@ -33,9 +32,6 @@ export default function Recorder(props: RecorderProps) { const [currentTime, setCurrentTime] = useState(0); const [timeInterval, setTimeInterval] = useState(null); const [duration, setDuration] = useState(0); - const [waveRegions, setWaveRegions] = useState( - null, - ); const [deviceId, setDeviceId] = useState(null); const [recordStarted, setRecordStarted] = useState(false); const [showDevices, setShowDevices] = useState(false); @@ -119,7 +115,6 @@ export default function Recorder(props: RecorderProps) { _wavesurfer.on("timeupdate", setCurrentTime); setRecord(_wavesurfer.registerPlugin(RecordPlugin.create())); - setWaveRegions(_wavesurfer.registerPlugin(CustomRegionsPlugin.create())); setWavesurfer(_wavesurfer); diff --git a/www/app/lib/custom-plugins/regions.ts b/www/app/lib/custom-plugins/regions.ts deleted file mode 100644 index dff05f3b..00000000 --- a/www/app/lib/custom-plugins/regions.ts +++ /dev/null @@ -1,18 +0,0 @@ -// Source code: https://github.com/katspaugh/wavesurfer.js/blob/fa2bcfe/src/plugins/regions.ts - -import RegionsPlugin, { - RegionsPluginOptions, -} from "wavesurfer.js/dist/plugins/regions"; - -class CustomRegionsPlugin extends RegionsPlugin { - public static create(options?: RegionsPluginOptions) { - return new CustomRegionsPlugin(options); - } - - constructor(options?: RegionsPluginOptions) { - super(options); - this["avoidOverlapping"] = () => {}; - } -} - -export default CustomRegionsPlugin; diff --git a/www/app/styles/recorder.js b/www/app/styles/recorder.js index dc9ace60..b31b9a61 100644 --- a/www/app/styles/recorder.js +++ b/www/app/styles/recorder.js @@ -15,7 +15,6 @@ export const waveSurferStyles = { font-size: 0.7rem; border-radius: 0 3px 3px 0; - position: absolute; width: 100px; max-width: fit-content; cursor: pointer; From fa4935c4548a44f0c4dae50c80f81ada3d605093 Mon Sep 17 00:00:00 2001 From: Sara Date: Mon, 15 Jan 2024 17:49:27 +0100 Subject: [PATCH 02/15] fix recording --- www/app/[domain]/transcripts/recorder.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/app/[domain]/transcripts/recorder.tsx b/www/app/[domain]/transcripts/recorder.tsx index 8ab6d9c1..3ef96d62 100644 --- a/www/app/[domain]/transcripts/recorder.tsx +++ b/www/app/[domain]/transcripts/recorder.tsx @@ -1,7 +1,7 @@ import React, { useRef, useEffect, useState } from "react"; import WaveSurfer from "wavesurfer.js"; -import RecordPlugin from "wavesurfer.js/dist/plugins/record.esm.js"; +import RecordPlugin from "../../lib/custom-plugins/record"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faMicrophone } from "@fortawesome/free-solid-svg-icons"; From 69ae5b281e67090fe23dc8c4675d7bc586bb9bfc Mon Sep 17 00:00:00 2001 From: Sara Date: Thu, 18 Jan 2024 14:05:34 +0100 Subject: [PATCH 03/15] refactor past meeting --- www/app/[domain]/browse/page.tsx | 1 + .../{ => [transcriptId]}/finalSummary.tsx | 118 +++++++--------- .../transcripts/[transcriptId]/page.tsx | 132 ++++++++---------- www/app/[domain]/transcripts/shareLink.tsx | 9 +- .../[domain]/transcripts/shareTranscript.tsx | 108 ++++++++++++++ .../[domain]/transcripts/useTranscriptList.ts | 1 + www/app/lib/time.ts | 2 + 7 files changed, 219 insertions(+), 152 deletions(-) rename www/app/[domain]/transcripts/{ => [transcriptId]}/finalSummary.tsx (54%) create mode 100644 www/app/[domain]/transcripts/shareTranscript.tsx diff --git a/www/app/[domain]/browse/page.tsx b/www/app/[domain]/browse/page.tsx index 211c927b..16321f9b 100644 --- a/www/app/[domain]/browse/page.tsx +++ b/www/app/[domain]/browse/page.tsx @@ -100,6 +100,7 @@ export default function TranscriptBrowser() { api .v1TranscriptDelete(transcriptToDeleteId) .then(() => { + refetch(); setDeletionLoading(false); refetch(); onCloseDeletion(); diff --git a/www/app/[domain]/transcripts/finalSummary.tsx b/www/app/[domain]/transcripts/[transcriptId]/finalSummary.tsx similarity index 54% rename from www/app/[domain]/transcripts/finalSummary.tsx rename to www/app/[domain]/transcripts/[transcriptId]/finalSummary.tsx index 6ad90b14..8d7311f1 100644 --- a/www/app/[domain]/transcripts/finalSummary.tsx +++ b/www/app/[domain]/transcripts/[transcriptId]/finalSummary.tsx @@ -1,25 +1,38 @@ -import { useRef, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import React from "react"; import Markdown from "react-markdown"; -import "../../styles/markdown.css"; -import { featureEnabled } from "../domainContext"; -import { UpdateTranscript } from "../../api"; -import useApi from "../../lib/useApi"; +import "../../../styles/markdown.css"; +import { UpdateTranscript } from "../../../api"; +import useApi from "../../../lib/useApi"; +import useTranscript from "../useTranscript"; +import useTopics from "../useTopics"; +import { Box, Flex, IconButton, Modal, ModalContent } from "@chakra-ui/react"; +import { FaShare } from "react-icons/fa"; +import ShareTranscript from "../shareTranscript"; type FinalSummaryProps = { - summary: string; - fullTranscript: string; transcriptId: string; - openZulipModal: () => void; }; export default function FinalSummary(props: FinalSummaryProps) { + const transcript = useTranscript(props.transcriptId); + const topics = useTopics(props.transcriptId); + const finalSummaryRef = useRef(null); - const [isCopiedSummary, setIsCopiedSummary] = useState(false); - const [isCopiedTranscript, setIsCopiedTranscript] = useState(false); + const [isEditMode, setIsEditMode] = useState(false); - const [preEditSummary, setPreEditSummary] = useState(props.summary); - const [editedSummary, setEditedSummary] = useState(props.summary); + const [preEditSummary, setPreEditSummary] = useState(""); + const [editedSummary, setEditedSummary] = useState(""); + + const [showShareModal, setShowShareModal] = useState(false); + + useEffect(() => { + setEditedSummary(transcript.response?.long_summary || ""); + }, [transcript.response?.long_summary]); + + if (!topics.topics || !transcript.response) { + return null; + } const updateSummary = async (newSummary: string, transcriptId: string) => { try { @@ -37,28 +50,6 @@ export default function FinalSummary(props: FinalSummaryProps) { } }; - const onCopySummaryClick = () => { - let text_to_copy = finalSummaryRef.current?.innerText; - - text_to_copy && - navigator.clipboard.writeText(text_to_copy).then(() => { - setIsCopiedSummary(true); - // Reset the copied state after 2 seconds - setTimeout(() => setIsCopiedSummary(false), 2000); - }); - }; - - const onCopyTranscriptClick = () => { - let text_to_copy = props.fullTranscript; - - text_to_copy && - navigator.clipboard.writeText(text_to_copy).then(() => { - setIsCopiedTranscript(true); - // Reset the copied state after 2 seconds - setTimeout(() => setIsCopiedTranscript(false), 2000); - }); - }; - const onEditClick = () => { setPreEditSummary(editedSummary); setIsEditMode(true); @@ -119,17 +110,6 @@ export default function FinalSummary(props: FinalSummaryProps) { {!isEditMode && ( <> - {featureEnabled("sendToZulip") && ( - - )} - - - + } + onClick={() => setShowShareModal(true)} + aria-label="Share" + /> + {showShareModal && ( + setShowShareModal(false)} + size="xl" + > + + + + + )} )} @@ -177,9 +153,9 @@ export default function FinalSummary(props: FinalSummaryProps) { /> ) : ( -

+

{editedSummary} -

+
)} ); diff --git a/www/app/[domain]/transcripts/[transcriptId]/page.tsx b/www/app/[domain]/transcripts/[transcriptId]/page.tsx index d0389fd9..1efb6c43 100644 --- a/www/app/[domain]/transcripts/[transcriptId]/page.tsx +++ b/www/app/[domain]/transcripts/[transcriptId]/page.tsx @@ -8,7 +8,7 @@ import { TopicList } from "../topicList"; import { Topic } from "../webSocketTypes"; import React, { useEffect, useState } from "react"; import "../../../styles/button.css"; -import FinalSummary from "../finalSummary"; +import FinalSummary from "./finalSummary"; import ShareLink from "../shareLink"; import QRCode from "react-qr-code"; import TranscriptTitle from "../transcriptTitle"; @@ -17,7 +17,16 @@ import Player from "../player"; import WaveformLoading from "../waveformLoading"; import { useRouter } from "next/navigation"; import { featureEnabled } from "../../domainContext"; -import { toShareMode } from "../../../lib/shareMode"; +import { + Box, + Button, + Flex, + Grid, + GridItem, + IconButton, + Text, +} from "@chakra-ui/react"; +import { FaPen } from "react-icons/fa"; type TranscriptDetails = { params: { @@ -34,7 +43,6 @@ export default function TranscriptDetails(details: TranscriptDetails) { const waveform = useWaveform(transcriptId); const useActiveTopic = useState(null); const mp3 = useMp3(transcriptId); - const [showModal, setShowModal] = useState(false); useEffect(() => { const statusToRedirect = ["idle", "recording", "processing"]; @@ -43,18 +51,11 @@ export default function TranscriptDetails(details: TranscriptDetails) { // Shallow redirection does not work on NextJS 13 // https://github.com/vercel/next.js/discussions/48110 // https://github.com/vercel/next.js/discussions/49540 - router.push(newUrl, undefined); + router.replace(newUrl); // history.replaceState({}, "", newUrl); } }, [transcript.response?.status]); - const fullTranscript = - topics.topics - ?.map((topic) => topic.transcript) - .join("\n\n") - .replace(/ +/g, " ") - .trim() || ""; - if (transcript.error || topics?.error) { return ( - {featureEnabled("sendToZulip") && ( - setShowModal(v)} - /> - )} -
- {transcript?.response?.title && ( - + + + + + } aria-label="Edit Transcript Title" /> + + - )} + {transcript.response.long_summary ? ( + <> + + + ) : ( + +
+ {transcript.response.status == "processing" ? ( + Loading Transcript + ) : ( + + There was an error generating the final summary, please come + back later + + )} +
+
+ )} +
{waveform.waveform && mp3.media ? ( )} -
-
- - -
-
- {transcript.response.long_summary ? ( - setShowModal(true)} - /> - ) : ( -
- {transcript.response.status == "processing" ? ( -

Loading Transcript

- ) : ( -

- There was an error generating the final summary, please come - back later -

- )} -
- )} -
- -
-
- -
-
- -
-
-
-
- + + ); } diff --git a/www/app/[domain]/transcripts/shareLink.tsx b/www/app/[domain]/transcripts/shareLink.tsx index 7e0d592d..57b53d3a 100644 --- a/www/app/[domain]/transcripts/shareLink.tsx +++ b/www/app/[domain]/transcripts/shareLink.tsx @@ -10,9 +10,10 @@ import { faSpinner } from "@fortawesome/free-solid-svg-icons"; import { UpdateTranscript } from "../../api"; import { ShareMode, toShareMode } from "../../lib/shareMode"; import useApi from "../../lib/useApi"; + type ShareLinkProps = { transcriptId: string; - userId: string | null; + transcriptUserId: string | null; shareMode: ShareMode; }; @@ -24,16 +25,16 @@ const ShareLink = (props: ShareLinkProps) => { const [isOwner, setIsOwner] = useState(false); const [shareMode, setShareMode] = useState(props.shareMode); const [shareLoading, setShareLoading] = useState(false); - const userinfo = useFiefUserinfo(); const api = useApi(); + const userId = useFiefUserinfo()?.sub; useEffect(() => { setCurrentUrl(window.location.href); }, []); useEffect(() => { - setIsOwner(!!(requireLogin && userinfo?.sub === props.userId)); - }, [userinfo, props.userId]); + setIsOwner(!!(requireLogin && userId === props.transcriptUserId)); + }, [userId, props.transcriptUserId]); const handleCopyClick = () => { if (inputRef.current) { diff --git a/www/app/[domain]/transcripts/shareTranscript.tsx b/www/app/[domain]/transcripts/shareTranscript.tsx new file mode 100644 index 00000000..5a61461e --- /dev/null +++ b/www/app/[domain]/transcripts/shareTranscript.tsx @@ -0,0 +1,108 @@ +import { useState } from "react"; +import { featureEnabled } from "../domainContext"; +import ShareModal from "./[transcriptId]/shareModal"; +import ShareLink from "./shareLink"; +import QRCode from "react-qr-code"; +import { toShareMode } from "../../lib/shareMode"; +import { GetTranscript, GetTranscriptTopic } from "../../api"; + +type ShareTranscriptProps = { + finalSummaryRef: any; + transcriptResponse: GetTranscript; + topicsResponse: GetTranscriptTopic[]; +}; + +export default function ShareTranscript(props: ShareTranscriptProps) { + const [showModal, setShowModal] = useState(false); + const [isCopiedSummary, setIsCopiedSummary] = useState(false); + const [isCopiedTranscript, setIsCopiedTranscript] = useState(false); + + const onCopySummaryClick = () => { + let text_to_copy = props.finalSummaryRef.current?.innerText; + + text_to_copy && + navigator.clipboard.writeText(text_to_copy).then(() => { + setIsCopiedSummary(true); + // Reset the copied state after 2 seconds + setTimeout(() => setIsCopiedSummary(false), 2000); + }); + }; + + const onCopyTranscriptClick = () => { + let text_to_copy = + props.topicsResponse + ?.map((topic) => topic.transcript) + .join("\n\n") + .replace(/ +/g, " ") + .trim() || ""; + + text_to_copy && + navigator.clipboard.writeText(text_to_copy).then(() => { + setIsCopiedTranscript(true); + // Reset the copied state after 2 seconds + setTimeout(() => setIsCopiedTranscript(false), 2000); + }); + }; + + return ( +
+ <> + {featureEnabled("sendToZulip") && ( + + )} + + + + {featureEnabled("sendToZulip") && ( + setShowModal(v)} + /> + )} + + + + + +
+ ); +} diff --git a/www/app/[domain]/transcripts/useTranscriptList.ts b/www/app/[domain]/transcripts/useTranscriptList.ts index 2cfab374..1e55cf7a 100644 --- a/www/app/[domain]/transcripts/useTranscriptList.ts +++ b/www/app/[domain]/transcripts/useTranscriptList.ts @@ -20,6 +20,7 @@ const useTranscriptList = (page: number): TranscriptList => { const [refetchCount, setRefetchCount] = useState(0); const refetch = () => { + setLoading(true); setRefetchCount(refetchCount + 1); }; diff --git a/www/app/lib/time.ts b/www/app/lib/time.ts index 28d5d330..de383f37 100644 --- a/www/app/lib/time.ts +++ b/www/app/lib/time.ts @@ -1,3 +1,5 @@ +// TODO format duraction in be ? + export const formatTime = (seconds: number): string => { let hours = Math.floor(seconds / 3600); let minutes = Math.floor((seconds % 3600) / 60); From f36e8bc2cba76886ee41cf58662c9c94109bb7d5 Mon Sep 17 00:00:00 2001 From: Sara Date: Mon, 22 Jan 2024 16:18:04 +0100 Subject: [PATCH 04/15] past meeting transcript side --- .../transcripts/[transcriptId]/page.tsx | 19 +- www/app/[domain]/transcripts/topicList.tsx | 166 +++++++++++------- .../[domain]/transcripts/transcriptTitle.tsx | 40 ++++- www/app/theme.ts | 32 +++- 4 files changed, 175 insertions(+), 82 deletions(-) diff --git a/www/app/[domain]/transcripts/[transcriptId]/page.tsx b/www/app/[domain]/transcripts/[transcriptId]/page.tsx index 1efb6c43..309093aa 100644 --- a/www/app/[domain]/transcripts/[transcriptId]/page.tsx +++ b/www/app/[domain]/transcripts/[transcriptId]/page.tsx @@ -71,21 +71,30 @@ export default function TranscriptDetails(details: TranscriptDetails) { return ( <> - + - + - } aria-label="Edit Transcript Title" /> + {topics.length > 0 ? ( <> -

Topics

- {autoscroll && ( )} -
topic.id == activeTopic?.id), + ]} + variant="custom" + allowToggle > {topics.map((topic, index) => ( - + {" "} + {getSpeakerName(segment.speaker)}: + {" "} + {segment.text} + + ))} + + ) : ( + <>{topic.transcript} + )} + + ))} -
+ ) : ( -
- Discussion topics will appear here after you start recording. -
- It may take up to 5 minutes of conversation for the first topic to - appear. -
+ + + Discussion topics will appear here after you start recording. + + + It may take up to 5 minutes of conversation for the first topic to + appear. + + )} - +
); } diff --git a/www/app/[domain]/transcripts/transcriptTitle.tsx b/www/app/[domain]/transcripts/transcriptTitle.tsx index fa456049..14ce7c97 100644 --- a/www/app/[domain]/transcripts/transcriptTitle.tsx +++ b/www/app/[domain]/transcripts/transcriptTitle.tsx @@ -1,6 +1,8 @@ import { useState } from "react"; import { UpdateTranscript } from "../../api"; import useApi from "../../lib/useApi"; +import { Heading, IconButton, Input } from "@chakra-ui/react"; +import { FaPen } from "react-icons/fa"; type TranscriptTitle = { title: string; @@ -19,7 +21,6 @@ const TranscriptTitle = (props: TranscriptTitle) => { const requestBody: UpdateTranscript = { title: newTitle, }; - const api = useApi(); const updatedTranscript = await api?.v1TranscriptUpdate( transcriptId, requestBody, @@ -46,6 +47,12 @@ const TranscriptTitle = (props: TranscriptTitle) => { } }; + const handleBlur = () => { + if (displayedTitle !== preEditTitle) { + updateTitle(displayedTitle, props.transcriptId); + } + setIsEditing(false); + }; const handleChange = (e) => { setDisplayedTitle(e.target.value); }; @@ -63,21 +70,36 @@ const TranscriptTitle = (props: TranscriptTitle) => { return ( <> {isEditing ? ( - ) : ( -

- {displayedTitle} -

+ <> + + {displayedTitle} + + } + aria-label="Edit Transcript Title" + onClick={handleTitleClick} + fontSize={"15px"} + /> + )} ); diff --git a/www/app/theme.ts b/www/app/theme.ts index e951eef0..4dfea21d 100644 --- a/www/app/theme.ts +++ b/www/app/theme.ts @@ -1,7 +1,34 @@ // 1. Import `extendTheme` import { extendTheme } from "@chakra-ui/react"; -// 2. Call `extendTheme` and pass your custom values +import { accordionAnatomy } from "@chakra-ui/anatomy"; +import { createMultiStyleConfigHelpers, defineStyle } from "@chakra-ui/react"; + +const { definePartsStyle, defineMultiStyleConfig } = + createMultiStyleConfigHelpers(accordionAnatomy.keys); + +const custom = definePartsStyle({ + container: { + border: "0", + borderRadius: "8px", + backgroundColor: "white", + mb: 2, + mr: 2, + }, + panel: { + pl: 8, + pb: 0, + }, + button: { + justifyContent: "flex-start", + pl: 2, + }, +}); + +const accordionTheme = defineMultiStyleConfig({ + variants: { custom }, +}); + const theme = extendTheme({ colors: { blue: { @@ -29,6 +56,9 @@ const theme = extendTheme({ light: "#FFFFFF", dark: "#0C0D0E", }, + components: { + Accordion: accordionTheme, + }, }); export default theme; From 66211262d0131bd531672805392dd9ab4d7b9556 Mon Sep 17 00:00:00 2001 From: Sara Date: Mon, 22 Jan 2024 16:24:11 +0100 Subject: [PATCH 05/15] past meeting transcript details --- www/app/[domain]/transcripts/topicList.tsx | 34 ++++++++++------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/www/app/[domain]/transcripts/topicList.tsx b/www/app/[domain]/transcripts/topicList.tsx index 6dd7655a..512498de 100644 --- a/www/app/[domain]/transcripts/topicList.tsx +++ b/www/app/[domain]/transcripts/topicList.tsx @@ -1,9 +1,4 @@ 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 { Topic } from "./webSocketTypes"; @@ -17,10 +12,8 @@ import { AccordionPanel, Box, Flex, - Icon, Text, } from "@chakra-ui/react"; -import { FaChevronDown, FaChevronRight } from "react-icons/fa"; type TopicListProps = { topics: Topic[]; @@ -155,21 +148,26 @@ export function TopicList({ pb={2} lineHeight={"1.3"} > - + [{formatTime(segment.start)}] - - + {" "} {getSpeakerName(segment.speaker)}: - {" "} + {" "} {segment.text} ))} From 68e708f62b93ffbe25454299477dd74c4f8e2377 Mon Sep 17 00:00:00 2001 From: Sara Date: Wed, 24 Jan 2024 13:57:16 +0100 Subject: [PATCH 06/15] player and share --- .../[transcriptId]/finalSummary.tsx | 162 ++++++++---------- .../transcripts/[transcriptId]/page.tsx | 33 ++-- www/app/[domain]/transcripts/player.tsx | 101 +++++++---- .../[domain]/transcripts/shareAndPrivacy.tsx | 148 ++++++++++++++++ www/app/[domain]/transcripts/shareCopy.tsx | 62 +++++++ www/app/[domain]/transcripts/shareLink.tsx | 120 +++---------- .../[domain]/transcripts/shareTranscript.tsx | 108 ------------ www/app/[domain]/transcripts/shareZulip.tsx | 30 ++++ www/app/[domain]/transcripts/topicList.tsx | 48 ++++-- www/app/providers.tsx | 2 +- www/app/styles/icons/pause.tsx | 14 ++ www/app/styles/icons/play.tsx | 12 ++ www/app/styles/recorder.js | 20 ++- www/app/{ => styles}/theme.ts | 54 +++--- 14 files changed, 516 insertions(+), 398 deletions(-) create mode 100644 www/app/[domain]/transcripts/shareAndPrivacy.tsx create mode 100644 www/app/[domain]/transcripts/shareCopy.tsx delete mode 100644 www/app/[domain]/transcripts/shareTranscript.tsx create mode 100644 www/app/[domain]/transcripts/shareZulip.tsx create mode 100644 www/app/styles/icons/pause.tsx create mode 100644 www/app/styles/icons/play.tsx rename www/app/{ => styles}/theme.ts (61%) diff --git a/www/app/[domain]/transcripts/[transcriptId]/finalSummary.tsx b/www/app/[domain]/transcripts/[transcriptId]/finalSummary.tsx index 8d7311f1..afde0aac 100644 --- a/www/app/[domain]/transcripts/[transcriptId]/finalSummary.tsx +++ b/www/app/[domain]/transcripts/[transcriptId]/finalSummary.tsx @@ -2,41 +2,50 @@ import { useEffect, useRef, useState } from "react"; import React from "react"; import Markdown from "react-markdown"; import "../../../styles/markdown.css"; -import { UpdateTranscript } from "../../../api"; +import { + GetTranscript, + GetTranscriptTopic, + UpdateTranscript, +} from "../../../api"; import useApi from "../../../lib/useApi"; -import useTranscript from "../useTranscript"; -import useTopics from "../useTopics"; -import { Box, Flex, IconButton, Modal, ModalContent } from "@chakra-ui/react"; -import { FaShare } from "react-icons/fa"; -import ShareTranscript from "../shareTranscript"; +import { + Flex, + Heading, + IconButton, + Button, + Textarea, + Spacer, +} from "@chakra-ui/react"; +import { FaPen } from "react-icons/fa"; +import { useError } from "../../../(errors)/errorContext"; +import ShareAndPrivacy from "../shareAndPrivacy"; type FinalSummaryProps = { - transcriptId: string; + transcriptResponse: GetTranscript; + topicsResponse: GetTranscriptTopic[]; }; export default function FinalSummary(props: FinalSummaryProps) { - const transcript = useTranscript(props.transcriptId); - const topics = useTopics(props.transcriptId); - const finalSummaryRef = useRef(null); const [isEditMode, setIsEditMode] = useState(false); const [preEditSummary, setPreEditSummary] = useState(""); const [editedSummary, setEditedSummary] = useState(""); - const [showShareModal, setShowShareModal] = useState(false); + const api = useApi(); + + const { setError } = useError(); useEffect(() => { - setEditedSummary(transcript.response?.long_summary || ""); - }, [transcript.response?.long_summary]); + setEditedSummary(props.transcriptResponse?.long_summary || ""); + }, [props.transcriptResponse?.long_summary]); - if (!topics.topics || !transcript.response) { + if (!props.topicsResponse || !props.transcriptResponse) { return null; } const updateSummary = async (newSummary: string, transcriptId: string) => { try { - const api = useApi(); const requestBody: UpdateTranscript = { long_summary: newSummary, }; @@ -47,6 +56,7 @@ export default function FinalSummary(props: FinalSummaryProps) { console.log("Updated long summary:", updatedTranscript); } catch (err) { console.error("Failed to update long summary:", err); + setError(err, "Failed to update long summary."); } }; @@ -61,7 +71,7 @@ export default function FinalSummary(props: FinalSummaryProps) { }; const onSaveClick = () => { - updateSummary(editedSummary, props.transcriptId); + updateSummary(editedSummary, props.transcriptResponse.id); setIsEditMode(false); }; @@ -77,86 +87,64 @@ export default function FinalSummary(props: FinalSummaryProps) { }; return ( -
-
-

- Final Summary -

+ + Summary -
- {isEditMode && ( - <> - - - - )} + {isEditMode && ( + <> + + + + + )} - {!isEditMode && ( - <> - - } - onClick={() => setShowShareModal(true)} - aria-label="Share" - /> - {showShareModal && ( - setShowShareModal(false)} - size="xl" - > - - - - - )} - - )} -
-
+ {!isEditMode && ( + <> + } + aria-label="Edit Summary" + onClick={onEditClick} + /> + + + + )} + {isEditMode ? ( -
-