Compare commits

...

5 Commits

Author SHA1 Message Date
Patrick
b839994de0
Merge pull request #101 from Mueller-Patrick/develop
Deployment
2021-06-26 14:43:54 +02:00
91716b8147 Merge remote-tracking branch 'origin/develop' into develop 2021-06-26 14:38:18 +02:00
Patrick
5be6d9bd4f
Update README.md 2021-06-26 14:37:06 +02:00
6e0f1e7659 Reformatting a bunch of files 2021-06-26 14:36:26 +02:00
4a7ef6d637 Adjusting some frontend tests 2021-06-26 14:33:58 +02:00
57 changed files with 1523 additions and 563 deletions

View File

@ -2,32 +2,35 @@
// https://karma-runner.github.io/1.0/config/configuration-file.html // https://karma-runner.github.io/1.0/config/configuration-file.html
module.exports = function (config) { module.exports = function (config) {
config.set({ config.set({
basePath: '', basePath: '',
frameworks: ['jasmine', '@angular-devkit/build-angular'], frameworks: ['jasmine', '@angular-devkit/build-angular'],
plugins: [ plugins: [
require('karma-jasmine'), require('karma-jasmine'),
require('karma-firefox-launcher'), require('karma-firefox-launcher'),
require('karma-chrome-launcher'), require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'), require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter'), require('karma-coverage-istanbul-reporter'),
require('@angular-devkit/build-angular/plugins/karma') require('@angular-devkit/build-angular/plugins/karma')
], ],
client: { client: {
clearContext: false // leave Jasmine Spec Runner output visible in browser clearContext: false, // leave Jasmine Spec Runner output visible in browser
}, jasmine: {
coverageIstanbulReporter: { random: false
dir: require('path').join(__dirname, './coverage/Betterzon'), }
reports: ['html', 'lcovonly', 'text-summary'], },
fixWebpackSourcePaths: true coverageIstanbulReporter: {
}, dir: require('path').join(__dirname, './coverage/Betterzon'),
reporters: ['progress', 'kjhtml'], reports: ['html', 'lcovonly', 'text-summary'],
port: 9876, fixWebpackSourcePaths: true
colors: true, },
logLevel: config.LOG_INFO, reporters: ['progress', 'kjhtml'],
autoWatch: true, port: 9876,
browsers: ['Firefox'], colors: true,
singleRun: false, logLevel: config.LOG_INFO,
restartOnFileChange: true autoWatch: true,
}); browsers: ['Firefox'],
singleRun: false,
restartOnFileChange: true
});
}; };

View File

@ -1,9 +1,10 @@
.wrapper_app { .wrapper_app {
padding-bottom: 2.5rem; /* Footer height */ padding-bottom: 2.5rem; /* Footer height */
} }
.footer_app { .footer_app {
position: relative; position: relative;
bottom: 0; bottom: 0;
width: 100%; width: 100%;
height: 2.5rem; /* Footer height */ height: 2.5rem; /* Footer height */
} }

View File

