refactor(admin): drive media page from server data

This commit is contained in:
Justin Edmund 2025-10-07 05:31:02 -07:00
parent 3a588fdf89
commit 878c0ae248
2 changed files with 73 additions and 28 deletions

View file

@ -0,0 +1,60 @@
import type { Actions, PageServerLoad } from './$types'
import { adminFetchJson } from '$lib/server/admin/authenticated-fetch'
import type { Media } from '@prisma/client'
interface MediaResponse {
media: Media[]
pagination: {
page: number
totalPages: number
total: number
limit: number
hasNext: boolean
hasPrev: boolean
}
}
function buildQueryString(url: URL) {
const params = new URLSearchParams()
const page = url.searchParams.get('page')
if (page) params.set('page', page)
const limit = url.searchParams.get('limit')
if (limit) params.set('limit', limit)
const mimeType = url.searchParams.get('mimeType')
if (mimeType) params.set('mimeType', mimeType)
const publishedFilter = url.searchParams.get('publishedFilter')
if (publishedFilter) params.set('publishedFilter', publishedFilter)
const sort = url.searchParams.get('sort')
if (sort) params.set('sort', sort)
const search = url.searchParams.get('search')
if (search) params.set('search', search)
const albumId = url.searchParams.get('albumId')
if (albumId) params.set('albumId', albumId)
const unused = url.searchParams.get('unused')
if (unused) params.set('unused', unused)
return params.toString()
}
export const load = (async (event) => {
event.depends('admin:media')
const query = buildQueryString(event.url)
const base = query ? `/api/media?${query}` : '/api/media'
const data = await adminFetchJson<MediaResponse>(event, base)
return {
items: data.media,
pagination: data.pagination
}
}) satisfies PageServerLoad
export const actions = {} satisfies Actions

View file

@ -1,5 +1,4 @@
<script lang="ts"> <script lang="ts">
import { onMount } from 'svelte'
import { goto } from '$app/navigation' import { goto } from '$app/navigation'
import AdminPage from '$lib/components/admin/AdminPage.svelte' import AdminPage from '$lib/components/admin/AdminPage.svelte'
import AdminHeader from '$lib/components/admin/AdminHeader.svelte' import AdminHeader from '$lib/components/admin/AdminHeader.svelte'
@ -15,13 +14,16 @@
import ChevronDown from '$icons/chevron-down.svg?component' import ChevronDown from '$icons/chevron-down.svg?component'
import PlayIcon from '$icons/play.svg?component' import PlayIcon from '$icons/play.svg?component'
import type { Media } from '@prisma/client' import type { Media } from '@prisma/client'
import type { PageData } from './$types'
let media = $state<Media[]>([]) const { data } = $props<{ data: PageData }>()
let isLoading = $state(true)
let media = $state<Media[]>(data.items ?? [])
let isLoading = $state(false)
let error = $state('') let error = $state('')
let currentPage = $state(1) let currentPage = $state(data.pagination?.page ?? 1)
let totalPages = $state(1) let totalPages = $state(data.pagination?.totalPages ?? 1)
let total = $state(0) let total = $state(data.pagination?.total ?? (data.items?.length ?? 0))
// Only using grid view // Only using grid view
// Filter states // Filter states
@ -70,10 +72,6 @@
// Dropdown state // Dropdown state
let isDropdownOpen = $state(false) let isDropdownOpen = $state(false)
onMount(async () => {
await loadMedia()
})
// Watch for search query changes with debounce // Watch for search query changes with debounce
$effect(() => { $effect(() => {
if (searchQuery !== undefined) { if (searchQuery !== undefined) {
@ -87,9 +85,6 @@
async function loadMedia(page = 1) { async function loadMedia(page = 1) {
try { try {
isLoading = true isLoading = true
const auth = localStorage.getItem('admin_auth')
if (!auth) return
let url = `/api/media?page=${page}&limit=24` let url = `/api/media?page=${page}&limit=24`
if (filterType !== 'all') { if (filterType !== 'all') {
url += `&mimeType=${filterType}` url += `&mimeType=${filterType}`
@ -105,7 +100,7 @@
} }
const response = await fetch(url, { const response = await fetch(url, {
headers: { Authorization: `Basic ${auth}` } credentials: 'same-origin'
}) })
if (!response.ok) throw new Error('Failed to load media') if (!response.ok) throw new Error('Failed to load media')
@ -252,15 +247,12 @@
try { try {
isDeleting = true isDeleting = true
const auth = localStorage.getItem('admin_auth')
if (!auth) return
const response = await fetch('/api/media/bulk-delete', { const response = await fetch('/api/media/bulk-delete', {
method: 'DELETE', method: 'DELETE',
headers: { headers: {
Authorization: `Basic ${auth}`,
'Content-Type': 'application/json' 'Content-Type': 'application/json'
}, },
credentials: 'same-origin',
body: JSON.stringify({ body: JSON.stringify({
mediaIds: Array.from(selectedMediaIds) mediaIds: Array.from(selectedMediaIds)
}) })
@ -269,8 +261,7 @@
if (!response.ok) { if (!response.ok) {
throw new Error('Failed to delete media files') throw new Error('Failed to delete media files')
} }
await response.json()
const result = await response.json()
// Remove deleted media from the list // Remove deleted media from the list
media = media.filter((m) => !selectedMediaIds.has(m.id)) media = media.filter((m) => !selectedMediaIds.has(m.id))
@ -294,17 +285,14 @@
if (selectedMediaIds.size === 0) return if (selectedMediaIds.size === 0) return
try { try {
const auth = localStorage.getItem('admin_auth')
if (!auth) return
// Update each selected media item // Update each selected media item
const promises = Array.from(selectedMediaIds).map(async (mediaId) => { const promises = Array.from(selectedMediaIds).map(async (mediaId) => {
const response = await fetch(`/api/media/${mediaId}`, { const response = await fetch(`/api/media/${mediaId}`, {
method: 'PUT', method: 'PUT',
headers: { headers: {
Authorization: `Basic ${auth}`,
'Content-Type': 'application/json' 'Content-Type': 'application/json'
}, },
credentials: 'same-origin',
body: JSON.stringify({ isPhotography: true }) body: JSON.stringify({ isPhotography: true })
}) })
@ -335,17 +323,14 @@
if (selectedMediaIds.size === 0) return if (selectedMediaIds.size === 0) return
try { try {
const auth = localStorage.getItem('admin_auth')
if (!auth) return
// Update each selected media item // Update each selected media item
const promises = Array.from(selectedMediaIds).map(async (mediaId) => { const promises = Array.from(selectedMediaIds).map(async (mediaId) => {
const response = await fetch(`/api/media/${mediaId}`, { const response = await fetch(`/api/media/${mediaId}`, {
method: 'PUT', method: 'PUT',
headers: { headers: {
Authorization: `Basic ${auth}`,
'Content-Type': 'application/json' 'Content-Type': 'application/json'
}, },
credentials: 'same-origin',
body: JSON.stringify({ isPhotography: false }) body: JSON.stringify({ isPhotography: false })
}) })