diff --git a/frontend/src/lib/components/ui/select/select-trigger.svelte b/frontend/src/lib/components/ui/select/select-trigger.svelte index 181300f..f8d9c84 100644 --- a/frontend/src/lib/components/ui/select/select-trigger.svelte +++ b/frontend/src/lib/components/ui/select/select-trigger.svelte @@ -7,6 +7,7 @@ type $$Events = SelectPrimitive.TriggerEvents let className: $$Props['class'] = undefined + export let customIcon: any export { className as class } @@ -21,6 +22,12 @@ on:keydown>
- + {#if customIcon} + + {:else} + + {/if}
diff --git a/frontend/src/routes/(app)/links/+page.server.ts b/frontend/src/routes/(app)/links/+page.server.ts index dc2f4a9..40baa93 100644 --- a/frontend/src/routes/(app)/links/+page.server.ts +++ b/frontend/src/routes/(app)/links/+page.server.ts @@ -1,12 +1,22 @@ 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 { project, shortener, visitor } from '$lib/db/schema' export const load = (async (event) => { const user = event.locals.userObject const project_uuid = event.url.searchParams.get('project') const search = event.url.searchParams.get('search') + let sortBy = event.url.searchParams.get('sortBy') let page = parseInt(event.url.searchParams.get('page') ?? '1') let perPage = parseInt( event.url.searchParams.get('perPage') ?? '10', @@ -20,6 +30,14 @@ export const load = (async (event) => { perPage = 10 } + if ( + sortBy !== 'latest' && + sortBy !== 'oldest' && + sortBy !== 'most_visited' + ) { + sortBy = 'latest' + } + let project_id: number | undefined let selected_project: { value: null | string; label: string } = { value: null, @@ -41,16 +59,16 @@ export const load = (async (event) => { } } - const shorteners = db.query.shortener.findMany({ - extras: { + const shortenerColumns = getTableColumns(shortener) + const shorteners = db + .select({ + ...shortenerColumns, + projectName: project.name, fullcount: sql`count(*) over()`.as('fullcount'), - }, - with: { - visitor: true, - project: true, - }, - orderBy: (shortener, { desc }) => [desc(shortener.createdAt)], - where: (shortener, { eq, and, ilike }) => + visitorCount: sql`count(${visitor.id})`, + }) + .from(shortener) + .where( and( eq(shortener.userId, user.id), project_id ? eq(shortener.projectId, project_id) : undefined, @@ -58,9 +76,20 @@ export const load = (async (event) => { ? ilike(shortener.link, `%${decodeURI(search)}%`) : 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({ where: (project, { eq }) => eq(project.userId, user.id), @@ -78,5 +107,6 @@ export const load = (async (event) => { page, perPage, search, + sortBy, } }) satisfies PageServerLoad diff --git a/frontend/src/routes/(app)/links/+page.svelte b/frontend/src/routes/(app)/links/+page.svelte index 2067745..20ce8b5 100644 --- a/frontend/src/routes/(app)/links/+page.svelte +++ b/frontend/src/routes/(app)/links/+page.svelte @@ -24,6 +24,7 @@ QrCode, Check, ChevronsUpDown, + SortDescIcon, } from 'lucide-svelte' import Qr from '$lib/components/QR.svelte' @@ -85,14 +86,17 @@ $: selectedProjectUUID = data.selected_project.value let search: string | null = data.search 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 = ( selectedProjectUUID: string | null, page: number, perPage: any, search: string | null, + sortBy: any, ) => { let query = [`page=${page}`, `perPage=${perPage.value}`] if (selectedProjectUUID) { @@ -101,6 +105,9 @@ if (search) { query.push(`search=${encodeURI(search)}`) } + if (sortBy) { + query.push(`sortBy=${sortBy.value}`) + } goto(`/links?${query.join('&')}`) } @@ -162,6 +169,21 @@ + + + + + + + Sort By + {#each ['latest', 'oldest', 'most_visited'] as sortBy} + {sortBy} + {/each} + + + +
- {#if shortener.project} + {#if shortener.projectName} {shortener.project.name} + >{shortener.projectName} {/if} {#if shortener.active} @@ -241,7 +263,7 @@ class="flex h-8 items-center justify-center gap-1 rounded bg-secondary text-sm">
- {shortener.visitor.length} visits + {shortener.visitorCount} visits