@ -1,8 +1,8 @@
import {TestBed} from '@angular/core/testing'; import {TestBed} from '@angular/core/testing';
import {AppComponent} from './app.component'; import {AppComponent} from './app.component';
import {RouterTestingModule} from "@angular/router/testing"; import {RouterTestingModule} from '@angular/router/testing';
import {NgcCookieConsentConfig, NgcCookieConsentModule} from "ngx-cookieconsent"; import {NgcCookieConsentConfig, NgcCookieConsentModule} from 'ngx-cookieconsent';
import {FormsModule} from "@angular/forms"; import {FormsModule} from '@angular/forms';
// For cookie consent module testing // For cookie consent module testing
const cookieConfig: NgcCookieConsentConfig = { const cookieConfig: NgcCookieConsentConfig = {

View File

@ -1,7 +1,7 @@
import {Component, OnDestroy, OnInit} from '@angular/core'; import {Component, OnDestroy, OnInit} from '@angular/core';
import {NgcCookieConsentService, NgcInitializeEvent, NgcNoCookieLawEvent, NgcStatusChangeEvent} from 'ngx-cookieconsent'; import {NgcCookieConsentService, NgcInitializeEvent, NgcNoCookieLawEvent, NgcStatusChangeEvent} from 'ngx-cookieconsent';
import {Subscription} from 'rxjs'; import {Subscription} from 'rxjs';
import {ApiService} from "./services/api.service"; import {ApiService} from './services/api.service';
@Component({ @Component({
@ -26,8 +26,7 @@ export class AppComponent implements OnInit, OnDestroy {
username?: string; username?: string;
constructor( constructor(
private ccService: NgcCookieConsentService, private ccService: NgcCookieConsentService
private api: ApiService
) { ) {
} }

View File

@ -23,23 +23,23 @@ import {NgcCookieConsentModule, NgcCookieConsentConfig} from 'ngx-cookieconsent'
import {MatSlideToggleModule} from '@angular/material/slide-toggle'; import {MatSlideToggleModule} from '@angular/material/slide-toggle';
import {TopBarComponent} from './components/top-bar/top-bar.component'; import {TopBarComponent} from './components/top-bar/top-bar.component';
import {RouterModule} from '@angular/router'; import {RouterModule} from '@angular/router';
import {MatButtonModule} from "@angular/material/button"; import {MatButtonModule} from '@angular/material/button';
import {MatToolbarModule} from '@angular/material/toolbar'; import {MatToolbarModule} from '@angular/material/toolbar';
import {MatIconModule} from '@angular/material/icon'; import {MatIconModule} from '@angular/material/icon';
import {MatSidenavModule} from '@angular/material/sidenav'; import {MatSidenavModule} from '@angular/material/sidenav';
import {MatListModule} from "@angular/material/list"; import {MatListModule} from '@angular/material/list';
import {BottomBarComponent} from './components/bottom-bar/bottom-bar.component'; import {BottomBarComponent} from './components/bottom-bar/bottom-bar.component';
import { HotDealsWidgetComponent } from './components/hot-deals-widget/hot-deals-widget.component'; import {HotDealsWidgetComponent} from './components/hot-deals-widget/hot-deals-widget.component';
import { SliderForProductsComponent } from './components/slider-for-products/slider-for-products.component'; import {SliderForProductsComponent} from './components/slider-for-products/slider-for-products.component';
import { RegistrationComponent } from './components/auth/registration/registration.component'; import {RegistrationComponent} from './components/auth/registration/registration.component';
import { MatCardModule } from "@angular/material/card"; import {MatCardModule} from '@angular/material/card';
import {SigninComponent} from "./components/auth/signin/signin.component"; import {SigninComponent} from './components/auth/signin/signin.component';
import { CopyrightComponent } from './components/copyright/copyright.component'; import {CopyrightComponent} from './components/copyright/copyright.component';
import { GreetingInfoSliderComponent } from './components/greeting-info-slider/greeting-info-slider.component'; import {GreetingInfoSliderComponent} from './components/greeting-info-slider/greeting-info-slider.component';
import { KundenComponent } from './components/kunden/kunden.component'; import {KundenComponent} from './components/kunden/kunden.component';
import { AboutUsComponent } from './components/about-us/about-us.component'; import {AboutUsComponent} from './components/about-us/about-us.component';
import { ProfileComponent } from './components/profile/profile.component'; import {ProfileComponent} from './pages/profile/profile.component';
import { ProfilePageComponent } from './pages/profile-page/profile-page.component'; import {ProfilePageComponent} from './pages/profile-page/profile-page.component';
// For cookie popup // For cookie popup
const cookieConfig: NgcCookieConsentConfig = { const cookieConfig: NgcCookieConsentConfig = {

View File

@ -9,10 +9,10 @@ import {ProductSearchPageComponent} from './pages/product-search-page/product-se
import {PageNotFoundPageComponent} from './pages/page-not-found-page/page-not-found-page.component'; import {PageNotFoundPageComponent} from './pages/page-not-found-page/page-not-found-page.component';
import {ImprintComponent} from './pages/imprint/imprint.component'; import {ImprintComponent} from './pages/imprint/imprint.component';
import {PrivacyComponent} from './pages/privacy/privacy.component'; import {PrivacyComponent} from './pages/privacy/privacy.component';
import {SigninComponent} from "./components/auth/signin/signin.component"; import {SigninComponent} from './components/auth/signin/signin.component';
import {RegistrationComponent} from "./components/auth/registration/registration.component"; import {RegistrationComponent} from './components/auth/registration/registration.component';
import {ProfileComponent} from "./components/profile/profile.component"; import {ProfileComponent} from './pages/profile/profile.component';
import {ProfilePageComponent} from "./pages/profile-page/profile-page.component"; import {ProfilePageComponent} from './pages/profile-page/profile-page.component';
const routes: Routes = [ const routes: Routes = [
{path: '', component: LandingpageComponent, pathMatch: 'full'}, {path: '', component: LandingpageComponent, pathMatch: 'full'},
@ -22,8 +22,8 @@ const routes: Routes = [
{path: 'datenschutz', component: PrivacyComponent}, {path: 'datenschutz', component: PrivacyComponent},
{path: 'signin', component: SigninComponent}, {path: 'signin', component: SigninComponent},
{path: 'registration', component: RegistrationComponent}, {path: 'registration', component: RegistrationComponent},
{path: "product-detail", component: ProductDetailPageComponent}, {path: 'product-detail', component: ProductDetailPageComponent},
{path: "profile", component: ProfilePageComponent}, {path: 'profile', component: ProfilePageComponent},
{path: '**', component: PageNotFoundPageComponent} {path: '**', component: PageNotFoundPageComponent}
]; ];

View File

@ -10,8 +10,10 @@
</div> </div>
<!-- About Section Content--> <!-- About Section Content-->
<div class="row"> <div class="row">
<div class="col-lg-4 ms-auto"><p class="lead">You follow the same passion as we do and you want to find alternatives to the de-facto monopolist Amazon?</p></div> <div class="col-lg-4 ms-auto"><p class="lead">You follow the same passion as we do and you want to find
<div class="col-lg-4 me-auto"><p class="lead">In this case, welcome aboard! Were happy that you share our passion and hope that we can help you achieving this goal with the website.</p></div> alternatives to the de-facto monopolist Amazon?</p></div>
<div class="col-lg-4 me-auto"><p class="lead">In this case, welcome aboard! Were happy that you share our
passion and hope that we can help you achieving this goal with the website.</p></div>
</div> </div>
</div> </div>
</section> </section>

View File

@ -1,25 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing'; import {ComponentFixture, TestBed} from '@angular/core/testing';
import { AboutUsComponent } from './about-us.component'; import {AboutUsComponent} from './about-us.component';
describe('AboutUsComponent', () => { describe('AboutUsComponent', () => {
let component: AboutUsComponent; let component: AboutUsComponent;
let fixture: ComponentFixture<AboutUsComponent>; let fixture: ComponentFixture<AboutUsComponent>;
beforeEach(async () => { beforeEach(async () => {
await TestBed.configureTestingModule({ await TestBed.configureTestingModule({
declarations: [ AboutUsComponent ] declarations: [AboutUsComponent]
}) })
.compileComponents(); .compileComponents();
}); });
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(AboutUsComponent); fixture = TestBed.createComponent(AboutUsComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
fixture.detectChanges(); fixture.detectChanges();
}); });
it('should create', () => { it('should create', () => {
expect(component).toBeTruthy(); expect(component).toBeTruthy();
}); });
}); });

View File

@ -1,8 +1,8 @@
import { NgModule } from '@angular/core'; import {NgModule} from '@angular/core';
import { Routes, RouterModule } from '@angular/router'; import {Routes, RouterModule} from '@angular/router';
import {RegistrationComponent} from "./registration/registration.component"; import {RegistrationComponent} from './registration/registration.component';
import {SigninComponent} from "./signin/signin.component"; import {SigninComponent} from './signin/signin.component';
import {ResetpasswortComponent} from "./resetpasswort/resetpasswort.component"; import {ResetpasswortComponent} from './resetpasswort/resetpasswort.component';
const routes: Routes = [ const routes: Routes = [
{ {
@ -20,7 +20,8 @@ const routes: Routes = [
]; ];
@NgModule({ @NgModule({
imports: [RouterModule.forChild(routes)], imports: [RouterModule.forChild(routes)],
exports: [RouterModule] exports: [RouterModule]
}) })
export class AuthRoutingModule { } export class AuthRoutingModule {
}

View File

@ -1,22 +1,23 @@
import { NgModule } from '@angular/core'; import {NgModule} from '@angular/core';
import { CommonModule } from '@angular/common'; import {CommonModule} from '@angular/common';
import { AuthRoutingModule } from './auth-routing.module'; import {AuthRoutingModule} from './auth-routing.module';
import { SigninComponent } from "./signin/signin.component"; import {SigninComponent} from './signin/signin.component';
import { RegistrationComponent } from './registration/registration.component'; import {RegistrationComponent} from './registration/registration.component';
import { ResetpasswortComponent } from './resetpasswort/resetpasswort.component'; import {ResetpasswortComponent} from './resetpasswort/resetpasswort.component';
@NgModule({ @NgModule({
declarations: [SigninComponent, RegistrationComponent, ResetpasswortComponent], declarations: [SigninComponent, RegistrationComponent, ResetpasswortComponent],
imports: [ imports: [
CommonModule, CommonModule,
AuthRoutingModule, AuthRoutingModule,
], ],
exports: [ exports: [
SigninComponent, SigninComponent,
RegistrationComponent, RegistrationComponent,
ResetpasswortComponent, ResetpasswortComponent,
], ],
}) })
export class AuthModule { } export class AuthModule {
}

View File

@ -1,11 +1,12 @@
.main-content{ .main-content {
width: 50%; width: 50%;
border-radius: 20px; border-radius: 20px;
box-shadow: 0 5px 5px rgba(0,0,0,.4); box-shadow: 0 5px 5px rgba(0, 0, 0, .4);
margin: 5em auto; margin: 5em auto;
display: flex; display: flex;
} }
.company__info{
.company__info {
background-color: #008080; background-color: #008080;
border-top-left-radius: 20px; border-top-left-radius: 20px;
border-bottom-left-radius: 20px; border-bottom-left-radius: 20px;
@ -14,63 +15,79 @@
justify-content: center; justify-content: center;
color: #fff; color: #fff;
} }
.fa-android{
font-size:3em; .fa-android {
font-size: 3em;
} }
@media screen and (max-width: 640px) { @media screen and (max-width: 640px) {
.main-content{width: 90%;} .main-content {
.company__info{ width: 90%;
}
.company__info {
display: none; display: none;
} }
.login_form{
border-top-left-radius:20px; .login_form {
border-bottom-left-radius:20px; border-top-left-radius: 20px;
border-bottom-left-radius: 20px;
} }
} }
@media screen and (min-width: 642px) and (max-width:800px){
.main-content{width: 70%;} @media screen and (min-width: 642px) and (max-width: 800px) {
.main-content {
width: 70%;
}
} }
.row > h2{
color:#008080; .row > h2 {
color: #008080;
} }
.login_form{
.login_form {
background-color: #fff; background-color: #fff;
border-top-right-radius:20px; border-top-right-radius: 20px;
border-bottom-right-radius:20px; border-bottom-right-radius: 20px;
border-top:1px solid #ccc; border-top: 1px solid #ccc;
border-right:1px solid #ccc; border-right: 1px solid #ccc;
} }
form{
form {
padding: 0 2em; padding: 0 2em;
} }
.form__input{
.form__input {
width: 100%; width: 100%;
border:0px solid transparent; border: 0px solid transparent;
border-radius: 0; border-radius: 0;
border-bottom: 1px solid #aaa; border-bottom: 1px solid #aaa;
padding: 1em .5em .5em; padding: 1em .5em .5em;
padding-left: 2em; padding-left: 2em;
outline:none; outline: none;
margin:1.5em auto; margin: 1.5em auto;
transition: all .5s ease; transition: all .5s ease;
} }
.form__input:focus{
.form__input:focus {
border-bottom-color: #008080; border-bottom-color: #008080;
box-shadow: 0 0 5px rgba(0,80,80,.4); box-shadow: 0 0 5px rgba(0, 80, 80, .4);
border-radius: 4px; border-radius: 4px;
} }
.btn_signin{
.btn_signin {
transition: all .5s ease; transition: all .5s ease;
width: 100%; width: 100%;
border-radius: 30px; border-radius: 30px;
color:#008080; color: #008080;
font-weight: 600; font-weight: 600;
background-color: #fff; background-color: #fff;
border: 1px solid #008080; border: 1px solid #008080;
margin-top: 1.5em; margin-top: 1.5em;
margin-bottom: 1em; margin-bottom: 1em;
} }
.btn_signin:hover, .btn:focus{
.btn_signin:hover, .btn:focus {
background-color: #008080; background-color: #008080;
color:#fff; color: #fff;
} }

View File

@ -11,18 +11,21 @@
<div class="row"> <div class="row">
<form [formGroup]="form" class="form-group" (ngSubmit)="onSubmit()"> <form [formGroup]="form" class="form-group" (ngSubmit)="onSubmit()">
<div class="row"> <div class="row">
<input type="text" formControlName="username" id="username" name="username" class="form__input" placeholder="Username"> <input type="text" formControlName="username" id="username" name="username"
class="form__input" placeholder="Username">
<div *ngIf="submitted && me.username.errors" class="invalid-feedback"> <div *ngIf="submitted && me.username.errors" class="invalid-feedback">
<div *ngIf="me.username.errors.required">Username is required</div> <div *ngIf="me.username.errors.required">Username is required</div>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<!-- <span class="fa fa-lock"></span> --> <!-- <span class="fa fa-lock"></span> -->
<input type="email" formControlName="email" name="email" id="email" class="form__input" placeholder= "E-Mail"> <input type="email" formControlName="email" name="email" id="email" class="form__input"
placeholder="E-Mail">
</div> </div>
<div class="row"> <div class="row">
<!-- <span class="fa fa-lock"></span> --> <!-- <span class="fa fa-lock"></span> -->
<input type="password" formControlName="password" name="password" id="password" class="form__input" placeholder="Password"> <input type="password" formControlName="password" name="password" id="password"
class="form__input" placeholder="Password">
</div> </div>
<!-- <!--
<div class="row"> <div class="row">

View File

@ -1,25 +1,54 @@
import { ComponentFixture, TestBed } from '@angular/core/testing'; import {ComponentFixture, TestBed} from '@angular/core/testing';
import { RegistrationComponent } from './registration.component'; import {RegistrationComponent} from './registration.component';
import {AbstractMockObservableService} from '../../../mocks/mock.service';
import {ApiService} from '../../../services/api.service';
import {FormBuilder, FormControl, Validators} from '@angular/forms';
import {Router} from '@angular/router';
class MockApiService extends AbstractMockObservableService {
registerUser(username: string, password: string, email: string): any {
this.content = [];
return this;
}
}
describe('RegistrationComponent', () => { describe('RegistrationComponent', () => {
let component: RegistrationComponent; let component: RegistrationComponent;
let fixture: ComponentFixture<RegistrationComponent>; let fixture: ComponentFixture<RegistrationComponent>;
let mockService;
let formBuilder: FormBuilder;
const router = {
navigate: jasmine.createSpy('navigate'),
routerState: jasmine.createSpy('routerState')
};
beforeEach(async () => { beforeEach(async () => {
await TestBed.configureTestingModule({ mockService = new MockApiService();
declarations: [ RegistrationComponent ] await TestBed.configureTestingModule({
}) declarations: [RegistrationComponent],
.compileComponents(); providers: [{provide: ApiService, useValue: mockService}, {provide: Router, useValue: router}, FormBuilder]
}); })
.compileComponents();
});
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(RegistrationComponent); fixture = TestBed.createComponent(RegistrationComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
fixture.detectChanges(); formBuilder = TestBed.get(FormBuilder);
}); component.form = formBuilder.group({
recipientTypes: new FormControl(
{
value: ['mock'],
disabled: true
},
Validators.required
)
});
fixture.detectChanges();
});
it('should create', () => { it('should create', () => {
expect(component).toBeTruthy(); expect(component).toBeTruthy();
}); });
}); });

View File

@ -1,25 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing'; import {ComponentFixture, TestBed} from '@angular/core/testing';
import { ResetpasswortComponent } from './resetpasswort.component'; import {ResetpasswortComponent} from './resetpasswort.component';
describe('ResetpasswortComponent', () => { describe('ResetpasswortComponent', () => {
let component: ResetpasswortComponent; let component: ResetpasswortComponent;
let fixture: ComponentFixture<ResetpasswortComponent>; let fixture: ComponentFixture<ResetpasswortComponent>;
beforeEach(async () => { beforeEach(async () => {
await TestBed.configureTestingModule({ await TestBed.configureTestingModule({
declarations: [ ResetpasswortComponent ] declarations: [ResetpasswortComponent]
}) })
.compileComponents(); .compileComponents();
}); });
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(ResetpasswortComponent); fixture = TestBed.createComponent(ResetpasswortComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
fixture.detectChanges(); fixture.detectChanges();
}); });
it('should create', () => { it('should create', () => {
expect(component).toBeTruthy(); expect(component).toBeTruthy();
}); });
}); });

View File

@ -1,11 +1,12 @@
.main-content{ .main-content {
width: 50%; width: 50%;
border-radius: 20px; border-radius: 20px;
box-shadow: 0 5px 5px rgba(0,0,0,.4); box-shadow: 0 5px 5px rgba(0, 0, 0, .4);
margin: 5em auto; margin: 5em auto;
display: flex; display: flex;
} }
.company__info{
.company__info {
background-color: #008080; background-color: #008080;
border-top-left-radius: 20px; border-top-left-radius: 20px;
border-bottom-left-radius: 20px; border-bottom-left-radius: 20px;
@ -14,63 +15,79 @@
justify-content: center; justify-content: center;
color: #fff; color: #fff;
} }
.fa-android{
font-size:3em; .fa-android {
font-size: 3em;
} }
@media screen and (max-width: 640px) { @media screen and (max-width: 640px) {
.main-content{width: 90%;} .main-content {
.company__info{ width: 90%;
}
.company__info {
display: none; display: none;
} }
.login_form{
border-top-left-radius:20px; .login_form {
border-bottom-left-radius:20px; border-top-left-radius: 20px;
border-bottom-left-radius: 20px;
} }
} }
@media screen and (min-width: 642px) and (max-width:800px){
.main-content{width: 70%;} @media screen and (min-width: 642px) and (max-width: 800px) {
.main-content {
width: 70%;
}
} }
.row > h2{
color:#008080; .row > h2 {
color: #008080;
} }
.login_form{
.login_form {
background-color: #fff; background-color: #fff;
border-top-right-radius:20px; border-top-right-radius: 20px;
border-bottom-right-radius:20px; border-bottom-right-radius: 20px;
border-top:1px solid #ccc; border-top: 1px solid #ccc;
border-right:1px solid #ccc; border-right: 1px solid #ccc;
} }
form{
form {
padding: 0 2em; padding: 0 2em;
} }
.form__input{
.form__input {
width: 100%; width: 100%;
border:0px solid transparent; border: 0px solid transparent;
border-radius: 0; border-radius: 0;
border-bottom: 1px solid #aaa; border-bottom: 1px solid #aaa;
padding: 1em .5em .5em; padding: 1em .5em .5em;
padding-left: 2em; padding-left: 2em;
outline:none; outline: none;
margin:1.5em auto; margin: 1.5em auto;
transition: all .5s ease; transition: all .5s ease;
} }
.form__input:focus{
.form__input:focus {
border-bottom-color: #008080; border-bottom-color: #008080;
box-shadow: 0 0 5px rgba(0,80,80,.4); box-shadow: 0 0 5px rgba(0, 80, 80, .4);
border-radius: 4px; border-radius: 4px;
} }
.btn_signin{
.btn_signin {
transition: all .5s ease; transition: all .5s ease;
width: 100%; width: 100%;
border-radius: 30px; border-radius: 30px;
color:#008080; color: #008080;
font-weight: 600; font-weight: 600;
background-color: #fff; background-color: #fff;
border: 1px solid #008080; border: 1px solid #008080;
margin-top: 1.5em; margin-top: 1.5em;
margin-bottom: 1em; margin-bottom: 1em;
} }
.btn_signin:hover, .btn:focus{
.btn_signin:hover, .btn:focus {
background-color: #008080; background-color: #008080;
color:#fff; color: #fff;
} }

View File

@ -11,11 +11,13 @@
<div class="row"> <div class="row">
<form [formGroup]="loginForm" class="form-group" (ngSubmit)="onSubmit()"> <form [formGroup]="loginForm" class="form-group" (ngSubmit)="onSubmit()">
<div class="row"> <div class="row">
<input type="text" formControlName="username" name="username" id="username" class="form__input" placeholder="Username"> <input type="text" formControlName="username" name="username" id="username"
class="form__input" placeholder="Username">
</div> </div>
<div class="row"> <div class="row">
<!-- <span class="fa fa-lock"></span> --> <!-- <span class="fa fa-lock"></span> -->
<input type="password" formControlName="password" name="password" id="password" class="form__input" placeholder="Password"> <input type="password" formControlName="password" name="password" id="password"
class="form__input" placeholder="Password">
</div> </div>
<div class="row"> <div class="row">
<input type="submit" value="Log in" class="btn_signin"> <input type="submit" value="Log in" class="btn_signin">

View File

@ -1,25 +1,54 @@
import { ComponentFixture, TestBed } from '@angular/core/testing'; import {ComponentFixture, TestBed} from '@angular/core/testing';
import { SigninComponent } from './signin.component'; import {SigninComponent} from './signin.component';
import {AbstractMockObservableService} from '../../../mocks/mock.service';
import {ApiService} from '../../../services/api.service';
import {FormBuilder, FormControl, Validators} from '@angular/forms';
import {Router} from '@angular/router';
class MockApiService extends AbstractMockObservableService {
loginUser(username: string, password: string): any {
this.content = [];
return this;
}
}
describe('SigninComponent', () => { describe('SigninComponent', () => {
let component: SigninComponent; let component: SigninComponent;
let fixture: ComponentFixture<SigninComponent>; let fixture: ComponentFixture<SigninComponent>;
let mockService;
let formBuilder: FormBuilder;
const router = {
navigate: jasmine.createSpy('navigate'),
routerState: jasmine.createSpy('routerState')
};
beforeEach(async () => { beforeEach(async () => {
await TestBed.configureTestingModule({ mockService = new MockApiService();
declarations: [ SigninComponent ] await TestBed.configureTestingModule({
}) declarations: [SigninComponent],
.compileComponents(); providers: [{provide: ApiService, useValue: mockService}, {provide: Router, useValue: router}, FormBuilder]
}); })
.compileComponents();
});
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(SigninComponent); fixture = TestBed.createComponent(SigninComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
fixture.detectChanges(); formBuilder = TestBed.get(FormBuilder);
}); component.loginForm = formBuilder.group({
recipientTypes: new FormControl(
{
value: ['mock'],
disabled: true
},
Validators.required
)
});
fixture.detectChanges();
});
it('should create', () => { it('should create', () => {
expect(component).toBeTruthy(); expect(component).toBeTruthy();
}); });
}); });

View File

@ -7,12 +7,14 @@
} }
.folge-uns-item { .folge-uns-item {
grid-column: 2; grid-row: 1; grid-column: 2;
grid-row: 1;
justify-self: center; justify-self: center;
} }
.link-items { .link-items {
grid-column: 2; grid-row: 2; grid-column: 2;
grid-row: 2;
justify-self: center; justify-self: center;
} }
@ -29,11 +31,13 @@
} }
.bottom-logo { .bottom-logo {
grid-column: 1; grid-row: 3; grid-column: 1;
grid-row: 3;
} }
.bottom-info { .bottom-info {
grid-column: 3; grid-row: 3; grid-column: 3;
grid-row: 3;
justify-self: right; justify-self: right;
} }

View File

