'use client'; import { zodResolver } from '@hookform/resolvers/zod'; import { ArrowLeft } from 'lucide-react'; import Link from 'next/link'; import { useRouter } from 'next/navigation'; import * as React from 'react'; import { useForm } from 'react-hook-form'; import { z } from 'zod'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; 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 { duAnApi, type CreateProjectPayload } from '@/lib/du-an-api'; const SLUG_REGEX = /^[a-z0-9-]+$/; const projectSchema = z.object({ name: z.string().min(1, 'Bắt buộc'), slug: z .string() .min(1, 'Bắt buộc') .regex(SLUG_REGEX, 'Chỉ cho phép chữ thường, số và dấu -'), developer: z.string().min(1, 'Bắt buộc'), developerLogo: z .string() .optional() .refine( (v) => !v || /^https?:\/\//.test(v), 'URL không hợp lệ', ), status: z.enum(['UPCOMING', 'SELLING', 'HANDOVER', 'COMPLETED']), totalUnits: z .string() .min(1, 'Bắt buộc') .refine((v) => /^\d+$/.test(v) && Number(v) > 0, 'Phải là số nguyên > 0'), address: z.string().min(1, 'Bắt buộc'), ward: z.string().min(1, 'Bắt buộc'), district: z.string().min(1, 'Bắt buộc'), city: z.string().min(1, 'Bắt buộc'), latitude: z .string() .min(1, 'Bắt buộc') .refine((v) => { const n = Number(v); return Number.isFinite(n) && n >= -90 && n <= 90; }, 'Từ -90 đến 90'), longitude: z .string() .min(1, 'Bắt buộc') .refine((v) => { const n = Number(v); return Number.isFinite(n) && n >= -180 && n <= 180; }, 'Từ -180 đến 180'), description: z.string().optional(), masterPlanUrl: z .string() .optional() .refine( (v) => !v || /^https?:\/\//.test(v), 'URL không hợp lệ', ), minPrice: z .string() .optional() .refine((v) => !v || /^\d+$/.test(v), 'Chỉ nhập số nguyên'), maxPrice: z .string() .optional() .refine((v) => !v || /^\d+$/.test(v), 'Chỉ nhập số nguyên'), totalArea: z .string() .optional() .refine((v) => !v || (Number.isFinite(Number(v)) && Number(v) > 0), 'Phải lớn hơn 0'), buildingCount: z .string() .optional() .refine((v) => !v || (/^\d+$/.test(v) && Number(v) > 0), 'Phải là số nguyên > 0'), floorCount: z .string() .optional() .refine((v) => !v || (/^\d+$/.test(v) && Number(v) > 0), 'Phải là số nguyên > 0'), startDate: z.string().optional(), completionDate: z.string().optional(), tags: z.string().optional(), }); type ProjectFormData = z.infer; function FormSection({ title, children, }: { title: string; children: React.ReactNode; }) { return ( {title} {children} ); } export default function CreateProjectPage() { const router = useRouter(); const [isSubmitting, setIsSubmitting] = React.useState(false); const [error, setError] = React.useState(null); const [success, setSuccess] = React.useState(false); const { register, handleSubmit, formState: { errors }, } = useForm({ resolver: zodResolver(projectSchema), mode: 'onTouched', defaultValues: { status: 'UPCOMING', }, }); const onSubmit = async (data: ProjectFormData) => { setIsSubmitting(true); setError(null); try { const payload: CreateProjectPayload = { name: data.name, slug: data.slug, developer: data.developer, status: data.status, totalUnits: Number(data.totalUnits), address: data.address, ward: data.ward, district: data.district, city: data.city, latitude: Number(data.latitude), longitude: Number(data.longitude), }; if (data.developerLogo) payload.developerLogo = data.developerLogo; if (data.description) payload.description = data.description; if (data.masterPlanUrl) payload.masterPlanUrl = data.masterPlanUrl; if (data.minPrice) payload.minPrice = data.minPrice; if (data.maxPrice) payload.maxPrice = data.maxPrice; if (data.totalArea) payload.totalArea = Number(data.totalArea); if (data.buildingCount) payload.buildingCount = Number(data.buildingCount); if (data.floorCount) payload.floorCount = Number(data.floorCount); if (data.startDate) payload.startDate = data.startDate; if (data.completionDate) payload.completionDate = data.completionDate; if (data.tags) { const tags = data.tags .split(',') .map((s) => s.trim()) .filter(Boolean); if (tags.length > 0) payload.tags = tags; } await duAnApi.create(payload); setSuccess(true); setTimeout(() => router.push('/projects'), 600); } catch (err) { setError(err instanceof Error ? err.message : 'Có lỗi xảy ra'); } finally { setIsSubmitting(false); } }; return (
Danh sách dự án

Thêm dự án mới

{success && (
Đã tạo dự án
)} {error && (
{error}
)}
{/* Thông tin cơ bản */}
{errors.name && (

{errors.name.message}

)}

URL thân thiện, chỉ chữ thường, số và dấu -

{errors.slug && (

{errors.slug.message}

)}
{errors.developer && (

{errors.developer.message}

)}
{errors.developerLogo && (

{errors.developerLogo.message}

)}
{errors.totalUnits && (

{errors.totalUnits.message}

)}