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
+38 -50
View File
@@ -7,17 +7,11 @@ import "react-datepicker/dist/react-datepicker.css";
import { createTripAction } from "@/features/trip/actions";
import { ImageUrlInput } from "@/features/trip/components/image-url-input";
import { formatLocalCalendarYmd } from "@/lib/trip-dates";
const SAMPLE_MOUNTAINS = [
{ name: "Gunung Papandayan", location: "Garut, Jawa Barat" },
{ name: "Gunung Ciremai", location: "Kuningan, Jawa Barat" },
{ name: "Gunung Pangrango", location: "Bogor/Cianjur, Jawa Barat" },
{ name: "Gunung Gede", location: "Bogor/Cianjur, Jawa Barat" },
{ name: "Gunung Tangkuban Parahu", location: "Bandung, Jawa Barat" },
{ name: "Gunung Bukit Tunggul", location: "Bandung, Jawa Barat" },
{ name: "Gunung Malabar", location: "Bandung, Jawa Barat" },
{ name: "Gunung Guntur", location: "Garut, Jawa Barat" },
];
import {
ACTIVITY_CATEGORIES,
categoryMeta,
} from "@/lib/activity-category";
import type { ActivityCategory } from "@/app/generated/prisma/enums";
function formatRupiahInput(value: string): string {
const num = value.replace(/\D/g, "");
@@ -37,10 +31,12 @@ export function CreateTripForm({ isVerifiedOrganizer }: CreateTripFormProps) {
const [error, setError] = useState("");
const [loading, setLoading] = useState(false);
const [category, setCategory] = useState<ActivityCategory>("HIKING");
const [startDate, setStartDate] = useState<Date | null>(null);
const [endDate, setEndDate] = useState<Date | null>(null);
const [priceDisplay, setPriceDisplay] = useState("");
const meta = categoryMeta(category);
const priceNumber = Number(parseRupiahInput(priceDisplay) || "0");
const isPaidTrip = priceNumber > 0;
const blockedByVerification = isPaidTrip && !isVerifiedOrganizer;
@@ -78,23 +74,6 @@ export function CreateTripForm({ isVerifiedOrganizer }: CreateTripFormProps) {
}
}
function handleMountainSelect(e: React.ChangeEvent<HTMLSelectElement>) {
const selected = SAMPLE_MOUNTAINS.find((m) => m.name === e.target.value);
if (selected) {
const form = e.target.form;
if (form) {
const mountainInput = form.elements.namedItem(
"mountain"
) as HTMLInputElement;
const locationInput = form.elements.namedItem(
"location"
) as HTMLInputElement;
mountainInput.value = selected.name;
locationInput.value = selected.location;
}
}
}
function handleDateChange(dates: [Date | null, Date | null]) {
const [start, end] = dates;
setStartDate(start);
@@ -115,25 +94,34 @@ export function CreateTripForm({ isVerifiedOrganizer }: CreateTripFormProps) {
)}
<form onSubmit={handleSubmit} className="space-y-5">
{/* Mountain Quick Picker */}
{/* Category Chips */}
<div className="rounded-xl bg-primary-50 p-4">
<label className="mb-2 flex items-center gap-1.5 text-sm font-bold text-primary-800">
<span>🏔</span> Pilih Gunung Jawa Barat
<label className="mb-2 block text-sm font-bold text-primary-800">
Kategori Aktivitas
</label>
<select
onChange={handleMountainSelect}
className="w-full rounded-lg border border-primary-200 bg-white px-4 py-2.5 text-sm text-neutral-800"
defaultValue=""
>
<option value="" disabled>
Pilih gunung...
</option>
{SAMPLE_MOUNTAINS.map((m) => (
<option key={m.name} value={m.name}>
{m.name} {m.location}
</option>
))}
</select>
<div className="flex flex-wrap gap-2">
{ACTIVITY_CATEGORIES.map((c) => {
const m = categoryMeta(c);
const active = c === category;
return (
<button
key={c}
type="button"
onClick={() => setCategory(c)}
aria-pressed={active}
className={`inline-flex items-center gap-1.5 rounded-full border px-3 py-1.5 text-xs font-medium transition-colors ${
active
? "border-primary-600 bg-primary-600 text-white"
: "border-primary-200 bg-white text-primary-800 hover:bg-primary-100"
}`}
>
<span>{m.icon}</span>
<span>{m.label}</span>
</button>
);
})}
</div>
<input type="hidden" name="category" value={category} />
</div>
<div>
@@ -152,16 +140,16 @@ export function CreateTripForm({ isVerifiedOrganizer }: CreateTripFormProps) {
<div className="grid gap-4 sm:grid-cols-2">
<div>
<label htmlFor="mountain" className="mb-1.5 block text-sm font-semibold text-neutral-700">
Nama Gunung
<label htmlFor="destination" className="mb-1.5 block text-sm font-semibold text-neutral-700">
{meta.destinationLabel}
</label>
<input
id="mountain"
name="mountain"
id="destination"
name="destination"
type="text"
required
className="w-full rounded-xl border border-neutral-200 bg-neutral-50 px-4 py-2.5 text-sm text-neutral-800 placeholder:text-neutral-400 focus:bg-white"
placeholder="Gunung Papandayan"
placeholder={meta.destinationPlaceholder}
/>
</div>
<div>