Nothing to see here

Go Back"; require_once "../includes/footer.php"; exit(); } $contact_row = mysqli_fetch_assoc($sql); // raw, for the helpers - $row gets reused below $row = $contact_row; $client_id = intval($row['client_id']); $client_name = escapeHtml($row['client_name']); $contact_name = escapeHtml($row['contact_name']); $contact_title = escapeHtml($row['contact_title']); $contact_department = escapeHtml($row['contact_department']); $contact_email = escapeHtml($row['contact_email']); $contact_pin = escapeHtml($row['contact_pin']); $contact_notes = escapeHtml($row['contact_notes']); $contact_primary = intval($row['contact_primary']); $contact_archived_at = $row['contact_archived_at']; $contact_created_at = escapeHtml($row['contact_created_at']); $contact_phone_link = contactPhoneLink($row['contact_phone'], $row['contact_phone_country_code'], $row['contact_extension']); $contact_mobile_link = contactPhoneLink($row['contact_mobile'], $row['contact_mobile_country_code']); $contact_phone_copy = escapeHtml(formatPhoneNumber($row['contact_phone'], $row['contact_phone_country_code'])); $contact_mobile_copy = escapeHtml(formatPhoneNumber($row['contact_mobile'], $row['contact_mobile_country_code'])); $contact_dial = $row['contact_phone'] ? 'phone' : ($row['contact_mobile'] ? 'mobile' : ''); $contact_portal = contactPortalAccess($row['contact_user_id'], $row['user_auth_method']); $contact_portal_mfa = $contact_portal === 'Password' && trim((string) $row['user_token']) !== ''; $contact_portal_last = $contact_portal ? portalContactLastSignIn($row['contact_user_id']) : null; // How they joined, when it was by an invite or signing up (functions/portal_invite.php) $contact_portal_joined = $contact_portal ? portalContactJoined($contact_id) : null; // View as contact - read access to clients and support is checked again when it starts (functions/portal.php) $can_view_as = $config_client_portal_enable && !$row['contact_archived_at'] && lookupUserPermission('module_support') >= 1; $contact_role_line = implode(' · ', array_filter([$contact_title, $contact_department])); $can_edit = lookupUserPermission('module_client') >= 2; $can_delete = lookupUserPermission('module_client') >= 3; $can_credentials = lookupUserPermission('module_credential') >= 1; $can_credentials_edit = lookupUserPermission('module_credential') >= 2; $can_support = lookupUserPermission('module_support') >= 1; $can_support_edit = lookupUserPermission('module_support') >= 2; // Override Tab Title // No Sanitizing needed as this var will only be used in the tab title $page_title = $row['contact_name']; // Tags - functions/tags.php $contact_tags_display = tagPills('contact', $contact_id, tagsForRecord('contact', $contact_id), "contacts.php?client_id=$client_id&"); // Assets assigned to them $sql_related_assets = mysqli_query($mysqli, "SELECT asset_id, asset_name, asset_description, asset_type, asset_make, asset_model, asset_serial, asset_status, asset_favorite, interface_ip FROM assets LEFT JOIN asset_interfaces ON interface_asset_id = asset_id AND interface_primary = 1 WHERE asset_contact_id = $contact_id AND asset_archived_at IS NULL ORDER BY asset_name ASC" ); $asset_count = mysqli_num_rows($sql_related_assets); // Credentials - only for agents who may see them $related_credentials = $can_credentials ? credentialRows("credential_contact_id = $contact_id AND credential_client_id = $client_id") : []; $credential_count = count($related_credentials); // Tickets they raised or are the contact on - open ones first $related_tickets = []; $ticket_open_count = 0; if ($can_support) { $related_tickets = ticketRows("tickets.ticket_contact_id = $contact_id"); $ticket_open_count = count(array_filter(array_column($related_tickets, 'is_open'))); } $ticket_count = count($related_tickets); // Recurring tickets $recurring_ticket_count = 0; if ($can_support) { $sql_related_recurring_tickets = mysqli_query($mysqli, "SELECT recurring_ticket_id, recurring_ticket_subject, recurring_ticket_priority, recurring_ticket_frequency, recurring_ticket_next_run, recurring_ticket_paused_at FROM recurring_tickets WHERE recurring_ticket_contact_id = $contact_id ORDER BY recurring_ticket_next_run ASC" ); $recurring_ticket_count = mysqli_num_rows($sql_related_recurring_tickets); } // Licenses they hold a seat on, with each one's seats in use and the key they were given $held_software = $can_support ? softwareHeldBy('contact', $contact_id) : []; $software_count = count($held_software); // Documents $sql_linked_documents = mysqli_query($mysqli, "SELECT documents.document_id, document_name, document_description, document_created_at, document_updated_at, user_name FROM contact_documents JOIN documents ON documents.document_id = contact_documents.document_id LEFT JOIN users ON document_created_by = user_id WHERE contact_documents.contact_id = $contact_id AND document_archived_at IS NULL ORDER BY document_name ASC" ); $document_count = mysqli_num_rows($sql_linked_documents); // Files $sql_linked_files = mysqli_query($mysqli, "SELECT files.file_id, file_name, file_description, file_ext, file_size, file_created_at FROM contact_files JOIN files ON files.file_id = contact_files.file_id WHERE contact_files.contact_id = $contact_id AND file_archived_at IS NULL ORDER BY file_name ASC" ); $file_count = mysqli_num_rows($sql_linked_files); // Services // The services they are a contact for - most important first $linked_services = servicesFor('contact', $contact_id); $service_count = count($linked_services); // Notes $sql_related_notes = mysqli_query($mysqli, "SELECT contact_note, contact_note_created_at, contact_note_id, contact_note_type, user_name FROM contact_notes LEFT JOIN users ON contact_note_created_by = user_id WHERE contact_note_contact_id = $contact_id AND contact_note_archived_at IS NULL ORDER BY contact_note_created_at DESC" ); $note_count = mysqli_num_rows($sql_related_notes); // Note type icons, read from the categories list so the seeded icons stay the single source of truth $note_type_icons = []; $sql_note_type_icons = mysqli_query($mysqli, "SELECT category_name, category_icon FROM categories WHERE category_type = 'contact_note_type'"); while ($row = mysqli_fetch_assoc($sql_note_type_icons)) { $note_type_icons[escapeHtml($row['category_name'])] = escapeHtml($row['category_icon']); } // The tabs, in the order a tech reaches for them // Its history, from the audit log $history = auditLogHistory('Contact', $contact_id); $contact_tabs = [ 'assets' => ['label' => 'Assets', 'icon' => 'fa-desktop', 'count' => $asset_count], 'credentials' => ['label' => 'Credentials', 'icon' => 'fa-key', 'count' => $credential_count], 'tickets' => ['label' => 'Tickets', 'icon' => 'fa-life-ring', 'count' => $ticket_count, 'badge' => $ticket_open_count], 'recurring' => ['label' => 'Recurring', 'icon' => 'fa-redo-alt', 'count' => $recurring_ticket_count], 'licenses' => ['label' => 'Licenses', 'icon' => 'fa-cube', 'count' => $software_count], 'documents' => ['label' => 'Documents', 'icon' => 'fa-file-alt', 'count' => $document_count], 'files' => ['label' => 'Files', 'icon' => 'fa-paperclip', 'count' => $file_count], 'services' => ['label' => 'Services', 'icon' => 'fa-stream', 'count' => $service_count], 'notes' => ['label' => 'Notes', 'icon' => 'fa-sticky-note', 'count' => $note_count], 'history' => ['label' => 'History', 'icon' => 'fa-history', 'count' => $history['count']], ]; if (!$can_credentials) { unset($contact_tabs['credentials']); } if (!$can_support) { // Assets and documentation are Support's too unset($contact_tabs['assets'], $contact_tabs['tickets'], $contact_tabs['recurring'], $contact_tabs['licenses'], $contact_tabs['documents'], $contact_tabs['files'], $contact_tabs['services']); } ?>
" target="_blank" rel="noopener" title="Open photo">

Archived

Reach

Phone
Mobile
Email
No phone or email recorded.

Details

Location
PIN
to verify them on a call
Portal
$contact_portal" . ($contact_portal_mfa ? ' and a code' : '') . "" : 'No access' ?>
' . timeAgo($contact_portal_last) . '' : 'Has not signed in yet' ?>
on
Ticket emails
And about the company's tickets:
Texts
Replied STOP
Nothing is texted to them until they text START to your number.
About their tickets, visits and invoices
Agreed
No mobile number Not asked yet
Asked by text - a YES turns them on
Added

Quick notes