feat: implement auto-sharing functionality for session creation across motivators, weekly check-ins, and year reviews, enhancing collaboration capabilities
This commit is contained in:
@@ -16,6 +16,16 @@ export async function createMotivatorSession(data: { title: string; participant:
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const motivatorSession = await motivatorsService.createMotivatorSession(session.user.id, data);
|
const motivatorSession = await motivatorsService.createMotivatorSession(session.user.id, data);
|
||||||
|
try {
|
||||||
|
await motivatorsService.shareMotivatorSession(
|
||||||
|
motivatorSession.id,
|
||||||
|
session.user.id,
|
||||||
|
data.participant,
|
||||||
|
'EDITOR'
|
||||||
|
);
|
||||||
|
} catch (shareError) {
|
||||||
|
console.error('Auto-share failed:', shareError);
|
||||||
|
}
|
||||||
revalidatePath('/motivators');
|
revalidatePath('/motivators');
|
||||||
return { success: true, data: motivatorSession };
|
return { success: true, data: motivatorSession };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -24,6 +24,16 @@ export async function createWeeklyCheckInSession(data: {
|
|||||||
session.user.id,
|
session.user.id,
|
||||||
data
|
data
|
||||||
);
|
);
|
||||||
|
try {
|
||||||
|
await weeklyCheckInService.shareWeeklyCheckInSession(
|
||||||
|
weeklyCheckInSession.id,
|
||||||
|
session.user.id,
|
||||||
|
data.participant,
|
||||||
|
'EDITOR'
|
||||||
|
);
|
||||||
|
} catch (shareError) {
|
||||||
|
console.error('Auto-share failed:', shareError);
|
||||||
|
}
|
||||||
revalidatePath('/weekly-checkin');
|
revalidatePath('/weekly-checkin');
|
||||||
revalidatePath('/sessions');
|
revalidatePath('/sessions');
|
||||||
return { success: true, data: weeklyCheckInSession };
|
return { success: true, data: weeklyCheckInSession };
|
||||||
|
|||||||
@@ -24,6 +24,16 @@ export async function createYearReviewSession(data: {
|
|||||||
session.user.id,
|
session.user.id,
|
||||||
data
|
data
|
||||||
);
|
);
|
||||||
|
try {
|
||||||
|
await yearReviewService.shareYearReviewSession(
|
||||||
|
yearReviewSession.id,
|
||||||
|
session.user.id,
|
||||||
|
data.participant,
|
||||||
|
'EDITOR'
|
||||||
|
);
|
||||||
|
} catch (shareError) {
|
||||||
|
console.error('Auto-share failed:', shareError);
|
||||||
|
}
|
||||||
revalidatePath('/year-review');
|
revalidatePath('/year-review');
|
||||||
revalidatePath('/sessions');
|
revalidatePath('/sessions');
|
||||||
return { success: true, data: yearReviewSession };
|
return { success: true, data: yearReviewSession };
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { NextResponse } from 'next/server';
|
import { NextResponse } from 'next/server';
|
||||||
import { auth } from '@/lib/auth';
|
import { auth } from '@/lib/auth';
|
||||||
import { prisma } from '@/services/database';
|
import { prisma } from '@/services/database';
|
||||||
|
import { shareSession } from '@/services/sessions';
|
||||||
|
|
||||||
export async function GET() {
|
export async function GET() {
|
||||||
try {
|
try {
|
||||||
@@ -56,6 +57,12 @@ export async function POST(request: Request) {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
await shareSession(newSession.id, session.user.id, collaborator, 'EDITOR');
|
||||||
|
} catch (shareError) {
|
||||||
|
console.error('Auto-share failed:', shareError);
|
||||||
|
}
|
||||||
|
|
||||||
return NextResponse.json(newSession, { status: 201 });
|
return NextResponse.json(newSession, { status: 201 });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error creating session:', error);
|
console.error('Error creating session:', error);
|
||||||
|
|||||||
31
src/app/api/teams/members/route.ts
Normal file
31
src/app/api/teams/members/route.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import { NextResponse } from 'next/server';
|
||||||
|
import { auth } from '@/lib/auth';
|
||||||
|
import { getUserTeams } from '@/services/teams';
|
||||||
|
import { getTeamMembersForShare } from '@/lib/share-utils';
|
||||||
|
|
||||||
|
export async function GET() {
|
||||||
|
try {
|
||||||
|
const session = await auth();
|
||||||
|
|
||||||
|
if (!session?.user?.id) {
|
||||||
|
return NextResponse.json({ error: 'Non autorisé' }, { status: 401 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const teams = await getUserTeams(session.user.id);
|
||||||
|
const otherMembers = getTeamMembersForShare(teams, session.user.id);
|
||||||
|
const currentUser = {
|
||||||
|
id: session.user.id,
|
||||||
|
email: session.user.email ?? '',
|
||||||
|
name: session.user.name ?? null,
|
||||||
|
};
|
||||||
|
const members = [currentUser, ...otherMembers];
|
||||||
|
|
||||||
|
return NextResponse.json({ members });
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching team members:', error);
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'Erreur lors de la récupération des membres' },
|
||||||
|
{ status: 500 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
CardContent,
|
CardContent,
|
||||||
Button,
|
Button,
|
||||||
Input,
|
Input,
|
||||||
|
ParticipantInput,
|
||||||
} from '@/components/ui';
|
} from '@/components/ui';
|
||||||
import { createMotivatorSession } from '@/actions/moving-motivators';
|
import { createMotivatorSession } from '@/actions/moving-motivators';
|
||||||
|
|
||||||
@@ -72,12 +73,7 @@ export default function NewMotivatorSessionPage() {
|
|||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Input
|
<ParticipantInput name="participant" required />
|
||||||
label="Nom du participant"
|
|
||||||
name="participant"
|
|
||||||
placeholder="Ex: Jean Dupont"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div className="rounded-lg border border-border bg-card-hover p-4">
|
<div className="rounded-lg border border-border bg-card-hover p-4">
|
||||||
<h3 className="font-medium text-foreground mb-2">Comment ça marche ?</h3>
|
<h3 className="font-medium text-foreground mb-2">Comment ça marche ?</h3>
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
CardContent,
|
CardContent,
|
||||||
Button,
|
Button,
|
||||||
Input,
|
Input,
|
||||||
|
ParticipantInput,
|
||||||
} from '@/components/ui';
|
} from '@/components/ui';
|
||||||
|
|
||||||
export default function NewSessionPage() {
|
export default function NewSessionPage() {
|
||||||
@@ -82,12 +83,7 @@ export default function NewSessionPage() {
|
|||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Input
|
<ParticipantInput name="collaborator" required />
|
||||||
label="Nom du collaborateur"
|
|
||||||
name="collaborator"
|
|
||||||
placeholder="Ex: Jean Dupont"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div className="flex gap-3 pt-4">
|
<div className="flex gap-3 pt-4">
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
CardContent,
|
CardContent,
|
||||||
Button,
|
Button,
|
||||||
Input,
|
Input,
|
||||||
|
ParticipantInput,
|
||||||
} from '@/components/ui';
|
} from '@/components/ui';
|
||||||
import { createWeeklyCheckInSession } from '@/actions/weekly-checkin';
|
import { createWeeklyCheckInSession } from '@/actions/weekly-checkin';
|
||||||
import { getWeekYearLabel } from '@/lib/date-utils';
|
import { getWeekYearLabel } from '@/lib/date-utils';
|
||||||
@@ -93,12 +94,7 @@ export default function NewWeeklyCheckInPage() {
|
|||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Input
|
<ParticipantInput name="participant" required />
|
||||||
label="Nom du collaborateur"
|
|
||||||
name="participant"
|
|
||||||
placeholder="Ex: Jean Dupont"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="date" className="block text-sm font-medium text-foreground mb-1">
|
<label htmlFor="date" className="block text-sm font-medium text-foreground mb-1">
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
CardContent,
|
CardContent,
|
||||||
Button,
|
Button,
|
||||||
Input,
|
Input,
|
||||||
|
ParticipantInput,
|
||||||
} from '@/components/ui';
|
} from '@/components/ui';
|
||||||
import { createYearReviewSession } from '@/actions/year-review';
|
import { createYearReviewSession } from '@/actions/year-review';
|
||||||
|
|
||||||
@@ -76,12 +77,7 @@ export default function NewYearReviewPage() {
|
|||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Input
|
<ParticipantInput name="participant" required />
|
||||||
label="Nom du participant"
|
|
||||||
name="participant"
|
|
||||||
placeholder="Ex: Jean Dupont"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="year" className="block text-sm font-medium text-foreground mb-1">
|
<label htmlFor="year" className="block text-sm font-medium text-foreground mb-1">
|
||||||
|
|||||||
56
src/components/ui/ParticipantInput.tsx
Normal file
56
src/components/ui/ParticipantInput.tsx
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
import { Select } from '@/components/ui';
|
||||||
|
|
||||||
|
interface TeamMemberUser {
|
||||||
|
id: string;
|
||||||
|
email: string;
|
||||||
|
name: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ParticipantInputProps {
|
||||||
|
name: string;
|
||||||
|
label?: string;
|
||||||
|
required?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ParticipantInput({
|
||||||
|
name,
|
||||||
|
label = "Choisir un membre de l'équipe",
|
||||||
|
required = true,
|
||||||
|
}: ParticipantInputProps) {
|
||||||
|
const [teamMembers, setTeamMembers] = useState<TeamMemberUser[]>([]);
|
||||||
|
const [value, setValue] = useState('');
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetch('/api/teams/members')
|
||||||
|
.then((res) => res.json())
|
||||||
|
.then((data) => setTeamMembers(data.members ?? []))
|
||||||
|
.catch(() => setTeamMembers([]))
|
||||||
|
.finally(() => setLoading(false));
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const options =
|
||||||
|
teamMembers.length > 0
|
||||||
|
? teamMembers.map((m) => ({
|
||||||
|
value: m.email,
|
||||||
|
label: m.name ? `${m.name} (${m.email})` : m.email,
|
||||||
|
}))
|
||||||
|
: [{ value: '', label: 'Aucun membre dans vos équipes', disabled: true }];
|
||||||
|
|
||||||
|
if (loading) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Select
|
||||||
|
name={name}
|
||||||
|
label={label}
|
||||||
|
options={options}
|
||||||
|
placeholder={teamMembers.length > 0 ? '— Sélectionner —' : undefined}
|
||||||
|
value={value}
|
||||||
|
onChange={(e) => setValue(e.target.value)}
|
||||||
|
required={required}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ export { EditableYearReviewTitle } from './EditableYearReviewTitle';
|
|||||||
export { EditableWeeklyCheckInTitle } from './EditableWeeklyCheckInTitle';
|
export { EditableWeeklyCheckInTitle } from './EditableWeeklyCheckInTitle';
|
||||||
export { EditableWeatherTitle } from './EditableWeatherTitle';
|
export { EditableWeatherTitle } from './EditableWeatherTitle';
|
||||||
export { Input } from './Input';
|
export { Input } from './Input';
|
||||||
|
export { ParticipantInput } from './ParticipantInput';
|
||||||
export { Modal, ModalFooter } from './Modal';
|
export { Modal, ModalFooter } from './Modal';
|
||||||
export { RocketIcon } from './RocketIcon';
|
export { RocketIcon } from './RocketIcon';
|
||||||
export { Select } from './Select';
|
export { Select } from './Select';
|
||||||
|
|||||||
Reference in New Issue
Block a user