mirror of
https://github.com/myronblair/tomsjavajive
synced 2026-06-30 17:50:32 -05:00
Fix integrations.php: handle POST before HTML output to fix blank screen on save
This commit is contained in:
+129
-272
@@ -1,112 +1,92 @@
|
|||||||
<?php
|
<?php
|
||||||
ob_start();
|
|
||||||
/**
|
/**
|
||||||
* Tom's Java Jive - Admin Integrations Settings
|
* Tom's Java Jive - Admin Integrations Settings
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Auth only — no HTML yet
|
||||||
|
require_once __DIR__ . '/../includes/auth.php';
|
||||||
|
AdminAuth::require();
|
||||||
|
|
||||||
|
// Handle POST before any output
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
$section = $_POST['section'] ?? '';
|
||||||
|
|
||||||
|
if ($section === 'cybermail') {
|
||||||
|
setSetting('cybermail_api_key', trim($_POST['cybermail_api_key'] ?? ''));
|
||||||
|
setSetting('cybermail_from_email', trim($_POST['cybermail_from_email'] ?? ''));
|
||||||
|
setSetting('cybermail_from_name', trim($_POST['cybermail_from_name'] ?? ''));
|
||||||
|
setSetting('email_notifications_enabled', isset($_POST['email_notifications_enabled']) ? '1' : '0');
|
||||||
|
setFlash('success', 'CyberMail settings saved.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($section === 'twilio') {
|
||||||
|
setSetting('twilio_account_sid', trim($_POST['twilio_account_sid'] ?? ''));
|
||||||
|
setSetting('twilio_auth_token', trim($_POST['twilio_auth_token'] ?? ''));
|
||||||
|
setSetting('twilio_phone_number', trim($_POST['twilio_phone_number'] ?? ''));
|
||||||
|
setSetting('sms_notifications_enabled', isset($_POST['sms_notifications_enabled']) ? '1' : '0');
|
||||||
|
setFlash('success', 'Twilio settings saved.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($section === 'push') {
|
||||||
|
setSetting('vapid_public_key', trim($_POST['vapid_public_key'] ?? ''));
|
||||||
|
setSetting('vapid_private_key', trim($_POST['vapid_private_key'] ?? ''));
|
||||||
|
setSetting('push_notifications_enabled', isset($_POST['push_notifications_enabled']) ? '1' : '0');
|
||||||
|
setFlash('success', 'Push notification settings saved.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($section === 'loyalty') {
|
||||||
|
setSetting('loyalty_enabled', isset($_POST['loyalty_enabled']) ? '1' : '0');
|
||||||
|
setFlash('success', 'Loyalty program settings saved.');
|
||||||
|
}
|
||||||
|
|
||||||
|
header('Location: /admin/integrations.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- GET: render page ---
|
||||||
|
ob_start();
|
||||||
$pageTitle = 'Integrations';
|
$pageTitle = 'Integrations';
|
||||||
$currentPage = 'integrations';
|
$currentPage = 'integrations';
|
||||||
require_once __DIR__ . '/includes/header.php';
|
require_once __DIR__ . '/includes/header.php';
|
||||||
|
|
||||||
// Handle form submission
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
||||||
$section = $_POST['section'] ?? '';
|
|
||||||
|
|
||||||
$settingsMap = [
|
|
||||||
'cybermail' => ['cybermail_api_key', 'cybermail_from_email', 'cybermail_from_name', 'email_notifications_enabled'],
|
|
||||||
'twilio' => ['twilio_account_sid', 'twilio_auth_token', 'twilio_phone_number', 'sms_notifications_enabled'],
|
|
||||||
'push' => ['vapid_public_key', 'vapid_private_key', 'push_notifications_enabled'],
|
|
||||||
'loyalty' => ['loyalty_enabled']
|
|
||||||
];
|
|
||||||
|
|
||||||
if (isset($settingsMap[$section])) {
|
|
||||||
foreach ($settingsMap[$section] as $key) {
|
|
||||||
$value = $_POST[$key] ?? '';
|
|
||||||
|
|
||||||
$existing = db()->fetch("SELECT id FROM settings WHERE setting_key = :key", ['key' => $key]);
|
|
||||||
|
|
||||||
if ($existing) {
|
|
||||||
db()->query(
|
|
||||||
"UPDATE settings SET setting_value = :value, updated_at = NOW() WHERE setting_key = :key",
|
|
||||||
['value' => $value, 'key' => $key]
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
db()->insert('settings', [
|
|
||||||
'setting_key' => $key,
|
|
||||||
'setting_value' => $value
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setFlash('success', ucfirst($section) . ' settings saved successfully!');
|
|
||||||
}
|
|
||||||
|
|
||||||
redirect('/admin/integrations.php');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load current settings
|
// Load current settings
|
||||||
$settings = [];
|
$cm = [
|
||||||
$allSettings = db()->fetchAll("SELECT setting_key, setting_value FROM settings");
|
'api_key' => getSetting('cybermail_api_key', ''),
|
||||||
foreach ($allSettings as $s) {
|
'from_email' => getSetting('cybermail_from_email', 'noreply@tomsjavajive.com'),
|
||||||
$settings[$s['setting_key']] = $s['setting_value'];
|
'from_name' => getSetting('cybermail_from_name', "Tom's Java Jive"),
|
||||||
}
|
'enabled' => getSetting('email_notifications_enabled', '0'),
|
||||||
|
];
|
||||||
|
$tw = [
|
||||||
|
'sid' => getSetting('twilio_account_sid', ''),
|
||||||
|
'token' => getSetting('twilio_auth_token', ''),
|
||||||
|
'phone' => getSetting('twilio_phone_number', ''),
|
||||||
|
'enabled' => getSetting('sms_notifications_enabled', '0'),
|
||||||
|
];
|
||||||
|
$push = [
|
||||||
|
'pub' => getSetting('vapid_public_key', ''),
|
||||||
|
'priv' => getSetting('vapid_private_key', ''),
|
||||||
|
'enabled' => getSetting('push_notifications_enabled', '0'),
|
||||||
|
];
|
||||||
|
$loyaltyEnabled = getSetting('loyalty_enabled', '1') === '1';
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.integration-card {
|
.integration-card { background: var(--admin-surface); border-radius: var(--admin-radius); margin-bottom: 1.5rem; }
|
||||||
background: var(--admin-surface);
|
.integration-header { display: flex; justify-content: space-between; align-items: center; padding: 1.25rem 1.5rem; border-bottom: 1px solid var(--admin-border); }
|
||||||
border-radius: var(--admin-radius);
|
.integration-title { display: flex; align-items: center; gap: 1rem; }
|
||||||
margin-bottom: 1.5rem;
|
.integration-icon { width: 48px; height: 48px; border-radius: 10px; display: flex; align-items: center; justify-content: center; font-size: 1.5rem; }
|
||||||
}
|
|
||||||
|
|
||||||
.integration-header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
padding: 1.25rem 1.5rem;
|
|
||||||
border-bottom: 1px solid var(--admin-border);
|
|
||||||
}
|
|
||||||
|
|
||||||
.integration-title {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.integration-icon {
|
|
||||||
width: 48px;
|
|
||||||
height: 48px;
|
|
||||||
border-radius: 10px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
font-size: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.integration-icon.cybermail { background: #0ea5e9; color: white; }
|
.integration-icon.cybermail { background: #0ea5e9; color: white; }
|
||||||
.integration-icon.twilio { background: #F22F46; color: white; }
|
.integration-icon.twilio { background: #F22F46; color: white; }
|
||||||
.integration-icon.push { background: #8B5CF6; color: white; }
|
.integration-icon.push { background: #8B5CF6; color: white; }
|
||||||
.integration-icon.loyalty { background: #F59E0B; color: white; }
|
.integration-icon.loyalty { background: #F59E0B; color: white; }
|
||||||
|
.integration-body { padding: 1.5rem; }
|
||||||
.integration-body {
|
.status-badge { padding: .375rem .75rem; border-radius: 20px; font-size: .75rem; font-weight: 600; }
|
||||||
padding: 1.5rem;
|
.status-badge.configured { background: rgba(16,185,129,.1); color: var(--admin-success); }
|
||||||
}
|
.status-badge.not-configured { background: rgba(245,158,11,.1); color: var(--admin-warning); }
|
||||||
|
.status-badge.enabled { background: rgba(16,185,129,.1); color: var(--admin-success); }
|
||||||
.status-badge {
|
.status-badge.disabled { background: rgba(239,68,68,.1); color: var(--admin-error); }
|
||||||
padding: 0.375rem 0.75rem;
|
.key-input { font-family: monospace; font-size: .875rem; }
|
||||||
border-radius: 20px;
|
.help-text { font-size: .75rem; color: var(--admin-text-muted); margin-top: .25rem; }
|
||||||
font-size: 0.75rem;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-badge.configured { background: rgba(16, 185, 129, 0.1); color: var(--admin-success); }
|
|
||||||
.status-badge.not-configured { background: rgba(245, 158, 11, 0.1); color: var(--admin-warning); }
|
|
||||||
.status-badge.enabled { background: rgba(16, 185, 129, 0.1); color: var(--admin-success); }
|
|
||||||
.status-badge.disabled { background: rgba(239, 68, 68, 0.1); color: var(--admin-error); }
|
|
||||||
|
|
||||||
.key-input { font-family: monospace; font-size: 0.875rem; }
|
|
||||||
.test-btn { margin-top: 0.5rem; }
|
|
||||||
.help-text { font-size: 0.75rem; color: var(--admin-text-muted); margin-top: 0.25rem; }
|
|
||||||
.help-link { color: var(--admin-primary); }
|
.help-link { color: var(--admin-primary); }
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
@@ -116,78 +96,52 @@ foreach ($allSettings as $s) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php if (hasFlash('success')): ?>
|
<?php if (hasFlash('success')): ?>
|
||||||
<div class="alert alert-success mb-2">
|
<div class="alert alert-success mb-2"><i class="fas fa-check-circle"></i> <?= getFlash('success') ?></div>
|
||||||
<i class="fas fa-check-circle"></i> <?= getFlash('success') ?>
|
|
||||||
</div>
|
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<!-- CyberMail Email -->
|
<!-- CyberMail -->
|
||||||
<div class="integration-card">
|
<div class="integration-card">
|
||||||
<div class="integration-header">
|
<div class="integration-header">
|
||||||
<div class="integration-title">
|
<div class="integration-title">
|
||||||
<div class="integration-icon cybermail">
|
<div class="integration-icon cybermail"><i class="fas fa-envelope"></i></div>
|
||||||
<i class="fas fa-envelope"></i>
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
<h3 style="margin:0;">CyberMail</h3>
|
<h3 style="margin:0;">CyberMail</h3>
|
||||||
<p style="margin: 0.25rem 0 0; color: var(--admin-text-muted); font-size: 0.875rem;">
|
<p style="margin:.25rem 0 0;color:var(--admin-text-muted);font-size:.875rem;">Transactional email — order confirmations, shipping updates</p>
|
||||||
Send transactional emails (order confirmations, shipping updates, etc.)
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<?php
|
<?php $cmOk = !empty($cm['api_key']); $cmOn = $cm['enabled'] === '1'; ?>
|
||||||
$cmConfigured = !empty($settings['cybermail_api_key']);
|
<span class="status-badge <?= $cmOk && $cmOn ? 'enabled' : ($cmOk ? 'configured' : 'not-configured') ?>">
|
||||||
$cmEnabled = ($settings['email_notifications_enabled'] ?? '0') === '1';
|
<?= $cmOk && $cmOn ? 'Enabled' : ($cmOk ? 'Configured' : 'Not Configured') ?>
|
||||||
?>
|
|
||||||
<span class="status-badge <?= $cmConfigured && $cmEnabled ? 'enabled' : ($cmConfigured ? 'configured' : 'not-configured') ?>">
|
|
||||||
<?= $cmConfigured && $cmEnabled ? 'Enabled' : ($cmConfigured ? 'Configured' : 'Not Configured') ?>
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="integration-body">
|
<div class="integration-body">
|
||||||
<form method="POST">
|
<form method="POST">
|
||||||
<input type="hidden" name="section" value="cybermail">
|
<input type="hidden" name="section" value="cybermail">
|
||||||
|
<div class="form-group">
|
||||||
<div class="form-row">
|
|
||||||
<div class="form-group" style="flex: 2;">
|
|
||||||
<label class="form-label">CyberMail API Key</label>
|
<label class="form-label">CyberMail API Key</label>
|
||||||
<input type="password" name="cybermail_api_key" class="form-input key-input"
|
<input type="password" name="cybermail_api_key" class="form-input key-input"
|
||||||
value="<?= htmlspecialchars($settings['cybermail_api_key'] ?? '') ?>"
|
value="<?= htmlspecialchars($cm['api_key']) ?>" placeholder="sk_live_...">
|
||||||
placeholder="sk_live_...">
|
<p class="help-text">Manage at <a href="https://platform.cyberpersons.com/email/api-keys/" target="_blank" class="help-link">CyberMail Dashboard</a></p>
|
||||||
<p class="help-text">
|
|
||||||
Manage at
|
|
||||||
<a href="https://platform.cyberpersons.com/email/api-keys/" target="_blank" class="help-link">CyberMail Dashboard</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-label">From Email</label>
|
<label class="form-label">From Email</label>
|
||||||
<input type="email" name="cybermail_from_email" class="form-input"
|
<input type="email" name="cybermail_from_email" class="form-input" value="<?= htmlspecialchars($cm['from_email']) ?>">
|
||||||
value="<?= htmlspecialchars($settings['cybermail_from_email'] ?? 'noreply@tomsjavajive.com') ?>">
|
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-label">From Name</label>
|
<label class="form-label">From Name</label>
|
||||||
<input type="text" name="cybermail_from_name" class="form-input"
|
<input type="text" name="cybermail_from_name" class="form-input" value="<?= htmlspecialchars($cm['from_name']) ?>">
|
||||||
value="<?= htmlspecialchars($settings['cybermail_from_name'] ?? "Tom's Java Jive") ?>">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-checkbox">
|
<label class="form-checkbox">
|
||||||
<input type="checkbox" name="email_notifications_enabled" value="1"
|
<input type="checkbox" name="email_notifications_enabled" value="1" <?= $cmOn ? 'checked' : '' ?>>
|
||||||
<?= ($settings['email_notifications_enabled'] ?? '0') === '1' ? 'checked' : '' ?>>
|
|
||||||
Enable email notifications
|
Enable email notifications
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div style="display:flex;gap:.5rem;">
|
||||||
<div style="display: flex; gap: 0.5rem;">
|
<button type="submit" class="btn btn-primary"><i class="fas fa-save"></i> Save Settings</button>
|
||||||
<button type="submit" class="btn btn-primary">
|
<button type="button" class="btn btn-secondary" onclick="testCyberMail()"><i class="fas fa-paper-plane"></i> Send Test Email</button>
|
||||||
<i class="fas fa-save"></i> Save Settings
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn btn-secondary" onclick="testCyberMail()">
|
|
||||||
<i class="fas fa-paper-plane"></i> Send Test Email
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@@ -197,69 +151,44 @@ foreach ($allSettings as $s) {
|
|||||||
<div class="integration-card">
|
<div class="integration-card">
|
||||||
<div class="integration-header">
|
<div class="integration-header">
|
||||||
<div class="integration-title">
|
<div class="integration-title">
|
||||||
<div class="integration-icon twilio">
|
<div class="integration-icon twilio"><i class="fas fa-sms"></i></div>
|
||||||
<i class="fas fa-sms"></i>
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
<h3 style="margin:0;">Twilio SMS</h3>
|
<h3 style="margin:0;">Twilio SMS</h3>
|
||||||
<p style="margin: 0.25rem 0 0; color: var(--admin-text-muted); font-size: 0.875rem;">
|
<p style="margin:.25rem 0 0;color:var(--admin-text-muted);font-size:.875rem;">SMS notifications for orders, shipping, and promotions</p>
|
||||||
Send SMS notifications for orders, shipping updates, and promotions
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<?php
|
<?php $twOk = !empty($tw['sid']) && !empty($tw['token']); $twOn = $tw['enabled'] === '1'; ?>
|
||||||
$twConfigured = !empty($settings['twilio_account_sid']) && !empty($settings['twilio_auth_token']);
|
<span class="status-badge <?= $twOk && $twOn ? 'enabled' : ($twOk ? 'configured' : 'not-configured') ?>">
|
||||||
$twEnabled = ($settings['sms_notifications_enabled'] ?? '0') === '1';
|
<?= $twOk && $twOn ? 'Enabled' : ($twOk ? 'Configured' : 'Not Configured') ?>
|
||||||
?>
|
|
||||||
<span class="status-badge <?= $twConfigured && $twEnabled ? 'enabled' : ($twConfigured ? 'configured' : 'not-configured') ?>">
|
|
||||||
<?= $twConfigured && $twEnabled ? 'Enabled' : ($twConfigured ? 'Configured' : 'Not Configured') ?>
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="integration-body">
|
<div class="integration-body">
|
||||||
<form method="POST">
|
<form method="POST">
|
||||||
<input type="hidden" name="section" value="twilio">
|
<input type="hidden" name="section" value="twilio">
|
||||||
|
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-label">Account SID</label>
|
<label class="form-label">Account SID</label>
|
||||||
<input type="text" name="twilio_account_sid" class="form-input key-input"
|
<input type="text" name="twilio_account_sid" class="form-input key-input" value="<?= htmlspecialchars($tw['sid']) ?>" placeholder="ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx">
|
||||||
value="<?= htmlspecialchars($settings['twilio_account_sid'] ?? '') ?>"
|
|
||||||
placeholder="ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx">
|
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-label">Auth Token</label>
|
<label class="form-label">Auth Token</label>
|
||||||
<input type="password" name="twilio_auth_token" class="form-input key-input"
|
<input type="password" name="twilio_auth_token" class="form-input key-input" value="<?= htmlspecialchars($tw['token']) ?>" placeholder="xxxxxxxx...">
|
||||||
value="<?= htmlspecialchars($settings['twilio_auth_token'] ?? '') ?>"
|
|
||||||
placeholder="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-label">Twilio Phone Number</label>
|
<label class="form-label">Twilio Phone Number</label>
|
||||||
<input type="text" name="twilio_phone_number" class="form-input"
|
<input type="text" name="twilio_phone_number" class="form-input" value="<?= htmlspecialchars($tw['phone']) ?>" placeholder="+1234567890">
|
||||||
value="<?= htmlspecialchars($settings['twilio_phone_number'] ?? '') ?>"
|
<p class="help-text">Get credentials at <a href="https://console.twilio.com/" target="_blank" class="help-link">Twilio Console</a></p>
|
||||||
placeholder="+1234567890">
|
|
||||||
<p class="help-text">
|
|
||||||
Get your credentials from
|
|
||||||
<a href="https://console.twilio.com/" target="_blank" class="help-link">Twilio Console</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-checkbox">
|
<label class="form-checkbox">
|
||||||
<input type="checkbox" name="sms_notifications_enabled" value="1"
|
<input type="checkbox" name="sms_notifications_enabled" value="1" <?= $twOn ? 'checked' : '' ?>>
|
||||||
<?= ($settings['sms_notifications_enabled'] ?? '0') === '1' ? 'checked' : '' ?>>
|
|
||||||
Enable SMS notifications
|
Enable SMS notifications
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div style="display:flex;gap:.5rem;">
|
||||||
<div style="display: flex; gap: 0.5rem;">
|
<button type="submit" class="btn btn-primary"><i class="fas fa-save"></i> Save Settings</button>
|
||||||
<button type="submit" class="btn btn-primary">
|
<button type="button" class="btn btn-secondary" onclick="testTwilio()"><i class="fas fa-sms"></i> Send Test SMS</button>
|
||||||
<i class="fas fa-save"></i> Save Settings
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn btn-secondary" onclick="testTwilio()">
|
|
||||||
<i class="fas fa-sms"></i> Send Test SMS
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@@ -269,57 +198,36 @@ foreach ($allSettings as $s) {
|
|||||||
<div class="integration-card">
|
<div class="integration-card">
|
||||||
<div class="integration-header">
|
<div class="integration-header">
|
||||||
<div class="integration-title">
|
<div class="integration-title">
|
||||||
<div class="integration-icon push">
|
<div class="integration-icon push"><i class="fas fa-bell"></i></div>
|
||||||
<i class="fas fa-bell"></i>
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
<h3 style="margin:0;">Push Notifications</h3>
|
<h3 style="margin:0;">Push Notifications</h3>
|
||||||
<p style="margin: 0.25rem 0 0; color: var(--admin-text-muted); font-size: 0.875rem;">
|
<p style="margin:.25rem 0 0;color:var(--admin-text-muted);font-size:.875rem;">Web push for order updates and promotions</p>
|
||||||
Web push notifications for order updates and promotions
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<?php
|
<?php $pushOk = !empty($push['pub']) && !empty($push['priv']); $pushOn = $push['enabled'] === '1'; ?>
|
||||||
$pushConfigured = !empty($settings['vapid_public_key']) && !empty($settings['vapid_private_key']);
|
<span class="status-badge <?= $pushOk && $pushOn ? 'enabled' : ($pushOk ? 'configured' : 'not-configured') ?>">
|
||||||
$pushEnabled = ($settings['push_notifications_enabled'] ?? '0') === '1';
|
<?= $pushOk && $pushOn ? 'Enabled' : ($pushOk ? 'Configured' : 'Not Configured') ?>
|
||||||
?>
|
|
||||||
<span class="status-badge <?= $pushConfigured && $pushEnabled ? 'enabled' : ($pushConfigured ? 'configured' : 'not-configured') ?>">
|
|
||||||
<?= $pushConfigured && $pushEnabled ? 'Enabled' : ($pushConfigured ? 'Configured' : 'Not Configured') ?>
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="integration-body">
|
<div class="integration-body">
|
||||||
<form method="POST">
|
<form method="POST">
|
||||||
<input type="hidden" name="section" value="push">
|
<input type="hidden" name="section" value="push">
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-label">VAPID Public Key</label>
|
<label class="form-label">VAPID Public Key</label>
|
||||||
<input type="text" name="vapid_public_key" class="form-input key-input"
|
<input type="text" name="vapid_public_key" class="form-input key-input" value="<?= htmlspecialchars($push['pub']) ?>" placeholder="BNxx...">
|
||||||
value="<?= htmlspecialchars($settings['vapid_public_key'] ?? '') ?>"
|
|
||||||
placeholder="BNxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx">
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-label">VAPID Private Key</label>
|
<label class="form-label">VAPID Private Key</label>
|
||||||
<input type="password" name="vapid_private_key" class="form-input key-input"
|
<input type="password" name="vapid_private_key" class="form-input key-input" value="<?= htmlspecialchars($push['priv']) ?>" placeholder="xx...">
|
||||||
value="<?= htmlspecialchars($settings['vapid_private_key'] ?? '') ?>"
|
<p class="help-text">Generate at <a href="https://web-push-codelab.glitch.me/" target="_blank" class="help-link">Web Push Codelab</a></p>
|
||||||
placeholder="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx">
|
|
||||||
<p class="help-text">
|
|
||||||
Generate VAPID keys at
|
|
||||||
<a href="https://web-push-codelab.glitch.me/" target="_blank" class="help-link">Web Push Codelab</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-checkbox">
|
<label class="form-checkbox">
|
||||||
<input type="checkbox" name="push_notifications_enabled" value="1"
|
<input type="checkbox" name="push_notifications_enabled" value="1" <?= $pushOn ? 'checked' : '' ?>>
|
||||||
<?= ($settings['push_notifications_enabled'] ?? '0') === '1' ? 'checked' : '' ?>>
|
|
||||||
Enable push notifications
|
Enable push notifications
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary"><i class="fas fa-save"></i> Save Settings</button>
|
||||||
<button type="submit" class="btn btn-primary">
|
|
||||||
<i class="fas fa-save"></i> Save Settings
|
|
||||||
</button>
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -328,79 +236,37 @@ foreach ($allSettings as $s) {
|
|||||||
<div class="integration-card">
|
<div class="integration-card">
|
||||||
<div class="integration-header">
|
<div class="integration-header">
|
||||||
<div class="integration-title">
|
<div class="integration-title">
|
||||||
<div class="integration-icon loyalty">
|
<div class="integration-icon loyalty"><i class="fas fa-crown"></i></div>
|
||||||
<i class="fas fa-crown"></i>
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
<h3 style="margin:0;">Loyalty Program</h3>
|
<h3 style="margin:0;">Loyalty Program</h3>
|
||||||
<p style="margin: 0.25rem 0 0; color: var(--admin-text-muted); font-size: 0.875rem;">
|
<p style="margin:.25rem 0 0;color:var(--admin-text-muted);font-size:.875rem;">Reward customers with points and tiers</p>
|
||||||
Reward customers with points and tiers (Bronze, Silver, Gold, Platinum)
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<?php $loyaltyEnabled = ($settings['loyalty_enabled'] ?? '1') === '1'; ?>
|
<span class="status-badge <?= $loyaltyEnabled ? 'enabled' : 'disabled' ?>"><?= $loyaltyEnabled ? 'Enabled' : 'Disabled' ?></span>
|
||||||
<span class="status-badge <?= $loyaltyEnabled ? 'enabled' : 'disabled' ?>">
|
|
||||||
<?= $loyaltyEnabled ? 'Enabled' : 'Disabled' ?>
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="integration-body">
|
<div class="integration-body">
|
||||||
<form method="POST">
|
<form method="POST">
|
||||||
<input type="hidden" name="section" value="loyalty">
|
<input type="hidden" name="section" value="loyalty">
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-checkbox">
|
<label class="form-checkbox">
|
||||||
<input type="checkbox" name="loyalty_enabled" value="1"
|
<input type="checkbox" name="loyalty_enabled" value="1" <?= $loyaltyEnabled ? 'checked' : '' ?>>
|
||||||
<?= $loyaltyEnabled ? 'checked' : '' ?>>
|
|
||||||
Enable loyalty program
|
Enable loyalty program
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="background:var(--admin-bg);padding:1.5rem;border-radius:var(--admin-radius);margin:1rem 0;">
|
<div style="background:var(--admin-bg);padding:1.5rem;border-radius:var(--admin-radius);margin:1rem 0;">
|
||||||
<h4 style="margin:0 0 1rem;">Tier Structure</h4>
|
<h4 style="margin:0 0 1rem;">Tier Structure</h4>
|
||||||
<table class="table" style="margin:0;">
|
<table class="table" style="margin:0;">
|
||||||
<thead>
|
<thead><tr><th>Tier</th><th>Min Points</th><th>Multiplier</th><th>Key Benefits</th></tr></thead>
|
||||||
<tr>
|
|
||||||
<th>Tier</th>
|
|
||||||
<th>Min Points</th>
|
|
||||||
<th>Multiplier</th>
|
|
||||||
<th>Key Benefits</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr><td><span style="color:#CD7F32;"><i class="fas fa-coffee"></i></span> Bronze Bean</td><td>0</td><td>1x</td><td>1 point/$1, Birthday reward</td></tr>
|
||||||
<td><span style="color: #CD7F32;"><i class="fas fa-coffee"></i></span> Bronze Bean</td>
|
<tr><td><span style="color:#C0C0C0;"><i class="fas fa-mug-hot"></i></span> Silver Roast</td><td>500</td><td>1.25x</td><td>Free shipping $25+, Double points weekends</td></tr>
|
||||||
<td>0</td>
|
<tr><td><span style="color:#FFD700;"><i class="fas fa-crown"></i></span> Gold Blend</td><td>1,500</td><td>1.5x</td><td>Free shipping all orders, Priority support</td></tr>
|
||||||
<td>1x</td>
|
<tr><td><span style="color:#E5E4E2;"><i class="fas fa-gem"></i></span> Platinum Reserve</td><td>5,000</td><td>2x</td><td>Express shipping, VIP events, Account manager</td></tr>
|
||||||
<td>1 point/$1, Birthday reward</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><span style="color: #C0C0C0;"><i class="fas fa-mug-hot"></i></span> Silver Roast</td>
|
|
||||||
<td>500</td>
|
|
||||||
<td>1.25x</td>
|
|
||||||
<td>Free shipping $25+, Double points weekends</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><span style="color: #FFD700;"><i class="fas fa-crown"></i></span> Gold Blend</td>
|
|
||||||
<td>1,500</td>
|
|
||||||
<td>1.5x</td>
|
|
||||||
<td>Free shipping all orders, Priority support</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><span style="color: #E5E4E2;"><i class="fas fa-gem"></i></span> Platinum Reserve</td>
|
|
||||||
<td>5,000</td>
|
|
||||||
<td>2x</td>
|
|
||||||
<td>Express shipping, VIP events, Account manager</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<p class="text-muted" style="margin: 1rem 0 0; font-size: 0.875rem;">
|
<p class="text-muted" style="margin:1rem 0 0;font-size:.875rem;">100 points = $1 credit • Points earned on every purchase</p>
|
||||||
100 points = $1 credit • Points earned on every purchase
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary"><i class="fas fa-save"></i> Save Settings</button>
|
||||||
<button type="submit" class="btn btn-primary">
|
|
||||||
<i class="fas fa-save"></i> Save Settings
|
|
||||||
</button>
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -422,9 +288,7 @@ foreach ($allSettings as $s) {
|
|||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-secondary" onclick="Modal.close('testModal')">Cancel</button>
|
<button type="button" class="btn btn-secondary" onclick="Modal.close('testModal')">Cancel</button>
|
||||||
<button type="submit" class="btn btn-primary" id="testSubmitBtn">
|
<button type="submit" class="btn btn-primary" id="testSubmitBtn"><i class="fas fa-paper-plane"></i> Send</button>
|
||||||
<i class="fas fa-paper-plane"></i> Send
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@@ -432,7 +296,6 @@ foreach ($allSettings as $s) {
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
let testType = '';
|
let testType = '';
|
||||||
|
|
||||||
function testCyberMail() {
|
function testCyberMail() {
|
||||||
testType = 'email';
|
testType = 'email';
|
||||||
document.getElementById('testModalTitle').textContent = 'Send Test Email';
|
document.getElementById('testModalTitle').textContent = 'Send Test Email';
|
||||||
@@ -442,7 +305,6 @@ function testCyberMail() {
|
|||||||
document.getElementById('testResult').style.display = 'none';
|
document.getElementById('testResult').style.display = 'none';
|
||||||
Modal.open('testModal');
|
Modal.open('testModal');
|
||||||
}
|
}
|
||||||
|
|
||||||
function testTwilio() {
|
function testTwilio() {
|
||||||
testType = 'sms';
|
testType = 'sms';
|
||||||
document.getElementById('testModalTitle').textContent = 'Send Test SMS';
|
document.getElementById('testModalTitle').textContent = 'Send Test SMS';
|
||||||
@@ -452,17 +314,13 @@ function testTwilio() {
|
|||||||
document.getElementById('testResult').style.display = 'none';
|
document.getElementById('testResult').style.display = 'none';
|
||||||
Modal.open('testModal');
|
Modal.open('testModal');
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('testForm').addEventListener('submit', async function(e) {
|
document.getElementById('testForm').addEventListener('submit', async function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
const recipient = document.getElementById('testRecipient').value;
|
const recipient = document.getElementById('testRecipient').value;
|
||||||
const resultDiv = document.getElementById('testResult');
|
const resultDiv = document.getElementById('testResult');
|
||||||
const submitBtn = document.getElementById('testSubmitBtn');
|
const submitBtn = document.getElementById('testSubmitBtn');
|
||||||
|
|
||||||
submitBtn.disabled = true;
|
submitBtn.disabled = true;
|
||||||
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Sending...';
|
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Sending...';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch('/api/test-notification.php', {
|
const response = await fetch('/api/test-notification.php', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -470,19 +328,18 @@ document.getElementById('testForm').addEventListener('submit', async function(e)
|
|||||||
body: JSON.stringify({type: testType, recipient})
|
body: JSON.stringify({type: testType, recipient})
|
||||||
});
|
});
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|
||||||
resultDiv.style.display = 'block';
|
resultDiv.style.display = 'block';
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
resultDiv.style.background = 'rgba(16, 185, 129, 0.1)';
|
resultDiv.style.background = 'rgba(16,185,129,.1)';
|
||||||
resultDiv.innerHTML = '<i class="fas fa-check-circle" style="color: var(--admin-success);"></i> ' + (data.message || 'Test sent successfully!');
|
resultDiv.innerHTML = '<i class="fas fa-check-circle" style="color:var(--admin-success);"></i> ' + (data.message || 'Sent successfully!');
|
||||||
} else {
|
} else {
|
||||||
resultDiv.style.background = 'rgba(239, 68, 68, 0.1)';
|
resultDiv.style.background = 'rgba(239,68,68,.1)';
|
||||||
resultDiv.innerHTML = '<i class="fas fa-times-circle" style="color: var(--admin-error);"></i> ' + (data.error || 'Failed to send test');
|
resultDiv.innerHTML = '<i class="fas fa-times-circle" style="color:var(--admin-error);"></i> ' + (data.error || 'Failed to send');
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
resultDiv.style.display = 'block';
|
resultDiv.style.display = 'block';
|
||||||
resultDiv.style.background = 'rgba(239, 68, 68, 0.1)';
|
resultDiv.style.background = 'rgba(239,68,68,.1)';
|
||||||
resultDiv.innerHTML = '<i class="fas fa-times-circle" style="color: var(--admin-error);"></i> Error: ' + err.message;
|
resultDiv.innerHTML = '<i class="fas fa-times-circle" style="color:var(--admin-error);"></i> ' + err.message;
|
||||||
} finally {
|
} finally {
|
||||||
submitBtn.disabled = false;
|
submitBtn.disabled = false;
|
||||||
submitBtn.innerHTML = '<i class="fas fa-paper-plane"></i> Send';
|
submitBtn.innerHTML = '<i class="fas fa-paper-plane"></i> Send';
|
||||||
|
|||||||
Reference in New Issue
Block a user