@@ -135,7 +135,13 @@ export function createListingRepository(db) {
|
||||
|
||||
const offset = (page - 1) * limit;
|
||||
const sortOrder =
|
||||
sort === "price_low"
|
||||
sort === "updated"
|
||||
? desc(listings.updatedAt)
|
||||
: sort === "name_asc"
|
||||
? products.name
|
||||
: sort === "name_desc"
|
||||
? desc(products.name)
|
||||
: sort === "price_low"
|
||||
? listings.askingPriceMinor
|
||||
: sort === "price_high"
|
||||
? desc(listings.askingPriceMinor)
|
||||
|
||||
@@ -58,8 +58,8 @@ export function createSearchQuery({
|
||||
throw new Error("minPriceMinor must be <= maxPriceMinor");
|
||||
}
|
||||
|
||||
if (!["recent", "price_low", "price_high"].includes(sort)) {
|
||||
throw new Error("sort must be recent, price_low, or price_high");
|
||||
if (!["recent", "updated", "name_asc", "name_desc", "price_low", "price_high"].includes(sort)) {
|
||||
throw new Error("sort must be recent, updated, name_asc, name_desc, price_low, or price_high");
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -57,6 +57,9 @@ test("builds a public query filter set that hides sold items by default", () =>
|
||||
|
||||
test("accepts only the supported public search sort values", () => {
|
||||
assert.equal(createSearchQuery({ sort: "price_low" }).sort, "price_low");
|
||||
assert.equal(createSearchQuery({ sort: "updated" }).sort, "updated");
|
||||
assert.equal(createSearchQuery({ sort: "name_asc" }).sort, "name_asc");
|
||||
assert.equal(createSearchQuery({ sort: "name_desc" }).sort, "name_desc");
|
||||
assert.throws(
|
||||
() => createSearchQuery({ sort: "random" }),
|
||||
/sort must be recent/,
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
.catalog-sort-select {
|
||||
display: grid;
|
||||
gap: var(--space-1);
|
||||
}
|
||||
|
||||
.catalog-sort-select span {
|
||||
color: var(--color-text-muted);
|
||||
font-size: var(--text-sm);
|
||||
}
|
||||
|
||||
.catalog-sort-select select {
|
||||
min-height: 44px;
|
||||
border: var(--border-thin) solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--space-2) var(--space-3);
|
||||
background: var(--color-surface);
|
||||
color: var(--color-text);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import CatalogSortSelect from './CatalogSortSelect.vue';
|
||||
|
||||
export default { title: 'Atoms/CatalogSortSelect', component: CatalogSortSelect };
|
||||
|
||||
export const RecentlyAdded = { args: { modelValue: 'recent' } };
|
||||
export const NameAscending = { args: { modelValue: 'name_asc' } };
|
||||
@@ -0,0 +1,28 @@
|
||||
<script setup>
|
||||
defineProps({
|
||||
modelValue: { type: String, required: true },
|
||||
});
|
||||
|
||||
defineEmits(['update:modelValue']);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<label class="catalog-sort-select">
|
||||
<span>Sort</span>
|
||||
<select
|
||||
:value="modelValue"
|
||||
@change="$emit('update:modelValue', $event.target.value)"
|
||||
>
|
||||
<option value="recent">Recently added</option>
|
||||
<option value="updated">Recently updated</option>
|
||||
<option value="name_asc">Name A-Z</option>
|
||||
<option value="name_desc">Name Z-A</option>
|
||||
<option value="price_low">Price: low to high</option>
|
||||
<option value="price_high">Price: high to low</option>
|
||||
</select>
|
||||
</label>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@use './CatalogSortSelect.scss';
|
||||
</style>
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
listPublicConditions,
|
||||
} from "@/services/catalog-service.js";
|
||||
import ListingCard from "@/components/molecules/ListingCard.vue";
|
||||
import CatalogSortSelect from "@/components/atoms/CatalogSortSelect.vue";
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
@@ -124,14 +125,7 @@ watch(
|
||||
>Max price (cents)
|
||||
<input v-model.number="maxPriceMinor" type="number" min="0"
|
||||
/></label>
|
||||
<label
|
||||
>Sort
|
||||
<select v-model="sort">
|
||||
<option value="recent">Recently added</option>
|
||||
<option value="price_low">Price: low to high</option>
|
||||
<option value="price_high">Price: high to low</option>
|
||||
</select></label
|
||||
>
|
||||
<CatalogSortSelect v-model="sort" />
|
||||
</div>
|
||||
</header>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user