Skip to content

Commit

Permalink
Merge pull request #6 from Popovkov57/development
Browse files Browse the repository at this point in the history
Development
  • Loading branch information
Popovkov57 authored Sep 30, 2022
2 parents 88d0e8e + d889fa2 commit 7b4b67b
Show file tree
Hide file tree
Showing 14 changed files with 251 additions and 12 deletions.
2 changes: 1 addition & 1 deletion authMiddleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ module.exports = function(req, res, next ) {
res.end();
return;
} else if ((((req.url.startsWith("/api/products") || req.url.startsWith("/products"))
||(res.url.startsWith("/api/categories") || req.url.startsWith("/categories"))) && req.method != "GET")
||(req.url.startsWith("/api/categories") || req.url.startsWith("/categories"))) && req.method != "GET")
||((req.url.startsWith("/api/orders") || req.url.startsWith("/orders")) && req.method != "POST")) {
let token = req.headers["authorization"];
if(token != null && token.startsWith("Bearer<")){
Expand Down
3 changes: 2 additions & 1 deletion data.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ module.exports = function() {
{ id: 8, name: "Human Chess Board", category: "Chess", description: "A fun game for the family", price: 75 },
{ id: 9, name: "Bling Bling King", category: "Chess", description: "Gold-plated, diamond-studded King", price: 1200 }
],
orders: []
orders: [],
categories: ["Watersports", "Soccer", "Chess"]
}
}
29 changes: 27 additions & 2 deletions src/app/admin/admin.component.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,28 @@
<div class="bg-info p-2 text-white">
<h3>Placeholder for Admin Features</h3>
<div class="container-fluid">
<div class="row">
<div class="col bg-dark text-white">
<a class="navbar-brand">SPORTS STORE Admin</a>
</div>
</div>
<div class="row mt-2">
<div class="col-3">
<div class="d-grid gap-2">
<button class="btn btn-outline-info btn-block"
routerLink="/admin/main/products" routerLinkActive="active">
Products
</button>
<button class="btn btn-outline-info btn-block"
routerLink="/admin/main/orders" routerLinkActive="active">
Orders
</button>
<button class="btn btn-outline-danger btn-block"
(click)="logout()">
Logout
</button>
</div>
</div>
<div class="col-9">
<router-outlet></router-outlet>
</div>
</div>
</div>
12 changes: 11 additions & 1 deletion src/app/admin/admin.component.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
import { Component } from "@angular/core";
import { Router } from "@angular/router";
import { AuthService } from "../model/auth.service";

@Component({
templateUrl: "admin.component.html"
})

export class AdminComponent {}
export class AdminComponent {

constructor(private auth: AuthService, private router: Router) {}

logout() {
this.auth.clear();
this.router.navigateByUrl("/");
}
}
15 changes: 13 additions & 2 deletions src/app/admin/admin.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,27 @@ import { RouterModule } from "@angular/router";
import { AuthComponent } from "./auth.component";
import { AdminComponent } from "./admin.component";
import { AuthGard } from "./auth.gard";
import { ProductTableComponent } from "./productTable.component";
import { ProductEditorComponent } from "./productEditor.component";
import { OrderTableComponent } from "./orderTable.component";

let routing = RouterModule.forChild([
{ path: "auth", component: AuthComponent },
{ path: "main", component: AdminComponent, canActivate: [AuthGard] },
{ path: "main", component: AdminComponent, canActivate: [AuthGard],
children: [
{ path: "products/:mode/:id", component: ProductEditorComponent },
{ path: "products/:mode", component: ProductEditorComponent },
{ path: "products", component: ProductTableComponent },
{ path: "orders", component: OrderTableComponent },
{ path: "**", redirectTo: "product" },
]
},
{ path: "**", redirectTo: "auth" },
])

