// ... 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 ...