feat: add legal-related page

This commit is contained in:
Sosokker 2024-11-17 19:54:26 +07:00
parent e1b6ba450c
commit 0d937e10ba
12 changed files with 582 additions and 10 deletions

View File

@ -0,0 +1,44 @@
"use client";
import { Separator } from "@/components/ui/separator";
import Link from "next/link";
export function NavSidebar() {
return (
<div className="w-64 p-6 bg-gray-100 dark:bg-gray-800 text-white shadow-lg rounded-lg border-2 border-gray-300 dark:border-gray-600">
<ul className="space-y-4 sticky top-24 text-black dark:text-white">
<Link href="/about">
<li className="flex items-center p-2 relative group hover:scale-105 transition-all duration-200 ease-in-out rounded-md">
<span>About</span>
<div className="absolute bottom-0 left-0 w-full h-[2px] bg-blue-600 scale-x-0 group-hover:scale-x-100 transition-all duration-300"></div>
</li>
</Link>
<Separator className="bg-gray-200 dark:bg-gray-700" />
<Link href="/privacy">
<li className="flex items-center p-2 relative group hover:scale-105 transition-all duration-200 ease-in-out rounded-md">
<span>Privacy</span>
<div className="absolute bottom-0 left-0 w-full h-[2px] bg-blue-600 scale-x-0 group-hover:scale-x-100 transition-all duration-300"></div>
</li>
</Link>
<Separator className="bg-gray-200 dark:bg-gray-700" />
<Link href="/risks">
<li className="flex items-center p-2 relative group hover:scale-105 transition-all duration-200 ease-in-out rounded-md">
<span>Risks</span>
<div className="absolute bottom-0 left-0 w-full h-[2px] bg-blue-600 scale-x-0 group-hover:scale-x-100 transition-all duration-300"></div>
</li>
</Link>
<Separator className="bg-gray-200 dark:bg-gray-700" />
<Link href="/terms">
<li className="flex items-center p-2 relative group hover:scale-105 transition-all duration-200 ease-in-out rounded-md">
<span>Terms</span>
<div className="absolute bottom-0 left-0 w-full h-[2px] bg-blue-600 scale-x-0 group-hover:scale-x-100 transition-all duration-300"></div>
</li>
</Link>
<Separator className="bg-gray-200 dark:bg-gray-700" />
</ul>
</div>
);
}

31
src/app/(legal)/Toc.tsx Normal file
View File

@ -0,0 +1,31 @@
"use client";
import Link from "next/link";
interface Section {
id: string;
title: string;
}
interface TableOfContentProps {
sections: Section[];
}
const TableOfContent = ({ sections }: TableOfContentProps) => {
return (
<div className="w-64 p-6 bg-gray-100 dark:bg-gray-800 text-white shadow-lg rounded-lg border-border border-2">
<h3 className="text-xl font-semibold text-blue-600 dark:text-blue-400 mb-6">Table of Contents</h3>
<ul className="space-y-4 sticky top-24">
{sections.map((section) => (
<li key={section.id}>
<Link href={`#${section.id}`} className="text-gray-800 dark:text-gray-300 hover:text-blue-400">
{`${sections.indexOf(section) + 1}. ${section.title}`}
</Link>
</li>
))}
</ul>
</div>
);
};
export default TableOfContent;

View File

