import React, { useState, useEffect, useMemo } from 'react';
import { initializeApp } from 'firebase/app';
import {
getAuth,
signInWithEmailAndPassword,
createUserWithEmailAndPassword,
signOut,
updateProfile,
onAuthStateChanged
} from 'firebase/auth';
import {
getFirestore,
collection,
addDoc,
query,
where,
onSnapshot,
doc,
updateDoc,
deleteDoc,
orderBy,
serverTimestamp,
getDocs
} from 'firebase/firestore';
import {
LayoutDashboard,
Calculator,
ClipboardList,
Users,
Settings,
LogOut,
Building2,
Menu,
X,
FileText,
CheckCircle,
AlertCircle,
Truck,
Hammer,
Save,
Download,
Share2
} from 'lucide-react';
// --- FIREBASE KURULUMU (Global Değişkenler) ---
const firebaseConfig = JSON.parse(__firebase_config);
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
const db = getFirestore(app);
// --- YARDIMCI FONKSİYONLAR ---
const turkceKarakterCevir = (text) => {
if (!text) return "";
const mapping = {
'ç': 'c', 'Ç': 'C', 'ğ': 'g', 'Ğ': 'G', 'ı': 'i', 'I': 'I',
'İ': 'I', 'ö': 'o', 'Ö': 'O', 'ş': 's', 'Ş': 'S', 'ü': 'u', 'Ü': 'U'
};
return text.split('').map(char => mapping[char] || char).join('');
};
// --- BİLEŞENLER ---
// 1. GİRİŞ VE KAYIT EKRANI (SAAS KURULUMU)
const AuthScreen = ({ onLogin }) => {
const [isRegistering, setIsRegistering] = useState(false);
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [companyName, setCompanyName] = useState(''); // SaaS Şirket Adı
const [licenseKey, setLicenseKey] = useState(''); // SaaS Lisans Anahtarı
const [error, setError] = useState('');
const [loading, setLoading] = useState(false);
const handleAuth = async (e) => {
e.preventDefault();
setLoading(true);
setError('');
try {
if (isRegistering) {
// Yeni Şirket Kaydı (SaaS Mantığı)
const userCredential = await createUserWithEmailAndPassword(auth, email, password);
const user = userCredential.user;
// Şirket Bilgilerini Kaydet
await addDoc(collection(db, 'companies'), {
name: companyName,
licenseKey: licenseKey,
ownerId: user.uid,
createdAt: serverTimestamp()
});
// Kullanıcı Profilini Oluştur
await addDoc(collection(db, 'users'), {
uid: user.uid,
email: user.email,
companyName: companyName,
role: 'admin', // İlk kullanıcı her zaman admindir
department: 'Yönetim',
createdAt: serverTimestamp()
});
await updateProfile(user, { displayName: companyName });
} else {
// Giriş Yap
await signInWithEmailAndPassword(auth, email, password);
}
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
return (
{/* Sol Taraf - Görsel/Marka */}
ASANSÖR SMHM
Süspansiyon Üretim & Yönetim Sistemi
Gelişmiş Ölçü Hesaplama
Üretim Takip Modülü
Bulut Tabanlı Arşiv
{/* Sağ Taraf - Form */}
{isRegistering ? 'Sistemi Kur & Şirketini Kaydet' : 'Yönetim Paneli Giriş'}
{isRegistering ? 'Firmanız için yeni bir veritabanı oluşturun.' : 'Hesabınıza erişmek için bilgilerinizi girin.'}
{error &&
}
);
};
// 2. HESAPLAMA MODÜLÜ (SMHM CORE)
const CalculationModule = ({ user, userData }) => {
const [refName, setRefName] = useState('');
const [elevatorCount, setElevatorCount] = useState(1);
const [dbg, setDbg] = useState('');
const [parca, setParca] = useState('');
const [profil, setProfil] = useState('');
const [lastResult, setLastResult] = useState(null);
const [saving, setSaving] = useState(false);
// Senkronizasyon Mantığı
const handleSync = (source, value) => {
const val = parseFloat(value);
if (isNaN(val)) return;
if (source === 'dbg') {
setDbg(value);
setParca((val - 8).toFixed(2));
setProfil((val - 13).toFixed(2));
} else if (source === 'parca') {
setParca(value);
setDbg((val + 8).toFixed(2));
setProfil((val - 5).toFixed(2));
} else if (source === 'profil') {
setProfil(value);
setDbg((val + 13).toFixed(2));
setParca((val + 5).toFixed(2));
}
};
const calculateAndSave = async () => {
if(!refName || !dbg) {
alert("Lütfen Proje Adı ve DBG değerini giriniz.");
return;
}
const resultData = {
projectRef: refName,
count: parseInt(elevatorCount),
dbg: dbg,
parca: parca,
profil: profil,
date: new Date().toLocaleDateString('tr-TR'),
createdBy: user.uid,
companyName: userData?.companyName,
status: 'Beklemede' // Hesaplandı, Üretimde, Tamamlandı
};
setLastResult(resultData);
setSaving(true);
try {
// Projeler tablosuna kaydet
await addDoc(collection(db, 'projects'), {
...resultData,
timestamp: serverTimestamp()
});
// Otomatik olarak bir üretim görevi oluştur
await addDoc(collection(db, 'tasks'), {
title: `${refName} - Süspansiyon Kesimi`,
description: `${elevatorCount} Adet. DBG: ${dbg}, Parça: ${parca}, Profil: ${profil}`,
department: 'Kesimhane',
status: 'Yapılacak',
assignedTo: 'Havuz',
projectId: refName,
companyName: userData?.companyName,
timestamp: serverTimestamp()
});
alert("Hesaplama kaydedildi ve Kesimhane'ye iş emri gönderildi.");
} catch (error) {
console.error("Hata:", error);
alert("Kaydedilirken hata oluştu.");
} finally {
setSaving(false);
}
};
const downloadPDF = () => {
if (!lastResult) return;
// window.jspdf kontrolü
if (typeof window.jspdf === 'undefined') {
alert("PDF kütüphanesi henüz yüklenmedi. Lütfen sayfayı yenileyip tekrar deneyin.");
return;
}
const { jsPDF } = window.jspdf;
const doc = new jsPDF();
const trRef = turkceKarakterCevir(lastResult.projectRef).toUpperCase();
doc.setFont("times", "bold");
doc.setFontSize(18);
doc.text("URETIM RAPORU", 105, 20, { align: "center" });
doc.setFontSize(12);
doc.setFont("times", "normal");
doc.text(`PROJE: ${trRef}`, 14, 40);
doc.text(`ADET: ${lastResult.count}`, 14, 48);
doc.text(`TARIH: ${lastResult.date}`, 14, 56);
const tableData = [
["Ray Arasi (DBG)", `${lastResult.dbg} cm`, "-"],
["Parca Uzunlugu", `${lastResult.parca} cm`, `${(lastResult.parca * lastResult.count).toFixed(2)} cm`],
["Profil Uzunlugu", `${lastResult.profil} cm`, `${(lastResult.profil * lastResult.count).toFixed(2)} cm`]
];
doc.autoTable({
head: [["MALZEME", "BIRIM OLCU", `TOPLAM (x${lastResult.count})`]],
body: tableData,
startY: 65,
});
doc.save(`${trRef}_RAPOR.pdf`);
};
return (
Yeni Hesaplama & İş Emri
{/* Üst Bilgiler */}
{/* Hesaplama Alanı */}
Ölçü Girişi (Otomatik Senkronize)
{/* Aksiyonlar */}
{lastResult && (
)}
);
};
// 3. İŞ/GÖREV YÖNETİMİ (KANBAN STYLE)
const TaskManager = ({ userData }) => {
const [tasks, setTasks] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
if (!userData?.companyName) return;
const q = query(
collection(db, 'tasks'),
where('companyName', '==', userData.companyName),
orderBy('timestamp', 'desc')
);
const unsubscribe = onSnapshot(q, (snapshot) => {
const taskList = snapshot.docs.map(doc => ({id: doc.id, ...doc.data()}));
setTasks(taskList);
setLoading(false);
});
return () => unsubscribe();
}, [userData]);
const updateStatus = async (taskId, newStatus) => {
const taskRef = doc(db, 'tasks', taskId);
await updateDoc(taskRef, { status: newStatus });
};
const StatusColumn = ({ title, status, icon: Icon, color }) => (
{title}
{tasks.filter(t => t.status === status).length}
{tasks.filter(t => t.status === status).map(task => (
{task.department}
{new Date(task.timestamp?.seconds * 1000).toLocaleDateString('tr-TR')}
{task.title}
{task.description}
{status !== 'Yapılacak' && (
)}
{status !== 'İşlemde' && (
)}
{status !== 'Tamamlandı' && (
)}
))}
{tasks.filter(t => t.status === status).length === 0 && (
Görev bulunmuyor
)}
);
return (
Üretim Bant Takibi
Kesimhane
Montaj
Sevkiyat
);
};
// 4. DASHBOARD (ANA EKRAN)
const Dashboard = ({ userData }) => {
const [stats, setStats] = useState({ total: 0, pending: 0, completed: 0 });
useEffect(() => {
if(!userData?.companyName) return;
const q = query(collection(db, 'tasks'), where('companyName', '==', userData.companyName));
const unsubscribe = onSnapshot(q, (snapshot) => {
const all = snapshot.docs.map(d => d.data());
setStats({
total: all.length,
pending: all.filter(t => t.status === 'Yapılacak').length,
completed: all.filter(t => t.status === 'Tamamlandı').length
});
});
return () => unsubscribe();
}, [userData]);
return (
Genel Bakış
{/* Kartlar */}
Toplam Proje
{stats.total}
Bekleyen İş
{stats.pending}
Tamamlanan
{stats.completed}
Firma
{userData?.companyName || 'Yükleniyor'}
{userData?.role}
{/* Hızlı İşlem Menüsü */}
Yeni Hesaplama Başlat
Süspansiyon ölçülerini girin ve iş emri oluşturun.
Sevkiyat Listeleri
Hazır paketler için malzeme listesi oluşturun.
);
};
// --- ANA UYGULAMA (APP) ---
export default function App() {
const [user, setUser] = useState(null);
const [userData, setUserData] = useState(null);
const [activeTab, setActiveTab] = useState('dashboard');
const [loading, setLoading] = useState(true);
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
// Load PDF libraries via CDN
useEffect(() => {
const loadScript = (src) => {
return new Promise((resolve, reject) => {
if (document.querySelector(`script[src="${src}"]`)) {
resolve();
return;
}
const script = document.createElement('script');
script.src = src;
script.async = true;
script.onload = resolve;
script.onerror = reject;
document.head.appendChild(script);
});
};
Promise.all([
loadScript("https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"),
loadScript("https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.5.28/jspdf.plugin.autotable.min.js")
]).then(() => {
console.log("PDF Libraries loaded");
}).catch(err => console.error("Failed to load PDF libs", err));
}, []);
useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, async (currentUser) => {
setUser(currentUser);
if (currentUser) {
// Kullanıcı verisini çek (Role, Company Name vb.)
const q = query(collection(db, 'users'), where('uid', '==', currentUser.uid));
const querySnapshot = await getDocs(q);
if(!querySnapshot.empty){
setUserData(querySnapshot.docs[0].data());
}
} else {
setUserData(null);
}
setLoading(false);
});
return () => unsubscribe();
}, []);
const handleSignOut = async () => {
await signOut(auth);
};
if (loading) return ;
if (!user) {
return ;
}
// --- LAYOUT ---
return (
{/* Sidebar - Desktop */}
{/* Main Content */}
{/* Mobile Header */}
ELEVATOR OS
{/* Mobile Menu Overlay */}
{isMobileMenuOpen && (
)}
{/* Dynamic View Area */}
{activeTab === 'dashboard' &&
}
{activeTab === 'calculate' &&
}
{activeTab === 'tasks' &&
}
{activeTab === 'team' && (
Personel Yönetimi
Bu modül Demo sürümünde aktif değildir.
)}
);
}