Skip to content

Commit

Permalink
improve stripe user experience
Browse files Browse the repository at this point in the history
  • Loading branch information
MarconLP committed Jul 12, 2023
1 parent 8190036 commit 66ecab9
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 48 deletions.
6 changes: 5 additions & 1 deletion src/components/Paywall.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,13 @@ export default function Paywall() {
}

const handleCheckout = async () => {
const { checkoutUrl } = await createCheckoutSession({ billedAnnually });
const { checkoutUrl } = await createCheckoutSession({
billedAnnually,
recordModalOpen,
});
if (checkoutUrl) {
if (recordModalOpen) {
setOpen(false);
window.open(checkoutUrl, "_blank", "noreferrer,width=500,height=500");
} else {
void router.push(checkoutUrl);
Expand Down
137 changes: 92 additions & 45 deletions src/pages/videos.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import Paywall from "~/components/Paywall";
import paywallAtom from "~/atoms/paywallAtom";
import { usePostHog } from "posthog-js/react";
import Image from "next/image";
import { useSearchParams } from "next/navigation";
import { useEffect } from "react";

const VideoList: NextPage = () => {
const [, setRecordOpen] = useAtom(recordVideoModalOpen);
Expand All @@ -26,11 +28,15 @@ const VideoList: NextPage = () => {
const { status, data: session } = useSession();
const { data: videos, isLoading } = api.video.getAll.useQuery();
const posthog = usePostHog();
const searchParams = useSearchParams();

if (status === "unauthenticated") {
void router.replace("/sign-in");
}

const checkoutCanceledQueryParam = searchParams.get("checkoutCanceled");
const closeQueryParam = searchParams.get("close");

const openRecordModal = () => {
if (
!navigator?.mediaDevices?.getDisplayMedia &&
Expand Down Expand Up @@ -64,6 +70,20 @@ const VideoList: NextPage = () => {
}
};

const closeWindow =
(typeof window !== "undefined" &&
window.innerWidth === 500 &&
window.innerHeight === 499) ||
closeQueryParam === "true";

useEffect(() => {
if (checkoutCanceledQueryParam === "false" && closeQueryParam === "false") {
setTimeout(() => {
void router.push("/videos").then(() => router.reload());
}, 5000);
}
}, [checkoutCanceledQueryParam, closeQueryParam]);

return (
<>
<Head>
Expand Down Expand Up @@ -107,54 +127,81 @@ const VideoList: NextPage = () => {
</div>
</div>
<div className="flex w-full grow items-start justify-center overflow-auto bg-[#fbfbfb] pt-14">
{videos && videos?.length <= 0 ? (
<div className="flex items-center justify-center px-8">
<div className="flex flex-col">
{closeWindow || checkoutCanceledQueryParam === "false" ? (
<>
{checkoutCanceledQueryParam === "false" ? (
<div className="flex flex-col">
<span className="text-lg font-semibold text-zinc-700">
Successfully upgraded
</span>
{closeQueryParam === "true" ? (
<span className="mt-1 text-base text-zinc-500">
You can now close this window
</span>
) : (
<span className="mt-1 text-base text-zinc-500">
You will be redirected shortly
</span>
)}
</div>
) : (
<span className="text-lg font-semibold text-zinc-700">
No videos found
</span>
<span className="mt-1 text-base text-zinc-500">
Videos you record will show up here. Already got videos?
Upload them!
You can now close this window
</span>
<div className="mt-4 flex flex-wrap gap-4">
<button
onClick={openRecordModal}
className="inline-flex items-center rounded-md border border-transparent bg-red-600 px-4 py-2 text-sm font-medium text-white shadow-sm hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2"
>
Record a video
</button>
<button
onClick={openUploadModal}
className="inline-flex items-center rounded-md border border-transparent bg-indigo-600 px-4 py-2 text-sm font-medium text-white shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
>
Upload a video
</button>
</div>
</div>
</div>
)}
</>
) : (
<div className="flex-start grid w-full max-w-[1300px] grid-cols-[repeat(auto-fill,250px)] flex-row flex-wrap items-center justify-center gap-14 px-4 pb-16">
{videos &&
videos.map(({ title, id, createdAt, thumbnailUrl }) => (
<VideoCard
title={title}
id={id}
createdAt={createdAt}
thumbnailUrl={thumbnailUrl}
key={id}
/>
))}

{isLoading ? (
<>
<VideoCardSkeleton />
<VideoCardSkeleton />
<VideoCardSkeleton />
<VideoCardSkeleton />
</>
) : null}
</div>
<>
{videos && videos?.length <= 0 ? (
<div className="flex items-center justify-center px-8">
<div className="flex flex-col">
<span className="text-lg font-semibold text-zinc-700">
No videos found
</span>
<span className="mt-1 text-base text-zinc-500">
Videos you record will show up here. Already got videos?
Upload them!
</span>
<div className="mt-4 flex flex-wrap gap-4">
<button
onClick={openRecordModal}
className="inline-flex items-center rounded-md border border-transparent bg-red-600 px-4 py-2 text-sm font-medium text-white shadow-sm hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2"
>
Record a video
</button>
<button
onClick={openUploadModal}
className="inline-flex items-center rounded-md border border-transparent bg-indigo-600 px-4 py-2 text-sm font-medium text-white shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
>
Upload a video
</button>
</div>
</div>
</div>
) : (
<div className="flex-start grid w-full max-w-[1300px] grid-cols-[repeat(auto-fill,250px)] flex-row flex-wrap items-center justify-center gap-14 px-4 pb-16">
{videos &&
videos.map(({ title, id, createdAt, thumbnailUrl }) => (
<VideoCard
title={title}
id={id}
createdAt={createdAt}
thumbnailUrl={thumbnailUrl}
key={id}
/>
))}

{isLoading ? (
<>
<VideoCardSkeleton />
<VideoCardSkeleton />
<VideoCardSkeleton />
<VideoCardSkeleton />
</>
) : null}
</div>
)}
</>
)}
</div>
</main>
Expand Down
8 changes: 6 additions & 2 deletions src/server/api/routers/stripe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import { z } from "zod";

export const stripeRouter = createTRPCRouter({
createCheckoutSession: protectedProcedure
.input(z.object({ billedAnnually: z.boolean() }))
.input(
z.object({ billedAnnually: z.boolean(), recordModalOpen: z.boolean() })
)
.mutation(
async ({ ctx: { prisma, stripe, session, req, posthog }, input }) => {
if (
Expand Down Expand Up @@ -45,7 +47,9 @@ export const stripeRouter = createTRPCRouter({
quantity: 1,
},
],
success_url: `${baseUrl}/videos?checkoutSuccess=true`,
success_url: input.recordModalOpen
? `${baseUrl}/videos?checkoutCanceled=false&close=true`
: `${baseUrl}/videos?checkoutCanceled=false&close=false`,
cancel_url: `${baseUrl}/videos?checkoutCanceled=true`,
subscription_data: {
metadata: {
Expand Down

1 comment on commit 66ecab9

@vercel
Copy link

@vercel vercel bot commented on 66ecab9 Jul 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.