Restructure route organization
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
import type { PageServerLoad } from './$types';
|
||||
import { error } from '@sveltejs/kit';
|
||||
import { prisma } from '$lib/db';
|
||||
import { canAccessAdmin } from '$lib/svelte-admin/roles';
|
||||
|
||||
export const load: PageServerLoad = async ({ params, parent }) => {
|
||||
const parentData = typeof parent === 'function' ? await parent() : {};
|
||||
const userRoleId = (parentData as { userRoleId?: number }).userRoleId ?? null;
|
||||
if (userRoleId != null && !canAccessAdmin(userRoleId)) {
|
||||
throw error(403, 'not authorized');
|
||||
}
|
||||
|
||||
const proclamation = await prisma.proclamation.findUnique({
|
||||
where: { id: params.id },
|
||||
include: {
|
||||
solfeggioFrequency: true,
|
||||
category: { include: { parent: true } }
|
||||
}
|
||||
});
|
||||
|
||||
if (!proclamation) {
|
||||
throw error(404, 'Proclamation not found');
|
||||
}
|
||||
|
||||
return { proclamation };
|
||||
};
|
||||
@@ -0,0 +1,45 @@
|
||||
<script lang="ts">
|
||||
import type { PageProps } from './$types';
|
||||
|
||||
let { data }: PageProps = $props();
|
||||
|
||||
const categoryBreadcrumb = $derived(
|
||||
data.proclamation.category.parent
|
||||
? `${data.proclamation.category.parent.name} / ${data.proclamation.category.name}`
|
||||
: data.proclamation.category.name
|
||||
);
|
||||
</script>
|
||||
|
||||
<div class="mx-auto flex h-full min-h-0 w-full max-w-3xl flex-col gap-6 p-6">
|
||||
<a
|
||||
href="/proclamations"
|
||||
class="text-sm text-blue-600 hover:text-blue-800 hover:underline"
|
||||
>
|
||||
← Back to Proclamations
|
||||
</a>
|
||||
|
||||
<div>
|
||||
<h1 class="text-2xl font-semibold text-gray-900">{data.proclamation.name}</h1>
|
||||
<p class="mt-1 text-sm text-gray-500">{categoryBreadcrumb}</p>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-wrap gap-4">
|
||||
<div class="rounded-lg border border-purple-200 bg-purple-50 px-4 py-2">
|
||||
<p class="text-xs font-medium text-purple-600">Frequency</p>
|
||||
<p class="text-sm font-semibold text-purple-900">
|
||||
{data.proclamation.solfeggioFrequency.value} Hz —
|
||||
{data.proclamation.solfeggioFrequency.name}
|
||||
</p>
|
||||
</div>
|
||||
<div class="rounded-lg border border-gray-200 bg-gray-50 px-4 py-2">
|
||||
<p class="text-xs font-medium text-gray-500">Price</p>
|
||||
<p class="text-sm font-semibold text-gray-900">
|
||||
${data.proclamation.price.toFixed(2)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="prose max-w-none rounded-lg border border-gray-200 bg-white p-6">
|
||||
{@html data.proclamation.content}
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,66 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { isHttpError } from '@sveltejs/kit';
|
||||
import { mockProclamation } from '$lib/test-utils';
|
||||
|
||||
vi.mock('$lib/db', () => ({
|
||||
prisma: {
|
||||
proclamation: { findUnique: vi.fn() }
|
||||
}
|
||||
}));
|
||||
|
||||
import { prisma } from '$lib/db';
|
||||
import { load } from './+page.server';
|
||||
|
||||
const findUnique = prisma.proclamation.findUnique as ReturnType<typeof vi.fn>;
|
||||
|
||||
describe('(protected)/admin/proclamations/[id] page server load', () => {
|
||||
beforeEach(() => {
|
||||
findUnique.mockReset();
|
||||
});
|
||||
|
||||
it('throws 404 when proclamation is not found', async () => {
|
||||
findUnique.mockResolvedValue(null);
|
||||
|
||||
const err = await Promise.resolve(
|
||||
load({ params: { id: 'nonexistent' } } as any)
|
||||
).catch((e: unknown) => e);
|
||||
expect(isHttpError(err, 404)).toBe(true);
|
||||
});
|
||||
|
||||
it('returns proclamation when found', async () => {
|
||||
const proclamation = mockProclamation();
|
||||
findUnique.mockResolvedValue(proclamation);
|
||||
|
||||
const result = (await load({ params: { id: 'proc-1' } } as any)) as any;
|
||||
expect(result.proclamation).toEqual(proclamation);
|
||||
});
|
||||
|
||||
it('queries by params.id with frequency and category (including parent)', async () => {
|
||||
findUnique.mockResolvedValue(mockProclamation());
|
||||
|
||||
await load({ params: { id: 'proc-1' } } as any);
|
||||
|
||||
expect(findUnique).toHaveBeenCalledWith({
|
||||
where: { id: 'proc-1' },
|
||||
include: {
|
||||
solfeggioFrequency: true,
|
||||
category: { include: { parent: true } }
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('returns proclamation with parent category when present', async () => {
|
||||
const proclamation = mockProclamation({
|
||||
category: {
|
||||
id: 2,
|
||||
name: 'Inner Healing',
|
||||
parentId: 1,
|
||||
parent: { id: 1, name: 'Healing', parentId: null }
|
||||
}
|
||||
});
|
||||
findUnique.mockResolvedValue(proclamation);
|
||||
|
||||
const result = (await load({ params: { id: 'proc-1' } } as any)) as any;
|
||||
expect(result.proclamation.category.parent.name).toBe('Healing');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user