add shareModal and the ability to toggle share state

This commit is contained in:
MarconLP 2023-04-14 15:04:55 +02:00
parent fcb3ecbb14
commit c089fb7d47
No known key found for this signature in database
GPG key ID: A08A9C8B623F5EA5
5 changed files with 122 additions and 57 deletions

View file

@ -32,6 +32,12 @@ const config = {
port: '',
pathname: '/**',
},
{
protocol: 'https',
hostname: '*.imgur.com',
port: '',
pathname: '/**',
},
{
protocol: 'https',
hostname: '*.githubusercontent.com',

View file

@ -16,13 +16,19 @@ datasource db {
}
model Video {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
title String
video_url String
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
title String
video_url String
userId String
sharing Boolean @default(false)
deleteAfterExpiry Boolean @default(false)
shareExpiryAt DateTime?
linkShareSeo Boolean @default(false)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId])
}
// Necessary for Next auth

View file

@ -1,15 +1,36 @@
import { Dialog, Switch, Transition } from "@headlessui/react";
import { Dialog, Transition } from "@headlessui/react";
import { Fragment, useState } from "react";
import { ModernSwitch } from "~/components/ModernSwitch";
import { api, type RouterOutputs } from "~/utils/api";
export function ShareModal() {
interface Props {
video: RouterOutputs["video"]["get"];
}
export function ShareModal({ video }: Props) {
const utils = api.useContext();
const [open, setOpen] = useState<boolean>(false);
const [sharing, setSharing] = useState<boolean>(false);
const [es, sses] = useState<boolean>(false);
const [as, ssgs] = useState<boolean>(false);
const setSharingMutation = api.video.setSharing.useMutation({
onMutate: async ({ videoId, sharing }) => {
await utils.video.get.cancel();
const previousValue = utils.video.get.getData({ videoId });
if (previousValue) {
utils.video.get.setData({ videoId }, { ...previousValue, sharing });
}
return { previousValue };
},
});
const [s, ss] = useState<boolean>(false);
const [linkCopied, setLinkCopied] = useState<boolean>(false);
const handleCopy = () => {
void navigator.clipboard.writeText(window.location.href);
setLinkCopied(true);
setTimeout(() => {
setLinkCopied(false);
}, 5000);
};
return (
<>
@ -58,34 +79,52 @@ export function ShareModal() {
<span className="text-sm font-medium">
Share link with anyone
</span>
<ModernSwitch enabled={s} toggle={ss} />
<ModernSwitch
enabled={video.sharing}
toggle={() =>
setSharingMutation.mutate({
videoId: video.id,
sharing: !video.sharing,
})
}
/>
</div>
<button className="my-2 h-8 w-full rounded-md bg-[#4169e1] text-sm font-medium text-white hover:bg-[#224fd7]">
Copy public link
</button>
<div className="w-full border border-solid border-[#e9ebf0] bg-[#fafbfc] px-[15px] py-3 text-xs">
<div className="flex h-6 items-center justify-between">
<span>Expire link</span>
{video.sharing ? (
<>
<button
onClick={handleCopy}
className="my-2 h-8 w-full rounded-md bg-[#4169e1] text-sm font-medium text-white hover:bg-[#224fd7]"
>
{linkCopied ? "Copied!" : "Copy public link"}
</button>
<div className="w-full border border-solid border-[#e9ebf0] bg-[#fafbfc] px-[15px] py-3 text-xs">
{/*<div className="flex h-6 items-center justify-between">*/}
{/* <span>Expire link</span>*/}
<button className="h-6 rounded border border-solid border-[#d5d9df] bg-white px-[7px]">
Never expire
</button>
</div>
<div className="mt-3 flex h-6 items-center justify-between">
<span>Delete video when expired</span>
<ModernSwitch enabled={s} toggle={ss} />
</div>
<div className="mt-3 flex h-6 items-center justify-between">
<span>Share link with search engines</span>
<ModernSwitch enabled={s} toggle={ss} />
</div>
<div className="mt-3 flex h-6 items-center justify-between">
<span>Embed code</span>
<button className="h-6 rounded border border-solid border-[#d5d9df] bg-white px-[7px]">
Copy code
</button>
</div>
</div>
{/* <button className="h-6 rounded border border-solid border-[#d5d9df] bg-white px-[7px] font-medium">*/}
{/* Never expire*/}
{/* </button>*/}
{/*</div>*/}
{/*<div className="mt-3 flex h-6 items-center justify-between">*/}
{/* <span>Delete video when expired</span>*/}
{/* <ModernSwitch enabled={s} toggle={ss} />*/}
{/*</div>*/}
<div className="mt-3 flex h-6 items-center justify-between">
<span>Share link with search engines</span>
<ModernSwitch
enabled={video.linkShareSeo}
toggle={() => console.log("test")}
/>
</div>
{/*<div className="mt-3 flex h-6 items-center justify-between">*/}
{/* <span>Embed code</span>*/}
{/* <button className="h-6 rounded border border-solid border-[#d5d9df] bg-white px-[7px] font-medium">*/}
{/* Copy code*/}
{/* </button>*/}
{/*</div>*/}
</div>
</>
) : null}
</div>
</Dialog.Panel>
</Transition.Child>

View file

@ -21,7 +21,7 @@ const VideoList: NextPage = () => {
}
);
if (!isLoading && !video?.success) {
if (!isLoading && !video) {
return (
<div className="flex h-screen w-screen flex-col items-center justify-center">
<span className="max-w-[80%] text-center text-2xl font-medium">
@ -50,29 +50,29 @@ const VideoList: NextPage = () => {
Personal Library
</span>
</Link>
<ShareModal />
{video ? <ShareModal video={video} /> : null}
</div>
</div>
<div className="flex h-full w-full grow flex-col items-center justify-start overflow-auto bg-[#fbfbfb]">
<div className="flex aspect-video max-h-[627px] w-full justify-center bg-black 2xl:max-h-[1160px]">
{video?.video?.video_url && (
{video?.video_url && (
<ReactPlayer
width="100%"
height="100%"
controls={true}
url={video.video?.video_url}
url={video?.video_url}
/>
)}
</div>
<div className="mb-10 mt-4 w-full max-w-[1800px] pl-[24px]">
<div>
{video?.video?.title ? (
{video?.title ? (
<div className="mb-4 flex flex-col">
<span className="text-[18px] text-lg font-medium">
{video?.video?.title}
{video.title}
</span>
<span className="text-[18px] text-sm text-gray-800">
{getTime(video?.video?.createdAt)}
{getTime(video.createdAt)}
</span>
</div>
) : (
@ -89,13 +89,14 @@ const VideoList: NextPage = () => {
<Image
width={40}
height={40}
src={video?.video?.user?.image ?? ""}
src={
video.user.image ??
"https://i.stack.imgur.com/dr5qp.jpg"
}
alt="profile photo"
/>
</div>
<span className="ml-3 font-medium">
{video?.video?.user?.name}
</span>
<span className="ml-3 font-medium">{video.user.name}</span>
</>
) : (
<>

View file

@ -4,6 +4,7 @@ import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc";
import { 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";
export const videoRouter = createTRPCRouter({
getAll: protectedProcedure.query(async ({ ctx }) => {
@ -29,9 +30,7 @@ export const videoRouter = createTRPCRouter({
});
if (video?.userId !== ctx.session.user.id) {
return {
success: false,
};
throw new TRPCError({ code: "FORBIDDEN" });
}
const getObjectCommand = new GetObjectCommand({
@ -43,10 +42,7 @@ export const videoRouter = createTRPCRouter({
video.video_url = signedUrl;
return {
success: true,
video,
};
return video;
}),
getUploadUrl: protectedProcedure
.input(z.object({ key: z.string() }))
@ -77,4 +73,21 @@ export const videoRouter = createTRPCRouter({
signedUrl,
};
}),
setSharing: protectedProcedure
.input(z.object({ videoId: z.string(), sharing: z.boolean() }))
.mutation(async ({ ctx, input }) => {
const updateVideo = await ctx.prisma.video.update({
where: {
id: input.videoId,
},
data: {
sharing: input.sharing,
},
});
return {
success: true,
updateVideo,
};
}),
});