chore: mark completion of sessions and SWOT components in devbook.md; add @hello-pangea/dnd dependency for drag & drop functionality

This commit is contained in:
Julien Froidefond
2025-11-27 13:15:56 +01:00
parent 27e409fb76
commit 628d64a5c6
12 changed files with 1398 additions and 45 deletions

215
src/services/sessions.ts Normal file
View File

@@ -0,0 +1,215 @@
import { prisma } from '@/services/database';
import type { SwotCategory } from '@prisma/client';
// ============================================
// Session CRUD
// ============================================
export async function getSessionsByUserId(userId: string) {
return prisma.session.findMany({
where: { userId },
include: {
_count: {
select: {
items: true,
actions: true,
},
},
},
orderBy: { updatedAt: 'desc' },
});
}
export async function getSessionById(sessionId: string, userId: string) {
return prisma.session.findFirst({
where: {
id: sessionId,
userId,
},
include: {
items: {
orderBy: { order: 'asc' },
},
actions: {
include: {
links: {
include: {
swotItem: true,
},
},
},
orderBy: { createdAt: 'asc' },
},
},
});
}
export async function createSession(userId: string, data: { title: string; collaborator: string }) {
return prisma.session.create({
data: {
...data,
userId,
},
});
}
export async function updateSession(
sessionId: string,
userId: string,
data: { title?: string; collaborator?: string }
) {
return prisma.session.updateMany({
where: { id: sessionId, userId },
data,
});
}
export async function deleteSession(sessionId: string, userId: string) {
return prisma.session.deleteMany({
where: { id: sessionId, userId },
});
}
// ============================================
// SWOT Items CRUD
// ============================================
export async function createSwotItem(
sessionId: string,
data: { content: string; category: SwotCategory }
) {
// Get max order for this category
const maxOrder = await prisma.swotItem.aggregate({
where: { sessionId, category: data.category },
_max: { order: true },
});
return prisma.swotItem.create({
data: {
...data,
sessionId,
order: (maxOrder._max.order ?? -1) + 1,
},
});
}
export async function updateSwotItem(
itemId: string,
data: { content?: string; category?: SwotCategory; order?: number }
) {
return prisma.swotItem.update({
where: { id: itemId },
data,
});
}
export async function deleteSwotItem(itemId: string) {
return prisma.swotItem.delete({
where: { id: itemId },
});
}
export async function reorderSwotItems(
sessionId: string,
category: SwotCategory,
itemIds: string[]
) {
const updates = itemIds.map((id, index) =>
prisma.swotItem.update({
where: { id },
data: { order: index },
})
);
return prisma.$transaction(updates);
}
export async function moveSwotItem(
itemId: string,
newCategory: SwotCategory,
newOrder: number
) {
return prisma.swotItem.update({
where: { id: itemId },
data: {
category: newCategory,
order: newOrder,
},
});
}
// ============================================
// Actions CRUD
// ============================================
export async function createAction(
sessionId: string,
data: {
title: string;
description?: string;
priority?: number;
linkedItemIds: string[];
}
) {
return prisma.action.create({
data: {
title: data.title,
description: data.description,
priority: data.priority ?? 0,
sessionId,
links: {
create: data.linkedItemIds.map((swotItemId) => ({
swotItemId,
})),
},
},
include: {
links: {
include: {
swotItem: true,
},
},
},
});
}
export async function updateAction(
actionId: string,
data: {
title?: string;
description?: string;
priority?: number;
status?: string;
dueDate?: Date | null;
}
) {
return prisma.action.update({
where: { id: actionId },
data,
});
}
export async function deleteAction(actionId: string) {
return prisma.action.delete({
where: { id: actionId },
});
}
export async function linkItemToAction(actionId: string, swotItemId: string) {
return prisma.actionLink.create({
data: {
actionId,
swotItemId,
},
});
}
export async function unlinkItemFromAction(actionId: string, swotItemId: string) {
return prisma.actionLink.deleteMany({
where: {
actionId,
swotItemId,
},
});
}