Chat GPT panel

This commit is contained in:
Flatlogic Bot 2025-12-28 19:43:55 +00:00
parent 293c559d7e
commit 6cb5e11e5f
24 changed files with 1564 additions and 417 deletions

View File

@ -1,9 +1,6 @@
<?php
session_start();
require_once __DIR__ . '/../includes/lang.php';
require_once __DIR__ . '/../includes/auth.php';
require_once __DIR__ . '/../includes/init.php';
require_role('admin');
require_once __DIR__ . '/../includes/helpers.php';
// Handle form submission for adding a new key
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_key'])) {
@ -67,16 +64,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['delete_key'])) {
$keys_stmt = db()->query("SELECT * FROM attribute_keys ORDER BY name");
$attribute_keys = $keys_stmt->fetchAll();
$page_title = "Klucze atrybutów";
?>
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Admin - Klucze atrybutów</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="../assets/css/custom.css">
</head>
<?php require_once __DIR__ . '/../includes/html_head.php'; ?>
<body>
<?php include 'menu.php'; ?>

View File

@ -1,9 +1,6 @@
<?php
session_start();
require_once __DIR__ . '/../includes/lang.php';
require_once __DIR__ . '/../includes/auth.php';
require_once __DIR__ . '/../includes/init.php';
require_role('admin');
require_once __DIR__ . '/../includes/helpers.php';
$pdo = db();
$message = '';
@ -61,16 +58,9 @@ $pricesStmt = $pdo->query("
");
$existingPrices = $pricesStmt->fetchAll(PDO::FETCH_ASSOC);
$page_title = "Cennik indywidualny";
?>
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Cennik indywidualny</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="../assets/css/custom.css">
</head>
<?php require_once __DIR__ . '/../includes/html_head.php'; ?>
<body>
<?php include 'menu.php'; ?>

View File

@ -1,9 +1,7 @@
<?php
session_start();
require_once __DIR__ . '/../includes/init.php';
require_once __DIR__ . '/../includes/auth.php';
require_role('admin');
require_once __DIR__ . '/../db/config.php';
require_once __DIR__ . '/../includes/helpers.php';
$clients = [];
$error_message = '';
@ -18,27 +16,21 @@ try {
$error_message = 'Błąd podczas pobierania klientów.';
}
$pageTitle = 'Klienci';
$page_title = 'Klienci';
?>
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?php echo $pageTitle; ?> - Panel Administracyjny</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<?php require_once __DIR__ . '/../includes/html_head.php'; ?>
<body>
<?php require_once __DIR__ . '/menu.php'; ?>
<main class="container mt-4">
<main class="container my-5">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="h2"><?php echo $page_title; ?></h1>
<a href="edit_client.php" class="btn btn-primary">
<i class="bi bi-plus-lg"></i> Dodaj klienta
</a>
</div>
<div class="card">
<div class="card-header">
<div class="d-flex justify-content-between align-items-center">
<h1><?php echo $pageTitle; ?></h1>
<a href="edit_client.php" class="btn btn-success">+ Dodaj klienta</a>
</div>
</div>
<div class="card-body">
<?php if ($error_message): ?>
<div class="alert alert-danger" role="alert">
@ -47,7 +39,7 @@ $pageTitle = 'Klienci';
<?php elseif ($pdo): ?>
<div class="table-responsive">
<table class="table table-striped table-hover">
<thead>
<thead class="table-light">
<tr>
<th>ID</th>
<th>Nazwa</th>
@ -87,8 +79,12 @@ $pageTitle = 'Klienci';
?>
</td>
<td>
<a href="edit_client.php?id=<?php echo $client['id']; ?>" class="btn btn-sm btn-primary">Edytuj</a>
<a href="client_prices.php?client_id=<?php echo $client['id']; ?>" class="btn btn-sm btn-info">Cennik</a>
<a href="edit_client.php?id=<?php echo $client['id']; ?>" class="btn btn-sm btn-secondary">
<i class="bi bi-pencil-fill"></i> Edytuj
</a>
<a href="client_prices.php?client_id=<?php echo $client['id']; ?>" class="btn btn-sm btn-info">
<i class="bi bi-tag-fill"></i> Cennik
</a>
</td>
</tr>
<?php endforeach; ?>
@ -101,6 +97,6 @@ $pageTitle = 'Klienci';
</div>
</main>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
<?php require_once __DIR__ . '/../includes/footer.php'; ?>
</body>
</html>

View File

@ -1,8 +1,6 @@
<?php
session_start();
require_once __DIR__ . '/../includes/auth.php';
require_once __DIR__ . '/../includes/init.php';
require_role('admin');
require_once __DIR__ . '/../includes/helpers.php';
$db = db();
@ -162,15 +160,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
}
}
}
$page_title = $pageTitle;
?>
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?php echo htmlspecialchars($pageTitle); ?></title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<?php require_once __DIR__ . '/../includes/html_head.php'; ?>
<body>
<?php require_once __DIR__ . '/menu.php'; ?>
<div class="container mt-4">
@ -281,6 +273,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
<?php require_once __DIR__ . '/../includes/footer.php'; ?>
</body>
</html>

