v1.0.0.1
StocketBase
- <?php
-
- declare(strict_types=1);
-
- require_once __DIR__ . '/includes/config.php';
- require_once __DIR__ . '/includes/database.php';
- require_once __DIR__ . '/includes/user-auth.php';
- require_once __DIR__ . '/includes/csrf.php';
- require_once __DIR__ . '/includes/language.php';
- require_once __DIR__ . '/includes/site-front.php';
- require_once __DIR__ . '/includes/currency.php';
-
- UserAuth::boot();
- UserAuth::requireLogin();
-
- $reader = UserAuth::user();
- $settings = SiteFront::settings();
- $flashMessage = null;
-
- if ($_SERVER['REQUEST_METHOD'] === 'POST') {
- if (!Csrf::verify($_POST['csrf_token'] ?? null)) {
- $flashMessage = Language::get('form_security_failed', 'Security check failed, please try again.');
- } else {
- $flashMessage = require __DIR__ . '/dashboard-actions/save-account.php';
- $reader = UserAuth::user();
- }
- }
-
- $subscriptionsStatement = Database::users()->prepare(
- 'SELECT * FROM subscriptions WHERE user_account_id = :id ORDER BY created_at DESC'
- );
- $subscriptionsStatement->execute(['id' => $reader['id']]);
- $subscriptions = $subscriptionsStatement->fetchAll();
-
- $consentsStatement = Database::users()->prepare(
- 'SELECT consent_type, is_granted FROM user_consents WHERE user_account_id = :id'
- );
- $consentsStatement->execute(['id' => $reader['id']]);
- $consentRows = $consentsStatement->fetchAll();
- $consents = [];
- foreach ($consentRows as $row) {
- $consents[$row['consent_type']] = (bool) $row['is_granted'];
- }
-
- $ordersStatement = Database::users()->prepare(
- 'SELECT * FROM orders WHERE user_account_id = :id ORDER BY created_at DESC LIMIT 100'
- );
- $ordersStatement->execute(['id' => $reader['id']]);
- $orders = $ordersStatement->fetchAll();
-
- require_once __DIR__ . '/includes/digital-files.php';
-
- $accountDownloads = [];
- $ownedProductIds = DigitalFiles::ownedProductIds((int) $reader['id']);
- if (!empty($ownedProductIds)) {
- $placeholders = implode(',', array_fill(0, count($ownedProductIds), '?'));
- $ownedProductsStatement = Database::site()->prepare("SELECT id, title FROM products WHERE id IN ({$placeholders})");
- $ownedProductsStatement->execute($ownedProductIds);
- $ownedTitles = array_column($ownedProductsStatement->fetchAll(), 'title', 'id');
-
- foreach ($ownedProductIds as $ownedProductId) {
- $ownedFiles = DigitalFiles::filesForProduct($ownedProductId);
- if (empty($ownedFiles)) {
- continue;
- }
- $ownedTitle = (string) ($ownedTitles[$ownedProductId] ?? ($ownedFiles[0]['product_title'] ?? ''));
- $accountDownloads[] = ['title' => $ownedTitle !== '' ? $ownedTitle : $ownedFiles[0]['original_name'], 'files' => $ownedFiles];
- }
- usort($accountDownloads, static fn(array $a, array $b): int => strcasecmp($a['title'], $b['title']));
- }
-
- $viewOrderId = (int) ($_GET['order'] ?? 0);
- $viewOrder = null;
- $viewOrderItems = [];
- if ($viewOrderId > 0) {
- $viewOrderStatement = Database::users()->prepare(
- 'SELECT * FROM orders WHERE id = :id AND user_account_id = :account_id LIMIT 1'
- );
- $viewOrderStatement->execute(['id' => $viewOrderId, 'account_id' => $reader['id']]);
- $viewOrder = $viewOrderStatement->fetch();
-
- if ($viewOrder) {
- $viewOrderItemsStatement = Database::users()->prepare(
- 'SELECT * FROM order_items WHERE order_id = :id ORDER BY id ASC'
- );
- $viewOrderItemsStatement->execute(['id' => $viewOrderId]);
- $viewOrderItems = $viewOrderItemsStatement->fetchAll();
- }
- }
-
- $pageTitle = Language::get('account_profile', 'Profile') . ' - ' . $settings['site_name'];
-
- require __DIR__ . '/includes/front-header.php';
-
- ?>
- <h1 class="article-title"><?= htmlspecialchars(Language::get('account_profile', 'Profile')) ?></h1>
-
- <?php if ($flashMessage !== null): ?>
- <p style="color: var(--accent);"><?= htmlspecialchars($flashMessage) ?></p>
- <?php endif; ?>
-
- <form method="post" style="max-width:420px;margin-bottom:32px;">
- <?= Csrf::field() ?>
- <input type="hidden" name="action" value="update_profile">
- <label><?= htmlspecialchars(Language::get('auth_display_name', 'Display name')) ?></label>
- <input type="text" name="display_name" value="<?= htmlspecialchars($reader['display_name'] ?? '') ?>" style="width:100%;padding:10px;border-radius:8px;border:1px solid var(--border);background:var(--panel);color:var(--text);margin:6px 0 14px;">
- <label><?= htmlspecialchars(Language::get('account_current_password', 'Current password (required to set a new password)')) ?></label>
- <input type="password" name="current_password" autocomplete="current-password" style="width:100%;padding:10px;border-radius:8px;border:1px solid var(--border);background:var(--panel);color:var(--text);margin:6px 0 14px;">
- <label><?= htmlspecialchars(Language::get('account_new_password', 'New password (leave blank to keep current)')) ?></label>
- <input type="password" name="new_password" minlength="8" style="width:100%;padding:10px;border-radius:8px;border:1px solid var(--border);background:var(--panel);color:var(--text);margin:6px 0 14px;">
- <button type="submit" class="unlock-btn" style="border:none;cursor:pointer;"><?= htmlspecialchars(Language::get('account_save', 'Save changes')) ?></button>
- </form>
-
- <h2><?= htmlspecialchars(Language::get('account_orders', 'Order history')) ?></h2>
-
- <?php if ($viewOrder !== null): ?>
- <p><a href="account.php">← <?= htmlspecialchars(Language::get('account_back_to_orders', 'Back to order history')) ?></a></p>
- <div class="order-summary">
- <p><strong><?= htmlspecialchars(Language::get('order_number_label', 'Order number')) ?>:</strong> <?= htmlspecialchars($viewOrder['order_number']) ?></p>
- <p><strong><?= htmlspecialchars(Language::get('order_status_label', 'Status')) ?>:</strong> <span class="status-pill status-<?= htmlspecialchars($viewOrder['status']) ?>"><?= htmlspecialchars(Language::get('order_status_' . $viewOrder['status'], ucfirst($viewOrder['status']))) ?></span></p>
- <p><strong><?= htmlspecialchars(Language::get('order_placed_label', 'Placed on')) ?>:</strong> <?= htmlspecialchars($viewOrder['created_at']) ?></p>
- <?php if (!empty($viewOrder['tracking_number'])): ?>
- <p><strong><?= htmlspecialchars(Language::get('order_tracking_label', 'Tracking')) ?>:</strong>
- <?php if (!empty($viewOrder['tracking_url'])): ?>
- <a href="<?= htmlspecialchars($viewOrder['tracking_url']) ?>" target="_blank" rel="noopener noreferrer"><?= htmlspecialchars($viewOrder['tracking_number']) ?></a>
- <?php else: ?>
- <?= htmlspecialchars($viewOrder['tracking_number']) ?>
- <?php endif; ?>
- </p>
- <?php endif; ?>
-
- <table class="dash-table">
- <thead>
- <tr>
- <th><?= htmlspecialchars(Language::get('cart_column_product', 'Product')) ?></th>
- <th><?= htmlspecialchars(Language::get('cart_column_quantity', 'Quantity')) ?></th>
- <th><?= htmlspecialchars(Language::get('cart_column_total', 'Total')) ?></th>
- </tr>
- </thead>
- <tbody>
- <?php foreach ($viewOrderItems as $orderItem): ?>
- <tr>
- <td><?= htmlspecialchars($orderItem['product_title_snapshot']) ?><?= $orderItem['variant_name_snapshot'] !== null ? ' — ' . htmlspecialchars($orderItem['variant_name_snapshot']) : '' ?></td>
- <td><?= (int) $orderItem['quantity'] ?></td>
- <td><?= htmlspecialchars(Currency::format((int) $orderItem['total_cents'], $viewOrder['currency'])) ?></td>
- </tr>
- <?php endforeach; ?>
- </tbody>
- </table>
-
- <div class="cart-summary">
- <div class="cart-summary-row"><span><?= htmlspecialchars(Language::get('cart_subtotal', 'Subtotal')) ?></span><span><?= htmlspecialchars(Currency::format((int) $viewOrder['subtotal_cents'], $viewOrder['currency'])) ?></span></div>
- <?php if ((int) $viewOrder['discount_cents'] > 0): ?>
- <div class="cart-summary-row"><span><?= htmlspecialchars(Language::get('cart_discount', 'Discount')) ?></span><span>-<?= htmlspecialchars(Currency::format((int) $viewOrder['discount_cents'], $viewOrder['currency'])) ?></span></div>
- <?php endif; ?>
- <div class="cart-summary-row cart-summary-total"><span><?= htmlspecialchars(Language::get('cart_total', 'Total')) ?></span><span><?= htmlspecialchars(Currency::format((int) $viewOrder['total_cents'], $viewOrder['currency'])) ?></span></div>
- </div>
- </div>
- <?php else: ?>
- <table class="dash-table">
- <thead>
- <tr>
- <th><?= htmlspecialchars(Language::get('order_number_label', 'Order number')) ?></th>
- <th><?= htmlspecialchars(Language::get('order_placed_label', 'Placed on')) ?></th>
- <th><?= htmlspecialchars(Language::get('order_status_label', 'Status')) ?></th>
- <th><?= htmlspecialchars(Language::get('cart_column_total', 'Total')) ?></th>
- <th></th>
- </tr>
- </thead>
- <tbody>
- <?php foreach ($orders as $orderRow): ?>
- <tr>
- <td><?= htmlspecialchars($orderRow['order_number']) ?></td>
- <td><?= htmlspecialchars($orderRow['created_at']) ?></td>
- <td><span class="status-pill status-<?= htmlspecialchars($orderRow['status']) ?>"><?= htmlspecialchars(Language::get('order_status_' . $orderRow['status'], ucfirst($orderRow['status']))) ?></span></td>
- <td><?= htmlspecialchars(Currency::format((int) $orderRow['total_cents'], $orderRow['currency'])) ?></td>
- <td><a href="account.php?order=<?= (int) $orderRow['id'] ?>"><?= htmlspecialchars(Language::get('order_view_button', 'View')) ?></a></td>
- </tr>
- <?php endforeach; ?>
- <?php if (empty($orders)): ?>
- <tr><td colspan="5"><?= htmlspecialchars(Language::get('account_no_orders', 'You have not placed any orders yet.')) ?></td></tr>
- <?php endif; ?>
- </tbody>
- </table>
- <?php endif; ?>
-
- <?php if (!empty($accountDownloads)): ?>
- <h2><?= htmlspecialchars(Language::get('account_downloads', 'Downloads')) ?></h2>
- <?php foreach ($accountDownloads as $accountDownload): ?>
- <h3 style="margin:18px 0 0;font-size:15px;"><?= htmlspecialchars($accountDownload['title']) ?></h3>
- <ul class="download-list">
- <?php foreach ($accountDownload['files'] as $accountFile): ?>
- <li>
- <a href="<?= htmlspecialchars(DigitalFiles::downloadUrl((int) $accountFile['id'])) ?>" rel="nofollow"><?= Icons::icon('download', 'icon icon-sm') ?><?= htmlspecialchars(DigitalFiles::displayName($accountFile)) ?></a>
- <small><?= htmlspecialchars(DigitalFiles::formatSize((int) $accountFile['size_bytes'])) ?></small>
- </li>
- <?php endforeach; ?>
- </ul>
- <?php endforeach; ?>
- <?php endif; ?>
-
- <?php if (($settings['pricing_model'] ?? 'per_product') === 'subscription' || !empty($subscriptions)): ?>
- <h2><?= htmlspecialchars(Language::get('account_subscriptions', 'Subscriptions')) ?></h2>
- <ul>
- <?php foreach ($subscriptions as $subscription): ?>
- <li><?= htmlspecialchars($subscription['provider']) ?> — <?= htmlspecialchars($subscription['plan_code'] ?? '') ?> (<?= htmlspecialchars(Language::get('subscription_status_' . $subscription['status'], $subscription['status'])) ?>)</li>
- <?php endforeach; ?>
- <?php if (empty($subscriptions)): ?>
- <li><?= htmlspecialchars(Language::get('account_no_subscriptions', 'No active subscriptions.')) ?></li>
- <?php endif; ?>
- </ul>
- <?php endif; ?>
-
- <h2><?= htmlspecialchars(Language::get('account_consents', 'Privacy consents')) ?></h2>
- <form method="post" style="max-width:420px;">
- <?= Csrf::field() ?>
- <input type="hidden" name="action" value="update_consents">
- <label><input type="checkbox" name="consent_analytics" <?= !empty($consents['analytics']) ? 'checked' : '' ?>> <?= htmlspecialchars(Language::get('account_consent_analytics', 'Allow analytics tracking')) ?></label>
- <label><input type="checkbox" name="consent_ads_personalization" <?= !empty($consents['ads_personalization']) ? 'checked' : '' ?>> <?= htmlspecialchars(Language::get('account_consent_ads', 'Allow personalized ads')) ?></label>
- <button type="submit" class="unlock-btn" style="border:none;cursor:pointer;margin-top:14px;"><?= htmlspecialchars(Language::get('account_save', 'Save changes')) ?></button>
- </form>
-
- <?php require __DIR__ . '/includes/front-footer.php'; ?>
-