Skip to content

Commit

Permalink
feat: switch whishper modal to its own page
Browse files Browse the repository at this point in the history
  • Loading branch information
aamirazad committed Nov 3, 2024
1 parent a4535f9 commit a60473d
Show file tree
Hide file tree
Showing 3 changed files with 235 additions and 254 deletions.
3 changes: 0 additions & 3 deletions src/app/@modal/default.tsx

This file was deleted.

244 changes: 235 additions & 9 deletions src/app/whishper/recording/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,240 @@
import AudioPreview from "@/components/audio-preview";
"use client";

export default async function FullAudioPage(
props: {
params: Promise<{ id: string }>;
import {
useQuery,
QueryClientProvider,
QueryClient,
} from "@tanstack/react-query";
import type { UsersTableType } from "@/server/db/schema";
import { Button, buttonVariants } from "@/components/ui/button";
import { useRouter } from "next/navigation";
import { ChevronLeft } from "lucide-react";
import { useState } from "react";
import OpenExternalLink from "@/components/external-link";
import type { WhishperRecordingType } from "@/types";
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { toast } from "sonner";
import BodyMessage from "@/components/body-message";
import ky from "ky";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
import { getUserData } from "@/app/actions";

const queryClient = new QueryClient();

async function fetchUserData(): Promise<UsersTableType> {
return await ky.get("/api/getUserData").json<UsersTableType>();
}

function SkeletonLoader() {
return (
<div className="flex w-full justify-center">
<div className="flex h-full justify-center md:w-1/2">
<div className="flex h-full w-full flex-col rounded-xl bg-slate-600/50">
<div className="m-4 flex h-full flex-grow flex-col justify-center gap-9">
{/* Title Skeleton */}
<div className="h-6 w-3/4 animate-pulse rounded-md bg-gray-300 px-2 py-1"></div>
{/* Audio Skeleton */}
<div className="my-2 flex w-full flex-grow justify-center">
<div className="h-10 w-full animate-pulse rounded-md bg-gray-300 md:w-3/4"></div>
</div>
</div>
</div>
</div>
</div>
);
}

async function fetchWhishperRecording(
searchId: string,
whishperURL: string,
): Promise<WhishperRecordingType | undefined> {
const data = await ky
.get(`${whishperURL}/api/transcriptions`)
.json<WhishperRecordingType[]>();
console.log(data);
return data.find((recording) => recording.id === searchId);
}

type AudioInfoProps = {
id: string;
};

function AudioInfo({ id }: AudioInfoProps) {
const router = useRouter();
const [isPlaying, setIsPlaying] = useState(false);

const {
data: userData,
isLoading: isUserDataLoading,
error: userDataError,
} = useQuery({
queryKey: ["userData"],
queryFn: getUserData,
});

const whishperURL = userData?.whishperURL;

const {
data: recordingData,
isLoading: isRecordingDataLoading,
error: recordingDataError,
} = useQuery({
queryKey: ["whishperRecording", id, whishperURL], // Include id in the query key
queryFn: () => fetchWhishperRecording(id, whishperURL!),
enabled: !!whishperURL, // Only fetch recording data when userData is available
});

if (isUserDataLoading) {
return <SkeletonLoader />;
}

if (userDataError ?? !userData) {
return <BodyMessage>Error loading user data</BodyMessage>;
}

if (isRecordingDataLoading) {
return <SkeletonLoader />;
}

if (recordingDataError ?? !recordingData) {
return <BodyMessage>Error loading recording data</BodyMessage>;
}
) {
const params = await props.params;

const decodedName = decodeURIComponent(recordingData.fileName);
const frontPart = decodedName.split("_WHSHPR_")[1] ?? decodedName;
const formattedName = frontPart.replace(".m4a", "") ?? decodedName;

return (
<div className="flex w-full justify-center">
<div className="flex h-full justify-center md:w-1/2">
<div className="flex h-full w-full flex-col rounded-xl bg-slate-600/50">
<div className="m-4 flex h-full flex-grow flex-col justify-center gap-9">
<div
className={`audioPreview flex flex-row items-center justify-between gap-2 rounded-md px-2 py-1 text-xl text-white ${isPlaying ? "bg-gradient-to-r from-indigo-900 to-purple-900" : ""}`}
>
{formattedName}
<Button
className="rounded-full border-none bg-slate-500/60 hover:bg-slate-500/90"
variant="outline"
size="icon"
onClick={() => router.back()}
>
<ChevronLeft />
</Button>
</div>
{/* Audio */}
<div className="flex w-full flex-grow justify-center">
<audio
controls={true}
className="w-full md:w-3/4"
onPlay={() => setIsPlaying(true)}
onPause={() => setIsPlaying(false)}
>
<source
src={`${userData.whishperURL}/api/video/${recordingData.fileName}`}
type="audio/mp4"
/>
</audio>
</div>
<div className="flex w-full flex-shrink-0 justify-center gap-12">
<Button className="w-24">
<OpenExternalLink
href={`${userData.whishperURL}/editor/${id}`}
className="text-primary-foreground"
>
Open
</OpenExternalLink>
</Button>
<TooltipProvider delayDuration={0}>
<Tooltip>
<TooltipTrigger>
<a
href={`${userData.whishperURL}/api/video/${recordingData.fileName}`}
download={recordingData.fileName}
className={`w-24 ${buttonVariants({ variant: "link" })}`}
target="_blank"
>
Download
</a>
</TooltipTrigger>
<TooltipContent>
<p>
To download the audio file, right click and select
&quot;Save as&quot;.
</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
<AlertDialog>
<AlertDialogTrigger>
<Button className="w-24" variant="destructive">
Delete
</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>
Are you absolutely sure?
</AlertDialogTitle>
<AlertDialogDescription>
This action cannot be undone. This will permanently delete
the recording.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction
onClick={async () => {
const response = await ky.delete(
`${userData.whishperURL}/api/transcriptions/${id}`,
);
if (response.ok) {
toast("Recording deleted", {
description: "The recording has been deleted.",
});
} else {
toast("Error deleting recording", {
description:
"An error occurred while deleting the recording.",
});
}
router.back();
}}
>
Continue
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</div>
</div>
</div>
</div>
</div>
);
}

export default function AudioPreview({ id }: { id: string }) {
return (
<main className="h-full w-full">
<AudioPreview id={params.id} />
</main>
<QueryClientProvider client={queryClient}>
<AudioInfo id={id} />
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
);
}
Loading

0 comments on commit a60473d

Please sign in to comment.