Browse Source

🛠️ Implemented StayCard component

🖼️ Added image gallery, content rendering
🏷️ Included listing details and pricing
 Added review ratings and badges
🔗 Integrated Link for navigation
main
John Doe 1 year ago
parent
commit
70398f1cc2
  1. 132
      src/components/StayCard.tsx

132
src/components/StayCard.tsx

@ -0,0 +1,132 @@
import React, { FC } from "react";
import { DEMO_STAY_LISTINGS } from "@/data/listings";
import { StayDataType } from "@/data/types";
import StartRating from "@/components/StartRating";
import BtnLikeIcon from "@/components/BtnLikeIcon";
import SaleOffBadge from "@/components/SaleOffBadge";
import Badge from "@/shared/Badge";
import Link from "next/link";
import GallerySlider from "./GallerySlider";
export interface StayCardProps {
className?: string;
data?: StayDataType;
size?: "default" | "small";
}
const DEMO_DATA = DEMO_STAY_LISTINGS[0];
const StayCard: FC<StayCardProps> = ({
size = "default",
className = "",
data = DEMO_DATA,
}) => {
const {
galleryImgs,
listingCategory,
address,
title,
bedrooms,
href,
like,
saleOff,
isAds,
price,
reviewStart,
reviewCount,
id,
} = data;
const renderSliderGallery = () => {
return (
<div className="relative w-full">
<GallerySlider
uniqueID={`StayCard_${id}`}
ratioClass="aspect-w-4 aspect-h-3 "
galleryImgs={galleryImgs}
href={href}
galleryClass={size === "default" ? undefined : ""}
/>
<BtnLikeIcon isLiked={like} className="absolute right-3 top-3 z-[1]" />
{saleOff && <SaleOffBadge className="absolute left-3 top-3" />}
</div>
);
};
const renderContent = () => {
return (
<div className={size === "default" ? "p-4 space-y-4" : "p-3 space-y-1"}>
<div className={size === "default" ? "space-y-2" : "space-y-1"}>
<span className="text-sm text-neutral-500 dark:text-neutral-400">
{listingCategory.name} · {bedrooms} beds
</span>
<div className="flex items-center space-x-2">
{isAds && <Badge name="ADS" color="green" />}
<h2
className={`font-semibold capitalize text-neutral-900 dark:text-white ${
size === "default" ? "text-base" : "text-base"
}`}
>
<span className="line-clamp-1">{title}</span>
</h2>
</div>
<div className="flex items-center text-neutral-500 dark:text-neutral-400 text-sm space-x-1.5">
{size === "default" && (
<svg
className="h-4 w-4"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={1.5}
d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z"
/>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={1.5}
d="M15 11a3 3 0 11-6 0 3 3 0 016 0z"
/>
</svg>
)}
<span className="">{address}</span>
</div>
</div>
<div className="w-14 border-b border-neutral-100 dark:border-neutral-800"></div>
<div className="flex justify-between items-center">
<span className="text-base font-semibold">
{price}
{` `}
{size === "default" && (
<span className="text-sm text-neutral-500 dark:text-neutral-400 font-normal">
/night
</span>
)}
</span>
{!!reviewStart && (
<StartRating reviewCount={reviewCount} point={reviewStart} />
)}
</div>
</div>
);
};
return (
<div
className={`nc-StayCard group relative bg-white dark:bg-neutral-900 ${
size === "default"
? "border border-neutral-100 dark:border-neutral-800 "
: ""
} rounded-2xl overflow-hidden hover:shadow-xl transition-shadow ${className}`}
data-nc-id="StayCard"
>
{renderSliderGallery()}
<Link href={href}>{renderContent()}</Link>
</div>
);
};
export default StayCard;
Loading…
Cancel
Save