103
admin/edit_kb_document.php Normal file
View File

@ -0,0 +1,103 @@
<?php
require_once __DIR__ . '/../includes/init.php';
require_admin();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$id = $_GET['id'] ?? null;
$title = $_POST['title'];
$content = $_POST['content'];
$tags = $_POST['tags'] ?? null;
$product_id = $_POST['product_id'] ?: null;
$language = $_POST['language'];
$is_active = isset($_POST['is_active']);
if ($id) {
$stmt = db()->prepare("UPDATE kb_documents SET title = ?, content = ?, tags = ?, product_id = ?, language = ?, is_active = ? WHERE id = ?");
$stmt->execute([$title, $content, $tags, $product_id, $language, $is_active, $id]);
} else {
$stmt = db()->prepare("INSERT INTO kb_documents (title, content, tags, product_id, language, is_active) VALUES (?, ?, ?, ?, ?, ?)");
$stmt->execute([$title, $content, $tags, $product_id, $language, $is_active]);
}
header('Location: kb_documents.php');
exit;
}
$id = $_GET['id'] ?? null;
$document = null;
if ($id) {
$stmt = db()->prepare("SELECT * FROM kb_documents WHERE id = ?");
$stmt->execute([$id]);
$document = $stmt->fetch();
}
$page_title = $id ? 'Edit Document' : 'Add Document';
require_once __DIR__ . '/../includes/html_head.php';
?>
<body>
<?php include 'menu.php'; ?>
<main class="container my-5">
<h1><i class="fa-solid fa-book"></i> <?= $page_title ?></h1>
<div class="card">
<div class="card-body">
<form action="edit_kb_document.php<?= $id ? '?id=' . $id : '' ?>" method="POST">
<div class="mb-3">
<label for="title" class="form-label">Title</label>
<input type="text" class="form-control" id="title" name="title" value="<?= htmlspecialchars($document['title'] ?? '') ?>" required>
</div>
<div class="mb-3">
<label for="content" class="form-label">Content</label>
<textarea class="form-control" id="content" name="content" rows="10" required><?= htmlspecialchars($document['content'] ?? '') ?></textarea>
</div>
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label for="tags" class="form-label">Tags (comma-separated)</label>
<input type="text" class="form-control" id="tags" name="tags" value="<?= htmlspecialchars($document['tags'] ?? '') ?>">
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label for="product_id" class="form-label">Product</label>
<select class="form-control" id="product_id" name="product_id">
<option value="">None</option>
<?php
$stmt = db()->query("SELECT id, name FROM products ORDER BY name");
while ($product = $stmt->fetch()) {
$selected = ($document['product_id'] ?? '') == $product['id'] ? 'selected' : '';
echo "<option value=\"{$product['id']}\" {$selected}>" . htmlspecialchars($product['name']) . "</option>";
}
?>
</select>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label for="language" class="form-label">Language</label>
<select class="form-control" id="language" name="language">
<option value="en" <?= ($document['language'] ?? 'en') == 'en' ? 'selected' : '' ?>>English</option>
<option value="pl" <?= ($document['language'] ?? '') == 'pl' ? 'selected' : '' ?>>Polish</option>
</select>
</div>
</div>
<div class="col-md-6">
<div class="mb-3 form-check form-switch">
<input class="form-check-input" type="checkbox" id="is_active" name="is_active" value="1" <?= ($document['is_active'] ?? true) ? 'checked' : '' ?> >
<label class="form-check-label" for="is_active">Active</label>
</div>
</div>
</div>
<button type="submit" class="btn btn-primary"><i class="fa-solid fa-save"></i> Save</button>
<a href="kb_documents.php" class="btn btn-secondary">Cancel</a>
</form>
</div>
</div>
<?php require_once __DIR__ . '/../includes/footer.php'; ?>

View File

@ -1,9 +1,6 @@
<?php
session_start();
require_once __DIR__ . '/../includes/auth.php';
require_once __DIR__ . '/../includes/helpers.php';
require_once __DIR__ . '/../includes/init.php';
require_role('admin');
require_once __DIR__ . '/../includes/i18n.php';
$pdo = db();
@ -288,14 +285,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$page_title = $product['id'] ? 'Edytuj produkt' : 'Dodaj produkt';
?>
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?php echo htmlspecialchars($page_title); ?> - Panel Administracyjny</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<?php require_once __DIR__ . '/../includes/html_head.php'; ?>
<body>
<?php include __DIR__ . '/menu.php'; ?>
<main class="container my-5">
@ -434,31 +424,6 @@ $page_title = $product['id'] ? 'Edytuj produkt' : 'Dodaj produkt';
</div>
</form>
</main>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
const priceNetInput = document.getElementById('price_net');
const priceGrossInput = document.getElementById('price_gross');
const vatRate = 1.23;
priceNetInput.addEventListener('input', function() {
const netValue = parseFloat(this.value);
if (!isNaN(netValue)) {
priceGrossInput.value = (netValue * vatRate).toFixed(2);
} else {
priceGrossInput.value = '';
}
});
priceGrossInput.addEventListener('input', function() {
const grossValue = parseFloat(this.value);
if (!isNaN(grossValue)) {
priceNetInput.value = (grossValue / vatRate).toFixed(2);
} else {
priceNetInput.value = '';
}
});
});
</script>
<?php require_once __DIR__ . '/../includes/footer.php'; ?>
</body>
</html>

