Initial commit
This commit is contained in:
commit
76232e4856
16
.editorconfig
Normal file
16
.editorconfig
Normal file
@ -0,0 +1,16 @@
|
||||
# Editor configuration, see https://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.ts]
|
||||
quote_type = single
|
||||
|
||||
[*.md]
|
||||
max_line_length = off
|
||||
trim_trailing_whitespace = false
|
||||
31
.github/workflows/node.js.yml
vendored
Normal file
31
.github/workflows/node.js.yml
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
|
||||
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs
|
||||
|
||||
name: Node.js CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "prod" ]
|
||||
pull_request:
|
||||
branches: [ "prod" ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [20.x]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: 'npm'
|
||||
- run: npm install
|
||||
- run: npm install -g @angular/cli
|
||||
- run: npm run build
|
||||
- run: npm test
|
||||
45
.gitignore
vendored
Normal file
45
.gitignore
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
.*
|
||||
|
||||
# Compiled output
|
||||
/dist
|
||||
/tmp
|
||||
/out-tsc
|
||||
/bazel-out
|
||||
|
||||
# Node
|
||||
/node_modules
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
|
||||
# IDEs and editors
|
||||
.idea/
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
|
||||
# Visual Studio Code
|
||||
.vscode
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
.history/*
|
||||
|
||||
# Miscellaneous
|
||||
/.angular/cache
|
||||
.sass-cache/
|
||||
/connect.lock
|
||||
/coverage
|
||||
/libpeerconnection.log
|
||||
testem.log
|
||||
/typings
|
||||
|
||||
# System files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
27
README.md
Normal file
27
README.md
Normal file
@ -0,0 +1,27 @@
|
||||
# Homepage
|
||||
|
||||
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 15.2.6.
|
||||
|
||||
## Development server
|
||||
|
||||
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files.
|
||||
|
||||
## Code scaffolding
|
||||
|
||||
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
|
||||
|
||||
## Build
|
||||
|
||||
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||
|
||||
## Running end-to-end tests
|
||||
|
||||
Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.
|
||||
|
||||
## Further help
|
||||
|
||||
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
|
||||
126
angular.json
Normal file
126
angular.json
Normal file
@ -0,0 +1,126 @@
|
||||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"version": 1,
|
||||
"newProjectRoot": "projects",
|
||||
"projects": {
|
||||
"homepage": {
|
||||
"projectType": "application",
|
||||
"schematics": {
|
||||
"@schematics/angular:component": {
|
||||
"style": "scss",
|
||||
"skipTests": true
|
||||
},
|
||||
"@schematics/angular:class": {
|
||||
"skipTests": true
|
||||
},
|
||||
"@schematics/angular:directive": {
|
||||
"skipTests": true
|
||||
},
|
||||
"@schematics/angular:guard": {
|
||||
"skipTests": true
|
||||
},
|
||||
"@schematics/angular:module": {
|
||||
"skipTests": true
|
||||
},
|
||||
"@schematics/angular:pipe": {
|
||||
"skipTests": true
|
||||
},
|
||||
"@schematics/angular:service": {
|
||||
"skipTests": true
|
||||
}
|
||||
},
|
||||
"root": "",
|
||||
"sourceRoot": "src",
|
||||
"prefix": "app",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:browser",
|
||||
"options": {
|
||||
"outputPath": "dist/homepage",
|
||||
"index": "src/index.html",
|
||||
"main": "src/main.ts",
|
||||
"polyfills": [
|
||||
"zone.js"
|
||||
],
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"assets": [
|
||||
"src/assets",
|
||||
"src/favicon.ico"
|
||||
],
|
||||
"styles": [
|
||||
"@angular/material/prebuilt-themes/deeppurple-amber.css",
|
||||
"src/styles.scss"
|
||||
],
|
||||
"scripts": []
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "800kb",
|
||||
"maximumError": "2mb"
|
||||
},
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
"maximumWarning": "2kb",
|
||||
"maximumError": "4kb"
|
||||
}
|
||||
],
|
||||
"outputHashing": "all"
|
||||
},
|
||||
"development": {
|
||||
"buildOptimizer": false,
|
||||
"optimization": false,
|
||||
"vendorChunk": true,
|
||||
"extractLicenses": false,
|
||||
"sourceMap": true,
|
||||
"namedChunks": true
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"configurations": {
|
||||
"production": {
|
||||
"browserTarget": "homepage:build:production"
|
||||
},
|
||||
"development": {
|
||||
"browserTarget": "homepage:build:development"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "development"
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||
"options": {
|
||||
"browserTarget": "homepage:build"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"polyfills": [
|
||||
"zone.js",
|
||||
"zone.js/testing"
|
||||
],
|
||||
"tsConfig": "tsconfig.spec.json",
|
||||
"assets": [
|
||||
"src/assets",
|
||||
"src/favicon.ico"
|
||||
],
|
||||
"styles": [
|
||||
"@angular/material/prebuilt-themes/deeppurple-amber.scss",
|
||||
"src/styles.scss"
|
||||
],
|
||||
"scripts": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"cli": {
|
||||
"analytics": false
|
||||
}
|
||||
}
|
||||
3
bin/script/build
Executable file
3
bin/script/build
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
$SCRIPT_DIR/exec build
|
||||
3
bin/script/down
Executable file
3
bin/script/down
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
$SCRIPT_DIR/exec down
|
||||
23
bin/script/exec
Executable file
23
bin/script/exec
Executable file
@ -0,0 +1,23 @@
|
||||
#!/bin/bash
|
||||
|
||||
COMMAND="$@"
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
|
||||
#LOAD ENV VARIABLES FROM .ENV
|
||||
#export $(grep -v '^#' "${SCRIPT_DIR}/../../.env" | xargs)
|
||||
|
||||
#MAC
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
docker-compose -f "${SCRIPT_DIR}/../../docker/docker-compose-mac.yml" $COMMAND
|
||||
|
||||
#LINUX
|
||||
elif [[ "$OSTYPE" == "linux-gnu" ]]; then
|
||||
docker-compose -f "${SCRIPT_DIR}/../../docker/docker-compose.yml" $COMMAND
|
||||
|
||||
else
|
||||
echo "Dieses Skript wird auf deinem Gerät nicht unterstützt"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#UNSET ENV VARIABLES FROM .ENV
|
||||
#unset $(grep -v '^#' "${SCRIPT_DIR}/../../.env" | sed -E 's/(.*)=.*/\1/' | xargs)
|
||||
19
bin/script/init
Executable file
19
bin/script/init
Executable file
@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
PROJECT_DIR=$(realpath $SCRIPT_DIR/../../)
|
||||
ENV_DIR=$(realpath $PROJECT_DIR/../../)
|
||||
|
||||
# Build and start docker containers
|
||||
$SCRIPT_DIR/exec build
|
||||
$SCRIPT_DIR/exec up -d
|
||||
|
||||
# Source drun
|
||||
source $ENV_DIR/bin/script/drun
|
||||
|
||||
# Install node Packages
|
||||
drun homepage-frontend npm install
|
||||
drun homepage-frontend npm install -g @angular/cli
|
||||
|
||||
# Initial build of website
|
||||
drun homepage-frontend npm run build
|
||||
3
bin/script/stop
Executable file
3
bin/script/stop
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
$SCRIPT_DIR/exec stop
|
||||
3
bin/script/up
Executable file
3
bin/script/up
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
$SCRIPT_DIR/exec up -d
|
||||
31
docker/docker-compose-mac.yml
Normal file
31
docker/docker-compose-mac.yml
Normal file
@ -0,0 +1,31 @@
|
||||
version: '3'
|
||||
|
||||
networks:
|
||||
homepage:
|
||||
external: true
|
||||
|
||||
services:
|
||||
homepage-frontend-app:
|
||||
image: homepage-frontend-app
|
||||
networks:
|
||||
- homepage
|
||||
volumes:
|
||||
- /Users/flo/dev/frontend/homepage/:/var/www/
|
||||
build:
|
||||
context: ./../
|
||||
dockerfile: ./docker/npm/dockerfile
|
||||
tty: true
|
||||
|
||||
homepage-frontend-nginx:
|
||||
image: homepage-frontend-nginx
|
||||
networks:
|
||||
- homepage
|
||||
volumes:
|
||||
- /Users/flo/dev/frontend/homepage/:/var/www/html:z
|
||||
build:
|
||||
context: ./../
|
||||
dockerfile: ./docker/nginx/dockerfile
|
||||
ports:
|
||||
- 80:80
|
||||
depends_on:
|
||||
- homepage-frontend-app
|
||||
31
docker/docker-compose.yml
Normal file
31
docker/docker-compose.yml
Normal file
@ -0,0 +1,31 @@
|
||||
version: '3'
|
||||
|
||||
networks:
|
||||
homepage:
|
||||
external: true
|
||||
|
||||
services:
|
||||
homepage-frontend-app:
|
||||
image: homepage-frontend-app
|
||||
networks:
|
||||
- homepage
|
||||
volumes:
|
||||
- ./../:/var/www/
|
||||
build:
|
||||
context: ./../
|
||||
dockerfile: ./docker/npm/dockerfile
|
||||
tty: true
|
||||
|
||||
homepage-frontend-nginx:
|
||||
image: homepage-frontend-nginx
|
||||
networks:
|
||||
- homepage
|
||||
volumes:
|
||||
- ./../:/var/www/html:z
|
||||
build:
|
||||
context: ./../
|
||||
dockerfile: ./docker/nginx/dockerfile
|
||||
ports:
|
||||
- 80:80
|
||||
depends_on:
|
||||
- homepage-frontend-app
|
||||
25
docker/nginx/config/nginx.conf
Normal file
25
docker/nginx/config/nginx.conf
Normal file
@ -0,0 +1,25 @@
|
||||
upstream host-backend-nginx {
|
||||
server homepage-backend-nginx:80;
|
||||
}
|
||||
|
||||
|
||||
server{
|
||||
listen 80 default_server;
|
||||
|
||||
root /var/www/html/dist/homepage;
|
||||
index index.html;
|
||||
|
||||
location / {
|
||||
try_files $uri$args $uri$args/ /index.html;
|
||||
}
|
||||
|
||||
location /api/ {
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-NginX-Proxy true;
|
||||
|
||||
proxy_pass http://host-backend-nginx;
|
||||
}
|
||||
}
|
||||
5
docker/nginx/dockerfile
Normal file
5
docker/nginx/dockerfile
Normal file
@ -0,0 +1,5 @@
|
||||
FROM nginx:alpine
|
||||
|
||||
COPY docker/nginx/config/nginx.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
12
docker/npm/dockerfile
Normal file
12
docker/npm/dockerfile
Normal file
@ -0,0 +1,12 @@
|
||||
FROM node:latest
|
||||
|
||||
WORKDIR /var/www/html
|
||||
|
||||
# confirm installation
|
||||
RUN node -v
|
||||
RUN npm -v
|
||||
|
||||
# use newest npm version
|
||||
RUN npm install npm
|
||||
|
||||
CMD ["/bin/bash"]
|
||||
12673
package-lock.json
generated
Normal file
12673
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
40
package.json
Normal file
40
package.json
Normal file
@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "homepage",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
"build": "ng build",
|
||||
"watch": "ng build --watch --configuration development",
|
||||
"test": "ng test"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "^15.2.0",
|
||||
"@angular/cdk": "^15.2.9",
|
||||
"@angular/common": "^15.2.0",
|
||||
"@angular/compiler": "^15.2.0",
|
||||
"@angular/core": "^15.2.0",
|
||||
"@angular/forms": "^15.2.0",
|
||||
"@angular/material": "^15.2.9",
|
||||
"@angular/platform-browser": "^15.2.0",
|
||||
"@angular/platform-browser-dynamic": "^15.2.0",
|
||||
"@angular/router": "^15.2.0",
|
||||
"rxjs": "~7.8.0",
|
||||
"tslib": "^2.3.0",
|
||||
"zone.js": "~0.12.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "^15.2.6",
|
||||
"@angular/cli": "~15.2.6",
|
||||
"@angular/compiler-cli": "^15.2.0",
|
||||
"@types/jasmine": "~4.3.0",
|
||||
"jasmine-core": "~4.5.0",
|
||||
"karma": "~6.4.0",
|
||||
"karma-chrome-launcher": "~3.1.0",
|
||||
"karma-coverage": "~2.2.0",
|
||||
"karma-jasmine": "~5.1.0",
|
||||
"karma-jasmine-html-reporter": "~2.0.0",
|
||||
"typescript": "~4.9.4"
|
||||
}
|
||||
}
|
||||
20
src/app/app-routing.module.ts
Normal file
20
src/app/app-routing.module.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { LoginComponent } from './auth/login/login.component';
|
||||
import { HomeComponent } from './home/home.component';
|
||||
import { RegistrationComponent } from './auth/registration/registration.component';
|
||||
import { RegistrationConfirmationComponent } from './auth/registration-confirmation/registration-confirmation.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: 'auth', component: LoginComponent },
|
||||
{ path: 'auth/registration', component: RegistrationComponent },
|
||||
{ path: 'auth/registration/:id', component: RegistrationConfirmationComponent },
|
||||
{ path: 'home', component: HomeComponent },
|
||||
{ path: '', redirectTo: '/auth', pathMatch: 'full' },
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forRoot(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class AppRoutingModule { }
|
||||
1
src/app/app.component.html
Normal file
1
src/app/app.component.html
Normal file
@ -0,0 +1 @@
|
||||
<router-outlet></router-outlet>
|
||||
4
src/app/app.component.scss
Normal file
4
src/app/app.component.scss
Normal file
@ -0,0 +1,4 @@
|
||||
app-login {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
}
|
||||
9
src/app/app.component.ts
Normal file
9
src/app/app.component.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.scss']
|
||||
})
|
||||
export class AppComponent {
|
||||
}
|
||||
74
src/app/app.module.ts
Normal file
74
src/app/app.module.ts
Normal file
@ -0,0 +1,74 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
|
||||
import { MatSidenavModule } from '@angular/material/sidenav';
|
||||
import { MatToolbarModule } from '@angular/material/toolbar';
|
||||
import { MatMenuModule } from '@angular/material/menu';
|
||||
import { MatListModule } from '@angular/material/list';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatGridListModule } from '@angular/material/grid-list'
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatExpansionModule } from '@angular/material/expansion';
|
||||
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatDividerModule } from '@angular/material/divider';
|
||||
import {MatDialogModule} from '@angular/material/dialog';
|
||||
import {MatSnackBarModule} from '@angular/material/snack-bar';
|
||||
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import { AppComponent } from './app.component';
|
||||
import { ProductListComponent } from './product/product-list/product-list.component';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { HomeComponent } from './home/home.component';
|
||||
import { ProductDetailsComponent } from './product/product-details/product-details.component';
|
||||
import { LoginComponent } from './auth/login/login.component';
|
||||
import { CreateProductComponent } from './product/create-product/create-product.component';
|
||||
import { RegistrationComponent } from './auth/registration/registration.component';
|
||||
import { RegistrationConfirmationComponent } from './auth/registration-confirmation/registration-confirmation.component';
|
||||
import { ProductComponent } from './product/product/product.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent,
|
||||
ProductListComponent,
|
||||
ProductDetailsComponent,
|
||||
LoginComponent,
|
||||
HomeComponent,
|
||||
CreateProductComponent,
|
||||
RegistrationComponent,
|
||||
RegistrationConfirmationComponent,
|
||||
ProductComponent,
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
HttpClientModule,
|
||||
AppRoutingModule,
|
||||
BrowserAnimationsModule,
|
||||
MatSlideToggleModule,
|
||||
MatCardModule,
|
||||
MatButtonModule,
|
||||
MatIconModule,
|
||||
MatGridListModule,
|
||||
MatFormFieldModule,
|
||||
FormsModule,
|
||||
MatExpansionModule,
|
||||
MatMenuModule,
|
||||
MatListModule,
|
||||
MatToolbarModule,
|
||||
MatSidenavModule,
|
||||
MatInputModule,
|
||||
MatSelectModule,
|
||||
MatDividerModule,
|
||||
MatDialogModule,
|
||||
MatSnackBarModule
|
||||
],
|
||||
providers: [],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule { }
|
||||
21
src/app/app.service.ts
Normal file
21
src/app/app.service.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class AppService {
|
||||
|
||||
private username: string|null;
|
||||
|
||||
constructor() {
|
||||
this.username = null;
|
||||
}
|
||||
|
||||
public getUsername(): string|null {
|
||||
return this.username;
|
||||
}
|
||||
|
||||
public setUsername(name: string|null): void {
|
||||
this.username = name;
|
||||
}
|
||||
}
|
||||
41
src/app/auth/login/login.component.html
Normal file
41
src/app/auth/login/login.component.html
Normal file
@ -0,0 +1,41 @@
|
||||
<mat-card>
|
||||
<mat-card-header>
|
||||
<mat-card-title>Login</mat-card-title>
|
||||
<mat-card-subtitle>Bitte melde Dich an</mat-card-subtitle>
|
||||
</mat-card-header>
|
||||
|
||||
<mat-card-content>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<mat-form-field>
|
||||
<mat-label>Identifier</mat-label>
|
||||
<input matInput [(ngModel)]="identifier">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="row">
|
||||
<mat-form-field>
|
||||
<mat-label>Password</mat-label>
|
||||
<input matInput type="password" [(ngModel)]="password">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md">
|
||||
<button mat-fab
|
||||
extended
|
||||
color="disabled"
|
||||
(click)="register()">
|
||||
Registrieren
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-md">
|
||||
<button mat-fab
|
||||
extended
|
||||
color="primary"
|
||||
(click)="login()">
|
||||
Login
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
23
src/app/auth/login/login.component.scss
Normal file
23
src/app/auth/login/login.component.scss
Normal file
@ -0,0 +1,23 @@
|
||||
mat-card {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
|
||||
button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* For tablet: */
|
||||
@media only screen and (min-width: 600px) {
|
||||
mat-card {
|
||||
width: 70%;
|
||||
}
|
||||
}
|
||||
|
||||
/* For desktop: */
|
||||
@media only screen and (min-width: 768px) {
|
||||
mat-card {
|
||||
width: 40%;
|
||||
}
|
||||
}
|
||||
60
src/app/auth/login/login.component.ts
Normal file
60
src/app/auth/login/login.component.ts
Normal file
@ -0,0 +1,60 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { RequestService } from '../../request.service';
|
||||
import { Router } from "@angular/router"
|
||||
import { AppService } from '../../app.service';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-login',
|
||||
templateUrl: './login.component.html',
|
||||
styleUrls: ['./login.component.scss']
|
||||
})
|
||||
export class LoginComponent implements OnInit {
|
||||
identifier: string|null = null;
|
||||
password: string|null = null;
|
||||
|
||||
constructor(
|
||||
public appService : AppService,
|
||||
public requestService : RequestService,
|
||||
private router: Router
|
||||
) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.stateRequest();
|
||||
}
|
||||
|
||||
login() {
|
||||
this.requestService.post(
|
||||
'auth/login-user',
|
||||
{
|
||||
identifier: this.identifier,
|
||||
password: this.password
|
||||
},
|
||||
(response:any) => {
|
||||
if(response.hasOwnProperty('sessionId')) {
|
||||
this.router.navigate(['/home']);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
register() {
|
||||
console.log('goto registration');
|
||||
this.router.navigate(['/auth/registration']);
|
||||
}
|
||||
|
||||
private stateRequest() {
|
||||
this.requestService.get(
|
||||
'user/state',
|
||||
{},
|
||||
(response:any) => {
|
||||
if (response.hasOwnProperty('sessionId')) {
|
||||
this.appService.setUsername(response.username);
|
||||
this.router.navigate(['/home']);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
<mat-card>
|
||||
<mat-card-header>
|
||||
<mat-card-title>Registrierung bestätigen</mat-card-title>
|
||||
<mat-card-subtitle>Bitte gib dein Passwort ein</mat-card-subtitle>
|
||||
</mat-card-header>
|
||||
|
||||
<mat-card-content>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<mat-form-field>
|
||||
<mat-label>Passwort</mat-label>
|
||||
<input matInput type="password" [(ngModel)]="password">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="row">
|
||||
<mat-form-field>
|
||||
<mat-label>Passwort wiederholen</mat-label>
|
||||
<input matInput type="password" [(ngModel)]="passwordConfirmation">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md">
|
||||
<button mat-fab
|
||||
extended
|
||||
color="primary"
|
||||
(click)="confirm()">
|
||||
Bestätigen
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
@ -0,0 +1,23 @@
|
||||
mat-card {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
|
||||
button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* For tablet: */
|
||||
@media only screen and (min-width: 600px) {
|
||||
mat-card {
|
||||
width: 70%;
|
||||
}
|
||||
}
|
||||
|
||||
/* For desktop: */
|
||||
@media only screen and (min-width: 768px) {
|
||||
mat-card {
|
||||
width: 40%;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { RequestService } from '../../request.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-registration-confirmation',
|
||||
templateUrl: './registration-confirmation.component.html',
|
||||
styleUrls: ['./registration-confirmation.component.scss']
|
||||
})
|
||||
export class RegistrationConfirmationComponent implements OnInit {
|
||||
public id: string;
|
||||
public password: string|null = null;
|
||||
public passwordConfirmation: string|null = null;
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
public requestService : RequestService,
|
||||
private router: Router
|
||||
) {
|
||||
this.id = '';
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.id = this.route.snapshot.paramMap.get('id') ?? '';
|
||||
}
|
||||
|
||||
confirm() {
|
||||
this.requestService.post(
|
||||
'auth/confirm-registration',
|
||||
{
|
||||
id: this.id,
|
||||
password: this.password,
|
||||
passwordConfirmation: this.passwordConfirmation,
|
||||
},
|
||||
(response:any) => {
|
||||
this.router.navigate(['/auth']);
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
33
src/app/auth/registration/registration.component.html
Normal file
33
src/app/auth/registration/registration.component.html
Normal file
@ -0,0 +1,33 @@
|
||||
<mat-card>
|
||||
<mat-card-header>
|
||||
<mat-card-title>Registrieren</mat-card-title>
|
||||
<mat-card-subtitle>Bitte gib deine Benutzerdaten an:</mat-card-subtitle>
|
||||
</mat-card-header>
|
||||
|
||||
<mat-card-content>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<mat-form-field>
|
||||
<mat-label>Benutzername</mat-label>
|
||||
<input matInput [(ngModel)]="username">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="row">
|
||||
<mat-form-field>
|
||||
<mat-label>E-Mail</mat-label>
|
||||
<input matInput [(ngModel)]="mail">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md">
|
||||
<button mat-fab
|
||||
extended
|
||||
color="primary"
|
||||
(click)="register()">
|
||||
Registrieren
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
23
src/app/auth/registration/registration.component.scss
Normal file
23
src/app/auth/registration/registration.component.scss
Normal file
@ -0,0 +1,23 @@
|
||||
mat-card {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
|
||||
button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* For tablet: */
|
||||
@media only screen and (min-width: 600px) {
|
||||
mat-card {
|
||||
width: 70%;
|
||||
}
|
||||
}
|
||||
|
||||
/* For desktop: */
|
||||
@media only screen and (min-width: 768px) {
|
||||
mat-card {
|
||||
width: 40%;
|
||||
}
|
||||
}
|
||||
39
src/app/auth/registration/registration.component.ts
Normal file
39
src/app/auth/registration/registration.component.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { AppService } from '../../app.service';
|
||||
import { RequestService } from '../../request.service';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'app-registration',
|
||||
templateUrl: './registration.component.html',
|
||||
styleUrls: ['./registration.component.scss']
|
||||
})
|
||||
export class RegistrationComponent {
|
||||
username: string|null = null;
|
||||
mail: string|null = null;
|
||||
|
||||
constructor(
|
||||
public appService : AppService,
|
||||
public requestService : RequestService,
|
||||
private router: Router
|
||||
) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.username = "";
|
||||
this.mail = "";
|
||||
}
|
||||
|
||||
register(): void {
|
||||
this.requestService.post(
|
||||
'auth/register-user',
|
||||
{
|
||||
username: this.username,
|
||||
mail: this.mail
|
||||
},
|
||||
(response:any) => {
|
||||
this.router.navigate(['/auth']);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
26
src/app/home/home.component.html
Normal file
26
src/app/home/home.component.html
Normal file
@ -0,0 +1,26 @@
|
||||
<mat-toolbar color="primary">
|
||||
<button mat-icon-button (click)="drawer.toggle(); list.onGetProductList()">
|
||||
<mat-icon>menu</mat-icon>
|
||||
</button>
|
||||
|
||||
|
||||
<span>
|
||||
{{title}}
|
||||
</span>
|
||||
|
||||
<button mat-button [matMenuTriggerFor]="menu">{{username}}</button>
|
||||
<mat-menu #menu="matMenu">
|
||||
<button mat-menu-item (click)="logout()">Logout</button>
|
||||
</mat-menu>
|
||||
</mat-toolbar>
|
||||
|
||||
<mat-drawer-container class="content">
|
||||
<mat-drawer #drawer class="example-sidenav" mode="over">
|
||||
<app-product-list #list (productSelected)="selectProduct($event); drawer.toggle(); list.onGetProductList()">
|
||||
</app-product-list>
|
||||
</mat-drawer>
|
||||
|
||||
<div class="example-sidenav-content">
|
||||
<app-product-details [product]="selectedProduct"></app-product-details>
|
||||
</div>
|
||||
</mat-drawer-container>
|
||||
13
src/app/home/home.component.scss
Normal file
13
src/app/home/home.component.scss
Normal file
@ -0,0 +1,13 @@
|
||||
span {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.content {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.example-sidenav-content {
|
||||
margin: 1em;
|
||||
height: 100%;
|
||||
}
|
||||
52
src/app/home/home.component.ts
Normal file
52
src/app/home/home.component.ts
Normal file
@ -0,0 +1,52 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Product } from '../product/product-list/product-list.component';
|
||||
import { RequestService } from '../request.service';
|
||||
import { Router } from "@angular/router"
|
||||
import { AppService } from '../app.service';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-home',
|
||||
templateUrl: './home.component.html',
|
||||
styleUrls: ['./home.component.scss']
|
||||
})
|
||||
export class HomeComponent {
|
||||
title = 'Homepage';
|
||||
username: string = "(null)";
|
||||
selectedProduct: Product|null = null;
|
||||
|
||||
constructor(
|
||||
public appService : AppService,
|
||||
public requestService : RequestService,
|
||||
private router: Router
|
||||
) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.requestService.get(
|
||||
'user/state',
|
||||
{},
|
||||
(response:any) => {
|
||||
if (response.status == 401) {
|
||||
this.router.navigate(['/auth']);
|
||||
} else {
|
||||
this.username = response.username;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
logout() {
|
||||
this.requestService.post(
|
||||
'auth/logout-user',
|
||||
{},
|
||||
(response:any) => {
|
||||
this.router.navigate(['/auth']);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
selectProduct(product: any) {
|
||||
this.selectedProduct = product;
|
||||
}
|
||||
}
|
||||
28
src/app/product/create-product/create-product.component.html
Normal file
28
src/app/product/create-product/create-product.component.html
Normal file
@ -0,0 +1,28 @@
|
||||
<mat-card>
|
||||
<mat-card-header>
|
||||
<mat-card-title>Neues Produkt</mat-card-title>
|
||||
<mat-card-subtitle>Bitte gebe die Daten des neuen Produkts an</mat-card-subtitle>
|
||||
</mat-card-header>
|
||||
|
||||
<mat-card-content>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<mat-form-field>
|
||||
<mat-label>Identifier</mat-label>
|
||||
<input matInput [(ngModel)]="identifier">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="row">
|
||||
<mat-form-field>
|
||||
<mat-label>Name</mat-label>
|
||||
<input matInput [(ngModel)]="name">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
|
||||
<mat-card-actions>
|
||||
<button mat-button (click)="cancel()">Abbrechen</button>
|
||||
<button mat-button [mat-dialog-close]="{identifier: identifier, name: name}" cdkFocusInitial>Ok</button>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
||||
24
src/app/product/create-product/create-product.component.ts
Normal file
24
src/app/product/create-product/create-product.component.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { MatDialogRef } from '@angular/material/dialog';
|
||||
|
||||
@Component({
|
||||
selector: 'app-create-product',
|
||||
templateUrl: './create-product.component.html',
|
||||
styleUrls: ['./create-product.component.scss']
|
||||
})
|
||||
export class CreateProductComponent {
|
||||
name: string
|
||||
identifier: string
|
||||
|
||||
constructor(
|
||||
private dialogRef: MatDialogRef<CreateProductComponent>
|
||||
) {
|
||||
this.name = '';
|
||||
this.identifier = '';
|
||||
}
|
||||
|
||||
cancel(){
|
||||
this.dialogRef.close();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
<iframe *ngIf="url != null" [src]="url">
|
||||
|
||||
</iframe>
|
||||
|
||||
<mat-card *ngIf="product != null">
|
||||
<mat-card-header>
|
||||
<mat-card-title>{{product.name}}</mat-card-title>
|
||||
<mat-card-subtitle>{{product.identifier}} - {{product.id}}</mat-card-subtitle>
|
||||
</mat-card-header>
|
||||
|
||||
<mat-divider/>
|
||||
|
||||
<mat-card-content>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<mat-form-field>
|
||||
<mat-label>Identifier</mat-label>
|
||||
<input matInput [(ngModel)]="product.identifier">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="row">
|
||||
<mat-form-field>
|
||||
<mat-label>Name</mat-label>
|
||||
<input matInput [(ngModel)]="product.name">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="row">
|
||||
<mat-form-field>
|
||||
<mat-label>Url</mat-label>
|
||||
<input matInput [(ngModel)]="product.url">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md">
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Erstellt am</mat-label>
|
||||
<input matInput [(ngModel)]="product.created" readonly>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-md">
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Zuletzt geändert am</mat-label>
|
||||
<input matInput [(ngModel)]="product.updated" readonly>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
|
||||
<mat-card-actions align="end">
|
||||
<button mat-fab color="primary"
|
||||
(click)="updateProduct(product)">
|
||||
<mat-icon>save</mat-icon>
|
||||
</button>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
||||
@ -0,0 +1,36 @@
|
||||
app-login {
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
mat-form-field {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
mat-divider {
|
||||
margin-top: 0.5em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
mat-card {
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* For tablet: */
|
||||
@media only screen and (min-width: 600px) {
|
||||
mat-card {
|
||||
max-width: 85%;
|
||||
}
|
||||
}
|
||||
|
||||
/* For desktop: */
|
||||
@media only screen and (min-width: 768px) {
|
||||
mat-card {
|
||||
max-width: 85%;
|
||||
}
|
||||
}
|
||||
40
src/app/product/product-details/product-details.component.ts
Normal file
40
src/app/product/product-details/product-details.component.ts
Normal file
@ -0,0 +1,40 @@
|
||||
import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
|
||||
import { RequestService } from '../../request.service';
|
||||
import { Product } from '../product-list/product-list.component';
|
||||
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
|
||||
|
||||
@Component({
|
||||
selector: 'app-product-details',
|
||||
templateUrl: './product-details.component.html',
|
||||
styleUrls: ['./product-details.component.scss']
|
||||
})
|
||||
export class ProductDetailsComponent implements OnChanges {
|
||||
@Input() product: Product|null = null
|
||||
url: SafeResourceUrl|null = null;
|
||||
|
||||
|
||||
constructor(
|
||||
public requestService : RequestService,
|
||||
private domSanitizer: DomSanitizer
|
||||
) {
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (this.product != null && this.product.url != null) {
|
||||
this.url = this.domSanitizer.bypassSecurityTrustResourceUrl(this.product.url);
|
||||
}
|
||||
else {
|
||||
this.url = null;
|
||||
}
|
||||
}
|
||||
|
||||
updateProduct(product: Product) {
|
||||
this.requestService.post(
|
||||
'product/update-product',
|
||||
product,
|
||||
(response:any) => {
|
||||
this.product = response
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
17
src/app/product/product-list/product-list.component.html
Normal file
17
src/app/product/product-list/product-list.component.html
Normal file
@ -0,0 +1,17 @@
|
||||
<mat-list>
|
||||
<mat-list-item class="listItem" *ngFor="let product of products" (click)="selectProduct(product)">
|
||||
<mat-icon matListItemIcon (click)="removeProduct(product)"> delete</mat-icon>
|
||||
<span matListItemTitle>{{product.name}}</span>
|
||||
<span matListItemLine>{{product.identifier}}</span>
|
||||
</mat-list-item>
|
||||
</mat-list>
|
||||
|
||||
<mat-divider></mat-divider>
|
||||
|
||||
<button mat-fab
|
||||
extended
|
||||
color="primary"
|
||||
(click)="createProduct()">
|
||||
<mat-icon>add</mat-icon>
|
||||
Add
|
||||
</button>
|
||||
18
src/app/product/product-list/product-list.component.scss
Normal file
18
src/app/product/product-list/product-list.component.scss
Normal file
@ -0,0 +1,18 @@
|
||||
mat-divider {
|
||||
margin-top: 0.5em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.listItem {
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
.listItem:hover {
|
||||
background-color: lightgray;
|
||||
}
|
||||
|
||||
button {
|
||||
margin-left: 1em;
|
||||
margin-right: 1em;
|
||||
width: 90%;
|
||||
}
|
||||
82
src/app/product/product-list/product-list.component.ts
Normal file
82
src/app/product/product-list/product-list.component.ts
Normal file
@ -0,0 +1,82 @@
|
||||
import { Component, EventEmitter, Output } from '@angular/core';
|
||||
import { RequestService } from '../../request.service';
|
||||
import {MatDialog, MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog';
|
||||
import { CreateProductComponent } from '../create-product/create-product.component';
|
||||
|
||||
export interface Product {
|
||||
id: string,
|
||||
identifier: string,
|
||||
name: string|null,
|
||||
url: string|null,
|
||||
created: string,
|
||||
updated: string
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-product-list',
|
||||
templateUrl: './product-list.component.html',
|
||||
styleUrls: ['./product-list.component.scss']
|
||||
})
|
||||
export class ProductListComponent {
|
||||
@Output() productSelected = new EventEmitter<Product|null>();
|
||||
products: Product[] = []
|
||||
|
||||
constructor(
|
||||
public requestService : RequestService,
|
||||
public dialog: MatDialog
|
||||
) {
|
||||
}
|
||||
|
||||
onGetProductList(): void {
|
||||
this.requestService.get(
|
||||
'product/product-list',
|
||||
{},
|
||||
(answer:any) => this.products = answer
|
||||
);
|
||||
}
|
||||
|
||||
selectProduct(product: Product|null) {
|
||||
this.productSelected.emit(product);
|
||||
}
|
||||
|
||||
createProduct() {
|
||||
|
||||
const createProductDialogRef = this.dialog.open(
|
||||
CreateProductComponent
|
||||
)
|
||||
|
||||
createProductDialogRef.afterClosed().subscribe(
|
||||
result => {
|
||||
if(result != undefined) {
|
||||
this.requestService.post(
|
||||
'product/create-product',
|
||||
{
|
||||
identifier: result.identifier,
|
||||
name: result.name
|
||||
},
|
||||
(answer:any) => {
|
||||
this.onGetProductList();
|
||||
this.selectProduct(answer);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
removeProduct(product: Product) {
|
||||
this.selectProduct(null);
|
||||
this.requestService.post(
|
||||
'product/delete-product',
|
||||
{
|
||||
id: product.id
|
||||
},
|
||||
(answer:any) => {
|
||||
this.selectProduct(null);
|
||||
this.onGetProductList();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
0
src/app/product/product/product.component.html
Normal file
0
src/app/product/product/product.component.html
Normal file
0
src/app/product/product/product.component.scss
Normal file
0
src/app/product/product/product.component.scss
Normal file
10
src/app/product/product/product.component.ts
Normal file
10
src/app/product/product/product.component.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-product',
|
||||
templateUrl: './product.component.html',
|
||||
styleUrls: ['./product.component.scss']
|
||||
})
|
||||
export class ProductComponent {
|
||||
|
||||
}
|
||||
83
src/app/request.service.ts
Normal file
83
src/app/request.service.ts
Normal file
@ -0,0 +1,83 @@
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Router } from '@angular/router';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class RequestService {
|
||||
|
||||
constructor(
|
||||
private http: HttpClient,
|
||||
private router: Router,
|
||||
private snackBar: MatSnackBar
|
||||
) {
|
||||
}
|
||||
|
||||
post(apiPath: string, body: any, fct: Function)
|
||||
{
|
||||
let url = this.obtainUrl(apiPath);
|
||||
let observable = this.http.post(url, body).subscribe(
|
||||
(answer:any) => {
|
||||
fct(answer);
|
||||
},
|
||||
(error:any) => {
|
||||
this.handleError(error);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
get(apiPath: string, body: any, fct: Function)
|
||||
{
|
||||
let url = this.obtainUrl(apiPath);
|
||||
let observable = this.http.get(url, body).subscribe(
|
||||
(answer:any) => {
|
||||
fct(answer);
|
||||
},
|
||||
(error:any) => {
|
||||
this.handleError(error);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private obtainUrl(apiPath: string): string {
|
||||
let hostString = window.location.host;
|
||||
let protocol = window.location.protocol;
|
||||
return protocol + '//' + hostString + '/api/' + apiPath;
|
||||
}
|
||||
|
||||
private handleError(answer: any): void {
|
||||
|
||||
if (answer.status == 401) {
|
||||
console.log('Deine Sitzung konnte nicht gefunden werden');
|
||||
this.router.navigate(['/auth']);
|
||||
return;
|
||||
}
|
||||
|
||||
if (answer.status == 403) {
|
||||
this.showSnackBar('Du bist nicht für diese Aktion autorisiert', 'Ok');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
let errorObject = answer.error.error;
|
||||
|
||||
if (errorObject.hasOwnProperty('message')) {
|
||||
throw errorObject.message.toString();
|
||||
}
|
||||
|
||||
if (errorObject.hasOwnProperty('code')) {
|
||||
throw errorObject.code.toString();
|
||||
}
|
||||
} catch(error:any) {
|
||||
this.showSnackBar(error.toString(), 'Ok');
|
||||
}
|
||||
}
|
||||
|
||||
private showSnackBar(message: string, action?: string) {
|
||||
this.snackBar.open(message.toString(), action, {
|
||||
duration: 3000,
|
||||
});
|
||||
}
|
||||
}
|
||||
0
src/assets/.gitkeep
Normal file
0
src/assets/.gitkeep
Normal file
1
src/assets/homepage-icon.svg
Normal file
1
src/assets/homepage-icon.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 20C7.6 20 4 16.4 4 12S7.6 4 12 4 20 7.6 20 12 16.4 20 12 20M12 2C6.5 2 2 6.5 2 12S6.5 22 12 22 22 17.5 22 12 17.5 2 12 2M11 14H13V17H16V12H18L12 7L6 12H8V17H11V14" /></svg>
|
||||
|
After Width: | Height: | Size: 245 B |
BIN
src/favicon.ico
Normal file
BIN
src/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
17
src/index.html
Normal file
17
src/index.html
Normal file
@ -0,0 +1,17 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Homepage</title>
|
||||
<base href="/" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
|
||||
</head>
|
||||
<body class="mat-typography mat-app-background">
|
||||
<app-root></app-root>
|
||||
</body>
|
||||
</html>
|
||||
7
src/main.ts
Normal file
7
src/main.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppModule } from './app/app.module';
|
||||
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule)
|
||||
.catch(err => console.error(err));
|
||||
13
src/styles.scss
Normal file
13
src/styles.scss
Normal file
@ -0,0 +1,13 @@
|
||||
body {
|
||||
margin: 0;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.container {
|
||||
padding: 0;
|
||||
max-width: unset;
|
||||
}
|
||||
|
||||
app-root {
|
||||
height: 100%;
|
||||
}
|
||||
14
tsconfig.app.json
Normal file
14
tsconfig.app.json
Normal file
@ -0,0 +1,14 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out-tsc/app",
|
||||
"types": []
|
||||
},
|
||||
"files": [
|
||||
"src/main.ts"
|
||||
],
|
||||
"include": [
|
||||
"src/**/*.d.ts"
|
||||
]
|
||||
}
|
||||
33
tsconfig.json
Normal file
33
tsconfig.json
Normal file
@ -0,0 +1,33 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"compileOnSave": false,
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./",
|
||||
"outDir": "./dist/out-tsc",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"noImplicitOverride": true,
|
||||
"noPropertyAccessFromIndexSignature": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"sourceMap": true,
|
||||
"declaration": false,
|
||||
"downlevelIteration": true,
|
||||
"experimentalDecorators": true,
|
||||
"moduleResolution": "node",
|
||||
"importHelpers": true,
|
||||
"target": "ES2022",
|
||||
"module": "ES2022",
|
||||
"useDefineForClassFields": false,
|
||||
"lib": [
|
||||
"ES2022",
|
||||
"dom"
|
||||
]
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"enableI18nLegacyMessageIdFormat": false,
|
||||
"strictInjectionParameters": true,
|
||||
"strictInputAccessModifiers": true,
|
||||
"strictTemplates": true
|
||||
}
|
||||
}
|
||||
14
tsconfig.spec.json
Normal file
14
tsconfig.spec.json
Normal file
@ -0,0 +1,14 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out-tsc/spec",
|
||||
"types": [
|
||||
"jasmine"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.spec.ts",
|
||||
"src/**/*.d.ts"
|
||||
]
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user