From 5c5c736ce8fad60b7a5c9fe05bd95303cb1ec20c Mon Sep 17 00:00:00 2001 From: Sosokker Date: Thu, 21 Nov 2024 11:56:49 +0700 Subject: [PATCH] ui: fix policy and terms acceptance ui and use dialog for invest --- .../invest/[id]/InvestmentAmountInfo.tsx | 13 ++ .../invest/[id]/PaymentDialog.tsx | 60 +++++ src/app/(investment)/invest/[id]/page.tsx | 213 +++++++++++------- 3 files changed, 203 insertions(+), 83 deletions(-) create mode 100644 src/app/(investment)/invest/[id]/InvestmentAmountInfo.tsx create mode 100644 src/app/(investment)/invest/[id]/PaymentDialog.tsx diff --git a/src/app/(investment)/invest/[id]/InvestmentAmountInfo.tsx b/src/app/(investment)/invest/[id]/InvestmentAmountInfo.tsx new file mode 100644 index 0000000..277f2fa --- /dev/null +++ b/src/app/(investment)/invest/[id]/InvestmentAmountInfo.tsx @@ -0,0 +1,13 @@ +import { Separator } from "@/components/ui/separator"; + +export function InvestmentAmountInfo({ amount }: { amount: number }) { + return ( +
+ +

Amount to be paid

+

${amount}

+
+ +
+ ); +} diff --git a/src/app/(investment)/invest/[id]/PaymentDialog.tsx b/src/app/(investment)/invest/[id]/PaymentDialog.tsx new file mode 100644 index 0000000..a4ef1a9 --- /dev/null +++ b/src/app/(investment)/invest/[id]/PaymentDialog.tsx @@ -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; + isAcceptTermAndService: () => boolean; + projectId: number; + investorId: string; +} + +export function PaymentDialog({ + open, + onOpenChange, + amount, + stripePromise, + isAcceptTermAndService, + projectId, + investorId, +}: PaymentDialogProps) { + return ( + + + + Payment Information + +
+

Proceed with the payment to complete your investment.

+ + + +
+ + + +
+
+ ); +} diff --git a/src/app/(investment)/invest/[id]/page.tsx b/src/app/(investment)/invest/[id]/page.tsx index 6f4344a..cc8c501 100644 --- a/src/app/(investment)/invest/[id]/page.tsx +++ b/src/app/(investment)/invest/[id]/page.tsx @@ -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(10); const [investor_id, setInvestorId] = useState(""); + 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 ? (

Error loading project data. Please try again later.

) : projectData ? ( - <> +

Invest in {projectData.project_name}

+
+
+ {/* Investment Amount Section */} +
+

Investment Amount

+

Payments are processed immediately in USD$

+ setInvestAmount(Number(e.currentTarget.value))} + /> + +
+ - {/* Investment Amount Section */} -
-

Investment Amount

- setInvestAmount(Number(e.currentTarget.value))} - /> -
- + {/* Terms and Services Section */} +
+

Terms and Services

+

Please read and accept Term and Services first

+
+ + + + Term + Description + + + + {term_data.map((item, index) => ( + + + {item.link != null ? ( + + {item.term} + + ) : ( + item.term + )} + + {item.description} + + ))} + +
- {/* Terms and Services Section */} -
-

Terms and Services

- - - - Select - Term - Description - - - - {term_data.map((item, index) => ( - - - + {/* First Checkbox with Terms */} +
+ handleCheckboxChange(index)} + checked={checkboxStates[0]} + onChange={() => handleCheckboxChange(0)} + className="h-4 w-4" /> - - {item.term} - {item.description} - - ))} - -
-
- +

+ 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's failure to fulfill its obligations. +

+
- {/* Payment Information Section */} -
-

Payment Information

- - - + {/* Second Checkbox for Acceptance */} +
+ handleCheckboxChange(1)} + className="h-4 w-4" + /> +

I have read and accept the terms of investment.

+
+
+
+
+ + + +
- + ) : (

No project data found.

)} + + ); }