fix(ui): elimina los 2 casos que quedaban de formulario debajo de un listado
Auditoria completa del frontend: quedaban 2 lugares con el mismo antipatron que ya se habia corregido en Proyectos/Departamentos/Usuarios/Catalogos. - ProjectActivitiesTab: "Nueva actividad" se apilaba debajo del listado de actividades. Ahora abre en su propio DetailPopup, igual que el resto. - ProjectInfoTab (pestaña Info de un proyecto): el combo "agregar miembro" se apilaba debajo de la lista de miembros. Ahora hay un boton "Agregar miembro" en el encabezado de esa tarjeta que abre un DetailPopup chico. Con esto no queda ningun listado del sistema con un formulario apilado debajo: todos usan DetailPopup (ver regla en project-md-templates/UI-UX-WINDOWS.md). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -11,6 +11,7 @@ import { Field, FieldRow } from '../../components/Field.jsx';
|
||||
import { ComboBox } from '../../components/ComboBox.jsx';
|
||||
import { StatusBadge, ProgressBar } from '../../components/StatusBadge.jsx';
|
||||
import { Badge } from '../../components/Badge.jsx';
|
||||
import { DetailPopup } from '../../components/DetailPopup.jsx';
|
||||
|
||||
function flatten(nodes, acc = []) {
|
||||
for (const n of nodes) { acc.push(n); if (n.children?.length) flatten(n.children, acc); }
|
||||
@@ -42,6 +43,7 @@ export default function ProjectInfoTab({ project, onChanged }) {
|
||||
const [editing, setEditing] = useState(false);
|
||||
const [form, setForm] = useState(() => toForm(project));
|
||||
const [addingMember, setAddingMember] = useState('');
|
||||
const [addMemberOpen, setAddMemberOpen] = useState(false);
|
||||
|
||||
useEffect(() => { setForm(toForm(project)); }, [project]);
|
||||
|
||||
@@ -75,6 +77,7 @@ export default function ProjectInfoTab({ project, onChanged }) {
|
||||
await runAction(async () => {
|
||||
await addProjectMember(project.id, Number(addingMember));
|
||||
setAddingMember('');
|
||||
setAddMemberOpen(false);
|
||||
onChanged();
|
||||
});
|
||||
}
|
||||
@@ -185,20 +188,28 @@ export default function ProjectInfoTab({ project, onChanged }) {
|
||||
)}
|
||||
|
||||
<div className="panel-card">
|
||||
<h3>{t('project_members')}</h3>
|
||||
<div className="toolbar">
|
||||
<h3 style={{ margin: 0 }}>{t('project_members')}</h3>
|
||||
<Button variant="standard" icon={UserPlus} onClick={() => setAddMemberOpen(true)}>{t('project_add_member')}</Button>
|
||||
</div>
|
||||
{project.members.map((m) => (
|
||||
<div key={m.user_id} style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '6px 0' }}>
|
||||
<span style={{ flex: 1, fontSize: '.82rem' }}>{m.name} <span className="text-muted">· {m.email}</span></span>
|
||||
<button className="icon-btn" onClick={() => confirmRemoveMember(m)}><Trash2 size={16} /></button>
|
||||
</div>
|
||||
))}
|
||||
<div style={{ display: 'flex', gap: 8, marginTop: 10 }}>
|
||||
<div style={{ flex: 1 }}>
|
||||
<ComboBox options={userOptions} value={addingMember} onChange={setAddingMember} placeholder={t('project_add_member')} />
|
||||
</div>
|
||||
<Button variant="standard" icon={UserPlus} onClick={addMember}>{t('project_add_member')}</Button>
|
||||
</div>
|
||||
{project.members.length === 0 && <div className="text-muted" style={{ fontSize: '.78rem' }}>{t('common_empty')}</div>}
|
||||
</div>
|
||||
|
||||
<DetailPopup open={addMemberOpen} title={t('project_add_member')} onClose={() => setAddMemberOpen(false)} width={420} height={260}>
|
||||
<Field label={t('project_add_member')}>
|
||||
<ComboBox options={userOptions} value={addingMember} onChange={setAddingMember} placeholder={t('project_add_member')} />
|
||||
</Field>
|
||||
<div style={{ display: 'flex', gap: 8, marginTop: 8 }}>
|
||||
<Button variant="accent" icon={UserPlus} onClick={addMember}>{t('common_save')}</Button>
|
||||
<Button variant="standard" onClick={() => setAddMemberOpen(false)}>{t('common_cancel')}</Button>
|
||||
</div>
|
||||
</DetailPopup>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user