Termék és felhasználó listázása
This commit is contained in:
parent
e8ccd3fff8
commit
d2018fa8b9
26 changed files with 284 additions and 138 deletions
|
@ -20,3 +20,7 @@ npm install
|
||||||
npm start
|
npm start
|
||||||
```
|
```
|
||||||
Ezután a http://localhost:3000/ cimen érhető el az oldal.
|
Ezután a http://localhost:3000/ cimen érhető el az oldal.
|
||||||
|
|
||||||
|
## Használat
|
||||||
|
* Felhasználónév: admin
|
||||||
|
* Jelszó: admin123
|
||||||
|
|
38
client/src/app/app-routing.module.ts
Normal file
38
client/src/app/app-routing.module.ts
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { RouterModule, Routes } from '@angular/router';
|
||||||
|
import { AuthCheck } from './auth-check';
|
||||||
|
import { ProductListComponent } from './product-list/product-list.component';
|
||||||
|
import { LoginComponent } from './login/login.component';
|
||||||
|
import { UserListComponent } from './user-list/user-list.component';
|
||||||
|
|
||||||
|
const routes: Routes = [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
canActivate: [AuthCheck],
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'users',
|
||||||
|
component: UserListComponent
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
component: ProductListComponent
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
children: [
|
||||||
|
{path: '', component: LoginComponent}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [RouterModule.forRoot(routes)],
|
||||||
|
exports: [RouterModule]
|
||||||
|
})
|
||||||
|
export class AppRoutingModule {
|
||||||
|
}
|
||||||
|
|
||||||
|
export type RouteData = { title: string; };
|
|
@ -13,9 +13,12 @@
|
||||||
<input matInput type="password" formControlName="password">
|
<input matInput type="password" formControlName="password">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<button mat-button class="mat-primary" (click)="doLogin()">Bejelentkezés</button>
|
<button mat-button class="mat-primary" (click)="doLogin()">Bejelentkezés</button>
|
||||||
<button mat-button>Regisztráció</button>
|
<button mat-button (click)="doRegister()">Regisztráció</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<h1>Termékek</h1>
|
<div>
|
||||||
|
<button mat-button class="mat-primary" (click)="router.navigate(['/'])">Termékek</button>
|
||||||
|
<button mat-button class="mat-primary" (click)="router.navigate(['/users'])">Felhasználók</button>
|
||||||
|
</div>
|
||||||
|
<router-outlet></router-outlet>
|
||||||
|
|
|
@ -14,7 +14,9 @@ export class AppComponent implements OnInit {
|
||||||
password: new FormControl()
|
password: new FormControl()
|
||||||
});
|
});
|
||||||
|
|
||||||
constructor(public userService: UserService, private router: Router) {
|
toggle = false;
|
||||||
|
|
||||||
|
constructor(public userService: UserService, public router: Router) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
@ -31,4 +33,7 @@ export class AppComponent implements OnInit {
|
||||||
alert("Hiba: " + (e?.error?.error ?? JSON.stringify(e)));
|
alert("Hiba: " + (e?.error?.error ?? JSON.stringify(e)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async doRegister() {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,11 +12,20 @@ import { MatTableModule } from '@angular/material/table';
|
||||||
import { MatPaginatorModule } from '@angular/material/paginator';
|
import { MatPaginatorModule } from '@angular/material/paginator';
|
||||||
import { MatSortModule } from '@angular/material/sort';
|
import { MatSortModule } from '@angular/material/sort';
|
||||||
import { HttpClientModule } from '@angular/common/http';
|
import { HttpClientModule } from '@angular/common/http';
|
||||||
|
import { AppRoutingModule } from './app-routing.module';
|
||||||
|
import { LoginComponent } from './login/login.component';
|
||||||
|
import { UserListComponent } from './user-list/user-list.component';
|
||||||
|
import { AuthCheck } from './auth-check';
|
||||||
|
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
||||||
|
import { RegisterComponent } from './register/register.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
AppComponent,
|
AppComponent,
|
||||||
ProductListComponent
|
ProductListComponent,
|
||||||
|
LoginComponent,
|
||||||
|
UserListComponent,
|
||||||
|
RegisterComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
|
@ -28,9 +37,13 @@ import { HttpClientModule } from '@angular/common/http';
|
||||||
MatTableModule,
|
MatTableModule,
|
||||||
MatPaginatorModule,
|
MatPaginatorModule,
|
||||||
MatSortModule,
|
MatSortModule,
|
||||||
HttpClientModule
|
HttpClientModule,
|
||||||
|
AppRoutingModule,
|
||||||
|
MatSlideToggleModule
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
AuthCheck
|
||||||
],
|
],
|
||||||
providers: [],
|
|
||||||
bootstrap: [AppComponent]
|
bootstrap: [AppComponent]
|
||||||
})
|
})
|
||||||
export class AppModule { }
|
export class AppModule { }
|
||||||
|
|
13
client/src/app/auth-check.ts
Normal file
13
client/src/app/auth-check.ts
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot } from '@angular/router';
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { UserService } from './services/user.service';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class AuthCheck implements CanActivate {
|
||||||
|
constructor(private userService: UserService) {
|
||||||
|
}
|
||||||
|
|
||||||
|
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
|
||||||
|
return !!this.userService.user;
|
||||||
|
}
|
||||||
|
}
|
0
client/src/app/login/login.component.css
Normal file
0
client/src/app/login/login.component.css
Normal file
1
client/src/app/login/login.component.html
Normal file
1
client/src/app/login/login.component.html
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<h1>Jelentkezz be</h1>
|
21
client/src/app/login/login.component.spec.ts
Normal file
21
client/src/app/login/login.component.spec.ts
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { LoginComponent } from './login.component';
|
||||||
|
|
||||||
|
describe('LoginComponent', () => {
|
||||||
|
let component: LoginComponent;
|
||||||
|
let fixture: ComponentFixture<LoginComponent>;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [LoginComponent]
|
||||||
|
});
|
||||||
|
fixture = TestBed.createComponent(LoginComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
10
client/src/app/login/login.component.ts
Normal file
10
client/src/app/login/login.component.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-login',
|
||||||
|
templateUrl: './login.component.html',
|
||||||
|
styleUrls: ['./login.component.css']
|
||||||
|
})
|
||||||
|
export class LoginComponent {
|
||||||
|
|
||||||
|
}
|
6
client/src/app/model/product.model.ts
Normal file
6
client/src/app/model/product.model.ts
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
export interface Product {
|
||||||
|
name: string;
|
||||||
|
price: number;
|
||||||
|
description: string;
|
||||||
|
id: string;
|
||||||
|
}
|
|
@ -1,111 +0,0 @@
|
||||||
import { DataSource } from '@angular/cdk/collections';
|
|
||||||
import { MatPaginator } from '@angular/material/paginator';
|
|
||||||
import { MatSort } from '@angular/material/sort';
|
|
||||||
import { map } from 'rxjs/operators';
|
|
||||||
import { Observable, of as observableOf, merge } from 'rxjs';
|
|
||||||
|
|
||||||
// TODO: Replace this with your own data model type
|
|
||||||
export interface ProductListItem {
|
|
||||||
name: string;
|
|
||||||
id: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: replace this with real data from your application
|
|
||||||
const EXAMPLE_DATA: ProductListItem[] = [
|
|
||||||
{id: 1, name: 'Hydrogen'},
|
|
||||||
{id: 2, name: 'Helium'},
|
|
||||||
{id: 3, name: 'Lithium'},
|
|
||||||
{id: 4, name: 'Beryllium'},
|
|
||||||
{id: 5, name: 'Boron'},
|
|
||||||
{id: 6, name: 'Carbon'},
|
|
||||||
{id: 7, name: 'Nitrogen'},
|
|
||||||
{id: 8, name: 'Oxygen'},
|
|
||||||
{id: 9, name: 'Fluorine'},
|
|
||||||
{id: 10, name: 'Neon'},
|
|
||||||
{id: 11, name: 'Sodium'},
|
|
||||||
{id: 12, name: 'Magnesium'},
|
|
||||||
{id: 13, name: 'Aluminum'},
|
|
||||||
{id: 14, name: 'Silicon'},
|
|
||||||
{id: 15, name: 'Phosphorus'},
|
|
||||||
{id: 16, name: 'Sulfur'},
|
|
||||||
{id: 17, name: 'Chlorine'},
|
|
||||||
{id: 18, name: 'Argon'},
|
|
||||||
{id: 19, name: 'Potassium'},
|
|
||||||
{id: 20, name: 'Calcium'},
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Data source for the ProductList view. This class should
|
|
||||||
* encapsulate all logic for fetching and manipulating the displayed data
|
|
||||||
* (including sorting, pagination, and filtering).
|
|
||||||
*/
|
|
||||||
export class ProductListDataSource extends DataSource<ProductListItem> {
|
|
||||||
data: ProductListItem[] = EXAMPLE_DATA;
|
|
||||||
paginator: MatPaginator | undefined;
|
|
||||||
sort: MatSort | undefined;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Connect this data source to the table. The table will only update when
|
|
||||||
* the returned stream emits new items.
|
|
||||||
* @returns A stream of the items to be rendered.
|
|
||||||
*/
|
|
||||||
connect(): Observable<ProductListItem[]> {
|
|
||||||
if (this.paginator && this.sort) {
|
|
||||||
// Combine everything that affects the rendered data into one update
|
|
||||||
// stream for the data-table to consume.
|
|
||||||
return merge(observableOf(this.data), this.paginator.page, this.sort.sortChange)
|
|
||||||
.pipe(map(() => {
|
|
||||||
return this.getPagedData(this.getSortedData([...this.data ]));
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
throw Error('Please set the paginator and sort on the data source before connecting.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the table is being destroyed. Use this function, to clean up
|
|
||||||
* any open connections or free any held resources that were set up during connect.
|
|
||||||
*/
|
|
||||||
disconnect(): void {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Paginate the data (client-side). If you're using server-side pagination,
|
|
||||||
* this would be replaced by requesting the appropriate data from the server.
|
|
||||||
*/
|
|
||||||
private getPagedData(data: ProductListItem[]): ProductListItem[] {
|
|
||||||
if (this.paginator) {
|
|
||||||
const startIndex = this.paginator.pageIndex * this.paginator.pageSize;
|
|
||||||
return data.splice(startIndex, this.paginator.pageSize);
|
|
||||||
} else {
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sort the data (client-side). If you're using server-side sorting,
|
|
||||||
* this would be replaced by requesting the appropriate data from the server.
|
|
||||||
*/
|
|
||||||
private getSortedData(data: ProductListItem[]): ProductListItem[] {
|
|
||||||
if (!this.sort || !this.sort.active || this.sort.direction === '') {
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
return data.sort((a, b) => {
|
|
||||||
const isAsc = this.sort?.direction === 'asc';
|
|
||||||
switch (this.sort?.active) {
|
|
||||||
case 'name': return compare(a.name, b.name, isAsc);
|
|
||||||
case 'id': return compare(+a.id, +b.id, isAsc);
|
|
||||||
default: return 0;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Simple sort comparator for example ID/Name columns (for client-side sorting). */
|
|
||||||
function compare(a: string | number, b: string | number, isAsc: boolean): number {
|
|
||||||
return (a < b ? -1 : 1) * (isAsc ? 1 : -1);
|
|
||||||
}
|
|
|
@ -1,15 +1,18 @@
|
||||||
<div class="mat-elevation-z8">
|
<div class="mat-elevation-z8">
|
||||||
<table mat-table class="full-width-table" matSort aria-label="Elements">
|
<table mat-table class="full-width-table" matSort aria-label="Elements">
|
||||||
<!-- Id Column -->
|
<ng-container matColumnDef="name">
|
||||||
<ng-container matColumnDef="id">
|
<th mat-header-cell *matHeaderCellDef mat-sort-header>Név</th>
|
||||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>Id</th>
|
<td mat-cell *matCellDef="let row">{{row.name}}</td>
|
||||||
<td mat-cell *matCellDef="let row">{{row.id}}</td>
|
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<!-- Name Column -->
|
<ng-container matColumnDef="description">
|
||||||
<ng-container matColumnDef="name">
|
<th mat-header-cell *matHeaderCellDef mat-sort-header>Leirás</th>
|
||||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>Name</th>
|
<td mat-cell *matCellDef="let row">{{row.description}}</td>
|
||||||
<td mat-cell *matCellDef="let row">{{row.name}}</td>
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="price">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header>Ár</th>
|
||||||
|
<td mat-cell *matCellDef="let row">{{row.price}}</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||||
|
@ -17,7 +20,7 @@
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<mat-paginator #paginator
|
<mat-paginator #paginator
|
||||||
[length]="dataSource?.data?.length"
|
[length]="(products | async)?.length"
|
||||||
[pageIndex]="0"
|
[pageIndex]="0"
|
||||||
[pageSize]="10"
|
[pageSize]="10"
|
||||||
[pageSizeOptions]="[5, 10, 20]"
|
[pageSizeOptions]="[5, 10, 20]"
|
||||||
|
|
|
@ -2,7 +2,10 @@ import { AfterViewInit, Component, ViewChild } from '@angular/core';
|
||||||
import { MatTable } from '@angular/material/table';
|
import { MatTable } from '@angular/material/table';
|
||||||
import { MatPaginator } from '@angular/material/paginator';
|
import { MatPaginator } from '@angular/material/paginator';
|
||||||
import { MatSort } from '@angular/material/sort';
|
import { MatSort } from '@angular/material/sort';
|
||||||
import { ProductListDataSource, ProductListItem } from './product-list-datasource';
|
import { ProductService } from '../services/product.service';
|
||||||
|
import { Product } from '../model/product.model';
|
||||||
|
import { map } from 'rxjs/operators';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-product-list',
|
selector: 'app-product-list',
|
||||||
|
@ -12,19 +15,18 @@ import { ProductListDataSource, ProductListItem } from './product-list-datasourc
|
||||||
export class ProductListComponent implements AfterViewInit {
|
export class ProductListComponent implements AfterViewInit {
|
||||||
@ViewChild(MatPaginator) paginator!: MatPaginator;
|
@ViewChild(MatPaginator) paginator!: MatPaginator;
|
||||||
@ViewChild(MatSort) sort!: MatSort;
|
@ViewChild(MatSort) sort!: MatSort;
|
||||||
@ViewChild(MatTable) table!: MatTable<ProductListItem>;
|
@ViewChild(MatTable) table!: MatTable<Product>;
|
||||||
dataSource: ProductListDataSource;
|
|
||||||
|
products: Observable<Product[]>
|
||||||
|
|
||||||
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
|
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
|
||||||
displayedColumns = ['id', 'name'];
|
displayedColumns = ['name', 'description', 'price'];
|
||||||
|
|
||||||
constructor() {
|
constructor(private service: ProductService) {
|
||||||
this.dataSource = new ProductListDataSource();
|
this.products = service.getList().pipe(map(value => value as Product[]));
|
||||||
}
|
}
|
||||||
|
|
||||||
ngAfterViewInit(): void {
|
ngAfterViewInit(): void {
|
||||||
this.dataSource.sort = this.sort;
|
this.table.dataSource = this.products;
|
||||||
this.dataSource.paginator = this.paginator;
|
|
||||||
this.table.dataSource = this.dataSource;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
0
client/src/app/register/register.component.css
Normal file
0
client/src/app/register/register.component.css
Normal file
1
client/src/app/register/register.component.html
Normal file
1
client/src/app/register/register.component.html
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<p>register works!</p>
|
21
client/src/app/register/register.component.spec.ts
Normal file
21
client/src/app/register/register.component.spec.ts
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { RegisterComponent } from './register.component';
|
||||||
|
|
||||||
|
describe('RegisterComponent', () => {
|
||||||
|
let component: RegisterComponent;
|
||||||
|
let fixture: ComponentFixture<RegisterComponent>;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [RegisterComponent]
|
||||||
|
});
|
||||||
|
fixture = TestBed.createComponent(RegisterComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
10
client/src/app/register/register.component.ts
Normal file
10
client/src/app/register/register.component.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-register',
|
||||||
|
templateUrl: './register.component.html',
|
||||||
|
styleUrls: ['./register.component.css']
|
||||||
|
})
|
||||||
|
export class RegisterComponent {
|
||||||
|
|
||||||
|
}
|
13
client/src/app/services/product.service.ts
Normal file
13
client/src/app/services/product.service.ts
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class ProductService {
|
||||||
|
constructor(private http: HttpClient) { }
|
||||||
|
|
||||||
|
getList() {
|
||||||
|
return this.http.get('/api/products')
|
||||||
|
}
|
||||||
|
}
|
|
@ -32,4 +32,8 @@ export class UserService {
|
||||||
this._user = undefined;
|
this._user = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getList() {
|
||||||
|
return this.http.get('/api/users')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
0
client/src/app/user-list/user-list.component.css
Normal file
0
client/src/app/user-list/user-list.component.css
Normal file
29
client/src/app/user-list/user-list.component.html
Normal file
29
client/src/app/user-list/user-list.component.html
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<div class="mat-elevation-z8">
|
||||||
|
<table mat-table class="full-width-table" matSort aria-label="Elements">
|
||||||
|
<ng-container matColumnDef="username">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header>Felhasználónév</th>
|
||||||
|
<td mat-cell *matCellDef="let row">{{row.username}}</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="accessLevel">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header>Hozzáférési szint</th>
|
||||||
|
<td mat-cell *matCellDef="let row">{{row.accessLevel}}</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="birthdate">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header>Születési dátum</th>
|
||||||
|
<td mat-cell *matCellDef="let row">{{row.birthdate | date}}</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||||
|
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<mat-paginator #paginator
|
||||||
|
[length]="(users | async)?.length"
|
||||||
|
[pageIndex]="0"
|
||||||
|
[pageSize]="10"
|
||||||
|
[pageSizeOptions]="[5, 10, 20]"
|
||||||
|
aria-label="Select page">
|
||||||
|
</mat-paginator>
|
||||||
|
</div>
|
21
client/src/app/user-list/user-list.component.spec.ts
Normal file
21
client/src/app/user-list/user-list.component.spec.ts
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { UserListComponent } from './user-list.component';
|
||||||
|
|
||||||
|
describe('UserListComponent', () => {
|
||||||
|
let component: UserListComponent;
|
||||||
|
let fixture: ComponentFixture<UserListComponent>;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [UserListComponent]
|
||||||
|
});
|
||||||
|
fixture = TestBed.createComponent(UserListComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
32
client/src/app/user-list/user-list.component.ts
Normal file
32
client/src/app/user-list/user-list.component.ts
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
import { AfterViewInit, Component, ViewChild } from '@angular/core';
|
||||||
|
import { MatTable } from '@angular/material/table';
|
||||||
|
import { MatPaginator } from '@angular/material/paginator';
|
||||||
|
import { MatSort } from '@angular/material/sort';
|
||||||
|
import { UserService } from '../services/user.service';
|
||||||
|
import { User } from '../model/user.model';
|
||||||
|
import { map } from 'rxjs/operators';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-user-list',
|
||||||
|
templateUrl: './user-list.component.html',
|
||||||
|
styleUrls: ['./user-list.component.css']
|
||||||
|
})
|
||||||
|
export class UserListComponent implements AfterViewInit {
|
||||||
|
@ViewChild(MatPaginator) paginator!: MatPaginator;
|
||||||
|
@ViewChild(MatSort) sort!: MatSort;
|
||||||
|
@ViewChild(MatTable) table!: MatTable<User>;
|
||||||
|
|
||||||
|
users: Observable<User[]>
|
||||||
|
|
||||||
|
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
|
||||||
|
displayedColumns = ['username', 'accessLevel', 'birthdate'];
|
||||||
|
|
||||||
|
constructor(private service: UserService) {
|
||||||
|
this.users = service.getList().pipe(map(value => value as User[]));
|
||||||
|
}
|
||||||
|
|
||||||
|
ngAfterViewInit(): void {
|
||||||
|
this.table.dataSource = this.users;
|
||||||
|
}
|
||||||
|
}
|
|
@ -58,6 +58,13 @@ app.use(passport.session({}));
|
||||||
app.use('/api/users', require('./usersRouter'))
|
app.use('/api/users', require('./usersRouter'))
|
||||||
app.use('/api/products', require('./productsRouter'))
|
app.use('/api/products', require('./productsRouter'))
|
||||||
|
|
||||||
|
app.use(function (req, _, next) {
|
||||||
|
if (!req.url.startsWith('/api') && req.url.indexOf('.') === -1) {
|
||||||
|
req.url = '/';
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
})
|
||||||
|
|
||||||
app.use('', express.static('public'))
|
app.use('', express.static('public'))
|
||||||
|
|
||||||
app.listen(3000, () => {
|
app.listen(3000, () => {
|
||||||
|
|
|
@ -29,7 +29,7 @@ router.get('/', async (req, res) => {
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const products = await Product.find();
|
const products = await Product.find();
|
||||||
res.status(200).json(products);
|
res.status(200).json(products.map(product => getProductData(product)));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
res.status(500).json({ message: error.message });
|
res.status(500).json({ message: error.message });
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ router.get('/:id', getProduct, (req, res) => {
|
||||||
if (!req.isAuthenticated()) {
|
if (!req.isAuthenticated()) {
|
||||||
return res.status(403).json({ message: "Unauthenticated" });
|
return res.status(403).json({ message: "Unauthenticated" });
|
||||||
}
|
}
|
||||||
res.json(res.product);
|
res.json(getProductData(res.product));
|
||||||
});
|
});
|
||||||
|
|
||||||
// POST /products - új termék létrehozása
|
// POST /products - új termék létrehozása
|
||||||
|
|
Loading…
Reference in a new issue