@ -0,0 +1,101 @@
"use client";
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
import TableOfContent from "../Toc";
import { NavSidebar } from "../NavigationSidebar";
const PrivacyPolicy = () => {
const sections = [
{ id: "introduction", title: "Introduction" },
{ id: "data-collection", title: "Data Collection" },
{ id: "data-usage", title: "Data Usage" },
{ id: "data-sharing", title: "Data Sharing" },
{ id: "data-security", title: "Data Security" },
{ id: "user-rights", title: "User Rights" },
{ id: "changes", title: "Changes to Privacy Policy" },
{ id: "contact", title: "Contact Information" },
];
return (
<div className="container max-w-screen-xl flex mt-5">
<div className="flex gap-2">
<NavSidebar />
<TableOfContent sections={sections} />
</div>
<div className="flex-1 ml-4">
<Card className="w-full max-w-3xl bg-white dark:bg-gray-800 shadow-lg rounded-lg">
<CardHeader>
<CardTitle className="text-3xl text-blue-600 dark:text-blue-400">Privacy Policy</CardTitle>
<CardDescription className="text-sm text-gray-500 dark:text-gray-400">
Last Updated: November 17, 2024
</CardDescription>
</CardHeader>
<CardContent>
<div className="prose dark:prose-invert text-gray-800 dark:text-gray-200">
<p>
This Privacy Policy (&quot;Policy&quot;) describes how we collect, use, and share your personal
information when you access and use our Website.
</p>
<h2 id="introduction">1. Introduction</h2>
<p>
We value your privacy. This Policy explains how we collect, use, and protect your personal data when you
use our services.
</p>
<h2 id="data-collection">2. Data Collection</h2>
<p>
We collect various types of information when you use our Website, including personal information,
technical data, and usage data. This includes your name, email address, IP address, and device
information.
</p>
<h2 id="data-usage">3. Data Usage</h2>
<p>
The data we collect is used to improve our services, personalize your experience, and ensure the
functionality of our Website. We may also use your data for marketing purposes and to communicate with
you.
</p>
<h2 id="data-sharing">4. Data Sharing</h2>
<p>
We do not sell your personal data to third parties. However, we may share your data with trusted
partners for the purpose of providing our services, complying with legal obligations, or protecting our
rights.
</p>
<h2 id="data-security">5. Data Security</h2>
<p>
We take reasonable measures to secure your personal data and protect it from unauthorized access,
alteration, disclosure, or destruction. However, no data transmission over the Internet can be
guaranteed as 100% secure.
</p>
<h2 id="user-rights">6. User Rights</h2>
<p>
You have the right to access, update, or delete your personal information. You may also object to the
processing of your data or request a restriction on how we process your data.
</p>
<h2 id="changes">7. Changes to Privacy Policy</h2>
<p>
We may update this Privacy Policy from time to time. Any changes will be posted on this page, and the
updated date will be reflected at the top of the page. We encourage you to review this Policy regularly.
</p>
<h2 id="contact">8. Contact Information</h2>
<p>
If you have any questions about this Privacy Policy or wish to exercise your rights, please contact us
at privacy@b2dventure.com.
</p>
</div>
</CardContent>
<CardFooter className="flex justify-center"></CardFooter>
</Card>
</div>
</div>
);
};
export default PrivacyPolicy;

View File