@ -6,15 +6,17 @@
<h4 class="text-uppercase mb-4">Location</h4> <h4 class="text-uppercase mb-4">Location</h4>
<p class="lead mb-0"> <p class="lead mb-0">
76133 Karlsruhe 76133 Karlsruhe
<br /> <br/>
</p> </p>
</div> </div>
<!-- Footer Social Icons--> <!-- Footer Social Icons-->
<div class="col-lg-4 mb-5 mb-lg-0"> <div class="col-lg-4 mb-5 mb-lg-0">
<h4 class="text-uppercase mb-4">FOLLOW US</h4> <h4 class="text-uppercase mb-4">FOLLOW US</h4>
<a class="btn btn-outline-light btn-social mx-1" href="https://github.com/Mueller-Patrick/Betterzon"><i class="fab fa-fw fa-github"></i></a> <a class="btn btn-outline-light btn-social mx-1" href="https://github.com/Mueller-Patrick/Betterzon"><i
<a class="btn btn-outline-light btn-social mx-1" href="https://blog.betterzon.xyz/"><i class="fab fa-fw fa-dribbble"></i></a> class="fab fa-fw fa-github"></i></a>
<a class="btn btn-outline-light btn-social mx-1" href="https://blog.betterzon.xyz/"><i
class="fab fa-fw fa-dribbble"></i></a>
</div> </div>
<!-- Footer About Text--> <!-- Footer About Text-->
<div class="col-lg-4"> <div class="col-lg-4">

View File

@ -1,25 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing'; import {ComponentFixture, TestBed} from '@angular/core/testing';
import { BottomBarComponent } from "./bottom-bar.component"; import {BottomBarComponent} from './bottom-bar.component';
describe("BottomBarComponent", () => { describe('BottomBarComponent', () => {
let component: BottomBarComponent; let component: BottomBarComponent;
let fixture: ComponentFixture<BottomBarComponent>; let fixture: ComponentFixture<BottomBarComponent>;
beforeEach(async () => { beforeEach(async () => {
await TestBed.configureTestingModule({ await TestBed.configureTestingModule({
declarations: [ BottomBarComponent ] declarations: [BottomBarComponent]
}) })
.compileComponents(); .compileComponents();
}); });
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(BottomBarComponent); fixture = TestBed.createComponent(BottomBarComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
fixture.detectChanges(); fixture.detectChanges();
}); });
it('should create', () => { it('should create', () => {
expect(component).toBeTruthy(); expect(component).toBeTruthy();
}); });
}); });

View File

@ -0,0 +1,24 @@
#imprintSection {
right: 1em;
bottom: 1em;
width: 100%;
text-align: right;
padding-right: 1em;
grid-area: right;
}
#imprintSection a {
color: white;
text-decoration: none;
}
#copyright {
display: grid;
grid-template-areas:
'left center right';
grid-template-columns: 30% 40% 30%;
}
#copyright-text {
grid-area: center;
}

View File

@ -1,3 +1,7 @@
<div class="copyright py-4 text-center text-white"> <div class="copyright py-4 text-center text-white" id="copyright">
<div class="container"><small>Copyright &copy; Betterzon 2021</small></div> <div class="container" id="copyright-text"><small>Copyright &copy; Betterzon 2021</small></div>
<div id="imprintSection">
<a href="/impressum">Imprint</a><br>
<a href="/datenschutz">Privacy Policy</a>
</div>
</div> </div>

View File

@ -1,25 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing'; import {ComponentFixture, TestBed} from '@angular/core/testing';
import { CopyrightComponent } from './copyright.component'; import {CopyrightComponent} from './copyright.component';
describe('CopyrightComponent', () => { describe('CopyrightComponent', () => {
let component: CopyrightComponent; let component: CopyrightComponent;
let fixture: ComponentFixture<CopyrightComponent>; let fixture: ComponentFixture<CopyrightComponent>;
beforeEach(async () => { beforeEach(async () => {
await TestBed.configureTestingModule({ await TestBed.configureTestingModule({
declarations: [ CopyrightComponent ] declarations: [CopyrightComponent]
}) })
.compileComponents(); .compileComponents();
}); });
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(CopyrightComponent); fixture = TestBed.createComponent(CopyrightComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
fixture.detectChanges(); fixture.detectChanges();
}); });
it('should create', () => { it('should create', () => {
expect(component).toBeTruthy(); expect(component).toBeTruthy();
}); });
}); });

View File

@ -9,10 +9,10 @@
<a href="https://blog.betterzon.xyz/" class="fa fa-info fa-4x icon-3d"></a> <a href="https://blog.betterzon.xyz/" class="fa fa-info fa-4x icon-3d"></a>
<a href="https://github.com/Mueller-Patrick/Betterzon/wiki" class="fa fa-wikipedia-w fa-4x icon-3d"></a> <a href="https://github.com/Mueller-Patrick/Betterzon/wiki" class="fa fa-wikipedia-w fa-4x icon-3d"></a>
</div> </div>
<div class = "blocks" id="copyright">© COPYRIGHT 2020</div> <div class="blocks" id="copyright">© COPYRIGHT 2020</div>
</div> </div>
<div id="imprintSection"> <div id="imprintSection">
<a href="/impressum" >Imprint</a><br> <a href="/impressum">Imprint</a><br>
<a href="/datenschutz">Privacy Policy</a> <a href="/datenschutz">Privacy Policy</a>
</div> </div>
</footer> </footer>

View File

@ -1,7 +1,7 @@
<header class="masthead bg-primary text-white text-center"> <header class="masthead bg-primary text-white text-center">
<div class="container d-flex align-items-center flex-column"> <div class="container d-flex align-items-center flex-column">
<!-- Masthead Avatar Image--> <!-- Masthead Avatar Image-->
<img class="masthead-avatar mb-5" src="assets/images/Betterzon.svg" alt="..." /> <img class="masthead-avatar mb-5" src="assets/images/Betterzon.svg" alt="..."/>
<!-- Masthead Heading--> <!-- Masthead Heading-->
<h1 class="masthead-heading text-uppercase mb-0"></h1> <h1 class="masthead-heading text-uppercase mb-0"></h1>
<!-- Icon Divider--> <!-- Icon Divider-->

View File

@ -1,25 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing'; import {ComponentFixture, TestBed} from '@angular/core/testing';
import { GreetingInfoSliderComponent } from './greeting-info-slider.component'; import {GreetingInfoSliderComponent} from './greeting-info-slider.component';
describe('GreetingInfoSliderComponent', () => { describe('GreetingInfoSliderComponent', () => {
let component: GreetingInfoSliderComponent; let component: GreetingInfoSliderComponent;
let fixture: ComponentFixture<GreetingInfoSliderComponent>; let fixture: ComponentFixture<GreetingInfoSliderComponent>;
beforeEach(async () => { beforeEach(async () => {
await TestBed.configureTestingModule({ await TestBed.configureTestingModule({
declarations: [ GreetingInfoSliderComponent ] declarations: [GreetingInfoSliderComponent]
}) })
.compileComponents(); .compileComponents();
}); });
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(GreetingInfoSliderComponent); fixture = TestBed.createComponent(GreetingInfoSliderComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
fixture.detectChanges(); fixture.detectChanges();
}); });
it('should create', () => { it('should create', () => {
expect(component).toBeTruthy(); expect(component).toBeTruthy();
}); });
}); });

View File

@ -5,7 +5,8 @@
<img src="assets/images/Betterzon.svg" alt="Betterzon Logo" width="50px" (click)="clickedLogo()"> <img src="assets/images/Betterzon.svg" alt="Betterzon Logo" width="50px" (click)="clickedLogo()">
</div> </div>
<div class="searchBox"> <div class="searchBox">
<input *ngIf="showSearch===true" type="text" [(ngModel)]="searchInput" placeholder="Search" (keyup.enter)="startedSearch()"> <input *ngIf="showSearch===true" type="text" [(ngModel)]="searchInput" placeholder="Search"
(keyup.enter)="startedSearch()">
</div> </div>
<div class="slider"> <div class="slider">
<mat-slide-toggle color="primary">dark me</mat-slide-toggle> <mat-slide-toggle color="primary">dark me</mat-slide-toggle>

View File

@ -9,26 +9,33 @@
<!-- Portfolio Grid Items--> <!-- Portfolio Grid Items-->
<div class="row justify-content-center"> <div class="row justify-content-center">
<!-- Portfolio Item 1--> <!-- Portfolio Item 1-->
<div class="col-md-4 mx-auto my-5" *ngFor="let productId of bestDealsProductIds" (click)="clickedProduct(productId)"> <div class="col-md-4 mx-auto my-5" *ngFor="let productId of bestDealsProductIds"
(click)="clickedProduct(productId)">
<div class="bbb_deals_wrapper"> <div class="bbb_deals_wrapper">
<div class="bbb_deals_image"><img src="https://www.mueller-patrick.tech/betterzon/images/{{productsPricesMap[productId]?.product?.image_guid}}.jpg" alt=""></div> <div class="bbb_deals_image"><img
src="https://www.mueller-patrick.tech/betterzon/images/{{productsPricesMap[productId]?.product?.image_guid}}.jpg"
alt=""></div>
<div class="bbb_deals_content"> <div class="bbb_deals_content">
<div class="bbb_deals_info_line d-flex flex-row justify-content-start"> <div class="bbb_deals_info_line d-flex flex-row justify-content-start">
<div class="bbb_deals_item_name">{{productsPricesMap[productId]?.product?.name}}</div> <div class="bbb_deals_item_name">{{productsPricesMap[productId]?.product?.name}}</div>
</div> </div>
<div class="bbb_deals_info_line d-flex flex-row justify-content-start"> <div class="bbb_deals_info_line d-flex flex-row justify-content-start">
<div class="bbb_deals_item_category">Amazon: <span id="bbb_deals_item_price_a"><strike>{{productsPricesMap[productId]?.amazonPrice?.price_in_cents/100}}€</strike></span></div> <div class="bbb_deals_item_category">Amazon: <span
id="bbb_deals_item_price_a"><strike>{{productsPricesMap[productId]?.amazonPrice?.price_in_cents / 100}}
</strike></span></div>
</div> </div>
<div class="bbb_deals_info_line d-flex flex-row justify-content-start"> <div class="bbb_deals_info_line d-flex flex-row justify-content-start">
<div class="bbb_deals_item_category">{{productsPricesMap[productId]?.vendor?.name}}: <span id="bbb_deals_item_price_b">{{productsPricesMap[productId]?.lowestPrice?.price_in_cents/100}}€</span></div> <div class="bbb_deals_item_category">{{productsPricesMap[productId]?.vendor?.name}}: <span
id="bbb_deals_item_price_b">{{productsPricesMap[productId]?.lowestPrice?.price_in_cents / 100}}
</span></div>
</div> </div>
<div class="available_bar"> <div class="available_bar">
<span style="width:17%"></span> <span style="width:17%"></span>
</div> </div>
</div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div>
</section> </section>

View File

@ -1,25 +1,58 @@
import { ComponentFixture, TestBed } from '@angular/core/testing'; import {ComponentFixture, TestBed} from '@angular/core/testing';
import { HotDealsWidgetComponent } from './hot-deals-widget.component'; import {HotDealsWidgetComponent} from './hot-deals-widget.component';
import {AbstractMockObservableService} from '../../mocks/mock.service';
import {ApiService} from '../../services/api.service';
import {ActivatedRoute, convertToParamMap, Router} from '@angular/router';
import {Observable, of} from 'rxjs';
class MockApiService extends AbstractMockObservableService {
getBestDeals(): any {
this.content = [];
return this;
}
getProductsByIds(): any {
this.content = [];
return this;
}
}
class ActivatedRouteMock {
public paramMap = of(convertToParamMap({
testId: 'abc123',
anotherId: 'd31e8b48-7309-4c83-9884-4142efdf7271',
}));
}
describe('HotDealsWidgetComponent', () => { describe('HotDealsWidgetComponent', () => {
let component: HotDealsWidgetComponent; let component: HotDealsWidgetComponent;
let fixture: ComponentFixture<HotDealsWidgetComponent>; let fixture: ComponentFixture<HotDealsWidgetComponent>;
let mockService;
const router = {
navigate: jasmine.createSpy('navigate'),
routerState: jasmine.createSpy('routerState')
};
beforeEach(async () => { beforeEach(async () => {
await TestBed.configureTestingModule({ mockService = new MockApiService();
declarations: [ HotDealsWidgetComponent ] await TestBed.configureTestingModule({
}) declarations: [HotDealsWidgetComponent],
.compileComponents(); providers: [{provide: ApiService, useValue: mockService}, {provide: Router, useValue: router}, {
}); provide: ActivatedRoute,
useValue: ActivatedRouteMock
}]
})
.compileComponents();
});
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(HotDealsWidgetComponent); fixture = TestBed.createComponent(HotDealsWidgetComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
fixture.detectChanges(); fixture.detectChanges();
}); });
it('should create', () => { it('should create', () => {
expect(component).toBeTruthy(); expect(component).toBeTruthy();
}); });
}); });

View File

@ -12,7 +12,8 @@
<div class="col-md-6 col-lg-4 mb-5"> <div class="col-md-6 col-lg-4 mb-5">
<div class="portfolio-item mx-auto" data-bs-toggle="modal" data-bs-target="#portfolioModal1"> <div class="portfolio-item mx-auto" data-bs-toggle="modal" data-bs-target="#portfolioModal1">
<div class="portfolio-item-caption d-flex align-items-center justify-content-center h-100 w-100"> <div class="portfolio-item-caption d-flex align-items-center justify-content-center h-100 w-100">
<div class="portfolio-item-caption-content text-center text-white"><i class="fas fa-plus fa-3x"></i></div> <div class="portfolio-item-caption-content text-center text-white"><i
class="fas fa-plus fa-3x"></i></div>
</div> </div>
<img width="100%" class="productImage" src="assets/images/cropped-unknown-1-1.png"/> <img width="100%" class="productImage" src="assets/images/cropped-unknown-1-1.png"/>
</div> </div>
@ -20,7 +21,8 @@
<div class="col-md-6 col-lg-4 mb-5"> <div class="col-md-6 col-lg-4 mb-5">
<div class="portfolio-item mx-auto" data-bs-toggle="modal" data-bs-target="#portfolioModal1"> <div class="portfolio-item mx-auto" data-bs-toggle="modal" data-bs-target="#portfolioModal1">
<div class="portfolio-item-caption d-flex align-items-center justify-content-center h-100 w-100"> <div class="portfolio-item-caption d-flex align-items-center justify-content-center h-100 w-100">
<div class="portfolio-item-caption-content text-center text-white"><i class="fas fa-plus fa-3x"></i></div> <div class="portfolio-item-caption-content text-center text-white"><i
class="fas fa-plus fa-3x"></i></div>
</div> </div>
<img width="100%" class="productImage" src="assets/images/plantshub.jpg"/> <img width="100%" class="productImage" src="assets/images/plantshub.jpg"/>
</div> </div>
@ -28,7 +30,8 @@
<div class="col-md-6 col-lg-4 mb-5"> <div class="col-md-6 col-lg-4 mb-5">
<div class="portfolio-item mx-auto" data-bs-toggle="modal" data-bs-target="#portfolioModal1"> <div class="portfolio-item mx-auto" data-bs-toggle="modal" data-bs-target="#portfolioModal1">
<div class="portfolio-item-caption d-flex align-items-center justify-content-center h-100 w-100"> <div class="portfolio-item-caption d-flex align-items-center justify-content-center h-100 w-100">
<div class="portfolio-item-caption-content text-center text-white"><i class="fas fa-plus fa-3x"></i></div> <div class="portfolio-item-caption-content text-center text-white"><i
class="fas fa-plus fa-3x"></i></div>
</div> </div>
<img width="70%" class="productImage" src="assets/images/CeangalLogo.png"/> <img width="70%" class="productImage" src="assets/images/CeangalLogo.png"/>
</div> </div>

