diff --git a/src/main/java/de/uni_passau/fim/PADAS/group3/DataDash/controler/CategoryController.java b/src/main/java/de/uni_passau/fim/PADAS/group3/DataDash/controler/CategoryController.java index 06454ed..5f725a3 100644 --- a/src/main/java/de/uni_passau/fim/PADAS/group3/DataDash/controler/CategoryController.java +++ b/src/main/java/de/uni_passau/fim/PADAS/group3/DataDash/controler/CategoryController.java @@ -1,18 +1,43 @@ package de.uni_passau.fim.PADAS.group3.DataDash.controler; +import java.util.List; +import java.util.UUID; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import de.uni_passau.fim.PADAS.group3.DataDash.model.Category; +import de.uni_passau.fim.PADAS.group3.DataDash.model.CategoryDto; +import de.uni_passau.fim.PADAS.group3.DataDash.model.CategoryService; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; + + @RestController @RequestMapping("/api/v1/categories") public class CategoryController { + @Autowired + private CategoryService categoryService; + @GetMapping - public Category[] getMethodName() { - return Category.values(); + public List getMethodName() { + return categoryService.getAllCategories() ; } + + @GetMapping("/id/{id}") + public CategoryDto getMethodName(@PathVariable("id") UUID id) { + return categoryService.getCategoryById(id); + } + + @PostMapping + public String postMethodName(@RequestBody CategoryDto dto) { + categoryService.addCategory(dto); + return null; + } + + } diff --git a/src/main/java/de/uni_passau/fim/PADAS/group3/DataDash/controler/PageController.java b/src/main/java/de/uni_passau/fim/PADAS/group3/DataDash/controler/PageController.java new file mode 100644 index 0000000..f1a0f6f --- /dev/null +++ b/src/main/java/de/uni_passau/fim/PADAS/group3/DataDash/controler/PageController.java @@ -0,0 +1,12 @@ +package de.uni_passau.fim.PADAS.group3.DataDash.controler; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +@Controller +public class PageController { + @GetMapping("/add") + public String getAddPage() { + return "add"; + } +} diff --git a/src/main/java/de/uni_passau/fim/PADAS/group3/DataDash/model/Category.java b/src/main/java/de/uni_passau/fim/PADAS/group3/DataDash/model/Category.java index b7cc30e..4246baa 100644 --- a/src/main/java/de/uni_passau/fim/PADAS/group3/DataDash/model/Category.java +++ b/src/main/java/de/uni_passau/fim/PADAS/group3/DataDash/model/Category.java @@ -1,14 +1,45 @@ package de.uni_passau.fim.PADAS.group3.DataDash.model; -public enum Category { - HEALTH, - ENVIRONMENT, - ECONOMY, - POLITICS, - TECHNOLOGY, - SPORTS, - SCIENCE, - CULTURE, - EDUCATION, - OTHER +import java.util.List; +import java.util.UUID; + +import org.springframework.context.annotation.Lazy; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; + +@Entity +public class Category { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private UUID id; + + private String name; + + @Lazy + @OneToMany(mappedBy = "categorie") + private List datasets; + + public Category(String name) { + this.name = name; + } + + public Category() { + } + + public UUID getId() { + return id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } } diff --git a/src/main/java/de/uni_passau/fim/PADAS/group3/DataDash/model/CategoryDto.java b/src/main/java/de/uni_passau/fim/PADAS/group3/DataDash/model/CategoryDto.java new file mode 100644 index 0000000..a21d0cf --- /dev/null +++ b/src/main/java/de/uni_passau/fim/PADAS/group3/DataDash/model/CategoryDto.java @@ -0,0 +1,27 @@ +package de.uni_passau.fim.PADAS.group3.DataDash.model; + +import java.util.UUID; + +public class CategoryDto { + + private String name; + private UUID id; + + public CategoryDto() { + } + + CategoryDto(String name, UUID id) { + this.name = name; + this.id = id; + } + + + public String getName() { + return name; + } + + public UUID getId() { + return id; + } +} + diff --git a/src/main/java/de/uni_passau/fim/PADAS/group3/DataDash/model/CategoryDtoMapper.java b/src/main/java/de/uni_passau/fim/PADAS/group3/DataDash/model/CategoryDtoMapper.java new file mode 100644 index 0000000..e7ecc10 --- /dev/null +++ b/src/main/java/de/uni_passau/fim/PADAS/group3/DataDash/model/CategoryDtoMapper.java @@ -0,0 +1,10 @@ +package de.uni_passau.fim.PADAS.group3.DataDash.model; + +public class CategoryDtoMapper { + + public static CategoryDto toDto(Category category) { + CategoryDto dto = new CategoryDto(category.getName(), category.getId()); + return dto; + } + +} diff --git a/src/main/java/de/uni_passau/fim/PADAS/group3/DataDash/model/CategoryRepository.java b/src/main/java/de/uni_passau/fim/PADAS/group3/DataDash/model/CategoryRepository.java new file mode 100644 index 0000000..a0b67e5 --- /dev/null +++ b/src/main/java/de/uni_passau/fim/PADAS/group3/DataDash/model/CategoryRepository.java @@ -0,0 +1,20 @@ +package de.uni_passau.fim.PADAS.group3.DataDash.model; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +import org.springframework.data.jpa.repository.JpaRepository; + + +public interface CategoryRepository extends JpaRepository{ + + Category getCategoryById(UUID id); + + @SuppressWarnings("null") + List findAll(); + List findByName(String name); + @SuppressWarnings("null") + Optional findById(UUID id); + +} diff --git a/src/main/java/de/uni_passau/fim/PADAS/group3/DataDash/model/CategoryService.java b/src/main/java/de/uni_passau/fim/PADAS/group3/DataDash/model/CategoryService.java new file mode 100644 index 0000000..ba36dc0 --- /dev/null +++ b/src/main/java/de/uni_passau/fim/PADAS/group3/DataDash/model/CategoryService.java @@ -0,0 +1,32 @@ +package de.uni_passau.fim.PADAS.group3.DataDash.model; + +import org.springframework.stereotype.Service; +import java.util.List; +import java.util.UUID; + + +@Service +public class CategoryService { + private CategoryRepository categoryRepository; + + public CategoryService(CategoryRepository categoryRepository) { + this.categoryRepository = categoryRepository; + } + + public void addCategory(CategoryDto category) { + Category cat = new Category(category.getName()); + categoryRepository.save(cat); + } + + public List getAllCategories() { + List tmp = categoryRepository.findAll(); + List s = tmp.stream().map(CategoryDtoMapper::toDto).toList(); + return s; + } + + public CategoryDto getCategoryById(UUID id) { + return CategoryDtoMapper.toDto(categoryRepository.getCategoryById(id)); + } + + +} diff --git a/src/main/java/de/uni_passau/fim/PADAS/group3/DataDash/model/Dataset.java b/src/main/java/de/uni_passau/fim/PADAS/group3/DataDash/model/Dataset.java index e59ee08..91f71a2 100644 --- a/src/main/java/de/uni_passau/fim/PADAS/group3/DataDash/model/Dataset.java +++ b/src/main/java/de/uni_passau/fim/PADAS/group3/DataDash/model/Dataset.java @@ -11,6 +11,7 @@ import jakarta.persistence.Enumerated; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; @Entity public class Dataset { @@ -39,7 +40,8 @@ public class Dataset { private int upvotes; private URL url; - @Enumerated(EnumType.STRING) + + @ManyToOne private Category categorie; public Dataset(String title, String abst, String description, String author, URL url, Category categories, Type type) { @@ -51,7 +53,7 @@ public class Dataset { setAbst(abst); setDescription(description); setAuthor(author); - setDate(LocalDate.now()); + setDate(LocalDate.now()); setCategorie(categories); setType(type); setUrl(url); diff --git a/src/main/java/de/uni_passau/fim/PADAS/group3/DataDash/model/DatasetService.java b/src/main/java/de/uni_passau/fim/PADAS/group3/DataDash/model/DatasetService.java index 43a0cb0..6694907 100644 --- a/src/main/java/de/uni_passau/fim/PADAS/group3/DataDash/model/DatasetService.java +++ b/src/main/java/de/uni_passau/fim/PADAS/group3/DataDash/model/DatasetService.java @@ -1,5 +1,6 @@ package de.uni_passau.fim.PADAS.group3.DataDash.model; +import java.time.LocalDate; import java.util.List; import java.util.Optional; import java.util.UUID; @@ -12,9 +13,11 @@ import org.springframework.data.domain.Page; @Service public class DatasetService { private dataRepository datasetRepository; + private CategoryRepository categoryRepository; - public DatasetService(dataRepository datasetRepository) { + public DatasetService(dataRepository datasetRepository, CategoryRepository categoryRepository) { this.datasetRepository = datasetRepository; + this.categoryRepository = categoryRepository; } public List getAllDatasets() { @@ -26,6 +29,7 @@ public class DatasetService { } public void addDataset(Dataset dataset) { + dataset.setDate(LocalDate.now()); datasetRepository.save(dataset); } @@ -93,9 +97,14 @@ public class DatasetService { public Page searchByOptionalCriteria(String search, String categories, String type, Pageable pageable) { //TODO: make it not Crash - Category category = categories.equals("%") ? null : Category.valueOf(categories); + //TODO: make it do useful stuff + Category category = categories.equals("%") ? null : categoryRepository.getCategoryById(UUID.fromString(categories)) ; Type t = type.equals("%") ? null : Type.valueOf(type); - return datasetRepository.searchByOptionalCriteria(Optional.ofNullable(search), Optional.ofNullable(category), Optional.ofNullable(t),pageable); + if(category == null){ + return datasetRepository.searchByOptionalCriteria(Optional.ofNullable(search), Optional.ofNullable(t),pageable); + } + return datasetRepository.searchByOptionalCriteriaWithCategory(Optional.ofNullable(search), category, Optional.ofNullable(t),pageable); } + } \ No newline at end of file diff --git a/src/main/java/de/uni_passau/fim/PADAS/group3/DataDash/model/LoadDummyDatabase.java b/src/main/java/de/uni_passau/fim/PADAS/group3/DataDash/model/LoadDummyDatabase.java index 42de661..18d9085 100644 --- a/src/main/java/de/uni_passau/fim/PADAS/group3/DataDash/model/LoadDummyDatabase.java +++ b/src/main/java/de/uni_passau/fim/PADAS/group3/DataDash/model/LoadDummyDatabase.java @@ -1,6 +1,7 @@ package de.uni_passau.fim.PADAS.group3.DataDash.model; import java.util.List; +import java.util.Random; import org.slf4j.LoggerFactory; import org.springframework.boot.CommandLineRunner; @@ -15,15 +16,21 @@ public class LoadDummyDatabase { private static final org.slf4j.Logger log = LoggerFactory.getLogger(LoadDummyDatabase.class); @Bean - CommandLineRunner initDatabase(dataRepository repository) { + CommandLineRunner initDatabase(dataRepository repository, CategoryRepository categoryRepository) { return args -> { for (int i = 0; i < 100; i++) { - Dataset dataset = new Dataset("Title" + i, "Abst" + i, "Description" + i, "Author" + i,null, Category.EDUCATION, Type.API); - repository.save(dataset); + Category category = new Category("Category" + i); + log.info("Preloading" + categoryRepository.save(category)); + + Dataset dataset = new Dataset("Title" + i, "Abst" + i, "Description" + i, "Author" + i,null, category, Type.API); + for (int j = 0; j < new Random().nextInt(50); j++) { + dataset.upvote(); + } log.info("Preloading" + repository.save(dataset)); + log.info("Preloading" + categoryRepository.save(category)); } List s = repository.findByTitleLike("%Title%"); log.info("Found Entry with ID: " + s.get(1).getId());}; diff --git a/src/main/java/de/uni_passau/fim/PADAS/group3/DataDash/model/dataRepository.java b/src/main/java/de/uni_passau/fim/PADAS/group3/DataDash/model/dataRepository.java index 17fde64..130415d 100644 --- a/src/main/java/de/uni_passau/fim/PADAS/group3/DataDash/model/dataRepository.java +++ b/src/main/java/de/uni_passau/fim/PADAS/group3/DataDash/model/dataRepository.java @@ -65,10 +65,19 @@ public interface dataRepository extends JpaRepository { "((LOWER(d.title) LIKE LOWER(:search)) OR " + "(LOWER(d.description) LIKE LOWER(:search)) OR " + "(LOWER(d.author) LIKE LOWER(:search))) AND" + - "(:categorie IS NULL OR d.categorie = :categorie) AND" + + "(d.categorie = :categorie) AND" + "(:type IS NULL OR d.type = :type)") - Page searchByOptionalCriteria(@Param("search") Optional search, - @Param("categorie") Optional categories, + Page searchByOptionalCriteriaWithCategory(@Param("search") Optional search, + @Param("categorie") Category categories, @Param("type") Optional type, Pageable pageable); -} \ No newline at end of file + + @Query("SELECT d FROM Dataset d WHERE " + + "((LOWER(d.title) LIKE LOWER(:search)) OR " + + "(LOWER(d.description) LIKE LOWER(:search)) OR " + + "(LOWER(d.author) LIKE LOWER(:search))) AND" + + "(:type IS NULL OR d.type = :type)") + Page searchByOptionalCriteria(@Param("search") Optional search, + @Param("type") Optional type, + Pageable pageable); +} diff --git a/src/main/resources/static/add.css b/src/main/resources/static/add.css index 4361843..6d62a6f 100644 --- a/src/main/resources/static/add.css +++ b/src/main/resources/static/add.css @@ -4,20 +4,6 @@ --accent-color: oklch(65.33% 0.158 247.76); } -form label:after { - content: ":"; -} - -form :is(input[type=text], textarea) { - background-color: var(--fg-color); - border: none; - border-radius: .25lh; - color: var(--text-color, white); - padding: .5em; - font-family: sans-serif; -} - -/* quick info box */ form { display: grid; grid-template-columns: 1fr 1fr auto; @@ -30,17 +16,57 @@ form > * { gap: 1rem; } -form :is(input[type=text], textarea) { +form label:after { + content: ":"; +} + +/* text entries */ +form :is(input[type=text], input[type=url], textarea) { + background-color: var(--fg-color); + border: none; + border-radius: .25lh; + color: var(--text-color, white); + padding: .5em; + font-family: sans-serif; flex-grow: 1; } +/* focus outlines */ +:is(form :is(input[type=text], input[type=url], textarea), .btn):focus-visible { + outline: 2px solid var(--accent-color); +} + +.btn, #is-dataset-toggle { + transition: outline ease-in 100ms; +} + +/* input validation */ +form :is(input[type=text], input[type=url], textarea):user-valid { + --validation-color: lime; +} + +form :is(input[type=text], input[type=url], textarea):user-invalid { + --validation-color: red; + outline-style: solid; +} + +form :is(input[type=text], input[type=url], textarea):is(:user-valid, :user-invalid) { + outline-color: var(--validation-color); +} + +form :is(input[type=text], input[type=url], textarea):is(:user-valid, :user-invalid):not(:focus-visible) { + outline-width: 1px; +} + /* switch */ label:has(#is-dataset) { gap: 0; } #is-dataset { - display: none; + top: -100vh; + left: -100vw; + position: absolute; } #is-dataset-toggle { @@ -66,6 +92,11 @@ label:has(#is-dataset) { box-sizing: border-box; background-color: var(--text-color); transition: inset-inline ease-out 50ms; + filter: drop-shadow(rgba(0, 0, 0, .8) 0 0 .25rem); +} + +#is-dataset:focus-visible + #is-dataset-toggle { + outline: 2px solid var(--accent-color); } #is-dataset:not(:checked) + #is-dataset-toggle::before { @@ -78,7 +109,11 @@ label:has(#is-dataset) { /* short description box */ form :has(#short-description) { - grid-column: 1 / 3; + grid-column: 1 / 2; +} + +form :has(#url) { + grid-column: 2 / 4; } /* full description box */ @@ -115,13 +150,18 @@ form :has(#short-description) { --drop-shadow-opacity: .5; --drop-shadow-offset-y: 0; --drop-shadow-blur: .25rem; - filter: drop-shadow( + --drop-shadow: drop-shadow( rgba(0, 0, 0, var(--drop-shadow-opacity)) 0 var(--drop-shadow-offset-y) var(--drop-shadow-blur) ); + filter: var(--drop-shadow); } -.btn:hover { +.btn:focus-visible, #is-dataset:focus-visible + #is-dataset-toggle { + outline-offset: 2px; +} + +.btn:not(:disabled):hover { background-color: color-mix(in oklab, var(--btn-color) 80%, var(--bg-color)); --drop-shadow-opacity: .8; --drop-shadow-offset-y: .25rem; @@ -131,3 +171,7 @@ form :has(#short-description) { .btn.suggested { --btn-color: var(--accent-color); } + +.btn:disabled { + filter: var(--drop-shadow) grayscale(.5) brightness(.5); +} diff --git a/src/main/resources/static/add.js b/src/main/resources/static/add.js new file mode 100644 index 0000000..280eb67 --- /dev/null +++ b/src/main/resources/static/add.js @@ -0,0 +1,59 @@ +const form = document.forms[0]; +const { + title: titleEntry, + author: authorEntry, + ["is-dataset"]: isDatasetSwitch, + ["short-description"]: shortDescriptionEntry, + url: urlEntry, + ["full-description"]: fullDescriptionEntry, + ["btn-add"]: addBtn, + ["btn-cancel"]: cancelBtn, +} = form.elements; + +const validationListener = () => { + addBtn.disabled = !form.checkValidity(); +}; + +// Register validationListener on all required inputs that must be valid +[ + titleEntry, + authorEntry, + shortDescriptionEntry, + urlEntry, + fullDescriptionEntry, +].forEach(input => input.addEventListener("input", validationListener)); + +form.addEventListener("submit", e => { + e.preventDefault(); + if (!form.reportValidity()) return; + + // Create the request body + const newContent = { + title: titleEntry.value, + author: authorEntry.value, + abst: shortDescriptionEntry.value, + url: urlEntry.value, + description: fullDescriptionEntry.value, + type: isDatasetSwitch.checked ? "API" : "DATASET", + categories: [], + }; + + console.debug(newContent); + + // Don't allow several requests to be sent at the same time + addBtn.disabled = true; + + fetch("/api/v1/datasets", { + method: "POST", + body: JSON.stringify(newContent), + headers: { + "Content-Type": "application/json;charset=utf-8" + } + }).then(response => { + if (response.status == 200) { + location.assign("/"); + } else { + addBtn.disabled = !form.checkValidity(); + } + }); +}); diff --git a/src/main/resources/static/contentUtility.js b/src/main/resources/static/contentUtility.js new file mode 100644 index 0000000..e2a032e --- /dev/null +++ b/src/main/resources/static/contentUtility.js @@ -0,0 +1,27 @@ +import {searchBarTimeout, searchSection} from "./main.js" +import Dataset from "./dataset.js" + +export function fetchQuery(fetchString) { + clearTimeout(searchBarTimeout); + fetch(fetchString) + .then(resp => resp.json()) + .then((data) => { + parseContent(data.content); + }); +} + +function parseContent(content) { + console.log(content); //TODO: remove + if (content.length === 0) { + searchSection.querySelector("#nothing-found ").classList.remove("hidden"); + } else { + searchSection.querySelector("#nothing-found").classList.add("hidden"); + const datasets = content.map(dataset => new Dataset(dataset)); + console.log(datasets); //TODO: remove + Array.from(searchSection.querySelectorAll(".datasets .dataset")).forEach(e => e.remove()); + for (const dataset of datasets) { + searchSection.querySelector(".datasets").appendChild(dataset.createDatasetHTMLElement()); + } + } + +} diff --git a/src/main/resources/static/dataset.js b/src/main/resources/static/dataset.js new file mode 100644 index 0000000..27245e5 --- /dev/null +++ b/src/main/resources/static/dataset.js @@ -0,0 +1,51 @@ +import { vote } from "./main.js"; + +export default class Dataset { + #abstract; + #author; + #categories; + #date; + #description; + #id; + #rating; + #title; + #type; + #upvotes; + #url; + #votes; + + constructor({abst: shortDescription, author, categories, date, description, id, rating, title, type, upvotes, url, votes}) { + this.#abstract = shortDescription; + this.#author = author; + this.#categories = categories; + this.#date = date; + this.#description = description; + this.#id = id; + this.#rating = rating; + this.#title = title; + this.#type = type; + this.#upvotes = upvotes; + this.#url = url; + this.#votes = votes; + } + + createDatasetHTMLElement() { + let template = document.querySelector("#dataset-template"); + const clone = template.content.cloneNode(true); + clone.querySelector(".dataset").dataset.id = this.#id; + clone.querySelector("h3").innerText = this.#title; + clone.querySelector("p").innerText = this.#description; + clone.querySelector("span").innerText = this.#upvotes; + + // Event Listeners + clone.querySelector(".upvote-btn").addEventListener("click", () => { + vote(this.#id, true); + }); + + clone.querySelector(".downvote-btn").addEventListener("click", () => { + vote(this.#id, false); + }) + + return clone; + } +} diff --git a/src/main/resources/static/main.css b/src/main/resources/static/main.css index 0711eca..63566c3 100644 --- a/src/main/resources/static/main.css +++ b/src/main/resources/static/main.css @@ -4,7 +4,7 @@ --text-color: #dbdbdb; --pad-datasets: 1rem; --pad-main: 2rem; - --min-card-size: 60ch; + --min-card-size: min(60ch, 33vw); --corner-radius: 1rem; font-size: 12pt; font-family: sans-serif; @@ -49,6 +49,9 @@ header { gap: .5rem; background-color: var(--fg-color, darkgrey); padding: .5rem 1rem; + margin-bottom: var(--pad-datasets); + margin-left: var(--pad-datasets); + margin-right: var(--pad-datasets); border-radius: 1.5rem; } @@ -58,6 +61,37 @@ header { color: var(--text-color); } +#nothing-found { + height: 60vh; + padding: 20vh 0; +} + +#nothing-found-bg { + background: url("sad-looking-glass.svg") center no-repeat; + background-size: contain; + width: 100%; + height: 40vh; +} + +#nothing-found-text { + text-align: center; +} + + +/* +#search .datasets:empty { + background: url("sad-looking-glass.svg"); + height: 7rem; + width: 7rem; + padding: var(--pad-main); +} + + */ + + +.hidden { + display: none; +} #search-entry:focus-visible { outline: none; } @@ -69,14 +103,18 @@ header { gap: 1rem; } -@container (width < 80ch) { + + + + +@container (width < 60ch) { .datasets { grid-template-columns: 1fr; } } .dataset { - padding: 1rem 2rem; + padding: var(--pad-datasets) 2rem; background-color: var(--fg-color, darkgrey); border-radius: var(--corner-radius); list-style: none; @@ -136,10 +174,22 @@ header { background-color: var(--bg-color); } -:is(.upvote-btn, .downvote-btn, #search-btn, #filter-btn, #sort-btn, #add-btn):is(:hover, :focus-visible) { +#add-btn:is(:hover, :focus-visible) { + filter: brightness(1.2); +} + +#add-btn:active { + filter: brightness(1.3); +} + +.btn.flat { + transition: filter ease-out 50ms; +} + +.btn.flat:is(:hover, :focus-visible) { filter: brightness(1.5); } -:is(.upvote-btn, .downvote-btn, #search-btn, #filter-btn, #sort-btn, #add-btn):active { +.btn.flat:active { filter: brightness(1.75); } diff --git a/src/main/resources/static/main.js b/src/main/resources/static/main.js new file mode 100644 index 0000000..65c62d6 --- /dev/null +++ b/src/main/resources/static/main.js @@ -0,0 +1,161 @@ +import { fetchQuery } from "./contentUtility.js"; + +const apiEndpoint = "/api/v1/datasets"; +const baseURL = location.origin; +const defaultPagingValue = 20; +const lastQuery = { + url: "", + totalPages: 0, + currentPage: 0 +}; + +// definition of all buttons & sections +const addButton = document.getElementById("add-btn"); +const filterButton = document.getElementById("filter-btn"); +const searchButton = document.getElementById("search-btn"); +const searchBar = document.getElementById("search-entry"); +const sortButton = document.getElementById("sort-btn"); +const upvoteButtons = document.getElementsByClassName("upvote-btn"); +const downvoteButtons = document.getElementsByClassName("downvote-btn"); +export const searchSection = document.getElementById("search"); +const recentSection = document.getElementById("recents"); +const mostLikedSection = document.getElementById("top"); + +// ID of the timeout, because we need to cancel it at some point +export let searchBarTimeout; +const searchDelay = 500; + +// Event listeners +addButton.addEventListener("click", () => { + navigateToAdd(); +}); + +filterButton.addEventListener("change", () => { + const filterString = filterButton.value; + filter(filterString); +}); + +searchButton.addEventListener("click", () => { + const searchString = searchBar.value; + search(searchString); +}); + +searchBar.addEventListener("input", () => { + updateSections(); + clearTimeout(searchBarTimeout); + searchBarTimeout = setTimeout(() => { + const searchString = searchBar.value; + search(searchString); + }, searchDelay); +}); + +searchBar.addEventListener('keypress', function (e) { + if (e.key === 'Enter') { + const searchString = searchBar.value; + search(searchString); + } +}) + +sortButton.addEventListener("change", () => { + const sortString = sortButton.value; + sort(sortString); +}); + +// Consider moving this to datasets.js completely +const upvoteButtonClickListener = e => { + const entryID = e.target.parentElement.parentElement.dataset.id; + vote(entryID, true); +}; +for (const upvoteButton of upvoteButtons) { + upvoteButton.addEventListener("click", upvoteButtonClickListener); +} + +// Consider moving this to datasets.js completely +const downvoteButtonClickListener = e => { + const entryID = e.target.parentElement.parentElement.dataset.id; + vote(entryID, false); +}; +for (const downvoteButton of downvoteButtons) { + downvoteButton.addEventListener("click", downvoteButtonClickListener); +} + +// functions of the main page +function navigateToAdd() { + //TODO: url to add page not yet implemented, add here + window.location.href = "/add"; +} + +function filter(filterString) { + filterString = filterString.toUpperCase(); + let fetchURL = new URL(apiEndpoint, baseURL); + fetchURL.searchParams.append("type", filterString); + fetchURL.searchParams.append("size", defaultPagingValue); + console.log(fetchURL); // TODO: remove + fetchQuery(fetchURL); +} + +function search(searchString) { + let fetchURL = new URL(apiEndpoint + "/search", baseURL); + fetchURL.searchParams.append("search", searchString.length === 0 ? "%" : searchString); + + console.log(fetchURL); // TODO: remove + fetchQuery(fetchURL); +} + +function sort(sortString) { + let query = sortString.toLowerCase().split(" "); + if (query[1] === "a-z" || query[1] === "↑" || query[1] === "oldest-newest") { + query[1] = "asc"; + } else { + query[1] = "desc"; + } + let fetchURL = new URL(apiEndpoint, baseURL); + fetchURL.searchParams.append("sort", query[0]); + fetchURL.searchParams.append("direction", query[1]); + console.log(fetchURL); // TODO: remove + fetchQuery(fetchURL); +} + +export function vote(entryID, up) { + const fetchURL = new URL( + `${apiEndpoint}/id/${entryID}/${up ? "up" : "down"}vote`, + baseURL, + ); + console.log(fetchURL); // TODO: remove + fetch(fetchURL, { + method: "PUT", //mode: 'no-cors' + headers: { + 'Content-Type': 'application/json', + // Add other headers as needed + }, + }); + /*.then(resp => resp.json()) // TODO: wait for backend + .then((data) => { + console.log(data.content); // TODO: remove*/ + let dataset = document.querySelector('[data-id= ' + CSS.escape(entryID) + ']') + dataset.querySelector("span").innerText++; // TODO: replace by parsed vote + /*});*/ +} + +function incrementPageCount() { + lastQuery.currentPage++; +} + +function updateSections() { + if (searchBar.value === "") { + searchSection.classList.add("hidden"); + recentSection.classList.remove("hidden"); + mostLikedSection.classList.remove("hidden"); + } else { + searchSection.classList.remove("hidden"); + recentSection.classList.add("hidden"); + mostLikedSection.classList.add("hidden"); + } +} + +window.onload = function () { + updateSections(); + if (searchBar.value !== "") { + search(searchBar.value); + } +} diff --git a/src/main/resources/static/sad-looking-glass.svg b/src/main/resources/static/sad-looking-glass.svg index 7ad3841..ab99a6e 100644 --- a/src/main/resources/static/sad-looking-glass.svg +++ b/src/main/resources/static/sad-looking-glass.svg @@ -1,2 +1,7 @@ - + + + + + + diff --git a/src/main/resources/templates/add.html b/src/main/resources/templates/add.html index d8472c1..30888c3 100644 --- a/src/main/resources/templates/add.html +++ b/src/main/resources/templates/add.html @@ -5,6 +5,7 @@ DataDash – Add dataset/API +
@@ -19,15 +20,15 @@ how to use it.

-
+ - - + + - +