Checkpoint: Correction complète de l'affichage du formateur dans la liste des séquences et dans le formulaire de modification. Ajout de la colonne formateurId dans la table sequences, modification du schéma Zod pour accepter null, et correction du FormateurCombobox pour stocker l'ID au lieu du nom. Le formateur s'affiche maintenant correctement dans la liste des séquences.

This commit is contained in:
Manus Sandbox
2025-11-20 04:36:02 -05:00
parent 7149458bb8
commit 1768e45dc1
15 changed files with 1133 additions and 5 deletions

View File

@@ -0,0 +1,98 @@
{
"query": "DESCRIBE sequences",
"command": "mysql --batch --raw --column-names --default-character-set=utf8mb4 --host gateway02.us-east-1.prod.aws.tidbcloud.com --port 4000 --user 4CrrYuB5tme73Qo.root --database 7PAT67UmWoxv8vwp8Bbcv6 --execute DESCRIBE sequences",
"rows": [
{
"Field": "id",
"Type": "int(11)",
"Null": "NO",
"Key": "PRI",
"Default": "NULL",
"Extra": "auto_increment"
},
{
"Field": "formationId",
"Type": "int(11)",
"Null": "NO",
"Key": "",
"Default": "NULL",
"Extra": ""
},
{
"Field": "nom",
"Type": "varchar(255)",
"Null": "NO",
"Key": "",
"Default": "NULL",
"Extra": ""
},
{
"Field": "lieu",
"Type": "varchar(500)",
"Null": "NO",
"Key": "",
"Default": "NULL",
"Extra": ""
},
{
"Field": "capaciteMax",
"Type": "int(11)",
"Null": "NO",
"Key": "",
"Default": "12",
"Extra": ""
},
{
"Field": "dateBlocage",
"Type": "datetime",
"Null": "NO",
"Key": "",
"Default": "NULL",
"Extra": ""
},
{
"Field": "statut",
"Type": "enum('ouverte','bloquee','terminee')",
"Null": "NO",
"Key": "",
"Default": "ouverte",
"Extra": ""
},
{
"Field": "createdAt",
"Type": "timestamp",
"Null": "NO",
"Key": "",
"Default": "CURRENT_TIMESTAMP",
"Extra": ""
},
{
"Field": "updatedAt",
"Type": "timestamp",
"Null": "NO",
"Key": "",
"Default": "CURRENT_TIMESTAMP",
"Extra": "DEFAULT_GENERATED on update CURRENT_TIMESTAMP"
},
{
"Field": "publicCible",
"Type": "enum('directeur','chef_service','tous','autre')",
"Null": "NO",
"Key": "",
"Default": "NULL",
"Extra": ""
},
{
"Field": "formateur",
"Type": "varchar(255)",
"Null": "YES",
"Key": "",
"Default": "NULL",
"Extra": ""
}
],
"messages": [],
"stdout": "Field\tType\tNull\tKey\tDefault\tExtra\nid\tint(11)\tNO\tPRI\tNULL\tauto_increment\nformationId\tint(11)\tNO\t\tNULL\t\nnom\tvarchar(255)\tNO\t\tNULL\t\nlieu\tvarchar(500)\tNO\t\tNULL\t\ncapaciteMax\tint(11)\tNO\t\t12\t\ndateBlocage\tdatetime\tNO\t\tNULL\t\nstatut\tenum('ouverte','bloquee','terminee')\tNO\t\touverte\t\ncreatedAt\ttimestamp\tNO\t\tCURRENT_TIMESTAMP\t\nupdatedAt\ttimestamp\tNO\t\tCURRENT_TIMESTAMP\tDEFAULT_GENERATED on update CURRENT_TIMESTAMP\npublicCible\tenum('directeur','chef_service','tous','autre')\tNO\t\tNULL\t\nformateur\tvarchar(255)\tYES\t\tNULL\t\n",
"stderr": "",
"execution_time_ms": 54
}

View File

@@ -0,0 +1,9 @@
{
"query": "ALTER TABLE sequences ADD COLUMN formateurId INT NULL",
"command": "mysql --batch --raw --column-names --default-character-set=utf8mb4 --host gateway02.us-east-1.prod.aws.tidbcloud.com --port 4000 --user 4CrrYuB5tme73Qo.root --database 7PAT67UmWoxv8vwp8Bbcv6 --execute ALTER TABLE sequences ADD COLUMN formateurId INT NULL",
"rows": [],
"messages": [],
"stdout": "",
"stderr": "",
"execution_time_ms": 433
}

