mirror of
https://github.com/Xevion/xevion.dev.git
synced 2026-01-31 22:26:33 -06:00
refactor: use common TagChip, switch to SSR for admin pages, better error & logger handling
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
import type { PageServerLoad } from "./$types";
|
||||
import { apiFetch } from "$lib/api.server";
|
||||
import { addIconsToTags } from "$lib/server/tag-icons";
|
||||
import type { AdminProject, AdminTagWithCount } from "$lib/admin-types";
|
||||
|
||||
export const load: PageServerLoad = async ({ params, fetch }) => {
|
||||
const { id } = params;
|
||||
|
||||
// Fetch project and tags in parallel
|
||||
const [project, tagsWithCounts] = await Promise.all([
|
||||
apiFetch<AdminProject>(`/api/projects/${id}`, { fetch }).catch(() => null),
|
||||
apiFetch<AdminTagWithCount[]>("/api/tags", { fetch }),
|
||||
]);
|
||||
|
||||
// Add icons to tags
|
||||
const availableTags = await addIconsToTags(tagsWithCounts);
|
||||
|
||||
return {
|
||||
project,
|
||||
availableTags,
|
||||
};
|
||||
};
|
||||
@@ -1,56 +1,29 @@
|
||||
<script lang="ts">
|
||||
import { page } from "$app/stores";
|
||||
import { goto } from "$app/navigation";
|
||||
import { resolve } from "$app/paths";
|
||||
import ProjectForm from "$lib/components/admin/ProjectForm.svelte";
|
||||
import { getAdminProject, getAdminTags, updateAdminProject } from "$lib/api";
|
||||
import { updateAdminProject } from "$lib/api";
|
||||
import type {
|
||||
AdminProject,
|
||||
AdminTag,
|
||||
AdminTagWithCount,
|
||||
CreateProjectData,
|
||||
UpdateProjectData,
|
||||
CreateProjectData,
|
||||
TagWithIcon,
|
||||
} from "$lib/admin-types";
|
||||
|
||||
const projectId = $derived(($page.params as { id: string }).id);
|
||||
|
||||
let project = $state<AdminProject | null>(null);
|
||||
let tags = $state<AdminTag[]>([]);
|
||||
let loading = $state(true);
|
||||
|
||||
async function loadData() {
|
||||
try {
|
||||
const [projectData, tagsWithCounts] = await Promise.all([
|
||||
getAdminProject(projectId),
|
||||
getAdminTags(),
|
||||
]);
|
||||
|
||||
project = projectData;
|
||||
tags = tagsWithCounts.map(
|
||||
(t: AdminTagWithCount): AdminTag => ({
|
||||
id: t.id,
|
||||
slug: t.slug,
|
||||
name: t.name,
|
||||
createdAt: t.createdAt,
|
||||
}),
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("Failed to load data:", error);
|
||||
alert("Failed to load project");
|
||||
goto(resolve("/admin/projects"));
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
interface Props {
|
||||
data: {
|
||||
project: import("$lib/admin-types").AdminProject | null;
|
||||
availableTags: TagWithIcon[];
|
||||
};
|
||||
}
|
||||
|
||||
$effect(() => {
|
||||
loadData();
|
||||
});
|
||||
let { data }: Props = $props();
|
||||
|
||||
async function handleSubmit(formData: CreateProjectData) {
|
||||
if (!data.project) return;
|
||||
|
||||
async function handleSubmit(data: CreateProjectData) {
|
||||
const updateData: UpdateProjectData = {
|
||||
...data,
|
||||
id: projectId,
|
||||
...formData,
|
||||
id: data.project.id,
|
||||
};
|
||||
await updateAdminProject(updateData);
|
||||
goto(resolve("/admin/projects"));
|
||||
@@ -71,23 +44,21 @@
|
||||
</div>
|
||||
|
||||
<!-- Form -->
|
||||
{#if loading}
|
||||
<div class="text-center py-12 text-admin-text-muted">Loading...</div>
|
||||
{:else if !project}
|
||||
{#if !data.project}
|
||||
<div class="text-center py-12">
|
||||
<p class="text-admin-text-muted mb-4">Project not found</p>
|
||||
<a
|
||||
href={resolve("/admin/projects")}
|
||||
class="text-admin-accent hover:text-admin-accent-hover"
|
||||
>
|
||||
← Back to projects
|
||||
Back to projects
|
||||
</a>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="rounded-lg border border-admin-border bg-admin-surface p-6">
|
||||
<ProjectForm
|
||||
{project}
|
||||
availableTags={tags}
|
||||
project={data.project}
|
||||
availableTags={data.availableTags}
|
||||
onsubmit={handleSubmit}
|
||||
submitLabel="Update Project"
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user