diff --git a/admin/order.php b/admin/order.php
new file mode 100644
index 0000000..5327bc6
--- /dev/null
+++ b/admin/order.php
@@ -0,0 +1,65 @@
+ 0) {
+ $stmt = db()->prepare('SELECT * FROM orders WHERE id = :id');
+ $stmt->execute([':id' => $orderId]);
+ $order = $stmt->fetch();
+ if ($order) {
+ $items = get_order_items((int) $order['id']);
+ }
+}
+
+render_header('Order Detail - E-SO9', 'admin');
+?>
+
+ Back to orders
+ Order detail
+
+
+ Order not found.
+
+
+
+
+
Order number
+
= e($order['order_number']) ?>
+
Customer
+
= e($order['customer_name']) ?>
+
= e($order['customer_email']) ?>
+
= e($order['customer_address']) ?>
+
Status
+
= e($order['status']) ?>
+
+
+
+
+
Items
+
+
No items recorded.
+
+
+
+ -
+ = e($item['name']) ?> x = e((string) $item['quantity']) ?>
+ = e(format_price((float) $item['price'])) ?>
+
+
+
+
+
+ Total
+ = e(format_price((float) $order['total_price'])) ?>
+
+
+
+
+
+
+
diff --git a/admin/orders.php b/admin/orders.php
new file mode 100644
index 0000000..0ac57aa
--- /dev/null
+++ b/admin/orders.php
@@ -0,0 +1,109 @@
+ 0 && in_array($status, $statuses, true)) {
+ update_order_status($orderId, $status);
+ flash_set('success', 'Order status updated.');
+ }
+ header('Location: /admin/orders.php');
+ exit;
+}
+
+$orders = get_orders();
+
+render_header('Admin Orders - E-SO9', 'admin');
+?>
+
+
+
+
Admin orders
+
Update order statuses and monitor totals.
+
+
Demo admin area. No authentication yet.
+
+
+
+
+
+
Total orders
+
= e((string) count($orders)) ?>
+
+
+
+
+
Total revenue
+
+
+ = e(format_price($revenue)) ?>
+
+
+
+
+
+
Latest status
+
= $orders ? e($orders[0]['status']) : 'N/A' ?>
+
+
+
+
+
+ No orders yet. Place a demo order to see entries.
+
+
+
+
+
+ | Order |
+ Customer |
+ Total |
+ Status |
+ Update |
+
+
+
+
+
+ |
+ = e($order['order_number']) ?>
+ = e($order['created_at']) ?>
+ |
+
+ = e($order['customer_name']) ?>
+ = e($order['customer_email']) ?>
+ |
+ = e(format_price((float) $order['total_price'])) ?> |
+
+ = e($order['status']) ?>
+ |
+
+
+ |
+
+
+
+
+
+
+
+
diff --git a/assets/css/custom.css b/assets/css/custom.css
new file mode 100644
index 0000000..5eeb534
--- /dev/null
+++ b/assets/css/custom.css
@@ -0,0 +1,90 @@
+:root {
+ --bg: #f6f7f9;
+ --surface: #ffffff;
+ --surface-muted: #f1f3f6;
+ --border: #e2e5ea;
+ --text: #111827;
+ --muted: #6b7280;
+ --accent: #0f766e;
+ --accent-strong: #0b5f59;
+ --radius-sm: 6px;
+ --radius-md: 10px;
+}
+
+body {
+ font-family: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
+ background: var(--bg);
+ color: var(--text);
+}
+
+.navbar {
+ backdrop-filter: blur(10px);
+}
+
+.hero {
+ background: var(--surface);
+ border: 1px solid var(--border);
+ border-radius: var(--radius-md);
+ padding: 2.5rem 2rem;
+}
+
+.badge-soft {
+ background: var(--surface-muted);
+ color: var(--muted);
+ border: 1px solid var(--border);
+}
+
+.product-card {
+ border: 1px solid var(--border);
+ border-radius: var(--radius-md);
+ background: var(--surface);
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
+}
+
+.product-card:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 12px 30px rgba(15, 23, 42, 0.08);
+}
+
+.product-card img {
+ border-bottom: 1px solid var(--border);
+ border-top-left-radius: var(--radius-md);
+ border-top-right-radius: var(--radius-md);
+}
+
+.btn-primary {
+ background: var(--accent);
+ border-color: var(--accent);
+}
+
+.btn-primary:hover,
+.btn-primary:focus {
+ background: var(--accent-strong);
+ border-color: var(--accent-strong);
+}
+
+.form-control,
+.form-select {
+ border-radius: var(--radius-sm);
+ border-color: var(--border);
+}
+
+.stat-card {
+ background: var(--surface);
+ border: 1px solid var(--border);
+ border-radius: var(--radius-md);
+ padding: 1.25rem;
+}
+
+.table {
+ border-color: var(--border);
+}
+
+.admin-note {
+ background: var(--surface-muted);
+ border: 1px dashed var(--border);
+ border-radius: var(--radius-sm);
+ padding: 0.75rem 1rem;
+ font-size: 0.9rem;
+ color: var(--muted);
+}
diff --git a/assets/js/main.js b/assets/js/main.js
new file mode 100644
index 0000000..48c5292
--- /dev/null
+++ b/assets/js/main.js
@@ -0,0 +1,9 @@
+document.addEventListener('DOMContentLoaded', () => {
+ const toastEls = document.querySelectorAll('[data-toast="auto"]');
+ toastEls.forEach((el) => {
+ if (window.bootstrap && bootstrap.Toast) {
+ const toast = new bootstrap.Toast(el, { delay: 3500 });
+ toast.show();
+ }
+ });
+});
diff --git a/cart.php b/cart.php
new file mode 100644
index 0000000..6cf6c38
--- /dev/null
+++ b/cart.php
@@ -0,0 +1,100 @@
+ 0) {
+ if ($action === 'update') {
+ cart_update($productId, $quantity);
+ flash_set('success', 'Cart updated.');
+ } else {
+ cart_add($productId, $quantity);
+ flash_set('success', 'Item added to cart.');
+ }
+ }
+ header('Location: /cart.php');
+ exit;
+}
+
+$items = cart_items();
+$total = cart_total();
+
+render_header('Cart - E-SO9', 'cart');
+?>
+
+ Your cart
+
+
+ Your cart is empty. Browse products to get started.
+ Go to shop
+
+
+
+
+
+
+
+ | Product |
+ Price |
+ Qty |
+ Total |
+ |
+
+
+
+
+
+ |
+ = e($item['product']['name']) ?>
+ = e($item['product']['category_name'] ?? 'General') ?>
+ |
+ = e(format_price((float) $item['product']['price'])) ?> |
+
+
+ |
+ = e(format_price((float) $item['line_total'])) ?> |
+
+
+ |
+
+
+
+
+
+
+
+
+
+ Subtotal
+ = e(format_price((float) $total)) ?>
+
+
+ Shipping
+ $0.00
+
+
+ Total
+ = e(format_price((float) $total)) ?>
+
+
Proceed to checkout
+
+
+
+
+
+
diff --git a/checkout.php b/checkout.php
new file mode 100644
index 0000000..d0db103
--- /dev/null
+++ b/checkout.php
@@ -0,0 +1,97 @@
+ $name,
+ 'email' => $email,
+ 'address' => $address
+ ], $items);
+
+ if ($orderNumber) {
+ cart_clear();
+ flash_set('success', 'Order placed successfully.');
+ header('Location: /order.php?order=' . urlencode($orderNumber));
+ exit;
+ }
+ $errors[] = 'Unable to place the order. Try again.';
+ }
+}
+
+render_header('Checkout - E-SO9', 'cart');
+?>
+
+ Checkout
+
+
+ = e($error) ?>
+
+
+
+
+
+
+
Order summary
+
+
Add items to cart to continue.
+
+
+
+ -
+ = e($item['product']['name']) ?> x = e((string) $item['quantity']) ?>
+ = e(format_price((float) $item['line_total'])) ?>
+
+
+
+
+ Total
+ = e(format_price((float) cart_total())) ?>
+
+
+
+
+
+
+
diff --git a/includes/bootstrap.php b/includes/bootstrap.php
new file mode 100644
index 0000000..b4a9fbf
--- /dev/null
+++ b/includes/bootstrap.php
@@ -0,0 +1,26 @@
+ $type, 'message' => $message];
+}
+
+function flash_get(): ?array {
+ if (empty($_SESSION['flash'])) {
+ return null;
+ }
+ $flash = $_SESSION['flash'];
+ unset($_SESSION['flash']);
+ return $flash;
+}
diff --git a/includes/layout.php b/includes/layout.php
new file mode 100644
index 0000000..4e727a2
--- /dev/null
+++ b/includes/layout.php
@@ -0,0 +1,74 @@
+ $active === $key ? 'active' : '';
+ echo "\n";
+ echo "\n";
+ echo "
\n";
+ echo " \n";
+ echo " \n";
+ echo " " . e($title) . "\n";
+ if ($projectDescription) {
+ echo " \n";
+ echo " \n";
+ echo " \n";
+ }
+ if ($projectImageUrl) {
+ echo " \n";
+ echo " \n";
+ }
+ echo " \n";
+ echo " \n";
+ echo " \n";
+ echo " \n";
+ echo " \n";
+ echo "\n";
+ echo "\n";
+ echo "\n";
+}
+
+function render_footer(): void {
+ $flash = flash_get();
+ echo "\n";
+ echo "\n";
+ echo "\n";
+
+ if ($flash) {
+ $type = $flash['type'] === 'success' ? 'success' : 'warning';
+ echo "\n";
+ echo "
\n";
+ echo "
\n";
+ echo "
" . e($flash['message']) . "
\n";
+ echo "
\n";
+ echo "
\n";
+ echo "
\n";
+ echo "
\n";
+ }
+
+ echo "\n\n";
+}
diff --git a/includes/store.php b/includes/store.php
new file mode 100644
index 0000000..5dcedc8
--- /dev/null
+++ b/includes/store.php
@@ -0,0 +1,349 @@
+exec(
+ 'CREATE TABLE IF NOT EXISTS categories (
+ id INT AUTO_INCREMENT PRIMARY KEY,
+ name VARCHAR(120) NOT NULL,
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4'
+ );
+
+ $pdo->exec(
+ 'CREATE TABLE IF NOT EXISTS products (
+ id INT AUTO_INCREMENT PRIMARY KEY,
+ name VARCHAR(160) NOT NULL,
+ description TEXT NOT NULL,
+ price DECIMAL(10,2) NOT NULL,
+ stock INT NOT NULL DEFAULT 0,
+ rating DECIMAL(3,2) NOT NULL DEFAULT 0.00,
+ category_id INT NULL,
+ image_url VARCHAR(255) NULL,
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ INDEX (category_id)
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4'
+ );
+
+ $pdo->exec(
+ 'CREATE TABLE IF NOT EXISTS orders (
+ id INT AUTO_INCREMENT PRIMARY KEY,
+ order_number VARCHAR(20) NOT NULL,
+ customer_name VARCHAR(120) NOT NULL,
+ customer_email VARCHAR(160) NOT NULL,
+ customer_address VARCHAR(255) NOT NULL,
+ status VARCHAR(30) NOT NULL,
+ total_price DECIMAL(10,2) NOT NULL,
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ UNIQUE KEY (order_number)
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4'
+ );
+
+ $pdo->exec(
+ 'CREATE TABLE IF NOT EXISTS order_items (
+ id INT AUTO_INCREMENT PRIMARY KEY,
+ order_id INT NOT NULL,
+ product_id INT NOT NULL,
+ quantity INT NOT NULL,
+ price DECIMAL(10,2) NOT NULL,
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ INDEX (order_id),
+ INDEX (product_id)
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4'
+ );
+}
+
+function seed_data(): void {
+ $pdo = db();
+ $count = (int) $pdo->query('SELECT COUNT(*) FROM products')->fetchColumn();
+ if ($count > 0) {
+ return;
+ }
+
+ $categories = [
+ 'Apparel',
+ 'Electronics',
+ 'Moroccan Goods'
+ ];
+
+ $categoryStmt = $pdo->prepare('INSERT INTO categories (name) VALUES (:name)');
+ $categoryIds = [];
+ foreach ($categories as $name) {
+ $categoryStmt->execute([':name' => $name]);
+ $categoryIds[$name] = (int) $pdo->lastInsertId();
+ }
+
+ $products = [
+ [
+ 'name' => 'Atlas Hoodie',
+ 'description' => 'Midweight cotton hoodie with brushed interior and clean stitch detailing.',
+ 'price' => 79.00,
+ 'stock' => 24,
+ 'rating' => 4.6,
+ 'category' => 'Apparel'
+ ],
+ [
+ 'name' => 'Casablanca Sneakers',
+ 'description' => 'Everyday sneaker with cushioned sole and minimalist profile.',
+ 'price' => 98.00,
+ 'stock' => 18,
+ 'rating' => 4.4,
+ 'category' => 'Apparel'
+ ],
+ [
+ 'name' => 'Rabat Smartwatch',
+ 'description' => 'Slim fitness watch with sleep tracking and a 7-day battery.',
+ 'price' => 149.00,
+ 'stock' => 12,
+ 'rating' => 4.2,
+ 'category' => 'Electronics'
+ ],
+ [
+ 'name' => 'Sahara Bluetooth Speaker',
+ 'description' => 'Portable speaker with clean bass and long-lasting battery.',
+ 'price' => 129.00,
+ 'stock' => 10,
+ 'rating' => 4.3,
+ 'category' => 'Electronics'
+ ],
+ [
+ 'name' => 'Fez Copper Lamp',
+ 'description' => 'Hand-finished lamp with soft perforated light pattern.',
+ 'price' => 119.00,
+ 'stock' => 7,
+ 'rating' => 4.8,
+ 'category' => 'Moroccan Goods'
+ ],
+ [
+ 'name' => 'Agadir Ceramic Tagine',
+ 'description' => 'Glazed ceramic tagine for slow cooking and elegant serving.',
+ 'price' => 84.00,
+ 'stock' => 9,
+ 'rating' => 4.7,
+ 'category' => 'Moroccan Goods'
+ ]
+ ];
+
+ $productStmt = $pdo->prepare(
+ 'INSERT INTO products (name, description, price, stock, rating, category_id) VALUES (:name, :description, :price, :stock, :rating, :category_id)'
+ );
+
+ foreach ($products as $product) {
+ $productStmt->execute([
+ ':name' => $product['name'],
+ ':description' => $product['description'],
+ ':price' => $product['price'],
+ ':stock' => $product['stock'],
+ ':rating' => $product['rating'],
+ ':category_id' => $categoryIds[$product['category']] ?? null
+ ]);
+ }
+}
+
+function get_categories(): array {
+ $stmt = db()->query('SELECT id, name FROM categories ORDER BY name ASC');
+ return $stmt->fetchAll();
+}
+
+function get_products(?string $search = null, ?int $categoryId = null, ?string $sort = null): array {
+ $sql = 'SELECT p.*, c.name AS category_name FROM products p LEFT JOIN categories c ON c.id = p.category_id WHERE 1=1';
+ $params = [];
+
+ if ($search) {
+ $sql .= ' AND (p.name LIKE :search OR p.description LIKE :search)';
+ $params[':search'] = '%' . $search . '%';
+ }
+
+ if ($categoryId) {
+ $sql .= ' AND p.category_id = :category_id';
+ $params[':category_id'] = $categoryId;
+ }
+
+ switch ($sort) {
+ case 'price_asc':
+ $sql .= ' ORDER BY p.price ASC';
+ break;
+ case 'price_desc':
+ $sql .= ' ORDER BY p.price DESC';
+ break;
+ default:
+ $sql .= ' ORDER BY p.created_at DESC';
+ break;
+ }
+
+ $stmt = db()->prepare($sql);
+ $stmt->execute($params);
+ return $stmt->fetchAll();
+}
+
+function get_product(int $id): ?array {
+ $stmt = db()->prepare('SELECT p.*, c.name AS category_name FROM products p LEFT JOIN categories c ON c.id = p.category_id WHERE p.id = :id');
+ $stmt->execute([':id' => $id]);
+ $product = $stmt->fetch();
+ return $product ?: null;
+}
+
+function format_price(float $price): string {
+ return '$' . number_format($price, 2);
+}
+
+function product_image_data(string $label): string {
+ $clean = preg_replace('/[^A-Za-z0-9]/', '', $label);
+ $text = strtoupper(substr($clean, 0, 2));
+ if ($text === '') {
+ $text = 'ES';
+ }
+ $svg = "";
+ return 'data:image/svg+xml;utf8,' . rawurlencode($svg);
+}
+
+function cart_count(): int {
+ $cart = $_SESSION['cart'] ?? [];
+ return array_sum($cart);
+}
+
+function cart_items(): array {
+ $cart = $_SESSION['cart'] ?? [];
+ if (!$cart) {
+ return [];
+ }
+
+ $ids = array_keys($cart);
+ $placeholders = implode(',', array_fill(0, count($ids), '?'));
+ $stmt = db()->prepare(
+ "SELECT p.*, c.name AS category_name FROM products p LEFT JOIN categories c ON c.id = p.category_id WHERE p.id IN ($placeholders)"
+ );
+ $stmt->execute($ids);
+ $products = $stmt->fetchAll();
+ $indexed = [];
+ foreach ($products as $product) {
+ $indexed[(int) $product['id']] = $product;
+ }
+
+ $items = [];
+ foreach ($cart as $productId => $qty) {
+ $product = $indexed[(int) $productId] ?? null;
+ if (!$product) {
+ continue;
+ }
+ $lineTotal = ((float) $product['price']) * $qty;
+ $items[] = [
+ 'product' => $product,
+ 'quantity' => $qty,
+ 'line_total' => $lineTotal
+ ];
+ }
+ return $items;
+}
+
+function cart_total(): float {
+ $total = 0.0;
+ foreach (cart_items() as $item) {
+ $total += $item['line_total'];
+ }
+ return $total;
+}
+
+function cart_add(int $productId, int $quantity): void {
+ if ($quantity < 1) {
+ return;
+ }
+ $cart = $_SESSION['cart'] ?? [];
+ $cart[$productId] = ($cart[$productId] ?? 0) + $quantity;
+ $_SESSION['cart'] = $cart;
+}
+
+function cart_update(int $productId, int $quantity): void {
+ $cart = $_SESSION['cart'] ?? [];
+ if ($quantity < 1) {
+ unset($cart[$productId]);
+ } else {
+ $cart[$productId] = $quantity;
+ }
+ $_SESSION['cart'] = $cart;
+}
+
+function cart_clear(): void {
+ unset($_SESSION['cart']);
+}
+
+function create_order(array $customer, array $items): ?string {
+ if (!$items) {
+ return null;
+ }
+
+ $pdo = db();
+ $pdo->beginTransaction();
+
+ try {
+ $orderNumber = 'ES9-' . strtoupper(bin2hex(random_bytes(3)));
+ $total = 0.0;
+ foreach ($items as $item) {
+ $total += $item['line_total'];
+ }
+
+ $orderStmt = $pdo->prepare(
+ 'INSERT INTO orders (order_number, customer_name, customer_email, customer_address, status, total_price) VALUES (:order_number, :customer_name, :customer_email, :customer_address, :status, :total_price)'
+ );
+ $orderStmt->execute([
+ ':order_number' => $orderNumber,
+ ':customer_name' => $customer['name'],
+ ':customer_email' => $customer['email'],
+ ':customer_address' => $customer['address'],
+ ':status' => 'Processing',
+ ':total_price' => $total
+ ]);
+
+ $orderId = (int) $pdo->lastInsertId();
+
+ $itemStmt = $pdo->prepare(
+ 'INSERT INTO order_items (order_id, product_id, quantity, price) VALUES (:order_id, :product_id, :quantity, :price)'
+ );
+
+ foreach ($items as $item) {
+ $itemStmt->execute([
+ ':order_id' => $orderId,
+ ':product_id' => $item['product']['id'],
+ ':quantity' => $item['quantity'],
+ ':price' => $item['product']['price']
+ ]);
+ }
+
+ $pdo->commit();
+ return $orderNumber;
+ } catch (Throwable $e) {
+ $pdo->rollBack();
+ return null;
+ }
+}
+
+function get_order_by_number(string $orderNumber): ?array {
+ $stmt = db()->prepare('SELECT * FROM orders WHERE order_number = :order_number');
+ $stmt->execute([':order_number' => $orderNumber]);
+ $order = $stmt->fetch();
+ return $order ?: null;
+}
+
+function get_order_items(int $orderId): array {
+ $stmt = db()->prepare(
+ 'SELECT oi.*, p.name, p.description FROM order_items oi LEFT JOIN products p ON p.id = oi.product_id WHERE oi.order_id = :order_id'
+ );
+ $stmt->execute([':order_id' => $orderId]);
+ return $stmt->fetchAll();
+}
+
+function get_orders(): array {
+ $stmt = db()->query('SELECT * FROM orders ORDER BY created_at DESC');
+ return $stmt->fetchAll();
+}
+
+function update_order_status(int $orderId, string $status): void {
+ $stmt = db()->prepare('UPDATE orders SET status = :status WHERE id = :id');
+ $stmt->execute([':status' => $status, ':id' => $orderId]);
+}
diff --git a/index.php b/index.php
index 7205f3d..15dd489 100644
--- a/index.php
+++ b/index.php
@@ -1,150 +1,87 @@
-
-
-
-
-
- New Style
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Analyzing your requirements and generating your website…
-
-
Loading…
+
+
+
+
+
Professional ecommerce MVP
+
E-SO9 curated storefront with fast checkout and admin tracking.
+
Browse products, add to cart, place a demo order, and track status. Admins can review orders and update fulfillment.
+
+
+
+
+
+
+
Categories
+
= e((string) count($categories)) ?>
+
+
+
+
Checkout status
+
Demo payments enabled
+
+
+
-
= ($_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) ?>
-
-
-
-
+
+
+
+
+
+
+
Featured products
+ Hand-picked for the launch
+
+
+
+
+
+
![<?= e($product['name']) ?>](<?= e($product['image_url'] ?: product_image_data($product['name'])) ?>)
+
+
= e($product['category_name'] ?? 'General') ?>
+
= e($product['name']) ?>
+
+
= e(format_price((float) $product['price'])) ?>
+
View
+
+
+
+
+
+
+
+
+
diff --git a/order.php b/order.php
new file mode 100644
index 0000000..fab70e1
--- /dev/null
+++ b/order.php
@@ -0,0 +1,46 @@
+
+
+ Order details
+
+
+ Order not found. Check the number and try again.
+ Track another order
+
+
+
+
+
+
+
Order number
+
= e($order['order_number']) ?>
+
+
= e($order['status']) ?>
+
+
+
Customer
+
= e($order['customer_name']) ?>
+
= e($order['customer_email']) ?>
+
= e($order['customer_address']) ?>
+
+
+
+
+
+
Total paid
+
= e(format_price((float) $order['total_price'])) ?>
+
Placed = e($order['created_at']) ?>
+
+
+
+
+
+
diff --git a/product.php b/product.php
new file mode 100644
index 0000000..9d87d56
--- /dev/null
+++ b/product.php
@@ -0,0 +1,40 @@
+
+
+
+
+
![<?= e($product['name']) ?>](<?= e($product['image_url'] ?: product_image_data($product['name'])) ?>)
+
+
+
= e($product['category_name'] ?? 'General') ?>
+
= e($product['name']) ?>
+
= e($product['description']) ?>
+
+ = e(format_price((float) $product['price'])) ?>
+ Rating = e((string) $product['rating']) ?>
+ Stock = e((string) $product['stock']) ?>
+
+
+
Demo checkout only. Orders are stored locally for the admin view.
+
+
+
+
diff --git a/shop.php b/shop.php
new file mode 100644
index 0000000..c2031e0
--- /dev/null
+++ b/shop.php
@@ -0,0 +1,63 @@
+
+
+
+
+
Shop all products
+
Search, filter, and add items to your cart.
+
+
+
+
+
+ No products matched your filters.
+
+
+
+
+
+
+
![<?= e($product['name']) ?>](<?= e($product['image_url'] ?: product_image_data($product['name'])) ?>)
+
+
= e($product['category_name'] ?? 'General') ?>
+
= e($product['name']) ?>
+
= e($product['description']) ?>
+
+
= e(format_price((float) $product['price'])) ?>
+
View
+
+
+
+
+
+
+
+
diff --git a/track.php b/track.php
new file mode 100644
index 0000000..524e17b
--- /dev/null
+++ b/track.php
@@ -0,0 +1,64 @@
+
+
+ Track your order
+
+
+
+
+
+
= e($error) ?>
+
+
+
+
+
+
+
Status
+
= e($order['status']) ?>
+
Order total
+
= e(format_price((float) $order['total_price'])) ?>
+
View full order
+
+
+
Place a demo order to see tracking updates here.
+
+
+
+
+