View File

@@ -0,0 +1,15 @@
{
"query": "SELECT id, nom, formateurId FROM sequences WHERE nom = 'Test Formateur 2'",
"command": "mysql --batch --raw --column-names --default-character-set=utf8mb4 --host gateway02.us-east-1.prod.aws.tidbcloud.com --port 4000 --user 4CrrYuB5tme73Qo.root --database 7PAT67UmWoxv8vwp8Bbcv6 --execute SELECT id, nom, formateurId FROM sequences WHERE nom = 'Test Formateur 2'",
"rows": [
{
"id": "150002",
"nom": "Test Formateur 2",
"formateurId": "NULL"
}
],
"messages": [],
"stdout": "id\tnom\tformateurId\n150002\tTest Formateur 2\tNULL\n",
"stderr": "",
"execution_time_ms": 52
}

View File

@@ -0,0 +1,24 @@
{
"query": "SELECT * FROM formateurs",
"command": "mysql --batch --raw --column-names --default-character-set=utf8mb4 --host gateway02.us-east-1.prod.aws.tidbcloud.com --port 4000 --user 4CrrYuB5tme73Qo.root --database 7PAT67UmWoxv8vwp8Bbcv6 --execute SELECT * FROM formateurs",
"rows": [
{
"id": "1",
"nom": "Jean Dupont",
"actif": "1",
"createdAt": "2025-11-20 08:56:03",
"updatedAt": "2025-11-20 08:56:03"
},
{
"id": "30001",
"nom": "George Clooney",
"actif": "1",
"createdAt": "2025-11-20 09:10:53",
"updatedAt": "2025-11-20 09:10:53"
}
],
"messages": [],
"stdout": "id\tnom\tactif\tcreatedAt\tupdatedAt\n1\tJean Dupont\t1\t2025-11-20 08:56:03\t2025-11-20 08:56:03\n30001\tGeorge Clooney\t1\t2025-11-20 09:10:53\t2025-11-20 09:10:53\n",
"stderr": "",
"execution_time_ms": 50
}

View File

@@ -0,0 +1,106 @@
{
"query": "SHOW COLUMNS FROM sequences",
"command": "mysql --batch --raw --column-names --default-character-set=utf8mb4 --host gateway02.us-east-1.prod.aws.tidbcloud.com --port 4000 --user 4CrrYuB5tme73Qo.root --database 7PAT67UmWoxv8vwp8Bbcv6 --execute SHOW COLUMNS FROM sequences",
"rows": [
{
"Field": "id",
"Type": "int(11)",
"Null": "NO",
"Key": "PRI",
"Default": "NULL",
"Extra": "auto_increment"
},
{
"Field": "formationId",
"Type": "int(11)",
"Null": "NO",
"Key": "",
"Default": "NULL",
"Extra": ""
},
{
"Field": "nom",
"Type": "varchar(255)",
"Null": "NO",
"Key": "",
"Default": "NULL",
"Extra": ""
},
{
"Field": "lieu",
"Type": "varchar(500)",
"Null": "NO",
"Key": "",
"Default": "NULL",
"Extra": ""
},
{
"Field": "capaciteMax",
"Type": "int(11)",
"Null": "NO",
"Key": "",
"Default": "12",
"Extra": ""
},
{
"Field": "dateBlocage",
"Type": "datetime",
"Null": "NO",
"Key": "",
"Default": "NULL",
"Extra": ""
},
{
"Field": "statut",
"Type": "enum('ouverte','bloquee','terminee')",
"Null": "NO",
"Key": "",
"Default": "ouverte",
"Extra": ""
},
{
"Field": "createdAt",
"Type": "timestamp",
"Null": "NO",
"Key": "",
"Default": "CURRENT_TIMESTAMP",
"Extra": ""
},
{
"Field": "updatedAt",
"Type": "timestamp",
"Null": "NO",
"Key": "",
"Default": "CURRENT_TIMESTAMP",
"Extra": "DEFAULT_GENERATED on update CURRENT_TIMESTAMP"
},
{
"Field": "publicCible",
"Type": "enum('directeur','chef_service','tous','autre')",
"Null": "NO",
"Key": "",
"Default": "NULL",
"Extra": ""
},
{
"Field": "formateur",
"Type": "varchar(255)",
"Null": "YES",
"Key": "",
"Default": "NULL",
"Extra": ""
},
{
"Field": "formateurId",
"Type": "int(11)",
"Null": "YES",
"Key": "",
"Default": "NULL",
"Extra": ""
}
],
"messages": [],
"stdout": "Field\tType\tNull\tKey\tDefault\tExtra\nid\tint(11)\tNO\tPRI\tNULL\tauto_increment\nformationId\tint(11)\tNO\t\tNULL\t\nnom\tvarchar(255)\tNO\t\tNULL\t\nlieu\tvarchar(500)\tNO\t\tNULL\t\ncapaciteMax\tint(11)\tNO\t\t12\t\ndateBlocage\tdatetime\tNO\t\tNULL\t\nstatut\tenum('ouverte','bloquee','terminee')\tNO\t\touverte\t\ncreatedAt\ttimestamp\tNO\t\tCURRENT_TIMESTAMP\t\nupdatedAt\ttimestamp\tNO\t\tCURRENT_TIMESTAMP\tDEFAULT_GENERATED on update CURRENT_TIMESTAMP\npublicCible\tenum('directeur','chef_service','tous','autre')\tNO\t\tNULL\t\nformateur\tvarchar(255)\tYES\t\tNULL\t\nformateurId\tint(11)\tYES\t\tNULL\t\n",
"stderr": "",
"execution_time_ms": 58
}

