feat: implement Year Review feature with session management, item categorization, and real-time collaboration
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 6m7s
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 6m7s
This commit is contained in:
329
src/actions/year-review.ts
Normal file
329
src/actions/year-review.ts
Normal file
@@ -0,0 +1,329 @@
|
||||
'use server';
|
||||
|
||||
import { revalidatePath } from 'next/cache';
|
||||
import { auth } from '@/lib/auth';
|
||||
import * as yearReviewService from '@/services/year-review';
|
||||
import type { YearReviewCategory } from '@prisma/client';
|
||||
|
||||
// ============================================
|
||||
// Session Actions
|
||||
// ============================================
|
||||
|
||||
export async function createYearReviewSession(data: {
|
||||
title: string;
|
||||
participant: string;
|
||||
year: number;
|
||||
}) {
|
||||
const session = await auth();
|
||||
if (!session?.user?.id) {
|
||||
return { success: false, error: 'Non autorisé' };
|
||||
}
|
||||
|
||||
try {
|
||||
const yearReviewSession = await yearReviewService.createYearReviewSession(
|
||||
session.user.id,
|
||||
data
|
||||
);
|
||||
revalidatePath('/year-review');
|
||||
revalidatePath('/sessions');
|
||||
return { success: true, data: yearReviewSession };
|
||||
} catch (error) {
|
||||
console.error('Error creating year review session:', error);
|
||||
return { success: false, error: 'Erreur lors de la création' };
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateYearReviewSession(
|
||||
sessionId: string,
|
||||
data: { title?: string; participant?: string; year?: number }
|
||||
) {
|
||||
const authSession = await auth();
|
||||
if (!authSession?.user?.id) {
|
||||
return { success: false, error: 'Non autorisé' };
|
||||
}
|
||||
|
||||
try {
|
||||
await yearReviewService.updateYearReviewSession(sessionId, authSession.user.id, data);
|
||||
|
||||
// Emit event for real-time sync
|
||||
await yearReviewService.createYearReviewSessionEvent(
|
||||
sessionId,
|
||||
authSession.user.id,
|
||||
'SESSION_UPDATED',
|
||||
data
|
||||
);
|
||||
|
||||
revalidatePath(`/year-review/${sessionId}`);
|
||||
revalidatePath('/year-review');
|
||||
revalidatePath('/sessions');
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('Error updating year review session:', error);
|
||||
return { success: false, error: 'Erreur lors de la mise à jour' };
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteYearReviewSession(sessionId: string) {
|
||||
const authSession = await auth();
|
||||
if (!authSession?.user?.id) {
|
||||
return { success: false, error: 'Non autorisé' };
|
||||
}
|
||||
|
||||
try {
|
||||
await yearReviewService.deleteYearReviewSession(sessionId, authSession.user.id);
|
||||
revalidatePath('/year-review');
|
||||
revalidatePath('/sessions');
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('Error deleting year review session:', error);
|
||||
return { success: false, error: 'Erreur lors de la suppression' };
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Item Actions
|
||||
// ============================================
|
||||
|
||||
export async function createYearReviewItem(
|
||||
sessionId: string,
|
||||
data: { content: string; category: YearReviewCategory }
|
||||
) {
|
||||
const authSession = await auth();
|
||||
if (!authSession?.user?.id) {
|
||||
return { success: false, error: 'Non autorisé' };
|
||||
}
|
||||
|
||||
// Check edit permission
|
||||
const canEdit = await yearReviewService.canEditYearReviewSession(
|
||||
sessionId,
|
||||
authSession.user.id
|
||||
);
|
||||
if (!canEdit) {
|
||||
return { success: false, error: 'Permission refusée' };
|
||||
}
|
||||
|
||||
try {
|
||||
const item = await yearReviewService.createYearReviewItem(sessionId, data);
|
||||
|
||||
// Emit event for real-time sync
|
||||
await yearReviewService.createYearReviewSessionEvent(
|
||||
sessionId,
|
||||
authSession.user.id,
|
||||
'ITEM_CREATED',
|
||||
{
|
||||
itemId: item.id,
|
||||
content: item.content,
|
||||
category: item.category,
|
||||
}
|
||||
);
|
||||
|
||||
revalidatePath(`/year-review/${sessionId}`);
|
||||
return { success: true, data: item };
|
||||
} catch (error) {
|
||||
console.error('Error creating year review item:', error);
|
||||
return { success: false, error: 'Erreur lors de la création' };
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateYearReviewItem(
|
||||
itemId: string,
|
||||
sessionId: string,
|
||||
data: { content?: string; category?: YearReviewCategory }
|
||||
) {
|
||||
const authSession = await auth();
|
||||
if (!authSession?.user?.id) {
|
||||
return { success: false, error: 'Non autorisé' };
|
||||
}
|
||||
|
||||
// Check edit permission
|
||||
const canEdit = await yearReviewService.canEditYearReviewSession(
|
||||
sessionId,
|
||||
authSession.user.id
|
||||
);
|
||||
if (!canEdit) {
|
||||
return { success: false, error: 'Permission refusée' };
|
||||
}
|
||||
|
||||
try {
|
||||
const item = await yearReviewService.updateYearReviewItem(itemId, data);
|
||||
|
||||
// Emit event for real-time sync
|
||||
await yearReviewService.createYearReviewSessionEvent(
|
||||
sessionId,
|
||||
authSession.user.id,
|
||||
'ITEM_UPDATED',
|
||||
{
|
||||
itemId: item.id,
|
||||
...data,
|
||||
}
|
||||
);
|
||||
|
||||
revalidatePath(`/year-review/${sessionId}`);
|
||||
return { success: true, data: item };
|
||||
} catch (error) {
|
||||
console.error('Error updating year review item:', error);
|
||||
return { success: false, error: 'Erreur lors de la mise à jour' };
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteYearReviewItem(itemId: string, sessionId: string) {
|
||||
const authSession = await auth();
|
||||
if (!authSession?.user?.id) {
|
||||
return { success: false, error: 'Non autorisé' };
|
||||
}
|
||||
|
||||
// Check edit permission
|
||||
const canEdit = await yearReviewService.canEditYearReviewSession(
|
||||
sessionId,
|
||||
authSession.user.id
|
||||
);
|
||||
if (!canEdit) {
|
||||
return { success: false, error: 'Permission refusée' };
|
||||
}
|
||||
|
||||
try {
|
||||
await yearReviewService.deleteYearReviewItem(itemId);
|
||||
|
||||
// Emit event for real-time sync
|
||||
await yearReviewService.createYearReviewSessionEvent(
|
||||
sessionId,
|
||||
authSession.user.id,
|
||||
'ITEM_DELETED',
|
||||
{ itemId }
|
||||
);
|
||||
|
||||
revalidatePath(`/year-review/${sessionId}`);
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('Error deleting year review item:', error);
|
||||
return { success: false, error: 'Erreur lors de la suppression' };
|
||||
}
|
||||
}
|
||||
|
||||
export async function moveYearReviewItem(
|
||||
itemId: string,
|
||||
sessionId: string,
|
||||
newCategory: YearReviewCategory,
|
||||
newOrder: number
|
||||
) {
|
||||
const authSession = await auth();
|
||||
if (!authSession?.user?.id) {
|
||||
return { success: false, error: 'Non autorisé' };
|
||||
}
|
||||
|
||||
// Check edit permission
|
||||
const canEdit = await yearReviewService.canEditYearReviewSession(
|
||||
sessionId,
|
||||
authSession.user.id
|
||||
);
|
||||
if (!canEdit) {
|
||||
return { success: false, error: 'Permission refusée' };
|
||||
}
|
||||
|
||||
try {
|
||||
await yearReviewService.moveYearReviewItem(itemId, newCategory, newOrder);
|
||||
|
||||
// Emit event for real-time sync
|
||||
await yearReviewService.createYearReviewSessionEvent(
|
||||
sessionId,
|
||||
authSession.user.id,
|
||||
'ITEM_MOVED',
|
||||
{
|
||||
itemId,
|
||||
category: newCategory,
|
||||
order: newOrder,
|
||||
}
|
||||
);
|
||||
|
||||
revalidatePath(`/year-review/${sessionId}`);
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('Error moving year review item:', error);
|
||||
return { success: false, error: 'Erreur lors du déplacement' };
|
||||
}
|
||||
}
|
||||
|
||||
export async function reorderYearReviewItems(
|
||||
sessionId: string,
|
||||
category: YearReviewCategory,
|
||||
itemIds: string[]
|
||||
) {
|
||||
const authSession = await auth();
|
||||
if (!authSession?.user?.id) {
|
||||
return { success: false, error: 'Non autorisé' };
|
||||
}
|
||||
|
||||
// Check edit permission
|
||||
const canEdit = await yearReviewService.canEditYearReviewSession(
|
||||
sessionId,
|
||||
authSession.user.id
|
||||
);
|
||||
if (!canEdit) {
|
||||
return { success: false, error: 'Permission refusée' };
|
||||
}
|
||||
|
||||
try {
|
||||
await yearReviewService.reorderYearReviewItems(sessionId, category, itemIds);
|
||||
|
||||
// Emit event for real-time sync
|
||||
await yearReviewService.createYearReviewSessionEvent(
|
||||
sessionId,
|
||||
authSession.user.id,
|
||||
'ITEMS_REORDERED',
|
||||
{ category, itemIds }
|
||||
);
|
||||
|
||||
revalidatePath(`/year-review/${sessionId}`);
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('Error reordering year review items:', error);
|
||||
return { success: false, error: 'Erreur lors du réordonnancement' };
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// Sharing Actions
|
||||
// ============================================
|
||||
|
||||
export async function shareYearReviewSession(
|
||||
sessionId: string,
|
||||
targetEmail: string,
|
||||
role: 'VIEWER' | 'EDITOR' = 'EDITOR'
|
||||
) {
|
||||
const authSession = await auth();
|
||||
if (!authSession?.user?.id) {
|
||||
return { success: false, error: 'Non autorisé' };
|
||||
}
|
||||
|
||||
try {
|
||||
const share = await yearReviewService.shareYearReviewSession(
|
||||
sessionId,
|
||||
authSession.user.id,
|
||||
targetEmail,
|
||||
role
|
||||
);
|
||||
revalidatePath(`/year-review/${sessionId}`);
|
||||
return { success: true, data: share };
|
||||
} catch (error) {
|
||||
console.error('Error sharing year review session:', error);
|
||||
const message = error instanceof Error ? error.message : 'Erreur lors du partage';
|
||||
return { success: false, error: message };
|
||||
}
|
||||
}
|
||||
|
||||
export async function removeYearReviewShare(sessionId: string, shareUserId: string) {
|
||||
const authSession = await auth();
|
||||
if (!authSession?.user?.id) {
|
||||
return { success: false, error: 'Non autorisé' };
|
||||
}
|
||||
|
||||
try {
|
||||
await yearReviewService.removeYearReviewShare(sessionId, authSession.user.id, shareUserId);
|
||||
revalidatePath(`/year-review/${sessionId}`);
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('Error removing year review share:', error);
|
||||
return { success: false, error: 'Erreur lors de la suppression du partage' };
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user