Files
mkd/components/objects/MoveBuildingsModal.tsx
2026-02-04 00:17:04 +05:00

215 lines
8.0 KiB
TypeScript
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React, { useState, useEffect } from 'react';
import { District, Building } from '../../types';
import { MapPin, ArrowRight, X, AlertCircle } from 'lucide-react';
import { backendApi } from '../../services/apiClient';
import { storageService } from '../../services/storageService';
interface Props {
isOpen: boolean;
onClose: () => void;
onComplete: () => void;
sourceDistrict: District;
buildings: Building[];
allDistricts: District[];
}
export const MoveBuildingsModal: React.FC<Props> = ({
isOpen,
onClose,
onComplete,
sourceDistrict,
buildings,
allDistricts,
}) => {
const [targetDistrictId, setTargetDistrictId] = useState<string>('');
const [isMoving, setIsMoving] = useState(false);
// Исключаем текущий участок из списка
const availableDistricts = allDistricts.filter(d => d.id !== sourceDistrict.id);
useEffect(() => {
if (isOpen && availableDistricts.length > 0 && !targetDistrictId) {
setTargetDistrictId(availableDistricts[0].id);
}
}, [isOpen, availableDistricts, targetDistrictId]);
if (!isOpen) return null;
const handleMove = async () => {
if (!targetDistrictId || buildings.length === 0) return;
setIsMoving(true);
try {
// Перемещаем каждый дом
for (const building of buildings) {
const updatedBuilding = {
...building,
districtId: targetDistrictId,
};
// Обновляем в localStorage
storageService.saveBuildingData(updatedBuilding);
// Обновляем на сервере
try {
await backendApi.updateBuilding(updatedBuilding);
} catch (error) {
console.error(`Failed to move building ${building.id}:`, error);
// Продолжаем с другими домами
}
}
onComplete();
} catch (error) {
console.error('Failed to move buildings:', error);
alert('Ошибка при перемещении домов. Попробуйте еще раз.');
} finally {
setIsMoving(false);
}
};
if (availableDistricts.length === 0) {
return (
<div
className="fixed inset-0 z-[100] flex items-center justify-center p-4 bg-slate-900/80 backdrop-blur-md animate-fade-in"
onClick={onClose}
>
<div
className="bg-white rounded-2xl w-full max-w-md shadow-2xl animate-slide-up"
onClick={(e) => e.stopPropagation()}
>
<div className="p-6">
<div className="flex items-center gap-3 mb-4">
<div className="p-2 bg-amber-50 rounded-lg">
<AlertCircle className="w-6 h-6 text-amber-500" />
</div>
<div>
<h3 className="text-lg font-black text-slate-900">Нет доступных участков</h3>
<p className="text-sm text-slate-500 mt-1">
Для перемещения домов нужен хотя бы один другой участок
</p>
</div>
</div>
<p className="text-sm text-slate-600 mb-4">
Создайте новый участок, чтобы переместить {buildings.length} {buildings.length === 1 ? 'дом' : 'домов'} из участка "{sourceDistrict.name}".
</p>
<button
onClick={onClose}
className="w-full px-4 py-3 rounded-xl bg-slate-100 text-slate-700 font-bold hover:bg-slate-200 transition-colors"
>
Понятно
</button>
</div>
</div>
</div>
);
}
return (
<div
className="fixed inset-0 z-[100] flex items-center justify-center p-4 bg-slate-900/80 backdrop-blur-md animate-fade-in"
onClick={onClose}
>
<div
className="bg-white rounded-2xl w-full max-w-lg shadow-2xl animate-slide-up max-h-[90vh] overflow-y-auto"
onClick={(e) => e.stopPropagation()}
>
{/* Header */}
<div className="p-6 border-b border-slate-200 sticky top-0 bg-white rounded-t-2xl">
<div className="flex items-start justify-between">
<div className="flex items-center gap-3">
<div className="p-2 bg-primary-50 rounded-lg">
<MapPin className="w-6 h-6 text-primary-500" />
</div>
<div>
<h3 className="text-lg font-black text-slate-900">Перемещение домов</h3>
<p className="text-sm text-slate-500 mt-1">
Выберите участок для перемещения {buildings.length} {buildings.length === 1 ? 'дома' : 'домов'}
</p>
</div>
</div>
<button
onClick={onClose}
disabled={isMoving}
className="p-2 hover:bg-slate-100 rounded-full transition-colors disabled:opacity-50"
>
<X className="w-5 h-5 text-slate-400" />
</button>
</div>
</div>
{/* Content */}
<div className="p-6 space-y-4">
<div className="bg-slate-50 rounded-xl p-4 border border-slate-200">
<p className="text-xs font-bold text-slate-500 uppercase mb-2">Из участка:</p>
<p className="text-sm font-bold text-slate-800">{sourceDistrict.name}</p>
</div>
<div className="flex items-center justify-center py-2">
<ArrowRight className="w-5 h-5 text-slate-400" />
</div>
<div>
<label className="block text-xs font-bold text-slate-500 uppercase mb-2">
В участок:
</label>
<select
value={targetDistrictId}
onChange={(e) => setTargetDistrictId(e.target.value)}
disabled={isMoving}
className="w-full p-3 bg-white border border-slate-300 rounded-xl text-sm font-bold text-slate-800 outline-none focus:ring-2 focus:ring-primary-500 disabled:opacity-50"
>
{availableDistricts.map(district => (
<option key={district.id} value={district.id}>
{district.name}
</option>
))}
</select>
</div>
{buildings.length > 0 && (
<div className="bg-amber-50 border border-amber-200 rounded-xl p-4">
<p className="text-xs font-bold text-amber-800 mb-2">Дома для перемещения:</p>
<div className="space-y-1 max-h-40 overflow-y-auto">
{buildings.map(building => (
<div key={building.id} className="text-sm text-amber-900">
{building.passport.address}
</div>
))}
</div>
</div>
)}
</div>
{/* Footer */}
<div className="p-6 border-t border-slate-200 flex gap-3">
<button
onClick={onClose}
disabled={isMoving}
className="flex-1 px-4 py-3 rounded-xl border border-slate-200 text-slate-700 font-bold hover:bg-slate-50 transition-colors disabled:opacity-50"
>
Отмена
</button>
<button
onClick={handleMove}
disabled={isMoving || !targetDistrictId}
className="flex-1 px-4 py-3 rounded-xl bg-primary-600 text-white font-bold hover:bg-primary-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2"
>
{isMoving ? (
<>
<div className="w-4 h-4 border-2 border-white/50 border-t-white rounded-full animate-spin" />
<span>Перемещение...</span>
</>
) : (
<>
<ArrowRight className="w-4 h-4" />
<span>Переместить</span>
</>
)}
</button>
</div>
</div>
</div>
);
};