Files
AutonetSellCar/temp_solutions_edit_page.tsx

208 lines
6.7 KiB
TypeScript

"use client";
import { useEffect, useState } from "react";
import { useRouter, useParams } from "next/navigation";
import { useAuth } from "@/contexts/AuthContext";
import { solutionsApi, SolutionAdmin, getUploadUrl } from "@/lib/api";
import SolutionForm from "@/components/admin/SolutionForm";
import { Loader2, Upload, Trash2 } from "lucide-react";
import YouTubeVideoManager from "@/components/admin/YouTubeVideoManager";
export default function EditSolutionPage() {
const { token } = useAuth();
const router = useRouter();
const params = useParams();
const solutionId = Number(params.id);
const [solution, setSolution] = useState<SolutionAdmin | null>(null);
const [isLoading, setIsLoading] = useState(true);
const [isSubmitting, setIsSubmitting] = useState(false);
const [isUploading, setIsUploading] = useState(false);
const fetchSolution = async () => {
if (!token) return;
try {
const data = await solutionsApi.adminGetOne(solutionId, token);
setSolution(data);
} catch (err) {
alert("솔루션을 찾을 수 없습니다.");
router.push("/admin/solutions");
} finally {
setIsLoading(false);
}
};
useEffect(() => {
fetchSolution();
}, [token, solutionId]);
const handleSubmit = async (data: any) => {
if (!token) return;
setIsSubmitting(true);
try {
await solutionsApi.adminUpdate(solutionId, data, token);
alert("저장되었습니다.");
fetchSolution();
} catch (err) {
alert("저장에 실패했습니다.");
} finally {
setIsSubmitting(false);
}
};
const handleImageUpload = async (
e: React.ChangeEvent<HTMLInputElement>,
isMain: boolean
) => {
if (!token || !e.target.files?.[0]) return;
setIsUploading(true);
try {
await solutionsApi.adminUploadImage(
solutionId,
e.target.files[0],
isMain,
token
);
fetchSolution();
} catch (err) {
alert("이미지 업로드에 실패했습니다.");
} finally {
setIsUploading(false);
e.target.value = "";
}
};
const handleDeleteImage = async (imageId: number) => {
if (!token || !confirm("이미지를 삭제하시겠습니까?")) return;
try {
await solutionsApi.adminDeleteImage(imageId, token);
fetchSolution();
} catch (err) {
alert("이미지 삭제에 실패했습니다.");
}
};
if (isLoading) {
return (
<div className="flex items-center justify-center h-64">
<Loader2 className="w-8 h-8 animate-spin text-[#3B82F6]" />
</div>
);
}
if (!solution) return null;
return (
<div>
<h1 className="text-2xl font-bold text-gray-900 mb-8"> </h1>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
{/* Form */}
<div className="lg:col-span-2">
<SolutionForm
initialData={solution}
onSubmit={handleSubmit}
isSubmitting={isSubmitting}
/>
</div>
{/* Image Upload */}
<div className="space-y-6">
{/* Main Image */}
<div className="bg-white rounded-xl p-6 shadow-sm">
<h3 className="font-semibold text-gray-900 mb-4"> </h3>
{solution.main_image ? (
<div className="relative">
<img
src={getUploadUrl(solution.main_image)}
alt="Main"
className="w-full h-48 object-cover rounded-lg"
/>
<label className="absolute bottom-2 right-2 px-3 py-1.5 bg-white/90 text-sm font-medium rounded-lg cursor-pointer hover:bg-white transition-colors">
<input
type="file"
accept="image/*"
className="hidden"
onChange={(e) => handleImageUpload(e, true)}
disabled={isUploading}
/>
</label>
</div>
) : (
<label className="flex flex-col items-center justify-center h-48 border-2 border-dashed border-gray-200 rounded-lg cursor-pointer hover:border-[#3B82F6] transition-colors">
{isUploading ? (
<Loader2 className="w-8 h-8 animate-spin text-[#3B82F6]" />
) : (
<>
<Upload className="w-8 h-8 text-gray-400 mb-2" />
<span className="text-sm text-gray-500">
</span>
</>
)}
<input
type="file"
accept="image/*"
className="hidden"
onChange={(e) => handleImageUpload(e, true)}
disabled={isUploading}
/>
</label>
)}
</div>
{/* Additional Images */}
<div className="bg-white rounded-xl p-6 shadow-sm">
<h3 className="font-semibold text-gray-900 mb-4"> </h3>
<div className="grid grid-cols-2 gap-3 mb-4">
{solution.images?.map((img) => (
<div key={img.id} className="relative group">
<img
src={getUploadUrl(img.image_url)}
alt=""
className="w-full h-24 object-cover rounded-lg"
/>
<button
onClick={() => handleDeleteImage(img.id)}
className="absolute top-1 right-1 p-1 bg-red-500 text-white rounded opacity-0 group-hover:opacity-100 transition-opacity"
>
<Trash2 className="w-4 h-4" />
</button>
</div>
))}
</div>
<label className="flex items-center justify-center py-3 border-2 border-dashed border-gray-200 rounded-lg cursor-pointer hover:border-[#3B82F6] transition-colors">
{isUploading ? (
<Loader2 className="w-5 h-5 animate-spin text-[#3B82F6]" />
) : (
<>
<Upload className="w-5 h-5 text-gray-400 mr-2" />
<span className="text-sm text-gray-500"> </span>
</>
)}
<input
type="file"
accept="image/*"
className="hidden"
onChange={(e) => handleImageUpload(e, false)}
disabled={isUploading}
/>
</label>
</div>
{/* YouTube Videos */}
<YouTubeVideoManager
entityType="solution"
entityId={solutionId}
entityTitle={solution.title_ko}
/>
</div>
</div>
</div>
);
}