Files
website/apps/web/src/components/LatestBrands.tsx
T

80 lines
2.5 KiB
TypeScript

import { useEffect, useState } from "react";
import { Link } from "react-router-dom";
import { MapPin } from "lucide-react";
import { fetchLatestBrands } from "../lib/services";
import type { Brand } from "../lib/types";
import "./LatestBrands.css";
export default function LatestBrands() {
const [brands, setBrands] = useState<Brand[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
let active = true;
fetchLatestBrands(4)
.then((items) => {
if (active) setBrands(items);
})
.catch((err: unknown) => {
if (active) {
setError(err instanceof Error ? err.message : "Could not load brands");
}
})
.finally(() => {
if (active) setLoading(false);
});
return () => {
active = false;
};
}, []);
return (
<section className="section brands" id="brands">
<div className="container">
<div className="section__head">
<span className="section__eyebrow">Partner directory</span>
<h2 className="section__title">Latest brands</h2>
<p className="section__lead">
Newly featured companies ready to connect across markets and industries.
</p>
</div>
{loading ? <p className="brands__status">Loading brands</p> : null}
{error ? (
<p className="brands__status brands__status--error">{error}</p>
) : null}
{!loading && !error && brands.length === 0 ? (
<p className="brands__status">No published brands yet.</p>
) : null}
<div className="brands__grid">
{brands.map((brand) => (
<Link
key={brand.id}
className="brands__item"
to={`/brands/${brand.slug}`}
>
<div className="brands__media">
{brand.imageUrl ? (
<img src={brand.imageUrl} alt="" loading="lazy" />
) : (
<span className="brands__placeholder" aria-hidden="true" />
)}
</div>
<div className="brands__body">
<h3>{brand.title}</h3>
{brand.abstract ? <p>{brand.abstract}</p> : null}
<span className="brands__loc">
<MapPin size={14} strokeWidth={2} />
{[brand.city, brand.country].filter(Boolean).join(", ")}
</span>
</div>
</Link>
))}
</div>
</div>
</section>
);
}