@NgModule({
imports: [CommonModule, FormsModule, routing],
providers: [AuthGard],
declarations: [AuthComponent, AdminComponent]
declarations: [AuthComponent, AdminComponent, ProductEditorComponent, ProductTableComponent, OrderTableComponent]
})
export class AdminModule{}
2 changes: 1 addition & 1 deletion src/app/admin/auth.component.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<div class="bg-info p-2 text-center">
<h3>SportsStore Admin</h3>
<h3>SPORTS STORE Authentication</h3>
</div>
<div class="bg-danger mt-2 p-2 text-center text-white" *ngIf="errorMessage != null">
{{ errorMessage }}
Expand Down
7 changes: 7 additions & 0 deletions src/app/admin/orderTable.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Component } from "@angular/core";

@Component({
template: `<div class="bg-info p-2 text-white"><h3>Order Table placeholder</h3></div>`
})

export class OrderTableComponent {}
27 changes: 27 additions & 0 deletions src/app/admin/productEditor.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<div class="bg-primary p-2 text-white" [class.bg-warning]="editing" [class.text-dark]="editing">
<h5> {{ editing ? "Edit" : "Create" }} Product </h5>
</div>
<form novalidate #form="ngForm" (submit)="save(form)">
<div class="form-group">
<label>Name</label>
<input class="form-control" name="name" [(ngModel)]="product.name"/>
</div>
<div class="form-group">
<label>Category</label>
<input class="form-control" name="category" [(ngModel)]="product.category"/>
</div>
<div class="form-group">
<label>Description</label>
<textarea class="form-control" name="description" [(ngModel)]="product.description"></textarea>
</div>
<div class="form-group">
<label>Price</label>
<input class="form-control" name="price" [(ngModel)]="product.price"/>
</div>
<button type="submit" class="btn btn-primary" [class.btn-warning]="editing">
{{ editing ? "Save" : "Create" }}
</button>
<button type="reset" class="btn btn-secondary" routerLink="/admin/main/products">
Cancel
</button>
</form>
30 changes: 30 additions & 0 deletions src/app/admin/productEditor.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Component } from "@angular/core";
import { NgForm } from "@angular/forms";
import { Router, ActivatedRoute } from "@angular/router";
import { Product } from "../model/product.model";
import { ProductRepository } from "../model/product.repository";

@Component({
templateUrl: "productEditor.component.html"
})

export class ProductEditorComponent {

editing: boolean = false;
product: Product = new Product();

constructor(private repository: ProductRepository,
private router: Router,
private activeRoute: ActivatedRoute ) {

this.editing = activeRoute.snapshot.params["mode"] == "edit";
if (this.editing) {
Object.assign(this.product, repository.getProduct(activeRoute.snapshot.params["id"]))
}
}

save(form: NgForm) {
this.repository.saveProduct(this.product);
this.router.navigateByUrl("/admin/main/products");
}
}
30 changes: 30 additions & 0 deletions src/app/admin/productTable.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<table class="table table-sm table-striped">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Category</th>
<th>Price</th>
<th></th>
</tr>
</thead>
<tbody>
<tr *ngFor="let product of getProducts()">
<td>{{ product.id }}</td>
<td>{{ product.name }}</td>
<td>{{ product.category }}</td>
<td>{{ product.price | currency:"USD":"symbol":"2.2-2" }}</td>
<td>
<button class="btn btn-sm btn-warning" [routerLink]="['/admin/main/products/edit', product.id]">
Edit
</button>
<button class="btn btn-sm btn-danger" (click)="deleteProduct(product.id)">
Delete
</button>
</td>
</tr>
</tbody>
</table>
<button class="btn btn-primary" routerLink="/admin/main/products/create">
Create New Product
</button>
21 changes: 21 additions & 0 deletions src/app/admin/productTable.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Component } from "@angular/core";
import { Product } from "../model/product.model";
import { ProductRepository } from "../model/product.repository";

@Component({
templateUrl: "productTable.component.html"
})

export class ProductTableComponent {

constructor(private repository: ProductRepository) {}

getProducts(): Product[] {
return this.repository.getProducts();
}

deleteProduct(id: number) {
this.repository.deleteProduct(id);
}

}
28 changes: 26 additions & 2 deletions src/app/model/order.repository.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,44 @@
import { Injectable } from "@angular/core";
import { Observable } from "rxjs";
import { Order } from "./order.model";
import { StaticDataSource } from "./static.datasource";
//import { StaticDataSource } from "./static.datasource";
import { RestDataSource } from "./rest.datasource";

