diff --git a/www/app/[domain]/transcripts/[transcriptId]/correct/page.tsx b/www/app/[domain]/transcripts/[transcriptId]/correct/page.tsx index 4f6ae512..c656b151 100644 --- a/www/app/[domain]/transcripts/[transcriptId]/correct/page.tsx +++ b/www/app/[domain]/transcripts/[transcriptId]/correct/page.tsx @@ -4,6 +4,8 @@ import useTranscript from "../../useTranscript"; import TopicHeader from "./topicHeader"; import TopicWords from "./topicWords"; import TopicPlayer from "./topicPlayer"; +import getApi from "../../../../lib/getApi"; +import useParticipants from "../../useParticipants"; type TranscriptCorrect = { params: { @@ -22,6 +24,9 @@ export default function TranscriptCorrect(details: TranscriptCorrect) { const [currentTopic, setCurrentTopic] = useState(""); const [selectedTime, setSelectedTime] = useState(); const [topicTime, setTopicTime] = useState(); + const api = getApi(); + const participants = useParticipants(transcriptId); + const stateSelectedSpeaker = useState(); // TODO BE // Get one topic with words @@ -30,6 +35,14 @@ export default function TranscriptCorrect(details: TranscriptCorrect) { // -> use full current topic instead of topicId here // -> remove time calculation and setting from TopicHeader // -> pass in topicTime to player directly + // Should we have participants by default, one for each speaker ? + + const createParticipant = () => { + api?.v1TranscriptAddParticipant({ + createParticipant: { name: "Samantha" }, + transcriptId, + }); + }; return (
@@ -44,6 +57,8 @@ export default function TranscriptCorrect(details: TranscriptCorrect) { currentTopic={currentTopic} transcriptId={transcriptId} setTopicTime={setTopicTime} + stateSelectedSpeaker={stateSelectedSpeaker} + participants={participants} />
@@ -52,6 +67,7 @@ export default function TranscriptCorrect(details: TranscriptCorrect) { selectedTime={selectedTime} topicTime={topicTime} /> +
); diff --git a/www/app/[domain]/transcripts/[transcriptId]/correct/topicPlayer.tsx b/www/app/[domain]/transcripts/[transcriptId]/correct/topicPlayer.tsx index a3c24f56..6b447a21 100644 --- a/www/app/[domain]/transcripts/[transcriptId]/correct/topicPlayer.tsx +++ b/www/app/[domain]/transcripts/[transcriptId]/correct/topicPlayer.tsx @@ -8,6 +8,8 @@ const TopicPlayer = ({ transcriptId, selectedTime, topicTime }) => { const [endSelectionCallback, setEndSelectionCallback] = useState<() => void>(); + //TODO shortcuts + useEffect(() => { setEndTopicCallback( () => @@ -29,7 +31,6 @@ const TopicPlayer = ({ transcriptId, selectedTime, topicTime }) => { }, [topicTime]); useEffect(() => { - console.log(endTopicCallback, "he"); endTopicCallback && mp3.media && mp3.media.addEventListener("timeupdate", endTopicCallback); @@ -77,7 +78,6 @@ const TopicPlayer = ({ transcriptId, selectedTime, topicTime }) => { endSelectionCallback && mp3.media && mp3.media.addEventListener("timeupdate", endSelectionCallback); - console.log(endSelectionCallback, "hi"); return () => { endSelectionCallback && mp3.media && diff --git a/www/app/[domain]/transcripts/[transcriptId]/correct/topicWords.tsx b/www/app/[domain]/transcripts/[transcriptId]/correct/topicWords.tsx index 585cccac..ea2f243d 100644 --- a/www/app/[domain]/transcripts/[transcriptId]/correct/topicWords.tsx +++ b/www/app/[domain]/transcripts/[transcriptId]/correct/topicWords.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from "react"; +import { useCallback, useEffect, useState } from "react"; import useTopicWithWords from "../../useTopicWithWords"; import WaveformLoading from "../../waveformLoading"; @@ -11,14 +11,21 @@ type Word = { type WordBySpeaker = { speaker: number; words: Word[] }[]; +// TODO fix selection reversed +// TODO shortcuts +// TODO fix key (using indexes might act up, not sure as we don't re-order per say) + const topicWords = ({ setSelectedTime, currentTopic, transcriptId, setTopicTime, + stateSelectedSpeaker, + participants, }) => { const topicWithWords = useTopicWithWords(currentTopic, transcriptId); const [wordsBySpeaker, setWordsBySpeaker] = useState(); + const [selectedSpeaker, setSelectedSpeaker] = stateSelectedSpeaker; useEffect(() => { if (topicWithWords.loading) { @@ -72,6 +79,7 @@ const topicWords = ({ const focusOffset = focusIsWord ? focusNode.textContent?.length : focusNode.parentNode?.lastChild?.textContent?.length; + if ( correctedAnchor && anchorOffset !== undefined && @@ -84,20 +92,32 @@ const topicWords = ({ correctedfocus, focusOffset, ); - setSelectedTime({ - start: - selection.anchorNode.parentElement?.dataset["start"] || - (selection.anchorNode.parentElement?.nextElementSibling as any) - ?.dataset["start"] || - 0, - end: - selection.focusNode.parentElement?.dataset["end"] || - ( - selection.focusNode.parentElement?.parentElement - ?.previousElementSibling?.lastElementChild as any - )?.dataset || - 0, - }); + + if ( + !anchorIsWord && + !focusIsWord && + anchorNode.parentElement == focusNode.parentElement + ) { + console.log(focusNode.parentElement?.dataset); + setSelectedSpeaker(focusNode.parentElement?.dataset["speaker"]); + setSelectedTime(undefined); + } else { + setSelectedSpeaker(undefined); + setSelectedTime({ + start: + selection.anchorNode.parentElement?.dataset["start"] || + (selection.anchorNode.parentElement?.nextElementSibling as any) + ?.dataset["start"] || + 0, + end: + selection.focusNode.parentElement?.dataset["end"] || + ( + selection.focusNode.parentElement?.parentElement + ?.previousElementSibling?.lastElementChild as any + )?.dataset || + 0, + }); + } } } if ( @@ -112,14 +132,34 @@ const topicWords = ({ }; }, []); - if (!topicWithWords.loading && wordsBySpeaker) { + const getSpeakerName = useCallback( + (speakerNumber: number) => { + return ( + participants.response.find((participant) => { + participant.speaker == speakerNumber; + }) || `Speaker ${speakerNumber}` + ); + }, + [participants], + ); + + if (!topicWithWords.loading && wordsBySpeaker && participants) { return (
- {wordsBySpeaker?.map((speakerWithWords) => ( -

- Speaker {speakerWithWords.speaker} :  - {speakerWithWords.words.map((word) => ( - + {wordsBySpeaker?.map((speakerWithWords, index) => ( +

+ + {getSpeakerName(speakerWithWords.speaker)} :  + + {speakerWithWords.words.map((word, index) => ( + {word.text} ))} diff --git a/www/app/[domain]/transcripts/useParticipants.ts b/www/app/[domain]/transcripts/useParticipants.ts new file mode 100644 index 00000000..cb9b556e --- /dev/null +++ b/www/app/[domain]/transcripts/useParticipants.ts @@ -0,0 +1,66 @@ +import { useEffect, useState } from "react"; +import { V1TranscriptGetParticipantsRequest } from "../../api/apis/DefaultApi"; +import { GetTranscript, Participant } from "../../api"; +import { useError } from "../../(errors)/errorContext"; +import getApi from "../../lib/getApi"; +import { shouldShowError } from "../../lib/errorUtils"; + +type ErrorParticipants = { + error: Error; + loading: false; + response: any; +}; + +type LoadingParticipants = { + response: any; + loading: true; + error: false; +}; + +type SuccessParticipants = { + response: Participant[]; + loading: false; + error: null; +}; + +const useParticipants = ( + transcriptId: string, +): ErrorParticipants | LoadingParticipants | SuccessParticipants => { + const [response, setResponse] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setErrorState] = useState(null); + const { setError } = useError(); + const api = getApi(); + + useEffect(() => { + if (!transcriptId || !api) return; + + setLoading(true); + const requestParameters: V1TranscriptGetParticipantsRequest = { + transcriptId, + }; + api + .v1TranscriptGetParticipants(requestParameters) + .then((result) => { + setResponse(result); + setLoading(false); + console.debug("Participants Loaded:", result); + }) + .catch((error) => { + const shouldShowHuman = shouldShowError(error); + if (shouldShowHuman) { + setError(error, "There was an error loading the participants"); + } else { + setError(error); + } + setErrorState(error); + }); + }, [transcriptId, !api]); + + return { response, loading, error } as + | ErrorParticipants + | LoadingParticipants + | SuccessParticipants; +}; + +export default useParticipants;