From 2332ec693491301b38c40aeaae5d589a470d9e6f Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Thu, 30 Oct 2025 14:24:12 +0000 Subject: [PATCH] 1.0 --- add-book.php | 98 ++++++++++++ assets/css/custom.css | 61 ++++++++ assets/js/main.js | 2 + catalog.php | 66 ++++++++ db/migrations/001_create_books_table.sql | 10 ++ db/migrations/002_create_users_table.sql | 8 + db/migrations/003_create_loans_table.sql | 10 ++ db/seed.php | 77 ++++++++++ includes/auth.php | 24 +++ includes/footer.php | 5 + includes/header.php | 55 +++++++ index.php | 188 +++++------------------ login.php | 73 +++++++++ logout.php | 6 + process-scan.php | 102 ++++++++++++ register.php | 97 ++++++++++++ scan.php | 151 ++++++++++++++++++ 17 files changed, 884 insertions(+), 149 deletions(-) create mode 100644 add-book.php create mode 100644 assets/css/custom.css create mode 100644 assets/js/main.js create mode 100644 catalog.php create mode 100644 db/migrations/001_create_books_table.sql create mode 100644 db/migrations/002_create_users_table.sql create mode 100644 db/migrations/003_create_loans_table.sql create mode 100644 db/seed.php create mode 100644 includes/auth.php create mode 100644 includes/footer.php create mode 100644 includes/header.php create mode 100644 login.php create mode 100644 logout.php create mode 100644 process-scan.php create mode 100644 register.php create mode 100644 scan.php diff --git a/add-book.php b/add-book.php new file mode 100644 index 0000000..e205fbe --- /dev/null +++ b/add-book.php @@ -0,0 +1,98 @@ +prepare( + "INSERT INTO books (title, author, isbn, description, qr_code_hash) VALUES (:title, :author, :isbn, :description, :qr_code_hash)" + ); + + if ($stmt->execute([ + ':title' => $title, + ':author' => $author, + ':isbn' => $isbn, + ':description' => $description, + ':qr_code_hash' => $qr_code_hash + ])) { + $success = "Book added successfully!"; + } else { + $errors[] = "Failed to add book."; + } + } catch (PDOException $e) { + $errors[] = "Database error: " . $e->getMessage(); + } + } +} + +require_once __DIR__ . '/includes/header.php'; +?> + +
+
+
+
+

Add a New Book

+
+
+ +
+ +

+ +
+ + +
+