View File

@ -1,8 +1,6 @@
<?php
require_once '../includes/init.php';
require_once '../includes/auth.php';
require_role('admin');
require_once __DIR__ . '/../db/config.php';
$pdo = db();
$user = [
@ -100,16 +98,10 @@ try {
} catch (PDOException $e) {
die("Błąd bazy danych: " . $e->getMessage());
}
$page_title = $pageTitle;
?>
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?php echo $pageTitle; ?></title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<?php require_once __DIR__ . '/../includes/html_head.php'; ?>
<body>
<?php include __DIR__ . '/menu.php'; ?>
@ -170,17 +162,6 @@ try {
</div>
</main>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
<script>
function toggleClientDropdown() {
var role = document.getElementById('role').value;
var dropdown = document.getElementById('client-dropdown');
if (role === 'client') {
dropdown.style.display = 'block';
} else {
dropdown.style.display = 'none';
}
}
</script>
<?php require_once __DIR__ . '/../includes/footer.php'; ?>
</body>
</html>

83
admin/kb_documents.php Normal file
View File

@ -0,0 +1,83 @@
<?php
require_once __DIR__ . '/../includes/init.php';
require_admin();
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['delete_id'])) {
$stmt = db()->prepare("DELETE FROM kb_documents WHERE id = ?");
$stmt->execute([$_POST['delete_id']]);
header('Location: kb_documents.php');
exit;
}
$stmt = db()->prepare("SELECT * FROM kb_documents ORDER BY created_at DESC");
$stmt->execute();
$documents = $stmt->fetchAll();
$page_title = 'Knowledge Base';
?>
<?php require_once __DIR__ . '/../includes/html_head.php'; ?>
<body>
<?php include 'menu.php'; ?>
<main class="container my-5">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="h2"><i class="bi bi-book"></i> Knowledge Base</h1>
<a href="edit_kb_document.php" class="btn btn-primary">
<i class="bi bi-plus-lg"></i> Add New
</a>
</div>
<div class="card">
<div class="card-body">
<table class="table table-striped table-hover">
<thead class="table-light">
<tr>
<th>Title</th>
<th>Language</th>
<th>Active</th>
<th>Created At</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<?php if (empty($documents)): ?>
<tr>
<td colspan="5" class="text-center">No documents found.</td>
</tr>
<?php else: ?>
<?php foreach ($documents as $doc) : ?>
<tr>
<td><?= htmlspecialchars($doc['title']) ?></td>
<td><?= htmlspecialchars($doc['language']) ?></td>
<td>
<?php if ($doc['is_active']): ?>
<span class="badge bg-success">Yes</span>
<?php else: ?>
<span class="badge bg-danger">No</span>
<?php endif; ?>
</td>
<td><?= htmlspecialchars($doc['created_at']) ?></td>
<td>
<a href="edit_kb_document.php?id=<?= $doc['id'] ?>" class="btn btn-sm btn-secondary">
<i class="bi bi-pencil-fill"></i> Edit
</a>
<form action="kb_documents.php" method="POST" class="d-inline" onsubmit="return confirm('Are you sure you want to delete this document?');">
<input type="hidden" name="delete_id" value="<?= $doc['id'] ?>">
<button type="submit" class="btn btn-sm btn-danger"><i class="bi bi-trash-fill"></i> Delete</button>
</form>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</main>
<?php require_once __DIR__ . '/../includes/footer.php'; ?>
</body>
</html>

View File

@ -1,6 +1,6 @@
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container-fluid">
<div class="container">
<a class="navbar-brand" href="/admin/orders.php">Admin Panel</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
@ -28,6 +28,9 @@
<li class="nav-item">
<a class="nav-link" href="settings.php">Ustawienia</a>
</li>
<li class="nav-item">
<a class="nav-link" href="kb_documents.php">Baza wiedzy</a>
</li>
</ul>
<ul class="navbar-nav ms-auto">
<li class="nav-item">

View File

