Merge pull request 'feature/search' (#19) from feature/search into master
Reviewed-by: Jannik Seiler <seil0@mosad.xyz>
This commit is contained in:
		
							
								
								
									
										0
									
								
								prototype/gradlew
									
									
									
									
										vendored
									
									
										
										
										Executable file → Normal file
									
								
							
							
						
						
									
										0
									
								
								prototype/gradlew
									
									
									
									
										vendored
									
									
										
										
										Executable file → Normal file
									
								
							@ -85,11 +85,6 @@ public class RequestController {
 | 
			
		||||
        return "redirect:/";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/shop/search")
 | 
			
		||||
    public String shopSearch() {
 | 
			
		||||
        return "shop/search";
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    @GetMapping("/intern/")
 | 
			
		||||
    public String intern() {
 | 
			
		||||
        return "intern/index";
 | 
			
		||||
 | 
			
		||||
@ -5,6 +5,7 @@ import org.hso.ecommerce.action.shop.GetRandomArticlesAction;
 | 
			
		||||
import org.hso.ecommerce.entities.shop.Article;
 | 
			
		||||
import org.hso.ecommerce.entities.shop.ShoppingCart;
 | 
			
		||||
import org.hso.ecommerce.repos.shop.ArticleRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.shop.CategoryRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.warehouse.WarehouseBookingPositionSlotEntryRepository;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.http.MediaType;
 | 
			
		||||
@ -30,12 +31,17 @@ public class ShopArticleController {
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private final WarehouseBookingPositionSlotEntryRepository warehouseBookingPositionSlotEntryRepository = null;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private final CategoryRepository categoryRepository = null;
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/{id}")
 | 
			
		||||
    public String shopArticlesById(Model model,
 | 
			
		||||
                                   @PathVariable("id") Long id,
 | 
			
		||||
                                   HttpServletRequest request,
 | 
			
		||||
                                   HttpServletResponse response
 | 
			
		||||
    ) {
 | 
			
		||||
        model.addAttribute("categories", categoryRepository.getCategories());   //for sidebar
 | 
			
		||||
 | 
			
		||||
        Article article = articleRepository.findArticleById(id);
 | 
			
		||||
 | 
			
		||||
        if (article == null) {
 | 
			
		||||
@ -45,13 +51,13 @@ public class ShopArticleController {
 | 
			
		||||
        }
 | 
			
		||||
        model.addAttribute("article", article);
 | 
			
		||||
 | 
			
		||||
        if (warehouseBookingPositionSlotEntryRepository.getByArticle(id).get(0).newSumSlot > 0) {
 | 
			
		||||
        if (warehouseBookingPositionSlotEntryRepository.getByArticle(id).get(0).newSumSlot > 0) {   //check if in Stock
 | 
			
		||||
            model.addAttribute("inStock", true);
 | 
			
		||||
        } else {
 | 
			
		||||
            model.addAttribute("inStock", false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        List<Article> commercialArticles = GetRandomArticlesAction.getRandomArticles(3, articleRepository.getAdvertisedArticles());
 | 
			
		||||
        List<Article> commercialArticles = GetRandomArticlesAction.getRandomArticles(3, articleRepository.getAdvertisedArticles()); //get 3 advertised Articles
 | 
			
		||||
        model.addAttribute("commercialArticles", commercialArticles);
 | 
			
		||||
 | 
			
		||||
        return "shop/articles/id";
 | 
			
		||||
@ -98,5 +104,4 @@ public class ShopArticleController {
 | 
			
		||||
        response.setContentType(MediaType.IMAGE_JPEG_VALUE);
 | 
			
		||||
        IOUtils.copy(in, response.getOutputStream());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -3,6 +3,7 @@ package org.hso.ecommerce.controller.shop;
 | 
			
		||||
import org.hso.ecommerce.action.shop.GetRandomArticlesAction;
 | 
			
		||||
import org.hso.ecommerce.entities.shop.Article;
 | 
			
		||||
import org.hso.ecommerce.repos.shop.ArticleRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.warehouse.WarehouseBookingPositionSlotEntryRepository;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.stereotype.Controller;
 | 
			
		||||
import org.springframework.ui.Model;
 | 
			
		||||
@ -19,6 +20,9 @@ public class ShopIndexController {
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private final ArticleRepository articleRepository = null;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private final WarehouseBookingPositionSlotEntryRepository warehouseBookingPositionSlotEntryRepository = null;
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/")
 | 
			
		||||
    public String home() {
 | 
			
		||||
        return "redirect:/shop/";
 | 
			
		||||
@ -27,18 +31,18 @@ public class ShopIndexController {
 | 
			
		||||
    @GetMapping("/shop/")
 | 
			
		||||
    public String shop(Model model, HttpSession session) {
 | 
			
		||||
 | 
			
		||||
        List<Article> commercialArticles = GetRandomArticlesAction.getRandomArticles(8, articleRepository.getAdvertisedArticles());
 | 
			
		||||
        List<Article> commercialArticles = GetRandomArticlesAction.getRandomArticles(8, articleRepository.getAdvertisedArticles()); //get random advertised Articles
 | 
			
		||||
        model.addAttribute("commercialArticles", commercialArticles);
 | 
			
		||||
 | 
			
		||||
        boolean isLoggedIn = false;
 | 
			
		||||
        boolean hasOrders = false;
 | 
			
		||||
 | 
			
		||||
        if (session != null && session.getAttribute("userId") != null) {
 | 
			
		||||
        if (session != null && session.getAttribute("userId") != null) {    //check if logged in
 | 
			
		||||
            long userId = (long) session.getAttribute("userId");
 | 
			
		||||
            isLoggedIn = true;
 | 
			
		||||
 | 
			
		||||
            List<Article> suggestedArticles = articleRepository.getOrderedArticles(userId);
 | 
			
		||||
            suggestedArticles = suggestedArticles.size() > 3 ? suggestedArticles.subList(0, 4) : suggestedArticles; //only latest 4 articles
 | 
			
		||||
            suggestedArticles = suggestedArticles.size() > 3 ? suggestedArticles.subList(0, 4) : suggestedArticles; //only latest 4 ordered articles
 | 
			
		||||
            if (suggestedArticles.size() > 0) {
 | 
			
		||||
                model.addAttribute("suggestedArticles", suggestedArticles);
 | 
			
		||||
                hasOrders = true;
 | 
			
		||||
@ -65,5 +69,4 @@ public class ShopIndexController {
 | 
			
		||||
    public String privacy() {
 | 
			
		||||
        return "privacy";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,48 @@
 | 
			
		||||
package org.hso.ecommerce.controller.shop;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.entities.shop.Article;
 | 
			
		||||
import org.hso.ecommerce.repos.shop.ArticleRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.shop.CategoryRepository;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.stereotype.Controller;
 | 
			
		||||
import org.springframework.ui.Model;
 | 
			
		||||
import org.springframework.web.bind.annotation.*;
 | 
			
		||||
 | 
			
		||||
import javax.servlet.http.HttpServletRequest;
 | 
			
		||||
import javax.servlet.http.HttpServletResponse;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
@Controller
 | 
			
		||||
//@RequestMapping("...")
 | 
			
		||||
@RequestMapping("/shop/search")
 | 
			
		||||
public class ShopSearchController {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private final ArticleRepository articleRepository = null;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private final CategoryRepository categoryRepository = null;
 | 
			
		||||
 | 
			
		||||
    @GetMapping("")
 | 
			
		||||
    public String searchArticles(@RequestParam(required = false, value = "term") String term,
 | 
			
		||||
                                 @RequestParam(required = false, value = "category") String category,
 | 
			
		||||
                                 Model model,
 | 
			
		||||
                                 HttpServletRequest request,
 | 
			
		||||
                                 HttpServletResponse response
 | 
			
		||||
    ) {
 | 
			
		||||
        model.addAttribute("categories", categoryRepository.getCategories());   //for sidebar
 | 
			
		||||
 | 
			
		||||
        if (term != null) { //if search by Term
 | 
			
		||||
            List<Article> articles = articleRepository.getArticlesByTerm(term); //search by Term
 | 
			
		||||
            model.addAttribute("articles", articles);
 | 
			
		||||
        } else if (category != null) {  //if search by Category
 | 
			
		||||
            List<Article> articles = articleRepository.getArticlesByCategory(category); //search by Category
 | 
			
		||||
            model.addAttribute("articles", articles);
 | 
			
		||||
        } else {
 | 
			
		||||
            request.setAttribute("error", "Es wurden keine Suchparameter angegeben.");
 | 
			
		||||
            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
 | 
			
		||||
            return "error/404";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return "/shop/search";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -17,7 +17,7 @@ public interface ArticleRepository extends JpaRepository<Article, Long> {
 | 
			
		||||
	@Query("SELECT a FROM Article a")
 | 
			
		||||
	List<Article> findAll();
 | 
			
		||||
 | 
			
		||||
    @Query("SELECT a FROM Article a JOIN a.related ao WHERE ao.shouldBeAdvertised = true")
 | 
			
		||||
    @Query(value = "Select a.* from articles as a, article_offers as ao, warehouse_booking_position_entries as wbpe where a.related_id = ao.id and wbpe.article_id = a.id and ao.should_be_advertised = true group by wbpe.slot_id having max(wbpe.id) and wbpe.new_sum_slot != 0", nativeQuery = true)
 | 
			
		||||
    List<Article> getAdvertisedArticles();
 | 
			
		||||
 | 
			
		||||
	@Query("SELECT a FROM CustomerOrderPosition cop JOIN cop.order co JOIN co.customer c JOIN cop.article a ORDER BY co.id DESC")
 | 
			
		||||
@ -26,5 +26,9 @@ public interface ArticleRepository extends JpaRepository<Article, Long> {
 | 
			
		||||
    @Query("SELECT a FROM CustomerOrderPosition cop JOIN cop.order co JOIN co.customer c JOIN cop.article a WHERE c.id = :customerId ORDER BY co.id DESC")
 | 
			
		||||
    List<Article> getOrderedArticles(long customerId);
 | 
			
		||||
 | 
			
		||||
    @Query(value = "Select a.* from articles as a, warehouse_booking_position_entries as wbpe where wbpe.article_id = a.id and a.title LIKE %:term% group by wbpe.slot_id having max(wbpe.id) and wbpe.new_sum_slot != 0", nativeQuery = true)
 | 
			
		||||
    List<Article> getArticlesByTerm(String term);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
    @Query(value = "Select a.* from articles as a, categories as c, article_categories_bindings as acb, warehouse_booking_position_entries as wbpe where wbpe.article_id = a.id and acb.articles_id = a.id and acb.categories_id = c.id and c.name = :category group by wbpe.slot_id having max(wbpe.id) and wbpe.new_sum_slot != 0", nativeQuery = true)
 | 
			
		||||
    List<Article> getArticlesByCategory(String category);
 | 
			
		||||
}
 | 
			
		||||
@ -6,6 +6,7 @@ import org.springframework.data.jpa.repository.Query;
 | 
			
		||||
import org.springframework.data.repository.query.Param;
 | 
			
		||||
import org.springframework.stereotype.Repository;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
 | 
			
		||||
@Repository
 | 
			
		||||
@ -14,4 +15,6 @@ public interface CategoryRepository extends JpaRepository<Category, Long> {
 | 
			
		||||
	@Query("SELECT a FROM Category a WHERE a.name = :name")
 | 
			
		||||
	Optional<Category> findCategoryByName(@Param("name") String name);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
    @Query("SELECT c FROM Category c")
 | 
			
		||||
    List<Category> getCategories();
 | 
			
		||||
}
 | 
			
		||||
@ -11,7 +11,7 @@
 | 
			
		||||
    <div class='content-width bar-flex'>
 | 
			
		||||
        <a class="button no-padding" href="/"><img class="logo" th:src="@{/img/ecom-logo-base.svg}"></a>
 | 
			
		||||
        <form class='spacer input-icon secondary' th:action="@{/shop/search}" method="GET">
 | 
			
		||||
            <input type="text" placeholder="Nach Produkten suchen..."/>
 | 
			
		||||
            <input type="text" name="term" placeholder="Nach Produkten suchen..."/>
 | 
			
		||||
            <button>Finden</button>
 | 
			
		||||
        </form>
 | 
			
		||||
        <a th:unless="${user}" class="button" th:href="@{/login}">Login</a>
 | 
			
		||||
@ -38,7 +38,6 @@
 | 
			
		||||
                  function toggle(id) {
 | 
			
		||||
                     document.getElementById(id).classList.toggle("invisible");
 | 
			
		||||
                  }
 | 
			
		||||
 | 
			
		||||
                </script>
 | 
			
		||||
                <a class="secondary button error" href="javascript:void(0)" onclick="toggle('error-msg');">X</a>
 | 
			
		||||
            </div>
 | 
			
		||||
@ -54,7 +53,6 @@
 | 
			
		||||
                  function toggle(id) {
 | 
			
		||||
                     document.getElementById(id).classList.toggle("invisible");
 | 
			
		||||
                  }
 | 
			
		||||
 | 
			
		||||
                </script>
 | 
			
		||||
                <a class="secondary button info" href="javascript:void(0)" onclick="toggle('info-msg');">X</a>
 | 
			
		||||
            </div>
 | 
			
		||||
@ -62,5 +60,4 @@
 | 
			
		||||
    </div>
 | 
			
		||||
</nav>
 | 
			
		||||
</body>
 | 
			
		||||
 | 
			
		||||
</html>
 | 
			
		||||
 | 
			
		||||
@ -7,15 +7,10 @@
 | 
			
		||||
</head>
 | 
			
		||||
 | 
			
		||||
<body>
 | 
			
		||||
<nav th:fragment="sidebar">
 | 
			
		||||
<nav th:fragment="sidebar (categories)">
 | 
			
		||||
    <h1>Kategorien</h1>
 | 
			
		||||
    <ul class="secondary">
 | 
			
		||||
        <li><a href="/shop/search">Aufnahmegeräte</a></li>
 | 
			
		||||
        <li><a href="/shop/search">Computer</a></li>
 | 
			
		||||
        <li><a href="/shop/search">Fernseher</a></li>
 | 
			
		||||
        <li><a href="/shop/search">Handys</a></li>
 | 
			
		||||
        <li><a href="/shop/search">Unterhaltungselektronik</a></li>
 | 
			
		||||
        <li><a href="/shop/search">Sonstiges</a></li>
 | 
			
		||||
        <li th:each="category: ${categories}"><a th:href="@{/shop/search(category=${category.name})}" th:text="${category.name}"></a></li>
 | 
			
		||||
    </ul>
 | 
			
		||||
</nav>
 | 
			
		||||
</body>
 | 
			
		||||
 | 
			
		||||
@ -14,7 +14,7 @@
 | 
			
		||||
<nav th:replace="fragments/header :: header">Header</nav>
 | 
			
		||||
<main class=" content-width">
 | 
			
		||||
    <div class="sidebar-layout" style="min-height: 75vh;">
 | 
			
		||||
        <nav th:replace="fragments/shop :: sidebar"></nav>
 | 
			
		||||
        <nav th:replace="fragments/shop :: sidebar(categories=${categories})"></nav>
 | 
			
		||||
        <div class="content-width">
 | 
			
		||||
            <div class="detailgrid">
 | 
			
		||||
                <div class="s">
 | 
			
		||||
@ -23,7 +23,9 @@
 | 
			
		||||
                    <script th:src="@{/js/back.js}"></script>
 | 
			
		||||
                    <div class="back" data-group="shop" data-insert="true"></div>
 | 
			
		||||
 | 
			
		||||
                    <h2><span th:text="${#numbers.formatDecimal(article.getPriceGross() * 0.01, 1, 'POINT', 2, 'COMMA')}"></span><span> EUR</span></h2>
 | 
			
		||||
                    <h2><span
 | 
			
		||||
                            th:text="${#numbers.formatDecimal(article.getPriceGross() * 0.01, 1, 'POINT', 2, 'COMMA')}"></span><span> EUR</span>
 | 
			
		||||
                    </h2>
 | 
			
		||||
                    <p th:text="${article.description}"></p>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="s">
 | 
			
		||||
@ -32,7 +34,9 @@
 | 
			
		||||
                <div class="s"></div>
 | 
			
		||||
                <form class="s" method="POST">
 | 
			
		||||
                    <div class="detailgrid m">
 | 
			
		||||
                        <h2><span th:text="${#numbers.formatDecimal(article.getPriceGross() * 0.01, 1, 'POINT', 2, 'COMMA')}"></span><span> EUR</span></h2>
 | 
			
		||||
                        <h2><span
 | 
			
		||||
                                th:text="${#numbers.formatDecimal(article.getPriceGross() * 0.01, 1, 'POINT', 2, 'COMMA')}"></span><span> EUR</span>
 | 
			
		||||
                        </h2>
 | 
			
		||||
                        <div>
 | 
			
		||||
                            <label class="nolinebreak">Menge:</label>
 | 
			
		||||
                            <select name="quantity" size="1">
 | 
			
		||||
@ -55,10 +59,13 @@
 | 
			
		||||
        <div>
 | 
			
		||||
            <h1>Weitere Schnäppchen</h1>
 | 
			
		||||
            <div class='grid m base shadow'>
 | 
			
		||||
                <section th:each="article: ${commercialArticles}"><a th:href="@{/shop/articles/{id}(id = ${article.id})}" class="section">
 | 
			
		||||
                <section th:each="article: ${commercialArticles}"><a
 | 
			
		||||
                        th:href="@{/shop/articles/{id}(id = ${article.id})}" class="section">
 | 
			
		||||
                    <img th:src="@{/shop/articles/{id}/image.jpg(id=${article.id})}"/>
 | 
			
		||||
                    <h2 th:text="${article.title}"></h2>
 | 
			
		||||
                    <p class='price'><span th:text="${#numbers.formatDecimal(article.getPriceGross() * 0.01, 1, 'POINT', 2, 'COMMA')}"></span><span> EUR</span></p>
 | 
			
		||||
                    <p class='price'><span
 | 
			
		||||
                            th:text="${#numbers.formatDecimal(article.getPriceGross() * 0.01, 1, 'POINT', 2, 'COMMA')}"></span><span> EUR</span>
 | 
			
		||||
                    </p>
 | 
			
		||||
                    <p th:text="${article.description}"></p>
 | 
			
		||||
                </a>
 | 
			
		||||
                </section>
 | 
			
		||||
 | 
			
		||||
@ -25,9 +25,11 @@
 | 
			
		||||
                    <a th:href="@{/shop/articles/{id}(id=${article.id})}" class="section">
 | 
			
		||||
 | 
			
		||||
                        <img th:src="@{/shop/articles/{id}/image.jpg(id=${article.id})}"/>
 | 
			
		||||
                        <h2 th:text="${article.title}" />
 | 
			
		||||
                        <p class='price'><span th:text="${#numbers.formatDecimal(article.getPriceGross() * 0.01, 1, 'POINT', 2, 'COMMA')}"></span><span> EUR</span></p>
 | 
			
		||||
                        <p th:text="${article.description}" />
 | 
			
		||||
                        <h2 th:text="${article.title}"/>
 | 
			
		||||
                        <p class='price'><span
 | 
			
		||||
                                th:text="${#numbers.formatDecimal(article.getPriceGross() * 0.01, 1, 'POINT', 2, 'COMMA')}"></span><span> EUR</span>
 | 
			
		||||
                        </p>
 | 
			
		||||
                        <p th:text="${article.description}"/>
 | 
			
		||||
                    </a>
 | 
			
		||||
                </section>
 | 
			
		||||
                <section class="spacer"></section>
 | 
			
		||||
@ -57,7 +59,7 @@
 | 
			
		||||
 | 
			
		||||
            <!-- If User is logged in but hasn't ordered anything yet-->
 | 
			
		||||
            <div th:if="${isLoggedIn == true and hasOrders == false}">
 | 
			
		||||
                <h1>Jetzt Shoppen und Empfehlungen erhalten!</h1>
 | 
			
		||||
                <h2>Jetzt Shoppen und Empfehlungen erhalten!</h2>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <!-- If User is logged in and has ordered something before-->
 | 
			
		||||
@ -67,9 +69,11 @@
 | 
			
		||||
                        <a th:href="@{/shop/articles/{id}(id=${article.id})}" class="section">
 | 
			
		||||
 | 
			
		||||
                            <img th:src="@{/shop/articles/{id}/image.jpg(id=${article.id})}"/>
 | 
			
		||||
                            <h2 th:text="${article.title}" />
 | 
			
		||||
                            <p class='price'><span th:text="${#numbers.formatDecimal(article.getPriceGross() * 0.01, 1, 'POINT', 2, 'COMMA')}"></span><span> EUR</span></p>
 | 
			
		||||
                            <p th:text="${article.description}" />
 | 
			
		||||
                            <h2 th:text="${article.title}"/>
 | 
			
		||||
                            <p class='price'><span
 | 
			
		||||
                                    th:text="${#numbers.formatDecimal(article.getPriceGross() * 0.01, 1, 'POINT', 2, 'COMMA')}"></span><span> EUR</span>
 | 
			
		||||
                            </p>
 | 
			
		||||
                            <p th:text="${article.description}"/>
 | 
			
		||||
                        </a>
 | 
			
		||||
                    </section>
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
@ -21,70 +21,29 @@
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
<main class="sidebar-layout content-width">
 | 
			
		||||
    <nav th:replace="fragments/shop :: sidebar"></nav>
 | 
			
		||||
    <nav th:replace="fragments/shop :: sidebar(categories=${categories})"></nav>
 | 
			
		||||
    <div class="content-width">
 | 
			
		||||
        <div class='grid m condensed'>
 | 
			
		||||
            <section><a th:href="@{/shop/articles/1234}" class="section">
 | 
			
		||||
                <img th:src="@{/img/product-1.jpg}">
 | 
			
		||||
                <h2>Tolle Kamera</h2>
 | 
			
		||||
                <p class='price'> 25.14 EUR</p>
 | 
			
		||||
                <p>
 | 
			
		||||
                    Eine TOLLE Kamera <br>
 | 
			
		||||
                    Jaja du denkst jetzt bestimmt: "Bei dem Preis kann sie gar nich sooo TOLL sein". <br>
 | 
			
		||||
                    Aber glaub mir, sie is echt echt TOLL! <br>
 | 
			
		||||
                    Indianerehrenwort!
 | 
			
		||||
                </p>
 | 
			
		||||
            </a>
 | 
			
		||||
            </section>
 | 
			
		||||
        <div class='grid m condensed' th:if="${articles.size() != 0}">
 | 
			
		||||
            <section th:each="article: ${articles}">
 | 
			
		||||
                <a th:href="@{/shop/articles/{id}(id=${article.id})}" class="section">
 | 
			
		||||
 | 
			
		||||
            <section><a th:href="@{/shop/articles/1234}" class="section">
 | 
			
		||||
                <img th:src="@{/img/product-2.jpg}">
 | 
			
		||||
                <h2>Bluetooth Kopfhörer</h2>
 | 
			
		||||
                <p class='price'> 10.14 EUR</p>
 | 
			
		||||
                <p>
 | 
			
		||||
                    Sind halt Kopfhörer ohne Kabel, mehr gibts da nich zu sagen.
 | 
			
		||||
                </p>
 | 
			
		||||
            </a>
 | 
			
		||||
                    <img th:src="@{/shop/articles/{id}/image.jpg(id=${article.id})}"/>
 | 
			
		||||
                    <h2 th:text="${article.title}"/>
 | 
			
		||||
                    <p class='price'><span
 | 
			
		||||
                            th:text="${#numbers.formatDecimal(article.getPriceGross() * 0.01, 1, 'POINT', 2, 'COMMA')}"></span><span> EUR</span>
 | 
			
		||||
                    </p>
 | 
			
		||||
                    <p th:text="${article.description}"/>
 | 
			
		||||
                </a>
 | 
			
		||||
            </section>
 | 
			
		||||
 | 
			
		||||
            <section><a th:href="@{/shop/articles/1234}" class="section">
 | 
			
		||||
                <img th:src="@{/img/product-3.jpg}">
 | 
			
		||||
                <h2>???</h2>
 | 
			
		||||
                <p class='price'> 25.14 EUR</p>
 | 
			
		||||
                <p>
 | 
			
		||||
                    Ich weiß selbst nich was das genau sein soll.<br>
 | 
			
		||||
                    Wenn dus willst kannst es gern haben, musst nur das Geld überweisen.
 | 
			
		||||
                </p>
 | 
			
		||||
            </a>
 | 
			
		||||
            </section>
 | 
			
		||||
 | 
			
		||||
            <section><a th:href="@{/shop/articles/1234}" class="section">
 | 
			
		||||
                <img th:src="@{/img/product-4.jpg}">
 | 
			
		||||
                <h2>Kamera Stativ.</h2>
 | 
			
		||||
                <p class='price'> 25.14 EUR</p>
 | 
			
		||||
                <p>
 | 
			
		||||
                    Das Stativ der Zukunft! Jetzt kaufen und verwenden für
 | 
			
		||||
                    wackelfreie Bilder aus der Zukunft!.
 | 
			
		||||
                </p>
 | 
			
		||||
            </a>
 | 
			
		||||
            </section>
 | 
			
		||||
 | 
			
		||||
            <section><a th:href="@{/shop/articles/1234}" class="section">
 | 
			
		||||
                <img th:src="@{/img/product-5.jpg}">
 | 
			
		||||
                <h2>Bluetooth Ersatzfernbedinung</h2>
 | 
			
		||||
                <p class='price'> 10.14 EUR</p>
 | 
			
		||||
                <p>
 | 
			
		||||
                    Kann alles und jeden ausknippsen.
 | 
			
		||||
                </p>
 | 
			
		||||
            </a>
 | 
			
		||||
            </section>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            <section class="spacer"></section>
 | 
			
		||||
            <section class="spacer"></section>
 | 
			
		||||
            <section class="spacer"></section>
 | 
			
		||||
            <section class="spacer"></section>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div th:if="${articles.size() == 0}">
 | 
			
		||||
            <h2>Keine Ergebnisse für diesen Suchterm gefunden!</h2>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</main>
 | 
			
		||||
<footer th:replace="fragments/footer :: footer"></footer>
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user