diff --git a/src/components/ExpireDateSelectMenu.tsx b/src/components/ExpireDateSelectMenu.tsx index a3c6171..dfb541d 100644 --- a/src/components/ExpireDateSelectMenu.tsx +++ b/src/components/ExpireDateSelectMenu.tsx @@ -37,6 +37,7 @@ export default function ExpireDateSelectMenu({ console.error(err.message); }, }); + const handleChange = (value: string) => { let timestamp: null | Date = new Date(); switch (value) { diff --git a/src/components/VideoMoreMenu.tsx b/src/components/VideoMoreMenu.tsx index 0f31bb6..7fdf1fe 100644 --- a/src/components/VideoMoreMenu.tsx +++ b/src/components/VideoMoreMenu.tsx @@ -1,6 +1,6 @@ -import { type RouterOutputs } from "~/utils/api"; -import { Menu, Transition } from "@headlessui/react"; -import { Fragment } from "react"; +import { api, type RouterOutputs } from "~/utils/api"; +import { Dialog, Menu, Transition } from "@headlessui/react"; +import { Fragment, useState } from "react"; import { DotsHorizontalIcon, DownloadIcon, @@ -13,10 +13,19 @@ interface Props { } export default function VideoMoreMenu({ video }: Props) { + const [title, setTitle] = useState(video.title); + const [renameMenuOpen, setRenameMenuOpen] = useState(false); + const utils = api.useContext(); + const items = [ { name: "Rename", icon: , + props: { + onClick: () => { + setRenameMenuOpen(true); + }, + }, }, { name: "Download", @@ -42,45 +51,135 @@ export default function VideoMoreMenu({ video }: Props) { }, ]; + const renameVideoMutation = api.video.renameVideo.useMutation({ + onMutate: async ({ videoId, title }) => { + 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); + }, + }); + return ( - -
- - - -
- - -
- {items.map((item) => ( -
- - {({ active }) => ( -
-
- {item.icon} + <> + {/* More options menu */} + +
+ + + +
+ + +
+ {items.map((item) => ( +
+ + {({ active }) => ( +
+
+ {item.icon} +
+

+ {item.name} +

-

{item.name}

+ )} +
+
+ ))} +
+
+
+
+ + {/* Rename dialog */} + + setRenameMenuOpen(false)} + > + +
+ + +
+
+ + +
+ +
+ setTitle(e.currentTarget.value)} + id="email" + name="email" + type="email" + autoComplete="email" + className="block w-full rounded-md border-0 px-2 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" + />
- )} - -
- ))} +
+ + + + +
- +
-
+ ); } diff --git a/src/server/api/routers/video.ts b/src/server/api/routers/video.ts index 6b94f26..5aed72b 100644 --- a/src/server/api/routers/video.ts +++ b/src/server/api/routers/video.ts @@ -143,6 +143,33 @@ export const videoRouter = createTRPCRouter({ throw new TRPCError({ code: "FORBIDDEN" }); } + return { + success: true, + updateVideo, + }; + }), + renameVideo: protectedProcedure + .input( + z.object({ + videoId: z.string(), + title: z.string(), + }) + ) + .mutation(async ({ ctx, input }) => { + const updateVideo = await ctx.prisma.video.updateMany({ + where: { + id: input.videoId, + userId: ctx.session.user.id, + }, + data: { + title: input.title, + }, + }); + + if (updateVideo.count === 0) { + throw new TRPCError({ code: "FORBIDDEN" }); + } + return { success: true, updateVideo,