diff --git a/src/components/VideoMoreMenu.tsx b/src/components/VideoMoreMenu.tsx index 7fdf1fe..491d49e 100644 --- a/src/components/VideoMoreMenu.tsx +++ b/src/components/VideoMoreMenu.tsx @@ -7,6 +7,7 @@ import { Pencil1Icon, TrashIcon, } from "@radix-ui/react-icons"; +import { useRouter } from "next/router"; interface Props { video: RouterOutputs["video"]["get"]; @@ -16,6 +17,7 @@ export default function VideoMoreMenu({ video }: Props) { const [title, setTitle] = useState(video.title); const [renameMenuOpen, setRenameMenuOpen] = useState(false); const utils = api.useContext(); + const router = useRouter(); const items = [ { @@ -48,9 +50,35 @@ export default function VideoMoreMenu({ video }: Props) { { name: "Delete", icon: , + props: { + onClick: () => { + deleteVideoMutation.mutate({ videoId: video.id }); + }, + }, }, ]; + const deleteVideoMutation = api.video.deleteVideo.useMutation({ + onMutate: async ({ videoId }) => { + await utils.video.get.cancel(); + const previousValue = utils.video.get.getData({ videoId }); + if (previousValue) { + utils.video.get.setData({ videoId }, { ...previousValue, title }); + } + return { previousValue }; + }, + onError: (err, { videoId }, context) => { + if (context?.previousValue) { + utils.video.get.setData({ videoId }, context.previousValue); + } + console.error(err.message); + }, + onSettled: () => { + void utils.video.getAll.invalidate(); + void router.push("/videos"); + }, + }); + const renameVideoMutation = api.video.renameVideo.useMutation({ onMutate: async ({ videoId, title }) => { await utils.video.get.cancel(); diff --git a/src/server/api/routers/video.ts b/src/server/api/routers/video.ts index 5aed72b..5517ccc 100644 --- a/src/server/api/routers/video.ts +++ b/src/server/api/routers/video.ts @@ -5,7 +5,11 @@ import { protectedProcedure, publicProcedure, } from "~/server/api/trpc"; -import { GetObjectCommand, PutObjectCommand } from "@aws-sdk/client-s3"; +import { + DeleteObjectCommand, + GetObjectCommand, + PutObjectCommand, +} from "@aws-sdk/client-s3"; import { env } from "~/env.mjs"; import { getSignedUrl } from "@aws-sdk/s3-request-presigner"; import { TRPCError } from "@trpc/server"; @@ -175,4 +179,35 @@ export const videoRouter = createTRPCRouter({ updateVideo, }; }), + deleteVideo: protectedProcedure + .input( + z.object({ + videoId: z.string(), + }) + ) + .mutation(async ({ ctx, input }) => { + const deleteVideo = await ctx.prisma.video.deleteMany({ + where: { + id: input.videoId, + userId: ctx.session.user.id, + }, + }); + + if (deleteVideo.count === 0) { + throw new TRPCError({ code: "FORBIDDEN" }); + } + + const deleteObjectCommand = new DeleteObjectCommand({ + Bucket: env.AWS_BUCKET_NAME, + Key: ctx.session.user.id + "/" + input.videoId, + }); + + const deleteObject = await ctx.s3.send(deleteObjectCommand); + + return { + success: true, + deleteVideo, + deleteObject, + }; + }), });