general category trip

This commit is contained in:
2026-05-07 18:47:45 +07:00
parent 12f13f2049
commit 49aa64c522
25 changed files with 904 additions and 386 deletions
+2 -2
View File
@@ -121,7 +121,7 @@ export default async function TripOgImage({
</div>
</div>
{/* Middle: title + mountain */}
{/* Middle: title + destination */}
<div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
<div
style={{
@@ -146,7 +146,7 @@ export default async function TripOgImage({
>
<span>📍</span>
<span>
{trip.mountain} · {trip.location}
{trip.destination} · {trip.location}
</span>
</div>
</div>
+6 -6
View File
@@ -36,8 +36,8 @@ export async function generateMetadata({
};
}
const title = `${trip.title}${trip.mountain}`;
const fallbackDescription = `Open trip ${trip.mountain} di ${trip.location}, ${formatTripCalendarDateRangeLong(trip.date, trip.endDate)}. Harga ${formatRupiah(trip.price)}/orang, max ${trip.maxParticipants} peserta. Gabung di ${siteConfig.name}.`;
const title = `${trip.title}${trip.destination}`;
const fallbackDescription = `Open trip ${trip.destination} di ${trip.location}, ${formatTripCalendarDateRangeLong(trip.date, trip.endDate)}. Harga ${formatRupiah(trip.price)}/orang, max ${trip.maxParticipants} peserta. Gabung di ${siteConfig.name}.`;
const description =
trip.description?.replace(/\s+/g, " ").trim().slice(0, 160) ||
fallbackDescription;
@@ -155,7 +155,7 @@ export default async function TripDetailPage({
eventAttendanceMode: "https://schema.org/OfflineEventAttendanceMode",
location: {
"@type": "Place",
name: trip.mountain,
name: trip.destination,
address: {
"@type": "PostalAddress",
addressLocality: trip.location,
@@ -206,7 +206,7 @@ export default async function TripDetailPage({
{
"@type": "ListItem",
position: 3,
name: trip.mountain,
name: trip.destination,
item: tripUrl,
},
],
@@ -226,7 +226,7 @@ export default async function TripDetailPage({
Open Trip
</Link>
<span>/</span>
<span className="truncate text-neutral-700">{trip.mountain}</span>
<span className="truncate text-neutral-700">{trip.destination}</span>
</div>
<div className="overflow-hidden rounded-2xl border border-neutral-200 bg-white shadow-sm">
@@ -241,7 +241,7 @@ export default async function TripDetailPage({
{trip.title}
</h1>
<p className="mt-0.5 flex items-center gap-1.5 text-sm text-neutral-500">
🏔 {trip.mountain}
🏔 {trip.destination}
</p>
</div>
<span
+25 -7
View File
@@ -5,21 +5,34 @@ import { tripService } from "@/server/services/trip.service";
import { TripCard } from "@/features/trip/components/trip-card";
import { TripFilter } from "@/features/trip/components/trip-filter";
import { siteConfig } from "@/lib/site";
import { categoryLabel, isActivityCategory } from "@/lib/activity-category";
interface TripsPageProps {
searchParams: Promise<{ q?: string; from?: string; to?: string }>;
searchParams: Promise<{
q?: string;
from?: string;
to?: string;
category?: string;
}>;
}
export async function generateMetadata({
searchParams,
}: TripsPageProps): Promise<Metadata> {
const { q } = await searchParams;
const { q, category: categoryParam } = await searchParams;
const category = isActivityCategory(categoryParam) ? categoryParam : undefined;
const categoryName = category ? categoryLabel(category) : null;
const title = q
? `Cari Teman Trip "${q}" — Gabung Bareng`
: "Cari Teman Trip & Aktivitas — Daftar Open Trip Aktif";
: categoryName
? `Cari Teman ${categoryName} — Daftar Open Trip Aktif`
: "Cari Teman Trip & Aktivitas — Daftar Open Trip Aktif";
const description = q
? `Hasil pencarian "${q}" di ${siteConfig.name}. Temukan teman seperjalanan, lihat trip & organizer terverifikasi, langsung gabung.`
: `Daftar open trip aktif di ${siteConfig.name} — hiking, camping, snorkeling, city trip, dan aktivitas bareng lainnya. Pilih trip, kenal calon teman seperjalanan, dan gabung bareng — grup kecil & organizer terverifikasi.`;
: categoryName
? `Daftar open trip ${categoryName.toLowerCase()} di ${siteConfig.name}. Pilih trip, kenal calon teman seperjalanan, dan gabung bareng — grup kecil & organizer terverifikasi.`
: `Daftar open trip aktif di ${siteConfig.name} — hiking, camping, snorkeling, city trip, dan aktivitas bareng lainnya. Pilih trip, kenal calon teman seperjalanan, dan gabung bareng — grup kecil & organizer terverifikasi.`;
return {
title,
description,
@@ -30,11 +43,13 @@ export async function generateMetadata({
export default async function TripsPage({ searchParams }: TripsPageProps) {
const params = await searchParams;
const hasFilters = params.q || params.from || params.to;
const category = isActivityCategory(params.category) ? params.category : undefined;
const hasFilters = Boolean(params.q || params.from || params.to || category);
const filters = {
q: params.q,
from: params.from,
to: params.to,
category,
};
const [trips, allTrips] = await Promise.all([
@@ -48,7 +63,9 @@ export default async function TripsPage({ searchParams }: TripsPageProps) {
<div className="mb-6 flex flex-col gap-3 sm:mb-8 sm:flex-row sm:items-center sm:justify-between">
<div>
<h1 className="text-xl font-bold text-neutral-800 sm:text-2xl">
Cari Teman Trip & Aktivitas
{category
? `Cari Teman ${categoryLabel(category)}`
: "Cari Teman Trip & Aktivitas"}
</h1>
<p className="mt-0.5 text-sm text-neutral-500">
{hasFilters
@@ -102,7 +119,8 @@ export default async function TripsPage({ searchParams }: TripsPageProps) {
key={trip.id}
id={trip.id}
title={trip.title}
mountain={trip.mountain}
category={trip.category}
destination={trip.destination}
location={trip.location}
date={trip.date}
endDate={trip.endDate}