From 86a3d44fd46527ff200f70e81236cd9d37e25f11 Mon Sep 17 00:00:00 2001 From: ErickMascarenhas <159568716+ErickMascarenhas@users.noreply.github.com> Date: Wed, 5 Aug 2026 17:01:07 -0300 Subject: [PATCH] feat: allow an undefined TEA support level when registering a student --- .../reports/screens/report-detail-screen.tsx | 1 + features/reports/utils/export-report.ts | 1 + .../sessions/hooks/use-student-profile.ts | 1 + .../sessions/hooks/use-student-sessions.ts | 1 + features/settings/constants/translations.ts | 9 +++++++ features/students/components/new-student.tsx | 1 + features/students/hooks/use-students.ts | 18 ++++++-------- features/students/screens/students-screen.tsx | 2 +- features/students/utils/support-level.ts | 24 +++++++++++++++++++ features/teams/hooks/use-team-data.ts | 24 ++----------------- ...0260805120000_nivel_suporte_indefinido.sql | 18 ++++++++++++++ 11 files changed, 66 insertions(+), 34 deletions(-) create mode 100644 features/students/utils/support-level.ts create mode 100644 supabase/migrations/20260805120000_nivel_suporte_indefinido.sql diff --git a/features/reports/screens/report-detail-screen.tsx b/features/reports/screens/report-detail-screen.tsx index 595a32ac..289cda61 100644 --- a/features/reports/screens/report-detail-screen.tsx +++ b/features/reports/screens/report-detail-screen.tsx @@ -68,6 +68,7 @@ function fmtSupportLevel( if (raw === "nivel_1") return t("reports.supportLevel1"); if (raw === "nivel_2") return t("reports.supportLevel2"); if (raw === "nivel_3") return t("reports.supportLevel3"); + if (raw === "indefinido") return t("reports.supportLevelUndefined"); return raw; } diff --git a/features/reports/utils/export-report.ts b/features/reports/utils/export-report.ts index 69651e87..b965db92 100644 --- a/features/reports/utils/export-report.ts +++ b/features/reports/utils/export-report.ts @@ -62,6 +62,7 @@ function fmtSupportLevel(raw: string | null, t: T): string { if (raw === "nivel_1") return t("reports.supportLevel1"); if (raw === "nivel_2") return t("reports.supportLevel2"); if (raw === "nivel_3") return t("reports.supportLevel3"); + if (raw === "indefinido") return t("reports.supportLevelUndefined"); return raw; } diff --git a/features/sessions/hooks/use-student-profile.ts b/features/sessions/hooks/use-student-profile.ts index 88c59ed6..7e2f30b8 100644 --- a/features/sessions/hooks/use-student-profile.ts +++ b/features/sessions/hooks/use-student-profile.ts @@ -19,6 +19,7 @@ function formatSupportLevel(level: string | null): string | null { if (level === "nivel_1") return "Nível 1"; if (level === "nivel_2") return "Nível 2"; if (level === "nivel_3") return "Nível 3"; + if (level === "indefinido") return "Indefinido"; return level; } diff --git a/features/sessions/hooks/use-student-sessions.ts b/features/sessions/hooks/use-student-sessions.ts index a77bedef..05a7ccd5 100644 --- a/features/sessions/hooks/use-student-sessions.ts +++ b/features/sessions/hooks/use-student-sessions.ts @@ -119,6 +119,7 @@ export function useStudentSessions(studentId?: string, options?: UseStudentSessi if (level === "nivel_1") return "Nível 1"; if (level === "nivel_2") return "Nível 2"; if (level === "nivel_3") return "Nível 3"; + if (level === "indefinido") return "Indefinido"; return level; }; diff --git a/features/settings/constants/translations.ts b/features/settings/constants/translations.ts index ad097a18..f7ec9e1e 100644 --- a/features/settings/constants/translations.ts +++ b/features/settings/constants/translations.ts @@ -596,6 +596,7 @@ export type TranslationKey = | "students.support.n1" | "students.support.n2" | "students.support.n3" + | "students.support.undefined" | "students.deleteTitle" | "students.form.createTitle" | "students.form.editTitle" @@ -615,6 +616,7 @@ export type TranslationKey = | "students.form.supportOption1" | "students.form.supportOption2" | "students.form.supportOption3" + | "students.form.supportOptionUndefined" | "students.form.healthConditions" | "students.form.healthConditionsPlaceholder" | "students.form.observations" @@ -801,6 +803,7 @@ export type TranslationKey = | "reports.supportLevel1" | "reports.supportLevel2" | "reports.supportLevel3" + | "reports.supportLevelUndefined" | "export.selectFormat" | "export.pdfWithCharts" | "export.csvTabular" @@ -1700,6 +1703,7 @@ export const translations: Record> = { "students.support.n1": "TEA nível 1", "students.support.n2": "TEA nível 2", "students.support.n3": "TEA nível 3", + "students.support.undefined": "TEA nível indefinido", "students.deleteTitle": "Excluir aluno?", "students.form.createTitle": "Novo aluno", "students.form.editTitle": "Editar aluno", @@ -1719,6 +1723,7 @@ export const translations: Record> = { "students.form.supportOption1": "Transtorno do Espectro Autista Nível 1", "students.form.supportOption2": "Transtorno do Espectro Autista Nível 2", "students.form.supportOption3": "Transtorno do Espectro Autista Nível 3", + "students.form.supportOptionUndefined": "Indefinido", "students.form.healthConditions": "Outras condições de saúde", "students.form.healthConditionsPlaceholder": "Outras condições de saúde (opcional)", "students.form.observations": "Observações", @@ -1916,6 +1921,7 @@ export const translations: Record> = { "reports.supportLevel1": "Nível 1", "reports.supportLevel2": "Nível 2", "reports.supportLevel3": "Nível 3", + "reports.supportLevelUndefined": "Indefinido", "export.selectFormat": "Selecionar formato", "export.pdfWithCharts": "PDF (com gráficos)", "export.csvTabular": "CSV (dados tabulares)", @@ -2812,6 +2818,7 @@ export const translations: Record> = { "students.support.n1": "ASD level 1", "students.support.n2": "ASD level 2", "students.support.n3": "ASD level 3", + "students.support.undefined": "ASD level undefined", "students.deleteTitle": "Delete student?", "students.form.createTitle": "New student", "students.form.editTitle": "Edit student", @@ -2831,6 +2838,7 @@ export const translations: Record> = { "students.form.supportOption1": "Autism Spectrum Disorder Level 1", "students.form.supportOption2": "Autism Spectrum Disorder Level 2", "students.form.supportOption3": "Autism Spectrum Disorder Level 3", + "students.form.supportOptionUndefined": "Undefined", "students.form.healthConditions": "Other health conditions", "students.form.healthConditionsPlaceholder": "Other health conditions (optional)", "students.form.observations": "Notes", @@ -3027,6 +3035,7 @@ export const translations: Record> = { "reports.supportLevel1": "Level 1", "reports.supportLevel2": "Level 2", "reports.supportLevel3": "Level 3", + "reports.supportLevelUndefined": "Undefined", "export.selectFormat": "Select format", "export.pdfWithCharts": "PDF (with charts)", "export.csvTabular": "CSV (tabular data)", diff --git a/features/students/components/new-student.tsx b/features/students/components/new-student.tsx index d8f5a29e..2ae03c42 100644 --- a/features/students/components/new-student.tsx +++ b/features/students/components/new-student.tsx @@ -75,6 +75,7 @@ export function NewStudent({ t("students.form.supportOption1"), t("students.form.supportOption2"), t("students.form.supportOption3"), + t("students.form.supportOptionUndefined"), ]; useEffect(() => { diff --git a/features/students/hooks/use-students.ts b/features/students/hooks/use-students.ts index 27198901..f0ba0291 100644 --- a/features/students/hooks/use-students.ts +++ b/features/students/hooks/use-students.ts @@ -1,5 +1,6 @@ import { supabase } from "@/lib/supabase"; import { calculateAge } from "@/lib/date-utils"; +import { toSupportLevelCode } from "@/features/students/utils/support-level"; import { useI18n } from "@/features/settings/contexts/i18n-context"; import { resolveEquipeId } from "@/lib/resolve-equipe-id"; import { uploadImage } from "@/lib/upload-image"; @@ -125,11 +126,13 @@ const loadStudents = useCallback(async (showLoader = true) => { weight: Number(aluno.peso) || 0, height: Number(aluno.altura) || 0, waist: Number(aluno.cintura) || 0, - supportLevel: + supportLevel: aluno.nivel_suporte === "nivel_1" ? "Nível 1" : aluno.nivel_suporte === "nivel_2" ? "Nível 2" - : "Nível 3", + : aluno.nivel_suporte === "nivel_3" + ? "Nível 3" + : "Indefinido", healthConditions: aluno.diagnostico_detalhado || "", observations: aluno.observacoes_clinicas || "", avatarUrl: aluno.avatar_url, @@ -188,10 +191,7 @@ const loadStudents = useCallback(async (showLoader = true) => { : (await uploadImage("avatares", photoUri, "alunos")) ?? null; } - let nivelSuporteDb = "nivel_1"; - const supportLower = data.supportLevel.toLowerCase(); - if (supportLower.includes("2")) nivelSuporteDb = "nivel_2"; - if (supportLower.includes("3")) nivelSuporteDb = "nivel_3"; + const nivelSuporteDb = toSupportLevelCode(data.supportLevel); let formattedDate = data.birthDate; if (formattedDate.includes("/")) { @@ -271,11 +271,7 @@ const loadStudents = useCallback(async (showLoader = true) => { } if (data.supportLevel !== undefined) { - let nivelSuporteDb = "nivel_1"; - const supportLower = data.supportLevel.toLowerCase(); - if (supportLower.includes("2")) nivelSuporteDb = "nivel_2"; - if (supportLower.includes("3")) nivelSuporteDb = "nivel_3"; - payload.nivel_suporte = nivelSuporteDb; + payload.nivel_suporte = toSupportLevelCode(data.supportLevel); } if (data.birthDate !== undefined) { diff --git a/features/students/screens/students-screen.tsx b/features/students/screens/students-screen.tsx index 3954ee21..d63e61ee 100644 --- a/features/students/screens/students-screen.tsx +++ b/features/students/screens/students-screen.tsx @@ -65,7 +65,7 @@ export function StudentsScreen({ tutorial = false }: StudentsScreenProps) { if (level.includes("1")) return t("students.support.n1"); if (level.includes("2")) return t("students.support.n2"); if (level.includes("3")) return t("students.support.n3"); - return level; + return t("students.support.undefined"); }; const content = ( diff --git a/features/students/utils/support-level.ts b/features/students/utils/support-level.ts new file mode 100644 index 00000000..fcd9daec --- /dev/null +++ b/features/students/utils/support-level.ts @@ -0,0 +1,24 @@ +/** A TEA support level as stored in `alunos.nivel_suporte`. */ +export type SupportLevelCode = "nivel_1" | "nivel_2" | "nivel_3" | "indefinido"; + +/** + * Maps the support level shown in the UI back to the code the database stores. + * + * @param label - Any support level wording the app produces: a picked option + * ("Transtorno do Espectro Autista Nível 2"), a short display label + * ("Nível 2", "Indefinido") or the stored code itself ("nivel_2"). + * @returns The matching code, or "indefinido" when no level can be identified. + * + * @remarks + * The level is identified by its digit — the only part every wording shares, + * in both locales and in the stored code. No wording of "Indefinido" carries a + * digit, so it doubles as the fallback: an unknown or empty support level is + * exactly an undefined one, and is now storable as such. + */ +export function toSupportLevelCode(label: string | null | undefined): SupportLevelCode { + const text = label ?? ""; + if (text.includes("1")) return "nivel_1"; + if (text.includes("2")) return "nivel_2"; + if (text.includes("3")) return "nivel_3"; + return "indefinido"; +} diff --git a/features/teams/hooks/use-team-data.ts b/features/teams/hooks/use-team-data.ts index 20b860b4..a0668217 100644 --- a/features/teams/hooks/use-team-data.ts +++ b/features/teams/hooks/use-team-data.ts @@ -2,6 +2,7 @@ import { resolveEquipeId } from "@/lib/resolve-equipe-id"; import { supabase } from "@/lib/supabase"; import { calculateAge } from "@/lib/date-utils"; import { uploadImage } from "@/lib/upload-image"; +import { toSupportLevelCode } from "@/features/students/utils/support-level"; import { useI18n } from "@/features/settings/contexts/i18n-context"; import { useEffect, useState } from "react"; import { Alert } from "react-native"; @@ -224,28 +225,7 @@ export function useTeamData() { formattedDate = `${year}-${month}-${day}`; } - let nivelSuporteDb = "nivel_1"; - const suporteText = data.supportLevel?.toLowerCase() || ""; - - if ( - suporteText.includes("nível 1") || - suporteText.includes("nivel 1") || - suporteText === "nivel_1" - ) { - nivelSuporteDb = "nivel_1"; - } else if ( - suporteText.includes("nível 2") || - suporteText.includes("nivel 2") || - suporteText === "nivel_2" - ) { - nivelSuporteDb = "nivel_2"; - } else if ( - suporteText.includes("nível 3") || - suporteText.includes("nivel 3") || - suporteText === "nivel_3" - ) { - nivelSuporteDb = "nivel_3"; - } + const nivelSuporteDb = toSupportLevelCode(data.supportLevel); const basePayload = { nome_completo: data.name, diff --git a/supabase/migrations/20260805120000_nivel_suporte_indefinido.sql b/supabase/migrations/20260805120000_nivel_suporte_indefinido.sql new file mode 100644 index 00000000..fe027f55 --- /dev/null +++ b/supabase/migrations/20260805120000_nivel_suporte_indefinido.sql @@ -0,0 +1,18 @@ +-- ======================================================================= +-- Migration: nível de suporte TEA passa a aceitar "Indefinido" +-- ======================================================================= +-- Nem toda criança chega ao programa com o nível de suporte já definido em +-- laudo. Até aqui o cadastro obrigava a escolher entre os níveis 1, 2 e 3, +-- o que forçava o avaliador a chutar um nível — e o chute vira histórico +-- clínico. O ENUM ganha um valor explícito para esse caso. +-- +-- A coluna alunos.nivel_suporte é NOT NULL, então "não sei ainda" não pode +-- ser representado por NULL: precisa ser um valor do próprio tipo. +-- +-- Mudança puramente aditiva: nenhum registro existente é alterado e os três +-- níveis continuam válidos. + +ALTER TYPE nivel_suporte_tea ADD VALUE IF NOT EXISTS 'indefinido'; + +COMMENT ON TYPE nivel_suporte_tea IS + 'Nível de suporte TEA do aluno. "indefinido" cobre quem ainda não tem o nível determinado.';