diff --git a/.manus/db/db-query-1763630401416.json b/.manus/db/db-query-1763630401416.json new file mode 100644 index 0000000..c584325 --- /dev/null +++ b/.manus/db/db-query-1763630401416.json @@ -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 +} \ No newline at end of file diff --git a/.manus/db/db-query-1763630454076.json b/.manus/db/db-query-1763630454076.json new file mode 100644 index 0000000..e94139f --- /dev/null +++ b/.manus/db/db-query-1763630454076.json @@ -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 +} \ No newline at end of file diff --git a/.manus/db/db-query-1763630621905.json b/.manus/db/db-query-1763630621905.json new file mode 100644 index 0000000..9025fbc --- /dev/null +++ b/.manus/db/db-query-1763630621905.json @@ -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 +} \ No newline at end of file diff --git a/.manus/db/db-query-1763630634589.json b/.manus/db/db-query-1763630634589.json new file mode 100644 index 0000000..38e2668 --- /dev/null +++ b/.manus/db/db-query-1763630634589.json @@ -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 +} \ No newline at end of file diff --git a/.manus/db/db-query-1763630882764.json b/.manus/db/db-query-1763630882764.json new file mode 100644 index 0000000..7a25441 --- /dev/null +++ b/.manus/db/db-query-1763630882764.json @@ -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 +} \ No newline at end of file diff --git a/.manus/db/db-query-error-1763630385067.json b/.manus/db/db-query-error-1763630385067.json new file mode 100644 index 0000000..d3128aa --- /dev/null +++ b/.manus/db/db-query-error-1763630385067.json @@ -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'" + ] +} \ No newline at end of file diff --git a/client/src/components/FormateurCombobox.tsx b/client/src/components/FormateurCombobox.tsx index c28703d..891312a 100644 --- a/client/src/components/FormateurCombobox.tsx +++ b/client/src/components/FormateurCombobox.tsx @@ -64,7 +64,7 @@ export default function FormateurCombobox({ createMutation.mutate({ nom: newFormateurNom.trim() }); }; - const selectedFormateur = formateurs?.find((f) => f.nom === value); + const selectedFormateur = formateurs?.find((f) => f.id.toString() === value); return ( <> @@ -89,7 +89,7 @@ export default function FormateurCombobox({ {formateurs?.map((formateur) => ( { onChange(currentValue === value ? "" : currentValue); setOpen(false); @@ -98,7 +98,7 @@ export default function FormateurCombobox({ {formateur.nom} diff --git a/client/src/pages/AdminSequences.tsx b/client/src/pages/AdminSequences.tsx index 396e91b..51eab28 100644 --- a/client/src/pages/AdminSequences.tsx +++ b/client/src/pages/AdminSequences.tsx @@ -144,6 +144,7 @@ export default function AdminSequences() { capaciteMax: sequence.capaciteMax?.toString() || "12", dateBlocage: safeFormatDate(sequence.dateBlocage), statut: sequence.statut || "ouverte", + formateur: sequence.formateurId?.toString() || "", dates: (sequence.dates || []).map((d: any) => ({ dateDebut: safeFormatDate(d.dateDebut), dateFin: safeFormatDate(d.dateFin), @@ -169,6 +170,7 @@ export default function AdminSequences() { capaciteMax: parseInt(formData.capaciteMax), dateBlocage: formData.dateBlocage, statut: formData.statut, + formateurId: formData.formateur ? parseInt(formData.formateur) : null, dates: formData.dates, }; @@ -654,7 +656,7 @@ export default function AdminSequences() { {sequence.lieu} - {sequence.formateur || "-"} + {sequence.formateur?.nom || "-"} {getPublicCibleLabel(sequence.publicCible)} diff --git a/drizzle/0011_natural_cyclops.sql b/drizzle/0011_natural_cyclops.sql new file mode 100644 index 0000000..2a703e5 --- /dev/null +++ b/drizzle/0011_natural_cyclops.sql @@ -0,0 +1 @@ +ALTER TABLE `sequences` ADD `formateurId` int; \ No newline at end of file diff --git a/drizzle/meta/0011_snapshot.json b/drizzle/meta/0011_snapshot.json new file mode 100644 index 0000000..6ab9c46 --- /dev/null +++ b/drizzle/meta/0011_snapshot.json @@ -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": {} + } +} \ No newline at end of file diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json index 2c6a11f..befeede 100644 --- a/drizzle/meta/_journal.json +++ b/drizzle/meta/_journal.json @@ -78,6 +78,13 @@ "when": 1763628773882, "tag": "0010_aspiring_kitty_pryde", "breakpoints": true + }, + { + "idx": 11, + "version": "5", + "when": 1763630439521, + "tag": "0011_natural_cyclops", + "breakpoints": true } ] } \ No newline at end of file diff --git a/drizzle/schema.ts b/drizzle/schema.ts index 5566a1e..875088c 100644 --- a/drizzle/schema.ts +++ b/drizzle/schema.ts @@ -73,6 +73,8 @@ export const sequences = mysqlTable("sequences", { lieu: varchar("lieu", { length: 500 }).notNull(), /** Public cible de la séquence (Directeur, Chef de service, Autre) */ publicCible: mysqlEnum("publicCible", ["directeur", "chef_service", "autre"]).notNull(), + /** ID du formateur assigné à cette séquence */ + formateurId: int("formateurId"), /** Capacité maximale (12 par défaut) */ capaciteMax: int("capaciteMax").default(12).notNull(), /** Date de blocage des inscriptions (J-15 avant la première date) */ diff --git a/server/db.ts b/server/db.ts index 9e57132..5a6b619 100644 --- a/server/db.ts +++ b/server/db.ts @@ -186,13 +186,23 @@ export async function getSequencesWithFormation() { 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( seqs.map(async (seq) => { 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 { ...seq, formation: formation.length > 0 ? { id: formation[0].id, nom: formation[0].nom } : null, + formateur, }; }) ); diff --git a/server/routers.ts b/server/routers.ts index e6a8c11..e1a29f1 100644 --- a/server/routers.ts +++ b/server/routers.ts @@ -188,6 +188,7 @@ export const appRouter = router({ nom: z.string().min(1), lieu: z.string().min(1), publicCible: z.enum(["directeur", "chef_service", "autre"]), + formateurId: z.number().nullable().optional(), capaciteMax: z.number().default(12), dateBlocage: z.string(), statut: z.enum(["ouverte", "bloquee", "terminee"]).optional(), @@ -227,6 +228,7 @@ export const appRouter = router({ nom: z.string().min(1), lieu: z.string().min(1), publicCible: z.enum(["directeur", "chef_service", "autre"]), + formateurId: z.number().nullable().optional(), capaciteMax: z.number(), dateBlocage: z.string(), statut: z.enum(["ouverte", "bloquee", "terminee"]), diff --git a/todo.md b/todo.md index c0aa485..4b3014e 100644 --- a/todo.md +++ b/todo.md @@ -344,3 +344,13 @@ - [x] Identifier le code qui appelle formateurs.create - [x] Ajouter la procédure formateurs.create manquante dans le routeur - [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