From 97273ac5192e2810fb9350380b5d43ef8da4af34 Mon Sep 17 00:00:00 2001 From: MarconLP <13001502+MarconLP@users.noreply.github.com> Date: Sat, 22 Apr 2023 00:50:11 +0200 Subject: [PATCH] limit free tier to 10 uploaded videos and show paywall when hitting this limit --- src/components/Recorder.tsx | 48 +++++++++++++++++++++++---------- src/server/api/routers/video.ts | 17 ++++++++++++ 2 files changed, 51 insertions(+), 14 deletions(-) diff --git a/src/components/Recorder.tsx b/src/components/Recorder.tsx index 2e07ce9..4a7027d 100644 --- a/src/components/Recorder.tsx +++ b/src/components/Recorder.tsx @@ -11,6 +11,9 @@ import dayjs from "dayjs"; import { useRouter } from "next/router"; import { api } from "~/utils/api"; import fixWebmDuration from "fix-webm-duration"; +import { TRPCClientError } from "@trpc/client"; +import { useAtom } from "jotai/index"; +import paywallAtom from "~/atoms/paywallAtom"; interface Props { closeModal: () => void; @@ -27,7 +30,6 @@ interface Props { export default function Recorder({ closeModal, step, setStep }: Props) { const [steam, setStream] = useState(null); const [blob, setBlob] = useState(null); - const refVideo = useRef(null); const recorderRef = useRef(null); const [pause, setPause] = useState(false); const [audioDevices, setAudioDevices] = useState([]); @@ -39,6 +41,7 @@ export default function Recorder({ closeModal, step, setStep }: Props) { const apiUtils = api.useContext(); const getSignedUrl = api.video.getUploadUrl.useMutation(); const [duration, setDuration] = useState(0); + const [, setPaywallOpen] = useAtom(paywallAtom); const handleRecording = async () => { const screenStream = await navigator.mediaDevices.getDisplayMedia({ @@ -139,22 +142,39 @@ export default function Recorder({ closeModal, step, setStep }: Props) { const handleUpload = async () => { if (!blob) return; + const dateString = "Recording - " + dayjs().format("D MMM YYYY") + ".webm"; setSubmitting(true); - const { signedUrl, id } = await getSignedUrl.mutateAsync({ - key: dateString, - }); - await axios - .put(signedUrl, blob.slice(), { - headers: { "Content-Type": "video/webm" }, - }) - .then(() => { - void router.push("share/" + id); - }) - .catch((err) => { - console.error(err); + + try { + const { signedUrl, id } = await getSignedUrl.mutateAsync({ + key: dateString, }); - setSubmitting(false); + await axios + .put(signedUrl, blob.slice(), { + headers: { "Content-Type": "video/webm" }, + }) + .then(() => { + void router.push("share/" + id); + }) + .catch((err) => { + console.error(err); + }); + } catch (err) { + if (err instanceof TRPCClientError) { + if ( + err.message === + "Sorry, you have reached the maximum video upload limit on our free tier. Please upgrade to upload more." + ) { + setPaywallOpen(true); + } + } else { + throw err; + } + } finally { + setSubmitting(false); + } + void apiUtils.video.getAll.invalidate(); }; diff --git a/src/server/api/routers/video.ts b/src/server/api/routers/video.ts index 5517ccc..a94e475 100644 --- a/src/server/api/routers/video.ts +++ b/src/server/api/routers/video.ts @@ -59,6 +59,23 @@ export const videoRouter = createTRPCRouter({ const { key } = input; const { s3 } = ctx; + const videos = await ctx.prisma.video.findMany({ + where: { + userId: ctx.session.user.id, + }, + }); + + if ( + videos.length >= 10 && + ctx.session.user.stripeSubscriptionStatus !== "active" + ) { + throw new TRPCError({ + code: "FORBIDDEN", + message: + "Sorry, you have reached the maximum video upload limit on our free tier. Please upgrade to upload more.", + }); + } + const video = await ctx.prisma.video.create({ data: { userId: ctx.session.user.id,