prevent double action

This commit is contained in:
Sara
2023-12-12 15:18:22 +01:00
parent 89dfda29a5
commit 5e7eeb8f24
6 changed files with 126 additions and 86 deletions

View File

@@ -38,7 +38,6 @@ export function selectedTextIsTimeSlice(
export default function TranscriptCorrect(details: TranscriptCorrect) { export default function TranscriptCorrect(details: TranscriptCorrect) {
const transcriptId = details.params.transcriptId; const transcriptId = details.params.transcriptId;
const transcript = useTranscript(transcriptId);
const stateCurrentTopic = useState<GetTranscriptTopic>(); const stateCurrentTopic = useState<GetTranscriptTopic>();
const [currentTopic, _sct] = stateCurrentTopic; const [currentTopic, _sct] = stateCurrentTopic;
const topicWithWords = useTopicWithWords(currentTopic?.id, transcriptId); const topicWithWords = useTopicWithWords(currentTopic?.id, transcriptId);
@@ -47,7 +46,6 @@ export default function TranscriptCorrect(details: TranscriptCorrect) {
const participants = useParticipants(transcriptId); const participants = useParticipants(transcriptId);
const stateSelectedText = useState<SelectedText>(); const stateSelectedText = useState<SelectedText>();
const [selectedText, _sst] = stateSelectedText; const [selectedText, _sst] = stateSelectedText;
console.log(selectedText);
useEffect(() => { useEffect(() => {
if (currentTopic) { if (currentTopic) {
@@ -60,9 +58,6 @@ export default function TranscriptCorrect(details: TranscriptCorrect) {
} }
}, [currentTopic]); }, [currentTopic]);
// TODO BE
// Creating a participant and a speaker ?
return ( return (
<div className="h-full grid grid-cols-2 gap-4"> <div className="h-full grid grid-cols-2 gap-4">
<div className="flex flex-col h-full"> <div className="flex flex-col h-full">

View File

@@ -12,7 +12,7 @@ type ParticipantList = {
topicWithWords: any; topicWithWords: any;
stateSelectedText: any; stateSelectedText: any;
}; };
// NTH re-order list when searching
const ParticipantList = ({ const ParticipantList = ({
transcriptId, transcriptId,
participants, participants,
@@ -31,12 +31,6 @@ const ParticipantList = ({
>(null); >(null);
const [oneMatch, setOneMatch] = useState<Participant>(); const [oneMatch, setOneMatch] = useState<Participant>();
useEffect(() => {
if (loading) {
setLoading(false);
}
}, [participants.loading]);
useEffect(() => { useEffect(() => {
if (participants.response) { if (participants.response) {
if (selectedTextIsSpeaker(selectedText)) { if (selectedTextIsSpeaker(selectedText)) {
@@ -93,6 +87,7 @@ const ParticipantList = ({
useEffect(() => { useEffect(() => {
document.onkeyup = (e) => { document.onkeyup = (e) => {
if (loading || participants.loading || topicWithWords.loading) return;
if (e.key === "Enter" && e.ctrlKey) { if (e.key === "Enter" && e.ctrlKey) {
if (oneMatch) { if (oneMatch) {
if (action == "Create and assign") { if (action == "Create and assign") {
@@ -115,7 +110,9 @@ const ParticipantList = ({
const mergeSpeaker = const mergeSpeaker =
(speakerFrom, participantTo: Participant) => async () => { (speakerFrom, participantTo: Participant) => async () => {
if (loading || participants.loading || topicWithWords.loading) return;
if (participantTo.speaker) { if (participantTo.speaker) {
setLoading(true);
await api?.v1TranscriptMergeSpeaker({ await api?.v1TranscriptMergeSpeaker({
transcriptId, transcriptId,
speakerMerge: { speakerMerge: {
@@ -134,17 +131,25 @@ const ParticipantList = ({
topicWithWords.refetch(); topicWithWords.refetch();
setAction(null); setAction(null);
setParticipantInput(""); setParticipantInput("");
setLoading(false);
}; };
const doAction = (e?) => { const doAction = (e?) => {
e?.preventDefault(); e?.preventDefault();
e?.stopPropagation(); e?.stopPropagation();
if (!participants.response) return; if (
loading ||
participants.loading ||
topicWithWords.loading ||
!participants.response
)
return;
if (action == "Rename" && selectedTextIsSpeaker(selectedText)) { if (action == "Rename" && selectedTextIsSpeaker(selectedText)) {
const participant = participants.response.find( const participant = participants.response.find(
(p) => p.speaker == selectedText, (p) => p.speaker == selectedText,
); );
if (participant && participant.name !== participantInput) { if (participant && participant.name !== participantInput) {
setLoading(true);
api api
?.v1TranscriptUpdateParticipant({ ?.v1TranscriptUpdateParticipant({
participantId: participant.id, participantId: participant.id,
@@ -155,6 +160,7 @@ const ParticipantList = ({
}) })
.then(() => { .then(() => {
participants.refetch(); participants.refetch();
setLoading(false);
}); });
} }
} else if ( } else if (
@@ -173,6 +179,7 @@ const ParticipantList = ({
.then(() => { .then(() => {
participants.refetch(); participants.refetch();
setParticipantInput(""); setParticipantInput("");
setLoading(false);
}); });
} else if ( } else if (
action == "Create and assign" && action == "Create and assign" &&
@@ -187,8 +194,8 @@ const ParticipantList = ({
transcriptId, transcriptId,
}) })
.then((participant) => { .then((participant) => {
setLoading(false);
assignTo(participant)(); assignTo(participant)();
participants.refetch();
setParticipantInput(""); setParticipantInput("");
}); });
} else if (action == "Create") { } else if (action == "Create") {
@@ -203,31 +210,34 @@ const ParticipantList = ({
.then(() => { .then(() => {
participants.refetch(); participants.refetch();
setParticipantInput(""); setParticipantInput("");
setLoading(false);
}); });
} }
}; };
const deleteParticipant = (participantId) => (e) => { const deleteParticipant = (participantId) => (e) => {
e.stopPropagation(); e.stopPropagation();
if (!loading) { if (loading || participants.loading || topicWithWords.loading) return;
api setLoading(true);
?.v1TranscriptDeleteParticipant({ api
transcriptId, ?.v1TranscriptDeleteParticipant({
participantId, transcriptId,
}) participantId,
.then(() => { })
participants.refetch(); .then(() => {
}); participants.refetch();
} setLoading(false);
});
}; };
const assignTo = const assignTo =
(participant) => (e?: React.MouseEvent<HTMLButtonElement>) => { (participant) => (e?: React.MouseEvent<HTMLButtonElement>) => {
e?.preventDefault(); e?.preventDefault();
e?.stopPropagation(); e?.stopPropagation();
// fix participant that doesnt have a speaker (wait API) if (loading || participants.loading || topicWithWords.loading) return;
if (!selectedTextIsTimeSlice(selectedText)) return; if (!selectedTextIsTimeSlice(selectedText)) return;
setLoading(true);
api api
?.v1TranscriptAssignSpeaker({ ?.v1TranscriptAssignSpeaker({
speakerAssignment: { speakerAssignment: {
@@ -239,6 +249,8 @@ const ParticipantList = ({
}) })
.then(() => { .then(() => {
topicWithWords.refetch(); topicWithWords.refetch();
participants.refetch();
setLoading(false);
}); });
}; };
@@ -253,6 +265,7 @@ const ParticipantList = ({
setSelectedParticipant(undefined); setSelectedParticipant(undefined);
setSelectedText(undefined); setSelectedText(undefined);
setAction(null); setAction(null);
setParticipantInput("");
}; };
const preventClick = (e) => { const preventClick = (e) => {
e?.stopPropagation(); e?.stopPropagation();
@@ -279,12 +292,14 @@ const ParticipantList = ({
)} )}
</div> </div>
{participants.loading && ( {loading ||
<FontAwesomeIcon participants.loading ||
icon={faSpinner} (topicWithWords.loading && (
className="animate-spin-slow text-gray-300 h-8" <FontAwesomeIcon
/> icon={faSpinner}
)} className="animate-spin-slow text-gray-300 h-8"
/>
))}
{participants.response && ( {participants.response && (
<ul> <ul>
{participants.response.map((participant: Participant) => ( {participants.response.map((participant: Participant) => (
@@ -306,23 +321,25 @@ const ParticipantList = ({
<span>{participant.name}</span> <span>{participant.name}</span>
<div> <div>
{selectedTextIsSpeaker(selectedText) && !loading && ( {selectedTextIsSpeaker(selectedText) &&
<button onClick={mergeSpeaker(selectedText, participant)}> !selectedParticipant &&
{oneMatch && !loading && (
action == "Create to rename" && <button onClick={mergeSpeaker(selectedText, participant)}>
participant.name.startsWith(participantInput) && ( {oneMatch &&
<> action == "Create to rename" &&
{" "} participant.name.startsWith(participantInput) && (
<span>CTRL + </span>{" "} <>
<FontAwesomeIcon {" "}
icon={faArrowTurnDown} <span>CTRL + </span>{" "}
className="rotate-90 mr-2" <FontAwesomeIcon
/>{" "} icon={faArrowTurnDown}
</> className="rotate-90 mr-2"
)}{" "} />{" "}
Merge </>
</button> )}{" "}
)} Merge
</button>
)}
{selectedTextIsTimeSlice(selectedText) && !loading && ( {selectedTextIsTimeSlice(selectedText) && !loading && (
<button onClick={assignTo(participant)}> <button onClick={assignTo(participant)}>
{oneMatch && {oneMatch &&

View File

@@ -2,7 +2,6 @@ import { faArrowLeft, faArrowRight } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import useTopics from "../../useTopics"; import useTopics from "../../useTopics";
import { Dispatch, SetStateAction, useEffect } from "react"; import { Dispatch, SetStateAction, useEffect } from "react";
import { TranscriptTopic } from "../../../../api/models/TranscriptTopic";
import { GetTranscriptTopic } from "../../../../api"; import { GetTranscriptTopic } from "../../../../api";
type TopicHeader = { type TopicHeader = {
@@ -26,17 +25,33 @@ export default function TopicHeader({
} }
}, [topics.loading]); }, [topics.loading]);
if (topics.topics && currentTopic) { const number = topics.topics?.findIndex(
const number = topics.topics.findIndex( (topic) => topic.id == currentTopic?.id,
(topic) => topic.id == currentTopic.id, );
); const canGoPrevious = typeof number == "number" && number > 0;
const canGoPrevious = number > 0; const total = topics.topics?.length;
const total = topics.topics.length; const canGoNext = total && typeof number == "number" && number + 1 < total;
const canGoNext = total && number < total + 1;
const onPrev = () => setCurrentTopic(topics.topics?.at(number - 1)); const onPrev = () =>
const onNext = () => setCurrentTopic(topics.topics?.at(number + 1)); canGoPrevious && setCurrentTopic(topics.topics?.at(number - 1));
const onNext = () =>
canGoNext && setCurrentTopic(topics.topics?.at(number + 1));
const keyHandler = (e) => {
if (e.key == "ArrowLeft") {
onPrev();
} else if (e.key == "ArrowRight") {
onNext();
}
};
useEffect(() => {
document.addEventListener("keyup", keyHandler);
return () => {
document.removeEventListener("keyup", keyHandler);
};
});
if (topics.topics && currentTopic && typeof number == "number") {
return ( return (
<div className="flex flex-row"> <div className="flex flex-row">
<button <button

View File

@@ -8,8 +8,23 @@ const TopicPlayer = ({ transcriptId, selectedTime, topicTime }) => {
const [endSelectionCallback, setEndSelectionCallback] = const [endSelectionCallback, setEndSelectionCallback] =
useState<() => void>(); useState<() => void>();
//TODO shortcuts const keyHandler = (e) => {
// TODO if selection changes while playing, don't play if (e.key == "!") {
if (isPlaying) {
mp3.media?.pause();
setIsPlaying(false);
} else {
mp3.media?.play();
setIsPlaying(true);
}
}
};
useEffect(() => {
document.addEventListener("keyup", keyHandler);
return () => {
document.removeEventListener("keyup", keyHandler);
};
});
useEffect(() => { useEffect(() => {
setEndTopicCallback( setEndTopicCallback(
@@ -26,10 +41,17 @@ const TopicPlayer = ({ transcriptId, selectedTime, topicTime }) => {
} }
}, },
); );
if (mp3.media) { if (mp3.media && topicTime) {
mp3.media.currentTime = topicTime.start; mp3.media?.pause();
// there's no callback on pause but apparently changing the time while palying doesn't work... so here is a timeout
setTimeout(() => {
if (mp3.media) {
mp3.media.currentTime = topicTime.start;
}
}, 10);
setIsPlaying(false);
} }
}, [topicTime]); }, [topicTime, mp3.media]);
useEffect(() => { useEffect(() => {
endTopicCallback && endTopicCallback &&
@@ -43,17 +65,9 @@ const TopicPlayer = ({ transcriptId, selectedTime, topicTime }) => {
}; };
}, [endTopicCallback]); }, [endTopicCallback]);
const setEndTime = (time) => () => {
if (mp3.media && time && mp3.media.currentTime >= time) {
mp3.media.pause();
setIsPlaying(false);
mp3.media.removeEventListener("timeupdate", setEndTime);
}
};
const playSelection = () => { const playSelection = () => {
if (mp3.media && selectedTime?.start !== undefined) { if (mp3.media && selectedTime?.start !== undefined) {
mp3.media.currentTime = selectedTime?.start; mp3.media.currentTime = selectedTime.start;
setEndSelectionCallback( setEndSelectionCallback(
() => () =>
function () { function () {
@@ -64,8 +78,7 @@ const TopicPlayer = ({ transcriptId, selectedTime, topicTime }) => {
) { ) {
mp3.media.pause(); mp3.media.pause();
setIsPlaying(false); setIsPlaying(false);
endSelectionCallback &&
removeEventListener("timeupdate", endSelectionCallback);
setEndSelectionCallback(() => {}); setEndSelectionCallback(() => {});
} }
}, },
@@ -101,7 +114,7 @@ const TopicPlayer = ({ transcriptId, selectedTime, topicTime }) => {
setIsPlaying(true); setIsPlaying(true);
}; };
const pause = () => { const pause = (e) => {
mp3.media?.pause(); mp3.media?.pause();
setIsPlaying(false); setIsPlaying(false);
}; };

View File

@@ -38,9 +38,11 @@ const useParticipants = (transcriptId: string): UseParticipants => {
const [count, setCount] = useState(0); const [count, setCount] = useState(0);
const refetch = () => { const refetch = () => {
setCount(count + 1); if (!loading) {
setLoading(true); setCount(count + 1);
setErrorState(null); setLoading(true);
setErrorState(null);
}
}; };
useEffect(() => { useEffect(() => {

View File

@@ -42,7 +42,7 @@ const useTopicWithWords = (
): UseTopicWithWords => { ): UseTopicWithWords => {
const [response, setResponse] = const [response, setResponse] =
useState<GetTranscriptTopicWithWordsPerSpeaker | null>(null); useState<GetTranscriptTopicWithWordsPerSpeaker | null>(null);
const [loading, setLoading] = useState<boolean>(true); const [loading, setLoading] = useState<boolean>(false);
const [error, setErrorState] = useState<Error | null>(null); const [error, setErrorState] = useState<Error | null>(null);
const { setError } = useError(); const { setError } = useError();
const api = getApi(); const api = getApi();
@@ -50,15 +50,13 @@ const useTopicWithWords = (
const [count, setCount] = useState(0); const [count, setCount] = useState(0);
const refetch = () => { const refetch = () => {
setCount(count + 1); if (!loading) {
setLoading(true); setCount(count + 1);
setErrorState(null); setLoading(true);
setErrorState(null);
}
}; };
useEffect(() => {
setLoading(true);
}, [transcriptId, topicId]);
useEffect(() => { useEffect(() => {
if (!transcriptId || !topicId || !api) return; if (!transcriptId || !topicId || !api) return;