diff --git a/www/app/(app)/transcripts/[transcriptId]/page.tsx b/www/app/(app)/transcripts/[transcriptId]/page.tsx index ec5f9ebb..1e020f1c 100644 --- a/www/app/(app)/transcripts/[transcriptId]/page.tsx +++ b/www/app/(app)/transcripts/[transcriptId]/page.tsx @@ -10,7 +10,15 @@ import FinalSummary from "./finalSummary"; import TranscriptTitle from "../transcriptTitle"; import Player from "../player"; import { useRouter } from "next/navigation"; -import { Box, Flex, Grid, GridItem, Skeleton, Text } from "@chakra-ui/react"; +import { + Box, + Flex, + Grid, + GridItem, + Skeleton, + Text, + Spinner, +} from "@chakra-ui/react"; import { useTranscriptGet } from "../../../lib/apiHooks"; import { TranscriptStatus } from "../../../lib/transcript"; @@ -28,6 +36,7 @@ export default function TranscriptDetails(details: TranscriptDetails) { "idle", "recording", "processing", + "uploaded", ] satisfies TranscriptStatus[] as TranscriptStatus[]; const transcript = useTranscriptGet(transcriptId); @@ -45,15 +54,55 @@ export default function TranscriptDetails(details: TranscriptDetails) { useState(null); useEffect(() => { - if (waiting) { - const newUrl = "/transcripts/" + params.transcriptId + "/record"; + if (!waiting || !transcript.data) return; + + const status = transcript.data.status; + let newUrl: string | null = null; + + if (status === "processing" || status === "uploaded") { + newUrl = `/transcripts/${params.transcriptId}/processing`; + } else if (status === "recording") { + newUrl = `/transcripts/${params.transcriptId}/record`; + } else if (status === "idle") { + newUrl = + transcript.data.source_kind === "file" + ? `/transcripts/${params.transcriptId}/upload` + : `/transcripts/${params.transcriptId}/record`; + } + + if (newUrl) { // Shallow redirection does not work on NextJS 13 // https://github.com/vercel/next.js/discussions/48110 // https://github.com/vercel/next.js/discussions/49540 router.replace(newUrl); - // history.replaceState({}, "", newUrl); } - }, [waiting]); + }, [waiting, transcript.data?.status, transcript.data?.source_kind]); + + if (waiting) { + return ( + + + + + + Loading transcript... + + + + + ); + } if (transcript.error || topics?.error) { return ( diff --git a/www/app/(app)/transcripts/[transcriptId]/processing/page.tsx b/www/app/(app)/transcripts/[transcriptId]/processing/page.tsx new file mode 100644 index 00000000..4422e077 --- /dev/null +++ b/www/app/(app)/transcripts/[transcriptId]/processing/page.tsx @@ -0,0 +1,97 @@ +"use client"; +import { useEffect, use } from "react"; +import { + Heading, + Text, + VStack, + Spinner, + Button, + Center, +} from "@chakra-ui/react"; +import { useRouter } from "next/navigation"; +import { useTranscriptGet } from "../../../../lib/apiHooks"; + +type TranscriptProcessing = { + params: Promise<{ + transcriptId: string; + }>; +}; + +export default function TranscriptProcessing(details: TranscriptProcessing) { + const params = use(details.params); + const transcriptId = params.transcriptId; + const router = useRouter(); + + const transcript = useTranscriptGet(transcriptId); + + useEffect(() => { + const status = transcript.data?.status; + if (!status) return; + + if (status === "ended" || status === "error") { + router.replace(`/transcripts/${transcriptId}`); + } else if (status === "recording") { + router.replace(`/transcripts/${transcriptId}/record`); + } else if (status === "idle") { + const dest = + transcript.data?.source_kind === "file" + ? `/transcripts/${transcriptId}/upload` + : `/transcripts/${transcriptId}/record`; + router.replace(dest); + } + }, [ + transcript.data?.status, + transcript.data?.source_kind, + router, + transcriptId, + ]); + + if (transcript.isLoading) { + return ( + + Loading transcript... + + ); + } + + if (transcript.error) { + return ( + + Transcript not found + We couldn't load this transcript. + + ); + } + + return ( + <> + +
+ + + + Processing recording + + + You can safely return to the library while your recording is being + processed. + + + +
+
+ + ); +} diff --git a/www/app/(app)/transcripts/[transcriptId]/upload/page.tsx b/www/app/(app)/transcripts/[transcriptId]/upload/page.tsx index b4bc25cc..9fc6a687 100644 --- a/www/app/(app)/transcripts/[transcriptId]/upload/page.tsx +++ b/www/app/(app)/transcripts/[transcriptId]/upload/page.tsx @@ -4,7 +4,7 @@ import { useWebSockets } from "../../useWebSockets"; import { lockWakeState, releaseWakeState } from "../../../../lib/wakeLock"; import { useRouter } from "next/navigation"; import useMp3 from "../../useMp3"; -import { Center, VStack, Text, Heading, Button } from "@chakra-ui/react"; +import { Center, VStack, Text, Heading } from "@chakra-ui/react"; import FileUploadButton from "../../fileUploadButton"; import { useTranscriptGet } from "../../../../lib/apiHooks"; @@ -53,6 +53,12 @@ const TranscriptUpload = (details: TranscriptUpload) => { const newUrl = "/transcripts/" + params.transcriptId; router.replace(newUrl); + } else if ( + newStatus && + (newStatus == "uploaded" || newStatus == "processing") + ) { + // After upload finishes (or if already processing), redirect to the unified processing page + router.replace(`/transcripts/${params.transcriptId}/processing`); } }, [webSockets.status?.value, transcript.data?.status]); @@ -71,7 +77,7 @@ const TranscriptUpload = (details: TranscriptUpload) => { <> { Upload meeting
- {status && status == "idle" && ( - <> - - Please select the file, supported formats: .mp3, m4a, .wav, - .mp4, .mov or .webm - - - - )} - {status && status == "uploaded" && ( - File is uploaded, processing... - )} - {(status == "recording" || status == "processing") && ( - <> - Processing your recording... - - You can safely return to the library while your file is being - processed. - - - - )} + + Please select the file, supported formats: .mp3, m4a, .wav, .mp4, + .mov or .webm + + + router.replace(`/transcripts/${params.transcriptId}/processing`) + } + />
diff --git a/www/app/(app)/transcripts/fileUploadButton.tsx b/www/app/(app)/transcripts/fileUploadButton.tsx index 1f5d72eb..b5fda7b6 100644 --- a/www/app/(app)/transcripts/fileUploadButton.tsx +++ b/www/app/(app)/transcripts/fileUploadButton.tsx @@ -5,6 +5,7 @@ import { useError } from "../../(errors)/errorContext"; type FileUploadButton = { transcriptId: string; + onUploadComplete?: () => void; }; export default function FileUploadButton(props: FileUploadButton) { @@ -31,6 +32,7 @@ export default function FileUploadButton(props: FileUploadButton) { const uploadNextChunk = async () => { if (chunkNumber == totalChunks) { setProgress(0); + props.onUploadComplete?.(); return; }