fix selection (for good?)

This commit is contained in:
Sara
2023-12-12 11:36:40 +01:00
parent 369a16b4a5
commit 4d5d76fe8f
3 changed files with 98 additions and 30 deletions

View File

@@ -4,7 +4,6 @@ import { useEffect, useRef, useState } from "react";
import { Participant } from "../../../../api"; import { Participant } from "../../../../api";
import getApi from "../../../../lib/getApi"; import getApi from "../../../../lib/getApi";
import { UseParticipants } from "../../useParticipants"; import { UseParticipants } from "../../useParticipants";
import { unescapeLeadingUnderscores } from "typescript";
type ParticipantList = { type ParticipantList = {
participants: UseParticipants; participants: UseParticipants;
@@ -27,6 +26,7 @@ const ParticipantList = ({
const [participantInput, setParticipantInput] = useState(""); const [participantInput, setParticipantInput] = useState("");
const inputRef = useRef<HTMLInputElement>(null); const inputRef = useRef<HTMLInputElement>(null);
const [selectedSpeaker, setSelectedSpeaker] = stateSelectedSpeaker; const [selectedSpeaker, setSelectedSpeaker] = stateSelectedSpeaker;
const [selectedParticipant, setSelectedParticipant] = useState<Participant>();
const [action, setAction] = useState< const [action, setAction] = useState<
"Create" | "Create to rename" | "Create and assign" | "Rename" | null "Create" | "Create to rename" | "Create and assign" | "Rename" | null
>(null); >(null);
@@ -47,9 +47,11 @@ const ParticipantList = ({
); );
if (participant) { if (participant) {
setParticipantInput(participant.name); setParticipantInput(participant.name);
setSelectedParticipant(participant);
inputRef.current?.focus(); inputRef.current?.focus();
setAction("Rename"); setAction("Rename");
} else { } else if (!selectedParticipant) {
setSelectedParticipant(undefined);
setParticipantInput(""); setParticipantInput("");
inputRef.current?.focus(); inputRef.current?.focus();
setAction("Create to rename"); setAction("Create to rename");
@@ -59,6 +61,10 @@ const ParticipantList = ({
setParticipantInput(""); setParticipantInput("");
inputRef.current?.focus(); inputRef.current?.focus();
setAction("Create and assign"); setAction("Create and assign");
setSelectedParticipant(undefined);
}
if (!selectedTime && !selectedSpeaker) {
setAction(null);
} }
} }
}, [selectedTime, selectedSpeaker]); }, [selectedTime, selectedSpeaker]);
@@ -78,6 +84,12 @@ const ParticipantList = ({
setOneMatch(undefined); setOneMatch(undefined);
} }
} }
if (participantInput && !action) {
setAction("Create");
}
if (!participantInput) {
setAction(null);
}
}, [participantInput]); }, [participantInput]);
useEffect(() => { useEffect(() => {
@@ -88,11 +100,15 @@ const ParticipantList = ({
setOneMatch(undefined); setOneMatch(undefined);
setParticipantInput(""); setParticipantInput("");
} }
} else if (e.key === "Enter") {
doAction();
} }
}; };
}); });
const doAction = (e) => { const doAction = (e?) => {
e?.preventDefault();
e?.stopPropagation();
if (!participants.response) return; if (!participants.response) return;
if (action == "Rename") { if (action == "Rename") {
const participant = participants.response.find( const participant = participants.response.find(
@@ -124,6 +140,7 @@ const ParticipantList = ({
}) })
.then(() => { .then(() => {
participants.refetch(); participants.refetch();
setParticipantInput("");
}); });
} else if (action == "Create and assign") { } else if (action == "Create and assign") {
setLoading(true); setLoading(true);
@@ -138,11 +155,22 @@ const ParticipantList = ({
.then((participant) => { .then((participant) => {
assignTo(participant)(); assignTo(participant)();
participants.refetch(); participants.refetch();
setParticipantInput("");
});
} else if (action == "Create") {
setLoading(true);
api
?.v1TranscriptAddParticipant({
createParticipant: {
name: participantInput,
},
transcriptId,
})
.then(() => {
participants.refetch();
setParticipantInput("");
}); });
} }
e.preventDefault();
console.log(e);
console.log(action);
}; };
const deleteParticipant = (participantId) => () => { const deleteParticipant = (participantId) => () => {
@@ -162,6 +190,7 @@ const ParticipantList = ({
(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 (selectedTime?.start == undefined || selectedTime?.end == undefined) if (selectedTime?.start == undefined || selectedTime?.end == undefined)
return; return;
api api
@@ -179,22 +208,29 @@ const ParticipantList = ({
}; };
const selectParticipant = (participant) => (e) => { const selectParticipant = (participant) => (e) => {
console.log(participant, e); setSelectedParticipant(participant);
setSelectedSpeaker(participant.speaker); setSelectedSpeaker(participant.speaker);
setAction("Rename");
setParticipantInput(participant.name);
}; };
return ( return (
<> <>
<form onSubmit={doAction}> <div>
<input <input
ref={inputRef} ref={inputRef}
onChange={(e) => setParticipantInput(e.target.value)} onChange={(e) => setParticipantInput(e.target.value)}
value={participantInput} value={participantInput}
/> />
<button type="submit"> {action && (
<FontAwesomeIcon icon={faArrowTurnDown} className="rotate-90 mr-2" /> <button onClick={doAction}>
{action} <FontAwesomeIcon
</button> icon={faArrowTurnDown}
</form> className="rotate-90 mr-2"
/>
{action}
</button>
)}
</div>
{participants.loading && ( {participants.loading && (
<FontAwesomeIcon <FontAwesomeIcon
@@ -214,7 +250,7 @@ const ParticipantList = ({
participant.name.startsWith(participantInput) participant.name.startsWith(participantInput)
? "bg-blue-100 " ? "bg-blue-100 "
: "") + : "") +
(participant.speaker == selectedSpeaker (participant.id == selectedParticipant?.id
? "border-blue-400 border" ? "border-blue-400 border"
: "") : "")
} }

View File

@@ -9,6 +9,7 @@ const TopicPlayer = ({ transcriptId, selectedTime, topicTime }) => {
useState<() => void>(); useState<() => void>();
//TODO shortcuts //TODO shortcuts
// TODO if selection changes while playing, don't play
useEffect(() => { useEffect(() => {
setEndTopicCallback( setEndTopicCallback(

View File

@@ -12,7 +12,7 @@ type Word = {
type WordBySpeaker = { speaker: number; words: Word[] }[]; type WordBySpeaker = { speaker: number; words: Word[] }[];
// TODO shortcuts // TODO shortcuts ?
// TODO fix key (using indexes might act up, not sure as we don't re-order per say) // TODO fix key (using indexes might act up, not sure as we don't re-order per say)
type TopicWordsProps = { type TopicWordsProps = {
@@ -63,6 +63,25 @@ const topicWords = ({
} }
}, [topicWithWords.response]); }, [topicWithWords.response]);
const getStartTimeFromFirstNode = (node, offset, reverse) => {
// if the first element is a word
return node.parentElement?.dataset["start"]
? // but after of the word (like on the blank space right of the word)
node.textContent?.length == offset
? // if next element is a word, we need the start of it
(node.parentElement?.nextElementSibling as any)?.dataset?.["start"] ||
// otherwise we get the start of the first word of the next paragraph
(
node.parentElement?.parentElement?.nextElementSibling
?.childNodes[1] as any
)?.dataset?.["start"] ||
(reverse ? 0 : 99)
: // otherwise it's just somewhere in the word and we get the start of the word
node.parentElement?.dataset["start"]
: // otherwise selection start is on a name and we get the start of the next word
(node.parentElement?.nextElementSibling as any)?.dataset["start"];
};
const onMouseUp = (e) => { const onMouseUp = (e) => {
let selection = window.getSelection(); let selection = window.getSelection();
if ( if (
@@ -102,35 +121,47 @@ const topicWords = ({
return; return;
} }
const anchorStart = anchorIsWord const anchorStart = getStartTimeFromFirstNode(
? anchorNode.parentElement?.dataset["start"] anchorNode,
: (selection.anchorNode.parentElement?.nextElementSibling as any) selection.anchorOffset,
?.dataset["start"]; false,
);
// if selection end on a word, we get the end time from the span that contains it
const focusEnd = const focusEnd =
selection.focusNode.parentElement?.dataset["end"] || selection.focusNode.parentElement?.dataset["end"] ||
// otherwise it was a name and we get the end of the last word of the previous paragraph
( (
selection.focusNode.parentElement?.parentElement selection.focusNode.parentElement?.parentElement
?.previousElementSibling?.lastElementChild as any ?.previousElementSibling?.lastElementChild as any
)?.dataset["end"]; )?.dataset["end"] ||
0;
const reverse = parseFloat(anchorStart) > parseFloat(focusEnd); const reverse = parseFloat(anchorStart) > parseFloat(focusEnd);
if (!reverse) { if (!reverse) {
setSelectedTime({ start: anchorStart, end: focusEnd }); setSelectedTime({
start: parseFloat(anchorStart),
end: parseFloat(focusEnd),
});
console.log("setting right"); console.log("setting right");
} else { } else {
const anchorEnd = anchorIsWord const anchorEnd =
? anchorNode.parentElement?.dataset["end"] anchorNode.parentElement?.dataset["end"] ||
: (selection.anchorNode.parentElement?.nextElementSibling as any)
?.dataset["end"];
const focusStart =
selection.focusNode.parentElement?.dataset["start"] ||
( (
selection.focusNode.parentElement?.parentElement selection.anchorNode.parentElement?.parentElement
?.previousElementSibling?.lastElementChild as any ?.previousElementSibling?.lastElementChild as any
)?.dataset["start"]; )?.dataset["end"];
const focusStart = getStartTimeFromFirstNode(
focusNode,
selection.focusOffset,
true,
);
setSelectedTime({ start: focusStart, end: anchorEnd }); setSelectedTime({ start: focusStart, end: anchorEnd });
console.log("setting reverse"); console.log("setting reverse");
} }
setSelectedSpeaker(); setSelectedSpeaker();
selection.empty(); selection.empty();
} }
@@ -147,7 +178,7 @@ const topicWords = ({
if (!topicWithWords.loading && wordsBySpeaker && participants.response) { if (!topicWithWords.loading && wordsBySpeaker && participants.response) {
return ( return (
<div onMouseUp={onMouseUp} onBlur={(e) => console.log(e)}> <div onMouseUp={onMouseUp} className="p-5 h-full w-full">
{wordsBySpeaker?.map((speakerWithWords, index) => ( {wordsBySpeaker?.map((speakerWithWords, index) => (
<p key={index}> <p key={index}>
<span <span