From 8d45670c2f6956c1ac226e7253a9f8c3ca8974c0 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Wed, 10 Sep 2025 20:32:30 +0000 Subject: [PATCH] Ver 1 --- admin/delete_product.php | 46 +++ admin/edit_product.php | 98 ++++++ admin/index.php | 105 +++++++ admin/logout.php | 6 + admin/save_product.php | 52 ++++ assets/css/custom.css | 110 +++++++ assets/js/main.js | 64 ++++ db/migrate.php | 43 +++ db/migrations/001_create_users_table.sql | 7 + db/migrations/002_create_products_table.sql | 10 + db/seed.php | 29 ++ index.php | 323 ++++++++++++-------- login.php | 93 ++++++ 13 files changed, 860 insertions(+), 126 deletions(-) create mode 100644 admin/delete_product.php create mode 100644 admin/edit_product.php create mode 100644 admin/index.php create mode 100644 admin/logout.php create mode 100644 admin/save_product.php create mode 100644 assets/css/custom.css create mode 100644 assets/js/main.js create mode 100644 db/migrate.php create mode 100644 db/migrations/001_create_users_table.sql create mode 100644 db/migrations/002_create_products_table.sql create mode 100644 db/seed.php create mode 100644 login.php diff --git a/admin/delete_product.php b/admin/delete_product.php new file mode 100644 index 0000000..130c3f4 --- /dev/null +++ b/admin/delete_product.php @@ -0,0 +1,46 @@ +prepare("SELECT stock_quantity FROM products WHERE id = ?"); + $stmt->execute([$product_id]); + $product = $stmt->fetch(PDO::FETCH_ASSOC); + + if ($product) { + if ((int)$product['stock_quantity'] === 0) { + // Stock is 0, so it's safe to delete + $delete_stmt = $pdo->prepare("DELETE FROM products WHERE id = ?"); + if ($delete_stmt->execute([$product_id])) { + $_SESSION['success_message'] = 'Product deleted successfully.'; + } else { + $_SESSION['error_message'] = 'Failed to delete product.'; + } + } else { + // Stock is not 0, prevent deletion + $_SESSION['error_message'] = 'Cannot delete product because it is not out of stock.'; + } + } else { + $_SESSION['error_message'] = 'Product not found.'; + } + } else { + $_SESSION['error_message'] = 'Invalid product ID.'; + } +} else { + $_SESSION['error_message'] = 'Invalid request method.'; +} + +header('Location: index.php'); +exit; diff --git a/admin/edit_product.php b/admin/edit_product.php new file mode 100644 index 0000000..ff650f1 --- /dev/null +++ b/admin/edit_product.php @@ -0,0 +1,98 @@ + '', + 'name' => '', + 'description' => '', + 'price' => '', + 'stock_quantity' => '', + 'image_url' => '' +]; +$pageTitle = 'Add New Product'; + +if (isset($_GET['id'])) { + $pageTitle = 'Edit Product'; + $pdo = db(); + $stmt = $pdo->prepare('SELECT * FROM products WHERE id = ?'); + $stmt->execute([$_GET['id']]); + $product = $stmt->fetch(PDO::FETCH_ASSOC); + + if (!$product) { + $_SESSION['error_message'] = 'Product not found.'; + header('Location: index.php'); + exit; + } +} +?> + + + + + + <?php echo $pageTitle; ?> - GiftShop Admin + + + + + +
+
+
+ + +
+
+
+ + + + +
+ + +
+
+ + +
+
+
+ + +
+
+ + +
+
+
+ + +
+ + +
+
+
+
+
+
+ + + + \ No newline at end of file diff --git a/admin/index.php b/admin/index.php new file mode 100644 index 0000000..a48877f --- /dev/null +++ b/admin/index.php @@ -0,0 +1,105 @@ +query('SELECT * FROM products ORDER BY created_at DESC'); +$products = $stmt->fetchAll(PDO::FETCH_ASSOC); +?> + + + + + + Admin Dashboard - GiftShop + + + + + + +
+
+

Product Management

+ + Add New Product + +
+ + +
+ +
+ + +
+ +
+ + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
NamePriceStockActions
No products found.
$ + + Edit + +
+ + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/admin/logout.php b/admin/logout.php new file mode 100644 index 0000000..d2a43de --- /dev/null +++ b/admin/logout.php @@ -0,0 +1,6 @@ +prepare($sql); + $stmt->execute([$name, $description, $price, $stock_quantity, $image_url, $id]); + $_SESSION['success_message'] = 'Product updated successfully.'; + } else { + // Insert new product + $sql = "INSERT INTO products (name, description, price, stock_quantity, image_url) VALUES (?, ?, ?, ?, ?)"; + $stmt = $pdo->prepare($sql); + $stmt->execute([$name, $description, $price, $stock_quantity, $image_url]); + $_SESSION['success_message'] = 'Product added successfully.'; + } + } catch (PDOException $e) { + // In a real app, you would log this error, not show it to the user + $_SESSION['error_message'] = 'Database error. Could not save product.'; + } + +} else { + $_SESSION['error_message'] = 'Invalid request method.'; +} + +header('Location: index.php'); +exit; diff --git a/assets/css/custom.css b/assets/css/custom.css new file mode 100644 index 0000000..60f19dc --- /dev/null +++ b/assets/css/custom.css @@ -0,0 +1,110 @@ + +/* assets/css/custom.css */ +@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600;700&family=Lato:wght@400;700&display=swap'); + +:root { + --primary-color: #DF7E6B; + --secondary-color: #F6C390; + --background-color: #FCF8F3; + --surface-color: #FFFFFF; + --text-color: #333333; + --border-radius: 0.5rem; +} + +body { + font-family: 'Lato', sans-serif; + background-color: var(--background-color); + color: var(--text-color); +} + +h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 { + font-family: 'Poppins', sans-serif; + font-weight: 600; +} + +.btn-primary { + background-color: var(--primary-color); + border-color: var(--primary-color); + border-radius: var(--border-radius); + padding: 0.75rem 1.5rem; + transition: all 0.3s ease; +} + +.btn-primary:hover { + opacity: 0.9; + transform: translateY(-2px); +} + +.btn-secondary { + background-color: transparent; + border-color: var(--primary-color); + color: var(--primary-color); + border-radius: var(--border-radius); + padding: 0.75rem 1.5rem; + transition: all 0.3s ease; +} + +.btn-secondary:hover { + background-color: var(--primary-color); + color: var(--surface-color); +} + +.navbar { + transition: padding 0.3s ease-in-out, background-color 0.3s ease-in-out; +} + +.navbar.scrolled { + padding-top: 0.5rem; + padding-bottom: 0.5rem; + background-color: rgba(255, 255, 255, 0.95); + box-shadow: 0 2px 10px rgba(0,0,0,0.1); +} + +.navbar-brand { + font-family: 'Poppins', sans-serif; + font-weight: 700; + color: var(--primary-color) !important; +} + +.hero { + padding: 6rem 0; + background-image: linear-gradient(135deg, rgba(246, 195, 144, 0.8), rgba(223, 126, 107, 0.8)), url('https://picsum.photos/seed/giftshop-hero/1600/900'); + background-size: cover; + background-position: center; + color: white; +} + +.hero h1 { + font-size: 3.5rem; + font-weight: 700; +} + +.section-icon { + font-size: 3rem; + color: var(--primary-color); +} + +.card { + border: none; + border-radius: var(--border-radius); + box-shadow: 0 4px 15px rgba(0,0,0,0.07); + transition: transform 0.3s ease, box-shadow 0.3s ease; +} + +.card:hover { + transform: translateY(-5px); + box-shadow: 0 8px 25px rgba(0,0,0,0.1); +} + +.testimonial-card .avatar { + width: 80px; + height: 80px; + border-radius: 50%; + object-fit: cover; + margin-top: -40px; + border: 4px solid var(--surface-color); +} + +footer { + background-color: var(--surface-color); +} diff --git a/assets/js/main.js b/assets/js/main.js new file mode 100644 index 0000000..6f79034 --- /dev/null +++ b/assets/js/main.js @@ -0,0 +1,64 @@ + +document.addEventListener('DOMContentLoaded', function () { + const navbar = document.querySelector('.navbar'); + const contactForm = document.querySelector('#contactForm'); + + // Navbar shrink on scroll + window.addEventListener('scroll', () => { + if (window.scrollY > 50) { + navbar.classList.add('scrolled'); + } else { + navbar.classList.remove('scrolled'); + } + }); + + // Smooth scrolling for anchor links + document.querySelectorAll('a[href^="#"]').forEach(anchor => { + anchor.addEventListener('click', function (e) { + e.preventDefault(); + const targetId = this.getAttribute('href'); + const targetElement = document.querySelector(targetId); + if(targetElement){ + targetElement.scrollIntoView({ behavior: 'smooth' }); + } + }); + }); + + // Basic form validation + if (contactForm) { + contactForm.addEventListener('submit', function(e) { + e.preventDefault(); + let isValid = true; + const name = document.getElementById('name'); + const email = document.getElementById('email'); + const message = document.getElementById('message'); + + // Reset validation + [name, email, message].forEach(el => { + el.classList.remove('is-invalid'); + }); + + if (name.value.trim() === '') { + name.classList.add('is-invalid'); + isValid = false; + } + if (!/^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/.test(email.value)) { + email.classList.add('is-invalid'); + isValid = false; + } + if (message.value.trim() === '') { + message.classList.add('is-invalid'); + isValid = false; + } + + if (isValid) { + // On a real site, you'd send this data to the server. + // For this demo, we'll just show a success message. + document.querySelector('#form-feedback').innerHTML = '
Thank you for your message! We will get back to you shortly.
'; + contactForm.reset(); + } else { + document.querySelector('#form-feedback').innerHTML = ''; + } + }); + } +}); diff --git a/db/migrate.php b/db/migrate.php new file mode 100644 index 0000000..89eb3ab --- /dev/null +++ b/db/migrate.php @@ -0,0 +1,43 @@ +exec('CREATE TABLE IF NOT EXISTS migrations (id INT AUTO_INCREMENT PRIMARY KEY, migration VARCHAR(255) NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)'); + + // Get all executed migrations + $stmt = $pdo->query('SELECT migration FROM migrations'); + $executedMigrations = $stmt ? $stmt->fetchAll(PDO::FETCH_COLUMN) : []; + + // Find all migration files + $migrationFiles = glob(__DIR__ . '/migrations/*.sql') ?: []; + sort($migrationFiles); + + $migrationsRun = false; + // Run pending migrations + foreach ($migrationFiles as $migrationFile) { + $migrationName = basename($migrationFile); + if (!in_array($migrationName, $executedMigrations)) { + $sql = file_get_contents($migrationFile); + if (!empty(trim($sql))) { + $pdo->exec($sql); + + // Log the migration + $stmt = $pdo->prepare('INSERT INTO migrations (migration) VALUES (?)'); + $stmt->execute([$migrationName]); + + echo "Migration from $migrationName ran successfully.\n"; + $migrationsRun = true; + } + } + } + + if (!$migrationsRun) { + echo "All migrations are up to date.\n"; + } + +} catch (PDOException $e) { + die("DB ERROR: " . $e->getMessage()); +} \ No newline at end of file diff --git a/db/migrations/001_create_users_table.sql b/db/migrations/001_create_users_table.sql new file mode 100644 index 0000000..4eece16 --- /dev/null +++ b/db/migrations/001_create_users_table.sql @@ -0,0 +1,7 @@ +CREATE TABLE IF NOT EXISTS users ( + id INT AUTO_INCREMENT PRIMARY KEY, + username VARCHAR(255) NOT NULL UNIQUE, + password VARCHAR(255) NOT NULL, + role VARCHAR(50) NOT NULL DEFAULT 'admin', + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); \ No newline at end of file diff --git a/db/migrations/002_create_products_table.sql b/db/migrations/002_create_products_table.sql new file mode 100644 index 0000000..239db46 --- /dev/null +++ b/db/migrations/002_create_products_table.sql @@ -0,0 +1,10 @@ +CREATE TABLE IF NOT EXISTS products ( + id INT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(255) NOT NULL, + description TEXT, + price DECIMAL(10, 2) NOT NULL, + stock_quantity INT NOT NULL DEFAULT 0, + image_url VARCHAR(255), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +); diff --git a/db/seed.php b/db/seed.php new file mode 100644 index 0000000..3b297ff --- /dev/null +++ b/db/seed.php @@ -0,0 +1,29 @@ +prepare("SELECT id FROM users WHERE username = 'admin'"); + $stmt->execute(); + if ($stmt->fetch()) { + echo "Admin user already exists.\n"; + } else { + $username = 'admin'; + $password = 'password'; // You should change this! + $hashed_password = password_hash($password, PASSWORD_DEFAULT); + $role = 'super_admin'; + + $stmt = $pdo->prepare("INSERT INTO users (username, password, role) VALUES (:username, :password, :role)"); + $stmt->bindParam(':username', $username); + $stmt->bindParam(':password', $hashed_password); + $stmt->bindParam(':role', $role); + $stmt->execute(); + echo "Default admin user created with username 'admin' and password 'password'.\n"; + } + +} catch (PDOException $e) { + die("DB ERROR: " . $e->getMessage()); +} + diff --git a/index.php b/index.php index e13ae95..8839fcb 100644 --- a/index.php +++ b/index.php @@ -1,131 +1,202 @@ - - + - - - New Style - - - - + + + GiftShop - Gifts for Every Occasion + + + + + + + + + -
-
-

Analyzing your requirements and generating your website…

-
- Loading… -
-

Flatlogic AI is collecting your requirements and applying the first changes.

-

This page will update automatically as the plan is implemented.

-

Runtime: PHP — UTC

-
-
- + + + + + +
+
+

Gifts for Every Occasion.

+

Discover unique flowers, candies, books, and more. Perfectly packaged and delivered with care.

+ Browse Catalog + Contact Us +
+
+ + +
+
+
+
+ +

Wide Variety

+

From fresh flowers to unique home goods, find the perfect present for anyone.

+
+
+ +

Custom Packaging

+

Make your gift extra special with our beautiful and creative packaging options.

+
+
+ +

Fast Delivery

+

We ensure your gifts are delivered quickly and with the utmost care across Poland.

+
+
+
+
+ + +
+
+
+

Our Presents

+

A glimpse into our curated collection.

+
+
+
+
+ A vibrant bouquet of fresh flowers. +
+
Flowers
+

Stunning bouquets for any celebration.

+
+
+
+
+
+ An assortment of colorful, artisanal candies. +
+
Candies & Sweets
+

Delicious treats to sweeten their day.

+
+
+
+
+
+ A stack of books tied with a ribbon. +
+
Books & Stationery
+

Inspiring reads and beautiful paper goods.

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

What Our Customers Say

+
+
+
+
+ Customer avatar +
+

"The most beautiful gift basket I've ever received! The quality and presentation were top-notch."

+
Anna K.
+
+
+
+
+
+ Customer avatar +
+

"Fast delivery and the flowers were so fresh. My go-to for last-minute gifts!"

+
Piotr Z.
+
+
+
+
+
+ Customer avatar +
+

"I love the unique items you can't find anywhere else. Highly recommended!"

+
Ewa N.
+
+
+
+
+
+
+ + +
+
+
+

Get In Touch

+

Have a question or a special request? Let us know!

+
+
+
+
+
+
+ + +
Please enter your name.
+
+
+ + +
Please enter a valid email address.
+
+
+ + +
Please enter your message.
+
+
+ +
+
+
+
+
+
+ + + + + + + + - + \ No newline at end of file diff --git a/login.php b/login.php new file mode 100644 index 0000000..0704bb2 --- /dev/null +++ b/login.php @@ -0,0 +1,93 @@ +prepare("SELECT * FROM users WHERE username = :username"); + $stmt->bindParam(':username', $username); + $stmt->execute(); + $user = $stmt->fetch(); + + if ($user && password_verify($password, $user['password'])) { + // Password is correct, start session + $_SESSION['user_id'] = $user['id']; + $_SESSION['username'] = $user['username']; + $_SESSION['user_role'] = $user['role']; + + // Redirect to admin dashboard + header('Location: admin/index.php'); + exit; + } else { + $error_message = 'Invalid username or password.'; + } + } catch (PDOException $e) { + $error_message = 'Database error: ' . $e->getMessage(); + } + } +} +?> + + + + + + Admin Login - GiftShop + + + + + +
+
+

Admin Login

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