BFLKUTUPHANE / index.html
Alirelian's picture
Add 2 files
e560316 verified
Raw
History Blame Contribute Delete
81.6 kB
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bartın Fen Lisesi Kütüphane Takip Sistemi</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">
<!-- Firebase SDK -->
<script src="https://www.gstatic.com/firebasejs/9.6.0/firebase-app-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/9.6.0/firebase-firestore-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/9.6.0/firebase-auth-compat.js"></script>
<style>
body {
background-color: #f5f0e6;
background-image: url('https://cdn.discordapp.com/attachments/1205496867694190604/1371135928302702702/k_31095013_okul_rsm_2.jpg?ex=68220957&is=6820b7d7&hm=7b8f37259e98230e49e4a46f993a8126d9aef68d43fd71457f9e1b302773532e&');
background-size: cover;
background-position: center;
background-attachment: fixed;
background-blend-mode: overlay;
background-color: rgba(245, 240, 230, 0.7);
}
.content-bg {
background-color: rgba(245, 240, 230, 0.9);
}
.card-bg {
background-color: #ede3d3;
}
.button-primary {
background-color: #8b6b61;
color: white;
}
.button-primary:hover {
background-color: #6d4c41;
}
.button-secondary {
background-color: #d6c7b0;
color: #3e2723;
}
.button-secondary:hover {
background-color: #bca892;
}
.nav-item.active {
border-bottom: 3px solid #8b6b61;
color: #5d4037;
}
.header-bg {
background-color: #5d4037;
color: white;
}
.footer-bg {
background-color: #3e2723;
color: white;
}
[x-cloak] { display: none !important; }
.security-warning {
position: fixed;
top: 0;
left: 0;
right: 0;
background-color: #d32f2f;
color: white;
text-align: center;
padding: 10px;
font-weight: bold;
z-index: 1000;
display: none;
}
.loading-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(255, 255, 255, 0.8);
display: flex;
justify-content: center;
align-items: center;
z-index: 2000;
}
.spinner {
border: 4px solid rgba(0, 0, 0, 0.1);
width: 36px;
height: 36px;
border-radius: 50%;
border-left-color: #8b6b61;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
</head>
<body class="font-sans" x-data="libraryApp()" x-cloak>
<!-- Loading Overlay -->
<div class="loading-overlay" x-show="isLoading">
<div class="spinner"></div>
</div>
<!-- Security Warning -->
<div class="security-warning" id="securityWarning">
<i class="fas fa-exclamation-triangle mr-2"></i>
UYARI: Bu sistem sadece yetkili personel içindir. Yetkisiz erişim yasaktır!
</div>
<!-- Header -->
<header class="header-bg">
<div class="container mx-auto px-4 py-4">
<div class="flex flex-col md:flex-row justify-between items-center">
<div class="flex items-center mb-4 md:mb-0">
<a href="#" @click.prevent="activeTab = 'catalog'" class="flex items-center">
<img src="https://cdn.discordapp.com/attachments/1205496867694190604/1371135714212839424/OKULOGOSU.png?ex=68220924&is=6820b7a4&hm=b1f6c1ba3afd33c1cf6d7b19bdb8c3a1e2d9a5f84e77ecb99d4dd5e71f277f68&"
alt="Bartın Fen Lisesi Logo"
class="h-16 mr-4">
<div>
<h1 class="text-2xl md:text-3xl font-bold">Bartın Fen Lisesi</h1>
<p class="opacity-90">Kütüphane Takip Sistemi</p>
</div>
</a>
</div>
<div class="flex flex-wrap justify-center gap-2">
<button @click="activeTab = 'catalog'" class="nav-item px-4 py-2 font-medium" :class="{'active': activeTab === 'catalog'}">
<i class="fas fa-book mr-2"></i>Kitap Kataloğu
</button>
<button @click="activeTab = 'borrow'" class="nav-item px-4 py-2 font-medium" :class="{'active': activeTab === 'borrow'}">
<i class="fas fa-hand-holding mr-2"></i>Ödünç Al
</button>
<button @click="activeTab = 'return'" class="nav-item px-4 py-2 font-medium" :class="{'active': activeTab === 'return'}">
<i class="fas fa-undo mr-2"></i>İade Et
</button>
<button @click="activeTab = 'history'" class="nav-item px-4 py-2 font-medium" :class="{'active': activeTab === 'history'}">
<i class="fas fa-history mr-2"></i>Geçmiş
</button>
<button @click="activeTab = 'admin'" class="nav-item px-4 py-2 font-medium bg-red-100 text-red-800 rounded" :class="{'active': activeTab === 'admin'}">
<i class="fas fa-lock mr-2"></i>Yönetici
</button>
</div>
</div>
</div>
</header>
<!-- Main Content -->
<main class="container mx-auto px-4 py-8">
<!-- Catalog Tab -->
<div x-show="activeTab === 'catalog'" class="space-y-8">
<div class="content-bg rounded-xl shadow-lg p-6">
<h2 class="text-2xl font-bold text-gray-800 mb-6 flex items-center">
<i class="fas fa-book mr-3 text-brown-600"></i>
Kitap Kataloğu
</h2>
<div class="mb-6 flex flex-col md:flex-row justify-between items-start md:items-center space-y-4 md:space-y-0">
<div class="relative w-full md:w-64">
<input type="text" x-model="searchQuery" placeholder="Kitap adı, yazar veya tür ara..."
class="w-full pl-10 pr-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-brown-500">
<i class="fas fa-search absolute left-3 top-3 text-gray-400"></i>
</div>
<div class="flex space-x-2">
<select x-model="sortBy" class="border rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-brown-500">
<option value="title">Kitap Adı (A-Z)</option>
<option value="titleDesc">Kitap Adı (Z-A)</option>
<option value="author">Yazar (A-Z)</option>
<option value="year">Yayın Yılı (Yeni-Eski)</option>
<option value="yearDesc">Yayın Yılı (Eski-Yeni)</option>
</select>
<select x-model="filterStatus" class="border rounded-lg px-3 py-2 focus:outline-none focus:ring-2 focus:ring-brown-500">
<option value="all">Tüm Kitaplar</option>
<option value="available">Mevcut Kitaplar</option>
<option value="borrowed">Ödünçteki Kitaplar</option>
</select>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<template x-for="book in filteredBooks" :key="book.id">
<div class="card-bg border rounded-lg overflow-hidden shadow-md transition-all hover:transform hover:-translate-y-1 hover:shadow-lg">
<div class="h-48 bg-gray-200 flex items-center justify-center">
<template x-if="book.cover">
<img :src="book.cover" :alt="book.title" class="h-full w-full object-cover">
</template>
<template x-if="!book.cover">
<i class="fas fa-book-open text-5xl text-gray-500"></i>
</template>
</div>
<div class="p-4">
<div class="flex justify-between items-start mb-2">
<h3 class="text-lg font-bold text-gray-800" x-text="book.title"></h3>
<span class="px-2 py-1 text-xs rounded-full"
:class="book.status === 'available' ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'"
x-text="book.status === 'available' ? 'Mevcut' : 'Ödünçte'"></span>
</div>
<p class="text-gray-600 mb-1" x-text="'Yazar: ' + book.author"></p>
<p class="text-gray-600 mb-1" x-text="'Tür: ' + book.genre"></p>
<p class="text-gray-600 mb-3" x-text="'Yayın Yılı: ' + book.year"></p>
<template x-if="book.status === 'available'">
<button @click="activeTab = 'borrow'; selectedBookId = book.id"
class="w-full button-primary py-2 rounded-lg transition">
Ödünç Al
</button>
</template>
</div>
</div>
</template>
</div>
</div>
<!-- Popular Books Section -->
<div class="content-bg rounded-xl shadow-lg p-6">
<h2 class="text-2xl font-bold text-gray-800 mb-6 flex items-center">
<i class="fas fa-star mr-3 text-yellow-500"></i>
En Çok Okunan Kitaplar
</h2>
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Kitap Adı</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Yazar</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Ödünç Alma Sayısı</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Durum</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
<template x-for="book in popularBooks" :key="book.id">
<tr>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900" x-text="book.title"></td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500" x-text="book.author"></td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500" x-text="book.borrowCount"></td>
<td class="px-6 py-4 whitespace-nowrap text-sm">
<span class="px-2 py-1 text-xs rounded-full"
:class="book.status === 'available' ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'"
x-text="book.status === 'available' ? 'Mevcut' : 'Ödünçte'"></span>
</td>
</tr>
</template>
</tbody>
</table>
</div>
</div>
</div>
<!-- Borrow Tab -->
<div x-show="activeTab === 'borrow'" class="content-bg rounded-xl shadow-lg p-6">
<h2 class="text-2xl font-bold text-gray-800 mb-6 flex items-center">
<i class="fas fa-hand-holding mr-3 text-brown-600"></i>
Kitap Ödünç Alma
</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
<div>
<h3 class="text-lg font-semibold text-gray-800 mb-4">Kitap Bilgileri</h3>
<template x-if="selectedBookId">
<div class="border rounded-lg p-4 mb-6 card-bg">
<template x-for="book in books" :key="book.id">
<template x-if="book.id === selectedBookId">
<div>
<div class="flex items-start mb-4">
<div class="w-24 h-32 bg-gray-200 flex items-center justify-center mr-4">
<template x-if="book.cover">
<img :src="book.cover" :alt="book.title" class="h-full w-full object-cover">
</template>
<template x-if="!book.cover">
<i class="fas fa-book-open text-3xl text-gray-500"></i>
</template>
</div>
<div>
<h4 class="font-bold text-gray-800" x-text="book.title"></h4>
<p class="text-gray-600 text-sm" x-text="'Yazar: ' + book.author"></p>
<p class="text-gray-600 text-sm" x-text="'Yayın Yılı: ' + book.year"></p>
<p class="text-gray-600 text-sm" x-text="'Tür: ' + book.genre"></p>
</div>
</div>
<div class="flex justify-between items-center">
<span class="px-2 py-1 text-xs rounded-full"
:class="book.status === 'available' ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'"
x-text="book.status === 'available' ? 'Mevcut' : 'Ödünçte'"></span>
<button @click="selectedBookId = null" class="text-sm text-brown-600 hover:text-brown-800">
Başka Kitap Seç
</button>
</div>
</div>
</template>
</template>
</div>
</template>
<template x-if="!selectedBookId">
<div class="border-2 border-dashed rounded-lg p-8 text-center mb-6 card-bg">
<i class="fas fa-book-open text-4xl text-gray-400 mb-3"></i>
<p class="text-gray-500">Ödünç almak için bir kitap seçin</p>
<button @click="activeTab = 'catalog'" class="mt-4 text-brown-600 hover:text-brown-800 font-medium">
Katalogdan Seç <i class="fas fa-arrow-right ml-1"></i>
</button>
</div>
</template>
</div>
<div>
<h3 class="text-lg font-semibold text-gray-800 mb-4">Öğrenci Bilgileri</h3>
<form @submit.prevent="borrowBook" class="space-y-4">
<div>
<label for="studentName" class="block text-sm font-medium text-gray-700 mb-1">Ad Soyad</label>
<input type="text" id="studentName" x-model="borrowForm.name" required
class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-brown-500">
</div>
<div>
<label for="studentNumber" class="block text-sm font-medium text-gray-700 mb-1">Okul Numarası</label>
<input type="text" id="studentNumber" x-model="borrowForm.number" required
class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-brown-500">
</div>
<div class="pt-2">
<button type="submit" :disabled="!selectedBookId"
class="w-full button-primary py-2 rounded-lg transition disabled:opacity-50 disabled:cursor-not-allowed">
Ödünç Al
</button>
</div>
</form>
</div>
</div>
</div>
<!-- Return Tab -->
<div x-show="activeTab === 'return'" class="content-bg rounded-xl shadow-lg p-6">
<h2 class="text-2xl font-bold text-gray-800 mb-6 flex items-center">
<i class="fas fa-undo mr-3 text-brown-600"></i>
Kitap İade Etme
</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
<div>
<h3 class="text-lg font-semibold text-gray-800 mb-4">Öğrenci Bilgileri</h3>
<div class="space-y-4">
<div>
<label for="returnStudentNumber" class="block text-sm font-medium text-gray-700 mb-1">Okul Numarası</label>
<input type="text" id="returnStudentNumber" x-model="returnForm.number" @input="findBorrowedBooks"
class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-brown-500">
</div>
</div>
</div>
<div>
<h3 class="text-lg font-semibold text-gray-800 mb-4">İade Edilecek Kitaplar</h3>
<template x-if="borrowedBooks.length > 0">
<div class="space-y-4">
<template x-for="book in borrowedBooks" :key="book.id">
<div class="border rounded-lg p-4 flex justify-between items-center card-bg">
<div>
<h4 class="font-bold text-gray-800" x-text="book.title"></h4>
<p class="text-gray-600 text-sm" x-text="'Ödünç Tarihi: ' + formatDate(book.borrowDate)"></p>
</div>
<button @click="returnBook(book.id)" class="px-4 py-2 button-primary rounded-lg transition">
İade Et
</button>
</div>
</template>
</div>
</template>
<template x-if="returnForm.number && borrowedBooks.length === 0">
<div class="border-2 border-dashed rounded-lg p-8 text-center card-bg">
<i class="fas fa-book text-4xl text-gray-400 mb-3"></i>
<p class="text-gray-500">Bu numaraya ait ödünç alınmış kitap bulunamadı</p>
</div>
</template>
<template x-if="!returnForm.number">
<div class="border-2 border-dashed rounded-lg p-8 text-center card-bg">
<i class="fas fa-info-circle text-4xl text-gray-400 mb-3"></i>
<p class="text-gray-500">İade etmek için okul numaranızı girin</p>
</div>
</template>
</div>
</div>
</div>
<!-- History Tab -->
<div x-show="activeTab === 'history'" class="content-bg rounded-xl shadow-lg p-6">
<h2 class="text-2xl font-bold text-gray-800 mb-6 flex items-center">
<i class="fas fa-history mr-3 text-brown-600"></i>
Ödünç Alma Geçmişi
</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
<div>
<h3 class="text-lg font-semibold text-gray-800 mb-4">Öğrenci Bilgileri</h3>
<div class="space-y-4">
<div>
<label for="historyStudentNumber" class="block text-sm font-medium text-gray-700 mb-1">Okul Numarası</label>
<input type="text" id="historyStudentNumber" x-model="historyForm.number" @input="findStudentHistory"
class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-brown-500">
</div>
</div>
</div>
<div>
<h3 class="text-lg font-semibold text-gray-800 mb-4">Geçmiş Kayıtlar</h3>
<template x-if="studentHistory.length > 0">
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Kitap Adı</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Ödünç Tarihi</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">İade Tarihi</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
<template x-for="record in studentHistory" :key="record.id">
<tr>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900" x-text="record.title"></td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500" x-text="formatDate(record.borrowDate)"></td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500" x-text="record.returnDate ? formatDate(record.returnDate) : 'İade edilmedi'"></td>
</tr>
</template>
</tbody>
</table>
</div>
</template>
<template x-if="historyForm.number && studentHistory.length === 0">
<div class="border-2 border-dashed rounded-lg p-8 text-center card-bg">
<i class="fas fa-book text-4xl text-gray-400 mb-3"></i>
<p class="text-gray-500">Bu numaraya ait geçmiş kayıt bulunamadı</p>
</div>
</template>
<template x-if="!historyForm.number">
<div class="border-2 border-dashed rounded-lg p-8 text-center card-bg">
<i class="fas fa-info-circle text-4xl text-gray-400 mb-3"></i>
<p class="text-gray-500">Geçmişi görüntülemek için okul numaranızı girin</p>
</div>
</template>
</div>
</div>
</div>
<!-- Admin Tab -->
<div x-show="activeTab === 'admin'" class="content-bg rounded-xl shadow-lg p-6">
<h2 class="text-2xl font-bold text-gray-800 mb-6 flex items-center">
<i class="fas fa-lock mr-3 text-red-600"></i>
Yönetici Paneli
</h2>
<div class="mb-6">
<label for="adminPassword" class="block text-sm font-medium text-gray-700 mb-1">Yönetici Şifresi</label>
<div class="flex space-x-2">
<input type="password" id="adminPassword" x-model="adminPassword" @keyup.enter="checkAdminPassword"
class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-brown-500">
<button @click="checkAdminPassword" class="px-4 py-2 button-primary rounded-lg transition">
Giriş Yap
</button>
</div>
<p x-show="adminError" class="mt-1 text-sm text-red-600" x-text="adminError"></p>
</div>
<template x-if="isAdmin">
<div class="space-y-8">
<!-- Current Borrowed Books -->
<div>
<h3 class="text-xl font-semibold text-gray-800 mb-4 flex items-center">
<i class="fas fa-book-reader mr-2"></i>
Ödünçte Olan Kitaplar
</h3>
<div class="mb-4 flex flex-col md:flex-row justify-between items-start md:items-center space-y-2 md:space-y-0">
<div class="relative w-full md:w-64">
<input type="text" x-model="adminBorrowedSearch" placeholder="Öğrenci veya kitap ara..."
class="w-full pl-10 pr-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-brown-500">
<i class="fas fa-search absolute left-3 top-3 text-gray-400"></i>
</div>
<button @click="exportToExcel('borrowed')" class="px-4 py-2 button-secondary rounded-lg transition">
<i class="fas fa-file-excel mr-2"></i>Excel'e Aktar
</button>
</div>
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider cursor-pointer" @click="sortAdminBorrowed('studentName')">
Öğrenci Adı <i class="fas fa-sort ml-1"></i>
</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider cursor-pointer" @click="sortAdminBorrowed('studentNumber')">
Okul No <i class="fas fa-sort ml-1"></i>
</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider cursor-pointer" @click="sortAdminBorrowed('title')">
Kitap Adı <i class="fas fa-sort ml-1"></i>
</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider cursor-pointer" @click="sortAdminBorrowed('borrowDate')">
Ödünç Tarihi <i class="fas fa-sort ml-1"></i>
</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
İşlem
</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
<template x-for="record in filteredAdminBorrowed" :key="record.id">
<tr>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900" x-text="record.studentName"></td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500" x-text="record.studentNumber"></td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500" x-text="record.title"></td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500" x-text="formatDate(record.borrowDate)"></td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
<button @click="adminReturnBook(record.id)" class="text-red-600 hover:text-red-800">
<i class="fas fa-undo mr-1"></i>İade Et
</button>
</td>
</tr>
</template>
</tbody>
</table>
</div>
</div>
<!-- Returned Books History -->
<div>
<h3 class="text-xl font-semibold text-gray-800 mb-4 flex items-center">
<i class="fas fa-clipboard-list mr-2"></i>
İade Edilen Kitaplar Geçmişi
</h3>
<div class="mb-4 flex flex-col md:flex-row justify-between items-start md:items-center space-y-2 md:space-y-0">
<div class="relative w-full md:w-64">
<input type="text" x-model="adminReturnedSearch" placeholder="Öğrenci veya kitap ara..."
class="w-full pl-10 pr-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-brown-500">
<i class="fas fa-search absolute left-3 top-3 text-gray-400"></i>
</div>
<div class="flex space-x-2">
<button @click="exportToExcel('returned')" class="px-4 py-2 button-secondary rounded-lg transition">
<i class="fas fa-file-excel mr-2"></i>Excel'e Aktar
</button>
<button @click="exportToPDF('returned')" class="px-4 py-2 button-primary rounded-lg transition">
<i class="fas fa-file-pdf mr-2"></i>PDF'ye Aktar
</button>
</div>
</div>
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider cursor-pointer" @click="sortAdminReturned('studentName')">
Öğrenci Adı <i class="fas fa-sort ml-1"></i>
</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider cursor-pointer" @click="sortAdminReturned('studentNumber')">
Okul No <i class="fas fa-sort ml-1"></i>
</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider cursor-pointer" @click="sortAdminReturned('title')">
Kitap Adı <i class="fas fa-sort ml-1"></i>
</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider cursor-pointer" @click="sortAdminReturned('borrowDate')">
Ödünç Tarihi <i class="fas fa-sort ml-1"></i>
</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider cursor-pointer" @click="sortAdminReturned('returnDate')">
İade Tarihi <i class="fas fa-sort ml-1"></i>
</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
<template x-for="record in filteredAdminReturned" :key="record.id">
<tr>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900" x-text="record.studentName"></td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500" x-text="record.studentNumber"></td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500" x-text="record.title"></td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500" x-text="formatDate(record.borrowDate)"></td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500" x-text="formatDate(record.returnDate)"></td>
</tr>
</template>
</tbody>
</table>
</div>
</div>
<!-- Add/Edit Books -->
<div>
<h3 class="text-xl font-semibold text-gray-800 mb-4 flex items-center">
<i class="fas fa-book-medical mr-2"></i>
Kitap Yönetimi
</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
<div>
<h4 class="text-lg font-medium text-gray-800 mb-4">Yeni Kitap Ekle</h4>
<form @submit.prevent="addBook" class="space-y-4">
<div>
<label for="newBookTitle" class="block text-sm font-medium text-gray-700 mb-1">Kitap Adı</label>
<input type="text" id="newBookTitle" x-model="newBook.title" required
class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-brown-500">
</div>
<div>
<label for="newBookAuthor" class="block text-sm font-medium text-gray-700 mb-1">Yazar</label>
<input type="text" id="newBookAuthor" x-model="newBook.author" required
class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-brown-500">
</div>
<div>
<label for="newBookGenre" class="block text-sm font-medium text-gray-700 mb-1">Tür</label>
<input type="text" id="newBookGenre" x-model="newBook.genre" required
class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-brown-500">
</div>
<div>
<label for="newBookYear" class="block text-sm font-medium text-gray-700 mb-1">Yayın Yılı</label>
<input type="number" id="newBookYear" x-model="newBook.year" required
class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-brown-500">
</div>
<div>
<label for="newBookISBN" class="block text-sm font-medium text-gray-700 mb-1">ISBN (İsteğe Bağlı)</label>
<input type="text" id="newBookISBN" x-model="newBook.isbn"
class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-brown-500">
</div>
<div>
<label for="newBookCover" class="block text-sm font-medium text-gray-700 mb-1">Kapak Görseli URL (İsteğe Bağlı)</label>
<input type="text" id="newBookCover" x-model="newBook.cover"
class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-brown-500">
</div>
<div class="pt-2">
<button type="submit" class="w-full button-primary py-2 rounded-lg transition">
Kitap Ekle
</button>
</div>
</form>
</div>
<div>
<h4 class="text-lg font-medium text-gray-800 mb-4">Kitap Düzenle/Sil</h4>
<div class="mb-4">
<label for="editBookSelect" class="block text-sm font-medium text-gray-700 mb-1">Kitap Seçin</label>
<select id="editBookSelect" x-model="selectedEditBookId" @change="loadBookForEdit"
class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-brown-500">
<option value="">Bir kitap seçin</option>
<template x-for="book in books" :key="book.id">
<option :value="book.id" x-text="book.title"></option>
</template>
</select>
</div>
<template x-if="selectedEditBookId">
<form @submit.prevent="updateBook" class="space-y-4">
<div>
<label for="editBookTitle" class="block text-sm font-medium text-gray-700 mb-1">Kitap Adı</label>
<input type="text" id="editBookTitle" x-model="editBook.title" required
class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-brown-500">
</div>
<div>
<label for="editBookAuthor" class="block text-sm font-medium text-gray-700 mb-1">Yazar</label>
<input type="text" id="editBookAuthor" x-model="editBook.author" required
class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-brown-500">
</div>
<div>
<label for="editBookGenre" class="block text-sm font-medium text-gray-700 mb-1">Tür</label>
<input type="text" id="editBookGenre" x-model="editBook.genre" required
class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-brown-500">
</div>
<div>
<label for="editBookYear" class="block text-sm font-medium text-gray-700 mb-1">Yayın Yılı</label>
<input type="number" id="editBookYear" x-model="editBook.year" required
class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-brown-500">
</div>
<div>
<label for="editBookISBN" class="block text-sm font-medium text-gray-700 mb-1">ISBN</label>
<input type="text" id="editBookISBN" x-model="editBook.isbn"
class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-brown-500">
</div>
<div>
<label for="editBookCover" class="block text-sm font-medium text-gray-700 mb-1">Kapak Görseli URL</label>
<input type="text" id="editBookCover" x-model="editBook.cover"
class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-brown-500">
</div>
<div>
<label for="editBookStatus" class="block text-sm font-medium text-gray-700 mb-1">Durum</label>
<select id="editBookStatus" x-model="editBook.status"
class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-brown-500">
<option value="available">Mevcut</option>
<option value="borrowed">Ödünçte</option>
</select>
</div>
<div class="flex space-x-2 pt-2">
<button type="submit" class="flex-1 button-primary py-2 rounded-lg transition">
Güncelle
</button>
<button type="button" @click="deleteBook" class="flex-1 bg-red-600 hover:bg-red-700 text-white py-2 rounded-lg transition">
Sil
</button>
</div>
</form>
</template>
</div>
</div>
</div>
</div>
</template>
</div>
</main>
<!-- Footer -->
<footer class="footer-bg py-8">
<div class="container mx-auto px-4">
<div class="flex flex-col md:flex-row justify-between items-center">
<div class="mb-4 md:mb-0">
<h2 class="text-xl font-bold">Bartın Fen Lisesi</h2>
<p class="text-gray-300">Kütüphane Takip Sistemi</p>
</div>
<div class="text-gray-300 text-sm">
<p>© 2023 Tüm hakları saklıdır.</p>
</div>
</div>
</div>
</footer>
<!-- Alpine.js and other scripts -->
<script src="https://cdn.jsdelivr.net/npm/alpinejs@3.12.0/dist/cdn.min.js" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.5.28/jspdf.plugin.autotable.min.js"></script>
<script>
// Firebase configuration
const firebaseConfig = {
apiKey: "AIzaSyD4XKx1Q2Q2X2X2X2X2X2X2X2X2X2X2X2X2",
authDomain: "bartin-fen-lisesi-kutuphane.firebaseapp.com",
projectId: "bartin-fen-lisesi-kutuphane",
storageBucket: "bartin-fen-lisesi-kutuphane.appspot.com",
messagingSenderId: "123456789012",
appId: "1:123456789012:web:abcdefghijklmnopqrstuv"
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
const db = firebase.firestore();
const auth = firebase.auth();
// Library Application
function libraryApp() {
return {
// Application State
activeTab: 'catalog',
isAdmin: false,
adminPassword: '',
adminError: '',
failedAttempts: 0,
lockoutTime: 0,
isLoading: true,
// Data
books: [],
transactions: [],
// Forms
borrowForm: {
name: '',
number: ''
},
returnForm: {
number: ''
},
historyForm: {
number: ''
},
newBook: {
title: '',
author: '',
genre: '',
year: '',
isbn: '',
cover: '',
status: 'available'
},
editBook: {
id: '',
title: '',
author: '',
genre: '',
year: '',
isbn: '',
cover: '',
status: 'available'
},
// UI State
selectedBookId: null,
selectedEditBookId: null,
searchQuery: '',
sortBy: 'title',
filterStatus: 'all',
adminBorrowedSearch: '',
adminReturnedSearch: '',
adminBorrowedSort: { field: 'borrowDate', direction: 'desc' },
adminReturnedSort: { field: 'returnDate', direction: 'desc' },
// Computed Properties
get popularBooks() {
return [...this.books]
.sort((a, b) => b.borrowCount - a.borrowCount)
.slice(0, 5);
},
get filteredBooks() {
let filtered = [...this.books];
// Apply search filter
if (this.searchQuery) {
const query = this.searchQuery.toLowerCase();
filtered = filtered.filter(book =>
book.title.toLowerCase().includes(query) ||
book.author.toLowerCase().includes(query) ||
book.genre.toLowerCase().includes(query)
);
}
// Apply status filter
if (this.filterStatus !== 'all') {
filtered = filtered.filter(book => book.status === this.filterStatus);
}
// Apply sorting
switch (this.sortBy) {
case 'title':
filtered.sort((a, b) => a.title.localeCompare(b.title));
break;
case 'titleDesc':
filtered.sort((a, b) => b.title.localeCompare(a.title));
break;
case 'author':
filtered.sort((a, b) => a.author.localeCompare(b.author));
break;
case 'year':
filtered.sort((a, b) => b.year - a.year);
break;
case 'yearDesc':
filtered.sort((a, b) => a.year - b.year);
break;
default:
filtered.sort((a, b) => a.title.localeCompare(b.title));
}
return filtered;
},
get borrowedBooks() {
if (!this.returnForm.number) return [];
return this.transactions
.filter(t => t.studentNumber === this.returnForm.number && !t.returnDate)
.map(t => {
const book = this.books.find(b => b.id === t.bookId);
return {
id: t.id,
title: book.title,
borrowDate: t.borrowDate
};
});
},
get studentHistory() {
if (!this.historyForm.number) return [];
return this.transactions
.filter(t => t.studentNumber === this.historyForm.number)
.map(t => {
const book = this.books.find(b => b.id === t.bookId);
return {
id: t.id,
title: book.title,
borrowDate: t.borrowDate,
returnDate: t.returnDate
};
});
},
get adminBorrowed() {
return this.transactions
.filter(t => !t.returnDate)
.map(t => {
const book = this.books.find(b => b.id === t.bookId);
return {
id: t.id,
studentName: t.studentName,
studentNumber: t.studentNumber,
title: book.title,
borrowDate: t.borrowDate,
bookId: t.bookId
};
});
},
get filteredAdminBorrowed() {
let filtered = [...this.adminBorrowed];
// Apply search filter
if (this.adminBorrowedSearch) {
const query = this.adminBorrowedSearch.toLowerCase();
filtered = filtered.filter(record =>
record.studentName.toLowerCase().includes(query) ||
record.studentNumber.toLowerCase().includes(query) ||
record.title.toLowerCase().includes(query)
);
}
// Apply sorting
const field = this.adminBorrowedSort.field;
const direction = this.adminBorrowedSort.direction;
filtered.sort((a, b) => {
if (a[field] < b[field]) return direction === 'asc' ? -1 : 1;
if (a[field] > b[field]) return direction === 'asc' ? 1 : -1;
return 0;
});
return filtered;
},
get adminReturned() {
return this.transactions
.filter(t => t.returnDate)
.map(t => {
const book = this.books.find(b => b.id === t.bookId);
return {
id: t.id,
studentName: t.studentName,
studentNumber: t.studentNumber,
title: book.title,
borrowDate: t.borrowDate,
returnDate: t.returnDate,
bookId: t.bookId
};
});
},
get filteredAdminReturned() {
let filtered = [...this.adminReturned];
// Apply search filter
if (this.adminReturnedSearch) {
const query = this.adminReturnedSearch.toLowerCase();
filtered = filtered.filter(record =>
record.studentName.toLowerCase().includes(query) ||
record.studentNumber.toLowerCase().includes(query) ||
record.title.toLowerCase().includes(query)
);
}
// Apply sorting
const field = this.adminReturnedSort.field;
const direction = this.adminReturnedSort.direction;
filtered.sort((a, b) => {
if (a[field] < b[field]) return direction === 'asc' ? -1 : 1;
if (a[field] > b[field]) return direction === 'asc' ? 1 : -1;
return 0;
});
return filtered;
},
// Methods
async init() {
// Check if there's a lockout time in localStorage
const storedLockout = localStorage.getItem('adminLockout');
if (storedLockout) {
this.lockoutTime = parseInt(storedLockout);
const remainingTime = this.lockoutTime - Date.now();
if (remainingTime > 0) {
this.showSecurityWarning();
this.adminError = `Çok fazla başarısız giriş denemesi. Lütfen ${Math.ceil(remainingTime / 1000)} saniye sonra tekrar deneyin.`;
} else {
localStorage.removeItem('adminLockout');
this.lockoutTime = 0;
this.failedAttempts = 0;
}
}
// Check if admin is already logged in
const adminSession = localStorage.getItem('adminSession');
if (adminSession && adminSession === 'active') {
this.isAdmin = true;
}
// Load data from Firestore
try {
// Load books
const booksSnapshot = await db.collection('books').get();
this.books = booksSnapshot.docs.map(doc => ({
id: doc.id,
...doc.data()
}));
// Load transactions
const transactionsSnapshot = await db.collection('transactions').get();
this.transactions = transactionsSnapshot.docs.map(doc => ({
id: doc.id,
...doc.data()
}));
this.isLoading = false;
// Set up real-time listeners
db.collection('books').onSnapshot(snapshot => {
this.books = snapshot.docs.map(doc => ({
id: doc.id,
...doc.data()
}));
});
db.collection('transactions').onSnapshot(snapshot => {
this.transactions = snapshot.docs.map(doc => ({
id: doc.id,
...doc.data()
}));
});
} catch (error) {
console.error("Veri yüklenirken hata oluştu:", error);
this.isLoading = false;
}
},
showSecurityWarning() {
const warning = document.getElementById('securityWarning');
warning.style.display = 'block';
setTimeout(() => {
warning.style.display = 'none';
}, 5000);
},
formatDate(dateString) {
if (!dateString) return '';
const date = new Date(dateString);
return date.toLocaleDateString('tr-TR');
},
async checkAdminPassword() {
// Check if account is locked
if (this.lockoutTime > Date.now()) {
const remainingTime = Math.ceil((this.lockoutTime - Date.now()) / 1000);
this.adminError = `Hesap geçici olarak kilitlendi. Lütfen ${remainingTime} saniye sonra tekrar deneyin.`;
this.showSecurityWarning();
return;
}
try {
// Sign in with email and password (in a real app, this would be proper authentication)
// For demo purposes, we're using a simple password check
if (this.adminPassword === 'tcttnctn') {
this.isAdmin = true;
this.adminError = '';
this.failedAttempts = 0;
localStorage.setItem('adminSession', 'active');
} else {
this.failedAttempts++;
if (this.failedAttempts >= 3) {
// Lock account for 5 minutes
this.lockoutTime = Date.now() + (5 * 60 * 1000);
localStorage.setItem('adminLockout', this.lockoutTime.toString());
this.adminError = `Çok fazla başarısız giriş denemesi. Lütfen 5 dakika sonra tekrar deneyin.`;
this.showSecurityWarning();
} else {
this.adminError = 'Geçersiz şifre! Lütfen tekrar deneyin.';
}
}
// Clear password field
this.adminPassword = '';
} catch (error) {
console.error("Giriş hatası:", error);
this.adminError = 'Giriş sırasında bir hata oluştu.';
}
},
async borrowBook() {
if (!this.selectedBookId) return;
try {
this.isLoading = true;
// Find the book
const bookRef = db.collection('books').doc(this.selectedBookId);
const bookDoc = await bookRef.get();
if (!bookDoc.exists) {
alert('Kitap bulunamadı!');
this.isLoading = false;
return;
}
const bookData = bookDoc.data();
// Check if book is available
if (bookData.status !== 'available') {
alert('Bu kitap şu anda ödünçte!');
this.isLoading = false;
return;
}
// Create transaction in Firestore
const newTransaction = {
bookId: this.selectedBookId,
studentName: this.borrowForm.name,
studentNumber: this.borrowForm.number,
borrowDate: new Date().toISOString(),
returnDate: null
};
await db.collection('transactions').add(newTransaction);
// Update book status in Firestore
await bookRef.update({
status: 'borrowed',
borrowCount: (bookData.borrowCount || 0) + 1
});
// Reset form
this.borrowForm.name = '';
this.borrowForm.number = '';
this.selectedBookId = null;
this.isLoading = false;
// Show success message
alert('Kitap ödünç alma işlemi başarılı!');
this.activeTab = 'catalog';
} catch (error) {
console.error("Ödünç alma hatası:", error);
this.isLoading = false;
alert('Ödünç alma işlemi sırasında bir hata oluştu.');
}
},
findBorrowedBooks() {
// This is handled by the computed property
},
async returnBook(transactionId) {
try {
this.isLoading = true;
// Find transaction
const transactionRef = db.collection('transactions').doc(transactionId);
const transactionDoc = await transactionRef.get();
if (!transactionDoc.exists) {
alert('İşlem bulunamadı!');
this.isLoading = false;
return;
}
const transactionData = transactionDoc.data();
// Update transaction in Firestore
await transactionRef.update({
returnDate: new Date().toISOString()
});
// Update book status in Firestore
await db.collection('books').doc(transactionData.bookId).update({
status: 'available'
});
// Reset form
this.returnForm.number = '';
this.isLoading = false;
// Show success message
alert('Kitap iade işlemi başarılı!');
} catch (error) {
console.error("İade hatası:", error);
this.isLoading = false;
alert('İade işlemi sırasında bir hata oluştu.');
}
},
findStudentHistory() {
// This is handled by the computed property
},
async adminReturnBook(transactionId) {
try {
this.isLoading = true;
// Find transaction
const transactionRef = db.collection('transactions').doc(transactionId);
const transactionDoc = await transactionRef.get();
if (!transactionDoc.exists) {
alert('İşlem bulunamadı!');
this.isLoading = false;
return;
}
const transactionData = transactionDoc.data();
// Update transaction in Firestore
await transactionRef.update({
returnDate: new Date().toISOString()
});
// Update book status in Firestore
await db.collection('books').doc(transactionData.bookId).update({
status: 'available'
});
this.isLoading = false;
// Show success message
alert('Kitap iade işlemi başarılı!');
} catch (error) {
console.error("İade hatası:", error);
this.isLoading = false;
alert('İade işlemi sırasında bir hata oluştu.');
}
},
sortAdminBorrowed(field) {
if (this.adminBorrowedSort.field === field) {
this.adminBorrowedSort.direction = this.adminBorrowedSort.direction === 'asc' ? 'desc' : 'asc';
} else {
this.adminBorrowedSort.field = field;
this.adminBorrowedSort.direction = 'asc';
}
},
sortAdminReturned(field) {
if (this.adminReturnedSort.field === field) {
this.adminReturnedSort.direction = this.adminReturnedSort.direction === 'asc' ? 'desc' : 'asc';
} else {
this.adminReturnedSort.field = field;
this.adminReturnedSort.direction = 'asc';
}
},
exportToExcel(type) {
const data = type === 'borrowed' ? this.filteredAdminBorrowed : this.filteredAdminReturned;
// Prepare worksheet
const ws = XLSX.utils.json_to_sheet(data.map(item => {
if (type === 'borrowed') {
return {
'Öğrenci Adı': item.studentName,
'Okul No': item.studentNumber,
'Kitap Adı': item.title,
'Ödünç Tarihi': this.formatDate(item.borrowDate)
};
} else {
return {
'Öğrenci Adı': item.studentName,
'Okul No': item.studentNumber,
'Kitap Adı': item.title,
'Ödünç Tarihi': this.formatDate(item.borrowDate),
'İade Tarihi': this.formatDate(item.returnDate)
};
}
}));
// Create workbook
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, type === 'borrowed' ? 'ÖdünçtekiKitaplar' : 'İadeEdilenKitaplar');
// Export
XLSX.writeFile(wb, `${type === 'borrowed' ? 'Oduncte_Kitaplar' : 'Iade_Edilen_Kitaplar'}.xlsx`);
},
exportToPDF(type) {
const { jsPDF } = window.jspdf;
const doc = new jsPDF();
// Add title
doc.setFontSize(18);
doc.text(`Bartın Fen Lisesi - ${type === 'borrowed' ? 'Ödünçteki Kitaplar' : 'İade Edilen Kitaplar'}`, 14, 15);
// Add date
doc.setFontSize(10);
doc.text(`Oluşturulma Tarihi: ${new Date().toLocaleDateString('tr-TR')}`, 14, 22);
// Prepare data
const data = type === 'borrowed' ? this.filteredAdminBorrowed : this.filteredAdminReturned;
const headers = type === 'borrowed'
? [['Öğrenci Adı', 'Okul No', 'Kitap Adı', 'Ödünç Tarihi']]
: [['Öğrenci Adı', 'Okul No', 'Kitap Adı', 'Ödünç Tarihi', 'İade Tarihi']];
const rows = data.map(item => {
if (type === 'borrowed') {
return [
item.studentName,
item.studentNumber,
item.title,
this.formatDate(item.borrowDate)
];
} else {
return [
item.studentName,
item.studentNumber,
item.title,
this.formatDate(item.borrowDate),
this.formatDate(item.returnDate)
];
}
});
// Add table
doc.autoTable({
head: headers,
body: rows,
startY: 25,
styles: { fontSize: 9 },
headStyles: { fillColor: [30, 58, 138] }
});
// Save PDF
doc.save(`${type === 'borrowed' ? 'Oduncte_Kitaplar' : 'Iade_Edilen_Kitaplar'}.pdf`);
},
async addBook() {
try {
this.isLoading = true;
// Add book to Firestore
await db.collection('books').add({
title: this.newBook.title,
author: this.newBook.author,
genre: this.newBook.genre,
year: this.newBook.year,
isbn: this.newBook.isbn,
cover: this.newBook.cover,
status: 'available',
borrowCount: 0
});
// Reset form
this.newBook = {
title: '',
author: '',
genre: '',
year: '',
isbn: '',
cover: '',
status: 'available'
};
this.isLoading = false;
// Show success message
alert('Kitap başarıyla eklendi!');
} catch (error) {
console.error("Kitap ekleme hatası:", error);
this.isLoading = false;
alert('Kitap ekleme işlemi sırasında bir hata oluştu.');
}
},
async loadBookForEdit() {
if (!this.selectedEditBookId) {
this.editBook = {
id: '',
title: '',
author: '',
genre: '',
year: '',
isbn: '',
cover: '',
status: 'available'
};
return;
}
try {
const bookDoc = await db.collection('books').doc(this.selectedEditBookId).get();
if (bookDoc.exists) {
const bookData = bookDoc.data();
this.editBook = {
id: bookDoc.id,
title: bookData.title,
author: bookData.author,
genre: bookData.genre,
year: bookData.year,
isbn: bookData.isbn,
cover: bookData.cover,
status: bookData.status
};
}
} catch (error) {
console.error("Kitap yükleme hatası:", error);
alert('Kitap bilgileri yüklenirken bir hata oluştu.');
}
},
async updateBook() {
try {
this.isLoading = true;
await db.collection('books').doc(this.editBook.id).update({
title: this.editBook.title,
author: this.editBook.author,
genre: this.editBook.genre,
year: this.editBook.year,
isbn: this.editBook.isbn,
cover: this.editBook.cover,
status: this.editBook.status
});
// Reset form
this.selectedEditBookId = null;
this.editBook = {
id: '',
title: '',
author: '',
genre: '',
year: '',
isbn: '',
cover: '',
status: 'available'
};
this.isLoading = false;
// Show success message
alert('Kitap başarıyla güncellendi!');
} catch (error) {
console.error("Kitap güncelleme hatası:", error);
this.isLoading = false;
alert('Kitap güncelleme işlemi sırasında bir hata oluştu.');
}
},
async deleteBook() {
if (!confirm('Bu kitabı silmek istediğinize emin misiniz?')) return;
try {
this.isLoading = true;
// Check if book is borrowed
const bookDoc = await db.collection('books').doc(this.editBook.id).get();
const bookData = bookDoc.data();
if (bookData.status === 'borrowed') {
alert('Ödünçte olan bir kitabı silemezsiniz!');
this.isLoading = false;
return;
}
// Delete book from Firestore
await db.collection('books').doc(this.editBook.id).delete();
// Reset form
this.selectedEditBookId = null;
this.editBook = {
id: '',
title: '',
author: '',
genre: '',
year: '',
isbn: '',
cover: '',
status: 'available'
};
this.isLoading = false;
// Show success message
alert('Kitap başarıyla silindi!');
} catch (error) {
console.error("Kitap silme hatası:", error);
this.isLoading = false;
alert('Kitap silme işlemi sırasında bir hata oluştu.');
}
}
};
}
// Initialize the app when the page loads
document.addEventListener('DOMContentLoaded', function() {
const app = Alpine.store('libraryApp');
if (app) {
app.init();
}
});
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Alirelian/bflkutuphanesi" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>