Add ListingCard component
This commit is contained in:
109
app/src/components/ListingCard.tsx
Normal file
109
app/src/components/ListingCard.tsx
Normal file
@@ -0,0 +1,109 @@
|
||||
import type { GestureResponderEvent } from "react-native";
|
||||
import type { JSX } from "react";
|
||||
import { Pressable, View } from "react-native";
|
||||
import { useRouter } from "expo-router";
|
||||
import { Button, Separator, Surface, Typography } from "heroui-native";
|
||||
import type { Product } from "@/data/mock";
|
||||
import { availabilityInfo } from "@/lib/status";
|
||||
import { StatusChip } from "@/components/StatusChip";
|
||||
import { useModals } from "@/state/modals";
|
||||
|
||||
interface ListingCardProps {
|
||||
product: Product;
|
||||
variant?: "list" | "grid";
|
||||
}
|
||||
|
||||
export function ListingCard({ product, variant = "grid" }: ListingCardProps): JSX.Element {
|
||||
const router = useRouter();
|
||||
const { requestBuy } = useModals();
|
||||
const availability = availabilityInfo(product.qty);
|
||||
const isOut = product.qty === 0;
|
||||
|
||||
const openListing = () => router.push(`/listing/${product.id}`);
|
||||
|
||||
const handleBuyPress = (event: GestureResponderEvent) => {
|
||||
event.stopPropagation();
|
||||
requestBuy(product.id);
|
||||
};
|
||||
|
||||
if (variant === "list") {
|
||||
return (
|
||||
<Pressable onPress={openListing}>
|
||||
<Surface variant="default" className="flex-row items-stretch gap-0 overflow-hidden p-0">
|
||||
<View
|
||||
className="w-24 items-center justify-center md:w-36"
|
||||
style={{ backgroundColor: product.bg }}
|
||||
>
|
||||
<Typography className="text-4xl">{product.emoji}</Typography>
|
||||
</View>
|
||||
<Separator orientation="vertical" />
|
||||
<View className="w-24 justify-center gap-0.5 p-3 md:w-32">
|
||||
<Typography type="h6" className="text-accent">
|
||||
{product.priceNum}
|
||||
</Typography>
|
||||
<Typography type="body-xs" color="muted">
|
||||
{product.cur}
|
||||
</Typography>
|
||||
</View>
|
||||
<Separator orientation="vertical" />
|
||||
<View className="flex-1 justify-center gap-1 p-3">
|
||||
<Typography type="body-sm" weight="semibold" numberOfLines={1}>
|
||||
{product.name}
|
||||
</Typography>
|
||||
<Typography type="body-xs" color="muted" numberOfLines={2}>
|
||||
{product.desc}
|
||||
</Typography>
|
||||
</View>
|
||||
<Separator orientation="vertical" />
|
||||
<View className="w-28 items-stretch justify-center gap-2 p-3">
|
||||
<StatusChip label={availability.label} color={availability.color} />
|
||||
<Button
|
||||
size="sm"
|
||||
variant={isOut ? "secondary" : "primary"}
|
||||
isDisabled={isOut}
|
||||
onPress={handleBuyPress}
|
||||
>
|
||||
<Button.Label>{isOut ? "Out of Stock" : "Buy Now"}</Button.Label>
|
||||
</Button>
|
||||
</View>
|
||||
</Surface>
|
||||
</Pressable>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Pressable onPress={openListing} className="w-1/2 p-1.5 md:w-1/3 lg:w-1/4">
|
||||
<Surface variant="default" className="gap-0 overflow-hidden p-0">
|
||||
<View
|
||||
className="h-32 items-center justify-center"
|
||||
style={{ backgroundColor: product.bg }}
|
||||
>
|
||||
<Typography className="text-4xl">{product.emoji}</Typography>
|
||||
</View>
|
||||
<View className="gap-1 p-2.5">
|
||||
<Typography type="body-sm" weight="semibold" numberOfLines={2}>
|
||||
{product.name}
|
||||
</Typography>
|
||||
<Typography type="body-xs" color="muted" numberOfLines={1}>
|
||||
{product.seller}
|
||||
</Typography>
|
||||
<View className="mt-1 flex-row items-center justify-between gap-1">
|
||||
<Typography type="body" weight="bold" className="text-accent">
|
||||
{product.price}
|
||||
</Typography>
|
||||
<StatusChip label={availability.label} color={availability.color} />
|
||||
</View>
|
||||
<Button
|
||||
size="sm"
|
||||
variant={isOut ? "secondary" : "primary"}
|
||||
isDisabled={isOut}
|
||||
className="mt-2 w-full"
|
||||
onPress={handleBuyPress}
|
||||
>
|
||||
<Button.Label>{isOut ? "Out of Stock" : "Buy Now"}</Button.Label>
|
||||
</Button>
|
||||
</View>
|
||||
</Surface>
|
||||
</Pressable>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user