Skip to content
Snippets Groups Projects
Commit 259c3b35 authored by Joshua Gill's avatar Joshua Gill
Browse files

Merge remote-tracking branch 'origin/issueThirtyNine' into issueThirtyNine

parents 759fbe3f 7fab4f28
No related branches found
No related tags found
2 merge requests!114LoggingService service class, new method to add a log to the "Logs" table when...,!107Issue complete
......@@ -23,6 +23,7 @@ repositories {
}
dependencies {
implementation 'com.google.code.gson:gson:2.8.9'
implementation 'commons-io:commons-io:2.8.0'
implementation 'io.jsonwebtoken:jjwt:0.9.1'
implementation 'org.springframework.session:spring-session-jdbc:2.4.3'
......
package com.example.clientproject.web.restControllers;
import com.example.clientproject.data.shops.Shops;
import com.example.clientproject.data.shops.ShopsRepo;
import com.example.clientproject.data.tags.Tags;
import com.example.clientproject.data.tags.TagsRepo;
import com.example.clientproject.services.RecommendationGenerator;
import com.google.gson.Gson;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpSession;
import java.util.*;
import java.util.stream.Collectors;
@RestController
public class ShopSearch {
@Autowired
ShopsRepo shopsRepo;
@Autowired
TagsRepo tagsRepo;
@Autowired
RecommendationGenerator recommendationGenerator;
@GetMapping("/shop/search")
public String searchShops(@RequestParam(value = "q", required = false) String query,
@RequestParam(value = "p", required = false) Integer page,
@RequestParam(value = "t", required = false) List<String> tags,
HttpSession session) throws Exception {
final Integer ITEMS_PER_PAGE = 6;
//Get all the active shops
List<Shops> allShops = shopsRepo.findActiveShops();
//Filter the shops using the query provided
if(query != null){
allShops = allShops
.stream()
.filter(s -> s.getShopName().toLowerCase(Locale.ROOT).strip().contains(query.toLowerCase(Locale.ROOT).strip()))
.collect(Collectors.toList());
}
//Filter using the tags provided
if(tags!=null){
List<Long> validTagIds = new ArrayList<>();
for (String t : tags){
Optional<Tags> tagsOptional = tagsRepo.findByTagNameIgnoreCase(t);
if(tagsOptional.isPresent()){
Long tagId = tagsOptional.get().getTagId();
if (!validTagIds.contains(tagId)){
validTagIds.add(tagId);
}
}
}
List<Shops> validShops = new ArrayList<>();
for (Shops s : allShops){
boolean match = false;
for (Tags t : s.getShopTags()){
if (validTagIds.contains(t.getTagId())){
match = true;
break;
}
}
if (match){
validShops.add(s);
}
}
allShops = validShops;
}
//Paginate
boolean hasNextPage = false;
if (allShops.size() > ITEMS_PER_PAGE){
if(page==null){
page = 1;
}
List<List<Shops>> pages = getPages(allShops, ITEMS_PER_PAGE);
if(page > pages.size()){
page = 1;
}
if (pages.size() >= page){
allShops = pages.get(page-1);
}
if (pages.size() >= page + 1){
hasNextPage = true;
}
}
//Sort in order of relevance
allShops = recommendationGenerator.getRecommendations(session, allShops);
//Convert to required format
List<HashMap<String, String>> formattedShops = new ArrayList<>();
for(Shops shop : allShops){
HashMap<String,String> data = new HashMap<>();
data.put("name",shop.getShopName());
data.put("banner",shop.getShopBanner());
data.put("id", String.valueOf(shop.getShopId()));
data.put("category",shop.getCategory().getCategoryName());
data.put("website",shop.getShopWebsite());
Integer reward_count = shop.getStampBoard().getRewards().size();
data.put("reward_count",String.valueOf(reward_count));
if(reward_count != 0){
data.put("next_reward_name",shop.getStampBoard().getRewards().get(0).getRewardName());
data.put("next_reward_pos",String.valueOf(shop.getStampBoard().getRewards().get(0).getRewardStampLocation()));
}else{
data.put("next_reward_name","No Rewards");
}
formattedShops.add(data);
}
Map<String,Object> returnMap = new HashMap<>();
returnMap.put("shops",formattedShops);
returnMap.put("hasNextPage", hasNextPage);
Gson gson = new Gson();
String json = gson.toJson(returnMap);
return json;
}
public <T> List<List<T>> getPages(Collection<T> c, Integer pageSize) {
if (c == null)
return Collections.emptyList();
List<T> list = new ArrayList<T>(c);
if (pageSize == null || pageSize <= 0 || pageSize > list.size())
pageSize = list.size();
int numPages = (int) Math.ceil((double)list.size() / (double)pageSize);
List<List<T>> pages = new ArrayList<List<T>>(numPages);
for (int pageNum = 0; pageNum < numPages;)
pages.add(list.subList(pageNum * pageSize, Math.min(++pageNum * pageSize, list.size())));
return pages;
}
}
src/main/resources/static/imgs/uploaded/02b3324f_113c_4c98_8ad6_7f1cf28f74c9.jpg

6.35 KiB

src/main/resources/static/imgs/uploaded/1eab1fb2_7744_4eb6_9505_8a1e9b59981b.jpg

6.35 KiB

src/main/resources/static/imgs/uploaded/7615374a_c54e_4854_ad96_14b719c5af9c.jpg

6.35 KiB

src/main/resources/static/imgs/uploaded/8d96f724_c612_4da0_9ab0_26a0ea2ad161.jpg

6.35 KiB

var tags = [];
var query = "";
var page = 1;
var searchBar = document.getElementById("main-search");
var tagGroup = document.getElementById("search-tag-group");
function updateSearch(e){
page = 1;
query = searchBar.value;
doSearch(false)
}
function removeTag(i){
tags.splice(i, 1);
page=1;
updateUI()
doSearch(false)
}
function addTag(e){
if(e.key== "Enter"){
if (searchBar.value != ""){
page = 1;
query = "";
tags.push(searchBar.value.toLowerCase());
searchBar.value = "";
updateUI();
doSearch(false);
}
}
}
function updateUI(){
tagGroup.innerHTML = "";
for(let [i,tag] of tags.entries()){
tagGroup.innerHTML += `
<div class="control mr-3">
<div class="tags has-addons">
<span class="tag gradient">${tag}</span>
<a class="tag is-delete" onclick="removeTag(${i})"></a>
</div>
</div>`
}
}
function doSearch(fromNextPageBtn){
let url = "/shop/search"
url += "?q=" + query
url += "&p=" + page.toString()
for (let t of tags){
url += "&t=" + t.toString()
}
fetch(url)
.then(e=>e.json())
.then(data=>{
if(!fromNextPageBtn){
document.getElementById("business_card_container").innerHTML = "";
}
for(let shop of data["shops"]){
addShop(shop);
}
if(data["hasNextPage"] == true){
document.getElementById("loadMoreBtn").style.display = "flex";
}else{
document.getElementById("loadMoreBtn").setAttribute('style', 'display:none!important');
}
});
}
function addShop(shopInfo){
let img_path = shopInfo["banner"]
let title = shopInfo["name"]
let reward_text = shopInfo["next_reward_name"] + " at " + shopInfo["next_reward_pos"] + " stamps"
let reward_amount = shopInfo["reward_count"]
let shopId = shopInfo["id"]
document.getElementById("business_card_container").innerHTML +=`
<div class="business_container box" style="position:relative;">
<div class="image" style="background-image:url(${img_path});"></div>
<div class="favouriteStar starContainer" onclick="favouriteBusiness(this,${shopId});">
<span class="icon favouriteStar">
<i class="far fa-star"></i>
</span>
<span class="icon favouriteStar">
<i class="fas fa-star"></i>
</span>
</div>
<div class="content">
<h1 class="title is-4 mb-1">${title}</h1>
<p class="mb-1">${reward_text}</p>
<div class="is-full-width" style="display:flex;justify-content: space-between;align-items: center">
<div class="level-left">
<span class="icon is-small is-left ml-1 mr-1">
<i class="fas fa-gift"></i>
</span>
<p>${reward_amount}</p>
</div>
<div class="level-right">
<button class="button is-rounded gradient" onclick="redirect(${shopId})">
View Shop
<span class="icon is-small is-left ml-1">
<i class="fas fa-arrow-right"></i>
</span>
</button>
</div>
</div>
</div>
</div>`
}
function loadNextPage(){
page++;
doSearch(true);
}
\ No newline at end of file
......@@ -62,22 +62,24 @@
<div class="container is-full-width is-flex is-justify-content-center is-align-items-center is-flex-direction-column mb-4">
<h1 class="title is-3">Where else can I earn rewards?</h1>
<div class="control has-icons-left mb-2" style="width: 60%;">
<input class="input" type="text" placeholder="Enter Brands or keywords e.g. Vegan, Clothing etc..">
<input class="input" type="text" placeholder="Enter Brands or keywords e.g. Vegan, Clothing etc.."
oninput="updateSearch(event)" onkeydown="addTag(event)" id="main-search">
<span class="icon is-small is-left">
<i class="fas fa-search"></i>
</span>
</div>
<!--Tags-->
<div class="field is-grouped is-grouped-multiline" style="width: 60%;">
<div th:each="tag: ${tags}" th:include="fragments/tag.html :: tag"
th:with="text=${tag}"></div>
<div class="field is-grouped is-grouped-multiline" style="width: 60%;" id="search-tag-group">
<!-- <div th:each="tag: ${tags}" th:include="fragments/tag.html :: tag"-->
<!-- th:with="text=${tag}"></div>-->
</div>
</div>
<div class="container is-full-width is-flex is-justify-content-center is-align-items-center is-flex-wrap-wrap">
<div th:each="shop,i: ${normalShops}" th:include="fragments/business_card.html :: business_card"
th:with="title=${shop.shopName}, reward_text='Free coffee at 6 stamps', reward_amount=4,
img_path=${shop.shopImage}, shopId=${shop.shopId}"></div>
<div class="container is-full-width is-flex is-justify-content-center is-align-items-center is-flex-wrap-wrap"
id="business_card_container">
</div>
<div class="is-full-width is-flex is-justify-content-center is-align-items-center" id="loadMoreBtn" style="display: none!important;;">
<a onclick="loadNextPage()">Load More</a>
</div>
</div>
......@@ -97,5 +99,7 @@
</div>
</div>
</div>
<script src="/js/searchBar.js"></script>
<script>doSearch(false);</script>
</body>
</html>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment