added sorting to links page

pull/3/head
TZGyn 2 years ago
parent 5878a18bfa
commit 5b3336142c
Signed by: TZGyn
GPG Key ID: 122EAF77AE81FD4A

@ -7,6 +7,7 @@
type $$Events = SelectPrimitive.TriggerEvents type $$Events = SelectPrimitive.TriggerEvents
let className: $$Props['class'] = undefined let className: $$Props['class'] = undefined
export let customIcon: any
export { className as class } export { className as class }
</script> </script>
@ -21,6 +22,12 @@
on:keydown> on:keydown>
<slot {builder} /> <slot {builder} />
<div> <div>
{#if customIcon}
<svelte:component
this={customIcon}
class="h-4 w-4 opacity-50" />
{:else}
<ChevronDown class="h-4 w-4 opacity-50" /> <ChevronDown class="h-4 w-4 opacity-50" />
{/if}
</div> </div>
</SelectPrimitive.Trigger> </SelectPrimitive.Trigger>

@ -1,12 +1,22 @@
import { db } from '$lib/db' import { db } from '$lib/db'
import { sql } from 'drizzle-orm' import {
and,
asc,
desc,
eq,
getTableColumns,
ilike,
sql,
} from 'drizzle-orm'
import type { PageServerLoad } from './$types' import type { PageServerLoad } from './$types'
import { project, shortener, visitor } from '$lib/db/schema'
export const load = (async (event) => { export const load = (async (event) => {
const user = event.locals.userObject const user = event.locals.userObject
const project_uuid = event.url.searchParams.get('project') const project_uuid = event.url.searchParams.get('project')
const search = event.url.searchParams.get('search') const search = event.url.searchParams.get('search')
let sortBy = event.url.searchParams.get('sortBy')
let page = parseInt(event.url.searchParams.get('page') ?? '1') let page = parseInt(event.url.searchParams.get('page') ?? '1')
let perPage = parseInt( let perPage = parseInt(
event.url.searchParams.get('perPage') ?? '10', event.url.searchParams.get('perPage') ?? '10',
@ -20,6 +30,14 @@ export const load = (async (event) => {
perPage = 10 perPage = 10
} }
if (
sortBy !== 'latest' &&
sortBy !== 'oldest' &&
sortBy !== 'most_visited'
) {
sortBy = 'latest'
}
let project_id: number | undefined let project_id: number | undefined
let selected_project: { value: null | string; label: string } = { let selected_project: { value: null | string; label: string } = {
value: null, value: null,
@ -41,16 +59,16 @@ export const load = (async (event) => {
} }
} }
const shorteners = db.query.shortener.findMany({ const shortenerColumns = getTableColumns(shortener)
extras: { const shorteners = db
.select({
...shortenerColumns,
projectName: project.name,
fullcount: sql<number>`count(*) over()`.as('fullcount'), fullcount: sql<number>`count(*) over()`.as('fullcount'),
}, visitorCount: sql<number>`count(${visitor.id})`,
with: { })
visitor: true, .from(shortener)
project: true, .where(
},
orderBy: (shortener, { desc }) => [desc(shortener.createdAt)],
where: (shortener, { eq, and, ilike }) =>
and( and(
eq(shortener.userId, user.id), eq(shortener.userId, user.id),
project_id ? eq(shortener.projectId, project_id) : undefined, project_id ? eq(shortener.projectId, project_id) : undefined,
@ -58,9 +76,20 @@ export const load = (async (event) => {
? ilike(shortener.link, `%${decodeURI(search)}%`) ? ilike(shortener.link, `%${decodeURI(search)}%`)
: undefined, : undefined,
), ),
offset: perPage * (page - 1), )
limit: perPage, .leftJoin(visitor, eq(shortener.id, visitor.shortenerId))
}) .leftJoin(project, eq(shortener.projectId, project.id))
.groupBy(shortener.id, project.id)
.offset(perPage * (page - 1))
.limit(perPage)
if (sortBy === 'latest') {
shorteners.orderBy(desc(shortener.createdAt))
} else if (sortBy === 'oldest') {
shorteners.orderBy(asc(shortener.createdAt))
} else if (sortBy === 'most_visited') {
shorteners.orderBy(sql`count(${visitor.id}) desc`)
}
const projects = db.query.project.findMany({ const projects = db.query.project.findMany({
where: (project, { eq }) => eq(project.userId, user.id), where: (project, { eq }) => eq(project.userId, user.id),
@ -78,5 +107,6 @@ export const load = (async (event) => {
page, page,
perPage, perPage,
search, search,
sortBy,
} }
}) satisfies PageServerLoad }) satisfies PageServerLoad

@ -24,6 +24,7 @@
QrCode, QrCode,
Check, Check,
ChevronsUpDown, ChevronsUpDown,
SortDescIcon,
} from 'lucide-svelte' } from 'lucide-svelte'
import Qr from '$lib/components/QR.svelte' import Qr from '$lib/components/QR.svelte'
@ -85,14 +86,17 @@
$: selectedProjectUUID = data.selected_project.value $: selectedProjectUUID = data.selected_project.value
let search: string | null = data.search let search: string | null = data.search
let searchUpdateTimeout: any let searchUpdateTimeout: any
let sortBy: any = { label: data.sortBy, value: data.sortBy }
$: browser && updateUrl(selectedProjectUUID, page, perPage, search) $: browser &&
updateUrl(selectedProjectUUID, page, perPage, search, sortBy)
const updateUrl = ( const updateUrl = (
selectedProjectUUID: string | null, selectedProjectUUID: string | null,
page: number, page: number,
perPage: any, perPage: any,
search: string | null, search: string | null,
sortBy: any,
) => { ) => {
let query = [`page=${page}`, `perPage=${perPage.value}`] let query = [`page=${page}`, `perPage=${perPage.value}`]
if (selectedProjectUUID) { if (selectedProjectUUID) {
@ -101,6 +105,9 @@
if (search) { if (search) {
query.push(`search=${encodeURI(search)}`) query.push(`search=${encodeURI(search)}`)
} }
if (sortBy) {
query.push(`sortBy=${sortBy.value}`)
}
goto(`/links?${query.join('&')}`) goto(`/links?${query.join('&')}`)
} }
@ -162,6 +169,21 @@
</Command.Root> </Command.Root>
</Popover.Content> </Popover.Content>
</Popover.Root> </Popover.Root>
<Select.Root bind:selected={sortBy}>
<Select.Trigger class="w-[180px]" customIcon={SortDescIcon}>
<Select.Value placeholder="Sort By" />
</Select.Trigger>
<Select.Content>
<Select.Group>
<Select.Label>Sort By</Select.Label>
{#each ['latest', 'oldest', 'most_visited'] as sortBy}
<Select.Item value={sortBy} label={sortBy}
>{sortBy}</Select.Item>
{/each}
</Select.Group>
</Select.Content>
<Select.Input name="favoriteFruit" />
</Select.Root>
<Input <Input
type="text" type="text"
placeholder="search" placeholder="search"
@ -212,9 +234,9 @@
<ExternalLink size={16} /> <ExternalLink size={16} />
</div> </div>
<div class="flex gap-4"> <div class="flex gap-4">
{#if shortener.project} {#if shortener.projectName}
<Badge variant="secondary" <Badge variant="secondary"
>{shortener.project.name}</Badge> >{shortener.projectName}</Badge>
{/if} {/if}
<Badge variant="outline" class="flex gap-2"> <Badge variant="outline" class="flex gap-2">
{#if shortener.active} {#if shortener.active}
@ -241,7 +263,7 @@
class="flex h-8 items-center justify-center gap-1 rounded bg-secondary text-sm"> class="flex h-8 items-center justify-center gap-1 rounded bg-secondary text-sm">
<BarChart size={20} /> <BarChart size={20} />
<div> <div>
{shortener.visitor.length} visits {shortener.visitorCount} visits
</div> </div>
</Button> </Button>
<Button <Button

Loading…
Cancel
Save