feat: mejorar la gestión de niveles de inglés en la selección de cursos
This commit is contained in:
@@ -1210,6 +1210,87 @@ pub async fn get_mysql_courses_by_plan(
|
|||||||
.await
|
.await
|
||||||
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al obtener los cursos: {}", e)))?;
|
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("Error al obtener los cursos: {}", e)))?;
|
||||||
|
|
||||||
|
// Intentar refrescar desde MySQL (fuente SAM) para evitar listas incompletas por espejo desactualizado.
|
||||||
|
if let Ok(mysql_pool) = connect_mysql_pool("MYSQL_DATABASE_URL").await {
|
||||||
|
let live_courses: Result<Vec<MySqlCourseInfo>, sqlx::Error> = sqlx::query_as(
|
||||||
|
r#"
|
||||||
|
SELECT DISTINCT
|
||||||
|
c.idCursos AS id_cursos,
|
||||||
|
c.NombreCurso AS nombre_curso,
|
||||||
|
c.NivelCurso AS nivel_curso,
|
||||||
|
pe.idPlanDeEstudios AS id_plan_de_estudios,
|
||||||
|
pe.Nombre AS nombre_plan,
|
||||||
|
c.Duracion AS duracion
|
||||||
|
FROM curso c
|
||||||
|
JOIN plandeestudios pe ON c.idPlanDeEstudios = pe.idPlanDeEstudios
|
||||||
|
WHERE c.Activo = 1
|
||||||
|
AND pe.Activo = 1
|
||||||
|
AND pe.idPlanDeEstudios = ?
|
||||||
|
ORDER BY c.NivelCurso, c.NombreCurso
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.bind(filters.plan_id)
|
||||||
|
.fetch_all(&mysql_pool)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
match live_courses {
|
||||||
|
Ok(live) if !live.is_empty() => {
|
||||||
|
if live.len() != courses.len() {
|
||||||
|
tracing::info!(
|
||||||
|
"Refrescando cursos SAM desde MySQL para plan {}: espejo={} mysql={}",
|
||||||
|
filters.plan_id,
|
||||||
|
courses.len(),
|
||||||
|
live.len()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Best effort: sincronizar también el plan consultado al espejo PostgreSQL.
|
||||||
|
let live_plans: Result<Vec<MySqlPlanInfo>, sqlx::Error> = sqlx::query_as(
|
||||||
|
r#"
|
||||||
|
SELECT DISTINCT
|
||||||
|
pe.idPlanDeEstudios AS id_plan_de_estudios,
|
||||||
|
pe.Nombre AS nombre_plan
|
||||||
|
FROM plandeestudios pe
|
||||||
|
WHERE pe.Activo = 1
|
||||||
|
AND pe.idPlanDeEstudios = ?
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.bind(filters.plan_id)
|
||||||
|
.fetch_all(&mysql_pool)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
if let Ok(plan_rows) = live_plans {
|
||||||
|
if !plan_rows.is_empty() {
|
||||||
|
if let Err(err) = save_mysql_courses_and_plans(&pool, org_ctx.id, plan_rows, live.clone()).await {
|
||||||
|
tracing::warn!(
|
||||||
|
"No se pudo actualizar espejo SAM para plan {}: {}",
|
||||||
|
filters.plan_id,
|
||||||
|
err
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
courses = live;
|
||||||
|
}
|
||||||
|
Ok(_) => {
|
||||||
|
tracing::debug!(
|
||||||
|
"MySQL devolvio 0 cursos activos para plan {}; se mantiene espejo local",
|
||||||
|
filters.plan_id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
tracing::warn!(
|
||||||
|
"No se pudo refrescar cursos SAM desde MySQL para plan {}: {}",
|
||||||
|
filters.plan_id,
|
||||||
|
err
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mysql_pool.close().await;
|
||||||
|
}
|
||||||
|
|
||||||
// Respaldo compatible con versiones anteriores: si el reflejo SAM está vacío, usar el reflejo de metadatos heredado.
|
// Respaldo compatible con versiones anteriores: si el reflejo SAM está vacío, usar el reflejo de metadatos heredado.
|
||||||
if courses.is_empty() {
|
if courses.is_empty() {
|
||||||
courses = sqlx::query_as(
|
courses = sqlx::query_as(
|
||||||
|
|||||||
@@ -249,14 +249,15 @@ export default function AdminSharedMaterialsPage() {
|
|||||||
setSelectedCourseId(value);
|
setSelectedCourseId(value);
|
||||||
setSplitToRegular(false);
|
setSplitToRegular(false);
|
||||||
const selected = courses.find((c) => c.idCursos === value);
|
const selected = courses.find((c) => c.idCursos === value);
|
||||||
if (selected?.NivelCurso !== undefined && selected?.NivelCurso !== null) {
|
if (selected?.NombreCurso) {
|
||||||
const n = selected.NivelCurso;
|
const normalized = selected.NombreCurso.toUpperCase().replace(/\s*INTENSIVE\s*/g, '').trim();
|
||||||
if (n <= 2) setEnglishLevel('beginner_1');
|
if (normalized.includes('ELEMENTARY')) setEnglishLevel('elementary');
|
||||||
else if (n <= 4) setEnglishLevel('beginner_2');
|
else if (normalized.includes('BEGINNER')) setEnglishLevel('beginner');
|
||||||
else if (n <= 6) setEnglishLevel('intermediate_1');
|
else if (normalized.includes('PRE-INTERMEDIATE') || normalized.includes('PRE INTERMEDIATE')) setEnglishLevel('pre_intermediate');
|
||||||
else if (n <= 8) setEnglishLevel('intermediate_2');
|
else if (normalized.includes('LOW INTERMEDIATE')) setEnglishLevel('low_intermediate');
|
||||||
else if (n <= 10) setEnglishLevel('advanced_1');
|
else if (normalized.includes('UPPER-INTERMEDIATE') || normalized.includes('UPPER INTERMEDIATE')) setEnglishLevel('upper_intermediate');
|
||||||
else setEnglishLevel('advanced_2');
|
else if (normalized.includes('PRE ADVANCED') || normalized.includes('PRE-ADVANCED')) setEnglishLevel('pre_advanced');
|
||||||
|
else if (normalized.includes('ADVANCED')) setEnglishLevel('advanced');
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
disabled={!selectedPlanId}
|
disabled={!selectedPlanId}
|
||||||
@@ -359,15 +360,13 @@ export default function AdminSharedMaterialsPage() {
|
|||||||
className="w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm"
|
className="w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm"
|
||||||
>
|
>
|
||||||
<option value="">Sin nivel (general)</option>
|
<option value="">Sin nivel (general)</option>
|
||||||
|
<option value="elementary">Elementary</option>
|
||||||
<option value="beginner">Beginner</option>
|
<option value="beginner">Beginner</option>
|
||||||
<option value="beginner_1">Beginner 1</option>
|
<option value="pre_intermediate">Pre Intermediate</option>
|
||||||
<option value="beginner_2">Beginner 2</option>
|
<option value="low_intermediate">Low Intermediate</option>
|
||||||
<option value="intermediate">Intermediate</option>
|
<option value="upper_intermediate">Upper Intermediate</option>
|
||||||
<option value="intermediate_1">Intermediate 1</option>
|
<option value="pre_advanced">Pre Advanced</option>
|
||||||
<option value="intermediate_2">Intermediate 2</option>
|
|
||||||
<option value="advanced">Advanced</option>
|
<option value="advanced">Advanced</option>
|
||||||
<option value="advanced_1">Advanced 1</option>
|
|
||||||
<option value="advanced_2">Advanced 2</option>
|
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user