first
This commit is contained in:
parent
840b2b94ca
commit
6872ff9a04
54
admin/orders/index.php
Normal file
54
admin/orders/index.php
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require_once __DIR__ . '../../../includes/Database.php';
|
||||||
|
require_once __DIR__ . '../includes/header.php';
|
||||||
|
|
||||||
|
$db = Database::getInstance();
|
||||||
|
$conn = $db->getConnection();
|
||||||
|
|
||||||
|
// Fetch all orders
|
||||||
|
$orders_stmt = $conn->query("SELECT * FROM orders ORDER BY created_at DESC");
|
||||||
|
$orders = $orders_stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="container mt-4">
|
||||||
|
<h1>Order Management</h1>
|
||||||
|
|
||||||
|
<table class="table table-bordered table-striped mt-4">
|
||||||
|
<thead class="thead-dark">
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Status</th>
|
||||||
|
<th>Total Amount</th>
|
||||||
|
<th>Customer Details</th>
|
||||||
|
<th>Date</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php if (count($orders) > 0): ?>
|
||||||
|
<?php foreach ($orders as $order): ?>
|
||||||
|
<tr>
|
||||||
|
<td><?php echo htmlspecialchars($order['id']); ?></td>
|
||||||
|
<td><?php echo htmlspecialchars($order['status']); ?></td>
|
||||||
|
<td>$<?php echo htmlspecialchars(number_format($order['total_amount'], 2)); ?></td>
|
||||||
|
<td><?php echo htmlspecialchars($order['customer_details']); ?></td>
|
||||||
|
<td><?php echo htmlspecialchars($order['created_at']); ?></td>
|
||||||
|
<td>
|
||||||
|
<a href="view.php?id=<?php echo $order['id']; ?>" class="btn btn-sm btn-info">View</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php else: ?>
|
||||||
|
<tr>
|
||||||
|
<td colspan="6" class="text-center">No orders found.</td>
|
||||||
|
</tr>
|
||||||
|
<?php endif; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
require_once __DIR__ . '../includes/footer.php';
|
||||||
|
?>
|
||||||
92
admin/orders/view.php
Normal file
92
admin/orders/view.php
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require_once __DIR__ . '../../../includes/Database.php';
|
||||||
|
require_once __DIR__ . '../includes/header.php';
|
||||||
|
|
||||||
|
$db = Database::getInstance();
|
||||||
|
$conn = $db->getConnection();
|
||||||
|
|
||||||
|
$order_id = $_GET['id'] ?? null;
|
||||||
|
|
||||||
|
if (!$order_id) {
|
||||||
|
header('Location: index.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch order details
|
||||||
|
$order_stmt = $conn->prepare("SELECT * FROM orders WHERE id = :id");
|
||||||
|
$order_stmt->bindParam(':id', $order_id);
|
||||||
|
$order_stmt->execute();
|
||||||
|
$order = $order_stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (!$order) {
|
||||||
|
header('Location: index.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch order items
|
||||||
|
$items_stmt = $conn->prepare("SELECT oi.*, p.sku, p.name_translations FROM order_items oi JOIN products p ON oi.product_id = p.id WHERE oi.order_id = :order_id");
|
||||||
|
$items_stmt->bindParam(':order_id', $order_id);
|
||||||
|
$items_stmt->execute();
|
||||||
|
$items = $items_stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="container mt-4">
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
|
<h1>Order #<?php echo htmlspecialchars($order['id']); ?></h1>
|
||||||
|
<a href="index.php" class="btn btn-secondary">Back to Orders</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">Order Details</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<p><strong>Status:</strong> <?php echo htmlspecialchars($order['status']); ?></p>
|
||||||
|
<p><strong>Total Amount:</strong> $<?php echo htmlspecialchars(number_format($order['total_amount'], 2)); ?></p>
|
||||||
|
<p><strong>Customer Details:</strong></p>
|
||||||
|
<pre><?php echo htmlspecialchars(json_encode(json_decode($order['customer_details']), JSON_PRETTY_PRINT)); ?></pre>
|
||||||
|
<p><strong>Date:</strong> <?php echo htmlspecialchars($order['created_at']); ?></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card mt-4">
|
||||||
|
<div class="card-header">Order Items</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<table class="table table-bordered">
|
||||||
|
<thead class="thead-dark">
|
||||||
|
<tr>
|
||||||
|
<th>SKU</th>
|
||||||
|
<th>Product Name</th>
|
||||||
|
<th>Quantity</th>
|
||||||
|
<th>Price at Purchase</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php if (count($items) > 0): ?>
|
||||||
|
<?php foreach ($items as $item): ?>
|
||||||
|
<tr>
|
||||||
|
<td><?php echo htmlspecialchars($item['sku']); ?></td>
|
||||||
|
<td>
|
||||||
|
<?php
|
||||||
|
$name_translations = json_decode($item['name_translations'], true);
|
||||||
|
echo htmlspecialchars($name_translations['en'] ?? 'N/A');
|
||||||
|
?>
|
||||||
|
</td>
|
||||||
|
<td><?php echo htmlspecialchars($item['quantity']); ?></td>
|
||||||
|
<td>$<?php echo htmlspecialchars(number_format($item['price_at_purchase'], 2)); ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php else: ?>
|
||||||
|
<tr>
|
||||||
|
<td colspan="4" class="text-center">No items found for this order.</td>
|
||||||
|
</tr>
|
||||||
|
<?php endif; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
require_once __DIR__ . '../includes/footer.php';
|
||||||
|
?>
|
||||||
@ -1,9 +1,4 @@
|
|||||||
<?php
|
<?php
|
||||||
session_start();
|
|
||||||
if (!isset($_SESSION['admin_logged_in']) || $_SESSION['admin_logged_in'] !== true) {
|
|
||||||
header('Location: /admin/index.php');
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
require_once __DIR__ . '../../../includes/Database.php';
|
require_once __DIR__ . '../../../includes/Database.php';
|
||||||
require_once __DIR__ . '../includes/header.php';
|
require_once __DIR__ . '../includes/header.php';
|
||||||
|
|||||||
@ -1,9 +1,4 @@
|
|||||||
<?php
|
<?php
|
||||||
session_start();
|
|
||||||
if (!isset($_SESSION['admin_logged_in']) || $_SESSION['admin_logged_in'] !== true) {
|
|
||||||
header('Location: /admin/index.php');
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
require_once __DIR__ . '../../../includes/Database.php';
|
require_once __DIR__ . '../../../includes/Database.php';
|
||||||
require_once __DIR__ . '../includes/header.php';
|
require_once __DIR__ . '../includes/header.php';
|
||||||
|
|||||||
@ -1,37 +1,28 @@
|
|||||||
|
|
||||||
<?php
|
<?php
|
||||||
session_start();
|
|
||||||
if (!isset($_SESSION['admin_logged_in']) || $_SESSION['admin_logged_in'] !== true) {
|
|
||||||
header('Location: /admin/index.php');
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
require_once __DIR__ . '/../../includes/Database.php';
|
require_once __DIR__ . '/../../db/config.php';
|
||||||
|
|
||||||
$db = Database::getInstance();
|
$pdo = db();
|
||||||
$connection = $db->getConnection();
|
$stmt = $pdo->query("SELECT * FROM settings ORDER BY id DESC LIMIT 1");
|
||||||
|
$settings = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
$settings = [];
|
|
||||||
$result = $connection->query("SELECT * FROM settings");
|
|
||||||
while ($row = $result->fetch_assoc()) {
|
|
||||||
$settings[$row['key_name']] = $row['key_value'];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
$stripe_secret_key = $_POST['stripe_secret_key'] ?? '';
|
$stripe_secret_key = $_POST['stripe_secret_key'] ?? '';
|
||||||
$stripe_publishable_key = $_POST['stripe_publishable_key'] ?? '';
|
$stripe_publishable_key = $_POST['stripe_publishable_key'] ?? '';
|
||||||
|
|
||||||
$stmt = $connection->prepare("INSERT INTO settings (key_name, key_value) VALUES (?, ?) ON DUPLICATE KEY UPDATE key_value = VALUES(key_value)");
|
// Check if settings exist
|
||||||
|
$stmt = $pdo->query("SELECT id FROM settings");
|
||||||
$key_name_secret = 'stripe_secret_key';
|
$exists = $stmt->fetch();
|
||||||
$stmt->bind_param("ss", $key_name_secret, $stripe_secret_key);
|
|
||||||
$stmt->execute();
|
|
||||||
|
|
||||||
$key_name_publishable = 'stripe_publishable_key';
|
if ($exists) {
|
||||||
$stmt->bind_param("ss", $key_name_publishable, $stripe_publishable_key);
|
$stmt = $pdo->prepare("UPDATE settings SET stripe_publishable_key = ?, stripe_secret_key = ? WHERE id = ?");
|
||||||
$stmt->execute();
|
$stmt->execute([$stripe_publishable_key, $stripe_secret_key, $settings['id']]);
|
||||||
|
} else {
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO settings (stripe_publishable_key, stripe_secret_key) VALUES (?, ?)");
|
||||||
|
$stmt->execute([$stripe_publishable_key, $stripe_secret_key]);
|
||||||
|
}
|
||||||
|
|
||||||
$stmt->close();
|
|
||||||
header('Location: /admin/settings/index.php?success=1');
|
header('Location: /admin/settings/index.php?success=1');
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
@ -56,5 +47,3 @@ include __DIR__ . '/../includes/header.php';
|
|||||||
<button type="submit" class="btn btn-primary">Save Settings</button>
|
<button type="submit" class="btn btn-primary">Save Settings</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php include __DIR__ . '/../includes/footer.php'; ?>
|
|
||||||
|
|||||||
@ -13,18 +13,15 @@ if (!file_exists(__DIR__ . '/../../vendor/autoload.php')) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
require_once __DIR__ . '/../../vendor/autoload.php';
|
require_once __DIR__ . '/../../vendor/autoload.php';
|
||||||
require_once __DIR__ . '/../../includes/Database.php';
|
require_once __DIR__ . '/../../db/config.php';
|
||||||
|
|
||||||
// Get DB connection
|
// Get DB connection
|
||||||
$db = Database::getInstance();
|
$pdo = db();
|
||||||
$connection = $db->getConnection();
|
|
||||||
|
|
||||||
// Fetch Stripe secret key from settings
|
// Fetch Stripe secret key from settings
|
||||||
$stripe_secret_key = '';
|
$stmt = $pdo->query("SELECT stripe_secret_key FROM settings ORDER BY id DESC LIMIT 1");
|
||||||
$result = $connection->query("SELECT key_value FROM settings WHERE key_name = 'stripe_secret_key'");
|
$settings = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
if ($row = $result->fetch_assoc()) {
|
$stripe_secret_key = $settings['stripe_secret_key'] ?? '';
|
||||||
$stripe_secret_key = $row['key_value'];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (empty($stripe_secret_key)) {
|
if (empty($stripe_secret_key)) {
|
||||||
http_response_code(500);
|
http_response_code(500);
|
||||||
@ -56,18 +53,16 @@ if ($product_id === false) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fetch product price from the database
|
// Fetch product price from the database
|
||||||
$stmt = $connection->prepare("SELECT price FROM products WHERE id = ?");
|
$stmt = $pdo->prepare("SELECT price FROM products WHERE id = ?");
|
||||||
$stmt->bind_param("i", $product_id);
|
$stmt->execute([$product_id]);
|
||||||
$stmt->execute();
|
$product = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
$result = $stmt->get_result();
|
|
||||||
|
|
||||||
if ($result->num_rows === 0) {
|
if (!$product) {
|
||||||
http_response_code(404);
|
http_response_code(404);
|
||||||
echo json_encode(['success' => false, 'message' => 'Product not found.']);
|
echo json_encode(['success' => false, 'message' => 'Product not found.']);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
$product = $result->fetch_assoc();
|
|
||||||
$price = $product['price'];
|
$price = $product['price'];
|
||||||
|
|
||||||
// Create a PaymentIntent
|
// Create a PaymentIntent
|
||||||
|
|||||||
98
checkout.php
Normal file
98
checkout.php
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'db/config.php';
|
||||||
|
|
||||||
|
if (!isset($_GET['product_id'])) {
|
||||||
|
header('Location: products.php');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$pdo = db();
|
||||||
|
$stmt = $pdo->prepare("SELECT p.id, p.name, p.description, p.price, t.name as translated_name, t.description as translated_description FROM products p LEFT JOIN translations t ON p.id = t.product_id AND t.language_code = 'en' WHERE p.id = ?");
|
||||||
|
$stmt->execute([$_GET['product_id']]);
|
||||||
|
$product = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (empty($product)) {
|
||||||
|
header('Location: products.php');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$stmt = $pdo->query("SELECT stripe_publishable_key FROM settings ORDER BY id DESC LIMIT 1");
|
||||||
|
$settings = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
$stripe_publishable_key = $settings['stripe_publishable_key'] ?? '';
|
||||||
|
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Checkout</title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<script src="https://js.stripe.com/v3/"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container mt-5">
|
||||||
|
<h1>Checkout</h1>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<h5 class="card-title"><?php echo htmlspecialchars($product['translated_name'] ?: $product['name']); ?></h5>
|
||||||
|
<p class="card-text"><?php echo htmlspecialchars($product['translated_description'] ?: $product['description']); ?></p>
|
||||||
|
<p class="card-text"><strong>Price: $<?php echo htmlspecialchars($product['price']); ?></strong></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<form id="payment-form">
|
||||||
|
<div id="card-element">
|
||||||
|
<!-- A Stripe Element will be inserted here. -->
|
||||||
|
</div>
|
||||||
|
<button id="submit" class="btn btn-primary mt-3">Pay</button>
|
||||||
|
<div id="error-message" role="alert"></div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
const stripe = Stripe('<?php echo $stripe_publishable_key; ?>');
|
||||||
|
const paymentForm = document.getElementById('payment-form');
|
||||||
|
const productId = <?php echo $product['id']; ?>;
|
||||||
|
|
||||||
|
let elements;
|
||||||
|
|
||||||
|
initialize();
|
||||||
|
|
||||||
|
async function initialize() {
|
||||||
|
const { clientSecret } = await fetch('api/payments/create-payment-intent.php', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ product_id: productId }),
|
||||||
|
}).then((r) => r.json());
|
||||||
|
|
||||||
|
elements = stripe.elements({ clientSecret });
|
||||||
|
|
||||||
|
const cardElement = elements.create('card');
|
||||||
|
cardElement.mount('#card-element');
|
||||||
|
}
|
||||||
|
|
||||||
|
paymentForm.addEventListener('submit', async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
const { error } = await stripe.confirmCardPayment(elements.getClientSecret(), {
|
||||||
|
payment_method: {
|
||||||
|
card: elements.getElement('card'),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
const messageContainer = document.getElementById('error-message');
|
||||||
|
messageContainer.textContent = error.message;
|
||||||
|
} else {
|
||||||
|
// Payment succeeded
|
||||||
|
window.location.href = 'payment-success.php';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
-- Verras Portal SQL Schema
|
-- Verras Portal SQL Schema
|
||||||
-- All tables use InnoDB engine for transaction support and foreign key constraints.
|
-- All tables use InnoDB engine for transaction support and foreign key constraints.
|
||||||
|
|
||||||
@ -33,24 +32,14 @@ CREATE TABLE IF NOT EXISTS `languages` (
|
|||||||
CREATE TABLE IF NOT EXISTS `products` (
|
CREATE TABLE IF NOT EXISTS `products` (
|
||||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
`sku` VARCHAR(100) NOT NULL UNIQUE,
|
`sku` VARCHAR(100) NOT NULL UNIQUE,
|
||||||
|
`name_translations` JSON,
|
||||||
|
`description_translations` JSON,
|
||||||
`price` DECIMAL(10, 2) NOT NULL,
|
`price` DECIMAL(10, 2) NOT NULL,
|
||||||
`image_url` VARCHAR(2048),
|
`image_url` VARCHAR(2048),
|
||||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||||
) ENGINE=InnoDB;
|
) ENGINE=InnoDB;
|
||||||
|
|
||||||
-- Table for product translations
|
|
||||||
CREATE TABLE IF NOT EXISTS `product_translations` (
|
|
||||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
|
||||||
`product_id` INT NOT NULL,
|
|
||||||
`language_code` VARCHAR(10) NOT NULL,
|
|
||||||
`name` VARCHAR(255) NOT NULL,
|
|
||||||
`description` TEXT,
|
|
||||||
UNIQUE KEY `product_lang_unique` (`product_id`, `language_code`),
|
|
||||||
FOREIGN KEY (`product_id`) REFERENCES `products`(`id`) ON DELETE CASCADE,
|
|
||||||
FOREIGN KEY (`language_code`) REFERENCES `languages`(`code`) ON DELETE CASCADE
|
|
||||||
) ENGINE=InnoDB;
|
|
||||||
|
|
||||||
-- Table for general content (banners, about us, etc.)
|
-- Table for general content (banners, about us, etc.)
|
||||||
CREATE TABLE IF NOT EXISTS `content` (
|
CREATE TABLE IF NOT EXISTS `content` (
|
||||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
@ -98,11 +87,11 @@ CREATE TABLE IF NOT EXISTS `order_items` (
|
|||||||
-- Table for application settings (e.g., Stripe keys)
|
-- Table for application settings (e.g., Stripe keys)
|
||||||
CREATE TABLE IF NOT EXISTS `settings` (
|
CREATE TABLE IF NOT EXISTS `settings` (
|
||||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
`key_name` VARCHAR(255) NOT NULL UNIQUE,
|
`stripe_publishable_key` VARCHAR(255),
|
||||||
`key_value` TEXT,
|
`stripe_secret_key` VARCHAR(255),
|
||||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
) ENGINE=InnoDB;
|
) ENGINE=InnoDB;
|
||||||
|
|
||||||
-- Insert default languages
|
-- Insert default languages
|
||||||
INSERT INTO `languages` (`code`, `name`) VALUES ('en', 'English'), ('es', 'Spanish')
|
INSERT INTO `languages` (`code`, `name`) VALUES ('en', 'English'), ('es', 'Spanish')
|
||||||
ON DUPLICATE KEY UPDATE `name`=`name`;
|
ON DUPLICATE KEY UPDATE `name`=`name`;
|
||||||
22
payment-success.php
Normal file
22
payment-success.php
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Payment Success</title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container mt-5">
|
||||||
|
<div class="alert alert-success">
|
||||||
|
<h4 class="alert-heading">Payment Successful!</h4>
|
||||||
|
<p>Thank you for your purchase. Your payment has been processed successfully.</p>
|
||||||
|
<hr>
|
||||||
|
<p class="mb-0">You will receive an email confirmation shortly.</p>
|
||||||
|
</div>
|
||||||
|
<a href="products.php" class="btn btn-primary">Continue Shopping</a>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
35
products.php
Normal file
35
products.php
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'includes/Database.php';
|
||||||
|
|
||||||
|
$db = new Database();
|
||||||
|
$products = $db->query("SELECT p.id, p.name, p.description, p.price, t.name as translated_name, t.description as translated_description FROM products p LEFT JOIN translations t ON p.id = t.product_id AND t.language_code = 'en'");
|
||||||
|
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Products</title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container mt-5">
|
||||||
|
<h1>Our Products</h1>
|
||||||
|
<div class="row">
|
||||||
|
<?php foreach ($products as $product): ?>
|
||||||
|
<div class="col-md-4 mb-4">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<h5 class="card-title"><?php echo htmlspecialchars($product['translated_name'] ?: $product['name']); ?></h5>
|
||||||
|
<p class="card-text"><?php echo htmlspecialchars($product['translated_description'] ?: $product['description']); ?></p>
|
||||||
|
<p class="card-text"><strong>Price: $<?php echo htmlspecialchars($product['price']); ?></strong></p>
|
||||||
|
<a href="checkout.php?product_id=<?php echo $product['id']; ?>" class="btn btn-primary">Buy Now</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Loading…
x
Reference in New Issue
Block a user