Implement admin and user sidebars with routing and styling updates
This commit is contained in:
@@ -0,0 +1,16 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { AdminModuleService } from './admin-module.service';
|
||||||
|
|
||||||
|
describe('AdminModuleService', () => {
|
||||||
|
let service: AdminModuleService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
service = TestBed.inject(AdminModuleService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import {Observable} from 'rxjs';
|
||||||
|
import {HttpClient} from '@angular/common/http';
|
||||||
|
import {User} from '../models/user.model';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class AdminModuleService {
|
||||||
|
baseUrl = 'http://localhost:8080/api';
|
||||||
|
|
||||||
|
constructor(private http: HttpClient) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
updateUserRoles(id: any,data: User): Observable<any> {
|
||||||
|
return this.http.put(`${this.baseUrl}/users/${id}`, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,28 +1,13 @@
|
|||||||
<!--<p>admin.component works!</p>-->
|
<app-side-bar-admin
|
||||||
|
class="pc-sidebar"
|
||||||
<app-navigation
|
>
|
||||||
class="pc-sidebar"
|
</app-side-bar-admin>
|
||||||
[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="pc-container">
|
||||||
<div class="coded-wrapper">
|
|
||||||
<div class="coded-content">
|
|
||||||
<div class="coded-inner-content">
|
|
||||||
<app-breadcrumb />
|
<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>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,22 +1,16 @@
|
|||||||
.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{
|
.pc-sidebar{
|
||||||
top: 120px;
|
top: 65px;
|
||||||
|
overflow-y: auto;
|
||||||
|
background-color: rgba(153, 153, 153, 0.16);
|
||||||
|
|
||||||
|
backdrop-filter: blur(8px);
|
||||||
|
}
|
||||||
|
.pc-container{
|
||||||
|
top: 0px;
|
||||||
|
padding-left: 5px;
|
||||||
|
padding-right: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {MatButton} from '@angular/material/button';
|
|||||||
import { ScrollPanelModule } from 'primeng/scrollpanel';
|
import { ScrollPanelModule } from 'primeng/scrollpanel';
|
||||||
import {MenuItem} from 'primeng/api';
|
import {MenuItem} from 'primeng/api';
|
||||||
import {PanelMenu} from 'primeng/panelmenu';
|
import {PanelMenu} from 'primeng/panelmenu';
|
||||||
|
import {SideBarAdminComponent} from '../side-bar-admin.component/side-bar-admin.component';
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-admin.component',
|
selector: 'app-admin.component',
|
||||||
imports: [
|
imports: [
|
||||||
@@ -24,6 +25,7 @@ import {PanelMenu} from 'primeng/panelmenu';
|
|||||||
RouterLink,
|
RouterLink,
|
||||||
PanelMenu,
|
PanelMenu,
|
||||||
NgStyle,
|
NgStyle,
|
||||||
|
SideBarAdminComponent,
|
||||||
|
|
||||||
],
|
],
|
||||||
schemas:[CUSTOM_ELEMENTS_SCHEMA],
|
schemas:[CUSTOM_ELEMENTS_SCHEMA],
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ const ADMIN_ROUTES: Routes = [
|
|||||||
|
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: 'welcome',
|
path: 'admin-welcome',
|
||||||
loadComponent: () => import('../admin-module/admin-welcome.component/admin-welcome.component').then((c) => c.AdminWelcomeComponent),
|
loadComponent: () => import('../admin-module/admin-welcome.component/admin-welcome.component').then((c) => c.AdminWelcomeComponent),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -17,9 +17,12 @@ const ADMIN_ROUTES: Routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'system',
|
path: 'system',
|
||||||
|
|
||||||
loadComponent: () => import('../admin-module/system.component/system.component').then((c) => c.SystemComponent)
|
loadComponent: () => import('../admin-module/system.component/system.component').then((c) => c.SystemComponent)
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
path: 'users',
|
||||||
|
loadComponent: () => import('../admin-module/users.component/users.component').then((c) => c.UsersComponent)
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|||||||
+35
@@ -0,0 +1,35 @@
|
|||||||
|
<mat-nav-list>
|
||||||
|
<a mat-list-item routerLink="admin-welcome">
|
||||||
|
<span class="entry">
|
||||||
|
<mat-icon>house</mat-icon>
|
||||||
|
@if (!isCollapsed) {
|
||||||
|
<span >Dashboard</span>
|
||||||
|
}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
<a mat-list-item routerLink="users">
|
||||||
|
<span class="entry">
|
||||||
|
<mat-icon>newspaper</mat-icon>
|
||||||
|
@if (!isCollapsed) {
|
||||||
|
<span >Users</span>
|
||||||
|
}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
<a mat-list-item routerLink="settings">
|
||||||
|
<span class="entry">
|
||||||
|
<mat-icon>newspaper</mat-icon>
|
||||||
|
@if (!isCollapsed) {
|
||||||
|
<span >Settings</span>
|
||||||
|
}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
<a mat-list-item routerLink="system">
|
||||||
|
<span class="entry">
|
||||||
|
<mat-icon>newspaper</mat-icon>
|
||||||
|
@if (!isCollapsed) {
|
||||||
|
<span >System</span>
|
||||||
|
}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</mat-nav-list>
|
||||||
|
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
.entry{
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1rem;
|
||||||
|
padding:0.75rem;
|
||||||
|
color: rgba(24, 255, 255, 0.96);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
a.mdc-list-item
|
||||||
|
{
|
||||||
|
|
||||||
|
background-color: rgba(24,255,255,0.04);
|
||||||
|
}
|
||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { SideBarAdminComponent } from './side-bar-admin.component';
|
||||||
|
|
||||||
|
describe('SideBarAdminComponent', () => {
|
||||||
|
let component: SideBarAdminComponent;
|
||||||
|
let fixture: ComponentFixture<SideBarAdminComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [SideBarAdminComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(SideBarAdminComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
import {Component, CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
|
||||||
|
import {MatListItem, MatNavList} from '@angular/material/list';
|
||||||
|
import {RouterLink} from '@angular/router';
|
||||||
|
import {MatIcon} from '@angular/material/icon';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-side-bar-admin',
|
||||||
|
imports: [
|
||||||
|
MatIcon,
|
||||||
|
MatListItem,
|
||||||
|
MatNavList,
|
||||||
|
RouterLink
|
||||||
|
],
|
||||||
|
templateUrl: './side-bar-admin.component.html',
|
||||||
|
styleUrl: './side-bar-admin.component.scss',
|
||||||
|
schemas:[CUSTOM_ELEMENTS_SCHEMA]
|
||||||
|
})
|
||||||
|
export class SideBarAdminComponent {
|
||||||
|
isCollapsed = false;
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
<table mat-table [dataSource]="users">
|
||||||
|
@for (column of columnsSchema; track column){
|
||||||
|
<ng-container [matColumnDef]="column.key">
|
||||||
|
<th mat-header-cell *matHeaderCellDef>
|
||||||
|
{{column.label}}
|
||||||
|
</th>
|
||||||
|
<td mat-cell *matCellDef="let element">
|
||||||
|
@switch (column.type) {
|
||||||
|
@case ('list') {
|
||||||
|
<mat-form-field class="example-chip-list">
|
||||||
|
<mat-chip-grid #chipGrid aria-label="Role selection">
|
||||||
|
@for (role of element.roles; track $index) {
|
||||||
|
<mat-chip-row (removed)="remove(role,element)">
|
||||||
|
{{role.name}}
|
||||||
|
|
||||||
|
<mat-icon
|
||||||
|
matChipRemove
|
||||||
|
[attr.aria-label]="'remove ' + role.name"
|
||||||
|
>
|
||||||
|
cancel
|
||||||
|
</mat-icon>
|
||||||
|
|
||||||
|
</mat-chip-row>
|
||||||
|
}
|
||||||
|
</mat-chip-grid>
|
||||||
|
<input
|
||||||
|
name="currentRole"
|
||||||
|
placeholder="Add role..."
|
||||||
|
[matChipInputFor]="chipGrid"
|
||||||
|
[matAutocomplete]="auto"
|
||||||
|
[matChipInputSeparatorKeyCodes]="separatorKeysCodes"
|
||||||
|
[formControl]="rolesControl"
|
||||||
|
[matChipInputAddOnBlur]="true"
|
||||||
|
(matChipInputTokenEnd)="add($event,element)"
|
||||||
|
(input)="change($event,filteredRoles(element.roles))"
|
||||||
|
/>
|
||||||
|
<mat-autocomplete [formControl]="ac"
|
||||||
|
autoActiveFirstOption
|
||||||
|
#auto
|
||||||
|
(optionSelected)="selected(element,$event); ">
|
||||||
|
@for (role of filteredRoles(element.roles); track role) {
|
||||||
|
<mat-option [value]="role">{{role.name}}</mat-option>
|
||||||
|
}
|
||||||
|
</mat-autocomplete>
|
||||||
|
</mat-form-field>
|
||||||
|
}
|
||||||
|
@default {
|
||||||
|
{{ element[column.key] }}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
}
|
||||||
|
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||||
|
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
|
||||||
|
</table>
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
.example-chip-list {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { UsersComponent } from './users.component';
|
||||||
|
|
||||||
|
describe('UsersComponent', () => {
|
||||||
|
let component: UsersComponent;
|
||||||
|
let fixture: ComponentFixture<UsersComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [UsersComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(UsersComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,185 @@
|
|||||||
|
import {ChangeDetectionStrategy, Component, CUSTOM_ELEMENTS_SCHEMA, model} from '@angular/core';
|
||||||
|
import {UserService} from '../../services/user.service';
|
||||||
|
import {RolesService} from '../../services/roles.service';
|
||||||
|
import {Role} from '../../models/role';
|
||||||
|
import {User} from '../../models/user.model';
|
||||||
|
import {
|
||||||
|
MatCell,
|
||||||
|
MatCellDef, MatColumnDef,
|
||||||
|
MatHeaderCell, MatHeaderCellDef,
|
||||||
|
MatHeaderRow,
|
||||||
|
MatHeaderRowDef,
|
||||||
|
MatRow,
|
||||||
|
MatRowDef, MatTable
|
||||||
|
} from '@angular/material/table';
|
||||||
|
import {FormControl, FormsModule, ReactiveFormsModule} from '@angular/forms';
|
||||||
|
import {
|
||||||
|
MatAutocomplete,
|
||||||
|
MatAutocompleteSelectedEvent,
|
||||||
|
MatAutocompleteTrigger,
|
||||||
|
MatOption
|
||||||
|
} from '@angular/material/autocomplete';
|
||||||
|
import {
|
||||||
|
MatChip,
|
||||||
|
MatChipGrid,
|
||||||
|
MatChipInput,
|
||||||
|
MatChipInputEvent,
|
||||||
|
MatChipRow,
|
||||||
|
MatChipsModule
|
||||||
|
} from '@angular/material/chips';
|
||||||
|
import {MatIcon} from '@angular/material/icon';
|
||||||
|
import {COMMA, ENTER} from '@angular/cdk/keycodes';
|
||||||
|
import {MatFormField} from '@angular/material/input';
|
||||||
|
import {MatSelect, MatSelectTrigger} from '@angular/material/select';
|
||||||
|
import {AdminModuleService} from '../admin-module.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-users.component',
|
||||||
|
imports: [
|
||||||
|
MatCell,
|
||||||
|
MatCellDef,
|
||||||
|
MatHeaderCell,
|
||||||
|
MatHeaderRow,
|
||||||
|
MatHeaderRowDef,
|
||||||
|
MatRow,
|
||||||
|
MatRowDef,
|
||||||
|
MatTable,
|
||||||
|
MatColumnDef,
|
||||||
|
MatHeaderCellDef,
|
||||||
|
FormsModule,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
MatChipGrid,
|
||||||
|
MatChipRow,
|
||||||
|
MatIcon,
|
||||||
|
MatAutocompleteTrigger,
|
||||||
|
MatChipInput,
|
||||||
|
MatAutocomplete,
|
||||||
|
MatOption,
|
||||||
|
MatFormField,
|
||||||
|
MatSelect,
|
||||||
|
MatSelectTrigger,
|
||||||
|
MatChip,
|
||||||
|
MatChipsModule
|
||||||
|
],
|
||||||
|
templateUrl: './users.component.html',
|
||||||
|
styleUrl: './users.component.scss',
|
||||||
|
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||||
|
})
|
||||||
|
export class UsersComponent {
|
||||||
|
|
||||||
|
readonly separatorKeysCodes: number[] = [ENTER, COMMA];
|
||||||
|
allRoles:Role[] = [];
|
||||||
|
users: User[] = [];
|
||||||
|
|
||||||
|
displayedColumns: string[] = UserColumns.map((col) => col.key)
|
||||||
|
columnsSchema: any = UserColumns
|
||||||
|
|
||||||
|
readonly currentRole = model('');
|
||||||
|
|
||||||
|
rolesControl = new FormControl([]);
|
||||||
|
protected ac = new FormControl('');
|
||||||
|
|
||||||
|
constructor(private userService: UserService,
|
||||||
|
private roleService: RolesService,
|
||||||
|
private adminService:AdminModuleService) {
|
||||||
|
this.getAllRoles();
|
||||||
|
this.getUsers();
|
||||||
|
}
|
||||||
|
|
||||||
|
getAllRoles():any{
|
||||||
|
this.roleService.getAllRoles().subscribe(
|
||||||
|
(data : any) => {
|
||||||
|
this.allRoles = data;
|
||||||
|
console.log(data);
|
||||||
|
},
|
||||||
|
(err : any)=> {
|
||||||
|
this.allRoles = JSON.parse(err.error).message;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
getUsers(){
|
||||||
|
this.userService.getAdminBoard().subscribe(
|
||||||
|
(data : any) => {
|
||||||
|
this.users = data;
|
||||||
|
console.log(data);
|
||||||
|
},
|
||||||
|
(err : any)=> {
|
||||||
|
console.log(JSON.parse(err.error).message);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
filteredRoles(roles : Role[]):any {
|
||||||
|
return this.allRoles.filter(
|
||||||
|
(r:Role) => !roles.some((item) => item.id === r.id),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
change($event: Event, roles: Role[]) {
|
||||||
|
roles.filter(
|
||||||
|
(r:Role) => !roles.some((item) => item.name?.toLowerCase() === r.name?.toLowerCase()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
selected(user: User, $event: MatAutocompleteSelectedEvent) {
|
||||||
|
user.roles.push($event.option.value);
|
||||||
|
this.saveUserRoles(user);
|
||||||
|
this.currentRole.set('');
|
||||||
|
$event.option.deselect();
|
||||||
|
}
|
||||||
|
|
||||||
|
add($event: MatChipInputEvent, user:User) {
|
||||||
|
/*const value = ($event.value || '').trim();
|
||||||
|
|
||||||
|
const role = this.allRoles.find(value1 => value1.name === value);
|
||||||
|
if(role){
|
||||||
|
user.roles.push(value);
|
||||||
|
this.saveUserRoles(user);
|
||||||
|
}*/
|
||||||
|
// Clear the input value
|
||||||
|
this.currentRole.set('');
|
||||||
|
}
|
||||||
|
|
||||||
|
remove(role: any, user: User) {
|
||||||
|
const updatedRoles: Role[] = user.roles.filter(
|
||||||
|
(r: Role) => r.id !== role.id // Simple comparison with the role to remove
|
||||||
|
);
|
||||||
|
|
||||||
|
if (updatedRoles && updatedRoles.length >= 1) {
|
||||||
|
user.roles = updatedRoles;
|
||||||
|
this.saveUserRoles(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
saveUserRoles(user:User){
|
||||||
|
this.adminService.updateUserRoles(user.id, user).subscribe(
|
||||||
|
(data:any) => {
|
||||||
|
console.log(data);
|
||||||
|
},
|
||||||
|
(err:any) => {
|
||||||
|
console.log(err);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const UserColumns = [
|
||||||
|
{
|
||||||
|
key: 'username',
|
||||||
|
type: 'text',
|
||||||
|
label: 'Name',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'email',
|
||||||
|
type: 'text',
|
||||||
|
label: 'Email',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'roles',
|
||||||
|
type: 'list',
|
||||||
|
label: 'Roles',
|
||||||
|
required: true,
|
||||||
|
}
|
||||||
|
];
|
||||||
@@ -80,7 +80,6 @@ export class BoardAdminComponent implements OnInit {
|
|||||||
return this.allRoles.filter(
|
return this.allRoles.filter(
|
||||||
(r:Role) => !roles.some((item) => item.id === r.id),
|
(r:Role) => !roles.some((item) => item.id === r.id),
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// private _filter(value: string): string[] {
|
// private _filter(value: string): string[] {
|
||||||
@@ -111,7 +110,7 @@ export class BoardAdminComponent implements OnInit {
|
|||||||
// this.announcer.announce(`Removed ${fruit}`);
|
// this.announcer.announce(`Removed ${fruit}`);
|
||||||
// return [...fruits];
|
// return [...fruits];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
</button>
|
</button>
|
||||||
<mat-menu #menu="matMenu">
|
<mat-menu #menu="matMenu">
|
||||||
@if (showAdminBoard) {
|
@if (showAdminBoard) {
|
||||||
<button mat-menu-item routerLink="admin/welcome">
|
<button mat-menu-item routerLink="admin/admin-welcome">
|
||||||
<mat-icon>admin_panel_settings</mat-icon>
|
<mat-icon>admin_panel_settings</mat-icon>
|
||||||
Admin Panel
|
Admin Panel
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -186,7 +186,9 @@ export class MainComponent implements OnInit{
|
|||||||
|
|
||||||
this.refreshToolbar();
|
this.refreshToolbar();
|
||||||
dialogLoginRef.close()
|
dialogLoginRef.close()
|
||||||
this.router.navigate(['main/user/user-welcome']);
|
|
||||||
|
|
||||||
|
this.router.navigate(['main/tutorials']);
|
||||||
},
|
},
|
||||||
err => {
|
err => {
|
||||||
dialogLoginRef.componentInstance.openLoginFailedSnackBar(err.error.message);
|
dialogLoginRef.componentInstance.openLoginFailedSnackBar(err.error.message);
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<mat-nav-list>
|
||||||
|
<a mat-list-item routerLink="user-welcome">
|
||||||
|
<span class="entry">
|
||||||
|
<mat-icon>house</mat-icon>
|
||||||
|
@if (!isCollapsed) {
|
||||||
|
<span >Dashboard</span>
|
||||||
|
}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
<a mat-list-item routerLink="tutorials-list">
|
||||||
|
<span class="entry">
|
||||||
|
<mat-icon>newspaper</mat-icon>
|
||||||
|
@if (!isCollapsed) {
|
||||||
|
<span >Tutorials</span>
|
||||||
|
}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</mat-nav-list>
|
||||||
|
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
.entry{
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1rem;
|
||||||
|
padding:0.75rem;
|
||||||
|
color: rgba(24, 255, 255, 0.96);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
a.mdc-list-item
|
||||||
|
{
|
||||||
|
|
||||||
|
background-color: rgba(24,255,255,0.04);
|
||||||
|
}
|
||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { SideBarUserComponent } from './side-bar-user.component';
|
||||||
|
|
||||||
|
describe('SideBarUserComponent', () => {
|
||||||
|
let component: SideBarUserComponent;
|
||||||
|
let fixture: ComponentFixture<SideBarUserComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [SideBarUserComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(SideBarUserComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import {Component, CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
|
||||||
|
import {MatListItem, MatNavList} from '@angular/material/list';
|
||||||
|
import {RouterLink} from '@angular/router';
|
||||||
|
import {MatIcon} from '@angular/material/icon';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-side-bar-user',
|
||||||
|
imports: [
|
||||||
|
MatIcon,
|
||||||
|
MatListItem,
|
||||||
|
MatNavList,
|
||||||
|
RouterLink
|
||||||
|
],
|
||||||
|
templateUrl: './side-bar-user.component.html',
|
||||||
|
styleUrl: './side-bar-user.component.scss',
|
||||||
|
schemas:[CUSTOM_ELEMENTS_SCHEMA]
|
||||||
|
})
|
||||||
|
export class SideBarUserComponent {
|
||||||
|
isCollapsed = false;
|
||||||
|
}
|
||||||
+1
-1
@@ -200,7 +200,7 @@ export const TutorialColumns = [
|
|||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'toBePublished',
|
key: 'tobepublished',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
label: 'To be published',
|
label: 'To be published',
|
||||||
required: true
|
required: true
|
||||||
|
|||||||
@@ -1,34 +1,9 @@
|
|||||||
<app-side-bar
|
<app-side-bar-user
|
||||||
class="pc-sidebar"
|
class="pc-sidebar"
|
||||||
>
|
>
|
||||||
|
</app-side-bar-user>
|
||||||
</app-side-bar>
|
|
||||||
|
|
||||||
<div class="pc-container">
|
<div class="pc-container">
|
||||||
<router-outlet></router-outlet>
|
<router-outlet></router-outlet>
|
||||||
</div>
|
</div>
|
||||||
<!--<mat-toolbar color="primary">-->
|
|
||||||
<!-- <button mat-icon-button aria-label="Menu icon" (click)="toggleMenu()">-->
|
|
||||||
<!-- <mat-icon>menu</mat-icon>-->
|
|
||||||
<!-- </button>-->
|
|
||||||
<!-- <h1>Responsive Material Sidenavigation</h1>-->
|
|
||||||
<!--</mat-toolbar>-->
|
|
||||||
<!--<mat-sidenav-container autosize="true">-->
|
|
||||||
<!-- <mat-sidenav [ngClass]="!isCollapsed ? 'expanded' : ''" [mode]="isMobile ? 'over' : 'side'" [opened]="isMobile ? 'false' : 'true'">-->
|
|
||||||
<!-- <mat-nav-list>-->
|
|
||||||
<!-- <a mat-list-item>-->
|
|
||||||
<!-- <span class="entry">-->
|
|
||||||
<!-- <mat-icon>house</mat-icon>-->
|
|
||||||
<!-- @if (!isCollapsed) {-->
|
|
||||||
<!-- <span >Dashboard</span>-->
|
|
||||||
<!-- }-->
|
|
||||||
<!-- </span>-->
|
|
||||||
<!-- </a>-->
|
|
||||||
<!-- </mat-nav-list>-->
|
|
||||||
<!-- </mat-sidenav>-->
|
|
||||||
<!-- <mat-sidenav-content>-->
|
|
||||||
<!-- Content-->
|
|
||||||
<!-- <router-outlet></router-outlet>-->
|
|
||||||
<!-- </mat-sidenav-content>-->
|
|
||||||
<!--</mat-sidenav-container>-->
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,49 +1,10 @@
|
|||||||
|
|
||||||
mat-toolbar{
|
|
||||||
position:fixed;
|
|
||||||
top:0;
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
mat-sidenav-container {
|
|
||||||
height:100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move the content down so that it won't be hidden by the toolbar
|
|
||||||
mat-sidenav {
|
|
||||||
padding-top: 3.5rem;
|
|
||||||
transition: width 0.3s ease;
|
|
||||||
@media screen and (min-width: 600px) {
|
|
||||||
padding-top: 4rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.entry{
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 1rem;
|
|
||||||
padding:0.75rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move the content down so that it won't be hidden by the toolbar
|
|
||||||
mat-sidenav-content{
|
|
||||||
padding-top: 3.5rem;
|
|
||||||
@media screen and (min-width: 600px) {
|
|
||||||
padding-top: 4rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.expanded {
|
|
||||||
width: 250px;
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------
|
//---------------
|
||||||
.pc-sidebar{
|
.pc-sidebar{
|
||||||
top: 65px;
|
top: 65px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
background-color: rgba(153, 153, 153, 0.16);
|
||||||
|
|
||||||
|
backdrop-filter: blur(8px);
|
||||||
}
|
}
|
||||||
.pc-container{
|
.pc-container{
|
||||||
top: 0px;
|
top: 0px;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {MatIcon} from '@angular/material/icon';
|
|||||||
import {BreakpointObserver} from '@angular/cdk/layout';
|
import {BreakpointObserver} from '@angular/cdk/layout';
|
||||||
import {MatToolbar} from '@angular/material/toolbar';
|
import {MatToolbar} from '@angular/material/toolbar';
|
||||||
import {MatIconButton} from '@angular/material/button';
|
import {MatIconButton} from '@angular/material/button';
|
||||||
|
import {SideBarUserComponent} from '../side-bar-user.component/side-bar-user.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-user.component',
|
selector: 'app-user.component',
|
||||||
@@ -21,7 +22,8 @@ import {MatIconButton} from '@angular/material/button';
|
|||||||
MatListItem,
|
MatListItem,
|
||||||
MatIcon,
|
MatIcon,
|
||||||
MatToolbar,
|
MatToolbar,
|
||||||
MatIconButton
|
MatIconButton,
|
||||||
|
SideBarUserComponent
|
||||||
],
|
],
|
||||||
templateUrl: './user.component.html',
|
templateUrl: './user.component.html',
|
||||||
styleUrl: './user.component.scss',
|
styleUrl: './user.component.scss',
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.jambotronGroup.jambotron.controllers;
|
package com.jambotronGroup.jambotron.controllers;
|
||||||
|
|
||||||
|
|
||||||
|
import com.jambotronGroup.jambotron.model.Tutorial;
|
||||||
import com.jambotronGroup.jambotron.model.User;
|
import com.jambotronGroup.jambotron.model.User;
|
||||||
import com.jambotronGroup.jambotron.repository.UserRepository;
|
import com.jambotronGroup.jambotron.repository.UserRepository;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -8,8 +9,7 @@ import org.springframework.http.HttpStatus;
|
|||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@CrossOrigin(origins = "${app.origin}", maxAge = 3600, allowCredentials="true")
|
@CrossOrigin(origins = "${app.origin}", maxAge = 3600, allowCredentials="true")
|
||||||
@RestController
|
@RestController
|
||||||
@@ -35,4 +35,31 @@ public class UsersController {
|
|||||||
return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
|
return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PutMapping("users/{id}")
|
||||||
|
public ResponseEntity<?> updateUserRoles(@PathVariable("id") long id, @RequestBody User user) {
|
||||||
|
Optional<User> userData = userRepository.findById(id);
|
||||||
|
Map<String, Object> map = new LinkedHashMap<String, Object>();
|
||||||
|
if (userData.isPresent()) {
|
||||||
|
User servUser = userData.get();
|
||||||
|
if(user.getRoles().size() > 0)
|
||||||
|
servUser.setRoles(user.getRoles());
|
||||||
|
else {
|
||||||
|
map.put("status", 0);
|
||||||
|
map.put("message", "User must have at least one role");
|
||||||
|
return new ResponseEntity<>(map, HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
servUser = userRepository.save(servUser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
|
||||||
|
map.put("status", 0);
|
||||||
|
map.put("message", e.getMessage());
|
||||||
|
return new ResponseEntity<>(map,HttpStatus.INTERNAL_SERVER_ERROR);
|
||||||
|
}
|
||||||
|
return new ResponseEntity<>(servUser, HttpStatus.OK);
|
||||||
|
} else {
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user