mirror of
https://github.com/Monadical-SAS/reflector.git
synced 2025-12-20 20:29:06 +00:00
prevent double action
This commit is contained in:
@@ -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">
|
||||||
|
|||||||
@@ -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 &&
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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(() => {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user