diff --git a/server/reflector/views/transcripts_participants.py b/server/reflector/views/transcripts_participants.py index fd08405c..d62d1dbf 100644 --- a/server/reflector/views/transcripts_participants.py +++ b/server/reflector/views/transcripts_participants.py @@ -41,6 +41,9 @@ async def transcript_get_participants( transcript_id, user_id=user_id ) + if transcript.participants is None: + return [] + return [ Participant.model_validate(participant) for participant in transcript.participants @@ -59,7 +62,7 @@ async def transcript_add_participant( ) # ensure the speaker is unique - if participant.speaker is not None: + if participant.speaker is not None and transcript.participants is not None: for p in transcript.participants: if p.speaker == participant.speaker: raise HTTPException( diff --git a/www/app/[domain]/layout.tsx b/www/app/[domain]/layout.tsx index 10297298..4e72ae06 100644 --- a/www/app/[domain]/layout.tsx +++ b/www/app/[domain]/layout.tsx @@ -91,7 +91,7 @@ export default async function RootLayout({ children, params }: LayoutProps) {
{/* Logo on the left */} diff --git a/www/app/[domain]/transcripts/[transcriptId]/correct/page.tsx b/www/app/[domain]/transcripts/[transcriptId]/correct/page.tsx index a0e55c30..5521c2db 100644 --- a/www/app/[domain]/transcripts/[transcriptId]/correct/page.tsx +++ b/www/app/[domain]/transcripts/[transcriptId]/correct/page.tsx @@ -1,5 +1,5 @@ "use client"; -import { useEffect, useState } from "react"; +import { useState } from "react"; import TopicHeader from "./topicHeader"; import TopicWords from "./topicWords"; import TopicPlayer from "./topicPlayer"; @@ -12,6 +12,7 @@ import getApi from "../../../../lib/getApi"; import useTranscript from "../../useTranscript"; import { useError } from "../../../../(errors)/errorContext"; import { useRouter } from "next/navigation"; +import { Box, Grid } from "@chakra-ui/react"; export type TranscriptCorrect = { params: { @@ -50,57 +51,76 @@ export default function TranscriptCorrect({ }; return ( -
-
+ + + + + + -
-
- {currentTopic ? ( - - ) : ( -
- )} - {participants.response && ( -
- - {!transcript.response?.reviewed && ( -
- -
- )} -
- )} -
-
+ + + {transcript.response && !transcript.response?.reviewed && ( +
+ +
+ )} + ); } diff --git a/www/app/[domain]/transcripts/[transcriptId]/correct/participantList.tsx b/www/app/[domain]/transcripts/[transcriptId]/correct/participantList.tsx index 24c97d04..bd70f0c8 100644 --- a/www/app/[domain]/transcripts/[transcriptId]/correct/participantList.tsx +++ b/www/app/[domain]/transcripts/[transcriptId]/correct/participantList.tsx @@ -6,6 +6,18 @@ import getApi from "../../../../lib/getApi"; import { UseParticipants } from "../../useParticipants"; import { selectedTextIsSpeaker, selectedTextIsTimeSlice } from "./types"; import { useError } from "../../../../(errors)/errorContext"; +import { + Box, + Button, + Flex, + Text, + UnorderedList, + Input, + Kbd, + Spinner, + ListItem, + Grid, +} from "@chakra-ui/react"; type ParticipantList = { participants: UseParticipants; @@ -13,7 +25,6 @@ type ParticipantList = { topicWithWords: any; stateSelectedText: any; }; -// NTH re-order list when searching const ParticipantList = ({ transcriptId, participants, @@ -58,12 +69,14 @@ const ParticipantList = ({ setAction("Create and assign"); setSelectedParticipant(undefined); } - if (typeof selectedText == undefined) { + + if (typeof selectedText == "undefined") { inputRef.current?.blur(); + setSelectedParticipant(undefined); setAction(null); } } - }, [selectedText, participants.response]); + }, [selectedText, !participants.response]); useEffect(() => { document.onkeyup = (e) => { @@ -250,6 +263,7 @@ const ParticipantList = ({ participants.refetch(); setParticipantInput(""); setLoading(false); + inputRef.current?.focus(); }) .catch((e) => { setError(e, "There was an error creating"); @@ -320,48 +334,56 @@ const ParticipantList = ({ } }; + const anyLoading = loading || participants.loading || topicWithWords.loading; + return ( -
-
-
- + + + - {action ? ( - - ) : ( -
- )} - {loading || - participants.loading || - (topicWithWords.loading && ( - - ))} -
+ +
{participants.response && ( -
    + {participants.response.map((participant: Participant) => ( -
  • 0 && selectedText && participant.name.startsWith(participantInput) @@ -371,69 +393,88 @@ const ParticipantList = ({ ? "bg-blue-200 border" : "") } - key={participant.id} + display="flex" + flexDirection="row" + justifyContent="space-between" + alignItems="center" + borderBottom="1px" + borderColor="gray.300" + py="2" + mx="2" + _last={{ borderBottom: "0" }} + key={participant.name} > - {participant.name} + {participant.name} -
    + {selectedTextIsSpeaker(selectedText) && !selectedParticipant && !loading && ( - + )} {selectedTextIsTimeSlice(selectedText) && !loading && ( - + )} - -
    -
  • + + + ))} -
+ )} -
-
+ + ); }; diff --git a/www/app/[domain]/transcripts/[transcriptId]/correct/soundWaveCss.tsx b/www/app/[domain]/transcripts/[transcriptId]/correct/soundWaveCss.tsx index 7e35787f..9b21b025 100644 --- a/www/app/[domain]/transcripts/[transcriptId]/correct/soundWaveCss.tsx +++ b/www/app/[domain]/transcripts/[transcriptId]/correct/soundWaveCss.tsx @@ -1,5 +1,5 @@ export default ({ playing }) => ( -
+
t.id == sessionTopic)) { setCurrentTopic(topics?.topics?.find((t) => t.id == sessionTopic)); - console.log("he", sessionTopic, !!sessionTopic); } else { setCurrentTopic(topics?.topics?.at(0)); - console.log("hi"); } } }, [topics.loading]); - // console.log(currentTopic) const number = topics.topics?.findIndex( (topic) => topic.id == currentTopic?.id, @@ -75,35 +83,85 @@ export default function TopicHeader({ }; }); - if (topics.topics && currentTopic && typeof number == "number") { - return ( -
- -

