Skip to content

Commit 8d06ccb

Browse files
authored
Merge pull request #307 from SHADOW-LIGHTS/top-up-quota-feature
[Server+LandingPage] Top up quota feature | bug fixes
2 parents c667490 + 5e7ddfe commit 8d06ccb

File tree

25 files changed

+2319
-16468
lines changed

25 files changed

+2319
-16468
lines changed

app/(auth)/layout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import PageIllustration from "@/components/page-illustration";
1+
import PageIllustration from "@/components/ui/page-illustration";
22

33
export default function AuthLayout({
44
children,

app/(default)/layout.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import { useEffect } from "react";
55
import AOS from "aos";
66
import "aos/dist/aos.css";
77

8-
import PageIllustration from "@/components/page-illustration";
8+
import PageIllustration from "@/components/ui/page-illustration";
9+
import Footer from "@/components/footer";
910

1011
export default function DefaultLayout({
1112
children,
@@ -27,6 +28,7 @@ export default function DefaultLayout({
2728
<PageIllustration />
2829
{children}
2930
</main>
31+
<Footer />
3032
</>
3133
);
3234
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { NextRequest, NextResponse } from "next/server";
2+
import { withAuth } from "@/utils/withAuth";
3+
import { createClient } from "@/utils/supabase/server";
4+
import { User } from "@supabase/supabase-js";
5+
import { STRIPE_PRICE_IDS } from "@/utils/constants";
6+
import { TEST_MODE_ENABLED } from "@/utils/constants";
7+
8+
const PEARAI_SERVER_URL = process.env.PEARAI_SERVER_URL;
9+
10+
async function createTopUpSession(request: NextRequest & { user: User }) {
11+
const supabase = createClient();
12+
13+
try {
14+
const { amount } = await request.json();
15+
const priceId = STRIPE_PRICE_IDS.TOP_UP_CREDITS[amount];
16+
if (!priceId) {
17+
return NextResponse.json({ error: "Invalid amount" }, { status: 400 });
18+
}
19+
const {
20+
data: { session },
21+
} = await supabase.auth.getSession();
22+
23+
if (!session) {
24+
return NextResponse.json(
25+
{ error: "Failed to get session" },
26+
{ status: 401 },
27+
);
28+
}
29+
30+
const token = session.access_token;
31+
const url = `${PEARAI_SERVER_URL}/payment${TEST_MODE_ENABLED ? "/test" : ""}/create-topup-session`;
32+
33+
const response = await fetch(url, {
34+
method: "POST",
35+
headers: {
36+
"Content-Type": "application/json",
37+
Authorization: `Bearer ${token}`,
38+
},
39+
body: JSON.stringify({ priceId, amount }),
40+
});
41+
42+
if (!response.ok) {
43+
const errorData = await response.json();
44+
throw new Error(
45+
errorData.error || `HTTP error! status: ${response.status}`,
46+
);
47+
}
48+
49+
const data = await response.json();
50+
return NextResponse.json({ url: data.url });
51+
} catch (error) {
52+
console.error("Error creating top-up session:", error);
53+
return NextResponse.json(
54+
{ error: "Failed to create top-up session" },
55+
{ status: 500 },
56+
);
57+
}
58+
}
59+
60+
export const POST = withAuth(createTopUpSession);

app/api/dashboard-usage/route.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,10 @@ const getDashboardUsage = async (request: NextRequest) => {
4040
}
4141

4242
const data = await res.json();
43-
return NextResponse.json(data);
43+
return NextResponse.json({
44+
percent_credit_used: data.percent_credit_used,
45+
remaining_topup_credits: data.remaining_topup_credits,
46+
});
4447
} catch (error) {
4548
return NextResponse.json(
4649
{ error: "Error getting requests usage" },

app/blog/[slug]/page.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { format, parseISO } from "date-fns";
33
import Image from "next/image";
44
import { notFound } from "next/navigation";
55
import { posts } from "@/lib/blog/postData";
6+
import Footer from "@/components/footer";
67

78
export const generateStaticParams = async () =>
89
posts.map((post) => ({ slug: post.url.split("/").pop() }));
@@ -83,6 +84,7 @@ const PostLayout = ({ params }: { params: { slug: string } }) => {
8384
dangerouslySetInnerHTML={{ __html: post.content }}
8485
/>
8586
</article>
87+
<Footer />
8688
<script
8789
type="application/ld+json"
8890
dangerouslySetInnerHTML={{

app/blog/page.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { constructMetadata } from "@/lib/utils";
33
import { compareDesc } from "date-fns";
44
import { Metadata } from "next";
55
import { posts } from "@/lib/blog/postData";
6+
import Footer from "@/components/footer";
67

78
export const metadata: Metadata = constructMetadata({
89
title: "Blog",
@@ -25,6 +26,7 @@ export default function Blog() {
2526
<PostCard key={idx} {...post} />
2627
))}
2728
</div>
29+
<Footer />
2830
</div>
2931
);
3032
}

app/faq/page.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { constructMetadata } from "@/lib/utils";
99
import { Metadata } from "next/types";
1010
import { FAQItem } from "@/types/faqItems";
1111
import React from "react";
12+
import Footer from "@/components/footer";
1213

1314
export const metadata: Metadata = constructMetadata({
1415
title: "FAQ",
@@ -77,6 +78,7 @@ const FAQ: React.FC = () => {
7778
</AccordionItem>
7879
</Accordion>
7980
</section>
81+
<Footer />
8082
</>
8183
);
8284
};

app/layout.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import dynamic from "next/dynamic";
99
import { Analytics } from "@vercel/analytics/react";
1010
import { SpeedInsights } from "@vercel/speed-insights/next";
1111
import { ThemeProvider } from "next-themes";
12-
import Footer from "@/components/footer";
1312

1413
const PostHogPageView = dynamic(() => import("./PostHogPageView"), {
1514
ssr: false,
@@ -36,7 +35,6 @@ export default function RootLayout({
3635
<div className="flex min-h-screen flex-col overflow-hidden">
3736
<Header />
3837
{children}
39-
<Footer />
4038
<Toaster position="bottom-right" richColors />
4139
<Analytics />
4240
<SpeedInsights />

components/about.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Card, CardContent, CardDescription } from "@/components/ui/card";
33
import { Tweet } from "@/components/tweet";
44
import { components } from "./ui/my-tweet";
55
import { Badge } from "./ui/badge";
6+
import Footer from "./footer";
67

78
type VideoData = {
89
src: string;
@@ -122,6 +123,7 @@ const AboutComponent: React.FC = () => {
122123
</p>
123124
</div>
124125
</div>
126+
<Footer />
125127
</section>
126128
);
127129
};

components/dashboard.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ type DashboardPageProps = {
1919

2020
export type UsageType = {
2121
percent_credit_used: number | null;
22+
remaining_topup_credits: number | null;
2223
};
2324

2425
export default function DashboardPage({
@@ -31,6 +32,7 @@ export default function DashboardPage({
3132
const [loading, setLoading] = useState(true);
3233
const [usage, setUsage] = useState<UsageType>({
3334
percent_credit_used: null,
35+
remaining_topup_credits: null,
3436
});
3537

3638
const handleCallbackForApp = useCallback(async () => {

0 commit comments

Comments
 (0)