Skip to content

Commit

Permalink
Add the ability to sort by price (#65)
Browse files Browse the repository at this point in the history
  • Loading branch information
cmintey authored Oct 23, 2023
1 parent ac1078d commit d92b455
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 65 deletions.
7 changes: 7 additions & 0 deletions src/ambient.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,10 @@ type Config = {
};
smtp: SMTPConfig;
};

type Option = {
value: string;
direction?: Direction;
displayValue: string;
};
type Direction = "asc" | "desc";
91 changes: 91 additions & 0 deletions src/lib/components/wishlists/chips/BaseChip.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<script lang="ts">
import { goto } from "$app/navigation";
import { page } from "$app/stores";
import { popup, type PopupSettings } from "@skeletonlabs/skeleton";
export let options: Option[];
export let defaultOption: Option;
export let searchParam: string;
export let directionParam: string | undefined = undefined;
export let prefix: string | undefined = undefined;
let filter = $page.url.searchParams.get(searchParam);
let direction = directionParam ? $page.url.searchParams.get(searchParam) : null;
let selectedOption: Option = defaultOption;
if (filter) {
for (const option of options) {
if (filter === option.value) {
if (option.direction) {
if (direction && option.direction === direction) {
selectedOption = option;
break;
}
} else {
selectedOption = option;
break;
}
}
}
}
const popupKey = `${searchParam}-options`;
let menuOpen = false;
const menuSettings: PopupSettings = {
event: "click",
target: popupKey,
state: ({ state }) => (menuOpen = state)
};
const handleClick = (option: Option) => {
selectedOption = option;
const newUrl = new URL($page.url);
if (option === defaultOption) {
newUrl.searchParams.delete(searchParam);
if (directionParam) newUrl.searchParams.delete(directionParam);
} else {
newUrl.searchParams.set(searchParam, option.value);
if (directionParam && option.direction)
newUrl.searchParams.set(directionParam, option.direction);
}
goto(newUrl, {
replaceState: true
});
};
</script>

<div class="flex flex-row space-x-4 pb-4">
<span class="relative">
<button
class="variant-ringed-primary chip"
class:variant-ghost-primary={selectedOption !== defaultOption}
use:popup={menuSettings}
>
{#if selectedOption.direction === "asc"}
<iconify-icon icon="ion:arrow-up" />
{:else if selectedOption.direction === "desc"}
<iconify-icon icon="ion:arrow-down" />
{:else if prefix}
<iconify-icon icon={prefix} />
{/if}
<span>{selectedOption.displayValue}</span>
<iconify-icon
class="arrow text-xs duration-300 ease-out"
class:rotate-180={menuOpen}
icon="ion:caret-down"
/>
</button>
<nav class="card list-nav p-4 shadow-xl" data-popup={popupKey}>
<ul>
{#each options as option}
<li>
<button class="list-option w-full" on:click={() => handleClick(option)}>
{option.displayValue}
</button>
</li>
{/each}
</ul>
</nav>
</span>
</div>
81 changes: 19 additions & 62 deletions src/lib/components/wishlists/chips/ClaimFilter.svelte
Original file line number Diff line number Diff line change
@@ -1,67 +1,24 @@
<script lang="ts">
import { goto } from "$app/navigation";
import { page } from "$app/stores";
import { popup, type PopupSettings } from "@skeletonlabs/skeleton";
import BaseChip from "./BaseChip.svelte";
const CLAIM_OPTIONS = {
all: "All",
claimed: "Claimed",
unclaimed: "Unclaimed"
};
type ClaimOption = keyof typeof CLAIM_OPTIONS;
const options: Option[] = [
{
value: "all",
displayValue: "All"
},
{
value: "claimed",
displayValue: "Claimed"
},
{
value: "unclaimed",
displayValue: "Unclaimed"
}
];
let menuOpen = false;
const menuSettings: PopupSettings = {
event: "click",
target: "view",
state: ({ state }) => (menuOpen = state)
};
let filter = $page.url.searchParams.get("filter");
let claimOption: ClaimOption = filter
? Object.keys(CLAIM_OPTIONS).includes(filter)
? (filter as ClaimOption)
: "all"
: "all";
const handleClick = (opt: unknown) => {
const option = opt as ClaimOption;
claimOption = option;
const newUrl = new URL($page.url);
if (option === "all") newUrl.searchParams.delete("filter");
else newUrl.searchParams.set("filter", option);
goto(newUrl, {
replaceState: true
});
};
const defaultOption = options[0];
const searchParam = "filter";
const prefix = "ion:filter";
</script>

<div class="flex flex-row space-x-4 pb-4">
<span class="relative">
<button
class="variant-ringed-primary chip"
class:variant-ghost-primary={claimOption !== "all"}
use:popup={menuSettings}
>
<span>{CLAIM_OPTIONS[claimOption]}</span>
<iconify-icon
class="arrow text-xs duration-300 ease-out"
class:rotate-180={menuOpen}
icon="ion:caret-down"
/>
</button>
<nav class="card list-nav p-4 shadow-xl" data-popup="view">
<ul>
{#each Object.entries(CLAIM_OPTIONS) as [optionKey, optionValue]}
<li>
<button class="list-option w-full" on:click={() => handleClick(optionKey)}>
{optionValue}
</button>
</li>
{/each}
</ul>
</nav>
</span>
</div>
<BaseChip {defaultOption} {options} {prefix} {searchParam} />
27 changes: 27 additions & 0 deletions src/lib/components/wishlists/chips/SortBy.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<script lang="ts">
import BaseChip from "./BaseChip.svelte";
const options: Option[] = [
{
value: "default",
displayValue: "Default Sort"
},
{
value: "price",
direction: "asc",
displayValue: "Price: Low to High"
},
{
value: "price",
direction: "desc",
displayValue: "Price: High to Low"
}
];
const defaultOption = options[0];
const searchParam = "sort";
const directionParam = "dir";
const prefix = "ion:swap-vertical";
</script>

<BaseChip {defaultOption} {directionParam} {options} {prefix} {searchParam} />
8 changes: 8 additions & 0 deletions src/routes/wishlists/[username]/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,16 @@ export const load: PageServerLoad = async ({ locals, params, depends, url }) =>
};
}

const orderBy: Prisma.ItemOrderByWithRelationInput = {};
const sort = url.searchParams.get("sort");
const direction = url.searchParams.get("dir");
if (sort === "price" && direction && (direction === "asc" || direction === "desc")) {
orderBy.price = direction;
}

const wishlistItems = await client.item.findMany({
where: search,
orderBy,
include: {
addedBy: {
select: {
Expand Down
12 changes: 9 additions & 3 deletions src/routes/wishlists/[username]/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import { crossfade } from "svelte/transition";
import { isInstalled } from "$lib/stores/is-installed";
import empty from "$lib/assets/no_wishes.svg";
import SortBy from "$lib/components/wishlists/chips/SortBy.svelte";
export let data: PageData;
Expand Down Expand Up @@ -84,10 +85,15 @@
<p class="text-2xl">No wishes yet</p>
</div>
{:else}
{#if !data.listOwner.isMe}
<ClaimFilterChip />
{/if}
<!-- chips -->
<div class="flex flex-row flex-wrap space-x-4">
{#if !data.listOwner.isMe}
<ClaimFilterChip />
{/if}
<SortBy />
</div>

<!-- items -->
<div class="flex flex-col space-y-4">
{#each data.items as item (item.id)}
<div
Expand Down

0 comments on commit d92b455

Please sign in to comment.