Session: dbd6ce87-b45b-4114-bc43-fb2b55a3d387
Coverage
1
Selected
1
Completed
0
Reused
0
Failed
0
Waived
Token Usage
705.13K
Prompt Tokens
32.97K
Completion Tokens
738.11K
Total Tokens
29
LLM Requests
654.85K
Cache Read
0
Cache Write
File breakdown 1 files
| File | Prompt | Completion | Cache Read | Cache Write | Total |
|---|---|---|---|---|---|
| templates/ssma/occurrence/partials/_modal_event.html.twig | 705.13K | 32.97K | 654.85K | 0 | 738.11K |
Files Reviewed 1 files
- templates/ssma/occurrence/partials/_modal_event.html.twig
Conversations 1 files
templates/ssma/occurrence/partials/_modal_event.html.twig 29 requests
main_task
Request #1
deepseek-v4-flash
P:5.7K C:267 CR:2.69K CW:0
2159ms
Reasoning
Let me analyze this code review task. The change is in `templates/ssma/occurrence/partials/_modal_event.html.twig`. Two lines added calling `evSyncDescaracterStageUi()` at the end of `evCreateInjuredPersonCard()` and `evRenderInjuredPersonBoxes()`.
Let me look at the context around these changes to understand what's happening. I need to read the file to understand the functions and check whether `evSyncDescaracterStageUi` is defined and whether the calls are correct.
Let me read the file context around the changed lines (2706 and 2823).
Tool Calls (2)
file_read
Show Details
Arguments
{"file_path": "templates/ssma/occurrence/partials/_modal_event.html.twig", "start_line": 2600, "end_line": 2900}
Result
File: templates/ssma/occurrence/partials/_modal_event.html.twig (Total lines: 7712)
IS_TRUNCATED: false
LINE_RANGE: 2600-2900
2600| if (el.classList.contains('ev-inj-had-injury') && typeof window.evSyncHadInjuryUi === 'function') {
2601| window.evSyncHadInjuryUi();
2602| }
2603| if (el.classList.contains('ev-inj-injury-classification')) {
2604| evSyncCardCatFromClassification(card);
2605| }
2606| if (el.classList.contains('ev-inj-consequence')) {
2607| evSyncCardDerivedSeverity(card);
2608| evSyncCardPotentialGteReal(card);
2609| evSyncInjuryFieldsByConsequence();
2610| }
2611| if (el.classList.contains('ev-inj-potential-consequence')) {
2612| evSyncCardPotentialGteReal(card);
2613| }
2614| evUpdateInjuredCardSummary(card);
2615| evSyncInjuredPersonDetailsHidden();
2616| evPersistDraftSoon();
2617| });
2618| el.addEventListener('input', function () {
2619| evSyncInjuredPersonDetailsHidden();
2620| evPersistDraftSoon();
2621| });
2622| });
2623|
2624| card.querySelectorAll('.ev-inj-descaracter-btn').forEach(function (btn) {
2625| btn.addEventListener('click', function () {
2626| var val = this.getAttribute('data-descaracter-val');
2627| if (val === '1' && !evCanDescharacterizeAccident()) {
2628| return;
2629| }
2630| card.setAttribute('data-descaracterizado', val);
2631| var hidden = document.getElementById('ev_descaracterizado');
2632| if (hidden) hidden.value = val;
2633| var toggle = card.querySelector('.ev-inj-descaracter-toggle');
2634| if (toggle) toggle.classList.remove('is-invalid');
2635| evSyncDescaracterUi();
2636| evSyncInjuredPersonDetailsHidden();
2637| evPersistDraftSoon();
2638| });
2639| });
2640| card.querySelectorAll('.ev-inj-descaracter-comment').forEach(function (ta) {
2641| ta.addEventListener('input', function () {
2642| ta.classList.remove('is-invalid');
2643| });
2644| });
2645| evFilterCardConsequences(card);
2646| evSyncCardCatFromClassification(card);
2647| evSyncDescaracterUi();
2648| if (window.jQuery && window.jQuery.fn.tooltip) {
2649| window.jQuery(card).find('.ev-inj-descaracter-tip').tooltip({ container: 'body' });
2650| }
2651| }
2652|
2653| function evCreateInjuredPersonCard(personId, saved, expand) {
2654| var wrap = document.getElementById('ev_injured_person_boxes');
2655| var tpl = document.getElementById('ev-injured-person-box-tpl');
2656| if (!wrap || !tpl || !personId) return null;
2657| var safe = String(personId).replace(/"/g, '');
2658| var existing = wrap.querySelector('.ev-injured-person-box[data-person-id="' + safe + '"]');
2659| if (existing) return existing;
2660|
2661| var source = tpl.querySelector('.ev-injured-person-box') || tpl.firstElementChild;
2662| if (!source) return null;
2663| var card = source.cloneNode(true);
2664| if (!card || !card.classList) return null;
2665| card.classList.remove('d-none');
2666|
2667| var involved = evGetPeopleInvolved();
2668| var sel = document.getElementById('ev_person_id');
2669| var opt = sel ? sel.querySelector('option[value="' + safe + '"]') : null;
2670| var name = involved.names[personId]
2671| || (opt ? String(opt.text || '').trim() : '')
2672| || ('#' + personId);
2673|
2674| card.setAttribute('data-person-id', String(personId));
2675| var nameEl = card.querySelector('.ev-inj-person-name');
2676| if (nameEl) nameEl.textContent = name;
2677| var sumName = card.querySelector('.js-ev-inj-summary-name');
2678| if (sumName) sumName.textContent = name;
2679|
2680| saved = saved || {};
2681| if (!saved.attendance_date) saved.attendance_date = evTodayDateInputValue();
2682| if (saved.had_injury === undefined) saved.had_injury = true;
2683| evApplyCardInjuryData(card, saved);
2684|
2685| evRenderInjuredPersonSummary(card, personId);
2686|
2687| wrap.appendChild(card);
2688| evBindInjuredCardEvents(card);
2689|
2690| if (expand) {
2691| evExpandInjuredCard(card);
2692| } else {
2693| evCollapseInjuredCard(card, true);
2694| if (evCurrentStep === 'aprofundamento'
2695| && evSelectedType() === 'ACIDENTE_PESSOAL'
2696| && !wrap.querySelector('.ev-injured-person-box.is-expanded')) {
2697| evExpandInjuredCard(card);
2698| }
2699| }
2700| if (evCurrentStep === 'aprofundamento' && evSelectedType() === 'ACIDENTE_PESSOAL') {
2701| if (typeof syncInjuryFieldsForCard === 'function') {
2702| syncInjuryFieldsForCard(card);
2703| }
2704| if (typeof evFilterCardConsequences === 'function') {
2705| evFilterCardConsequences(card);
2706| }
2707| }
2708| evEnsurePrimaryInjuredMarked();
2709| evSyncDescaracterStageUi();
2710| return card;
2711| }
2712|
2713| function evRemoveInjuredPersonBox(personId) {
2714| var wrap = document.getElementById('ev_injured_person_boxes');
2715| if (!wrap || !personId) return;
2716| var safe = String(personId).replace(/"/g, '');
2717| var card = wrap.querySelector('.ev-injured-person-box[data-person-id="' + safe + '"]');
2718| if (!card) return;
2719| var wasPrimary = card.classList.contains('is-primary');
2720| if (card.classList.contains('is-expanded')) {
2721| evParkBodyMapBlock();
2722| evClearCanonicalInjuryIds();
2723| }
2724| card.remove();
2725| var details = evGetInjuredDetailsObj();
2726| delete details[String(personId)];
2727| evSetInjuredDetailsObj(details);
2728| // Não auto-expande a próxima — todas ficam colapsadas até o usuário editar.
2729| if (wasPrimary) {
2730| var next = wrap.querySelector('.ev-injured-person-box[data-person-id]');
2731| if (next) {
2732| evSelectPrimaryInjuredPerson(next.getAttribute('data-person-id'));
2733| } else {
2734| var sel = document.getElementById('ev_person_id');
2735| if (sel) sel.removeAttribute('data-primary-injured-id');
2736| evSyncInjuredPickCircles('');
2737| }
2738| } else {
2739| evSyncPrimaryInjuredPersonId();
2740| }
2741| evFilterInjuredPersonSelect();
2742| evPersistDraftSoon();
2743| evUpdateInjuredPersonsEmptyState();
2744| }
2745|
2746| /**
2747| * Select oculto (legado): adicionar acidentado manualmente — fluxo principal = cards via Pessoas envolvidas.
2748| */
2749| var _evAddingInjuredLock = false;
2750| function evAddInjuredPersonFromSelect() {
2751| if (_evAddingInjuredLock) return;
2752| var sel = document.getElementById('ev_person_id');
2753| if (!sel) return;
2754| var personId = String(sel.value || '');
2755| if (!personId) return;
2756|
2757| _evAddingInjuredLock = true;
2758| try {
2759| var wrap = document.getElementById('ev_injured_person_boxes');
2760| var safe = personId.replace(/"/g, '');
2761| var existing = wrap && wrap.querySelector('.ev-injured-person-box[data-person-id="' + safe + '"]');
2762| if (existing) {
2763| // Mantém colapsada; usuário edita pelo lápis.
2764| evUpdateInjuredCardSummary(existing);
2765| } else {
2766| var saved = evGetInjuredDetailsObj()[personId] || {};
2767| var created = evCreateInjuredPersonCard(personId, saved, false);
2768| if (!created) {
2769| console.warn('[SSMA] Falha ao criar caixinha do acidentado', personId);
2770| } else {
2771| evSyncInjuredPersonDetailsHidden();
2772| }
2773| }
2774| // Limpa o select sem reentrar (setCustomSelectValue dispara change).
2775| sel.value = '';
2776| if (typeof window.setCustomSelectValue === 'function') {
2777| window.setCustomSelectValue('ev_person_id', '');
2778| } else {
2779| evSyncCustomSelectVisual('ev_person_id', true);
2780| }
2781| evSyncPrimaryInjuredPersonId();
2782| evFilterInjuredPersonSelect();
2783| } finally {
2784| _evAddingInjuredLock = false;
2785| }
2786| }
2787|
2788| /** Remonta caixinhas a partir de injured_person_details (+ person_id legado). */
2789| function evRenderInjuredPersonBoxes() {
2790| var wrap = document.getElementById('ev_injured_person_boxes');
2791| if (!wrap) return;
2792| var details = evGetInjuredDetailsObj();
2793| var ids = Object.keys(details);
2794| var primary = '';
2795| var sel = document.getElementById('ev_person_id');
2796| if (sel && sel.value) primary = String(sel.value);
2797| if (!primary && sel && sel.getAttribute('data-primary-injured-id')) {
2798| primary = String(sel.getAttribute('data-primary-injured-id') || '');
2799| }
2800|
2801| if (primary && !details[primary]) {
2802| details[primary] = { attendance_date: evTodayDateInputValue(), had_injury: true, body_parts: [] };
2803| evSetInjuredDetailsObj(details);
2804| ids = Object.keys(details);
2805| }
2806|
2807| evParkBodyMapBlock();
2808| evClearCanonicalInjuryIds();
2809| wrap.innerHTML = '';
2810|
2811| ids.forEach(function (pid) {
2812| // Sempre cria colapsada; expandir só via lápis (ou validação).
2813| evCreateInjuredPersonCard(pid, details[pid] || {}, false);
2814| });
2815| // Respeita primary já salvo; senão marca o primeiro.
2816| var preferred = primary || '';
2817| if (preferred && wrap.querySelector('.ev-injured-person-box[data-person-id="' + preferred.replace(/"/g, '') + '"]')) {
2818| evSelectPrimaryInjuredPerson(preferred);
2819| } else {
2820| evEnsurePrimaryInjuredMarked();
2821| }
2822| evSyncInjuredPersonDetailsHidden();
2823| evSyncPrimaryInjuredPersonId();
2824| evFilterInjuredPersonSelect();
2825| evUpdateInjuredPersonsEmptyState();
2826| evSyncDescaracterStageUi();
2827| if (evCurrentStep === 'aprofundamento' && evSelectedType() === 'ACIDENTE_PESSOAL') {
2828| window.requestAnimationFrame(function () {
2829| if (typeof evEnsurePrimaryInjuredCardExpanded === 'function') {
2830| evEnsurePrimaryInjuredCardExpanded();
2831| }
2832| });
2833| }
2834| }
2835| var evDraftTimer = null;
2836| function evPersistDraftSoon() {
2837| if (evDraftTimer) clearTimeout(evDraftTimer);
2838| evDraftTimer = setTimeout(evPersistDraftNow, 400);
2839| }
2840| function evPersistDraftNow() {
2841| var mode = (document.getElementById('ev_form_mode') || {}).value || 'create';
2842| if (mode !== 'create') return;
2843| try {
2844| var form = document.getElementById('form-event-new');
2845| if (!form) return;
2846| var data = {};
2847| Array.prototype.forEach.call(form.elements, function (el) {
2848| if (!el.name && !el.id) return;
2849| var key = el.id || el.name;
2850| if (!key) return;
2851| if (el.type === 'checkbox' || el.type === 'radio') {
2852| data[key] = !!el.checked;
2853| } else {
2854| data[key] = el.value;
2855| }
2856| });
2857| data.__people_ids = (document.getElementById('ev_people_ids') || {}).value || '';
2858| data.__witness_ids = (document.getElementById('ev_witness_ids') || {}).value || '';
2859| data.__injured_details = (document.getElementById('ev_injured_person_details') || {}).value || '';
2860| sessionStorage.setItem(EV_DRAFT_KEY, JSON.stringify(data));
2861| } catch (e) {}
2862| }
2863| function evClearDraft() {
2864| try { sessionStorage.removeItem(EV_DRAFT_KEY); } catch (e) {}
2865| }
2866| function evRestoreDraftIfAny() {
2867| try {
2868| var raw = sessionStorage.getItem(EV_DRAFT_KEY);
2869| if (!raw) return false;
2870| var data = JSON.parse(raw);
2871| if (!data || typeof data !== 'object') return false;
2872| Object.keys(data).forEach(function (key) {
2873| if (key.indexOf('__') === 0) return;
2874| var el = document.getElementById(key);
2875| if (!el) return;
2876| if (el.type === 'checkbox' || el.type === 'radio') {
2877| el.checked = !!data[key];
2878| } else {
2879| el.value = data[key];
2880| }
2881| });
2882| if (data.__people_ids) {
2883| var pe = document.getElementById('ev_people_ids');
2884| if (pe) pe.value = data.__people_ids;
2885| }
2886| if (data.__witness_ids) {
2887| var we = document.getElementById('ev_witness_ids');
2888| if (we) we.value = data.__witness_ids;
2889| }
2890| if (data.__injured_details) {
2891| var ie = document.getElementById('ev_injured_person_details');
2892| if (ie) ie.value = data.__injured_details;
2893| }
2894| // Remonta caixinhas após restaurar o JSON do draft.
2895| setTimeout(function () {
2896| if (typeof evRenderInjuredPersonBoxes === 'function') evRenderInjuredPersonBoxes();
2897| }, 0);
2898| return true;
2899| } catch (e) {
2900| return false;
code_search
Show Details
Arguments
{"search_text": "evSyncDescaracterStageUi"}
Result
File: templates/ssma/occurrence/partials/_modal_event.html.twig
Match lines: 8
2709| evSyncDescaracterStageUi();
2826| evSyncDescaracterStageUi();
2917| function evSyncDescaracterStageUi() {
2947| evSyncDescaracterStageUi();
3323| evSyncDescaracterStageUi();
3398| evSyncDescaracterStageUi();
5288| evSyncDescaracterStageUi();
5736| evSyncDescaracterStageUi();
Request #2
deepseek-v4-flash
P:10.02K C:206 CR:5.89K CW:0
1686ms
Reasoning
Let me look at the `evSyncDescaracterStageUi` function definition around line 2917 to understand its logic.
Tool Calls (2)
file_read
Show Details
Arguments
{"end_line": 2980, "file_path": "templates/ssma/occurrence/partials/_modal_event.html.twig", "start_line": 2900}
Result
File: templates/ssma/occurrence/partials/_modal_event.html.twig (Total lines: 7712)
IS_TRUNCATED: false
LINE_RANGE: 2900-2980
2900| return false;
2901| }
2902| }
2903|
2904| function evCanDescharacterizeAccident() {
2905| return window.SSMA_CAN_DESCARACTERIZE === true || window.SSMA_CAN_DESCARACTERIZE === 'true';
2906| }
2907|
2908| function evIsDescaracterSuspectChecked() {
2909| var el = document.getElementById('ev_descaracter_suspect');
2910| return !!(el && el.checked);
2911| }
2912|
2913| function evIsCreateMode() {
2914| return ((document.getElementById('ev_form_mode') || { value: 'create' }).value === 'create');
2915| }
2916|
2917| function evSyncDescaracterStageUi() {
2918| var isAp = evSelectedType() === 'ACIDENTE_PESSOAL';
2919| var isDoctorAprof = !!evAprofundamentoOnlyMode;
2920| var form = document.getElementById('form-event-new');
2921| if (form) form.classList.toggle('is-doctor-aprof', isDoctorAprof);
2922| // Checkbox global de suspeita (etapa 1) fica sempre oculto — suspeita agora é por card no aprofundamento.
2923| var suspectWrap = document.getElementById('ev-suspeita-wrap');
2924| if (suspectWrap) {
2925| suspectWrap.classList.add('d-none');
2926| }
2927| document.querySelectorAll('.ev-inj-descaracter').forEach(function (el) {
2928| // Seção de descaracterização aparece sempre que é Acidente Pessoal (criação e aprofundamento).
2929| // Na criação: só o checkbox de suspeita fica visível (Sim/Não oculto via CSS fora do aprofundamento).
2930| el.classList.toggle('d-none', !isAp);
2931| });
2932| // Sincroniza Sim/Não de cada card com o estado do checkbox de suspeita do próprio card.
2933| document.querySelectorAll('.ev-injured-person-box').forEach(function (card) {
2934| var suspChk = card.querySelector('.ev-inj-suspect-chk');
2935| var yesNoWrap = card.querySelector('.ev-inj-descaracter-yesno-wrap');
2936| if (suspChk && yesNoWrap) {
2937| yesNoWrap.classList.toggle('d-none', !suspChk.checked);
2938| }
2939| });
2940| }
2941|
2942| function evSyncDescaracterUi() {
2943| var hidden = document.getElementById('ev_descaracterizado');
2944| var canSn = evCanDescharacterizeAccident();
2945| var cur = String((hidden || {}).value || '');
2946|
2947| evSyncDescaracterStageUi();
2948|
2949| // Pré-seleciona "Sim" quando o profissional não tem permissão de descaracterização
2950| // e o campo ainda está vazio. Ele só pode dizer "Sim" de qualquer forma, então
2951| // pré-preencher evita a validação falhar sem o usuário perceber o que falta.
2952| if (!canSn && cur === '' && evAprofundamentoOnlyMode && hidden) {
2953| hidden.value = '0';
2954| cur = '0';
2955| document.querySelectorAll('.ev-injured-person-box').forEach(function (c) {
2956| c.setAttribute('data-descaracterizado', '0');
2957| });
2958| }
2959|
2960| document.querySelectorAll('.ev-injured-person-box').forEach(function (card) {
2961| var noPerm = card.querySelector('.ev-inj-descaracter-no-perm');
2962| var cardDesc = card.getAttribute('data-descaracterizado') || cur;
2963| if (noPerm) noPerm.classList.toggle('d-none', canSn);
2964| card.querySelectorAll('.ev-inj-descaracter-btn').forEach(function (b) {
2965| var val = b.getAttribute('data-descaracter-val');
2966| // Sem permissão: "Não" fica visível mas desabilitado — o par Sim/Não precisa aparecer.
2967| if (val === '1' && !canSn) {
2968| b.disabled = true;
2969| b.classList.remove('d-none');
2970| b.setAttribute('title', 'Sem permissão para descaracterizar o acidente.');
2971| } else {
2972| b.disabled = false;
2973| b.classList.remove('d-none');
2974| b.removeAttribute('title');
2975| }
2976| });
2977| if (window.SsmaShared && typeof window.SsmaShared.toggleYesNo === 'function') {
2978| window.SsmaShared.toggleYesNo(card.querySelectorAll('.ev-inj-descaracter-btn'), cardDesc !== '' ? cardDesc : null, {
2979| valueAttr: 'data-descaracter-val'
2980| });
file_read
Show Details
Arguments
{"end_line": 3420, "file_path": "templates/ssma/occurrence/partials/_modal_event.html.twig", "start_line": 3300}
Result
File: templates/ssma/occurrence/partials/_modal_event.html.twig (Total lines: 7712)
IS_TRUNCATED: false
LINE_RANGE: 3300-3420
3300| if (panel) panel.classList.toggle('is-readonly', !!readonly);
3301| if (alert) {
3302| alert.classList.toggle('d-none', !readonly);
3303| if (evIsAprofundamentoFinalized() && !EV_IS_ADMIN_APROFUNDAMENTO) {
3304| alert.innerHTML = '<i class="fas fa-lock mr-2"></i>Aprofundamento finalizado. Somente um administrador ou gestor administrador pode alterar.';
3305| } else {
3306| alert.innerHTML = '<i class="fas fa-exclamation-triangle mr-2"></i>O aprofundamento é preenchido pelo profissional responsável (gestor direto do colaborador ou equipe técnica SSMA).';
3307| }
3308| }
3309| var controls = document.querySelectorAll(
3310| '#ev-technical-section input, #ev-technical-section select, #ev-technical-section textarea,' +
3311| '#ev-spec-type-card input, #ev-spec-type-card select, #ev-spec-type-card textarea,' +
3312| '#ev-gravity-wrap input, #ev-gravity-wrap select,' +
3313| '#ev-corrective-actions-section input, #ev-corrective-actions-section select, #ev-corrective-actions-section textarea, #ev-corrective-actions-section button,' +
3314| '#ev-step-aprofundamento .ev-inj-descaracter-btn'
3315| );
3316| Array.prototype.forEach.call(controls, function (el) {
3317| if (!el || el.type === 'hidden') return;
3318| if (el.classList && el.classList.contains('ev-inj-descaracter-suspect-ro')) return;
3319| el.disabled = !!readonly;
3320| });
3321| // Reaplica bloqueio Sem dano — o loop acima zera disabled de todos os selects.
3322| evSyncInjuryTypeByConsequence();
3323| evSyncDescaracterStageUi();
3324| }
3325|
3326| function evUpdateFooter() {
3327| var type = evSelectedType();
3328| var canEditAprofundamento = evCanEditAprofundamento(type);
3329| var back = document.getElementById('ev-btn-back');
3330| var cancel = document.getElementById('ev-btn-cancel');
3331| var save = document.getElementById('ev-btn-save');
3332| var draft = document.getElementById('ev-btn-draft');
3333| var label = document.getElementById('ev-btn-label');
3334| if (draft) {
3335| draft.classList.toggle('d-none', !evAprofundamentoOnlyMode || evCurrentStep !== 'aprofundamento');
3336| }
3337| if (evAprofundamentoOnlyMode) {
3338| if (back) back.classList.add('d-none');
3339| if (cancel) cancel.classList.remove('d-none');
3340| if (!label || !save) return;
3341| if (evIsAprofundamentoFinalized() && !EV_IS_ADMIN_APROFUNDAMENTO) {
3342| save.disabled = true;
3343| save.classList.add('d-none');
3344| if (draft) draft.classList.add('d-none');
3345| return;
3346| }
3347| save.classList.remove('d-none');
3348| save.disabled = false;
3349| label.textContent = evIsAprofundamentoFinalized() ? 'Salvar alterações' : 'Finalizar';
3350| return;
3351| }
3352| if (back) back.classList.toggle('d-none', evCurrentStep !== 'aprofundamento');
3353| if (cancel) cancel.classList.toggle('d-none', evCurrentStep === 'aprofundamento');
3354| if (!label || !save) return;
3355| save.classList.remove('d-none');
3356| save.disabled = false;
3357| if (evCurrentStep === 'general') {
3358| label.innerHTML = (evRequiresAprofundamento(type) && evCanEditAprofundamento(type))
3359| ? 'Aprofundamento <i class="fas fa-chevron-right ml-1"></i>'
3360| : ((document.getElementById('ev_form_mode') || { value: 'create' }).value === 'edit'
3361| ? 'Salvar alterações'
3362| : 'Registrar');
3363| return;
3364| }
3365| label.textContent = (document.getElementById('ev_form_mode') || { value: 'create' }).value === 'edit'
3366| ? 'Salvar alterações'
3367| : 'Registrar';
3368| // Registrar nunca fica bloqueado por falta de permissão de aprofundamento.
3369| save.disabled = false;
3370| }
3371|
3372| function evSetStep(step) {
3373| if (evAprofundamentoOnlyMode) {
3374| step = 'aprofundamento';
3375| }
3376| evCurrentStep = step === 'aprofundamento' ? 'aprofundamento' : 'general';
3377| var general = document.getElementById('ev-step-general');
3378| var apro = document.getElementById('ev-step-aprofundamento');
3379| if (general) {
3380| general.classList.toggle('d-none', evCurrentStep !== 'general');
3381| general.classList.toggle('is-readonly', !!evAprofundamentoOnlyMode);
3382| }
3383| if (apro) apro.classList.toggle('d-none', evCurrentStep !== 'aprofundamento');
3384| document.querySelectorAll('#ev-steps-bar .insp-step-seg').forEach(function (bar) {
3385| var key = bar.getAttribute('data-ev-progress');
3386| if (evAprofundamentoOnlyMode) {
3387| bar.classList.toggle('is-active', key === 'aprofundamento');
3388| bar.classList.toggle('active', key === 'aprofundamento');
3389| } else {
3390| bar.classList.toggle('is-active', key === 'general' || key === evCurrentStep);
3391| bar.classList.toggle('active', key === 'general' || key === evCurrentStep);
3392| }
3393| });
3394| var body = document.querySelector('#modalEventNew-offcanvas-wrapper .offcanvas-body');
3395| if (body) body.scrollTop = 0;
3396| evSetAprofundamentoReadonly(!evCanEditAprofundamento(evSelectedType()));
3397| evUpdateFooter();
3398| evSyncDescaracterStageUi();
3399| if (evCurrentStep === 'aprofundamento') {
3400| var stepType = evSelectedType();
3401| evSyncCriticalityField(stepType);
3402| if (evRequiresAccidentTechnical(stepType)) {
3403| evSyncDerivedSeverityFromConsequence();
3404| }
3405| if (stepType === 'ACIDENTE_PESSOAL') {
3406| window.requestAnimationFrame(function () {
3407| var cardAp = evEnsurePrimaryInjuredCardExpanded();
3408| if (cardAp && evCardHadInjury(cardAp)) {
3409| evEnsureBodyMapForCard(cardAp);
3410| }
3411| });
3412| } else if (evHadInjuryForValidation()) {
3413| evEnsureBodyMapForCard(evGetActiveInjuredCardForBodyMap());
3414| }
3415| }
3416| }
3417|
3418| function evInitTypeSelectFromConfig() {
3419| var cfg = window.ssmaOccurrenceTypeConfig || { types: [] };
3420| var allowedTypes = window.SSMA_ALLOWED_CREATE_TYPES || [];
Request #3
deepseek-v4-flash
P:13.38K C:2.96K CR:10.11K CW:0
20481ms
Reasoning
Now let me understand what's happening. The change adds calls to `evSyncDescaracterStageUi()` at:
1. Line 2709 - end of `evCreateInjuredPersonCard()`
2. Line 2826 - end of `evRenderInjuredPersonBoxes()`
But note that `evRenderInjuredPersonBoxes()` calls `evCreateInjuredPersonCard(pid, details[pid] || {}, false)` in a loop (line 2813). So each `evCreateInjuredPersonCard` call now also calls `evSyncDescaracterStageUi()`. Then `evRenderInjuredPersonBoxes()` calls `evSyncDescaracterStageUi()` at its end too.
The change in `evCreateInjuredPersonCard` may cause `evSyncDescaracterStageUi` to run while cards are still being processed. But since the call is idempotent-ish (toggles based on DOM state), it should be fine.
Also note `evRenderInjuredPersonBoxes()` calls `evSyncDescaracterStageUi()` at line 2826. Since `evCreateInjuredPersonCard` is also called inside, this adds another invocation. This is mostly redundant but harmless (perf micro). Not blocking.
Now let me check that this change is within the scope declared (fix the checkbox display sync). The added calls look fine logically.
Wait — but where's the bug? The original problem: When creating a card in "criação" (creation), the checkbox `.ev-inj-descaracter` stays `d-none` because `evSyncDescaracterStageUi()` only ran when changing type. Now they add the call after the card creation. But note: `evSyncDescaracterStageUi` uses `evSelectedType()` — is that set at the point these functions are invoked? Let me check where `evCreateInjuredPersonCard` and `evRenderInjuredPersonBoxes` are invoked to see if type is selected at that time.
Actually, wait — a bigger question: since `evSyncDescaracterStageUi` is defined within this same IIFE scope (all these functions), calling it directly is fine.
Let me check that both calls are within a block `<script>` inside a template. There's nothing else obviously wrong.
However, there is a potential concern: This is a huge template (7712 lines). Per the user rules, this is a "god template" and any PR that increases the mixing of markup/JS should be flagged. But this change only adds 2 function calls to existing JS within the template — it doesn't add new markup/JS. So probably doesn't warrant a "god template" flag for this tiny PR — though the rule says: "Se este template já é um 'god template' (centenas de linhas misturando markup, estado e chamadas AJAX), qualquer PR que aumente ainda mais essa mistura deve ser sinalizada antes de qualquer outro achado."
Hmm. This PR does add two JS calls inside the template's script block, increasing mixing. But it's a hotfix to existing code. Should I flag it? It's part of the codebase already with 7700+ lines. Since the change is a minimal hotfix touching existing functions, flagging god-template might be relevant as an alert/note but the PR itself adds only 2 lines to existing JS functions. Let me consider.
Now, is there any functional issue? Let me verify whether calling `evSyncDescaracterStageUi` at end of `evCreateInjuredPersonCard` and `evRenderInjuredPersonBoxes` is safe with respect to ordering when called during initialization before `evSelectedType` etc. Let me look at how the initialization happens.
Actually `evSyncDescaracterStageUi` reads DOM and toggles classes. It's idempotent, safe.
Potential issue: In `evRenderInjuredPersonBoxes`, at line 2827, there's a `requestAnimationFrame` call that checks whether `evCurrentStep === 'aprofundamento'` — this only runs in aprofundamento. The added `evSyncDescaracterStageUi()` at line 2826 runs before that check. Fine.
Let me now check whether `evSyncDescaracterStageUi` shows the checkbox at the right time given the type could not be 'ACIDENTE_PESSOAL'. In creation step, user has chosen type before adding a person (the flow: choose type → add person → card). So type is set. But what if type is changed AFTER adding people? In that scenario, type-change handler runs `evSyncDescaracterStageUi` anyway (it's referenced in 3323, 3398, 5288, 5736). So fine.
Let me examine where `evRenderInjuredPersonBoxes` is first called during initialization to ensure `evSyncDescaracterStageUi` doesn't do something before DOM ready. But that would be pre-existing risk if called elsewhere; the new call within those functions will run whenever they run. Since those functions presumably run after DOM ready and after required elements exist, no issue.
Let me also verify whether the function `evSyncDescaracterStageUi` is defined later in the same scope — yes at 2917, which is within the same IIFE. Function declarations are hoisted within the IIFE, so calling from functions defined earlier is fine.
Let me confirm the function signature/scope: is `evSyncDescaracterStageUi` global or local? It's defined inside the same scope as evCreateInjuredPersonCard. Calls at 2709 and 2826 are within the same scope. Good.
Now let's double-check whether these added calls introduce regression: In the "aprofundamento" mode, cards are created via `evCreateInjuredPersonCard` too? Possibly. During aprofundamento (edit), when the offcanvas renders, `evRenderInjuredPersonBoxes` might be invoked. Calling `evSyncDescaracterStageUi` there... In aprofundamento, the checkbox visibility depends on type AP. For AP, the descaracter section shows. This is consistent with existing behavior.
Now what about the fact that `evRenderInjuredPersonBoxes` iterates over cards calling `evCreateInjuredPersonCard`, and each now calls `evSyncDescaracterStageUi` before `evEnsurePrimaryInjuredMarked()`? Actually, the added line in `evCreateInjuredPersonCard` is at the very end (after evEnsurePrimaryInjuredMarked). Good.
Potential duplicate work — each card creation calls `evSyncDescaracterStageUi`, which iterates over all `.ev-injured-person-box` elements, toggling classes. With N cards, that's O(N²) DOM queries. But typically N is small (injured persons per accident), so this is negligible. In `evRenderInjuredPersonBoxes`, the whole loop already iterates, and then the final call repeats the full sync. Minor inefficiency, not blocking.
Now for the review checklist: correctness, security, performance, maintainability, test coverage.
Let me see the other lines where `evSyncDescaracterStageUi` is called (5288, 5736) to understand context.
Actually, let me check whether there's a guard to see if the checkbox/descaracter block markup exists in the injured person card template within creation flow — but the issue isn't the markup.
Wait, there might be a subtle problem. In creation mode (ev_form_mode=create), the checkbox "Há suspeita de descaracterização" per card should be visible. In aprofundamento mode, the checkbox is hidden and only Sim/Não show? Let me read the docs or the referenced logic. Actually from the #677 description, the checkbox stays hidden in aprofundamento? Let me read more of the function.
Actually, from code: `evSyncDescaracterStageUi`:
- gets isAp = type === ACIDENTE_PESSOAL
- hides global suspectWrap (`ev-suspeita-wrap`) always
- toggles `.ev-inj-descaracter` d-none = !isAp — the section visible if AP
- Then syncs yes/no wrap with each card's suspect checkbox.
The CSS mentioned "Na criação: só o checkbox de suspeita fica visível (Sim/Não oculto via CSS fora do aprofundamento)." So there's CSS controlling visibility based on mode (probably a class like `.is-doctor-aprof` or step). Fine.
Now the added calls just force re-sync after card created. Makes sense.
Let me also consider: in `evCreateInjuredPersonCard`, when there's `saved` containing `descaracter_suspect`, does creating the card set the checkbox? Presumably in `evApplyCardInjuryData`. Then `evSyncDescaracterStageUi` will update yes/no wrap appropriately. Fine.
Now, one more check: is there a scenario where a card's checkbox `.ev-inj-suspect-chk` exists only inside an expanded section that's inside a `d-none` container? `classList.toggle` works regardless of visibility.
I think functionally the change is fine and matches the declared hotfix intent.
Now, is there any issue of scope? The PR changes one file within the declared scope. Fine.
God-template concern: This file is 7712 lines — definitely a god template. Per user-specific rules, this should be flagged with highest weight — any PR that increases mixing should be flagged. However, the PR only adds two JS calls to existing logic — it doesn't create new mixed content, and reverting would defeat the hotfix. I think it's fair to make a light comment noting the architectural concern (moving this JS to public/js/) but it shouldn't be blocking. However, I should weigh whether to make such a comment for a 2-line hotfix. The user-specific rule says "God template — maior peso. Se este template já é um 'god template'... qualquer PR que aumente ainda mais essa mistura deve ser sinalizada antes de qualquer outro achado." — so I should mention it. But per the guidance "Avoid commenting on correct code or unchanged code." — the change is only two lines, both correct. The god-template note is about the file's overall structure which pre-exists. Hmm.
The rule says "qualquer PR que aumente ainda mais essa mistura deve ser sinalizada". This PR does add two more JS statements to the giant script block inside the template. So per the mandate, I could flag it as low-severity architectural note.
But also the "Strict Focus Rules": focus on issues in newly added code. The added code is correct. Might not be any real functional bug.
Let me look for deeper issues. Maybe there is an actual problem: `evRenderInjuredPersonBoxes()` calls `evCreateInjuredPersonCard()` for each pid, and each `evCreateInjuredPersonCard` now calls `evSyncDescaracterStageUi()`. This is inside a loop, calling a function that queries the entire document for `.ev-injured-person-box` and toggles classes — O(n²) but negligible in practice for small n.
Also worth checking: does `evRenderInjuredPersonBoxes` get invoked in a scenario where type is NOT ACIDENTE_PESSOAL? E.g., if a draft restore happens before type is selected? In draft restore flow, after JSON restore, `evRenderInjuredPersonBoxes` is invoked. If the type selection hasn't happened (e.g., on page load restoring draft in creation), then isAp would be false, `.ev-inj-descaracter` would be hidden — which is consistent with the intended behavior (checkbox only when AP). Later when user selects AP type, type-change handler calls sync. So no issue.
Let me check the callers of `evRenderInjuredPersonBoxes` and `evCreateInjuredPersonCard` to make sure nothing calls them before functions/dom exist. It's all in DOM-ready/on-change flows.
Let me also check there is no double-sync issue when evCreateInjuredPersonCard is called for existing cards: At line 2658-2659, if existing, returns early without sync — the added sync is after, fine.
Now, is there anything about `evCurrentStep` usage in evSyncDescaracterStageUi? It doesn't use step. It uses type and mode. OK.
Now let me check the area around line 5288 and 5736 to see other contexts, just to confirm no undefined references and consistency.
Actually, I already know evSyncDescaracterStageUi exists in scope. The two added calls are placed correctly.
Now, is there anything that would break if `evSelectedType()` returns null at that point (e.g., card created before type chosen — legacy flow via select at line 2750 `evAddInjuredPersonFromSelect`)? The `evAddInjuredPersonFromSelect` path may add people before type selected? In creation, the type must be chosen first because adding person requires being in the "general" step with type... but let me not over-infer.
Let me check `evSelectedType`.
Tool Calls (2)
code_search
Show Details
Arguments
{"search_text": "function evSelectedType"}
Result
File: templates/ssma/occurrence/partials/_modal_event.html.twig
Match lines: 1
1553| function evSelectedType() {
file_read
Show Details
Arguments
{"end_line": 3310, "file_path": "templates/ssma/occurrence/partials/_modal_event.html.twig", "start_line": 3240}
Result
File: templates/ssma/occurrence/partials/_modal_event.html.twig (Total lines: 7712)
IS_TRUNCATED: false
LINE_RANGE: 3240-3310
3240| });
3241| return rows;
3242| }
3243|
3244| function evFillCorrectiveActions(list) {
3245| var host = document.getElementById('ev-corrective-actions-list');
3246| if (!host) return;
3247| host.innerHTML = '';
3248| evCorrectiveActionSeq = 0;
3249| var rows = Array.isArray(list) ? list : [];
3250| if (!rows.length) {
3251| host.insertAdjacentHTML('beforeend', evBuildCorrectiveActionRow({}));
3252| } else {
3253| rows.forEach(function (row) {
3254| host.insertAdjacentHTML('beforeend', evBuildCorrectiveActionRow(row || {}));
3255| });
3256| }
3257| evRenumberCorrectiveActions();
3258| evBindCorrectiveMemberSearch(host);
3259| }
3260|
3261| function evValidateCorrectiveActions(MV) {
3262| if (!evRequiresAprofundamento(evSelectedType())) return true;
3263| var ok = true;
3264| var items = document.querySelectorAll('#ev-corrective-actions-list .ev-corrective-action-item');
3265| if (!items.length) {
3266| return true;
3267| }
3268| Array.prototype.forEach.call(items, function (item) {
3269| var description = ((item.querySelector('.ev-ca-description') || {}).value || '').trim();
3270| var resolved = !!(item.querySelector('.ev-ca-resolved') || {}).checked;
3271| var deadline = ((item.querySelector('.ev-ca-deadline') || {}).value || '').trim();
3272| var responsibleId = ((item.querySelector('.ev-ca-responsible') || {}).value || '').trim();
3273| var validatorId = ((item.querySelector('.ev-ca-validator') || {}).value || '').trim();
3274| var hierarchy = ((item.querySelector('.ev-ca-hierarchy') || {}).value || '').trim();
3275| var empty = !description && !responsibleId && !validatorId && !hierarchy && !deadline && !resolved;
3276| if (empty) return;
3277| if (!description) {
3278| ok = false;
3279| if (MV && window.jQuery) MV.markInvalid(window.jQuery(item.querySelector('.ev-ca-description')));
3280| }
3281| if (!responsibleId) {
3282| ok = false;
3283| if (MV && window.jQuery) MV.markInvalid(window.jQuery(item.querySelector('.ev-ca-responsible')));
3284| }
3285| if (!hierarchy) {
3286| ok = false;
3287| if (MV && window.jQuery) MV.markInvalid(window.jQuery(item.querySelector('.ev-ca-hierarchy')));
3288| }
3289| if (!resolved && !deadline) {
3290| ok = false;
3291| if (MV && window.jQuery) MV.markInvalid(window.jQuery(item.querySelector('.ev-ca-deadline')));
3292| }
3293| });
3294| return ok;
3295| }
3296|
3297| function evSetAprofundamentoReadonly(readonly) {
3298| var panel = document.getElementById('ev-step-aprofundamento');
3299| var alert = document.getElementById('ev-aprofundamento-denied-alert');
3300| if (panel) panel.classList.toggle('is-readonly', !!readonly);
3301| if (alert) {
3302| alert.classList.toggle('d-none', !readonly);
3303| if (evIsAprofundamentoFinalized() && !EV_IS_ADMIN_APROFUNDAMENTO) {
3304| alert.innerHTML = '<i class="fas fa-lock mr-2"></i>Aprofundamento finalizado. Somente um administrador ou gestor administrador pode alterar.';
3305| } else {
3306| alert.innerHTML = '<i class="fas fa-exclamation-triangle mr-2"></i>O aprofundamento é preenchido pelo profissional responsável (gestor direto do colaborador ou equipe técnica SSMA).';
3307| }
3308| }
3309| var controls = document.querySelectorAll(
3310| '#ev-technical-section input, #ev-technical-section select, #ev-technical-section textarea,' +
Request #4
deepseek-v4-flash
P:17.46K C:111 CR:16.26K CW:0
1240ms
Reasoning
Let me look at `evSelectedType` at 1553.
Tool Calls (1)
file_read
Show Details
Arguments
{"end_line": 1580, "file_path": "templates/ssma/occurrence/partials/_modal_event.html.twig", "start_line": 1530}
Result
File: templates/ssma/occurrence/partials/_modal_event.html.twig (Total lines: 7712)
IS_TRUNCATED: false
LINE_RANGE: 1530-1580
1530| { value: 'administrative', label: 'Administrativa' },
1531| { value: 'epi', label: 'EPI' }
1532| ];
1533| var EV_CORRECTIVE_MEMBER_OPTIONS = [
1534| {% for member in allMembers|default([]) %}
1535| { id: {{ member.id|json_encode|raw }}, name: {{ member.name|json_encode|raw }} }{% if not loop.last %},{% endif %}
1536| {% endfor %}
1537| ];
1538|
1539| /** Pré-preenchimento (ex.: gestor/equipe do usuário com escopo por equipe). */
1540| window.SSMA_EVENT_FORM_DEFAULTS = {{ ssma_event_form_defaults|default({})|json_encode|raw }};
1541|
1542| var EV_KNOWN_TYPE_KEYS = ['ROS', 'QUASE_ACIDENTE', 'ACIDENTE_PESSOAL', 'ACIDENTE_MATERIAL', 'ACIDENTE_AMBIENTAL'];
1543| /** Tipos com passo de Aprofundamento (ROS/QA + acidentes). */
1544| var EV_APROFUNDAMENTO_TYPE_KEYS = ['ROS', 'QUASE_ACIDENTE', 'ACIDENTE_PESSOAL', 'ACIDENTE_MATERIAL', 'ACIDENTE_AMBIENTAL'];
1545| /** Acidentes: bloco técnico (consequência real, lesão, etc.) dentro do Aprofundamento. */
1546| var EV_APROFUNDAMENTO_ACCIDENT_KEYS = ['ACIDENTE_PESSOAL', 'ACIDENTE_MATERIAL', 'ACIDENTE_AMBIENTAL'];
1547| var evCurrentStep = 'general';
1548| var evAprofundamentoOnlyMode = false;
1549| var evAprofundamentoFinalizeIntent = true;
1550| var evAprofundamentoFinalized = false;
1551| var evCorrectiveActionSeq = 0;
1552|
1553| function evSelectedType() {
1554| return (document.getElementById('ev_type') || { value: '' }).value || '';
1555| }
1556|
1557| /** ROS "Visto e resolvido" = SIM: dispensa o Aprofundamento Técnico (fluxo fica em 1 etapa). */
1558| function evIsRosResolvedChecked() {
1559| var chk = document.getElementById('ev_ros_resolved');
1560| return !!(chk && chk.checked);
1561| }
1562|
1563| /** Reflete o estado do checkbox #ev_immediate_risk nos botões Sim/Não visíveis. */
1564| function evSyncImmediateRiskButtonsUI() {
1565| var riskChk = document.getElementById('ev_immediate_risk');
1566| var isYes = !!(riskChk && riskChk.checked);
1567| if (window.SsmaShared && typeof window.SsmaShared.toggleYesNo === 'function') {
1568| window.SsmaShared.toggleYesNo('.js-ev-immediate-risk-opt', isYes ? '1' : '0');
1569| }
1570| }
1571|
1572| function evRequiresAprofundamento(type) {
1573| var t = type || evSelectedType();
1574| if (t === 'ROS' && evIsRosResolvedChecked()) {
1575| return false;
1576| }
1577| return EV_APROFUNDAMENTO_TYPE_KEYS.indexOf(t) !== -1;
1578| }
1579|
1580| /** Campos técnicos de acidente (não ROS/QA). */
Request #5
deepseek-v4-flash
P:18.5K C:2.14K CR:17.54K CW:0
15760ms
Reasoning
OK. The change is functionally straightforward. Now, per the user-specific rules, there's a big concern to evaluate:
1. God template — this file is 7712 lines. The diff adds JS into it. Per instructions, flag with highest weight before any other finding. But per "Strict Focus Rules" focus on issues in newly added code. The new lines are part of a giant inline `<script>` — this adds two more lines of UI logic to a template. That's consistent with existing architecture though (pre-existing). This is a hotfix to fix a bug. Hmm, should I flag "god template"? Given the instructions state it should be "sinalizada antes de qualquer outro achado", I could include a low-priority note.
However, considering the PR is only adding two function calls to existing functions in a template that already has thousands of lines of JS — this is not "aumentar ainda mais essa mistura" in a meaningful new way; it's modifying existing JS inside the template. But strictly, the PR does keep the status quo. I think a fair comment, per the mandate, is to note that the fix is being placed in the god template and recommend migrating logic to `public/js/` eventually. But should I not comment because it's out of scope for a hotfix? The instruction says to signal any PR that increases the mix. Since the change itself is minimal and is the actual fix, this is more of a maintainability note. I'll include it with low severity, category "maintainability".
Let me double-check that the added line at 2826 in `evRenderInjuredPersonBoxes` is redundant with 2709 given the function calls `evCreateInjuredPersonCard` per pid. If `details` is empty (no ids), then only the line at 2826 runs. So both are useful. In the common case both run. That's minor redundancy but not an issue.
Now, could there be a real issue: In `evCreateInjuredPersonCard`, the added call occurs even when the function returns early? No—early returns happen before the final lines. The call at the end only runs when the card was created (or existed and appended). Actually, wait: if existing (line 2658-2659) returns existing early, no sync. That's fine.
Another check — is there potential for `evSyncDescaracterStageUi` to throw if called when the type selector doesn't exist? `evSelectedType` handles null element gracefully. `form.classList` guarded by if(form). `suspectWrap` guarded. querySelectorAll safe. So no throw.
Let me also verify that the placement in `evCreateInjuredPersonCard` covers the flow in `evAddInjuredPersonFromSelect`, `evRenderInjuredPersonBoxes`, and wherever else cards get created. But there may be other creation paths, e.g., a global handler that adds "pessoas envolvidas" then creates a card — but those likely route to `evCreateInjuredPersonCard`. So the fix is comprehensive.
Wait, is `evRenderInjuredPersonBoxes` invoked on initial page load for edit mode? Let me not dig too deep.
Consider whether there is a scenario where these functions are called before `evSyncDescaracterStageUi` is defined — function declarations inside the same IIFE are hoisted, so no issue. But is `evSyncDescaracterStageUi` inside the same IIFE? Both evCreateInjuredPersonCard (line 2653) and evSyncDescaracterStageUi (2917) — we saw them all within same block (2600-2980). Yes.
Alright. Given this is a small hotfix with correct logic, the review comments I might leave:
1. (Low / maintainability) The file is already a "god template" of 7.7k lines and this hotfix continues to add UI logic inline in Twig instead of in `public/js/`. Since this change is a tiny hotfix, not blocking, but recommend moving logic out in the future.
2. Possibly mention that in `evRenderInjuredPersonBoxes`, the added sync call also runs for each card created inside the loop (each `evCreateInjuredPersonCard` already syncs), so it runs O(n) times over all boxes — redundant but harmless; could restructure to sync once. Severity low.
Hmm. Is a comment about redundancy worth it? It could be noise. But maybe combine.
Actually wait — I need to think about whether there's a functional redundancy subtlety that could cause a bug: In `evRenderInjuredPersonBoxes`, cards are created in a loop; each `evCreateInjuredPersonCard` ends with `evSyncDescaracterStageUi()` which toggles `.ev-inj-descaracter` visibility for ALL cards, using current type. That's fine.
But consider `evRenderInjuredPersonBoxes` used in edit mode / aprofundamento where a draft JSON is restored? Restore flow calls `evRenderInjuredPersonBoxes`. Then cards are created before the "main" `evSyncDescaracterStageUi` at 2826, and the aprofundamento-specific `requestAnimationFrame` handles expansion.
What about the checkbox suspect sync: `evSyncDescaracterStageUi` at 2933-2939 syncs yes/no based on each card's suspect checkbox checked state. If a card was created with saved data (descaracter_suspect true), the checkbox would be checked in `evApplyCardInjuryData`, and yes/no hidden correctly. Fine.
I think functionally this is correct and safe.
Should I verify the docs referenced to see intended behavior? The docs are in docs/ssma. Not needed.
Now let me consider severity & whether to provide any code_comment. The instructions say: focus primarily on actual code logic and functionality, avoid commenting on correct code or unchanged code. The added code is correct. The redundancy between the two calls is a very minor perf point.
Given the "god template" mandatory rule, I should signal it. Let me make a single low-severity maintainability comment at line 2709 about god-template, noting both that it continues inline mixing and that the call at 2826 is partially redundant because the loop's card creations already sync. Actually each comment must attach to new code lines.
But careful: My comment must be precise and per the format: (1) what changed and impact in plain language; (2) why it matters; (3) what to do.
Let me think about the real technical issue with the redundancy more concretely:
`evRenderInjuredPersonBoxes` calls `evCreateInjuredPersonCard` for each injured person. With the added sync at the end of `evCreateInjuredPersonCard`, each loop iteration runs `evSyncDescaracterStageUi`, which itself queries all `.ev-injured-person-box` cards and toggles classes on each — meaning with N cards, sync runs N times during rendering, plus once more at 2826. `evSyncDescaracterStageUi` also toggles the `is-doctor-aprof` class on form and d-none on `#ev-suspeita-wrap` — repeated operations. It's O(n²) over card count, but n is tiny (injured persons). So performance impact negligible. Not a blocker.
The more relevant angle: architectural maintainability (god template). Mandatory flag. But it's pre-existing; this PR only adds two lines. I'd note it as "atenção" per the user rules, but since this is exactly a bug-fix hotfix touching existing functions, maybe the god template comment is boilerplate noise. The user rule is emphatic though: "God template — maior peso... qualquer PR que aumente ainda mais essa mistura deve ser sinalizada antes de qualquer outro achado." I'll include it as a low-severity maintainability note tied to the added lines, acknowledging it's pre-existing and not blocking for this hotfix.
Now, is there any real concern regarding the two sync calls being functionally necessary but the second one at 2826 runs also when no card exists (details empty)? In creation flow before any person added, `evRenderInjuredPersonBoxes` might be called on type change; if no details, no cards; calling sync is fine and consistent.
Also consider possible interaction: after adding person in creation, the added call makes the `.ev-inj-descaracter` visible. But the docs say Sim/Não only in aprofundamento, hidden in creation via CSS. Let me check CSS references to know which elements exist per card template. Actually, there might be a deeper issue: does the card markup in creation even contain the checkbox? The PR background says "Ao criar o card, o bloco `.ev-inj-descaracter` continuava com `d-none`" — so markup exists; it was hidden. Fine.
Let me also check that when in creation mode and type is ACIDENTE_PESSOAL, the card checkbox will actually be visible given the CSS that hides Sim/Não outside aprofundamento. That's from #677, unchanged here.
Now, do I need to verify there are no other code paths where a card is created without going through `evCreateInjuredPersonCard`, e.g., insertion of HTML strings (clone/HTML building elsewhere)? Let me search for `.ev-injured-person-box` creation via insertAdjacentHTML.
Tool Calls (1)
code_search
Show Details
Arguments
{"search_text": "ev-injured-person-box-tpl|ev-injured-person-box'|evCreateInjuredPersonCard|evRenderInjuredPersonBoxes", "use_perl_regexp": true, "file_patterns": ["templates/ssma/occurrence/partials/_modal_event.html.twig"]}
Result
File: templates/ssma/occurrence/partials/_modal_event.html.twig
Match lines: 22
662| <div id="ev-injured-person-box-tpl" class="d-none" aria-hidden="true">
2378| evCreateInjuredPersonCard(personId, saved, false);
2653| function evCreateInjuredPersonCard(personId, saved, expand) {
2655| var tpl = document.getElementById('ev-injured-person-box-tpl');
2661| var source = tpl.querySelector('.ev-injured-person-box') || tpl.firstElementChild;
2767| var created = evCreateInjuredPersonCard(personId, saved, false);
2789| function evRenderInjuredPersonBoxes() {
2813| evCreateInjuredPersonCard(pid, details[pid] || {}, false);
2896| if (typeof evRenderInjuredPersonBoxes === 'function') evRenderInjuredPersonBoxes();
2933| document.querySelectorAll('.ev-injured-person-box').forEach(function (card) {
2955| document.querySelectorAll('.ev-injured-person-box').forEach(function (c) {
2960| document.querySelectorAll('.ev-injured-person-box').forEach(function (card) {
5533| || wrap.querySelector('.ev-injured-person-box');
5658| ? triggerEl.closest('.ev-injured-person-box')
5667| document.querySelectorAll('.ev-injured-person-box').forEach(function (c) {
5678| var card = t.closest ? t.closest('.ev-injured-person-box') : null;
5684| var card = t.closest ? t.closest('.ev-injured-person-box') : null;
5744| var card = e.target.closest('.ev-injured-person-box');
5980| var firstInjCard = boxesWrap && boxesWrap.querySelector('.ev-injured-person-box');
6457| evRenderInjuredPersonBoxes();
6470| evRenderInjuredPersonBoxes();
6483| document.querySelectorAll('.ev-injured-person-box').forEach(function (card) {
Request #6
deepseek-v4-flash
P:21.13K C:115 CR:20.61K CW:0
1695ms
Reasoning
Let me look at line 2378 context to understand the other path that creates cards.
Tool Calls (1)
file_read
Show Details
Arguments
{"end_line": 2400, "file_path": "templates/ssma/occurrence/partials/_modal_event.html.twig", "start_line": 2350}
Result
File: templates/ssma/occurrence/partials/_modal_event.html.twig (Total lines: 7712)
IS_TRUNCATED: false
LINE_RANGE: 2350-2400
2350| return;
2351| }
2352| var involved = evGetPeopleInvolved();
2353| var wrap = document.getElementById('ev_injured_person_boxes');
2354| if (!involved.ids.length) {
2355| // Nunca apagar caixinhas médicas já montadas / details salvos só porque as tags
2356| // de "Pessoas envolvidas" ainda não estão no DOM (bug em edição → parte médica some).
2357| var existingDetails = evGetInjuredDetailsObj();
2358| var hasCards = !!(wrap && wrap.querySelector('.ev-injured-person-box[data-person-id]'));
2359| if (hasCards || Object.keys(existingDetails || {}).length) {
2360| evUpdateInjuredPersonsEmptyState();
2361| return;
2362| }
2363| if (wrap) wrap.innerHTML = '';
2364| evSetInjuredDetailsObj({});
2365| if (typeof evParkBodyMapBlock === 'function') evParkBodyMapBlock();
2366| if (typeof evClearCanonicalInjuryIds === 'function') evClearCanonicalInjuryIds();
2367| var sel = document.getElementById('ev_person_id');
2368| if (sel) sel.removeAttribute('data-primary-injured-id');
2369| evUpdateInjuredPersonsEmptyState();
2370| return;
2371| }
2372| involved.ids.forEach(function (personId) {
2373| if (!personId || !wrap) return;
2374| var safe = String(personId).replace(/"/g, '');
2375| var existing = wrap.querySelector('.ev-injured-person-box[data-person-id="' + safe + '"]');
2376| if (!existing) {
2377| var saved = evGetInjuredDetailsObj()[personId] || {};
2378| evCreateInjuredPersonCard(personId, saved, false);
2379| } else {
2380| evRenderInjuredPersonSummary(existing, existing.getAttribute('data-person-id'));
2381| evUpdateInjuredCardSummary(existing);
2382| }
2383| });
2384| evPruneInjuredBoxesNotInvolved();
2385| evEnsurePrimaryInjuredMarked();
2386| evSyncInjuredPersonDetailsHidden();
2387| evUpdateInjuredPersonsEmptyState();
2388| var boxesWrap = document.getElementById('ev_injured_person_boxes');
2389| if (boxesWrap) boxesWrap.classList.remove('is-invalid');
2390| }
2391|
2392| /** No passo Aprofundamento (AP), expande o acidentado principal para exibir lesão/consequências/mapa. */
2393| function evEnsurePrimaryInjuredCardExpanded() {
2394| if (evSelectedType() !== 'ACIDENTE_PESSOAL') return null;
2395| evSyncInjuredCardsFromInvolved();
2396| var wrap = document.getElementById('ev_injured_person_boxes');
2397| if (!wrap) return null;
2398| var card = (typeof evGetPrimaryInjuredCard === 'function' ? evGetPrimaryInjuredCard() : null)
2399| || wrap.querySelector('.ev-injured-person-box[data-person-id]');
2400| if (!card) return null;
Request #7
deepseek-v4-flash
P:22.09K C:4.93K CR:21.25K CW:0
36380ms
Reasoning
So the main paths creating a card call `evCreateInjuredPersonCard` (which is where the sync line was added). Good — the fix covers the involved-people flow via `evSyncInjuredCardsFromInvolved` too, since that calls `evCreateInjuredPersonCard` per new person. So the added call inside `evCreateInjuredPersonCard` is the right coverage point.
`evRenderInjuredPersonBoxes` is the re-render path (restore draft / edit) which now also syncs at the end (since if all cards already exist, `evCreateInjuredPersonCard` returns early and doesn't reach the sync — important!). Actually, important subtlety: `evRenderInjuredPersonBoxes` clears the wrap and re-creates cards (wrap.innerHTML = ''), so cards don't exist yet when it iterates. Each created card goes through `evCreateInjuredPersonCard` full path, and syncs at the end. Wait, but cards are re-created fresh in `evRenderInjuredPersonBoxes`, so `evCreateInjuredPersonCard` is always fully executed (not early return), and each one syncs. Then the final sync at 2826 covers the case where there are no cards and also acts as a catch-all. OK.
Another important subtlety: `evRenderInjuredPersonBoxes` calls `evSyncDescaracterStageUi` at line 2826 which is placed right after `evUpdateInjuredPersonsEmptyState()`. But note `evSyncInjuredCardsFromInvolved` (a different path that adds cards for involved people when they come from "Pessoas envolvidas" tags) does NOT call `evSyncDescaracterStageUi` at its end — but since each card creation inside it now triggers sync through `evCreateInjuredPersonCard`, the checkbox will be toggled when the first card is created. Actually wait — in `evSyncInjuredCardsFromInvolved`, if people already exist as cards (not new), no card creation happens, so no sync; but the cards already exist and would have been synced at creation time. So this is fine.
What about the flow described in the PR (add person in "Pessoas envolvidas")? Let me find where involved people are added (probably a dropdown multi-select change handler). That probably calls `evSyncInjuredCardsFromInvolved` (line ~2350). Card creation goes through `evCreateInjuredPersonCard`. New sync line handles it.
So functionally, this diff matches the declared intent and appears correct.
Now, the only mandatory finding per user rules: god template. This is a 7712-line Twig with ~5000+ lines of inline JS. The diff adds more logic there. I'll issue a low-severity maintainability comment on the added lines.
But wait — should I refrain given "Avoid commenting on correct code or unchanged code"? The mandate in user rules explicitly instructs to flag god-template expansion. This PR does extend inline JS in the template (2 lines). I'll attach the comment to one of the added lines (e.g., line 2709, evSyncDescaracterStageUi(); after evEnsurePrimaryInjuredMarked();).
I should keep comments concise and objective.
Let me draft:
Comment 1 (maintainability, low): The two added calls follow the pattern of an enormous inline script (7.7k-line template). Not a blocker for the hotfix, but it continues mixing UI state logic into the Twig. Future refactor to move this to public/js would be better; no change requested now.
Actually — I should weigh whether to comment at all. The instruction list says "Se o template já é um god template, qualquer PR que aumente ainda mais essa mistura deve ser sinalizada antes de qualquer outro achado." So yes, signal it.
Should I also mention redundancy of double sync when `evRenderInjuredPersonBoxes` iterates? Could fold into one comment or a separate low one. Actually, better to keep review concise. I might produce one comment per added line location? Both added lines are effectively the same fix repeated in two functions. It could be one comment attached to one location and mention both.
Hmm. But code_comment tool anchors comments to specific lines. I could give two comments, both low severity — one per added line — but that may be redundant. Better: one comment about god-template architecture anchored to first line, and mention second location in the text.
Let me think whether there is a genuinely more substantive issue: Is `evSyncDescaracterStageUi` the only missing sync, or is there something about `evSyncDescaracterUi` vs `evSyncDescaracterStageUi`? The diff adds `evSyncDescaracterStageUi`, which toggles the `.ev-inj-descaracter` d-none based on type. Note: `evBindInjuredCardEvents` (line 2647) already calls `evSyncDescaracterUi()` at the end for the card being created — which internally calls `evSyncDescaracterStageUi()` (line 2947). Wait! `evSyncDescaracterUi` calls `evSyncDescaracterStageUi` at its top (line 2947). So when `evBindInjuredCardEvents(card)` runs inside `evCreateInjuredPersonCard` at line 2688, it already triggers `evSyncDescaracterStageUi()`!
Hold on. Let me re-check: `evBindInjuredCardEvents` at line 2647 calls `evSyncDescaracterUi()`, and `evSyncDescaracterUi` calls `evSyncDescaracterStageUi()` at line 2947. So after each card creation, the stage UI sync already ran during binding...
But wait — does `evBindInjuredCardEvents` always run? In `evCreateInjuredPersonCard`, line 2688 calls `evBindInjuredCardEvents(card)`. Let me check line 2647 is inside evBindInjuredCardEvents. Yes, the code from 2600-2651 is the body of `evBindInjuredCardEvents` (probably). Let me confirm where evBindInjuredCardEvents starts. Line 2652 is `function evCreateInjuredPersonCard`. So evBindInjuredCardEvents ends around line 2651. At 2647 it calls `evSyncDescaracterUi()`.
So if `evSyncDescaracterUi` calls `evSyncDescaracterStageUi`, then the checkbox sync already occurs when each card is created (via evBindInjuredCardEvents → evSyncDescaracterUi → evSyncDescaracterStageUi). Hmm — but the bug says the block stayed d-none when adding a person. Let me check: maybe `evBindInjuredCardEvents` early-returns or the `evSyncDescaracterUi` path only exists in later code? Or perhaps `evSyncDescaracterStageUi` was introduced in #677 with CSS that hid things until later, and the real issue is elsewhere.
Wait, actually maybe `evBindInjuredCardEvents` only calls `evSyncDescaracterUi` — which internally now calls stage sync (line 2947). So why was the checkbox still hidden? Let me look at the sequence in evCreateInjuredPersonCard:
1. Line 2688: evBindInjuredCardEvents(card) — triggers evSyncDescaracterUi → evSyncDescaracterStageUi.
2. That would toggle `.ev-inj-descaracter` visible if AP...
Hmm, that contradicts the reported bug. Unless evSyncDescaracterUi's call to evSyncDescaracterStageUi is new (part of this PR? no, only 2 lines added). Let me look at git history? We can't; we only have the diff. The diff shows only the two added lines in this review group. Both calls added are `evSyncDescaracterStageUi()` at 2709 and 2826. So `evSyncDescaracterUi` already existed calling `evSyncDescaracterStageUi`.
Wait — but the bug in the PR description: "evSyncDescaracterStageUi() só rodava ao mudar o tipo, não depois de evCreateInjuredPersonCard/evRenderInjuredPersonBoxes." But we see at line 2647 (in evBindInjuredCardEvents), called by evCreateInjuredPersonCard at line 2688, evSyncDescaracterUi() is called → which calls evSyncDescaracterStageUi. So it DID run after card creation already... unless line 2647 was recently added by a previous PR (#677) and there's a subtlety.
Hmm wait — maybe the reported bug scenario is specifically about `evRenderInjuredPersonBoxes` (draft restore/edit mode) or the person is added via "Pessoas envolvidas" where `evSyncInjuredCardsFromInvolved` is used and cards may already exist (early return in evCreateInjuredPersonCard). But new cards would call evBindInjuredCardEvents → sync anyway.
Actually, let me not overanalyze whether the bug existed; the fix adds sync at the end of both functions, which is harmless and idempotent. The only possible concern: it could mask other UI state — but sync is a pure function of current type/cards state, and re-running it after card creation is consistent.
Actually, is there any case where re-running `evSyncDescaracterStageUi` at the END of `evCreateInjuredPersonCard` could UNDO something that was set for a *previously expanded card*? Consider aprofundamento: each card's yes/no visibility is synced based on that card's suspect checkbox. Re-running doesn't change other cards' checkbox states. Harmless.
Hmm — But what about `evSyncDescaracterUi` in binding (2647) — that one also runs at binding time before the card is appended? Actually the card is appended at 2687 then bind at 2688. So sync runs after append. So really sync already ran. Then why the bug? Maybe in the creation flow for the person via the "Pessoas envolvidas" chips, the handler doesn't use evCreateInjuredPersonCard; instead card markup is inserted elsewhere and only evRenderInjuredPersonSummary/evUpdateInjuredCardSummary are used (line 2380-2382) — those don't sync.
Wait, look at lines 2372-2383 in evSyncInjuredCardsFromInvolved: for existing cards it calls `evRenderInjuredPersonSummary` and `evUpdateInjuredCardSummary` — but for NEW cards it calls `evCreateInjuredPersonCard`. But maybe the reported flow "adicionar pessoa" first shows a card already created earlier when the person was selected in "Pessoas envolvidas"? Eh.
Rather than dwell, note that the fix's correctness is plausible and harmless. Since I can't run the code, I focus on the review observations.
Actually, hold on — let me reconsider whether the addition at 2709 might even be needed at all, given evBindInjuredCardEvents → evSyncDescaracterUi → evSyncDescaracterStageUi already runs during card creation. If that chain existed before, the checkbox would already show... Unless `evSyncDescaracterStageUi` at line 2947 was NOT reached because `evSyncDescaracterUi` returns before? Let me read the full evSyncDescaracterUi (from 2942 onward past 2980) to confirm it always calls evSyncDescaracterStageUi at top. Yes line 2947 `evSyncDescaracterStageUi();` immediately after variable declarations. So the chain exists.
Hmm, so maybe the actual bug scenario: In creation mode, after adding the first person, the card is created (sync runs → checkbox visible), but then something re-hides it? Or maybe the checkbox block `.ev-inj-descaracter` is inside the card template but in creation mode it should only show checkbox — CSS `outside-aprof` hides Sim/Não. Maybe visibility gating requires body scroll or the box expand. Anyway not our concern.
Alternatively, maybe the relevant creation path is where the card is created NOT via evBindInjuredCardEvents... e.g., when creating cards for many people at once via evSyncInjuredCardsFromInvolved while some already exist.
Given this ambiguity, my safest feedback:
1. God template / maintainability (mandatory per rules): note the addition extends inline logic in a 7.7k-line template; suggest eventual migration to public/js. Low severity.
2. Potential redundancy: since `evBindInjuredCardEvents` (inside card creation) already calls `evSyncDescaracterUi` → `evSyncDescaracterStageUi`, the added line at 2709 runs the sync a second time on that path; and inside `evRenderInjuredPersonBoxes` the loop causes it to run once per card plus the extra at 2826. Harmless but redundant; might indicate the fix could be placed only where cards already exist (early-return path) — e.g., inside evSyncInjuredCardsFromInvolved for existing cards. Actually this is an interesting, potentially useful point: the real gap is where an existing card gets shown without sync. But I can't fully confirm.
Given uncertainty, keep comments concise and low severity, and confirm the logic is safe.
Actually, maybe I should reflect: is adding a code_comment with low severity even valuable? The task says report code issues. If no real issues found, call task_done. But the user rules explicitly say god-template PRs must be flagged before any other finding. I'll include that one comment (low, maintainability), and optionally a short note about the double-run redundancy (also low). Two low comments may be acceptable, but let's avoid noise: The double-run redundancy is arguably worth one medium-low note only if there's an actual risk. There's no actual risk (idempotent). I'd rather leave only the god-template note and mention the redundancy inside it briefly? Hmm, that mixes topics. Keep the god template note focused.
Actually, I realize the more useful observation is: the added call inside `evCreateInjuredPersonCard` already happens via `evBindInjuredCardEvents` → `evSyncDescaracterUi` (line 2647 → 2947). If that's true, this fix would be redundant for newly-created cards, meaning the actual broken path is cards that ALREADY exist when a new person is added (early-return at 2658) or cards rendered via other paths. But I can't confirm the real gap without full context. However, as a reviewer I can raise it as a question/observation — is the added sync in `evCreateInjuredPersonCard` necessary given binding already syncs? It's a valid review question, but might be noise given that we're not sure. If the author observed the bug, then evidently the earlier sync didn't suffice — maybe because evBindInjuredCardEvents' sync ran BEFORE the card was fully constructed with type-specific markup? Actually binding runs after append (2687→2688) and after data applied (2683) — full markup present. So sync at that point should have revealed it. Unless `evSyncDescaracterUi` chain is gated: Let me double check that at 2647 it's unconditional.
Looking at 2600-2651:
- card event listeners for change on `.ev-inj-had-injury` etc.
- 2645: evFilterCardConsequences(card);
- 2646: evSyncCardCatFromClassification(card);
- 2647: evSyncDescaracterUi();
- 2648-2650: tooltip init.
So yes unconditional. So creation of a new card already triggers stage sync via binding. So why did bug occur? Perhaps the reported flow adds person via "Pessoas envolvidas" when that person's card was ALREADY created (early return at 2658-2659, no binding sync again) and previously created under a different type selection? But type selection is fixed before adding people...
OR: maybe the observed bug was in edit/reopen flow where `evRenderInjuredPersonBoxes` renders cards at init BEFORE `ev_type` was selected/synced, and no later sync occurred when... hmm.
I cannot fully resolve; nonetheless the fix is harmless and addresses reported symptom. As reviewer, I might phrase a low-severity maintainability note and move on, concluding no blocking issues. Possibly also raise the redundancy as a "question" low severity, but let me decide whether that adds value. I think one consolidated comment is cleaner.
Let me also double-check the placement of the new call at 2826 relative to `evCurrentStep === 'aprofundamento'` requestAnimationFrame: The new call at 2826 executes BEFORE the rAF check at 2827. In aprofundamento render with `evAprofundamentoOnlyMode`, `evSyncDescaracterStageUi` toggles is-doctor-aprof on the form and calls toggle per card — no interference with rAF expansion.
One more possibility of regression: `evSyncDescaracterStageUi` toggles `yesNoWrap` visibility based on the suspect checkbox, and also hides `#ev-suspeita-wrap` (global). In creation mode, the per-card checkbox `.ev-inj-suspect-chk` lives in the card. But is the `.ev-inj-descaracter` (section) being shown for creation now? Yes when AP. CSS hides Sim/Não outside aprofundamento (from #677). But if a card has suspect checked and the user is in creation, yesNoWrap is shown? It would be hidden by CSS outside aprofundamento only when not `.is-doctor-aprof`? Comments said "Sim/Não oculto via CSS fora do aprofundamento". So fine.
Alright — no functional bug found. The change matches scope, uses existing function, is idempotent, safe.
Decision: Provide one low-severity maintainability comment about god template (mandated), and conclude with task_done.
Wait, but let me reconsider whether to also call out something real about code placement at 2826: `evRenderInjuredPersonBoxes` also gets invoked at page init in edit mode and when restoring draft. At init, before DOM for ev-suspeita-wrap exists? Wrap `#ev-suspeita-wrap` maybe doesn't exist in aprofundamento-only mode; guarded. Fine.
Let me write the final comment in Portuguese following the required format: (1) plain language impact; (2) why matters; (3) what to do.
Comment (anchored to line 2709 `evSyncDescaracterStageUi();` in evCreateInjuredPersonCard):
Content: "A correção adiciona mais duas chamadas de sincronização de tela dentro do bloco de script deste template, que já passa de 7.700 linhas e concentra markup, estado e chamadas AJAX. Na prática, cada nova correção de UI neste arquivo aumenta a dificuldade de manter e testar o fluxo, e o padrão do projeto é manter essa lógica em public/js/. Para este hotfix a mudança é aceitável e de baixo risco, mas vale registrar o débito: ao tocar de novo nesse fluxo, migrar a lógica de evCreateInjuredPersonCard/evRenderInjuredPersonBoxes e das funções de sincronização para um arquivo JS dedicado."
Severity low, category maintainability.
Should I add the note about redundant double sync? Let me consider it as an "other"/"low" with clear explanation:
"evSyncDescaracterStageUi também já roda durante a criação do card via evBindInjuredCardEvents → evSyncDescaracterUi (linhas 2647/2947); com a chamada nova, a sincronização passa a ocorrer duas vezes no mesmo fluxo e, dentro de evRenderInjuredPersonBoxes, uma vez por card no loop (linha 2813) mais a chamada no fim. Como a função é idempotente o impacto é só custo desnecessário de manipulação de DOM — se a intenção era cobrir apenas cards já existentes (retorno antecipado em evCreateInjuredPersonCard), o ponto de correção mais preciso seria onde esses cards existentes são reaproveitados."
Hmm. Actually this observation about early-return in evCreateInjuredPersonCard is valuable: at 2658, when the card already exists, `evCreateInjuredPersonCard` returns early — no sync. So for flows where a card already exists and type hasn't been synced... but type change handler syncs anyway. The scenario "existing card" means the card was already created earlier while type AP was set → the earlier creation should have synced. So no gap.
I'll keep the comment focused but mention the redundancy briefly. Actually, the user wants concise. I'll combine into one comment per new line? Two comments at two different locations with overlapping content might be duplicated. I'll do a single comment anchored to the first added line and mention the second line as part of the same observation.
Actually, given the guideline to focus on newly added code and there are no confirmed bugs, maybe best to keep only the god-template note. It satisfies the mandatory rule while being honest that no functional problems found. I'll then call task_done.
Wait, I should double check whether an actual, subtle issue exists regarding `evRenderInjuredPersonBoxes` being called before cards exist AND before `#ev_type` set, in contexts where the offcanvas opens in aprofundamento edit mode with draft restore — but those run only with a saved event having type. It's fine.
Let me now also confirm scope compliance: the change belongs to ssma occurrence modal; it's within the declared scope; no endpoint contract issues; no XSS; no new components needed. All good.
Final answer: 1 comment (low) about god template and redundancy, then task_done.
Let me write concise Portuguese comment in required format.
Analisei o diff e o contexto das duas linhas adicionadas. Vou verificar rapidamente o trecho da função de sincronização e o fluxo de criação de card que já chama `evSyncDescaracterUi`.
Tool Calls (1)
file_read
Show Details
Arguments
{"end_line": 2652, "file_path": "templates/ssma/occurrence/partials/_modal_event.html.twig", "start_line": 2580}
Result
File: templates/ssma/occurrence/partials/_modal_event.html.twig (Total lines: 7712)
IS_TRUNCATED: false
LINE_RANGE: 2580-2652
2580| e.preventDefault();
2581| e.stopPropagation();
2582| // Mesmo padrão das Inspeções (Desvios): lápis alterna expandir/recolher.
2583| if (card.classList.contains('is-expanded')) {
2584| evCollapseInjuredCard(card);
2585| } else {
2586| evExpandInjuredCard(card);
2587| }
2588| });
2589| });
2590| var pick = card.querySelector('.js-ev-inj-pick');
2591| if (pick) {
2592| pick.addEventListener('click', function (e) {
2593| e.preventDefault();
2594| e.stopPropagation();
2595| evSelectPrimaryInjuredPerson(card.getAttribute('data-person-id'));
2596| });
2597| }
2598| card.querySelectorAll('.ev-inj-attendance, .ev-inj-relato, .ev-inj-injury-type, .ev-inj-injury-severity, .ev-inj-injury-classification, .ev-inj-had-injury, .ev-inj-consequence, .ev-inj-potential-consequence, .ev-inj-descaracter-comment').forEach(function (el) {
2599| el.addEventListener('change', function () {
2600| if (el.classList.contains('ev-inj-had-injury') && typeof window.evSyncHadInjuryUi === 'function') {
2601| window.evSyncHadInjuryUi();
2602| }
2603| if (el.classList.contains('ev-inj-injury-classification')) {
2604| evSyncCardCatFromClassification(card);
2605| }
2606| if (el.classList.contains('ev-inj-consequence')) {
2607| evSyncCardDerivedSeverity(card);
2608| evSyncCardPotentialGteReal(card);
2609| evSyncInjuryFieldsByConsequence();
2610| }
2611| if (el.classList.contains('ev-inj-potential-consequence')) {
2612| evSyncCardPotentialGteReal(card);
2613| }
2614| evUpdateInjuredCardSummary(card);
2615| evSyncInjuredPersonDetailsHidden();
2616| evPersistDraftSoon();
2617| });
2618| el.addEventListener('input', function () {
2619| evSyncInjuredPersonDetailsHidden();
2620| evPersistDraftSoon();
2621| });
2622| });
2623|
2624| card.querySelectorAll('.ev-inj-descaracter-btn').forEach(function (btn) {
2625| btn.addEventListener('click', function () {
2626| var val = this.getAttribute('data-descaracter-val');
2627| if (val === '1' && !evCanDescharacterizeAccident()) {
2628| return;
2629| }
2630| card.setAttribute('data-descaracterizado', val);
2631| var hidden = document.getElementById('ev_descaracterizado');
2632| if (hidden) hidden.value = val;
2633| var toggle = card.querySelector('.ev-inj-descaracter-toggle');
2634| if (toggle) toggle.classList.remove('is-invalid');
2635| evSyncDescaracterUi();
2636| evSyncInjuredPersonDetailsHidden();
2637| evPersistDraftSoon();
2638| });
2639| });
2640| card.querySelectorAll('.ev-inj-descaracter-comment').forEach(function (ta) {
2641| ta.addEventListener('input', function () {
2642| ta.classList.remove('is-invalid');
2643| });
2644| });
2645| evFilterCardConsequences(card);
2646| evSyncCardCatFromClassification(card);
2647| evSyncDescaracterUi();
2648| if (window.jQuery && window.jQuery.fn.tooltip) {
2649| window.jQuery(card).find('.ev-inj-descaracter-tip').tooltip({ container: 'body' });
2650| }
2651| }
2652|
Request #8
deepseek-v4-flash
P:28.02K C:3.72K CR:27.01K CW:0
27715ms
Reasoning
Confirmed: `evBindInjuredCardEvents` at line 2647 calls `evSyncDescaracterUi()`, which itself calls `evSyncDescaracterStageUi()` at line 2947. So for every card created via `evCreateInjuredPersonCard`, the stage sync already runs during binding (line 2688 → 2647 → 2947). The new line at 2709 therefore runs the same sync twice in the same creation path. That doesn't break anything (idempotent), but it's worth noting that the actual gap likely is in flows where cards already exist (early return at 2658) or in `evRenderInjuredPersonBoxes` after `wrap.innerHTML = ''` rebuild.
Hmm, but wait: in `evRenderInjuredPersonBoxes`, each card is created from scratch (wrap cleared), so binding triggers sync per card too. So the added call at 2826 is the redundant one there as well (runs N+1 times).
But if sync already runs on card creation, why did the reported bug exist ("checkbox não aparecia")? Perhaps because the `.ev-inj-descaracter` markup with checkbox inside the card template is only revealed when... hmm, or maybe the bug scenario is in the "Pessoas envolvidas" flow where the person was added and the card created at an earlier time, but ev_type was '' during a draft restore: evSyncInjuredCardsFromInvolved runs when type was restored afterward? Actually in a draft restore, type gets restored and then the type change handler runs sync. Hard to say.
Either way, I don't need to resolve the root cause. As reviewer, since the added sync is idempotent and idempotent re-runs are safe, no functional bug. But there is an interesting nuance: if sync already happened during binding, then adding it again at the end indicates the real missing path is elsewhere — a reviewer could ask whether the fix addresses the actual root cause or just masks it (since running the sync twice at card creation means it will also run even when it shouldn't be needed, and it doesn't cover cards that exist without creation).
Actually wait — it DOES cover the "existing card returned early" scenario partially? No: in evCreateInjuredPersonCard, early return at 2658 means the added line at 2709 is NOT reached for existing cards. So for existing cards, no new sync. So if the bug was "card already exists and block remains hidden", this fix doesn't cover it either. But per the PR description, the bug was after adding a person, i.e., new card creation.
Given the redundancy with the binding-time sync (line 2647 → evSyncDescaracterUi → evSyncDescaracterStageUi line 2947), the claim in the PR description that "evSyncDescaracterStageUi() só rodava ao mudar o tipo, não depois de evCreateInjuredPersonCard" seems inaccurate for the card creation path. But maybe evSyncDescaracterUi→evSyncDescaracterStageUi chain was introduced recently (PR #677 landed just before). If the bug persisted, perhaps in creation mode `evSyncDescaracterStageUi` still doesn't show the checkbox because some other CSS class (d-none added after sync) later. Hmm.
Not necessary to fully resolve. But as reviewer I could flag a "redundant/innefective?" question. Since I cannot prove the fix fails, I should avoid claiming a bug. I'll flag:
1. God template (mandated) — low severity.
2. Redundancy — the new call in evCreateInjuredPersonCard duplicates sync that already runs in evBindInjuredCardEvents (2647→2947); ask whether the real gap is the early-return/existing-card path, and that running the loop-level sync per card plus the extra call in evRenderInjuredPersonBoxes multiplies DOM work (N+1 runs). Low severity.
Actually per format guidance for comments: plain language first, then technical details.
I'll produce two comments anchored to each added line:
Comment A (line 2709):
- Content (low, maintainability): about god template + note that sync already executes when binding events (evBindInjuredCardEvents → evSyncDescaracterUi → evSyncDescaracterStageUi), so this second call on same path is redundant; suggest verifying the actual missing path (cards já existentes / early return) and considering consolidating.
- Hmm, that's mixing. Let me split: the redundancy claim is a functional/maintainability observation. Keep separate anchors.
Actually, let me structure:
Comment 1 anchored at line 2709 (category maintainability, severity low):
"Estas duas chamadas novas ficam dentro de um script de template que já ultrapassa 7.700 linhas misturando markup, estado e AJAX; cada correção de tela nesse arquivo aumenta o custo de manutenção e o risco de regressão. Não bloqueia este hotfix, mas o débito deve ser registrado: a lógica de evCreateInjuredPersonCard/evRenderInjuredPersonBoxes e das funções evSync* deveria viver em public/js/, com o template só disparando o init."
Comment 2 anchored at line 2826 or 2709 (category other/low): redundancy observation:
"Ao criar um card, a sincronização já roda dentro de evBindInjuredCardEvents (que chama evSyncDescaracterUi → evSyncDescaracterStageUi) e, em evRenderInjuredPersonBoxes, ela é executada uma vez por card dentro do loop mais esta chamada no fim. Como a função só alterna classes com base no estado atual, repeti-la é inofensivo, mas se o bug reportado ocorria mesmo com o card recém-criado, vale confirmar que a causa não está em outro ponto (ex.: card já existente retorna cedo em evCreateInjuredPersonCard sem passar pela sincronização) — senão a correção só mascara o sintoma."
Hmm, these are both somewhat weak. But I think the user rules want the god-template flag first. The redundancy note is genuinely useful to confirm fix targets the right path.
Let me reconsider whether the redundancy comment is accurate — is line 2647's call inside evBindInjuredCardEvents unconditional and executed for each card creation? Yes, at 2688 evBindInjuredCardEvents(card) is called after append, and 2647 evSyncDescaracterUi() executes; evSyncDescaracterUi at 2942 calls evSyncDescaracterStageUi at 2947 unconditionally. So yes — the sync runs on every fresh card creation even without this PR.
Wait, then how could the reported bug have occurred if sync already ran on card creation? Two possibilities:
a) The reported flow doesn't go through evCreateInjuredPersonCard. But evSyncInjuredCardsFromInvolved (line 2372-2383) does call evCreateInjuredPersonCard for new cards.
b) The bug happened in a flow where the card is created BEFORE type is set to ACIDENTE_PESSOAL, then type change triggers sync that now should fix it (type handler). Hmm but the PR says sync only ran when changing type and not after card creation...
Actually wait — I should check evSyncDescaracterStageUi line 2927 toggles `.ev-inj-descaracter` visibility based on isAp. When card creation happens, sync runs. If type is AP at that point, the section is shown. So bug shouldn't exist. Unless the issue is that the section `.ev-inj-descaracter` is visible but the checkbox itself is inside an area that gets hidden later (e.g., after `evUpdateInjuredPersonsEmptyState` or some subsequent step).
Actually maybe I'm wrong about which function is called during the "Pessoas envolvidas" flow. Let me search where people-added event handlers call card functions. The flow "Pessoas envolvidas" probably uses a people-picker that adds chips and calls `evSyncInjuredCardsFromInvolved`. New person → card created → sync (line 2647) runs. Hmm.
But maybe there's a distinct newer flow where cards for medical data are created only inside evRenderInjuredPersonBoxes without binding? No—binding always in create.
I shouldn't keep second-guessing. Since there's a plausible mechanism for the fix to be effective (maybe the earlier binding sync ran while some other code later added d-none to the section), the fix is harmless and the review value is: (1) god-template flag; (2) possible redundancy/root-cause question. Both are low-severity, non-blocking.
Let me also double check the code_comment tool anchoring: existing_code must match new lines. I'll anchor comment to "evSyncDescaracterStageUi();" — but this line appears twice (2709 and 2826). The tool says it matches consecutive lines; since the snippet "evSyncDescaracterStageUi();" is identical in both places, the anchor may be ambiguous. To disambiguate, include surrounding lines that are unique. For line 2709, include:
```
evEnsurePrimaryInjuredMarked();
evSyncDescaracterStageUi();
return card;
```
These are new lines? The added line is only evSyncDescaracterStageUi(); the surrounding lines are unchanged context. The tool requires "Only return newly added code lines, should not include deleted code or unchanged code lines." Hmm — but including unchanged context helps anchor. Actually the instruction says existing_code should contain newly added lines. To be safe, the snippet should include the added line; but identical text at two spots is ambiguous. Provide multiple consecutive lines including unique context, which includes unchanged lines. The spec for the sliding-window matching says "It should contain one or several consecutive lines of code most relevant to your comment." I think including context lines is acceptable, but they warn not to include deleted lines. Context unchanged lines are fine.
Alternatively use distinct anchors:
- Line 2709 comment anchor: "evSyncDescaracterStageUi();\n return card;" (added line + unchanged following line).
- Line 2826 comment anchor: "evUpdateInjuredPersonsEmptyState();\n evSyncDescaracterStageUi();" — evUpdateInjuredPersonsEmptyState is unchanged above the added line.
Both contain the added line plus unique context. Good.
Actually I'll just put a single combined comment (both added lines same nature) anchored to line 2709 with context "evSyncDescaracterStageUi();\n return card;". But the god-template and redundancy points both apply. It might be cleaner to provide 2 comments:
1) anchored to line 2709 (with "return card;" after) — god template + redundancy note combined? No, keep the redundancy anchored to the evRenderInjuredPersonBoxes location? Actually the redundancy applies mostly to evCreateInjuredPersonCard path (binding already syncs). And the "N+1" applies to evRenderInjuredPersonBoxes loop. Both new lines.
To be concise: I'll write one comment per added line, both low severity, no duplication:
- Comment 1 (2709, maintainability/low): god template + registrar débito. Format per instructions.
- Comment 2 (2826, other/low): redundância/root cause check.
Wait, but Comment 1 about god-template relates to the file generally. Anchor at 2709 fine.
Let me finalize the Portuguese text:
Comment 1:
"Essa sincronização de tela entra no meio de um script de template com mais de 7.700 linhas, que já mistura markup, estado da tela e chamadas AJAX. Cada ajuste novo nesse arquivo aumenta o custo de manutenção e o risco de regressão em fluxos que dependem do mesmo bloco. Não bloqueia o hotfix, mas registre o débito: a lógica de criação/atualização dos cards e das funções evSync* deveria viver em public/js/, com o Twig apenas iniciando o script."
Comment 2:
"Na criação de um card a sincronização já roda dentro de evBindInjuredCardEvents (que chama evSyncDescaracterUi e, por dentro dela, evSyncDescaracterStageUi). Ou seja, no caminho de card recém-criado essa chamada é executada duas vezes, e em evRenderInjuredPersonBoxes ela roda uma vez por card no loop antes desta chamada final. É idempotente e não causa quebra, mas vale confirmar que o caso que falhava é mesmo o de card novo — se for o de card já existente (que retorna cedo em evCreateInjuredPersonCard), este ponto não cobre o problema e o sintoma continuaria."
Hmm wait — actually, the early return at evCreateInjuredPersonCard: cards that already exist were created earlier with sync, so they'd already be correct... unless the bug path creates the card markup outside this function. Let me not over-assert. The note phrase "vale confirmar" is fine as a question.
But let me reconsider whether Comment 2 is worth it given uncertainty and low value. I think a reviewer would genuinely ask "why is this needed if binding already syncs?" — it helps validate that the fix is at the right place. Keep it low severity.
Also need to weigh: The instructions say comments should address issues; if no issue, task_done. Given these two low-severity notes are legitimate per user rules (god template mandatory), I'll post them and then task_done.
Let me make sure the exact text snippet for anchors exists in the diff. The added line at 2826 is preceded by unchanged `evUpdateInjuredPersonsEmptyState();` and followed by `if (evCurrentStep === 'aprofundamento'...`. For anchor use:
```
evUpdateInjuredPersonsEmptyState();
evSyncDescaracterStageUi();
```
For 2709 use:
```
evSyncDescaracterStageUi();
return card;
```
Both contain the added line. Good.
Severities: god-template = low? The user rules say it has "maior peso" but as a flag. Given no new structural mixing beyond two lines, I'd say "low" severity maintainability. Redundancy = low.
Let me post.
Analisei o diff e o contexto das funções envolvidas. As duas chamadas adicionadas estão corretas do ponto de vista funcional (a função é idempotente e segura para rodar após a montagem do card), então não há bug ou risco de segurança/integridade. Deixo apenas observações de manutenção/arquitetura exigidas pelas regras do repositório.
Tool Calls (2)
code_comment
Show Details
Arguments
{"comments": [{"content": "Essa sincronização de tela entra no meio de um script de template que já passa de 7.700 linhas, misturando markup, estado da tela e chamadas AJAX. Cada ajuste novo nesse arquivo aumenta o custo de manutenção e o risco de regressão em fluxos que dependem do mesmo bloco. Não bloqueia o hotfix (a mudança é pequena e correta), mas registre o débito: a lógica de montagem dos cards e das funções evSync* deveria viver em public/js/, com o Twig apenas iniciando o script.", "existing_code": " evSyncDescaracterStageUi();\n return card;", "category": "maintainability", "severity": "low", "path": "templates/ssma/occurrence/partials/_modal_event.html.twig"}]}
Result
(async)
code_comment
Show Details
Arguments
{"comments": [{"content": "Na criação de um card a sincronização de descaracterização já roda dentro de evBindInjuredCardEvents (que chama evSyncDescaracterUi e, por dentro dela, evSyncDescaracterStageUi) — ou seja, no caminho de card recém-criado ela passa a executar duas vezes; e em evRenderInjuredPersonBoxes ela roda uma vez por card dentro do loop antes desta chamada final. Como a função só alterna classes com base no estado atual, repetir é inofensivo, mas vale confirmar que o cenário que falhava é mesmo o de card novo: se o problema for card já existente (que retorna cedo em evCreateInjuredPersonCard e não passa pela sincronização), este ponto não cobre o caso.", "existing_code": " evUpdateInjuredPersonsEmptyState();\n evSyncDescaracterStageUi();", "category": "other", "severity": "low", "path": "templates/ssma/occurrence/partials/_modal_event.html.twig"}]}
Result
(async)
Request #9
deepseek-v4-flash
P:31.77K C:53 CR:31.74K CW:0
1574ms
Reasoning
Now conclude with task_done.
Tool Calls (1)
task_done
Show Details
Arguments
{"state": "DONE"}
Request #10
deepseek-v4-flash
P:6K C:494 CR:5.63K CW:0
3034ms
Reasoning
Let me analyze the task. I need to review the changes in the file `templates/ssma/occurrence/partials/_modal_event.html.twig`.
The diff adds `evSyncDescaracterStageUi();` calls at the end of `evCreateInjuredPersonCard()` and `evRenderInjuredPersonBoxes()`.
There are two previously confirmed findings that I should NOT repeat:
1. God template concern - the file is over 7,700 lines mixing markup, state, and AJAX.
2. Double sync / redundant call concern in `evCreateInjuredPersonCard` (because `evBindInjuredCardEvents` already calls `evSyncDescaracterUi` which calls `evSyncDescaracterStageUi`) and in `evRenderInjuredPersonBoxes`.
Wait, actually looking at the confirmed findings again:
1. Finding 1: About the god template and maintainability.
2. Finding 2: About the double execution issue.
So I should continue reviewing the files and report other real issues.
Let me look at the actual code context to understand what's happening. Let me read the file around these areas.
Let me investigate the relevant functions:
- `evCreateInjuredPersonCard()`
- `evRenderInjuredPersonBoxes()`
- `evSyncDescaracterStageUi()`
- `evSyncDescaracterUi()`
- `evBindInjuredCardEvents()`
- `evEnsurePrimaryInjuredMarked()`
Let me read the code.
Tool Calls (2)
file_read
Show Details
Arguments
{"file_path": "templates/ssma/occurrence/partials/_modal_event.html.twig", "start_line": 2550, "end_line": 2850}
Result
File: templates/ssma/occurrence/partials/_modal_event.html.twig (Total lines: 7712)
IS_TRUNCATED: false
LINE_RANGE: 2550-2850
2550| var wrap = document.getElementById('ev_injured_person_boxes');
2551| var sel = document.getElementById('ev_person_id');
2552| if (!wrap || !personId) return;
2553| var safe = String(personId);
2554| if (sel) sel.setAttribute('data-primary-injured-id', safe);
2555| evSyncInjuredPickCircles(safe);
2556| evPersistDraftSoon();
2557| }
2558|
2559| function evEnsurePrimaryInjuredMarked() {
2560| var wrap = document.getElementById('ev_injured_person_boxes');
2561| if (!wrap) return;
2562| var hasPrimary = !!wrap.querySelector('.ev-injured-person-box.is-primary');
2563| if (hasPrimary) {
2564| evSyncPrimaryInjuredPersonId();
2565| return;
2566| }
2567| var first = wrap.querySelector('.ev-injured-person-box[data-person-id]');
2568| if (first) {
2569| evSelectPrimaryInjuredPerson(first.getAttribute('data-person-id'));
2570| } else {
2571| evSyncPrimaryInjuredPersonId();
2572| }
2573| }
2574|
2575| function evBindInjuredCardEvents(card) {
2576| if (!card || card.dataset.bound === '1') return;
2577| card.dataset.bound = '1';
2578| card.querySelectorAll('.js-ev-inj-toggle').forEach(function (btn) {
2579| btn.addEventListener('click', function (e) {
2580| e.preventDefault();
2581| e.stopPropagation();
2582| // Mesmo padrão das Inspeções (Desvios): lápis alterna expandir/recolher.
2583| if (card.classList.contains('is-expanded')) {
2584| evCollapseInjuredCard(card);
2585| } else {
2586| evExpandInjuredCard(card);
2587| }
2588| });
2589| });
2590| var pick = card.querySelector('.js-ev-inj-pick');
2591| if (pick) {
2592| pick.addEventListener('click', function (e) {
2593| e.preventDefault();
2594| e.stopPropagation();
2595| evSelectPrimaryInjuredPerson(card.getAttribute('data-person-id'));
2596| });
2597| }
2598| card.querySelectorAll('.ev-inj-attendance, .ev-inj-relato, .ev-inj-injury-type, .ev-inj-injury-severity, .ev-inj-injury-classification, .ev-inj-had-injury, .ev-inj-consequence, .ev-inj-potential-consequence, .ev-inj-descaracter-comment').forEach(function (el) {
2599| el.addEventListener('change', function () {
2600| if (el.classList.contains('ev-inj-had-injury') && typeof window.evSyncHadInjuryUi === 'function') {
2601| window.evSyncHadInjuryUi();
2602| }
2603| if (el.classList.contains('ev-inj-injury-classification')) {
2604| evSyncCardCatFromClassification(card);
2605| }
2606| if (el.classList.contains('ev-inj-consequence')) {
2607| evSyncCardDerivedSeverity(card);
2608| evSyncCardPotentialGteReal(card);
2609| evSyncInjuryFieldsByConsequence();
2610| }
2611| if (el.classList.contains('ev-inj-potential-consequence')) {
2612| evSyncCardPotentialGteReal(card);
2613| }
2614| evUpdateInjuredCardSummary(card);
2615| evSyncInjuredPersonDetailsHidden();
2616| evPersistDraftSoon();
2617| });
2618| el.addEventListener('input', function () {
2619| evSyncInjuredPersonDetailsHidden();
2620| evPersistDraftSoon();
2621| });
2622| });
2623|
2624| card.querySelectorAll('.ev-inj-descaracter-btn').forEach(function (btn) {
2625| btn.addEventListener('click', function () {
2626| var val = this.getAttribute('data-descaracter-val');
2627| if (val === '1' && !evCanDescharacterizeAccident()) {
2628| return;
2629| }
2630| card.setAttribute('data-descaracterizado', val);
2631| var hidden = document.getElementById('ev_descaracterizado');
2632| if (hidden) hidden.value = val;
2633| var toggle = card.querySelector('.ev-inj-descaracter-toggle');
2634| if (toggle) toggle.classList.remove('is-invalid');
2635| evSyncDescaracterUi();
2636| evSyncInjuredPersonDetailsHidden();
2637| evPersistDraftSoon();
2638| });
2639| });
2640| card.querySelectorAll('.ev-inj-descaracter-comment').forEach(function (ta) {
2641| ta.addEventListener('input', function () {
2642| ta.classList.remove('is-invalid');
2643| });
2644| });
2645| evFilterCardConsequences(card);
2646| evSyncCardCatFromClassification(card);
2647| evSyncDescaracterUi();
2648| if (window.jQuery && window.jQuery.fn.tooltip) {
2649| window.jQuery(card).find('.ev-inj-descaracter-tip').tooltip({ container: 'body' });
2650| }
2651| }
2652|
2653| function evCreateInjuredPersonCard(personId, saved, expand) {
2654| var wrap = document.getElementById('ev_injured_person_boxes');
2655| var tpl = document.getElementById('ev-injured-person-box-tpl');
2656| if (!wrap || !tpl || !personId) return null;
2657| var safe = String(personId).replace(/"/g, '');
2658| var existing = wrap.querySelector('.ev-injured-person-box[data-person-id="' + safe + '"]');
2659| if (existing) return existing;
2660|
2661| var source = tpl.querySelector('.ev-injured-person-box') || tpl.firstElementChild;
2662| if (!source) return null;
2663| var card = source.cloneNode(true);
2664| if (!card || !card.classList) return null;
2665| card.classList.remove('d-none');
2666|
2667| var involved = evGetPeopleInvolved();
2668| var sel = document.getElementById('ev_person_id');
2669| var opt = sel ? sel.querySelector('option[value="' + safe + '"]') : null;
2670| var name = involved.names[personId]
2671| || (opt ? String(opt.text || '').trim() : '')
2672| || ('#' + personId);
2673|
2674| card.setAttribute('data-person-id', String(personId));
2675| var nameEl = card.querySelector('.ev-inj-person-name');
2676| if (nameEl) nameEl.textContent = name;
2677| var sumName = card.querySelector('.js-ev-inj-summary-name');
2678| if (sumName) sumName.textContent = name;
2679|
2680| saved = saved || {};
2681| if (!saved.attendance_date) saved.attendance_date = evTodayDateInputValue();
2682| if (saved.had_injury === undefined) saved.had_injury = true;
2683| evApplyCardInjuryData(card, saved);
2684|
2685| evRenderInjuredPersonSummary(card, personId);
2686|
2687| wrap.appendChild(card);
2688| evBindInjuredCardEvents(card);
2689|
2690| if (expand) {
2691| evExpandInjuredCard(card);
2692| } else {
2693| evCollapseInjuredCard(card, true);
2694| if (evCurrentStep === 'aprofundamento'
2695| && evSelectedType() === 'ACIDENTE_PESSOAL'
2696| && !wrap.querySelector('.ev-injured-person-box.is-expanded')) {
2697| evExpandInjuredCard(card);
2698| }
2699| }
2700| if (evCurrentStep === 'aprofundamento' && evSelectedType() === 'ACIDENTE_PESSOAL') {
2701| if (typeof syncInjuryFieldsForCard === 'function') {
2702| syncInjuryFieldsForCard(card);
2703| }
2704| if (typeof evFilterCardConsequences === 'function') {
2705| evFilterCardConsequences(card);
2706| }
2707| }
2708| evEnsurePrimaryInjuredMarked();
2709| evSyncDescaracterStageUi();
2710| return card;
2711| }
2712|
2713| function evRemoveInjuredPersonBox(personId) {
2714| var wrap = document.getElementById('ev_injured_person_boxes');
2715| if (!wrap || !personId) return;
2716| var safe = String(personId).replace(/"/g, '');
2717| var card = wrap.querySelector('.ev-injured-person-box[data-person-id="' + safe + '"]');
2718| if (!card) return;
2719| var wasPrimary = card.classList.contains('is-primary');
2720| if (card.classList.contains('is-expanded')) {
2721| evParkBodyMapBlock();
2722| evClearCanonicalInjuryIds();
2723| }
2724| card.remove();
2725| var details = evGetInjuredDetailsObj();
2726| delete details[String(personId)];
2727| evSetInjuredDetailsObj(details);
2728| // Não auto-expande a próxima — todas ficam colapsadas até o usuário editar.
2729| if (wasPrimary) {
2730| var next = wrap.querySelector('.ev-injured-person-box[data-person-id]');
2731| if (next) {
2732| evSelectPrimaryInjuredPerson(next.getAttribute('data-person-id'));
2733| } else {
2734| var sel = document.getElementById('ev_person_id');
2735| if (sel) sel.removeAttribute('data-primary-injured-id');
2736| evSyncInjuredPickCircles('');
2737| }
2738| } else {
2739| evSyncPrimaryInjuredPersonId();
2740| }
2741| evFilterInjuredPersonSelect();
2742| evPersistDraftSoon();
2743| evUpdateInjuredPersonsEmptyState();
2744| }
2745|
2746| /**
2747| * Select oculto (legado): adicionar acidentado manualmente — fluxo principal = cards via Pessoas envolvidas.
2748| */
2749| var _evAddingInjuredLock = false;
2750| function evAddInjuredPersonFromSelect() {
2751| if (_evAddingInjuredLock) return;
2752| var sel = document.getElementById('ev_person_id');
2753| if (!sel) return;
2754| var personId = String(sel.value || '');
2755| if (!personId) return;
2756|
2757| _evAddingInjuredLock = true;
2758| try {
2759| var wrap = document.getElementById('ev_injured_person_boxes');
2760| var safe = personId.replace(/"/g, '');
2761| var existing = wrap && wrap.querySelector('.ev-injured-person-box[data-person-id="' + safe + '"]');
2762| if (existing) {
2763| // Mantém colapsada; usuário edita pelo lápis.
2764| evUpdateInjuredCardSummary(existing);
2765| } else {
2766| var saved = evGetInjuredDetailsObj()[personId] || {};
2767| var created = evCreateInjuredPersonCard(personId, saved, false);
2768| if (!created) {
2769| console.warn('[SSMA] Falha ao criar caixinha do acidentado', personId);
2770| } else {
2771| evSyncInjuredPersonDetailsHidden();
2772| }
2773| }
2774| // Limpa o select sem reentrar (setCustomSelectValue dispara change).
2775| sel.value = '';
2776| if (typeof window.setCustomSelectValue === 'function') {
2777| window.setCustomSelectValue('ev_person_id', '');
2778| } else {
2779| evSyncCustomSelectVisual('ev_person_id', true);
2780| }
2781| evSyncPrimaryInjuredPersonId();
2782| evFilterInjuredPersonSelect();
2783| } finally {
2784| _evAddingInjuredLock = false;
2785| }
2786| }
2787|
2788| /** Remonta caixinhas a partir de injured_person_details (+ person_id legado). */
2789| function evRenderInjuredPersonBoxes() {
2790| var wrap = document.getElementById('ev_injured_person_boxes');
2791| if (!wrap) return;
2792| var details = evGetInjuredDetailsObj();
2793| var ids = Object.keys(details);
2794| var primary = '';
2795| var sel = document.getElementById('ev_person_id');
2796| if (sel && sel.value) primary = String(sel.value);
2797| if (!primary && sel && sel.getAttribute('data-primary-injured-id')) {
2798| primary = String(sel.getAttribute('data-primary-injured-id') || '');
2799| }
2800|
2801| if (primary && !details[primary]) {
2802| details[primary] = { attendance_date: evTodayDateInputValue(), had_injury: true, body_parts: [] };
2803| evSetInjuredDetailsObj(details);
2804| ids = Object.keys(details);
2805| }
2806|
2807| evParkBodyMapBlock();
2808| evClearCanonicalInjuryIds();
2809| wrap.innerHTML = '';
2810|
2811| ids.forEach(function (pid) {
2812| // Sempre cria colapsada; expandir só via lápis (ou validação).
2813| evCreateInjuredPersonCard(pid, details[pid] || {}, false);
2814| });
2815| // Respeita primary já salvo; senão marca o primeiro.
2816| var preferred = primary || '';
2817| if (preferred && wrap.querySelector('.ev-injured-person-box[data-person-id="' + preferred.replace(/"/g, '') + '"]')) {
2818| evSelectPrimaryInjuredPerson(preferred);
2819| } else {
2820| evEnsurePrimaryInjuredMarked();
2821| }
2822| evSyncInjuredPersonDetailsHidden();
2823| evSyncPrimaryInjuredPersonId();
2824| evFilterInjuredPersonSelect();
2825| evUpdateInjuredPersonsEmptyState();
2826| evSyncDescaracterStageUi();
2827| if (evCurrentStep === 'aprofundamento' && evSelectedType() === 'ACIDENTE_PESSOAL') {
2828| window.requestAnimationFrame(function () {
2829| if (typeof evEnsurePrimaryInjuredCardExpanded === 'function') {
2830| evEnsurePrimaryInjuredCardExpanded();
2831| }
2832| });
2833| }
2834| }
2835| var evDraftTimer = null;
2836| function evPersistDraftSoon() {
2837| if (evDraftTimer) clearTimeout(evDraftTimer);
2838| evDraftTimer = setTimeout(evPersistDraftNow, 400);
2839| }
2840| function evPersistDraftNow() {
2841| var mode = (document.getElementById('ev_form_mode') || {}).value || 'create';
2842| if (mode !== 'create') return;
2843| try {
2844| var form = document.getElementById('form-event-new');
2845| if (!form) return;
2846| var data = {};
2847| Array.prototype.forEach.call(form.elements, function (el) {
2848| if (!el.name && !el.id) return;
2849| var key = el.id || el.name;
2850| if (!key) return;
code_search
Show Details
Arguments
{"search_text": "function evSyncDescaracterStageUi", "file_patterns": ["templates/ssma/occurrence/partials/_modal_event.html.twig"]}
Result
File: templates/ssma/occurrence/partials/_modal_event.html.twig
Match lines: 1
2917| function evSyncDescaracterStageUi() {
Request #11
deepseek-v4-flash
P:10.52K C:120 CR:6.4K CW:0
1221ms
Reasoning
Let me look at `evSyncDescaracterStageUi`, `evSyncDescaracterUi` functions.
Tool Calls (1)
file_read
Show Details
Arguments
{"end_line": 3100, "file_path": "templates/ssma/occurrence/partials/_modal_event.html.twig", "start_line": 2850}
Result
File: templates/ssma/occurrence/partials/_modal_event.html.twig (Total lines: 7712)
IS_TRUNCATED: false
LINE_RANGE: 2850-3100
2850| if (!key) return;
2851| if (el.type === 'checkbox' || el.type === 'radio') {
2852| data[key] = !!el.checked;
2853| } else {
2854| data[key] = el.value;
2855| }
2856| });
2857| data.__people_ids = (document.getElementById('ev_people_ids') || {}).value || '';
2858| data.__witness_ids = (document.getElementById('ev_witness_ids') || {}).value || '';
2859| data.__injured_details = (document.getElementById('ev_injured_person_details') || {}).value || '';
2860| sessionStorage.setItem(EV_DRAFT_KEY, JSON.stringify(data));
2861| } catch (e) {}
2862| }
2863| function evClearDraft() {
2864| try { sessionStorage.removeItem(EV_DRAFT_KEY); } catch (e) {}
2865| }
2866| function evRestoreDraftIfAny() {
2867| try {
2868| var raw = sessionStorage.getItem(EV_DRAFT_KEY);
2869| if (!raw) return false;
2870| var data = JSON.parse(raw);
2871| if (!data || typeof data !== 'object') return false;
2872| Object.keys(data).forEach(function (key) {
2873| if (key.indexOf('__') === 0) return;
2874| var el = document.getElementById(key);
2875| if (!el) return;
2876| if (el.type === 'checkbox' || el.type === 'radio') {
2877| el.checked = !!data[key];
2878| } else {
2879| el.value = data[key];
2880| }
2881| });
2882| if (data.__people_ids) {
2883| var pe = document.getElementById('ev_people_ids');
2884| if (pe) pe.value = data.__people_ids;
2885| }
2886| if (data.__witness_ids) {
2887| var we = document.getElementById('ev_witness_ids');
2888| if (we) we.value = data.__witness_ids;
2889| }
2890| if (data.__injured_details) {
2891| var ie = document.getElementById('ev_injured_person_details');
2892| if (ie) ie.value = data.__injured_details;
2893| }
2894| // Remonta caixinhas após restaurar o JSON do draft.
2895| setTimeout(function () {
2896| if (typeof evRenderInjuredPersonBoxes === 'function') evRenderInjuredPersonBoxes();
2897| }, 0);
2898| return true;
2899| } catch (e) {
2900| return false;
2901| }
2902| }
2903|
2904| function evCanDescharacterizeAccident() {
2905| return window.SSMA_CAN_DESCARACTERIZE === true || window.SSMA_CAN_DESCARACTERIZE === 'true';
2906| }
2907|
2908| function evIsDescaracterSuspectChecked() {
2909| var el = document.getElementById('ev_descaracter_suspect');
2910| return !!(el && el.checked);
2911| }
2912|
2913| function evIsCreateMode() {
2914| return ((document.getElementById('ev_form_mode') || { value: 'create' }).value === 'create');
2915| }
2916|
2917| function evSyncDescaracterStageUi() {
2918| var isAp = evSelectedType() === 'ACIDENTE_PESSOAL';
2919| var isDoctorAprof = !!evAprofundamentoOnlyMode;
2920| var form = document.getElementById('form-event-new');
2921| if (form) form.classList.toggle('is-doctor-aprof', isDoctorAprof);
2922| // Checkbox global de suspeita (etapa 1) fica sempre oculto — suspeita agora é por card no aprofundamento.
2923| var suspectWrap = document.getElementById('ev-suspeita-wrap');
2924| if (suspectWrap) {
2925| suspectWrap.classList.add('d-none');
2926| }
2927| document.querySelectorAll('.ev-inj-descaracter').forEach(function (el) {
2928| // Seção de descaracterização aparece sempre que é Acidente Pessoal (criação e aprofundamento).
2929| // Na criação: só o checkbox de suspeita fica visível (Sim/Não oculto via CSS fora do aprofundamento).
2930| el.classList.toggle('d-none', !isAp);
2931| });
2932| // Sincroniza Sim/Não de cada card com o estado do checkbox de suspeita do próprio card.
2933| document.querySelectorAll('.ev-injured-person-box').forEach(function (card) {
2934| var suspChk = card.querySelector('.ev-inj-suspect-chk');
2935| var yesNoWrap = card.querySelector('.ev-inj-descaracter-yesno-wrap');
2936| if (suspChk && yesNoWrap) {
2937| yesNoWrap.classList.toggle('d-none', !suspChk.checked);
2938| }
2939| });
2940| }
2941|
2942| function evSyncDescaracterUi() {
2943| var hidden = document.getElementById('ev_descaracterizado');
2944| var canSn = evCanDescharacterizeAccident();
2945| var cur = String((hidden || {}).value || '');
2946|
2947| evSyncDescaracterStageUi();
2948|
2949| // Pré-seleciona "Sim" quando o profissional não tem permissão de descaracterização
2950| // e o campo ainda está vazio. Ele só pode dizer "Sim" de qualquer forma, então
2951| // pré-preencher evita a validação falhar sem o usuário perceber o que falta.
2952| if (!canSn && cur === '' && evAprofundamentoOnlyMode && hidden) {
2953| hidden.value = '0';
2954| cur = '0';
2955| document.querySelectorAll('.ev-injured-person-box').forEach(function (c) {
2956| c.setAttribute('data-descaracterizado', '0');
2957| });
2958| }
2959|
2960| document.querySelectorAll('.ev-injured-person-box').forEach(function (card) {
2961| var noPerm = card.querySelector('.ev-inj-descaracter-no-perm');
2962| var cardDesc = card.getAttribute('data-descaracterizado') || cur;
2963| if (noPerm) noPerm.classList.toggle('d-none', canSn);
2964| card.querySelectorAll('.ev-inj-descaracter-btn').forEach(function (b) {
2965| var val = b.getAttribute('data-descaracter-val');
2966| // Sem permissão: "Não" fica visível mas desabilitado — o par Sim/Não precisa aparecer.
2967| if (val === '1' && !canSn) {
2968| b.disabled = true;
2969| b.classList.remove('d-none');
2970| b.setAttribute('title', 'Sem permissão para descaracterizar o acidente.');
2971| } else {
2972| b.disabled = false;
2973| b.classList.remove('d-none');
2974| b.removeAttribute('title');
2975| }
2976| });
2977| if (window.SsmaShared && typeof window.SsmaShared.toggleYesNo === 'function') {
2978| window.SsmaShared.toggleYesNo(card.querySelectorAll('.ev-inj-descaracter-btn'), cardDesc !== '' ? cardDesc : null, {
2979| valueAttr: 'data-descaracter-val'
2980| });
2981| }
2982| });
2983| }
2984|
2985| /** Etapa 0: admin Aura + membro — esconde título/status só na criação; na edição volta. */
2986| function evApplyAuraTitleStatusVisibility(mode) {
2987| var row = document.getElementById('ev-title-status-row');
2988| if (!row) return;
2989| var hideOnCreate = !!window.SSMA_HIDE_EVENT_TITLE_STATUS_ON_CREATE
2990| || !!window.SSMA_IS_AURA_ADMIN;
2991| var hide = hideOnCreate && mode === 'create';
2992| row.classList.toggle('d-none', hide);
2993| var statusEl = document.getElementById('ev_status');
2994| if (statusEl) {
2995| if (hide) {
2996| statusEl.removeAttribute('required');
2997| if (!statusEl.value) statusEl.value = 'ABERTO';
2998| } else {
2999| statusEl.setAttribute('required', 'required');
3000| }
3001| }
3002| }
3003|
3004| function evSyncAaIdentFields(type) {
3005| var wrap = document.getElementById('ev-aa-ident-fields');
3006| if (!wrap) return;
3007| var show = type === 'ACIDENTE_AMBIENTAL';
3008| wrap.classList.toggle('d-none', !show);
3009| }
3010|
3011| function evSyncContainmentTimeEnabled() {
3012| var done = document.getElementById('ev_containment_done');
3013| var time = document.getElementById('ev_containment_time');
3014| if (!done || !time) return;
3015| time.disabled = !done.checked;
3016| if (!done.checked) time.value = '';
3017| }
3018|
3019| // true se a data/hora informada cair em um dia de calendário posterior a hoje (local).
3020| function evIsEventDatetimeFutureDay(value) {
3021| if (!value) return false;
3022| var evWhen = new Date(value);
3023| if (isNaN(evWhen.getTime())) return true;
3024| var now = new Date();
3025| var todayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate());
3026| var eventDayStart = new Date(evWhen.getFullYear(), evWhen.getMonth(), evWhen.getDate());
3027| return eventDayStart.getTime() > todayStart.getTime();
3028| }
3029|
3030| function evCheckFormValidityScoped(MV) {
3031| var form = document.getElementById('form-event-new');
3032| if (!form) return true;
3033| var ok = true;
3034| Array.prototype.forEach.call(form.elements, function (el) {
3035| if (!evIsElementVisibleForValidation(el)) {
3036| return;
3037| }
3038| if (el.type === 'button' || el.type === 'submit') {
3039| return;
3040| }
3041| if (typeof el.checkValidity === 'function' && el.willValidate && !el.checkValidity()) {
3042| ok = false;
3043| if (MV && window.jQuery) MV.markInvalid(window.jQuery(el));
3044| }
3045| });
3046| return ok;
3047| }
3048|
3049| /** Membro que relatou o evento (ROS: Relatado por ou usuário logado; QA: 1ª pessoa envolvida). */
3050| function evReporterMemberIdForAprofundamento(type) {
3051| type = type || evSelectedType();
3052| if (type === 'ROS') {
3053| var reportedBy = String((document.getElementById('ev_manager') || { value: '' }).value || '').trim();
3054| if (reportedBy) {
3055| return reportedBy;
3056| }
3057| return EV_LOGGED_MEMBER_ID ? String(EV_LOGGED_MEMBER_ID) : '';
3058| }
3059| if (type === 'QUASE_ACIDENTE') {
3060| var qaPerson = String((document.getElementById('ev_person_id_qa') || { value: '' }).value || '').trim();
3061| if (qaPerson) {
3062| return qaPerson;
3063| }
3064| var peopleIds = String((document.getElementById('ev_people_ids') || { value: '' }).value || '').trim();
3065| if (peopleIds) {
3066| return peopleIds.split(',')[0].trim();
3067| }
3068| return EV_LOGGED_MEMBER_ID ? String(EV_LOGGED_MEMBER_ID) : '';
3069| }
3070| return '';
3071| }
3072|
3073| /** Gestor direto (superior) do membro que relatou — preenche o Aprofundamento. */
3074| function evIsLoggedUserDirectManagerOfReporter(type) {
3075| if (!EV_LOGGED_MEMBER_ID) {
3076| return false;
3077| }
3078| var reporterId = evReporterMemberIdForAprofundamento(type);
3079| if (!reporterId) {
3080| return false;
3081| }
3082| var meta = (window.SSMA_EV_MEMBERS_BY_ID || {})[String(reporterId)];
3083| if (!meta || meta.superior_id == null || meta.superior_id === '') {
3084| return false;
3085| }
3086| return String(meta.superior_id) === String(EV_LOGGED_MEMBER_ID);
3087| }
3088|
3089| function evIsAprofundamentoFinalized() {
3090| return !!evAprofundamentoFinalized;
3091| }
3092|
3093| function evCanEditAprofundamento(type) {
3094| type = type || evSelectedType();
3095| if (!evRequiresAprofundamento(type)) {
3096| return false;
3097| }
3098| if (evIsAprofundamentoFinalized() && !EV_IS_ADMIN_APROFUNDAMENTO) {
3099| return false;
3100| }
Request #12
deepseek-v4-flash
P:14.04K C:2.11K CR:10.62K CW:0
13755ms
Reasoning
Now let me understand the key context.
The confirmed findings say:
1. God template concern (7,700+ lines).
2. Double sync in `evCreateInjuredPersonCard` (via evBindInjuredCardEvents → evSyncDescaracterUi → evSyncDescaracterStageUi) and redundant sync in `evRenderInjuredPersonBoxes` (which iterates cards through evCreateInjuredPersonCard, each one already binds events and syncs).
Wait, but actually the confirmed finding #2 already addresses this duplicate-call issue. Let me re-read: "Na criação de um card a sincronização de descaracterização já roda dentro de evBindInjuredCardEvents (que chama evSyncDescaracterUi e, por dentro dela, evSyncDescaracterStageUi) — ou seja, no caminho de card recém-criado ela passa a executar duas vezes; e em evRenderInjuredPersonBoxes ela roda uma v..."
So that's already confirmed, and I should NOT repeat it.
Now I should look for other real issues. Let me analyze the change's functionality itself.
The diff adds `evSyncDescaracterStageUi();` at:
1. End of `evCreateInjuredPersonCard()` (line 2709) — after `evEnsurePrimaryInjuredMarked();`
2. End of `evRenderInjuredPersonBoxes()` (line 2826) — after `evUpdateInjuredPersonsEmptyState();`
Now, `evSyncDescaracterStageUi()` at line 2917 uses `evSelectedType()`, `evAprofundamentoOnlyMode`, `form-event-new`, `ev-suspeita-wrap`.
Let me look at where `evSyncDescaracterStageUi` is called elsewhere — when changing the type. Let me look for the context of the type change handler, and where the descaracter-related UI is set up.
Actually, wait — there's a potential functional issue. Let me check the flow more carefully.
In `evCreateInjuredPersonCard`, `evBindInjuredCardEvents(card)` is called. Inside `evBindInjuredCardEvents`, `evSyncDescaracterUi()` is invoked at line 2647 (after `evFilterCardConsequences(card); evSyncCardCatFromClassification(card);`). And `evSyncDescaracterUi` calls `evSyncDescaracterStageUi()` at line 2947.
So at creation time of the card within `evCreateInjuredPersonCard`, `evSyncDescaracterStageUi` is already executed once (via bind). Then a second explicit call at line 2709 happens — harmless duplicate for that path.
Hmm — wait, but does `evBindInjuredCardEvents` return early if `card.dataset.bound === '1'`? Yes: at line 2576, `if (!card || card.dataset.bound === '1') return;`. For new cards, they aren't bound yet, so events bind and `evSyncDescaracterUi` runs.
Now, importantly: is there a scenario where `evSyncDescaracterStageUi` visibility toggle (`d-none` on `.ev-inj-descaracter`) could now be re-toggled incorrectly? Let's consider the intended behavior. `.ev-inj-descaracter` blocks should be shown when `isAp` (type is ACIDENTE_PESSOAL) — in both creation and aprofundamento. And per PR description, at creation only the suspect checkbox is visible, Sim/Não hidden (via CSS outside aprofundamento).
The added call makes the block visible at card creation. However, since the card is a clone of the template, the `.ev-inj-descaracter` element in the cloned card may have `d-none` class initially (since template default). The added call removes the `d-none` when the type is ACIDENTE_PESSOAL. So this achieves the fix's goal.
But wait — is there a possibility of the fix not being sufficient, or introducing a regression? The confirmed finding 2 covers the duplication and the redundant extra sync. But is there any real NEW issue introduced by these two lines beyond the redundancy? Let's check.
Potential concerns:
1. In `evCreateInjuredPersonCard`, the added call happens after card creation even when the type isn't ACIDENTE_PESSOAL (i.e., for ROS / QUASE_ACIDENTE / etc.), but that's fine since it toggles to hidden anyway, and it only touches elements when the card contains `.ev-inj-descaracter` blocks. Actually, `evSyncDescaracterStageUi` runs over all `.ev-inj-descaracter` elements — should be harmless.
2. What about the initial page load in aprofundamento mode where cards are rendered? `evRenderInjuredPersonBoxes()` calls `evCreateInjuredPersonCard` for each id, which already syncs via bind... then explicitly syncs again at the end of the loop. Duplicate only.
3. Potential subtle issue: `evCreateInjuredPersonCard` may be called when the DOM element `ev-suspeita-wrap` is not ready, but that function handles null.
4. What about performance? Called twice per card plus once per render loop, negligible.
Now let's verify the confirmed finding #2's claim more thoroughly: is `evSyncDescaracterStageUi` really called via `evBindInjuredCardEvents` → `evSyncDescaracterUi`? At line 2647, yes, `evSyncDescaracterUi()` is called, and at line 2947 `evSyncDescaracterUi` calls `evSyncDescaracterStageUi()`. So yes, in the card-creation path the sync is now executed twice. And in `evRenderInjuredPersonBoxes`, since each card creation already syncs, the new call at line 2826 is redundant as well. These are the confirmed findings.
Let me now look for other real issues. Let me look at where `evSyncDescaracterStageUi` is referenced to be sure the function is defined before use and doesn't depend on `evAprofundamentoOnlyMode` being defined, etc. It's all within the same script block, so ordering is not a runtime issue since these are invoked later via events.
But hold on: are `evCreateInjuredPersonCard` and `evRenderInjuredPersonBoxes` possibly called before `evSyncDescaracterStageUi` is defined? They're all function declarations within a script, hoisted. Function declarations are hoisted within the same scope. Fine.
Now, is there any other real issue? Let me consider: what happens when this template is used in the "aprofundamento técnico" screen? The diff adds a sync at the end of `evRenderInjuredPersonBoxes`, which already runs in aprofundamento. Wait — the issue there is the rendering of injured cards in aprofundamento (e.g., #636). In aprofundamento the `.ev-inj-descaracter` block should show Sim/Não. `evSyncDescaracterStageUi` handles toggling based on `isAp` only... hmm, and there's the `yesNoWrap` toggling based on `suspChk.checked`.
Let me consider a scenario where a regression might occur: the second call in `evCreateInjuredPersonCard` runs even when the newly added card is being created during the **aprofundamento** stage (e.g., editing an event in aprofundamento and adding an injured person). The function toggles `.ev-inj-descaracter` `d-none` based on `isAp`, and toggles yes/no wrap based on the suspect checkbox state of each card. This is same behavior as before in aprofundamento, just runs twice. No regression.
Let me also think about whether `evSyncDescaracterStageUi` might hide something in creation that #677 intended to keep... No.
Another thought — the real "bug fix intent" is that when type is selected first and then a person added, the card is cloned from a template where `.ev-inj-descaracter` still has `d-none` (from the template markup). Because the type change event that previously ran the sync happened BEFORE the card existed, the newly cloned card's `d-none` block was never removed. The fix syncs after creating the card. Makes sense.
But is there another place where cards are created and the sync is missed? `evApplyInjuredDetails`? Let me search for other `evCreateInjuredPersonCard` callers and other places where cards might be appended without the sync. Actually, there might be another path that clones the card — but given confirmed findings cover redundancy, I should still look for additional genuine issues.
Let me check the callers of `evCreateInjuredPersonCard` and `evRenderInjuredPersonBoxes`.
Tool Calls (2)
code_search
Show Details
Arguments
{"file_patterns": ["templates/ssma/occurrence/partials/_modal_event.html.twig"], "search_text": "evCreateInjuredPersonCard|evRenderInjuredPersonBoxes|evSyncDescaracterStageUi"}
Result
No matches found
code_search
Show Details
Arguments
{"file_patterns": ["templates/ssma/occurrence/partials/_modal_event.html.twig"], "search_text": "ev-suspeita-wrap|ev_descaracter_suspect|ev-inj-descaracter"}
Result
No matches found
Request #13
deepseek-v4-flash
P:16.18K C:227 CR:16.13K CW:0
2071ms
Reasoning
Interesting - no matches? Maybe the search needs to search in the right place. The file_patterns is relative to repo root. The path is `templates/ssma/occurrence/partials/_modal_event.html.twig`. Search with that should work. Perhaps the tool has trouble with the underscore? Let me try with the full path with file pattern.
Tool Calls (2)
code_search
Show Details
Arguments
{"file_patterns": ["templates/ssma/occurrence/partials/_modal_event.html.twig"], "search_text": "evRenderInjuredPersonBoxes"}
Result
File: templates/ssma/occurrence/partials/_modal_event.html.twig
Match lines: 4
2789| function evRenderInjuredPersonBoxes() {
2896| if (typeof evRenderInjuredPersonBoxes === 'function') evRenderInjuredPersonBoxes();
6457| evRenderInjuredPersonBoxes();
6470| evRenderInjuredPersonBoxes();
code_search
Show Details
Arguments
{"file_patterns": ["templates/ssma/occurrence/**"], "search_text": "evSyncDescaracterStageUi"}
Result
File: templates/ssma/occurrence/partials/_modal_event.html.twig
Match lines: 8
2709| evSyncDescaracterStageUi();
2826| evSyncDescaracterStageUi();
2917| function evSyncDescaracterStageUi() {
2947| evSyncDescaracterStageUi();
3323| evSyncDescaracterStageUi();
3398| evSyncDescaracterStageUi();
5288| evSyncDescaracterStageUi();
5736| evSyncDescaracterStageUi();
Request #14
deepseek-v4-flash
P:16.64K C:268 CR:16.38K CW:0
2326ms
Reasoning
Now, let me look at callers of `evRenderInjuredPersonBoxes` at lines 6457, 6470 and the other callers of `evSyncDescaracterStageUi` at 3323, 3398, 5288, 5736. Let me read these contexts to make sure I understand flow and whether the fix is complete, and whether there are missing spots or new issues.
Tool Calls (2)
file_read
Show Details
Arguments
{"end_line": 3420, "file_path": "templates/ssma/occurrence/partials/_modal_event.html.twig", "start_line": 3300}
Result
File: templates/ssma/occurrence/partials/_modal_event.html.twig (Total lines: 7712)
IS_TRUNCATED: false
LINE_RANGE: 3300-3420
3300| if (panel) panel.classList.toggle('is-readonly', !!readonly);
3301| if (alert) {
3302| alert.classList.toggle('d-none', !readonly);
3303| if (evIsAprofundamentoFinalized() && !EV_IS_ADMIN_APROFUNDAMENTO) {
3304| alert.innerHTML = '<i class="fas fa-lock mr-2"></i>Aprofundamento finalizado. Somente um administrador ou gestor administrador pode alterar.';
3305| } else {
3306| alert.innerHTML = '<i class="fas fa-exclamation-triangle mr-2"></i>O aprofundamento é preenchido pelo profissional responsável (gestor direto do colaborador ou equipe técnica SSMA).';
3307| }
3308| }
3309| var controls = document.querySelectorAll(
3310| '#ev-technical-section input, #ev-technical-section select, #ev-technical-section textarea,' +
3311| '#ev-spec-type-card input, #ev-spec-type-card select, #ev-spec-type-card textarea,' +
3312| '#ev-gravity-wrap input, #ev-gravity-wrap select,' +
3313| '#ev-corrective-actions-section input, #ev-corrective-actions-section select, #ev-corrective-actions-section textarea, #ev-corrective-actions-section button,' +
3314| '#ev-step-aprofundamento .ev-inj-descaracter-btn'
3315| );
3316| Array.prototype.forEach.call(controls, function (el) {
3317| if (!el || el.type === 'hidden') return;
3318| if (el.classList && el.classList.contains('ev-inj-descaracter-suspect-ro')) return;
3319| el.disabled = !!readonly;
3320| });
3321| // Reaplica bloqueio Sem dano — o loop acima zera disabled de todos os selects.
3322| evSyncInjuryTypeByConsequence();
3323| evSyncDescaracterStageUi();
3324| }
3325|
3326| function evUpdateFooter() {
3327| var type = evSelectedType();
3328| var canEditAprofundamento = evCanEditAprofundamento(type);
3329| var back = document.getElementById('ev-btn-back');
3330| var cancel = document.getElementById('ev-btn-cancel');
3331| var save = document.getElementById('ev-btn-save');
3332| var draft = document.getElementById('ev-btn-draft');
3333| var label = document.getElementById('ev-btn-label');
3334| if (draft) {
3335| draft.classList.toggle('d-none', !evAprofundamentoOnlyMode || evCurrentStep !== 'aprofundamento');
3336| }
3337| if (evAprofundamentoOnlyMode) {
3338| if (back) back.classList.add('d-none');
3339| if (cancel) cancel.classList.remove('d-none');
3340| if (!label || !save) return;
3341| if (evIsAprofundamentoFinalized() && !EV_IS_ADMIN_APROFUNDAMENTO) {
3342| save.disabled = true;
3343| save.classList.add('d-none');
3344| if (draft) draft.classList.add('d-none');
3345| return;
3346| }
3347| save.classList.remove('d-none');
3348| save.disabled = false;
3349| label.textContent = evIsAprofundamentoFinalized() ? 'Salvar alterações' : 'Finalizar';
3350| return;
3351| }
3352| if (back) back.classList.toggle('d-none', evCurrentStep !== 'aprofundamento');
3353| if (cancel) cancel.classList.toggle('d-none', evCurrentStep === 'aprofundamento');
3354| if (!label || !save) return;
3355| save.classList.remove('d-none');
3356| save.disabled = false;
3357| if (evCurrentStep === 'general') {
3358| label.innerHTML = (evRequiresAprofundamento(type) && evCanEditAprofundamento(type))
3359| ? 'Aprofundamento <i class="fas fa-chevron-right ml-1"></i>'
3360| : ((document.getElementById('ev_form_mode') || { value: 'create' }).value === 'edit'
3361| ? 'Salvar alterações'
3362| : 'Registrar');
3363| return;
3364| }
3365| label.textContent = (document.getElementById('ev_form_mode') || { value: 'create' }).value === 'edit'
3366| ? 'Salvar alterações'
3367| : 'Registrar';
3368| // Registrar nunca fica bloqueado por falta de permissão de aprofundamento.
3369| save.disabled = false;
3370| }
3371|
3372| function evSetStep(step) {
3373| if (evAprofundamentoOnlyMode) {
3374| step = 'aprofundamento';
3375| }
3376| evCurrentStep = step === 'aprofundamento' ? 'aprofundamento' : 'general';
3377| var general = document.getElementById('ev-step-general');
3378| var apro = document.getElementById('ev-step-aprofundamento');
3379| if (general) {
3380| general.classList.toggle('d-none', evCurrentStep !== 'general');
3381| general.classList.toggle('is-readonly', !!evAprofundamentoOnlyMode);
3382| }
3383| if (apro) apro.classList.toggle('d-none', evCurrentStep !== 'aprofundamento');
3384| document.querySelectorAll('#ev-steps-bar .insp-step-seg').forEach(function (bar) {
3385| var key = bar.getAttribute('data-ev-progress');
3386| if (evAprofundamentoOnlyMode) {
3387| bar.classList.toggle('is-active', key === 'aprofundamento');
3388| bar.classList.toggle('active', key === 'aprofundamento');
3389| } else {
3390| bar.classList.toggle('is-active', key === 'general' || key === evCurrentStep);
3391| bar.classList.toggle('active', key === 'general' || key === evCurrentStep);
3392| }
3393| });
3394| var body = document.querySelector('#modalEventNew-offcanvas-wrapper .offcanvas-body');
3395| if (body) body.scrollTop = 0;
3396| evSetAprofundamentoReadonly(!evCanEditAprofundamento(evSelectedType()));
3397| evUpdateFooter();
3398| evSyncDescaracterStageUi();
3399| if (evCurrentStep === 'aprofundamento') {
3400| var stepType = evSelectedType();
3401| evSyncCriticalityField(stepType);
3402| if (evRequiresAccidentTechnical(stepType)) {
3403| evSyncDerivedSeverityFromConsequence();
3404| }
3405| if (stepType === 'ACIDENTE_PESSOAL') {
3406| window.requestAnimationFrame(function () {
3407| var cardAp = evEnsurePrimaryInjuredCardExpanded();
3408| if (cardAp && evCardHadInjury(cardAp)) {
3409| evEnsureBodyMapForCard(cardAp);
3410| }
3411| });
3412| } else if (evHadInjuryForValidation()) {
3413| evEnsureBodyMapForCard(evGetActiveInjuredCardForBodyMap());
3414| }
3415| }
3416| }
3417|
3418| function evInitTypeSelectFromConfig() {
3419| var cfg = window.ssmaOccurrenceTypeConfig || { types: [] };
3420| var allowedTypes = window.SSMA_ALLOWED_CREATE_TYPES || [];
file_read
Show Details
Arguments
{"end_line": 6475, "file_path": "templates/ssma/occurrence/partials/_modal_event.html.twig", "start_line": 6440}
Result
File: templates/ssma/occurrence/partials/_modal_event.html.twig (Total lines: 7712)
IS_TRUNCATED: false
LINE_RANGE: 6440-6475
6440| if (seed.breve_relato === undefined) seed.breve_relato = '';
6441| injObj[String(personIdForBox)] = seed;
6442| }
6443| injRaw = JSON.stringify(injObj);
6444| } catch (eSeed) {}
6445| var injEl = document.getElementById('ev_injured_person_details');
6446| if (injEl) injEl.value = String(injRaw || '');
6447| var personSelSeed = document.getElementById('ev_person_id');
6448| if (personSelSeed && personIdForBox) {
6449| personSelSeed.setAttribute('data-primary-injured-id', String(personIdForBox));
6450| // Não deixa valor no select (select = adicionar); primary vai via data-attr.
6451| personSelSeed.value = '';
6452| if (typeof window.setCustomSelectValue === 'function') {
6453| window.setCustomSelectValue('ev_person_id', '');
6454| }
6455| }
6456| evFilterInjuredPersonSelect();
6457| evRenderInjuredPersonBoxes();
6458|
6459| if (type === 'ACIDENTE_PESSOAL') {
6460| // Re-sync depois das tags + details: garante caixinhas médicas mesmo se
6461| // setTagSelectValues rodou antes do hidden ou membro não estava no select.
6462| syncBodyRegionVisibility();
6463| evSyncInjuryFieldsByConsequence();
6464| if (typeof window.evSyncLtiAvailability === 'function') { window.evSyncLtiAvailability(); }
6465| evSyncInjuredCardsFromInvolved();
6466| // Se sync ainda não viu pessoas nas tags, remonta a partir dos details salvos.
6467| var wrapAfter = document.getElementById('ev_injured_person_boxes');
6468| var hasMedCards = !!(wrapAfter && wrapAfter.querySelector('.ev-injured-person-box[data-person-id]'));
6469| if (!hasMedCards && Object.keys(evGetInjuredDetailsObj() || {}).length) {
6470| evRenderInjuredPersonBoxes();
6471| }
6472| if (evCurrentStep === 'aprofundamento' && typeof evEnsurePrimaryInjuredCardExpanded === 'function') {
6473| evEnsurePrimaryInjuredCardExpanded();
6474| }
6475| }
Request #15
deepseek-v4-flash
P:19.43K C:210 CR:16.9K CW:0
1882ms
Reasoning
Let me now look at line 5288 and 5736 contexts to understand where else `evSyncDescaracterStageUi` is called.
Tool Calls (2)
file_read
Show Details
Arguments
{"end_line": 5300, "file_path": "templates/ssma/occurrence/partials/_modal_event.html.twig", "start_line": 5250}
Result
File: templates/ssma/occurrence/partials/_modal_event.html.twig (Total lines: 7712)
IS_TRUNCATED: false
LINE_RANGE: 5250-5300
5250| var EV_CRITICALITY_COLORS = {
5251| LEVE: { bg: 'rgba(37,173,82,0.12)', color: '#25AD52', border: '#25AD52' },
5252| BAIXO: { bg: 'rgba(37,173,82,0.12)', color: '#25AD52', border: '#25AD52' },
5253| MEDIO: { bg: 'rgba(255,193,7,0.15)', color: '#B78103', border: '#FFC107' },
5254| MODERADO: { bg: 'rgba(255,193,7,0.15)', color: '#B78103', border: '#FFC107' },
5255| ALTO: { bg: 'rgba(253,126,20,0.14)', color: '#FD7E14', border: '#FD7E14' },
5256| SEVERO: { bg: 'rgba(234,21,28,0.12)', color: '#EA151C', border: '#EA151C' },
5257| CRITICO:{ bg: 'rgba(234,21,28,0.12)', color: '#EA151C', border: '#EA151C' }
5258| };
5259|
5260| /** Gravidade: acidentes, ROS e Quase Acidente derivam da consequência. */
5261| function evSyncCriticalityField(type) {
5262| var wrap = document.getElementById('ev-gravity-wrap');
5263| var sel = document.getElementById('ev_criticality');
5264| var derivedWrap = document.getElementById('ev-derived-severity-wrap');
5265| var rosDerivedWrap = document.getElementById('ev-ros-derived-severity-wrap');
5266| var qaDerivedWrap = document.getElementById('ev-qa-derived-severity-wrap');
5267| if (!sel) return;
5268| var isAccident = evRequiresAccidentTechnical(type);
5269| var isRos = type === 'ROS';
5270| var isQa = type === 'QUASE_ACIDENTE';
5271| if (wrap) {
5272| wrap.classList.add('d-none');
5273| }
5274| sel.required = false;
5275| if (derivedWrap) derivedWrap.classList.toggle('d-none', !isAccident);
5276| if (rosDerivedWrap) rosDerivedWrap.classList.toggle('d-none', !isRos);
5277| if (qaDerivedWrap) qaDerivedWrap.classList.toggle('d-none', !isQa);
5278| if (isAccident) {
5279| evSyncDerivedSeverityFromConsequence();
5280| } else if (isRos) {
5281| evSyncRosDerivedSeverityFromPotential();
5282| } else if (isQa) {
5283| evSyncQaDerivedSeverityFromPotential();
5284| }
5285| evSyncAaIdentFields(type);
5286| evSyncPeopleFieldForType(type);
5287| evSyncReportedByFieldForType(type);
5288| evSyncDescaracterStageUi();
5289| }
5290|
5291| function evSyncPeopleFieldForType(type) {
5292| var wrap = document.getElementById('ev-people-field-wrap');
5293| if (!wrap) return;
5294| var hide = type === 'ROS';
5295| wrap.classList.toggle('d-none', hide);
5296| if (hide) {
5297| var peopleIds = document.getElementById('ev_people_ids');
5298| if (peopleIds) peopleIds.value = '';
5299| var tags = document.getElementById('ev_people_tags');
5300| if (tags) tags.innerHTML = '';
file_read
Show Details
Arguments
{"end_line": 5750, "file_path": "templates/ssma/occurrence/partials/_modal_event.html.twig", "start_line": 5700}
Result
File: templates/ssma/occurrence/partials/_modal_event.html.twig (Total lines: 7712)
IS_TRUNCATED: false
LINE_RANGE: 5700-5750
5700|
5701| var leaveEl = document.getElementById('ev_work_leave');
5702| if (leaveEl) {
5703| leaveEl.addEventListener('change', syncLtiAvailability);
5704| }
5705|
5706| document.addEventListener('ev:formLoaded', syncLtiAvailability);
5707| window.evSyncLtiAvailability = syncLtiAvailability;
5708| }());
5709|
5710| (function () {
5711| var consEl = document.getElementById('ev_consequence');
5712| if (consEl) {
5713| consEl.addEventListener('change', function () {
5714| evSyncDerivedSeverityFromConsequence();
5715| evSyncInjuryTypeByConsequence();
5716| });
5717| }
5718| var potEl = document.getElementById('ev_potential_consequence');
5719| if (potEl) {
5720| potEl.addEventListener('change', evPersistDraftSoon);
5721| }
5722| var derivedSel = document.getElementById('ev_derived_criticality_select');
5723| if (derivedSel) {
5724| derivedSel.addEventListener('change', function () {
5725| var hidden = document.getElementById('ev_derived_criticality');
5726| var critSel = document.getElementById('ev_criticality');
5727| if (hidden) hidden.value = this.value || '';
5728| if (critSel && this.value) critSel.value = this.value;
5729| evPersistDraftSoon();
5730| });
5731| }
5732| // Descaracterização: suspeita na 1ª etapa; caracterizado na caixinha (aprofundamento).
5733| var suspectChk = document.getElementById('ev_descaracter_suspect');
5734| if (suspectChk) {
5735| suspectChk.addEventListener('change', function () {
5736| evSyncDescaracterStageUi();
5737| evSyncInjuredPersonDetailsHidden();
5738| evPersistDraftSoon();
5739| });
5740| }
5741| // Checkbox de suspeita por card (aprofundamento): mostra/oculta Sim/Não do próprio card.
5742| document.addEventListener('change', function (e) {
5743| if (!e.target || !e.target.classList.contains('ev-inj-suspect-chk')) return;
5744| var card = e.target.closest('.ev-injured-person-box');
5745| if (!card) return;
5746| var yesNoWrap = card.querySelector('.ev-inj-descaracter-yesno-wrap');
5747| if (yesNoWrap) yesNoWrap.classList.toggle('d-none', !e.target.checked);
5748| // Atualiza o data-descaracter-suspect do card para serialização.
5749| card.setAttribute('data-descaracter-suspect', e.target.checked ? '1' : '0');
5750| // Espelha no campo global usado pelo payload (evIsDescaracterSuspectChecked).
Request #16
deepseek-v4-flash
P:21.33K C:2.52K CR:19.58K CW:0
17532ms
Reasoning
Now I understand the flow. The change adds calls to `evSyncDescaracterStageUi()` in two places. The confirmed findings already flagged the duplication and the god template issue. My task: review and report any other real issues.
Let me check for potential functional issue: `evSyncDescaracterStageUi` runs over every `.ev-inj-descaracter` element and toggles `d-none` based on `isAp`. When type isn't ACIDENTE_PESSOAL but cards exist (which shouldn't normally), the block hides. OK.
But there's a subtle functional thing to examine: The purpose of the change is: at creation, the checkbox of suspicion should be visible when an injured card is created. Now, the template clone — when a card is cloned, the `.ev-inj-descaracter` element inside the card template may have `d-none` class. Let me check the template's card markup to see whether `.ev-inj-descaracter` starts with `d-none` and whether the checkbox is inside it.
Actually the fix at the function level is fine. Let me consider whether the additional sync could cause an issue where the `.ev-inj-descaracter` block gets shown for ACIDENTE_PESSOAL even when not appropriate. `isAp = evSelectedType() === 'ACIDENTE_PESSOAL'`. This shows it whenever the type is ACIDENTE_PESSOAL regardless of step, which matches PR rules ("Aparece sempre que é Acidente Pessoal (criação e aprofundamento)"). Good.
Let me look for other potential real issues that are NOT the confirmed ones.
Possible areas:
1. `evCreateInjuredPersonCard` — after calling `evSyncDescaracterStageUi()`, the function returns card. But wait — the newly cloned card's `.ev-inj-descaracter` blocks: at line 2927-2931, `document.querySelectorAll('.ev-inj-descaracter')` includes those inside the new card because the card is already appended to the wrap before `evBindInjuredCardEvents` is invoked (appendChild at line 2687 happens before bind at line 2688, and bind already calls evSyncDescaracterUi → evSyncDescaracterStageUi). So even without the new call, the card would get synced... Wait — actually, this is the crux of confirmed finding #2: since evBindInjuredCardEvents already calls evSyncDescaracterUi (line 2647), which calls evSyncDescaracterStageUi, the checkbox would already be shown on card creation...
Hmm, wait. But the PR says the bug exists: the checkbox didn't appear. If evBindInjuredCardEvents already runs evSyncDescaracterUi at line 2647, then evSyncDescaracterStageUi would have already been called on card creation. So why was the bug present?
Let me re-read carefully. When was line 2647 added? It may have been added in this same PR or #677. Actually, we need to compare — the diff shows only 2 lines added in this file, at lines 2709 and 2826. So the code at 2647 existed before this PR. So if evBindInjuredCardEvents already calls evSyncDescaracterUi, then the descaracterization checkbox would show already on card creation.
Unless... the evSyncDescaracterUi at line 2647 runs BEFORE the card's content fully mirrors? No — it's called after the card is appended and bound.
Wait, let me check the timeline. Actually, wait — maybe the order of these calls matters relative to other event handling. Let's check evSyncDescaracterStageUi's behavior at card creation: it toggles `.ev-inj-descaracter` visibility based on `isAp`. If the type was chosen as ACIDENTE_PESSOAL, then isAp is true, so the block shows. Actually, `evBindInjuredCardEvents` runs evSyncDescaracterUi at line 2647 → evSyncDescaracterStageUi at line 2947 → removes d-none from `.ev-inj-descaracter` blocks (all in DOM, including new card). So the checkbox would already be shown...
Hmm, unless something later re-hides it. Is there a place where d-none is added back after the card creation? Let's trace `evSyncInjuredPersonDetailsHidden` or `evCollapseInjuredCard` maybe? Actually, in creation flow, after `evCreateInjuredPersonCard`, functions called: `evSyncInjuredPersonDetailsHidden()`, `evSyncPrimaryInjuredPersonId()`, `evFilterInjuredPersonSelect()`, and `evPersistDraftSoon()`? Hmm.
Actually, let's check if the real bug is on card creation when `evCreateInjuredPersonCard` is called with `saved` values where the type wasn't yet set? Hmm. Actually, I think it's worth verifying whether there was an actual regression observed in the bug report (they validated on staging), so the fix presumably is effective. The bug report says the checkbox did not appear in practice, and that evSyncDescaracterStageUi only ran when the type changed.
Wait, but evBindInjuredCardEvents → evSyncDescaracterUi is a real chain present in the current version of the file. Maybe evSyncDescaracterUi previously (in #677 release) did NOT call evSyncDescaracterStageUi? Let's look at line 2947: it's currently there. But maybe it was added in this same commit? The diff we review shows only two added lines... but maybe the evSyncDescaracterUi's call to evSyncDescaracterStageUi is pre-existing from #677. Let me check the file's git diff for context to confirm this function was already there before the change — the file_read_diff would help compare to base, but our diff only shows this one file with 2 added lines. So the pre-existing file already has line 2947 (evSyncDescaracterStageUi() inside evSyncDescaracterUi) and line 2647.
OK so the fix added these calls in two places. Whether they're redundant with the pre-existing sync inside evBindInjuredCardEvents — that's finding #2 (already confirmed). Whether the extra call in evRenderInjuredPersonBoxes is redundant — also finding #2.
So what else could be a real problem? Let me think about the semantics of the fix and whether the added line in `evCreateInjuredPersonCard` could regress the aprofundamento:
In `evCreateInjuredPersonCard`, the new call runs `evSyncDescaracterStageUi`, which, at line 2933-2939, iterates all cards and toggles `yesNoWrap` visibility based on each card's suspect checkbox checked state. Now, during the creation step, per PR rules, the Sim/Não shouldn't appear. The toggling in evSyncDescaracterStageUi at line 2937 `yesNoWrap.classList.toggle('d-none', !suspChk.checked)` shows yes/no when checkbox is checked. Wait — but in the creation step, Sim/Não is hidden via CSS outside aprofundamento (per comments). Where's that CSS? It says "Sim/Não oculto via CSS fora do aprofundamento". That's a CSS rule `#modalEventNew... .ev-step-general .ev-inj-descaracter-yesno-wrap {display:none}` maybe. So within general step, the CSS handles hiding; the JS toggle only matters in aprofundamento.
Now what about a card in creation where a draft restored with suspect checked? Card created at step general with checked checkbox → evSyncDescaracterStageUi toggles `yesNoWrap` show (removes d-none). But CSS in general step hides it. Fine.
But wait, is this new call changing behavior for aprofundamento? In aprofundamento, cards are created/rendered. Consider a card being created for aprofundamento where the user hasn't checked suspect. `evSyncDescaracterStageUi` toggles `d-none` on yesNoWrap (keeps hidden). Fine.
Consider the suspect checkbox per card (`.ev-inj-suspect-chk`) is bound in evBindInjuredCardEvents? Actually there is a document-level 'change' listener at line 5742 that handles `.ev-inj-suspect-chk`. Fine.
Now, is there a scenario where the new call in evRenderInjuredPersonBoxes happens when `evAprofundamentoOnlyMode` is true but the form type has been switched...? Not relevant.
OK, so potential other real issues:
1. Since the confirmed finding says duplication and the god template issue are already reported, I need to avoid repeating them. Let me look for any OTHER issue: e.g., the new call inside `evCreateInjuredPersonCard` runs `evSyncDescaracterStageUi()` which iterates over all `.ev-inj-descaracter` elements and removes/keeps `d-none` based on type. But if `evCreateInjuredPersonCard` is invoked when the wrap is empty or cards exist for non-AP types... Not an issue.
2. Ordering: In `evRenderInjuredPersonBoxes`, the sync is added BEFORE the requestAnimationFrame for aprofundamento's expansion. That's fine.
3. Now — think about whether the new call inside `evCreateInjuredPersonCard` could cause a regression for the scenario in #677's `evSyncCardCatFromClassification` or `evFilterCardConsequences`. No.
4. Wait — actually maybe there's a real issue: The added call in `evCreateInjuredPersonCard` runs `evSyncDescaracterStageUi()` which relies on `evSelectedType()`. But cards can be created for ACIDENTE_PESSOAL in "edição/aprofundamento", but what about the QA/other type where there might not be an ACIDENTE_PESSOAL? Doesn't matter.
5. Another angle: `evSyncDescaracterStageUi` also toggles `form.classList.toggle('is-doctor-aprof', isDoctorAprof)` — every card creation re-toggles this class on the form — harmless idempotent.
6. And `suspectWrap.classList.add('d-none')` — always add d-none. This forces global suspect wrap hidden even in aprofundamento mode where perhaps #636/#677 shows per-card. Since comment says "Checkbox global de suspeita (etapa 1) fica sempre oculto". OK.
Hmm. So probably the main concern is covered by confirmed findings. I should look for any other issues like:
- Missing `evSyncDescaracterStageUi` in a card-creation path that isn't covered, e.g., `evSyncInjuredCardsFromInvolved` may create cards via a different method (not evCreateInjuredPersonCard)? Let me check.
Let me look at `evSyncInjuredCardsFromInvolved` and `evApplyCardInjuryData` and other card-rendering methods to see if they create cards directly via template clone without going through evCreateInjuredPersonCard.
Tool Calls (1)
code_search
Show Details
Arguments
{"file_patterns": ["templates/ssma/occurrence/partials/_modal_event.html.twig"], "search_text": "cloneNode|ev-injured-person-box-tpl|evSyncInjuredCardsFromInvolved"}
Result
No matches found
Request #17
deepseek-v4-flash
P:23.87K C:274 CR:23.81K CW:0
2218ms
Reasoning
Search returned no matches. Maybe the regex search tool is not matching because of case? Actually earlier searches with a single string returned results. Hmm, but these also returned no matches initially for `evCreateInjuredPersonCard|...` (regex with pipe?). The second call with a single string `evRenderInjuredPersonBoxes` worked. So regex might not be supported? Wait the description says `use_perl_regexp` defaults false, so `cloneNode|ev-injured...` is treated as literal. Let me search each individually.
Tool Calls (2)
code_search
Show Details
Arguments
{"file_patterns": ["templates/ssma/occurrence/partials/_modal_event.html.twig"], "search_text": "cloneNode"}
Result
File: templates/ssma/occurrence/partials/_modal_event.html.twig Match lines: 1 2663| var card = source.cloneNode(true);
code_search
Show Details
Arguments
{"file_patterns": ["templates/ssma/occurrence/partials/_modal_event.html.twig"], "search_text": "evSyncInjuredCardsFromInvolved"}
Result
File: templates/ssma/occurrence/partials/_modal_event.html.twig
Match lines: 8
2347| function evSyncInjuredCardsFromInvolved() {
2395| evSyncInjuredCardsFromInvolved();
5133| evSyncInjuredCardsFromInvolved();
5782| evSyncInjuredCardsFromInvolved();
5978| evSyncInjuredCardsFromInvolved();
6465| evSyncInjuredCardsFromInvolved();
7033| if (typeof evSyncInjuredCardsFromInvolved === 'function') {
7034| evSyncInjuredCardsFromInvolved();
Request #18
deepseek-v4-flash
P:24.34K C:97 CR:24.06K CW:0
1688ms
Tool Calls (1)
file_read
Show Details
Arguments
{"end_line": 2430, "file_path": "templates/ssma/occurrence/partials/_modal_event.html.twig", "start_line": 2340}
Result
File: templates/ssma/occurrence/partials/_modal_event.html.twig (Total lines: 7712)
IS_TRUNCATED: false
LINE_RANGE: 2340-2430
2340| }
2341| var pessoaLabel = count === 1 ? 'acidentado registrado' : 'acidentados registrados';
2342| var ocorrenciaLabel = count === 1 ? 'ocorrência' : 'ocorrências';
2343| summaryText.textContent = count + ' ' + pessoaLabel + ' — o painel contabiliza ' + count + ' ' + ocorrenciaLabel + '.';
2344| summary.classList.remove('d-none');
2345| }
2346|
2347| function evSyncInjuredCardsFromInvolved() {
2348| if (evSelectedType() !== 'ACIDENTE_PESSOAL') {
2349| evUpdateInjuredPersonsEmptyState();
2350| return;
2351| }
2352| var involved = evGetPeopleInvolved();
2353| var wrap = document.getElementById('ev_injured_person_boxes');
2354| if (!involved.ids.length) {
2355| // Nunca apagar caixinhas médicas já montadas / details salvos só porque as tags
2356| // de "Pessoas envolvidas" ainda não estão no DOM (bug em edição → parte médica some).
2357| var existingDetails = evGetInjuredDetailsObj();
2358| var hasCards = !!(wrap && wrap.querySelector('.ev-injured-person-box[data-person-id]'));
2359| if (hasCards || Object.keys(existingDetails || {}).length) {
2360| evUpdateInjuredPersonsEmptyState();
2361| return;
2362| }
2363| if (wrap) wrap.innerHTML = '';
2364| evSetInjuredDetailsObj({});
2365| if (typeof evParkBodyMapBlock === 'function') evParkBodyMapBlock();
2366| if (typeof evClearCanonicalInjuryIds === 'function') evClearCanonicalInjuryIds();
2367| var sel = document.getElementById('ev_person_id');
2368| if (sel) sel.removeAttribute('data-primary-injured-id');
2369| evUpdateInjuredPersonsEmptyState();
2370| return;
2371| }
2372| involved.ids.forEach(function (personId) {
2373| if (!personId || !wrap) return;
2374| var safe = String(personId).replace(/"/g, '');
2375| var existing = wrap.querySelector('.ev-injured-person-box[data-person-id="' + safe + '"]');
2376| if (!existing) {
2377| var saved = evGetInjuredDetailsObj()[personId] || {};
2378| evCreateInjuredPersonCard(personId, saved, false);
2379| } else {
2380| evRenderInjuredPersonSummary(existing, existing.getAttribute('data-person-id'));
2381| evUpdateInjuredCardSummary(existing);
2382| }
2383| });
2384| evPruneInjuredBoxesNotInvolved();
2385| evEnsurePrimaryInjuredMarked();
2386| evSyncInjuredPersonDetailsHidden();
2387| evUpdateInjuredPersonsEmptyState();
2388| var boxesWrap = document.getElementById('ev_injured_person_boxes');
2389| if (boxesWrap) boxesWrap.classList.remove('is-invalid');
2390| }
2391|
2392| /** No passo Aprofundamento (AP), expande o acidentado principal para exibir lesão/consequências/mapa. */
2393| function evEnsurePrimaryInjuredCardExpanded() {
2394| if (evSelectedType() !== 'ACIDENTE_PESSOAL') return null;
2395| evSyncInjuredCardsFromInvolved();
2396| var wrap = document.getElementById('ev_injured_person_boxes');
2397| if (!wrap) return null;
2398| var card = (typeof evGetPrimaryInjuredCard === 'function' ? evGetPrimaryInjuredCard() : null)
2399| || wrap.querySelector('.ev-injured-person-box[data-person-id]');
2400| if (!card) return null;
2401| if (!card.classList.contains('is-expanded')) {
2402| evExpandInjuredCard(card);
2403| } else if (typeof syncInjuryFieldsForCard === 'function') {
2404| syncInjuryFieldsForCard(card);
2405| }
2406| if (typeof evFilterCardConsequences === 'function') {
2407| evFilterCardConsequences(card);
2408| }
2409| document.querySelectorAll('#ev_injured_person_boxes .ev-injured-person-box[data-person-id]').forEach(function (c) {
2410| if (typeof syncInjuryFieldsForCard === 'function') {
2411| syncInjuryFieldsForCard(c);
2412| }
2413| if (typeof evFilterCardConsequences === 'function') {
2414| evFilterCardConsequences(c);
2415| }
2416| });
2417| evRenderInjuredPersonSummary(card, card.getAttribute('data-person-id'));
2418| return card;
2419| }
2420|
2421| function evCollapseInjuredCard(card, skipSync) {
2422| if (!card || !card.parentNode) return;
2423| if (card.classList.contains('is-expanded') && !skipSync) {
2424| // Persiste só este card (não reescreve o mapa inteiro de details).
2425| var pid = card.getAttribute('data-person-id');
2426| if (pid) {
2427| var all = evGetInjuredDetailsObj();
2428| all[pid] = evReadCardInjuryData(card);
2429| evSetInjuredDetailsObj(all);
2430| evPersistDraftSoon();
Request #19
deepseek-v4-flash
P:25.86K C:397 CR:24.32K CW:0
3277ms
Reasoning
There is another card creation path via `evSyncInjuredCardsFromInvolved` → `evCreateInjuredPersonCard`, which is covered by the fix (since it goes through evCreateInjuredPersonCard). And this function also has a `evEnsurePrimaryInjuredMarked` after the loop, without an explicit sync... but since each creation syncs, covered. The confirmed finding #2 addresses redundancy.
Now let me search the template markup for `.ev-inj-descaracter` to see whether the block in the card template starts with `d-none` (so the new sync is what removes it). Actually I couldn't find it because the search earlier had no matches? Wait, I searched for `ev-suspeita-wrap|ev_descaracter_suspect|ev-inj-descaracter` as literal text (with pipes) which found nothing. But the code at line 2923 references `ev-suspeita-wrap` and at line 2927 `.ev-inj-descaracter`. So a search for these literal strings individually should find matches in the HTML part. Let me run separate searches.
Tool Calls (2)
code_search
Show Details
Arguments
{"file_patterns": ["templates/ssma/occurrence/partials/_modal_event.html.twig"], "search_text": "ev-inj-descaracter"}
Result
File: templates/ssma/occurrence/partials/_modal_event.html.twig
Match lines: 32
1289|#form-event-new .ev-inj-descaracter-toggle {
1292|#form-event-new .ev-inj-descaracter-btn.active {
1297|#form-event-new .ev-inj-descaracter-btn[disabled] {
1301|#form-event-new .ev-inj-descaracter {
1305|#form-event-new:not(.is-doctor-aprof) .ev-inj-descaracter-toggle,
1306|#form-event-new:not(.is-doctor-aprof) .ev-inj-descaracter-comment-wrap,
1307|#form-event-new:not(.is-doctor-aprof) .ev-inj-descaracter-no-perm {
1310|#form-event-new .ev-inj-descaracter-toggle.is-invalid {
1392|.ev-step-panel.is-readonly .ev-inj-descaracter-btn {
1396|#form-event-new .ev-inj-descaracter-suspect-ro {
1401|#form-event-new .ev-inj-descaracter-suspect-ro-wrap .form-check-label {
2201| descaracter_comment: (card.querySelector('.ev-inj-descaracter-comment') || {}).value || '',
2208| var cardBtns = card.querySelectorAll('.ev-inj-descaracter-btn.active');
2257| var comm = card.querySelector('.ev-inj-descaracter-comment');
2598| card.querySelectorAll('.ev-inj-attendance, .ev-inj-relato, .ev-inj-injury-type, .ev-inj-injury-severity, .ev-inj-injury-classification, .ev-inj-had-injury, .ev-inj-consequence, .ev-inj-potential-consequence, .ev-inj-descaracter-comment').forEach(function (el) {
2624| card.querySelectorAll('.ev-inj-descaracter-btn').forEach(function (btn) {
2633| var toggle = card.querySelector('.ev-inj-descaracter-toggle');
2640| card.querySelectorAll('.ev-inj-descaracter-comment').forEach(function (ta) {
2649| window.jQuery(card).find('.ev-inj-descaracter-tip').tooltip({ container: 'body' });
2927| document.querySelectorAll('.ev-inj-descaracter').forEach(function (el) {
2935| var yesNoWrap = card.querySelector('.ev-inj-descaracter-yesno-wrap');
2961| var noPerm = card.querySelector('.ev-inj-descaracter-no-perm');
2964| card.querySelectorAll('.ev-inj-descaracter-btn').forEach(function (b) {
2978| window.SsmaShared.toggleYesNo(card.querySelectorAll('.ev-inj-descaracter-btn'), cardDesc !== '' ? cardDesc : null, {
3314| '#ev-step-aprofundamento .ev-inj-descaracter-btn'
3318| if (el.classList && el.classList.contains('ev-inj-descaracter-suspect-ro')) return;
5746| var yesNoWrap = card.querySelector('.ev-inj-descaracter-yesno-wrap');
6026| var toggle = card.querySelector('.ev-inj-descaracter-toggle');
6027| var comm = card.querySelector('.ev-inj-descaracter-comment');
6059| || (focusCard && focusCard.querySelector('.ev-inj-descaracter'))
6487| var yesNoWrap = card.querySelector('.ev-inj-descaracter-yesno-wrap');
7121| ? String((primaryCard.querySelector('.ev-inj-descaracter-comment') || {}).value || '').trim()
code_search
Show Details
Arguments
{"file_patterns": ["templates/ssma/occurrence/partials/_modal_event.html.twig"], "search_text": "ev-inj-suspect-chk"}
Result
File: templates/ssma/occurrence/partials/_modal_event.html.twig
Match lines: 3
2934| var suspChk = card.querySelector('.ev-inj-suspect-chk');
5743| if (!e.target || !e.target.classList.contains('ev-inj-suspect-chk')) return;
6484| var chk = card.querySelector('.ev-inj-suspect-chk');
Request #20
deepseek-v4-flash
P:27.17K C:234 CR:26.24K CW:0
2325ms
Reasoning
The HTML for the card template markup likely includes `.ev-inj-descaracter` elements with `d-none`. Let me look at lines around 6059 and 6480-6500 to understand the card creation and the suspect checkbox handling in the creation step.
Tool Calls (2)
file_read
Show Details
Arguments
{"end_line": 6110, "file_path": "templates/ssma/occurrence/partials/_modal_event.html.twig", "start_line": 6000}
Result
File: templates/ssma/occurrence/partials/_modal_event.html.twig (Total lines: 7712)
IS_TRUNCATED: false
LINE_RANGE: 6000-6110
6000| var cons = card.querySelector('.ev-inj-consequence');
6001| var pot = card.querySelector('.ev-inj-potential-consequence');
6002| if (cons && !cons.value) mark(cons);
6003| if (pot && !pot.value) mark(pot);
6004| });
6005| }
6006| if (!(document.getElementById('ev_barrier_type_ap') || {}).value) mark('#ev_barrier_type_ap');
6007| if (hadInj && !semDano) {
6008| var injCard = primaryCardForVal || evGetPrimaryInjuredCard();
6009| var typeEl = injCard
6010| ? injCard.querySelector('.ev-inj-injury-type')
6011| : document.getElementById('ev_injury_type');
6012| var sevEl = injCard
6013| ? injCard.querySelector('.ev-inj-injury-severity')
6014| : document.getElementById('ev_injury_severity');
6015| if (typeEl && !typeEl.value) mark(typeEl);
6016| if (sevEl && !sevEl.value) mark(sevEl);
6017| var classEl = injCard ? injCard.querySelector('.ev-inj-injury-classification') : null;
6018| if (classEl && !classEl.value) mark(classEl);
6019| }
6020| if (boxesWrap && evAprofundamentoOnlyMode) {
6021| var descaracterInvalid = false;
6022| var focusCard = null;
6023| var focusEl = null;
6024| boxesWrap.querySelectorAll('.ev-injured-person-box[data-person-id]').forEach(function (card) {
6025| var desc = card.getAttribute('data-descaracterizado') || '';
6026| var toggle = card.querySelector('.ev-inj-descaracter-toggle');
6027| var comm = card.querySelector('.ev-inj-descaracter-comment');
6028| if (toggle) toggle.classList.remove('is-invalid');
6029| if (desc === '0' || desc === '1') {
6030| if (comm && !String(comm.value || '').trim()) {
6031| mark(comm);
6032| descaracterInvalid = true;
6033| if (!focusCard) {
6034| focusCard = card;
6035| focusEl = comm;
6036| }
6037| }
6038| } else {
6039| if (toggle) {
6040| toggle.classList.add('is-invalid');
6041| if (MV) MV.markInvalid($(toggle));
6042| }
6043| if (comm) mark(comm);
6044| ok = false;
6045| descaracterInvalid = true;
6046| if (!focusCard) {
6047| focusCard = card;
6048| focusEl = toggle || comm || card;
6049| }
6050| }
6051| });
6052| if (descaracterInvalid) {
6053| window.__ssmaEvSkipGenericValidationToast = true;
6054| if (focusCard && typeof evExpandInjuredCard === 'function') {
6055| evExpandInjuredCard(focusCard);
6056| }
6057| window.setTimeout(function () {
6058| var target = focusEl
6059| || (focusCard && focusCard.querySelector('.ev-inj-descaracter'))
6060| || focusCard;
6061| if (target && typeof target.scrollIntoView === 'function') {
6062| try { target.scrollIntoView({ block: 'center', behavior: 'smooth' }); } catch (eScroll) {}
6063| }
6064| }, 80);
6065| if (typeof showToast === 'function') {
6066| showToast(
6067| 'No card do acidentado (acima da Ação), responda “Caracterizado como acidente?” e preencha o comentário.',
6068| 'Aprofundamento',
6069| 'fas fa-exclamation-circle',
6070| 'bg-warning'
6071| );
6072| }
6073| }
6074| }
6075| } else if (type === 'ACIDENTE_MATERIAL') {
6076| if (!(document.getElementById('ev_asset_type') || {}).value) mark('#ev_asset_type');
6077| if (!(document.getElementById('ev_consequence') || {}).value) mark('#ev_consequence');
6078| if (!(document.getElementById('ev_potential_consequence') || {}).value) mark('#ev_potential_consequence');
6079| if (!(document.getElementById('ev_barrier_type_am') || {}).value) mark('#ev_barrier_type_am');
6080| } else if (type === 'ACIDENTE_AMBIENTAL') {
6081| if (!(document.getElementById('ev_environmental_medium') || {}).value) {
6082| mark('#ev_environmental_medium');
6083| }
6084| if (!(document.getElementById('ev_pollutant_type') || {}).value) {
6085| mark('#ev_pollutant_type');
6086| }
6087| if (!(document.getElementById('ev_consequence') || {}).value) mark('#ev_consequence');
6088| if (!(document.getElementById('ev_potential_consequence') || {}).value) mark('#ev_potential_consequence');
6089| if (!(document.getElementById('ev_barrier_type_aa') || {}).value) mark('#ev_barrier_type_aa');
6090| }
6091| return ok;
6092| }
6093|
6094| /* ── Helpers internos para populateForEdit ────────────── */
6095| function evSetVal(id, val) {
6096| var el = document.getElementById(id);
6097| if (el && val !== undefined && val !== null && val !== '') el.value = String(val);
6098| if (id === 'ev_person_id' || id === 'ev_person_id_qa') {
6099| if (typeof window.setCustomSelectValue === 'function' && val !== undefined && val !== null && val !== '') {
6100| window.setCustomSelectValue(id, String(val));
6101| } else {
6102| evSyncCustomSelectVisual(id, false);
6103| }
6104| }
6105| }
6106| /** Garante option legada no select (meio/poluente/barreira antigos) ao editar. */
6107| function evEnsureSelectOption(selectId, value) {
6108| if (value === undefined || value === null || value === '') return;
6109| var sel = document.getElementById(selectId);
6110| if (!sel) return;
file_read
Show Details
Arguments
{"end_line": 6520, "file_path": "templates/ssma/occurrence/partials/_modal_event.html.twig", "start_line": 6475}
Result
File: templates/ssma/occurrence/partials/_modal_event.html.twig (Total lines: 7712)
IS_TRUNCATED: false
LINE_RANGE: 6475-6520
6475| }
6476|
6477| // ── Descaracterização ────────────────────────────────
6478| // Restaura suspeita por card a partir do det ou do injured_person_details do card primário.
6479| var suspectRaw = det.descaracter_suspect != null ? det.descaracter_suspect : data.descaracter_suspect;
6480| var suspectOn = suspectRaw === true || suspectRaw === 1 || suspectRaw === '1';
6481| evSetChk('ev_descaracter_suspect', suspectOn);
6482| // Propaga suspeita para cada card (checkbox editável no aprofundamento).
6483| document.querySelectorAll('.ev-injured-person-box').forEach(function (card) {
6484| var chk = card.querySelector('.ev-inj-suspect-chk');
6485| if (chk) chk.checked = suspectOn;
6486| card.setAttribute('data-descaracter-suspect', suspectOn ? '1' : '0');
6487| var yesNoWrap = card.querySelector('.ev-inj-descaracter-yesno-wrap');
6488| if (yesNoWrap) yesNoWrap.classList.toggle('d-none', !suspectOn);
6489| });
6490| var descVal = det.descaracterizado != null ? det.descaracterizado : data.descaracterizado;
6491| if (descVal === true || descVal === 1) descVal = '1';
6492| if (descVal === false || descVal === 0) descVal = '0';
6493| evSetVal('ev_descaracterizado', descVal == null ? '' : String(descVal));
6494| evSyncDescaracterUi();
6495|
6496| // ── Evidências já anexadas ──────────────────────────
6497| var evidences = Array.isArray(det.evidences) ? det.evidences : (Array.isArray(data.evidences) ? data.evidences : []);
6498| evEvidences = evidences.map(function (e) {
6499| return {
6500| name: e.name || e.filename || '',
6501| path: e.path || '',
6502| persisted: true
6503| };
6504| });
6505| evEvidenceRenderList();
6506|
6507| // ── Labels do modal ─────────────────────────────────
6508| var btnLbl = document.getElementById('ev-btn-label');
6509| var modalTitle = document.getElementById('ev-modal-title');
6510| if (modalTitle) modalTitle.textContent = 'Editar ocorrência';
6511| evApplyAuraTitleStatusVisibility('edit');
6512| evSetStep('general');
6513| $('#ev_manager').trigger('change');
6514| };
6515|
6516| /**
6517| * Abre o offcanvas no aprofundamento (especialista).
6518| * Admin/gestor administrador edita tudo desde informações gerais — não trava o 1º passo.
6519| */
6520| window.EvModal.openAprofundamento = function (data) {
Request #21
deepseek-v4-flash
P:29.82K C:1.47K CR:27.39K CW:0
10918ms
Reasoning
Now, the primary point of review: the change is 2 added lines calling `evSyncDescaracterStageUi()` after card creation and after re-rendering boxes.
The confirmed findings already flag:
1. God template maintainability.
2. Redundancy/duplication of sync on the card-creation path and render path.
I need to check whether there are OTHER real issues. Let me think about potential issues:
**Potential issue A — the call inside `evCreateInjuredPersonCard` runs on every card addition regardless of type, and the call in `evSyncDescaracterStageUi` toggles `.ev-inj-descaracter` visibility for all cards.** But for cards not in ACIDENTE_PESSOAL, they aren't created. So no.
**Potential issue B — `evRenderInjuredPersonBoxes` is also called during populate/edit for `ACIDENTE_PESSOAL` and possibly for other types?** Let me check where `evRenderInjuredPersonBoxes` is called and whether the sync could run before the type select is set. If cards exist for type ROS with `.ev-inj-descaracter` blocks in DOM (unlikely because cards are only created for ACIDENTE_PESSOAL)... they wouldn't be.
**Potential issue C — The call within `evCreateInjuredPersonCard` may run BEFORE the checkbox element (`ev_descaracter_suspect`) / global wrap exists when adding from a select in create mode. It handles null.
**Potential issue D — Behavior regression in the aprofundamento stage:** In aprofundamento, when adding an injured card, `evSyncDescaracterStageUi` now runs twice but both times the same. So behavior not changed.
Wait, there's a subtle issue worth verifying: At line 2923-2926, evSyncDescaracterStageUi ALWAYS hides `#ev-suspeita-wrap` (adds d-none). Per the comment: "Checkbox global de suspeita (etapa 1) fica sempre oculto — suspeita agora é por card no aprofundamento." That is the established state.
Now, potential functional gap: Does the fix actually address the reported bug? The bug says checkbox did not appear because sync only ran when changing type, not after evCreateInjuredPersonCard/evRenderInjuredPersonBoxes. But from reading current code, evBindInjuredCardEvents at line 2647 calls evSyncDescaracterUi (which calls evSyncDescaracterStageUi). Was that call to evSyncDescaracterUi (line 2647) present in the released version #677? If yes, then the bug shouldn't have existed, and the fix would be redundant. But maybe line 2647 was also added in the same PR... no, the diff shows only two added lines in this file, so 2647 existed before this PR in the staging branch.
Hold on. Maybe the file in the base branch differs from what we see now: line 2647 could have been introduced by #677 (already merged) but maybe calling `evSyncDescaracterUi` wasn't enough to reveal the checkbox because of something about the timing or because `.ev-inj-descaracter` for the *newly cloned* card is not yet in the DOM at the time line 2647 runs... no, it is appended at line 2687 before bind at 2688.
Hmm wait, but there's a subtlety: `evSyncDescaracterUi` calls `evSyncDescaracterStageUi`, which hides `.ev-inj-descaracter` only if not AP. If AP and general step, the block shows. So after binding, the new card's descaracter section would show. Then... what would re-hide it? Is there a subsequent function that re-adds `d-none` to `.ev-inj-descaracter` in the creation flow? Possibly `evCollapseInjuredCard(card, true)` (line 2693) — does it hide sections? Let me check `evCollapseInjuredCard`.
Actually the important thing to determine is whether there is a real functional problem with the new code, not reconstructing the bug. Since previous reviewers found duplication, and the PR intent is a hotfix adding the sync, this is the core. For new issues, consider:
**Potential real issue E — wrong placement inside evCreateInjuredPersonCard with respect to `evEnsurePrimaryInjuredMarked()`**: after the new call there could be a change-related re-entrancy... evSyncDescaracterStageUi doesn't trigger change events; it only toggles classes. So no re-entrancy.
**Potential issue F — `evRenderInjuredPersonBoxes` calls `evSyncDescaracterStageUi` BEFORE the aprofundamento expansion runs in rAF.** Fine.
**Potential issue G — Missing sync at the end of `evSyncInjuredCardsFromInvolved` (other card creation entry point).** Actually cards created there go through evCreateInjuredPersonCard which now has the sync. So covered. But in `evSyncInjuredCardsFromInvolved`, when cards already exist (`else` branch) they don't get synced — but existing cards were synced at creation and evSyncDescaracterUi is run on type change. Anyway, that path doesn't need sync.
OK so the primary question is: are there additional genuine issues beyond the confirmed duplicates/god-template? Let me consider timing/visibility in the creation flow to check whether the added call could accidentally make the **Sim/Não (yes/no) buttons** appear at creation — the PR claims Sim/Não must NOT appear in the creation step (they're shown via CSS only in aprofundamento with `.is-doctor-aprof`). Let me check the CSS lines 1301-1310.
At line 1301: `#form-event-new .ev-inj-descaracter { ... }` and line 1305-1307: `#form-event-new:not(.is-doctor-aprof) .ev-inj-descaracter-toggle, .ev-inj-descaracter-comment-wrap, .ev-inj-descaracter-no-perm { display:none; }` presumably. So in non-aprofundamento the Sim/Não toggle etc are hidden via CSS, and the JS at line 2937 toggles yesNoWrap via d-none but CSS also hides. Let me read the CSS.
Tool Calls (1)
file_read
Show Details
Arguments
{"end_line": 1410, "file_path": "templates/ssma/occurrence/partials/_modal_event.html.twig", "start_line": 1280}
Result
File: templates/ssma/occurrence/partials/_modal_event.html.twig (Total lines: 7712)
IS_TRUNCATED: false
LINE_RANGE: 1280-1410
1280|#form-event-new .ev-inj-consequence-row .form-control,
1281|#form-event-new .ev-inj-consequence-row select.form-control {
1282| height: calc(1.5em + 0.75rem + 2px);
1283| min-height: calc(1.5em + 0.75rem + 2px);
1284| padding: 0.375rem 0.75rem;
1285| font-size: 1rem;
1286| line-height: 1.5;
1287| box-sizing: border-box;
1288|}
1289|#form-event-new .ev-inj-descaracter-toggle {
1290| gap: 8px;
1291|}
1292|#form-event-new .ev-inj-descaracter-btn.active {
1293| background: #1a6e7f !important;
1294| color: #fff !important;
1295| border-color: #1a6e7f !important;
1296|}
1297|#form-event-new .ev-inj-descaracter-btn[disabled] {
1298| opacity: 0.45;
1299| cursor: not-allowed;
1300|}
1301|#form-event-new .ev-inj-descaracter {
1302| padding-bottom: 4px;
1303|}
1304|/* Sim/Não de descaracterização fica oculto fora do aprofundamento — só o checkbox de suspeita aparece na criação. */
1305|#form-event-new:not(.is-doctor-aprof) .ev-inj-descaracter-toggle,
1306|#form-event-new:not(.is-doctor-aprof) .ev-inj-descaracter-comment-wrap,
1307|#form-event-new:not(.is-doctor-aprof) .ev-inj-descaracter-no-perm {
1308| display: none !important;
1309|}
1310|#form-event-new .ev-inj-descaracter-toggle.is-invalid {
1311| outline: 2px solid #dc3545;
1312| outline-offset: 2px;
1313| border-radius: 8px;
1314|}
1315|/* Botão seta = mesmo padrão das Configurações (.ssma-config-tipo-action-btn) */
1316|#form-event-new .ssma-config-tipo-action-btn {
1317| display: inline-flex;
1318| align-items: center;
1319| justify-content: center;
1320| width: 36px;
1321| height: 36px;
1322| padding: 0;
1323| border: 0;
1324| border-radius: 8px;
1325| background: transparent;
1326| color: #6c757d;
1327| cursor: pointer;
1328|}
1329|#form-event-new .ssma-config-tipo-action-btn:hover {
1330| background: rgba(15, 23, 42, 0.06);
1331| color: #495057;
1332|}
1333|#form-event-new .ssma-config-tipo-action-btn:focus,
1334|#form-event-new .ssma-config-tipo-action-btn:active {
1335| outline: none;
1336| box-shadow: none;
1337|}
1338|#form-event-new .ssma-section-chevron {
1339| transition: transform .2s;
1340|}
1341|#form-event-new .ssma-config-tipo-action-btn[aria-expanded="false"] .ssma-section-chevron {
1342| transform: rotate(180deg);
1343|}
1344|#modalEventNew-offcanvas-wrapper .ev-ap-pessoa-caixinha .custom-modern-select.open .custom-modern-options {
1345| z-index: 40;
1346|}
1347|#form-event-new .ev-inj-card.is-expanded {
1348| order: 99;
1349|}
1350|#form-event-new #ev_injured_person_boxes {
1351| display: flex;
1352| flex-direction: column;
1353|}
1354|#form-event-new #ev_injured_person_boxes.is-invalid {
1355| outline: 2px solid #dc3545;
1356| outline-offset: 4px;
1357| border-radius: 8px;
1358| padding: 4px;
1359|}
1360|/* Colaborador acidentado: mesmo padrão de _custom_select da Abordagem */
1361|#modalEventNew-offcanvas-wrapper .form-group .custom-modern-select-wrapper {
1362| display: block;
1363| width: 100%;
1364| max-width: 100%;
1365|}
1366|#modalEventNew-offcanvas-wrapper .form-group .custom-modern-select {
1367| width: 100%;
1368|}
1369|#modalEventNew-offcanvas-wrapper .form-group .custom-modern-select-trigger {
1370| width: 100%;
1371| justify-content: space-between;
1372| border-radius: 8px;
1373| padding: 10px 12px;
1374| border: 1px solid #e0e0e0;
1375| font-size: 14px;
1376| font-weight: 400;
1377| line-height: 1.5;
1378| box-sizing: border-box;
1379|}
1380|#modalEventNew-offcanvas-wrapper .form-group .custom-modern-select.open .custom-modern-options {
1381| z-index: 30;
1382|}
1383|#modalEventNew-offcanvas-wrapper .custom-modern-select-wrapper.is-invalid .custom-modern-select-trigger {
1384| border-color: #dc3545 !important;
1385| box-shadow: none;
1386|}
1387|.ev-step-panel.is-readonly .custom-modern-select-trigger {
1388| background-color: #F1F3F5 !important;
1389| opacity: 0.78;
1390| pointer-events: none;
1391|}
1392|.ev-step-panel.is-readonly .ev-inj-descaracter-btn {
1393| pointer-events: none;
1394| opacity: 0.72;
1395|}
1396|#form-event-new .ev-inj-descaracter-suspect-ro {
1397| pointer-events: none;
1398| opacity: 1;
1399| accent-color: var(--company-theme1-800, #0F3D4A);
1400|}
1401|#form-event-new .ev-inj-descaracter-suspect-ro-wrap .form-check-label {
1402| color: #495057;
1403|}
1404|#form-event-new .ev-injury-field-blocked,
1405|#form-event-new select.ev-injury-field-blocked:disabled {
1406| opacity: 0.55;
1407| background-color: #F1F3F5 !important;
1408| cursor: not-allowed;
1409|}
1410|#form-event-new .ev-injury-fields-sem-dano #ev_injury_type,
Request #22
deepseek-v4-flash
P:33.01K C:325 CR:31.23K CW:0
3362ms
Reasoning
The CSS is fine: in non-aprofundamento (`:not(.is-doctor-aprof)`), the Sim/Não toggle/comment/no-perm sections are hidden via CSS; only the suspect checkbox area remains visible. So the change just reveals `.ev-inj-descaracter` block (the section), and the checkbox inside becomes visible; Sim/Não stays hidden by CSS outside aprofundamento. Behavior in creation matches the PR's spec.
Now let me look at the template markup of the card to understand the `.ev-inj-descaracter` block's default d-none state. Let's locate the `ev-injured-person-box-tpl` template markup. It probably contains markup with `d-none` for `.ev-inj-descaracter` maybe hidden by default. Let me search.
Tool Calls (2)
code_search
Show Details
Arguments
{"file_patterns": ["templates/ssma/occurrence/partials/_modal_event.html.twig"], "search_text": "ev-injured-person-box-tpl"}
Result
File: templates/ssma/occurrence/partials/_modal_event.html.twig
Match lines: 2
662| <div id="ev-injured-person-box-tpl" class="d-none" aria-hidden="true">
2655| var tpl = document.getElementById('ev-injured-person-box-tpl');
code_search
Show Details
Arguments
{"file_patterns": ["templates/ssma/occurrence/partials/_modal_event.html.twig"], "search_text": "ev-suspeita-wrap"}
Result
File: templates/ssma/occurrence/partials/_modal_event.html.twig
Match lines: 2
289| <div class="form-group d-none" id="ev-suspeita-wrap">
2923| var suspectWrap = document.getElementById('ev-suspeita-wrap');
Request #23
deepseek-v4-flash
P:33.48K C:130 CR:33.28K CW:0
1363ms
Reasoning
Let me look at the card template markup (starting line 662) to see the `.ev-inj-descaracter` block default state and where the checkbox is.
Tool Calls (1)
file_read
Show Details
Arguments
{"end_line": 1100, "file_path": "templates/ssma/occurrence/partials/_modal_event.html.twig", "start_line": 662}
Result
File: templates/ssma/occurrence/partials/_modal_event.html.twig (Total lines: 7712)
IS_TRUNCATED: false
LINE_RANGE: 662-1100
662| <div id="ev-injured-person-box-tpl" class="d-none" aria-hidden="true">
663| {% include 'ssma/occurrence/partials/_ev_injured_person_box.html.twig' with {
664| person_id: '',
665| person_name: '',
666| attendance_date: '',
667| breve_relato: ''
668| } %}
669| </div>
670|
671| {# Body map fica estacionado aqui e é movido para dentro da caixinha do acidentado #}
672| <div id="ev-body-map-park" class="d-none" aria-hidden="true">
673| <div id="ev-body-map-block" class="d-none mt-2 ev-ap-body-map-field">
674| <p class="mb-1 ev-ap-body-map-title">Partes do corpo</p>
675| <div id="ev-body-map-wrap" class="w-100">
676| <div id="ev-body-map-host" class="ssma-ev-body-map-host d-flex justify-content-center mb-3"></div>
677| {# Um float por lado (mão esq/dir, pé esq/dir) — posição via JS (data-region no SVG) #}
678| <div id="ev_extremity_hand_float_esq" class="ev-extremity-float d-none" aria-hidden="true">
679| <div class="ev-ef-label">Mão esq. <span class="ev-ef-subtitle">dedo(s)</span></div>
680| <div class="ev-ef-checks">
681| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="POLEGAR"> Polegar</label>
682| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="INDICADOR"> Indicador</label>
683| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="MEDIO"> Dedo médio</label>
684| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="ANULAR"> Anelar</label>
685| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="MINIMO"> Mínimo</label>
686| </div>
687| <input type="hidden" id="ev_hand_finger_esq" name="ev_hand_finger_esq" value="">
688| </div>
689| <div id="ev_extremity_hand_float_dir" class="ev-extremity-float d-none" aria-hidden="true">
690| <div class="ev-ef-label">Mão dir. <span class="ev-ef-subtitle">dedo(s)</span></div>
691| <div class="ev-ef-checks">
692| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="POLEGAR"> Polegar</label>
693| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="INDICADOR"> Indicador</label>
694| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="MEDIO"> Dedo médio</label>
695| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="ANULAR"> Anelar</label>
696| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="MINIMO"> Mínimo</label>
697| </div>
698| <input type="hidden" id="ev_hand_finger_dir" name="ev_hand_finger_dir" value="">
699| </div>
700| <div id="ev_extremity_foot_float_esq" class="ev-extremity-float d-none" aria-hidden="true">
701| <div class="ev-ef-label">Pé esq. <span class="ev-ef-subtitle">dedo(s)</span></div>
702| <div class="ev-ef-checks">
703| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="HALUX"> Hálux</label>
704| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="SEGUNDO_DEDO"> 2º dedo</label>
705| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="TERCEIRO_DEDO"> 3º dedo</label>
706| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="QUARTO_DEDO"> 4º dedo</label>
707| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="MINIMO_PE"> Mínimo</label>
708| </div>
709| <input type="hidden" id="ev_foot_toe_esq" name="ev_foot_toe_esq" value="">
710| </div>
711| <div id="ev_extremity_foot_float_dir" class="ev-extremity-float d-none" aria-hidden="true">
712| <div class="ev-ef-label">Pé dir. <span class="ev-ef-subtitle">dedo(s)</span></div>
713| <div class="ev-ef-checks">
714| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="HALUX"> Hálux</label>
715| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="SEGUNDO_DEDO"> 2º dedo</label>
716| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="TERCEIRO_DEDO"> 3º dedo</label>
717| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="QUARTO_DEDO"> 4º dedo</label>
718| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="MINIMO_PE"> Mínimo</label>
719| </div>
720| <input type="hidden" id="ev_foot_toe_dir" name="ev_foot_toe_dir" value="">
721| </div>
722| <div id="ev_zone_cabeca_float" class="ev-extremity-float ev-zone-float d-none" aria-hidden="true">
723| <div class="ev-ef-label">Cabeça <span class="ev-ef-subtitle">detalhe</span></div>
724| <div class="ev-ef-checks ev-ef-checks--grid">
725| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="OLHO_ESQ"> Olho esq.</label>
726| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="OLHO_DIR"> Olho dir.</label>
727| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="BOCA"> Boca</label>
728| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="NARIZ"> Nariz</label>
729| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="ORELHA_ESQ"> Orelha esq.</label>
730| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="ORELHA_DIR"> Orelha dir.</label>
731| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="TESTA"> Testa</label>
732| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="MENTO"> Queixo</label>
733| </div>
734| <input type="hidden" id="ev_cabeca_zones" name="ev_cabeca_zones" value="">
735| </div>
736| <div id="ev_zone_pescoco_float" class="ev-extremity-float ev-zone-float d-none" aria-hidden="true">
737| <div class="ev-ef-label">Pescoço <span class="ev-ef-subtitle">detalhe</span></div>
738| <div class="ev-ef-checks">
739| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="PESCOCO_ANT"> À frente</label>
740| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="PESCOCO_POST"> Nuca</label>
741| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="PESCOCO_LAT_ESQ"> Lado esq.</label>
742| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="PESCOCO_LAT_DIR"> Lado dir.</label>
743| </div>
744| <input type="hidden" id="ev_pescoco_zones" name="ev_pescoco_zones" value="">
745| </div>
746| <div id="ev_zone_face_float" class="ev-extremity-float ev-zone-float d-none" aria-hidden="true">
747| <div class="ev-ef-label">Face <span class="ev-ef-subtitle">detalhe</span></div>
748| <div class="ev-ef-checks ev-ef-checks--grid">
749| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="FACE_BOCA"> Boca</label>
750| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="FACE_NARIZ"> Nariz</label>
751| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="FACE_BOCHE_ESQ"> Bochecha esq.</label>
752| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="FACE_BOCHE_DIR"> Bochecha dir.</label>
753| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="FACE_MENTO"> Mento</label>
754| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="FACE_MAXILAR"> Maxilar</label>
755| </div>
756| <input type="hidden" id="ev_face_zones" name="ev_face_zones" value="">
757| </div>
758| <div id="ev_zone_olhos_float" class="ev-extremity-float ev-zone-float d-none" aria-hidden="true">
759| <div class="ev-ef-label">Olhos <span class="ev-ef-subtitle">detalhe</span></div>
760| <div class="ev-ef-checks">
761| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="OLHO_ESQ"> Olho esq.</label>
762| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="OLHO_DIR"> Olho dir.</label>
763| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="SOBRANCELHA_ESQ"> Sobrancelha esq.</label>
764| <label class="ev-ef-check-item"><input type="checkbox" class="ev-ef-cb" value="SOBRANCELHA_DIR"> Sobrancelha dir.</label>
765| </div>
766| <input type="hidden" id="ev_olhos_zones" name="ev_olhos_zones" value="">
767| </div>
768| </div>
769| <div class="form-group mb-0">
770| <select id="ev_body_region_select" class="d-none ssma-tag-engine-select" tabindex="-1" aria-hidden="true">
771| <option value="">Selecione a região</option>
772| <option value="CABECA">Cabeça</option>
773| <option value="OLHOS">Olhos</option>
774| <option value="FACE">Face</option>
775| <option value="PESCOCO">Pescoço</option>
776| <option value="OMBRO_ESQ">Ombro esquerdo</option>
777| <option value="OMBRO_DIR">Ombro direito</option>
778| <option value="OMBRO">Ombro (ambos — legado)</option>
779| <option value="BRACO_ESQ">Braço esquerdo</option>
780| <option value="BRACO_DIR">Braço direito</option>
781| <option value="BRACO">Braço (ambos — legado)</option>
782| <option value="ANTEBRACO_ESQ">Antebraço esquerdo</option>
783| <option value="ANTEBRACO_DIR">Antebraço direito</option>
784| <option value="ANTEBRACO">Antebraço (ambos — legado)</option>
785| <option value="MAO_ESQ">Mão esquerda</option>
786| <option value="MAO_DIR">Mão direita</option>
787| <option value="MAO">Mão (ambas — legado)</option>
788| <option value="TORAX">Tórax</option>
789| <option value="ABDOMEN">Abdômen</option>
790| <option value="COSTAS">Costas</option>
791| <option value="QUADRIL_ESQ">Quadril esquerdo</option>
792| <option value="QUADRIL_DIR">Quadril direito</option>
793| <option value="QUADRIL">Quadril (ambos — legado)</option>
794| <option value="COXA_ESQ">Coxa esquerda</option>
795| <option value="COXA_DIR">Coxa direita</option>
796| <option value="COXA">Coxa (ambas — legado)</option>
797| <option value="JOELHO_ESQ">Joelho esquerdo</option>
798| <option value="JOELHO_DIR">Joelho direito</option>
799| <option value="JOELHO">Joelho (ambos — legado)</option>
800| <option value="PERNA_ESQ">Perna esquerda</option>
801| <option value="PERNA_DIR">Perna direita</option>
802| <option value="PERNA">Perna (ambas — legado)</option>
803| <option value="PE_ESQ">Pé esquerdo</option>
804| <option value="PE_DIR">Pé direito</option>
805| <option value="PE">Pé (ambos — legado)</option>
806| <option value="MULTIPLO">Múltiplo</option>
807| </select>
808| <p class="mb-1 small text-muted d-none" id="ev-body-region-tags-label">Regiões selecionadas</p>
809| <div id="ev_body_region_tags" class="d-none" role="list" aria-labelledby="ev-body-region-tags-label"></div>
810| </div>
811| <div class="form-group mb-0 mt-3 d-none">
812| <label for="ev_body_location_detail">Detalhamento da localização <span class="text-muted font-weight-normal">(opcional)</span></label>
813| <textarea class="form-control" id="ev_body_location_detail" name="ev_body_location_detail" rows="2" maxlength="2000" placeholder="Ex.: face lateral do joelho, próximo ao cotovelo…"></textarea>
814| </div>
815| </div>
816| </div>{# /#ev-body-map-park #}
817|
818| {# Caracterizado: valor sincronizado a partir da caixinha do acidentado. Suspeita fica na 1ª etapa. #}
819| <input type="hidden" id="ev_descaracterizado" name="ev_descaracterizado" value="">
820| </div>{# /#ev-ap-pessoa-caixinha #}
821| {# Regra de produto: custo removido de AP — só AM possui custo.
822| ROS e Quase acidente são comunicativos — sem custo; Ambiental não usa este campo. #}
823| <p class="small text-muted mb-0">Após a análise, você ainda pode adicionar novas evidências.</p>
824| </div>
825|
826| {# ── ACIDENTE MATERIAL ────────────────── #}
827| <div id="ev-block-am" class="ev-type-block d-none">
828| <div class="form-row">
829| <div class="col-6">
830| <div class="form-group">
831| <label for="ev_asset_type">Tipo do ativo afetado <span class="text-danger">*</span></label>
832| <select class="form-control" id="ev_asset_type" name="ev_asset_type">
833| <option value="" disabled selected>–</option>
834| <option value="MAQUINA">Máquina</option>
835| <option value="VEICULO">Veículo</option>
836| <option value="ESTRUTURA">Estrutura</option>
837| <option value="INSTALACAO_ELETRICA">Instalação elétrica</option>
838| <option value="TUBULACAO">Tubulação</option>
839| <option value="OUTRO">Outro</option>
840| </select>
841| </div>
842| </div>
843| {# Custo do acidente — só Acidente Material (removido de Acidente Pessoal). #}
844| <div class="col-6">
845| <div class="form-group">
846| <label for="ev_estimated_loss">Custo do acidente</label>
847| <div class="input-group">
848| <div class="input-group-prepend">
849| <span class="input-group-text">R$</span>
850| </div>
851| <input type="number" class="form-control" id="ev_estimated_loss" name="ev_estimated_loss"
852| min="0" step="0.01" placeholder="0,00">
853| </div>
854| </div>
855| </div>
856| </div>
857| <div class="form-row">
858| <div class="col-6">
859| <div class="form-group">
860| <label for="ev_downtime">Parada (horas)</label>
861| <input type="number" class="form-control" id="ev_downtime" name="ev_downtime"
862| min="0" step="0.5" placeholder="0">
863| </div>
864| </div>
865| </div>
866| <div class="form-group">
867| <div class="form-check">
868| <input class="form-check-input" type="checkbox" id="ev_operational_impact" name="ev_operational_impact" value="1">
869| <label class="form-check-label" for="ev_operational_impact">Impacto operacional?</label>
870| </div>
871| </div>
872| {# Brenda: só Tipo de barreira (sem Dimensão / Barreira que falhou). #}
873| {% include 'ssma/occurrence/partials/_ev_shared_barrier.html.twig' with {
874| _barrier_suffix: '_am',
875| _hide_failed_barrier: true,
876| _show_barrier_help: true
877| } %}
878| </div>
879|
880| {# ── ACIDENTE AMBIENTAL ───────────────── #}
881| <div id="ev-block-aa" class="ev-type-block d-none">
882| {# Meio/poluente/volume/contenção → Identificação (ev-aa-ident-fields). Impacto externo removido. #}
883| <div class="form-group">
884| <label for="ev_affected_area">Área afetada</label>
885| <input type="text" class="form-control" id="ev_affected_area" name="ev_affected_area"
886| placeholder="Descreva a área afetada (opcional)">
887| </div>
888| {# Brenda: só Tipo de barreira (sem Dimensão / Barreira que falhou). #}
889| {% include 'ssma/occurrence/partials/_ev_shared_barrier.html.twig' with {
890| _barrier_suffix: '_aa',
891| _hide_failed_barrier: true,
892| _show_barrier_help: true
893| } %}
894| </div>
895|
896| </div>{# /ev-technical-section #}
897|
898| {# Ação imediata — Aprofundamento (lista repetível) #}
899| <div class="card app-card-surface p-3 mb-0" id="ev-corrective-actions-section">
900| <div class="d-flex align-items-center justify-content-between mb-2">
901| <h5 class="ssma-form-section text-primary mb-0">Ação</h5>
902| </div>
903| <div id="ev-corrective-actions-list"></div>
904| <button type="button" class="mhs-btn-secondary btn-sm mt-2" id="ev-corrective-action-add">
905| <i class="fas fa-plus mr-1"></i>Adicionar ação
906| </button>
907| </div>
908|
909| </div>{# /ev-step-aprofundamento #}
910|
911| {# ══════════════════════════════════════════
912| BLOCO 5 — Ação inicial
913| (visível somente para profissionais técnicos)
914| ══════════════════════════════════════════ #}
915| <div id="ev-acao-inicial-section" class="card app-card-surface p-3 mb-0 d-none">
916| <h5 class="ssma-form-section text-primary">Ação inicial</h5>
917|
918| <div class="form-group">
919| <label for="ev_responsible_select">Responsável(is) pela resolução <span class="text-danger">*</span></label>
920| <select class="form-control" id="ev_responsible_select" name="ev_responsible_select">
921| <option value="" selected disabled>Selecione o(s) responsável(is)</option>
922| {% for member in allMembers %}
923| <option value="{{ member.id }}" data-name="{{ member.name }}">{{ member.name }}</option>
924| {% endfor %}
925| </select>
926| <div id="ev_responsible_tags" class="d-flex flex-wrap mt-2"></div>
927| </div>
928|
929| <div class="form-group">
930| <label for="ev_approach">Tipo de abordagem <span class="text-danger">*</span></label>
931| <select class="form-control ev-approach-select2" id="ev_approach" name="ev_approach">
932| <option value="CORRECAO_OPERACIONAL" selected>Correção Operacional</option>
933| <option value="MEDIACAO">Mediação</option>
934| <option value="TREINAMENTO">Treinamento</option>
935| <option value="MELHORIA_PROCESSO">Melhoria de Processo</option>
936| <option value="ACAO_DISCIPLINAR">Ação Disciplinar</option>
937| </select>
938| {# Campo customizado mantido oculto para compatibilidade de payload #}
939| <input type="hidden" id="ev_approach_custom" name="ev_approach_custom" value="">
940| </div>
941| </div>{# /ev-acao-inicial-section #}
942|
943| </form>
944| {% endblock %}
945|
946| {% block modal_footer %}
947| <button type="button" class="mhs-btn-cancel d-none" id="ev-btn-back">
948| <i class="fas fa-chevron-left mr-1"></i>Informações Gerais
949| </button>
950| <button type="button" class="mhs-btn-cancel" id="ev-btn-cancel" data-dismiss-offcanvas="modalEventNew">Fechar</button>
951| <button type="button" class="mhs-btn-secondary d-none" id="ev-btn-draft">Salvar rascunho</button>
952| <button type="button" class="mhs-btn-primary" id="ev-btn-save">
953| <span class="spinner-border spinner-border-sm d-none" id="ev-btn-spinner"></span>
954| <span id="ev-btn-label">Aprofundamento <i class="fas fa-chevron-right ml-1"></i></span>
955| </button>
956| {% endblock %}
957|
958|{% endembed %}
959|
960|<style>
961|/* Select nativo fica atrás do campo "Buscar testemunha/pessoa..." — esconde para não duplicar na etapa 1. */
962|#modalEventNew-offcanvas-wrapper select.ssma-member-tag-native-select,
963|#modalEventNew-offcanvas-wrapper .form-group:has(> .ssma-member-tag-search-wrap) > select.form-control {
964| display: none !important;
965|}
966|#modalEventNew-offcanvas-wrapper #ev_containment_time_wrap .ev-containment-row {
967| gap: 0.5rem;
968| flex-wrap: nowrap;
969| justify-content: flex-start;
970| align-items: center;
971|}
972|#modalEventNew-offcanvas-wrapper #ev_containment_time_wrap .ev-containment-check {
973| display: flex;
974| align-items: flex-start;
975| gap: 0.35rem;
976| flex: 0 0 auto;
977| max-width: none;
978|}
979|#modalEventNew-offcanvas-wrapper #ev_containment_time_wrap .ev-containment-check .form-check-input {
980| margin-top: 0.15rem;
981| flex-shrink: 0;
982|}
983|#modalEventNew-offcanvas-wrapper #ev_containment_time_wrap .ev-containment-check .form-check-label {
984| white-space: normal;
985| line-height: 1.25;
986| word-break: normal;
987| overflow-wrap: normal;
988|}
989|/* Mesma altura do Volume estimado (L) — form-control padrão Bootstrap */
990|#modalEventNew-offcanvas-wrapper #ev_containment_time_wrap .ev-containment-time-input {
991| flex: 1 1 auto;
992| width: auto;
993| min-width: 6.75rem;
994| max-width: none;
995| align-self: center;
996| height: calc(1.5em + 0.75rem + 2px);
997| min-height: calc(1.5em + 0.75rem + 2px);
998| padding-top: 0.375rem;
999| padding-bottom: 0.375rem;
1000| box-sizing: border-box;
1001|}
1002|.ev-steps-bar {
1003| padding-bottom: 20px;
1004|}
1005|/* ROS: "Registro do ocorrido" primeiro, depois "Contexto", depois "Identificação" (só GMR/Tipo residual). */
1006|#ev-step-general-cards {
1007| display: flex;
1008| flex-direction: column;
1009|}
1010|#ev-step-general-cards #ev-card-identificacao { order: 1; }
1011|/* Novo ROS: card Identificação fica vazio (tipo/título ocultos) — esconde de vez. */
1012|#ev-step-general-cards.ev-type-ros-layout #ev-card-identificacao.ev-ident-empty {
1013| display: none !important;
1014|}
1015|#ev-step-general-cards #ev-card-contexto { order: 2; }
1016|#ev-step-general-cards #ev-card-registro { order: 3; }
1017|#ev-step-general-cards.ev-type-ros-layout #ev-card-registro { order: 1; }
1018|#ev-step-general-cards.ev-type-ros-layout #ev-card-contexto { order: 2; }
1019|#ev-step-general-cards.ev-type-ros-layout #ev-card-identificacao { order: 3; }
1020|.js-ev-immediate-risk-opt.active {
1021| background: #1a6e7f !important;
1022| color: #fff !important;
1023| border-color: #1a6e7f !important;
1024|}
1025|#form-event-new .ev-meta-fields-row .ev-meta-field-label {
1026| display: block;
1027| min-height: 1.35rem;
1028| margin-bottom: 0.35rem;
1029| line-height: 1.25;
1030| white-space: nowrap;
1031| overflow: hidden;
1032| text-overflow: ellipsis;
1033|}
1034|#form-event-new .ev-meta-field-hint-spacer {
1035| display: block;
1036| min-height: 1.35rem;
1037| margin-top: 0.25rem;
1038| font-size: 12px;
1039| line-height: 1.35;
1040|}
1041|/* ROS: GMR ao lado da Categoria — hint do Local não empurra o GMR para baixo */
1042|#form-event-new .ev-location-stack-col.ev-location-stack-col--gmr-beside-category .ev-gmr-context-slot {
1043| display: none;
1044|}
1045|#form-event-new #ev-category-gmr-row {
1046| margin-top: 0.75rem;
1047|}
1048|#form-event-new .ev-location-stack-col #ev-gmr-wrap {
1049| margin-top: 0.75rem;
1050| margin-bottom: 0;
1051|}
1052|#form-event-new .ev-meta-fields-row .form-control {
1053| height: calc(1.5em + 0.75rem + 2px);
1054| min-height: calc(1.5em + 0.75rem + 2px);
1055| max-height: calc(1.5em + 0.75rem + 2px);
1056| line-height: 1.5;
1057| padding-top: 0.375rem;
1058| padding-bottom: 0.375rem;
1059| box-sizing: border-box;
1060|}
1061|#form-event-new #ev_derived_criticality_select {
1062| min-height: calc(1.5em + 0.5rem + 2px);
1063| height: auto;
1064| line-height: 1.5;
1065|}
1066|#form-event-new .ev-meta-fields-row #ev_datetime {
1067| min-width: 0;
1068| width: 100%;
1069| appearance: none;
1070| -webkit-appearance: none;
1071|}
1072|#form-event-new .ev-meta-fields-row #ev_location {
1073| height: calc(1.5em + 0.75rem + 2px);
1074| min-height: calc(1.5em + 0.75rem + 2px);
1075| max-height: calc(1.5em + 0.75rem + 2px);
1076|}
1077|#modalEventNew-offcanvas-wrapper .ev-steps-bar .insp-step-seg {
1078| height: 4px;
1079| border-radius: 2px;
1080|}
1081|#modalEventNew-offcanvas-wrapper .ev-steps-bar .insp-step-seg.active {
1082| background: var(--primary, #186073);
1083|}
1084|#ev-aprofundamento-denied-alert {
1085| background-color: #fff8e1;
1086| border-color: #ffe8a1;
1087| color: #856404;
1088|}
1089|.ev-step-panel.is-readonly .form-control,
1090|.ev-step-panel.is-readonly .custom-select,
1091|.ev-step-panel.is-readonly .select2-selection,
1092|.ev-step-panel.is-readonly .ssma-shared-upload-area {
1093| background-color: #F1F3F5 !important;
1094| opacity: 0.78;
1095| pointer-events: none;
1096|}
1097|.ev-step-panel.is-readonly .form-check-input,
1098|.ev-step-panel.is-readonly #ev-body-map-host {
1099| pointer-events: none;
1100|}
Request #24
deepseek-v4-flash
P:41.71K C:120 CR:33.54K CW:0
1937ms
Reasoning
The card template itself is included from `_ev_injured_person_box.html.twig`. Let me find that file to understand the markup. It's outside review_files, but I can read it for context. Let me read the markup to understand the `.ev-inj-descaracter` block default state.
Tool Calls (1)
file_find
Show Details
Arguments
{"query_name": "_ev_injured_person_box.html.twig"}
Result
templates/ssma/occurrence/partials/_ev_injured_person_box.html.twig
Request #25
deepseek-v4-flash
P:41.87K C:66 CR:41.73K CW:0
1331ms
Tool Calls (1)
file_read
Show Details
Arguments
{"file_path": "templates/ssma/occurrence/partials/_ev_injured_person_box.html.twig"}
Result
File: templates/ssma/occurrence/partials/_ev_injured_person_box.html.twig (Total lines: 225)
IS_TRUNCATED: false
LINE_RANGE: 1-225
1|{#
2| Caixinha completa por colaborador acidentado (Figma / padrão Desvios em Inspeções).
3| Campos usam classes; IDs canônicos (ev_had_injury, etc.) são atribuídos via JS
4| só no card expandido ativo, para reaproveitar mapa corporal e validadores.
5|#}
6|<div class="ev-inj-card ev-injured-person-box" data-person-id="{{ person_id|default('') }}">
7| {# Resumo (colapsado) #}
8| <div class="ev-inj-card-summary d-none js-ev-inj-summary">
9| <button type="button"
10| class="ev-inj-pick-circle js-ev-inj-pick"
11| title="Marcar como colaborador acidentado principal"
12| aria-label="Marcar como colaborador acidentado principal"
13| aria-pressed="false"></button>
14| <div class="ev-inj-card-summary-main">
15| <span class="ev-inj-card-summary-name js-ev-inj-summary-name">{{ person_name|default('Nome do Colaborador') }}</span>
16| <div class="ev-inj-card-summary-person small text-muted js-ev-inj-summary-person">
17| <span><span class="text-muted">Matrícula:</span> <span class="js-ev-inj-sum-collapsed-registration">—</span></span>
18| <span class="mx-1">·</span>
19| <span><span class="text-muted">Cargo:</span> <span class="js-ev-inj-sum-collapsed-position">—</span></span>
20| <span class="mx-1">·</span>
21| <span><span class="text-muted">Turno:</span> <span class="js-ev-inj-sum-collapsed-shift">—</span></span>
22| </div>
23| <span class="ev-inj-card-summary-meta js-ev-inj-summary-meta text-muted small d-block">—</span>
24| </div>
25| <div class="ev-inj-card-summary-actions">
26| <button type="button" class="js-ev-inj-toggle" title="Editar">
27| <i class="fas fa-pencil-alt"></i>
28| </button>
29| </div>
30| </div>
31|
32| {# Formulário expandido #}
33| <div class="ev-inj-card-form js-ev-inj-form">
34| <div class="d-flex align-items-center justify-content-between mb-2">
35| <h6 class="mb-0 font-weight-bold ev-inj-person-name">{{ person_name|default('') }}</h6>
36| <button type="button"
37| class="js-ev-inj-toggle ssma-config-tipo-action-btn"
38| aria-expanded="true"
39| title="Recolher"
40| aria-label="Recolher">
41| <i class="fas fa-chevron-up text-muted ssma-section-chevron" style="font-size:12px;"></i>
42| </button>
43| </div>
44|
45| {# Resumo cadastral do acidentado #}
46| <div class="ev-inj-person-summary js-ev-inj-person-summary">
47| <div class="ev-inj-sum-title">Resumo do acidentado</div>
48| <dl class="ev-inj-sum-grid mb-0">
49| <div class="ev-inj-sum-item">
50| <dt>Matrícula</dt>
51| <dd class="js-ev-inj-sum-registration">—</dd>
52| </div>
53| <div class="ev-inj-sum-item ev-inj-sum-item--wide">
54| <dt>Cargo</dt>
55| <dd class="js-ev-inj-sum-position">—</dd>
56| </div>
57| <div class="ev-inj-sum-item ev-inj-sum-item--wide">
58| <dt>Turno</dt>
59| <dd class="js-ev-inj-sum-shift">—</dd>
60| </div>
61| <div class="ev-inj-sum-item">
62| <dt>Superior</dt>
63| <dd class="js-ev-inj-sum-supervisor">—</dd>
64| </div>
65| <div class="ev-inj-sum-item ev-inj-sum-item--wide">
66| <dt>Gerência</dt>
67| <dd class="js-ev-inj-sum-gerencia">—</dd>
68| </div>
69| </dl>
70| </div>
71|
72| <div class="form-group mb-2">
73| <label class="small mb-0">Data de atendimento</label>
74| <input type="date"
75| class="form-control form-control-sm ev-inj-attendance"
76| value="{{ attendance_date|default('') }}">
77| </div>
78|
79| <div class="form-group mb-2">
80| <label class="small mb-0">Breve relato <span class="text-muted">(opcional)</span></label>
81| <textarea class="form-control form-control-sm ev-inj-relato"
82| rows="2"
83| placeholder="Breve relato">{{ breve_relato|default('') }}</textarea>
84| </div>
85|
86| <div class="form-group mb-2">
87| <div class="form-check">
88| <input class="form-check-input ev-inj-had-injury" type="checkbox" value="1" checked>
89| <label class="form-check-label">Houve lesão</label>
90| </div>
91| </div>
92|
93| <div class="ev-inj-injury-fields">
94| <div class="form-row ev-inj-type-severity-row ev-inj-type-row">
95| <div class="col-6">
96| <div class="form-group">
97| <label>Tipo da Lesão <span class="text-danger ev-inj-injury-required-mark">*</span></label>
98| <select class="form-control ev-inj-injury-type">
99| <option value="" disabled selected>Selecione o tipo de lesão</option>
100| <option value="CORTE">Corte</option>
101| <option value="ESMAGAMENTO">Esmagamento</option>
102| <option value="FRATURA">Fratura</option>
103| <option value="LUXACAO">Luxação</option>
104| <option value="QUEIMADURA">Queimadura</option>
105| <option value="INTOXICACAO">Intoxicação</option>
106| <option value="AMPUTACAO">Amputação</option>
107| <option value="CONTUSAO">Contusão</option>
108| <option value="OUTRO">Outro</option>
109| </select>
110| </div>
111| </div>
112| <div class="col-6">
113| <div class="form-group">
114| <label>Severidade da Lesão <span class="text-danger ev-inj-injury-required-mark">*</span></label>
115| <select class="form-control ev-inj-injury-severity">
116| <option value="" disabled selected>Selecione a severidade</option>
117| <option value="LEVE">Leve</option>
118| <option value="MODERADA">Moderada</option>
119| <option value="GRAVE">Grave</option>
120| <option value="CRITICA">Crítica</option>
121| </select>
122| </div>
123| </div>
124| </div>
125|
126| <div class="ev-inj-body-map-slot"></div>
127|
128| <div class="form-row mt-2 ev-inj-cat-row">
129| <div class="col-6">
130| <div class="form-group ev-inj-classification-row">
131| <label>Classificação de Ocorrência <span class="text-danger">*</span></label>
132| <select class="form-control ev-inj-injury-classification">
133| <option value="" disabled selected>Selecione</option>
134| <option value="FAC" data-leave="NAO">FAC — Primeiros socorros</option>
135| <option value="MTC" data-leave="NAO">MTC — Tratamento médico</option>
136| <option value="RWC" data-leave="NAO">RWC — Trabalho restrito</option>
137| <option value="FAT" data-leave="TOTAL">FAT — Fatalidade</option>
138| <option value="LTI_INCAPACITANTE" data-leave="TOTAL">LTI — Afastamento</option>
139| <option value="LTI_FATALIDADE" data-leave="TOTAL" class="d-none">LTI — Fatalidade (legado)</option>
140| <option value="LTI" data-leave="TOTAL" class="d-none">LTI — Afastamento (legado)</option>
141| </select>
142| </div>
143| </div>
144| <div class="col-6">
145| <div class="form-group">
146| <label>Tipo de CAT</label>
147| <select class="form-control ev-inj-work-leave" disabled aria-readonly="true" tabindex="-1">
148| <option value="">Selecione a classificação</option>
149| <option value="NAO">Sem afastamento</option>
150| <option value="TOTAL">Com afastamento</option>
151| </select>
152| </div>
153| </div>
154| </div>
155|
156| <div class="form-row ev-inj-consequence-row d-none" aria-hidden="true">
157| <div class="col-6">
158| <div class="form-group mb-2">
159| <label>Consequência real <span class="text-danger">*</span></label>
160| <select class="form-control ev-inj-consequence">
161| <option value="" disabled selected>Selecione a consequência</option>
162| {% include 'ssma/occurrence/partials/_ev_consequence_options.html.twig' %}
163| </select>
164| <div class="ev-inj-derived-severity-wrap mt-2">
165| <label class="text-muted small d-block mb-1">Gravidade da ocorrência (automática)</label>
166| <span class="ev-inj-derived-severity-badge ssma-shared-tag"
167| style="background:rgba(108,117,125,0.10);color:#6c757d;border-color:#adb5bd;">—</span>
168| </div>
169| </div>
170| </div>
171| <div class="col-6">
172| <div class="form-group mb-2">
173| <label>Consequência potencial <span class="text-danger">*</span></label>
174| <select class="form-control ev-inj-potential-consequence">
175| <option value="" disabled selected>Selecione a consequência</option>
176| {% include 'ssma/occurrence/partials/_ev_consequence_options.html.twig' %}
177| </select>
178| </div>
179| </div>
180| </div>
181|
182| {# CAT eSocial — exibido quando integração estiver ativa #}
183| <div class="ev-inj-esocial-cat-wrap d-none mt-2 p-2 rounded border">
184| <div class="small font-weight-bold mb-1">Registro da CAT no eSocial (automático)</div>
185| <div class="ev-inj-esocial-cat-body small text-muted">—</div>
186| </div>
187| </div>
188|
189| <p class="small text-muted font-italic mb-0 mt-2">Oriente o profissional a anexar evidências (fotos, laudos) na etapa de registro, se aplicável.</p>
190|
191| {# Descaracterização — visível na criação e no aprofundamento para Acidente Pessoal. Na criação: só checkbox de suspeita; Sim/Não e comentário ficam ocultos via CSS até o aprofundamento. #}
192| <div class="ev-inj-descaracter mt-3 pt-3 border-top d-none">
193| <div class="form-check mb-2">
194| <input class="form-check-input ev-inj-suspect-chk" type="checkbox">
195| <label class="form-check-label font-weight-bold">Há suspeita de descaracterização do acidente?</label>
196| </div>
197| <div class="ev-inj-descaracter-yesno-wrap d-none">
198| <label class="d-block small mb-2 font-weight-bold">
199| Caracterizado como acidente?
200| <i class="fas fa-info-circle text-muted ml-1 ev-inj-descaracter-tip"
201| style="cursor:help;font-size:12px;"
202| data-toggle="tooltip"
203| data-placement="top"
204| title="Sim = é acidente. Não (descaracterizar) só quem tem permissão na coluna Descaracterizar em Profissionais de Saúde."></i>
205| </label>
206| <div class="ev-inj-descaracter-toggle d-flex align-items-center mb-3" role="group" aria-label="Caracterizado como acidente">
207| <button type="button" class="mhs-btn-cancel ev-inj-descaracter-btn" data-descaracter-val="0" style="min-width:84px;">Sim</button>
208| <button type="button" class="mhs-btn-cancel ev-inj-descaracter-btn" data-descaracter-val="1" style="min-width:84px;">Não</button>
209| </div>
210| <div class="form-group mb-0 ev-inj-descaracter-comment-wrap">
211| <label class="small mb-1">Comentário <span class="text-danger">*</span></label>
212| <textarea class="form-control form-control-sm ev-inj-descaracter-comment"
213| rows="2"
214| maxlength="2000"></textarea>
215| </div>
216| <p class="ev-inj-descaracter-no-perm small text-muted mb-0 mt-2 d-none">
217| Sem permissão para descaracterizar o acidente.
218| Peça ao gestor que marque a coluna <strong>Descaracterizar</strong> em
219| Profissionais de Saúde (configuração de aprofundamento).
220| </p>
221| </div>
222| </div>
223| </div>
224|</div>
225|
Request #26
deepseek-v4-flash
P:45.53K C:2.21K CR:41.86K CW:0
15602ms
Reasoning
Important! The card markup has `.ev-inj-descaracter` initially with `d-none` class (line 192). So when a card is created fresh, the section is hidden until evSyncDescaracterStageUi toggles `d-none` off.
Also note that `evCreateInjuredPersonCard` → `evBindInjuredCardEvents` (line 2647: evSyncDescaracterUi) → evSyncDescaracterStageUi — would remove the `d-none`. So the new added line 2709 may be redundant in the card-creation path... unless line 2647 was added recently.
Wait, but maybe evSyncDescaracterUi call in evBindInjuredCardEvents was added by PR #677's earlier branch and in this staging branch after the original hotfix branch point? Since the diff only shows +2 lines, the base for this diff already contains line 2647. Hmm — wait, could evBindInjuredCardEvents' evSyncDescaracterUi (line 2647) be a recently added fix in this hotfix's target branch (new_staging2)? Doesn't matter.
OK so the confirmed finding #2 is precisely that the new call in evCreateInjuredPersonCard is redundant because evBindInjuredCardEvents already runs the sync. Given the bug existed (checkbox didn't show), maybe the actual root cause was different: maybe the evSyncDescaracterUi call at line 2647 does not actually exist in the code of the release branch where the bug was reported (i.e., #677 released code did not have line 2647). But we can only review what's here.
Wait — let me reconsider. Since the current file has line 2647 calling evSyncDescaracterUi, and that function calls evSyncDescaracterStageUi at line 2947, then when a card is created via evCreateInjuredPersonCard, the descaracter section would already be revealed... IF `evSelectedType()` returns 'ACIDENTE_PESSOAL' at that time. During creation, the type is chosen before adding a person, so yes.
But hmm, note evSyncDescaracterUi at 2647 runs BEFORE the `if (expand)` branch, before `evEnsurePrimaryInjuredMarked()`. In the creation step, `evCollapseInjuredCard(card, true)` is called at line 2693. Does `evCollapseInjuredCard` hide `.ev-inj-descaracter` section? Let me check evCollapseInjuredCard. It hides the form portion? Let me look at evCollapseInjuredCard implementation. But the section being inside `.ev-inj-card-form`, which may be hidden when collapsed. When user expands the card (via the pencil toggle), the form is shown. So the descaracter section would be visible only when expanded.
Let me check evExpandInjuredCard and evCollapseInjuredCard to see if they manipulate d-none on `.ev-inj-descaracter`. Possibly evExpandInjuredCard sets form visible. Then the section is revealed.
Anyway, with line 2647 present, the section would be visible when the card is expanded in AP creation. But the PR states the bug existed... this is confusing. Wait — maybe line 2647 `evSyncDescaracterUi();` was just added in PR #677 to a different flow (aprofundamento), not this file... but it's in this file now. Actually the current file IS the result of #677+others, and line 2647 is the existing code in the branch. So if line 2647 already existed, why did the bug occur?
Actually wait — re-read the bug description: "evSyncDescaracterStageUi() só rodava ao mudar o tipo, não depois de evCreateInjuredPersonCard / evRenderInjuredPersonBoxes." That's the author's diagnosis. But if evBindInjuredCardEvents calls evSyncDescaracterUi which calls evSyncDescaracterStageUi... then the author's claim is wrong? Unless evSyncDescaracterUi at line 2647 was added as part of the same hotfix commit... But the diff only shows the two added lines. So evSyncDescaracterUi at line 2647 is part of the base. Hmm.
But maybe line 2647 has been there since #677, and the checkbox still didn't show because... let me examine: in `evBindInjuredCardEvents`, at 2624-2639, `card.querySelectorAll('.ev-inj-descaracter-btn')` events bound. Then at 2645 `evFilterCardConsequences(card)`, then `evSyncCardCatFromClassification(card)`, then `evSyncDescaracterUi()` at 2647.
Hmm, wait — was `evSyncDescaracterUi()` at line 2647 perhaps added in this same hotfix commit but in a previous file? No, the diff is just 2 lines added in _modal_event.
Well, in any case, this is a topic already flagged by confirmed finding #2 — redundancy on the creation path. It's explicitly called out and confirmed, so I should not repeat it.
Let me search for the remaining potential issues:
**Potential functional gap — `evSyncInjuredCardsFromInvolved` in `evEnsurePrimaryInjuredCardExpanded`** — when cards already exist (`else` branch at 2379-2382), no sync needed. OK.
**Potential issue — when a card is created in creation step, then user removes another card (`evRemoveInjuredPersonBox`) — no re-sync needed since removal doesn't need to show checkbox.
**Potential issue — Draft restore** — `evRestoreDraftIfAny` → `evRenderInjuredPersonBoxes` — covered by added sync at the end. OK.
**What about non-AP type when there are no cards?** The sync is invoked even when type isn't AP. For evCreateInjuredPersonCard, only called for AP. In evRenderInjuredPersonBoxes, could be called for ROS/QA (details from legacy) — cards may not exist; sync would still run on the wrap empty — harmless.
Now, let me confirm the primary functional question from the perspective of the fix's goal: does the added call actually remove `d-none` from `.ev-inj-descaracter` inside the newly created card in creation step? Yes, provided evSelectedType() is ACIDENTE_PESSOAL. That works.
But now consider a scenario: In the creation step, a card is created for AP with expand=false. The user then collapses... hmm.
I should check whether the fix is complete, i.e., whether there are OTHER card-creation paths that remain unsynced. Actually, this is a real review point: `evCreateInjuredPersonCard` is the only place where cards are created (single clone point). Other flows route through it. So the fix is complete with these two call sites... although the creation path sync was already covered via evBindInjuredCardEvents.
Wait, actually let me double-check: is it possible the bug is genuine because `evBindInjuredCardEvents` runs `evSyncDescaracterUi` BEFORE the checkbox `.ev-inj-suspect-chk`? No—the clone includes the checkbox.
Hmm, maybe the actual root cause: the `evSyncDescaracterUi` at line 2647 was introduced by #677 in the same file, but #677 was only merged to a specific branch where the checkbox was hidden differently... We don't have access to git history beyond the diff. Given the previously confirmed findings, my job is to find NEW issues.
Let me think about what else is problematic:
1. **evRenderInjuredPersonBoxes when called during edit/aprofundamento where type select not yet set** — evSelectedType() could return '' before the type select is populated on page load, causing evSyncDescaracterStageUi to hide `.ev-inj-descaracter` blocks for ACIDENTE_PESSOAL edit if boxes are rendered before type is set. Where is evRenderInjuredPersonBoxes called on init? Let me check the init flow. If it's invoked after the type is set, no problem. But if a card is rendered with a null/'' type, the sync would hide the section until a later sync (e.g., at type select change). Let me check where evRenderInjuredPersonBoxes is invoked during page initialization/loading.
Line 6457 and 6470 are in `evSeedPeopleAndInjured` (or similar - populate), and line 2896 is draft restore. Let me search for a call during initial form load, e.g., evInit functions, or on 'ev:formLoaded'.
Let me look at lines around 7033-7034 (from search results), plus where evSyncInjuredCardsFromInvolved gets triggered on type change. Let me look at 5100-5140 and 5760-5800, 5960-5985.
Tool Calls (3)
file_read
Show Details
Arguments
{"end_line": 5140, "file_path": "templates/ssma/occurrence/partials/_modal_event.html.twig", "start_line": 5090}
Result
File: templates/ssma/occurrence/partials/_modal_event.html.twig (Total lines: 7712)
IS_TRUNCATED: false
LINE_RANGE: 5090-5140
5090| evUpdateAprofundamentoTitle(type);
5091| evUpdateStepsBarVisibility(type);
5092| evSyncGmrPosition(type);
5093|
5094| var generalCardsWrap = document.getElementById('ev-step-general-cards');
5095| if (generalCardsWrap) {
5096| generalCardsWrap.classList.toggle('ev-type-ros-layout', type === 'ROS');
5097| }
5098|
5099| // ROS (criação "Novo ROS"): o card Identificação fica vazio (tipo/título ocultos) — esconde o bloco.
5100| var identCard = document.getElementById('ev-card-identificacao');
5101| if (identCard) {
5102| var titleRow = document.getElementById('ev-title-status-row');
5103| var titleVisible = titleRow && !titleRow.classList.contains('d-none');
5104| var typeVisible = !(document.getElementById('ev_type_wrap') || { classList: { contains: function () { return true; } } }).classList.contains('d-none');
5105| var aaVisible = (function () {
5106| var aa = document.getElementById('ev-aa-ident-fields');
5107| return aa && !aa.classList.contains('d-none');
5108| })();
5109| var hideIdent = type === 'ROS' && !titleVisible && !typeVisible && !aaVisible;
5110| identCard.classList.toggle('d-none', hideIdent);
5111| identCard.classList.toggle('ev-ident-empty', hideIdent);
5112| }
5113|
5114| // QA: re-apply person row toggle + consequência potencial
5115| if (type === 'QUASE_ACIDENTE') {
5116| toggleQaPersonRow();
5117| if (typeof filterQaPotentialConsequence === 'function') {
5118| filterQaPotentialConsequence();
5119| }
5120| }
5121|
5122| // ROS: re-apply potential consequence filter
5123| if (type === 'ROS') {
5124| filterRosPotentialConsequence();
5125| }
5126|
5127| // Ao mudar tipo, sincroniza visibilidade do bloco de regiões
5128| if (type === 'ACIDENTE_PESSOAL') {
5129| syncBodyRegionVisibility();
5130| if (evHadInjuryForValidation()) {
5131| evEnsureBodyMapForCard(evGetActiveInjuredCardForBodyMap());
5132| }
5133| evSyncInjuredCardsFromInvolved();
5134| } else {
5135| var bmb = document.getElementById('ev-body-map-block');
5136| if (bmb) bmb.classList.add('d-none');
5137| }
5138|
5139| if (typeof window.renderEvCategorySelect === 'function') {
5140| window.renderEvCategorySelect(type, '');
file_read
Show Details
Arguments
{"end_line": 5800, "file_path": "templates/ssma/occurrence/partials/_modal_event.html.twig", "start_line": 5750}
Result
File: templates/ssma/occurrence/partials/_modal_event.html.twig (Total lines: 7712)
IS_TRUNCATED: false
LINE_RANGE: 5750-5800
5750| // Espelha no campo global usado pelo payload (evIsDescaracterSuspectChecked).
5751| var globalChk = document.getElementById('ev_descaracter_suspect');
5752| if (globalChk) globalChk.checked = e.target.checked;
5753| evSyncInjuredPersonDetailsHidden();
5754| evPersistDraftSoon();
5755| });
5756| var contDone = document.getElementById('ev_containment_done');
5757| if (contDone) {
5758| contDone.addEventListener('change', function () {
5759| evSyncContainmentTimeEnabled();
5760| evPersistDraftSoon();
5761| });
5762| }
5763| var form = document.getElementById('form-event-new');
5764| if (form) {
5765| form.addEventListener('change', evPersistDraftSoon);
5766| form.addEventListener('input', evPersistDraftSoon);
5767| }
5768| document.addEventListener('ev:formLoaded', function () {
5769| evSyncCriticalityField(evSelectedType());
5770| evSyncDerivedSeverityFromConsequence();
5771| evSyncInjuryTypeByConsequence();
5772| evSyncInjuryClassificationByLeave();
5773| if (typeof window.initAllCustomSelectWrappers === 'function') {
5774| window.initAllCustomSelectWrappers();
5775| }
5776| evFilterInjuredPersonSelect();
5777| evSyncDescaracterUi();
5778| evSyncContainmentTimeEnabled();
5779| });
5780| document.addEventListener('ev:peopleTagsChanged', function () {
5781| evFilterInjuredPersonSelect();
5782| evSyncInjuredCardsFromInvolved();
5783| });
5784| // jQuery .on: o _custom_select dispara change via $.trigger (não chega em addEventListener nativo em alguns casos).
5785| if (window.jQuery) {
5786| window.jQuery(document)
5787| .off('change.evInjuredAdd', '#ev_person_id')
5788| .on('change.evInjuredAdd', '#ev_person_id', function () {
5789| var wrap = this.closest ? this.closest('.custom-modern-select-wrapper') : null;
5790| if (wrap) wrap.classList.remove('is-invalid');
5791| evAddInjuredPersonFromSelect();
5792| });
5793| window.jQuery(document)
5794| .off('change.evInjuredQa', '#ev_person_id_qa')
5795| .on('change.evInjuredQa', '#ev_person_id_qa', function () {
5796| var wrap = this.closest ? this.closest('.custom-modern-select-wrapper') : null;
5797| if (wrap) wrap.classList.remove('is-invalid');
5798| });
5799| window.jQuery(document)
5800| .off('change.evAaIdent', '#ev_environmental_medium, #ev_pollutant_type')
file_read
Show Details
Arguments
{"end_line": 5990, "file_path": "templates/ssma/occurrence/partials/_modal_event.html.twig", "start_line": 5950}
Result
File: templates/ssma/occurrence/partials/_modal_event.html.twig (Total lines: 7712)
IS_TRUNCATED: false
LINE_RANGE: 5950-5990
5950| function evValidateTypeSpecificFields(MV) {
5951| var $ = window.jQuery;
5952| if (!$) return true;
5953| var type = (document.getElementById('ev_type') || {}).value || '';
5954| var ok = true;
5955| function mark(elOrSel) {
5956| ok = false;
5957| if (MV) MV.markInvalid(typeof elOrSel === 'string' ? $(elOrSel) : $(elOrSel));
5958| }
5959| if (type === 'ROS') {
5960| if (!(document.getElementById('ev_involvement_type_ros') || {}).value) mark('#ev_involvement_type_ros');
5961| if (!(document.getElementById('ev_deviation_type') || {}).value) mark('#ev_deviation_type');
5962| if (!(document.getElementById('ev_barrier_type_ros') || {}).value) mark('#ev_barrier_type_ros');
5963| if (!(document.getElementById('ev_ros_potential_consequence') || {}).value) mark('#ev_ros_potential_consequence');
5964| } else if (type === 'QUASE_ACIDENTE') {
5965| var invQa = (document.getElementById('ev_involvement_type_qa') || {}).value || '';
5966| if (!invQa) mark('#ev_involvement_type_qa');
5967| if (!(document.getElementById('ev_barrier_type_qa') || {}).value) mark('#ev_barrier_type_qa');
5968| if (!(document.getElementById('ev_qa_potential_consequence') || {}).value) mark('#ev_qa_potential_consequence');
5969| if (invQa === 'PERSON') {
5970| if (!(document.getElementById('ev_person_id_qa') || {}).value) {
5971| mark('#ev_person_id_qa');
5972| var qaWrap = $('#ev_person_id_qa').closest('.custom-modern-select-wrapper');
5973| if (qaWrap.length) qaWrap.addClass('is-invalid');
5974| }
5975| if (!(document.getElementById('ev_person_type_qa') || {}).value) mark('#ev_person_type_qa');
5976| }
5977| } else if (type === 'ACIDENTE_PESSOAL') {
5978| evSyncInjuredCardsFromInvolved();
5979| var boxesWrap = document.getElementById('ev_injured_person_boxes');
5980| var firstInjCard = boxesWrap && boxesWrap.querySelector('.ev-injured-person-box');
5981| if (firstInjCard && !boxesWrap.querySelector('.ev-injured-person-box.is-expanded')
5982| && typeof evExpandInjuredCard === 'function') {
5983| evExpandInjuredCard(firstInjCard);
5984| }
5985| var primaryInjured = (typeof evGetPrimaryInjuredPersonId === 'function')
5986| ? evGetPrimaryInjuredPersonId()
5987| : '';
5988| if (!primaryInjured) {
5989| if (boxesWrap) boxesWrap.classList.add('is-invalid');
5990| var header = document.getElementById('ev-injured-persons-header');
Request #27
deepseek-v4-flash
P:50.05K C:3.16K CR:47.62K CW:0
22997ms
Reasoning
The change scope is small and focused. All card creation goes through `evCreateInjuredPersonCard` and all remounts through `evRenderInjuredPersonBoxes`. Now let me think about additional potential issues specific to the added lines beyond redundancy:
**Observation about `evCreateInjuredPersonCard` line 2709 ordering**: The new call runs after `evEnsurePrimaryInjuredMarked()`. `evEnsurePrimaryInjuredMarked` can trigger `evSelectPrimaryInjuredPerson` which may call `evSyncPrimaryInjuredPersonId()`/`evPersistDraftSoon()`. That's fine.
**What about the clone case `if (existing) return existing;`** — when the card already exists (e.g., re-adding same person via select while the card exists), evCreateInjuredPersonCard returns early WITHOUT syncing. But that's the update path handled elsewhere (evUpdateInjuredCardSummary). Fine.
Now, is there any issue where `evSyncDescaracterStageUi` is invoked while the `#ev_type` select hasn't been set, causing an **unwanted hide** for ACIDENTE_PESSOAL cards during the initial page load/edit populate? Let's inspect populateForEdit flow at 6457. At line 6457, evRenderInjuredPersonBoxes is called inside a function where type is already known ('ACIDENTE_PESSOAL' branch at 6459). Let me find the enclosing function. Let me read lines 6300-6460 to see the context (the seed for people/injured details and type). If `evSelectedType()` returns the type correctly at that moment, then no problem.
Actually the more relevant check: this new sync call now runs whenever cards render. If type is e.g. ACIDENTE_MATERIAL (no cards exist) it's a no-op. If the type is ACIDENTE_PESSOAL, it shows the descaracter section on each card. But wait — in **aprofundamento-only mode** (`evAprofundamentoOnlyMode`), what about `ev_descaracterizado` hidden field value and yes/no visibility toggling? That's handled by evSyncDescaracterUi too.
Now potential issue: `evRenderInjuredPersonBoxes` may be called while cards exist for the ACIDENTE_PESSOAL in **step general** (creation). The sync toggles the section visible. But then user proceeds to aprofundamento step. At `evSetStep('aprofundamento')`, evSyncDescaracterStageUi runs (line 3398) and evSyncDescaracterUi runs too (within evSetAprofundamentoReadonly at 3323?). Fine.
I think that functionally the fix is acceptable, but the redundancy confirmed.
Let me look for other NEW real issues that reviewers would flag:
1. Duplicate IDs issue — the clone of card: each card's checkbox `.ev-inj-suspect-chk` has no ID, so ok.
2. The card clone contains the checkbox that is not bound via `.ev-inj-suspect-chk`? Global document-level change listener at 5742 covers delegated events. OK.
3. Wait — subtle bug potential: In creation step, the checkbox per card toggles `data-descaracter-suspect` and mirrors to global `ev_descaracter_suspect`. But per PR rule, on creation, Sim/Não must NOT appear. Since the per-card checkbox IS visible in creation now (the point of the fix), toggling it would show yes/no wrap... but CSS hides Sim/Não outside aprofundamento. However, evSyncDescaracterStageUi (line 2933-2939) removes d-none on yesNoWrap when checkbox checked. But CSS `#form-event-new:not(.is-doctor-aprof) .ev-inj-descaracter-toggle` uses `display:none !important` — stronger than the `.d-none` class? Actually `.d-none` sets `display: none !important` in Bootstrap. Both use important; which wins depends on specificity/order. `.ev-inj-descaracter-yesno-wrap` class-based toggle with Bootstrap's `.d-none{display:none!important}` has specificity of 0,1,0; the CSS selector `#form-event-new:not(.is-doctor-aprof) .ev-inj-descaracter-toggle` has higher specificity for the toggle, comment wrap and no-perm elements. But yesNoWrap element itself (`.ev-inj-descaracter-yesno-wrap`) is not in the CSS selector list — only its children (.ev-inj-descaracter-toggle, -comment-wrap, -no-perm) are. So toggling d-none on yesNoWrap shows the wrapper but its children stay hidden by CSS. In creation, Sim/Não buttons/comment hidden. So fine.
Actually wait — `.ev-inj-descaracter-yesno-wrap` — if `d-none` removed when the checkbox is checked, the wrapper div appears (with margin/padding, empty, possibly border?). The wrapper has no visual content since children hidden. It's just an empty div — could show a tiny empty space. But CSS `display:none !important` on children; wrapper itself empty -> no visual problem.
Alright.
Let me think about whether there could be an issue with the fix not covering the "change to another type" scenario: If user selects ACIDENTE_PESSOAL, adds a card (checkbox visible), then switches type to ROS, the cards are removed (evSyncInjuredCardsFromInvolved → prune) and evSyncCriticalityField → evSyncDescaracterStageUi hides sections. fine.
Now the real question: are there issues beyond confirmed findings? Since the change is minimal and reviewed already, maybe not. But let me also assess the "review checklist" and requirement — regression, security, isolation by company, integrity, migrations, tests.
Since this is a template JS change, no security or migration concern. There's no test infrastructure for Twig templates presumably. The main ones are covered by previous findings.
But I should verify one more thing: **evSyncDescaracterStageUi depends on `evSelectedType()`** which reads the current type. In `evCreateInjuredPersonCard`, when adding a person during creation before the type field value is set? The type select `#ev_type` is presumably set before user can add people (since adding people UI is type dependent). Should be fine.
Another important check: in the "aprofundamento-only" (doctor) flow, cards are created via `evEnsurePrimaryInjuredCardExpanded` → `evSyncInjuredCardsFromInvolved` → evCreateInjuredPersonCard → now syncs twice. Duplicate is the confirmed issue.
Now, could there be an infinite loop? evSyncDescaracterStageUi does not dispatch events. No.
Could the call in `evRenderInjuredPersonBoxes` produce a **visible flash/regression** when re-rendering boxes in the **aprofundamento** stage during validation (evValidateTypeSpecificFields → evSyncInjuredCardsFromInvolved, not render). evRenderInjuredPersonBoxes is called at populate/edit time, and draft restore. Re-render after restore → sync toggles sections visibility based on current type. In edit-mode open for an ACIDENTE_PESSOAL, cards render; then descaracter sections show. Previously without sync at render, they would stay hidden unless a later evSyncDescaracterUi ran (e.g., at form load 'ev:formLoaded' event → evSyncDescaracterUi at 5777). So the additional sync at render is redundant in those flows too. In any case the duplication is the confirmed finding.
Let me reconsider whether there's a **functional reason the fix would be ineffective** in the exact scenario reported (create mode: choose type → add person → card appears, checkbox still hidden). If line 2647 (evSyncDescaracterUi within evBindInjuredCardEvents) already existed at the base of this PR, then the bug reported couldn't happen, because binding the card would run evSyncDescaracterStageUi. Unless... the checkbox is *inside* the collapsed `.ev-inj-card-form` which is hidden until expanded? No, the bug was about after expanding.
Wait, maybe in the creation flow, when adding a person from "Pessoas envolvidas" tags (evSyncInjuredCardsFromInvolved), the cards already exist path vs new path... evSyncInjuredCardsFromInvolved at line 2376-2378 only creates a card if it doesn't exist, and when the card was created earlier (in a previous add), fine.
Hmm — Wait. Let me reconsider: what if the bug happened because the card was created while the form was NOT yet in 'create' mode via draft restore on a non-AP type and then type changed to AP? Edge.
OK, at this point, I'm confident there aren't additional clear functional bugs beyond the redundancy/god-template previously confirmed, which I must not repeat.
But wait, I should reconsider one more angle that could be an actual NEW issue distinct from the confirmed redundancy finding: **The second call in `evRenderInjuredPersonBoxes` is placed AFTER `evEnsurePrimaryInjuredMarked()`/`evSelectPrimaryInjuredPerson()` and other evSync functions but BEFORE the `if (evCurrentStep === 'aprofundamento' ...)` requestAnimationFrame.** Actually that's fine.
Actually, let me reconsider — the previously confirmed finding #2 states redundancy with the creation path and that `evRenderInjuredPersonBoxes` runs one extra redundant time. Both confirmed. So no new comment for that.
What about a third issue: **performance?** `evSyncDescaracterStageUi` iterates `document.querySelectorAll('.ev-inj-descaracter')` and `.ev-injured-person-box` each call. With many cards it's O(n) per sync; negligible.
Let me double check there's no security aspect: the changes only manipulate CSS classes. No innerHTML, no |raw. Nothing.
I should maybe verify whether `evSyncDescaracterStageUi`'s second effect (line 2933-2939 toggling the yesNoWrap for all cards based on the checked state of the suspect checkbox) could cause a bug in the **create** step when the fix makes the per-card suspect checkbox visible. On create step, if the user checks the suspect checkbox and then adds a second person, evCreateInjuredPersonCard runs evSyncDescaracterStageUi which iterates all cards and toggles yes/no wrappers based on each card's checkbox state. The CSS hides Sim/Não on create, so okay. Then when proceeding to aprofundamento (evSetStep), the same function runs again. So the checkbox checked state persists (per card). In aprofundamento, the card's Sim/Não should appear only when suspect checked. But if the user unchecked... OK.
Actually wait, the card checkbox `.ev-inj-suspect-chk` is per card. When user proceeds from creation to aprofundamento, do card checkboxes get synced from global? At 6483-6488 (populateForEdit) they sync per card from det/global. For new events (create mode), there's no transition between steps that copies the checked states to a global field... Hmm, but that's existing logic from #677 — not in scope.
OK — Given the mandate: "The following issues were already identified and confirmed in a prior review pass. Do not repeat them. Continue reviewing all files ... and report any other real issues you find."
So I must decide whether there are any other real issues. If I find no other real issues, I should call `task_done`. But maybe there's something else.
Let me look more carefully at the `evRenderInjuredPersonBoxes` added sync and `evCreateInjuredPersonCard` to see if there's a subtle **ordering bug** — where the sync toggles d-none to show `.ev-inj-descaracter` but that happens even when the card is in a collapsed state... not a bug.
Let me reconsider possible regression on the **aprofundamento validation** (descaracterInvalid logic at 6020+). Not affected.
Now, one genuinely interesting angle: **The new sync call inside `evCreateInjuredPersonCard` also hides the `.ev-inj-descaracter` blocks if the current type is NOT ACIDENTE_PESSOAL.** When can a card exist for a non-AP type? Cards are removed when switching types (evSyncInjuredCardsFromInvolved else branch empties the wrap at 2363 when not AP? Actually, when type isn't AP, evSyncInjuredCardsFromInvolved returns early with just evUpdateInjuredPersonsEmptyState at line 2349, not clearing the wrap!). Hmm wait, at 2347-2351: if type != AP, it returns. So if user has cards from AP and then switches to ROS, do cards remain? evSyncInjuredCardsFromInvolved is only called within the `if (type === 'ACIDENTE_PESSOAL')` branch at 5128-5133; in the else branch they call `evUpdateInjuredPersonsEmptyState()` maybe elsewhere. Cards of AP under ROS would be weird but not introduced here.
Given the analysis, the changes are minimal, and the two confirmed issues cover the notable problems (redundancy + god-template).
Actually, hold on. Let me reconsider the redundancy claim more carefully to make sure I'm not missing a NEW bug that the confirmed finding glosses over. The confirmed finding #2 says evSyncDescaracterUi inside evBindInjuredCardEvents calls evSyncDescaracterStageUi. Let me re-examine: evBindInjuredCardEvents is only called from evCreateInjuredPersonCard? Let me confirm. Search for evBindInjuredCardEvents calls.
Tool Calls (2)
code_search
Show Details
Arguments
{"file_patterns": ["templates/ssma/occurrence/partials/_modal_event.html.twig"], "search_text": "evBindInjuredCardEvents"}
Result
File: templates/ssma/occurrence/partials/_modal_event.html.twig
Match lines: 2
2575| function evBindInjuredCardEvents(card) {
2688| evBindInjuredCardEvents(card);
code_search
Show Details
Arguments
{"file_patterns": ["templates/ssma/occurrence/partials/_modal_event.html.twig"], "search_text": "evSetStep"}
Result
File: templates/ssma/occurrence/partials/_modal_event.html.twig
Match lines: 8
3372| function evSetStep(step) {
6512| evSetStep('general');
6537| evSetStep('aprofundamento');
6656| evSetStep('general');
6663| evSetStep('general');
6701| evSetStep('aprofundamento');
6711| evSetStep('aprofundamento');
6722| evSetStep('general');
Request #28
deepseek-v4-flash
P:53.4K C:3.16K CR:53.12K CW:0
23930ms
Reasoning
Confirmed: `evBindInjuredCardEvents` is only called from `evCreateInjuredPersonCard` (line 2688), and it runs `evSyncDescaracterUi()` → `evSyncDescaracterStageUi()` at card binding. So the added line 2709 is redundant for the path where evBindInjuredCardEvents runs... but wait, hold on — I need to re-check when the descaracter section would show for a *newly created card* during creation step. Since evSyncDescaracterUi→evSyncDescaracterStageUi is invoked within evBindInjuredCardEvents, the section shows already. So why was the original bug reported? Possibly the base (from #677's branch) at the time the bug was reported didn't have line 2647 (`evSyncDescaracterUi()` in evBindInjuredCardEvents), but it does now in `new_staging2`. In any case, the redundancy is confirmed. Fine.
Let me now double-check that evSyncDescaracterUi and evSyncDescaracterStageUi functions are declared within the same scope, and the ordering of function declarations vs the calls at lines 2709/2826.
Actually, one new angle: The new call at line 2709 in `evCreateInjuredPersonCard` runs after the function returns... no, before return card.
OK. At this point I've reviewed the file and code changes carefully. Both confirmed findings cover the identified issues (redundancy and god-template maintainability). Let me make sure there aren't any further real issues worth reporting that aren't the same as confirmed ones:
- Completeness: All card creation paths route through evCreateInjuredPersonCard; but wait — are there paths that clone the box template or add cards without evCreateInjuredPersonCard? Search returned only one `cloneNode` at 2663 within evCreateInjuredPersonCard. Good.
- The `evRenderInjuredPersonBoxes` is the only remount. Draft-restore path is covered. Edit-populate path at 6457/6470 covered.
So functionally, the fix is complete (albeit redundant on one path).
- Possible issue: no call to evSyncDescaracterUi (full sync incl. yes/no and permission) after creating the card in the create flow — only stage UI. But at creation Sim/Não are hidden by CSS anyway; for aprofundamento, evSyncDescaracterUi runs during binding already. Not a real new issue.
- The function call depends on `evSelectedType()`. At creation flow the type is set before adding a person. Fine.
- In the `evRenderInjuredPersonBoxes` re-render path triggered by draft restore when opening create modal — type select might still be default? Hmm, draft restore at line 2896 uses setTimeout 0 after restoring values — type is restored from the draft before render? `evRestoreDraftIfAny` iterates over keys setting el values; the type field `#ev_type` value is set from the draft, and then setTimeout calls evRenderInjuredPersonBoxes. But does setting `#ev_type` value programmatically trigger the type change handler (evSyncCriticalityField→evSyncDescaracterStageUi)? Probably not. But now the render sync covers it — this is actually one of the flows the fix targets. Fine.
Alright — there don't appear to be additional issues beyond the confirmed ones. However, the instructions say to not repeat confirmed findings, and to report any *other real issues*. If none exist, I should just conclude with task_done.
But let me carefully consider one more potential genuine problem: **The confirmed finding #2 might be considered resolved by the two new lines?** It says duplication: on a newly created card the sync now runs twice (once through bind, once via added line) and on re-render runs N+1 times. Since finding #2 already captures this, no need to repeat.
Let me also examine whether there's a **NEW issue** related to `evRenderInjuredPersonBoxes` being invoked in `evEnsurePrimaryInjuredCardExpanded`? No, evRenderInjuredPersonBoxes is not called there; evSyncInjuredCardsFromInvolved is.
Let me check the diff line context around the two added lines to understand the diff hunk exactly (what exactly are the added lines and their position) — already seen: line 2709 after evEnsurePrimaryInjuredMarked(); return card; line 2826 after evUpdateInjuredPersonsEmptyState(); before the aprofundamento rAF.
Let me now do a final sanity check to consider whether there are ordering implications at line 2826 with respect to function `evFilterInjuredPersonSelect()` and `evUpdateInjuredPersonsEmptyState()`: the sync is the last in that group — okay.
One thing that could be reported as a separate finding, distinct from confirmed #1 (god template) and #2 (duplicate sync): **the call at 2709 may not fix the actual reported bug at all, since the sync already ran at bind** — but that's exactly what confirmed finding #2 is about (the extra call inside evCreateInjuredPersonCard duplicates). I'd rather not rephrase and re-report the same root issue because the instructions forbid repeating.
Actually, wait. Let me re-read the confirmed finding #2's text carefully:
"Na criação de um card a sincronização de descaracterização já roda dentro de evBindInjuredCardEvents (que chama evSyncDescaracterUi e, por dentro dela, evSyncDescaracterStageUi) — ou seja, no caminho de card recém-criado ela passa a executar duas vezes; e em evRenderInjuredPersonBoxes ela roda uma v..." (truncated)
Yes — it flags redundancy in both paths. I won't repeat.
Now, is there any scenario where the added calls *break* behavior? Consider creating cards in aprofundamento for ACIDENTE_PESSOAL while the form has `.is-doctor-aprof`. On a newly created card in aprofundamento (e.g., adding a missing injured person in aprofundamento by specialist), the newly cloned `.ev-inj-descaracter` block has `d-none`; evBindInjuredCardEvents sync reveals it; both syncs then toggle yes/no visibility appropriately per suspect checkbox. Good.
I should decide whether to also mention the lack of tests? For a 2-line JS change inside a Twig template, no test infra exists — not a meaningful finding. Security: nothing.
Also, isolation per company — no server changes.
Let me confirm the two lines added — I've reviewed them at lines 2709 and 2826. Both have been verified.
I think we can conclude: no new issues to report beyond the previously confirmed ones. But hold on — the instructions require me to review each file, and after confirming no more issues, call task_done.
Actually, wait. Let me reconsider one more possible issue with severity that is distinct: The added call in `evCreateInjuredPersonCard` executes `evSyncDescaracterStageUi()` **unconditionally on every card creation** including cards created in non-AP or in aprofundamento... The effect at line 2927-2931 toggles `d-none` for `.ev-inj-descaracter` based on type only. If type is AP, it removes d-none — from *all* cards' sections, not only the new one. If previously the descaracter section was intentionally hidden (e.g., the per-card suspect checkbox unchecked in aprofundamento with a read-only mode?), showing the section only reveals the checkbox, which is a read-only `ev-inj-descaracter-suspect-ro` in read-only context. Actually in readonly mode controls are disabled; the `.ev-inj-descaracter` section contains the suspect checkbox that is disabled but visible (read-only mode shows info). So it's fine.
Hmm, but actually there is an important nuance I should verify: In the **edit** flow for events already in aprofundamento, `populateForEdit` may load with type ACIDENTE_PESSOAL and call `evRenderInjuredPersonBoxes` (line 6457) — with the new sync line at 2826, all descaracter sections get revealed, even if the global suspect checkbox is unchecked — which is correct per spec since each card shows the suspect checkbox anyway. Good.
Alright, no further issues. But let me at least double check whether the added call could throw (ReferenceError) in contexts where `evCreateInjuredPersonCard` is used by other templates via window? It's declared inside this script block, only this template. Search across public/js? Since functions are inside the template only. It's fine.
One more angle: `evSyncDescaracterStageUi` is not defined on `window`, but called in same closure scope. Both are in the same `<script>` presumably. Let me verify both functions are within the same closure (IIFE) scope — evCreateInjuredPersonCard at 2653 and evSyncDescaracterStageUi at 2917 are both declared in the same function scope (they are sibling function declarations). Since they are function declarations, hoisted within the enclosing function. Fine.
Now, per the user's mandatory formatting: "Comentário sempre em português..." But only if we produce comments. If no new issues, we call task_done.
Given that confirmed findings already cover the god template issue and the redundancy, and I don't find additional genuine issues, I'll call task_done with DONE.
But wait — let me reconsider whether the two added lines introduce a *behavioral regression in aprofundamento* worth flagging as new:
When a **descaracterização is finalized/read-only** (evAprofundamentoFinalized and not admin), `evSetAprofundamentoReadonly(true)` runs and calls `evSyncDescaracterStageUi` (line 3323). Then if the user somehow re-renders injured boxes (e.g., via draft restore or other event) the sync re-runs toggling classes but NOT re-applying readonly — read-only state is applied to elements already in DOM; new cards in a read-only state shouldn't be creatable because controls are disabled. This is pre-existing; the added line doesn't create new cards by itself.
OK. There is one subtlety I want to verify before finishing: are the new calls made in code paths that can execute **before** the DOM elements `.ev-inj-descaracter` markup exists in the page? They are inside card creation; card markup includes the section. OK.
Now let me be thorough about "evCreateInjuredPersonCard returning early" — if there's an existing card, line 2659 returns existing card WITHOUT syncing. That means when the same person is re-added via select while card exists (line 2762-2764 branch), evUpdateInjuredCardSummary(existing) runs but no sync occurs; the section remains in whatever state it was. Since it was previously created and synced, it's visible already. Not an issue introduced here.
Alright. I also want to verify the confirmed finding #2 statement isn't wrong about the redundancy, because if the redundancy is actually *necessary* (fix goal), then reporting redundancy as an issue might still be accepted. But the instructions say these were confirmed by prior review; not to repeat.
Now for a holistic approach per the checklist (correctness, security, performance, maintainability, tests): Given only a 2-line diff, we've thoroughly analyzed it. The two confirmed findings capture the material points. I find no other real issue. Also need to respect: "If the current code review task is complete, call task_done."
Let me double check I haven't missed anything in the diff text: the diff shows only two added lines:
1. `evSyncDescaracterStageUi();` after `evEnsurePrimaryInjuredMarked();` and before `return card;`
2. `evSyncDescaracterStageUi();` after `evUpdateInjuredPersonsEmptyState();`
Both are inside `<script>` presumably. Both reviewed.
Final decision: call task_done.
Actually, wait — hold on. Let me reconsider once more if there is a *further distinct* issue: **the fix does not call `evSyncDescaracterStageUi()` when a card is removed**, so if the last card is removed while type is AP in the creation step, the `.ev-inj-descaracter` section of... no, removing the card removes its section. Not needed.
And the **empty state** update (evUpdateInjuredPersonsEmptyState) might display a message in the place where the card would be — no descaracter section present. Fine.
Also, the new sync on every card creation also toggles `form.classList.toggle('is-doctor-aprof', isDoctorAprof)`; that's idempotent given evAprofundamentoOnlyMode constant.
I'm confident there are no other real issues. Task done.
Analisei as duas linhas adicionadas no template e o fluxo ao redor delas.
**Resumo da revisão:**
- `evSyncDescaracterStageUi()` (linha 2917) apenas alterna classes CSS (`d-none`, `is-doctor-aprof`), sem tocar em valores gravados, DOM via `innerHTML` ou payload — sem impacto de segurança/isolamento/integridade de dados.
- Todos os pontos de criação de card passam por `evCreateInjuredPersonCard()` (único `cloneNode` do template) e a remontagem passa por `evRenderInjuredPersonBoxes()` — ou seja, os dois pontos de inserção da chamada cobrem os fluxos de adicionar pessoa, draft restore e populateForEdit.
- Fora do aprofundamento, Sim/Não e comentário permanecem ocultos por CSS (`#form-event-new:not(.is-doctor-aprof)` com `display:none !important`), então a chamada extra não expõe a seção de Sim/Não na criação — a regra de negócio descrita na PR é preservada.
- A redundância das chamadas (o sync já roda dentro de `evBindInjuredCardEvents` → `evSyncDescaracterUi`) e o aumento do "god template" já estão cobertos pelos achados confirmados anteriores.
Não identifiquei outros problemas reais introduzidos por este diff.
Tool Calls (1)
task_done
Show Details
Arguments
{"state": "DONE"}
review_filter_task
Request #1
deepseek-v4-flash
P:2.79K C:866 CR:1.92K CW:0
6712ms
Reasoning
Let me analyze the two comments.
The diff shows two additions of `evSyncDescaracterStageUi();` calls in the file `templates/ssma/occurrence/partials/_modal_event.html.twig`.
Comment c-0: Talks about maintenance cost, architectural debt — suggests the logic should live in public/js/. This is a style/maintainability comment, not factually wrong. The existing code shown is `evSyncDescaracterStageUi();\n return card;` which matches the first hunk. The comment isn't factually incorrect per the diff. It's about architecture/style. Approve.
Comment c-1: Claims that on card creation, the sync already runs inside evBindInjuredCardEvents (which calls evSyncDescaracterUi and through it evSyncDescaracterStageUi), so on newly created card path it runs twice; and in evRenderInjuredPersonBoxes it runs once per card within the loop before this final call. This is a behavioral claim about code elsewhere in the file (functions evBindInjuredCardEvents, evSyncDescaracterUi, evRenderInjuredPersonBoxes). We cannot see those bodies in the diff. The comment reasons about runtime behavior in code we can't see. The Agent had access to the full codebase. We cannot verify, and unverifiable is not incorrect. It claims duplication but is cautious. This is not protected subject per se... Actually it's about behavior — double execution — but it's not asserting a behavioral change; it's speculating. Hmm.
Protected subjects: memory safety, concurrency, linkage, behavioral/compatibility change, unused parameter. Comment c-1 discusses whether the sync runs twice and whether the fix covers the failing case — that's about behavior of the code at runtime. Is it "behavioral change"? It's not claiming old code produced X and new code no longer does. It's more of an analysis. The subject is not clearly a protected category.
Ground A: does the comment target code not in the subject file's diff? The comment discusses function bodies (evBindInjuredCardEvents, evSyncDescaracterUi, evRenderInjuredPersonBoxes) that don't appear in the diff at all. The diff only shows two added lines calling evSyncDescaracterStageUi. The comment's claims about "within the loop evSyncDescaracterStageUi runs once per card" and "evBindInjuredCardEvents calls evSyncDescaracterUi and inside it evSyncDescaracterStageUi" are claims about code not visible in the diff. But Ground A requires that the comment describes code that appears nowhere in the subject file's diff — the symbol/statement/construct described appears nowhere in the file's diff. Hmm.
Actually Ground A: "the comment targets code that is not in its subject file's diff." The comment c-1 is filed against this file, and it describes the behavior of evSyncDescaracterStageUi and other functions. The added lines do appear in the diff (the two `evSyncDescaracterStageUi()` calls). The comment references the added line — its existing_code matches. Its central claim is that this call duplicates what already happens elsewhere. But the "elsewhere" code is not in the diff. We cannot verify.
Ground B: does a diff line literally contradict the comment's central claim? The central claim is that card creation already calls the sync elsewhere, so it runs twice. We can't see that. There's no line contradicting it in the diff.
The comment is speculative ("vale confirmar", "se o problema for card já existente... este ponto não cobre o caso"). It's not asserting a definitive falsehood.
The default is to approve. Since we can't prove either ground, approve both.
Let me double check: is comment c-1 perhaps clearly wrong because the diff proves... no. The diff only adds calls; we don't know whether they're redundant. Approve both.
Tool Calls (1)
approve_all_comments
Show Details
Arguments
{}
Review Comments (2 findings)
templates/ssma/occurrence/partials/_modal_event.html.twig 2 comments
No comments match this filter.