dashboard.ts 5.42 KB
import type {
  DashboardCategorySliceDto,
  DashboardMetricCardDto,
  DashboardOverviewDto,
  DashboardRecentLabelItemDto,
  DashboardWeeklyPointDto,
} from './dashboard-types';

import { requestClient } from '#/api/request';

const PATH = '/dashboard/overview';

function num(x: unknown, fallback = 0): number {
  const n = typeof x === 'number' ? x : Number(x);
  return Number.isFinite(n) ? n : fallback;
}

function str(o: Record<string, unknown>, camel: string, pascal: string, fallback = '') {
  const v = o[camel] ?? o[pascal];
  if (v === null || v === undefined) {
    return fallback;
  }
  return String(v);
}

function normMetric(raw: unknown): DashboardMetricCardDto {
  if (!raw || typeof raw !== 'object') {
    return {
      changeRate: 0,
      changeValue: 0,
      key: '',
      previousValue: 0,
      title: '',
      value: 0,
    };
  }
  const o = raw as Record<string, unknown>;
  return {
    changeRate: num(o.changeRate ?? o.ChangeRate, 0),
    changeValue: num(o.changeValue ?? o.ChangeValue, 0),
    key: String(o.key ?? o.Key ?? ''),
    previousValue: num(o.previousValue ?? o.PreviousValue, 0),
    title: String(o.title ?? o.Title ?? ''),
    value: num(o.value ?? o.Value, 0),
  };
}

function normWeeklyPoint(raw: unknown): DashboardWeeklyPointDto | null {
  if (!raw || typeof raw !== 'object') {
    return null;
  }
  const o = raw as Record<string, unknown>;
  const date = String(o.date ?? o.Date ?? '');
  if (!date) {
    return null;
  }
  return { date, value: num(o.value ?? o.Value, 0) };
}

function normCategorySlice(raw: unknown): DashboardCategorySliceDto | null {
  if (!raw || typeof raw !== 'object') {
    return null;
  }
  const o = raw as Record<string, unknown>;
  return {
    categoryId: String(o.categoryId ?? o.CategoryId ?? ''),
    categoryName: String(o.categoryName ?? o.CategoryName ?? ''),
    count: num(o.count ?? o.Count, 0),
    ratio: num(o.ratio ?? o.Ratio, 0),
  };
}

function normRecentLabel(raw: unknown): DashboardRecentLabelItemDto | null {
  if (!raw || typeof raw !== 'object') {
    return null;
  }
  const o = raw as Record<string, unknown>;
  const taskId = str(o, 'taskId', 'TaskId', '');
  const labelCode = str(o, 'labelCode', 'LabelCode', '');
  if (!taskId && !labelCode) {
    return null;
  }
  const pbUid = o.printedByUserId ?? o.PrintedByUserId;
  return {
    displayName: str(o, 'displayName', 'DisplayName', '—') || '—',
    labelCode: labelCode || '—',
    labelTypeBadge: str(o, 'labelTypeBadge', 'LabelTypeBadge', '—') || '—',
    printedAt: str(o, 'printedAt', 'PrintedAt', ''),
    printedByName: str(o, 'printedByName', 'PrintedByName', '—') || '—',
    printedByUserId:
      pbUid === null || pbUid === undefined ? null : String(pbUid),
    status: str(o, 'status', 'Status', 'active') || 'active',
    taskId: taskId || labelCode,
  };
}

function emptyMetric(key: string, title: string): DashboardMetricCardDto {
  return {
    changeRate: 0,
    changeValue: 0,
    key,
    previousValue: 0,
    title,
    value: 0,
  };
}

export function emptyDashboardOverview(): DashboardOverviewDto {
  return {
    activeTemplates: emptyMetric('activeTemplates', 'Active Templates'),
    activeUsers: emptyMetric('activeUsers', 'Active Users'),
    byCategory: [],
    byCategoryTotal: 0,
    generatedAt: null,
    labelsPrintedToday: emptyMetric('labelsPrintedToday', 'Labels Printed Today'),
    locations: emptyMetric('locations', 'Locations'),
    people: emptyMetric('people', 'People'),
    products: emptyMetric('products', 'Products'),
    recentLabels: [],
    weeklyPrintVolume: [],
  };
}

function normalizeOverview(raw: unknown): DashboardOverviewDto {
  if (!raw || typeof raw !== 'object') {
    return emptyDashboardOverview();
  }
  const o = raw as Record<string, unknown>;

  const weeklyRaw = (o.weeklyPrintVolume ?? o.WeeklyPrintVolume) as unknown;
  const weeklyArr = Array.isArray(weeklyRaw) ? weeklyRaw : [];

  const byCat = (o.byCategory ?? o.ByCategory) as unknown;
  const legacyCat = (o.categoryDistribution ?? o.CategoryDistribution) as unknown;
  const catArr =
    Array.isArray(byCat) && byCat.length
      ? byCat
      : Array.isArray(legacyCat)
        ? legacyCat
        : [];

  const totalRaw =
    o.byCategoryTotal ??
    o.ByCategoryTotal ??
    o.categoryDistributionTotal ??
    o.CategoryDistributionTotal;

  const recentRaw = (o.recentLabels ?? o.RecentLabels) as unknown;
  const recentArr = Array.isArray(recentRaw) ? recentRaw : [];

  return {
    activeTemplates: normMetric(o.activeTemplates ?? o.ActiveTemplates),
    activeUsers: normMetric(o.activeUsers ?? o.ActiveUsers),
    byCategory: catArr
      .map(normCategorySlice)
      .filter((x): x is DashboardCategorySliceDto => x !== null),
    byCategoryTotal: num(totalRaw, 0),
    generatedAt: (o.generatedAt ?? o.GeneratedAt ?? null) as string | null,
    labelsPrintedToday: normMetric(o.labelsPrintedToday ?? o.LabelsPrintedToday),
    locations: normMetric(o.locations ?? o.Locations),
    people: normMetric(o.people ?? o.People),
    products: normMetric(o.products ?? o.Products),
    recentLabels: recentArr
      .map(normRecentLabel)
      .filter((x): x is DashboardRecentLabelItemDto => x !== null),
    weeklyPrintVolume: weeklyArr
      .map(normWeeklyPoint)
      .filter((x): x is DashboardWeeklyPointDto => x !== null),
  };
}

export function dashboardOverview() {
  return requestClient
    .get<unknown>(`${PATH}`, { errorMessageMode: 'message' })
    .then((raw) => normalizeOverview(raw));
}