'use client';
import dynamic from 'next/dynamic';
import type { UseFormRegister, UseFormSetValue, UseFormWatch, FieldErrors } from 'react-hook-form';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Select } from '@/components/ui/select';
import { Textarea } from '@/components/ui/textarea';
import {
TRANSACTION_TYPES,
PROPERTY_TYPES,
DIRECTIONS,
FURNISHING_OPTIONS,
PROPERTY_CONDITION_OPTIONS,
type CreateListingFormData,
} from '@/lib/validations/listings';
// Mapbox picker is client-only + imports `mapbox-gl` which pulls WebGL
// utilities — dynamic-import with ssr:false to keep it out of the server
// bundle.
const LocationPicker = dynamic(
() => import('@/components/map/location-picker').then((m) => m.LocationPicker),
{
ssr: false,
loading: () => (
Đang tải bản đồ...
),
},
);
interface StepProps {
register: UseFormRegister;
errors: FieldErrors;
}
interface StepLocationProps extends StepProps {
/** Optional — when provided, StepLocation renders the Mapbox picker and
* writes latitude/longitude (+ auto-fills address/ward/district/city on
* geocoder pick) into the form state. */
setValue?: UseFormSetValue;
watch?: UseFormWatch;
}
function FieldError({ message }: { message?: string }) {
if (!message) return null;
return {message}
;
}
// ─── Step 1: Basic Info ──────────────────────────────────
export function StepBasicInfo({ register, errors }: StepProps) {
return (
Thông tin cơ bản
);
}
// ─── Step 2: Location ────────────────────────────────────
export function StepLocation({ register, errors, setValue, watch }: StepLocationProps) {
// Watch lat/lng so the picker stays in sync when the user edits the text
// inputs manually.
const latStr = watch?.('latitude') ?? '';
const lngStr = watch?.('longitude') ?? '';
const latNum = latStr ? Number(latStr) : null;
const lngNum = lngStr ? Number(lngStr) : null;
const latValid = latNum != null && Number.isFinite(latNum) && latNum >= -90 && latNum <= 90;
const lngValid = lngNum != null && Number.isFinite(lngNum) && lngNum >= -180 && lngNum <= 180;
return (
Vị trí
{setValue && (
{
setValue('latitude', coords.lat.toFixed(6), { shouldValidate: true, shouldDirty: true });
setValue('longitude', coords.lng.toFixed(6), { shouldValidate: true, shouldDirty: true });
if (resolved) {
if (resolved.address) setValue('address', resolved.address, { shouldDirty: true });
if (resolved.ward) setValue('ward', resolved.ward, { shouldDirty: true });
if (resolved.district) setValue('district', resolved.district, { shouldDirty: true });
if (resolved.city) setValue('city', resolved.city, { shouldDirty: true });
}
}}
height="360px"
/>
)}
);
}
// ─── Step 3: Details ─────────────────────────────────────
export function StepDetails({ register, errors }: StepProps) {
return (
);
}
// ─── Step 4: Pricing ─────────────────────────────────────
export function StepPricing({ register, errors }: StepProps) {
return (
);
}