nice
This commit is contained in:
parent
6b5e5dbdf1
commit
50663a561a
10 changed files with 115 additions and 32 deletions
25
client/admin/package-lock.json
generated
25
client/admin/package-lock.json
generated
|
@ -16,6 +16,8 @@
|
||||||
"@angular/platform-browser": "^18.2.0",
|
"@angular/platform-browser": "^18.2.0",
|
||||||
"@angular/platform-browser-dynamic": "^18.2.0",
|
"@angular/platform-browser-dynamic": "^18.2.0",
|
||||||
"@angular/router": "^18.2.0",
|
"@angular/router": "^18.2.0",
|
||||||
|
"@ng-icons/core": "^29.6.1",
|
||||||
|
"@ng-icons/ionicons": "^29.6.1",
|
||||||
"rxjs": "~7.8.0",
|
"rxjs": "~7.8.0",
|
||||||
"tslib": "^2.3.0",
|
"tslib": "^2.3.0",
|
||||||
"zone.js": "~0.14.10"
|
"zone.js": "~0.14.10"
|
||||||
|
@ -3599,6 +3601,29 @@
|
||||||
"win32"
|
"win32"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"node_modules/@ng-icons/core": {
|
||||||
|
"version": "29.6.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ng-icons/core/-/core-29.6.1.tgz",
|
||||||
|
"integrity": "sha512-PyDLfmBA8rvMm2edQmSHV4fyPz0aImOW6/183YD8tIovDaWyk9imr3v2qSxlc1BjEnE355uPtPLXnvLs5hkEbQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.2.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@angular/common": ">=18.0.0",
|
||||||
|
"@angular/core": ">=18.0.0",
|
||||||
|
"rxjs": "^6.5.3 || ^7.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@ng-icons/ionicons": {
|
||||||
|
"version": "29.6.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ng-icons/ionicons/-/ionicons-29.6.1.tgz",
|
||||||
|
"integrity": "sha512-+ZIDHjFuqfVTexFfyw5vtasbxqpsQFcur5hKesOzzRqnq6o4KatNsCPjwY8GUoNviY/FKGwPSUXfsWj6YOnoDQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@ngtools/webpack": {
|
"node_modules/@ngtools/webpack": {
|
||||||
"version": "18.2.10",
|
"version": "18.2.10",
|
||||||
"resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-18.2.10.tgz",
|
"resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-18.2.10.tgz",
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
"@angular/platform-browser": "^18.2.0",
|
"@angular/platform-browser": "^18.2.0",
|
||||||
"@angular/platform-browser-dynamic": "^18.2.0",
|
"@angular/platform-browser-dynamic": "^18.2.0",
|
||||||
"@angular/router": "^18.2.0",
|
"@angular/router": "^18.2.0",
|
||||||
|
"@ng-icons/core": "^29.6.1",
|
||||||
|
"@ng-icons/ionicons": "^29.6.1",
|
||||||
"rxjs": "~7.8.0",
|
"rxjs": "~7.8.0",
|
||||||
"tslib": "^2.3.0",
|
"tslib": "^2.3.0",
|
||||||
"zone.js": "~0.14.10"
|
"zone.js": "~0.14.10"
|
||||||
|
|
|
@ -1,26 +1,63 @@
|
||||||
<div class="navbar bg-base-100">
|
<!-- Navbar -->
|
||||||
<a class="btn btn-ghost text-xl">Stillbox</a>
|
<nav class="navbar justify-between bg-base-300">
|
||||||
</div>
|
<!-- Logo -->
|
||||||
<div class="drawer lg:drawer-open">
|
<a class="btn btn-ghost text-lg">
|
||||||
<input id="my-drawer-2" type="checkbox" class="drawer-toggle" />
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
|
||||||
<div class="drawer-content flex flex-col items-center justify-center">
|
<path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" />
|
||||||
<!-- Page content here -->
|
<path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" />
|
||||||
<div class="container mx-auto px-4">
|
</svg>
|
||||||
<router-outlet />
|
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<!-- Menu for mobile -->
|
||||||
|
<div class="dropdown dropdown-end sm:hidden">
|
||||||
|
<button class="btn btn-ghost">
|
||||||
|
<i class="fa-solid fa-bars text-lg"></i>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<ul tabindex="0" class="dropdown-content menu z-[1] bg-base-200 p-6 rounded-box shadow w-56 gap-2">
|
||||||
|
<li><a>Item</a></li>
|
||||||
|
<a class="btn btn-sm btn-primary">Do</a>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<label for="my-drawer-2" class="btn btn-primary drawer-button lg:hidden">
|
|
||||||
Open drawer
|
<!-- Menu for desktop -->
|
||||||
</label>
|
<ul class="hidden menu sm:menu-horizontal gap-2">
|
||||||
</div>
|
<li><a>Item</a></li>
|
||||||
<div class="drawer-side">
|
<a class="btn btn-sm btn-primary">Do</a>
|
||||||
<label
|
|
||||||
for="my-drawer-2"
|
|
||||||
aria-label="close sidebar"
|
|
||||||
class="drawer-overlay"
|
|
||||||
></label>
|
|
||||||
<ul class="menu bg-base-200 text-base-content min-h-full w-80 p-4">
|
|
||||||
<li><a>Home</a></li>
|
|
||||||
<li><a>Talkgroups</a></li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</nav>
|
||||||
|
<div class="flex overflow-hidden relative">
|
||||||
|
<!-- Sidebar -->
|
||||||
|
<aside class="h-screen sticky top-0 flex flex-col overflow-y-auto gap-2 py-6 px-2 bg-base-200">
|
||||||
|
<a class="btn btn-square btn-ghost btn-secondary text-xl" title="Home" routerLink="/home" routerLinkActive="btn-active">
|
||||||
|
<ng-icon name="ionHome"></ng-icon>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a routerLink="/calls" routerLinkActive="btn-active" class="btn btn-ghost btn-secondary text-xl" title="Calls">
|
||||||
|
<ng-icon name="ionMegaphoneOutline"></ng-icon>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a class="btn btn-square btn-ghost text-xl" title="Talkgroups" routerLink="/talkgroups" routerLinkActive="btn-active">
|
||||||
|
<ng-icon name="ionChatbubbles"></ng-icon>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<div class="divider my-0"></div>
|
||||||
|
|
||||||
|
<a class="btn btn-square btn-ghost text-xl" title="Incidents" routerLink="/incidents" routerLinkActive="btn-active">
|
||||||
|
<ng-icon name="ionNewspaperOutline"></ng-icon>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a class="btn btn-square btn-ghost text-xl" title="Alerts" routerLink="/alerts" routerLinkActive="btn-active">
|
||||||
|
<ng-icon name="ionAlertCircleOutline"></ng-icon>
|
||||||
|
</a>
|
||||||
|
<div class="divider my-0"></div>
|
||||||
|
|
||||||
|
<a class="btn btn-circle btn-ghost text-xl" title="Listen">
|
||||||
|
<ng-icon name="ionRadioOutline"></ng-icon>
|
||||||
|
</a>
|
||||||
|
</aside>
|
||||||
|
<div class="container mx-auto px-4">
|
||||||
|
<router-outlet />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,13 +1,19 @@
|
||||||
import { Component } from '@angular/core';
|
import { Component, inject } from '@angular/core';
|
||||||
import { RouterOutlet } from '@angular/router';
|
import { RouterModule, RouterOutlet, RouterLink } from '@angular/router';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { AuthService } from './login/auth.service';
|
||||||
|
import { NgIconComponent, provideIcons } from '@ng-icons/core';
|
||||||
|
import { ionMenuOutline, ionChatbubbles, ionNewspaperOutline, ionAlertCircleOutline, ionRadioOutline, ionHome, ionMegaphoneOutline } from '@ng-icons/ionicons';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [RouterOutlet],
|
imports: [CommonModule, RouterOutlet, RouterModule, RouterLink, NgIconComponent],
|
||||||
templateUrl: './app.component.html',
|
templateUrl: './app.component.html',
|
||||||
styleUrl: './app.component.css',
|
styleUrl: './app.component.css',
|
||||||
|
providers: [ provideIcons({ ionMenuOutline, ionChatbubbles, ionNewspaperOutline, ionAlertCircleOutline, ionRadioOutline, ionHome, ionMegaphoneOutline })],
|
||||||
})
|
})
|
||||||
export class AppComponent {
|
export class AppComponent {
|
||||||
|
auth: AuthService = inject(AuthService);
|
||||||
title = 'admin';
|
title = 'admin';
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1,3 @@
|
||||||
<p>Hi</p>
|
<p>
|
||||||
|
This will be a dashboard someday.
|
||||||
|
</p>
|
||||||
|
|
|
@ -7,4 +7,5 @@ import { Component } from '@angular/core';
|
||||||
templateUrl: './home.component.html',
|
templateUrl: './home.component.html',
|
||||||
styleUrl: './home.component.css',
|
styleUrl: './home.component.css',
|
||||||
})
|
})
|
||||||
export class HomeComponent {}
|
export class HomeComponent {
|
||||||
|
}
|
||||||
|
|
|
@ -11,11 +11,18 @@ export class Jwt {
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
})
|
})
|
||||||
export class APIService {
|
export class AuthService {
|
||||||
|
loggedIn: boolean = false;
|
||||||
constructor(
|
constructor(
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
private _router: Router,
|
private _router: Router,
|
||||||
) {}
|
) {
|
||||||
|
let ssJWT = sessionStorage.getItem('jwt');
|
||||||
|
if (ssJWT) {
|
||||||
|
this.loggedIn = true;
|
||||||
|
this._router.navigateByUrl('/home');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
login(username: string, password: string): Observable<HttpResponse<Jwt>> {
|
login(username: string, password: string): Observable<HttpResponse<Jwt>> {
|
||||||
return this.http
|
return this.http
|
||||||
|
@ -28,6 +35,7 @@ export class APIService {
|
||||||
tap((event) => {
|
tap((event) => {
|
||||||
if (event.status == 200) {
|
if (event.status == 200) {
|
||||||
sessionStorage.setItem('jwt', event.body?.jwt.toString() ?? '');
|
sessionStorage.setItem('jwt', event.body?.jwt.toString() ?? '');
|
||||||
|
this.loggedIn = true;
|
||||||
this._router.navigateByUrl('/home');
|
this._router.navigateByUrl('/home');
|
||||||
}
|
}
|
||||||
}),
|
}),
|
|
@ -8,6 +8,7 @@
|
||||||
[(ngModel)]="username"
|
[(ngModel)]="username"
|
||||||
class="grow"
|
class="grow"
|
||||||
placeholder="login"
|
placeholder="login"
|
||||||
|
(keyup.enter)="onSubmit()"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<label class="input input-bordered flex items-center gap-2 mb-2">
|
<label class="input input-bordered flex items-center gap-2 mb-2">
|
||||||
|
@ -16,6 +17,7 @@
|
||||||
[(ngModel)]="password"
|
[(ngModel)]="password"
|
||||||
class="grow"
|
class="grow"
|
||||||
placeholder="password"
|
placeholder="password"
|
||||||
|
(keyup.enter)="onSubmit()"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Component, inject } from '@angular/core';
|
import { Component, inject } from '@angular/core';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
import { APIService } from '../api.service';
|
import { AuthService } from '../login/auth.service';
|
||||||
import { catchError, of } from 'rxjs';
|
import { catchError, of } from 'rxjs';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ import { Router } from '@angular/router';
|
||||||
styleUrl: './login.component.css',
|
styleUrl: './login.component.css',
|
||||||
})
|
})
|
||||||
export class LoginComponent {
|
export class LoginComponent {
|
||||||
apiService: APIService = inject(APIService);
|
apiService: AuthService = inject(AuthService);
|
||||||
router: Router = inject(Router);
|
router: Router = inject(Router);
|
||||||
username: string = '';
|
username: string = '';
|
||||||
password: string = '';
|
password: string = '';
|
||||||
|
|
Loading…
Reference in a new issue