@ -0,0 +1,105 @@
"use client";
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
import TableOfContent from "../Toc";
import { NavSidebar } from "../NavigationSidebar";
const InvestmentRisks = () => {
const sections = [
{ id: "investment-risk", title: "Investment Risk" },
{ id: "business-closure", title: "Business Closure" },
{ id: "no-return", title: "No Return on Investment" },
{ id: "market-conditions", title: "Market Conditions" },
{ id: "regulatory-risk", title: "Regulatory Risk" },
{ id: "liquidity-risk", title: "Liquidity Risk" },
{ id: "economic-factors", title: "Economic Factors" },
{ id: "mitigation-strategies", title: "Mitigation Strategies" },
];
return (
<div className="container max-w-screen-xl flex mt-5">
<div className="flex gap-2">
<NavSidebar />
<TableOfContent sections={sections} />
</div>
<div className="flex-1 ml-4">
<Card className="w-full max-w-3xl bg-white dark:bg-gray-800 shadow-lg rounded-lg">
<CardHeader>
<CardTitle className="text-3xl text-blue-600 dark:text-blue-400">Investment Risks</CardTitle>
<CardDescription className="text-sm text-gray-500 dark:text-gray-400">
Last Updated: November 17, 2024
</CardDescription>
</CardHeader>
<CardContent>
<div className="prose dark:prose-invert text-gray-800 dark:text-gray-200">
<p>
Investing in opportunities through our platform carries inherent risks. It is important that you fully
understand these risks before proceeding with any investment. This page outlines some of the potential
risks associated with investing in businesses listed on our platform.
</p>
<h2 id="investment-risk">1. Investment Risk</h2>
<p>
All investments carry risk. The value of your investment may fluctuate, and there is a possibility that
you could lose the entire amount invested. You should only invest money that you can afford to lose.
</p>
<h2 id="business-closure">2. Business Closure</h2>
<p>
The businesses listed on our platform may face financial difficulties or other challenges that could
lead to their closure. In the event of a business closing, investors may lose their entire investment,
and there may be no recourse for recovering the invested funds.
</p>
<h2 id="no-return">3. No Return on Investment</h2>
<p>
While some businesses may generate returns, there is no guarantee that you will receive a return on your
investment. If a business does not succeed or fails to generate profits, you may not receive any return
on your investment.
</p>
<h2 id="market-conditions">4. Market Conditions</h2>
<p>
Economic and market conditions can affect the success of a business. Factors such as changes in demand,
competition, or overall market downturns can negatively impact the businesss ability to generate
revenue and, consequently, affect your investment return.
</p>
<h2 id="regulatory-risk">5. Regulatory Risk</h2>
<p>
Changes in laws or regulations could affect the operations of a business and impact its ability to
operate successfully. Businesses may face additional compliance costs or regulatory restrictions, which
can negatively impact their profitability and the value of your investment.
</p>
<h2 id="liquidity-risk">6. Liquidity Risk</h2>
<p>
Investment opportunities on our platform may lack liquidity. This means you may not be able to easily
sell or exit your investment when you wish. The inability to quickly liquidate an investment may impact
your ability to access your funds.
</p>
<h2 id="economic-factors">7. Economic Factors</h2>
<p>
Broader economic factors, such as inflation, unemployment, and interest rates, can influence business
performance and impact your investment. Negative economic shifts can lead to a decline in investment
value.
</p>
<h2 id="mitigation-strategies">8. Mitigation Strategies</h2>
<p>
While we cannot eliminate all risks, we recommend conducting thorough due diligence before investing.
Additionally, diversifying your investment portfolio and staying informed about market trends and
business performance can help mitigate some of these risks.
</p>
</div>
</CardContent>
<CardFooter className="flex justify-center"></CardFooter>
</Card>
</div>
</div>
);
};
export default InvestmentRisks;

View File

