get participant list, select speaker

This commit is contained in:
Sara
2023-12-08 19:47:59 +01:00
parent c12f396b82
commit f1964b0542
4 changed files with 145 additions and 23 deletions

View File

@@ -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<TimeSlice>();
const [topicTime, setTopicTime] = useState<TimeSlice>();
const api = getApi();
const participants = useParticipants(transcriptId);
const stateSelectedSpeaker = useState<number>();
// 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 (
<div className="h-full grid grid-cols-2 gap-4">
@@ -44,6 +57,8 @@ export default function TranscriptCorrect(details: TranscriptCorrect) {
currentTopic={currentTopic}
transcriptId={transcriptId}
setTopicTime={setTopicTime}
stateSelectedSpeaker={stateSelectedSpeaker}
participants={participants}
/>
</div>
<div>
@@ -52,6 +67,7 @@ export default function TranscriptCorrect(details: TranscriptCorrect) {
selectedTime={selectedTime}
topicTime={topicTime}
/>
<button onClick={createParticipant}>Create</button>
</div>
</div>
);

View File

@@ -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 &&

View File

@@ -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<WordBySpeaker>();
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 (
<div>
{wordsBySpeaker?.map((speakerWithWords) => (
<p>
<span>Speaker&nbsp;{speakerWithWords.speaker}&nbsp;:&nbsp;</span>
{speakerWithWords.words.map((word) => (
<span data-start={word.start} data-end={word.end}>
{wordsBySpeaker?.map((speakerWithWords, index) => (
<p key={index}>
<span
data-speaker={speakerWithWords.speaker}
className={
selectedSpeaker == speakerWithWords.speaker
? "bg-yellow-200"
: ""
}
>
{getSpeakerName(speakerWithWords.speaker)}&nbsp;:&nbsp;
</span>
{speakerWithWords.words.map((word, index) => (
<span data-start={word.start} data-end={word.end} key={index}>
{word.text}
</span>
))}

View File

@@ -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<GetTranscript | null>(null);
const [loading, setLoading] = useState<boolean>(true);
const [error, setErrorState] = useState<Error | null>(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;