View File

@ -1,25 +1,53 @@
import { ComponentFixture, TestBed } from '@angular/core/testing'; import {ComponentFixture, TestBed} from '@angular/core/testing';
import { KundenComponent } from './kunden.component'; import {KundenComponent} from './kunden.component';
import {AbstractMockObservableService} from '../../mocks/mock.service';
import {ApiService} from '../../services/api.service';
import {ActivatedRoute, convertToParamMap, Router} from '@angular/router';
import {of} from 'rxjs';
class MockApiService extends AbstractMockObservableService {
getProducts(): any {
this.content = [];
return this;
}
}
class ActivatedRouteMock {
public paramMap = of(convertToParamMap({
testId: 'abc123',
anotherId: 'd31e8b48-7309-4c83-9884-4142efdf7271',
}));
}
describe('KundenComponent', () => { describe('KundenComponent', () => {
let component: KundenComponent; let component: KundenComponent;
let fixture: ComponentFixture<KundenComponent>; let fixture: ComponentFixture<KundenComponent>;
let mockService;
const router = {
navigate: jasmine.createSpy('navigate'),
routerState: jasmine.createSpy('routerState')
};
beforeEach(async () => { beforeEach(async () => {
await TestBed.configureTestingModule({ mockService = new MockApiService();
declarations: [ KundenComponent ] await TestBed.configureTestingModule({
}) declarations: [KundenComponent],
.compileComponents(); providers: [{provide: ApiService, useValue: mockService}, {provide: Router, useValue: router}, {
}); provide: ActivatedRoute,
useValue: ActivatedRouteMock
}]
})
.compileComponents();
});
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(KundenComponent); fixture = TestBed.createComponent(KundenComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
fixture.detectChanges(); fixture.detectChanges();
}); });
it('should create', () => { it('should create', () => {
expect(component).toBeTruthy(); expect(component).toBeTruthy();
}); });
}); });

View File

@ -58,6 +58,11 @@ class MockApiService extends AbstractMockObservableService {
this.content = [vendor]; this.content = [vendor];
return this; return this;
} }
getSessionInfoFromLocalStorage(): any {
this.content = [];
return this;
}
} }
describe('ProductDetailsComponent', () => { describe('ProductDetailsComponent', () => {

View File

@ -5,43 +5,49 @@
<div class="d-flex justify-content-center row"> <div class="d-flex justify-content-center row">
<div class="col-md-10"> <div class="col-md-10">
<div class="row p-2 bg-white border rounded" *ngFor="let product of products"> <div class="row p-2 bg-white border rounded" *ngFor="let product of products">
<div class="col-md-3 mt-1"><img width="50%" class="img-fluid img-responsive rounded product-image" src="https://www.mueller-patrick.tech/betterzon/images/{{product.image_guid}}.jpg"></div> <div class="col-md-3 mt-1"><img width="50%" class="img-fluid img-responsive rounded product-image"
src="https://www.mueller-patrick.tech/betterzon/images/{{product.image_guid}}.jpg">
</div>
<div class="col-md-6 mt-1"> <div class="col-md-6 mt-1">
<h5>{{product.name}}</h5> <h5>{{product.name}}</h5>
<div class="d-flex flex-row"> <div class="d-flex flex-row">
<p class="text-justify text-truncate para mb-0">{{product.short_description}}</p> <p class="text-justify text-truncate para mb-0">{{product.short_description}}</p>
</div> </div>
<div class="mt-1 mb-1 spec-1"><span></span><span class="dot"></span><span></span><span class="dot"></span><span><br></span></div> <div class="mt-1 mb-1 spec-1"><span></span><span class="dot"></span><span></span><span
<div class="mt-1 mb-1 spec-1"><span></span><span class="dot"></span><span></span><span class="dot"></span><span><br></span></div> class="dot"></span><span><br></span></div>
<div class="mt-1 mb-1 spec-1"><span></span><span class="dot"></span><span></span><span
class="dot"></span><span><br></span></div>
</div> </div>
<div class="align-items-center align-content-center col-md-3 border-left mt-1"> <div class="align-items-center align-content-center col-md-3 border-left mt-1">
<div class="d-flex flex-row align-items-center"> <div class="d-flex flex-row align-items-center">
<h4 class="mr-1">${{pricesMap[product.product_id]?.price_in_cents/100}}</h4> <h4 class="mr-1">${{pricesMap[product.product_id]?.price_in_cents / 100}}</h4>
</div>
<div class="d-flex flex-column mt-4">
<button class="btn btn-primary btn-sm" type="button" (click)="clickedProduct(product)">Details
</button>
</div> </div>
<div class="d-flex flex-column mt-4"><button class="btn btn-primary btn-sm" type="button" (click)="clickedProduct(product)">Details</button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> <!--
<!-- <div class="productItem" *ngFor="let product of products" (click)="clickedProduct(product)">
<div class="productItem" *ngFor="let product of products" (click)="clickedProduct(product)"> <div class="productImageContainer" *ngIf="showProductPicture===true">
<div class="productImageContainer" *ngIf="showProductPicture===true"> <img class="productImage" src="https://www.mueller-patrick.tech/betterzon/images/{{product.image_guid}}.jpg"/>
<img class="productImage" src="https://www.mueller-patrick.tech/betterzon/images/{{product.image_guid}}.jpg"/>
</div>
<div class="productTitle">
<b>{{product.name}}</b>
</div>
<div class="productPrice">
5€
</div>
<div class="productDescription">
<div *ngIf="product.short_description.length > 300">
{{product.short_description.substring(0, 300) + "..."}}
</div> </div>
<div *ngIf="product.short_description.length <= 300"> <div class="productTitle">
{{product.short_description}} <b>{{product.name}}</b>
</div>
<div class="productPrice">
5€
</div>
<div class="productDescription">
<div *ngIf="product.short_description.length > 300">
{{product.short_description.substring(0, 300) + "..."}}
</div>
<div *ngIf="product.short_description.length <= 300">
{{product.short_description}}
</div>
</div> </div>
</div> </div>
</div> -->
-->

View File

@ -70,7 +70,8 @@ describe('ProductListComponent', () => {
last_modified: new Date(), last_modified: new Date(),
manufacturer_id: 1, manufacturer_id: 1,
selling_rank: '1', selling_rank: '1',
category_id: 1 category_id: 1,
price: 0
}; };
component.clickedProduct(product); component.clickedProduct(product);

View File

@ -79,7 +79,7 @@ export class ProductListComponent implements OnInit {
this.getPrices(); this.getPrices();
}); });
} }
clickedProduct(product: Product): void { clickedProduct(product: Product): void {
this.router.navigate([('/product/' + product.product_id)]); this.router.navigate([('/product/' + product.product_id)]);
} }

View File

@ -1,25 +0,0 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ProfileComponent } from './profile.component';
describe('ProfileComponent', () => {
let component: ProfileComponent;
let fixture: ComponentFixture<ProfileComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ ProfileComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(ProfileComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -1,25 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing'; import {ComponentFixture, TestBed} from '@angular/core/testing';
import { SliderForProductsComponent } from './slider-for-products.component'; import {SliderForProductsComponent} from './slider-for-products.component';
describe('SliderForProductsComponent', () => { describe('SliderForProductsComponent', () => {
let component: SliderForProductsComponent; let component: SliderForProductsComponent;
let fixture: ComponentFixture<SliderForProductsComponent>; let fixture: ComponentFixture<SliderForProductsComponent>;
beforeEach(async () => { beforeEach(async () => {
await TestBed.configureTestingModule({ await TestBed.configureTestingModule({
declarations: [ SliderForProductsComponent ] declarations: [SliderForProductsComponent]
}) })
.compileComponents(); .compileComponents();
}); });
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(SliderForProductsComponent); fixture = TestBed.createComponent(SliderForProductsComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
fixture.detectChanges(); fixture.detectChanges();
}); });
it('should create', () => { it('should create', () => {
expect(component).toBeTruthy(); expect(component).toBeTruthy();
}); });
}); });

View File

@ -2,21 +2,32 @@
<div class="container"> <div class="container">
<a class="navbar-brand" routerLink=""> Betterzon</a> <a class="navbar-brand" routerLink=""> Betterzon</a>
<div class="form-inline my-2 my-lg-0"> <div class="form-inline my-2 my-lg-0">
<input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search" (keyup.enter)="getSearchedProducts()" [(ngModel)]="searchQuery"> <input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search"
(keyup.enter)="getSearchedProducts()" [(ngModel)]="searchQuery">
</div> </div>
<button class="navbar-toggler text-uppercase font-weight-bold bg-primary text-white rounded" type="button" data-bs-toggle="collapse" data-bs-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation"> <button class="navbar-toggler text-uppercase font-weight-bold bg-primary text-white rounded" type="button"
data-bs-toggle="collapse" data-bs-target="#navbarResponsive" aria-controls="navbarResponsive"
aria-expanded="false" aria-label="Toggle navigation">
Menu Menu
<i class="fas fa-bars"></i> <i class="fas fa-bars"></i>
</button> </button>
<div class="collapse navbar-collapse" id="navbarResponsive"> <div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav ms-auto"> <ul class="navbar-nav ms-auto">
<li class="nav-item mx-0 mx-lg-1"><a class="nav-link py-3 px-0 px-lg-3 rounded" href="#top-gesuchte">top-offers</a></li> <li class="nav-item mx-0 mx-lg-1"><a class="nav-link py-3 px-0 px-lg-3 rounded" href="#top-gesuchte">top-offers</a>
<li class="nav-item mx-0 mx-lg-1"><a class="nav-link py-3 px-0 px-lg-3 rounded" href="#about">about</a></li> </li>
<li class="nav-item mx-0 mx-lg-1"><a class="nav-link py-3 px-0 px-lg-3 rounded" href="#unsere-kunden">our clients</a></li> <li class="nav-item mx-0 mx-lg-1"><a class="nav-link py-3 px-0 px-lg-3 rounded" href="#about">about</a>
<li class="nav-item mx-0 mx-lg-1" *ngIf="!isLoggedIn"><a class="nav-link py-3 px-0 px-lg-3 rounded" routerLink="/signin">sign in</a></li> </li>
<li class="nav-item mx-0 mx-lg-1" *ngIf="!isLoggedIn"><a class="nav-link py-3 px-0 px-lg-3 rounded" routerLink="/registration">sign up</a></li> <li class="nav-item mx-0 mx-lg-1"><a class="nav-link py-3 px-0 px-lg-3 rounded" href="#unsere-kunden">our
<li class="nav-item mx-0 mx-lg-1" *ngIf="isLoggedIn"><a class="nav-link py-3 px-0 px-lg-3 rounded" routerLink="" (click)="logout()">log out</a></li> clients</a></li>
<li class="nav-item mx-0 mx-lg-1" *ngIf="isLoggedIn"><a class="nav-link py-3 px-0 px-lg-3 rounded" routerLink="/profile">profile</a></li> <li class="nav-item mx-0 mx-lg-1" *ngIf="!isLoggedIn"><a class="nav-link py-3 px-0 px-lg-3 rounded"
routerLink="/signin">sign in</a></li>
<li class="nav-item mx-0 mx-lg-1" *ngIf="!isLoggedIn"><a class="nav-link py-3 px-0 px-lg-3 rounded"
routerLink="/registration">sign up</a></li>
<li class="nav-item mx-0 mx-lg-1" *ngIf="isLoggedIn"><a class="nav-link py-3 px-0 px-lg-3 rounded"
routerLink="" (click)="logout()">log out</a>
</li>
<li class="nav-item mx-0 mx-lg-1" *ngIf="isLoggedIn"><a class="nav-link py-3 px-0 px-lg-3 rounded"
routerLink="/profile">profile</a></li>
</ul> </ul>
</div> </div>
</div> </div>

View File

@ -1,25 +1,48 @@
import { ComponentFixture, TestBed } from '@angular/core/testing'; import {ComponentFixture, TestBed} from '@angular/core/testing';
import { TopBarComponent } from './top-bar.component'; import {TopBarComponent} from './top-bar.component';
import {FormBuilder} from '@angular/forms';
import {ApiService} from '../../services/api.service';
import {Router} from '@angular/router';
import {AbstractMockObservableService} from '../../mocks/mock.service';
class MockApiService extends AbstractMockObservableService {
getUserInfo(): any {
this.content = [];
return this;
}
getSessionInfoFromLocalStorage(): any {
this.content = [];
return this;
}
}
describe('TopBarComponent', () => { describe('TopBarComponent', () => {
let component: TopBarComponent; let component: TopBarComponent;
let fixture: ComponentFixture<TopBarComponent>; let fixture: ComponentFixture<TopBarComponent>;
let mockService;
const router = {
navigate: jasmine.createSpy('navigate'),
routerState: jasmine.createSpy('routerState')
};
beforeEach(async () => { beforeEach(async () => {
await TestBed.configureTestingModule({ mockService = new MockApiService();
declarations: [ TopBarComponent ] await TestBed.configureTestingModule({
}) declarations: [TopBarComponent],
.compileComponents(); providers: [{provide: ApiService, useValue: mockService}, {provide: Router, useValue: router}]
}); })
.compileComponents();
});
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(TopBarComponent); fixture = TestBed.createComponent(TopBarComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
fixture.detectChanges(); fixture.detectChanges();
}); });
it('should create', () => { it('should create', () => {
expect(component).toBeTruthy(); expect(component).toBeTruthy();
}); });
}); });

