refactor: apply prettier and remove unused var

This commit is contained in:
sirin 2024-10-28 21:23:30 +07:00
parent 2221b5be69
commit d1872386ca
5 changed files with 60 additions and 403 deletions

View File

@ -1,3 +1,5 @@
src/app/(investment)/deals/[id]/followShareButton.tsx
src/components/ui/*
src/types/database.types.ts
src/types/database.types.ts
src/components/BusinessForm.tsx
src/components/ProjectForm.tsx

View File

@ -1,191 +0,0 @@
"use client";
import React, { useState, useEffect } from "react";
import Image from "next/image";
import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious } from "@/components/ui/carousel";
import { Card, CardContent } from "@/components/ui/card";
import CountUp from "react-countup";
import { Progress } from "@/components/ui/progress";
import { Separator } from "@/components/ui/separator";
import { Button } from "@/components/ui/button";
import { ShareIcon, StarIcon } from "lucide-react";
import { Toaster, toast } from "react-hot-toast";
import useSession from "@/lib/supabase/useSession";
import { redirect } from "next/navigation";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
import Link from "next/link";
export default function Invest() {
const [progress, setProgress] = useState(0);
const [tab, setTab] = useState("Pitch");
const { session, loading } = useSession();
const user = session?.user;
const [sessionLoaded, setSessionLoaded] = useState(false);
const [isFollow, setIsFollow] = useState(false);
useEffect(() => {
// set sessionLoaded to true once session is confirmed
if (!loading) {
setSessionLoaded(true);
}
}, [loading]);
const handleClick = (item: string) => {
setTab(item);
};
const handleShare = () => {
const currentUrl = window.location.href;
if (document.hasFocus()) {
navigator.clipboard.writeText(currentUrl).then(() => {
toast.success("URL copied to clipboard!");
});
}
};
const handleFollow = () => {
if (user) {
setIsFollow((prevState) => !prevState);
// save follow to database
} else {
redirect("/login");
}
};
useEffect(() => {
// percent success
const timer = setTimeout(() => setProgress(66), 500);
return () => clearTimeout(timer);
}, []);
return (
<div>
<div>
<Toaster position="top-right" reverseOrder={false} />
</div>
<div className="w-[90%] h-[450px]-500 md:m-auto mt-12 md:mt-12 pl-14 md:pl-24">
<div>
{/* Name, star and share button packed */}
<div className="grid grid-cols-4">
<div className="flex col-span-2">
<Image src="./logo.svg" alt="logo" width={50} height={50} className="sm:scale-75" />
<div className="mt-3 font-bold text-lg md:text-3xl">NVIDIA</div>
</div>
<div className="grid grid-cols-2 gap-5 justify-self-end ">
<div className="mt-2 cursor-pointer" onClick={handleFollow}>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<StarIcon id="follow" fill={isFollow ? "#FFFF00" : "#fff"} strokeWidth={2} />
</TooltipTrigger>
<TooltipContent>
<p>Follow NIVIDIA</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
<div onClick={handleShare} className=" cursor-pointer mt-2">
<ShareIcon />
</div>
</div>
</div>
{/* end of pack */}
<p className="mt-2 sm:text-sm"> World's first non-metal sustainable battery</p>
<div className="flex flex-wrap mt-3">
{["Technology", "Gaming"].map((tag) => (
<span key={tag} className="text-xs rounded-md bg-slate-200 dark:bg-slate-700 p-1 mx-1 mb-1">
{tag}
</span>
))}
</div>
<div className="grid grid-cols-2 mt-5">
{/* image carousel */}
<div>
<Carousel className="w-full mt-20 md:mt-0">
<CarouselContent className="h-[400px] flex h-full">
{Array.from({ length: 5 }).map((_, index) => (
<CarouselItem key={index}>
<img src="./boiler1.jpg" alt="" className="rounded-lg self-center" />
</CarouselItem>
))}
</CarouselContent>{" "}
<CarouselPrevious />
<CarouselNext />
</Carousel>
<Carousel className="w-2/3 md:w-full ml-10 md:ml-0 mt-5 md:mt-10 ">
<CarouselContent>
{/* boiler plate for an actual pictures */}
<CarouselItem className="pl-1 md:basis-1/2 lg:basis-1/3">
<img src="./boiler1.jpg" alt="" className="rounded-lg" />
</CarouselItem>
<CarouselItem className="pl-1 md:basis-1/2 lg:basis-1/3">
<img src="./boiler1.jpg" alt="" className="rounded-lg" />
</CarouselItem>
<CarouselItem className="pl-1 md:basis-1/2 lg:basis-1/3">
<img src="./boiler1.jpg" alt="" className="rounded-lg" />
</CarouselItem>
<CarouselItem className="pl-1 md:basis-1/2 lg:basis-1/3">
<img src="./boiler1.jpg" alt="" className="rounded-lg" />
</CarouselItem>
<CarouselItem className="pl-1 md:basis-1/2 lg:basis-1/3">
<img src="./boiler1.jpg" alt="" className="rounded-lg" />
</CarouselItem>
</CarouselContent>
</Carousel>
</div>
<div className=" w-2/3 mt-4 m-auto grid-rows-5">
<div className="pl-5">
<h1 className="font-semibold text-xl md:text-4xl mt-8">
<CountUp start={0} end={100000} duration={2} prefix="$" className="" />
</h1>
<p className="text-sm md:text-lg"> 5% raised of $5M max goal</p>
<Progress value={progress} className="w-[60%] h-3 mt-3" />
<h1 className="font-semibold text-4xl md:mt-8">
{" "}
<CountUp start={0} end={1000} duration={2} className="text-xl md:text-4xl" />
</h1>
<p className="text-sm md:text-lg"> Investors</p>
</div>
<Separator decorative className="mt-3 w-3/4 ml-5" />
<h1 className="font-semibold text-xl md:text-4xl mt-8 ml-5">
<CountUp start={0} end={5800} duration={2} className="text-xl md:text-4xl" /> hours
</h1>
<p className="ml-5"> Left to invest</p>
<Button className="mt-5 md:mt-10 ml-0 md:ml-[25%] scale-75 md:scale-100">
<Link href="/invest">Invest in NVIDIA</Link>
</Button>
</div>
</div>
</div>
</div>
{/* menu */}
<div className="flex w-[90%] mt-24 m-auto ml-10 md:ml-32">
<ul className="list-none flex gap-10 text-lg md:text-xl ">
<li>
<a onClick={() => handleClick("Pitch")} className={tab === "Pitch" ? "text-blue-600" : ""}>
Pitch
</a>
</li>
<li>
<a onClick={() => handleClick("General Data")} className={tab === "General Data" ? "text-blue-600" : ""}>
General Data
</a>
</li>
<li>
<a onClick={() => handleClick("Updates")} className={tab === "Updates" ? "text-blue-600" : ""}>
Updates
</a>
</li>
</ul>
</div>
<hr className="mt-2" />
{/* Card section */}
<div className="flex w-full mt-10">
{/* Cards */}
<Card className="m-auto border-slate-800 w-3/4 p-6">
<CardContent>
<Card>
<CardContent>{tab}</CardContent>
</Card>
</CardContent>
</Card>
</div>
</div>
);
}

