Files
ng-signals-template/src/app/users/ui/users.page.ts
T
ehoandClaude Sonnet 5 c895929f58 fix: enable strict mode, honest HTTP boundary, and add routing
Three fixes to the parts of the template that contradicted its own
"illegal states unrepresentable" claim:

- tsconfig: turn on strict + strictTemplates (measured zero fallout —
  the codebase already typechecked cleanly, it just wasn't enforced).
- RemoteData<T> drops its unused error type parameter (Resource.error
  is always Error) and Failure now carries a real Error. Pages read the
  union with @let instead of re-deriving from the resource, which
  deletes the non-null assertion strictNullChecks would otherwise flag.
- users.adapter.ts never checked response.ok, so an HTTP error resolved
  as a garbage Success and crashed instead of reaching RemoteData's
  Failure branch. New shared/infrastructure/http.ts adds the status
  check plus hand-written parse guards and abortSignal forwarding; the
  six fetch stubs across the test suite (which encoded the missing
  check) and adapter spec now cover the Failure and Empty paths.

Also adds real routing (@angular/router was a dependency with zero
imports and a fake "Back" button): /users and /users/:id are now
deep-linkable via withComponentInputBinding(), tested with
RouterTestingHarness driving real navigation.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-01 10:29:47 +02:00

39 lines
1.6 KiB
TypeScript

import { Component, computed, inject, input } from '@angular/core';
import { Router } from '@angular/router';
import { PageShellComponent } from '@shared/ui/templates/page-shell.component';
import { AsyncComponent } from '@shared/ui/molecules/async.component';
import { fromResource } from '@shared/application/remote-data';
import { UserListComponent } from '@users/ui/organisms/user-list.component';
import { UserDetailComponent } from '@users/ui/organisms/user-detail.component';
import { usersResource } from '@users/application/users.resource';
import { isEmptyUserList } from '@users/domain/user';
@Component({
selector: 'app-users-page',
imports: [PageShellComponent, AsyncComponent, UserListComponent, UserDetailComponent],
template: `
<app-page-shell heading="Users">
@if (selectedUserId(); as id) {
<app-user-detail [userId]="id" (close)="router.navigate(['/users'])" />
} @else {
@let list = listData();
<app-async [data]="list" (retry)="usersResource.reload()">
@if (list.tag === 'Success' && list.value) {
<app-user-list [users]="list.value" (select)="router.navigate(['/users', $event])" />
}
</app-async>
}
</app-page-shell>
`,
})
export class UsersPage {
protected router = inject(Router);
userId = input<string>();
protected selectedUserId = computed(() => {
const id = this.userId();
return id ? Number(id) : null;
});
protected usersResource = usersResource();
protected listData = computed(() => fromResource(this.usersResource, isEmptyUserList));
}