c4efe4453b
- ✅ - ✅ - ✅
129 lines
4.1 KiB
TypeScript
129 lines
4.1 KiB
TypeScript
import { groupItineraryByDay } from "@/lib/itinerary";
|
||
|
||
interface ItineraryItem {
|
||
day: number;
|
||
startTime: string;
|
||
endTime: string | null;
|
||
activity: string;
|
||
order: number;
|
||
}
|
||
|
||
interface TripProgramBlockProps {
|
||
meetingPoint: string | null;
|
||
itinerary: string | null;
|
||
itineraryItems: ItineraryItem[];
|
||
whatsIncluded: string | null;
|
||
whatsExcluded: string | null;
|
||
}
|
||
|
||
export function TripProgramBlock({
|
||
meetingPoint,
|
||
itinerary,
|
||
itineraryItems,
|
||
whatsIncluded,
|
||
whatsExcluded,
|
||
}: TripProgramBlockProps) {
|
||
const hasStructuredItinerary = itineraryItems.length > 0;
|
||
const hasLegacyItinerary = !hasStructuredItinerary && !!itinerary;
|
||
const hasAny =
|
||
meetingPoint ||
|
||
hasStructuredItinerary ||
|
||
hasLegacyItinerary ||
|
||
whatsIncluded ||
|
||
whatsExcluded;
|
||
if (!hasAny) return null;
|
||
|
||
const grouped = hasStructuredItinerary
|
||
? groupItineraryByDay(itineraryItems)
|
||
: null;
|
||
|
||
return (
|
||
<div className="space-y-4 rounded-xl border border-neutral-200 bg-neutral-50/50 p-4 sm:p-5">
|
||
<h2 className="text-xs font-bold text-neutral-800 sm:text-sm">
|
||
Detail perjalanan
|
||
</h2>
|
||
|
||
{meetingPoint && (
|
||
<div>
|
||
<h3 className="mb-1 text-[11px] font-bold uppercase tracking-wide text-primary-700 sm:text-xs">
|
||
Meeting point
|
||
</h3>
|
||
<p className="whitespace-pre-wrap text-xs leading-relaxed text-neutral-700 sm:text-sm">
|
||
{meetingPoint}
|
||
</p>
|
||
</div>
|
||
)}
|
||
|
||
{grouped && (
|
||
<div>
|
||
<h3 className="mb-2 text-[11px] font-bold uppercase tracking-wide text-primary-700 sm:text-xs">
|
||
Itinerary
|
||
</h3>
|
||
<div className="space-y-3">
|
||
{[...grouped.entries()].map(([day, items]) => (
|
||
<div
|
||
key={day}
|
||
className="rounded-lg border border-primary-100 bg-white p-3 sm:p-4"
|
||
>
|
||
<p className="mb-2 text-xs font-bold text-primary-800 sm:text-sm">
|
||
Hari {day}
|
||
</p>
|
||
<ol className="space-y-2">
|
||
{items.map((item) => (
|
||
<li
|
||
key={item.order}
|
||
className="flex gap-3 text-xs leading-relaxed text-neutral-700 sm:text-sm"
|
||
>
|
||
<span className="shrink-0 font-mono text-[11px] font-semibold text-primary-700 sm:text-xs">
|
||
{item.startTime}
|
||
{item.endTime ? `–${item.endTime}` : ""}
|
||
</span>
|
||
<span className="min-w-0 flex-1">{item.activity}</span>
|
||
</li>
|
||
))}
|
||
</ol>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{hasLegacyItinerary && (
|
||
<div>
|
||
<h3 className="mb-1 text-[11px] font-bold uppercase tracking-wide text-primary-700 sm:text-xs">
|
||
Itinerary
|
||
</h3>
|
||
<p className="whitespace-pre-wrap text-xs leading-relaxed text-neutral-700 sm:text-sm">
|
||
{itinerary}
|
||
</p>
|
||
</div>
|
||
)}
|
||
|
||
{(whatsIncluded || whatsExcluded) && (
|
||
<div className="grid gap-4 sm:grid-cols-2">
|
||
{whatsIncluded && (
|
||
<div className="rounded-lg border border-secondary-200 bg-white p-3">
|
||
<h3 className="mb-2 text-[11px] font-bold uppercase tracking-wide text-secondary-800 sm:text-xs">
|
||
Termasuk
|
||
</h3>
|
||
<p className="whitespace-pre-wrap text-xs leading-relaxed text-neutral-700 sm:text-sm">
|
||
{whatsIncluded}
|
||
</p>
|
||
</div>
|
||
)}
|
||
{whatsExcluded && (
|
||
<div className="rounded-lg border border-neutral-200 bg-white p-3">
|
||
<h3 className="mb-2 text-[11px] font-bold uppercase tracking-wide text-neutral-600 sm:text-xs">
|
||
Tidak termasuk
|
||
</h3>
|
||
<p className="whitespace-pre-wrap text-xs leading-relaxed text-neutral-700 sm:text-sm">
|
||
{whatsExcluded}
|
||
</p>
|
||
</div>
|
||
)}
|
||
</div>
|
||
)}
|
||
</div>
|
||
);
|
||
}
|