Skip to content

Commit 857a75e

Browse files
committed
feat: handle auth state in the navbar
1 parent 4f50a9c commit 857a75e

File tree

4 files changed

+101
-54
lines changed

4 files changed

+101
-54
lines changed

src/app/app.routes.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@ import { map } from 'rxjs/operators';
88
*/
99
const requireAuth = () => {
1010
const router = inject(Router);
11-
return inject(UserService).isAuthenticated.pipe(
12-
map(isAuth => isAuth || router.createUrlTree(['/login']))
13-
);
11+
return inject(UserService).isAuthenticated.pipe(map(isAuth => isAuth || router.createUrlTree(['/login'])));
1412
};
1513

1614
export const routes: Routes = [

src/app/core/interceptors/error.interceptor.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,10 @@ export const errorInterceptor: HttpInterceptorFn = (req, next) => {
4343

4444
// Normalize error format: { errors: {...}, status: number }
4545
// Provides fallback message for network errors (status 0) or missing body
46-
const body = err.error && typeof err.error === 'object' && 'errors' in err.error
47-
? err.error
48-
: { errors: { network: ['Unable to connect. Please check your internet connection.'] } };
46+
const body =
47+
err.error && typeof err.error === 'object' && 'errors' in err.error
48+
? err.error
49+
: { errors: { network: ['Unable to connect. Please check your internet connection.'] } };
4950

5051
return throwError(() => ({ ...body, status: err.status }));
5152
}),

src/app/core/layout/header.component.html

Lines changed: 92 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -2,51 +2,98 @@
22
<div class="container">
33
<a class="navbar-brand" routerLink="/">conduit</a>
44

