mirror of
https://github.com/Sosokker/B2D-Ventures.git
synced 2025-12-19 05:54:06 +01:00
feat: store investment statement in database
This commit is contained in:
parent
fc1dd4b4d9
commit
d8a2f13d6c
@ -1,7 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import React, { useEffect, useState } from "react";
|
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 convertToSubcurrency from "@/lib/convertToSubcurrency";
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
@ -14,12 +14,19 @@ import {
|
|||||||
DialogClose,
|
DialogClose,
|
||||||
} from "@/components/ui/dialog";
|
} from "@/components/ui/dialog";
|
||||||
import { Button } from "@/components/ui/button";
|
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 = ({
|
const CheckoutPage = ({
|
||||||
amount,
|
amount,
|
||||||
|
project_id,
|
||||||
|
investor_id,
|
||||||
isAcceptTermAndService,
|
isAcceptTermAndService,
|
||||||
}: {
|
}: {
|
||||||
amount: number;
|
amount: number;
|
||||||
|
project_id: number;
|
||||||
|
investor_id: string;
|
||||||
isAcceptTermAndService: () => boolean;
|
isAcceptTermAndService: () => boolean;
|
||||||
}) => {
|
}) => {
|
||||||
const stripe = useStripe();
|
const stripe = useStripe();
|
||||||
@ -27,8 +34,12 @@ const CheckoutPage = ({
|
|||||||
const [errorMessage, setErrorMessage] = useState<string>();
|
const [errorMessage, setErrorMessage] = useState<string>();
|
||||||
const [clientSecret, setClientSecret] = useState("");
|
const [clientSecret, setClientSecret] = useState("");
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [isDialogOpen, setIsDialogOpen] = useState(false); // State for dialog open/close
|
const [isDialogOpen, setIsDialogOpen] = useState(false);
|
||||||
const isAcceptTerm = isAcceptTermAndService();
|
const isAcceptTerm = isAcceptTermAndService();
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const { session } = useSession();
|
||||||
|
const user = session?.user;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetch("/api/create-payment-intent", {
|
fetch("/api/create-payment-intent", {
|
||||||
@ -58,19 +69,39 @@ const CheckoutPage = ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { error } = await stripe.confirmPayment({
|
await stripe
|
||||||
elements,
|
.confirmCardPayment(clientSecret, {
|
||||||
clientSecret,
|
payment_method: {
|
||||||
confirmParams: {
|
card: elements.getElement(CardElement)!,
|
||||||
return_url: `http://www.localhost:3000/payment-success?amount=${amount}`,
|
},
|
||||||
},
|
})
|
||||||
});
|
.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) {
|
if (error) {
|
||||||
setErrorMessage(error.message);
|
console.error("Supabase Insert Error:", error.message);
|
||||||
}
|
} else {
|
||||||
|
console.log("Insert successful:", data);
|
||||||
setLoading(false);
|
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) {
|
if (!clientSecret || !stripe || !elements) {
|
||||||
@ -89,7 +120,7 @@ const CheckoutPage = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{clientSecret && <PaymentElement />}
|
{clientSecret && <CardElement />}
|
||||||
|
|
||||||
{errorMessage && <div>{errorMessage}</div>}
|
{errorMessage && <div>{errorMessage}</div>}
|
||||||
|
|
||||||
|
|||||||
@ -2,15 +2,21 @@
|
|||||||
|
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
|
import { useParams } from "next/navigation";
|
||||||
import { Separator } from "@/components/ui/separator";
|
import { Separator } from "@/components/ui/separator";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
|
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 convertToSubcurrency from "@/lib/convertToSubcurrency";
|
||||||
import CheckoutPage from "./checkoutPage";
|
import CheckoutPage from "./checkoutPage";
|
||||||
import { Elements } from "@stripe/react-stripe-js";
|
import { Elements } from "@stripe/react-stripe-js";
|
||||||
import { loadStripe } from "@stripe/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) {
|
if (process.env.NEXT_PUBLIC_STRIPE_PUBLIC_KEY === undefined) {
|
||||||
throw new Error("NEXT_PUBLIC_STRIPE_PUBLIC_KEY is not defined");
|
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 [checkedTerms, setCheckedTerms] = useState(Array(term_data.length).fill(false));
|
||||||
const [investAmount, setInvestAmount] = useState(10);
|
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 handleCheckboxChange = (index: number) => {
|
||||||
const updatedCheckedTerms = [...checkedTerms];
|
const updatedCheckedTerms = [...checkedTerms];
|
||||||
updatedCheckedTerms[index] = !updatedCheckedTerms[index];
|
updatedCheckedTerms[index] = !updatedCheckedTerms[index];
|
||||||
@ -62,7 +76,7 @@ export default function InvestPage() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mx-10 md:mx-40 my-10">
|
<div className="mx-10 md:mx-40 my-10">
|
||||||
<h1 className="text-2xl md:text-4xl font-bold">Invest on NVIDIA</h1>
|
<h1 className="text-2xl md:text-4xl font-bold">Invest on ${projectData?.project_name}</h1>
|
||||||
<Separator className="my-4" />
|
<Separator className="my-4" />
|
||||||
<div></div>
|
<div></div>
|
||||||
<div>
|
<div>
|
||||||
@ -113,7 +127,12 @@ export default function InvestPage() {
|
|||||||
amount: convertToSubcurrency(investAmount),
|
amount: convertToSubcurrency(investAmount),
|
||||||
currency: "usd",
|
currency: "usd",
|
||||||
}}>
|
}}>
|
||||||
<CheckoutPage amount={investAmount} isAcceptTermAndService={isAcceptTermAndService} />
|
<CheckoutPage
|
||||||
|
amount={investAmount}
|
||||||
|
isAcceptTermAndService={isAcceptTermAndService}
|
||||||
|
project_id={Number(params.id)}
|
||||||
|
investor_id={investor_id}
|
||||||
|
/>
|
||||||
</Elements>
|
</Elements>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,4 +1,10 @@
|
|||||||
|
import { redirect } from "next/navigation";
|
||||||
|
|
||||||
export default function PaymentSuccess({ searchParams: { amount } }: { searchParams: { amount: string } }) {
|
export default function PaymentSuccess({ searchParams: { amount } }: { searchParams: { amount: string } }) {
|
||||||
|
if (!amount) {
|
||||||
|
redirect("/");
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="max-w-6xl mx-auto p-10 text-white text-center border m-10 rounded-md bg-gradient-to-tr from-blue-500 to-purple-500">
|
<main className="max-w-6xl mx-auto p-10 text-white text-center border m-10 rounded-md bg-gradient-to-tr from-blue-500 to-purple-500">
|
||||||
<div className="mb-10">
|
<div className="mb-10">
|
||||||
|
|||||||
@ -1,11 +1,14 @@
|
|||||||
import { SupabaseClient } from "@supabase/supabase-js";
|
import { SupabaseClient } from "@supabase/supabase-js";
|
||||||
|
|
||||||
async function getTopProjects(client: SupabaseClient, numberOfRecords: number = 4) {
|
async function getTopProjects(
|
||||||
try {
|
client: SupabaseClient,
|
||||||
const { data, error } = await client
|
numberOfRecords: number = 4,
|
||||||
.from("Project")
|
) {
|
||||||
.select(
|
try {
|
||||||
`
|
const { data, error } = await client
|
||||||
|
.from("Project")
|
||||||
|
.select(
|
||||||
|
`
|
||||||
id,
|
id,
|
||||||
projectName,
|
projectName,
|
||||||
businessId,
|
businessId,
|
||||||
@ -27,22 +30,44 @@ async function getTopProjects(client: SupabaseClient, numberOfRecords: number =
|
|||||||
Business (
|
Business (
|
||||||
location
|
location
|
||||||
)
|
)
|
||||||
`
|
`,
|
||||||
)
|
)
|
||||||
.order("publishedTime", { ascending: false })
|
.order("publishedTime", { ascending: false })
|
||||||
.limit(numberOfRecords);
|
.limit(numberOfRecords);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error("Error fetching top projects:", error.message);
|
console.error("Error fetching top projects:", error.message);
|
||||||
return { data: null, error: 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." };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
async function getProjectData(client: SupabaseClient, projectId: number) {
|
||||||
const query = client.from("Project").select(
|
const query = client.from("Project").select(
|
||||||
@ -62,11 +87,11 @@ async function getProjectData(client: SupabaseClient, projectId: number) {
|
|||||||
tag_name:value
|
tag_name:value
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
`
|
`,
|
||||||
).eq("id", projectId).single()
|
).eq("id", projectId).single();
|
||||||
|
|
||||||
const {data, error} = await query;
|
const { data, error } = await query;
|
||||||
return { data, error }
|
return { data, error };
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FilterParams {
|
export interface FilterParams {
|
||||||
@ -79,14 +104,25 @@ export interface FilterParams {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface FilterProjectQueryParams extends FilterParams {
|
export interface FilterProjectQueryParams extends FilterParams {
|
||||||
page: number,
|
page: number;
|
||||||
pageSize: 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 start = (page - 1) * pageSize;
|
||||||
const end = start + pageSize - 1;
|
const end = start + pageSize - 1;
|
||||||
|
|
||||||
let query = client.from("Project").select(
|
let query = client.from("Project").select(
|
||||||
`
|
`
|
||||||
project_id:id,
|
project_id:id,
|
||||||
@ -114,8 +150,8 @@ function searchProjectsQuery(client: SupabaseClient, {searchTerm, tagsFilter, pr
|
|||||||
),
|
),
|
||||||
business_location:location
|
business_location:location
|
||||||
)
|
)
|
||||||
`
|
`,
|
||||||
).order("publishedTime", { ascending: false }).range(start, end)
|
).order("publishedTime", { ascending: false }).range(start, end);
|
||||||
|
|
||||||
if (sortByTimeFilter === "all") {
|
if (sortByTimeFilter === "all") {
|
||||||
sortByTimeFilter = undefined;
|
sortByTimeFilter = undefined;
|
||||||
@ -134,24 +170,27 @@ function searchProjectsQuery(client: SupabaseClient, {searchTerm, tagsFilter, pr
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (searchTerm) {
|
if (searchTerm) {
|
||||||
query = query.ilike('projectName', `%${searchTerm}%`)
|
query = query.ilike("projectName", `%${searchTerm}%`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tagsFilter) {
|
if (tagsFilter) {
|
||||||
query = query.in('ItemTag.Tag.value', tagsFilter)
|
query = query.in("ItemTag.Tag.value", tagsFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (projectStatus) {
|
if (projectStatus) {
|
||||||
query = query.eq("ProjectStatus.value", projectStatus)
|
query = query.eq("ProjectStatus.value", projectStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (businessTypeFilter) {
|
if (businessTypeFilter) {
|
||||||
query = query.eq("Business.businessType.value", businessTypeFilter)
|
query = query.eq("Business.businessType.value", businessTypeFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
export { getTopProjects, getProjectData, searchProjectsQuery };
|
getProjectData,
|
||||||
|
getProjectDataQuery,
|
||||||
|
getTopProjects,
|
||||||
|
searchProjectsQuery,
|
||||||
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user