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