diff --git a/src/app/(investment)/invest/[id]/checkoutPage.tsx b/src/app/(investment)/invest/[id]/checkoutPage.tsx index bbae0e2..5fbdf49 100644 --- a/src/app/(investment)/invest/[id]/checkoutPage.tsx +++ b/src/app/(investment)/invest/[id]/checkoutPage.tsx @@ -1,7 +1,7 @@ "use client"; import React, { useEffect, useState } from "react"; -import { useStripe, useElements, PaymentElement } from "@stripe/react-stripe-js"; +import { useStripe, useElements, CardElement } from "@stripe/react-stripe-js"; import convertToSubcurrency from "@/lib/convertToSubcurrency"; import { Dialog, @@ -14,12 +14,19 @@ import { DialogClose, } from "@/components/ui/dialog"; import { Button } from "@/components/ui/button"; +import useSession from "@/lib/supabase/useSession"; +import { createSupabaseClient } from "@/lib/supabase/clientComponentClient"; +import { useRouter } from "next/navigation"; const CheckoutPage = ({ amount, + project_id, + investor_id, isAcceptTermAndService, }: { amount: number; + project_id: number; + investor_id: string; isAcceptTermAndService: () => boolean; }) => { const stripe = useStripe(); @@ -27,8 +34,12 @@ const CheckoutPage = ({ const [errorMessage, setErrorMessage] = useState(); const [clientSecret, setClientSecret] = useState(""); const [loading, setLoading] = useState(false); - const [isDialogOpen, setIsDialogOpen] = useState(false); // State for dialog open/close + const [isDialogOpen, setIsDialogOpen] = useState(false); const isAcceptTerm = isAcceptTermAndService(); + const router = useRouter(); + + const { session } = useSession(); + const user = session?.user; useEffect(() => { fetch("/api/create-payment-intent", { @@ -58,19 +69,39 @@ const CheckoutPage = ({ return; } - const { error } = await stripe.confirmPayment({ - elements, - clientSecret, - confirmParams: { - return_url: `http://www.localhost:3000/payment-success?amount=${amount}`, - }, - }); + await stripe + .confirmCardPayment(clientSecret, { + payment_method: { + card: elements.getElement(CardElement)!, + }, + }) + .then(async (result) => { + if (result.error) { + setErrorMessage(result.error.message); + } else { + try { + const supabase = createSupabaseClient(); + const { data, error } = await supabase.from("InvestmentDeal").insert([ + { + investorId: investor_id, + projectId: project_id, + dealAmount: amount, + }, + ]); + console.log("ADADSADWADWWAD"); - if (error) { - setErrorMessage(error.message); - } - - setLoading(false); + if (error) { + console.error("Supabase Insert Error:", error.message); + } else { + console.log("Insert successful:", data); + router.push(`http://www.localhost:3000/payment-success?amount=${amount}`); + } + } catch (err) { + console.error("Unexpected error during Supabase insert:", err); + } + } + setLoading(false); + }); }; if (!clientSecret || !stripe || !elements) { @@ -89,7 +120,7 @@ const CheckoutPage = ({ return (
- {clientSecret && } + {clientSecret && } {errorMessage &&
{errorMessage}
} diff --git a/src/app/(investment)/invest/[id]/page.tsx b/src/app/(investment)/invest/[id]/page.tsx index 784efc4..1409243 100644 --- a/src/app/(investment)/invest/[id]/page.tsx +++ b/src/app/(investment)/invest/[id]/page.tsx @@ -2,15 +2,21 @@ import { useState } from "react"; import { useRouter } from "next/navigation"; +import { useParams } from "next/navigation"; import { Separator } from "@/components/ui/separator"; import { Input } from "@/components/ui/input"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; +import { useQuery } from "@supabase-cache-helpers/postgrest-react-query"; import convertToSubcurrency from "@/lib/convertToSubcurrency"; import CheckoutPage from "./checkoutPage"; import { Elements } from "@stripe/react-stripe-js"; import { loadStripe } from "@stripe/stripe-js"; +import { getProjectDataQuery } from "@/lib/data/projectQuery"; +import { createSupabaseClient } from "@/lib/supabase/clientComponentClient"; +import useSession from "@/lib/supabase/useSession"; + if (process.env.NEXT_PUBLIC_STRIPE_PUBLIC_KEY === undefined) { throw new Error("NEXT_PUBLIC_STRIPE_PUBLIC_KEY is not defined"); } @@ -47,6 +53,14 @@ export default function InvestPage() { const [checkedTerms, setCheckedTerms] = useState(Array(term_data.length).fill(false)); const [investAmount, setInvestAmount] = useState(10); + const { session } = useSession(); + const investor_id = session!.user.id; + + const params = useParams<{ id: string }>(); + const supabase = createSupabaseClient(); + + const { data: projectData, isLoading: isLoadingProject } = useQuery(getProjectDataQuery(supabase, Number(params.id))); + const handleCheckboxChange = (index: number) => { const updatedCheckedTerms = [...checkedTerms]; updatedCheckedTerms[index] = !updatedCheckedTerms[index]; @@ -62,7 +76,7 @@ export default function InvestPage() { return (
-

Invest on NVIDIA

+

Invest on ${projectData?.project_name}

@@ -113,7 +127,12 @@ export default function InvestPage() { amount: convertToSubcurrency(investAmount), currency: "usd", }}> - +
diff --git a/src/app/(investment)/payment-success/page.tsx b/src/app/(investment)/payment-success/page.tsx index 36052dc..b297416 100644 --- a/src/app/(investment)/payment-success/page.tsx +++ b/src/app/(investment)/payment-success/page.tsx @@ -1,4 +1,10 @@ +import { redirect } from "next/navigation"; + export default function PaymentSuccess({ searchParams: { amount } }: { searchParams: { amount: string } }) { + if (!amount) { + redirect("/"); + } + return (
diff --git a/src/lib/data/projectQuery.ts b/src/lib/data/projectQuery.ts index c6d0d71..ff64ab3 100644 --- a/src/lib/data/projectQuery.ts +++ b/src/lib/data/projectQuery.ts @@ -1,11 +1,14 @@ import { SupabaseClient } from "@supabase/supabase-js"; -async function getTopProjects(client: SupabaseClient, numberOfRecords: number = 4) { - try { - const { data, error } = await client - .from("Project") - .select( - ` +async function getTopProjects( + client: SupabaseClient, + numberOfRecords: number = 4, +) { + try { + const { data, error } = await client + .from("Project") + .select( + ` id, projectName, businessId, @@ -27,22 +30,44 @@ async function getTopProjects(client: SupabaseClient, numberOfRecords: number = Business ( location ) - ` - ) - .order("publishedTime", { ascending: false }) - .limit(numberOfRecords); + `, + ) + .order("publishedTime", { ascending: false }) + .limit(numberOfRecords); - if (error) { - console.error("Error fetching top projects:", error.message); - return { data: null, error: error.message }; - } - - return { data, error: null }; - } catch (err) { - console.error("Unexpected error:", err); - return { data: null, error: "An unexpected error occurred." }; + if (error) { + console.error("Error fetching top projects:", error.message); + return { data: null, error: error.message }; } + + return { data, error: null }; + } catch (err) { + console.error("Unexpected error:", err); + return { data: null, error: "An unexpected error occurred." }; } +} + +function getProjectDataQuery(client: SupabaseClient, projectId: number) { + return client.from("Project").select( + ` + project_name:projectName, + project_short_description:projectShortDescription, + project_description:projectDescription, + published_time:publishedTime, + ...ProjectInvestmentDetail!inner ( + min_investment:minInvestment, + total_investment:totalInvestment, + target_investment:targetInvestment, + investment_deadline:investmentDeadline + ), + tags:ItemTag!inner ( + ...Tag!inner ( + tag_name:value + ) + ) + `, + ).eq("id", projectId).single(); +} async function getProjectData(client: SupabaseClient, projectId: number) { const query = client.from("Project").select( @@ -62,11 +87,11 @@ async function getProjectData(client: SupabaseClient, projectId: number) { tag_name:value ) ) - ` - ).eq("id", projectId).single() + `, + ).eq("id", projectId).single(); - const {data, error} = await query; - return { data, error } + const { data, error } = await query; + return { data, error }; } export interface FilterParams { @@ -79,14 +104,25 @@ export interface FilterParams { } export interface FilterProjectQueryParams extends FilterParams { - page: number, - pageSize: number + page: number; + pageSize: number; } -function searchProjectsQuery(client: SupabaseClient, {searchTerm, tagsFilter, projectStatus, businessTypeFilter, sortByTimeFilter, page = 1, pageSize = 4}: FilterProjectQueryParams) { +function searchProjectsQuery( + client: SupabaseClient, + { + searchTerm, + tagsFilter, + projectStatus, + businessTypeFilter, + sortByTimeFilter, + page = 1, + pageSize = 4, + }: FilterProjectQueryParams, +) { const start = (page - 1) * pageSize; const end = start + pageSize - 1; - + let query = client.from("Project").select( ` project_id:id, @@ -114,8 +150,8 @@ function searchProjectsQuery(client: SupabaseClient, {searchTerm, tagsFilter, pr ), business_location:location ) - ` - ).order("publishedTime", { ascending: false }).range(start, end) + `, + ).order("publishedTime", { ascending: false }).range(start, end); if (sortByTimeFilter === "all") { sortByTimeFilter = undefined; @@ -134,24 +170,27 @@ function searchProjectsQuery(client: SupabaseClient, {searchTerm, tagsFilter, pr } if (searchTerm) { - query = query.ilike('projectName', `%${searchTerm}%`) + query = query.ilike("projectName", `%${searchTerm}%`); } if (tagsFilter) { - query = query.in('ItemTag.Tag.value', tagsFilter) + query = query.in("ItemTag.Tag.value", tagsFilter); } if (projectStatus) { - query = query.eq("ProjectStatus.value", projectStatus) + query = query.eq("ProjectStatus.value", projectStatus); } if (businessTypeFilter) { - query = query.eq("Business.businessType.value", businessTypeFilter) + query = query.eq("Business.businessType.value", businessTypeFilter); } return query; } - -export { getTopProjects, getProjectData, searchProjectsQuery }; - +export { + getProjectData, + getProjectDataQuery, + getTopProjects, + searchProjectsQuery, +};