feat: enhance session management by resolving collaborators to users and integrating CollaboratorDisplay component across motivators and sessions pages

This commit is contained in:
Julien Froidefond
2025-11-28 11:04:58 +01:00
parent 941151553f
commit eaeb1335fa
10 changed files with 237 additions and 33 deletions

View File

@@ -60,6 +60,53 @@ export async function getUserByEmail(email: string) {
});
}
// Check if string looks like an email
function isEmail(str: string): boolean {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(str);
}
export interface ResolvedCollaborator {
raw: string; // Original value (name or email)
matchedUser: {
id: string;
email: string;
name: string | null;
} | null;
}
// Resolve collaborator string to user - try email first, then name
export async function resolveCollaborator(collaborator: string): Promise<ResolvedCollaborator> {
const trimmed = collaborator.trim();
// 1. Try email match first
if (isEmail(trimmed)) {
const user = await prisma.user.findUnique({
where: { email: trimmed.toLowerCase() },
select: { id: true, email: true, name: true },
});
if (user) {
return { raw: collaborator, matchedUser: user };
}
}
// 2. Fallback: try matching by name (case-insensitive via raw query for SQLite)
// SQLite LIKE is case-insensitive by default for ASCII
const users = await prisma.user.findMany({
where: {
name: { not: null },
},
select: { id: true, email: true, name: true },
});
const normalizedSearch = trimmed.toLowerCase();
const userByName = users.find(
(u) => u.name?.toLowerCase() === normalizedSearch
) || null;
return { raw: collaborator, matchedUser: userByName };
}
export async function getUserById(id: string) {
return prisma.user.findUnique({
where: { id },

View File

@@ -1,4 +1,5 @@
import { prisma } from '@/services/database';
import { resolveCollaborator } from '@/services/auth';
import type { ShareRole, MotivatorType } from '@prisma/client';
// ============================================
@@ -56,9 +57,19 @@ export async function getMotivatorSessionsByUserId(userId: string) {
sharedAt: s.createdAt,
}));
return [...ownedWithRole, ...sharedWithRole].sort(
const allSessions = [...ownedWithRole, ...sharedWithRole].sort(
(a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime()
);
// Resolve participants to users
const sessionsWithResolved = await Promise.all(
allSessions.map(async (s) => ({
...s,
resolvedParticipant: await resolveCollaborator(s.participant),
}))
);
return sessionsWithResolved;
}
export async function getMotivatorSessionById(sessionId: string, userId: string) {
@@ -92,7 +103,10 @@ export async function getMotivatorSessionById(sessionId: string, userId: string)
const role = isOwner ? ('OWNER' as const) : share?.role || ('VIEWER' as const);
const canEdit = isOwner || role === 'EDITOR';
return { ...session, isOwner, role, canEdit };
// Resolve participant to user if it's an email
const resolvedParticipant = await resolveCollaborator(session.participant);
return { ...session, isOwner, role, canEdit, resolvedParticipant };
}
// Check if user can access session (owner or shared)

View File

@@ -1,4 +1,5 @@
import { prisma } from '@/services/database';
import { resolveCollaborator } from '@/services/auth';
import type { SwotCategory, ShareRole } from '@prisma/client';
// ============================================
@@ -58,9 +59,19 @@ export async function getSessionsByUserId(userId: string) {
sharedAt: s.createdAt,
}));
return [...ownedWithRole, ...sharedWithRole].sort(
const allSessions = [...ownedWithRole, ...sharedWithRole].sort(
(a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime()
);
// Resolve collaborators to users
const sessionsWithResolved = await Promise.all(
allSessions.map(async (s) => ({
...s,
resolvedCollaborator: await resolveCollaborator(s.collaborator),
}))
);
return sessionsWithResolved;
}
export async function getSessionById(sessionId: string, userId: string) {
@@ -104,7 +115,10 @@ export async function getSessionById(sessionId: string, userId: string) {
const role = isOwner ? ('OWNER' as const) : share?.role || ('VIEWER' as const);
const canEdit = isOwner || role === 'EDITOR';
return { ...session, isOwner, role, canEdit };
// Resolve collaborator to user if it's an email
const resolvedCollaborator = await resolveCollaborator(session.collaborator);
return { ...session, isOwner, role, canEdit, resolvedCollaborator };
}
// Check if user can access session (owner or shared)