View File

@ -1,5 +1,5 @@
<app-header [showSearch]="true"></app-header> <app-top-bar></app-top-bar>
<div id="imprint"> <div id="imprint" class="container masthead">
<h1>Impressum</h1> <h1>Impressum</h1>
<h2>Angaben gem&auml;&szlig; &sect; 5 TMG</h2> <h2>Angaben gem&auml;&szlig; &sect; 5 TMG</h2>
@ -17,14 +17,16 @@
<h3>Haftung f&uuml;r Inhalte</h3> <h3>Haftung f&uuml;r Inhalte</h3>
<p> <p>
Als Diensteanbieter sind wir gem&auml;&szlig; &sect; 7 Abs.1 TMG f&uuml;r eigene Als Diensteanbieter sind wir gem&auml;&szlig; &sect; 7 Abs.1 TMG f&uuml;r eigene
Inhalte auf diesen Seiten nach den allgemeinen Gesetzen verantwortlich. Nach &sect;&sect; 8 bis 10 TMG sind wir als Inhalte auf diesen Seiten nach den allgemeinen Gesetzen verantwortlich. Nach &sect;&sect; 8 bis 10 TMG sind wir
als
Diensteanbieter jedoch nicht verpflichtet, &uuml;bermittelte oder gespeicherte fremde Informationen zu &uuml;berwachen Diensteanbieter jedoch nicht verpflichtet, &uuml;bermittelte oder gespeicherte fremde Informationen zu &uuml;berwachen
oder nach Umst&auml;nden zu forschen, die auf eine rechtswidrige T&auml;tigkeit hinweisen. oder nach Umst&auml;nden zu forschen, die auf eine rechtswidrige T&auml;tigkeit hinweisen.
</p> </p>
<p> <p>
Verpflichtungen zur Entfernung oder Sperrung der Nutzung von Informationen nach den allgemeinen Gesetzen bleiben Verpflichtungen zur Entfernung oder Sperrung der Nutzung von Informationen nach den allgemeinen Gesetzen bleiben
hiervon unber&uuml;hrt. hiervon unber&uuml;hrt.
Eine diesbez&uuml;gliche Haftung ist jedoch erst ab dem Zeitpunkt der Kenntnis einer konkreten Rechtsverletzung m&ouml;glich. Eine diesbez&uuml;gliche Haftung ist jedoch erst ab dem Zeitpunkt der Kenntnis einer konkreten Rechtsverletzung
m&ouml;glich.
Bei Bekanntwerden von entsprechenden Rechtsverletzungen werden wir diese Inhalte umgehend entfernen. Bei Bekanntwerden von entsprechenden Rechtsverletzungen werden wir diese Inhalte umgehend entfernen.
</p> </p>
@ -44,16 +46,21 @@
<h3>Urheberrecht</h3> <h3>Urheberrecht</h3>
<p> <p>
Die durch die Seitenbetreiber erstellten Inhalte und Werke auf diesen Seiten unterliegen dem deutschen Urheberrecht. Die durch die Seitenbetreiber erstellten Inhalte und Werke auf diesen Seiten unterliegen dem deutschen
Urheberrecht.
Die Vervielf&auml;ltigung, Bearbeitung, Verbreitung und jede Art der Verwertung au&szlig;erhalb der Grenzen des Die Vervielf&auml;ltigung, Bearbeitung, Verbreitung und jede Art der Verwertung au&szlig;erhalb der Grenzen des
Urheberrechtes bed&uuml;rfen der schriftlichen Zustimmung des jeweiligen Autors bzw. Erstellers. Downloads und Urheberrechtes bed&uuml;rfen der schriftlichen Zustimmung des jeweiligen Autors bzw. Erstellers. Downloads und
Kopien dieser Seite sind nur f&uuml;r den privaten, nicht kommerziellen Gebrauch gestattet. Kopien dieser Seite sind nur f&uuml;r den privaten, nicht kommerziellen Gebrauch gestattet.
</p> </p>
<p> <p>
Soweit die Inhalte auf dieser Seite nicht vom Betreiber erstellt wurden, werden die Urheberrechte Dritter beachtet. Soweit die Inhalte auf dieser Seite nicht vom Betreiber erstellt wurden, werden die Urheberrechte Dritter
Insbesondere werden Inhalte Dritter als solche gekennzeichnet. Sollten Sie trotzdem auf eine Urheberrechtsverletzung beachtet.
aufmerksam werden, bitten wir um einen entsprechenden Hinweis. Bei Bekanntwerden von Rechtsverletzungen werden wir Insbesondere werden Inhalte Dritter als solche gekennzeichnet. Sollten Sie trotzdem auf eine
Urheberrechtsverletzung
aufmerksam werden, bitten wir um einen entsprechenden Hinweis. Bei Bekanntwerden von Rechtsverletzungen werden
wir
derartige Inhalte umgehend entfernen. derartige Inhalte umgehend entfernen.
</p> </p>
</div> </div>
<app-footer></app-footer> <app-bottom-bar></app-bottom-bar>
<app-copyright></app-copyright>

View File

@ -1,15 +1,16 @@
import { Component, OnInit } from '@angular/core'; import {Component, OnInit} from '@angular/core';
@Component({ @Component({
selector: 'app-imprint', selector: 'app-imprint',
templateUrl: './imprint.component.html', templateUrl: './imprint.component.html',
styleUrls: ['./imprint.component.css'] styleUrls: ['./imprint.component.css']
}) })
export class ImprintComponent implements OnInit { export class ImprintComponent implements OnInit {
constructor() { } constructor() {
}
ngOnInit(): void { ngOnInit(): void {
} }
} }

View File