5-
<!-- Show this for logged out users -->
6-
<ul *ifAuthenticated="false" class="nav navbar-nav pull-xs-right">
7-
<li class="nav-item">
8-
<a class="nav-link" routerLink="/"> Home </a>
9-
</li>
10-
11-
<li class="nav-item">
12-
<a class="nav-link" routerLink="/login" routerLinkActive="active"> Sign in </a>
13-
</li>
14-
15-
<li class="nav-item">
16-
<a class="nav-link" routerLink="/register" routerLinkActive="active"> Sign up </a>
17-
</li>
18-
</ul>
19-
20-
<!-- Show this for logged in users -->
21-
<ul *ifAuthenticated="true" class="nav navbar-nav pull-xs-right">
22-
<li class="nav-item">
23-
<a class="nav-link" routerLink="/" routerLinkActive="active" [routerLinkActiveOptions]="{ exact: true }">
24-
Home
25-
</a>
26-
</li>
27-
28-
<li class="nav-item">
29-
<a class="nav-link" routerLink="/editor" routerLinkActive="active">
30-
<i class="ion-compose"></i>&nbsp;New Article
31-
</a>
32-
</li>
33-
34-
<li class="nav-item">
35-
<a class="nav-link" routerLink="/settings" routerLinkActive="active">
36-
<i class="ion-gear-a"></i>&nbsp;Settings
37-
</a>
38-
</li>
39-
40-
@if (currentUser$ | async; as currentUser) {
41-
<li class="nav-item">
42-
<a class="nav-link" [routerLink]="['/profile', currentUser.username]" routerLinkActive="active">
43-
@if (currentUser.image) {
44-
<img [src]="currentUser.image" class="user-pic" />
45-
}
46-
{{ currentUser.username }}
47-
</a>
48-
</li>
5+
@if (authState$ | async; as authState) {
6+
<!-- Show this for logged out users -->
7+
@if (authState === 'unauthenticated') {
8+
<ul class="nav navbar-nav pull-xs-right">
9+
<li class="nav-item">
10+
<a class="nav-link" routerLink="/"> Home </a>
11+
</li>
12+
13+
<li class="nav-item">
14+
<a class="nav-link" routerLink="/login" routerLinkActive="active"> Sign in </a>
15+
</li>
16+
17+
<li class="nav-item">
18+
<a class="nav-link" routerLink="/register" routerLinkActive="active"> Sign up </a>
19+
</li>
20+
</ul>
21+
}
22+
23+
<!-- Show this for logged in users -->
24+
@if (authState === 'authenticated') {
25+
<ul class="nav navbar-nav pull-xs-right">
26+
<li class="nav-item">
27+
<a class="nav-link" routerLink="/" routerLinkActive="active" [routerLinkActiveOptions]="{ exact: true }">
28+
Home
29+
</a>
30+
</li>
31+
32+
<li class="nav-item">
33+
<a class="nav-link" routerLink="/editor" routerLinkActive="active">
34+
<i class="ion-compose"></i>&nbsp;New Article
35+
</a>
36+
</li>
37+
38+
<li class="nav-item">
39+
<a class="nav-link" routerLink="/settings" routerLinkActive="active">
40+
<i class="ion-gear-a"></i>&nbsp;Settings
41+
</a>
42+
</li>
43+
44+
@if (currentUser$ | async; as currentUser) {
45+
<li class="nav-item">
46+
<a class="nav-link" [routerLink]="['/profile', currentUser.username]" routerLinkActive="active">
47+
@if (currentUser.image) {
48+
<img [src]="currentUser.image" class="user-pic" />
49+
}
50+
{{ currentUser.username }}
51+
</a>
52+
</li>
53+
}
54+
</ul>
55+
}
56+
57+
<!-- Show this when auth is temporarily unavailable (server error) -->
58+
@if (authState === 'unavailable') {
59+
<ul class="nav navbar-nav pull-xs-right">
60+
<li class="nav-item">
61+
<a class="nav-link" routerLink="/" routerLinkActive="active" [routerLinkActiveOptions]="{ exact: true }">
62+
Home
63+
</a>
64+
</li>
65+
66+
<li class="nav-item">
67+
<a class="nav-link" routerLink="/editor" routerLinkActive="active">
68+
<i class="ion-compose"></i>&nbsp;New Article
69+
</a>
70+
</li>
71+
72+
<li class="nav-item">
73+
<a class="nav-link" routerLink="/settings" routerLinkActive="active">
74+
<i class="ion-gear-a"></i>&nbsp;Settings
75+
</a>
76+
</li>
77+
78+
<li class="nav-item">
79+
<span class="nav-link" title="Auth unavailable - retrying automatically">
80+
<i class="ion-load-c"></i>&nbsp;Connecting...
81+
</span>
82+
</li>
83+
</ul>
84+
}
85+
86+
<!-- Show this while loading auth state -->
87+
@if (authState === 'loading') {
88+
<ul class="nav navbar-nav pull-xs-right">
89+
<li class="nav-item">
90+
<a class="nav-link" routerLink="/"> Home </a>
91+
</li>
92+
<li class="nav-item">
93+
<span class="nav-link">Loading...</span>
94+
</li>
95+
</ul>
4996
}
50-
</ul>
97+
}
5198
</div>
5299
</nav>

src/app/core/layout/header.component.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@ import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
22
import { UserService } from '../auth/services/user.service';
33
import { RouterLink, RouterLinkActive } from '@angular/router';
44
import { AsyncPipe } from '@angular/common';
5-
import { IfAuthenticatedDirective } from '../auth/if-authenticated.directive';
65

76
@Component({
87
selector: 'app-layout-header',
98
templateUrl: './header.component.html',
10-
imports: [RouterLinkActive, RouterLink, AsyncPipe, IfAuthenticatedDirective],
9+
imports: [RouterLinkActive, RouterLink, AsyncPipe],
1110
changeDetection: ChangeDetectionStrategy.OnPush,
1211
})
1312
export class HeaderComponent {
14-
currentUser$ = inject(UserService).currentUser;
13+
private userService = inject(UserService);
14+
currentUser$ = this.userService.currentUser;
15+
authState$ = this.userService.authState;
1516
}

0 commit comments

Comments
 (0)