import { getPropertyId, formatPropertyPath, executeReport } from "../../client.js";
import { periodToDateRange } from "../../utils/date.js";
import { formatDuration } from "../../utils/format.js";
import {
formatPercentageFromDecimal,
calculatePercentage,
} from "../../utils/percentage.js";
import type {
GetDeviceBreakdownInput,
GetDeviceBreakdownOutput,
DeviceData,
OSData,
BrowserData,
} from "../../types.js";
/**
* デバイス別のアクセス内訳を取得
*/
export async function getDeviceBreakdown(
input: GetDeviceBreakdownInput
): Promise<GetDeviceBreakdownOutput> {
const propertyId = getPropertyId(input.propertyId);
const property = formatPropertyPath(propertyId);
const dateRange = periodToDateRange(input.period);
// デバイスカテゴリ別のデータ取得
const deviceResponse = await executeReport({
property,
dateRanges: [dateRange],
dimensions: [{ name: "deviceCategory" }],
metrics: [
{ name: "totalUsers" },
{ name: "sessions" },
{ name: "bounceRate" },
{ name: "averageSessionDuration" },
],
orderBys: [{ metric: { metricName: "totalUsers" }, desc: true }],
});
// 合計ユーザー数を取得
const totalUsers =
deviceResponse.totals?.[0]?.metricValues?.[0]?.value
? parseFloat(deviceResponse.totals[0].metricValues[0].value)
: 0;
const devices: DeviceData[] = [];
for (const row of deviceResponse.rows || []) {
const dimensionValues = row.dimensionValues || [];
const metricValues = row.metricValues || [];
const getValue = (index: number): number => {
const value = metricValues[index]?.value;
return value ? parseFloat(value) : 0;
};
const users = Math.round(getValue(0));
const deviceCategory = dimensionValues[0]?.value || "unknown";
devices.push({
deviceCategory: deviceCategory as "desktop" | "mobile" | "tablet",
users,
sessions: Math.round(getValue(1)),
percentage: calculatePercentage(users, totalUsers),
bounceRate: formatPercentageFromDecimal(getValue(2)),
avgSessionDuration: formatDuration(getValue(3)),
});
}
// OS別のデータ取得
const osResponse = await executeReport({
property,
dateRanges: [dateRange],
dimensions: [{ name: "operatingSystem" }],
metrics: [{ name: "totalUsers" }],
orderBys: [{ metric: { metricName: "totalUsers" }, desc: true }],
limit: 10,
});
const operatingSystems: OSData[] = [];
for (const row of osResponse.rows || []) {
const dimensionValues = row.dimensionValues || [];
const metricValues = row.metricValues || [];
const users = metricValues[0]?.value
? Math.round(parseFloat(metricValues[0].value))
: 0;
operatingSystems.push({
name: dimensionValues[0]?.value || "(不明)",
users,
percentage: calculatePercentage(users, totalUsers),
});
}
// ブラウザ別のデータ取得
const browserResponse = await executeReport({
property,
dateRanges: [dateRange],
dimensions: [{ name: "browser" }],
metrics: [{ name: "totalUsers" }],
orderBys: [{ metric: { metricName: "totalUsers" }, desc: true }],
limit: 10,
});
const browsers: BrowserData[] = [];
for (const row of browserResponse.rows || []) {
const dimensionValues = row.dimensionValues || [];
const metricValues = row.metricValues || [];
const users = metricValues[0]?.value
? Math.round(parseFloat(metricValues[0].value))
: 0;
browsers.push({
name: dimensionValues[0]?.value || "(不明)",
users,
percentage: calculatePercentage(users, totalUsers),
});
}
return {
devices,
operatingSystems,
browsers,
};
}