Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add checkout inside page #1130

Merged
merged 4 commits into from
Nov 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .env.prod
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
NEXT_PUBLIC_AWS_USERPOOL_ID=us-east-1_YFNT7b4nQ
NEXT_PUBLIC_AWS_APPCLIENT_ID=5s3qsuck8dcfrb4u1l4mm15mos
75 changes: 65 additions & 10 deletions app/pricing/components/price.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,73 @@
"use client";

import { Check } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import Link from "next/link";
import { useUser } from "@/app/user/UserContext";
import { User } from "@/lib/auth";
import { useState } from "react";
import { useRouter } from "next/navigation";


function SubscriptionButtons(user: User | null, loading: boolean, subscriptionClick: (planFrequency: PlanFrequency) => void) {
const isSubscribed = user !== null && user.isPro;

if (isSubscribed) {
return <>
<p className="text-green-500 text-center">You are already subscribed!</p>
<Button className="w-full bg-blue-600 hover:bg-blue-700">
<Link href="/user">
View Your Profile
</Link>
</Button>
</>;
}

return <>
<Button className="w-full bg-blue-600 hover:bg-blue-700" onClick={() => subscriptionClick(PlanFrequency.MONTHLY)}>
{loading ? "Loading..." : "Subscribe Monthly"}
</Button>
<Button className="w-full bg-indigo-600 hover:bg-indigo-700"
onClick={() => subscriptionClick(PlanFrequency.YEARLY)}>
{loading ? "Loading..." : "Subscribe Yearly (Save 17%)"}
</Button>
</>;
}

enum PlanFrequency {
MONTHLY,
YEARLY
}

export default function Pricing() {
const [loading, setLoading] = useState<boolean>(false);
const { user } = useUser();
const router = useRouter();

function handleSubscriptionClick(planFrequency: PlanFrequency) {
if (user === null) {
console.log(user);
router.push("/user/login");
return;
}

setLoading(true);
const subscriptionType = planFrequency === PlanFrequency.MONTHLY ? "MONTHLY" : "YEARLY";
const url = `/api/v3/checkout/session/${subscriptionType}`;
fetch(url, { method: "POST" })
.then((response) => response.json())
.then((data) => {
if (data.sessionUrl) {
setLoading(false);
router.push(data.sessionUrl);
} else {
setLoading(false);
console.error("No session URL received from the server.");
}
});
}

return (
<div className="container mx-auto px-4 py-12">
<div className="text-center mb-12">
Expand Down Expand Up @@ -100,16 +164,7 @@ export default function Pricing() {
</ul>
</div>
<div className="space-y-3 mt-auto">
<Button className="w-full bg-blue-600 hover:bg-blue-700">
<Link href="/user/signup">
Subscribe Monthly
</Link>
</Button>
<Button className="w-full bg-indigo-600 hover:bg-indigo-700">
<Link href="/user/signup">
Subscribe Yearly (Save 17%)
</Link>
</Button>
{SubscriptionButtons(user, loading, handleSubscriptionClick)}
</div>
</Card>
</div>
Expand Down
50 changes: 1 addition & 49 deletions app/pricing/page.tsx
Original file line number Diff line number Diff line change
@@ -1,60 +1,12 @@
"use client";

import Script from "next/script";
import { useEffect, useState } from "react";
import PublicPriceComponent from "@/app/pricing/components/price";
import { useUser } from "@/app/user/UserContext";

declare global {
namespace JSX {
interface IntrinsicElements {
"stripe-pricing-table": React.DetailedHTMLProps<
React.HTMLAttributes<HTMLElement>,
HTMLElement
>;
}
}
}

async function getCustomerSecret() {
const res = await fetch(`/api/v3/user/subscription-portal/customer-session`, {
method: "POST",
headers: {
"X-Api-Key": process.env.PEPY_API_KEY!
}
});

const body = await res.json();
return body["customerSecret"];
}

export default function Home() {
const { user, error } = useUser();
const [customerSecret, setCustomerSecret] = useState<null | String>(null);

useEffect(() => {
if (user !== null) {
getCustomerSecret().then(secret => setCustomerSecret(secret));
}
}, [user]);

console.log("Customer Secret", customerSecret);
const stripePricingTable = (
<>
<stripe-pricing-table
pricing-table-id="prctbl_1O3NjqLkhgcLjWWE4QWZ1F1G"
publishable-key="pk_live_fGp4vBPOGSP5uIvvM2qXoQyZ006F0MCL4G"
customer-session-client-secret={customerSecret}
></stripe-pricing-table>
</>
);

const pricingTable = user === null ? (<PublicPriceComponent />) : stripePricingTable;

return (
<>
<Script src="https://js.stripe.com/v3/pricing-table.js" async={true} />
{pricingTable}
<PublicPriceComponent />
</>
);
}
4 changes: 2 additions & 2 deletions lib/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ export interface IConfirmPasswordCallback {
onFailure: (err: string) => void;
}

const USER_POOL_ID = "us-east-1_YFNT7b4nQ";
const CLIENT_ID = "67oda21n4538a52ub88r0tav24";
const USER_POOL_ID = process.env.NEXT_PUBLIC_AWS_USERPOOL_ID ?? "us-east-1_YFNT7b4nQ";
const CLIENT_ID = process.env.NEXT_PUBLIC_AWS_APPCLIENT_ID ?? "67oda21n4538a52ub88r0tav24";
export const userPool = new CognitoUserPool({
UserPoolId: USER_POOL_ID,
ClientId: CLIENT_ID,
Expand Down
5 changes: 3 additions & 2 deletions middleware.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type {NextRequest} from 'next/server'
import {NextResponse} from 'next/server'
import type { NextRequest } from "next/server";
import { NextResponse } from "next/server";

export const config = {
matcher: ['/api/:path*', '/subscriptions']
Expand All @@ -9,6 +9,7 @@ export function middleware(request: NextRequest) {
try {
const requestHeaders = new Headers(request.headers)
const accessToken = request.cookies.getAll().filter(cookie => cookie.name.includes('accessToken'));
requestHeaders.delete("cookie");
if (accessToken.length === 1) {
requestHeaders.set('Authorization', 'Bearer ' + accessToken[0].value);
}
Expand Down
1 change: 1 addition & 0 deletions next.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const PEPY_HOST = "https://api.pepy.tech";
//const PEPY_HOST = "http://localhost:8081"
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: false,
Expand Down
Loading