add end date and create logo and fix filter
This commit is contained in:
@@ -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>{" "}
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user