// ... existing code ... const firebaseConfig = { apiKey: "AIzaSyAowbdLOHE67Q05ulS91y3Bi9XD9Ml5OxU", authDomain: "true-design-85c3b.firebaseapp.com", projectId: "true-design-85c3b", storageBucket: "true-design-85c3b.firebasestorage.app", messagingSenderId: "1079556876551", appId: "1:1079556876551:web:01a74904b7d6bb6e3abda2" }; const app = initializeApp(firebaseConfig); const auth = getAuth(app); const db = getFirestore(app); const appId = typeof __app_id !== 'undefined' ? __app_id : 'true-design-85c3b'; const ROOM_OPTIONS = [ // ... existing code ... // ====== ЗАГРУЗКА ДАННЫХ ====== const loadProjects = async () => { if (!currentUser.value) return; try { const qProj = query(collection(db, 'artifacts', appId, 'public', 'data', 'projects'), where('designerId', '==', currentUser.value.uid)); const pSnap = await getDocs(qProj); let loadedProjects = pSnap.docs.map(d => ({ id: d.id, ...d.data() })); if (loadedProjects.length > 0) { const qRooms = collection(db, 'artifacts', appId, 'public', 'data', 'rooms'); const rSnap = await getDocs(qRooms); const allRooms = rSnap.docs.map(d => ({ id: d.id, ...d.data() })); loadedProjects = loadedProjects.map(p => { // ... existing code ... }; const loadClients = async () => { if (!currentUser.value) return; try { const q = query(collection(db, 'artifacts', appId, 'public', 'data', 'clients'), where('designerId', '==', currentUser.value.uid)); const snap = await getDocs(q); clients.value = snap.docs.map(d => ({ id: d.id, ...d.data() })); } catch (e) { console.error('Ошибка загрузки клиентов:', e); } }; // ====== ПРОЕКТЫ ====== // ... existing code ... const projectPayload = { title, clientEmail: projectForm.clientEmail.trim().toLowerCase(), address: projectForm.address.trim(), linkDrawings: projectForm.linkDrawings.trim(), linkVisuals: projectForm.linkVisuals.trim(), linkOther: projectForm.linkOther.trim(), stage: projectForm.stage, status: projectForm.status, targetBudget: projectForm.targetBudget ? Number(projectForm.targetBudget) : null, designerId: currentUser.value.uid, updatedAt: serverTimestamp() }; try { const projectRef = doc(db, 'artifacts', appId, 'public', 'data', 'projects', pid); if (!isEditMode.value) projectPayload.createdAt = serverTimestamp(); await setDoc(projectRef, projectPayload, { merge: true }); // Batch update для комнат (идеальная логика первого варианта) const qRooms = query(collection(db, 'artifacts', appId, 'public', 'data', 'rooms'), where('projectId', '==', pid)); const existingRoomsSnap = await getDocs(qRooms); const existingRooms = existingRoomsSnap.docs.map(d => ({ ref: d.ref, data: d.data() })); const batch = writeBatch(db); // Удаляем снятые галочки existingRooms.forEach(roomDoc => { if (!projectForm.selectedRooms.includes(roomDoc.data.roomType)) { batch.delete(roomDoc.ref); } }); // Сохраняем активные (создаем новые или обновляем порядок) projectForm.selectedRooms.forEach((roomType, index) => { const existing = existingRooms.find(d => d.data.roomType === roomType); let roomRef = existing ? existing.ref : doc(collection(db, 'artifacts', appId, 'public', 'data', 'rooms')); batch.set(roomRef, { projectId: pid, // ... existing code ... const saveClient = async () => { if (!clientForm.name || !clientForm.email) return; isSaving.value = true; try { const clientCol = collection(db, 'artifacts', appId, 'public', 'data', 'clients'); const cid = clientForm.id || doc(clientCol).id; const payload = { name: clientForm.name.trim(), email: clientForm.email.trim().toLowerCase(), phone: clientForm.phone.trim(), notes: clientForm.notes.trim(), designerId: currentUser.value.uid, updatedAt: serverTimestamp() }; if (!clientForm.id) payload.createdAt = serverTimestamp(); await setDoc(doc(db, 'artifacts', appId, 'public', 'data', 'clients', cid), payload, { merge: true }); await loadClients(); isClientModalOpen.value = false; } catch(e) { // ... existing code ... // ====== ОБЩИЕ ДЕЙСТВИЯ ====== const confirmAction = async () => { const targetId = alertData.targetId; const actionType = alertData.actionType; if (!targetId) return; isAlertOpen.value = false; document.getElementById('ta-loader').style.opacity = '1'; document.getElementById('ta-loader').style.display = 'flex'; try { if (actionType === 'project') { const qRooms = query(collection(db, 'artifacts', appId, 'public', 'data', 'rooms'), where('projectId', '==', targetId)); const rSnap = await getDocs(qRooms); const batch = writeBatch(db); rSnap.docs.forEach(d => batch.delete(d.ref)); batch.delete(doc(db, 'artifacts', appId, 'public', 'data', 'projects', targetId)); await batch.commit(); await loadProjects(); } else if (actionType === 'client') { await deleteDoc(doc(db, 'artifacts', appId, 'public', 'data', 'clients', targetId)); await loadClients(); } } catch (e) { console.error(e); // ... existing code ... onMounted(() => { initAuth().then(() => { onAuthStateChanged(auth, async (user) => { if (!user) { safeRedirect('/login'); return; } currentUser.value = user; currentUserEmail.value = user.email || 'Дизайнер (Превью)'; try { const userDoc = await getDoc(doc(db, 'artifacts', appId, 'public', 'data', 'users', user.uid)); let role = 'designer'; if (!userDoc.exists()) { if (user.isAnonymous) { await setDoc(doc(db, 'artifacts', appId, 'public', 'data', 'users', user.uid), { email: 'preview@designer.com', name: 'Дизайнер (Превью)', role: 'designer', status: 'active', createdAt: serverTimestamp() }); } else { safeRedirect('/login'); return; } } else { role = userDoc.data().role || 'client'; } localStorage.setItem('userRole', role); if (role !== 'designer') { // ... existing code ...