Skip to content

Commit

Permalink
feat: update browse page to support multiple states and types (#162)
Browse files Browse the repository at this point in the history
feat: update browse schema and page to support multiple states and types
  • Loading branch information
davidemarcoli authored Nov 1, 2024
1 parent b295113 commit cc3bcdd
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 47 deletions.
37 changes: 19 additions & 18 deletions src/lib/schema/browse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,24 @@ import { z } from 'zod';

export const schema = z.object({
state: z
.enum([
'',
'Unknown',
'Unreleased',
'Ongoing',
'Requested',
'Indexed',
'Scraped',
'Downloaded',
'Symlinked',
'Completed',
'PartiallyCompleted',
'Failed'
])
.default(''),
type: z.enum(['movie', 'show', 'movie,show']).default('movie,show'),
.array(
z.enum([
'',
'Unknown',
'Unreleased',
'Ongoing',
'Requested',
'Indexed',
'Scraped',
'Downloaded',
'Symlinked',
'Completed',
'PartiallyCompleted',
'Failed'
])
)
.default([]),
type: z.array(z.enum(['movie', 'show'])).default(['movie', 'show']),
sort: z.enum(['date_desc', 'date_asc', 'title_asc', 'title_desc']).default('date_desc')
});

Expand All @@ -38,8 +40,7 @@ export const states = {

export const types = {
movie: 'Movies',
show: 'Shows',
'movie,show': 'Movies & Shows'
show: 'Shows'
};

export const sortOptions = {
Expand Down
76 changes: 60 additions & 16 deletions src/routes/browse/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { page } from '$app/stores';
import Header from '$lib/components/header.svelte';
import * as Pagination from '$lib/components/ui/pagination';
import { ItemsService } from '$lib/client';
Expand All @@ -12,12 +14,15 @@
import { states, types, sortOptions } from '$lib/schema/browse';
import type { RivenItem } from '$lib/types';
import type { Selected } from 'bits-ui';
export let data;
let items = data.itemsData.items;
let totalItems = data.itemsData.total_items;
let pageNumber = data.page;
let pageNumber = $page.url.searchParams.get('page')
? parseInt($page.url.searchParams.get('page')!)
: 1;
const limit = 24;
$: totalDataItems = writable(totalItems);
Expand All @@ -28,38 +33,60 @@
const { form: formData, enhance } = form;
$: selectedState = {
label: states[$formData.state],
value: $formData.state
};
// Initialize form data from URL params
$: {
const params = $page.url.searchParams;
$formData.state =
params
.get('state')
?.split(',')
.map((state) => state as keyof typeof states) || $formData.state;
$formData.type =
params
.get('type')
?.split(',')
.map((type) => type as keyof typeof types) || $formData.type;
$formData.sort = (params.get('sort') as keyof typeof sortOptions) || $formData.sort;
}
$: selectedType = {
label: types[$formData.type],
value: $formData.type
};
// Update selected values based on form data
$: selectedState = $formData.state.map((state) => ({
label: states[state],
value: state
}));
$: selectedType = $formData.type.map((type) => ({
label: types[type],
value: type
}));
$: selectedSort = {
label: sortOptions[$formData.sort],
value: $formData.sort
};
async function fetchItems() {
const url = new URL(window.location.href);
url.searchParams.set('page', pageNumber.toString());
url.searchParams.set('state', $formData.state.join(','));
url.searchParams.set('type', $formData.type.join(','));
url.searchParams.set('sort', $formData.sort);
goto(url.toString(), { replaceState: true });
let { data } = await ItemsService.getItems({
query: {
page: pageNumber,
sort: $formData.sort,
limit,
type: $formData.type,
states: $formData.state
type: $formData.type.join(','),
states: $formData.state.join(',')
}
});
if (data) {
items = data.items as unknown as RivenItem[];
totalItems = data.total_items;
$totalDataItems = totalItems;
} else {
//pass
}
}
Expand All @@ -74,6 +101,20 @@
: ($formData.sort.replace('desc', 'asc') as keyof typeof sortOptions);
fetchItems();
}
function mapSelectedStates(selectedStates: Selected<string>[]) {
return selectedStates
.values()
.map((v) => v.value as keyof typeof states)
.toArray();
}
function mapSelectedTypes(selectedTypes: Selected<string>[]) {
return selectedTypes
.values()
.map((v) => v.value as keyof typeof types)
.toArray();
}
</script>

<svelte:head>
Expand All @@ -97,10 +138,11 @@
selected={selectedState}
onSelectedChange={(s) => {
if (s) {
$formData.state = s.value;
$formData.state = mapSelectedStates(s);
handleFilterChange();
}
}}
multiple
>
<Select.Input name={attrs.name} />
<Select.Trigger {...attrs} class="w-[180px]">
Expand All @@ -123,10 +165,11 @@
selected={selectedType}
onSelectedChange={(s) => {
if (s) {
$formData.type = s.value;
$formData.type = mapSelectedTypes(s);
handleFilterChange();
}
}}
multiple
>
<Select.Input name={attrs.name} />
<Select.Trigger {...attrs} class="w-[180px]">
Expand Down Expand Up @@ -187,10 +230,11 @@
{/each}
</div>

<div class="mt-8">
<div class="my-8">
<Pagination.Root
count={$totalDataItems}
perPage={limit}
page={pageNumber}
let:pages
let:currentPage
onPageChange={(page) => {
Expand Down
31 changes: 25 additions & 6 deletions src/routes/browse/+page.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,33 @@
import { superValidate } from 'sveltekit-superforms/client';
import { schema } from '$lib/schema/browse';
import { ItemsService } from '$lib/client';
import { ItemsService, type States } from '$lib/client';
import { zod } from 'sveltekit-superforms/adapters';
import type { PageLoad } from '../$types';
import type { RivenGetItemsResponse } from '$lib/types';

export const load = (async () => {
export const load = (async ({ url }) => {
const form = await superValidate({}, zod(schema));
const page = 1;
const limit = 12;
let page = 1;
const limit = 24;

if (url.searchParams.has('page')) {
page = parseInt(url.searchParams.get('page') as string);
}
if (url.searchParams.has('sort')) {
form.data.sort = url.searchParams.get('sort') as
| 'date_desc'
| 'date_asc'
| 'title_asc'
| 'title_desc';
}
if (url.searchParams.has('type')) {
form.data.type = url.searchParams.get('type')?.split(',') as ['movie', 'show'];
}
if (url.searchParams.has('state')) {
form.data.state = url.searchParams.get('state')?.split(',') as States[];
} else {
form.data.state = [''];
}

async function getItems(): Promise<RivenGetItemsResponse> {
try {
Expand All @@ -17,8 +36,8 @@ export const load = (async () => {
page,
sort: form.data.sort,
limit,
type: form.data.type,
states: form.data.state
type: form.data.type.join(','),
states: form.data.state.join(',')
}
});

Expand Down
12 changes: 5 additions & 7 deletions src/routes/summary/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,23 @@
{
title: 'Total Items',
value: data.stats?.total_items || 0,
refTo: '/library'
refTo: '/browse'
},
{
title: 'Total Movies',
value: data.stats?.total_movies || 0,
refTo: '/library?types=movie'
refTo: '/browse?type=movie'
},
{
title: 'Total Shows',
value: data.stats?.total_shows || 0,
refTo: '/library?types=show'
refTo: '/browse?type=show'
},
{
title: 'Incomplete Items',
value: data.stats?.incomplete_items || 0,
refTo:
'/library?states=Unknown%2CRequested%2CIndexed%2CScraped%2CDownloaded%2CSymlinked%2CFailed%2CPartiallyCompleted'
'/browse?state=Unknown%2CRequested%2CIndexed%2CScraped%2CDownloaded%2CSymlinked%2CFailed%2CPartiallyCompleted'
}
];
Expand Down Expand Up @@ -218,9 +218,7 @@
</Card.Header>
<Card.Content>
<p class="text-lg lg:text-3xl">{data.stats.states[state]}</p>
<a href={`/library?states=${state}`} class="text-sm text-muted-foreground">
See items
</a>
<a href={`/browse?state=${state}`} class="text-sm text-muted-foreground"> See items </a>
</Card.Content>
</Card.Root>
{/each}
Expand Down

0 comments on commit cc3bcdd

Please sign in to comment.