View File

@@ -0,0 +1,8 @@
{
"query": "SELECT id, nom, formateurId FROM sequences WHERE nom = 'Test Formateur'",
"command": "mysql --batch --raw --column-names --default-character-set=utf8mb4 --host gateway02.us-east-1.prod.aws.tidbcloud.com --port 4000 --user 4CrrYuB5tme73Qo.root --database 7PAT67UmWoxv8vwp8Bbcv6 --execute SELECT id, nom, formateurId FROM sequences WHERE nom = 'Test Formateur'",
"returncode": 1,
"logs": [
"ERROR 1054 (42S22) at line 1: Unknown column 'formateurid' in 'field list'"
]
}

View File

@@ -64,7 +64,7 @@ export default function FormateurCombobox({
createMutation.mutate({ nom: newFormateurNom.trim() }); createMutation.mutate({ nom: newFormateurNom.trim() });
}; };
const selectedFormateur = formateurs?.find((f) => f.nom === value); const selectedFormateur = formateurs?.find((f) => f.id.toString() === value);
return ( return (
<> <>
@@ -89,7 +89,7 @@ export default function FormateurCombobox({
{formateurs?.map((formateur) => ( {formateurs?.map((formateur) => (
<CommandItem <CommandItem
key={formateur.id} key={formateur.id}
value={formateur.nom} value={formateur.id.toString()}
onSelect={(currentValue) => { onSelect={(currentValue) => {
onChange(currentValue === value ? "" : currentValue); onChange(currentValue === value ? "" : currentValue);
setOpen(false); setOpen(false);
@@ -98,7 +98,7 @@ export default function FormateurCombobox({
<Check <Check
className={cn( className={cn(
"mr-2 h-4 w-4", "mr-2 h-4 w-4",
value === formateur.nom ? "opacity-100" : "opacity-0" value === formateur.id.toString() ? "opacity-100" : "opacity-0"
)} )}
/> />
{formateur.nom} {formateur.nom}

View File

@@ -144,6 +144,7 @@ export default function AdminSequences() {
capaciteMax: sequence.capaciteMax?.toString() || "12", capaciteMax: sequence.capaciteMax?.toString() || "12",
dateBlocage: safeFormatDate(sequence.dateBlocage), dateBlocage: safeFormatDate(sequence.dateBlocage),
statut: sequence.statut || "ouverte", statut: sequence.statut || "ouverte",
formateur: sequence.formateurId?.toString() || "",
dates: (sequence.dates || []).map((d: any) => ({ dates: (sequence.dates || []).map((d: any) => ({
dateDebut: safeFormatDate(d.dateDebut), dateDebut: safeFormatDate(d.dateDebut),
dateFin: safeFormatDate(d.dateFin), dateFin: safeFormatDate(d.dateFin),
@@ -169,6 +170,7 @@ export default function AdminSequences() {
capaciteMax: parseInt(formData.capaciteMax), capaciteMax: parseInt(formData.capaciteMax),
dateBlocage: formData.dateBlocage, dateBlocage: formData.dateBlocage,
statut: formData.statut, statut: formData.statut,
formateurId: formData.formateur ? parseInt(formData.formateur) : null,
dates: formData.dates, dates: formData.dates,
}; };
@@ -654,7 +656,7 @@ export default function AdminSequences() {
</div> </div>
</TableCell> </TableCell>
<TableCell className="max-w-xs truncate">{sequence.lieu}</TableCell> <TableCell className="max-w-xs truncate">{sequence.lieu}</TableCell>
<TableCell className="text-sm">{sequence.formateur || "-"}</TableCell> <TableCell className="text-sm">{sequence.formateur?.nom || "-"}</TableCell>
<TableCell> <TableCell>
<span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${getPublicCibleBadge(sequence.publicCible)}`}> <span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${getPublicCibleBadge(sequence.publicCible)}`}>
{getPublicCibleLabel(sequence.publicCible)} {getPublicCibleLabel(sequence.publicCible)}

View File

@@ -0,0 +1 @@
ALTER TABLE `sequences` ADD `formateurId` int;

View File

@@ -0,0 +1,834 @@
{
"version": "5",
"dialect": "mysql",
"id": "443cedd2-fcbf-4247-a935-e69461bb7446",
"prevId": "8f8379ca-fd36-48b1-abf9-4b53c2877ad8",
"tables": {
"apprenants": {
"name": "apprenants",
"columns": {
"id": {
"name": "id",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": true
},
"nom": {
"name": "nom",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"prenom": {
"name": "prenom",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"email": {
"name": "email",
"type": "varchar(320)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"codeEtablissement": {
"name": "codeEtablissement",
"type": "varchar(50)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"fonction": {
"name": "fonction",
"type": "enum('directeur','chef_service','autre')",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"onUpdate": true,
"default": "(now())"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"apprenants_id": {
"name": "apprenants_id",
"columns": [
"id"
]
}
},
"uniqueConstraints": {
"apprenants_email_unique": {
"name": "apprenants_email_unique",
"columns": [
"email"
]
}
},
"checkConstraint": {}
},
"datesFormation": {
"name": "datesFormation",
"columns": {
"id": {
"name": "id",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": true
},
"sequenceId": {
"name": "sequenceId",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"dateDebut": {
"name": "dateDebut",
"type": "datetime",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"dateFin": {
"name": "dateFin",
"type": "datetime",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"ordre": {
"name": "ordre",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"datesFormation_id": {
"name": "datesFormation_id",
"columns": [
"id"
]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"emailConfig": {
"name": "emailConfig",
"columns": {
"id": {
"name": "id",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": true
},
"provider": {
"name": "provider",
"type": "varchar(50)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "'resend'"
},
"apiKey": {
"name": "apiKey",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"fromEmail": {
"name": "fromEmail",
"type": "varchar(320)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"fromName": {
"name": "fromName",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "'Formation Manager Itinova'"
},
"mode": {
"name": "mode",
"type": "enum('simulation','production')",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "'simulation'"
},
"domainVerified": {
"name": "domainVerified",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": false
},
"active": {
"name": "active",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"onUpdate": true,
"default": "(now())"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"emailConfig_id": {
"name": "emailConfig_id",
"columns": [
"id"
]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"emailTemplates": {
"name": "emailTemplates",
"columns": {
"id": {
"name": "id",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": true
},
"type": {
"name": "type",
"type": "varchar(50)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"logoUrl": {
"name": "logoUrl",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"primaryColor": {
"name": "primaryColor",
"type": "varchar(7)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "'#2563eb'"
},
"headerBgColor": {
"name": "headerBgColor",
"type": "varchar(7)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "'#2563eb'"
},
"headerTextColor": {
"name": "headerTextColor",
"type": "varchar(7)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "'#ffffff'"
},
"headerTitle": {
"name": "headerTitle",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "'Formation Manager Itinova'"
},
"footerText": {
"name": "footerText",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"active": {
"name": "active",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"onUpdate": true,
"default": "(now())"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"emailTemplates_id": {
"name": "emailTemplates_id",
"columns": [
"id"
]
}
},
"uniqueConstraints": {
"emailTemplates_type_unique": {
"name": "emailTemplates_type_unique",
"columns": [
"type"
]
}
},
"checkConstraint": {}
},
"formateurs": {
"name": "formateurs",
"columns": {
"id": {
"name": "id",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": true
},
"nom": {
"name": "nom",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"onUpdate": true,
"default": "(now())"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"formateurs_id": {
"name": "formateurs_id",
"columns": [
"id"
]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"formations": {
"name": "formations",
"columns": {
"id": {
"name": "id",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": true
},
"nom": {
"name": "nom",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"lienUnique": {
"name": "lienUnique",
"type": "varchar(100)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"actif": {
"name": "actif",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"onUpdate": true,
"default": "(now())"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"formations_id": {
"name": "formations_id",
"columns": [
"id"
]
}
},
"uniqueConstraints": {
"formations_lienUnique_unique": {
"name": "formations_lienUnique_unique",
"columns": [
"lienUnique"
]
}
},
"checkConstraint": {}
},
"inscriptions": {
"name": "inscriptions",
"columns": {
"id": {
"name": "id",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": true
},
"apprenantId": {
"name": "apprenantId",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"sequenceId": {
"name": "sequenceId",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"statut": {
"name": "statut",
"type": "enum('confirmee','liste_attente','annulee')",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"dateInscription": {
"name": "dateInscription",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"onUpdate": true,
"default": "(now())"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"inscriptions_id": {
"name": "inscriptions_id",
"columns": [
"id"
]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"passwordResetTokens": {
"name": "passwordResetTokens",
"columns": {
"id": {
"name": "id",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": true
},
"userId": {
"name": "userId",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"token": {
"name": "token",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"expiresAt": {
"name": "expiresAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"used": {
"name": "used",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": false
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"passwordResetTokens_id": {
"name": "passwordResetTokens_id",
"columns": [
"id"
]
}
},
"uniqueConstraints": {
"passwordResetTokens_token_unique": {
"name": "passwordResetTokens_token_unique",
"columns": [
"token"
]
}
},
"checkConstraint": {}
},
"sequences": {
"name": "sequences",
"columns": {
"id": {
"name": "id",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": true
},
"formationId": {
"name": "formationId",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"nom": {
"name": "nom",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"lieu": {
"name": "lieu",
"type": "varchar(500)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"publicCible": {
"name": "publicCible",
"type": "enum('directeur','chef_service','autre')",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"formateurId": {
"name": "formateurId",
"type": "int",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"capaciteMax": {
"name": "capaciteMax",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": 12
},
"dateBlocage": {
"name": "dateBlocage",
"type": "datetime",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"statut": {
"name": "statut",
"type": "enum('ouverte','bloquee','terminee')",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "'ouverte'"
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"onUpdate": true,
"default": "(now())"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"sequences_id": {
"name": "sequences_id",
"columns": [
"id"
]
}
},
"uniqueConstraints": {},
"checkConstraint": {}
},
"users": {
"name": "users",
"columns": {
"id": {
"name": "id",
"type": "int",
"primaryKey": false,
"notNull": true,
"autoincrement": true
},
"openId": {
"name": "openId",
"type": "varchar(64)",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"email": {
"name": "email",
"type": "varchar(320)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"loginMethod": {
"name": "loginMethod",
"type": "varchar(64)",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"role": {
"name": "role",
"type": "enum('user','admin')",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "'user'"
},
"isActive": {
"name": "isActive",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
},
"updatedAt": {
"name": "updatedAt",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"onUpdate": true,
"default": "(now())"
},
"lastSignedIn": {
"name": "lastSignedIn",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "(now())"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"users_id": {
"name": "users_id",
"columns": [
"id"
]
}
},
"uniqueConstraints": {
"users_openId_unique": {
"name": "users_openId_unique",
"columns": [
"openId"
]
}
},
"checkConstraint": {}
}
},
"views": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
},
"internal": {
"tables": {},
"indexes": {}
}
}

View File

@@ -78,6 +78,13 @@
"when": 1763628773882, "when": 1763628773882,
"tag": "0010_aspiring_kitty_pryde", "tag": "0010_aspiring_kitty_pryde",
"breakpoints": true "breakpoints": true
},
{
"idx": 11,
"version": "5",
"when": 1763630439521,
"tag": "0011_natural_cyclops",
"breakpoints": true
} }
] ]
} }

View File

@@ -73,6 +73,8 @@ export const sequences = mysqlTable("sequences", {
lieu: varchar("lieu", { length: 500 }).notNull(), lieu: varchar("lieu", { length: 500 }).notNull(),
/** Public cible de la séquence (Directeur, Chef de service, Autre) */ /** Public cible de la séquence (Directeur, Chef de service, Autre) */
publicCible: mysqlEnum("publicCible", ["directeur", "chef_service", "autre"]).notNull(), publicCible: mysqlEnum("publicCible", ["directeur", "chef_service", "autre"]).notNull(),
/** ID du formateur assigné à cette séquence */
formateurId: int("formateurId"),
/** Capacité maximale (12 par défaut) */ /** Capacité maximale (12 par défaut) */
capaciteMax: int("capaciteMax").default(12).notNull(), capaciteMax: int("capaciteMax").default(12).notNull(),
/** Date de blocage des inscriptions (J-15 avant la première date) */ /** Date de blocage des inscriptions (J-15 avant la première date) */

View File

@@ -186,13 +186,23 @@ export async function getSequencesWithFormation() {
const seqs = await db.select().from(sequences); const seqs = await db.select().from(sequences);
// Récupérer les informations de formation pour chaque séquence // Récupérer les informations de formation et de formateur pour chaque séquence
return await Promise.all( return await Promise.all(
seqs.map(async (seq) => { seqs.map(async (seq) => {
const formation = await db.select().from(formations).where(eq(formations.id, seq.formationId)).limit(1); const formation = await db.select().from(formations).where(eq(formations.id, seq.formationId)).limit(1);
let formateur = null;
if (seq.formateurId) {
const formateurResult = await db.select().from(formateurs).where(eq(formateurs.id, seq.formateurId)).limit(1);
if (formateurResult.length > 0) {
formateur = { id: formateurResult[0].id, nom: formateurResult[0].nom };
}
}
return { return {
...seq, ...seq,
formation: formation.length > 0 ? { id: formation[0].id, nom: formation[0].nom } : null, formation: formation.length > 0 ? { id: formation[0].id, nom: formation[0].nom } : null,
formateur,
}; };
}) })
); );

View File

@@ -188,6 +188,7 @@ export const appRouter = router({
nom: z.string().min(1), nom: z.string().min(1),
lieu: z.string().min(1), lieu: z.string().min(1),
publicCible: z.enum(["directeur", "chef_service", "autre"]), publicCible: z.enum(["directeur", "chef_service", "autre"]),
formateurId: z.number().nullable().optional(),
capaciteMax: z.number().default(12), capaciteMax: z.number().default(12),
dateBlocage: z.string(), dateBlocage: z.string(),
statut: z.enum(["ouverte", "bloquee", "terminee"]).optional(), statut: z.enum(["ouverte", "bloquee", "terminee"]).optional(),
@@ -227,6 +228,7 @@ export const appRouter = router({
nom: z.string().min(1), nom: z.string().min(1),
lieu: z.string().min(1), lieu: z.string().min(1),
publicCible: z.enum(["directeur", "chef_service", "autre"]), publicCible: z.enum(["directeur", "chef_service", "autre"]),
formateurId: z.number().nullable().optional(),
capaciteMax: z.number(), capaciteMax: z.number(),
dateBlocage: z.string(), dateBlocage: z.string(),
statut: z.enum(["ouverte", "bloquee", "terminee"]), statut: z.enum(["ouverte", "bloquee", "terminee"]),

10
todo.md
View File

@@ -344,3 +344,13 @@
- [x] Identifier le code qui appelle formateurs.create - [x] Identifier le code qui appelle formateurs.create
- [x] Ajouter la procédure formateurs.create manquante dans le routeur - [x] Ajouter la procédure formateurs.create manquante dans le routeur
- [x] Tester la correction - [x] Tester la correction
## Correction affichage du formateur dans les séquences
- [x] Vérifier comment getSequencesWithFormation récupère les informations du formateur
- [x] Corriger la jointure pour inclure les données du formateur
- [x] Vérifier l'affichage dans AdminSequences.tsx
- [x] Ajouter formateurId dans le schéma de validation de sequences.create
- [x] Ajouter formateurId dans le schéma de validation de sequences.update
- [x] Corriger le schéma Zod pour accepter null (formateurId: z.number().nullable().optional())
- [x] Modifier FormateurCombobox pour stocker l'ID au lieu du nom
- [x] Tester les modifications dans la liste et dans le dialog de modification