@ -1,6 +1,6 @@
import {Component, OnInit} from '@angular/core'; import {Component, OnInit} from '@angular/core';
import {Router} from '@angular/router'; import {Router} from '@angular/router';
import {ApiService} from "../../services/api.service"; import {ApiService} from '../../services/api.service';
@Component({ @Component({
selector: 'app-landingpage', selector: 'app-landingpage',
@ -12,8 +12,7 @@ export class LandingpageComponent implements OnInit {
isLoggedIn = false; isLoggedIn = false;
constructor( constructor(
private router: Router, private router: Router
private api: ApiService
) { ) {
} }

View File

@ -1,15 +1,16 @@
import { Component, OnInit } from '@angular/core'; import {Component, OnInit} from '@angular/core';
@Component({ @Component({
selector: 'app-page-not-found-page', selector: 'app-page-not-found-page',
templateUrl: './page-not-found-page.component.html', templateUrl: './page-not-found-page.component.html',
styleUrls: ['./page-not-found-page.component.css'] styleUrls: ['./page-not-found-page.component.css']
}) })
export class PageNotFoundPageComponent implements OnInit { export class PageNotFoundPageComponent implements OnInit {
constructor() { } constructor() {
}
ngOnInit(): void { ngOnInit(): void {
} }
} }

View File

@ -1,11 +1,12 @@
<app-header [showSearch]="true"></app-header> <app-top-bar></app-top-bar>
<div id="privacy"> <div id="privacy" class="container masthead">
<h1>Datenschutz&shy;erkl&auml;rung</h1> <h1>Datenschutz&shy;erkl&auml;rung</h1>
<h2>1. Datenschutz auf einen Blick</h2> <h2>1. Datenschutz auf einen Blick</h2>
<h3>Allgemeine Hinweise</h3> <h3>Allgemeine Hinweise</h3>
<p> <p>
Die folgenden Hinweise geben einen einfachen &Uuml;berblick dar&uuml;ber, was mit Ihren Die folgenden Hinweise geben einen einfachen &Uuml;berblick dar&uuml;ber, was mit Ihren
personenbezogenen Daten passiert, wenn Sie diese Website besuchen. Personenbezogene Daten sind alle Daten, mit denen personenbezogenen Daten passiert, wenn Sie diese Website besuchen. Personenbezogene Daten sind alle Daten, mit
denen
Sie pers&ouml;nlich identifiziert werden k&ouml;nnen. Ausf&uuml;hrliche Informationen zum Thema Datenschutz Sie pers&ouml;nlich identifiziert werden k&ouml;nnen. Ausf&uuml;hrliche Informationen zum Thema Datenschutz
entnehmen Sie unserer unter diesem Text aufgef&uuml;hrten Datenschutzerkl&auml;rung. entnehmen Sie unserer unter diesem Text aufgef&uuml;hrten Datenschutzerkl&auml;rung.
</p> </p>
@ -40,8 +41,10 @@
Sie haben jederzeit das Recht, unentgeltlich Auskunft &uuml;ber Sie haben jederzeit das Recht, unentgeltlich Auskunft &uuml;ber
Herkunft, Empf&auml;nger und Zweck Ihrer gespeicherten personenbezogenen Daten zu erhalten. Sie haben au&szlig;erdem Herkunft, Empf&auml;nger und Zweck Ihrer gespeicherten personenbezogenen Daten zu erhalten. Sie haben au&szlig;erdem
ein Recht, die Berichtigung oder L&ouml;schung dieser Daten zu verlangen. Wenn Sie eine Einwilligung zur ein Recht, die Berichtigung oder L&ouml;schung dieser Daten zu verlangen. Wenn Sie eine Einwilligung zur
Datenverarbeitung erteilt haben, k&ouml;nnen Sie diese Einwilligung jederzeit f&uuml;r die Zukunft widerrufen. Au&szlig;erdem Datenverarbeitung erteilt haben, k&ouml;nnen Sie diese Einwilligung jederzeit f&uuml;r die Zukunft widerrufen.
haben Sie das Recht, unter bestimmten Umst&auml;nden die Einschr&auml;nkung der Verarbeitung Ihrer personenbezogenen Au&szlig;erdem
haben Sie das Recht, unter bestimmten Umst&auml;nden die Einschr&auml;nkung der Verarbeitung Ihrer
personenbezogenen
Daten zu verlangen. Des Weiteren steht Ihnen ein Beschwerderecht bei der zust&auml;ndigen Aufsichtsbeh&ouml;rde Daten zu verlangen. Des Weiteren steht Ihnen ein Beschwerderecht bei der zust&auml;ndigen Aufsichtsbeh&ouml;rde
zu. zu.
</p> </p>
@ -85,13 +88,15 @@
<h3>Datenschutz</h3> <h3>Datenschutz</h3>
<p> <p>
Die Betreiber dieser Seiten nehmen den Schutz Ihrer pers&ouml;nlichen Daten sehr ernst. Wir Die Betreiber dieser Seiten nehmen den Schutz Ihrer pers&ouml;nlichen Daten sehr ernst. Wir
behandeln Ihre personenbezogenen Daten vertraulich und entsprechend der gesetzlichen Datenschutzvorschriften sowie behandeln Ihre personenbezogenen Daten vertraulich und entsprechend der gesetzlichen Datenschutzvorschriften
sowie
dieser Datenschutzerkl&auml;rung. dieser Datenschutzerkl&auml;rung.
</p> </p>
<p> <p>
Wenn Sie diese Website benutzen, werden verschiedene personenbezogene Daten Wenn Sie diese Website benutzen, werden verschiedene personenbezogene Daten
erhoben. Personenbezogene Daten sind Daten, mit denen Sie pers&ouml;nlich identifiziert werden k&ouml;nnen. Die erhoben. Personenbezogene Daten sind Daten, mit denen Sie pers&ouml;nlich identifiziert werden k&ouml;nnen. Die
vorliegende Datenschutzerkl&auml;rung erl&auml;utert, welche Daten wir erheben und wof&uuml;r wir sie nutzen. Sie vorliegende Datenschutzerkl&auml;rung erl&auml;utert, welche Daten wir erheben und wof&uuml;r wir sie nutzen.
Sie
erl&auml;utert auch, wie und zu welchem Zweck das geschieht. erl&auml;utert auch, wie und zu welchem Zweck das geschieht.
</p> </p>
<p> <p>
@ -115,7 +120,8 @@
E-Mail: betterzon-privacy@mueller-patrick.tech E-Mail: betterzon-privacy@mueller-patrick.tech
</p> </p>
<p> <p>
Verantwortliche Stelle ist die nat&uuml;rliche oder juristische Person, die allein oder gemeinsam mit anderen &uuml;ber Verantwortliche Stelle ist die nat&uuml;rliche oder juristische Person, die allein oder gemeinsam mit anderen
&uuml;ber
die Zwecke und Mittel der Verarbeitung von personenbezogenen Daten (z.&nbsp;B. Namen, E-Mail-Adressen o. &Auml;.) die Zwecke und Mittel der Verarbeitung von personenbezogenen Daten (z.&nbsp;B. Namen, E-Mail-Adressen o. &Auml;.)
entscheidet. entscheidet.
</p> </p>
@ -124,7 +130,8 @@
<p> <p>
Soweit innerhalb dieser Datenschutzerkl&auml;rung keine speziellere Speicherdauer genannt Soweit innerhalb dieser Datenschutzerkl&auml;rung keine speziellere Speicherdauer genannt
wurde, verbleiben Ihre personenbezogenen Daten bei uns, bis der Zweck f&uuml;r die Datenverarbeitung entf&auml;llt. wurde, verbleiben Ihre personenbezogenen Daten bei uns, bis der Zweck f&uuml;r die Datenverarbeitung entf&auml;llt.
Wenn Sie ein berechtigtes L&ouml;schersuchen geltend machen oder eine Einwilligung zur Datenverarbeitung widerrufen, Wenn Sie ein berechtigtes L&ouml;schersuchen geltend machen oder eine Einwilligung zur Datenverarbeitung
widerrufen,
werden Ihre Daten gel&ouml;scht, sofern wir keine anderen rechtlich zul&auml;ssigen Gr&uuml;nde f&uuml;r die werden Ihre Daten gel&ouml;scht, sofern wir keine anderen rechtlich zul&auml;ssigen Gr&uuml;nde f&uuml;r die
Speicherung Ihrer personenbezogenen Daten haben (z.B. steuer- oder handelsrechtliche Aufbewahrungsfristen); im Speicherung Ihrer personenbezogenen Daten haben (z.B. steuer- oder handelsrechtliche Aufbewahrungsfristen); im
letztgenannten Fall erfolgt die L&ouml;schung nach Fortfall dieser Gr&uuml;nde. letztgenannten Fall erfolgt die L&ouml;schung nach Fortfall dieser Gr&uuml;nde.
@ -139,7 +146,8 @@
Datenschutzniveau garantiert werden kann. Beispielsweise sind US-Unternehmen dazu verpflichtet, personenbezogene Datenschutzniveau garantiert werden kann. Beispielsweise sind US-Unternehmen dazu verpflichtet, personenbezogene
Daten an Sicherheitsbeh&ouml;rden herauszugeben, ohne dass Sie als Betroffener hiergegen gerichtlich vorgehen k&ouml;nnten. Daten an Sicherheitsbeh&ouml;rden herauszugeben, ohne dass Sie als Betroffener hiergegen gerichtlich vorgehen k&ouml;nnten.
Es kann daher nicht ausgeschlossen werden, dass US-Beh&ouml;rden (z.B. Geheimdienste) Ihre auf US-Servern Es kann daher nicht ausgeschlossen werden, dass US-Beh&ouml;rden (z.B. Geheimdienste) Ihre auf US-Servern
befindlichen Daten zu &Uuml;berwachungszwecken verarbeiten, auswerten und dauerhaft speichern. Wir haben auf diese befindlichen Daten zu &Uuml;berwachungszwecken verarbeiten, auswerten und dauerhaft speichern. Wir haben auf
diese
Verarbeitungst&auml;tigkeiten keinen Einfluss. Verarbeitungst&auml;tigkeiten keinen Einfluss.
</p> </p>
@ -150,15 +158,19 @@
erfolgten Datenverarbeitung bleibt vom Widerruf unber&uuml;hrt. erfolgten Datenverarbeitung bleibt vom Widerruf unber&uuml;hrt.
</p> </p>
<h3>Widerspruchsrecht gegen die Datenerhebung in besonderen F&auml;llen sowie gegen Direktwerbung (Art. 21 DSGVO)</h3> <h3>Widerspruchsrecht gegen die Datenerhebung in besonderen F&auml;llen sowie gegen Direktwerbung (Art. 21
DSGVO)</h3>
<p> <p>
WENN DIE DATENVERARBEITUNG AUF GRUNDLAGE VON ART. 6 ABS. 1 LIT. E ODER F DSGVO ERFOLGT, HABEN SIE JEDERZEIT DAS WENN DIE DATENVERARBEITUNG AUF GRUNDLAGE VON ART. 6 ABS. 1 LIT. E ODER F DSGVO ERFOLGT, HABEN SIE JEDERZEIT DAS
RECHT, AUS GR&Uuml;NDEN, DIE SICH AUS IHRER BESONDEREN SITUATION ERGEBEN, GEGEN DIE VERARBEITUNG IHRER RECHT, AUS GR&Uuml;NDEN, DIE SICH AUS IHRER BESONDEREN SITUATION ERGEBEN, GEGEN DIE VERARBEITUNG IHRER
PERSONENBEZOGENEN DATEN WIDERSPRUCH EINZULEGEN; DIES GILT AUCH F&Uuml;R EIN AUF DIESE BESTIMMUNGEN GEST&Uuml;TZTES PERSONENBEZOGENEN DATEN WIDERSPRUCH EINZULEGEN; DIES GILT AUCH F&Uuml;R EIN AUF DIESE BESTIMMUNGEN GEST&Uuml;TZTES
PROFILING. DIE JEWEILIGE RECHTSGRUNDLAGE, AUF DENEN EINE VERARBEITUNG BERUHT, ENTNEHMEN SIE DIESER DATENSCHUTZERKL&Auml;RUNG. PROFILING. DIE JEWEILIGE RECHTSGRUNDLAGE, AUF DENEN EINE VERARBEITUNG BERUHT, ENTNEHMEN SIE DIESER
WENN SIE WIDERSPRUCH EINLEGEN, WERDEN WIR IHRE BETROFFENEN PERSONENBEZOGENEN DATEN NICHT MEHR VERARBEITEN, ES SEI DATENSCHUTZERKL&Auml;RUNG.
WENN SIE WIDERSPRUCH EINLEGEN, WERDEN WIR IHRE BETROFFENEN PERSONENBEZOGENEN DATEN NICHT MEHR VERARBEITEN, ES
SEI
DENN, WIR K&Ouml;NNEN ZWINGENDE SCHUTZW&Uuml;RDIGE GR&Uuml;NDE F&Uuml;R DIE VERARBEITUNG NACHWEISEN, DIE IHRE DENN, WIR K&Ouml;NNEN ZWINGENDE SCHUTZW&Uuml;RDIGE GR&Uuml;NDE F&Uuml;R DIE VERARBEITUNG NACHWEISEN, DIE IHRE
INTERESSEN, RECHTE UND FREIHEITEN &Uuml;BERWIEGEN ODER DIE VERARBEITUNG DIENT DER GELTENDMACHUNG, AUS&Uuml;BUNG ODER INTERESSEN, RECHTE UND FREIHEITEN &Uuml;BERWIEGEN ODER DIE VERARBEITUNG DIENT DER GELTENDMACHUNG, AUS&Uuml;BUNG
ODER
VERTEIDIGUNG VON RECHTSANSPR&Uuml;CHEN (WIDERSPRUCH NACH ART. 21 ABS. 1 DSGVO). VERTEIDIGUNG VON RECHTSANSPR&Uuml;CHEN (WIDERSPRUCH NACH ART. 21 ABS. 1 DSGVO).
</p> </p>
<p> <p>
@ -166,7 +178,8 @@
DATEN VERARBEITET, UM DIREKTWERBUNG ZU BETREIBEN, SO HABEN SIE DAS RECHT, JEDERZEIT WIDERSPRUCH GEGEN DIE DATEN VERARBEITET, UM DIREKTWERBUNG ZU BETREIBEN, SO HABEN SIE DAS RECHT, JEDERZEIT WIDERSPRUCH GEGEN DIE
VERARBEITUNG SIE BETREFFENDER PERSONENBEZOGENER DATEN ZUM ZWECKE DERARTIGER WERBUNG EINZULEGEN; DIES GILT AUCH F&Uuml;R VERARBEITUNG SIE BETREFFENDER PERSONENBEZOGENER DATEN ZUM ZWECKE DERARTIGER WERBUNG EINZULEGEN; DIES GILT AUCH F&Uuml;R
DAS PROFILING, SOWEIT ES MIT SOLCHER DIREKTWERBUNG IN VERBINDUNG STEHT. WENN SIE WIDERSPRECHEN, WERDEN IHRE DAS PROFILING, SOWEIT ES MIT SOLCHER DIREKTWERBUNG IN VERBINDUNG STEHT. WENN SIE WIDERSPRECHEN, WERDEN IHRE
PERSONENBEZOGENEN DATEN ANSCHLIESSEND NICHT MEHR ZUM ZWECKE DER DIREKTWERBUNG VERWENDET (WIDERSPRUCH NACH ART. 21 PERSONENBEZOGENEN DATEN ANSCHLIESSEND NICHT MEHR ZUM ZWECKE DER DIREKTWERBUNG VERWENDET (WIDERSPRUCH NACH ART.
21
ABS. 2 DSGVO). ABS. 2 DSGVO).
</p> </p>
@ -174,7 +187,8 @@
<p> <p>
Im Falle von Verst&ouml;&szlig;en Im Falle von Verst&ouml;&szlig;en
gegen die DSGVO steht den Betroffenen ein Beschwerderecht bei einer Aufsichtsbeh&ouml;rde, insbesondere in dem gegen die DSGVO steht den Betroffenen ein Beschwerderecht bei einer Aufsichtsbeh&ouml;rde, insbesondere in dem
Mitgliedstaat ihres gew&ouml;hnlichen Aufenthalts, ihres Arbeitsplatzes oder des Orts des mutma&szlig;lichen Versto&szlig;es Mitgliedstaat ihres gew&ouml;hnlichen Aufenthalts, ihres Arbeitsplatzes oder des Orts des mutma&szlig;lichen
Versto&szlig;es
zu. Das Beschwerderecht besteht unbeschadet anderweitiger verwaltungsrechtlicher oder gerichtlicher zu. Das Beschwerderecht besteht unbeschadet anderweitiger verwaltungsrechtlicher oder gerichtlicher
Rechtsbehelfe. Rechtsbehelfe.
</p> </p>
@ -182,7 +196,8 @@
<h3>Recht auf Daten&shy;&uuml;bertrag&shy;barkeit</h3> <h3>Recht auf Daten&shy;&uuml;bertrag&shy;barkeit</h3>
<p> <p>
Sie haben das Recht, Daten, die wir auf Grundlage Ihrer Sie haben das Recht, Daten, die wir auf Grundlage Ihrer
Einwilligung oder in Erf&uuml;llung eines Vertrags automatisiert verarbeiten, an sich oder an einen Dritten in einem Einwilligung oder in Erf&uuml;llung eines Vertrags automatisiert verarbeiten, an sich oder an einen Dritten in
einem
g&auml;ngigen, maschinenlesbaren Format aush&auml;ndigen zu lassen. Sofern Sie die direkte &Uuml;bertragung der g&auml;ngigen, maschinenlesbaren Format aush&auml;ndigen zu lassen. Sofern Sie die direkte &Uuml;bertragung der
Daten an einen anderen Verantwortlichen verlangen, erfolgt dies nur, soweit es technisch machbar ist. Daten an einen anderen Verantwortlichen verlangen, erfolgt dies nur, soweit es technisch machbar ist.
</p> </p>
@ -190,8 +205,10 @@
<h3>SSL- bzw. TLS-Verschl&uuml;sselung</h3> <h3>SSL- bzw. TLS-Verschl&uuml;sselung</h3>
<p> <p>
Diese Seite nutzt aus Sicherheitsgr&uuml;nden und zum Schutz der &Uuml;bertragung Diese Seite nutzt aus Sicherheitsgr&uuml;nden und zum Schutz der &Uuml;bertragung
vertraulicher Inhalte, wie zum Beispiel Bestellungen oder Anfragen, die Sie an uns als Seitenbetreiber senden, eine vertraulicher Inhalte, wie zum Beispiel Bestellungen oder Anfragen, die Sie an uns als Seitenbetreiber senden,
SSL- bzw. TLS-Verschl&uuml;sselung. Eine verschl&uuml;sselte Verbindung erkennen Sie daran, dass die Adresszeile des eine
SSL- bzw. TLS-Verschl&uuml;sselung. Eine verschl&uuml;sselte Verbindung erkennen Sie daran, dass die Adresszeile
des
Browsers von &bdquo;http://&ldquo; auf &bdquo;https://&ldquo; wechselt und an dem Schloss-Symbol in Ihrer Browsers von &bdquo;http://&ldquo; auf &bdquo;https://&ldquo; wechselt und an dem Schloss-Symbol in Ihrer
Browserzeile. Browserzeile.
</p> </p>
@ -203,8 +220,10 @@
<h3>Auskunft, L&ouml;schung und Berichtigung</h3> <h3>Auskunft, L&ouml;schung und Berichtigung</h3>
<p> <p>
Sie haben im Rahmen der geltenden gesetzlichen Bestimmungen Sie haben im Rahmen der geltenden gesetzlichen Bestimmungen
jederzeit das Recht auf unentgeltliche Auskunft &uuml;ber Ihre gespeicherten personenbezogenen Daten, deren Herkunft jederzeit das Recht auf unentgeltliche Auskunft &uuml;ber Ihre gespeicherten personenbezogenen Daten, deren
und Empf&auml;nger und den Zweck der Datenverarbeitung und ggf. ein Recht auf Berichtigung oder L&ouml;schung dieser Herkunft
und Empf&auml;nger und den Zweck der Datenverarbeitung und ggf. ein Recht auf Berichtigung oder L&ouml;schung
dieser
Daten. Hierzu sowie zu weiteren Fragen zum Thema personenbezogene Daten k&ouml;nnen Sie sich jederzeit an uns Daten. Hierzu sowie zu weiteren Fragen zum Thema personenbezogene Daten k&ouml;nnen Sie sich jederzeit an uns
wenden. wenden.
</p> </p>
@ -216,22 +235,29 @@
</p> </p>
<ul> <ul>
<li> <li>
Wenn Sie die Richtigkeit Ihrer bei uns gespeicherten personenbezogenen Daten bestreiten, ben&ouml;tigen wir in Wenn Sie die Richtigkeit Ihrer bei uns gespeicherten personenbezogenen Daten bestreiten, ben&ouml;tigen wir
der Regel Zeit, um dies zu &uuml;berpr&uuml;fen. F&uuml;r die Dauer der Pr&uuml;fung haben Sie das Recht, die in
der Regel Zeit, um dies zu &uuml;berpr&uuml;fen. F&uuml;r die Dauer der Pr&uuml;fung haben Sie das Recht,
die
Einschr&auml;nkung der Verarbeitung Ihrer personenbezogenen Daten zu verlangen. Einschr&auml;nkung der Verarbeitung Ihrer personenbezogenen Daten zu verlangen.
</li> </li>
<li> <li>
Wenn die Verarbeitung Ihrer personenbezogenen Daten unrechtm&auml;&szlig;ig geschah/geschieht, k&ouml;nnen Sie Wenn die Verarbeitung Ihrer personenbezogenen Daten unrechtm&auml;&szlig;ig geschah/geschieht, k&ouml;nnen
Sie
statt der L&ouml;schung die Einschr&auml;nkung der Datenverarbeitung verlangen. statt der L&ouml;schung die Einschr&auml;nkung der Datenverarbeitung verlangen.
</li> </li>
<li> <li>
Wenn wir Ihre personenbezogenen Daten nicht mehr ben&ouml;tigen, Sie sie jedoch zur Aus&uuml;bung, Verteidigung Wenn wir Ihre personenbezogenen Daten nicht mehr ben&ouml;tigen, Sie sie jedoch zur Aus&uuml;bung,
oder Geltendmachung von Rechtsanspr&uuml;chen ben&ouml;tigen, haben Sie das Recht, statt der L&ouml;schung die Verteidigung
oder Geltendmachung von Rechtsanspr&uuml;chen ben&ouml;tigen, haben Sie das Recht, statt der L&ouml;schung
die
Einschr&auml;nkung der Verarbeitung Ihrer personenbezogenen Daten zu verlangen. Einschr&auml;nkung der Verarbeitung Ihrer personenbezogenen Daten zu verlangen.
</li> </li>
<li> <li>
Wenn Sie einen Widerspruch nach Art. 21 Abs. 1 DSGVO eingelegt haben, muss eine Abw&auml;gung zwischen Ihren und Wenn Sie einen Widerspruch nach Art. 21 Abs. 1 DSGVO eingelegt haben, muss eine Abw&auml;gung zwischen Ihren
unseren Interessen vorgenommen werden. Solange noch nicht feststeht, wessen Interessen &uuml;berwiegen, haben und
unseren Interessen vorgenommen werden. Solange noch nicht feststeht, wessen Interessen &uuml;berwiegen,
haben
Sie das Recht, die Einschr&auml;nkung der Verarbeitung Ihrer personenbezogenen Daten zu verlangen. Sie das Recht, die Einschr&auml;nkung der Verarbeitung Ihrer personenbezogenen Daten zu verlangen.
</li> </li>
</ul> </ul>
@ -239,7 +265,8 @@
Wenn Sie die Verarbeitung Ihrer personenbezogenen Daten eingeschr&auml;nkt haben, d&uuml;rfen diese Daten Wenn Sie die Verarbeitung Ihrer personenbezogenen Daten eingeschr&auml;nkt haben, d&uuml;rfen diese Daten
&ndash; von ihrer Speicherung abgesehen &ndash; nur mit Ihrer Einwilligung oder zur Geltendmachung, Aus&uuml;bung &ndash; von ihrer Speicherung abgesehen &ndash; nur mit Ihrer Einwilligung oder zur Geltendmachung, Aus&uuml;bung
oder Verteidigung von Rechtsanspr&uuml;chen oder zum Schutz der Rechte einer anderen nat&uuml;rlichen oder oder Verteidigung von Rechtsanspr&uuml;chen oder zum Schutz der Rechte einer anderen nat&uuml;rlichen oder
juristischen Person oder aus Gr&uuml;nden eines wichtigen &ouml;ffentlichen Interesses der Europ&auml;ischen Union juristischen Person oder aus Gr&uuml;nden eines wichtigen &ouml;ffentlichen Interesses der Europ&auml;ischen
Union
oder eines Mitgliedstaats verarbeitet werden. oder eines Mitgliedstaats verarbeitet werden.
</p> </p>
@ -250,12 +277,14 @@
und richten auf Ihrem Endger&auml;t keinen Schaden an. Sie werden entweder vor&uuml;bergehend f&uuml;r die Dauer und richten auf Ihrem Endger&auml;t keinen Schaden an. Sie werden entweder vor&uuml;bergehend f&uuml;r die Dauer
einer Sitzung (Session-Cookies) oder dauerhaft (permanente Cookies) auf Ihrem Endger&auml;t gespeichert. einer Sitzung (Session-Cookies) oder dauerhaft (permanente Cookies) auf Ihrem Endger&auml;t gespeichert.
Session-Cookies werden nach Ende Ihres Besuchs automatisch gel&ouml;scht. Permanente Cookies bleiben auf Ihrem Session-Cookies werden nach Ende Ihres Besuchs automatisch gel&ouml;scht. Permanente Cookies bleiben auf Ihrem
Endger&auml;t gespeichert, bis Sie diese selbst l&ouml;schen&nbsp;oder eine automatische L&ouml;schung durch Ihren Endger&auml;t gespeichert, bis Sie diese selbst l&ouml;schen&nbsp;oder eine automatische L&ouml;schung durch
Ihren
Webbrowser erfolgt. Webbrowser erfolgt.
</p> </p>
<p> <p>
Teilweise k&ouml;nnen auch Cookies von Drittunternehmen auf Ihrem Endger&auml;t Teilweise k&ouml;nnen auch Cookies von Drittunternehmen auf Ihrem Endger&auml;t
gespeichert werden, wenn Sie unsere Seite betreten (Third-Party-Cookies). Diese erm&ouml;glichen uns oder Ihnen die gespeichert werden, wenn Sie unsere Seite betreten (Third-Party-Cookies). Diese erm&ouml;glichen uns oder Ihnen
die
Nutzung bestimmter Dienstleistungen des Drittunternehmens (z.B. Cookies zur Abwicklung von Nutzung bestimmter Dienstleistungen des Drittunternehmens (z.B. Cookies zur Abwicklung von
Zahlungsdienstleistungen). Zahlungsdienstleistungen).
</p> </p>
@ -267,24 +296,31 @@
</p> </p>
<p> <p>
Cookies, die zur Durchf&uuml;hrung des elektronischen Kommunikationsvorgangs (notwendige Cookies) Cookies, die zur Durchf&uuml;hrung des elektronischen Kommunikationsvorgangs (notwendige Cookies)
oder zur Bereitstellung bestimmter, von Ihnen erw&uuml;nschter Funktionen (funktionale Cookies, z. B. f&uuml;r die oder zur Bereitstellung bestimmter, von Ihnen erw&uuml;nschter Funktionen (funktionale Cookies, z. B. f&uuml;r
Warenkorbfunktion) oder zur Optimierung der Website (z.B. Cookies zur Messung des Webpublikums) erforderlich sind, die
werden auf Grundlage von Art. 6 Abs. 1 lit. f DSGVO gespeichert, sofern keine andere Rechtsgrundlage angegeben wird. Warenkorbfunktion) oder zur Optimierung der Website (z.B. Cookies zur Messung des Webpublikums) erforderlich
Der Websitebetreiber hat ein berechtigtes Interesse an der Speicherung von Cookies zur technisch fehlerfreien und sind,
werden auf Grundlage von Art. 6 Abs. 1 lit. f DSGVO gespeichert, sofern keine andere Rechtsgrundlage angegeben
wird.
Der Websitebetreiber hat ein berechtigtes Interesse an der Speicherung von Cookies zur technisch fehlerfreien
und
optimierten Bereitstellung seiner Dienste. Sofern eine Einwilligung zur Speicherung von Cookies abgefragt wurde, optimierten Bereitstellung seiner Dienste. Sofern eine Einwilligung zur Speicherung von Cookies abgefragt wurde,
erfolgt die Speicherung der betreffenden Cookies ausschlie&szlig;lich auf Grundlage dieser Einwilligung (Art. 6 Abs. erfolgt die Speicherung der betreffenden Cookies ausschlie&szlig;lich auf Grundlage dieser Einwilligung (Art. 6
Abs.
1 lit. a DSGVO); die Einwilligung ist jederzeit widerrufbar. 1 lit. a DSGVO); die Einwilligung ist jederzeit widerrufbar.
</p> </p>
<p> <p>
Sie k&ouml;nnen Ihren Browser so einstellen, Sie k&ouml;nnen Ihren Browser so einstellen,
dass Sie &uuml;ber das Setzen von Cookies informiert werden und Cookies nur im Einzelfall erlauben, die Annahme von dass Sie &uuml;ber das Setzen von Cookies informiert werden und Cookies nur im Einzelfall erlauben, die Annahme
von
Cookies f&uuml;r bestimmte F&auml;lle oder generell ausschlie&szlig;en sowie das automatische L&ouml;schen der Cookies f&uuml;r bestimmte F&auml;lle oder generell ausschlie&szlig;en sowie das automatische L&ouml;schen der
Cookies beim Schlie&szlig;en des Browsers aktivieren. Bei der Deaktivierung von Cookies kann die Funktionalit&auml;t Cookies beim Schlie&szlig;en des Browsers aktivieren. Bei der Deaktivierung von Cookies kann die Funktionalit&auml;t
dieser Website eingeschr&auml;nkt sein. dieser Website eingeschr&auml;nkt sein.
</p> </p>
<p> <p>
Soweit Cookies von Drittunternehmen oder zu Analysezwecken eingesetzt Soweit Cookies von Drittunternehmen oder zu Analysezwecken eingesetzt
werden, werden wir Sie hier&uuml;ber im Rahmen dieser Datenschutzerkl&auml;rung gesondert informieren und ggf. eine werden, werden wir Sie hier&uuml;ber im Rahmen dieser Datenschutzerkl&auml;rung gesondert informieren und ggf.
eine
Einwilligung abfragen. Einwilligung abfragen.
</p> </p>
@ -318,10 +354,13 @@
den Fall von Anschlussfragen bei uns gespeichert. Diese Daten geben wir nicht ohne Ihre Einwilligung weiter. den Fall von Anschlussfragen bei uns gespeichert. Diese Daten geben wir nicht ohne Ihre Einwilligung weiter.
</p> </p>
<p> <p>
Die Verarbeitung dieser Daten erfolgt auf Grundlage von Art. 6 Abs. 1 lit. b DSGVO, sofern Ihre Anfrage mit der Erf&uuml;llung Die Verarbeitung dieser Daten erfolgt auf Grundlage von Art. 6 Abs. 1 lit. b DSGVO, sofern Ihre Anfrage mit der
eines Vertrags zusammenh&auml;ngt oder zur Durchf&uuml;hrung vorvertraglicher Ma&szlig;nahmen erforderlich ist. In Erf&uuml;llung
eines Vertrags zusammenh&auml;ngt oder zur Durchf&uuml;hrung vorvertraglicher Ma&szlig;nahmen erforderlich ist.
In
allen &uuml;brigen F&auml;llen beruht die Verarbeitung auf unserem berechtigten Interesse an der effektiven allen &uuml;brigen F&auml;llen beruht die Verarbeitung auf unserem berechtigten Interesse an der effektiven
Bearbeitung der an uns gerichteten Anfragen (Art. 6 Abs. 1 lit. f DSGVO) oder auf Ihrer Einwilligung (Art. 6 Abs. 1 Bearbeitung der an uns gerichteten Anfragen (Art. 6 Abs. 1 lit. f DSGVO) oder auf Ihrer Einwilligung (Art. 6
Abs. 1
lit. a DSGVO) sofern diese abgefragt wurde. lit. a DSGVO) sofern diese abgefragt wurde.
</p> </p>
<p> <p>
@ -335,21 +374,25 @@
<p> <p>
Wenn Sie uns per E-Mail, Telefon oder Telefax kontaktieren, wird Wenn Sie uns per E-Mail, Telefon oder Telefax kontaktieren, wird
Ihre Anfrage inklusive aller daraus hervorgehenden personenbezogenen Daten (Name, Anfrage) zum Zwecke der Ihre Anfrage inklusive aller daraus hervorgehenden personenbezogenen Daten (Name, Anfrage) zum Zwecke der
Bearbeitung Ihres Anliegens bei uns gespeichert und verarbeitet. Diese Daten geben wir nicht ohne Ihre Einwilligung Bearbeitung Ihres Anliegens bei uns gespeichert und verarbeitet. Diese Daten geben wir nicht ohne Ihre
Einwilligung
weiter. weiter.
</p> </p>
<p> <p>
Die Verarbeitung dieser Daten erfolgt auf Grundlage von Art. 6 Abs. 1 lit. b DSGVO, sofern Ihre Die Verarbeitung dieser Daten erfolgt auf Grundlage von Art. 6 Abs. 1 lit. b DSGVO, sofern Ihre
Anfrage mit der Erf&uuml;llung eines Vertrags zusammenh&auml;ngt oder zur Durchf&uuml;hrung vorvertraglicher Ma&szlig;nahmen Anfrage mit der Erf&uuml;llung eines Vertrags zusammenh&auml;ngt oder zur Durchf&uuml;hrung vorvertraglicher Ma&szlig;nahmen
erforderlich ist. In allen &uuml;brigen F&auml;llen beruht die Verarbeitung auf unserem berechtigten Interesse an erforderlich ist. In allen &uuml;brigen F&auml;llen beruht die Verarbeitung auf unserem berechtigten Interesse
der effektiven Bearbeitung der an uns gerichteten Anfragen (Art. 6 Abs. 1 lit. f DSGVO) oder auf Ihrer Einwilligung an
der effektiven Bearbeitung der an uns gerichteten Anfragen (Art. 6 Abs. 1 lit. f DSGVO) oder auf Ihrer
Einwilligung
(Art. 6 Abs. 1 lit. a DSGVO) sofern diese abgefragt wurde. (Art. 6 Abs. 1 lit. a DSGVO) sofern diese abgefragt wurde.
</p> </p>
<p> <p>
Die von Ihnen an uns per Kontaktanfragen &uuml;bersandten Die von Ihnen an uns per Kontaktanfragen &uuml;bersandten
Daten verbleiben bei uns, bis Sie uns zur L&ouml;schung auffordern, Ihre Einwilligung zur Speicherung widerrufen Daten verbleiben bei uns, bis Sie uns zur L&ouml;schung auffordern, Ihre Einwilligung zur Speicherung widerrufen
oder der Zweck f&uuml;r die Datenspeicherung entf&auml;llt (z.&nbsp;B. nach abgeschlossener Bearbeitung Ihres oder der Zweck f&uuml;r die Datenspeicherung entf&auml;llt (z.&nbsp;B. nach abgeschlossener Bearbeitung Ihres
Anliegens). Zwingende gesetzliche Bestimmungen &ndash; insbesondere gesetzliche Aufbewahrungsfristen &ndash; bleiben Anliegens). Zwingende gesetzliche Bestimmungen &ndash; insbesondere gesetzliche Aufbewahrungsfristen &ndash;
bleiben
unber&uuml;hrt. unber&uuml;hrt.
</p> </p>
@ -363,10 +406,13 @@
<p> <p>
Zu diesem Zweck muss der von Ihnen Zu diesem Zweck muss der von Ihnen
verwendete Browser Verbindung zu den Servern von Google aufnehmen. Hierdurch erlangt Google Kenntnis dar&uuml;ber, verwendete Browser Verbindung zu den Servern von Google aufnehmen. Hierdurch erlangt Google Kenntnis dar&uuml;ber,
dass &uuml;ber Ihre IP-Adresse diese Website aufgerufen wurde. Die Nutzung von Google WebFonts erfolgt auf Grundlage dass &uuml;ber Ihre IP-Adresse diese Website aufgerufen wurde. Die Nutzung von Google WebFonts erfolgt auf
von Art. 6 Abs. 1 lit. f DSGVO. Der Websitebetreiber hat ein berechtigtes Interesse an der einheitlichen Darstellung Grundlage
von Art. 6 Abs. 1 lit. f DSGVO. Der Websitebetreiber hat ein berechtigtes Interesse an der einheitlichen
Darstellung
des Schriftbildes auf seiner Website. Sofern eine entsprechende Einwilligung abgefragt wurde (z. B. eine des Schriftbildes auf seiner Website. Sofern eine entsprechende Einwilligung abgefragt wurde (z. B. eine
Einwilligung zur Speicherung von Cookies), erfolgt die Verarbeitung ausschlie&szlig;lich auf Grundlage von Art. 6 Einwilligung zur Speicherung von Cookies), erfolgt die Verarbeitung ausschlie&szlig;lich auf Grundlage von Art.
6
Abs. 1 lit. a DSGVO; die Einwilligung ist jederzeit widerrufbar. Abs. 1 lit. a DSGVO; die Einwilligung ist jederzeit widerrufbar.
</p> </p>
<p> <p>
@ -376,7 +422,8 @@
<p> <p>
Weitere Informationen zu Google Web Fonts finden Sie Weitere Informationen zu Google Web Fonts finden Sie
unter <a href="https://developers.google.com/fonts/faq" target="_blank" rel="noopener noreferrer">https://developers.google.com/fonts/faq</a> unter <a href="https://developers.google.com/fonts/faq" target="_blank" rel="noopener noreferrer">https://developers.google.com/fonts/faq</a>
und in der Datenschutzerkl&auml;rung von Google: <a href="https://policies.google.com/privacy?hl=de" target="_blank" und in der Datenschutzerkl&auml;rung von Google: <a href="https://policies.google.com/privacy?hl=de"
target="_blank"
rel="noopener noreferrer">https://policies.google.com/privacy?hl=de</a>. rel="noopener noreferrer">https://policies.google.com/privacy?hl=de</a>.
</p> </p>
@ -388,10 +435,12 @@
<p> <p>
Beim Aufruf Beim Aufruf
einer Seite l&auml;dt Ihr Browser die ben&ouml;tigten Fonts in ihren Browsercache, um Texte, Schriftarten und einer Seite l&auml;dt Ihr Browser die ben&ouml;tigten Fonts in ihren Browsercache, um Texte, Schriftarten und
Symbole korrekt anzuzeigen. Zu diesem Zweck muss der von Ihnen verwendete Browser Verbindung zu den Servern von Font Symbole korrekt anzuzeigen. Zu diesem Zweck muss der von Ihnen verwendete Browser Verbindung zu den Servern von
Font
Awesome aufnehmen. Hierdurch erlangt Font Awesome Kenntnis dar&uuml;ber, dass &uuml;ber Ihre IP-Adresse diese Awesome aufnehmen. Hierdurch erlangt Font Awesome Kenntnis dar&uuml;ber, dass &uuml;ber Ihre IP-Adresse diese
Website aufgerufen wurde. Die Nutzung von Font Awesome erfolgt auf Grundlage von Art. 6 Abs. 1 lit. f DSGVO. Wir Website aufgerufen wurde. Die Nutzung von Font Awesome erfolgt auf Grundlage von Art. 6 Abs. 1 lit. f DSGVO. Wir
haben ein berechtigtes Interesse an der einheitlichen Darstellung des Schriftbildes auf unserer Website. Sofern eine haben ein berechtigtes Interesse an der einheitlichen Darstellung des Schriftbildes auf unserer Website. Sofern
eine
entsprechende Einwilligung abgefragt wurde (z. B. eine Einwilligung zur Speicherung von Cookies), erfolgt die entsprechende Einwilligung abgefragt wurde (z. B. eine Einwilligung zur Speicherung von Cookies), erfolgt die
Verarbeitung ausschlie&szlig;lich auf Grundlage von Art. 6 Abs. 1 lit. a DSGVO; die Einwilligung ist jederzeit Verarbeitung ausschlie&szlig;lich auf Grundlage von Art. 6 Abs. 1 lit. a DSGVO; die Einwilligung ist jederzeit
widerrufbar. widerrufbar.
@ -405,4 +454,5 @@
von Font Awesome unter: <a href="https://fontawesome.com/privacy" target="_blank" rel="noopener noreferrer">https://fontawesome.com/privacy</a>. von Font Awesome unter: <a href="https://fontawesome.com/privacy" target="_blank" rel="noopener noreferrer">https://fontawesome.com/privacy</a>.
</p> </p>
</div> </div>
<app-footer></app-footer> <app-bottom-bar></app-bottom-bar>
<app-copyright></app-copyright>

View File

@ -1,15 +1,16 @@
import { Component, OnInit } from '@angular/core'; import {Component, OnInit} from '@angular/core';
@Component({ @Component({
selector: 'app-privacy', selector: 'app-privacy',
templateUrl: './privacy.component.html', templateUrl: './privacy.component.html',
styleUrls: ['./privacy.component.css'] styleUrls: ['./privacy.component.css']
}) })
export class PrivacyComponent implements OnInit { export class PrivacyComponent implements OnInit {
constructor() { } constructor() {
}
ngOnInit(): void { ngOnInit(): void {
} }
} }

View File

@ -1,25 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing'; import {ComponentFixture, TestBed} from '@angular/core/testing';
import { ProfilePageComponent } from './profile-page.component'; import {ProfilePageComponent} from './profile-page.component';
describe('ProfilePageComponent', () => { describe('ProfilePageComponent', () => {
let component: ProfilePageComponent; let component: ProfilePageComponent;
let fixture: ComponentFixture<ProfilePageComponent>; let fixture: ComponentFixture<ProfilePageComponent>;
beforeEach(async () => { beforeEach(async () => {
await TestBed.configureTestingModule({ await TestBed.configureTestingModule({
declarations: [ ProfilePageComponent ] declarations: [ProfilePageComponent]
}) })
.compileComponents(); .compileComponents();
}); });
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(ProfilePageComponent); fixture = TestBed.createComponent(ProfilePageComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
fixture.detectChanges(); fixture.detectChanges();
}); });
it('should create', () => { it('should create', () => {
expect(component).toBeTruthy(); expect(component).toBeTruthy();
}); });
}); });

View File

@ -1,15 +1,16 @@
import { Component, OnInit } from '@angular/core'; import {Component, OnInit} from '@angular/core';
@Component({ @Component({
selector: 'app-profile-page', selector: 'app-profile-page',
templateUrl: './profile-page.component.html', templateUrl: './profile-page.component.html',
styleUrls: ['./profile-page.component.css'] styleUrls: ['./profile-page.component.css']
}) })
export class ProfilePageComponent implements OnInit { export class ProfilePageComponent implements OnInit {
constructor() { } constructor() {
}
ngOnInit(): void { ngOnInit(): void {
} }
} }

View File

@ -1,8 +1,8 @@
.inf-content{ .inf-content {
border:1px solid #DDDDDD; border: 1px solid #DDDDDD;
-webkit-border-radius:10px; -webkit-border-radius: 10px;
-moz-border-radius:10px; -moz-border-radius: 10px;
border-radius:10px; border-radius: 10px;
box-shadow: 7px 7px 7px rgba(0, 0, 0, 0.3); box-shadow: 7px 7px 7px rgba(0, 0, 0, 0.3);
} }

View File

@ -2,7 +2,8 @@
<div class="panel-body inf-content"> <div class="panel-body inf-content">
<div class="row"> <div class="row">
<div class="col-md-4"> <div class="col-md-4">
<img alt="" style="width:600px;" title="" class="img-circle img-thumbnail isTooltip" src="https://bootdey.com/img/Content/avatar/avatar7.png" data-original-title="Usuario"> <img alt="" style="width:600px;" title="" class="img-circle img-thumbnail isTooltip"
src="https://bootdey.com/img/Content/avatar/avatar7.png" data-original-title="Usuario">
<ul title="Ratings" class="list-inline ratings text-center"> <ul title="Ratings" class="list-inline ratings text-center">
<li><a href="#"><span class="glyphicon glyphicon-star"></span></a></li> <li><a href="#"><span class="glyphicon glyphicon-star"></span></a></li>
<li><a href="#"><span class="glyphicon glyphicon-star"></span></a></li> <li><a href="#"><span class="glyphicon glyphicon-star"></span></a></li>
@ -86,13 +87,14 @@
{{productsMap[alarm.product_id]?.name}} {{productsMap[alarm.product_id]?.name}}
</td> </td>
<td> <td>
{{alarm.defined_price/100}}€ {{alarm.defined_price / 100}}€
</td> </td>
<td> <td>
<img class="delete" src="../assets/images/pencil.png"> <img class="delete" src="../assets/images/pencil.png">
</td> </td>
<td> <td>
<img class="delete" src="../assets/images/Delete_icon-icons.com_55931.png" (click)="delete(alarm.alarm_id)"> <img class="delete" src="../assets/images/Delete_icon-icons.com_55931.png"
(click)="delete(alarm.alarm_id)">
</td> </td>
</tr> </tr>
</table> </table>

View File

@ -0,0 +1,47 @@
import {ComponentFixture, TestBed} from '@angular/core/testing';
import {ProfileComponent} from './profile.component';
import {AbstractMockObservableService} from '../../mocks/mock.service';
import {ApiService} from '../../services/api.service';
class MockApiService extends AbstractMockObservableService {
getUserInfo(): any {
this.content = [];
return this;
}
getPriceAlarms(): any {
this.content = [];
return this;
}
getProductsByIds(): any {
this.content = [];
return this;
}
}
describe('ProfileComponent', () => {
let component: ProfileComponent;
let fixture: ComponentFixture<ProfileComponent>;
let mockService;
beforeEach(async () => {
mockService = new MockApiService();
await TestBed.configureTestingModule({
declarations: [ProfileComponent],
providers: [{provide: ApiService, useValue: mockService}]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(ProfileComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -1,7 +1,7 @@
import {TestBed} from '@angular/core/testing'; import {TestBed} from '@angular/core/testing';
import {ApiService} from './api.service'; import {ApiService} from './api.service';
import {HttpClientModule} from "@angular/common/http"; import {HttpClientModule} from '@angular/common/http';
describe('ApiService', () => { describe('ApiService', () => {
let service: ApiService; let service: ApiService;

View File

@ -106,7 +106,7 @@ export class ApiService {
let asin = ''; let asin = '';
// Check if the parameter is a link or an asin // Check if the parameter is a link or an asin
const linkRegex: RegExp = /^http[s]{0,1}:\/\/.*\/dp\/(.[^\/]*)\/{0,1}.*$/; const linkRegex: RegExp = /^http[s]?:\/\/.*\/dp\/(.[^\/]*)\/?.*$/;
const matches = linkRegex.exec(asinOrLink); const matches = linkRegex.exec(asinOrLink);
if (matches) { if (matches) {
// param is a link, extract asin // param is a link, extract asin

View File

@ -1,12 +1,12 @@
import { enableProdMode } from '@angular/core'; import {enableProdMode} from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module'; import {AppModule} from './app/app.module';
import { environment } from './environments/environment'; import {environment} from './environments/environment';
if (environment.production) { if (environment.production) {
enableProdMode(); enableProdMode();
} }
platformBrowserDynamic().bootstrapModule(AppModule) platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err)); .catch(err => console.error(err));

File diff suppressed because it is too large Load Diff

View File

@ -1,23 +1,23 @@
// This file is required by karma.conf.js and loads recursively all the .spec and framework files // This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'zone.js/dist/zone-testing'; import 'zone.js/dist/zone-testing';
import { getTestBed } from '@angular/core/testing'; import {getTestBed} from '@angular/core/testing';
import { import {
BrowserDynamicTestingModule, BrowserDynamicTestingModule,
platformBrowserDynamicTesting platformBrowserDynamicTesting
} from '@angular/platform-browser-dynamic/testing'; } from '@angular/platform-browser-dynamic/testing';
declare const require: { declare const require: {
context(path: string, deep?: boolean, filter?: RegExp): { context(path: string, deep?: boolean, filter?: RegExp): {
keys(): string[]; keys(): string[];
<T>(id: string): T; <T>(id: string): T;
}; };
}; };
// First, initialize the Angular testing environment. // First, initialize the Angular testing environment.
getTestBed().initTestEnvironment( getTestBed().initTestEnvironment(
BrowserDynamicTestingModule, BrowserDynamicTestingModule,
platformBrowserDynamicTesting() platformBrowserDynamicTesting()
); );
// Then we find all the tests. // Then we find all the tests.
const context = require.context('./', true, /\.spec\.ts$/); const context = require.context('./', true, /\.spec\.ts$/);

View File

@ -5,7 +5,7 @@ Wiki: https://github.com/Mueller-Patrick/Betterzon/wiki
# Code Quality # Code Quality
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/88e47ebf837b43af9d12147c22f77f7f)](https://www.codacy.com/gh/Mueller-Patrick/Betterzon/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=Mueller-Patrick/Betterzon&amp;utm_campaign=Badge_Grade) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/88e47ebf837b43af9d12147c22f77f7f)](https://www.codacy.com/gh/Mueller-Patrick/Betterzon/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=Mueller-Patrick/Betterzon&amp;utm_campaign=Badge_Grade)
[![Code Coverage](https://img.shields.io/badge/coverage-71%25-green)](https://ci.betterzon.xyz) [![Code Coverage](https://img.shields.io/badge/coverage-81%25-green)](https://ci.betterzon.xyz)
# Project Status # Project Status
[![Website Status](https://img.shields.io/website?label=www.betterzon.xyz&style=for-the-badge&url=https%3A%2F%2Fwww.betterzon.xyz)](https://www.betterzon.xyz) [![Website Status](https://img.shields.io/website?label=www.betterzon.xyz&style=for-the-badge&url=https%3A%2F%2Fwww.betterzon.xyz)](https://www.betterzon.xyz)