@ -0,0 +1,108 @@
"use client";
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
import TableOfContent from "../Toc";
import { NavSidebar } from "../NavigationSidebar";
const TermsOfService = () => {
const sections = [
{ id: "eligibility", title: "Eligibility" },
{ id: "user-accounts", title: "User Accounts" },
{ id: "user-content", title: "User Content" },
{ id: "investment-activity", title: "Investment Activity" },
{ id: "disclaimers", title: "Disclaimers" },
{ id: "limitation-of-liability", title: "Limitation of Liability" },
{ id: "indemnification", title: "Indemnification" },
{ id: "termination", title: "Termination" },
];
return (
<div className="container max-w-screen-xl flex mt-5">
<div className="flex gap-2">
<NavSidebar />
<TableOfContent sections={sections} />
</div>
<div className="flex-1 ml-4">
<Card className="w-full max-w-3xl bg-white dark:bg-gray-800 shadow-lg rounded-lg">
<CardHeader>
<CardTitle className="text-3xl text-blue-600 dark:text-blue-400">Terms of Service</CardTitle>
<CardDescription className="text-sm text-gray-500 dark:text-gray-400">
Last Updated: November 17, 2024
</CardDescription>
</CardHeader>
<CardContent>
<div className="prose dark:prose-invert text-gray-800 dark:text-gray-200">
<p>
These Terms of Service (&quot;Terms&quot;) govern your access to and use of the Website, which is owned
and operated by B2DVenture Company LLC (&quot;B2DVenture&quot;, &quot;we&quot;, &quot;us&quot;, or
&quot;our&quot;).
</p>
<h2 id="eligibility">1. Eligibility</h2>
<p>
You must be at least 18 years old and have the legal capacity to enter into a binding agreement in order
to use the Website. You may not access or use the Website if you are not qualified.
</p>
<h2 id="user-accounts">2. User Accounts</h2>
<p>
In order to access certain features of the Website, such as uploading investment opportunities or making
investments, you may be required to create an account.
</p>
<p>
You are responsible for maintaining the confidentiality of your account information, including your
username and password. You are also responsible for all activity that occurs under your account.
</p>
<h2 id="user-content">3. User Content</h2>
<p>
The Website allows users to upload content, including images, videos, and text (collectively, &quot;User
Content&quot;). You retain all ownership rights in your User Content. However, by uploading User Content
to the Website, you grant B2DVenture a non-exclusive, royalty-free, worldwide license to use, reproduce,
modify, publish, and distribute your User Content in connection with the Website and our business.
</p>
<h2 id="investment-activity">4. Investment Activity</h2>
<p>
The Website is a platform that connects businesses seeking funding (the &quot;Issuers&quot;) with
potential investors (the &quot;Investors&quot;). B2DVenture does not act as a financial advisor, broker,
or dealer. We do not recommend or endorse any particular investment opportunity.
</p>
<h2 id="disclaimers">5. Disclaimers</h2>
<p>
The Website and the information contained herein are provided for informational purposes only and should
not be considered as investment advice.
</p>
<h2 id="limitation-of-liability">6. Limitation of Liability</h2>
<p>
B2DVenture shall not be liable for any damages arising out of or in connection with your use of the
Website, including but not limited to, direct, indirect, incidental, consequential, or punitive damages.
</p>
<h2 id="indemnification">7. Indemnification</h2>
<p>
You agree to indemnify and hold harmless B2DVenture, its officers, directors, employees, agents, and
licensors from and against any and all claims, demands, losses, liabilities, costs, or expenses
(including attorneys&quot; fees) arising out of or in connection with your use of the Website or your
violation of these Terms.
</p>
<h2 id="termination">8. Termination</h2>
<p>
We may terminate your access to the Website for any reason, at any time, without notice. This includes
if you violate any of these Terms, or if we believe that your use of the Website is harmful to us or to
any other user.
</p>
</div>
</CardContent>
<CardFooter className="flex justify-center"></CardFooter>
</Card>
</div>
</div>
);
};
export default TermsOfService;

View File