@ -1,9 +1,6 @@
<?php
session_start();
require_once __DIR__ . '/../includes/auth.php';
require_once __DIR__ . '/../includes/init.php';
require_role('admin');
require_once __DIR__ . '/../db/config.php';
require_once __DIR__ . '/../includes/helpers.php';
$pdo = db();
$order_id = $_GET['id'] ?? null;
@ -119,19 +116,10 @@ $items_stmt->execute([$order_id]);
$order_items = $items_stmt->fetchAll(PDO::FETCH_ASSOC);
$statuses = ['pending_payment', 'paid', 'in_progress', 'shipped', 'completed', 'cancelled'];
$pageTitle = 'Szczegóły zamówienia #' . htmlspecialchars($order['id']);
$page_title = 'Szczegóły zamówienia #' . htmlspecialchars($order['id']);
?>
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?php echo $pageTitle; ?> - Panel Administracyjny</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
</head>
<?php require_once __DIR__ . '/../includes/html_head.php'; ?>
<body>
<?php require_once __DIR__ . '/menu.php'; ?>
<main class="container mt-4">
@ -219,6 +207,6 @@ $pageTitle = 'Szczegóły zamówienia #' . htmlspecialchars($order['id']);
</div>
</div>
</main>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
<?php require_once __DIR__ . '/../includes/footer.php'; ?>
</body>
</html>

View File