+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+
+
+
+
+ + diff --git a/assets/css/custom.css b/assets/css/custom.css new file mode 100644 index 0000000..8369f23 --- /dev/null +++ b/assets/css/custom.css @@ -0,0 +1,61 @@ +/* assets/css/custom.css */ +body { + font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; + background-color: #F8F9FA; + color: #212529; +} + +.navbar { + box-shadow: 0 2px 4px rgba(0,0,0,.04); +} + +.hero { + background: linear-gradient(45deg, #007BFF, #0056b3); + color: white; +} + +.hero .btn-primary { + background-color: #FFFFFF; + color: #007BFF; + border-color: #FFFFFF; + font-weight: bold; +} +.hero .btn-primary:hover { + background-color: #f0f0f0; + color: #0056b3; +} + +.book-card { + background-color: #FFFFFF; + border: 1px solid #dee2e6; + border-radius: 0.375rem; + transition: transform .2s ease-in-out, box-shadow .2s ease-in-out; +} + +.book-card:hover { + transform: translateY(-5px); + box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15); +} + +.book-card .card-title { + color: #007BFF; +} + +.book-card .badge { + font-size: 0.8rem; +} + +.status-available { + color: #198754; + font-weight: bold; +} + +.status-borrowed { + color: #dc3545; + font-weight: bold; +} + +.footer { + background-color: #343a40; + color: white; +} \ No newline at end of file diff --git a/assets/js/main.js b/assets/js/main.js new file mode 100644 index 0000000..a89109f --- /dev/null +++ b/assets/js/main.js @@ -0,0 +1,2 @@ +// Intentionally blank for now. +// Future client-side interactions can be added here. \ No newline at end of file diff --git a/catalog.php b/catalog.php new file mode 100644 index 0000000..9f58500 --- /dev/null +++ b/catalog.php @@ -0,0 +1,66 @@ +prepare($query); +$stmt->execute($params); +$books = $stmt->fetchAll(PDO::FETCH_ASSOC); +?> + + +
+
+

Book Catalog

+
+
+
+
+ + +
+
+
+
+ +
+ +
+
No books found matching your search criteria.
+
+ + +
+
+
+
+
+

+
+

ISBN:

+

+ Status: + + + +

+
+
+
+
+ + +
+
+
+ + diff --git a/db/migrations/001_create_books_table.sql b/db/migrations/001_create_books_table.sql new file mode 100644 index 0000000..bf867ae --- /dev/null +++ b/db/migrations/001_create_books_table.sql @@ -0,0 +1,10 @@ +CREATE TABLE IF NOT EXISTS books ( + id INT AUTO_INCREMENT PRIMARY KEY, + title VARCHAR(255) NOT NULL, + author VARCHAR(255) NOT NULL, + isbn VARCHAR(20) UNIQUE NOT NULL, + description TEXT, + qr_code_hash VARCHAR(255) UNIQUE, + status ENUM('available', 'borrowed') NOT NULL DEFAULT 'available', + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); \ No newline at end of file diff --git a/db/migrations/002_create_users_table.sql b/db/migrations/002_create_users_table.sql new file mode 100644 index 0000000..6eab772 --- /dev/null +++ b/db/migrations/002_create_users_table.sql @@ -0,0 +1,8 @@ +CREATE TABLE IF NOT EXISTS `users` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `name` VARCHAR(255) NOT NULL, + `email` VARCHAR(255) NOT NULL UNIQUE, + `password` VARCHAR(255) NOT NULL, + `role` ENUM('Member', 'Librarian', 'Admin') NOT NULL DEFAULT 'Member', + `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); diff --git a/db/migrations/003_create_loans_table.sql b/db/migrations/003_create_loans_table.sql new file mode 100644 index 0000000..e92e015 --- /dev/null +++ b/db/migrations/003_create_loans_table.sql @@ -0,0 +1,10 @@ +CREATE TABLE IF NOT EXISTS `loans` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `book_id` INT NOT NULL, + `user_id` INT NOT NULL, + `loan_date` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + `due_date` TIMESTAMP NOT NULL, + `return_date` TIMESTAMP NULL, + FOREIGN KEY (`book_id`) REFERENCES `books`(`id`), + FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) +); diff --git a/db/seed.php b/db/seed.php new file mode 100644 index 0000000..e449453 --- /dev/null +++ b/db/seed.php @@ -0,0 +1,77 @@ + PDO::ERRMODE_EXCEPTION, + ]); + // Create the database if it doesn't exist + $pdo_admin->exec("CREATE DATABASE IF NOT EXISTS `".DB_NAME."`"); + echo "Database '".DB_NAME."' created or already exists.\n"; + + // Now, connect to the specific database + $pdo = db(); + $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + // 1. Run migrations + $migrations = glob(__DIR__ . '/migrations/*.sql'); + sort($migrations); + foreach ($migrations as $migration) { + $sql = file_get_contents($migration); + $pdo->exec($sql); + echo "Executed migration: " . basename($migration) . "\n"; + } + + // 2. Check if table is empty before seeding + $stmt = $pdo->query("SELECT COUNT(*) FROM books"); + if ($stmt->fetchColumn() > 0) { + echo "Table 'books' is not empty. Seeding skipped.\n"; + exit; + } + + // 3. Seed data + $books = [ + [ + 'title' => 'The Hitchhiker\'s Guide to the Galaxy', + 'author' => 'Douglas Adams', + 'isbn' => '978-0345391803', + 'description' => 'A comedy science fiction series created by Douglas Adams.', + 'qr_code_hash' => md5('978-0345391803') + ], + [ + 'title' => 'Pride and Prejudice', + 'author' => 'Jane Austen', + 'isbn' => '978-1503290563', + 'description' => 'A romantic novel of manners written by Jane Austen in 1813.', + 'qr_code_hash' => md5('978-1503290563') + ], + [ + 'title' => 'To Kill a Mockingbird', + 'author' => 'Harper Lee', + 'isbn' => '978-0061120084', + 'description' => 'A novel by Harper Lee published in 1960. Instantly successful, widely read in high schools and middle schools in the United States, it has become a classic of modern American literature, winning the Pulitzer Prize.', + 'qr_code_hash' => md5('978-0061120084') + ], + [ + 'title' => '1984', + 'author' => 'George Orwell', + 'isbn' => '978-0451524935', + 'description' => 'A dystopian social science fiction novel and cautionary tale by English writer George Orwell.', + 'qr_code_hash' => md5('978-0451524935') + ] + ]; + + $stmt = $pdo->prepare( + "INSERT INTO books (title, author, isbn, description, qr_code_hash) VALUES (:title, :author, :isbn, :description, :qr_code_hash)" + ); + + foreach ($books as $book) { + $stmt->execute($book); + } + + echo "Seeded " . count($books) . " books.\n"; + +} catch (PDOException $e) { + die("DB ERROR: " . $e->getMessage()); +} \ No newline at end of file diff --git a/includes/auth.php b/includes/auth.php new file mode 100644 index 0000000..c8bc957 --- /dev/null +++ b/includes/auth.php @@ -0,0 +1,24 @@ + + + + + \ No newline at end of file diff --git a/includes/header.php b/includes/header.php new file mode 100644 index 0000000..51bc84e --- /dev/null +++ b/includes/header.php @@ -0,0 +1,55 @@ + + + + + + + QR Code Library System + + + + + + +
\ No newline at end of file diff --git a/index.php b/index.php index 7205f3d..1da0cab 100644 --- a/index.php +++ b/index.php @@ -1,150 +1,40 @@ - -$phpVersion = PHP_VERSION; -$now = date('Y-m-d H:i:s'); -?> - - - - - - New Style - - - - - - - - - - - - - - - - - - - - - -
-
-

Analyzing your requirements and generating your website…

-
- Loading… -
-

AI is collecting your requirements and applying the first changes.

-

This page will update automatically as the plan is implemented.

-

Runtime: PHP — UTC

-
-
-
- Page updated: (UTC) -
- - +
+
+

Welcome to the Future of Reading

+

A smart, simple, and seamless library experience powered by QR codes.

+ Explore the Catalog +
+
+ +
+
+

How It Works

+
+
+
+ +

1. Find Your Book

+

Browse our extensive digital catalog to find the books you love.

+
+
+
+
+ +

2. Scan to Borrow

+

Use your phone to scan the book's QR code for instant self-checkout.

+
+
+
+
+ +

3. Enjoy Reading

+

Enjoy your book! We'll send you a reminder before it's due.

+
+
+
+
+
+ + \ No newline at end of file diff --git a/login.php b/login.php new file mode 100644 index 0000000..17fc00d --- /dev/null +++ b/login.php @@ -0,0 +1,73 @@ +prepare("SELECT * FROM users WHERE email = ?"); + $stmt->execute([$email]); + $user = $stmt->fetch(); + + if ($user && password_verify($password, $user['password'])) { + $_SESSION['user_id'] = $user['id']; + $_SESSION['user_name'] = $user['name']; + $_SESSION['user_role'] = $user['role']; + header("Location: index.php"); + exit; + } else { + $errors[] = 'Invalid email or password'; + } + } catch (PDOException $e) { + $errors[] = "Database error: " . $e->getMessage(); + } + } +} + +require_once __DIR__ . '/includes/header.php'; +?> + +
+
+
+
+

Login

+
+
+ +
+ +

+ +
+ +
+
+ + +
+
+ + +
+ +
+
+
+
+
+ + diff --git a/logout.php b/logout.php new file mode 100644 index 0000000..f83284d --- /dev/null +++ b/logout.php @@ -0,0 +1,6 @@ + false, 'message' => 'Invalid request']; + +if ($_SERVER["REQUEST_METHOD"] == "POST") { + $action = $_POST['action'] ?? ''; + $qr_code_hash = $_POST['qr_code_hash'] ?? ''; + + if (empty($action) || empty($qr_code_hash)) { + $response['message'] = 'Missing action or QR code'; + echo json_encode($response); + exit; + } + + try { + $pdo = db(); + + // Find the book by QR code hash + $stmt = $pdo->prepare("SELECT id FROM books WHERE qr_code_hash = ?"); + $stmt->execute([$qr_code_hash]); + $book = $stmt->fetch(); + + if (!$book) { + $response['message'] = 'Book not found'; + echo json_encode($response); + exit; + } + + $book_id = $book['id']; + + if ($action === 'checkout') { + $user_email = $_POST['user_email'] ?? ''; + if (empty($user_email)) { + $response['message'] = 'Missing user email for checkout'; + echo json_encode($response); + exit; + } + + // Find the user by email + $stmt = $pdo->prepare("SELECT id FROM users WHERE email = ?"); + $stmt->execute([$user_email]); + $user = $stmt->fetch(); + + if (!$user) { + $response['message'] = 'User not found'; + echo json_encode($response); + exit; + } + + $user_id = $user['id']; + + // Check if the book is already on loan + $stmt = $pdo->prepare("SELECT id FROM loans WHERE book_id = ? AND return_date IS NULL"); + $stmt->execute([$book_id]); + if ($stmt->fetch()) { + $response['message'] = 'Book is already on loan'; + echo json_encode($response); + exit; + } + + $loan_date = date('Y-m-d H:i:s'); + $due_date = date('Y-m-d H:i:s', strtotime('+2 weeks')); + + $stmt = $pdo->prepare("INSERT INTO loans (book_id, user_id, due_date) VALUES (?, ?, ?)"); + if ($stmt->execute([$book_id, $user_id, $due_date])) { + $response['success'] = true; + $response['message'] = 'Book checked out successfully'; + } else { + $response['message'] = 'Failed to check out book'; + } + + } elseif ($action === 'checkin') { + $stmt = $pdo->prepare("UPDATE loans SET return_date = CURRENT_TIMESTAMP WHERE book_id = ? AND return_date IS NULL"); + if ($stmt->execute([$book_id])) { + if ($stmt->rowCount() > 0) { + $response['success'] = true; + $response['message'] = 'Book checked in successfully'; + } else { + $response['message'] = 'Book was not on loan'; + } + } else { + $response['message'] = 'Failed to check in book'; + } + } else { + $response['message'] = 'Invalid action'; + } + + } catch (PDOException $e) { + $response['message'] = 'Database error: ' . $e->getMessage(); + } + + echo json_encode($response); + exit; +} + +echo json_encode($response); diff --git a/register.php b/register.php new file mode 100644 index 0000000..5f75b39 --- /dev/null +++ b/register.php @@ -0,0 +1,97 @@ +prepare("SELECT * FROM users WHERE email = ?"); + $stmt->execute([$email]); + if ($stmt->fetch()) { + $errors[] = 'Email already exists'; + } else { + $hashed_password = password_hash($password, PASSWORD_DEFAULT); + $stmt = $pdo->prepare("INSERT INTO users (name, email, password, role) VALUES (?, ?, ?, 'Member')"); + if ($stmt->execute([$name, $email, $hashed_password])) { + $user_id = $pdo->lastInsertId(); + $_SESSION['user_id'] = $user_id; + $_SESSION['user_name'] = $name; + $_SESSION['user_role'] = 'Member'; + header("Location: index.php"); + exit; + } else { + $errors[] = 'Failed to register user'; + } + } + } catch (PDOException $e) { + $errors[] = "Database error: " . $e->getMessage(); + } + } +} + +require_once __DIR__ . '/includes/header.php'; +?> + +
+
+
+
+

Register

+
+
+ +
+ +

+ +
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+
+
+
+
+ + diff --git a/scan.php b/scan.php new file mode 100644 index 0000000..5c7c455 --- /dev/null +++ b/scan.php @@ -0,0 +1,151 @@ + + +
+
+
+

Scan QR Code

+
+
+ + +
+ + +
+
+
+
+
+
+

Manual Entry

+
+
+
+ + +
+
+ + +
+ +
+
+
+
+ + +
+ +
+
+
+
+
+ + + + +