{{ theme.skipToContentLabel || 'Skip to content' }}

Asset Management: Add Last Contact Time and Created Columns

Date: 2026-01-15 Author: AI Assistant Status: Completed

Overview

Added two new columns to the Asset Management table to display:

  • Last Contact - Shows the last contact time from last_contact_time_utc field
  • Created - Shows the creation timestamp from created_at field

Changes Made

1. Updated SortField Type

File: src/features/assets/services/assetsService.ts

Added last_contact_time_utc to the SortField type to enable sorting by last contact time.

typescript
export type SortField =
  | "display_id"
  | "asset_id"
  | "serial_number"
  | "asset_type_code"
  | "telematics_provider_code"
  | "mine_site"
  | "operational_status_code"
  | "archived"
  | "created_at"
  | "last_contact_time_utc"  // Added
  | "client_name"
  | "fleet_name";

2. Updated Asset Management Page

File: src/app/(admin)/(pages)/asset-management/index.tsx

Added Date Formatting Function

typescript
const formatDateTime = (value?: string | null) => {
  if (!value) return "-";
  const date = new Date(value);
  if (Number.isNaN(date.getTime())) return "-";
  return date.toLocaleString("en-AU", {
    dateStyle: "short",
    timeStyle: "short",
  });
};

Updated Table Headers

Added two new sortable headers:

  • "Last Contact" (11% width) - sorts by last_contact_time_utc
  • "Created" (10% width) - sorts by created_at

Adjusted existing column widths to accommodate the new columns:

  • Display ID: 18% → 14%
  • Asset ID: 20% → 16% → 13% (further reduced for better spacing)
  • Serial: 10% → 8% → 12% (increased for better visibility)
  • Type: 12% → 9%
  • Provider: 10% → 8%
  • Mine Site: 14% → 10%
  • Status: 8% → 7%
  • Actions: 8% → 7% → 6% (reduced for better spacing)

Updated Table Body

Added two new data cells in each table row:

tsx
<td className="px-4 py-3 text-xs text-slate-600 dark:text-slate-400">
  {formatDateTime(asset.last_contact_time_utc)}
</td>
<td className="px-4 py-3 text-xs text-slate-600 dark:text-slate-400">
  {formatDateTime(asset.created_at)}
</td>

Updated Empty State

Changed the empty state colspan from 8 to 10 to match the new column count.

Features

  1. Sortable Columns: Both new columns support ascending/descending sorting
  2. Date Formatting: Dates are displayed in Australian format (en-AU) with short date and time
  3. Null Handling: Shows "-" when date values are null or invalid
  4. Responsive Design: Column widths adjusted to maintain table layout
  5. Dark Mode Support: Text colors adapt to light/dark themes

Testing

To test the changes:

  1. Navigate to Asset Management page (/asset-management)
  2. Verify the two new columns appear in the table
  3. Click on column headers to test sorting functionality
  4. Check that dates display correctly in format: "dd/MM/yy, h:mm am/pm"
  5. Verify empty/null values show as "-"

Data Source

  • Last Contact Time: data_assets.last_contact_time_utc - UTC timestamp from SingleSourceIOT API
  • Created: data_assets.created_at - Database creation timestamp (auto-managed)

Additional Enhancement: Serial Number Styling

Updated Serial Column Display

Changed the Serial Number column to match the Asset ID column styling:

Before:

  • Plain text display
  • No truncation for long serial numbers
  • No copy functionality

After:

  • Styled code block with background (bg-slate-100 dark:bg-slate-700)
  • Truncated display with truncate class for long values
  • Hover tooltip shows full serial number via title attribute
  • Copy button appears on row hover (same as Asset ID)
  • Monospace font for better readability

Implementation:

tsx
{asset.serial_number ? (
  <div className="flex items-center gap-1.5 group">
    <code
      className="text-xs bg-slate-100 dark:bg-slate-700 px-2 py-1 rounded font-mono text-slate-600 dark:text-slate-400 truncate block"
      title={asset.serial_number}
    >
      {asset.serial_number}
    </code>
    <button
      className="p-1 text-slate-400 hover:text-blue-600 dark:hover:text-blue-400 opacity-0 group-hover:opacity-100 transition-opacity flex-shrink-0"
      title="Copy Serial Number"
      onClick={(e) => {
        e.stopPropagation();
        void navigator.clipboard.writeText(asset.serial_number || "");
      }}
    >
      <Icon className="w-3.5 h-3.5" icon="solar:copy-linear" />
    </button>
  </div>
) : (
  <span className="text-sm text-slate-400 dark:text-slate-500">—</span>
)}

Notes

  • The last_contact_time_utc field may be null for assets that haven't connected yet
  • The created_at field is automatically populated by the database on record creation
  • Both fields are already present in the database schema - no migration needed
  • Date format uses Australian locale (en-AU) consistent with other pages in the application
  • Serial Number and Asset ID columns now share consistent styling and UX patterns