@ -1,10 +1,6 @@
<?php
session_start();
require_once __DIR__ . '/../includes/auth.php';
require_once __DIR__ . '/../includes/init.php';
require_role('admin');
require_once __DIR__ . '/../includes/helpers.php';
require_once __DIR__ . '/../includes/i18n.php';
function t_filter_status($status) {
if ($status === 'new_today') return 'Nowe (dziś)';
@ -88,18 +84,10 @@ try {
$error = "Błąd bazy danych: " . $e->getMessage();
}
$pageTitle = "Zarządzanie zamówieniami";
$page_title = "Zarządzanie zamówieniami";
?>
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?= $pageTitle ?></title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="../assets/css/custom.css">
</head>
<?php require_once __DIR__ . '/../includes/html_head.php'; ?>
<body>
<?php include 'menu.php'; ?>
<div class="container">
@ -205,6 +193,6 @@ $pageTitle = "Zarządzanie zamówieniami";
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
<?php require_once __DIR__ . '/../includes/footer.php'; ?>
</body>
</html>

View File

@ -1,8 +1,5 @@
<?php
session_start();
require_once __DIR__ . '/../includes/auth.php';
require_once __DIR__ . '/../includes/helpers.php';
require_once __DIR__ . '/../includes/init.php';
require_role('admin');
$pdo = db();
@ -11,16 +8,7 @@ $products = $stmt->fetchAll();
$page_title = 'Zarządzanie produktami';
?>
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?php echo htmlspecialchars($page_title); ?></title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
<link rel="stylesheet" href="../assets/css/custom.css?v=<?php echo time(); ?>">
</head>
<?php require_once __DIR__ . '/../includes/html_head.php'; ?>
<body>
<?php include 'menu.php'; ?>
@ -85,7 +73,7 @@ $page_title = 'Zarządzanie produktami';
</div>
</main>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<?php require_once __DIR__ . '/../includes/footer.php'; ?>
</body>
</html>

View File

@ -39,7 +39,7 @@ $page_title = 'Ustawienia Walut';
<?php require_once __DIR__ . '/../includes/html_head.php'; ?>
<body>
<div class="container-fluid">
<div class="container">
<div class="row">
<?php require_once __DIR__ . '/menu.php'; ?>
<main class="col-md-9 ms-sm-auto col-lg-10 px-md-4">

View File

@ -1,7 +1,5 @@
<?php
session_start();
require_once __DIR__ . '/../includes/auth.php';
require_once __DIR__ . '/../includes/helpers.php';
require_once __DIR__ . '/../includes/init.php';
require_role('admin');
$pdo = db();
@ -10,15 +8,7 @@ $users = $stmt->fetchAll();
$page_title = 'Użytkownicy';
?>
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?php echo htmlspecialchars($page_title); ?> - Panel Administracyjny</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
</head>
<?php require_once __DIR__ . '/../includes/html_head.php'; ?>
<body>
<?php include __DIR__ . '/menu.php'; ?>
@ -78,6 +68,6 @@ $page_title = 'Użytkownicy';
</div>
</main>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<?php require_once __DIR__ . '/../includes/footer.php'; ?>
</body>
</html>

93
chat_send.php Normal file
View File

@ -0,0 +1,93 @@
<?php
require_once __DIR__ . '/includes/init.php';
require_once __DIR__ . '/ai/LocalAIApi.php';
header('Content-Type: application/json');
// Get or create a session ID
if (isset($_SESSION['chat_session_id'])) {
$session_id = $_SESSION['chat_session_id'];
} else {
$user_id = $_SESSION['user']['id'] ?? null;
$client_id = $_SESSION['user']['client_id'] ?? null;
$stmt = db()->prepare("INSERT INTO chat_sessions (user_id, client_id) VALUES (?, ?)");
$stmt->execute([$user_id, $client_id]);
$session_id = db()->lastInsertId();
$_SESSION['chat_session_id'] = $session_id;
}
// Load conversation history
$stmt = db()->prepare("SELECT sender, message FROM chat_messages WHERE session_id = ? ORDER BY created_at ASC");
$stmt->execute([$session_id]);
$history = $stmt->fetchAll(PDO::FETCH_ASSOC);
function search_kb($message) {
$terms = explode(' ', $message);
$sql = "SELECT * FROM kb_documents WHERE is_active = 1 AND (";
$conditions = [];
foreach ($terms as $term) {
$conditions[] = "title LIKE ? OR content LIKE ?";
}
$sql .= implode(' OR ', $conditions) . ") LIMIT 3";
$stmt = db()->prepare($sql);
$params = [];
foreach ($terms as $term) {
$params[] = '%' . $term . '%';
$params[] = '%' . $term . '%';
}
$stmt->execute($params);
return $stmt->fetchAll();
}
$input = json_decode(file_get_contents('php://input'), true);
$message = $input['message'] ?? '';
if (empty($message)) {
echo json_encode(['reply' => 'Please enter a message.']);
exit;
}
// Save user message
$stmt = db()->prepare("INSERT INTO chat_messages (session_id, sender, message) VALUES (?, 'user', ?)");
$stmt->execute([$session_id, $message]);
$kb_documents = search_kb($message);
$prompt = "You are a helpful assistant for Extrading, a company that sells construction materials. Please answer in ' . ($lang ?? 'en') . ' language. Answer the user\'s questions based on the provided context. If the answer is not in the context, say you don\'t know.\n\n";
if (!empty($kb_documents)) {
$prompt .= "Context from knowledge base:\n";
foreach ($kb_documents as $doc) {
$prompt .= "- Title: " . $doc['title'] . "\n";
$prompt .= " Content: " . $doc['content'] . "\n";
}
$prompt .= "\n";
}
$prompt .= "Conversation history:\n";
foreach ($history as $msg) {
$prompt .= $msg['sender'] . ": " . $msg['message'] . "\n";
}
$prompt .= "user: " . $message . "\n";
$prompt .= "assistant:";
$response = LocalAIApi::createResponse([
'input' => [
['role' => 'system', 'content' => $prompt]
]
]);
if (!empty($response['success'])) {
$reply = LocalAIApi::extractText($response);
} else {
$reply = 'Sorry, I am having trouble connecting to the AI service. Please try again later.';
error_log('AI API Error: ' . ($response['error'] ?? 'Unknown error'));
}
// Save assistant message
$stmt = db()->prepare("INSERT INTO chat_messages (session_id, sender, message) VALUES (?, 'assistant', ?)");
$stmt->execute([$session_id, $reply]);
echo json_encode(['reply' => $reply]);

View File

@ -0,0 +1,13 @@
CREATE TABLE IF NOT EXISTS `kb_documents` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`title` VARCHAR(255) NOT NULL,
`content` TEXT NOT NULL,
`tags` VARCHAR(255),
`product_id` INT,
`language` VARCHAR(10) NOT NULL DEFAULT 'en',
`is_active` BOOLEAN NOT NULL DEFAULT TRUE,
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (`product_id`) REFERENCES `products`(`id`) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

View File

@ -0,0 +1,10 @@
CREATE TABLE IF NOT EXISTS `chat_sessions` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`user_id` INT,
`client_id` INT,
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE,
FOREIGN KEY (`client_id`) REFERENCES `clients`(`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

View File

@ -0,0 +1,10 @@
CREATE TABLE IF NOT EXISTS `chat_messages` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`session_id` INT NOT NULL,
`sender` ENUM('user', 'assistant') NOT NULL,
`message` TEXT NOT NULL,
`sources` TEXT,
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (`session_id`) REFERENCES `chat_sessions`(`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

File diff suppressed because it is too large Load Diff

View File

@ -1 +1 @@
I have fixed the pricing display issue on the product detail and order pages. Please check again.
I've fixed the translations for the chat widget. All the text, including the title, welcome message, input placeholder, and send button, should now be correctly translated based on the language you select in the client panel. Please check and let me know if you see any other issues.

View File

@ -3,6 +3,194 @@
<p class="mb-0">&copy; <?php echo date("Y"); ?> powered by LEA24. All Rights Reserved.</p>
</div>
</footer>
<?php
$show_chat = false;
if (is_admin()) {
if (basename($_SERVER['PHP_SELF']) == 'kb_documents.php') {
$show_chat = true;
}
} else {
$show_chat = true;
}
if ($show_chat):
?>
<style>
.chat-widget-button {
position: fixed;
bottom: 20px;
right: 20px;
width: 60px;
height: 60px;
border-radius: 50%;
background-color: #0d6efd;
color: white;
display: flex;
justify-content: center;
align-items: center;
font-size: 24px;
cursor: pointer;
z-index: 1050;
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
}
.chat-widget-button:hover {
background-color: #0b5ed7;
}
.chat-modal .modal-body {
height: 400px;
overflow-y: auto;
}
.chat-message {
margin-bottom: 15px;
}
.chat-message.user .message-content {
background-color: #e9f5ff;
padding: 10px;
border-radius: 10px;
display: inline-block;
max-width: 80%;
}
.chat-message.assistant .message-content {
background-color: #f1f1f1;
padding: 10px;
border-radius: 10px;
display: inline-block;
max-width: 80%;
}
.chat-message.user {
text-align: right;
}
.thinking-indicator span {
display: inline-block;
width: 8px;
height: 8px;
border-radius: 50%;
background-color: #888;
margin: 0 2px;
animation: pulse 1.4s infinite ease-in-out both;
}
.thinking-indicator span:nth-child(1) {
animation-delay: -0.32s;
}
.thinking-indicator span:nth-child(2) {
animation-delay: -0.16s;
}
@keyframes pulse {
0%, 80%, 100% {
transform: scale(0);
}
40% {
transform: scale(1.0);
}
}
</style>
<div class="chat-widget-button" data-bs-toggle="modal" data-bs-target="#chatModal">
<i class="fa-solid fa-comments"></i>
</div>
<div class="modal fade chat-modal" id="chatModal" tabindex="-1" aria-labelledby="chatModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-end">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="chatModalLabel"><?php echo t('chat_with_assistant'); ?></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body" id="chat-transcript">
<div class="chat-message assistant">
<div class="message-content">
<?php echo t('chat_hello'); ?>
</div>
</div>
</div>
<div class="modal-footer">
<div class="input-group">
<input type="text" class="form-control" id="chat-input" placeholder="<?php echo t('chat_placeholder'); ?>">
<button class="btn btn-primary" id="chat-send"><?php echo t('chat_send_button'); ?></button>
</div>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function () {
const chatTranscript = document.getElementById('chat-transcript');
const chatInput = document.getElementById('chat-input');
const chatSend = document.getElementById('chat-send');
function addMessage(sender, message) {
const messageElement = document.createElement('div');
messageElement.classList.add('chat-message', sender);
const messageContent = document.createElement('div');
messageContent.classList.add('message-content');
messageContent.textContent = message;
messageElement.appendChild(messageContent);
chatTranscript.appendChild(messageElement);
chatTranscript.scrollTop = chatTranscript.scrollHeight;
}
function showThinkingIndicator() {
const thinkingElement = document.createElement('div');
thinkingElement.classList.add('chat-message', 'assistant', 'thinking-indicator');
const messageContent = document.createElement('div');
messageContent.classList.add('message-content');
messageContent.innerHTML = '<span></span><span></span><span></span>';
thinkingElement.appendChild(messageContent);
chatTranscript.appendChild(thinkingElement);
chatTranscript.scrollTop = chatTranscript.scrollHeight;
}
function hideThinkingIndicator() {
const thinkingElement = document.querySelector('.thinking-indicator');
if (thinkingElement) {
thinkingElement.remove();
}
}
function sendMessage() {
const message = chatInput.value.trim();
if (message === '') return;
addMessage('user', message);
chatInput.value = '';
showThinkingIndicator();
// AJAX call to backend
const xhr = new XMLHttpRequest();
xhr.open('POST', 'chat_send.php', true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onload = function () {
hideThinkingIndicator();
if (xhr.status === 200) {
const response = JSON.parse(xhr.responseText);
addMessage('assistant', response.reply);
} else {
addMessage('assistant', 'Sorry, something went wrong. Please try again later.');
}
};
xhr.onerror = function () {
hideThinkingIndicator();
addMessage('assistant', 'Sorry, something went wrong. Please try again later.');
};
xhr.send(JSON.stringify({ message: message }));
}
chatSend.addEventListener('click', sendMessage);
chatInput.addEventListener('keypress', function (e) {
if (e.key === 'Enter') {
sendMessage();
}
});
});
</script>
<?php endif; ?>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

View File

@ -181,6 +181,10 @@ $translations = [
'order_summary' => 'Podsumowanie zamówienia',
'grand_total' => 'Suma całkowita',
'price' => 'Cena',
'chat_with_assistant' => 'Czat z naszym asystentem',
'chat_hello' => 'Cześć! W czym mogę dzisiaj pomóc?',
'chat_placeholder' => 'Wpisz swoją wiadomość...',
'chat_send_button' => 'Wyślij',
],
'en' => [
'login_header' => 'Login',
@ -359,6 +363,10 @@ $translations = [
'order_summary' => 'Order Summary',
'grand_total' => 'Grand Total',
'price' => 'Price',
'chat_with_assistant' => 'Chat with our Assistant',
'chat_hello' => 'Hello! How can I help you today?',
'chat_placeholder' => 'Type your message...',
'chat_send_button' => 'Send',
],
];

View File

@ -1,232 +0,0 @@
<?php
if (session_status() == PHP_SESSION_NONE) {
session_start();
}
// Language selection logic
if (isset($_GET['lang'])) {
$_SESSION['lang'] = $_GET['lang'] === 'en' ? 'en' : 'pl';
// Redirect to the same page without the lang parameter
header('Location: ' . strtok($_SERVER["REQUEST_URI"], '?'));
exit;
}
$lang = $_SESSION['lang'] ?? 'pl';
$translations = [
'pl' => [
'menu_catalog' => 'Katalog',
'menu_cart' => 'Koszyk',
'menu_orders' => 'Zamówienia',
'menu_profile' => 'Profil',
'menu_logout' => 'Wyloguj',
'btn_add_to_cart' => 'Dodaj do koszyka',
'btn_go_to_cart' => 'Przejdź do koszyka',
'btn_checkout' => 'Przejdź do zamówienia',
'btn_back_to_shop' => 'Wróć do sklepu',
'label_quantity' => 'Ilość',
'label_price' => 'Cena',
'label_total' => 'Razem',
'label_product' => 'Produkt',
'title_cart' => 'Koszyk',
'title_orders' => 'Twoje zamówienia',
'title_order_details' => 'Szczegóły zamówienia',
'title_checkout' => 'Podsumowanie zamówienia',
'title_profile' => 'Profil użytkownika',
'footer_powered_by' => 'powered by LEA24',
'cart_empty' => 'Twój koszyk jest pusty.',
'product' => 'Produkt',
'remove' => 'Usuń',
'subtotal' => 'Suma częściowa',
'continue_shopping' => 'Kontynuuj zakupy',
'order_summary' => 'Podsumowanie',
'order_date' => 'Data zamówienia',
'order_status' => 'Status',
'order_total' => 'Suma',
'order_action' => 'Akcja',
'order_view' => 'Zobacz',
'order_id' => 'ID Zamówienia',
'order_number' => 'Numer zamówienia',
'order_confirmation' => 'Potwierdzenie zamówienia',
'order_thank_you' => 'Dziękujemy za złożenie zamówienia.',
'order_number_is' => 'Numer Twojego zamówienia to',
'first_name' => 'Imię',
'last_name' => 'Nazwisko',
'email' => 'Email',
'current_password' => 'Aktualne hasło',
'new_password' => 'Nowe hasło',
'confirm_new_password' => 'Potwierdź nowe hasło',
'update_profile' => 'Zaktualizuj profil',
'password_note' => 'Pozostaw puste, jeśli nie chcesz zmieniać hasła.',
'profile_updated' => 'Profil zaktualizowany pomyślnie.',
'password_updated' => 'Hasło zaktualizowane pomyślnie.',
'password_mismatch' => 'Nowe hasła nie są zgodne.',
'incorrect_password' => 'Nieprawidłowe aktualne hasło.',
'app_title' => 'B2B Commerce',
'btn_update' => 'Zaktualizuj',
'btn_remove' => 'Usuń',
'label_unit_price' => 'Cena jednostkowa',
'label_subtotal' => 'Suma częściowa',
'confirm_order' => 'Potwierdź zamówienie',
'delivery_payment_options' => 'Opcje dostawy i płatności',
'delivery_source' => 'Źródło dostawy',
'central_warehouse' => 'Magazyn Centralny',
'external_supplier' => 'Dostawca zewnętrzny',
'available_trade_credit' => 'Dostępny limit kredytu kupieckiego',
'order_notes' => 'Uwagi do zamówienia',
'order_history' => 'Historia zamówień',
'error_client_id_not_found' => 'Nie znaleziono identyfikatora klienta. Zaloguj się ponownie.',
'error_fetching_orders' => 'Wystąpił błąd podczas pobierania zamówień. Prosimy spróbować ponownie później.',
'no_orders_yet' => 'Nie masz jeszcze żadnych zamówień.',
'btn_view_details' => 'Szczegóły',
'error_no_permission' => 'Brak uprawnień do wyświetlenia tego zamówienia.',
'error_order_not_found' => 'Nie znaleziono zamówienia lub nie masz do niego dostępu.',
'error_database' => 'Błąd bazy danych. Prosimy spróbować ponownie później.',
'label_payment_method' => 'Metoda płatności',
'label_notes' => 'Uwagi',
'label_image' => 'Zdjęcie',
'label_no_image' => 'Brak zdjęcia',
'btn_back_to_orders' => 'Wróć do listy zamówień',
'order_details_for' => 'Szczegóły zamówienia',
'error_loading_profile' => 'Wystąpił błąd podczas ładowania danych profilu. Prosimy spróbować ponownie później.',
'profile_meta_description' => 'Zarządzaj swoim profilem w platformie B2B Commerce.',
'toggle_navigation' => 'Przełącz nawigację',
'label_email' => 'Adres e-mail',
'label_client' => 'Klient',
'password_management' => 'Zarządzanie hasłem',
'feature_in_preparation' => 'Funkcja w przygotowaniu.',
'track_status_in' => 'Możesz śledzić jego status w panelu',
'my_orders' => 'Moje zamówienia',
'header_account' => 'Konto',
// Standardized Statuses
'status_pending' => 'Oczekujące',
'status_pending_payment' => 'Oczekuje na płatność',
'status_paid' => 'Zapłacone',
'status_in_progress' => 'W realizacji',
'status_shipped' => 'Wysłane',
'status_partially_shipped' => 'Częściowo wysłane',
'status_completed' => 'Zrealizowane',
'status_cancelled' => 'Anulowane',
// Standardized Payment Methods
'payment_method' => 'Metoda płatności',
'payment_bank_transfer' => 'Przelew tradycyjny',
'payment_online' => 'Płatność online (Przelewy24)',
'payment_credit' => 'Kredyt kupiecki',
'header_welcome' => 'Witaj',
'footer_text' => 'powered by LEA24',
],
'en' => [
'menu_catalog' => 'Catalog',
'menu_cart' => 'Cart',
'menu_orders' => 'Orders',
'menu_profile' => 'Profile',
'menu_logout' => 'Logout',
'btn_add_to_cart' => 'Add to cart',
'btn_go_to_cart' => 'Go to cart',
'btn_checkout' => 'Proceed to checkout',
'btn_back_to_shop' => 'Back to shop',
'label_quantity' => 'Quantity',
'label_price' => 'Price',
'label_total' => 'Total',
'label_product' => 'Product',
'title_cart' => 'Shopping Cart',
'title_orders' => 'Your Orders',
'title_order_details' => 'Order Details',
'title_checkout' => 'Checkout',
'title_profile' => 'User Profile',
'footer_powered_by' => 'powered by LEA24',
'cart_empty' => 'Your cart is empty.',
'product' => 'Product',
'remove' => 'Remove',
'subtotal' => 'Subtotal',
'continue_shopping' => 'Continue shopping',
'order_summary' => 'Order Summary',
'order_date' => 'Order Date',
'order_status' => 'Status',
'order_total' => 'Total',
'order_action' => 'Action',
'order_view' => 'View',
'order_id' => 'Order ID',
'order_number' => 'Order Number',
'order_confirmation' => 'Order Confirmation',
'order_thank_you' => 'Thank you for your order.',
'order_number_is' => 'Your order number is',
'first_name' => 'First Name',
'last_name' => 'Last Name',
'email' => 'Email',
'current_password' => 'Current Password',
'new_password' => 'New Password',
'confirm_new_password' => 'Confirm New Password',
'update_profile' => 'Update Profile',
'password_note' => 'Leave blank if you don\'t want to change the password.',
'profile_updated' => 'Profile updated successfully.',
'password_updated' => 'Password updated successfully.',
'password_mismatch' => 'New passwords do not match.',
'incorrect_password' => 'Incorrect current password.',
'app_title' => 'B2B Commerce',
'btn_update' => 'Update',
'btn_remove' => 'Remove',
'label_unit_price' => 'Unit price',
'label_subtotal' => 'Subtotal',
'confirm_order' => 'Confirm order',
'delivery_payment_options' => 'Delivery and payment options',
'delivery_source' => 'Delivery source',
'central_warehouse' => 'Central Warehouse',
'external_supplier' => 'External Supplier',
'available_trade_credit' => 'Available trade credit',
'order_notes' => 'Order notes',
'order_history' => 'Order History',
'error_client_id_not_found' => 'Client ID not found. Please log in again.',
'error_fetching_orders' => 'An error occurred while fetching orders. Please try again later.',
'no_orders_yet' => 'You have no orders yet.',
'btn_view_details' => 'Details',
'error_no_permission' => 'You do not have permission to view this order.',
'error_order_not_found' => 'Order not found or you do not have access to it.',
'error_database' => 'Database error. Please try again later.',
'label_payment_method' => 'Payment Method',
'label_notes' => 'Notes',
'label_image' => 'Image',
'label_no_image' => 'No image',
'btn_back_to_orders' => 'Back to orders',
'order_details_for' => 'Order Details',
'error_loading_profile' => 'An error occurred while loading profile data. Please try again later.',
'profile_meta_description' => 'Manage your profile on the B2B Commerce platform.',
'toggle_navigation' => 'Toggle navigation',
'label_email' => 'Email address',
'label_client' => 'Client',
'password_management' => 'Password Management',
'feature_in_preparation' => 'Feature in preparation.',
'track_status_in' => 'You can track its status in the',
'my_orders' => 'My Orders',
'header_account' => 'Account',
// Standardized Statuses
'status_pending' => 'Pending',
'status_pending_payment' => 'Pending payment',
'status_paid' => 'Paid',
'status_in_progress' => 'In progress',
'status_shipped' => 'Shipped',
'status_partially_shipped' => 'Partially shipped',
'status_completed' => 'Completed',
'status_cancelled' => 'Cancelled',
// Standardized Payment Methods
'payment_method' => 'Payment method',
'payment_bank_transfer' => 'Bank transfer',
'payment_online' => 'Online payment (Przelewy24)',
'payment_credit' => 'Trade credit',
'header_welcome' => 'Welcome',
'footer_text' => 'powered by LEA24',
]
];
if (!function_exists('t')) {
function t($key) {
global $translations, $lang;
return $translations[$lang][$key] ?? $key;
}
}
function getCurrentLanguage() {
global $lang;
return $lang;
}
?>

View File

@ -3,7 +3,7 @@ if (session_status() === PHP_SESSION_NONE) {
session_start();
}
require_once 'mail/MailService.php';
require_once 'includes/lang.php';
require_once 'includes/init.php';
require_once 'includes/auth.php';
require_login();
require_once 'includes/helpers.php';