This commit is contained in:
Jan K9f 2025-08-20 08:29:13 +02:00
commit 03ddce0290
Signed by: jank
GPG key ID: 22BEAC760B3333D6
25 changed files with 240 additions and 165 deletions

View file

@ -16,9 +16,7 @@
"outputPath": "dist/auth",
"index": "src/index.html",
"browser": "src/main.ts",
"polyfills": [
"zone.js"
],
"polyfills": ["zone.js"],
"tsConfig": "tsconfig.app.json",
"assets": [
{
@ -74,10 +72,7 @@
"test": {
"builder": "@angular/build:karma",
"options": {
"polyfills": [
"zone.js",
"zone.js/testing"
],
"polyfills": ["zone.js", "zone.js/testing"],
"tsConfig": "tsconfig.spec.json",
"assets": [
{

View file

@ -2,9 +2,8 @@ import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
@Component({
selector: 'app-root',
imports: [RouterOutlet],
templateUrl: './app.component.html',
selector: 'app-root',
imports: [RouterOutlet],
templateUrl: './app.component.html',
})
export class AppComponent {
}
export class AppComponent {}

View file

@ -1,14 +1,14 @@
import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
import {provideRouter, withDebugTracing} from '@angular/router';
import { provideRouter, withDebugTracing } from '@angular/router';
import { routes } from './app.routes';
import {provideHttpClient, withInterceptors} from "@angular/common/http";
import {httpInterceptor} from "./service/http.interceptor";
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { httpInterceptor } from './service/http.interceptor';
export const appConfig: ApplicationConfig = {
providers: [
provideZoneChangeDetection({ eventCoalescing: true }),
provideRouter(routes, withDebugTracing()),
provideHttpClient(withInterceptors([httpInterceptor])),
]
],
};

View file

@ -1,5 +1,5 @@
import { Routes } from '@angular/router';
import {authGuard} from "./service/auth.guard";
import { authGuard } from './service/auth.guard';
export const routes: Routes = [
{
@ -7,7 +7,8 @@ export const routes: Routes = [
children: [
{
path: 'register',
loadComponent: () => import('./component/auth/register/register.component'),
loadComponent: () =>
import('./component/auth/register/register.component'),
},
{
path: 'login',
@ -21,7 +22,8 @@ export const routes: Routes = [
children: [
{
path: 'dashboard',
loadComponent: () => import('./component/dashboard/dashboard.component'),
loadComponent: () =>
import('./component/dashboard/dashboard.component'),
},
{
path: 'users',
@ -29,5 +31,5 @@ export const routes: Routes = [
},
],
canActivate: [authGuard],
}
},
];

View file

@ -8,15 +8,27 @@
<form [formGroup]="form">
<div class="mb-3">
<label for="username" class="form-label">Username</label>
<input type="text" id="username" class="form-control" formControlName="username">
<input
type="text"
id="username"
class="form-control"
formControlName="username"
/>
</div>
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<input type="password" id="password" class="form-control" formControlName="password">
<input
type="password"
id="password"
class="form-control"
formControlName="password"
/>
</div>
<button type="submit" class="btn btn-primary" (click)="login()">Login</button>
<button type="submit" class="btn btn-primary" (click)="login()">
Login
</button>
</form>
</div>
</div>
</div>
</div>
</div>

View file

@ -1,14 +1,17 @@
import {Component, inject} from '@angular/core';
import {FormBuilder, FormGroup, ReactiveFormsModule, Validators} from "@angular/forms";
import AuthService from "../../../service/auth.service";
import {AuthResponse, Token} from "../../../models";
import {Router} from "@angular/router";
import { Component, inject } from '@angular/core';
import {
FormBuilder,
FormGroup,
ReactiveFormsModule,
Validators,
} from '@angular/forms';
import AuthService from '../../../service/auth.service';
import { AuthResponse, Token } from '../../../models';
import { Router } from '@angular/router';
@Component({
selector: 'app-login',
imports: [
ReactiveFormsModule
],
imports: [ReactiveFormsModule],
templateUrl: './login.component.html',
})
export default class LoginComponent {
@ -23,7 +26,7 @@ export default class LoginComponent {
login() {
if (this.form.invalid) {
console.log(this.form.errors)
console.log(this.form.errors);
return;
}
@ -31,7 +34,7 @@ export default class LoginComponent {
localStorage.setItem('access_token', r.accessToken);
localStorage.setItem('refresh_token', r.refreshToken);
this.router.navigate(['dashboard'])
this.router.navigate(['dashboard']);
});
}
}

View file

@ -9,11 +9,21 @@
<div class="row">
<div class="col-md-6 mb-3">
<label for="firstname" class="form-label">First Name</label>
<input id="firstname" class="form-control" formControlName="firstname" type="text">
<input
id="firstname"
class="form-control"
formControlName="firstname"
type="text"
/>
</div>
<div class="col-md-6 mb-3">
<label for="lastname" class="form-label">Last Name</label>
<input id="lastname" class="form-control" formControlName="lastname" type="text">
<input
id="lastname"
class="form-control"
formControlName="lastname"
type="text"
/>
</div>
</div>
@ -22,25 +32,50 @@
<div class="row">
<div class="col-md-8 mb-3">
<label for="street" class="form-label">Street</label>
<input id="street" class="form-control" formControlName="street" type="text">
<input
id="street"
class="form-control"
formControlName="street"
type="text"
/>
</div>
<div class="col-md-4 mb-3">
<label for="nr" class="form-label">Number</label>
<input id="nr" class="form-control" formControlName="nr" type="text">
<input
id="nr"
class="form-control"
formControlName="nr"
type="text"
/>
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label for="city" class="form-label">City</label>
<input id="city" class="form-control" formControlName="city" type="text">
<input
id="city"
class="form-control"
formControlName="city"
type="text"
/>
</div>
<div class="col-md-3 mb-3">
<label for="state" class="form-label">State</label>
<input id="state" class="form-control" formControlName="state" type="text">
<input
id="state"
class="form-control"
formControlName="state"
type="text"
/>
</div>
<div class="col-md-3 mb-3">
<label for="zip" class="form-label">ZIP Code</label>
<input id="zip" class="form-control" formControlName="zip" type="text">
<input
id="zip"
class="form-control"
formControlName="zip"
type="text"
/>
</div>
</div>
</div>
@ -50,11 +85,23 @@
<div class="row">
<div class="col-md-6 mb-3">
<label for="email" class="form-label">Email</label>
<input id="email" class="form-control" formControlName="email" type="email">
<input
id="email"
class="form-control"
formControlName="email"
type="email"
/>
</div>
<div class="col-md-6 mb-3">
<label for="confirmEmail" class="form-label">Confirm Email</label>
<input id="confirmEmail" class="form-control" formControlName="confirmEmail" type="email">
<label for="confirmEmail" class="form-label"
>Confirm Email</label
>
<input
id="confirmEmail"
class="form-control"
formControlName="confirmEmail"
type="email"
/>
</div>
</div>
</div>
@ -64,18 +111,32 @@
<div class="row">
<div class="col-md-6 mb-3">
<label for="password" class="form-label">Password</label>
<input id="password" class="form-control" formControlName="password" type="password">
<input
id="password"
class="form-control"
formControlName="password"
type="password"
/>
</div>
<div class="col-md-6 mb-3">
<label for="confirmPassword" class="form-label">Confirm Password</label>
<input id="confirmPassword" class="form-control" formControlName="confirmPassword" type="password">
<label for="confirmPassword" class="form-label"
>Confirm Password</label
>
<input
id="confirmPassword"
class="form-control"
formControlName="confirmPassword"
type="password"
/>
</div>
</div>
</div>
<button type="submit" class="btn btn-primary mt-3" (click)="submit()">Submit</button>
<button type="submit" class="btn btn-primary mt-3" (click)="submit()">
Submit
</button>
</form>
</div>
</div>
</div>
</div>
</div>

View file

@ -1,13 +1,16 @@
import {Component, inject} from '@angular/core';
import {FormBuilder, FormGroup, ReactiveFormsModule, Validators} from "@angular/forms";
import AuthService from "../../../service/auth.service";
import CustomValidators from "../../../service/custom.validators";
import { Component, inject } from '@angular/core';
import {
FormBuilder,
FormGroup,
ReactiveFormsModule,
Validators,
} from '@angular/forms';
import AuthService from '../../../service/auth.service';
import CustomValidators from '../../../service/custom.validators';
@Component({
selector: 'app-register',
imports: [
ReactiveFormsModule
],
imports: [ReactiveFormsModule],
templateUrl: './register.component.html',
})
export default class RegisterComponent {

View file

@ -1,7 +1,9 @@
<div class="container-fluid">
<div class="row">
<main class="col-md-9 ms-sm-auto col-lg-10 px-md-4">
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
<div
class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"
>
<h1 class="h2">Dashboard</h1>
</div>

View file

@ -1,14 +1,10 @@
import {Component} from '@angular/core';
import "../side/side.component";
import {RouterOutlet} from "@angular/router";
import { Component } from '@angular/core';
import '../side/side.component';
import { RouterOutlet } from '@angular/router';
@Component({
selector: 'app-dashboard',
imports: [
RouterOutlet
],
imports: [RouterOutlet],
templateUrl: './dashboard.component.html',
})
export default class DashboardComponent {
}
export default class DashboardComponent {}

View file

@ -1,7 +1,15 @@
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container-fluid">
<a class="navbar-brand" href="#">Auth App</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<button
class="navbar-toggler"
type="button"
data-bs-toggle="collapse"
data-bs-target="#navbarNav"
aria-controls="navbarNav"
aria-expanded="false"
aria-label="Toggle navigation"
>
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">

View file

@ -1,14 +1,10 @@
import {Component} from '@angular/core';
import {RouterLink} from "@angular/router";
import { Component } from '@angular/core';
import { RouterLink } from '@angular/router';
@Component({
selector: 'app-header',
imports: [
RouterLink
],
imports: [RouterLink],
templateUrl: './header.component.html',
styleUrl: './header.component.css'
styleUrl: './header.component.css',
})
export default class HeaderComponent {
}
export default class HeaderComponent {}

View file

@ -1,17 +1,11 @@
import { Component } from '@angular/core';
import HeaderComponent from "../header/header.component";
import SideComponent from "../side/side.component";
import {RouterOutlet} from "@angular/router";
import HeaderComponent from '../header/header.component';
import SideComponent from '../side/side.component';
import { RouterOutlet } from '@angular/router';
@Component({
selector: 'app-random-ahh',
imports: [
HeaderComponent,
SideComponent,
RouterOutlet
],
imports: [HeaderComponent, SideComponent, RouterOutlet],
templateUrl: './random-ahh.component.html',
})
export default class RandomAhhComponent {
}
export default class RandomAhhComponent {}

View file

@ -1,4 +1,7 @@
<nav id="sidebarMenu" class="col-md-3 col-lg-2 d-md-block bg-light sidebar collapse">
<nav
id="sidebarMenu"
class="col-md-3 col-lg-2 d-md-block bg-light sidebar collapse"
>
<div class="position-sticky pt-3">
<ul class="nav flex-column">
<li class="nav-item">
@ -39,4 +42,4 @@
</li>
</ul>
</div>
</nav>
</nav>

View file

@ -4,8 +4,6 @@ import { Component } from '@angular/core';
selector: 'app-side',
imports: [],
templateUrl: './side.component.html',
styleUrl: './side.component.css'
styleUrl: './side.component.css',
})
export default class SideComponent {
}
export default class SideComponent {}

View file

@ -5,6 +5,4 @@ import { Component } from '@angular/core';
imports: [],
templateUrl: './users.component.html',
})
export default class UsersComponent {
}
export default class UsersComponent {}

View file

@ -1,18 +1,24 @@
import {CanActivateFn} from "@angular/router";
import {inject} from "@angular/core";
import {HttpClient, HttpErrorResponse, HttpResponse} from "@angular/common/http";
import {catchError, map, of} from "rxjs";
import {User} from "../models";
import { CanActivateFn } from '@angular/router';
import { inject } from '@angular/core';
import {
HttpClient,
HttpErrorResponse,
HttpResponse,
} from '@angular/common/http';
import { catchError, map, of } from 'rxjs';
import { User } from '../models';
export const authGuard: CanActivateFn = () => {
return inject(HttpClient).get<User>('https://dummyjson.com/auth/me', { observe: 'response' }).pipe(
map((res: HttpResponse<User>) => {
console.log(res);
return res.status === 200;
}),
catchError((err: HttpErrorResponse) => {
console.log(err);
return of(false);
})
);
return inject(HttpClient)
.get<User>('https://dummyjson.com/auth/me', { observe: 'response' })
.pipe(
map((res: HttpResponse<User>) => {
console.log(res);
return res.status === 200;
}),
catchError((err: HttpErrorResponse) => {
console.log(err);
return of(false);
}),
);
};

View file

@ -1,7 +1,6 @@
import {inject, Injectable} from "@angular/core";
import {HttpClient} from "@angular/common/http";
import {AuthResponse} from "../models";
import { inject, Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { AuthResponse } from '../models';
@Injectable({
providedIn: 'root',
@ -9,13 +8,14 @@ import {AuthResponse} from "../models";
export default class AuthService {
http: HttpClient = inject(HttpClient);
register(data: { email: string, password: string }): void {
register(data: { email: string; password: string }): void {
console.log(data);
}
login(loginData: { username: string, password: string }) {
return this.http.post<AuthResponse>('https://dummyjson.com/auth/login', loginData)
login(loginData: { username: string; password: string }) {
return this.http.post<AuthResponse>(
'https://dummyjson.com/auth/login',
loginData,
);
}
}

View file

@ -1,31 +1,32 @@
import {AbstractControl, ValidatorFn} from "@angular/forms";
import { AbstractControl, ValidatorFn } from '@angular/forms';
export default class CustomValidators {
public static email(): ValidatorFn {
return (emailGroup: AbstractControl) => {
if (emailGroup.get('email')?.value !== emailGroup.get('confirmEmail')) {
return {emailMismatch: true}
return { emailMismatch: true };
}
return {};
}
};
}
public static password(): ValidatorFn {
return (passwordGroup: AbstractControl) => {
if (passwordGroup.get('password')?.value !== passwordGroup.get('confirmPassword')) {
return {emailMismatch: true}
if (
passwordGroup.get('password')?.value !==
passwordGroup.get('confirmPassword')
) {
return { emailMismatch: true };
}
return {};
}
};
}
static address(): ValidatorFn {
return (addressGroup: AbstractControl) => {
return {};
}
};
}
}

View file

@ -1,9 +1,18 @@
import {HttpHandlerFn, HttpInterceptorFn, HttpRequest} from "@angular/common/http";
import {
HttpHandlerFn,
HttpInterceptorFn,
HttpRequest,
} from '@angular/common/http';
export const httpInterceptor: HttpInterceptorFn = (req: HttpRequest<unknown>, next: HttpHandlerFn) => {
return next(req.clone({
export const httpInterceptor: HttpInterceptorFn = (
req: HttpRequest<unknown>,
next: HttpHandlerFn,
) => {
return next(
req.clone({
setHeaders: {
Authorization: "Bearer " + localStorage.getItem('access_token')
}
}));
}
Authorization: 'Bearer ' + localStorage.getItem('access_token'),
},
}),
);
};

View file

@ -1,13 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Auth</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<app-root></app-root>
</body>
<head>
<meta charset="utf-8" />
<title>Auth</title>
<base href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
</head>
<body>
<app-root></app-root>
</body>
</html>

View file

@ -2,5 +2,6 @@ import { bootstrapApplication } from '@angular/platform-browser';
import { appConfig } from './app/app.config';
import { AppComponent } from './app/app.component';
bootstrapApplication(AppComponent, appConfig)
.catch((err) => console.error(err));
bootstrapApplication(AppComponent, appConfig).catch((err) =>
console.error(err),
);

View file

@ -6,10 +6,6 @@
"outDir": "./out-tsc/app",
"types": []
},
"files": [
"src/main.ts"
],
"include": [
"src/**/*.d.ts"
]
"files": ["src/main.ts"],
"include": ["src/**/*.d.ts"]
}

View file

@ -18,10 +18,7 @@
"importHelpers": true,
"target": "ES2022",
"module": "ES2022",
"lib": [
"ES2022",
"dom"
]
"lib": ["ES2022", "dom"]
},
"angularCompilerOptions": {
"enableI18nLegacyMessageIdFormat": false,

View file

@ -4,12 +4,7 @@
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/spec",
"types": [
"jasmine"
]
"types": ["jasmine"]
},
"include": [
"src/**/*.spec.ts",
"src/**/*.d.ts"
]
"include": ["src/**/*.spec.ts", "src/**/*.d.ts"]
}