From c0bcbfb547ec3caf1c2ad1c39c5265e243745b81 Mon Sep 17 00:00:00 2001 From: Jose Date: Fri, 30 Jan 2026 22:38:15 +0100 Subject: [PATCH] only change password, docs and mail left --- src/components/Anuncios/AnuncioCard.jsx | 8 +- src/components/Gastos/GastoCard.jsx | 54 ++++--- src/components/Ingresos/IngresoCard.jsx | 61 ++++---- src/components/Socios/SocioCard.jsx | 70 +++++---- src/components/Solicitudes/NewUserForm.jsx | 18 +-- src/components/Solicitudes/SolicitudCard.jsx | 113 +++++++++++---- src/context/DataContext.jsx | 4 +- src/context/ErrorContext.jsx | 36 +++++ src/hooks/useData.js | 141 ++++++++++++------- src/main.jsx | 15 +- src/pages/Anuncios.jsx | 25 +--- src/pages/Balance.jsx | 7 +- src/pages/Documentacion.jsx | 7 +- src/pages/Gastos.jsx | 33 ++--- src/pages/Ingresos.jsx | 44 +++--- src/pages/ListaEspera.jsx | 7 +- src/pages/Perfil.jsx | 91 ++++++------ src/pages/Socios.jsx | 48 ++++--- src/pages/Solicitudes.jsx | 7 +- src/util/alertHelpers.jsx | 15 -- src/util/parsers/errorParser.js | 10 -- 21 files changed, 473 insertions(+), 341 deletions(-) create mode 100644 src/context/ErrorContext.jsx delete mode 100644 src/util/alertHelpers.jsx delete mode 100644 src/util/parsers/errorParser.js diff --git a/src/components/Anuncios/AnuncioCard.jsx b/src/components/Anuncios/AnuncioCard.jsx index cd84b69..ff5db55 100644 --- a/src/components/Anuncios/AnuncioCard.jsx +++ b/src/components/Anuncios/AnuncioCard.jsx @@ -4,7 +4,6 @@ import AnimatedDropdown from '../../components/AnimatedDropdown'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faEdit, faTrash, faEllipsisVertical } from '@fortawesome/free-solid-svg-icons'; import '../../css/AnuncioCard.css'; -import { renderErrorAlert } from '../../util/alertHelpers'; import { EditorProvider, Editor, @@ -37,7 +36,7 @@ const formatDateTime = (iso) => { }; }; -const AnuncioCard = ({ anuncio, isNew = false, onCreate, onUpdate, onDelete, onCancel, error, onClearError }) => { +const AnuncioCard = ({ anuncio, isNew = false, onCreate, onUpdate, onDelete, onCancel }) => { const createMode = isNew; const [editMode, setEditMode] = useState(createMode); const [showFullBody, setShowFullBody] = useState(false); @@ -59,20 +58,17 @@ const AnuncioCard = ({ anuncio, isNew = false, onCreate, onUpdate, onDelete, onC }, [anuncio, editMode]); const handleEdit = () => { - if (onClearError) onClearError(); setEditMode(true); }; const handleDelete = () => typeof onDelete === 'function' && onDelete(anuncio.announceId); const handleCancel = () => { - if (onClearError) onClearError(); if (createMode && onCancel) return onCancel(); setEditMode(false); }; const handleSave = () => { - if (onClearError) onClearError(); const sanitizedBody = DOMPurify.sanitize(formData.body); formData.body = sanitizedBody; const updated = { ...anuncio, ...formData }; @@ -133,8 +129,6 @@ const AnuncioCard = ({ anuncio, isNew = false, onCreate, onUpdate, onDelete, onC - {(editMode || createMode) && renderErrorAlert(error)} - {editMode || createMode ? ( { return base + (map[tipo] || 'farmer.svg'); }; -const GastoCard = ({ gasto, isNew = false, onCreate, onUpdate, onDelete, onCancel, error, onClearError }) => { +const GastoCard = ({ gasto, isNew = false, onCreate, onUpdate, onDelete, onCancel, fieldErrors }) => { const createMode = isNew; const [editMode, setEditMode] = useState(createMode); const { theme } = useTheme(); @@ -52,6 +51,8 @@ const GastoCard = ({ gasto, isNew = false, onCreate, onUpdate, onDelete, onCance createdAt: gasto.createdAt?.slice(0, 16) || (isNew ? getNowAsLocalDatetime() : ''), }); + const getFieldError = (field) => fieldErrors?.[field] ?? null; + useEffect(() => { if (!editMode) { setFormData({ @@ -71,13 +72,11 @@ const GastoCard = ({ gasto, isNew = false, onCreate, onUpdate, onDelete, onCance const handleDelete = () => typeof onDelete === 'function' && onDelete(gasto.expenseId); const handleCancel = () => { - if (onClearError) onClearError(); if (isNew && typeof onCancel === 'function') return onCancel(); setEditMode(false); }; const handleSave = () => { - if (onClearError) onClearError(); const newExpense = { ...gasto, ...formData }; if (createMode && typeof onCreate === 'function') return onCreate(newExpense); if (typeof onUpdate === 'function') return onUpdate(newExpense, gasto.expenseId); @@ -91,12 +90,18 @@ const GastoCard = ({ gasto, isNew = false, onCreate, onUpdate, onDelete, onCance
{editMode ? ( - handleChange('concept', e.target.value.toUpperCase())} - /> + <> + handleChange('concept', e.target.value.toUpperCase())} + /> + + {getFieldError("concept")} + + ) : formData.concept} @@ -132,13 +137,17 @@ const GastoCard = ({ gasto, isNew = false, onCreate, onUpdate, onDelete, onCance - {(editMode || createMode) && renderErrorAlert(error)} - Importe:{' '} {editMode ? ( - handleChange('amount', parseFloat(e.target.value))} style={{ maxWidth: '150px', display: 'inline-block' }} /> + <> + handleChange('amount', parseFloat(e.target.value))} style={{ maxWidth: '150px', display: 'inline-block' }} /> + + {getFieldError("amount")} + + ) : `${formData.amount.toFixed(2)} €`} @@ -146,7 +155,13 @@ const GastoCard = ({ gasto, isNew = false, onCreate, onUpdate, onDelete, onCance Proveedor:{' '} {editMode ? ( - handleChange('supplier', e.target.value)} /> + <> + handleChange('supplier', e.target.value)} /> + + {getFieldError("supplier")} + + ) : formData.supplier} @@ -154,7 +169,13 @@ const GastoCard = ({ gasto, isNew = false, onCreate, onUpdate, onDelete, onCance Factura:{' '} {editMode ? ( - handleChange('invoice', e.target.value)} /> + <> + handleChange('invoice', e.target.value)} /> + + {getFieldError("invoice")} + + ) : formData.invoice} @@ -190,7 +211,8 @@ GastoCard.propTypes = { onCreate: PropTypes.func, onUpdate: PropTypes.func, onDelete: PropTypes.func, - onCancel: PropTypes.func + onCancel: PropTypes.func, + fieldErrors: PropTypes.object }; export default GastoCard; diff --git a/src/components/Ingresos/IngresoCard.jsx b/src/components/Ingresos/IngresoCard.jsx index 4e9a2ca..24bb717 100644 --- a/src/components/Ingresos/IngresoCard.jsx +++ b/src/components/Ingresos/IngresoCard.jsx @@ -18,7 +18,6 @@ import { CONSTANTS } from '../../util/constants'; import '../../css/IngresoCard.css'; import { useTheme } from '../../hooks/useTheme'; import { DateParser } from '../../util/parsers/dateParser'; -import { renderErrorAlert } from '../../util/alertHelpers'; import { getNowAsLocalDatetime } from '../../util/date'; import SpanishDateTimePicker from '../SpanishDateTimePicker'; @@ -50,9 +49,8 @@ const IngresoCard = ({ onCancel, className = '', editable = true, - error, - onClearError, - members = [] + members = [], + fieldErrors }) => { const createMode = isNew; const [editMode, setEditMode] = useState(createMode); @@ -69,6 +67,8 @@ const IngresoCard = ({ createdAt: income.createdAt?.slice(0, 16) || (isNew ? getNowAsLocalDatetime() : ''), }); + const getFieldError = (field) => fieldErrors?.[field] ?? null; + useEffect(() => { if (!editMode) { setFormData({ @@ -103,13 +103,11 @@ const IngresoCard = ({ setFormData(prev => ({ ...prev, [field]: value })); const handleCancel = () => { - if (onClearError) onClearError(); if (isNew && typeof onCancel === 'function') return onCancel(); setEditMode(false); }; const handleSave = () => { - if (onClearError) onClearError(); const newIncome = { ...income, ...formData }; if (createMode && typeof onCreate === 'function') return onCreate(newIncome); if (typeof onUpdate === 'function') return onUpdate(newIncome, income.incomeId); @@ -130,12 +128,18 @@ const IngresoCard = ({
{editMode ? ( - handleChange('concept', e.target.value.toUpperCase())} - /> + <> + handleChange('concept', e.target.value.toUpperCase())} + /> + + {getFieldError("concept")} + + ) : formData.concept} @@ -161,7 +165,7 @@ const IngresoCard = ({ > {({ closeDropdown }) => ( <> -
{ setEditMode(true); onClearError && onClearError(); closeDropdown(); }}> +
{ setEditMode(true); closeDropdown(); }}> Editar
{ handleDelete(); closeDropdown(); }}> @@ -175,8 +179,6 @@ const IngresoCard = ({ - {(editMode || createMode) && renderErrorAlert(error)} - Socio:{' '} @@ -236,15 +238,21 @@ const IngresoCard = ({ Importe:{' '} {editMode ? ( - handleChange('amount', parseFloat(e.target.value))} - style={{ maxWidth: '150px', display: 'inline-block' }} - /> + <> + handleChange('amount', parseFloat(e.target.value))} + style={{ maxWidth: '150px', display: 'inline-block' }} + /> + + {getFieldError("amount")} + + ) : `${formData.amount.toFixed(2)} €`} @@ -299,9 +307,8 @@ IngresoCard.propTypes = { onCancel: PropTypes.func, className: PropTypes.string, editable: PropTypes.bool, - error: PropTypes.string, - onClearError: PropTypes.func, - members: PropTypes.array + members: PropTypes.array, + fieldErrors: PropTypes.object }; export default IngresoCard; diff --git a/src/components/Socios/SocioCard.jsx b/src/components/Socios/SocioCard.jsx index 302f170..332707a 100644 --- a/src/components/Socios/SocioCard.jsx +++ b/src/components/Socios/SocioCard.jsx @@ -20,7 +20,6 @@ import TipoSocioDropdown from './TipoSocioDropdown'; import { getNowAsLocalDatetime } from '../../util/date'; import { generateSecurePassword } from '../../util/passwordGenerator'; import { DateParser } from '../../util/parsers/dateParser'; -import { renderErrorAlert } from '../../util/alertHelpers'; import { useDataContext } from "../../hooks/useDataContext"; import SpanishDateTimePicker from '../SpanishDateTimePicker'; @@ -91,7 +90,7 @@ const getPFP = (tipo) => { const MotionCard = _motion.create(Card); -const SocioCard = ({ identity, isNew = false, onCreate, onUpdate, onDelete, onCancel, onViewIncomes, error, onClearError, positionIfWaitlist }) => { +const SocioCard = ({ identity, isNew = false, onCreate, onUpdate, onDelete, onCancel, onViewIncomes, positionIfWaitlist, fieldErrors }) => { const createMode = isNew; const [editMode, setEditMode] = useState(isNew); const [showPassword, setShowPassword] = useState(false); @@ -116,6 +115,8 @@ const SocioCard = ({ identity, isNew = false, onCreate, onUpdate, onDelete, onCa password: createMode && !editMode ? generateSecurePassword() : null, }); + const getFieldError = (field) => fieldErrors?.[field] ?? null; + useEffect(() => { if (!editMode) { setFormData({ @@ -143,12 +144,12 @@ const SocioCard = ({ identity, isNew = false, onCreate, onUpdate, onDelete, onCa const fetchLastNumber = async () => { try { if (!(createMode || editMode)) return; - - const latestNumber = await getData("http://localhost:8081/v2/huertos/users/latest-number"); - + + const latestNumber = await getData("http://localhost:8081/v2/huertos/users/latest-number", {}, false); + const nuevoNumero = latestNumber + 1; setLatestNumber(nuevoNumero); - + setFormData(prev => ({ ...prev, memberNumber: prev.memberNumber || nuevoNumero @@ -157,25 +158,22 @@ const SocioCard = ({ identity, isNew = false, onCreate, onUpdate, onDelete, onCa console.error("Error al obtener el número de socio:", err); } }; - + fetchLastNumber(); }, [createMode, editMode, getData]); const handleEdit = () => { - if (onClearError) onClearError(); setEditMode(true); }; const handleDelete = () => typeof onDelete === "function" && onDelete(identity.user.userId); const handleCancel = () => { - if (onClearError) onClearError(); if (isNew && typeof onCancel === 'function') return onCancel(); setEditMode(false); }; const handleSave = () => { - if (onClearError) onClearError(); const newSocio = { ...identity, ...formData }; if (createMode && typeof onCreate === 'function') return onCreate(newSocio); if (typeof onUpdate === 'function') return onUpdate(newSocio, identity.user.userId); @@ -224,7 +222,13 @@ const SocioCard = ({ identity, isNew = false, onCreate, onUpdate, onDelete, onCa
{editMode ? ( - handleChange('displayName', e.target.value)} style={{ maxWidth: '220px' }} /> + <> + handleChange('displayName', e.target.value)} style={{ maxWidth: '220px' }} /> + + {getFieldError("displayName")} + + ) : formData.displayName} {editMode ? ( @@ -262,8 +266,6 @@ const SocioCard = ({ identity, isNew = false, onCreate, onUpdate, onDelete, onCa - {(editMode || createMode) && renderErrorAlert(error)} - {[{ label: 'DNI', clazz: '', icon: faIdCard, value: formData.dni, field: 'dni', type: 'text', maxWidth: '180px' @@ -279,7 +281,13 @@ const SocioCard = ({ identity, isNew = false, onCreate, onUpdate, onDelete, onCa {label} {editMode ? ( - handleChange(field, e.target.value)} style={{ maxWidth }} /> + <> + handleChange(field, e.target.value)} style={{ maxWidth }} /> + + {getFieldError(`${field}`)} + + ) : ( {parseNull(value)} )} @@ -289,14 +297,20 @@ const SocioCard = ({ identity, isNew = false, onCreate, onUpdate, onDelete, onCa CONTRASEÑA
- handleChange('password', e.target.value)} - style={{ maxWidth: '200px' }} - /> + <> + handleChange('password', e.target.value)} + style={{ maxWidth: '200px' }} + isInvalid={!!fieldErrors?.password} + /> + + {getFieldError("password")} + +