Checkpoint: Correction du bug d'émargement formateur bloqué sur la saisie d'email
- Ajout de la détection automatique formateur/apprenant dans EmargementScan.tsx - Nouvelle procédure tRPC getSequenceByToken pour récupérer les infos de séquence - Interface adaptée selon le type d'utilisateur (apprenant ou formateur) - Déploiement réussi sur le VPS de production Le système détecte maintenant automatiquement si l'email correspond à un apprenant ou un formateur, et affiche l'interface appropriée pour chaque cas.
This commit is contained in:
@@ -1,250 +0,0 @@
|
||||
import { eq, and, desc, sql } from "drizzle-orm";
|
||||
import { getDb } from "./db";
|
||||
import {
|
||||
questionnaires,
|
||||
questions,
|
||||
reponsesQuestionnaires,
|
||||
reponsesQuestions,
|
||||
envoisQuestionnaires,
|
||||
type Questionnaire,
|
||||
type InsertQuestionnaire,
|
||||
type Question,
|
||||
type InsertQuestion,
|
||||
type ReponseQuestionnaire,
|
||||
type InsertReponseQuestionnaire,
|
||||
type ReponseQuestion,
|
||||
type InsertReponseQuestion,
|
||||
type EnvoiQuestionnaire,
|
||||
type InsertEnvoiQuestionnaire,
|
||||
} from "../drizzle/schema";
|
||||
|
||||
// ========== QUESTIONNAIRES ==========
|
||||
|
||||
export async function getAllQuestionnaires() {
|
||||
const db = await getDb();
|
||||
if (!db) return [];
|
||||
return await db.select().from(questionnaires).orderBy(desc(questionnaires.createdAt));
|
||||
}
|
||||
|
||||
export async function getQuestionnaireById(id: number) {
|
||||
const db = await getDb();
|
||||
if (!db) return null;
|
||||
const result = await db.select().from(questionnaires).where(eq(questionnaires.id, id)).limit(1);
|
||||
return result[0] || null;
|
||||
}
|
||||
|
||||
export async function createQuestionnaire(data: InsertQuestionnaire) {
|
||||
const db = await getDb();
|
||||
if (!db) throw new Error("Database not available");
|
||||
const result = await db.insert(questionnaires).values(data);
|
||||
return result[0].insertId;
|
||||
}
|
||||
|
||||
export async function updateQuestionnaire(id: number, data: Partial<InsertQuestionnaire>) {
|
||||
const db = await getDb();
|
||||
if (!db) throw new Error("Database not available");
|
||||
await db.update(questionnaires).set(data).where(eq(questionnaires.id, id));
|
||||
}
|
||||
|
||||
export async function deleteQuestionnaire(id: number) {
|
||||
const db = await getDb();
|
||||
if (!db) throw new Error("Database not available");
|
||||
// Supprimer d'abord les questions associées
|
||||
await db.delete(questions).where(eq(questions.questionnaireId, id));
|
||||
// Puis le questionnaire
|
||||
await db.delete(questionnaires).where(eq(questionnaires.id, id));
|
||||
}
|
||||
|
||||
// ========== QUESTIONS ==========
|
||||
|
||||
export async function getQuestionsByQuestionnaireId(questionnaireId: number) {
|
||||
const db = await getDb();
|
||||
if (!db) return [];
|
||||
return await db
|
||||
.select()
|
||||
.from(questions)
|
||||
.where(eq(questions.questionnaireId, questionnaireId))
|
||||
.orderBy(questions.ordre);
|
||||
}
|
||||
|
||||
export async function createQuestion(data: InsertQuestion) {
|
||||
const db = await getDb();
|
||||
if (!db) throw new Error("Database not available");
|
||||
const result = await db.insert(questions).values(data);
|
||||
return result[0].insertId;
|
||||
}
|
||||
|
||||
export async function updateQuestion(id: number, data: Partial<InsertQuestion>) {
|
||||
const db = await getDb();
|
||||
if (!db) throw new Error("Database not available");
|
||||
await db.update(questions).set(data).where(eq(questions.id, id));
|
||||
}
|
||||
|
||||
export async function deleteQuestion(id: number) {
|
||||
const db = await getDb();
|
||||
if (!db) throw new Error("Database not available");
|
||||
await db.delete(questions).where(eq(questions.id, id));
|
||||
}
|
||||
|
||||
// ========== RÉPONSES QUESTIONNAIRES ==========
|
||||
|
||||
export async function createReponseQuestionnaire(data: InsertReponseQuestionnaire) {
|
||||
const db = await getDb();
|
||||
if (!db) throw new Error("Database not available");
|
||||
const result = await db.insert(reponsesQuestionnaires).values(data);
|
||||
return result[0].insertId;
|
||||
}
|
||||
|
||||
export async function getReponseQuestionnaire(questionnaireId: number, apprenantId: number, sequenceId: number) {
|
||||
const db = await getDb();
|
||||
if (!db) return null;
|
||||
const result = await db
|
||||
.select()
|
||||
.from(reponsesQuestionnaires)
|
||||
.where(
|
||||
and(
|
||||
eq(reponsesQuestionnaires.questionnaireId, questionnaireId),
|
||||
eq(reponsesQuestionnaires.apprenantId, apprenantId),
|
||||
eq(reponsesQuestionnaires.sequenceId, sequenceId)
|
||||
)
|
||||
)
|
||||
.limit(1);
|
||||
return result[0] || null;
|
||||
}
|
||||
|
||||
export async function updateReponseQuestionnaire(id: number, data: Partial<InsertReponseQuestionnaire>) {
|
||||
const db = await getDb();
|
||||
if (!db) throw new Error("Database not available");
|
||||
await db.update(reponsesQuestionnaires).set(data).where(eq(reponsesQuestionnaires.id, id));
|
||||
}
|
||||
|
||||
// ========== RÉPONSES QUESTIONS ==========
|
||||
|
||||
export async function createReponseQuestion(data: InsertReponseQuestion) {
|
||||
const db = await getDb();
|
||||
if (!db) throw new Error("Database not available");
|
||||
const result = await db.insert(reponsesQuestions).values(data);
|
||||
return result[0].insertId;
|
||||
}
|
||||
|
||||
export async function getReponsesByReponseQuestionnaireId(reponseQuestionnaireId: number) {
|
||||
const db = await getDb();
|
||||
if (!db) return [];
|
||||
return await db
|
||||
.select()
|
||||
.from(reponsesQuestions)
|
||||
.where(eq(reponsesQuestions.reponseQuestionnaireId, reponseQuestionnaireId));
|
||||
}
|
||||
|
||||
// ========== ENVOIS QUESTIONNAIRES ==========
|
||||
|
||||
export async function createEnvoiQuestionnaire(data: InsertEnvoiQuestionnaire) {
|
||||
const db = await getDb();
|
||||
if (!db) throw new Error("Database not available");
|
||||
const result = await db.insert(envoisQuestionnaires).values(data);
|
||||
return result[0].insertId;
|
||||
}
|
||||
|
||||
export async function getEnvoiByToken(token: string) {
|
||||
const db = await getDb();
|
||||
if (!db) return null;
|
||||
const result = await db
|
||||
.select()
|
||||
.from(envoisQuestionnaires)
|
||||
.where(eq(envoisQuestionnaires.token, token))
|
||||
.limit(1);
|
||||
return result[0] || null;
|
||||
}
|
||||
|
||||
export async function updateEnvoiQuestionnaire(id: number, data: Partial<InsertEnvoiQuestionnaire>) {
|
||||
const db = await getDb();
|
||||
if (!db) throw new Error("Database not available");
|
||||
await db.update(envoisQuestionnaires).set(data).where(eq(envoisQuestionnaires.id, id));
|
||||
}
|
||||
|
||||
export async function checkEnvoiExists(questionnaireId: number, apprenantId: number, sequenceId: number) {
|
||||
const db = await getDb();
|
||||
if (!db) return false;
|
||||
const result = await db
|
||||
.select()
|
||||
.from(envoisQuestionnaires)
|
||||
.where(
|
||||
and(
|
||||
eq(envoisQuestionnaires.questionnaireId, questionnaireId),
|
||||
eq(envoisQuestionnaires.apprenantId, apprenantId),
|
||||
eq(envoisQuestionnaires.sequenceId, sequenceId)
|
||||
)
|
||||
)
|
||||
.limit(1);
|
||||
return result.length > 0;
|
||||
}
|
||||
|
||||
// ========== STATISTIQUES ==========
|
||||
|
||||
/**
|
||||
* Récupère les statistiques d'un questionnaire
|
||||
*/
|
||||
export async function getQuestionnaireStats(questionnaireId: number) {
|
||||
const db = await getDb();
|
||||
if (!db) return null;
|
||||
|
||||
// Nombre total d'envois
|
||||
const envoisResult = await db
|
||||
.select({ count: sql<number>`count(*)` })
|
||||
.from(envoisQuestionnaires)
|
||||
.where(eq(envoisQuestionnaires.questionnaireId, questionnaireId));
|
||||
const totalEnvois = envoisResult[0]?.count || 0;
|
||||
|
||||
// Nombre de réponses
|
||||
const reponsesResult = await db
|
||||
.select({ count: sql<number>`count(*)` })
|
||||
.from(reponsesQuestionnaires)
|
||||
.where(
|
||||
and(
|
||||
eq(reponsesQuestionnaires.questionnaireId, questionnaireId),
|
||||
eq(reponsesQuestionnaires.complete, true)
|
||||
)
|
||||
);
|
||||
const totalReponses = reponsesResult[0]?.count || 0;
|
||||
|
||||
// Taux de réponse
|
||||
const tauxReponse = totalEnvois > 0 ? (totalReponses / totalEnvois) * 100 : 0;
|
||||
|
||||
return {
|
||||
totalEnvois,
|
||||
totalReponses,
|
||||
tauxReponse: Math.round(tauxReponse * 10) / 10, // 1 décimale
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère les réponses détaillées d'un questionnaire pour analyse
|
||||
*/
|
||||
export async function getReponsesDetailleesQuestionnaire(questionnaireId: number) {
|
||||
const db = await getDb();
|
||||
if (!db) return [];
|
||||
|
||||
const result = await db
|
||||
.select({
|
||||
reponseQuestionnaireId: reponsesQuestionnaires.id,
|
||||
apprenantId: reponsesQuestionnaires.apprenantId,
|
||||
sequenceId: reponsesQuestionnaires.sequenceId,
|
||||
dateReponse: reponsesQuestionnaires.dateReponse,
|
||||
questionId: reponsesQuestions.questionId,
|
||||
reponseNumerique: reponsesQuestions.reponseNumerique,
|
||||
reponseTexte: reponsesQuestions.reponseTexte,
|
||||
})
|
||||
.from(reponsesQuestionnaires)
|
||||
.leftJoin(
|
||||
reponsesQuestions,
|
||||
eq(reponsesQuestions.reponseQuestionnaireId, reponsesQuestionnaires.id)
|
||||
)
|
||||
.where(
|
||||
and(
|
||||
eq(reponsesQuestionnaires.questionnaireId, questionnaireId),
|
||||
eq(reponsesQuestionnaires.complete, true)
|
||||
)
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
Reference in New Issue
Block a user