diff --git a/assets/css/custom.css b/assets/css/custom.css
new file mode 100644
index 0000000..1bfc8ad
--- /dev/null
+++ b/assets/css/custom.css
@@ -0,0 +1,143 @@
+@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700;900&display=swap');
+
+:root {
+ --primary-color: #5A67D8;
+ --secondary-color: #38B2AC;
+ --text-color: #2D3748;
+ --bg-gradient-start: #f5f7fa;
+ --bg-gradient-end: #c3cfe2;
+ --card-bg: rgba(255, 255, 255, 0.6);
+ --card-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.1);
+ --card-border: rgba(255, 255, 255, 0.18);
+}
+
+body {
+ font-family: 'Inter', sans-serif;
+ background: linear-gradient(135deg, var(--bg-gradient-start) 0%, var(--bg-gradient-end) 100%);
+ color: var(--text-color);
+ min-height: 100vh;
+}
+
+.navbar-sticky {
+ position: sticky;
+ top: 0;
+ z-index: 1020;
+ background: rgba(255, 255, 255, 0.8);
+ backdrop-filter: blur(10px);
+ -webkit-backdrop-filter: blur(10px);
+ border-bottom: 1px solid rgba(0,0,0,.1);
+ transition: background 0.3s ease-in-out, box-shadow 0.3s ease-in-out;
+}
+
+.navbar-sticky.scrolled {
+ background: rgba(255, 255, 255, 0.95);
+ box-shadow: 0 4px 6px rgba(0,0,0,0.05);
+}
+
+.brand-logo {
+ font-weight: 900;
+ font-size: 1.75rem;
+ color: var(--primary-color);
+}
+
+.hero-section {
+ padding: 6rem 0;
+}
+
+.hero-title {
+ font-weight: 900;
+ font-size: 3.5rem;
+}
+
+.hero-subtitle {
+ font-size: 1.25rem;
+ color: #4A5568;
+}
+
+.search-bar-wrapper {
+ position: relative;
+ max-width: 600px;
+ margin: 2rem auto;
+}
+
+.search-input {
+ border-radius: 50px;
+ border: 1px solid #E2E8F0;
+ padding: 1rem 2rem 1rem 3.5rem;
+ font-size: 1.1rem;
+ transition: all 0.3s ease-in-out;
+ box-shadow: 0 4px 6px rgba(0,0,0,0.05);
+}
+
+.search-input:focus {
+ box-shadow: 0 8px 25px rgba(0,0,0,0.1);
+ transform: translateY(-2px);
+ border-color: var(--primary-color);
+}
+
+.search-icon {
+ position: absolute;
+ left: 1.25rem;
+ top: 50%;
+ transform: translateY(-50%);
+ color: #A0AEC0;
+}
+
+.category-card {
+ background: var(--card-bg);
+ border-radius: 1rem;
+ border: 1px solid var(--card-border);
+ box-shadow: var(--card-shadow);
+ backdrop-filter: blur(8px);
+ -webkit-backdrop-filter: blur(8px);
+ padding: 2rem;
+ text-align: center;
+ transition: all 0.3s ease-in-out;
+ text-decoration: none;
+ color: var(--text-color);
+ overflow: hidden;
+ position: relative;
+}
+
+.category-card:before {
+ content: '';
+ position: absolute;
+ top: -50%;
+ left: -50%;
+ width: 200%;
+ height: 200%;
+ background: radial-gradient(circle, rgba(255,255,255,0.4) 0%, rgba(255,255,255,0) 60%);
+ transform: scale(0);
+ transition: transform 0.5s ease;
+}
+
+
+.category-card:hover {
+ transform: translateY(-10px) scale(1.03);
+ box-shadow: 0 16px 40px rgba(31, 38, 135, 0.15);
+}
+
+.category-card:hover:before {
+ transform: scale(1);
+}
+
+.category-card .card-icon {
+ font-size: 3rem;
+ margin-bottom: 1rem;
+ color: var(--primary-color);
+ transition: color 0.3s ease;
+}
+
+.category-card:hover .card-icon {
+ color: var(--secondary-color);
+}
+
+.card-title {
+ font-weight: 700;
+ font-size: 1.25rem;
+}
+
+.footer {
+ background: transparent;
+ border-top: 1px solid rgba(0,0,0,.05);
+}
\ No newline at end of file
diff --git a/assets/js/main.js b/assets/js/main.js
new file mode 100644
index 0000000..c426493
--- /dev/null
+++ b/assets/js/main.js
@@ -0,0 +1,13 @@
+
+document.addEventListener('DOMContentLoaded', function () {
+ const navbar = document.querySelector('.navbar-sticky');
+ if (navbar) {
+ window.addEventListener('scroll', function () {
+ if (window.scrollY > 20) {
+ navbar.classList.add('scrolled');
+ } else {
+ navbar.classList.remove('scrolled');
+ }
+ });
+ }
+});
diff --git a/category.php b/category.php
new file mode 100644
index 0000000..6fc874b
--- /dev/null
+++ b/category.php
@@ -0,0 +1,170 @@
+prepare("SELECT * FROM categories WHERE slug = ?");
+$stmt->execute([$category_slug]);
+$category = $stmt->fetch(PDO::FETCH_ASSOC);
+
+if (!$category) {
+ die("Category not found.");
+}
+
+$sort = $_GET['sort'] ?? 'popularity'; // New default for categories
+$filter_brand = $_GET['filter_brand'] ?? '';
+
+$results = [];
+$brands = [];
+
+// Get all products in this category
+$sql = "SELECT p.id, p.name, p.brand, p.image_url FROM products p WHERE p.category_id = ?";
+$params = [$category['id']];
+
+// Get all possible brands for the current category
+$brand_stmt = $pdo->prepare("SELECT DISTINCT brand FROM products WHERE category_id = ? AND brand IS NOT NULL ORDER BY brand");
+$brand_stmt->execute([$category['id']]);
+$brands = $brand_stmt->fetchAll(PDO::FETCH_COLUMN);
+
+// Add brand filter
+if (!empty($filter_brand)) {
+ $sql .= " AND p.brand = ?";
+ $params[] = $filter_brand;
+}
+
+// Sorting logic for category page
+switch ($sort) {
+ case 'price_asc':
+ $sql .= " ORDER BY (SELECT MIN(effective_price) FROM product_listings WHERE product_id = p.id) ASC";
+ break;
+ case 'price_desc':
+ $sql .= " ORDER BY (SELECT MIN(effective_price) FROM product_listings WHERE product_id = p.id) DESC";
+ break;
+ case 'rating':
+ $sql .= " ORDER BY (SELECT AVG(rating) FROM product_listings WHERE product_id = p.id) DESC";
+ break;
+ default: // Popularity/relevance for categories could be based on number of listings or other metrics
+ $sql .= " ORDER BY p.id DESC"; // Simple default: newest products first
+ break;
+}
+
+$stmt = $pdo->prepare($sql);
+$stmt->execute($params);
+$products = $stmt->fetchAll(PDO::FETCH_ASSOC);
+
+$product_ids = array_column($products, 'id');
+if (!empty($product_ids)) {
+ $placeholders = implode(',', array_fill(0, count($product_ids), '?'));
+ $stmt = $pdo->prepare("SELECT *, pl.id as listing_id, plat.name as platform_name FROM product_listings pl JOIN platforms plat ON pl.platform_id = plat.id WHERE pl.product_id IN ($placeholders)");
+ $stmt->execute($product_ids);
+ $listings = $stmt->fetchAll(PDO::FETCH_ASSOC);
+
+ $listings_by_product = [];
+ foreach ($listings as $listing) {
+ $listings_by_product[$listing['product_id']][] = $listing;
+ }
+
+ foreach ($products as $product) {
+ $product['listings'] = $listings_by_product[$product['id']] ?? [];
+ if (!empty($product['listings'])) {
+ $cheapest = array_reduce($product['listings'], fn($c, $i) => ($c === null || $i['effective_price'] < $c['effective_price']) ? $i : $c);
+ $product['cheapest_price'] = $cheapest['effective_price'];
+ $product['badge'] = $cheapest['badge'];
+ }
+ $results[] = $product;
+ }
+}
+
+?>
+
+
+
+
+
+ - XUPER MALL
+
+
+
+
+
+
← Back to Home
+
+
+
+
+
+
No products found in this category yet.
+
+
+
+
+
+
+
+
![<?php echo htmlspecialchars($product['name']); ?>](<?php echo htmlspecialchars($product['image_url'] ?? 'https://via.placeholder.com/150'); ?>)
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..52e2849
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,5 @@
+{
+ "require": {
+ "fakerphp/faker": "^1.24"
+ }
+}
diff --git a/composer.lock b/composer.lock
new file mode 100644
index 0000000..cc87a9e
--- /dev/null
+++ b/composer.lock
@@ -0,0 +1,202 @@
+{
+ "_readme": [
+ "This file locks the dependencies of your project to a known state",
+ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
+ "This file is @generated automatically"
+ ],
+ "content-hash": "0ac0340f2120a65e4928bde600db496b",
+ "packages": [
+ {
+ "name": "fakerphp/faker",
+ "version": "v1.24.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/FakerPHP/Faker.git",
+ "reference": "e0ee18eb1e6dc3cda3ce9fd97e5a0689a88a64b5"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/e0ee18eb1e6dc3cda3ce9fd97e5a0689a88a64b5",
+ "reference": "e0ee18eb1e6dc3cda3ce9fd97e5a0689a88a64b5",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.4 || ^8.0",
+ "psr/container": "^1.0 || ^2.0",
+ "symfony/deprecation-contracts": "^2.2 || ^3.0"
+ },
+ "conflict": {
+ "fzaninotto/faker": "*"
+ },
+ "require-dev": {
+ "bamarni/composer-bin-plugin": "^1.4.1",
+ "doctrine/persistence": "^1.3 || ^2.0",
+ "ext-intl": "*",
+ "phpunit/phpunit": "^9.5.26",
+ "symfony/phpunit-bridge": "^5.4.16"
+ },
+ "suggest": {
+ "doctrine/orm": "Required to use Faker\\ORM\\Doctrine",
+ "ext-curl": "Required by Faker\\Provider\\Image to download images.",
+ "ext-dom": "Required by Faker\\Provider\\HtmlLorem for generating random HTML.",
+ "ext-iconv": "Required by Faker\\Provider\\ru_RU\\Text::realText() for generating real Russian text.",
+ "ext-mbstring": "Required for multibyte Unicode string functionality."
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Faker\\": "src/Faker/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "François Zaninotto"
+ }
+ ],
+ "description": "Faker is a PHP library that generates fake data for you.",
+ "keywords": [
+ "data",
+ "faker",
+ "fixtures"
+ ],
+ "support": {
+ "issues": "https://github.com/FakerPHP/Faker/issues",
+ "source": "https://github.com/FakerPHP/Faker/tree/v1.24.1"
+ },
+ "time": "2024-11-21T13:46:39+00:00"
+ },
+ {
+ "name": "psr/container",
+ "version": "2.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/container.git",
+ "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963",
+ "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.4.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Container\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "Common Container Interface (PHP FIG PSR-11)",
+ "homepage": "https://github.com/php-fig/container",
+ "keywords": [
+ "PSR-11",
+ "container",
+ "container-interface",
+ "container-interop",
+ "psr"
+ ],
+ "support": {
+ "issues": "https://github.com/php-fig/container/issues",
+ "source": "https://github.com/php-fig/container/tree/2.0.2"
+ },
+ "time": "2021-11-05T16:47:00+00:00"
+ },
+ {
+ "name": "symfony/deprecation-contracts",
+ "version": "v3.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/deprecation-contracts.git",
+ "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62",
+ "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/contracts",
+ "name": "symfony/contracts"
+ },
+ "branch-alias": {
+ "dev-main": "3.6-dev"
+ }
+ },
+ "autoload": {
+ "files": [
+ "function.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "A generic function and convention to trigger deprecation notices",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-09-25T14:21:43+00:00"
+ }
+ ],
+ "packages-dev": [],
+ "aliases": [],
+ "minimum-stability": "stable",
+ "stability-flags": {},
+ "prefer-stable": false,
+ "prefer-lowest": false,
+ "platform": {},
+ "platform-dev": {},
+ "plugin-api-version": "2.9.0"
+}
diff --git a/composer.phar b/composer.phar
new file mode 100755
index 0000000..02740c5
Binary files /dev/null and b/composer.phar differ
diff --git a/db/migrations/001_initial_schema.php b/db/migrations/001_initial_schema.php
new file mode 100644
index 0000000..b32251f
--- /dev/null
+++ b/db/migrations/001_initial_schema.php
@@ -0,0 +1,71 @@
+exec($sql);
+ echo "Database schema created successfully." . PHP_EOL;
+ } catch (PDOException $e) {
+ die("Error creating schema: " . $e->getMessage());
+ }
+}
+
+// If this script is run directly, execute the migration.
+if (basename(__FILE__) == basename($_SERVER["SCRIPT_FILENAME"])) {
+ migrate_001_initial_schema();
+}
diff --git a/db/seeders/seed_categories.php b/db/seeders/seed_categories.php
new file mode 100644
index 0000000..d61d798
--- /dev/null
+++ b/db/seeders/seed_categories.php
@@ -0,0 +1,23 @@
+ 'E-Commerce', 'slug' => 'ecommerce', 'icon_url' => 'shopping-bag'],
+ ['name' => 'Food Delivery', 'slug' => 'food', 'icon_url' => 'coffee'],
+ ['name' => 'Movie Tickets', 'slug' => 'movies', 'icon_url' => 'film'],
+ ['name' => '30-Min Delivery', 'slug' => 'delivery', 'icon_url' => 'truck'],
+ ];
+
+ $stmt = $pdo->prepare("INSERT INTO categories (name, slug, icon_url) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE name=VALUES(name)");
+
+ foreach ($categories as $category) {
+ $stmt->execute([$category['name'], $category['slug'], $category['icon_url']]);
+ }
+ echo "Categories seeded successfully." . PHP_EOL;
+}
+
+if (basename(__FILE__) == basename($_SERVER["SCRIPT_FILENAME"])) {
+ seed_categories();
+}
diff --git a/db/seeders/seed_platforms.php b/db/seeders/seed_platforms.php
new file mode 100644
index 0000000..8d7f944
--- /dev/null
+++ b/db/seeders/seed_platforms.php
@@ -0,0 +1,30 @@
+ 'Amazon', 'slug' => 'amazon', 'logo_url' => 'assets/images/logos/amazon.png'],
+ ['name' => 'Flipkart', 'slug' => 'flipkart', 'logo_url' => 'assets/images/logos/flipkart.png'],
+ ['name' => 'Myntra', 'slug' => 'myntra', 'logo_url' => 'assets/images/logos/myntra.png'],
+ ['name' => 'Zomato', 'slug' => 'zomato', 'logo_url' => 'assets/images/logos/zomato.png'],
+ ['name' => 'Swiggy', 'slug' => 'swiggy', 'logo_url' => 'assets/images/logos/swiggy.png'],
+ ['name' => 'Magicpin', 'slug' => 'magicpin', 'logo_url' => 'assets/images/logos/magicpin.png'],
+ ['name' => 'Blinkit', 'slug' => 'blinkit', 'logo_url' => 'assets/images/logos/blinkit.png'],
+ ['name' => 'Jiomart', 'slug' => 'jiomart', 'logo_url' => 'assets/images/logos/jiomart.png'],
+ ['name' => 'Instamart', 'slug' => 'instamart', 'logo_url' => 'assets/images/logos/instamart.png'],
+ ['name' => 'BookMyShow', 'slug' => 'bookmyshow', 'logo_url' => 'assets/images/logos/bookmyshow.png'],
+ ['name' => 'PaytmMovies', 'slug' => 'paytmmovies', 'logo_url' => 'assets/images/logos/paytmmovies.png'],
+ ['name' => 'PVR', 'slug' => 'pvr', 'logo_url' => 'assets/images/logos/pvr.png'],
+ ];
+
+ $stmt = $pdo->prepare("INSERT INTO platforms (name, slug, logo_url) VALUES (:name, :slug, :logo_url) ON DUPLICATE KEY UPDATE name=VALUES(name), slug=VALUES(slug), logo_url=VALUES(logo_url)");
+
+ foreach ($platforms as $platform) {
+ $stmt->execute($platform);
+ }
+
+ echo "Platforms seeded successfully.\n";
+}
+
+seed_platforms();
diff --git a/db/seeders/seed_product_listings.php b/db/seeders/seed_product_listings.php
new file mode 100644
index 0000000..eb78828
--- /dev/null
+++ b/db/seeders/seed_product_listings.php
@@ -0,0 +1,54 @@
+query("SELECT id FROM products")->fetchAll(PDO::FETCH_COLUMN);
+ $platform_ids = $pdo->query("SELECT id FROM platforms")->fetchAll(PDO::FETCH_COLUMN);
+
+ if (empty($product_ids) || empty($platform_ids)) {
+ echo "Please seed products and platforms first.\n";
+ return;
+ }
+
+ $listings = [];
+ foreach ($product_ids as $product_id) {
+ $num_listings = rand(1, count($platform_ids));
+ $used_platforms = [];
+ for ($i = 0; $i < $num_listings; $i++) {
+ $platform_id = $platform_ids[array_rand($platform_ids)];
+ if (in_array($platform_id, $used_platforms)) {
+ continue;
+ }
+ $used_platforms[] = $platform_id;
+
+ $original_price = $faker->randomFloat(2, 10, 1000);
+ $discounted_price = $original_price - $faker->randomFloat(2, 0, $original_price * 0.5);
+ $coupon_price = $discounted_price - $faker->randomFloat(2, 0, $discounted_price * 0.2);
+
+ $listings[] = [
+ 'product_id' => $product_id,
+ 'platform_id' => $platform_id,
+ 'original_price' => $original_price,
+ 'discounted_price' => $discounted_price,
+ 'coupon_price' => $coupon_price,
+ 'rating' => $faker->randomFloat(1, 1, 5),
+ 'product_url' => $faker->url,
+ ];
+ }
+ }
+
+ $stmt = $pdo->prepare("INSERT INTO product_listings (product_id, platform_id, original_price, discounted_price, coupon_price, rating, product_url) VALUES (:product_id, :platform_id, :original_price, :discounted_price, :coupon_price, :rating, :product_url)");
+
+ foreach ($listings as $listing) {
+ $stmt->execute($listing);
+ }
+
+ echo count($listings) . " product listings seeded successfully.\n";
+}
+
+seed_product_listings();
diff --git a/db/seeders/seed_products.php b/db/seeders/seed_products.php
new file mode 100644
index 0000000..10551a9
--- /dev/null
+++ b/db/seeders/seed_products.php
@@ -0,0 +1,39 @@
+query("SELECT id FROM categories");
+ $category_ids = $stmt->fetchAll(PDO::FETCH_COLUMN);
+
+ if (empty($category_ids)) {
+ echo "Please seed categories first.\n";
+ return;
+ }
+
+ $products = [];
+ for ($i = 0; $i < 300; $i++) {
+ $products[] = [
+ 'name' => $faker->words(3, true),
+ 'brand' => $faker->company,
+ 'category_id' => $category_ids[array_rand($category_ids)],
+ 'subcategory' => $faker->word,
+ 'image_url' => $faker->imageUrl(640, 480, 'technics', true),
+ ];
+ }
+
+ $stmt = $pdo->prepare("INSERT INTO products (name, brand, category_id, subcategory, image_url) VALUES (:name, :brand, :category_id, :subcategory, :image_url)");
+
+ foreach ($products as $product) {
+ $stmt->execute($product);
+ }
+
+ echo "300 products seeded successfully.\n";
+}
+
+seed_products();
+
diff --git a/index.php b/index.php
index 7205f3d..b686150 100644
--- a/index.php
+++ b/index.php
@@ -1,150 +1,112 @@
-
-
+
-
-
- New Style
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+ XUPER MALL - Real-Time Price Comparison
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
Analyzing your requirements and generating your website…
-
- Loading…
-
-
= ($_SERVER['HTTP_HOST'] ?? '') === 'appwizzy.com' ? 'AppWizzy' : 'Flatlogic' ?> AI is collecting your requirements and applying the first changes.
-
This page will update automatically as the plan is implemented.
-
Runtime: PHP = htmlspecialchars($phpVersion) ?> — UTC = htmlspecialchars($now) ?>
-
-
-
+
+
+
+
+
+
+
Find it. Compare it. Save on it.
+
Your ultimate real-time price comparison hub.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+