'ticket.php?id=' . intval($row['ticket_id']), 'icon' => $resolved ? 'fa-check' : 'fa-reply', 'tone' => $resolved ? 'is-info' : '', 'title' => $row['ticket_subject'], 'line' => ($resolved ? 'Resolved - is it fixed? Close it, or reopen it' : 'We replied - waiting on you') . ' · ' . $row['ticket_prefix'] . $row['ticket_number'], ]; } // Tasks on their tickets waiting for the client's approval $sql = mysqli_query($mysqli, "SELECT tickets.ticket_id, ticket_prefix, ticket_number, task_name FROM task_approvals JOIN tasks ON task_id = approval_task_id JOIN tickets ON tickets.ticket_id = task_ticket_id LEFT JOIN ticket_statuses ON ticket_status = ticket_status_id WHERE $scope_sql AND approval_scope = 'client' AND approval_status = 'pending' AND task_completed_at IS NULL AND tickets.ticket_closed_at IS NULL ORDER BY approval_id DESC LIMIT 4"); while ($row = mysqli_fetch_assoc($sql)) { $needs_you[] = [ 'href' => 'ticket.php?id=' . intval($row['ticket_id']), 'icon' => 'fa-clipboard-check', 'tone' => '', 'title' => 'Approve: ' . $row['task_name'], 'line' => 'Waiting for your approval · ' . $row['ticket_prefix'] . $row['ticket_number'], ]; } // Money - what is owed, and what is past due $balance = 0.0; $overdue = 0.0; $overdue_count = 0; $next_due = null; $client_currency = $session_company_currency; if ($can_billing) { $client_currency = mysqli_fetch_row(mysqli_query($mysqli, "SELECT client_currency_code FROM clients WHERE client_id = $session_client_id"))[0] ?: $session_company_currency; foreach (billingClientOpenInvoices($session_client_id) as $invoice) { $left = round(floatval($invoice['invoice_amount']) - floatval($invoice['paid']), 2); $balance += $left; if ($invoice['invoice_due'] < date('Y-m-d')) { $overdue += $left; $overdue_count++; $needs_you[] = [ 'href' => 'invoice.php?id=' . intval($invoice['invoice_id']), 'icon' => 'fa-file-invoice-dollar', 'tone' => 'is-danger', 'title' => 'Invoice ' . $invoice['invoice_prefix'] . $invoice['invoice_number'] . ' is past due', 'line' => numfmt_format_currency($currency_format, $left, $client_currency) . ' left - due ' . date('M j, Y', strtotime($invoice['invoice_due'])), ]; } elseif ($next_due === null || $invoice['invoice_due'] < $next_due) { $next_due = $invoice['invoice_due']; } } // Quotes waiting for their answer $sql = mysqli_query($mysqli, "SELECT quote_id, quote_prefix, quote_number, quote_scope, quote_amount, quote_currency_code, quote_expire FROM quotes WHERE quote_client_id = $session_client_id AND " . portalQuoteWaitingSql() . " ORDER BY quote_expire ASC LIMIT 4"); while ($row = mysqli_fetch_assoc($sql)) { $needs_you[] = [ 'href' => 'quote.php?id=' . intval($row['quote_id']), 'icon' => 'fa-comment-dollar', 'tone' => '', 'title' => 'Quote ' . $row['quote_prefix'] . $row['quote_number'] . ' is waiting for your answer', 'line' => trim($row['quote_scope'] . ' · ' . billingMoney($row['quote_amount'], $row['quote_currency_code']), ' ·') . ' · good until ' . date('M j', strtotime($row['quote_expire'])), ]; } } $pay_href = $can_billing && billingStripeProvider() ? 'unpaid_invoices.php' : 'invoices.php'; // Open tickets, newest first $recent = mysqli_query($mysqli, "SELECT " . portalTicketColumnsSql() . ", contact_name FROM tickets LEFT JOIN ticket_statuses ON ticket_status = ticket_status_id LEFT JOIN contacts ON contact_id = tickets.ticket_contact_id WHERE $scope_sql AND tickets.ticket_archived_at IS NULL AND {$tabs['open']['where']} ORDER BY COALESCE(tickets.ticket_updated_at, tickets.ticket_created_at) DESC LIMIT 5"); // Renewals coming up in the next 45 days, and anything that lapsed in the last 30 $renewals = []; if ($can_it) { $window = "BETWEEN CURDATE() - INTERVAL 30 DAY AND CURDATE() + INTERVAL 45 DAY"; $sources = [ ['domains.php', 'fa-globe', 'Domain', "SELECT domain_name, domain_expire, 0 FROM domains WHERE domain_client_id = $session_client_id AND domain_archived_at IS NULL AND domain_expire $window"], ['domains.php?tab=certificates', 'fa-lock', 'Certificate', "SELECT certificate_name, certificate_expire, 0 FROM certificates WHERE certificate_client_id = $session_client_id AND certificate_archived_at IS NULL AND certificate_expire $window"], ['licenses.php', 'fa-cube', 'License', "SELECT software_name, software_expire, 0 FROM software WHERE software_client_id = $session_client_id AND software_archived_at IS NULL AND software_expire $window"], ['asset.php?id=', 'fa-shield-alt', 'Warranty', "SELECT asset_name, asset_warranty_expire, asset_id FROM assets WHERE asset_client_id = $session_client_id AND asset_archived_at IS NULL AND asset_warranty_expire $window"], ]; foreach ($sources as [$href, $icon, $kind, $query]) { $sql = mysqli_query($mysqli, $query); while ($row = mysqli_fetch_row($sql)) { $renewals[] = ['href' => $href . (intval($row[2]) ? intval($row[2]) : ''), 'icon' => $icon, 'kind' => $kind, 'name' => $row[0], 'date' => $row[1]]; } } usort($renewals, function ($a, $b) { return strcmp($a['date'], $b['date']); }); } // The devices this contact uses $devices = []; $sql = mysqli_query($mysqli, "SELECT asset_id, asset_name, asset_type, asset_make, asset_model, asset_warranty_expire, asset_uri_client FROM assets WHERE asset_contact_id = $session_contact_id AND asset_client_id = $session_client_id AND asset_archived_at IS NULL ORDER BY asset_name ASC LIMIT 6"); while ($row = mysqli_fetch_assoc($sql)) { $devices[] = $row; } // The request forms they can use - ticket templates offered in the portal $request_forms = ticketTemplatePortalForms($session_client_id, $sees_all); // How to reach us $company = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT company_phone, company_phone_country_code, company_email, company_website FROM companies WHERE company_id = 1")); $hour = intval(date('G')); $greeting = $hour < 12 ? 'Good morning' : ($hour < 18 ? 'Good afternoon' : 'Good evening'); $first_name = strtok(trim((string) $contact['contact_name']), ' ') ?: ''; ?>

0) { ?>

·
Waiting on you
0) { ?> past due 0 && $next_due) { ?> Due Nothing owed
coming up

Needs you

"You're all caught up", 'text' => 'Nothing is waiting on you right now.', 'icon' => 'fa-check', 'filtered' => false]) ?>
'No open tickets', 'text' => 'Something not working? Raise a ticket and we will pick it up.', 'icon' => 'fa-life-ring', 'filtered' => false, 'actions' => [['label' => 'New ticket', 'href' => 'ticket_add.php']]]) ?>

Ask for something

5) { ?>All

Your devices

All devices

Coming up

'Nothing renewing soon', 'text' => 'Domains, certificates, licenses and warranties due in the next 45 days show here.', 'icon' => 'fa-check', 'filtered' => false]) ?>

Need us fast?

For anything urgent, call us - and raise a ticket so it is on record.