Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions frontend/app/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export default [
route("about", "routes/about.tsx"),
route("help", "routes/help.tsx"),
route("feedback", "routes/feedback.tsx"),
route("analytics", "routes/analytics.tsx"),
route("search", "routes/search.tsx"),
route("search/results", "routes/search.results.ts"),
route("catalog/:id", "routes/catalog.$id.ts"),
Expand Down
22 changes: 22 additions & 0 deletions frontend/app/routes/analytics.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/* eslint-disable react-refresh/only-export-components */
import type { LoaderFunctionArgs, MetaFunction } from 'react-router';
import { AnalyticsPage } from '../../src/pages/AnalyticsPage';
import { buildSeoMeta } from '../../src/config/seo';

const description =
'The July 2026 monthly pulse for discovery, resources, collections, and platform activity across the BTAA Geoportal.';

export function loader({ request }: LoaderFunctionArgs) {
return { currentUrl: new URL(request.url).href };
}

export const meta: MetaFunction<typeof loader> = ({ data }) =>
buildSeoMeta({
title: 'Geo Charts — July 2026',
description,
url: data?.currentUrl,
});

export default function Analytics() {
return <AnalyticsPage />;
}
200 changes: 200 additions & 0 deletions frontend/src/__tests__/pages/AnalyticsPage.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
import { fireEvent, render, screen } from '@testing-library/react';
import { BrowserRouter } from 'react-router';
import { HelmetProvider } from 'react-helmet-async';
import type { ReactNode } from 'react';
import { vi } from 'vitest';
import { AnalyticsPage } from '../../pages/AnalyticsPage';
import { axeWithWCAG22 } from '../../test-utils/axe';

vi.mock('../../components/layout/Header', () => ({
Header: () => <div data-testid="header">Header</div>,
}));

vi.mock('../../components/layout/Footer', () => ({
Footer: () => <div data-testid="footer">Footer</div>,
}));

vi.mock('recharts', () => ({
Area: () => null,
AreaChart: ({ data }: { data?: Array<Record<string, unknown>> }) => (
<div
data-testid={
data?.[0] && 'views' in data[0]
? 'member-activity-chart'
: 'activity-chart'
}
/>
),
CartesianGrid: () => null,
Line: () => null,
ResponsiveContainer: ({ children }: { children: ReactNode }) => (
<div>{children}</div>
),
Tooltip: () => null,
XAxis: () => null,
YAxis: () => null,
}));

describe('AnalyticsPage', () => {
function renderPage() {
return render(
<HelmetProvider>
<BrowserRouter>
<AnalyticsPage />
</BrowserRouter>
</HelmetProvider>
);
}

it('renders the July dashboard and ranked catalog links', () => {
renderPage();

expect(
screen.getByRole('heading', {
name: /monthly analytics dashboard/i,
level: 1,
})
).toBeInTheDocument();
expect(screen.getByText('613.1K')).toBeInTheDocument();
expect(
screen.getAllByRole('link', {
name: 'Emporium, Pennsylvania, 1892',
})[0]
).toHaveAttribute(
'href',
'/resources/95dcf338-fc27-4d3b-8883-967b3223933b'
);
expect(
screen.getByRole('link', { name: 'Urban Base Layers Collection' })
).toHaveAttribute('href', '/resources/b1g_urbanBaseLayers');
expect(screen.getByTestId('activity-chart')).toBeInTheDocument();
expect(screen.getByTestId('member-activity-chart')).toBeInTheDocument();
expect(screen.getByText('99.997%')).toBeInTheDocument();
expect(
screen.getByRole('heading', { name: 'Top zero-result queries' })
).toBeInTheDocument();
expect(
screen.getByRole('link', { name: '14.271281, 44.702708' })
).toHaveAttribute('href', '/search?q=14.271281%2C%2044.702708');
expect(
screen.getByText(/758 zero-result searches included query text/i)
).toBeInTheDocument();
expect(
screen.getAllByRole('link', {
name: "Map of Home Owners' Loan Corporation [Los Angeles, California] {1939}",
})[0]
).toHaveAttribute(
'href',
'/resources/2f3c06da-21a0-410f-b230-be07165aeb89'
);
expect(
screen.getByRole('heading', { name: 'API requests and reliability' })
).toBeInTheDocument();
expect(screen.getByText('Turnstile status checks')).toBeInTheDocument();
expect(screen.getByText(/84.1% of the peak/i)).toBeInTheDocument();
expect(
screen.getByRole('heading', {
name: 'How BTAA member content performed',
})
).toBeInTheDocument();
expect(
screen.getByText(/69\.4% of search impressions/i)
).toBeInTheDocument();
expect(screen.getByText(/64\.8% of portal views/i)).toBeInTheDocument();
expect(
screen.getByText(/63\.1% of all download clicks/i)
).toBeInTheDocument();
expect(screen.getByRole('link', { name: 'Chicago' })).toHaveAttribute(
'href',
'/search?include_filters%5Bb1g_code_s%5D%5B%5D=12'
);
expect(
screen.getAllByRole('link', {
name: /KH-4a: Declassified Satellite Imagery/i,
})[0]
).toHaveAttribute('href', '/resources/camel-1022954');
expect(screen.getByText(/17 contributing institutions/i)).toBeVisible();
});

it('filters the report to a campus and restores the alliance view', () => {
renderPage();

const chicagoFilter = screen.getByRole('button', {
name: 'Show University of Chicago July report',
});
expect(chicagoFilter).toHaveAttribute('aria-pressed', 'false');

fireEvent.click(chicagoFilter);

expect(chicagoFilter).toHaveAttribute('aria-pressed', 'true');
expect(
screen.getByRole('heading', {
name: 'University of Chicago',
level: 3,
})
).toBeInTheDocument();
expect(
screen.getByRole('link', { name: 'Browse Chicago content' })
).toHaveAttribute(
'href',
'/search?include_filters%5Bb1g_code_s%5D%5B%5D=12'
);
expect(
screen.getByRole('link', { name: 'Survey of Egypt: El Bagur' })
).toHaveAttribute('href', '/resources/camel-1013673');
expect(screen.queryByText(/17 contributing institutions/i)).toBeNull();

fireEvent.click(screen.getByRole('button', { name: 'All BTAA' }));

expect(
screen.getByRole('heading', {
name: 'All BTAA member content',
level: 3,
})
).toBeInTheDocument();
expect(screen.getByText(/17 contributing institutions/i)).toBeVisible();
});

it('explains when a campus had no direct download-link clicks', () => {
renderPage();

fireEvent.click(
screen.getByRole('button', {
name: 'Show University of Oregon July report',
})
);

expect(
screen.getByText(
/No direct download-link clicks were recorded; 9 source-site clicks were still captured/i
)
).toBeInTheDocument();
});

it('has no detectable WCAG 2.2 A or AA violations', async () => {
const { container } = renderPage();
const results = await axeWithWCAG22(container);

expect(results.violations).toHaveLength(0);
}, 15_000);

it('uses the local thumbnail route and falls back to a resource icon', () => {
renderPage();

const thumbnail = screen.getByTestId(
'analytics-thumbnail-95dcf338-fc27-4d3b-8883-967b3223933b'
);
expect(thumbnail).toHaveAttribute(
'src',
'/resources/95dcf338-fc27-4d3b-8883-967b3223933b/thumbnail'
);

fireEvent.error(thumbnail);

expect(
screen.getByTestId(
'analytics-thumbnail-fallback-95dcf338-fc27-4d3b-8883-967b3223933b'
)
).toBeInTheDocument();
});
});
5 changes: 5 additions & 0 deletions frontend/src/components/layout/Footer.client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ function BtaaFooter({ id }: FooterProps) {
Help
</a>
</li>
<li>
<a href="/analytics" className={footerLinkClass}>
Monthly Analytics
</a>
</li>
<li>
<a
href="https://gin.btaa.org/tutorials"
Expand Down
Loading
Loading