Added primitive search mechanism in backend.
Began implementing search mechanism for frontend.
This commit is contained in:
@@ -1,117 +1,76 @@
|
||||
import Alpine from "alpinejs";
|
||||
import { apiHttp } from "~/assets/js/services/http.js";
|
||||
|
||||
// All input fields.
|
||||
let inputs = {
|
||||
maxPriceEnabled: document.getElementById("max-price-enabled"),
|
||||
maxShippingEnabled: document.getElementById("max-shipping-enabled"),
|
||||
minRating: document.getElementById("min-rating"),
|
||||
maxPrice: document.getElementById("max-price"),
|
||||
maxShipping: document.getElementById("max-shipping"),
|
||||
keepUnknownPurchases: document.getElementById("keep-unknown-purchases"),
|
||||
keepUnknownReviews: document.getElementById("keep-unknown-reviews"),
|
||||
keepUnknownShipping: document.getElementById("keep-unknown-shipping"),
|
||||
keepUnrated: document.getElementById("keep-unrated"),
|
||||
minPrice: document.getElementById("min-price"),
|
||||
minPurchases: document.getElementById("min-purchases"),
|
||||
minReviews: document.getElementById("min-reviews"),
|
||||
shopToggles: {}
|
||||
};
|
||||
const startingSlide = "#quick-picks-slide";
|
||||
|
||||
async function main() {
|
||||
setupInteractiveBehavior();
|
||||
await setupInitialValues((await apiHttp.get("/Search/Default/Filters")).data);
|
||||
await setupShopToggles((await apiHttp.get("/Search/Shops/Available")).data);
|
||||
|
||||
document.querySelector("#configuration .invisible").classList.remove("invisible"); // Load completed, show the UI.
|
||||
}
|
||||
|
||||
function setupInteractiveBehavior() {
|
||||
let configurationElem = document.getElementById("configuration");
|
||||
function initInteractiveElements() {
|
||||
let configurationToggle = document.getElementById("configuration-toggle");
|
||||
let configurationElem = document.getElementById("configuration");
|
||||
configurationElem.addEventListener("show.bs.collapse", function () {
|
||||
configurationToggle.classList.add("active");
|
||||
});
|
||||
configurationElem.addEventListener("hidden.bs.collapse", function () {
|
||||
configurationToggle.classList.remove("active");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
inputs.maxPriceEnabled.addEventListener("change", function () {
|
||||
inputs.maxPrice.disabled = !this.checked;
|
||||
});
|
||||
|
||||
inputs.maxShippingEnabled.addEventListener("change", function () {
|
||||
inputs.maxShipping.disabled = !this.checked;
|
||||
});
|
||||
|
||||
inputs.minRating.addEventListener("input", function () {
|
||||
document.getElementById("min-rating-display").innerHTML = `Minimum rating: ${this.value}%`;
|
||||
async function initConfigurationData() {
|
||||
const givenConfig = (await apiHttp.get("/SearchOutline/Filters")).data;
|
||||
const disabledShops = (await apiHttp.get("/SearchOutline/DisabledShops")).data;
|
||||
const availableShops = (await apiHttp.get("/Search/Available")).data;
|
||||
document.addEventListener("alpine:init", () => {
|
||||
Alpine.data("configuration", () => {
|
||||
const configuration = {
|
||||
maxPriceEnabled: givenConfig.enableUpperPrice,
|
||||
maxPrice: givenConfig.upperPrice,
|
||||
minPrice: givenConfig.lowerPrice,
|
||||
maxShippingEnabled: givenConfig.enableMaxShippingFee,
|
||||
maxShipping: givenConfig.maxShippingFee,
|
||||
keepUnknownShipping: givenConfig.keepUnknownShipping,
|
||||
minRating: givenConfig.minRating * 100,
|
||||
keepUnrated: givenConfig.keepUnrated,
|
||||
minReviews: givenConfig.minReviews,
|
||||
keepUnknownReviews: givenConfig.keepUnknownReviewCount,
|
||||
keepUnknownPurchases: givenConfig.keepUnknownPurchaseCount,
|
||||
minPurchases: givenConfig.minPurchases,
|
||||
shops: {},
|
||||
};
|
||||
availableShops.forEach(shop => {
|
||||
configuration.shops[shop] = !disabledShops.includes(shop);
|
||||
});
|
||||
return configuration;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function setupInitialValues(filters) {
|
||||
inputs.maxShippingEnabled.checked = filters.enableMaxShippingFee;
|
||||
inputs.maxShippingEnabled.dispatchEvent(new Event("change"));
|
||||
function initSlides() {
|
||||
document.querySelectorAll("#content-pages > .selectors > .nav-item > button").forEach(tabElem => {
|
||||
tabElem.addEventListener("click", () => {
|
||||
const destUrl = new URL(tabElem.getAttribute("data-bs-target"), window.location.href);
|
||||
if (location.href === destUrl.href) return;
|
||||
history.pushState({}, document.title, destUrl);
|
||||
});
|
||||
});
|
||||
const goTo = () => {
|
||||
const match = location.href.match("(#[\\w-]+)");
|
||||
const idAnchor = match && match[1] ? match[1] : startingSlide;
|
||||
document.querySelector("#content-pages > .selectors > .nav-item > .active")?.classList.remove("active");
|
||||
document.querySelector("#content-pages > .multipage-slides > .active.show")?.classList.remove("active", "show");
|
||||
document.querySelector(`#content-pages > .selectors > .nav-item > [data-bs-target="${idAnchor}"]`).classList.add("active");
|
||||
document.querySelector(`#content-pages > .multipage-slides > ${idAnchor}`).classList.add("active", "show");
|
||||
};
|
||||
window.addEventListener("popstate", goTo);
|
||||
goTo();
|
||||
|
||||
inputs.maxPriceEnabled.checked = filters.enableUpperPrice;
|
||||
inputs.maxPriceEnabled.dispatchEvent(new Event("change"));
|
||||
|
||||
inputs.keepUnknownPurchases.checked = filters.keepUnknownPurchaseCount;
|
||||
inputs.keepUnknownPurchases.dispatchEvent(new Event("change"));
|
||||
|
||||
inputs.keepUnknownReviews.checked = filters.keepUnknownReviewCount;
|
||||
inputs.keepUnknownReviews.dispatchEvent(new Event("change"));
|
||||
|
||||
inputs.keepUnknownShipping.checked = filters.keepUnknownShipping;
|
||||
inputs.keepUnknownShipping.dispatchEvent(new Event("change"));
|
||||
|
||||
inputs.keepUnrated.checked = filters.keepUnrated;
|
||||
inputs.keepUnrated.dispatchEvent(new Event("change"));
|
||||
|
||||
inputs.minPrice.value = filters.lowerPrice;
|
||||
inputs.minPrice.dispatchEvent(new Event("change"));
|
||||
|
||||
inputs.maxShipping.value = filters.maxShippingFee;
|
||||
inputs.maxShipping.dispatchEvent(new Event("change"));
|
||||
|
||||
inputs.minPurchases.value = filters.minPurchases;
|
||||
inputs.minPurchases.dispatchEvent(new Event("change"));
|
||||
|
||||
inputs.minRating.value = filters.minRating * 100;
|
||||
inputs.minRating.dispatchEvent(new Event("input"));
|
||||
|
||||
inputs.minReviews.value = filters.minReviews;
|
||||
inputs.minReviews.dispatchEvent(new Event("change"));
|
||||
|
||||
inputs.maxPrice.value = filters.upperPrice;
|
||||
inputs.maxPrice.dispatchEvent(new Event("change"));
|
||||
require("bootstrap/js/dist/tab.js");
|
||||
document.querySelector("#content-pages").classList.remove("invisible");
|
||||
}
|
||||
|
||||
async function setupShopToggles(availableShops) {
|
||||
let disabledShops = (await apiHttp.get("/Search/Default/DisabledShops")).data;
|
||||
let shopsElem = document.getElementById("shop-checkboxes");
|
||||
availableShops.forEach(shopName => {
|
||||
let id = `${shopName}-enabled`;
|
||||
let shopLabelElem = document.createElement("label");
|
||||
shopLabelElem.classList.add("form-check-label");
|
||||
shopLabelElem.htmlFor = id;
|
||||
shopLabelElem.innerHTML = `Enable ${shopName}`;
|
||||
|
||||
let shopCheckboxElem = document.createElement("input");
|
||||
shopCheckboxElem.classList.add("form-check-input");
|
||||
shopCheckboxElem.type = "checkbox";
|
||||
shopCheckboxElem.id = id;
|
||||
shopCheckboxElem.checked = !disabledShops.includes(shopName);
|
||||
inputs.shopToggles[shopName] = shopCheckboxElem;
|
||||
|
||||
let shopToggleElem = document.createElement("div");
|
||||
shopToggleElem.classList.add("form-check");
|
||||
shopToggleElem.appendChild(shopCheckboxElem);
|
||||
shopToggleElem.appendChild(shopLabelElem);
|
||||
shopsElem.appendChild(shopToggleElem);
|
||||
});
|
||||
async function main() {
|
||||
initInteractiveElements();
|
||||
await initConfigurationData();
|
||||
initSlides();
|
||||
Alpine.start();
|
||||
}
|
||||
|
||||
main();
|
||||
|
||||
// TODO: Implement search.
|
||||
|
@@ -17,10 +17,11 @@ header > nav {
|
||||
&.active {
|
||||
@include themer.themed {
|
||||
color: themer.color-of("navbar-active");
|
||||
border-color: themer.color-of("navbar-active");
|
||||
border-bottom-color: themer.color-of("navbar-active");
|
||||
}
|
||||
padding-bottom: 2px;
|
||||
border-bottom-style: solid;
|
||||
border-bottom-width: 1px;
|
||||
border-bottom-width: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,26 +83,32 @@ footer {
|
||||
}
|
||||
|
||||
.concise {
|
||||
@extend .container;
|
||||
max-width: 630px;
|
||||
width: inherit;
|
||||
}
|
||||
|
||||
.less-concise {
|
||||
@extend .container;
|
||||
max-width: 720px;
|
||||
width: inherit;
|
||||
}
|
||||
|
||||
hr.concise {
|
||||
@extend .my-3;
|
||||
@include themer.themed {
|
||||
color: themer.color-of("special");
|
||||
hr {
|
||||
&.concise {
|
||||
@extend .my-2;
|
||||
width: 15%;
|
||||
max-width: 160px;
|
||||
min-width: 32px;
|
||||
height: 2px;
|
||||
}
|
||||
&.less-concise {
|
||||
@extend .my-2;
|
||||
width: 30%;
|
||||
max-width: 270px;
|
||||
min-width: 32px;
|
||||
height: 2px;
|
||||
}
|
||||
width: 15%;
|
||||
max-width: 160px;
|
||||
min-width: 32px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
height: 2px;
|
||||
}
|
||||
|
||||
html {
|
||||
@@ -118,4 +125,62 @@ body {
|
||||
background-color: themer.color-of("background");
|
||||
color: themer.color-of("text");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.text-muted {
|
||||
@include themer.themed {
|
||||
color: themer.color-of("muted") !important;
|
||||
}
|
||||
}
|
||||
|
||||
.multipage {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
|
||||
.multipage-slides, .multipage-slides > .multipage-slide.active {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.multipage-slide {
|
||||
.multipage-content {
|
||||
@extend .container;
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.multipage-title {
|
||||
@extend .less-concise;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-pills.selectors {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: 1rem;
|
||||
button[type="button"] {
|
||||
margin-right: 5px;
|
||||
margin-left: 5px;
|
||||
opacity: 0.4;
|
||||
border-style: none;
|
||||
font-size: 1.5rem;
|
||||
min-width: 30px;
|
||||
width: auto;
|
||||
height: auto;
|
||||
background-color: transparent;
|
||||
background-clip: border-box;
|
||||
@include themer.themed {
|
||||
border-bottom: 2px solid themer.color-of("text");
|
||||
}
|
||||
border-bottom-style: none;
|
||||
|
||||
&.active {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user