ui: fix policy and terms acceptance ui and use dialog for invest

This commit is contained in:
Sosokker 2024-11-21 11:56:49 +07:00
parent 91cd786eb6
commit 5c5c736ce8
3 changed files with 203 additions and 83 deletions

View File

@ -0,0 +1,13 @@
import { Separator } from "@/components/ui/separator";
export function InvestmentAmountInfo({ amount }: { amount: number }) {
return (
<div className="mt-4">
<span className="flex flex-row justify-between">
<p>Amount to be paid</p>
<p>${amount}</p>
</span>
<Separator />
</div>
);
}

View File

@ -0,0 +1,60 @@
"use client";
import React from "react";
import { Elements } from "@stripe/react-stripe-js";
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import CheckoutPage from "./checkoutPage";
import convertToSubcurrency from "@/lib/convertToSubcurrency";
import { Button } from "@/components/ui/button";
interface PaymentDialogProps {
open: boolean;
// eslint-disable-next-line no-unused-vars
onOpenChange: (open: boolean) => void;
amount: number;
stripePromise: Promise<any>;
isAcceptTermAndService: () => boolean;
projectId: number;
investorId: string;
}
export function PaymentDialog({
open,
onOpenChange,
amount,
stripePromise,
isAcceptTermAndService,
projectId,
investorId,
}: PaymentDialogProps) {
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent>
<DialogHeader>
<DialogTitle>Payment Information</DialogTitle>
</DialogHeader>
<div className="space-y-4">
<p>Proceed with the payment to complete your investment.</p>
<Elements
stripe={stripePromise}
options={{
mode: "payment",
amount: convertToSubcurrency(amount),
currency: "usd",
}}
>
<CheckoutPage
amount={amount}
isAcceptTermAndService={isAcceptTermAndService}
project_id={projectId}
investor_id={investorId}
/>
</Elements>
</div>
<DialogFooter>
<Button onClick={() => onOpenChange(false)}>Cancel</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}

View File

