Files
portal/src/routes/(protected)/(user)/proclamations/+page.svelte
T

113 lines
3.4 KiB
Svelte

<script lang="ts">
import { goto } from '$app/navigation';
import type { PageProps } from './$types';
let { data }: PageProps = $props();
function displayCategoryName(category: { name: string; displayName?: string }) {
return category.displayName ?? category.name;
}
let search = $state('');
let categoryId: number | null = $state(null);
let initialized = $state(false);
$effect(() => {
if (!initialized) {
search = data.search;
categoryId = data.categoryId;
initialized = true;
}
});
function applyFilters() {
const params = new URLSearchParams();
if (search) params.set('search', search);
if (categoryId) params.set('category', String(categoryId));
goto(`/proclamations?${params.toString()}`, { replaceState: true });
}
function clearFilters() {
search = '';
categoryId = null;
goto('/proclamations', { replaceState: true });
}
</script>
<div class="flex h-full min-h-0 flex-col gap-6 p-6">
<h1 class="text-2xl font-semibold text-gray-900">Proclamations</h1>
<!-- Filters -->
<div class="flex flex-wrap items-end gap-4">
<div>
<label for="search" class="block text-sm font-medium text-gray-700">Search</label>
<input
type="text"
id="search"
bind:value={search}
placeholder="Search by name..."
class="mt-1 rounded-lg border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500"
onkeydown={(e) => e.key === 'Enter' && applyFilters()}
/>
</div>
<div>
<label for="category" class="block text-sm font-medium text-gray-700">Category</label>
<select
id="category"
bind:value={categoryId}
onchange={applyFilters}
class="mt-1 rounded-lg border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500"
>
<option value={null}>All Categories</option>
{#each data.categories as cat}
<option value={cat.id}>{displayCategoryName(cat)}</option>
{/each}
</select>
</div>
<button
type="button"
class="rounded-lg bg-blue-600 px-4 py-2 font-medium text-white transition-colors hover:bg-blue-700"
onclick={applyFilters}
>
Search
</button>
{#if data.search || data.categoryId}
<button
type="button"
class="rounded-lg border border-gray-300 px-4 py-2 text-sm font-medium text-gray-700 transition-colors hover:bg-gray-50"
onclick={clearFilters}
>
Clear
</button>
{/if}
</div>
<!-- Results -->
{#if data.proclamations.length > 0}
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
{#each data.proclamations as proclamation}
<a
href="/proclamations/{proclamation.id}"
class="flex flex-col rounded-lg border border-gray-200 bg-white p-5 shadow-sm transition-shadow hover:shadow-md"
>
<h2 class="text-lg font-medium text-gray-900">{proclamation.name}</h2>
<p class="mt-1 text-sm text-gray-500">{displayCategoryName(proclamation.category)}</p>
<div class="mt-auto flex items-center justify-between pt-4">
<span class="text-sm text-purple-600">
{proclamation.solfeggioFrequency.value} Hz &mdash;
{proclamation.solfeggioFrequency.name}
</span>
<span class="font-semibold text-gray-900">
${proclamation.price.toFixed(2)}
</span>
</div>
</a>
{/each}
</div>
{:else}
<div class="flex flex-1 items-center justify-center">
<p class="text-lg text-gray-500">No proclamations found.</p>
</div>
{/if}
</div>