Files
2026-05-16 23:00:37 -05:00

182 lines
6.0 KiB
PHP

<?php
/**
* Tom's Java Jive - Push Notification Service
*
* Handles web push notifications using VAPID
*/
class PushNotification {
private string $publicKey;
private string $privateKey;
private string $subject;
public function __construct() {
// VAPID keys - generate your own at: https://web-push-codelab.glitch.me/
$this->publicKey = getSetting('vapid_public_key', 'YOUR_VAPID_PUBLIC_KEY');
$this->privateKey = getSetting('vapid_private_key', 'YOUR_VAPID_PRIVATE_KEY');
$this->subject = 'mailto:' . getSetting('admin_email', 'admin@tomsjavajive.com');
}
/**
* Get VAPID public key for client
*/
public function getPublicKey(): string {
return $this->publicKey;
}
/**
* Send push notification to a subscription
*/
public function send(array $subscription, string $title, string $body, array $options = []): array {
$payload = json_encode([
'title' => $title,
'body' => $body,
'icon' => $options['icon'] ?? '/assets/icons/icon-192.png',
'badge' => $options['badge'] ?? '/assets/icons/badge-72.png',
'url' => $options['url'] ?? '/',
'tag' => $options['tag'] ?? null,
'data' => $options['data'] ?? []
]);
// For now, we'll store notifications for when the user comes online
// Full web push requires a library like minishlink/web-push
// This is a simplified version that works with the service worker
try {
// Store notification for retrieval
$notificationId = generateId('notif_');
db()->insert('push_notifications', [
'notification_id' => $notificationId,
'subscription_endpoint' => $subscription['endpoint'],
'payload' => $payload,
'status' => 'pending',
'created_at' => date('Y-m-d H:i:s')
]);
return ['success' => true, 'notification_id' => $notificationId];
} catch (Exception $e) {
return ['success' => false, 'error' => $e->getMessage()];
}
}
/**
* Send notification to all subscribed users
*/
public function broadcast(string $title, string $body, array $options = []): array {
$subscriptions = db()->fetchAll("SELECT * FROM push_subscriptions WHERE is_active = 1");
$results = ['sent' => 0, 'failed' => 0];
foreach ($subscriptions as $sub) {
$subscription = [
'endpoint' => $sub['endpoint'],
'keys' => [
'p256dh' => $sub['p256dh_key'],
'auth' => $sub['auth_key']
]
];
$result = $this->send($subscription, $title, $body, $options);
if ($result['success']) {
$results['sent']++;
} else {
$results['failed']++;
}
}
return $results;
}
/**
* Send order status update notification
*/
public function sendOrderUpdate(string $customerId, array $order, string $status): array {
$subscription = $this->getCustomerSubscription($customerId);
if (!$subscription) {
return ['success' => false, 'error' => 'No subscription found'];
}
$messages = [
'confirmed' => "Your order #{$order['order_number']} has been confirmed!",
'processing' => "We're preparing your order #{$order['order_number']}",
'shipped' => "Your order #{$order['order_number']} is on its way!",
'delivered' => "Your order #{$order['order_number']} has been delivered!",
'ready' => "Your order #{$order['order_number']} is ready for pickup!"
];
return $this->send(
$subscription,
"Order Update",
$messages[$status] ?? "Order #{$order['order_number']} status: {$status}",
[
'url' => "/account/order.php?id={$order['order_id']}",
'tag' => "order-{$order['order_id']}"
]
);
}
/**
* Send promotional notification
*/
public function sendPromotion(string $customerId, string $title, string $message, string $url = '/shop.php'): array {
$subscription = $this->getCustomerSubscription($customerId);
if (!$subscription) {
return ['success' => false, 'error' => 'No subscription found'];
}
return $this->send($subscription, $title, $message, ['url' => $url]);
}
/**
* Send loyalty tier notification
*/
public function sendTierNotification(string $customerId, string $tierName, array $benefits): array {
$subscription = $this->getCustomerSubscription($customerId);
if (!$subscription) {
return ['success' => false, 'error' => 'No subscription found'];
}
return $this->send(
$subscription,
"Congratulations! You're now {$tierName}!",
"Enjoy new benefits: " . implode(', ', array_slice($benefits, 0, 2)),
['url' => '/account/']
);
}
/**
* Get customer's push subscription
*/
private function getCustomerSubscription(string $customerId): ?array {
$sub = db()->fetch(
"SELECT * FROM push_subscriptions WHERE customer_id = :id AND is_active = 1 ORDER BY created_at DESC LIMIT 1",
['id' => $customerId]
);
if (!$sub) {
return null;
}
return [
'endpoint' => $sub['endpoint'],
'keys' => [
'p256dh' => $sub['p256dh_key'],
'auth' => $sub['auth_key']
]
];
}
}
// Helper function for easy access
function pushNotify(): PushNotification {
static $instance = null;
if ($instance === null) {
$instance = new PushNotification();
}
return $instance;
}