Skip to content
Merged
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 .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,4 @@ __screenshots__/
# System files
.DS_Store
Thumbs.db
.claude/settings.json
12 changes: 12 additions & 0 deletions changelog/v0.5.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# v0.5.0

## New Features
- Document viewer URL now includes document number (e.g. /filings/document/xxx/1)
- Clicking documents in sidebar updates the URL for sharing and bookmarking
- Navigate directly to a specific document via URL

## Improvements
- Homepage redesigned with dark uniform card layout and teal accent theme
- New stats bar highlighting platform features
- Updated screenshots throughout the homepage
- Google Tag Manager integration with custom events for search and document views
Binary file added public/screenshots/document-viewer.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/screenshots/documents-mobile.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/screenshots/filings-desktop-results.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed public/screenshots/filings-desktop-results.png
Binary file not shown.
Binary file added public/screenshots/filings-presentations.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed public/screenshots/filings-presentations.png
Binary file not shown.
Binary file added public/screenshots/fillings-queires.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/screenshots/queries-mobile-panel.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions src/app/app.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ export const routes: Routes = [
loadComponent: () =>
import('./features/filings/filing-search.component').then((m) => m.FilingSearchComponent),
},
{
path: 'filings/document/:accessionNumber/:documentNumber',
canActivate: [authGuard],
loadComponent: () =>
import('./features/document/document-viewer.component').then((m) => m.DocumentViewerComponent),
},
{
path: 'filings/document/:accessionNumber',
canActivate: [authGuard],
Expand Down
24 changes: 23 additions & 1 deletion src/app/components/welcome-modal/changelog.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,33 @@
export const APP_VERSION = '0.4.0';
export const APP_VERSION = '0.5.0';

export interface ChangelogEntry {
version: string;
sections: { title: string; items: string[] }[];
}

export const CHANGELOG: ChangelogEntry[] = [
{
version: '0.5.0',
sections: [
{
title: 'New Features',
items: [
'Document viewer URL now includes document number (e.g. /filings/document/xxx/1)',
'Clicking documents in sidebar updates the URL for sharing and bookmarking',
'Navigate directly to a specific document via URL',
],
},
{
title: 'Improvements',
items: [
'Homepage redesigned with dark uniform card layout and teal accent theme',
'New stats bar highlighting platform features',
'Updated screenshots throughout the homepage',
'Google Tag Manager integration with custom events for search and document views',
],
},
],
},
{
version: '0.4.0',
sections: [
Expand Down
40 changes: 40 additions & 0 deletions src/app/core/services/analytics.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Injectable } from '@angular/core';

@Injectable({ providedIn: 'root' })
export class AnalyticsService {
private readonly enabled = typeof window !== 'undefined' && window.location.hostname === 'nullabroke.com';

private push(event: Record<string, unknown>) {
if (!this.enabled) return;
const w = window as unknown as { dataLayer: Record<string, unknown>[] };
w.dataLayer = w.dataLayer || [];
w.dataLayer.push(event);
}

trackSearch(queryName: string, resultCount: number) {
this.push({
event: 'query_search',
query_name: queryName,
result_count: resultCount,
});
}

trackNewQuery() {
this.push({ event: 'query_create' });
}

trackSelectQuery(queryName: string) {
this.push({
event: 'query_select',
query_name: queryName,
});
}

trackDocumentView(accessionNumber: string, documentNumber: string) {
this.push({
event: 'document_view',
accession_number: accessionNumber,
document_number: documentNumber,
});
}
}
35 changes: 31 additions & 4 deletions src/app/features/document/document-viewer.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
HostListener,
} from '@angular/core';
import { ActivatedRoute, RouterLink } from '@angular/router';
import { Location } from '@angular/common';
import { DomSanitizer, SafeHtml, SafeResourceUrl } from '@angular/platform-browser';
import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
import { map } from 'rxjs';
Expand All @@ -29,6 +30,7 @@ import {
lucideImage,
} from '@ng-icons/lucide';

import { AnalyticsService } from '../../core/services/analytics.service';
import { AppChromeService } from '../../core/services/app-chrome.service';
import { FilingService } from '../../core/services/filing.service';
import { DocumentService } from '../../core/services/document.service';
Expand Down Expand Up @@ -87,19 +89,25 @@ interface IframeMessage {
styleUrl: './document-viewer.component.css',
})
export class DocumentViewerComponent {
private readonly analytics = inject(AnalyticsService);
private readonly appChrome = inject(AppChromeService);
private readonly route = inject(ActivatedRoute);
private readonly location = inject(Location);
private readonly sanitizer = inject(DomSanitizer);
private readonly filingService = inject(FilingService);
private readonly documentService = inject(DocumentService);
private readonly xbrlParser = inject(XbrlParserService);
private readonly destroyRef = inject(DestroyRef);

// Convert route params to signal
// Convert route params to signals
accessionNumber = toSignal(
this.route.paramMap.pipe(map((params) => params.get('accessionNumber'))),
{ initialValue: null }
);
documentNumber = toSignal(
this.route.paramMap.pipe(map((params) => params.get('documentNumber'))),
{ initialValue: null }
);

loading = signal(true);
error = signal<string | null>(null);
Expand Down Expand Up @@ -223,9 +231,15 @@ export class DocumentViewerComponent {
});
this.documents.set(viewableDocs);

// Auto-select the first document
// Select document based on URL param, or default to first
if (viewableDocs.length > 0) {
this.selectDocument(viewableDocs[0]);
const docNum = this.documentNumber();
let selectedDoc = viewableDocs[0];
if (docNum) {
const match = viewableDocs.find(d => d.sequence?.toString() === docNum);
if (match) selectedDoc = match;
}
this.selectDocument(selectedDoc, true);
}
}
this.loading.set(false);
Expand All @@ -238,9 +252,22 @@ export class DocumentViewerComponent {
});
}