@ -3,6 +3,8 @@ import { Card, CardContent, CardFooter, CardDescription, CardHeader, CardTitle }
import { LoginButton } from "@/components/auth/loginButton";
import { LoginForm } from "@/components/auth/loginForm";
import Link from "next/link";
export default function Login() {
return (
<div
@ -23,7 +25,17 @@ export default function Login() {
<LoginButton />
</CardContent>
<CardFooter className="text-xs justify-center">
By signing up, you agree to the Terms of Service and acknowledge youve read our Privacy Policy.
<span>
By signing in, you agree to the{" "}
<Link href="/terms" rel="noopener noreferrer" target="_blank" className="text-blue-600 underline">
Terms of Service
</Link>{" "}
and acknowledge youve read our{" "}
<Link href="/privacy" rel="noopener noreferrer" target="_blank" className="text-blue-600 underline">
Privacy Policy
</Link>
.
</span>
</CardFooter>
</Card>
</div>

View File

@ -3,11 +3,13 @@ import { Card, CardContent, CardFooter, CardDescription, CardHeader, CardTitle }
import { SignupButton } from "@/components/auth/signupButton";
import { SignupForm } from "@/components/auth/signupForm";
import Link from "next/link";
export default function Signup() {
return (
<div
className="bg-cover bg-center min-h-screen flex items-center justify-center"
style={{ backgroundImage: "url(/signup.png)" }}
style={{ backgroundImage: "url(/login.png)" }}
>
<Card>
<CardHeader className="items-center">
@ -23,7 +25,17 @@ export default function Signup() {
<SignupButton />
</CardContent>
<CardFooter className="text-xs justify-center">
By signing up, you agree to the Terms of Service and acknowledge youve read our Privacy Policy.
<span>
By signing up, you agree to the{" "}
<Link href="/terms" rel="noopener noreferrer" target="_blank" className="text-blue-600 underline">
Terms of Service
</Link>{" "}
and acknowledge youve read our{" "}
<Link href="/privacy" rel="noopener noreferrer" target="_blank" className="text-blue-600 underline">
Privacy Policy
</Link>
.
</span>{" "}
</CardFooter>
</Card>
</div>

View File

@ -18,13 +18,13 @@ export function SiteFooter() {
<Link href="/about" className="hover:underline">
About Us
</Link>
<Link href="/services" className="hover:underline">
Services
<Link href="/privacy" className="hover:underline">
Privacy
</Link>
<Link
href="mailto:b2d.ventures.contact@gmail.com"
className="hover:underline"
>
<Link href="/terms" className="hover:underline">
Terms and Service
</Link>
<Link href="mailto:b2d.ventures.contact@gmail.com" className="hover:underline">
Contact
</Link>
</div>

140
src/components/ui/sheet.tsx Normal file
View File

@ -0,0 +1,140 @@
"use client"
import * as React from "react"
import * as SheetPrimitive from "@radix-ui/react-dialog"
import { cva, type VariantProps } from "class-variance-authority"
import { X } from "lucide-react"
import { cn } from "@/lib/utils"
const Sheet = SheetPrimitive.Root
const SheetTrigger = SheetPrimitive.Trigger
const SheetClose = SheetPrimitive.Close
const SheetPortal = SheetPrimitive.Portal
const SheetOverlay = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Overlay
className={cn(
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
className
)}
{...props}
ref={ref}
/>
))
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName
const sheetVariants = cva(
"fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500",
{
variants: {
side: {
top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
bottom:
"inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
right:
"inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
},
},
defaultVariants: {
side: "right",
},
}
)
interface SheetContentProps
extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,
VariantProps<typeof sheetVariants> {}
const SheetContent = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Content>,
SheetContentProps
>(({ side = "right", className, children, ...props }, ref) => (
<SheetPortal>
<SheetOverlay />
<SheetPrimitive.Content
ref={ref}
className={cn(sheetVariants({ side }), className)}
{...props}
>
{children}
<SheetPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary">
<X className="h-4 w-4" />
<span className="sr-only">Close</span>
</SheetPrimitive.Close>
</SheetPrimitive.Content>
</SheetPortal>
))
SheetContent.displayName = SheetPrimitive.Content.displayName
const SheetHeader = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col space-y-2 text-center sm:text-left",
className
)}
{...props}
/>
)
SheetHeader.displayName = "SheetHeader"
const SheetFooter = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
className
)}
{...props}
/>
)
SheetFooter.displayName = "SheetFooter"
const SheetTitle = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Title
ref={ref}
className={cn("text-lg font-semibold text-foreground", className)}
{...props}
/>
))
SheetTitle.displayName = SheetPrimitive.Title.displayName
const SheetDescription = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Description
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
))
SheetDescription.displayName = SheetPrimitive.Description.displayName
export {
Sheet,
SheetPortal,
SheetOverlay,
SheetTrigger,
SheetClose,
SheetContent,
SheetHeader,
SheetFooter,
SheetTitle,
SheetDescription,
}

19
src/hooks/use-mobile.tsx Normal file
View File

@ -0,0 +1,19 @@
import * as React from "react"
const MOBILE_BREAKPOINT = 768
export function useIsMobile() {
const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined)
React.useEffect(() => {
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)
const onChange = () => {
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
}
mql.addEventListener("change", onChange)
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
return () => mql.removeEventListener("change", onChange)
}, [])
return !!isMobile
}

View File

@ -14,6 +14,6 @@ export const config = {
* - favicon.ico (favicon file)
* Feel free to modify this pattern to include more paths.
*/
"/((?!_next/static|_next/image|$|favicon.ico|payment-success|verify|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)",
"/((?!_next/static|_next/image|$|favicon.ico|payment-success|verify|terms|contact|risks|about|privacy|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)",
],
};