import { db } from '$lib/server/db'; import { items, folders, categories, reservations } from '$lib/server/db/schema'; import { eq, and, isNull, inArray, sql } from 'drizzle-orm'; import { error } from '@sveltejs/kit'; import { processProperties } from '$lib/utils/propertyUtils'; import { getOrSeedHomeFolder } from '$lib/server/db/utils'; export const load = async ({ params, url }: { params: { path: string }, url: URL }) => { const pathSegments = params.path.split('/').filter(Boolean); let currentFolder = null; const breadcrumbs: any[] = []; // Start with Home folder as the root parent const homeFolder = await getOrSeedHomeFolder(); let parentId: string | null = homeFolder.id; for (const segment of pathSegments) { const folder = await db.select().from(folders) .where(and( eq(folders.name, decodeURIComponent(segment)), eq(folders.parentId, parentId) )) .limit(1); if (folder.length === 0) { throw error(404, 'Folder not found'); } currentFolder = folder[0]; parentId = currentFolder.id; const parentPath = breadcrumbs.map(b => b.name).join('/'); breadcrumbs.push({ name: currentFolder.name, url: `/folders${parentPath ? '/' + parentPath : ''}/${currentFolder.name}` }); } if (!currentFolder) { throw error(404, 'Folder not found'); } // Fetch subfolders const subfolders = await db.select().from(folders) .where(eq(folders.parentId, currentFolder.id)); // Fetch items const folderItems = await db.select({ id: items.id, name: items.name, count: items.count, categoryName: categories.name, categoryId: items.categoryId, folderId: items.folderId, tags: items.tags, properties: items.properties, reservedCount: sql`(SELECT COALESCE(SUM(count), 0) FROM reservations WHERE item_id = ${items.id})`.mapWith(Number) }) .from(items) .leftJoin(categories, eq(items.categoryId, categories.id)) .where(eq(items.folderId, currentFolder.id)); const allCategories = await db.select().from(categories); const allFolders = await db.select().from(folders); return { currentFolder, breadcrumbs, items: folderItems, subfolders, categories: allCategories, allFolders }; }; export const actions = { createFolder: async ({ request }: { request: Request }) => { const data = await request.formData(); const name = data.get('name') as string; const parentId = data.get('parentId') as string || null; await db.insert(folders).values({ name, parentId }); return { success: true }; }, createItem: async ({ request }: { request: Request }) => { const data = await request.formData(); const name = (data.get('name') as string) || null; const folderId = data.get('folderId') as string; const categoryId = data.get('categoryId') as string; const count = parseInt(data.get('count') as string) || 0; const properties = processProperties(data); await db.insert(items).values({ name, folderId: folderId, categoryId, count, properties }); return { success: true }; }, updateItem: async ({ request }: { request: Request }) => { const data = await request.formData(); const id = data.get('id') as string; const name = (data.get('name') as string) || null; const categoryId = data.get('categoryId') as string; const count = parseInt(data.get('count') as string) || 0; const folderId = data.get('folderId') as string; const properties = processProperties(data); const updateData: any = { name, categoryId, count, properties, updatedAt: new Date() }; if (folderId !== undefined) { updateData.folderId = folderId; } await db.update(items) .set(updateData) .where(eq(items.id, id)); return { success: true }; }, deleteItem: async ({ request }: { request: Request }) => { const data = await request.formData(); const id = data.get('id') as string; await db.delete(items).where(eq(items.id, id)); return { success: true }; }, moveItem: async ({ request }: { request: Request }) => { const data = await request.formData(); const id = data.get('id') as string; const folderId = data.get('folderId') as string; await db.update(items).set({ folderId: folderId }).where(eq(items.id, id)); return { success: true }; }, bulkDelete: async ({ request }: { request: Request }) => { const data = await request.formData(); const ids = JSON.parse(data.get('ids') as string); if (ids.length > 0) { await db.delete(items).where(inArray(items.id, ids)); } return { success: true }; }, bulkMove: async ({ request }: { request: Request }) => { const data = await request.formData(); const ids = JSON.parse(data.get('ids') as string); const folderId = data.get('folderId') as string; if (ids.length > 0) { await db.update(items).set({ folderId: folderId }).where(inArray(items.id, ids)); } return { success: true }; }, updateCount: async ({ request }: { request: Request }) => { const data = await request.formData(); const id = data.get('id') as string; const delta = parseInt(data.get('delta') as string) || 0; const item = await db.select({ count: items.count }).from(items).where(eq(items.id, id)).limit(1); if (item.length > 0) { const newCount = Math.max(0, (item[0].count || 0) + delta); await db.update(items).set({ count: newCount }).where(eq(items.id, id)); } return { success: true }; }, renameFolder: async ({ request }: { request: Request }) => { const data = await request.formData(); const id = data.get('id') as string; const name = data.get('name') as string; await db.update(folders) .set({ name }) .where(eq(folders.id, id)); return { success: true }; }, moveFolder: async ({ request }: { request: Request }) => { const data = await request.formData(); const id = data.get('id') as string; const parentId = data.get('folderId') as string; // Reusing folderId param name from item move // Prevent moving folder into itself or its children (basic check: not into itself) if (id === parentId) { // In a real app we'd check for cycles, but for now just prevent direct self-parenting return { success: false, error: "Cannot move folder into itself" }; } await db.update(folders) .set({ parentId: parentId || null }) .where(eq(folders.id, id)); return { success: true }; }, deleteFolder: async ({ request }: { request: Request }) => { const data = await request.formData(); const id = data.get('id') as string; // Note: This assumes cascading delete or that the user has emptied the folder. // If not cascading, this might fail. For now, we assume simple delete. await db.delete(folders).where(eq(folders.id, id)); return { success: true }; } };