selectDocument(doc: DocumentFile) {
selectDocument(doc: DocumentFile, replaceUrl = false) {
this.selectedDocument.set(doc);

// Update URL to reflect selected document number
const accNum = this.accessionNumber();
if (accNum && doc.sequence != null) {
const seq = doc.sequence.toString();
const path = `/filings/document/${accNum}/${seq}`;
if (replaceUrl) {
this.location.replaceState(path);
} else {
this.location.go(path);
}
this.analytics.trackDocumentView(accNum, seq);
}

if (this.isXbrlDocument(doc)) {
this.enterXbrlMode();
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ describe('FilingResultRowComponent', () => {
it('should have routerLink to correct document URL', async () => {
await setupTest();
const link = fixture.nativeElement.querySelector('a');
expect(link.getAttribute('href')).toBe('/filings/document/0001234567-24-000001');
expect(link.getAttribute('href')).toBe('/filings/document/0001234567-24-000001/1');
});

it('should use grid layout with 3 columns', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { Filing } from '../../../core/models/filing.model';
imports: [RouterLink, DatePipe],
template: `
<a
[routerLink]="['/filings/document', filing().accessionNumber]"
[routerLink]="['/filings/document', filing().accessionNumber, 1]"
class="grid grid-cols-[1fr_auto_auto] items-center gap-x-4 w-full px-3 py-2 text-left hover:bg-[#2a2d2e] cursor-pointer no-underline"
role="listitem"
>
Expand Down
4 changes: 4 additions & 0 deletions src/app/features/filings/filing-search.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { FilingService } from '../../core/services/filing.service';
import { SavedQueriesService } from '../../core/services/saved-queries.service';
import { Filing } from '../../core/models/filing.model';
import { SavedQuery } from '../../core/models/query-parameter.model';
import { AnalyticsService } from '../../core/services/analytics.service';
import { QueryParametersComponent } from '../../components/query-builder';
import {
FilingStatusBarComponent,
Expand Down Expand Up @@ -71,6 +72,7 @@ export class FilingSearchComponent {
private readonly appChrome = inject(AppChromeService);
private readonly filingService = inject(FilingService);
private readonly savedQueriesService = inject(SavedQueriesService);
private readonly analytics = inject(AnalyticsService);
private readonly router = inject(Router);
private readonly route = inject(ActivatedRoute);
private readonly destroyRef = inject(DestroyRef);
Expand Down Expand Up @@ -234,6 +236,7 @@ export class FilingSearchComponent {
this.results.set(filings ?? []);
this.loading.set(false);
this.stopLogoAfterAnimation(animStart, ANIM_DURATION);
this.analytics.trackSearch(this.titleText(), (filings ?? []).length);
},
error: () => {
this.results.set([]);
Expand All @@ -247,6 +250,7 @@ export class FilingSearchComponent {
newQuery() {
this.savedQueriesService.newQuery();
this.queryControl.setValue('', { emitEvent: false });
this.analytics.trackNewQuery();
}

selectSavedQuery(guid: string) {
Expand Down
Loading
Loading