// ════════════════════════════════════════════════════════════════════
require_once __DIR__ . '/../inc/config.php';
$_alerts_path = __DIR__ . '/../inc/agent_alerts.php';
if (file_exists($_alerts_path)) require_once $_alerts_path;
if (!is_logged_in()) {
header('Location: ' . $url . 'login.php?redirect=agent_alerts.php'); exit;
}
$uid = current_uid();
$username = h($_SESSION['username'] ?? '');
$user = db_query("SELECT * FROM users WHERE id=? LIMIT 1", 'i', $uid);
$user = $user ? $user[0] : [];
$user_phone = $user['phone'] ?? '';
// ── Self-heal: ensure alert tables exist ────────────────────────────
if ($conn) {
try {
$conn->query("CREATE TABLE IF NOT EXISTS `agent_alert_prefs` (
`user_id` INT NOT NULL PRIMARY KEY,
`sms_enabled` TINYINT(1) DEFAULT 0,
`alert_phone` VARCHAR(30) DEFAULT NULL,
`service_locations` TEXT NULL,
`alert_types` VARCHAR(60) DEFAULT 'all',
`min_fee` DECIMAL(10,2) DEFAULT '0.00',
`quiet_hours` VARCHAR(20) DEFAULT NULL,
`verified` TINYINT(1) DEFAULT 0,
`verified_at` DATETIME NULL,
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX `idx_alert_enabled` (`sms_enabled`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
$conn->query("CREATE TABLE IF NOT EXISTS `sms_alert_queue` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`user_id` INT NOT NULL,
`phone` VARCHAR(30) NOT NULL,
`message` TEXT NOT NULL,
`opp_type` VARCHAR(20) DEFAULT NULL,
`opp_id` INT DEFAULT NULL,
`status` TINYINT DEFAULT 0,
`provider_id` VARCHAR(100) DEFAULT NULL,
`error` TEXT NULL,
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
`sent_at` DATETIME NULL,
INDEX `idx_sms_status` (`status`),
INDEX `idx_sms_user` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
} catch (\Throwable $e) {}
}
// ── POST: save preferences ─────────────────────────────────────────
$msg = ''; $err = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['save_alert_prefs']) && csrf_verify()) {
$sms_on = !empty($_POST['alert_sms_enabled']) ? 1 : 0;
$phone_in = trim((string)($_POST['alert_phone'] ?? ''));
$phone_clean = preg_replace('/[^\d+]/', '', $phone_in);
$locs = trim((string)($_POST['service_locations'] ?? ''));
if (strlen($locs) > 4000) $locs = substr($locs, 0, 4000);
$type_in = $_POST['alert_types'] ?? [];
if (is_string($type_in)) $type_in = [$type_in];
$type_in = array_filter($type_in, function($t){return in_array($t, ['return','usher','scout'], true);});
$alert_types = empty($type_in) || count($type_in) === 3 ? 'all' : implode(',', $type_in);
$min_fee = (float)preg_replace('/[^\d.]/', '', (string)($_POST['alert_min_fee'] ?? '0'));
if ($sms_on && $phone_clean === '') {
$err = 'A phone number is required to receive SMS alerts.';
} else {
try {
$ep = $conn->real_escape_string($phone_clean);
$el = $conn->real_escape_string($locs);
$et = $conn->real_escape_string($alert_types);
$conn->query("INSERT INTO agent_alert_prefs (user_id, sms_enabled, alert_phone, service_locations, alert_types, min_fee)
VALUES ($uid, $sms_on, '$ep', '$el', '$et', $min_fee)
ON DUPLICATE KEY UPDATE sms_enabled=$sms_on, alert_phone='$ep', service_locations='$el', alert_types='$et', min_fee=$min_fee");
$msg = $sms_on ? "SMS alerts enabled. You'll be texted when matching opportunities are posted." : 'Alert preferences saved.';
} catch (\Throwable $e) {
$err = 'Could not save: ' . $e->getMessage();
}
}
}
// ── Load current prefs ─────────────────────────────────────────────
$prefs = ['sms_enabled'=>0,'alert_phone'=>'','service_locations'=>'','alert_types'=>'all','min_fee'=>0,'verified'=>0];
try {
$r = $conn->query("SELECT * FROM agent_alert_prefs WHERE user_id=$uid LIMIT 1");
if ($r && $r->num_rows > 0) {
$row = $r->fetch_assoc();
$prefs = [
'sms_enabled' => (int)$row['sms_enabled'],
'alert_phone' => (string)($row['alert_phone'] ?? ''),
'service_locations' => (string)($row['service_locations'] ?? ''),
'alert_types' => (string)($row['alert_types'] ?? 'all'),
'min_fee' => (float)($row['min_fee'] ?? 0),
'verified' => (int)($row['verified'] ?? 0),
];
} else {
$prefs['alert_phone'] = $user_phone;
}
} catch (\Throwable $e) {}
// ── Recent alert log for this agent ────────────────────────────────
$recent_alerts = [];
try {
$r = $conn->query("SELECT id, phone, message, opp_type, opp_id, status, provider_id, error, created_at, sent_at
FROM sms_alert_queue
WHERE user_id = $uid
ORDER BY created_at DESC
LIMIT 25");
if ($r) while ($row = $r->fetch_assoc()) $recent_alerts[] = $row;
} catch (\Throwable $e) {}
$sel_types = $prefs['alert_types'] === 'all' ? ['return','usher','scout'] : explode(',', $prefs['alert_types']);
$status_disp = [0 => ['Queued','#b8860b'], 1 => ['Sent','#1a7f37'], 2 => ['Failed','#e53935']];
$type_icon = ['return'=>'📦','usher'=>'🚗','scout'=>'🔍'];
?>
Opportunity Alerts | B* DYNA
Business Services
Enterprise Systems
Industries
Consumer Programs
Consumer Apps
Pharmacy
Design
Engineering
Software & Data
Security
BDYNA Overview
Work With BDYNA
Agent Settings
Opportunity Alerts
Get a text the moment a return, vehicle usher, or drive scout job posts in your service area. Configure your phone, locations, and filters below.