@Injectable()
export class OrderRepository {

private orders: Order[] = [];
private loaded: boolean = false;

constructor(private dataSource: StaticDataSource) {}
constructor(private dataSource: RestDataSource) {}

loadOrders() {
this.loaded = true;
this.dataSource.getOrders().subscribe(o => {
this.orders = o;
});
}

getOrders(): Order[] {
if (!this.loaded) {
this.loadOrders();
}
return this.orders;
}

saveOrder(order: Order): Observable<Order> {
return this.dataSource.saveOrder(order);
}

updateOrder(order: Order) {
this.dataSource.updateOrder(order).subscribe(o => {
this.orders.splice(this.orders.findIndex(o => o.id = order.id), 1, order);
})
}

deleteOrder(id: number) {
this.dataSource.deleteOrder(id).subscribe(o => {
this.orders.splice(this.orders.findIndex(o => o.id == id), 1);
})
}
}
24 changes: 22 additions & 2 deletions src/app/model/product.repository.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { Injectable } from "@angular/core";
import { Product } from "./product.model";
import { StaticDataSource } from "./static.datasource";
//import { StaticDataSource } from "./static.datasource";
import { RestDataSource } from "./rest.datasource";

@Injectable()
export class ProductRepository {
private products: Product[] = [];
private categories: string[] = [];

constructor(private dataSource: StaticDataSource) {
constructor(private dataSource: RestDataSource) {
dataSource.getProducts().subscribe(data => {
this.products = data;
this.categories = data.map(p => p.category).filter((c, index, array) => array.indexOf(c) == index).sort();
Expand All @@ -25,4 +26,23 @@ export class ProductRepository {
getCategories(): string[] {
return this.categories;
}

saveProduct(product: Product) {
if (product.id == null || product.id == 0) {
this.dataSource.saveProduct(product).subscribe(p => this.products.push(p));
} else {
this.dataSource.updateProduct(product)
.subscribe(p => {
this.products.splice(this.products.
findIndex(p => p.id == product.id), 1, product);
});
}
}

deleteProduct(id: number) {
this.dataSource.deleteProduct(id).subscribe(p => {
let index = this.products.findIndex(p => p.id == id);
this.products.splice(index, 1);
});
}
}
33 changes: 33 additions & 0 deletions src/app/model/rest.datasource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Product } from "./product.model";
import { Cart } from "./cart.model";
import { Order } from "./order.model";
import { map } from "rxjs";
import { HttpHeaders } from "@angular/common/http";

const PROTOCOL = "http";
const PORT = 3500;
Expand Down Expand Up @@ -36,4 +37,36 @@ export class RestDataSource {
return response.success;
}))
}

saveProduct(product: Product): Observable<Product> {
return this.http.post<Product>(this.baseUrl + "products", product, this.getOptions());
}

updateProduct(product: Product): Observable<Product> {
return this.http.put<Product>(`${this.baseUrl}products/${product.id}`, product, this.getOptions());
}

deleteProduct(id: number): Observable<Product> {
return this.http.delete<Product>(`${this.baseUrl}products/${id}`, this.getOptions());
}

getOrders(): Observable<Order[]> {
return this.http.get<Order[]>(this.baseUrl + "orders", this.getOptions());
}

deleteOrder(id: number): Observable<Order> {
return this.http.delete<Order>(`${this.baseUrl}orders/${id}`, this.getOptions());
}

updateOrder(order: Order): Observable<Order> {
return this.http.put<Order>(`${this.baseUrl}order/${order.id}`, order, this.getOptions());
}

private getOptions() {
return {
headers: new HttpHeaders({
"Authorization": `Bearer<${this.auth_token}>`
})
}
}
}

0 comments on commit 7b4b67b

Please sign in to comment.