Skip to content
This repository was archived by the owner on Sep 25, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/components/talks/TalksSchedule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -289,8 +289,8 @@ export default function TalksSchedule({ talks, onScheduleTalk }: TalksSchedulePr
</Card>
</div>
<PlanningOverview
rooms={rooms.map(({ roomId, name }) => ({ roomId, name }))}
date={selectedDate}
rooms={rooms.map(({ roomId, name }) => ({ roomId, name }))}
/>
</div>
);
Expand Down
14,163 changes: 10,697 additions & 3,466 deletions app/package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"@radix-ui/react-tabs": "^1.1.11",
"@tanstack/react-query": "^5.76.1",
"@types/bcrypt": "^5.0.2",
"axios": "^1.9.0",
"bcrypt": "^6.0.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
Expand All @@ -40,6 +41,7 @@
"react": "^19.0.0",
"react-day-picker": "8.10.1",
"react-dom": "^19.0.0",
"swr": "^2.3.3",
"tailwind-merge": "^3.3.0",
"zod": "^3.24.4"
},
Expand Down
18 changes: 15 additions & 3 deletions app/pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,23 @@
import '@/styles/globals.css';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { SessionProvider } from 'next-auth/react';
import type { AppProps } from 'next/app';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

const queryClient = new QueryClient();
import { useState } from 'react';

