Compare commits

..

No commits in common. "45b5e0444219ea48bd677cc3a0854359ea4e1823" and "fe2c064e3003fbdf79c6dc1cdf02dae0c02353c2" have entirely different histories.

41 changed files with 2036 additions and 2449 deletions

View File

@ -25,8 +25,8 @@ crawlingstatusRouter.get('/', async (req: Request, res: Response) => {
try {
// Authenticate user
const user_ip = req.connection.remoteAddress ?? '';
const session_id = (req.query.session_id ?? '').toString();
const session_key = (req.query.session_key ?? '').toString();
const session_id = req.body.session_id;
const session_key = req.body.session_key;
const user = await UserService.checkSession(session_id, session_key, user_ip);
if (!user.is_admin) {

View File

@ -24,8 +24,8 @@ favoriteshopsRouter.get('/', async (req: Request, res: Response) => {
try {
// Authenticate user
const user_ip = req.connection.remoteAddress ?? '';
const session_id = (req.query.session_id ?? '').toString();
const session_key = (req.query.session_key ?? '').toString();
const session_id = req.params.session_id;
const session_key = req.params.session_key;
const user = await UserService.checkSession(session_id, session_key, user_ip);
const priceAlarms = await FavoriteShopsService.getFavoriteShops(user.user_id);
@ -76,8 +76,8 @@ favoriteshopsRouter.delete('/:id', async (req: Request, res: Response) => {
try {
// Authenticate user
const user_ip = req.connection.remoteAddress ?? '';
const session_id = (req.query.session_id ?? '').toString();
const session_key = (req.query.session_key ?? '').toString();
const session_id = req.params.session_id;
const session_key = req.params.session_key;
const user = await UserService.checkSession(session_id, session_key, user_ip);
// Get info for price alarm creation

View File

@ -24,8 +24,8 @@ pricealarmsRouter.get('/', async (req: Request, res: Response) => {
try {
// Authenticate user
const user_ip = req.connection.remoteAddress ?? '';
const session_id = (req.query.session_id ?? '').toString();
const session_key = (req.query.session_key ?? '').toString();
const session_id = req.params.session_id;
const session_key = req.params.session_key;
const user = await UserService.checkSession(session_id, session_key, user_ip);
const priceAlarms = await PriceAlarmsService.getPriceAlarms(user.user_id);
@ -106,29 +106,3 @@ pricealarmsRouter.put('/', async (req: Request, res: Response) => {
res.status(500).send(JSON.stringify({'message': 'Internal Server Error. Try again later.'}));
}
});
// DELETE pricealarms/:id
pricealarmsRouter.delete('/:id', async (req, res) => {
try {
// Authenticate user
const user_ip = req.connection.remoteAddress ?? '';
const session_id = (req.query.session_id ?? '').toString();
const session_key = (req.query.session_key ?? '').toString();
const user = await UserService.checkSession(session_id, session_key, user_ip);
const id: number = parseInt(req.params.id, 10);
const success = await PriceAlarmsService.deletePriceAlarm(id, user.user_id);
if (success) {
res.status(200).send(JSON.stringify({success: true}));
return;
} else {
res.status(500).send(JSON.stringify({success: false}));
return;
}
} catch (e) {
console.log('Error handling a request: ' + e.message);
res.status(500).send(JSON.stringify({'message': 'Internal Server Error. Try again later.'}));
}
});

View File

@ -92,24 +92,3 @@ export const updatePriceAlarm = async (alarm_id: number, user_id: number, define
}
}
};
/**
* Deletes the given price alarm
* @param alarm_id The id of the price alarm to update
* @param user_id The id of the user that wants to update the price alarm
*/
export const deletePriceAlarm = async (alarm_id: number, user_id: number): Promise<boolean> => {
let conn;
try {
conn = await pool.getConnection();
const res = await conn.query('DELETE FROM price_alarms WHERE alarm_id = ? AND user_id = ?', [alarm_id, user_id]);
return res.affectedRows === 1;
} catch (err) {
throw err;
} finally {
if (conn) {
conn.end();
}
}
};

View File

@ -282,11 +282,11 @@ export const getBestDeals = async (amount: number): Promise<Prices> => {
'price_in_cents': lowestPrice.price_in_cents,
'timestamp': lowestPrice.timestamp,
'amazonDifference': (amazonPrice.price_in_cents - lowestPrice.price_in_cents),
'amazonDifferencePercent': ((amazonPrice.price_in_cents / lowestPrice.price_in_cents) * 100),
'amazonDifferencePercent': ((1 - (lowestPrice.price_in_cents / amazonPrice.price_in_cents)) * 100),
};
// Push only deals were the amazon price is actually higher
if (deal.amazonDifferencePercent > 0 && deal.amazonDifference > 0) {
if (deal.amazonDifferencePercent > 0) {
deals.push(deal as Deal);
}
}

View File

@ -37,8 +37,8 @@ vendorsRouter.get('/managed', async (req: Request, res: Response) => {
try {
// Authenticate user
const user_ip = req.connection.remoteAddress ?? '';
const session_id = (req.query.session_id ?? '').toString();
const session_key = (req.query.session_key ?? '').toString();
const session_id = req.params.session_id;
const session_key = req.params.session_key;
const user = await UserService.checkSession(session_id, session_key, user_ip);
const vendors = await VendorService.getManagedShops(user.user_id);

View File

@ -8,16 +8,14 @@ import stepdefs.Preconditions;
@RunWith(Cucumber.class)
@CucumberOptions(
features = {"src/test/resource/searchProduct.feature",
"src/test/resource/priceAlarms.feature",
"src/test/resource/favoriteShopList.feature",
"src/test/resource/manageVendor.feature"}
features = {"src/test/resource/searchProduct.feature",
"src/test/resource/priceAlarms.feature"}
)
public class RunTest {
@BeforeClass
public static void setup() {
Preconditions.driver = new FirefoxDriver();
Preconditions.driver= new FirefoxDriver();
}
@AfterClass

View File

@ -1,27 +0,0 @@
package stepdefs;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
public class FavoriteShopList {
@Given("^the user has at least (\\d+) favorite shop$")
public void the_user_has_at_least_favorite_shop(int arg1) throws Exception {
}
@When("^the user clicks on favorite shops$")
public void the_user_clicks_on_favorite_shops() throws Exception {
}
@Then("^he should see his favorite shops list$")
public void he_Should_see_his_favorite_shops_list() throws Exception {
}
@When("^he clicks on delete a favorite shop entry$")
public void he_clicks_on_delete_a_favorite_shop_enty() throws Exception {
}
@Then("^the favorite shop entry should be deleted$")
public void the_favorite_shop_entry_should_be_deleted() throws Exception {
}
}

View File

@ -1,31 +0,0 @@
package stepdefs;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
public class ManageVendor {
@Given("^the user is logged in as vendor manager$")
public void the_user_is_logged_in_as_vendor_manager() throws Exception {
}
@When("^the user opens the shop managing page$")
public void the_user_opens_the_shop_managing_page() throws Exception {
}
@When("^the user clicks on deactivate a listing$")
public void the_user_clicks_on_deactivate_a_listing() throws Exception {
}
@Then("^the listing should be deactivated$")
public void the_listing_should_be_deactivated() throws Exception {
}
@When("^the user clicks on deactivate the shop$")
public void the_user_clicks_on_deactivate_the_shop() throws Exception {
}
@Then("^the shop and all related listings should be deactivated$")
public void the_shop_and_all_related_listings_should_be_deactivated() throws Exception {
}
}

View File

@ -16,7 +16,7 @@ public class SearchProduct {
//throw new PendingException();
Preconditions.driver.get("https://betterzon.xyz");
WebElement logo = (new WebDriverWait(Preconditions.driver, 10))
.until(ExpectedConditions.elementToBeClickable(By.cssSelector(".navbar-brand")));
.until(ExpectedConditions.elementToBeClickable(By.cssSelector(".logo")));
}
@When("^the user enters the search term \"([^\"]*)\" and clicks search$")
@ -25,7 +25,7 @@ public class SearchProduct {
searchField.sendKeys(searchTerm);
searchField.sendKeys(Keys.ENTER);
WebElement logo = (new WebDriverWait(Preconditions.driver, 10))
.until(ExpectedConditions.elementToBeClickable(By.cssSelector(".navbar-brand")));
.until(ExpectedConditions.elementToBeClickable(By.cssSelector(".logo")));
}
@Then("^the user should see the error page \"([^\"]*)\"$")

View File

@ -1,20 +0,0 @@
Feature: Favorite Shop List
Scenario: Access Favorite Shop List
Given the user is on the landing page
And the user is logged in
And the user has at least 1 favorite shop
When the user clicks on the profile icon
Then the profile details popup should open
When the user clicks on favorite shops
Then he should see his favorite shops list
Scenario: Remove Favorite Shop Entry
Given the user is on the landing page
And the user is logged in
And the user has at least 1 favorite shop
When the user clicks on the profile icon
Then the profile details popup should open
When the user clicks on favorite shops
And he clicks on delete a favorite shop entry
Then the favorite shop entry should be deleted

View File

@ -1,15 +0,0 @@
Feature: Manage Vendor Shop
Scenario: Deactivate Product Listing
Given the user is on the landing page
And the user is logged in as vendor manager
When the user opens the shop managing page
And the user clicks on deactivate a listing
Then the listing should be deactivated
Scenario: Deactivate Shop Completely
Given the user is on the landing page
And the user is logged in as vendor manager
When the user opens the shop managing page
And the user clicks on deactivate the shop
Then the shop and all related listings should be deactivated

View File

@ -10,8 +10,8 @@
</div>
<!-- About Section Content-->
<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 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 class="col-lg-4 ms-auto"><p class="lead">text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries</p></div>
<div class="col-lg-4 me-auto"><p class="lead">text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries</p></div>
</div>
</div>
</section>

View File

@ -6,7 +6,7 @@
<div class="col-md-8 col-xs-12 col-sm-12 login_form ">
<div class="container-fluid">
<div class="row">
<h2>Registration</h2>
<h2>Konto erstellen</h2>
</div>
<div class="row">
<form [formGroup]="form" class="form-group" (ngSubmit)="onSubmit()">
@ -22,17 +22,17 @@
</div>
<div class="row">
<!-- <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="Kennwort">
</div>
<!--
<div class="row">
<input type="password" name="password" id="password_repeated" class="form__input" placeholder="Kennwort bestätigen">
</div> -->
<div class="row">
<input type="submit" value="Sign up" class="btn_signin">
<input type="submit" value="Erstellen" class="btn_signin">
</div>
<div class="row">
<p>Have an account?<a href="/signin">Log In</a></p>
<a href="/signin">Sich anmelden</a>
</div>
</form>
</div>

View File

@ -6,7 +6,7 @@
<div class="col-md-8 col-xs-12 col-sm-12 login_form ">
<div class="container-fluid">
<div class="row">
<h2>Sign In</h2>
<h2>Anmelden</h2>
</div>
<div class="row">
<form [formGroup]="loginForm" class="form-group" (ngSubmit)="onSubmit()">
@ -18,12 +18,12 @@
<input type="password" formControlName="password" name="password" id="password" class="form__input" placeholder="Password">
</div>
<div class="row">
<input type="submit" value="Log in" class="btn_signin">
<input type="submit" value="Anmelden" class="btn_signin">
</div>
</form>
</div>
<div class="row">
<p>No account yet?<a href="/registration">sign up</a></p>
<a href="/registration">Konto erstellen</a>
</div>
</div>
</div>

View File

@ -5,22 +5,24 @@
<div class="col-lg-4 mb-5 mb-lg-0">
<h4 class="text-uppercase mb-4">Location</h4>
<p class="lead mb-0">
76133 Karlsruhe
70376 Stuttgart
<br />
</p>
</div>
<!-- Footer Social Icons-->
<div class="col-lg-4 mb-5 mb-lg-0">
<h4 class="text-uppercase mb-4">FOLLOW UNS</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://blog.betterzon.xyz/"><i class="fab fa-fw fa-dribbble"></i></a>
<h4 class="text-uppercase mb-4">FOLGE UNS</h4>
<a class="btn btn-outline-light btn-social mx-1" href="#!"><i class="fab fa-fw fa-github"></i></a>
<a class="btn btn-outline-light btn-social mx-1" href="#!"><i class="fab fa-fw fa-twitter"></i></a>
<a class="btn btn-outline-light btn-social mx-1" href="#!"><i class="fab fa-fw fa-linkedin-in"></i></a>
<a class="btn btn-outline-light btn-social mx-1" href="#!"><i class="fab fa-fw fa-dribbble"></i></a>
</div>
<!-- Footer About Text-->
<div class="col-lg-4">
<h4 class="text-uppercase mb-4">CONTACT US</h4>
<h4 class="text-uppercase mb-4">SOME INFO</h4>
<p class="lead mb-0">
betterzon-contact@mueller-patrick.tech
text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries
</p>
</div>
</div>

View File

@ -1,3 +1,3 @@
<div class="copyright py-4 text-center text-white">
<div class="container"><small>Copyright &copy; Betterzon 2021</small></div>
<div class="container"><small>Copyright &copy; Your Website 2021</small></div>
</div>

View File

@ -1,7 +1,7 @@
<section class="page-section portfolio" id="top-gesuchte">
<div class="container">
<!-- Portfolio Section Heading-->
<h2 class="page-section-heading text-center text-uppercase text-secondary mb-0">TOP-SEARCHES</h2>
<h2 class="page-section-heading text-center text-uppercase text-secondary mb-0">TOP-ANGEBOTE</h2>
<!-- Icon Divider-->
<div class="divider-custom">
<div class="divider-custom-line"></div>

View File

@ -81,14 +81,14 @@ export class HotDealsWidgetComponent implements OnInit {
}
getVendors(): void {
this.bestDealsProductIds.forEach(
productId => {
const currentDeal = this.productsPricesMap[productId].lowestPrice;
this.productsPricesMap.keys().forEach(
key => {
const currentDeal = this.productsPricesMap[key].lowestPrice;
this.apiService.getVendorById(currentDeal.vendor_id).subscribe(
vendor => {
this.productsPricesMap[productId].vendor = vendor;
});
});
this.productsPricesMap[key].vendor = vendor
})
})
}

View File

@ -1,7 +1,7 @@
<section class="page-section portfolio" id="unsere-kunden">
<div class="container">
<!-- Portfolio Section Heading-->
<h2 class="page-section-heading text-center text-uppercase text-secondary mb-0">THEY TRUST US</h2>
<h2 class="page-section-heading text-center text-uppercase text-secondary mb-0">SIE VERTRAUEN UNS</h2>
<!-- Icon Divider-->
<div class="divider-custom">
<div class="divider-custom-line"></div>

View File

@ -1,6 +1,3 @@
<header class="masthead bg-transparent text-white text-center" id="w1">
</header>
<div class="productItem">
<div class="productImageContainer">
<img class="productImage" src="https://www.mueller-patrick.tech/betterzon/images/{{product.image_guid}}.jpg"/>
@ -23,12 +20,8 @@
{{product?.short_description}}
</div>
</div>
<div class="priceAlarm" *ngIf="!isLoggedIn" routerLink="/signin">
Login to set a price alarm
</div>
<div class="priceAlarm" *ngIf="isLoggedIn">
<input type="search" id="s" name="price" [(ngModel)]="price">
<div (click)="setPriceAlarm()">Set Price Alarm</div>
<div class="priceAlarm" (click)="setPriceAlarm()">
Set Price Alarm
</div>
<div class="bestPriceContainer">
<div class="bestPrice">

View File

@ -34,8 +34,6 @@ export class ProductDetailsComponent implements OnInit {
vendorMap = {};
@ViewChild('chart') chart: ChartComponent;
public chartOptions: ChartOptions;
isLoggedIn: boolean;
price: any;
constructor(
private apiService: ApiService
@ -46,9 +44,6 @@ export class ProductDetailsComponent implements OnInit {
this.getProduct();
this.getVendors();
this.getPrices();
if (this.apiService.getSessionInfoFromLocalStorage().session_id != "") {
this.isLoggedIn = true;
}
}
getProduct(): void {
@ -124,10 +119,8 @@ export class ProductDetailsComponent implements OnInit {
}
setPriceAlarm() {
this.apiService.createPriceAlarms(this.productId, this.price*100).subscribe(
this.apiService.createPriceAlarms(this.productId, 9).subscribe(
alarms => console.log(alarms)
)
}
}

View File

@ -1,30 +1,6 @@
<div *ngIf="products.length==0">
No Products found!
</div>
<div class="container mt-5 mb-5">
<div class="d-flex justify-content-center row">
<div class="col-md-10">
<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-6 mt-1">
<h5>{{product.name}}</h5>
<div class="d-flex flex-row">
<p class="text-justify text-truncate para mb-0">{{product.short_description}}</p>
</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 class="dot"></span><span><br></span></div>
</div>
<div class="align-items-center align-content-center col-md-3 border-left mt-1">
<div class="d-flex flex-row align-items-center">
<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>
</div>
</div>
<!--
<div class="productItem" *ngFor="let product of products" (click)="clickedProduct(product)">
<div class="productImageContainer" *ngIf="showProductPicture===true">
<img class="productImage" src="https://www.mueller-patrick.tech/betterzon/images/{{product.image_guid}}.jpg"/>
@ -44,4 +20,3 @@
</div>
</div>
</div>
-->

View File

@ -10,7 +10,6 @@ import {ActivatedRoute, Router} from '@angular/router';
})
export class ProductListComponent implements OnInit {
products: Product[] = [];
pricesMap: any = {};
@Input() numberOfProducts: number;
@Input() showProductPicture: boolean;
@Input() searchQuery: string;
@ -54,35 +53,15 @@ export class ProductListComponent implements OnInit {
}
getProducts(): void {
this.apiService.getProducts().subscribe(products => {
this.products = products;
this.getPrices();
});
this.apiService.getProducts().subscribe(products => this.products = products);
}
getPrices(): void {
this.products.forEach(
product => {
this.apiService.getLowestPrices(product.product_id).subscribe(
prices => {
this.pricesMap[product.product_id] = prices[prices.length - 1];
}
);
}
);
}
getSearchedProducts(): void {
this.apiService.getProductsByQuery(this.searchQuery).subscribe(products => {
this.products = products;
this.getPrices();
});
this.apiService.getProductsByQuery(this.searchQuery).subscribe(products => this.products = products);
}
clickedProduct(product: Product): void {
this.router.navigate([('/product/' + product.product_id)]);
}
}

View File

@ -1,21 +0,0 @@
.inf-content{
border:1px solid #DDDDDD;
-webkit-border-radius:10px;
-moz-border-radius:10px;
border-radius:10px;
box-shadow: 7px 7px 7px rgba(0, 0, 0, 0.3);
}
.header-in-page {
padding-top: calc(1rem + 20px);
padding-bottom: 1rem;
}
table, th, td {
border: 1px solid black;
}
.delete:hover {
cursor: pointer;
color: #0d5a4b;
}

View File

@ -1,104 +1,3 @@
<div class="container bootstrap snippets bootdey">
<div class="panel-body inf-content">
<div class="row">
<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">
<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>
<li><a href="#"><span class="glyphicon glyphicon-star"></span></a></li>
</ul>
</div>
<div class="col-md-6">
<strong>Information</strong><br>
<div class="table-responsive">
<table class="table table-user-information">
<tbody>
<tr>
<td>
<strong>
<span class="glyphicon glyphicon-bookmark text-primary"></span>
Username
</strong>
</td>
<td class="text-primary">
{{currentUser.username}}
</td>
</tr>
<tr>
<td>
<strong>
<span class="glyphicon glyphicon-eye-open text-primary"></span>
Role
</strong>
</td>
<td class="text-primary">
User
</td>
</tr>
<tr>
<td>
<strong>
<span class="glyphicon glyphicon-envelope text-primary"></span>
Email
</strong>
</td>
<td class="text-primary">
{{currentUser.email}}
</td>
</tr>
<tr>
<td>
<strong>
<span class="glyphicon glyphicon-calendar text-primary"></span>
created
</strong>
</td>
<td class="text-primary">
{{currentUser.registration_date}}
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<header class="header-in-page">
</header>
<div class="container bootstrap snippets bootdey">
<div class="col-auto">
<table class="table table-hover">
<tr>
<th>Product</th>
<th>Price</th>
<th>Change</th>
<th>Delete</th>
</tr>
<tr *ngFor="let alarm of alarms">
<td>
{{productsMap[alarm.product_id]?.name}}
</td>
<td>
{{alarm.defined_price/100}}
</td>
<td>
<img class="delete" src="../assets/images/Delete_icon-icons.com_55931.png" (click)="delete(alarm.alarm_id)">
</td>
<td>
<img class="delete" src="../assets/images/Delete_icon-icons.com_55931.png" (click)="delete(alarm.alarm_id)">
</td>
</tr>
</table>
</div>
</div>
<!--
<div class="container" *ngIf="currentUser; else loggedOut">
<p>
<strong>e-mail</strong>
@ -134,4 +33,4 @@
<ng-template #loggedOut>
Please login.
</ng-template>
-->

View File

@ -49,10 +49,4 @@ export class ProfileComponent implements OnInit {
}
)
}
delete(id:number): void {
this.api.deletePriceAlarm(id).subscribe(
res => window.location.reload()
)
}
}

View File

@ -10,13 +10,13 @@
</button>
<div class="collapse navbar-collapse" id="navbarResponsive">
<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-searches</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>
<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" *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>
<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-Gesuchte</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">über uns</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">Unsere Kunden</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">Anmelden</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">Konto Erstellen</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>
</div>
</div>

View File

@ -4,9 +4,9 @@ import {Router} from "@angular/router";
@Component({
selector: 'app-top-bar',
templateUrl: './top-bar.component.html',
styleUrls: ['./top-bar.component.css']
selector: 'app-top-bar',
templateUrl: './top-bar.component.html',
styleUrls: ['./top-bar.component.css']
})
export class TopBarComponent implements OnInit {

View File

@ -0,0 +1,50 @@
#mainComponents {
margin: 5em;
margin-top: .5em;
margin-bottom: .5em;
}
#productListsContainer {
display: grid;
grid-template-areas:
'search search'
'popularSearches bestDeals';
grid-template-columns: 50% 50%;
}
#searchContainer {
position: relative;
grid-area: search;
height: 10em;
}
#searchContainer input {
position: relative;
font-size: 1.5em;
padding: .25em;
display: block;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
margin: auto;
-ms-transform: translateY(50%);
transform: translateY(2.5em);
}
#popularSearchesList {
grid-area: popularSearches;
padding: .5em;
}
#popularSearchesList h2 {
text-align: center;
}
#bestDealsList {
grid-area: bestDeals;
padding: .5em;
}
#bestDealsList h2 {
text-align: center;
}

View File

@ -1,43 +1,5 @@
body {
background: #eee
#mainComponents {
margin: 5em;
margin-top: .5em;
margin-bottom: .5em;
}
.ratings i {
font-size: 16px;
color: red
}
.strike-text {
color: red;
text-decoration: line-through
}
.product-image {
width: 20%;
height: 20%;
}
.dot {
height: 7px;
width: 7px;
margin-left: 6px;
margin-right: 6px;
margin-top: 3px;
background-color: blue;
border-radius: 50%;
display: inline-block
}
.spec-1 {
color: #938787;
font-size: 15px
}
h5 {
font-weight: 400
}
.para {
font-size: 16px
}

View File

@ -1,14 +1,7 @@
<app-top-bar></app-top-bar>
<header class="masthead bg-transparent text-white text-center" id="w1">
</header>
<div id="mainComponents">
<app-product-list numberOfProducts="20" [showProductPicture]="true" searchQuery="{{searchTerm}}"
type="search"></app-product-list>
</div>
<header class="masthead bg-transparent text-white text-center">
</header>
<app-bottom-bar></app-bottom-bar>

View File

@ -1,4 +0,0 @@
.header-in-page {
padding-top: calc(2rem + 20px);
padding-bottom: 6rem;
}

View File

@ -1,10 +1,3 @@
<app-top-bar></app-top-bar>
<header class="header-in-page">
</header>
<app-profile></app-profile>
<header class="header-in-page">
</header>
<app-bottom-bar></app-bottom-bar>
<app-copyright></app-copyright>

View File

@ -445,25 +445,6 @@ export class ApiService {
}
}
/**
* Deletes the given price alarm
* @param alarmId the price alarm to delete
* @return Observable<any> The observable response of the api
*/
deletePriceAlarm(alarmId: number): Observable<any> {
try {
const sessionInfo = this.getSessionInfoFromLocalStorage();
let params = new HttpParams();
params = params.append('session_id', sessionInfo.session_id);
params = params.append('session_key', sessionInfo.session_key);
return this.http.delete((this.apiUrl + '/pricealarms/' + alarmId), {params});
} catch (exception) {
process.stderr.write(`ERROR received from ${this.apiUrl}: ${exception}\n`);
}
}
/* __ __
/ / / /_______ __________

Binary file not shown.

Before

Width:  |  Height:  |  Size: 239 B

View File

@ -447,8 +447,8 @@ progress {
}
.lead {
font-size: 1.30rem;
font-weight: 400;
font-size: 1.25rem;
font-weight: 300;
}
.display-1 {

View File

@ -5,7 +5,7 @@ Wiki: https://github.com/Mueller-Patrick/Betterzon/wiki
# 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)
[![Code Coverage](https://img.shields.io/badge/coverage-71%25-green)](https://ci.betterzon.xyz)
[![Code Coverage](https://img.shields.io/badge/coverage-82%25-green)](https://ci.betterzon.xyz)
# 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)

View File

@ -1 +1 @@
<mxfile host="Electron" modified="2021-06-15T10:10:23.336Z" agent="5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/13.4.5 Chrome/83.0.4103.122 Electron/9.1.0 Safari/537.36" etag="xPXaWnl_FRrq1LtBykUU" version="13.4.5" type="device"><diagram id="QFWcWedTnleHV76omDGD" name="Page-1">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</diagram></mxfile>
<mxfile host="app.diagrams.net" modified="2020-12-03T09:39:52.243Z" agent="5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36" etag="RUzsjnuqX_zRTCHSTruo" version="13.10.6" type="github"><diagram id="QFWcWedTnleHV76omDGD" name="Page-1">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</diagram></mxfile>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 85 KiB

After

Width:  |  Height:  |  Size: 87 KiB

File diff suppressed because it is too large Load Diff