Add new components, styles, and services for user management and navigation
This commit is contained in:
+38
@@ -0,0 +1,38 @@
|
||||
<p>admin-welcome.component works!</p>
|
||||
<p>admin-welcome.component works!</p>
|
||||
<p>admin-welcome.component works!</p><p>admin-welcome.component works!</p>
|
||||
<p>admin-welcome.component works!</p>
|
||||
<p>admin-welcome.component works!</p>
|
||||
<p>admin-welcome.component works!</p>
|
||||
<p>admin-welcome.component works!</p>
|
||||
<p>admin-welcome.component works!</p>
|
||||
<p>admin-welcome.component works!</p>
|
||||
<p>admin-welcome.component works!</p>
|
||||
<p>admin-welcome.component works!</p>
|
||||
<p>admin-welcome.component works!</p>
|
||||
<p>admin-welcome.component works!</p>
|
||||
<p>admin-welcome.component works!</p>
|
||||
<p>admin-welcome.component works!</p>
|
||||
<p>admin-welcome.component works!</p>
|
||||
<p>admin-welcome.component works!</p><p>admin-welcome.component works!</p>
|
||||
<p>admin-welcome.component works!</p>
|
||||
<p>admin-welcome.component works!</p>
|
||||
<p>admin-welcome.component works!</p>
|
||||
<p>admin-welcome.component works!</p>
|
||||
<p>admin-welcome.component works!</p><p>admin-welcome.component works!</p>
|
||||
<p>admin-welcome.component works!</p>
|
||||
<p>admin-welcome.component works!</p>
|
||||
<p>admin-welcome.component works!</p>
|
||||
<p>admin-welcome.component works!</p>
|
||||
<p>admin-welcome.component works!</p>
|
||||
<p>admin-welcome.component works!</p>
|
||||
<p>admin-welcome.component works!</p>
|
||||
<p>admin-welcome.component works!</p>
|
||||
<p>admin-welcome.component works!</p>
|
||||
<p>admin-welcome.component works!</p>
|
||||
<p>admin-welcome.component works!</p>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { AdminWelcomeComponent } from './admin-welcome.component';
|
||||
|
||||
describe('AdminWelcomeComponent', () => {
|
||||
let component: AdminWelcomeComponent;
|
||||
let fixture: ComponentFixture<AdminWelcomeComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [AdminWelcomeComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(AdminWelcomeComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-admin-welcome.component',
|
||||
imports: [],
|
||||
templateUrl: './admin-welcome.component.html',
|
||||
styleUrl: './admin-welcome.component.scss'
|
||||
})
|
||||
export class AdminWelcomeComponent {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<!--<p>admin.component works!</p>-->
|
||||
|
||||
<app-navigation
|
||||
class="pc-sidebar"
|
||||
[ngClass]="{
|
||||
'navbar-collapsed': navCollapsed,
|
||||
'mob-open': navCollapsedMob
|
||||
}"
|
||||
(NavCollapse)="this.navCollapsed = !this.navCollapsed"
|
||||
/>
|
||||
<app-nav-bar (NavCollapsedMob)="navMobClick()" (NavCollapse)="this.navCollapsed = !this.navCollapsed"/>
|
||||
<div class="pc-container">
|
||||
<div class="coded-wrapper">
|
||||
<div class="coded-content">
|
||||
<div class="coded-inner-content">
|
||||
<app-breadcrumb />
|
||||
<div class="main-body">
|
||||
<div class="page-wrapper">
|
||||
<router-outlet />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pc-menu-overlay" (click)="closeMenu()" (keydown)="handleKeyDown($event)" tabindex="0"></div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!--<div class="pc-container">
|
||||
<div class="coded-wrapper">
|
||||
<div class="coded-content">
|
||||
<div class="coded-inner-content">
|
||||
<app-breadcrumb />
|
||||
<div class="main-body">
|
||||
<div class="page-wrapper">
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pc-menu-overlay" (click)="closeMenu()" (keydown)="handleKeyDown($event)" tabindex="0"></div>
|
||||
</div>-->
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
.example-container {
|
||||
width: 500px;
|
||||
height: 300px;
|
||||
border: 1px solid rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.example-sidenav-content {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.example-sidenav {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.pc-sidebar{
|
||||
top: 120px;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { AdminComponent } from './admin.component';
|
||||
|
||||
describe('AdminComponent', () => {
|
||||
let component: AdminComponent;
|
||||
let fixture: ComponentFixture<AdminComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [AdminComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(AdminComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,112 @@
|
||||
import {Component, CUSTOM_ELEMENTS_SCHEMA, inject, OnInit} from '@angular/core';
|
||||
import {BreadcrumbComponent} from "../../components/breadcrumb/breadcrumb.component";
|
||||
import {NavBarComponent} from "../../layouts/admin-layout/nav-bar/nav-bar.component";
|
||||
import {NavigationComponent} from "../../layouts/admin-layout/navigation/navigation.component";
|
||||
import {Router, RouterLink, RouterOutlet} from "@angular/router";
|
||||
import {DOCUMENT, NgClass, NgStyle} from '@angular/common';
|
||||
import {MatDrawerContainer, MatSidenavModule} from '@angular/material/sidenav';
|
||||
import {MatButton} from '@angular/material/button';
|
||||
import { ScrollPanelModule } from 'primeng/scrollpanel';
|
||||
import {MenuItem} from 'primeng/api';
|
||||
import {PanelMenu} from 'primeng/panelmenu';
|
||||
@Component({
|
||||
selector: 'app-admin.component',
|
||||
imports: [
|
||||
BreadcrumbComponent,
|
||||
NavBarComponent,
|
||||
NavigationComponent,
|
||||
RouterOutlet,
|
||||
NgClass,
|
||||
MatDrawerContainer,
|
||||
MatSidenavModule,
|
||||
ScrollPanelModule,
|
||||
MatButton,
|
||||
RouterLink,
|
||||
PanelMenu,
|
||||
NgStyle,
|
||||
|
||||
],
|
||||
schemas:[CUSTOM_ELEMENTS_SCHEMA],
|
||||
templateUrl: './admin.component.html',
|
||||
styleUrl: './admin.component.scss'
|
||||
})
|
||||
export class AdminComponent implements OnInit {
|
||||
private document = inject<Document>(DOCUMENT);
|
||||
height = 0;
|
||||
|
||||
items: MenuItem[] | undefined;
|
||||
|
||||
|
||||
constructor(private router: Router) {
|
||||
this.height = 0
|
||||
|
||||
|
||||
}
|
||||
|
||||
// public props
|
||||
navCollapsed: boolean = false;
|
||||
navCollapsedMob: boolean = false;
|
||||
|
||||
// public method
|
||||
navMobClick() {
|
||||
if (this.navCollapsedMob && !document.querySelector('app-navigation.pc-sidebar')?.classList.contains('mob-open')) {
|
||||
this.navCollapsedMob = !this.navCollapsedMob;
|
||||
setTimeout(() => {
|
||||
this.navCollapsedMob = !this.navCollapsedMob;
|
||||
}, 100);
|
||||
} else {
|
||||
this.navCollapsedMob = !this.navCollapsedMob;
|
||||
}
|
||||
if (document.querySelector('app-navigation.pc-sidebar')?.classList.contains('navbar-collapsed')) {
|
||||
document.querySelector('app-navigation.pc-sidebar')?.classList.remove('navbar-collapsed');
|
||||
}
|
||||
}
|
||||
|
||||
handleKeyDown(event: KeyboardEvent): void {
|
||||
if (event.key === 'Escape') {
|
||||
this.closeMenu();
|
||||
}
|
||||
}
|
||||
|
||||
closeMenu() {
|
||||
if (document.querySelector('app-navigation.pc-sidebar')?.classList.contains('mob-open')) {
|
||||
document.querySelector('app-navigation.pc-sidebar')?.classList.remove('mob-open');
|
||||
}
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
if(this.document.defaultView !== null || this.document.defaultView !== undefined) {
|
||||
// @ts-ignore
|
||||
this.height = this.document.defaultView.innerHeight;
|
||||
}
|
||||
else
|
||||
this.height = 0;
|
||||
|
||||
this.items = [
|
||||
{
|
||||
label: 'Admin',
|
||||
icon: 'pi pi-palette',
|
||||
command: () => {
|
||||
this.router.navigate(['/main/admin/welcome']);
|
||||
},
|
||||
items: [
|
||||
{
|
||||
label: 'Settings',
|
||||
icon: 'pi pi-eraser',
|
||||
// route: '/main/admin/settings'
|
||||
command: () => {
|
||||
this.router.navigate(['/main/admin/settings']);
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'System',
|
||||
icon: 'pi pi-heart',
|
||||
route: '/main/admin/system'
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import {CUSTOM_ELEMENTS_SCHEMA, NgModule} from '@angular/core';
|
||||
import {mainRouting} from '../main-module/main.routing';
|
||||
import {MainComponent} from '../main-module/main.component/main.component';
|
||||
import {RouterModule} from '@angular/router';
|
||||
import {AdminComponent} from './admin.component/admin.component';
|
||||
import {adminRouting} from './admin.routing';
|
||||
import { ScrollPanelModule } from 'primeng/scrollpanel';
|
||||
@NgModule({
|
||||
declarations: [
|
||||
|
||||
],
|
||||
imports: [adminRouting, AdminComponent,ScrollPanelModule],
|
||||
exports: [RouterModule],
|
||||
schemas:[CUSTOM_ELEMENTS_SCHEMA]
|
||||
})
|
||||
export class AdminModule {}
|
||||
@@ -0,0 +1,27 @@
|
||||
import {RouterModule, Routes} from '@angular/router';
|
||||
import {AdminComponent} from './admin.component/admin.component';
|
||||
|
||||
const ADMIN_ROUTES: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: AdminComponent,
|
||||
|
||||
children: [
|
||||
{
|
||||
path: 'welcome',
|
||||
loadComponent: () => import('../admin-module/admin-welcome.component/admin-welcome.component').then((c) => c.AdminWelcomeComponent),
|
||||
},
|
||||
{
|
||||
path: 'settings',
|
||||
loadComponent: () => import('../admin-module/settings.component/settings.component').then((c) => c.SettingsComponent)
|
||||
},
|
||||
{
|
||||
path: 'system',
|
||||
|
||||
loadComponent: () => import('../admin-module/system.component/system.component').then((c) => c.SystemComponent)
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
export const adminRouting = RouterModule.forChild(ADMIN_ROUTES);
|
||||
@@ -0,0 +1 @@
|
||||
<p>settings.component works!</p>
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { SettingsComponent } from './settings.component';
|
||||
|
||||
describe('SettingsComponent', () => {
|
||||
let component: SettingsComponent;
|
||||
let fixture: ComponentFixture<SettingsComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [SettingsComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(SettingsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-settings.component',
|
||||
imports: [],
|
||||
templateUrl: './settings.component.html',
|
||||
styleUrl: './settings.component.scss'
|
||||
})
|
||||
export class SettingsComponent {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
|
||||
<mat-card>
|
||||
<mat-card-content>
|
||||
<mat-divider></mat-divider>
|
||||
<mat-tab-group>
|
||||
<mat-tab label="Custom beans">
|
||||
Content 1
|
||||
<table mat-table
|
||||
[dataSource]="customBeans" multiTemplateDataRows="true" class="mat-elevation-z8">
|
||||
@for (column of displayedColumns; track column) {
|
||||
<ng-container matColumnDef="{{column}}">
|
||||
<th mat-header-cell *matHeaderCellDef>{{column}}</th>
|
||||
<td mat-cell *matCellDef="let element ; let k = dataIndex;">{{element[column]}}</td>
|
||||
</ng-container>
|
||||
}
|
||||
<ng-container matColumnDef="expand">
|
||||
<th mat-header-cell *matHeaderCellDef aria-label="row actions"> </th>
|
||||
<td mat-cell *matCellDef="let element">
|
||||
<button
|
||||
matIconButton
|
||||
aria-label="expand row"
|
||||
(click)="toggle(element); $event.stopPropagation()"
|
||||
class="example-toggle-button"
|
||||
[class.example-toggle-button-expanded]="isExpanded(element)">
|
||||
<mat-icon>keyboard_arrow_down</mat-icon>
|
||||
</button>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Expanded Content Column - The detail row is made up of this one column that spans across all columns -->
|
||||
<ng-container matColumnDef="expandedDetail">
|
||||
<td mat-cell *matCellDef="let element" [attr.colspan]="columnsToDisplayWithExpand.length">
|
||||
<div class="example-element-detail-wrapper"
|
||||
[class.example-element-detail-wrapper-expanded]="isExpanded(element)">
|
||||
<div class="example-element-detail">
|
||||
|
||||
<mat-list role="list">
|
||||
<mat-list-item role="listitem">Name: {{element.name}}</mat-list-item>
|
||||
<mat-list-item role="listitem">Type: {{element.type}}</mat-list-item>
|
||||
</mat-list>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="columnsToDisplayWithExpand"></tr>
|
||||
<tr mat-row *matRowDef="let element; columns: columnsToDisplayWithExpand;"
|
||||
class="example-element-row"
|
||||
[class.example-expanded-row]="isExpanded(element)"
|
||||
(click)="toggle(element)">
|
||||
</tr>
|
||||
<tr mat-row *matRowDef="let row; columns: ['expandedDetail']" class="example-detail-row"></tr>
|
||||
</table>
|
||||
|
||||
</mat-tab>
|
||||
<mat-tab label="All beans">
|
||||
Content 2
|
||||
<table mat-table
|
||||
[dataSource]="allBeans" multiTemplateDataRows="true" class="mat-elevation-z8">
|
||||
@for (column of displayedColumns; track column) {
|
||||
<ng-container matColumnDef="{{column}}">
|
||||
<th mat-header-cell *matHeaderCellDef>{{column}}</th>
|
||||
<td mat-cell *matCellDef="let element ; let k = dataIndex;">{{element[column]}}</td>
|
||||
</ng-container>
|
||||
}
|
||||
<ng-container matColumnDef="expand">
|
||||
<th mat-header-cell *matHeaderCellDef aria-label="row actions"> </th>
|
||||
<td mat-cell *matCellDef="let element">
|
||||
<button
|
||||
matIconButton
|
||||
aria-label="expand row"
|
||||
(click)="toggle(element); $event.stopPropagation()"
|
||||
class="example-toggle-button"
|
||||
[class.example-toggle-button-expanded]="isExpanded(element)">
|
||||
<mat-icon>keyboard_arrow_down</mat-icon>
|
||||
</button>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Expanded Content Column - The detail row is made up of this one column that spans across all columns -->
|
||||
<ng-container matColumnDef="expandedDetail">
|
||||
<td mat-cell *matCellDef="let element" [attr.colspan]="columnsToDisplayWithExpand.length">
|
||||
<div class="example-element-detail-wrapper"
|
||||
[class.example-element-detail-wrapper-expanded]="isExpanded(element)">
|
||||
<div class="example-element-detail">
|
||||
|
||||
<mat-list role="list">
|
||||
<mat-list-item role="listitem">Name: {{element.name}}</mat-list-item>
|
||||
<mat-list-item role="listitem">Type: {{element.type}}</mat-list-item>
|
||||
</mat-list>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="columnsToDisplayWithExpand"></tr>
|
||||
<tr mat-row *matRowDef="let element; columns: columnsToDisplayWithExpand;"
|
||||
class="example-element-row"
|
||||
[class.example-expanded-row]="isExpanded(element)"
|
||||
(click)="toggle(element)">
|
||||
</tr>
|
||||
<tr mat-row *matRowDef="let row; columns: ['expandedDetail']" class="example-detail-row"></tr>
|
||||
</table>
|
||||
</mat-tab>
|
||||
</mat-tab-group>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
@@ -0,0 +1,113 @@
|
||||
mat-card{
|
||||
//margin: 20px;
|
||||
background-color: rgba(240, 248, 255, 0.7);
|
||||
backdrop-filter: blur(8px);
|
||||
}
|
||||
|
||||
mat-card-title{
|
||||
color: cyan;
|
||||
}
|
||||
|
||||
mat-card-subtitle{
|
||||
color: #009dff;
|
||||
}
|
||||
|
||||
mat-tab{
|
||||
color:black;
|
||||
}
|
||||
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
margin-top: 20px;
|
||||
color:lightgrey;
|
||||
}
|
||||
|
||||
|
||||
mat-list{
|
||||
//background-color: #1389d3;
|
||||
color:black;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
mat-list-item{
|
||||
margin: 10px 10px 10px 10px;
|
||||
background-color: #447694;
|
||||
|
||||
color: #009dff;
|
||||
}
|
||||
|
||||
tr.example-detail-row {
|
||||
height: 0;
|
||||
background: #fffdfd;
|
||||
}
|
||||
|
||||
tr.example-element-row {
|
||||
cursor: pointer;
|
||||
color: #1389d3;
|
||||
background: #fffdfd;
|
||||
}
|
||||
|
||||
tr.example-element-row:not(.example-expanded-row):hover {
|
||||
background: whitesmoke;
|
||||
}
|
||||
|
||||
tr.example-element-row:not(.example-expanded-row):active {
|
||||
background: #efefef;
|
||||
}
|
||||
|
||||
.example-element-row td {
|
||||
border-bottom-width: 0;
|
||||
}
|
||||
|
||||
.example-element-detail-wrapper {
|
||||
overflow: hidden;
|
||||
display: grid;
|
||||
grid-template-rows: 0fr;
|
||||
grid-template-columns: 100%;
|
||||
transition: grid-template-rows 225ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.example-element-detail-wrapper-expanded {
|
||||
grid-template-rows: 1fr;
|
||||
|
||||
}
|
||||
|
||||
.example-element-detail {
|
||||
display: flex;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.example-element-diagram {
|
||||
min-width: 80px;
|
||||
border: 2px solid black;
|
||||
padding: 8px;
|
||||
font-weight: lighter;
|
||||
margin: 8px 0;
|
||||
height: 104px;
|
||||
}
|
||||
|
||||
.example-element-symbol {
|
||||
font-weight: bold;
|
||||
font-size: 40px;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
.example-element-description {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.example-element-description-attribution {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.example-toggle-button {
|
||||
transition: transform 225ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.example-toggle-button-expanded {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { SystemComponent } from './system.component';
|
||||
|
||||
describe('SystemComponent', () => {
|
||||
let component: SystemComponent;
|
||||
let fixture: ComponentFixture<SystemComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [SystemComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(SystemComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,138 @@
|
||||
import {Component, CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
|
||||
import {MatCard, MatCardContent, MatCardHeader} from '@angular/material/card';
|
||||
import {MatDivider} from '@angular/material/divider';
|
||||
import {MatTab, MatTabGroup} from '@angular/material/tabs';
|
||||
import {
|
||||
MatCell,
|
||||
MatCellDef,
|
||||
MatColumnDef,
|
||||
MatHeaderCell, MatHeaderCellDef,
|
||||
MatHeaderRow, MatHeaderRowDef,
|
||||
MatRow,
|
||||
MatRowDef,
|
||||
MatTable
|
||||
} from '@angular/material/table';
|
||||
import {MatList, MatListItem} from '@angular/material/list';
|
||||
import {MatIconButton} from '@angular/material/button';
|
||||
import {SystemService} from '../../services/system.service';
|
||||
import {Bean} from '../../models/Bean';
|
||||
import {MatIcon} from '@angular/material/icon';
|
||||
|
||||
@Component({
|
||||
selector: 'app-system.component',
|
||||
imports: [
|
||||
MatCard,
|
||||
MatCardHeader,
|
||||
MatCardContent,
|
||||
MatDivider,
|
||||
MatTabGroup,
|
||||
MatTab,
|
||||
MatTable,
|
||||
MatColumnDef,
|
||||
MatIcon,
|
||||
MatCell,
|
||||
MatCellDef,
|
||||
MatList,
|
||||
MatListItem,
|
||||
MatRow,
|
||||
MatHeaderRow,
|
||||
MatRowDef,
|
||||
MatHeaderCell,
|
||||
MatHeaderCellDef,
|
||||
MatIconButton,
|
||||
MatIcon,
|
||||
MatHeaderRowDef
|
||||
],
|
||||
templateUrl: './system.component.html',
|
||||
styleUrl: './system.component.scss',
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||
})
|
||||
export class SystemComponent {
|
||||
customBeans:Bean[] = [] ;
|
||||
allBeans:Bean[] = [] ;
|
||||
displayedColumns: string[] = ['shortName', 'typeShortName', 'scope'];
|
||||
|
||||
columnsToDisplayWithExpand = [...this.displayedColumns, 'expand'];
|
||||
|
||||
expandedElement: Bean | null = null;
|
||||
|
||||
resultsLength = 0;
|
||||
isLoadingResults = true;
|
||||
isRateLimitReached = false;
|
||||
|
||||
constructor(private systemService: SystemService) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
this.retrieveBeans();
|
||||
}
|
||||
|
||||
retrieveBeans(): void {
|
||||
this.systemService.getCustomBeans()
|
||||
.subscribe(
|
||||
(data: Bean[]) => {
|
||||
this.customBeans = data;
|
||||
console.log(data);
|
||||
},
|
||||
(error: any) => {
|
||||
console.log(error);
|
||||
});
|
||||
this.systemService.getAllBeans()
|
||||
.subscribe(
|
||||
(data: Bean[]) => {
|
||||
this.allBeans = data;
|
||||
console.log(data);
|
||||
},
|
||||
(error: any) => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
/** Checks whether an element is expanded. */
|
||||
isExpanded(element: Bean) {
|
||||
return this.expandedElement === element;
|
||||
}
|
||||
|
||||
/** Toggles the expanded state of an element. */
|
||||
toggle(element: Bean) {
|
||||
this.expandedElement = this.isExpanded(element) ? null : element;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//ngAfterViewInit() {
|
||||
//this.exampleDatabase = new ExampleHttpDatabase(this._httpClient);
|
||||
|
||||
// If the user changes the sort order, reset back to the first page.
|
||||
/* this.sort.sortChange.subscribe(() => (this.paginator.pageIndex = 0));
|
||||
|
||||
merge(this.sort.sortChange, this.paginator.page)
|
||||
.pipe(
|
||||
startWith({}),
|
||||
switchMap(() => {
|
||||
this.isLoadingResults = true;
|
||||
return this.exampleDatabase!.getRepoIssues(
|
||||
this.sort.active,
|
||||
this.sort.direction,
|
||||
this.paginator.pageIndex,
|
||||
).pipe(catchError(() => observableOf(null)));
|
||||
}),
|
||||
map(data => {
|
||||
// Flip flag to show that loading has finished.
|
||||
this.isLoadingResults = false;
|
||||
this.isRateLimitReached = data === null;
|
||||
|
||||
if (data === null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Only refresh the result length if there is new data. In case of rate
|
||||
// limit errors, we do not want to reset the paginator to zero, as that
|
||||
// would prevent users from re-triggering requests.
|
||||
this.resultsLength = data.total_count;
|
||||
return data.items;
|
||||
}),
|
||||
)
|
||||
.subscribe(data => (this.data = data));*/
|
||||
}
|
||||
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { TutorialsListComponent } from './components/tutorials-list/tutorials-list.component';
|
||||
import { TutorialDetailsComponent } from './components/tutorial-details/tutorial-details.component';
|
||||
import { AddTutorialComponent } from './components/add-tutorial/add-tutorial.component';
|
||||
import { BoardAdminComponent } from './components/board-admin/board-admin.component';
|
||||
import { BoardModeratorComponent } from './components/board-moderator/board-moderator.component';
|
||||
import { BoardUserComponent } from './components/board-user/board-user.component';
|
||||
import { ProfileComponent } from './components/profile/profile.component';
|
||||
import { RegisterComponent } from './components/register/register.component';
|
||||
import { LoginComponent } from './components/login/login.component';
|
||||
import { HomeComponent } from './components/home/home.component';
|
||||
import {SystemComponent} from './components/system.component/system.component';
|
||||
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: 'home', component: HomeComponent },
|
||||
{ path: 'login', component: LoginComponent },
|
||||
{ path: 'register', component: RegisterComponent },
|
||||
{ path: 'profile', component: ProfileComponent },
|
||||
{ path: 'user', component: BoardUserComponent },
|
||||
{ path: 'mod', component: BoardModeratorComponent },
|
||||
{ path: 'admin', component: BoardAdminComponent },
|
||||
{ path: '', redirectTo: 'home', pathMatch: 'full' },
|
||||
{ path: 'tutorials', component: TutorialsListComponent },
|
||||
{ path: 'tutorials/:id', component: TutorialDetailsComponent },
|
||||
{ path: 'add', component: AddTutorialComponent },
|
||||
{ path: 'system', component: SystemComponent}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forRoot(routes, {useHash: true})],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class AppRoutingModule { }
|
||||
@@ -1,16 +1,27 @@
|
||||
import {Component, inject, OnInit} from '@angular/core';
|
||||
import {Component, CUSTOM_ELEMENTS_SCHEMA, inject, OnInit} from '@angular/core';
|
||||
import { TokenStorageService } from './services/token-storage.service';
|
||||
import {MatDialog} from "@angular/material/dialog";
|
||||
import {DialogComponent} from "./components/dialog/dialog.component";
|
||||
import {AuthService} from "./services/auth.service";
|
||||
import {Subscription} from "rxjs";
|
||||
import {EventBusService} from "./_shared/event-bus.service";
|
||||
import {RouterLink, RouterOutlet} from '@angular/router';
|
||||
import {MatButton} from '@angular/material/button';
|
||||
import {MatToolbar} from '@angular/material/toolbar';
|
||||
import {MatIcon} from '@angular/material/icon';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.scss'],
|
||||
standalone: false
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
imports: [
|
||||
RouterOutlet,
|
||||
MatIcon,
|
||||
MatButton,
|
||||
RouterLink,
|
||||
MatToolbar
|
||||
],
|
||||
styleUrls: ['./app.component.scss']
|
||||
})
|
||||
export class AppComponent implements OnInit {
|
||||
readonly dialog = inject(MatDialog);
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import { mergeApplicationConfig, ApplicationConfig } from '@angular/core';
|
||||
import { provideServerRendering, withRoutes } from '@angular/ssr';
|
||||
import { appConfig } from './app.config';
|
||||
import { serverRoutes } from './app.routes.server';
|
||||
|
||||
const serverConfig: ApplicationConfig = {
|
||||
providers: [
|
||||
provideServerRendering(withRoutes(serverRoutes))
|
||||
]
|
||||
};
|
||||
|
||||
export const config = mergeApplicationConfig(appConfig, serverConfig);
|
||||
@@ -0,0 +1,28 @@
|
||||
import {
|
||||
ApplicationConfig,
|
||||
importProvidersFrom,
|
||||
provideBrowserGlobalErrorListeners,
|
||||
provideZoneChangeDetection
|
||||
} from '@angular/core';
|
||||
import { provideRouter } from '@angular/router';
|
||||
|
||||
import { routes } from './app.routes';
|
||||
import { provideClientHydration, withEventReplay } from '@angular/platform-browser';
|
||||
import {AppModule} from './app.module';
|
||||
import {providePrimeNG} from 'primeng/config';
|
||||
import Aura from '@primeng/themes/aura';
|
||||
|
||||
export const appConfig: ApplicationConfig = {
|
||||
providers: [
|
||||
provideBrowserGlobalErrorListeners(),
|
||||
provideZoneChangeDetection({ eventCoalescing: true }),
|
||||
provideRouter(routes), provideClientHydration(withEventReplay()),
|
||||
|
||||
importProvidersFrom(AppModule),
|
||||
providePrimeNG({
|
||||
theme: {
|
||||
preset: Aura
|
||||
}
|
||||
})
|
||||
]
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
<router-outlet></router-outlet>
|
||||
@@ -1,118 +1,40 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
|
||||
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
import { TutorialsListComponent } from './components/tutorials-list/tutorials-list.component';
|
||||
import { TutorialDetailsComponent } from './components/tutorial-details/tutorial-details.component';
|
||||
import { AddTutorialComponent } from './components/add-tutorial/add-tutorial.component';
|
||||
import { LoginComponent } from './components/login/login.component';
|
||||
import { RegisterComponent } from './components/register/register.component';
|
||||
import { HomeComponent } from './components/home/home.component';
|
||||
import { ProfileComponent } from './components/profile/profile.component';
|
||||
import { BoardAdminComponent } from './components/board-admin/board-admin.component';
|
||||
import { BoardModeratorComponent } from './components/board-moderator/board-moderator.component';
|
||||
import { BoardUserComponent } from './components/board-user/board-user.component';
|
||||
|
||||
import { authInterceptorProviders } from './helpers/auth.interceptor';
|
||||
import {provideHttpClient, withInterceptorsFromDi} from "@angular/common/http";
|
||||
import {provideAnimationsAsync} from "@angular/platform-browser/animations/async";
|
||||
import {MatToolbar} from "@angular/material/toolbar";
|
||||
import {MatAnchor, MatButton} from "@angular/material/button";
|
||||
import {MatIcon} from "@angular/material/icon";
|
||||
import {MatChipGrid, MatChipInput, MatChipListbox, MatChipOption, MatChipRow} from "@angular/material/chips";
|
||||
import {MatAutocomplete, MatAutocompleteTrigger, MatOption} from "@angular/material/autocomplete";
|
||||
import {MatFormField} from "@angular/material/form-field";
|
||||
import {MatLabel} from '@angular/material/form-field';
|
||||
|
||||
|
||||
import {
|
||||
MatCard, MatCardActions,
|
||||
MatCardContent,
|
||||
MatCardHeader,
|
||||
MatCardImage,
|
||||
MatCardSubtitle,
|
||||
MatCardTitle
|
||||
} from '@angular/material/card';
|
||||
import {MatInput} from '@angular/material/input';
|
||||
import {EditorComponent} from '@progress/kendo-angular-editor';
|
||||
import {ArticleComments} from './components/article-comments/article-comments';
|
||||
import {MatProgressSpinner} from '@angular/material/progress-spinner';
|
||||
import {providePrimeNG} from 'primeng/config';
|
||||
import Aura from '@primeng/themes/aura';
|
||||
import {Button} from 'primeng/button';
|
||||
import {ScrollPanelModule} from 'primeng/scrollpanel';
|
||||
import {Splitter} from 'primeng/splitter';
|
||||
|
||||
import {CUSTOM_ELEMENTS_SCHEMA, NgModule} from '@angular/core';
|
||||
import { BrowserModule }
|
||||
from '@angular/platform-browser';
|
||||
|
||||
import { BrowserAnimationsModule }
|
||||
from '@angular/platform-browser/animations';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import {provideHttpClient, withInterceptorsFromDi} from '@angular/common/http';
|
||||
|
||||
import {MainComponent} from './main-module/main.component/main.component';
|
||||
import {authInterceptorProviders} from './helpers/auth.interceptor';
|
||||
import {AdminComponent} from './admin-module/admin.component/admin.component';
|
||||
import {AdminWelcomeComponent} from './admin-module/admin-welcome.component/admin-welcome.component';
|
||||
import {SettingsComponent} from './admin-module/settings.component/settings.component';
|
||||
import {SystemComponent} from './admin-module/system.component/system.component';
|
||||
import {appRouting} from './app.routes';
|
||||
import {App} from './app';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent,
|
||||
TutorialsListComponent,
|
||||
TutorialDetailsComponent,
|
||||
AddTutorialComponent,
|
||||
|
||||
RegisterComponent,
|
||||
HomeComponent,
|
||||
ProfileComponent,
|
||||
BoardAdminComponent,
|
||||
BoardModeratorComponent,
|
||||
BoardUserComponent
|
||||
|
||||
],
|
||||
bootstrap: [AppComponent],
|
||||
imports: [
|
||||
appRouting,
|
||||
MainComponent,
|
||||
BrowserModule,
|
||||
AppRoutingModule,
|
||||
FormsModule,
|
||||
LoginComponent,
|
||||
MatToolbar,
|
||||
MatButton,
|
||||
MatIcon,
|
||||
MatAnchor,
|
||||
MatChipGrid,
|
||||
MatChipRow,
|
||||
MatChipInput,
|
||||
MatAutocompleteTrigger,
|
||||
MatAutocomplete,
|
||||
MatOption,
|
||||
MatFormField,
|
||||
MatChipListbox,
|
||||
MatChipOption,
|
||||
ReactiveFormsModule,
|
||||
MatCardContent,
|
||||
MatCardSubtitle,
|
||||
MatCardTitle,
|
||||
MatCard,
|
||||
MatCardHeader,
|
||||
MatCardImage,
|
||||
MatCardActions,
|
||||
MatInput,
|
||||
MatLabel,
|
||||
EditorComponent,
|
||||
ArticleComments,
|
||||
MatProgressSpinner,
|
||||
Button,
|
||||
ScrollPanelModule,
|
||||
Splitter
|
||||
|
||||
MatIconModule,
|
||||
BrowserAnimationsModule,
|
||||
AdminComponent,
|
||||
AdminWelcomeComponent,
|
||||
SettingsComponent,
|
||||
SystemComponent
|
||||
],
|
||||
providers: [
|
||||
authInterceptorProviders,
|
||||
provideHttpClient(withInterceptorsFromDi()),
|
||||
provideAnimationsAsync(),
|
||||
providePrimeNG({
|
||||
theme: {
|
||||
preset: Aura,
|
||||
options: {darkModeSelector: '.p-dark'}
|
||||
}
|
||||
})
|
||||
] })
|
||||
|
||||
authInterceptorProviders,provideHttpClient(withInterceptorsFromDi())],
|
||||
|
||||
bootstrap: [],
|
||||
schemas: [ CUSTOM_ELEMENTS_SCHEMA ]
|
||||
})
|
||||
export class AppModule { }
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import { RenderMode, ServerRoute } from '@angular/ssr';
|
||||
|
||||
export const serverRoutes: ServerRoute[] = [
|
||||
{
|
||||
path: '**',
|
||||
renderMode: RenderMode.Prerender
|
||||
}
|
||||
];
|
||||
@@ -0,0 +1,20 @@
|
||||
import {RouterModule, Routes} from '@angular/router';
|
||||
import {AdminComponent} from './layouts/admin-layout/admin-layout.component';
|
||||
import {MainComponent} from './main-module/main.component/main.component';
|
||||
import {NgModule} from '@angular/core';
|
||||
|
||||
export const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
redirectTo: 'main/home',
|
||||
pathMatch: 'full'
|
||||
},
|
||||
{
|
||||
path: 'main',
|
||||
loadChildren: () =>
|
||||
import('./main-module/main.module').then((m) => m.MainModule),
|
||||
}
|
||||
|
||||
];
|
||||
export const appRouting = RouterModule.forRoot(routes);
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { App } from './app';
|
||||
|
||||
describe('App', () => {
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [App],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
it('should create the app', () => {
|
||||
const fixture = TestBed.createComponent(App);
|
||||
const app = fixture.componentInstance;
|
||||
expect(app).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should render title', () => {
|
||||
const fixture = TestBed.createComponent(App);
|
||||
fixture.detectChanges();
|
||||
const compiled = fixture.nativeElement as HTMLElement;
|
||||
expect(compiled.querySelector('h1')?.textContent).toContain('Hello, jambotron-ui');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { RouterOutlet } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.html',
|
||||
imports: [
|
||||
RouterOutlet
|
||||
],
|
||||
styleUrl: './app.scss'
|
||||
})
|
||||
export class App {
|
||||
protected title = 'jambotron-ui';
|
||||
|
||||
constructor() { }
|
||||
}
|
||||
@@ -44,7 +44,8 @@
|
||||
<input matInput required
|
||||
[(ngModel)]="tutorial.title">
|
||||
</mat-form-field>
|
||||
<kendo-editor [(ngModel)]="tutorial.description" ></kendo-editor>
|
||||
<!-- <kendo-editor [(ngModel)]="tutorial.description" ></kendo-editor>-->
|
||||
<textarea matInput required [(ngModel)]="tutorial.description"></textarea>
|
||||
</mat-card-content>
|
||||
<mat-card-actions>
|
||||
<button matButton (click)="saveTutorial()" *ngIf="!submitted">Save</button>
|
||||
|
||||
@@ -1,12 +1,32 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import {Component, CUSTOM_ELEMENTS_SCHEMA, OnInit} from '@angular/core';
|
||||
import {Tutorial} from '../../models/tutorial.model';
|
||||
import {TutorialService} from '../../services/tutorial.service';
|
||||
import {MatCard, MatCardActions, MatCardContent, MatCardHeader} from '@angular/material/card';
|
||||
import {FormsModule} from '@angular/forms';
|
||||
import {MatButton} from '@angular/material/button';
|
||||
import {MatFormField, MatInput, MatLabel} from '@angular/material/input';
|
||||
import {NgIf} from '@angular/common';
|
||||
|
||||
@Component({
|
||||
selector: 'app-add-tutorial',
|
||||
templateUrl: './add-tutorial.component.html',
|
||||
styleUrls: ['./add-tutorial.component.scss'],
|
||||
standalone: false
|
||||
imports: [
|
||||
MatCardActions,
|
||||
FormsModule,
|
||||
MatCard,
|
||||
MatCardHeader,
|
||||
MatCardContent,
|
||||
MatFormField,
|
||||
MatLabel,
|
||||
|
||||
MatButton,
|
||||
MatInput,
|
||||
NgIf,
|
||||
MatLabel,
|
||||
|
||||
],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||
})
|
||||
export class AddTutorialComponent implements OnInit {
|
||||
|
||||
|
||||
@@ -1,25 +1,45 @@
|
||||
import {Component, computed, model, OnInit} from '@angular/core';
|
||||
import {Component, computed, CUSTOM_ELEMENTS_SCHEMA, model, OnInit} from '@angular/core';
|
||||
|
||||
import {User} from "../../models/user.model";
|
||||
import {MatChipInputEvent} from "@angular/material/chips";
|
||||
import {MatAutocompleteSelectedEvent} from "@angular/material/autocomplete";
|
||||
import {MatChipGrid, MatChipInput, MatChipInputEvent, MatChipRow} from "@angular/material/chips";
|
||||
import {
|
||||
MatAutocomplete,
|
||||
MatAutocompleteSelectedEvent,
|
||||
MatAutocompleteTrigger,
|
||||
MatOption
|
||||
} from "@angular/material/autocomplete";
|
||||
import {COMMA, ENTER} from "@angular/cdk/keycodes";
|
||||
import {AsyncPipe} from "@angular/common";
|
||||
import {FormControl} from "@angular/forms";
|
||||
import {AsyncPipe, NgForOf} from "@angular/common";
|
||||
import {FormControl, ReactiveFormsModule} from "@angular/forms";
|
||||
import {Observable, startWith} from "rxjs";
|
||||
import {map} from "rxjs/operators";
|
||||
import {UserService} from '../../services/user.service';
|
||||
import {RolesService} from '../../services/roles.service';
|
||||
import {Role} from '../../models/role';
|
||||
import {MatIcon} from '@angular/material/icon';
|
||||
import {MatFormField} from '@angular/material/form-field';
|
||||
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-board-admin',
|
||||
templateUrl: './board-admin.component.html',
|
||||
styleUrls: ['./board-admin.component.scss'],
|
||||
standalone: false,
|
||||
selector: 'app-board-admin',
|
||||
templateUrl: './board-admin.component.html',
|
||||
styleUrls: ['./board-admin.component.scss'],
|
||||
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
imports: [
|
||||
MatAutocomplete,
|
||||
ReactiveFormsModule,
|
||||
MatOption,
|
||||
NgForOf,
|
||||
MatFormField,
|
||||
MatChipGrid,
|
||||
|
||||
MatChipRow,
|
||||
MatIcon,
|
||||
MatChipInput,
|
||||
MatAutocompleteTrigger
|
||||
]
|
||||
})
|
||||
export class BoardAdminComponent implements OnInit {
|
||||
private gridApi: any;
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
<div class="card" [ngClass]="cardClass()">
|
||||
@if (showHeader()) {
|
||||
<div class="card-header d-flex align-items-center justify-content-between" [ngClass]="headerClass()">
|
||||
<div>
|
||||
<h5>{{ cardTitle() }}</h5>
|
||||
<ng-container *ngTemplateOutlet="headerTitleTemplate"></ng-container>
|
||||
</div>
|
||||
<ng-container *ngTemplateOutlet="headerOptionsTemplate"></ng-container>
|
||||
</div>
|
||||
}
|
||||
@if (showContent()) {
|
||||
<div class="card-body" [ngClass]="blockClass()" [style.padding.px]="padding()">
|
||||
<ng-content></ng-content>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
@@ -0,0 +1,58 @@
|
||||
// Angular import
|
||||
import { Component, ContentChild, ElementRef, TemplateRef, input } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
selector: 'app-card',
|
||||
standalone: true,
|
||||
imports: [CommonModule],
|
||||
templateUrl: './card.component.html',
|
||||
styleUrls: ['./card.component.scss']
|
||||
})
|
||||
export class CardComponent {
|
||||
// public props
|
||||
/**
|
||||
* Title of card. It will be visible at left side of card header
|
||||
*/
|
||||
cardTitle = input<string>();
|
||||
|
||||
/**
|
||||
* Class to be applied at card level
|
||||
*/
|
||||
cardClass = input<string>();
|
||||
|
||||
/**
|
||||
* To hide content from card
|
||||
*/
|
||||
showContent = input(true);
|
||||
|
||||
/**
|
||||
* Class to be applied at card content.
|
||||
*/
|
||||
blockClass = input<string>();
|
||||
|
||||
/**
|
||||
* Class to be applied on card header
|
||||
*/
|
||||
headerClass = input<string>();
|
||||
|
||||
/**
|
||||
* To hide header from card
|
||||
*/
|
||||
showHeader = input(true);
|
||||
|
||||
/**
|
||||
* padding around card content. default in px
|
||||
*/
|
||||
padding = input(20); // set default to 24 px
|
||||
|
||||
/**
|
||||
* Template reference of header actions on custom header
|
||||
*/
|
||||
@ContentChild('headerOptionsTemplate') headerOptionsTemplate!: TemplateRef<ElementRef>;
|
||||
|
||||
/**
|
||||
* Template reference of header actions besides title at left
|
||||
*/
|
||||
@ContentChild('headerTitleTemplate') headerTitleTemplate!: TemplateRef<ElementRef>;
|
||||
}
|
||||
@@ -14,7 +14,8 @@ import {MatFormField, MatLabel, MatSuffix} from "@angular/material/form-field";
|
||||
import {MatInput} from "@angular/material/input";
|
||||
import {FormsModule} from "@angular/forms";
|
||||
import {MatIcon} from "@angular/material/icon";
|
||||
import {DialogData} from "../../app.component";
|
||||
import {DialogData} from '../../main-module/main.component/main.component';
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
<p>home.component works!</p>
|
||||
+1
-3
@@ -8,12 +8,10 @@ describe('HomeComponent', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ HomeComponent ]
|
||||
imports: [HomeComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(HomeComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
@@ -0,0 +1,11 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-home.component',
|
||||
imports: [],
|
||||
templateUrl: './home.component.html',
|
||||
styleUrl: './home.component.scss'
|
||||
})
|
||||
export class HomeComponent {
|
||||
|
||||
}
|
||||
@@ -1,145 +0,0 @@
|
||||
<p-splitter [style]="{ height: '300px' }" styleClass="mb-8" layout="vertical">
|
||||
<ng-template #panel>
|
||||
<div class="flex items-center justify-center h-full">Panel 1</div>
|
||||
</ng-template>
|
||||
<ng-template #panel>
|
||||
<div class="flex items-center justify-center h-full">Panel 2</div>
|
||||
<p-scrollPanel [style]="{ width: '100%', height: '150px' }">
|
||||
|
||||
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet...
|
||||
</p>
|
||||
<p>
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium...
|
||||
</p>
|
||||
<p class="m-0">
|
||||
At vero eos et accusamus et iusto odio dignissimos...
|
||||
dfsd
|
||||
f
|
||||
sdf
|
||||
|
||||
dsf
|
||||
sd
|
||||
f
|
||||
sd
|
||||
fs
|
||||
fs
|
||||
fsfs
|
||||
fs
|
||||
fs
|
||||
fs
|
||||
fs
|
||||
fs
|
||||
</p>
|
||||
<app-article-comments />
|
||||
</p-scrollPanel>
|
||||
|
||||
|
||||
</ng-template>
|
||||
</p-splitter>
|
||||
|
||||
<p-scrollPanel [style]="{ width: '100%', height: '150px' }">
|
||||
|
||||
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet...
|
||||
</p>
|
||||
<p>
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium...
|
||||
</p>
|
||||
<p class="m-0">
|
||||
At vero eos et accusamus et iusto odio dignissimos...
|
||||
dfsd
|
||||
f
|
||||
sdf
|
||||
|
||||
dsf
|
||||
sd
|
||||
f
|
||||
sd
|
||||
fs
|
||||
fs
|
||||
fsfs
|
||||
fs
|
||||
fs
|
||||
fs
|
||||
fs
|
||||
fs
|
||||
</p>
|
||||
<app-article-comments />
|
||||
</p-scrollPanel>
|
||||
|
||||
|
||||
|
||||
|
||||
<!--
|
||||
@defer (on viewport(container); prefetch on idle) {
|
||||
<app-article-comments></app-article-comments>
|
||||
} @loading {
|
||||
<mat-progress-spinner></mat-progress-spinner>
|
||||
|
||||
loading
|
||||
} @placeholder {
|
||||
<div class="skeleton-loader"></div>
|
||||
|
||||
<app-article-comments></app-article-comments>
|
||||
placeholder
|
||||
} @error {
|
||||
Error
|
||||
}
|
||||
|
||||
|
||||
<div #container>
|
||||
<h1>How I feel about Angular</h1>
|
||||
<article>
|
||||
<p>
|
||||
Angular is my favorite framework, and
|
||||
this is why. Angular has the coolest
|
||||
deferrable view feature that makes defer
|
||||
loading content the easiest and most
|
||||
ergonomic it could possibly be.
|
||||
</p>
|
||||
</article>
|
||||
|
||||
@defer {
|
||||
<app-article-comments />
|
||||
} @placeholder (minimum 1s) {
|
||||
<p>Placeholder for comments</p>
|
||||
} @loading (minimum 1s; after 500ms) {
|
||||
<p>Loading comments...</p>
|
||||
} @error {
|
||||
<p>Failed to load comments</p>
|
||||
}
|
||||
|
||||
</div>
|
||||
|
||||
<ng-container [ngComponentOutlet]="profileComponent()" />
|
||||
-->
|
||||
|
||||
<mat-card #showComments appearance="outlined" >
|
||||
<mat-card-header>
|
||||
<mat-card-title>Tutorials</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
|
||||
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
|
||||
@defer (on hover; on interaction(showComments)) {
|
||||
<app-article-comments />
|
||||
} @placeholder ( ;minimum 1s) {
|
||||
<p>Placeholder for comments</p>
|
||||
} @loading (minimum 1s; after 500ms) {
|
||||
<p>Loading comments...</p>
|
||||
} @error {
|
||||
<p>Failed to load comments</p>
|
||||
}
|
||||
|
||||
@for (tutorial of tutorials; track $index){
|
||||
<mat-card appearance="outlined" class="tutorial-card">
|
||||
<mat-card-content [innerHTML]="tutorial.description">
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
mat-card{
|
||||
margin: 20px;
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
mat-card-title{
|
||||
color: cyan;
|
||||
}
|
||||
.tutorial-card{
|
||||
color: white;
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
import {Component, computed, OnInit} from '@angular/core';
|
||||
import {TutorialService} from '../../services/tutorial.service';
|
||||
|
||||
import {Tutorial} from '../../models/tutorial.model';
|
||||
import {ArticleComments} from '../article-comments/article-comments';
|
||||
import {AddTutorialComponent} from '../add-tutorial/add-tutorial.component';
|
||||
import { ScrollPanelModule } from 'primeng/scrollpanel';
|
||||
|
||||
@Component({
|
||||
selector: 'app-home',
|
||||
templateUrl: './home.component.html',
|
||||
styleUrls: ['./home.component.scss'],
|
||||
standalone: false
|
||||
})
|
||||
export class HomeComponent implements OnInit {
|
||||
content?: string;
|
||||
|
||||
tutorials?: Tutorial[];
|
||||
|
||||
constructor(private tutorialService: TutorialService) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
this.retrieveTutorials();
|
||||
}
|
||||
retrieveTutorials(): void {
|
||||
this.tutorialService.getAll()
|
||||
.subscribe(
|
||||
data => {
|
||||
this.tutorials = data;
|
||||
console.log(data);
|
||||
},
|
||||
error => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
profileComponent = computed(() => AddTutorialComponent);
|
||||
}
|
||||
@@ -1,12 +1,16 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import {TokenStorageService} from '../../services/token-storage.service';
|
||||
import {NgForOf, NgIf} from '@angular/common';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-profile',
|
||||
templateUrl: './profile.component.html',
|
||||
styleUrls: ['./profile.component.scss'],
|
||||
standalone: false
|
||||
selector: 'app-profile',
|
||||
templateUrl: './profile.component.html',
|
||||
imports: [
|
||||
NgForOf,
|
||||
NgIf
|
||||
],
|
||||
styleUrls: ['./profile.component.scss']
|
||||
})
|
||||
export class ProfileComponent implements OnInit {
|
||||
currentUser: any;
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import {AuthService} from '../../services/auth.service';
|
||||
import {FormsModule} from '@angular/forms';
|
||||
import {NgIf} from '@angular/common';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-register',
|
||||
templateUrl: './register.component.html',
|
||||
styleUrls: ['./register.component.scss'],
|
||||
standalone: false
|
||||
selector: 'app-register',
|
||||
templateUrl: './register.component.html',
|
||||
imports: [
|
||||
FormsModule,
|
||||
NgIf
|
||||
],
|
||||
styleUrls: ['./register.component.scss']
|
||||
})
|
||||
export class RegisterComponent implements OnInit {
|
||||
form: any = {
|
||||
|
||||
@@ -3,13 +3,18 @@ import { Component, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import {Tutorial} from '../../models/tutorial.model';
|
||||
import {TutorialService} from '../../services/tutorial.service';
|
||||
import {FormsModule} from '@angular/forms';
|
||||
import {NgIf} from '@angular/common';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-tutorial-details',
|
||||
templateUrl: './tutorial-details.component.html',
|
||||
styleUrls: ['./tutorial-details.component.scss'],
|
||||
standalone: false
|
||||
selector: 'app-tutorial-details',
|
||||
templateUrl: './tutorial-details.component.html',
|
||||
imports: [
|
||||
FormsModule,
|
||||
NgIf
|
||||
],
|
||||
styleUrls: ['./tutorial-details.component.scss']
|
||||
})
|
||||
export class TutorialDetailsComponent implements OnInit {
|
||||
|
||||
|
||||
@@ -3,12 +3,19 @@ import { Component, OnInit } from '@angular/core';
|
||||
|
||||
import {Tutorial} from '../../models/tutorial.model';
|
||||
import {TutorialService} from '../../services/tutorial.service';
|
||||
import {FormsModule} from '@angular/forms';
|
||||
import {RouterLink} from '@angular/router';
|
||||
import {NgIf} from '@angular/common';
|
||||
|
||||
@Component({
|
||||
selector: 'app-tutorials-list',
|
||||
templateUrl: './tutorials-list.component.html',
|
||||
styleUrls: ['./tutorials-list.component.scss'],
|
||||
standalone: false
|
||||
selector: 'app-tutorials-list',
|
||||
templateUrl: './tutorials-list.component.html',
|
||||
imports: [
|
||||
FormsModule,
|
||||
RouterLink,
|
||||
NgIf
|
||||
],
|
||||
styleUrls: ['./tutorials-list.component.scss']
|
||||
})
|
||||
export class TutorialsListComponent implements OnInit {
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
@for (tutorial of tutorials; track $index){
|
||||
<mat-card appearance="outlined" class="tutorial-card">
|
||||
<mat-card-header>
|
||||
<mat-card-title>{{tutorial.title}}</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content [innerHTML]="tutorial.description">
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { TutorialsComponent } from './tutorials.component';
|
||||
|
||||
describe('TutorialsComponent', () => {
|
||||
let component: TutorialsComponent;
|
||||
let fixture: ComponentFixture<TutorialsComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [TutorialsComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(TutorialsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,39 @@
|
||||
import {Component, CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
|
||||
import {Tutorial} from '../../models/tutorial.model';
|
||||
import {TutorialService} from '../../services/tutorial.service';
|
||||
import {MatCard, MatCardContent, MatCardHeader} from '@angular/material/card';
|
||||
|
||||
@Component({
|
||||
selector: 'app-tutorials.component',
|
||||
imports: [
|
||||
MatCard,
|
||||
MatCardContent,
|
||||
MatCardHeader
|
||||
],
|
||||
templateUrl: './tutorials.component.html',
|
||||
styleUrl: './tutorials.component.scss',
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||
})
|
||||
export class TutorialsComponent {
|
||||
tutorials?: Tutorial[];
|
||||
|
||||
constructor(private tutorialService: TutorialService) {
|
||||
this.retrieveTutorials();
|
||||
}
|
||||
|
||||
// ngOnInit(): void {
|
||||
// this.retrieveTutorials();
|
||||
// }
|
||||
|
||||
retrieveTutorials(): void {
|
||||
this.tutorialService.getAll()
|
||||
.subscribe(
|
||||
data => {
|
||||
this.tutorials = data;
|
||||
console.log(data);
|
||||
},
|
||||
error => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<!--<p>main.component works!</p>-->
|
||||
|
||||
<mat-toolbar class="fixed-top">
|
||||
<button mat-raised-button routerLink="/" href="#">
|
||||
My App
|
||||
</button>
|
||||
<span class="menu-spacer"></span>
|
||||
<button mat-raised-button routerLink="tutorials">
|
||||
Tutorials
|
||||
</button>
|
||||
@if (isLoggedIn) {
|
||||
<button mat-raised-button routerLink="add-tutorial" >
|
||||
Add tutorial
|
||||
</button>
|
||||
}
|
||||
<span class="menu-spacer"></span>
|
||||
@if (showAdminBoard) {
|
||||
<button mat-raised-button routerLink="admin/welcome">
|
||||
<mat-icon>manage_accounts</mat-icon>
|
||||
Admin Bord
|
||||
</button>
|
||||
}
|
||||
|
||||
@if (showAdminBoard) {
|
||||
<button mat-raised-button routerLink="system" >
|
||||
<mat-icon>settings_applications</mat-icon>
|
||||
System
|
||||
</button>
|
||||
}
|
||||
|
||||
<span class="menu-spacer"></span>
|
||||
@if (isLoggedIn) {
|
||||
<button mat-raised-button routerLink="register">
|
||||
<mat-icon>app_registration</mat-icon>
|
||||
Register
|
||||
</button>
|
||||
}
|
||||
@if (!isLoggedIn) {
|
||||
<button mat-raised-button (click)="openDialog('100ms', '5ms')" >
|
||||
<!-- <i antIcon type="bell" theme="outline"></i>-->
|
||||
<!-- <mat-icon>login</mat-icon>-->
|
||||
Login
|
||||
</button>
|
||||
}
|
||||
@if (isLoggedIn) {
|
||||
<button mat-raised-button routerLink="profile" >
|
||||
<mat-icon>account_circle</mat-icon>
|
||||
{{ username }}
|
||||
</button>
|
||||
<button mat-raised-button (click)="logout()">
|
||||
<mat-icon>logout</mat-icon>
|
||||
Logout
|
||||
</button>
|
||||
|
||||
}
|
||||
|
||||
|
||||
</mat-toolbar>
|
||||
|
||||
|
||||
<!--<app-nav-bar (NavCollapsedMob)="navMobClick()" (NavCollapse)="this.navCollapsed = !this.navCollapsed" />-->
|
||||
<div class="router_outlet_padding">
|
||||
<router-outlet/>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
|
||||
mat-toolbar{
|
||||
background-color: rgba(153,153,153,0.16);
|
||||
backdrop-filter: blur(8px);
|
||||
}
|
||||
.menu-spacer {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
.fixed-top {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
z-index: 1000; // Ensure toolbar stays above other content
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { MainComponent } from './main.component';
|
||||
|
||||
describe('MainComponent', () => {
|
||||
let component: MainComponent;
|
||||
let fixture: ComponentFixture<MainComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [MainComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(MainComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,163 @@
|
||||
import {Component, CUSTOM_ELEMENTS_SCHEMA, inject} from '@angular/core';
|
||||
//import {NavigationComponent} from '../navigation/navigation.component';
|
||||
import {NgClass} from '@angular/common';
|
||||
import {NavigationComponent} from '../../layouts/admin-layout/navigation/navigation.component';
|
||||
import {RouterLink, RouterOutlet} from '@angular/router';
|
||||
import {BreadcrumbComponent} from '../../components/breadcrumb/breadcrumb.component';
|
||||
import {NavBarComponent} from '../../layouts/admin-layout/nav-bar/nav-bar.component';
|
||||
import {MatToolbar} from '@angular/material/toolbar';
|
||||
import {MatButton} from '@angular/material/button';
|
||||
import {IconDirective} from '@ant-design/icons-angular';
|
||||
import {MatDialog} from '@angular/material/dialog';
|
||||
import {Subscription} from 'rxjs';
|
||||
import {TokenStorageService} from '../../services/token-storage.service';
|
||||
import {AuthService} from '../../services/auth.service';
|
||||
import {EventBusService} from '../../_shared/event-bus.service';
|
||||
import {DialogComponent} from '../../components/dialog/dialog.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-main.component',
|
||||
imports: [
|
||||
NavBarComponent,
|
||||
MatToolbar,
|
||||
MatButton,
|
||||
RouterLink,
|
||||
IconDirective,
|
||||
RouterOutlet
|
||||
],
|
||||
schemas: [ CUSTOM_ELEMENTS_SCHEMA ],
|
||||
templateUrl: './main.component.html',
|
||||
styleUrl: './main.component.scss'
|
||||
})
|
||||
export class MainComponent {
|
||||
// public props
|
||||
navCollapsed: boolean = false;
|
||||
navCollapsedMob: boolean = false;
|
||||
|
||||
readonly dialog = inject(MatDialog);
|
||||
//private authService = new AuthService(provideHttpClient())
|
||||
public dialogData : DialogData = {password: "", username: ""};
|
||||
|
||||
private roles: string[] = [];
|
||||
isLoggedIn = false;
|
||||
showAdminBoard = false;
|
||||
showModeratorBoard = false;
|
||||
username?: string;
|
||||
|
||||
eventBusSub?: Subscription;
|
||||
private errorMessage: any;
|
||||
private isLoginFailed: boolean = false;
|
||||
|
||||
private storageService: TokenStorageService = inject(TokenStorageService);
|
||||
private authService: AuthService = inject(AuthService);
|
||||
private eventBusService: EventBusService = inject(EventBusService);
|
||||
|
||||
constructor(
|
||||
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.isLoggedIn = this.storageService.isLoggedIn();
|
||||
|
||||
if (this.isLoggedIn) {
|
||||
const user = this.storageService.getUser();
|
||||
this.roles = user.roles;
|
||||
|
||||
this.showAdminBoard = true;//this.roles.includes('ROLE_ADMIN');
|
||||
this.showModeratorBoard = this.roles.includes('ROLE_MODERATOR');
|
||||
|
||||
this.username = user.username;
|
||||
}
|
||||
|
||||
this.eventBusSub = this.eventBusService.on('logout', () => {
|
||||
this.logout();
|
||||
});
|
||||
}
|
||||
|
||||
// public method
|
||||
navMobClick() {
|
||||
if (this.navCollapsedMob && !document.querySelector('app-navigation.pc-sidebar')?.classList.contains('mob-open')) {
|
||||
this.navCollapsedMob = !this.navCollapsedMob;
|
||||
setTimeout(() => {
|
||||
this.navCollapsedMob = !this.navCollapsedMob;
|
||||
}, 100);
|
||||
} else {
|
||||
this.navCollapsedMob = !this.navCollapsedMob;
|
||||
}
|
||||
if (document.querySelector('app-navigation.pc-sidebar')?.classList.contains('navbar-collapsed')) {
|
||||
document.querySelector('app-navigation.pc-sidebar')?.classList.remove('navbar-collapsed');
|
||||
}
|
||||
}
|
||||
|
||||
handleKeyDown(event: KeyboardEvent): void {
|
||||
if (event.key === 'Escape') {
|
||||
this.closeMenu();
|
||||
}
|
||||
}
|
||||
|
||||
closeMenu() {
|
||||
if (document.querySelector('app-navigation.pc-sidebar')?.classList.contains('mob-open')) {
|
||||
document.querySelector('app-navigation.pc-sidebar')?.classList.remove('mob-open');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
logout(): void {
|
||||
this.authService.logout().subscribe({
|
||||
next: res => {
|
||||
console.log(res);
|
||||
this.storageService.clean();
|
||||
|
||||
window.location.reload();
|
||||
},
|
||||
error: err => {
|
||||
console.log(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
openDialog(enterAnimationDuration: string, exitAnimationDuration: string) {
|
||||
|
||||
let dialogRef = this.dialog.open(DialogComponent, {
|
||||
width: '350px',
|
||||
enterAnimationDuration,
|
||||
exitAnimationDuration,
|
||||
data: {username: this.dialogData.username, password: this.dialogData.password}
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
console.log('The dialog was closed');
|
||||
if(result== null){
|
||||
return;
|
||||
}
|
||||
this.dialogData = result;
|
||||
|
||||
this.authService.login(this.dialogData.username, this.dialogData.password).subscribe(
|
||||
data => {
|
||||
this.storageService.saveToken(data.accessToken);
|
||||
this.storageService.saveUser(data);
|
||||
|
||||
this.isLoginFailed = false;
|
||||
this.isLoggedIn = true;
|
||||
let user = this.storageService.getUser();
|
||||
this.roles = user.roles;
|
||||
//this.username = user.username;
|
||||
this.reloadPage();
|
||||
},
|
||||
err => {
|
||||
this.errorMessage = err.error.message;
|
||||
this.isLoginFailed = true;
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
}
|
||||
reloadPage(): void {
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
}
|
||||
export interface DialogData {
|
||||
username: string;
|
||||
password: string;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import {RouterModule} from '@angular/router';
|
||||
import {MainComponent} from './main.component/main.component';
|
||||
import {mainRouting} from './main.routing';
|
||||
import {NgModule} from '@angular/core';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
|
||||
],
|
||||
imports: [mainRouting, MainComponent],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class MainModule {}
|
||||
@@ -0,0 +1,44 @@
|
||||
import {RouterModule, Routes} from '@angular/router';
|
||||
import {HomeComponent} from '../components/home.component/home.component';
|
||||
import {MainComponent} from './main.component/main.component';
|
||||
import {TutorialsListComponent} from '../components/tutorials-list/tutorials-list.component';
|
||||
import {TutorialsComponent} from '../components/tutorials.component/tutorials.component';
|
||||
import {AddTutorialComponent} from '../components/add-tutorial/add-tutorial.component';
|
||||
import {RegisterComponent} from '../components/register/register.component';
|
||||
import {ProfileComponent} from '../components/profile/profile.component';
|
||||
|
||||
const MAIN_ROUTES: Routes =[
|
||||
{
|
||||
path: '',
|
||||
component: MainComponent,
|
||||
children: [
|
||||
{
|
||||
path: 'admin',
|
||||
loadChildren: () =>
|
||||
import('../admin-module/admin.module').then((m) => m.AdminModule),
|
||||
},
|
||||
{
|
||||
path: 'home',
|
||||
component: HomeComponent
|
||||
},
|
||||
{
|
||||
path: 'tutorials',
|
||||
component: TutorialsComponent
|
||||
},
|
||||
{
|
||||
path: 'add-tutorial',
|
||||
component: AddTutorialComponent
|
||||
},
|
||||
{
|
||||
path: 'register',
|
||||
component : RegisterComponent
|
||||
},
|
||||
{
|
||||
path: 'profile',
|
||||
component : ProfileComponent
|
||||
}
|
||||
],
|
||||
}
|
||||
];
|
||||
|
||||
export const mainRouting = RouterModule.forChild(MAIN_ROUTES);
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import {inject, Injectable} from '@angular/core';
|
||||
import {DOCUMENT} from '@angular/common';
|
||||
|
||||
const TOKEN_KEY = 'auth-token';
|
||||
const USER_KEY = 'auth-user';
|
||||
@@ -7,28 +8,33 @@ const USER_KEY = 'auth-user';
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class TokenStorageService {
|
||||
constructor() { }
|
||||
|
||||
private document = inject<Document>(DOCUMENT);
|
||||
|
||||
constructor() {
|
||||
|
||||
}
|
||||
|
||||
signOut(): void {
|
||||
window.sessionStorage.clear();
|
||||
this.document.defaultView?.sessionStorage.clear();
|
||||
}
|
||||
|
||||
public saveToken(token: string): void {
|
||||
window.sessionStorage.removeItem(TOKEN_KEY);
|
||||
window.sessionStorage.setItem(TOKEN_KEY, token);
|
||||
document.defaultView?.sessionStorage.removeItem(TOKEN_KEY);
|
||||
document.defaultView?.sessionStorage.setItem(TOKEN_KEY, token);
|
||||
}
|
||||
|
||||
public getToken(): string | null {
|
||||
return window.sessionStorage.getItem(TOKEN_KEY);
|
||||
public getToken(): string | null| undefined {
|
||||
return document.defaultView?.sessionStorage.getItem(TOKEN_KEY);
|
||||
}
|
||||
|
||||
public saveUser(user: any): void {
|
||||
window.sessionStorage.removeItem(USER_KEY);
|
||||
window.sessionStorage.setItem(USER_KEY, JSON.stringify(user));
|
||||
document.defaultView?.sessionStorage.removeItem(USER_KEY);
|
||||
document.defaultView?.sessionStorage.setItem(USER_KEY, JSON.stringify(user));
|
||||
}
|
||||
|
||||
public getUser(): any {
|
||||
const user = window.sessionStorage.getItem(USER_KEY);
|
||||
const user = document.defaultView?.sessionStorage.getItem(USER_KEY);
|
||||
if (user) {
|
||||
return JSON.parse(user);
|
||||
}
|
||||
@@ -37,11 +43,11 @@ export class TokenStorageService {
|
||||
}
|
||||
|
||||
clean(): void {
|
||||
window.sessionStorage.clear();
|
||||
document.defaultView?.sessionStorage.clear();
|
||||
}
|
||||
|
||||
public isLoggedIn(): boolean {
|
||||
const user = window.sessionStorage.getItem(USER_KEY);
|
||||
const user = this.document.defaultView?.sessionStorage?.getItem(USER_KEY);
|
||||
if (user) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user