Fix: custom dates on socios, ingresos and gastos. Add: new endpoint for getting socios dropdown on ingresos.
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
"all": "/users",
|
||||
"byId": "/users/:userId",
|
||||
"me": "/users/me",
|
||||
"dropdown": "/users/dropdown",
|
||||
"latestNumber": "/users/latest-number",
|
||||
"waitlist": "/users/waitlist",
|
||||
"waitlistLimited": "/users/waitlist/limited",
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"all": "/users",
|
||||
"byId": "/users/:userId",
|
||||
"me": "/users/me",
|
||||
"dropdown": "/users/dropdown",
|
||||
"latestNumber": "/users/latest-number",
|
||||
"waitlist": "/users/waitlist",
|
||||
"waitlistLimited": "/users/waitlist/limited",
|
||||
|
||||
@@ -48,7 +48,7 @@ const GastoCard = ({ gasto, isNew = false, onCreate, onUpdate, onDelete, onCance
|
||||
supplier: gasto.supplier || '',
|
||||
invoice: gasto.invoice || '',
|
||||
type: gasto.type ?? 0,
|
||||
createdAt: gasto.createdAt?.slice(0, 16) || (isNew ? getNowAsLocalDatetime() : ''),
|
||||
createdAt: gasto.createdAt || (isNew ? getNowAsLocalDatetime() : ''),
|
||||
});
|
||||
|
||||
const getFieldError = (field) => fieldErrors?.[field] ?? null;
|
||||
@@ -61,7 +61,7 @@ const GastoCard = ({ gasto, isNew = false, onCreate, onUpdate, onDelete, onCance
|
||||
supplier: gasto.supplier || '',
|
||||
invoice: gasto.invoice || '',
|
||||
type: gasto.type ?? 0,
|
||||
createdAt: gasto.createdAt?.slice(0, 16) || (isNew ? getNowAsLocalDatetime() : ''),
|
||||
createdAt: gasto.createdAt || (isNew ? getNowAsLocalDatetime() : ''),
|
||||
});
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
@@ -109,7 +109,7 @@ const GastoCard = ({ gasto, isNew = false, onCreate, onUpdate, onDelete, onCance
|
||||
<SpanishDateTimePicker
|
||||
selected={new Date(formData.createdAt)}
|
||||
onChange={(date) =>
|
||||
handleChange('createdAt', date.toISOString().slice(0, 16))
|
||||
handleChange('createdAt', date.toISOString())
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
|
||||
@@ -49,7 +49,7 @@ const IngresoCard = ({
|
||||
onCancel,
|
||||
className = '',
|
||||
editable = true,
|
||||
members = [],
|
||||
dropdown = new Map(),
|
||||
fieldErrors
|
||||
}) => {
|
||||
const createMode = isNew;
|
||||
@@ -64,7 +64,7 @@ const IngresoCard = ({
|
||||
memberNumber: income.memberNumber,
|
||||
userId: income.userId,
|
||||
displayName: income.displayName || '',
|
||||
createdAt: income.createdAt?.slice(0, 16) || (isNew ? getNowAsLocalDatetime() : ''),
|
||||
createdAt: income.createdAt || (isNew ? getNowAsLocalDatetime() : ''),
|
||||
});
|
||||
|
||||
const getFieldError = (field) => fieldErrors?.[field] ?? null;
|
||||
@@ -79,26 +79,12 @@ const IngresoCard = ({
|
||||
userId: income.userId,
|
||||
memberNumber: income.memberNumber,
|
||||
displayName: income.displayName || '',
|
||||
createdAt: income.createdAt?.slice(0, 16) || (isNew ? getNowAsLocalDatetime() : ''),
|
||||
createdAt: income.createdAt || (isNew ? getNowAsLocalDatetime() : ''),
|
||||
});
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [income, editMode]);
|
||||
|
||||
useEffect(() => {
|
||||
if (formData.memberNumber && !formData.userId) {
|
||||
const member = members.find(m => m.memberNumber === formData.memberNumber);
|
||||
if (member) {
|
||||
setFormData(prev => ({
|
||||
...prev,
|
||||
userId: member.userId,
|
||||
displayName: member.displayName
|
||||
}));
|
||||
}
|
||||
}
|
||||
}, [formData.memberNumber, formData.userId, members]);
|
||||
|
||||
|
||||
const handleChange = (field, value) =>
|
||||
setFormData(prev => ({ ...prev, [field]: value }));
|
||||
|
||||
@@ -115,9 +101,12 @@ const IngresoCard = ({
|
||||
|
||||
const handleDelete = () => typeof onDelete === 'function' && onDelete(income.incomeId);
|
||||
|
||||
const uniqueMembers = Array.from(
|
||||
new Map(members.map(item => [item.memberNumber, item])).values()
|
||||
).sort((a, b) => a.memberNumber - b.memberNumber);
|
||||
const uniqueMembers = Array.from(dropdown.entries())
|
||||
.map(([memberNumber, member]) => ({
|
||||
memberNumber,
|
||||
...member
|
||||
}))
|
||||
.sort((a, b) => a.memberNumber - b.memberNumber);
|
||||
|
||||
return (
|
||||
<MotionCard className={`ingreso-card shadow-sm rounded-4 border-0 h-100 ${className}`}>
|
||||
@@ -148,7 +137,7 @@ const IngresoCard = ({
|
||||
<SpanishDateTimePicker
|
||||
selected={new Date(formData.createdAt)}
|
||||
onChange={(date) =>
|
||||
handleChange('createdAt', date.toISOString().slice(0, 16))
|
||||
handleChange('createdAt', date.toISOString())
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
@@ -188,8 +177,8 @@ const IngresoCard = ({
|
||||
size="sm"
|
||||
value={formData.memberNumber ?? ""}
|
||||
onChange={(e) => {
|
||||
const memberNumber = parseInt(e.target.value);
|
||||
const member = members.find(m => m.memberNumber === memberNumber);
|
||||
const memberNumber = parseInt(e.target.value, 10);
|
||||
const member = dropdown.get(memberNumber);
|
||||
|
||||
handleChange('memberNumber', memberNumber);
|
||||
handleChange('userId', member?.userId ?? null);
|
||||
|
||||
@@ -33,7 +33,7 @@ const renderDateField = (label, icon, dateValue, editMode, fieldKey, handleChang
|
||||
<SpanishDateTimePicker
|
||||
selected={dateValue ? new Date(dateValue) : null}
|
||||
onChange={(date) =>
|
||||
date ? handleChange(fieldKey, date.toISOString().slice(0, 16)) : handleChange(fieldKey, null)
|
||||
date ? handleChange(fieldKey, date.toISOString()) : handleChange(fieldKey, null)
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
@@ -108,9 +108,9 @@ const SocioCard = ({ identity, isNew = false, onCreate, onUpdate, onDelete, onCa
|
||||
notes: identity?.metadata.notes || '',
|
||||
status: identity?.account.status,
|
||||
type: identity?.metadata.type,
|
||||
createdAt: identity?.metadata.createdAt?.slice(0, 16) || (isNew ? getNowAsLocalDatetime() : ''),
|
||||
assignedAt: identity?.metadata.assignedAt?.slice(0, 16) || undefined,
|
||||
deactivatedAt: identity?.metadata.deactivatedAt?.slice(0, 16) || undefined,
|
||||
createdAt: identity?.metadata.createdAt || (isNew ? getNowAsLocalDatetime() : ''),
|
||||
assignedAt: identity?.metadata.assignedAt || undefined,
|
||||
deactivatedAt: identity?.metadata.deactivatedAt || undefined,
|
||||
globalRole: 0,
|
||||
password: createMode && !editMode ? generateSecurePassword() : null,
|
||||
});
|
||||
@@ -130,9 +130,9 @@ const SocioCard = ({ identity, isNew = false, onCreate, onUpdate, onDelete, onCa
|
||||
notes: identity.metadata.notes || '',
|
||||
status: identity.account.status,
|
||||
type: identity.metadata.type,
|
||||
createdAt: identity.metadata.createdAt?.slice(0, 16) || (isNew ? getNowAsLocalDatetime() : ''),
|
||||
assignedAt: identity.metadata.assignedAt?.slice(0, 16) || undefined,
|
||||
deactivatedAt: identity.metadata.deactivatedAt?.slice(0, 16) || undefined,
|
||||
createdAt: identity.metadata.createdAt || (isNew ? getNowAsLocalDatetime() : ''),
|
||||
assignedAt: identity.metadata.assignedAt || undefined,
|
||||
deactivatedAt: identity.metadata.deactivatedAt || undefined,
|
||||
globalRole: 0,
|
||||
password: createMode ? generateSecurePassword() : ''
|
||||
});
|
||||
|
||||
@@ -140,7 +140,7 @@ NewUserForm.propTypes = {
|
||||
userType: PropTypes.number.isRequired,
|
||||
plotNumber: PropTypes.number.isRequired,
|
||||
onSubmit: PropTypes.func.isRequired,
|
||||
errors: PropTypes.object
|
||||
fieldErrors: PropTypes.object
|
||||
};
|
||||
|
||||
export default NewUserForm;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useConfig } from '../hooks/useConfig';
|
||||
import { DataProvider } from '../context/DataContext';
|
||||
import { useDataContext } from '../hooks/useDataContext';
|
||||
@@ -32,7 +32,7 @@ const Ingresos = () => {
|
||||
const reqConfig = {
|
||||
baseUrl: config.apiConfig.baseUrl + config.apiConfig.endpoints.incomes.withInfo,
|
||||
rawUrl: config.apiConfig.baseUrl + config.apiConfig.endpoints.incomes.all,
|
||||
usersUrl: config.apiConfig.baseUrl + config.apiConfig.endpoints.users.all,
|
||||
dropdownUrl: config.apiConfig.baseUrl + config.apiConfig.endpoints.users.dropdown,
|
||||
params: {}
|
||||
};
|
||||
|
||||
@@ -44,24 +44,35 @@ const Ingresos = () => {
|
||||
};
|
||||
|
||||
const IngresosContent = ({ reqConfig }) => {
|
||||
const { data, dataLoading, postData, putData, deleteData } = useDataContext();
|
||||
const { data, dataLoading, getData, postData, putData, deleteData } = useDataContext();
|
||||
const [showPDFModal, setShowPDFModal] = useState(false);
|
||||
const [creatingIngreso, setCreatingIngreso] = useState(false);
|
||||
const [tempIngreso, setTempIngreso] = useState(null);
|
||||
const [deleteTargetId, setDeleteTargetId] = useState(null);
|
||||
const [fieldErrors, setFieldErrors] = useState(null);
|
||||
const [dropdown, setDropdown] = useState(new Map());
|
||||
|
||||
const members = data
|
||||
? Array.from(
|
||||
new Map(
|
||||
data.map(i => [i.memberNumber, {
|
||||
memberNumber: i.memberNumber,
|
||||
displayName: i.displayName,
|
||||
userId: i.userId
|
||||
}])
|
||||
).values()
|
||||
).sort((a, b) => a.memberNumber - b.memberNumber)
|
||||
: [];
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
const response = await getData(reqConfig.dropdownUrl);
|
||||
const map = new Map();
|
||||
response
|
||||
.sort((a, b) => a.memberNumber - b.memberNumber)
|
||||
.forEach(item => {
|
||||
map.set(item.memberNumber, {
|
||||
userId: item.userId,
|
||||
displayName: item.displayName
|
||||
});
|
||||
});
|
||||
setDropdown(map);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
};
|
||||
fetchData();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [reqConfig.dropdownUrl]);
|
||||
|
||||
const {
|
||||
filtered,
|
||||
@@ -100,13 +111,15 @@ const IngresosContent = ({ reqConfig }) => {
|
||||
});
|
||||
|
||||
const handleCreate = () => {
|
||||
const firstMember = members[0];
|
||||
if (dropdown.size === 0) return;
|
||||
const firstEntry = dropdown.entries().next().value;
|
||||
const [memberNumber, member] = firstEntry ?? [];
|
||||
|
||||
setCreatingIngreso(true);
|
||||
setTempIngreso({
|
||||
incomeId: null,
|
||||
memberNumber: firstMember?.memberNumber ?? null,
|
||||
userId: firstMember?.userId ?? null,
|
||||
memberNumber: memberNumber ?? null,
|
||||
userId: member?.userId ?? null,
|
||||
concept: '',
|
||||
amount: 0.0,
|
||||
frequency: CONSTANTS.PAYMENT_FREQUENCY_YEARLY,
|
||||
@@ -162,7 +175,7 @@ const IngresosContent = ({ reqConfig }) => {
|
||||
searchTerm={searchTerm}
|
||||
onSearchChange={setSearchTerm}
|
||||
filtersComponent={<IngresosFilter filters={filters} onChange={setFilters} />}
|
||||
onCreate={handleCreate}
|
||||
onCreate={dropdown.size > 0 ? handleCreate : null}
|
||||
onPDF={() => setShowPDFModal(true)}
|
||||
/>
|
||||
|
||||
@@ -175,7 +188,7 @@ const IngresosContent = ({ reqConfig }) => {
|
||||
isNew
|
||||
onCreate={handleCreateSubmit}
|
||||
onCancel={handleCancelCreate}
|
||||
members={members}
|
||||
dropdown={dropdown}
|
||||
fieldErrors={fieldErrors}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -90,9 +90,13 @@ const ListaEsperaContent = ({ reqConfig }) => {
|
||||
|
||||
setShowNewUserFormModal(false);
|
||||
setShowConfirmationModal(true);
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
} catch (_err) {
|
||||
setValidationErrors({ general: "Error inesperado al enviar la solicitud" });
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
} catch (err) {
|
||||
if (err.status === 422 && err.errors) {
|
||||
setValidationErrors(err.errors);
|
||||
} else {
|
||||
setShowNewUserFormModal(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -152,7 +156,7 @@ const ListaEsperaContent = ({ reqConfig }) => {
|
||||
userType={0}
|
||||
plotNumber={0}
|
||||
onSubmit={handleRegisterSubmit}
|
||||
errors={validationErrors}
|
||||
fieldErrors={validationErrors}
|
||||
/>
|
||||
</CustomModal>
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ export const DateParser = {
|
||||
if (!isoString) return '—';
|
||||
|
||||
const date = new Date(isoString);
|
||||
if (isNaN(date)) return '—'; // Para proteger aún más por si llega basura
|
||||
if (isNaN(date)) return '—';
|
||||
|
||||
return new Intl.DateTimeFormat('es-ES', {
|
||||
day: '2-digit',
|
||||
|
||||
Reference in New Issue
Block a user