add end date and create logo and fix filter

This commit is contained in:
arifal
2026-04-17 00:16:31 +07:00
parent 82c1da9951
commit 7159e9108f
35 changed files with 743 additions and 82 deletions
+4 -2
View File
@@ -1,6 +1,6 @@
import Image from "next/image";
import Link from "next/link";
import { formatRupiah, formatDate } from "@/lib/utils";
import { formatRupiah, formatDateRange } from "@/lib/utils";
interface TripCardProps {
id: string;
@@ -8,6 +8,7 @@ interface TripCardProps {
mountain: string;
location: string;
date: Date | string;
endDate?: Date | string | null;
price: number;
maxParticipants: number;
participantCount: number;
@@ -23,6 +24,7 @@ export function TripCard({
mountain,
location,
date,
endDate,
price,
maxParticipants,
participantCount,
@@ -78,7 +80,7 @@ export function TripCard({
</div>
<div className="flex items-center gap-1.5">
<span className="text-xs text-secondary-500">📅</span>{" "}
{formatDate(date)}
{formatDateRange(date, endDate)}
</div>
<div className="flex items-center gap-1.5">
<span className="text-xs text-secondary-500">👤</span>{" "}
+145
View File
@@ -0,0 +1,145 @@
"use client";
import { useRouter, useSearchParams } from "next/navigation";
import { useState } from "react";
import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";
export function TripFilter() {
const router = useRouter();
const searchParams = useSearchParams();
const [query, setQuery] = useState(searchParams.get("q") ?? "");
const [startDate, setStartDate] = useState<Date | null>(
searchParams.get("from") ? new Date(searchParams.get("from")!) : null
);
const [endDate, setEndDate] = useState<Date | null>(
searchParams.get("to") ? new Date(searchParams.get("to")!) : null
);
function handleDateChange(dates: [Date | null, Date | null]) {
const [start, end] = dates;
setStartDate(start);
setEndDate(end);
// When both dates are cleared (via X button), auto-submit to reset results
if (!start && !end) {
const params = new URLSearchParams();
if (query.trim()) params.set("q", query.trim());
const qs = params.toString();
router.push(`/trips${qs ? `?${qs}` : ""}`);
}
}
function handleSearch(e: React.FormEvent) {
e.preventDefault();
const params = new URLSearchParams();
if (query.trim()) params.set("q", query.trim());
if (startDate) params.set("from", startDate.toISOString().split("T")[0]);
if (endDate) params.set("to", endDate.toISOString().split("T")[0]);
const qs = params.toString();
router.push(`/trips${qs ? `?${qs}` : ""}`);
}
function handleReset() {
setQuery("");
setStartDate(null);
setEndDate(null);
router.push("/trips");
}
const hasFilters = query || startDate || endDate;
return (
<form
onSubmit={handleSearch}
className="rounded-2xl border border-neutral-200 bg-white p-4 shadow-sm sm:p-5"
>
<div className="flex flex-col gap-3 sm:flex-row sm:items-end sm:gap-3">
{/* Search input */}
<div className="flex-1">
<label className="mb-1.5 block text-xs font-medium text-neutral-500">
Cari trip
</label>
<div className="relative">
<span className="absolute left-3 top-1/2 -translate-y-1/2 text-neutral-400">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
className="h-4 w-4"
>
<path
fillRule="evenodd"
d="M9 3.5a5.5 5.5 0 100 11 5.5 5.5 0 000-11zM2 9a7 7 0 1112.452 4.391l3.328 3.329a.75.75 0 11-1.06 1.06l-3.329-3.328A7 7 0 012 9z"
clipRule="evenodd"
/>
</svg>
</span>
<input
type="text"
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Gunung, lokasi, atau nama trip..."
className="w-full rounded-xl border border-neutral-200 bg-neutral-50 py-2.5 pl-9 pr-3 text-sm text-neutral-800 placeholder:text-neutral-400 focus:border-primary-500 focus:bg-white"
/>
</div>
</div>
{/* Date range */}
<div className="sm:w-64">
<label className="mb-1.5 block text-xs font-medium text-neutral-500">
Rentang tanggal berangkat
</label>
<div className="relative">
<span className="absolute left-3 top-1/2 z-10 -translate-y-1/2 text-neutral-400">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
className="h-4 w-4"
>
<path
fillRule="evenodd"
d="M5.75 2a.75.75 0 01.75.75V4h7V2.75a.75.75 0 011.5 0V4h.25A2.75 2.75 0 0118 6.75v8.5A2.75 2.75 0 0115.25 18H4.75A2.75 2.75 0 012 15.25v-8.5A2.75 2.75 0 014.75 4H5V2.75A.75.75 0 015.75 2zm-1 5.5c-.69 0-1.25.56-1.25 1.25v6.5c0 .69.56 1.25 1.25 1.25h10.5c.69 0 1.25-.56 1.25-1.25v-6.5c0-.69-.56-1.25-1.25-1.25H4.75z"
clipRule="evenodd"
/>
</svg>
</span>
<DatePicker
selectsRange
startDate={startDate}
endDate={endDate}
onChange={handleDateChange}
minDate={new Date()}
placeholderText="Pilih tanggal..."
dateFormat="dd MMM yyyy"
isClearable
className="w-full rounded-xl border border-neutral-200 bg-neutral-50 py-2.5 pl-9 pr-3 text-sm text-neutral-800 placeholder:text-neutral-400 focus:border-primary-500 focus:bg-white"
/>
</div>
</div>
{/* Buttons */}
<div className="flex gap-2 sm:shrink-0">
<button
type="submit"
className="flex-1 rounded-xl bg-primary-600 px-5 py-2.5 text-sm font-semibold text-white shadow-md shadow-primary-600/20 transition-colors hover:bg-primary-700 sm:flex-none"
>
Cari
</button>
{hasFilters && (
<button
type="button"
onClick={handleReset}
className="rounded-xl border border-neutral-200 px-3 py-2.5 text-sm font-medium text-neutral-500 transition-colors hover:bg-neutral-50 hover:text-neutral-700"
>
Reset
</button>
)}
</div>
</div>
</form>
);
}