Add the usage chart with range and grouping controls

Angular · Angular · advanced · greenfield

Adds the usage chart to the analytics page: range buttons (7d/30d/90d), a Daily/Monthly grouping toggle, and a bar list of bucketed totals. An effect watches the controls and loads usage for the selected range, bucketing the response by the selected grouping; controls lock while a request is in flight and a failed load offers Retry. Verified by switching ranges and watching the buckets reload.

The analytics page of a SaaS admin. HttpClient is the app-wide HTTP layer; the usage API is fast but uncancellable. Monthly grouping exists because 90d at day granularity is too dense to read.

Requirements

Files touched

--- src/app/usage/usage-chart.component.ts
+import { Component, effect, inject, signal } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+
+interface UsagePoint {
+  ts: string; // YYYY-MM-DD, sorted ascending
+  count: number;
+}
+
+interface Bucket {
+  label: string;
+  total: number;
+}
+
+function bucketBy(points: UsagePoint[], granularity: 'day' | 'month'): Bucket[] {
+  const totals = new Map<string, number>();
+  for (const point of points) {
+    const label = granularity === 'month' ? point.ts.slice(0, 7) : point.ts;
+    totals.set(label, (totals.get(label) ?? 0) + point.count);
+  }
+  return [...totals.entries()].map(([label, total]) => ({ label, total }));
+}
+
+@Component({
+  selector: 'app-usage-chart',
+  standalone: true,
+  template: `
+    <section class="usage-chart" aria-label="Usage">
+      <header class="usage-controls">
+        @for (option of RANGES; track option) {

Review this PR

Angular practice