From 58811264088b12d314dab92fd7dd9ff02256ddeb Mon Sep 17 00:00:00 2001 From: AutonetSellCar Deploy Date: Sun, 1 Feb 2026 21:13:55 +0900 Subject: [PATCH] feat: Add Request functionality to All Cars tab - Add checkbox selection for cars in All Cars tab when requestId is present - Add "Add to Request" button with selection count - Add select all/deselect all functionality - Highlight selected cars with blue ring Co-Authored-By: Claude Opus 4.5 --- frontend/src/app/admin/cars/page.tsx | 146 ++++++++++++++++++++++++++- 1 file changed, 145 insertions(+), 1 deletion(-) diff --git a/frontend/src/app/admin/cars/page.tsx b/frontend/src/app/admin/cars/page.tsx index 5182a31..c272b22 100644 --- a/frontend/src/app/admin/cars/page.tsx +++ b/frontend/src/app/admin/cars/page.tsx @@ -151,6 +151,8 @@ export default function CarsAdminPage() { const [allCarsLoading, setAllCarsLoading] = useState(false); const [allCarsTotal, setAllCarsTotal] = useState(0); const [allCarsPage, setAllCarsPage] = useState(1); + const [selectedAllCars, setSelectedAllCars] = useState>(new Set()); + const [addingAllCarsToRequest, setAddingAllCarsToRequest] = useState(false); // Carmodoo search state const [makers, setMakers] = useState([]); @@ -1093,6 +1095,92 @@ export default function CarsAdminPage() { } }; + // All Cars 탭에서 Request에 추가하는 함수 + const handleAddAllCarsToRequest = async () => { + if (!requestId) return; + if (selectedAllCars.size === 0) { + alert('Please select at least one car to add to the request.'); + return; + } + + if (!confirm(`${selectedAllCars.size}개의 차량을 추천 목록에 추가하시겠습니까?`)) { + return; + } + + setAddingAllCarsToRequest(true); + + try { + const selectedCarsList = allCars.filter(car => selectedAllCars.has(car.id)); + let addedCount = 0; + let errorCount = 0; + + for (const car of selectedCarsList) { + try { + const mainImage = car.images?.find((img) => img.is_main)?.url || car.images?.[0]?.url; + await vehicleRequestsApi.adminAddVehicle(parseInt(requestId), { + request_id: parseInt(requestId), + car_id: car.id, // 이미 로컬 DB에 있는 차량이므로 car_id 사용 + car_data: { + id: car.id.toString(), + car_name: car.car_name, + maker_name: car.maker?.name, + model_name: car.model?.name, + year: car.year, + mileage: car.mileage, + final_price: car.final_price_krw || car.price_krw, + fuel: car.fuel, + transmission: car.transmission, + color: car.color, + main_image: mainImage, + }, + is_approved: true, + }); + addedCount++; + } catch (err) { + console.error(`Failed to add car ${car.id}:`, err); + errorCount++; + } + } + + setSelectedAllCars(new Set()); + + if (errorCount > 0) { + alert(`${addedCount}개의 차량이 추천 목록에 추가되었습니다.\n(실패: ${errorCount}개)`); + } else { + alert(`${addedCount}개의 차량이 추천 목록에 추가되었습니다.`); + } + + router.push('/admin/vehicle-requests'); + } catch (err) { + console.error('Add to request failed:', err); + alert('추천 목록 추가에 실패했습니다.'); + } finally { + setAddingAllCarsToRequest(false); + } + }; + + // All Cars 선택 토글 + const toggleAllCarSelection = (carId: number) => { + setSelectedAllCars(prev => { + const newSet = new Set(prev); + if (newSet.has(carId)) { + newSet.delete(carId); + } else { + newSet.add(carId); + } + return newSet; + }); + }; + + // All Cars 전체 선택/해제 + const handleSelectAllAllCars = () => { + if (selectedAllCars.size === allCars.length) { + setSelectedAllCars(new Set()); + } else { + setSelectedAllCars(new Set(allCars.map(car => car.id))); + } + }; + const handleDeleteCar = async (carId: number) => { if (!confirm('Are you sure you want to delete this car?')) { return; @@ -1700,6 +1788,45 @@ export default function CarsAdminPage() { This shows the cars that are visible to users (is_displayed = true). This is the same view as the public /cars page.

+ {/* Selection Controls for Request Mode */} + {requestId && allCars.length > 0 && ( +
+
+ + + {selectedAllCars.size} selected + +
+ +
+ )} + {allCarsLoading ? (
@@ -1717,13 +1844,30 @@ export default function CarsAdminPage() {
{allCars.map((car) => { const mainImage = getImageUrl(car.images?.find((img) => img.is_main)?.url || car.images?.[0]?.url); + const isSelected = selectedAllCars.has(car.id); return (
handleCarClick(car)} >
+ {/* Checkbox for Request Mode */} + {requestId && ( +
e.stopPropagation()} + > + toggleAllCarSelection(car.id)} + className="w-5 h-5 text-blue-600 rounded cursor-pointer" + /> +
+ )} {mainImage ? (