mirror of
https://github.com/myronblair/tomsjavajive-app
synced 2026-06-30 17:50:56 -05:00
327 lines
14 KiB
PHP
327 lines
14 KiB
PHP
<?php
|
|
ob_start();
|
|
/**
|
|
* Tom's Java Jive - Admin Gift Cards
|
|
*/
|
|
|
|
$pageTitle = 'Gift Cards';
|
|
require_once __DIR__ . '/includes/header.php';
|
|
|
|
// Handle actions
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
$action = $_POST['action'] ?? '';
|
|
|
|
if ($action === 'create') {
|
|
$initialBalance = floatval($_POST['initial_balance'] ?? 0);
|
|
$recipientEmail = trim($_POST['recipient_email'] ?? '');
|
|
$recipientName = trim($_POST['recipient_name'] ?? '');
|
|
$message = trim($_POST['message'] ?? '');
|
|
$purchaserEmail = trim($_POST['purchaser_email'] ?? '');
|
|
|
|
if ($initialBalance > 0) {
|
|
$code = strtoupper('GC' . bin2hex(random_bytes(4)));
|
|
|
|
db()->insert('gift_cards', [
|
|
'gift_card_id' => generateId('gc_'),
|
|
'code' => $code,
|
|
'initial_balance' => $initialBalance,
|
|
'current_balance' => $initialBalance,
|
|
'purchaser_email' => $purchaserEmail ?: null,
|
|
'recipient_email' => $recipientEmail ?: null,
|
|
'recipient_name' => $recipientName ?: null,
|
|
'message' => $message ?: null,
|
|
'is_active' => 1
|
|
]);
|
|
|
|
setFlash('success', "Gift card created! Code: $code");
|
|
|
|
// Send email if recipient provided
|
|
if ($recipientEmail) {
|
|
$html = <<<HTML
|
|
<div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
|
|
<div style="background: #8B4513; color: white; padding: 20px; text-align: center;">
|
|
<h1 style="margin: 0;">You've Received a Gift!</h1>
|
|
</div>
|
|
<div style="padding: 30px; background: #FDFBF7; text-align: center;">
|
|
<p>Hi{$recipientName},</p>
|
|
<p>You've received a Tom's Java Jive gift card!</p>
|
|
<div style="background: white; padding: 20px; border-radius: 8px; margin: 20px 0;">
|
|
<p style="font-size: 24px; font-weight: bold; color: #E86A33;">$initialBalance</p>
|
|
<p style="font-size: 18px; letter-spacing: 3px;">$code</p>
|
|
</div>
|
|
<?php if ($message): ?><p style='font-style: italic;'>\<?php endif; ?>
|
|
<a href="https://tomsjavajive.com/shop.php" style="display: inline-block; background: #E86A33; color: white; padding: 12px 24px; border-radius: 6px; text-decoration: none; margin-top: 20px;">Shop Now</a>
|
|
</div>
|
|
</div>
|
|
HTML;
|
|
|
|
sendEmail($recipientEmail, "You've Received a Gift Card!", $html);
|
|
}
|
|
} else {
|
|
setFlash('error', 'Invalid balance amount');
|
|
}
|
|
|
|
header('Location: /admin/gift-cards.php');
|
|
exit;
|
|
}
|
|
|
|
if ($action === 'toggle' && !empty($_POST['gift_card_id'])) {
|
|
$gc = db()->fetch("SELECT is_active FROM gift_cards WHERE gift_card_id = :id", ['id' => $_POST['gift_card_id']]);
|
|
if ($gc) {
|
|
db()->update('gift_cards', ['is_active' => !$gc['is_active']], 'gift_card_id = :id', ['id' => $_POST['gift_card_id']]);
|
|
setFlash('success', 'Gift card status updated');
|
|
}
|
|
header('Location: /admin/gift-cards.php');
|
|
exit;
|
|
}
|
|
|
|
if ($action === 'adjust' && !empty($_POST['gift_card_id'])) {
|
|
$amount = floatval($_POST['amount'] ?? 0);
|
|
if ($amount != 0) {
|
|
db()->query(
|
|
"UPDATE gift_cards SET current_balance = current_balance + :amt WHERE gift_card_id = :id",
|
|
['amt' => $amount, 'id' => $_POST['gift_card_id']]
|
|
);
|
|
setFlash('success', 'Balance adjusted');
|
|
}
|
|
header('Location: /admin/gift-cards.php');
|
|
exit;
|
|
}
|
|
}
|
|
|
|
// Filters
|
|
$search = $_GET['search'] ?? '';
|
|
$status = $_GET['status'] ?? '';
|
|
$page = max(1, intval($_GET['page'] ?? 1));
|
|
|
|
$where = ['1=1'];
|
|
$params = [];
|
|
|
|
if ($search) {
|
|
$where[] = '(code LIKE :search OR recipient_email LIKE :search)';
|
|
$params['search'] = '%' . $search . '%';
|
|
}
|
|
|
|
if ($status === 'active') {
|
|
$where[] = 'is_active = 1 AND current_balance > 0';
|
|
} elseif ($status === 'depleted') {
|
|
$where[] = 'current_balance <= 0';
|
|
} elseif ($status === 'disabled') {
|
|
$where[] = 'is_active = 0';
|
|
}
|
|
|
|
$whereClause = implode(' AND ', $where);
|
|
$total = db()->count('gift_cards', $whereClause, $params);
|
|
$pagination = paginate($total, $page, ADMIN_ITEMS_PER_PAGE);
|
|
|
|
$giftCards = db()->fetchAll(
|
|
"SELECT * FROM gift_cards WHERE {$whereClause} ORDER BY created_at DESC LIMIT :limit OFFSET :offset",
|
|
array_merge($params, ['limit' => $pagination['per_page'], 'offset' => $pagination['offset']])
|
|
);
|
|
|
|
// Stats
|
|
$totalValue = db()->fetch("SELECT SUM(current_balance) as total FROM gift_cards WHERE is_active = 1")['total'] ?? 0;
|
|
$activeCount = db()->count('gift_cards', 'is_active = 1 AND current_balance > 0');
|
|
?>
|
|
|
|
<div class="page-header">
|
|
<h1 class="page-title">Gift Cards</h1>
|
|
<button class="btn btn-primary" onclick="Modal.open('createModal')">
|
|
<i class="fas fa-plus"></i> Create Gift Card
|
|
</button>
|
|
</div>
|
|
|
|
<?php if (hasFlash('success')): ?>
|
|
<div class="alert alert-success"><i class="fas fa-check-circle"></i> <?= getFlash('success') ?></div>
|
|
<?php endif; ?>
|
|
<?php if (hasFlash('error')): ?>
|
|
<div class="alert alert-error"><i class="fas fa-exclamation-circle"></i> <?= getFlash('error') ?></div>
|
|
<?php endif; ?>
|
|
|
|
<!-- Stats -->
|
|
<div class="stats-grid" style="margin-bottom: 1.5rem;">
|
|
<div class="stat-card">
|
|
<div class="stat-card-icon primary"><i class="fas fa-gift"></i></div>
|
|
<div>
|
|
<div class="stat-card-value"><?= $activeCount ?></div>
|
|
<div class="stat-card-label">Active Cards</div>
|
|
</div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<div class="stat-card-icon success"><i class="fas fa-dollar-sign"></i></div>
|
|
<div>
|
|
<div class="stat-card-value"><?= formatCurrency($totalValue) ?></div>
|
|
<div class="stat-card-label">Outstanding Value</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Filters -->
|
|
<div class="admin-card">
|
|
<div class="admin-card-body">
|
|
<form method="GET" style="display: flex; gap: 1rem; flex-wrap: wrap; align-items: end;">
|
|
<div class="form-group mb-0" style="flex: 1; min-width: 200px;">
|
|
<label class="form-label">Search</label>
|
|
<input type="text" name="search" class="form-input" placeholder="Code or email..." value="<?= htmlspecialchars($search) ?>">
|
|
</div>
|
|
<div class="form-group mb-0">
|
|
<label class="form-label">Status</label>
|
|
<select name="status" class="form-select">
|
|
<option value="">All</option>
|
|
<option value="active" <?= $status === 'active' ? 'selected' : '' ?>>Active</option>
|
|
<option value="depleted" <?= $status === 'depleted' ? 'selected' : '' ?>>Depleted</option>
|
|
<option value="disabled" <?= $status === 'disabled' ? 'selected' : '' ?>>Disabled</option>
|
|
</select>
|
|
</div>
|
|
<button type="submit" class="btn btn-secondary"><i class="fas fa-filter"></i> Filter</button>
|
|
<?php if ($search || $status): ?>
|
|
<a href="/admin/gift-cards.php" class="btn btn-secondary">Clear</a>
|
|
<?php endif; ?>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Table -->
|
|
<div class="admin-card">
|
|
<div class="admin-card-body" style="padding: 0;">
|
|
<table class="admin-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Code</th>
|
|
<th>Recipient</th>
|
|
<th>Initial</th>
|
|
<th>Balance</th>
|
|
<th>Status</th>
|
|
<th>Created</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php if (empty($giftCards)): ?>
|
|
<tr><td colspan="7" class="text-muted" style="text-align: center; padding: 2rem;">No gift cards found</td></tr>
|
|
<?php else: ?>
|
|
<?php foreach ($giftCards as $gc): ?>
|
|
<tr>
|
|
<td><strong style="font-family: monospace;"><?= htmlspecialchars($gc['code']) ?></strong></td>
|
|
<td><?= htmlspecialchars($gc['recipient_email'] ?? $gc['recipient_name'] ?? '-') ?></td>
|
|
<td><?= formatCurrency($gc['initial_balance']) ?></td>
|
|
<td>
|
|
<?php if ($gc['current_balance'] <= 0): ?>
|
|
<span class="badge badge-error">$0.00</span>
|
|
<?php else: ?>
|
|
<strong class="text-success"><?= formatCurrency($gc['current_balance']) ?></strong>
|
|
<?php endif; ?>
|
|
</td>
|
|
<td>
|
|
<?php if (!$gc['is_active']): ?>
|
|
<span class="badge badge-error">Disabled</span>
|
|
<?php elseif ($gc['current_balance'] <= 0): ?>
|
|
<span class="badge badge-warning">Depleted</span>
|
|
<?php else: ?>
|
|
<span class="badge badge-success">Active</span>
|
|
<?php endif; ?>
|
|
</td>
|
|
<td class="text-muted"><?= formatDate($gc['created_at']) ?></td>
|
|
<td>
|
|
<button class="btn btn-sm btn-secondary" onclick="openAdjustModal('<?= $gc['gift_card_id'] ?>', '<?= $gc['code'] ?>', <?= $gc['current_balance'] ?>)">
|
|
<i class="fas fa-edit"></i>
|
|
</button>
|
|
<form method="POST" style="display: inline;">
|
|
<input type="hidden" name="action" value="toggle">
|
|
<input type="hidden" name="gift_card_id" value="<?= $gc['gift_card_id'] ?>">
|
|
<button type="submit" class="btn btn-sm btn-secondary" title="<?= $gc['is_active'] ? 'Disable' : 'Enable' ?>">
|
|
<i class="fas fa-<?= $gc['is_active'] ? 'ban' : 'check' ?>"></i>
|
|
</button>
|
|
</form>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
<?php endif; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<?php if ($pagination['total_pages'] > 1): ?>
|
|
<div style="display: flex; justify-content: center; margin-top: 1rem;">
|
|
<?= renderPagination($pagination, '/admin/gift-cards.php?search=' . urlencode($search) . '&status=' . $status) ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<!-- Create Modal -->
|
|
<div class="modal-overlay" id="createModal">
|
|
<div class="modal">
|
|
<div class="modal-header">
|
|
<h3 class="modal-title">Create Gift Card</h3>
|
|
<button type="button" class="modal-close" onclick="Modal.close('createModal')">×</button>
|
|
</div>
|
|
<form method="POST">
|
|
<div class="modal-body">
|
|
<input type="hidden" name="action" value="create">
|
|
<div class="form-group">
|
|
<label class="form-label">Amount *</label>
|
|
<input type="number" name="initial_balance" class="form-input" step="0.01" min="1" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label class="form-label">Recipient Email (optional)</label>
|
|
<input type="email" name="recipient_email" class="form-input">
|
|
</div>
|
|
<div class="form-group">
|
|
<label class="form-label">Recipient Name (optional)</label>
|
|
<input type="text" name="recipient_name" class="form-input">
|
|
</div>
|
|
<div class="form-group">
|
|
<label class="form-label">Personal Message (optional)</label>
|
|
<textarea name="message" class="form-textarea" rows="2"></textarea>
|
|
</div>
|
|
<div class="form-group mb-0">
|
|
<label class="form-label">Purchaser Email (optional)</label>
|
|
<input type="email" name="purchaser_email" class="form-input">
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" onclick="Modal.close('createModal')">Cancel</button>
|
|
<button type="submit" class="btn btn-primary">Create Gift Card</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Adjust Modal -->
|
|
<div class="modal-overlay" id="adjustModal">
|
|
<div class="modal">
|
|
<div class="modal-header">
|
|
<h3 class="modal-title">Adjust Balance</h3>
|
|
<button type="button" class="modal-close" onclick="Modal.close('adjustModal')">×</button>
|
|
</div>
|
|
<form method="POST">
|
|
<div class="modal-body">
|
|
<input type="hidden" name="action" value="adjust">
|
|
<input type="hidden" name="gift_card_id" id="adjust-gc-id">
|
|
<p>Card: <strong id="adjust-gc-code"></strong></p>
|
|
<p>Current Balance: <strong id="adjust-gc-balance"></strong></p>
|
|
<div class="form-group">
|
|
<label class="form-label">Adjustment Amount</label>
|
|
<input type="number" name="amount" class="form-input" step="0.01" placeholder="Use negative to deduct">
|
|
<small class="text-muted">Enter positive to add, negative to subtract</small>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" onclick="Modal.close('adjustModal')">Cancel</button>
|
|
<button type="submit" class="btn btn-primary">Apply Adjustment</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
function openAdjustModal(id, code, balance) {
|
|
document.getElementById('adjust-gc-id').value = id;
|
|
document.getElementById('adjust-gc-code').textContent = code;
|
|
document.getElementById('adjust-gc-balance').textContent = '$' + parseFloat(balance).toFixed(2);
|
|
Modal.open('adjustModal');
|
|
}
|
|
</script>
|
|
|
|
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|