No title

 <!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>Admin Panel | Mubarik Osman</title>

    <script src="https://cdn.tailwindcss.com"></script>

    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">

    

    <script>

        tailwind.config = {

            darkMode: 'class',

            theme: {

                extend: { colors: { brand: { accent: '#4f46e5', dark: '#0f172a' } } }

            }

        }

    </script>

</head>

<body class="bg-gray-100 text-slate-800 font-sans antialiased">


    <div id="login-screen" class="fixed inset-0 z-50 flex items-center justify-center bg-gray-900 transition-opacity duration-500">

        <div class="bg-white p-8 rounded-2xl shadow-2xl w-full max-w-md">

            <div class="text-center mb-8">

                <h1 class="text-3xl font-black text-gray-800">MUBARIK<span class="text-brand-accent">.</span></h1>

                <p class="text-gray-500 text-sm mt-2">Admin Dashboard Login</p>

            </div>

            <form id="login-form" class="space-y-4">

                <div>

                    <label class="block text-sm font-bold mb-2">Email</label>

                    <input type="email" id="login-email" class="w-full px-4 py-3 rounded-lg border border-gray-300 focus:border-brand-accent focus:outline-none" placeholder="admin@example.com" required>

                </div>

                <div>

                    <label class="block text-sm font-bold mb-2">Password</label>

                    <input type="password" id="login-password" class="w-full px-4 py-3 rounded-lg border border-gray-300 focus:border-brand-accent focus:outline-none" placeholder="••••••••" required>

                </div>

                <button type="submit" class="w-full bg-brand-accent text-white py-3 rounded-lg font-bold hover:bg-indigo-700 transition-colors shadow-lg">

                    <i class="fa-solid fa-lock mr-2"></i> Access Dashboard

                </button>

            </form>

            <p id="login-error" class="text-red-500 text-sm text-center mt-4 hidden"></p>

        </div>

    </div>


    <div id="dashboard-screen" class="hidden flex h-screen overflow-hidden">

        

        <aside class="w-64 bg-brand-dark text-white flex flex-col shadow-xl z-20">

            <div class="h-20 flex items-center justify-center border-b border-gray-800">

                <h2 class="text-2xl font-bold tracking-tighter">ADMIN<span class="text-brand-accent">.</span></h2>

            </div>

            <nav class="flex-1 overflow-y-auto py-4">

                <ul class="space-y-1 px-2">

                    <li><button onclick="switchTab('projects')" class="nav-btn w-full text-left px-4 py-3 rounded-lg hover:bg-gray-800 transition-colors flex items-center gap-3"><i class="fa-solid fa-briefcase w-5"></i> Projects</button></li>

                    <li><button onclick="switchTab('services')" class="nav-btn w-full text-left px-4 py-3 rounded-lg hover:bg-gray-800 transition-colors flex items-center gap-3"><i class="fa-solid fa-layer-group w-5"></i> Services</button></li>

                    <li><button onclick="switchTab('skills')" class="nav-btn w-full text-left px-4 py-3 rounded-lg hover:bg-gray-800 transition-colors flex items-center gap-3"><i class="fa-solid fa-bolt w-5"></i> Skills</button></li>

                    <li><button onclick="switchTab('experience')" class="nav-btn w-full text-left px-4 py-3 rounded-lg hover:bg-gray-800 transition-colors flex items-center gap-3"><i class="fa-solid fa-road w-5"></i> Journey</button></li>

                    <li><button onclick="switchTab('certificates')" class="nav-btn w-full text-left px-4 py-3 rounded-lg hover:bg-gray-800 transition-colors flex items-center gap-3"><i class="fa-solid fa-certificate w-5"></i> Certificates</button></li>

                    <li><button onclick="switchTab('stats')" class="nav-btn w-full text-left px-4 py-3 rounded-lg hover:bg-gray-800 transition-colors flex items-center gap-3"><i class="fa-solid fa-chart-simple w-5"></i> Stats</button></li>

                    <li><button onclick="switchTab('socials')" class="nav-btn w-full text-left px-4 py-3 rounded-lg hover:bg-gray-800 transition-colors flex items-center gap-3"><i class="fa-solid fa-share-nodes w-5"></i> Socials</button></li>

                    <li class="pt-4 mt-4 border-t border-gray-800">

                        <button onclick="switchTab('messages')" class="nav-btn w-full text-left px-4 py-3 rounded-lg hover:bg-gray-800 text-yellow-400 transition-colors flex items-center gap-3"><i class="fa-solid fa-envelope w-5"></i> Messages</button>

                    </li>

                </ul>

            </nav>

            <div class="p-4 border-t border-gray-800">

                <button id="logout-btn" class="w-full bg-red-600 hover:bg-red-700 text-white py-2 rounded-lg font-bold text-sm transition-colors">Logout</button>

            </div>

        </aside>


        <main class="flex-1 overflow-y-auto bg-gray-100 p-8 relative">

            

            <div id="tab-projects" class="tab-content hidden">

                <div class="flex justify-between items-center mb-8">

                    <h2 class="text-3xl font-bold text-gray-800">Manage Projects</h2>

                </div>

                

                <div class="bg-white p-6 rounded-xl shadow-sm mb-8 border border-gray-200">

                    <h3 class="font-bold text-lg mb-4 text-brand-accent">Add New Project</h3>

                    <form onsubmit="handleCreate(event, 'projects')" class="grid grid-cols-1 md:grid-cols-2 gap-4">

                        <input type="text" name="title" placeholder="Project Title (e.g., HantiKaab)" class="input-std" required>

                        <input type="text" name="type" placeholder="Type (e.g., SaaS, Mobile App)" class="input-std" required>

                        <input type="text" name="img" placeholder="Image URL (https://...)" class="input-std" required>

                        <input type="text" name="desc" placeholder="Short Description" class="input-std md:col-span-2" required>

                        <button type="submit" class="btn-primary md:col-span-2">Add Project</button>

                    </form>

                </div>


                <div id="list-projects" class="grid grid-cols-1 md:grid-cols-2 gap-6"></div>

            </div>


            <div id="tab-skills" class="tab-content hidden">

                <h2 class="text-3xl font-bold text-gray-800 mb-8">Manage Skills</h2>

                <div class="bg-white p-6 rounded-xl shadow-sm mb-8 border border-gray-200">

                    <h3 class="font-bold text-lg mb-4 text-brand-accent">Add New Skill</h3>

                    <form onsubmit="handleCreate(event, 'skills')" class="grid grid-cols-1 md:grid-cols-3 gap-4">

                        <input type="text" name="name" placeholder="Skill Name (e.g. React)" class="input-std" required>

                        <select name="cat" class="input-std" required>

                            <option value="frontend">Frontend</option>

                            <option value="backend">Backend</option>

                            <option value="design">Design</option>

                            <option value="soft">Soft Skill</option>

                        </select>

                        <input type="text" name="icon" placeholder="FontAwesome Class (e.g. fa-brands fa-react)" class="input-std" required>

                        <button type="submit" class="btn-primary md:col-span-3">Add Skill</button>

                    </form>

                </div>

                <div id="list-skills" class="flex flex-wrap gap-3"></div>

            </div>


            <div id="tab-services" class="tab-content hidden">

                <h2 class="text-3xl font-bold text-gray-800 mb-8">Manage Services</h2>

                <div class="bg-white p-6 rounded-xl shadow-sm mb-8 border border-gray-200">

                    <h3 class="font-bold text-lg mb-4 text-brand-accent">Add Service</h3>

                    <form onsubmit="handleCreate(event, 'services')" class="grid grid-cols-1 md:grid-cols-2 gap-4">

                        <input type="text" name="title" placeholder="Service Title" class="input-std" required>

                        <input type="text" name="icon" placeholder="Icon (fa-solid fa-code)" class="input-std" required>

                        <input type="text" name="desc" placeholder="Description" class="input-std md:col-span-2" required>

                        <button type="submit" class="btn-primary md:col-span-2">Add Service</button>

                    </form>

                </div>

                <div id="list-services" class="grid grid-cols-1 md:grid-cols-2 gap-6"></div>

            </div>


            <div id="tab-experience" class="tab-content hidden">

                <h2 class="text-3xl font-bold text-gray-800 mb-8">Manage Journey</h2>

                <div class="bg-white p-6 rounded-xl shadow-sm mb-8 border border-gray-200">

                    <h3 class="font-bold text-lg mb-4 text-brand-accent">Add Experience</h3>

                    <form onsubmit="handleCreate(event, 'experience')" class="grid grid-cols-1 md:grid-cols-2 gap-4">

                        <input type="text" name="year" placeholder="Year Range (e.g. 2023 - Present)" class="input-std" required>

                        <input type="text" name="title" placeholder="Job Title" class="input-std" required>

                        <input type="text" name="company" placeholder="Company Name" class="input-std" required>

                        <input type="text" name="desc" placeholder="Description" class="input-std md:col-span-2" required>

                        <button type="submit" class="btn-primary md:col-span-2">Add Entry</button>

                    </form>

                </div>

                <div id="list-experience" class="space-y-4"></div>

            </div>


            <div id="tab-messages" class="tab-content hidden">

                <h2 class="text-3xl font-bold text-gray-800 mb-8">Client Messages</h2>

                <div id="list-messages" class="space-y-4">

                    <p class="text-gray-500">Loading messages...</p>

                </div>

            </div>


            <div id="tab-stats" class="tab-content hidden">

                <h2 class="text-3xl font-bold text-gray-800 mb-8">Manage Stats</h2>

                <div class="bg-white p-6 rounded-xl shadow-sm mb-8 border border-gray-200">

                    <h3 class="font-bold text-lg mb-4 text-brand-accent">Add Stat</h3>

                    <form onsubmit="handleCreate(event, 'stats')" class="grid grid-cols-1 md:grid-cols-3 gap-4">

                        <input type="number" name="count" placeholder="Number (e.g. 100)" class="input-std" required>

                        <input type="text" name="label" placeholder="Label (e.g. Projects)" class="input-std" required>

                        <input type="text" name="suffix" placeholder="Suffix (e.g. + or %)" class="input-std">

                        <button type="submit" class="btn-primary md:col-span-3">Add Stat</button>

                    </form>

                </div>

                <div id="list-stats" class="grid grid-cols-2 md:grid-cols-4 gap-4"></div>

            </div>


            <div id="tab-certificates" class="tab-content hidden">

                <h2 class="text-3xl font-bold text-gray-800 mb-8">Manage Certificates</h2>

                <div class="bg-white p-6 rounded-xl shadow-sm mb-8 border border-gray-200">

                    <h3 class="font-bold text-lg mb-4 text-brand-accent">Add Certificate</h3>

                    <form onsubmit="handleCreate(event, 'certificates')" class="grid grid-cols-1 md:grid-cols-2 gap-4">

                        <input type="text" name="title" placeholder="Cert Title" class="input-std" required>

                        <input type="text" name="img" placeholder="Image URL" class="input-std" required>

                        <input type="text" name="desc" placeholder="Description" class="input-std md:col-span-2" required>

                        <button type="submit" class="btn-primary md:col-span-2">Add Certificate</button>

                    </form>

                </div>

                <div id="list-certificates" class="grid grid-cols-1 md:grid-cols-2 gap-6"></div>

            </div>


            <div id="tab-socials" class="tab-content hidden">

                <h2 class="text-3xl font-bold text-gray-800 mb-8">Manage Socials</h2>

                <div class="bg-white p-6 rounded-xl shadow-sm mb-8 border border-gray-200">

                    <h3 class="font-bold text-lg mb-4 text-brand-accent">Add Social Link</h3>

                    <form onsubmit="handleCreate(event, 'socials')" class="grid grid-cols-1 md:grid-cols-3 gap-4">

                        <input type="text" name="name" placeholder="Name (e.g. GitHub)" class="input-std" required>

                        <input type="text" name="url" placeholder="URL link" class="input-std" required>

                        <input type="text" name="icon" placeholder="FontAwesome Icon" class="input-std" required>

                        <button type="submit" class="btn-primary md:col-span-3">Add Link</button>

                    </form>

                </div>

                <div id="list-socials" class="grid grid-cols-2 md:grid-cols-4 gap-4"></div>

            </div>


        </main>

    </div>


    <style>

        .input-std { @apply w-full px-4 py-3 rounded-lg border border-gray-200 focus:border-brand-accent focus:outline-none focus:ring-1 focus:ring-brand-accent text-sm; }

        .btn-primary { @apply w-full bg-brand-accent text-white py-3 rounded-lg font-bold hover:bg-indigo-700 transition-colors shadow-md; }

        .btn-delete { @apply text-red-500 hover:text-red-700 text-sm font-bold ml-auto; }

    </style>


    <script type="module">

        import { initializeApp } from "https://www.gstatic.com/firebasejs/9.6.1/firebase-app.js";

        import { getAuth, signInWithEmailAndPassword, onAuthStateChanged, signOut } from "https://www.gstatic.com/firebasejs/9.6.1/firebase-auth.js";

        import { getFirestore, collection, addDoc, getDocs, deleteDoc, doc, query, orderBy, onSnapshot } from "https://www.gstatic.com/firebasejs/9.6.1/firebase-firestore.js";


        // --- 1. CONFIG (Same as Index) ---

        const firebaseConfig = {

            apiKey: "AIzaSyC7dQr5Ub5LP-UUq30N6Sn7X1JB_AZFLcQ",

            authDomain: "portfalio1.firebaseapp.com",

            projectId: "portfalio1",

            storageBucket: "portfalio1.firebasestorage.app",

            messagingSenderId: "806539469974",

            appId: "1:806539469974:web:368f1711bdd2d09a5f8eb7",

            measurementId: "G-CGFDMTH1N8"

        };


        const app = initializeApp(firebaseConfig);

        const auth = getAuth(app);

        const db = getFirestore(app);


        // --- 2. AUTHENTICATION LOGIC ---

        const loginScreen = document.getElementById('login-screen');

        const dashboardScreen = document.getElementById('dashboard-screen');

        const loginForm = document.getElementById('login-form');

        const logoutBtn = document.getElementById('logout-btn');


        onAuthStateChanged(auth, (user) => {

            if (user) {

                loginScreen.classList.add('hidden');

                dashboardScreen.classList.remove('hidden');

                // Load default tab

                switchTab('projects');

            } else {

                loginScreen.classList.remove('hidden');

                dashboardScreen.classList.add('hidden');

            }

        });


        loginForm.addEventListener('submit', (e) => {

            e.preventDefault();

            const email = document.getElementById('login-email').value;

            const password = document.getElementById('login-password').value;

            const errorMsg = document.getElementById('login-error');

            

            signInWithEmailAndPassword(auth, email, password)

                .catch((error) => {

                    errorMsg.textContent = "Login Failed: " + error.message;

                    errorMsg.classList.remove('hidden');

                });

        });


        logoutBtn.addEventListener('click', () => signOut(auth));


        // --- 3. UI NAVIGATION ---

        window.switchTab = (tabName) => {

            // Hide all tabs

            document.querySelectorAll('.tab-content').forEach(el => el.classList.add('hidden'));

            // Show selected

            document.getElementById(`tab-${tabName}`).classList.remove('hidden');

            

            // Highlight sidebar

            document.querySelectorAll('.nav-btn').forEach(btn => btn.classList.remove('bg-gray-800', 'border-l-4', 'border-brand-accent'));

            // (Simple highlighting logic omitted for brevity, functionality works)

            

            // Fetch data for this tab

            loadCollectionData(tabName);

        }


        // --- 4. DATA HANDLING (CRUD) ---


        // Generic Create

        window.handleCreate = async (e, collectionName) => {

            e.preventDefault();

            const btn = e.target.querySelector('button');

            const originalText = btn.innerText;

            btn.innerText = "Saving...";

            btn.disabled = true;


            const formData = new FormData(e.target);

            const data = Object.fromEntries(formData.entries());

            

            // Add default color for services if missing

            if(collectionName === 'services') {

                data.from = '#4f46e5'; 

                data.to = '#8b5cf6';

            }

            // Add Date for messages sorting

            if(collectionName === 'messages') data.timestamp = new Date();


            try {

                await addDoc(collection(db, collectionName), data);

                e.target.reset();

                alert("Item added successfully!");

                // No need to reload, real-time listener will handle it? 

                // Or just manual reload for simplicity in admin:

                loadCollectionData(collectionName); 

            } catch (error) {

                alert("Error: " + error.message);

            } finally {

                btn.innerText = originalText;

                btn.disabled = false;

            }

        };


        // Generic Delete

        window.deleteItem = async (collectionName, id) => {

            if(confirm("Are you sure you want to delete this item? This updates the live site.")) {

                try {

                    await deleteDoc(doc(db, collectionName, id));

                    loadCollectionData(collectionName);

                } catch(e) {

                    alert("Delete failed: " + e.message);

                }

            }

        }


        // --- 5. RENDER LOGIC PER COLLECTION ---

        async function loadCollectionData(colName) {

            const container = document.getElementById(`list-${colName}`);

            container.innerHTML = '<div class="w-full text-center py-10"><i class="fa-solid fa-spinner fa-spin text-2xl text-brand-accent"></i></div>';


            let q = collection(db, colName);

            // Sort messages by date

            if(colName === 'messages') q = query(collection(db, colName), orderBy('timestamp', 'desc'));


            try {

                const querySnapshot = await getDocs(q);

                container.innerHTML = ''; // Clear loader


                if (querySnapshot.empty) {

                    container.innerHTML = '<p class="text-gray-400 italic col-span-full">No items found in database.</p>';

                    return;

                }


                querySnapshot.forEach((doc) => {

                    const data = doc.data();

                    const id = doc.id;

                    const html = generateCardHTML(colName, data, id);

                    container.insertAdjacentHTML('beforeend', html);

                });

            } catch (e) {

                container.innerHTML = `<p class="text-red-500">Error loading data: ${e.message}</p>`;

            }

        }


        function generateCardHTML(type, data, id) {

            // Helper for Delete Button

            const delBtn = `<button onclick="deleteItem('${type}', '${id}')" class="absolute top-2 right-2 bg-red-100 text-red-600 p-2 rounded-full hover:bg-red-200 transition-colors shadow-sm"><i class="fa-solid fa-trash"></i></button>`;


            if (type === 'projects') {

                return `

                    <div class="bg-white rounded-xl shadow-sm border border-gray-200 overflow-hidden relative group">

                        ${delBtn}

                        <div class="h-32 bg-gray-100 overflow-hidden">

                            <img src="${data.img || data.image}" class="w-full h-full object-cover">

                        </div>

                        <div class="p-4">

                            <span class="text-xs font-bold text-brand-accent uppercase">${data.type}</span>

                            <h4 class="font-bold text-lg">${data.title}</h4>

                            <p class="text-xs text-gray-500 mt-1 line-clamp-2">${data.desc}</p>

                        </div>

                    </div>`;

            }

            

            if (type === 'skills') {

                return `

                    <div class="bg-white px-4 py-2 rounded-lg border border-gray-200 shadow-sm flex items-center gap-3 relative pr-10">

                        <i class="${data.icon} text-brand-accent"></i>

                        <div>

                            <p class="font-bold text-sm">${data.name}</p>

                            <p class="text-[10px] text-gray-400 uppercase">${data.cat}</p>

                        </div>

                        <button onclick="deleteItem('${type}', '${id}')" class="text-red-400 hover:text-red-600 absolute right-3"><i class="fa-solid fa-times"></i></button>

                    </div>`;

            }


            if (type === 'services') {

                return `

                    <div class="bg-white p-4 rounded-xl border border-gray-200 relative">

                        ${delBtn}

                        <div class="flex items-center gap-3 mb-2">

                            <div class="w-8 h-8 rounded bg-indigo-50 flex items-center justify-center text-brand-accent"><i class="${data.icon}"></i></div>

                            <h4 class="font-bold">${data.title}</h4>

                        </div>

                        <p class="text-xs text-gray-500">${data.desc}</p>

                    </div>`;

            }


            if (type === 'experience') {

                return `

                    <div class="bg-white p-4 rounded-xl border border-gray-200 relative flex gap-4 items-start">

                        <div class="flex-1">

                            <span class="text-xs font-bold bg-gray-100 px-2 py-1 rounded text-gray-600">${data.year}</span>

                            <h4 class="font-bold mt-1">${data.title}</h4>

                            <p class="text-sm text-brand-accent">${data.company}</p>

                        </div>

                        <button onclick="deleteItem('${type}', '${id}')" class="text-red-400 hover:text-red-600"><i class="fa-solid fa-trash"></i></button>

                    </div>`;

            }


            if (type === 'messages') {

                const date = data.timestamp ? new Date(data.timestamp.seconds * 1000).toLocaleDateString() : 'N/A';

                return `

                    <div class="bg-white p-4 rounded-xl border border-l-4 border-l-brand-accent border-gray-200 relative">

                        <div class="flex justify-between items-start mb-2">

                            <div>

                                <h4 class="font-bold text-gray-800">${data.name}</h4>

                                <a href="mailto:${data.email}" class="text-sm text-brand-accent hover:underline">${data.email}</a>

                            </div>

                            <span class="text-xs text-gray-400">${date}</span>

                        </div>

                        <p class="text-sm text-gray-600 bg-gray-50 p-3 rounded italic">"${data.message}"</p>

                        <div class="mt-2 text-right">

                             <button onclick="deleteItem('${type}', '${id}')" class="text-xs text-red-400 hover:text-red-600">Delete Message</button>

                        </div>

                    </div>`;

            }


            if (type === 'stats') {

                return `

                    <div class="bg-white p-4 rounded-xl border border-gray-200 text-center relative group">

                        ${delBtn}

                        <h3 class="text-2xl font-black text-brand-accent">${data.count}${data.suffix || ''}</h3>

                        <p class="text-xs font-bold uppercase text-gray-500">${data.label}</p>

                    </div>`;

            }


            if (type === 'certificates') {

                return `

                    <div class="bg-white p-4 rounded-xl border border-gray-200 relative group flex gap-3 items-center">

                        <img src="${data.img}" class="w-12 h-12 rounded object-cover">

                        <div class="flex-1">

                            <h4 class="font-bold text-sm">${data.title}</h4>

                            <p class="text-xs text-gray-500 truncate w-32">${data.desc}</p>

                        </div>

                        <button onclick="deleteItem('${type}', '${id}')" class="text-red-400 hover:text-red-600"><i class="fa-solid fa-trash"></i></button>

                    </div>`;

            }


            if (type === 'socials') {

                return `

                    <div class="bg-white p-3 rounded-lg border border-gray-200 flex items-center justify-between">

                        <div class="flex items-center gap-2">

                            <i class="${data.icon} text-gray-600"></i>

                            <span class="font-bold text-sm">${data.name}</span>

                        </div>

                        <button onclick="deleteItem('${type}', '${id}')" class="text-red-400 hover:text-red-600"><i class="fa-solid fa-times"></i></button>

                    </div>`;

            }


            return '';

        }


    </script>

</body>

</html>

Previous Post Next Post