export default function App({ Component, pageProps }: AppProps) {
const [queryClient] = useState(
() =>
new QueryClient({
defaultOptions: {
queries: {
refetchOnWindowFocus: false,
staleTime: 30000, // 30 secondes
retry: 1,
},
},
}),
);

return (
<SessionProvider>
<QueryClientProvider client={queryClient}>
Expand Down
3 changes: 1 addition & 2 deletions app/pages/api/auth/[...nextauth].ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { prisma } from '@/lib/prisma';
import { roleToRoleId } from '@/utils/auth.utils';
import bcrypt from 'bcrypt';
import NextAuth, { User } from 'next-auth';
import { NextAuthOptions } from 'next-auth';
import NextAuth, { NextAuthOptions, User } from 'next-auth';
import CredentialsProvider from 'next-auth/providers/credentials';

declare module 'next-auth' {
Expand Down
9 changes: 6 additions & 3 deletions app/pages/api/references/rooms.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { getRooms } from '@/services/referenceDataService';
import { asApiError } from '@/types/error';
import { NextApiRequest, NextApiResponse } from 'next';

/**
Expand All @@ -13,8 +14,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
try {
const rooms = await getRooms();
return res.status(200).json(rooms);
} catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Une erreur est survenue';
return res.status(500).json({ error: errorMessage });
} catch (error: unknown) {
const apiError = asApiError(error);
return res
.status(apiError.status || 500)
.json({ error: apiError.message || 'Une erreur est survenue' });
}
}
11 changes: 7 additions & 4 deletions app/pages/api/references/subjects.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { NextApiRequest, NextApiResponse } from 'next';
import { getSubjects } from '@/services/referenceDataService';
import { asApiError } from '@/types/error';
import { NextApiRequest, NextApiResponse } from 'next';

/**
* API pour récupérer tous les sujets disponibles
Expand All @@ -13,8 +14,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
try {
const subjects = await getSubjects();
return res.status(200).json(subjects);
} catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Une erreur est survenue';
return res.status(500).json({ error: errorMessage });
} catch (error: unknown) {
const apiError = asApiError(error);
return res
.status(apiError.status || 500)
.json({ error: apiError.message || 'Une erreur est survenue' });
}
}
9 changes: 6 additions & 3 deletions app/pages/api/references/talkLevels.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { getTalkLevels } from '@/services/referenceDataService';
import { asApiError } from '@/types/error';
import { NextApiRequest, NextApiResponse } from 'next';

/**
Expand All @@ -13,8 +14,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
try {
const levels = await getTalkLevels();
return res.status(200).json(levels);
} catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Une erreur est survenue';
return res.status(500).json({ error: errorMessage });
} catch (error: unknown) {
const apiError = asApiError(error);
return res
.status(apiError.status || 500)
.json({ error: apiError.message || 'Une erreur est survenue' });
}
}
11 changes: 7 additions & 4 deletions app/pages/api/references/talkStatuses.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { NextApiRequest, NextApiResponse } from 'next';
import { getTalkStatuses } from '@/services/referenceDataService';
import { asApiError } from '@/types/error';
import { NextApiRequest, NextApiResponse } from 'next';

/**
* API pour récupérer tous les statuts de talks disponibles
Expand All @@ -13,8 +14,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
try {
const statuses = await getTalkStatuses();
return res.status(200).json(statuses);
} catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Une erreur est survenue';
return res.status(500).json({ error: errorMessage });
} catch (error: unknown) {
const apiError = asApiError(error);
return res
.status(apiError.status || 500)
.json({ error: apiError.message || 'Une erreur est survenue' });
}
}
11 changes: 6 additions & 5 deletions app/pages/api/schedules/available-rooms.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { getAvailableRoomsForTimeSlot } from '@/services/scheduleService';
import { asApiError } from '@/types/error';
import { NextApiRequest, NextApiResponse } from 'next';
import { getSession } from 'next-auth/react';

Expand Down Expand Up @@ -31,10 +32,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
);

return res.status(200).json(availableRooms);
} catch (error) {
if (error instanceof Error) {
return res.status(500).json({ error: error.message });
}
return res.status(500).json({ error: 'Une erreur inconnue est survenue' });
} catch (error: unknown) {
const apiError = asApiError(error);
return res
.status(apiError.status || 500)
.json({ error: apiError.message || 'Une erreur est survenue' });
}
}
78 changes: 62 additions & 16 deletions app/pages/api/schedules/available-times.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import { prisma } from '@/lib/prisma';
import { getAvailableTimesForRoom } from '@/services/scheduleService';
import { asApiError } from '@/types/error';
import { NextApiRequest, NextApiResponse } from 'next';
import { getSession } from 'next-auth/react';

/**
* API pour récupérer les créneaux disponibles pour une salle à une date spécifique
* GET: Retourne les créneaux disponibles
*/
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
// Pour les requêtes GET, nous permettons l'accès sans authentification
// Vérifier l'authentification
const session = await getSession({ req });
if (!session?.user) {
return res.status(401).json({ error: 'Authentification requise' });
}
// const session = await getSession({ req });
// if (!session?.user) {
// return res.status(401).json({ error: 'Authentification requise' });
// }
// L'authentification sera vérifiée côté front-end pour afficher ou non les fonctionalités de planification

// Accepter uniquement les requêtes GET
if (req.method !== 'GET') {
Expand All @@ -21,20 +24,63 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
try {
const { roomId, date } = req.query;

if (!roomId || !date) {
return res.status(400).json({ error: 'roomId et date sont requis' });
// Si roomId et date sont fournis, retourner les créneaux disponibles pour cette salle et cette date
if (roomId && date) {
const availableTimes = await getAvailableTimesForRoom(
parseInt(roomId as string),
date as string,
);
return res.status(200).json(availableTimes);
}

const availableTimes = await getAvailableTimesForRoom(
parseInt(roomId as string),
date as string,
);
// Si aucun paramètre n'est fourni, retourner tous les créneaux horaires disponibles
// Générer des créneaux horaires de 9h à 19h par défaut
const defaultSlots = [];
const today = new Date();
const tomorrow = new Date(today);
tomorrow.setDate(tomorrow.getDate() + 1);

// On génère des créneaux pour aujourd'hui et demain
for (let day = 0; day < 2; day++) {
const date = day === 0 ? today : tomorrow;
const [dateString] = date.toISOString().split('T');

const rooms = await prisma.rooms.findMany();
for (const room of rooms) {
for (let hour = 9; hour < 19; hour++) {
const startHour = `${hour.toString().padStart(2, '0')}:00`;
const endHour = `${(hour + 1).toString().padStart(2, '0')}:00`;

return res.status(200).json(availableTimes);
} catch (error) {
if (error instanceof Error) {
return res.status(500).json({ error: error.message });
const existingSchedule = await prisma.schedules.findFirst({
where: {
room_id: room.id,
start_time: {
gte: new Date(`${dateString}T${startHour}:00`),
lt: new Date(`${dateString}T${endHour}:00`),
},
},
});

// Si le créneau n'est pas réservé, l'ajouter à la liste
if (!existingSchedule) {
defaultSlots.push({
id: `${room.id}-${dateString}-${hour}`,
date: dateString,
start_time: startHour,
end_time: endHour,
room_id: room.id,
talk_id: null,
});
}
}
}
}
return res.status(500).json({ error: 'Une erreur inconnue est survenue' });

return res.status(200).json(defaultSlots);
} catch (error: unknown) {
const apiError = asApiError(error);
return res
.status(apiError.status || 500)
.json({ error: apiError.message || 'Une erreur est survenue' });
}
}
Loading