mirror of
https://github.com/myronblair/tomsjavajive
synced 2026-06-30 17:50:32 -05:00
182 lines
6.0 KiB
PHP
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;
|
|
}
|