feat: version 2.17.2 -- Proyectos: selector Avance (Todos / Ocultar 100% / Solo 100%)

Reemplaza el checkbox "Ocultar proyectos 100%" para cubrir tambien "solo 100%"
sin combinaciones contradictorias. Persistido en localStorage; migra el valor
del checkbox anterior.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Milton Gonzalez
2026-10-20 15:10:54 -05:00
parent a488965450
commit cdd49a7eff
6 changed files with 47 additions and 19 deletions
+31 -14
View File
@@ -22,7 +22,8 @@ import { DetailPopup } from '../../components/DetailPopup.jsx';
import { SharedWithIcon } from '../../components/SharedWithIcon.jsx';
const CAN_DELETE_ROLES = ['superadmin', 'admin', 'it_manager', 'project_lead'];
const HIDE_COMPLETED_KEY = 'plc_projects_hide_completed';
const PROGRESS_FILTER_KEY = 'plc_projects_progress_filter';
const LEGACY_HIDE_COMPLETED_KEY = 'plc_projects_hide_completed';
function flatten(nodes, acc = []) {
for (const n of nodes) { acc.push(n); if (n.children?.length) flatten(n.children, acc); }
@@ -49,13 +50,18 @@ export default function ProyectosPage() {
const [filterStatusId, setFilterStatusId] = useState('');
const [filterPriorityId, setFilterPriorityId] = useState('');
const [filterDueSoon, setFilterDueSoon] = useState(false);
// Persistido en el navegador: se conserva al cerrar sesion o recargar.
const [hideCompleted, setHideCompleted] = useState(() => {
try { return localStorage.getItem(HIDE_COMPLETED_KEY) === '1'; } catch { return false; }
// '' = todos, 'hide' = ocultar 100%, 'only' = solo 100%. Persistido en el navegador (sobrevive
// al cierre de sesion). Respeta el checkbox anterior "Ocultar 100%" (clave vieja) si existia.
const [progressFilter, setProgressFilter] = useState(() => {
try {
const saved = localStorage.getItem(PROGRESS_FILTER_KEY);
if (saved !== null) return saved;
return localStorage.getItem(LEGACY_HIDE_COMPLETED_KEY) === '1' ? 'hide' : '';
} catch { return ''; }
});
function toggleHideCompleted(checked) {
setHideCompleted(checked);
try { localStorage.setItem(HIDE_COMPLETED_KEY, checked ? '1' : '0'); } catch { /* sin storage: solo en memoria */ }
function changeProgressFilter(value) {
setProgressFilter(value);
try { localStorage.setItem(PROGRESS_FILTER_KEY, value); } catch { /* sin storage: solo en memoria */ }
}
const [filterOwnerUserId, setFilterOwnerUserId] = useState('');
// Prueba exploratoria: filtro "ver todos / por usuario" solo para roles que ya ven todos los
@@ -194,9 +200,9 @@ export default function ProyectosPage() {
return diffDays >= 0 && diffDays <= 7;
})
: projects;
const visibleProjects = hideCompleted && !showTrash
? dueSoonProjects.filter((p) => Number(p.progress_pct) < 100)
: dueSoonProjects;
const visibleProjects = showTrash || !progressFilter
? dueSoonProjects
: dueSoonProjects.filter((p) => (Number(p.progress_pct) >= 100) === (progressFilter === 'only'));
return (
<div>
@@ -239,6 +245,21 @@ export default function ProyectosPage() {
<ComboBox options={[{ value: '', label: t('common_all') }, ...priorityOptions]} value={filterPriorityId} onChange={setFilterPriorityId} placeholder={t('common_priority')} />
</div>
</div>
<div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
<span className="text-muted" style={{ fontSize: '.72rem', whiteSpace: 'nowrap' }}>{t('project_filter_progress')}</span>
<div style={{ width: 160 }}>
<ComboBox
options={[
{ value: '', label: t('common_all') },
{ value: 'hide', label: t('project_filter_progress_hide') },
{ value: 'only', label: t('project_filter_progress_only') },
]}
value={progressFilter}
onChange={changeProgressFilter}
placeholder={t('project_filter_progress')}
/>
</div>
</div>
{canFilterByUser && (
<div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
<span className="text-muted" style={{ fontSize: '.72rem', whiteSpace: 'nowrap' }}>Usuario</span>
@@ -256,10 +277,6 @@ export default function ProyectosPage() {
<input type="checkbox" checked={filterDueSoon} onChange={(e) => setFilterDueSoon(e.target.checked)} />
{t('project_filter_due_soon')}
</label>
<label className="checkbox-row">
<input type="checkbox" checked={hideCompleted} onChange={(e) => toggleHideCompleted(e.target.checked)} />
{t('project_filter_hide_completed')}
</label>
</>
)}
</div>