@ -7,13 +7,17 @@ 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 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 { InvestmentAmountInfo } from "./InvestmentAmountInfo";
import { Button } from "@/components/ui/button";
import { PaymentDialog } from "./PaymentDialog";
import Link from "next/link";
if (process.env.NEXT_PUBLIC_STRIPE_PUBLIC_KEY === undefined) {
throw new Error("NEXT_PUBLIC_STRIPE_PUBLIC_KEY is not defined");
@ -22,35 +26,35 @@ const stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLIC_KEY);
const term_data = [
{
term: "Minimum Investment",
description: "The minimum investment amount is $500.",
},
{
term: "Investment Horizon",
description: "Investments are typically locked for a minimum of 12 months.",
term: "Risk Disclosure",
description:
"Investments carry risks, including the potential loss of principal. It is important to carefully consider your risk tolerance before proceeding with any investment.",
link: "/risks",
},
{
term: "Fees",
description: "A management fee of 2% will be applied annually.",
description:
"A management fee of 3% will be taken from the company after the fundraising is completed. This fee is non-refundable.",
link: null,
},
{
term: "Returns",
description: "Expected annual returns are between 8% and 12%.",
},
{
term: "Risk Disclosure",
description: "Investments carry risks, including the loss of principal.",
link: null,
},
{
term: "Withdrawal Policy",
description: "Withdrawals can be made after the lock-in period.",
description:
"Withdrawals cannot be made after the fundraising period ends. Once the investment is finalized, it is non-refundable.",
link: null,
},
];
export default function InvestPage() {
const [checkedTerms, setCheckedTerms] = useState(Array(term_data.length).fill(false));
const [investAmount, setInvestAmount] = useState(10);
const [checkboxStates, setCheckboxStates] = useState([false, false]);
const [investAmount, setInvestAmount] = useState<number>(10);
const [investor_id, setInvestorId] = useState<string>("");
const [showPaymentModal, setPaymentModal] = useState(false);
const params = useParams<{ id: string }>();
const supabase = createSupabaseClient();
@ -77,16 +81,17 @@ export default function InvestPage() {
} = useQuery(getProjectDataQuery(supabase, Number(params.id)));
const handleCheckboxChange = (index: number) => {
const updatedCheckedTerms = [...checkedTerms];
updatedCheckedTerms[index] = !updatedCheckedTerms[index];
setCheckedTerms(updatedCheckedTerms);
const updatedCheckboxStates = [...checkboxStates];
updatedCheckboxStates[index] = !updatedCheckboxStates[index];
setCheckboxStates(updatedCheckboxStates);
};
const isAcceptTermAndService = () => {
if (checkedTerms.some((checked) => !checked)) {
return false;
}
return true;
return checkboxStates.every((checked) => checked);
};
const getInputBorderColor = (min: number) => {
return investAmount >= min ? "border-green-500" : "border-red-500";
};
return (
@ -96,76 +101,118 @@ export default function InvestPage() {
) : projectError ? (
<p>Error loading project data. Please try again later.</p>
) : projectData ? (
<>
<div>
<h1 className="text-2xl md:text-4xl font-bold">Invest in {projectData.project_name}</h1>
<Separator className="my-4" />
<div className="flex gap-6">
<div id="investment" className="w-3/4">
{/* Investment Amount Section */}
<div className="w-3/4">
<h2 className="text:base md:text-2xl font-bold">Investment Amount</h2>
<h3 className="text-gray-500 text-md">Payments are processed immediately in USD$</h3>
<Input
className={`py-7 mt-4 text-lg border-2 ${getInputBorderColor(10)} rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus-visible:ring-0`}
type="number"
placeholder="min $10"
min={10}
onChangeCapture={(e) => setInvestAmount(Number(e.currentTarget.value))}
/>
<InvestmentAmountInfo amount={investAmount} />
</div>
<Separator className="my-4" />
{/* Investment Amount Section */}
<div className="w-1/2 space-y-2">
<h2 className="text:base md:text-2xl">Investment Amount</h2>
<Input
className="w-52"
type="number"
placeholder="min $10"
min={10}
onChangeCapture={(e) => setInvestAmount(Number(e.currentTarget.value))}
/>
</div>
<Separator className="my-4" />
{/* Terms and Services Section */}
<div className="md:w-2/3 space-y-2">
<h2 className="text-2xl">Terms and Services</h2>
<h3 className="text-gray-500 text-md">Please read and accept Term and Services first</h3>
<div id="term-condition">
<Table>
<TableHeader>
<TableRow>
<TableHead>Term</TableHead>
<TableHead>Description</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{term_data.map((item, index) => (
<TableRow key={index}>
<TableCell>
{item.link != null ? (
<Link
href={item.link}
rel="noopener noreferrer"
target="_blank"
className="text-blue-500 underline"
>
{item.term}
</Link>
) : (
item.term
)}
</TableCell>
<TableCell>{item.description}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
{/* Terms and Services Section */}
<div className="md:w-2/3 space-y-2">
<h2 className="text-2xl">Terms and Services</h2>
<Table>
<TableHeader>
<TableRow>
<TableHead>Select</TableHead>
<TableHead>Term</TableHead>
<TableHead>Description</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{term_data.map((item, index) => (
<TableRow key={index}>
<TableCell>
<input
<div className="mt-4 space-y-4">
{/* First Checkbox with Terms */}
<div className="flex items-center space-x-2">
<Input
type="checkbox"
checked={checkedTerms[index]}
onChange={() => handleCheckboxChange(index)}
checked={checkboxStates[0]}
onChange={() => handleCheckboxChange(0)}
className="h-4 w-4"
/>
</TableCell>
<TableCell>{item.term}</TableCell>
<TableCell>{item.description}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
<Separator className="my-4" />
<p className="text-xs text-gray-500">
I understand that this offering involves the use of a third-party custodian, who will act as the
legal holder of the assets involved. As an investor, I acknowledge that I will be required to
create an account with this custodian and enter into necessary agreements, including those
related to the custody of the assets. I am aware that I may need to provide certain information
to verify my identity and complete the account creation process. I also understand that the
platform facilitating this offering does not manage or hold any custodial accounts for its
investors. Additionally, I recognize that the platform, its affiliates, or its representatives
will not be held responsible for any damages, losses, costs, or expenses arising from (i) the
creation or management of custodial accounts, (ii) unauthorized access or loss of assets within
these accounts, or (iii) the custodian&apos;s failure to fulfill its obligations.
</p>
</div>
{/* Payment Information Section */}
<div className="w-full space-y-2">
<h2 className="text:base md:text-2xl">Payment Information</h2>
<Elements
stripe={stripePromise}
options={{
mode: "payment",
amount: convertToSubcurrency(investAmount),
currency: "usd",
}}
>
<CheckoutPage
amount={investAmount}
isAcceptTermAndService={isAcceptTermAndService}
project_id={Number(params.id)}
investor_id={investor_id}
/>
</Elements>
{/* Second Checkbox for Acceptance */}
<div className="flex items-center space-x-2">
<Input
type="checkbox"
checked={checkboxStates[1]}
onChange={() => handleCheckboxChange(1)}
className="h-4 w-4"
/>
<p className="text-xs text-gray-500">I have read and accept the terms of investment.</p>
</div>
</div>
</div>
</div>
<Separator className="my-4" />
<Button disabled={!isAcceptTermAndService()} onClick={() => setPaymentModal(true)}>
Proceed to Payment
</Button>
</div>
</div>
</>
</div>
) : (
<p>No project data found.</p>
)}
<PaymentDialog
open={showPaymentModal}
onOpenChange={setPaymentModal}
amount={investAmount}
stripePromise={stripePromise}
isAcceptTermAndService={isAcceptTermAndService}
projectId={Number(params.id)}
investorId={investor_id}
/>
</div>
);
}