View File

@ -1,4 +1,5 @@
"use client";
import { createSupabaseClient } from "@/lib/supabase/clientComponentClient";
import ProjectForm from "@/components/ProjectForm";
import { projectFormSchema } from "@/types/schemas/application.schema";
@ -29,8 +30,7 @@ export default function ApplyProject() {
.insert([
{
user_id: userId,
pitch_deck_url:
pitchType === "string" ? recvData["projectPitchDeck"] : "",
pitch_deck_url: pitchType === "string" ? recvData["projectPitchDeck"] : "",
target_investment: recvData["targetInvest"],
deadline: recvData["deadline"],
project_name: recvData["projectName"],
@ -58,36 +58,21 @@ export default function ApplyProject() {
const results = await Promise.all(tagPromises);
// Collect errors
const errors = results
.filter((result) => result.error)
.map((result) => result.error);
const errors = results.filter((result) => result.error).map((result) => result.error);
return { errors };
};
const uploadPitchFile = async (
file: File,
userId: string,
projectId: string
) => {
const uploadPitchFile = async (file: File, userId: string, projectId: string) => {
if (!file || !userId) {
console.error("Pitch file or user ID is undefined.");
return false;
}
return await uploadFile(
file,
BUCKET_PITCH_APPLICATION_NAME,
`${userId}/${projectId}/pitches/${file.name}`
);
return await uploadFile(file, BUCKET_PITCH_APPLICATION_NAME, `${userId}/${projectId}/pitches/${file.name}`);
};
const uploadLogoAndPhotos = async (
logoFile: File,
photos: File[],
userId: string,
projectId: string
) => {
const uploadLogoAndPhotos = async (logoFile: File, photos: File[], userId: string, projectId: string) => {
const uploadResults: { logo?: any; photos: any[] } = { photos: [] };
// upload logo
@ -108,11 +93,7 @@ export default function ApplyProject() {
// upload each photo
const uploadPhotoPromises = photos.map((image) =>
uploadFile(
image,
BUCKET_PITCH_APPLICATION_NAME,
`${userId}/${projectId}/photos/${image.name}`
)
uploadFile(image, BUCKET_PITCH_APPLICATION_NAME, `${userId}/${projectId}/photos/${image.name}`)
);
const photoResults = await Promise.all(uploadPhotoPromises);
@ -132,8 +113,7 @@ export default function ApplyProject() {
Swal.fire({
icon: error == null ? "success" : "error",
title: error == null ? "Success" : `Error: ${error.code}`,
text:
error == null ? "Your application has been submitted" : error.message,
text: error == null ? "Your application has been submitted" : error.message,
confirmButtonColor: error == null ? "green" : "red",
}).then((result) => {
if (result.isConfirmed) {
@ -168,11 +148,7 @@ export default function ApplyProject() {
// upload pitch file if its a file
if (typeof recvData["projectPitchDeck"] === "object") {
const uploadPitchSuccess = await uploadPitchFile(
recvData["projectPitchDeck"],
user.id,
projectId
);
const uploadPitchSuccess = await uploadPitchFile(recvData["projectPitchDeck"], user.id, projectId);
if (!uploadPitchSuccess) {
console.error("Error uploading pitch file.");
@ -196,21 +172,11 @@ export default function ApplyProject() {
// console.log("Logo Path:", logo.data.path);
// console.table(photos);
const logoURL = await getPrivateURL(
logo.data.path,
BUCKET_PITCH_APPLICATION_NAME
);
const logoURL = await getPrivateURL(logo.data.path, BUCKET_PITCH_APPLICATION_NAME);
let photoURLsArray: string[] = [];
const photoURLPromises = photos.map(
async (item: {
success: boolean;
errors: typeof errors;
data: { path: string };
}) => {
const photoURL = await getPrivateURL(
item.data.path,
BUCKET_PITCH_APPLICATION_NAME
);
async (item: { success: boolean; errors: typeof errors; data: { path: string } }) => {
const photoURL = await getPrivateURL(item.data.path, BUCKET_PITCH_APPLICATION_NAME);
if (photoURL?.signedUrl) {
photoURLsArray.push(photoURL.signedUrl);
} else {
@ -233,11 +199,7 @@ export default function ApplyProject() {
setIsSuccess(true);
displayAlert(error);
};
const updateImageURL = async (
url: string | string[],
columnName: string,
projectId: number
) => {
const updateImageURL = async (url: string | string[], columnName: string, projectId: number) => {
const { error } = await supabase
.from("project_application")
.update({ [columnName]: url })
@ -250,9 +212,7 @@ export default function ApplyProject() {
}
};
const getPrivateURL = async (path: string, bucketName: string) => {
const { data } = await supabase.storage
.from(bucketName)
.createSignedUrl(path, 9999999999999999999999999999);
const { data } = await supabase.storage.from(bucketName).createSignedUrl(path, 9999999999999999999999999999);
// console.table(data);
return data;
};
@ -265,12 +225,10 @@ export default function ApplyProject() {
</h1>
<div className="mt-5 justify-self-center">
<p className="text-sm md:text-base text-neutral-500">
Begin Your First Fundraising Project. Starting a fundraising project
is mandatory for all businesses.
Begin Your First Fundraising Project. Starting a fundraising project is mandatory for all businesses.
</p>
<p className="text-sm md:text-base text-neutral-500">
This step is crucial to begin your journey and unlock the necessary
tools for raising funds.
This step is crucial to begin your journey and unlock the necessary tools for raising funds.
</p>
</div>
</div>

View File

@ -3,27 +3,14 @@ import { SubmitHandler, useForm } from "react-hook-form";
import { Button } from "@/components/ui/button";
import { DualOptionSelector } from "@/components/dualSelector";
import { MultipleOptionSelector } from "@/components/multipleSelector";
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { businessFormSchema } from "@/types/schemas/application.schema";
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import { Label } from "@/components/ui/label";
import { Switch } from "@/components/ui/switch";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@radix-ui/react-tooltip";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@radix-ui/react-tooltip";
import { createSupabaseClient } from "@/lib/supabase/clientComponentClient";
type businessSchema = z.infer<typeof businessFormSchema>;
@ -54,14 +41,10 @@ const BusinessForm = ({
let supabase = createSupabaseClient();
const [businessPitch, setBusinessPitch] = useState("text");
const [businessPitchFile, setBusinessPitchFile] = useState("");
const [countries, setCountries] = useState<{ id: number; name: string }[]>(
[]
);
const [countries, setCountries] = useState<{ id: number; name: string }[]>([]);
const [industry, setIndustry] = useState<{ id: number; name: string }[]>([]);
const fetchIndustry = async () => {
let { data: BusinessType, error } = await supabase
.from("business_type")
.select("id, value");
let { data: BusinessType, error } = await supabase.from("business_type").select("id, value");
if (error) {
console.error(error);
@ -84,18 +67,12 @@ const BusinessForm = ({
throw new Error("Network response was not ok");
}
const data = await response.json();
const countryList = data.map(
(country: { name: { common: string } }, index: number) => ({
id: index + 1,
name: country.name.common,
})
);
const countryList = data.map((country: { name: { common: string } }, index: number) => ({
id: index + 1,
name: country.name.common,
}));
setCountries(
countryList.sort((a: { name: string }, b: { name: any }) =>
a.name.localeCompare(b.name)
)
);
setCountries(countryList.sort((a: { name: string }, b: { name: any }) => a.name.localeCompare(b.name)));
} catch (error) {
console.error("Error fetching countries:", error);
}
@ -106,15 +83,11 @@ const BusinessForm = ({
}, []);
return (
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit as SubmitHandler<businessSchema>)}
className="space-y-8"
>
<form onSubmit={form.handleSubmit(onSubmit as SubmitHandler<businessSchema>)} className="space-y-8">
<div className="grid grid-flow-row auto-rows-max w-3/4 ml-1/2 md:ml-[0%] ">
<h1 className="text-3xl font-bold mt-10 ml-96">About your company</h1>
<p className="ml-96 mt-5 text-neutral-500">
<span className="text-red-500 font-bold">**</span>All requested
information in this section is required.
<span className="text-red-500 font-bold">**</span>All requested information in this section is required.
</p>
<div className="ml-96 mt-5 space-y-10">
{/* Company Name */}
@ -123,21 +96,13 @@ const BusinessForm = ({
name="companyName"
render={({ field }: { field: any }) => (
<FormItem>
<FormLabel className="font-bold text-lg">
Company name
</FormLabel>
<FormLabel className="font-bold text-lg">Company name</FormLabel>
<FormControl>
<div className="mt-10 space-y-5">
<div className="flex space-x-5">
<Input
type="text"
id="companyName"
className="w-96"
{...field}
/>
<Input type="text" id="companyName" className="w-96" {...field} />
<span className="text-[12px] text-neutral-500 self-center">
This should be the name your company uses on your{" "}
<br />
This should be the name your company uses on your <br />
website and in the market.
</span>
</div>
@ -162,9 +127,7 @@ const BusinessForm = ({
// console.log("Country selected: " + selectedValues.name);
field.onChange(selectedValues.name);
}}
description={
<>Select the country where your business is based.</>
}
description={<>Select the country where your business is based.</>}
placeholder="Select a country"
selectLabel="Country"
/>
@ -189,12 +152,7 @@ const BusinessForm = ({
// console.log("Type of selected value:", selectedValues.id);
field.onChange(selectedValues.id);
}}
description={
<>
Choose the industry that best aligns with your
business.
</>
}
description={<>Choose the industry that best aligns with your business.</>}
placeholder="Select an industry"
selectLabel="Industry"
/>
@ -229,8 +187,7 @@ const BusinessForm = ({
value={field.value}
/>
<span className="text-[12px] text-neutral-500 self-center">
The sum total of past financing, including angel or
venture <br />
The sum total of past financing, including angel or venture <br />
capital, loans, grants, or token sales.
</span>
</div>
@ -251,11 +208,7 @@ const BusinessForm = ({
<div className="flex space-x-5">
<DualOptionSelector
name="isInUS"
label={
<>
Is your company incorporated in the United States?
</>
}
label={<>Is your company incorporated in the United States?</>}
choice1="Yes"
choice2="No"
handleFunction={(selectedValues: string) => {
@ -266,8 +219,7 @@ const BusinessForm = ({
value={field.value}
/>
<span className="text-[12px] text-neutral-500 self-center">
Only companies that are incorporated or formed in the US
are eligible to raise via Reg CF.
Only companies that are incorporated or formed in the US are eligible to raise via Reg CF.
</span>
</div>
</FormControl>
@ -287,21 +239,14 @@ const BusinessForm = ({
<DualOptionSelector
name="isForSale"
value={field.value}
label={
<>Is your product available (for sale) in market?</>
}
label={<>Is your product available (for sale) in market?</>}
choice1="Yes"
choice2="No"
handleFunction={(selectedValues: string) => {
// setIsForSale;
field.onChange(selectedValues);
}}
description={
<>
Only check this box if customers can access, use, or
buy your product today.
</>
}
description={<>Only check this box if customers can access, use, or buy your product today.</>}
/>
</div>
</FormControl>
@ -328,10 +273,7 @@ const BusinessForm = ({
field.onChange(selectedValues);
}}
description={
<>
Only check this box if your company is making money.
Please elaborate on revenue below.
</>
<>Only check this box if your company is making money. Please elaborate on revenue below.</>
}
/>
</div>
@ -356,9 +298,7 @@ const BusinessForm = ({
<div className="flex space-x-2 w-96">
<Button
type="button"
variant={
businessPitch === "text" ? "default" : "outline"
}
variant={businessPitch === "text" ? "default" : "outline"}
onClick={() => setBusinessPitch("text")}
className="w-32 h-12 text-base"
>
@ -366,9 +306,7 @@ const BusinessForm = ({
</Button>
<Button
type="button"
variant={
businessPitch === "file" ? "default" : "outline"
}
variant={businessPitch === "file" ? "default" : "outline"}
onClick={() => setBusinessPitch("file")}
className="w-32 h-12 text-base"
>
@ -378,14 +316,8 @@ const BusinessForm = ({
<div className="flex space-x-5">
<Input
type={businessPitch === "file" ? "file" : "text"}
placeholder={
businessPitch === "file"
? "Upload your Markdown file"
: "https:// "
}
accept={
businessPitch === "file" ? ".md" : undefined
}
placeholder={businessPitch === "file" ? "Upload your Markdown file" : "https:// "}
accept={businessPitch === "file" ? ".md" : undefined}
onChange={(e) => {
const value = e.target;
if (businessPitch === "file") {
@ -399,17 +331,12 @@ const BusinessForm = ({
/>
<span className="text-[12px] text-neutral-500 self-center">
Your pitch deck and other application info will be
used for <br />
Your pitch deck and other application info will be used for <br />
internal purposes only. <br />
Please make sure this document is publicly
accessible. This can <br />
be a DocSend, Box, Dropbox, Google Drive or other
link.
Please make sure this document is publicly accessible. This can <br />
be a DocSend, Box, Dropbox, Google Drive or other link.
<br />
<p className="text-red-500">
** support only markdown(.md) format
</p>
<p className="text-red-500">** support only markdown(.md) format</p>
</span>
</div>
{businessPitchFile && (
@ -448,10 +375,7 @@ const BusinessForm = ({
field.onChange(selectedValues.name);
}}
description={
<>
Include your email list, social media following (e.g.,
Instagram, Discord, Twitter).
</>
<>Include your email list, social media following (e.g., Instagram, Discord, Twitter).</>
}
placeholder="Select"
selectLabel="Select"
@ -462,32 +386,25 @@ const BusinessForm = ({
)}
/>
<div className="flex space-x-5">
<Switch
onCheckedChange={() => setApplyProject(!applyProject)}
></Switch>
<Switch onCheckedChange={() => setApplyProject(!applyProject)}></Switch>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<span className="text-[12px] text-neutral-500 self-center cursor-pointer">
Would you like to apply for your first fundraising project
as well?
Would you like to apply for your first fundraising project as well?
</span>
</TooltipTrigger>
<TooltipContent>
<p className="text-[11px]">
Toggling this option allows you to begin your first
project, <br /> which is crucial for unlocking the tools
necessary to raise funds.
Toggling this option allows you to begin your first project, <br /> which is crucial for unlocking
the tools necessary to raise funds.
</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
<center>
<Button
className="mt-12 mb-20 h-10 text-base font-bold py-6 px-5"
type="submit"
>
<Button className="mt-12 mb-20 h-10 text-base font-bold py-6 px-5" type="submit">
Submit application
</Button>
</center>

View File

@ -1,25 +1,11 @@
"use client";
import { Icons } from "./ui/icons";
import { Button } from "./ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "./ui/card";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "./ui/card";
import { Input } from "./ui/input";
import { Label } from "./ui/label";
import { RadioGroup, RadioGroupItem } from "./ui/radio-group";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "./ui/select";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./ui/select";
export function CardsPaymentMethod() {
return (
@ -33,12 +19,7 @@ export function CardsPaymentMethod() {
<CardContent className="grid gap-6">
<RadioGroup defaultValue="card" className="flex w-full justify-center gap-1 md:gap-3">
<div className="w-[100px] lg:w-[130px]">
<RadioGroupItem
value="card"
id="card"
className="peer sr-only"
aria-label="Card"
/>
<RadioGroupItem value="card" id="card" className="peer sr-only" aria-label="Card" />
<Label
htmlFor="card"
className="flex flex-col items-center justify-between rounded-md border-2 border-muted bg-transparent p-4 hover:bg-accent hover:text-accent-foreground peer-data-[state=checked]:border-primary [&:has([data-state=checked])]:border-primary"
@ -61,12 +42,7 @@ export function CardsPaymentMethod() {
</div>
<div className="w-[100px] lg:w-[130px]">
<RadioGroupItem
value="paypal"
id="paypal"
className="peer sr-only"
aria-label="Paypal"
/>
<RadioGroupItem value="paypal" id="paypal" className="peer sr-only" aria-label="Paypal" />
<Label
htmlFor="paypal"
className="flex flex-col items-center justify-between rounded-md border-2 border-muted bg-transparent p-4 hover:bg-accent hover:text-accent-foreground peer-data-[state=checked]:border-primary [&:has([data-state=checked])]:border-primary"
@ -77,12 +53,7 @@ export function CardsPaymentMethod() {
</div>
<div className="w-[100px] lg:w-[130px]">
<RadioGroupItem
value="apple"
id="apple"
className="peer sr-only"
aria-label="Apple"
/>
<RadioGroupItem value="apple" id="apple" className="peer sr-only" aria-label="Apple" />
<Label
htmlFor="apple"
className="flex flex-col items-center justify-between rounded-md border-2 border-muted bg-transparent p-4 hover:bg-accent hover:text-accent-foreground peer-data-[state=checked]:border-primary [&:has([data-state=checked])]:border-primary"