- {currentTopic.title}{" "} - - {number + 1}/{total} - -

- -
- ); - } - return null; + {canGoNext ? ( + + + + ) : ( + + )} + + + + ); } diff --git a/www/app/[domain]/transcripts/[transcriptId]/correct/topicPlayer.tsx b/www/app/[domain]/transcripts/[transcriptId]/correct/topicPlayer.tsx index 932c8ee6..1bdf72ea 100644 --- a/www/app/[domain]/transcripts/[transcriptId]/correct/topicPlayer.tsx +++ b/www/app/[domain]/transcripts/[transcriptId]/correct/topicPlayer.tsx @@ -3,18 +3,29 @@ import useMp3 from "../../useMp3"; import { formatTime } from "../../../../lib/time"; import SoundWaveCss from "./soundWaveCss"; import { TimeSlice } from "./types"; +import { + BoxProps, + Button, + Wrap, + Text, + WrapItem, + Kbd, + Skeleton, + chakra, +} from "@chakra-ui/react"; type TopicPlayer = { transcriptId: string; selectedTime: TimeSlice | undefined; - topicTime: TimeSlice; + topicTime: TimeSlice | undefined; }; const TopicPlayer = ({ transcriptId, selectedTime, topicTime, -}: TopicPlayer) => { + ...chakraProps +}: TopicPlayer & BoxProps) => { const mp3 = useMp3(transcriptId); const [isPlaying, setIsPlaying] = useState(false); const [endTopicCallback, setEndTopicCallback] = useState<() => void>(); @@ -46,6 +57,7 @@ const TopicPlayer = ({ }); const calcShowTime = () => { + if (!topicTime) return; setShowTime( `${ mp3.media?.currentTime @@ -67,6 +79,7 @@ const TopicPlayer = ({ setEndTopicCallback( () => function () { + if (!topicTime) return; if (mp3.media && mp3.media.currentTime >= topicTime.end) { mp3.media.pause(); setIsPlaying(false); @@ -81,13 +94,14 @@ const TopicPlayer = ({ // 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) { + if (!topicTime) return; mp3.media.currentTime = topicTime.start; setShowTime(`00:00/${formatTime(topicTime.end - topicTime.start)}`); } }, 10); setIsPlaying(false); } - }, [!mp3.media, topicTime.start, topicTime.end]); + }, [!mp3.media, topicTime?.start, topicTime?.end]); useEffect(() => { endTopicCallback && @@ -141,6 +155,7 @@ const TopicPlayer = ({ const playTopic = (e) => { e?.preventDefault(); e?.target?.blur(); + if (!topicTime) return; if (mp3.media) { mp3.media.currentTime = topicTime.start; mp3.media.play(); @@ -165,37 +180,65 @@ const TopicPlayer = ({ mp3.media?.pause(); setIsPlaying(false); }; + console.log(topicTime); - if (mp3.media) { - return ( -
- -
{showTime}
- - {!isPlaying ? ( - + + + {!isPlaying ? ( + + ) : ( + + )} + + + - ) : ( - - )} - {selectedTime && ( - - )} -
- ); - } + , Play selection + + + + + ); }; export default TopicPlayer; diff --git a/www/app/[domain]/transcripts/[transcriptId]/correct/topicWords.tsx b/www/app/[domain]/transcripts/[transcriptId]/correct/topicWords.tsx index 2cd5a483..6fdb6130 100644 --- a/www/app/[domain]/transcripts/[transcriptId]/correct/topicWords.tsx +++ b/www/app/[domain]/transcripts/[transcriptId]/correct/topicWords.tsx @@ -3,6 +3,14 @@ import WaveformLoading from "../../waveformLoading"; import { UseParticipants } from "../../useParticipants"; import { UseTopicWithWords } from "../../useTopicWithWords"; import { TimeSlice, selectedTextIsTimeSlice } from "./types"; +import { + BoxProps, + Box, + Container, + Text, + chakra, + Spinner, +} from "@chakra-ui/react"; type TopicWordsProps = { stateSelectedText: [ @@ -17,7 +25,8 @@ const topicWords = ({ stateSelectedText, participants, topicWithWords, -}: TopicWordsProps) => { + ...chakraProps +}: TopicWordsProps & BoxProps) => { const [selectedText, setSelectedText] = stateSelectedText; useEffect(() => { @@ -150,45 +159,54 @@ const topicWords = ({ participants.response ) { return ( -
+ {topicWithWords.response.wordsPerSpeaker.map( (speakerWithWords, index) => ( -

- + {getSpeakerName(speakerWithWords.speaker)} :  - + {speakerWithWords.words.map((word, index) => ( - = word.end - ? "bg-yellow-200" + ? "yellow.200" : "" } > {word.text} - + ))} -

+ ), )} -
+ ); } if (topicWithWords.loading || participants.loading) - return ; + return ; if (topicWithWords.error || participants.error) return

error

; return null; };