initial checkin

This commit is contained in:
2026-04-10 21:48:23 -05:00
parent 28fe3bfa48
commit fdc05f8048
49 changed files with 10162 additions and 1 deletions

74
src/pages/ToursPage.tsx Normal file
View File

@@ -0,0 +1,74 @@
import { useEffect, useState } from "react";
import { Link } from "react-router-dom";
import { formatApiMessage } from "../api/client";
import * as api from "../api/services";
import type { AdventureOffering } from "../api/types";
export function ToursPage() {
const [offerings, setOfferings] = useState<AdventureOffering[]>([]);
const [error, setError] = useState<string | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
let cancelled = false;
(async () => {
try {
const data = await api.listAdventureOfferings();
if (!cancelled) setOfferings(data);
} catch (e) {
if (!cancelled) setError(formatApiMessage(e));
} finally {
if (!cancelled) setLoading(false);
}
})();
return () => {
cancelled = true;
};
}, []);
return (
<div className="page tours-catalog">
<h1>Tours & adventures</h1>
<p className="lede">
Guided experiences from GET <code>/api/v1/adventrues/offerings/</code>. Open a listing for marketing
attribution IDs used at booking time.
</p>
{loading && <p className="muted">Loading</p>}
{error && <p className="muted">{error}</p>}
<ul className="card-list">
{offerings.map((o) => {
const img =
o.images.find((i) => i.is_primary)?.image_url ?? o.images[0]?.image_url;
return (
<li key={o.id}>
<article className="card">
<div
className="tours-card-image"
style={
img
? { backgroundImage: `url(${img})` }
: { background: "linear-gradient(135deg, #fef9c3, #facc15)" }
}
/>
<h2>{o.title}</h2>
<p>{o.vendor_business_name}</p>
<p className="muted">
{o.meeting_point} · {o.duration_minutes} min · up to {o.capacity} guests
</p>
<p>
<strong>${o.price_per_person}</strong> / person
</p>
<Link to={`/tours/${o.public_id}`} className="text-link">
View details
</Link>
</article>
</li>
);
})}
</ul>
{!loading && !error && offerings.length === 0 && (
<p className="muted">No adventures published yet.</p>
)}
</div>
);
}