Ongoing adaptation to new backend structure
This commit is contained in:
@@ -1,77 +1,72 @@
|
|||||||
{
|
{
|
||||||
"apiConfig": {
|
"apiConfig": {
|
||||||
"baseUrl": "http://api.huertos.local",
|
"baseUrl": "http://localhost:8081/v2/huertos",
|
||||||
"coreUrl": "http://api.miarma.local",
|
"coreUrl": "http://localhost:8080/v2/core",
|
||||||
"endpoints": {
|
"endpoints": {
|
||||||
"auth": {
|
"auth": {
|
||||||
"login": "/v1/login",
|
"login": "/auth/login",
|
||||||
"validateToken": "/auth/v1/validate-token",
|
"refreshToken": "/auth/refresh",
|
||||||
"refreshToken": "/auth/v1/refresh-token",
|
"changePassword": "/auth/change-password",
|
||||||
"changePassword": "/auth/v1/change-password",
|
"validateToken": "/auth/validate"
|
||||||
"loginValidate": "/auth/v1/login/validate"
|
|
||||||
},
|
},
|
||||||
"members": {
|
"users": {
|
||||||
"all": "/raw/v1/members",
|
"all": "/users",
|
||||||
"byId": "/raw/v1/members/:user_id",
|
"byId": "/users/:userId",
|
||||||
"profile": "/v1/members/profile",
|
"me": "/users/me",
|
||||||
"byMemberNumber": "/v1/members/number/:member_number",
|
"latestNumber": "/users/latest-number",
|
||||||
"byPlotNumber": "/v1/members/plot/:plot_number",
|
"waitlist": "/users/waitlist",
|
||||||
"byDni": "/v1/members/dni/:dni",
|
"waitlistLimited": "/users/waitlist/limited",
|
||||||
"payments": "/v1/members/number/:member_number/incomes",
|
"byMemberNumber": "/users/number/:memberNumber",
|
||||||
"hasPaid": "/v1/members/number/:member_number/has-paid",
|
"incomesPreview": "/users/number/:memberNumber/incomes",
|
||||||
"waitlist": "/v1/members/waitlist",
|
"hasPaid": "/users/number/:memberNumber/has-paid",
|
||||||
"limitedWaitlist": "/v1/members/waitlist/limited",
|
"hasCollaborator": "/users/number/:memberNumber/has-collaborator",
|
||||||
"lastMemberNumber": "/v1/members/latest-number",
|
"hasGreenhouse": "/users/number/:memberNumber/has-greenhouse",
|
||||||
"hasCollaborator": "/v1/members/number/:member_number/has-collaborator",
|
"hasCollaboratorRequest": "/users/number/:memberNumber/has-collaborator-request",
|
||||||
"hasCollaboratorRequest": "/v1/members/number/:member_number/has-collaborator-request",
|
"hasGreenhouseRequest": "/users/number/:memberNumber/has-greenhouse-request",
|
||||||
"hasGreenHouse": "/v1/members/number/:member_number/has-greenhouse",
|
"byPlotNumber": "/users/plot/:plotNumber",
|
||||||
"hasGreenHouseRequest": "/v1/members/number/:member_number/has-greenhouse-request",
|
"byDni": "/users/dni/:dni"
|
||||||
"changeType": "/v1/members/number/:user_id/type",
|
|
||||||
"changeStatus": "/v1/members/number/:user_id/status"
|
|
||||||
},
|
},
|
||||||
"incomes": {
|
"incomes": {
|
||||||
"all": "/raw/v1/incomes",
|
"all": "/incomes",
|
||||||
"allWithNames": "/raw/v1/incomes-with-names",
|
"withNames": "/incomes/with-names",
|
||||||
"byId": "/raw/v1/incomes/:income_id",
|
"mine": "/incomes/mine",
|
||||||
"myIncomes": "/v1/incomes/my-incomes"
|
"byId": "/incomes/:incomeId"
|
||||||
},
|
},
|
||||||
"expenses": {
|
"expenses": {
|
||||||
"all": "/raw/v1/expenses",
|
"all": "/expenses",
|
||||||
"byId": "/raw/v1/expenses/:expense_id"
|
"byId": "/expenses/:expenseId"
|
||||||
},
|
},
|
||||||
"balance": {
|
"balance": {
|
||||||
"all": "/raw/v1/balance"
|
"all": "/balance"
|
||||||
},
|
},
|
||||||
"announces": {
|
"announcements": {
|
||||||
"all": "/raw/v1/announces",
|
"all": "/announcements",
|
||||||
"byId": "/raw/v1/announces/:announce_id"
|
"byId": "/announcements/:announceId"
|
||||||
},
|
},
|
||||||
"requests": {
|
"requests": {
|
||||||
"all": "/raw/v1/requests",
|
"all": "/requests",
|
||||||
"byId": "/raw/v1/requests/:request_id",
|
"waitlist": "/requests/waitlist",
|
||||||
"allWithPreUsers": "/v1/requests-full",
|
"byId": "/requests/:requestId",
|
||||||
"byIdWithPreUser": "/v1/requests-full/:request_id",
|
"count": "/requests/count",
|
||||||
"countPending": "/v1/requests/count",
|
"mine": "/requests/mine",
|
||||||
"myRequests": "/v1/requests/my-requests",
|
"full": "/requests/full",
|
||||||
"accept": "/v1/requests/:request_id/accept",
|
"fullById": "/requests/full/:requestId",
|
||||||
"reject": "/v1/requests/:request_id/reject"
|
"accept": "/requests/:requestId/accept",
|
||||||
|
"reject": "/requests/:requestId/reject"
|
||||||
},
|
},
|
||||||
"pre_users": {
|
"preUsers": {
|
||||||
"all": "/raw/v1/pre_users",
|
"all": "/pre-users",
|
||||||
"byId": "/raw/v1/pre_users/:pre_user_id",
|
"byId": "/pre-users/:preUserId",
|
||||||
"validation": "/v1/pre_users/validate"
|
"validate": "/pre-users/validate"
|
||||||
},
|
},
|
||||||
"files": {
|
"files": {
|
||||||
"all": "/raw/v1/files",
|
"all": "/files",
|
||||||
"byId": "/raw/v1/files/:file_id",
|
"byId": "/files/:fileId"
|
||||||
"upload": "/raw/v1/files/upload",
|
|
||||||
"download": "/raw/v1/files/download/:file_id",
|
|
||||||
"userFiles": "/raw/v1/files/myfiles"
|
|
||||||
},
|
},
|
||||||
"mail": {
|
"mail": {
|
||||||
"all": "/v1/mails",
|
"all": "/mails",
|
||||||
"byIndex": "/v1/mails/:index",
|
"byIndex": "/mails/:index",
|
||||||
"send": "/v1/mails/send"
|
"send": "/mails/send"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,77 +1,71 @@
|
|||||||
{
|
{
|
||||||
"apiConfig": {
|
"apiConfig": {
|
||||||
"baseUrl": "https://api.huertosbellavista.es",
|
"baseUrl": "https://api.miarma.net/v2/huertos",
|
||||||
"coreUrl": "https://api.miarma.net",
|
"coreUrl": "https://api.miarma.net/v2/core",
|
||||||
"endpoints": {
|
"endpoints": {
|
||||||
"auth": {
|
"auth": {
|
||||||
"login": "/v1/login",
|
"login": "/auth/login",
|
||||||
"validateToken": "/auth/v1/validate-token",
|
"refreshToken": "/auth/refresh",
|
||||||
"refreshToken": "/auth/v1/refresh-token",
|
"changePassword": "/auth/change-password"
|
||||||
"changePassword": "/auth/v1/change-password",
|
|
||||||
"loginValidate": "/auth/v1/login/validate"
|
|
||||||
},
|
},
|
||||||
"members": {
|
"users": {
|
||||||
"all": "/raw/v1/members",
|
"all": "/users",
|
||||||
"byId": "/raw/v1/members/:user_id",
|
"byId": "/users/:userId",
|
||||||
"profile": "/v1/members/profile",
|
"me": "/users/me",
|
||||||
"byMemberNumber": "/v1/members/number/:member_number",
|
"latestNumber": "/users/latest-number",
|
||||||
"byPlotNumber": "/v1/members/plot/:plot_number",
|
"waitlist": "/users/waitlist",
|
||||||
"byDni": "/v1/members/dni/:dni",
|
"waitlistLimited": "/users/waitlist/limited",
|
||||||
"payments": "/v1/members/number/:member_number/incomes",
|
"byMemberNumber": "/users/number/:memberNumber",
|
||||||
"hasPaid": "/v1/members/number/:member_number/has-paid",
|
"incomesPreview": "/users/number/:memberNumber/incomes",
|
||||||
"waitlist": "/v1/members/waitlist",
|
"hasPaid": "/users/number/:memberNumber/has-paid",
|
||||||
"limitedWaitlist": "/v1/members/waitlist/limited",
|
"hasCollaborator": "/users/number/:memberNumber/has-collaborator",
|
||||||
"lastMemberNumber": "/v1/members/latest-number",
|
"hasGreenhouse": "/users/number/:memberNumber/has-greenhouse",
|
||||||
"hasCollaborator": "/v1/members/number/:member_number/has-collaborator",
|
"hasCollaboratorRequest": "/users/number/:memberNumber/has-collaborator-request",
|
||||||
"hasCollaboratorRequest": "/v1/members/number/:member_number/has-collaborator-request",
|
"hasGreenhouseRequest": "/users/number/:memberNumber/has-greenhouse-request",
|
||||||
"hasGreenHouse": "/v1/members/number/:member_number/has-greenhouse",
|
"byPlotNumber": "/users/plot/:plotNumber",
|
||||||
"hasGreenHouseRequest": "/v1/members/number/:member_number/has-greenhouse-request",
|
"byDni": "/users/dni/:dni"
|
||||||
"changeType": "/v1/members/number/:user_id/type",
|
|
||||||
"changeStatus": "/v1/members/number/:user_id/status"
|
|
||||||
},
|
},
|
||||||
"incomes": {
|
"incomes": {
|
||||||
"all": "/raw/v1/incomes",
|
"all": "/incomes",
|
||||||
"allWithNames": "/raw/v1/incomes-with-names",
|
"withNames": "/incomes/with-names",
|
||||||
"byId": "/raw/v1/incomes/:income_id",
|
"mine": "/incomes/mine",
|
||||||
"myIncomes": "/v1/incomes/my-incomes"
|
"byId": "/incomes/:incomeId"
|
||||||
},
|
},
|
||||||
"expenses": {
|
"expenses": {
|
||||||
"all": "/raw/v1/expenses",
|
"all": "/expenses",
|
||||||
"byId": "/raw/v1/expenses/:expense_id"
|
"byId": "/expenses/:expenseId"
|
||||||
},
|
},
|
||||||
"balance": {
|
"balance": {
|
||||||
"all": "/raw/v1/balance"
|
"all": "/balance"
|
||||||
},
|
},
|
||||||
"announces": {
|
"announcements": {
|
||||||
"all": "/raw/v1/announces",
|
"all": "/announcements",
|
||||||
"byId": "/raw/v1/announces/:announce_id"
|
"byId": "/announcements/:announceId"
|
||||||
},
|
},
|
||||||
"requests": {
|
"requests": {
|
||||||
"all": "/raw/v1/requests",
|
"all": "/requests",
|
||||||
"byId": "/raw/v1/requests/:request_id",
|
"waitlist": "/requests/waitlist",
|
||||||
"allWithPreUsers": "/v1/requests-full",
|
"byId": "/requests/:requestId",
|
||||||
"byIdWithPreUser": "/v1/requests-full/:request_id",
|
"count": "/requests/count",
|
||||||
"countPending": "/v1/requests/count",
|
"mine": "/requests/mine",
|
||||||
"myRequests": "/v1/requests/my-requests",
|
"full": "/requests/full",
|
||||||
"accept": "/v1/requests/:request_id/accept",
|
"fullById": "/requests/full/:requestId",
|
||||||
"reject": "/v1/requests/:request_id/reject"
|
"accept": "/requests/:requestId/accept",
|
||||||
|
"reject": "/requests/:requestId/reject"
|
||||||
},
|
},
|
||||||
"pre_users": {
|
"preUsers": {
|
||||||
"all": "/raw/v1/pre_users",
|
"all": "/pre-users",
|
||||||
"byId": "/raw/v1/pre_users/:pre_user_id",
|
"byId": "/pre-users/:preUserId",
|
||||||
"validation": "/v1/pre_users/validate"
|
"validate": "/pre-users/validate"
|
||||||
},
|
},
|
||||||
"files": {
|
"files": {
|
||||||
"all": "/raw/v1/files",
|
"all": "/files",
|
||||||
"byId": "/raw/v1/files/:file_id",
|
"byId": "/files/:fileId"
|
||||||
"upload": "/raw/v1/files/upload",
|
|
||||||
"download": "/raw/v1/files/download/:file_id",
|
|
||||||
"userFiles": "/raw/v1/files/myfiles"
|
|
||||||
},
|
},
|
||||||
"mail": {
|
"mail": {
|
||||||
"all": "/v1/mails",
|
"all": "/mails",
|
||||||
"byIndex": "/v1/mails/:index",
|
"byIndex": "/mails/:index",
|
||||||
"send": "/v1/mails/send"
|
"send": "/mails/send"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ const AnuncioCard = ({ anuncio, isNew = false, onCreate, onUpdate, onDelete, onC
|
|||||||
const [formData, setFormData] = useState({
|
const [formData, setFormData] = useState({
|
||||||
body: anuncio.body || '',
|
body: anuncio.body || '',
|
||||||
priority: anuncio.priority ?? 1,
|
priority: anuncio.priority ?? 1,
|
||||||
published_by: JSON.parse(localStorage.getItem('user'))?.user_id,
|
publishedBy: JSON.parse(localStorage.getItem('identity'))?.user?.userId,
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -53,7 +53,7 @@ const AnuncioCard = ({ anuncio, isNew = false, onCreate, onUpdate, onDelete, onC
|
|||||||
setFormData({
|
setFormData({
|
||||||
body: anuncio.body || '',
|
body: anuncio.body || '',
|
||||||
priority: anuncio.priority ?? 1,
|
priority: anuncio.priority ?? 1,
|
||||||
published_by: JSON.parse(localStorage.getItem('user'))?.user_id,
|
publishedBy: JSON.parse(localStorage.getItem('identity'))?.user?.userId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [anuncio, editMode]);
|
}, [anuncio, editMode]);
|
||||||
@@ -63,7 +63,7 @@ const AnuncioCard = ({ anuncio, isNew = false, onCreate, onUpdate, onDelete, onC
|
|||||||
setEditMode(true);
|
setEditMode(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDelete = () => typeof onDelete === 'function' && onDelete(anuncio.announce_id);
|
const handleDelete = () => typeof onDelete === 'function' && onDelete(anuncio.announceId);
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
if (onClearError) onClearError();
|
if (onClearError) onClearError();
|
||||||
@@ -77,12 +77,12 @@ const AnuncioCard = ({ anuncio, isNew = false, onCreate, onUpdate, onDelete, onC
|
|||||||
formData.body = sanitizedBody;
|
formData.body = sanitizedBody;
|
||||||
const updated = { ...anuncio, ...formData };
|
const updated = { ...anuncio, ...formData };
|
||||||
if (createMode && typeof onCreate === 'function') return onCreate(updated);
|
if (createMode && typeof onCreate === 'function') return onCreate(updated);
|
||||||
if (typeof onUpdate === 'function') return onUpdate(updated, anuncio.announce_id);
|
if (typeof onUpdate === 'function') return onUpdate(updated, anuncio.announceId);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleChange = (field, value) => setFormData((prev) => ({ ...prev, [field]: value }));
|
const handleChange = (field, value) => setFormData((prev) => ({ ...prev, [field]: value }));
|
||||||
|
|
||||||
const { date, time } = formatDateTime(anuncio.created_at);
|
const { date, time } = formatDateTime(anuncio.createdAt);
|
||||||
const priorityInfo = PRIORITY_CONFIG[formData.priority] || PRIORITY_CONFIG[1];
|
const priorityInfo = PRIORITY_CONFIG[formData.priority] || PRIORITY_CONFIG[1];
|
||||||
const isLongBody = formData.body.length > 300;
|
const isLongBody = formData.body.length > 300;
|
||||||
const displayBody = isLongBody && !showFullBody
|
const displayBody = isLongBody && !showFullBody
|
||||||
@@ -101,11 +101,15 @@ const AnuncioCard = ({ anuncio, isNew = false, onCreate, onUpdate, onDelete, onC
|
|||||||
<Card className="anuncio-card rounded-4 border-0 shadow-sm mb-4">
|
<Card className="anuncio-card rounded-4 border-0 shadow-sm mb-4">
|
||||||
<Card.Header className="d-flex justify-content-between align-items-center rounded-top-4 px-3 py-2">
|
<Card.Header className="d-flex justify-content-between align-items-center rounded-top-4 px-3 py-2">
|
||||||
<div className="d-flex flex-column">
|
<div className="d-flex flex-column">
|
||||||
<span className="fw-bold">📢 Anuncio #{anuncio.announce_id}</span>
|
<span className="fw-bold">📢 Anuncio {!createMode ? ("#"+anuncio.idx) : ("")}</span>
|
||||||
<small className="muted">
|
{!createMode ? (
|
||||||
Publicado el {date} a las {time} por{' '}
|
<small className="muted">
|
||||||
<span className="fw-semibold">#{anuncio.published_by}</span>
|
Publicado el {date} a las {time} por{' '}
|
||||||
</small>
|
<span className="fw-semibold">{anuncio.publishedByName}</span>
|
||||||
|
</small>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{!createMode && !editMode && (
|
{!createMode && !editMode && (
|
||||||
<AnimatedDropdown
|
<AnimatedDropdown
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ function App() {
|
|||||||
<NavBar />
|
<NavBar />
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<Home />} />
|
<Route path="/" element={<Home />} />
|
||||||
{/*
|
|
||||||
<Route path="/lista-espera" element={<ListaEspera />} />
|
<Route path="/lista-espera" element={<ListaEspera />} />
|
||||||
<Route path="/login" element={<Login />} />
|
<Route path="/login" element={<Login />} />
|
||||||
<Route path="/gestion/socios" element={
|
<Route path="/gestion/socios" element={
|
||||||
@@ -80,7 +79,6 @@ function App() {
|
|||||||
<Correo />
|
<Correo />
|
||||||
</ProtectedRoute>
|
</ProtectedRoute>
|
||||||
} />
|
} />
|
||||||
*/}
|
|
||||||
<Route path="/*" element={<Maintenance />} />
|
<Route path="/*" element={<Maintenance />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
{routesWithFooter.includes(useLocation().pathname) ? <Footer /> : null}
|
{routesWithFooter.includes(useLocation().pathname) ? <Footer /> : null}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { useAuth } from "../../hooks/useAuth.js";
|
import { useAuth } from "../../hooks/useAuth.js";
|
||||||
|
|
||||||
const IfRole = ({ roles, children }) => {
|
const IfRole = ({ roles, children }) => {
|
||||||
const { user, authStatus } = useAuth();
|
const { identity, authStatus } = useAuth();
|
||||||
|
|
||||||
if (authStatus !== "authenticated") return null;
|
if (authStatus !== "authenticated") return null;
|
||||||
|
|
||||||
const userRole = user?.role;
|
const userRole = identity?.metadata?.role;
|
||||||
|
|
||||||
return roles.includes(userRole) ? children : null;
|
return roles.includes(userRole) ? children : null;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,15 +11,15 @@ import CustomContainer from '../CustomContainer.jsx';
|
|||||||
import ContentWrapper from '../ContentWrapper.jsx';
|
import ContentWrapper from '../ContentWrapper.jsx';
|
||||||
|
|
||||||
import '../../css/LoginForm.css';
|
import '../../css/LoginForm.css';
|
||||||
|
import { CONSTANTS } from '../../util/constants.js';
|
||||||
|
|
||||||
const LoginForm = () => {
|
const LoginForm = () => {
|
||||||
const { login, error } = useContext(AuthContext);
|
const { login, error } = useContext(AuthContext);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const [formState, setFormState] = useState({
|
const [formState, setFormState] = useState({
|
||||||
emailOrUserName: "",
|
username: "",
|
||||||
password: "",
|
password: ""
|
||||||
keepLoggedIn: false
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleChange = (e) => {
|
const handleChange = (e) => {
|
||||||
@@ -30,19 +30,12 @@ const LoginForm = () => {
|
|||||||
const handleSubmit = async (e) => {
|
const handleSubmit = async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
const isEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formState.emailOrUserName);
|
|
||||||
|
|
||||||
const loginBody = {
|
const loginBody = {
|
||||||
|
username: formState.username,
|
||||||
password: formState.password,
|
password: formState.password,
|
||||||
keepLoggedIn: Boolean(formState.keepLoggedIn),
|
serviceId: CONSTANTS.SERVICE_ID
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isEmail) {
|
|
||||||
loginBody.email = formState.emailOrUserName;
|
|
||||||
} else {
|
|
||||||
loginBody.userName = formState.emailOrUserName;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await login(loginBody);
|
await login(loginBody);
|
||||||
navigate("/");
|
navigate("/");
|
||||||
@@ -63,15 +56,15 @@ const LoginForm = () => {
|
|||||||
label={
|
label={
|
||||||
<>
|
<>
|
||||||
<FontAwesomeIcon icon={faUser} className="me-2" />
|
<FontAwesomeIcon icon={faUser} className="me-2" />
|
||||||
Usuario o Email
|
Usuario
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Form.Control
|
<Form.Control
|
||||||
type="text"
|
type="text"
|
||||||
placeholder=""
|
placeholder=""
|
||||||
name="emailOrUserName"
|
name="username"
|
||||||
value={formState.emailOrUserName}
|
value={formState.username}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
className="rounded-4"
|
className="rounded-4"
|
||||||
/>
|
/>
|
||||||
@@ -83,7 +76,7 @@ const LoginForm = () => {
|
|||||||
name="password"
|
name="password"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="d-flex flex-column flex-sm-row justify-content-between align-items-center gap-2">
|
{/*<div className="d-flex flex-column flex-sm-row justify-content-between align-items-center gap-2">
|
||||||
<Form.Check
|
<Form.Check
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
name="keepLoggedIn"
|
name="keepLoggedIn"
|
||||||
@@ -92,10 +85,10 @@ const LoginForm = () => {
|
|||||||
value={formState.keepLoggedIn}
|
value={formState.keepLoggedIn}
|
||||||
onChange={(e) => { formState.keepLoggedIn = e.target.checked; setFormState({ ...formState }) }}
|
onChange={(e) => { formState.keepLoggedIn = e.target.checked; setFormState({ ...formState }) }}
|
||||||
/>
|
/>
|
||||||
{/*<Link disabled to="#" className="muted">
|
<Link disabled to="#" className="muted">
|
||||||
Olvidé mi contraseña
|
Olvidé mi contraseña
|
||||||
</Link>*/}
|
</Link>
|
||||||
</div>
|
</div>*/}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{error && (
|
{error && (
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ import { faSpinner } from "@fortawesome/free-solid-svg-icons";
|
|||||||
const ProtectedRoute = ({ minimumRoles, children }) => {
|
const ProtectedRoute = ({ minimumRoles, children }) => {
|
||||||
const { authStatus } = useAuth();
|
const { authStatus } = useAuth();
|
||||||
|
|
||||||
if (authStatus === "checking") return <FontAwesomeIcon icon={faSpinner} />; // o un loader si quieres
|
if (authStatus === "checking") return <FontAwesomeIcon icon={faSpinner} />;
|
||||||
if (authStatus === "unauthenticated") return <Navigate to="/login" replace />;
|
if (authStatus === "unauthenticated") return <Navigate to="/login" replace />;
|
||||||
if (authStatus === "authenticated" && minimumRoles) {
|
if (authStatus === "authenticated" && minimumRoles) {
|
||||||
const userRole = JSON.parse(localStorage.getItem("user"))?.role;
|
const userRole = JSON.parse(localStorage.getItem("identity"))?.metadata?.role;
|
||||||
if (!minimumRoles.includes(userRole)) return <Navigate to="/" replace />;
|
if (!minimumRoles.includes(userRole)) return <Navigate to="/" replace />;
|
||||||
}
|
}
|
||||||
return children;
|
return children;
|
||||||
|
|||||||
@@ -67,17 +67,17 @@ const formatCurrency = (value) =>
|
|||||||
|
|
||||||
export const BalancePDF = ({ balance }) => {
|
export const BalancePDF = ({ balance }) => {
|
||||||
const {
|
const {
|
||||||
initial_bank,
|
initialBank,
|
||||||
initial_cash,
|
initialCash,
|
||||||
total_bank_expenses,
|
totalBankExpenses,
|
||||||
total_cash_expenses,
|
totalCashExpenses,
|
||||||
total_bank_incomes,
|
totalBankIncomes,
|
||||||
total_cash_incomes,
|
totalCashIncomes,
|
||||||
created_at
|
createdAt
|
||||||
} = balance;
|
} = balance;
|
||||||
|
|
||||||
const final_bank = initial_bank + total_bank_incomes - total_bank_expenses;
|
const finalBank = initialBank + totalBankIncomes - totalBankExpenses;
|
||||||
const final_cash = initial_cash + total_cash_incomes - total_cash_expenses;
|
const finalCash = initialCash + totalCashIncomes - totalCashExpenses;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Document>
|
<Document>
|
||||||
@@ -91,22 +91,22 @@ export const BalancePDF = ({ balance }) => {
|
|||||||
</View>
|
</View>
|
||||||
|
|
||||||
<Text style={styles.sectionTitle}>Banco</Text>
|
<Text style={styles.sectionTitle}>Banco</Text>
|
||||||
<View style={styles.row}><Text style={styles.label}>Saldo inicial</Text><Text style={styles.value}>{formatCurrency(initial_bank)}</Text></View>
|
<View style={styles.row}><Text style={styles.label}>Saldo inicial</Text><Text style={styles.value}>{formatCurrency(initialBank)}</Text></View>
|
||||||
<View style={styles.row}><Text style={styles.label}>Ingresos</Text><Text style={styles.value}>{formatCurrency(total_bank_incomes)}</Text></View>
|
<View style={styles.row}><Text style={styles.label}>Ingresos</Text><Text style={styles.value}>{formatCurrency(totalBankIncomes)}</Text></View>
|
||||||
<View style={styles.row}><Text style={styles.label}>Gastos</Text><Text style={styles.value}>{formatCurrency(total_bank_expenses)}</Text></View>
|
<View style={styles.row}><Text style={styles.label}>Gastos</Text><Text style={styles.value}>{formatCurrency(totalBankExpenses)}</Text></View>
|
||||||
|
|
||||||
<Text style={styles.sectionTitle}>Caja</Text>
|
<Text style={styles.sectionTitle}>Caja</Text>
|
||||||
<View style={styles.row}><Text style={styles.label}>Saldo inicial</Text><Text style={styles.value}>{formatCurrency(initial_cash)}</Text></View>
|
<View style={styles.row}><Text style={styles.label}>Saldo inicial</Text><Text style={styles.value}>{formatCurrency(initialCash)}</Text></View>
|
||||||
<View style={styles.row}><Text style={styles.label}>Ingresos</Text><Text style={styles.value}>{formatCurrency(total_cash_incomes)}</Text></View>
|
<View style={styles.row}><Text style={styles.label}>Ingresos</Text><Text style={styles.value}>{formatCurrency(totalCashIncomes)}</Text></View>
|
||||||
<View style={styles.row}><Text style={styles.label}>Gastos</Text><Text style={styles.value}>{formatCurrency(total_cash_expenses)}</Text></View>
|
<View style={styles.row}><Text style={styles.label}>Gastos</Text><Text style={styles.value}>{formatCurrency(totalCashExpenses)}</Text></View>
|
||||||
|
|
||||||
<Text style={styles.sectionTitle}>Total</Text>
|
<Text style={styles.sectionTitle}>Total</Text>
|
||||||
<View style={styles.row}><Text style={styles.label}>Banco</Text><Text style={styles.value}>{formatCurrency(final_bank)}</Text></View>
|
<View style={styles.row}><Text style={styles.label}>Banco</Text><Text style={styles.value}>{formatCurrency(finalBank)}</Text></View>
|
||||||
<View style={styles.row}><Text style={styles.label}>Caja</Text><Text style={styles.value}>{formatCurrency(final_cash)}</Text></View>
|
<View style={styles.row}><Text style={styles.label}>Caja</Text><Text style={styles.value}>{formatCurrency(finalCash)}</Text></View>
|
||||||
<View style={styles.row}><Text style={styles.label}>Total</Text><Text style={styles.value}>{formatCurrency(final_bank + final_cash)}</Text></View>
|
<View style={styles.row}><Text style={styles.label}>Total</Text><Text style={styles.value}>{formatCurrency(finalBank + finalCash)}</Text></View>
|
||||||
|
|
||||||
<Text style={[styles.label, { marginTop: 20 }]}>
|
<Text style={[styles.label, { marginTop: 20 }]}>
|
||||||
Última actualización: {format(new Date(created_at), 'dd/MM/yyyy HH:mm')}
|
Última actualización: {format(new Date(createdAt), 'dd/MM/yyyy HH:mm')}
|
||||||
</Text>
|
</Text>
|
||||||
</Page>
|
</Page>
|
||||||
</Document>
|
</Document>
|
||||||
|
|||||||
@@ -24,17 +24,17 @@ const BalanceReport = ({ balance }) => {
|
|||||||
const closePDFModal = () => setShowPDF(false);
|
const closePDFModal = () => setShowPDF(false);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
initial_bank,
|
initialBank,
|
||||||
initial_cash,
|
initialCash,
|
||||||
total_bank_expenses,
|
totalBankExpenses,
|
||||||
total_cash_expenses,
|
totalCashExpenses,
|
||||||
total_bank_incomes,
|
totalBankIncomes,
|
||||||
total_cash_incomes,
|
totalCashIncomes,
|
||||||
created_at
|
createdAt
|
||||||
} = balance;
|
} = balance;
|
||||||
|
|
||||||
const final_bank = initial_bank + total_bank_incomes - total_bank_expenses;
|
const finalBank = initialBank + totalBankIncomes - totalBankExpenses;
|
||||||
const final_cash = initial_cash + total_cash_incomes - total_cash_expenses;
|
const finalCash = initialCash + totalCashIncomes - totalCashExpenses;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -56,20 +56,20 @@ const BalanceReport = ({ balance }) => {
|
|||||||
<Col md={6}>
|
<Col md={6}>
|
||||||
<div className="balance-box">
|
<div className="balance-box">
|
||||||
<h4><FontAwesomeIcon icon={faPiggyBank} className="me-2" />Banco</h4>
|
<h4><FontAwesomeIcon icon={faPiggyBank} className="me-2" />Banco</h4>
|
||||||
<p>Saldo inicial: <span className="balance-value">{formatCurrency(initial_bank)}</span></p>
|
<p>Saldo inicial: <span className="balance-value">{formatCurrency(initialBank)}</span></p>
|
||||||
<p><FontAwesomeIcon icon={faArrowUp} className="me-1 text-success" />Ingresos: <span className="balance-value">{formatCurrency(total_bank_incomes)}</span></p>
|
<p><FontAwesomeIcon icon={faArrowUp} className="me-1 text-success" />Ingresos: <span className="balance-value">{formatCurrency(totalBankIncomes)}</span></p>
|
||||||
<p><FontAwesomeIcon icon={faArrowDown} className="me-1 text-danger" />Gastos: <span className="balance-value">{formatCurrency(total_bank_expenses)}</span></p>
|
<p><FontAwesomeIcon icon={faArrowDown} className="me-1 text-danger" />Gastos: <span className="balance-value">{formatCurrency(totalBankExpenses)}</span></p>
|
||||||
<p className="fw-bold mt-3">💰 Saldo final: {formatCurrency(final_bank)}</p>
|
<p className="fw-bold mt-3">💰 Saldo final: {formatCurrency(finalBank)}</p>
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
<Col md={6}>
|
<Col md={6}>
|
||||||
<div className="balance-box">
|
<div className="balance-box">
|
||||||
<h4><FontAwesomeIcon icon={faCoins} className="me-2" />Caja</h4>
|
<h4><FontAwesomeIcon icon={faCoins} className="me-2" />Caja</h4>
|
||||||
<p>Saldo inicial: <span className="balance-value">{formatCurrency(initial_cash)}</span></p>
|
<p>Saldo inicial: <span className="balance-value">{formatCurrency(initialCash)}</span></p>
|
||||||
<p><FontAwesomeIcon icon={faArrowUp} className="me-1 text-success" />Ingresos: <span className="balance-value">{formatCurrency(total_cash_incomes)}</span></p>
|
<p><FontAwesomeIcon icon={faArrowUp} className="me-1 text-success" />Ingresos: <span className="balance-value">{formatCurrency(totalCashIncomes)}</span></p>
|
||||||
<p><FontAwesomeIcon icon={faArrowDown} className="me-1 text-danger" />Gastos: <span className="balance-value">{formatCurrency(total_cash_expenses)}</span></p>
|
<p><FontAwesomeIcon icon={faArrowDown} className="me-1 text-danger" />Gastos: <span className="balance-value">{formatCurrency(totalCashExpenses)}</span></p>
|
||||||
<p className="fw-bold mt-3">💵 Saldo final: {formatCurrency(final_cash)}</p>
|
<p className="fw-bold mt-3">💵 Saldo final: {formatCurrency(finalCash)}</p>
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
@@ -77,7 +77,7 @@ const BalanceReport = ({ balance }) => {
|
|||||||
<Row className="mt-4">
|
<Row className="mt-4">
|
||||||
<Col className="text-end balance-timestamp">
|
<Col className="text-end balance-timestamp">
|
||||||
<FontAwesomeIcon icon={faClock} className="me-2" />
|
<FontAwesomeIcon icon={faClock} className="me-2" />
|
||||||
Última actualización: {format(new Date(created_at), 'dd/MM/yyyy HH:mm')}
|
Última actualización: {format(new Date(createdAt), 'dd/MM/yyyy HH:mm')}
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -25,19 +25,19 @@ const File = ({ file, onDelete }) => {
|
|||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
className="file-card col-sm-3 col-lg-2 col-xxl-1 m-0 p-0 position-relative text-decoration-none bg-transparent"
|
className="file-card col-sm-3 col-lg-2 col-xxl-1 m-0 p-0 position-relative text-decoration-none bg-transparent"
|
||||||
onClick={() => window.open(`https://miarma.net/files/huertos/${file.file_name}`, "_blank")}
|
onClick={() => window.open(`https://miarma.net/files/huertos/${file.fileName}`, "_blank")}
|
||||||
>
|
>
|
||||||
<Card.Body className="text-center">
|
<Card.Body className="text-center">
|
||||||
<img
|
<img
|
||||||
src={getIcon(file.mime_type)}
|
src={getIcon(file.mimeType)}
|
||||||
alt={file.file_name}
|
alt={file.fileName}
|
||||||
className="img-fluid mb-2"
|
className="img-fluid mb-2"
|
||||||
/>
|
/>
|
||||||
<OverlayTrigger
|
<OverlayTrigger
|
||||||
placement="bottom"
|
placement="bottom"
|
||||||
overlay={<Tooltip>{file.file_name}</Tooltip>}
|
overlay={<Tooltip>{file.fileName}</Tooltip>}
|
||||||
>
|
>
|
||||||
<p className="m-0 p-0 text-truncate">{file.file_name}</p>
|
<p className="m-0 p-0 text-truncate">{file.fileName}</p>
|
||||||
</OverlayTrigger>
|
</OverlayTrigger>
|
||||||
</Card.Body>
|
</Card.Body>
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ const GastoCard = ({ gasto, isNew = false, onCreate, onUpdate, onDelete, onCance
|
|||||||
supplier: gasto.supplier || '',
|
supplier: gasto.supplier || '',
|
||||||
invoice: gasto.invoice || '',
|
invoice: gasto.invoice || '',
|
||||||
type: gasto.type ?? 0,
|
type: gasto.type ?? 0,
|
||||||
created_at: gasto.created_at?.slice(0, 16) || (isNew ? getNowAsLocalDatetime() : ''),
|
createdAt: gasto.createdAt?.slice(0, 16) || (isNew ? getNowAsLocalDatetime() : ''),
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -60,7 +60,7 @@ const GastoCard = ({ gasto, isNew = false, onCreate, onUpdate, onDelete, onCance
|
|||||||
supplier: gasto.supplier || '',
|
supplier: gasto.supplier || '',
|
||||||
invoice: gasto.invoice || '',
|
invoice: gasto.invoice || '',
|
||||||
type: gasto.type ?? 0,
|
type: gasto.type ?? 0,
|
||||||
created_at: gasto.created_at?.slice(0, 16) || (isNew ? getNowAsLocalDatetime() : ''),
|
createdAt: gasto.createdAt?.slice(0, 16) || (isNew ? getNowAsLocalDatetime() : ''),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
@@ -68,7 +68,7 @@ const GastoCard = ({ gasto, isNew = false, onCreate, onUpdate, onDelete, onCance
|
|||||||
|
|
||||||
const handleChange = (field, value) => setFormData(prev => ({ ...prev, [field]: value }));
|
const handleChange = (field, value) => setFormData(prev => ({ ...prev, [field]: value }));
|
||||||
|
|
||||||
const handleDelete = () => typeof onDelete === 'function' && onDelete(gasto.expense_id);
|
const handleDelete = () => typeof onDelete === 'function' && onDelete(gasto.expenseId);
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
if (onClearError) onClearError();
|
if (onClearError) onClearError();
|
||||||
@@ -80,7 +80,7 @@ const GastoCard = ({ gasto, isNew = false, onCreate, onUpdate, onDelete, onCance
|
|||||||
if (onClearError) onClearError();
|
if (onClearError) onClearError();
|
||||||
const newExpense = { ...gasto, ...formData };
|
const newExpense = { ...gasto, ...formData };
|
||||||
if (createMode && typeof onCreate === 'function') return onCreate(newExpense);
|
if (createMode && typeof onCreate === 'function') return onCreate(newExpense);
|
||||||
if (typeof onUpdate === 'function') return onUpdate(newExpense, gasto.expense_id);
|
if (typeof onUpdate === 'function') return onUpdate(newExpense, gasto.expenseId);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -102,13 +102,13 @@ const GastoCard = ({ gasto, isNew = false, onCreate, onUpdate, onDelete, onCance
|
|||||||
<small>
|
<small>
|
||||||
{editMode ? (
|
{editMode ? (
|
||||||
<SpanishDateTimePicker
|
<SpanishDateTimePicker
|
||||||
selected={new Date(formData.created_at)}
|
selected={new Date(formData.createdAt)}
|
||||||
onChange={(date) =>
|
onChange={(date) =>
|
||||||
handleChange('created_at', date.toISOString().slice(0, 16))
|
handleChange('createdAt', date.toISOString().slice(0, 16))
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
DateParser.isoToStringWithTime(formData.created_at)
|
DateParser.isoToStringWithTime(formData.createdAt)
|
||||||
)}
|
)}
|
||||||
</small>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ export const GastosPDF = ({ gastos }) => (
|
|||||||
{ borderBottomRightRadius: idx === gastos.length - 1 ? 10 : 0 },
|
{ borderBottomRightRadius: idx === gastos.length - 1 ? 10 : 0 },
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<Text style={[styles.cell, { flex: 2 }]}>{parseDate(gasto.created_at)}</Text>
|
<Text style={[styles.cell, { flex: 2 }]}>{parseDate(gasto.createdAt)}</Text>
|
||||||
<Text style={[styles.cell, { flex: 4 }]}>{gasto.concept}</Text>
|
<Text style={[styles.cell, { flex: 4 }]}>{gasto.concept}</Text>
|
||||||
<Text style={[styles.cell, { flex: 2 }]}>{gasto.amount.toFixed(2)} €</Text>
|
<Text style={[styles.cell, { flex: 2 }]}>{gasto.amount.toFixed(2)} €</Text>
|
||||||
<Text style={[styles.cell, { flex: 3 }]}>{gasto.supplier}</Text>
|
<Text style={[styles.cell, { flex: 3 }]}>{gasto.supplier}</Text>
|
||||||
|
|||||||
@@ -63,8 +63,8 @@ const IngresoCard = ({
|
|||||||
amount: income.amount || 0,
|
amount: income.amount || 0,
|
||||||
type: income.type ?? CONSTANTS.PAYMENT_TYPE_CASH,
|
type: income.type ?? CONSTANTS.PAYMENT_TYPE_CASH,
|
||||||
frequency: income.frequency ?? CONSTANTS.PAYMENT_FREQUENCY_YEARLY,
|
frequency: income.frequency ?? CONSTANTS.PAYMENT_FREQUENCY_YEARLY,
|
||||||
member_number: income.member_number,
|
memberNumber: income.memberNumber,
|
||||||
created_at: income.created_at?.slice(0, 16) || (isNew ? getNowAsLocalDatetime() : ''),
|
createdAt: income.createdAt?.slice(0, 16) || (isNew ? getNowAsLocalDatetime() : ''),
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -74,9 +74,9 @@ const IngresoCard = ({
|
|||||||
amount: income.amount || 0,
|
amount: income.amount || 0,
|
||||||
type: income.type ?? CONSTANTS.PAYMENT_TYPE_CASH,
|
type: income.type ?? CONSTANTS.PAYMENT_TYPE_CASH,
|
||||||
frequency: income.frequency ?? CONSTANTS.PAYMENT_FREQUENCY_YEARLY,
|
frequency: income.frequency ?? CONSTANTS.PAYMENT_FREQUENCY_YEARLY,
|
||||||
display_name: income.display_name,
|
displayName: income.displayName,
|
||||||
member_number: income.member_number,
|
memberNumber: income.memberNumber,
|
||||||
created_at: income.created_at?.slice(0, 16) || (isNew ? getNowAsLocalDatetime() : ''),
|
createdAt: income.createdAt?.slice(0, 16) || (isNew ? getNowAsLocalDatetime() : ''),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
@@ -95,14 +95,14 @@ const IngresoCard = ({
|
|||||||
if (onClearError) onClearError();
|
if (onClearError) onClearError();
|
||||||
const newIncome = { ...income, ...formData };
|
const newIncome = { ...income, ...formData };
|
||||||
if (createMode && typeof onCreate === 'function') return onCreate(newIncome);
|
if (createMode && typeof onCreate === 'function') return onCreate(newIncome);
|
||||||
if (typeof onUpdate === 'function') return onUpdate(newIncome, income.income_id);
|
if (typeof onUpdate === 'function') return onUpdate(newIncome, income.incomeId);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDelete = () => typeof onDelete === 'function' && onDelete(income.income_id);
|
const handleDelete = () => typeof onDelete === 'function' && onDelete(income.incomeId);
|
||||||
|
|
||||||
const uniqueMembers = Array.from(
|
const uniqueMembers = Array.from(
|
||||||
new Map(members.map(item => [item.member_number, item])).values()
|
new Map(members.map(item => [item.memberNumber, item])).values()
|
||||||
).sort((a, b) => a.member_number - b.member_number);
|
).sort((a, b) => a.memberNumber - b.memberNumber);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MotionCard className={`ingreso-card shadow-sm rounded-4 border-0 h-100 ${className}`}>
|
<MotionCard className={`ingreso-card shadow-sm rounded-4 border-0 h-100 ${className}`}>
|
||||||
@@ -125,13 +125,13 @@ const IngresoCard = ({
|
|||||||
<small>
|
<small>
|
||||||
{editMode ? (
|
{editMode ? (
|
||||||
<SpanishDateTimePicker
|
<SpanishDateTimePicker
|
||||||
selected={new Date(formData.created_at)}
|
selected={new Date(formData.createdAt)}
|
||||||
onChange={(date) =>
|
onChange={(date) =>
|
||||||
handleChange('created_at', date.toISOString().slice(0, 16))
|
handleChange('createdAt', date.toISOString().slice(0, 16))
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
DateParser.isoToStringWithTime(formData.created_at)
|
DateParser.isoToStringWithTime(formData.createdAt)
|
||||||
)}
|
)}
|
||||||
</small>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
@@ -167,13 +167,13 @@ const IngresoCard = ({
|
|||||||
<Form.Select
|
<Form.Select
|
||||||
className="themed-input"
|
className="themed-input"
|
||||||
size="sm"
|
size="sm"
|
||||||
value={formData.member_number}
|
value={formData.memberNumber}
|
||||||
onChange={(e) => handleChange('member_number', parseInt(e.target.value))}
|
onChange={(e) => handleChange('memberNumber', parseInt(e.target.value))}
|
||||||
style={{ maxWidth: '300px', display: 'inline-block' }}
|
style={{ maxWidth: '300px', display: 'inline-block' }}
|
||||||
>
|
>
|
||||||
{uniqueMembers.map((m) => (
|
{uniqueMembers.map((m) => (
|
||||||
<option key={m.member_number} value={m.member_number}>
|
<option key={m.memberNumber} value={m.memberNumber}>
|
||||||
{`${m.display_name} (${m.member_number})`}
|
{`${m.displayName} (${m.memberNumber})`}
|
||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</Form.Select>
|
</Form.Select>
|
||||||
@@ -187,24 +187,24 @@ const IngresoCard = ({
|
|||||||
disabled
|
disabled
|
||||||
size="sm"
|
size="sm"
|
||||||
type="text"
|
type="text"
|
||||||
value={`${formData.display_name || 'Socio'} (${formData.member_number})`}
|
value={`${formData.displayName || 'Socio'} (${formData.memberNumber})`}
|
||||||
style={{ maxWidth: '300px', display: 'inline-block' }}
|
style={{ maxWidth: '300px', display: 'inline-block' }}
|
||||||
/>
|
/>
|
||||||
</OverlayTrigger>
|
</OverlayTrigger>
|
||||||
) : (
|
) : (
|
||||||
formData.display_name ? (
|
formData.displayName ? (
|
||||||
<>
|
<>
|
||||||
<OverlayTrigger
|
<OverlayTrigger
|
||||||
placement="top"
|
placement="top"
|
||||||
overlay={<Tooltip>{formData.display_name}</Tooltip>}
|
overlay={<Tooltip>{formData.displayName}</Tooltip>}
|
||||||
>
|
>
|
||||||
<span className="text-truncate d-inline-block" style={{ maxWidth: '200px', verticalAlign: 'middle' }}>
|
<span className="text-truncate d-inline-block" style={{ maxWidth: '200px', verticalAlign: 'middle' }}>
|
||||||
{formData.display_name}
|
{formData.displayName}
|
||||||
</span>
|
</span>
|
||||||
</OverlayTrigger>
|
</OverlayTrigger>
|
||||||
({formData.member_number})
|
({formData.memberNumber})
|
||||||
</>
|
</>
|
||||||
) : formData.member_number
|
) : formData.memberNumber
|
||||||
)}
|
)}
|
||||||
</Card.Text>
|
</Card.Text>
|
||||||
|
|
||||||
|
|||||||
@@ -105,12 +105,12 @@ export const IngresosPDF = ({ ingresos }) => (
|
|||||||
{ borderBottomRightRadius: idx === ingresos.length - 1 ? 10 : 0 },
|
{ borderBottomRightRadius: idx === ingresos.length - 1 ? 10 : 0 },
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<Text style={[styles.cell, { flex: 1 }]}>{ing.member_number}</Text>
|
<Text style={[styles.cell, { flex: 1 }]}>{ing.memberNumber}</Text>
|
||||||
<Text style={[styles.cell, { flex: 3 }]}>{ing.concept}</Text>
|
<Text style={[styles.cell, { flex: 3 }]}>{ing.concept}</Text>
|
||||||
<Text style={[styles.cell, { flex: 1 }]}>{ing.amount.toFixed(2)} €</Text>
|
<Text style={[styles.cell, { flex: 1 }]}>{ing.amount.toFixed(2)} €</Text>
|
||||||
<Text style={[styles.cell, { flex: 1 }]}>{getTypeLabel(ing.type)}</Text>
|
<Text style={[styles.cell, { flex: 1 }]}>{getTypeLabel(ing.type)}</Text>
|
||||||
<Text style={[styles.cell, { flex: 1 }]}>{getFreqLabel(ing.frequency)}</Text>
|
<Text style={[styles.cell, { flex: 1 }]}>{getFreqLabel(ing.frequency)}</Text>
|
||||||
<Text style={[styles.cell, { flex: 2 }]}>{parseDate(ing.created_at)}</Text>
|
<Text style={[styles.cell, { flex: 2 }]}>{parseDate(ing.createdAt)}</Text>
|
||||||
</View>
|
</View>
|
||||||
))}
|
))}
|
||||||
</Page>
|
</Page>
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import AnimatedDropdown from '../AnimatedDropdown.jsx';
|
|||||||
import { CONSTANTS } from '../../util/constants.js';
|
import { CONSTANTS } from '../../util/constants.js';
|
||||||
|
|
||||||
const NavBar = () => {
|
const NavBar = () => {
|
||||||
const { user, logout } = useAuth();
|
const { identity, logout } = useAuth();
|
||||||
const [showingUserDropdown, setShowingUserDropdown] = useState(false);
|
const [showingUserDropdown, setShowingUserDropdown] = useState(false);
|
||||||
const [expanded, setExpanded] = useState(false);
|
const [expanded, setExpanded] = useState(false);
|
||||||
const [isLg, setIsLg] = useState(window.innerWidth >= 992);
|
const [isLg, setIsLg] = useState(window.innerWidth >= 992);
|
||||||
@@ -138,7 +138,7 @@ const NavBar = () => {
|
|||||||
onToggle={(isOpen) => setShowingUserDropdown(isOpen)}
|
onToggle={(isOpen) => setShowingUserDropdown(isOpen)}
|
||||||
trigger={
|
trigger={
|
||||||
<Link className="nav-link dropdown-toggle fw-bold">
|
<Link className="nav-link dropdown-toggle fw-bold">
|
||||||
@{user?.user_name}
|
@{identity?.account?.username}
|
||||||
</Link>
|
</Link>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -45,16 +45,16 @@ const renderDateField = (label, icon, dateValue, editMode, fieldKey, handleChang
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getFechas = (formData, editMode, handleChange) => {
|
const getFechas = (formData, editMode, handleChange) => {
|
||||||
const { created_at, assigned_at, deactivated_at } = formData;
|
const { createdAt, assignedAt, deactivatedAt } = formData;
|
||||||
|
|
||||||
// Si no hay fechas y no está en modo edición, no muestres nada
|
// Si no hay fechas y no está en modo edición, no muestres nada
|
||||||
if (!editMode && !created_at && !assigned_at && !deactivated_at) return null;
|
if (!editMode && !createdAt && !assignedAt && !deactivatedAt) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ListGroup className="mt-2 border-1 rounded-3 shadow-sm">
|
<ListGroup className="mt-2 border-1 rounded-3 shadow-sm">
|
||||||
{renderDateField("ALTA", faCalendar, created_at, editMode, "created_at", handleChange)}
|
{renderDateField("ALTA", faCalendar, createdAt, editMode, "createdAt", handleChange)}
|
||||||
{renderDateField("ENTREGA", faCalendar, assigned_at, editMode, "assigned_at", handleChange)}
|
{renderDateField("ENTREGA", faCalendar, assignedAt, editMode, "assignedAt", handleChange)}
|
||||||
{renderDateField("BAJA", faCalendar, deactivated_at, editMode, "deactivated_at", handleChange)}
|
{renderDateField("BAJA", faCalendar, deactivatedAt, editMode, "deactivatedAt", handleChange)}
|
||||||
</ListGroup>
|
</ListGroup>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -91,7 +91,7 @@ const getPFP = (tipo) => {
|
|||||||
|
|
||||||
const MotionCard = _motion.create(Card);
|
const MotionCard = _motion.create(Card);
|
||||||
|
|
||||||
const SocioCard = ({ socio, isNew = false, onCreate, onUpdate, onDelete, onCancel, onViewIncomes, error, onClearError, positionIfWaitlist }) => {
|
const SocioCard = ({ identity, isNew = false, onCreate, onUpdate, onDelete, onCancel, onViewIncomes, error, onClearError, positionIfWaitlist }) => {
|
||||||
const createMode = isNew;
|
const createMode = isNew;
|
||||||
const [editMode, setEditMode] = useState(isNew);
|
const [editMode, setEditMode] = useState(isNew);
|
||||||
const [showPassword, setShowPassword] = useState(false);
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
@@ -99,60 +99,59 @@ const SocioCard = ({ socio, isNew = false, onCreate, onUpdate, onDelete, onCance
|
|||||||
const { getData } = useDataContext();
|
const { getData } = useDataContext();
|
||||||
|
|
||||||
const [formData, setFormData] = useState({
|
const [formData, setFormData] = useState({
|
||||||
display_name: socio.display_name,
|
displayName: identity?.user.displayName,
|
||||||
user_name: socio.user_name,
|
userName: identity?.account.username,
|
||||||
email: socio.email || '',
|
email: identity?.account.email || '',
|
||||||
dni: socio.dni,
|
dni: identity?.metadata.dni,
|
||||||
phone: socio.phone,
|
phone: identity?.metadata.phone,
|
||||||
member_number: socio.member_number || latestNumber,
|
memberNumber: identity?.metadata.memberNumber || latestNumber,
|
||||||
plot_number: socio.plot_number,
|
plotNumber: identity?.metadata.plotNumber,
|
||||||
notes: socio.notes || '',
|
notes: identity?.metadata.notes || '',
|
||||||
status: socio.status,
|
status: identity?.account.status,
|
||||||
type: socio.type,
|
type: identity?.metadata.type,
|
||||||
created_at: socio.created_at?.slice(0, 16) || (isNew ? getNowAsLocalDatetime() : ''),
|
createdAt: identity?.metadata.createdAt?.slice(0, 16) || (isNew ? getNowAsLocalDatetime() : ''),
|
||||||
assigned_at: socio.assigned_at?.slice(0, 16) || undefined,
|
assignedAt: identity?.metadata.assignedAt?.slice(0, 16) || undefined,
|
||||||
deactivated_at: socio.deactivated_at?.slice(0, 16) || undefined,
|
deactivatedAt: identity?.metadata.deactivatedAt?.slice(0, 16) || undefined,
|
||||||
global_role: 0,
|
globalRole: 0,
|
||||||
password: createMode && !editMode ? generateSecurePassword() : null,
|
password: createMode && !editMode ? generateSecurePassword() : null,
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!editMode) {
|
if (!editMode) {
|
||||||
setFormData({
|
setFormData({
|
||||||
display_name: socio.display_name,
|
displayName: identity.user.displayName,
|
||||||
user_name: socio.user_name,
|
userName: identity.account.username,
|
||||||
email: socio.email || '',
|
email: identity.account.email || '',
|
||||||
dni: socio.dni,
|
dni: identity.metadata.dni,
|
||||||
phone: socio.phone,
|
phone: identity.metadata.phone,
|
||||||
member_number: socio.member_number,
|
memberNumber: identity.metadata.memberNumber,
|
||||||
plot_number: socio.plot_number,
|
plotNumber: identity.metadata.plotNumber,
|
||||||
notes: socio.notes || '',
|
notes: identity.metadata.notes || '',
|
||||||
status: socio.status,
|
status: identity.account.status,
|
||||||
type: socio.type,
|
type: identity.metadat.type,
|
||||||
created_at: socio.created_at?.slice(0, 16) || (isNew ? getNowAsLocalDatetime() : ''),
|
createdAt: identity.metadata.createdAt?.slice(0, 16) || (isNew ? getNowAsLocalDatetime() : ''),
|
||||||
assigned_at: socio.assigned_at?.slice(0, 16) || undefined,
|
assignedAt: identity.metadata.assignedAt?.slice(0, 16) || undefined,
|
||||||
deactivated_at: socio.deactivated_at?.slice(0, 16) || undefined,
|
deactivatedAt: identity.metadata.deactivatedAt?.slice(0, 16) || undefined,
|
||||||
global_role: 0,
|
globalRole: 0,
|
||||||
password: createMode ? generateSecurePassword() : ''
|
password: createMode ? generateSecurePassword() : ''
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [socio, editMode]);
|
}, [identity, editMode]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchLastNumber = async () => {
|
const fetchLastNumber = async () => {
|
||||||
try {
|
try {
|
||||||
if (!(createMode || editMode)) return;
|
if (!(createMode || editMode)) return;
|
||||||
|
|
||||||
const { data, error } = await getData("https://api.huertosbellavista.es/v1/members/latest-number");
|
const latestNumber = await getData("http://localhost:8081/v2/huertos/users/latest-number");
|
||||||
if (error) throw new Error(error);
|
|
||||||
|
|
||||||
const nuevoNumero = data.lastMemberNumber + 1;
|
const nuevoNumero = latestNumber + 1;
|
||||||
setLatestNumber(nuevoNumero);
|
setLatestNumber(nuevoNumero);
|
||||||
|
|
||||||
setFormData(prev => ({
|
setFormData(prev => ({
|
||||||
...prev,
|
...prev,
|
||||||
member_number: prev.member_number || nuevoNumero
|
memberNumber: prev.memberNumber || nuevoNumero
|
||||||
}));
|
}));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Error al obtener el número de socio:", err);
|
console.error("Error al obtener el número de socio:", err);
|
||||||
@@ -167,7 +166,7 @@ const SocioCard = ({ socio, isNew = false, onCreate, onUpdate, onDelete, onCance
|
|||||||
setEditMode(true);
|
setEditMode(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDelete = () => typeof onDelete === "function" && onDelete(socio.user_id);
|
const handleDelete = () => typeof onDelete === "function" && onDelete(identity.user.userId);
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
if (onClearError) onClearError();
|
if (onClearError) onClearError();
|
||||||
@@ -177,16 +176,16 @@ const SocioCard = ({ socio, isNew = false, onCreate, onUpdate, onDelete, onCance
|
|||||||
|
|
||||||
const handleSave = () => {
|
const handleSave = () => {
|
||||||
if (onClearError) onClearError();
|
if (onClearError) onClearError();
|
||||||
const newSocio = { ...socio, ...formData };
|
const newSocio = { ...identity, ...formData };
|
||||||
if (createMode && typeof onCreate === 'function') return onCreate(newSocio);
|
if (createMode && typeof onCreate === 'function') return onCreate(newSocio);
|
||||||
if (typeof onUpdate === 'function') return onUpdate(newSocio, socio.user_id);
|
if (typeof onUpdate === 'function') return onUpdate(newSocio, identity.user.userId);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleChange = (field, value) => {
|
const handleChange = (field, value) => {
|
||||||
if (["member_number"].includes(field)) {
|
if (["memberNumber"].includes(field)) {
|
||||||
value = value === "" ? latestNumber : parseInt(value);
|
value = value === "" ? latestNumber : parseInt(value);
|
||||||
}
|
}
|
||||||
if (field === "display_name") {
|
if (field === "displayName") {
|
||||||
value = value.toUpperCase();
|
value = value.toUpperCase();
|
||||||
}
|
}
|
||||||
if (field === "dni") {
|
if (field === "dni") {
|
||||||
@@ -196,7 +195,7 @@ const SocioCard = ({ socio, isNew = false, onCreate, onUpdate, onDelete, onCance
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleViewIncomes = () => {
|
const handleViewIncomes = () => {
|
||||||
onViewIncomes(socio.user_id);
|
onViewIncomes(identity.user.userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -206,7 +205,7 @@ const SocioCard = ({ socio, isNew = false, onCreate, onUpdate, onDelete, onCance
|
|||||||
{editMode ? (
|
{editMode ? (
|
||||||
<TipoSocioDropdown value={formData.type} onChange={(val) => handleChange('type', val)} />
|
<TipoSocioDropdown value={formData.type} onChange={(val) => handleChange('type', val)} />
|
||||||
) : (
|
) : (
|
||||||
positionIfWaitlist && socio.type === 0 ? (
|
positionIfWaitlist && identity.metadata.type === 0 ? (
|
||||||
<OverlayTrigger
|
<OverlayTrigger
|
||||||
placement="top"
|
placement="top"
|
||||||
overlay={
|
overlay={
|
||||||
@@ -225,8 +224,8 @@ const SocioCard = ({ socio, isNew = false, onCreate, onUpdate, onDelete, onCance
|
|||||||
<div className='d-flex flex-column gap-1'>
|
<div className='d-flex flex-column gap-1'>
|
||||||
<Card.Title className="m-0">
|
<Card.Title className="m-0">
|
||||||
{editMode ? (
|
{editMode ? (
|
||||||
<Form.Control className="themed-input" size="sm" value={formData.display_name} onChange={(e) => handleChange('display_name', e.target.value)} style={{ maxWidth: '220px' }} />
|
<Form.Control className="themed-input" size="sm" value={formData.displayName} onChange={(e) => handleChange('displayName', e.target.value)} style={{ maxWidth: '220px' }} />
|
||||||
) : formData.display_name}
|
) : formData.displayName}
|
||||||
</Card.Title>
|
</Card.Title>
|
||||||
{editMode ? (
|
{editMode ? (
|
||||||
<Form.Select className="themed-input" size="sm" value={formData.status} onChange={(e) => handleChange('status', parseInt(e.target.value))} style={{ maxWidth: '8rem' }}>
|
<Form.Select className="themed-input" size="sm" value={formData.status} onChange={(e) => handleChange('status', parseInt(e.target.value))} style={{ maxWidth: '8rem' }}>
|
||||||
@@ -269,9 +268,9 @@ const SocioCard = ({ socio, isNew = false, onCreate, onUpdate, onDelete, onCance
|
|||||||
{[{
|
{[{
|
||||||
label: 'DNI', clazz: '', icon: faIdCard, value: formData.dni, field: 'dni', type: 'text', maxWidth: '180px'
|
label: 'DNI', clazz: '', icon: faIdCard, value: formData.dni, field: 'dni', type: 'text', maxWidth: '180px'
|
||||||
}, {
|
}, {
|
||||||
label: 'SOCIO Nº', clazz: '', icon: faUser, value: formData.member_number || latestNumber, field: 'member_number', type: 'number', maxWidth: '100px'
|
label: 'SOCIO Nº', clazz: '', icon: faUser, value: formData.memberNumber || latestNumber, field: 'memberNumber', type: 'number', maxWidth: '100px'
|
||||||
}, {
|
}, {
|
||||||
label: 'HUERTO Nº', clazz: '', icon: faSunPlantWilt, value: formData.plot_number, field: 'plot_number', type: 'number', maxWidth: '100px'
|
label: 'HUERTO Nº', clazz: '', icon: faSunPlantWilt, value: formData.plotNumber, field: 'plotNumber', type: 'number', maxWidth: '100px'
|
||||||
}, {
|
}, {
|
||||||
label: 'TLF.', clazz: '', icon: faPhone, value: formData.phone, field: 'phone', type: 'number', maxWidth: '200px'
|
label: 'TLF.', clazz: '', icon: faPhone, value: formData.phone, field: 'phone', type: 'number', maxWidth: '200px'
|
||||||
}, {
|
}, {
|
||||||
|
|||||||
@@ -107,13 +107,13 @@ export const SociosPDF = ({ socios }) => (
|
|||||||
{ borderBottomRightRadius: idx === socios.length - 1 ? 10 : 0 },
|
{ borderBottomRightRadius: idx === socios.length - 1 ? 10 : 0 },
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<Text style={[styles.cell, { flex: 0.2 }]}>{socio?.member_number}</Text>
|
<Text style={[styles.cell, { flex: 0.2 }]}>{socio?.memberNumber}</Text>
|
||||||
<Text style={[styles.cell, { flex: 0.2 }]}>{socio?.plot_number}</Text>
|
<Text style={[styles.cell, { flex: 0.2 }]}>{socio?.plotNumber}</Text>
|
||||||
<Text style={[styles.cell, { flex: 3 }]}>{socio?.display_name}</Text>
|
<Text style={[styles.cell, { flex: 3 }]}>{socio?.displayName}</Text>
|
||||||
<Text style={[styles.cell, { flex: 1 }]}>{socio?.dni}</Text>
|
<Text style={[styles.cell, { flex: 1 }]}>{socio?.dni}</Text>
|
||||||
<Text style={[styles.cell, { flex: 1 }]}>{socio?.phone}</Text>
|
<Text style={[styles.cell, { flex: 1 }]}>{socio?.phone}</Text>
|
||||||
<Text style={[styles.cell, { flex: 3 }]}>{socio?.email || ''}</Text>
|
<Text style={[styles.cell, { flex: 3 }]}>{socio?.email || ''}</Text>
|
||||||
<Text style={[styles.cell, { flex: 1 }]}>{parseDate(socio?.created_at?.split('T')[0] || '')}</Text>
|
<Text style={[styles.cell, { flex: 1 }]}>{parseDate(socio?.createdAt?.split('T')[0] || '')}</Text>
|
||||||
<Text style={[styles.cell, { flex: 1 }]}>
|
<Text style={[styles.cell, { flex: 1 }]}>
|
||||||
{(() => {
|
{(() => {
|
||||||
switch (socio?.type) {
|
switch (socio?.type) {
|
||||||
|
|||||||
@@ -3,22 +3,25 @@ import { Form, Row, Col, Button } from 'react-bootstrap';
|
|||||||
import { useDataContext } from '../../hooks/useDataContext';
|
import { useDataContext } from '../../hooks/useDataContext';
|
||||||
import { Alert } from 'react-bootstrap';
|
import { Alert } from 'react-bootstrap';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
import { generateSecurePassword } from '../../util/passwordGenerator';
|
||||||
|
|
||||||
|
|
||||||
const PreUserForm = ({ onSubmit, userType, plotNumber, errors = {} }) => {
|
const PreUserForm = ({ onSubmit, userType, plotNumber, errors = {} }) => {
|
||||||
const { getData } = useDataContext();
|
const { getData } = useDataContext();
|
||||||
const fetchedOnce = useRef(false);
|
const fetchedOnce = useRef(false);
|
||||||
|
|
||||||
const [form, setForm] = useState({
|
const [form, setForm] = useState({
|
||||||
user_name: '',
|
userName: '',
|
||||||
display_name: '',
|
password: generateSecurePassword(8),
|
||||||
|
displayName: '',
|
||||||
dni: '',
|
dni: '',
|
||||||
phone: '',
|
phone: '',
|
||||||
email: '',
|
email: '',
|
||||||
address: '',
|
address: '',
|
||||||
zip_code: '',
|
zipCode: '',
|
||||||
city: '',
|
city: '',
|
||||||
member_number: '',
|
memberNumber: '',
|
||||||
plot_number: plotNumber,
|
plotNumber: plotNumber,
|
||||||
type: userType,
|
type: userType,
|
||||||
status: 1,
|
status: 1,
|
||||||
role: 0
|
role: 0
|
||||||
@@ -30,12 +33,10 @@ const PreUserForm = ({ onSubmit, userType, plotNumber, errors = {} }) => {
|
|||||||
fetchedOnce.current = true;
|
fetchedOnce.current = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { data, error } = await getData("https://api.huertosbellavista.es/v1/members/latest-number");
|
const latestNumber = await getData("http://localhost:8081/v2/huertos/users/latest-number");
|
||||||
if (error) throw new Error(error);
|
|
||||||
|
|
||||||
setForm((prev) => ({
|
setForm((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
member_number: data.lastMemberNumber + 1
|
memberNumber: latestNumber + 1
|
||||||
}));
|
}));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Error al obtener el número de socio:", err);
|
console.error("Error al obtener el número de socio:", err);
|
||||||
@@ -47,21 +48,21 @@ const PreUserForm = ({ onSubmit, userType, plotNumber, errors = {} }) => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const trimmedName = form.display_name?.trim() ?? "";
|
const trimmedName = form.displayName?.trim() ?? "";
|
||||||
|
|
||||||
const nuevoUsername = trimmedName
|
const nuevoUsername = trimmedName
|
||||||
? trimmedName.split(' ')[0].toLowerCase() : "";
|
? trimmedName.split(' ')[0].toLowerCase() : "";
|
||||||
|
|
||||||
if (form.user_name !== nuevoUsername) {
|
if (form.userName !== nuevoUsername) {
|
||||||
setForm(prev => ({ ...prev, user_name: nuevoUsername }));
|
setForm(prev => ({ ...prev, userName: nuevoUsername }));
|
||||||
}
|
}
|
||||||
}, [form.member_number, form.display_name, form.user_name]);
|
}, [form.memberNumber, form.displayName, form.userName]);
|
||||||
|
|
||||||
const handleChange = (e) => {
|
const handleChange = (e) => {
|
||||||
const { name, value, type } = e.target;
|
const { name, value, type } = e.target;
|
||||||
let updatedValue = value;
|
let updatedValue = value;
|
||||||
|
|
||||||
if (name === 'display_name' || name === 'dni') {
|
if (name === 'displayName' || name === 'dni') {
|
||||||
updatedValue = value.toUpperCase();
|
updatedValue = value.toUpperCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,13 +85,13 @@ const PreUserForm = ({ onSubmit, userType, plotNumber, errors = {} }) => {
|
|||||||
<Row className="gy-3">
|
<Row className="gy-3">
|
||||||
|
|
||||||
{[
|
{[
|
||||||
{ label: 'Nombre completo', name: 'display_name', type: 'text', required: true },
|
{ label: 'Nombre completo', name: 'displayName', type: 'text', required: true },
|
||||||
{ label: 'Nombre de usuario', name: 'user_name', type: 'text', required: true },
|
{ label: 'Nombre de usuario', name: 'userName', type: 'text', required: true },
|
||||||
{ label: 'DNI', name: 'dni', type: 'text', required: true, maxLength: 9 },
|
{ label: 'DNI', name: 'dni', type: 'text', required: true, maxLength: 9 },
|
||||||
{ label: 'Teléfono', name: 'phone', type: 'tel', required: true },
|
{ label: 'Teléfono', name: 'phone', type: 'tel', required: true },
|
||||||
{ label: 'Correo electrónico', name: 'email', type: 'email', required: true },
|
{ label: 'Correo electrónico', name: 'email', type: 'email', required: true },
|
||||||
{ label: 'Domicilio', name: 'address', type: 'text' },
|
{ label: 'Domicilio', name: 'address', type: 'text' },
|
||||||
{ label: 'Código Postal', name: 'zip_code', type: 'text' },
|
{ label: 'Código Postal', name: 'zipCode', type: 'text' },
|
||||||
{ label: 'Ciudad', name: 'city', type: 'text' }
|
{ label: 'Ciudad', name: 'city', type: 'text' }
|
||||||
].map(({ label, name, type, required, maxLength }) => (
|
].map(({ label, name, type, required, maxLength }) => (
|
||||||
<Col md={4} key={name}>
|
<Col md={4} key={name}>
|
||||||
@@ -120,8 +121,8 @@ const PreUserForm = ({ onSubmit, userType, plotNumber, errors = {} }) => {
|
|||||||
className="shadow-sm"
|
className="shadow-sm"
|
||||||
disabled
|
disabled
|
||||||
type="number"
|
type="number"
|
||||||
name="member_number"
|
name="memberNumber"
|
||||||
value={form.member_number}
|
value={form.memberNumber}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
/>
|
/>
|
||||||
</Form.Group>
|
</Form.Group>
|
||||||
|
|||||||
@@ -35,15 +35,15 @@ const getPFP = (tipo) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const renderDescripcionSolicitud = (data, onProfile) => {
|
const renderDescripcionSolicitud = (data, onProfile) => {
|
||||||
const { request_type, request_status, requested_by_name, pre_display_name } = data;
|
const { type, status, requestedByName, preDisplayName } = data;
|
||||||
|
|
||||||
switch (request_type) {
|
switch (type) {
|
||||||
case 0:
|
case 0:
|
||||||
if (requested_by_name) {
|
if (requestedByName) {
|
||||||
return `${requested_by_name} quiere darse de alta.`;
|
return `${requestedByName} quiere darse de alta.`;
|
||||||
} else if (request_status !== 1 && pre_display_name) {
|
} else if (status !== 1 && preDisplayName) {
|
||||||
return `${pre_display_name} quiere darse de alta.`;
|
return `${preDisplayName} quiere darse de alta.`;
|
||||||
} else if (request_status !== 1) {
|
} else if (status !== 1) {
|
||||||
return `Alguien quiere darse de alta.`;
|
return `Alguien quiere darse de alta.`;
|
||||||
} else {
|
} else {
|
||||||
return `Se ha aceptado esta solicitud de alta.`;
|
return `Se ha aceptado esta solicitud de alta.`;
|
||||||
@@ -52,30 +52,30 @@ const renderDescripcionSolicitud = (data, onProfile) => {
|
|||||||
case 1:
|
case 1:
|
||||||
return onProfile
|
return onProfile
|
||||||
? "Has solicitado darte de baja."
|
? "Has solicitado darte de baja."
|
||||||
: requested_by_name
|
: requestedByName
|
||||||
? `${requested_by_name} quiere darse de baja.`
|
? `${requestedByName} quiere darse de baja.`
|
||||||
: request_status !== 1
|
: status !== 1
|
||||||
? `Alguien quiere darse de baja.`
|
? `Alguien quiere darse de baja.`
|
||||||
: `Se ha aceptado esta solicitud de baja.`;
|
: `Se ha aceptado esta solicitud de baja.`;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
if (onProfile) {
|
if (onProfile) {
|
||||||
switch (request_status) {
|
switch (status) {
|
||||||
case 0: return "Has solicitado añadir un colaborador.";
|
case 0: return "Has solicitado añadir un colaborador.";
|
||||||
case 1: return "Tu solicitud de colaborador ha sido aceptada.";
|
case 1: return "Tu solicitud de colaborador ha sido aceptada.";
|
||||||
case 2: return "Tu solicitud de colaborador ha sido rechazada.";
|
case 2: return "Tu solicitud de colaborador ha sido rechazada.";
|
||||||
default: return "Solicitud de colaborador desconocida.";
|
default: return "Solicitud de colaborador desconocida.";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch (request_status) {
|
switch (status) {
|
||||||
case 0:
|
case 0:
|
||||||
return requested_by_name
|
return requestedByName
|
||||||
? `${requested_by_name} quiere añadir a ${pre_display_name || "un colaborador"} como colaborador.`
|
? `${requestedByName} quiere añadir a ${preDisplayName || "un colaborador"} como colaborador.`
|
||||||
: `Alguien quiere añadir a ${pre_display_name || "un colaborador"} como colaborador.`;
|
: `Alguien quiere añadir a ${preDisplayName || "un colaborador"} como colaborador.`;
|
||||||
case 1:
|
case 1:
|
||||||
return `La solicitud de colaborador de ${requested_by_name || "alguien"} ha sido aceptada.`;
|
return `La solicitud de colaborador de ${requestedByName || "alguien"} ha sido aceptada.`;
|
||||||
case 2:
|
case 2:
|
||||||
return `La solicitud de colaborador de ${requested_by_name || "alguien"} ha sido rechazada.`;
|
return `La solicitud de colaborador de ${requestedByName || "alguien"} ha sido rechazada.`;
|
||||||
default:
|
default:
|
||||||
return "Solicitud de colaborador desconocida.";
|
return "Solicitud de colaborador desconocida.";
|
||||||
}
|
}
|
||||||
@@ -84,27 +84,27 @@ const renderDescripcionSolicitud = (data, onProfile) => {
|
|||||||
case 3:
|
case 3:
|
||||||
return onProfile
|
return onProfile
|
||||||
? "Has solicitado quitar tu colaborador."
|
? "Has solicitado quitar tu colaborador."
|
||||||
: requested_by_name
|
: requestedByName
|
||||||
? `${requested_by_name} quiere quitar su colaborador.`
|
? `${requestedByName} quiere quitar su colaborador.`
|
||||||
: request_status !== 1
|
: status !== 1
|
||||||
? `Alguien quiere quitar su colaborador.`
|
? `Alguien quiere quitar su colaborador.`
|
||||||
: `Se ha aceptado esta solicitud de baja de colaborador.`;
|
: `Se ha aceptado esta solicitud de baja de colaborador.`;
|
||||||
|
|
||||||
case 4:
|
case 4:
|
||||||
return onProfile
|
return onProfile
|
||||||
? "Has solicitado una parcela en el invernadero."
|
? "Has solicitado una parcela en el invernadero."
|
||||||
: requested_by_name
|
: requestedByName
|
||||||
? `${requested_by_name} quiere una parcela en el invernadero.`
|
? `${requestedByName} quiere una parcela en el invernadero.`
|
||||||
: request_status !== 1
|
: status !== 1
|
||||||
? `Alguien quiere una parcela en el invernadero.`
|
? `Alguien quiere una parcela en el invernadero.`
|
||||||
: `Se ha aceptado esta solicitud de parcela en el invernadero.`;
|
: `Se ha aceptado esta solicitud de parcela en el invernadero.`;
|
||||||
|
|
||||||
case 5:
|
case 5:
|
||||||
return onProfile
|
return onProfile
|
||||||
? "Has solicitado dejar tu parcela del invernadero."
|
? "Has solicitado dejar tu parcela del invernadero."
|
||||||
: requested_by_name
|
: requestedByName
|
||||||
? `${requested_by_name} quiere dejar su parcela del invernadero.`
|
? `${requestedByName} quiere dejar su parcela del invernadero.`
|
||||||
: request_status !== 1
|
: status !== 1
|
||||||
? `Alguien quiere dejar su parcela del invernadero.`
|
? `Alguien quiere dejar su parcela del invernadero.`
|
||||||
: `Se ha aceptado esta solicitud de salida del invernadero.`;
|
: `Se ha aceptado esta solicitud de salida del invernadero.`;
|
||||||
|
|
||||||
@@ -114,18 +114,18 @@ const renderDescripcionSolicitud = (data, onProfile) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const SolicitudCard = ({ data, onAccept, onReject, onDelete, editable = true, onProfile = false }) => {
|
const SolicitudCard = ({ data, onAccept, onReject, onDelete, editable = true, onProfile = false }) => {
|
||||||
const handleDelete = () => typeof onDelete === "function" && onDelete(data.request_id);
|
const handleDelete = () => typeof onDelete === "function" && onDelete(data.requestId);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MotionCard className="solicitud-card shadow-sm rounded-4 h-100">
|
<MotionCard className="solicitud-card shadow-sm rounded-4 h-100">
|
||||||
<Card.Header className="rounded-top-4 d-flex justify-content-between align-items-center">
|
<Card.Header className="rounded-top-4 d-flex justify-content-between align-items-center">
|
||||||
<div className="d-flex align-items-center">
|
<div className="d-flex align-items-center">
|
||||||
<img src={getPFP(data.pre_type)} width="36" className="rounded me-3" alt="PFP" />
|
<img src={getPFP(data.preType)} width="36" className="rounded me-3" alt="PFP" />
|
||||||
<div>
|
<div>
|
||||||
<Card.Title className="mb-0">
|
<Card.Title className="mb-0">
|
||||||
Solicitud #{data.request_id} - {getTipoSolicitud(data.request_type)}
|
Solicitud #{data.requestId} - {getTipoSolicitud(data.type)}
|
||||||
</Card.Title>
|
</Card.Title>
|
||||||
<small className='state-small'>Estado: <strong>{getEstadoSolicitud(data.request_status)}</strong></small>
|
<small className='state-small'>Estado: <strong>{getEstadoSolicitud(data.status)}</strong></small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -147,7 +147,7 @@ const SolicitudCard = ({ data, onAccept, onReject, onDelete, editable = true, on
|
|||||||
<ListGroup variant="flush" className="border rounded-3 mb-3">
|
<ListGroup variant="flush" className="border rounded-3 mb-3">
|
||||||
<ListGroup.Item>
|
<ListGroup.Item>
|
||||||
<FontAwesomeIcon icon={faCalendar} className="me-2" />
|
<FontAwesomeIcon icon={faCalendar} className="me-2" />
|
||||||
Fecha de solicitud: <strong>{parseDate(data.request_created_at)}</strong>
|
Fecha de solicitud: <strong>{parseDate(data.request_createdAt)}</strong>
|
||||||
</ListGroup.Item>
|
</ListGroup.Item>
|
||||||
</ListGroup>
|
</ListGroup>
|
||||||
|
|
||||||
@@ -157,24 +157,24 @@ const SolicitudCard = ({ data, onAccept, onReject, onDelete, editable = true, on
|
|||||||
</ListGroup.Item>
|
</ListGroup.Item>
|
||||||
</ListGroup>
|
</ListGroup>
|
||||||
|
|
||||||
{data.pre_display_name && (
|
{data.preDisplayName && (
|
||||||
<>
|
<>
|
||||||
<Card.Subtitle className="card-subtitle mt-3 mb-2">Datos del futuro socio</Card.Subtitle>
|
<Card.Subtitle className="card-subtitle mt-3 mb-2">Datos del futuro socio</Card.Subtitle>
|
||||||
<ListGroup variant="flush" className="border rounded-3">
|
<ListGroup variant="flush" className="border rounded-3">
|
||||||
<ListGroup.Item><FontAwesomeIcon icon={faUser} className="me-2" />Nombre: <strong>{data.pre_display_name}</strong></ListGroup.Item>
|
<ListGroup.Item><FontAwesomeIcon icon={faUser} className="me-2" />Nombre: <strong>{data.preDisplayName}</strong></ListGroup.Item>
|
||||||
<ListGroup.Item><FontAwesomeIcon icon={faIdCard} className="me-2" />DNI: <strong>{data.pre_dni}</strong></ListGroup.Item>
|
<ListGroup.Item><FontAwesomeIcon icon={faIdCard} className="me-2" />DNI: <strong>{data.preDni}</strong></ListGroup.Item>
|
||||||
<ListGroup.Item><FontAwesomeIcon icon={faPhone} className="me-2" />Teléfono: <strong>{data.pre_phone}</strong></ListGroup.Item>
|
<ListGroup.Item><FontAwesomeIcon icon={faPhone} className="me-2" />Teléfono: <strong>{data.prePhone}</strong></ListGroup.Item>
|
||||||
<ListGroup.Item><FontAwesomeIcon icon={faEnvelope} className="me-2" />Email: <strong>{data.pre_email}</strong></ListGroup.Item>
|
<ListGroup.Item><FontAwesomeIcon icon={faEnvelope} className="me-2" />Email: <strong>{data.preEmail}</strong></ListGroup.Item>
|
||||||
<ListGroup.Item><FontAwesomeIcon icon={faHome} className="me-2" />Dirección: <strong>{data.pre_address ?? 'NO'}</strong></ListGroup.Item>
|
<ListGroup.Item><FontAwesomeIcon icon={faHome} className="me-2" />Dirección: <strong>{data.preAddress ?? 'NO'}</strong></ListGroup.Item>
|
||||||
<ListGroup.Item><FontAwesomeIcon icon={faMapMarkerAlt} className="me-2" />Ciudad: <strong>{data.pre_city ?? 'NO'} ({data.pre_zip_code ?? 'NO'})</strong></ListGroup.Item>
|
<ListGroup.Item><FontAwesomeIcon icon={faMapMarkerAlt} className="me-2" />Ciudad: <strong>{data.preCity ?? 'NO'} ({data.preZipCode ?? 'NO'})</strong></ListGroup.Item>
|
||||||
<ListGroup.Item><FontAwesomeIcon icon={faHashtag} className="me-2" />Nº socio: <strong>{data.pre_member_number ?? 'NO'}</strong> | Nº huerto: <strong>{data.pre_plot_number ?? 'NO'}</strong></ListGroup.Item>
|
<ListGroup.Item><FontAwesomeIcon icon={faHashtag} className="me-2" />Nº socio: <strong>{data.preMemberNumber ?? 'NO'}</strong> | Nº huerto: <strong>{data.prePlotNumber ?? 'NO'}</strong></ListGroup.Item>
|
||||||
<ListGroup.Item><FontAwesomeIcon icon={faSeedling} className="me-2" />Tipo: <strong>{['Lista de Espera', 'Hortelano', 'Hortelano + Invernadero', 'Colaborador'][data.pre_type]}</strong></ListGroup.Item>
|
<ListGroup.Item><FontAwesomeIcon icon={faSeedling} className="me-2" />Tipo: <strong>{['Lista de Espera', 'Hortelano', 'Hortelano + Invernadero', 'Colaborador'][data.preType]}</strong></ListGroup.Item>
|
||||||
<ListGroup.Item><FontAwesomeIcon icon={faUserShield} className="me-2" />Rol: <strong>{['Usuario', 'Admin', 'Desarrollador'][data.pre_role]}</strong></ListGroup.Item>
|
<ListGroup.Item><FontAwesomeIcon icon={faUserShield} className="me-2" />Rol: <strong>{['Usuario', 'Admin', 'Desarrollador'][data.preRole]}</strong></ListGroup.Item>
|
||||||
</ListGroup>
|
</ListGroup>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{editable && data.request_status === 0 && (
|
{editable && data.status === 0 && (
|
||||||
<div className="d-flex justify-content-end gap-2 mt-3">
|
<div className="d-flex justify-content-end gap-2 mt-3">
|
||||||
<Button variant="danger" size="sm" onClick={() => onReject?.(data)}>Rechazar</Button>
|
<Button variant="danger" size="sm" onClick={() => onReject?.(data)}>Rechazar</Button>
|
||||||
<Button variant="success" size="sm" onClick={() => onAccept?.(data)}>Aceptar</Button>
|
<Button variant="success" size="sm" onClick={() => onAccept?.(data)}>Aceptar</Button>
|
||||||
|
|||||||
@@ -8,8 +8,12 @@ export const AuthProvider = ({ children }) => {
|
|||||||
const axios = createAxiosInstance();
|
const axios = createAxiosInstance();
|
||||||
const { config } = useConfig();
|
const { config } = useConfig();
|
||||||
|
|
||||||
const [user, setUser] = useState(() => JSON.parse(localStorage.getItem("user")) || null);
|
|
||||||
const [token, setToken] = useState(() => localStorage.getItem("token"));
|
const [token, setToken] = useState(() => localStorage.getItem("token"));
|
||||||
|
const [identity, setIdentity] = useState(() => {
|
||||||
|
const stored = localStorage.getItem("identity");
|
||||||
|
return stored ? JSON.parse(stored) : null;
|
||||||
|
});
|
||||||
|
|
||||||
const [authStatus, setAuthStatus] = useState("checking");
|
const [authStatus, setAuthStatus] = useState("checking");
|
||||||
const [error, setError] = useState(null);
|
const [error, setError] = useState(null);
|
||||||
|
|
||||||
@@ -21,7 +25,7 @@ export const AuthProvider = ({ children }) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const BASE_URL = config.apiConfig.baseUrl;
|
const BASE_URL = config.apiConfig.coreUrl;
|
||||||
const VALIDATE_URL = `${BASE_URL}${config.apiConfig.endpoints.auth.validateToken}`;
|
const VALIDATE_URL = `${BASE_URL}${config.apiConfig.endpoints.auth.validateToken}`;
|
||||||
|
|
||||||
const checkAuth = async () => {
|
const checkAuth = async () => {
|
||||||
@@ -29,6 +33,7 @@ export const AuthProvider = ({ children }) => {
|
|||||||
const res = await axios.get(VALIDATE_URL, {
|
const res = await axios.get(VALIDATE_URL, {
|
||||||
headers: { Authorization: `Bearer ${token}` },
|
headers: { Authorization: `Bearer ${token}` },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
setAuthStatus("authenticated");
|
setAuthStatus("authenticated");
|
||||||
} else {
|
} else {
|
||||||
@@ -45,19 +50,26 @@ export const AuthProvider = ({ children }) => {
|
|||||||
|
|
||||||
const login = async (formData) => {
|
const login = async (formData) => {
|
||||||
setError(null);
|
setError(null);
|
||||||
|
|
||||||
const BASE_URL = config.apiConfig.baseUrl;
|
const BASE_URL = config.apiConfig.baseUrl;
|
||||||
const LOGIN_URL = `${BASE_URL}${config.apiConfig.endpoints.auth.login}`;
|
const LOGIN_URL = `${BASE_URL}${config.apiConfig.endpoints.auth.login}`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await axios.post(LOGIN_URL, formData);
|
const res = await axios.post(LOGIN_URL, formData);
|
||||||
const { token, member, tokenTime } = res.data.data;
|
|
||||||
|
const { token, user, account, metadata } = res.data;
|
||||||
|
|
||||||
|
const identity = {
|
||||||
|
user,
|
||||||
|
account,
|
||||||
|
metadata,
|
||||||
|
};
|
||||||
|
|
||||||
localStorage.setItem("token", token);
|
localStorage.setItem("token", token);
|
||||||
localStorage.setItem("user", JSON.stringify(member));
|
localStorage.setItem("identity", JSON.stringify(identity));
|
||||||
localStorage.setItem("tokenTime", tokenTime);
|
|
||||||
|
|
||||||
setToken(token);
|
setToken(token);
|
||||||
setUser(member);
|
setIdentity(identity);
|
||||||
setAuthStatus("authenticated");
|
setAuthStatus("authenticated");
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Error al iniciar sesión:", err);
|
console.error("Error al iniciar sesión:", err);
|
||||||
@@ -70,7 +82,7 @@ export const AuthProvider = ({ children }) => {
|
|||||||
if (status === 400) {
|
if (status === 400) {
|
||||||
message = "Usuario o contraseña incorrectos.";
|
message = "Usuario o contraseña incorrectos.";
|
||||||
} else if (status === 403) {
|
} else if (status === 403) {
|
||||||
message = "Tu cuenta está inactiva o ha sido suspendida.";
|
message = "Tu cuenta está inactiva o suspendida.";
|
||||||
} else if (status === 404) {
|
} else if (status === 404) {
|
||||||
message = "Usuario no encontrado.";
|
message = "Usuario no encontrado.";
|
||||||
} else if (data?.message) {
|
} else if (data?.message) {
|
||||||
@@ -84,14 +96,24 @@ export const AuthProvider = ({ children }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const logout = () => {
|
const logout = () => {
|
||||||
localStorage.clear();
|
localStorage.removeItem("token");
|
||||||
setUser(null);
|
localStorage.removeItem("identity");
|
||||||
|
setIdentity(null);
|
||||||
setToken(null);
|
setToken(null);
|
||||||
setAuthStatus("unauthenticated");
|
setAuthStatus("unauthenticated");
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AuthContext.Provider value={{ user, token, authStatus, login, logout, error }}>
|
<AuthContext.Provider
|
||||||
|
value={{
|
||||||
|
identity, // { user, account, metadata }
|
||||||
|
token,
|
||||||
|
authStatus,
|
||||||
|
login,
|
||||||
|
logout,
|
||||||
|
error,
|
||||||
|
}}
|
||||||
|
>
|
||||||
{children}
|
{children}
|
||||||
</AuthContext.Provider>
|
</AuthContext.Provider>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -30,9 +30,9 @@ export const useData = (config) => {
|
|||||||
headers: getAuthHeaders(),
|
headers: getAuthHeaders(),
|
||||||
params: current.params,
|
params: current.params,
|
||||||
});
|
});
|
||||||
setData(response.data.data);
|
setData(response.data);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setError(err.response?.data?.message || err.message);
|
setError(err.response?.data);
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
@@ -45,18 +45,11 @@ export const useData = (config) => {
|
|||||||
}, [config, fetchData]);
|
}, [config, fetchData]);
|
||||||
|
|
||||||
const getData = async (url, params = {}) => {
|
const getData = async (url, params = {}) => {
|
||||||
try {
|
const response = await axios.get(url, {
|
||||||
const response = await axios.get(url, {
|
headers: getAuthHeaders(),
|
||||||
headers: getAuthHeaders(),
|
params,
|
||||||
params,
|
});
|
||||||
});
|
return response.data;
|
||||||
return { data: response.data.data, error: null };
|
|
||||||
} catch (err) {
|
|
||||||
return {
|
|
||||||
data: null,
|
|
||||||
error: err.response?.data?.message || err.message,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const postData = async (endpoint, payload) => {
|
const postData = async (endpoint, payload) => {
|
||||||
@@ -66,28 +59,24 @@ export const useData = (config) => {
|
|||||||
};
|
};
|
||||||
const response = await axios.post(endpoint, payload, { headers });
|
const response = await axios.post(endpoint, payload, { headers });
|
||||||
await fetchData();
|
await fetchData();
|
||||||
return response.data.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
const postDataValidated = async (endpoint, payload) => {
|
const postDataValidated = async (endpoint, payload) => {
|
||||||
try {
|
try {
|
||||||
const headers = {
|
const response = await axios.post(endpoint, payload, {
|
||||||
Authorization: `Bearer ${localStorage.getItem("token")}`,
|
headers: {
|
||||||
...(payload instanceof FormData ? {} : { "Content-Type": "application/json" }),
|
Authorization: `Bearer ${localStorage.getItem("token")}`,
|
||||||
};
|
"Content-Type": "application/json",
|
||||||
const response = await axios.post(endpoint, payload, { headers });
|
},
|
||||||
return { data: response.data.data, errors: null };
|
});
|
||||||
|
|
||||||
|
return { ok: true };
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const raw = err.response?.data?.message;
|
return {
|
||||||
let parsed = {};
|
ok: false,
|
||||||
|
errors: err.response?.data?.errors || {}
|
||||||
try {
|
};
|
||||||
parsed = JSON.parse(raw);
|
|
||||||
} catch {
|
|
||||||
return { data: null, errors: { general: raw || err.message } };
|
|
||||||
}
|
|
||||||
|
|
||||||
return { data: null, errors: parsed };
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -96,7 +85,7 @@ export const useData = (config) => {
|
|||||||
headers: getAuthHeaders(),
|
headers: getAuthHeaders(),
|
||||||
});
|
});
|
||||||
await fetchData();
|
await fetchData();
|
||||||
return response.data.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
const deleteData = async (endpoint) => {
|
const deleteData = async (endpoint) => {
|
||||||
@@ -104,7 +93,7 @@ export const useData = (config) => {
|
|||||||
headers: getAuthHeaders(),
|
headers: getAuthHeaders(),
|
||||||
});
|
});
|
||||||
await fetchData();
|
await fetchData();
|
||||||
return response.data.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
const deleteDataWithBody = async (endpoint, payload) => {
|
const deleteDataWithBody = async (endpoint, payload) => {
|
||||||
@@ -113,7 +102,7 @@ export const useData = (config) => {
|
|||||||
data: payload,
|
data: payload,
|
||||||
});
|
});
|
||||||
await fetchData();
|
await fetchData();
|
||||||
return response.data.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ const useRequestCount = () => {
|
|||||||
const fetchCount = async () => {
|
const fetchCount = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await axios.get(
|
const res = await axios.get(
|
||||||
config.apiConfig.baseUrl + config.apiConfig.endpoints.requests.countPending,
|
config.apiConfig.baseUrl + config.apiConfig.endpoints.requests.count,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${localStorage.getItem('token')}`,
|
Authorization: `Bearer ${localStorage.getItem('token')}`,
|
||||||
@@ -20,7 +20,7 @@ const useRequestCount = () => {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
setCount(res.data.data.count);
|
setCount(res.data.count);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('❌ Error al obtener el número de solicitudes:', err.message);
|
console.error('❌ Error al obtener el número de solicitudes:', err.message);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,9 +25,9 @@ const Anuncios = () => {
|
|||||||
if (configLoading) return <p><LoadingIcon /></p>;
|
if (configLoading) return <p><LoadingIcon /></p>;
|
||||||
|
|
||||||
const reqConfig = {
|
const reqConfig = {
|
||||||
baseUrl: `${config.apiConfig.baseUrl}${config.apiConfig.endpoints.announces.all}`,
|
baseUrl: `${config.apiConfig.baseUrl}${config.apiConfig.endpoints.announcements.all}`,
|
||||||
params: {
|
params: {
|
||||||
_sort: 'created_at',
|
_sort: 'createdAt',
|
||||||
_order: 'desc',
|
_order: 'desc',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -61,7 +61,7 @@ const AnunciosContent = ({ reqConfig }) => {
|
|||||||
(filters.baja && anuncio.priority === 0) ||
|
(filters.baja && anuncio.priority === 0) ||
|
||||||
(filters.media && anuncio.priority === 1) ||
|
(filters.media && anuncio.priority === 1) ||
|
||||||
(filters.alta && anuncio.priority === 2);
|
(filters.alta && anuncio.priority === 2);
|
||||||
const createdAt = new Date(anuncio.created_at);
|
const createdAt = new Date(anuncio.createdAt);
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const matchesFecha =
|
const matchesFecha =
|
||||||
(filters.ultimos7 && (now - createdAt) / (1000 * 60 * 60 * 24) <= 7) ||
|
(filters.ultimos7 && (now - createdAt) / (1000 * 60 * 60 * 24) <= 7) ||
|
||||||
@@ -74,7 +74,7 @@ const AnunciosContent = ({ reqConfig }) => {
|
|||||||
const normalized = term.toLowerCase();
|
const normalized = term.toLowerCase();
|
||||||
return (
|
return (
|
||||||
anuncio.body?.toLowerCase().includes(normalized) ||
|
anuncio.body?.toLowerCase().includes(normalized) ||
|
||||||
anuncio.published_by_name?.toLowerCase().includes(normalized)
|
anuncio.publishedByName?.toLowerCase().includes(normalized)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
initialFilters: {
|
initialFilters: {
|
||||||
@@ -90,10 +90,10 @@ const AnunciosContent = ({ reqConfig }) => {
|
|||||||
const handleCreate = () => {
|
const handleCreate = () => {
|
||||||
setCreatingAnuncio(true);
|
setCreatingAnuncio(true);
|
||||||
setTempAnuncio({
|
setTempAnuncio({
|
||||||
announce_id: null,
|
|
||||||
body: 'Nuevo anuncio',
|
body: 'Nuevo anuncio',
|
||||||
priority: 1,
|
priority: 1,
|
||||||
published_by_name: 'Admin',
|
publishedBy: JSON.parse(localStorage.getItem("identity"))?.user?.displayName,
|
||||||
|
createdAt: Date.now()
|
||||||
});
|
});
|
||||||
document.querySelector('.cards-grid')?.scrollTo({ top: 0, behavior: 'smooth' });
|
document.querySelector('.cards-grid')?.scrollTo({ top: 0, behavior: 'smooth' });
|
||||||
};
|
};
|
||||||
@@ -162,12 +162,12 @@ const AnunciosContent = ({ reqConfig }) => {
|
|||||||
/>
|
/>
|
||||||
</EditorProvider>
|
</EditorProvider>
|
||||||
)}
|
)}
|
||||||
renderCard={(anuncio) => (
|
renderCard={(anuncio, idx) => (
|
||||||
<AnuncioCard
|
<AnuncioCard
|
||||||
key={anuncio.announce_id}
|
key={anuncio.announceId}
|
||||||
anuncio={anuncio}
|
anuncio={{...anuncio, idx: idx}}
|
||||||
onUpdate={(a, id) => handleEditSubmit(a, id)}
|
onUpdate={(a, id) => handleEditSubmit(a, id)}
|
||||||
onDelete={() => handleDelete(anuncio.announce_id)}
|
onDelete={() => handleDelete(anuncio.announceId)}
|
||||||
error={error}
|
error={error}
|
||||||
onClearError={() => setError(null)}
|
onClearError={() => setError(null)}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -19,9 +19,8 @@ const Documentacion = () => {
|
|||||||
|
|
||||||
const reqConfig = {
|
const reqConfig = {
|
||||||
baseUrl: config.apiConfig.coreUrl + config.apiConfig.endpoints.files.all,
|
baseUrl: config.apiConfig.coreUrl + config.apiConfig.endpoints.files.all,
|
||||||
uploadUrl: config.apiConfig.coreUrl + config.apiConfig.endpoints.files.upload,
|
|
||||||
params: {
|
params: {
|
||||||
_sort: 'uploaded_at',
|
_sort: 'uploadedAt',
|
||||||
_order: 'desc'
|
_order: 'desc'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -40,22 +39,22 @@ const DocumentacionContent = ({ reqConfig }) => {
|
|||||||
|
|
||||||
const handleSelectFiles = async (files) => {
|
const handleSelectFiles = async (files) => {
|
||||||
const file = files[0];
|
const file = files[0];
|
||||||
if (!file || !reqConfig?.uploadUrl) return;
|
if (!file || !reqConfig?.baseUrl) return;
|
||||||
|
|
||||||
const file_name = file.name;
|
const fileName = file.name;
|
||||||
const mime_type = file.type || "application/octet-stream";
|
const mimeType = file.type || "application/octet-stream";
|
||||||
const uploaded_by = JSON.parse(localStorage.getItem("user"))?.user_id;
|
const uploadedBy = JSON.parse(localStorage.getItem("identity"))?.user?.userId;
|
||||||
const context = 1;
|
const context = 1;
|
||||||
|
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append("file", file);
|
formData.append("file", file);
|
||||||
formData.append("file_name", file_name);
|
formData.append("fileName", fileName);
|
||||||
formData.append("mime_type", mime_type);
|
formData.append("mimeType", mimeType);
|
||||||
formData.append("uploaded_by", uploaded_by);
|
formData.append("uploadedBy", uploadedBy);
|
||||||
formData.append("context", context);
|
formData.append("context", context);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await postData(reqConfig.uploadUrl, formData);
|
await postData(reqConfig.baseUrl, formData);
|
||||||
fileUploadRef.current?.resetSelectedFiles();
|
fileUploadRef.current?.resetSelectedFiles();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Error al subir archivo:", err);
|
console.error("Error al subir archivo:", err);
|
||||||
@@ -100,8 +99,8 @@ const DocumentacionContent = ({ reqConfig }) => {
|
|||||||
variant="danger"
|
variant="danger"
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
try {
|
try {
|
||||||
await deleteDataWithBody(`${reqConfig.baseUrl}/${deleteTarget.file_id}`, {
|
await deleteDataWithBody(`${reqConfig.baseUrl}/${deleteTarget.fileId}`, {
|
||||||
file_path: deleteTarget.file_path
|
filePath: deleteTarget.filePath
|
||||||
});
|
});
|
||||||
setDeleteTarget(null);
|
setDeleteTarget(null);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ const Gastos = () => {
|
|||||||
const reqConfig = {
|
const reqConfig = {
|
||||||
baseUrl: `${config.apiConfig.baseUrl}${config.apiConfig.endpoints.expenses.all}`,
|
baseUrl: `${config.apiConfig.baseUrl}${config.apiConfig.endpoints.expenses.all}`,
|
||||||
params: {
|
params: {
|
||||||
_sort: 'created_at',
|
_sort: 'createdAt',
|
||||||
_order: 'desc',
|
_order: 'desc',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -84,7 +84,7 @@ const GastosContent = ({ reqConfig }) => {
|
|||||||
const handleCreate = () => {
|
const handleCreate = () => {
|
||||||
setCreatingGasto(true);
|
setCreatingGasto(true);
|
||||||
setTempGasto({
|
setTempGasto({
|
||||||
expense_id: null,
|
expenseId: null,
|
||||||
concept: '',
|
concept: '',
|
||||||
amount: 0.0,
|
amount: 0.0,
|
||||||
supplier: '',
|
supplier: '',
|
||||||
@@ -160,7 +160,7 @@ const GastosContent = ({ reqConfig }) => {
|
|||||||
)}
|
)}
|
||||||
renderCard={(gasto) => (
|
renderCard={(gasto) => (
|
||||||
<GastoCard
|
<GastoCard
|
||||||
key={gasto.expense_id}
|
key={gasto.expenseId}
|
||||||
gasto={gasto}
|
gasto={gasto}
|
||||||
onUpdate={handleEditSubmit}
|
onUpdate={handleEditSubmit}
|
||||||
onDelete={handleDelete}
|
onDelete={handleDelete}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ const Ingresos = () => {
|
|||||||
rawUrl: config.apiConfig.baseUrl + config.apiConfig.endpoints.incomes.all,
|
rawUrl: config.apiConfig.baseUrl + config.apiConfig.endpoints.incomes.all,
|
||||||
membersUrl: config.apiConfig.baseUrl + config.apiConfig.endpoints.members.all,
|
membersUrl: config.apiConfig.baseUrl + config.apiConfig.endpoints.members.all,
|
||||||
params: {
|
params: {
|
||||||
_sort: 'created_at',
|
_sort: 'createdAt',
|
||||||
_order: 'desc'
|
_order: 'desc'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -98,16 +98,16 @@ const IngresosContent = ({ reqConfig }) => {
|
|||||||
searchFn: (ingreso, term) => {
|
searchFn: (ingreso, term) => {
|
||||||
const normalized = term.toLowerCase();
|
const normalized = term.toLowerCase();
|
||||||
return ingreso.concept?.toLowerCase().includes(normalized) ||
|
return ingreso.concept?.toLowerCase().includes(normalized) ||
|
||||||
String(ingreso.member_number).includes(normalized) ||
|
String(ingreso.memberNumber).includes(normalized) ||
|
||||||
ingreso.display_name?.toLowerCase().includes(normalized);
|
ingreso.displayName?.toLowerCase().includes(normalized);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleCreate = () => {
|
const handleCreate = () => {
|
||||||
setCreatingIngreso(true);
|
setCreatingIngreso(true);
|
||||||
setTempIngreso({
|
setTempIngreso({
|
||||||
income_id: null,
|
incomeId: null,
|
||||||
member_number: 0,
|
memberNumber: 0,
|
||||||
concept: '',
|
concept: '',
|
||||||
amount: 0.0,
|
amount: 0.0,
|
||||||
frequency: CONSTANTS.PAYMENT_FREQUENCY_YEARLY,
|
frequency: CONSTANTS.PAYMENT_FREQUENCY_YEARLY,
|
||||||
@@ -183,10 +183,10 @@ const IngresosContent = ({ reqConfig }) => {
|
|||||||
)}
|
)}
|
||||||
renderCard={(income) => (
|
renderCard={(income) => (
|
||||||
<IngresoCard
|
<IngresoCard
|
||||||
key={income.income_id}
|
key={income.incomeId}
|
||||||
income={income}
|
income={income}
|
||||||
onUpdate={(data, id) => handleEditSubmit(data, id)}
|
onUpdate={(data, id) => handleEditSubmit(data, id)}
|
||||||
onDelete={() => handleDelete(income.income_id)}
|
onDelete={() => handleDelete(income.incomeId)}
|
||||||
error={error}
|
error={error}
|
||||||
onClearError={() => setError(null)}
|
onClearError={() => setError(null)}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -23,10 +23,10 @@ const ListaEspera = () => {
|
|||||||
if (configLoading) return <p><LoadingIcon /></p>;
|
if (configLoading) return <p><LoadingIcon /></p>;
|
||||||
|
|
||||||
const reqConfig = {
|
const reqConfig = {
|
||||||
baseUrl: config.apiConfig.baseUrl + config.apiConfig.endpoints.members.limitedWaitlist,
|
baseUrl: config.apiConfig.baseUrl + config.apiConfig.endpoints.users.waitlistLimited,
|
||||||
requestUrl: config.apiConfig.baseUrl + config.apiConfig.endpoints.requests.all,
|
requestUrl: config.apiConfig.baseUrl + config.apiConfig.endpoints.requests.all,
|
||||||
preUsersUrl: config.apiConfig.baseUrl + config.apiConfig.endpoints.pre_users.all,
|
preUsersUrl: config.apiConfig.baseUrl + config.apiConfig.endpoints.preUsers.all,
|
||||||
preUserValidationUrl: config.apiConfig.baseUrl + config.apiConfig.endpoints.pre_users.validation,
|
preUserValidationUrl: config.apiConfig.baseUrl + config.apiConfig.endpoints.preUsers.validate,
|
||||||
params: {}
|
params: {}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ const ListaEspera = () => {
|
|||||||
|
|
||||||
const ListaEsperaContent = ({ reqConfig }) => {
|
const ListaEsperaContent = ({ reqConfig }) => {
|
||||||
const { authStatus } = useAuth();
|
const { authStatus } = useAuth();
|
||||||
const { data, dataLoading, dataError, postDataValidated, postData } = useDataContext();
|
const { data, dataLoading, dataError, postData, postDataValidated } = useDataContext();
|
||||||
|
|
||||||
const [showWelcomeModal, setShowWelcomeModal] = useState(false);
|
const [showWelcomeModal, setShowWelcomeModal] = useState(false);
|
||||||
const [showPreUserFormModal, setShowPreUserFormModal] = useState(false);
|
const [showPreUserFormModal, setShowPreUserFormModal] = useState(false);
|
||||||
@@ -64,27 +64,30 @@ const ListaEsperaContent = ({ reqConfig }) => {
|
|||||||
const handleRegisterSubmit = async (formData) => {
|
const handleRegisterSubmit = async (formData) => {
|
||||||
setValidationErrors({});
|
setValidationErrors({});
|
||||||
|
|
||||||
const { _, errors } = await postDataValidated(reqConfig.preUserValidationUrl, formData);
|
const validation = await postDataValidated(
|
||||||
|
reqConfig.preUserValidationUrl,
|
||||||
|
formData
|
||||||
|
);
|
||||||
|
|
||||||
if (errors) {
|
if (!validation.ok) {
|
||||||
setValidationErrors(errors);
|
setValidationErrors(validation.errors);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const request = await postData(reqConfig.requestUrl, { type: 0, status: 0 });
|
const request = await postData(reqConfig.requestUrl, { type: 0, status: 0 });
|
||||||
const requestId = request?.request_id;
|
const requestId = request?.requestId;
|
||||||
if (!requestId) throw new Error("No se pudo registrar la solicitud.");
|
if (!requestId) throw new Error("No se pudo registrar la solicitud.");
|
||||||
|
|
||||||
await postData(reqConfig.preUsersUrl, {
|
await postData(reqConfig.preUsersUrl, {
|
||||||
...formData,
|
...formData,
|
||||||
request_id: requestId
|
requestId
|
||||||
});
|
});
|
||||||
|
|
||||||
setShowPreUserFormModal(false);
|
setShowPreUserFormModal(false);
|
||||||
setShowConfirmationModal(true);
|
setShowConfirmationModal(true);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setValidationErrors({ general: err.message });
|
setValidationErrors({ general: "Error inesperado al enviar la solicitud" });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -94,13 +97,6 @@ const ListaEsperaContent = ({ reqConfig }) => {
|
|||||||
setShowPreUserFormModal(true);
|
setShowPreUserFormModal(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapped = [...(data ?? [])]
|
|
||||||
.sort((a, b) => new Date(a.created_at) - new Date(b.created_at))
|
|
||||||
.map((item) => ({
|
|
||||||
...item,
|
|
||||||
created_at: DateParser.timestampToString(item.created_at)
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (dataLoading) return <p className="text-center my-5"><LoadingIcon /></p>;
|
if (dataLoading) return <p className="text-center my-5"><LoadingIcon /></p>;
|
||||||
if (dataError) return <p className="text-danger text-center my-5">{dataError}</p>;
|
if (dataError) return <p className="text-danger text-center my-5">{dataError}</p>;
|
||||||
|
|
||||||
@@ -117,7 +113,7 @@ const ListaEsperaContent = ({ reqConfig }) => {
|
|||||||
</IfNotAuthenticated>
|
</IfNotAuthenticated>
|
||||||
</div>
|
</div>
|
||||||
<hr className="section-divider" />
|
<hr className="section-divider" />
|
||||||
<List datos={mapped} config={{ title: 'display_name', subtitle: 'created_at', showIndex: true }} />
|
<List datos={data} config={{ title: 'name', subtitle: '', showIndex: true }} />
|
||||||
|
|
||||||
{authStatus === 'unauthenticated' && (
|
{authStatus === 'unauthenticated' && (
|
||||||
<Modal show={showWelcomeModal} onHide={() => setShowWelcomeModal(false)}>
|
<Modal show={showWelcomeModal} onHide={() => setShowWelcomeModal(false)}>
|
||||||
|
|||||||
@@ -66,12 +66,12 @@ const Perfil = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const reqConfig = {
|
const reqConfig = {
|
||||||
baseUrl: `${config.apiConfig.baseUrl}${config.apiConfig.endpoints.members.profile}`,
|
baseUrl: `${config.apiConfig.baseUrl}${config.apiConfig.endpoints.users.me}`,
|
||||||
myIncomesUrl: buildUrl(config.apiConfig.baseUrl, config.apiConfig.endpoints.incomes.myIncomes),
|
myIncomesUrl: buildUrl(config.apiConfig.baseUrl, config.apiConfig.endpoints.incomes.mine),
|
||||||
requestUrl: buildUrl(config.apiConfig.baseUrl, config.apiConfig.endpoints.requests.all),
|
requestUrl: buildUrl(config.apiConfig.baseUrl, config.apiConfig.endpoints.requests.all),
|
||||||
preUsersUrl: buildUrl(config.apiConfig.baseUrl, config.apiConfig.endpoints.pre_users.all),
|
preUsersUrl: buildUrl(config.apiConfig.baseUrl, config.apiConfig.endpoints.preUsers.all),
|
||||||
preUserValidationUrl: buildUrl(config.apiConfig.baseUrl, config.apiConfig.endpoints.pre_users.validation),
|
preUserValidationUrl: buildUrl(config.apiConfig.baseUrl, config.apiConfig.endpoints.preUsers.validate),
|
||||||
myRequestsUrl: buildUrl(config.apiConfig.baseUrl, config.apiConfig.endpoints.requests.myRequests),
|
myRequestsUrl: buildUrl(config.apiConfig.baseUrl, config.apiConfig.endpoints.requests.mine),
|
||||||
changePasswordUrl: buildUrl(config.apiConfig.coreUrl, config.apiConfig.endpoints.auth.changePassword),
|
changePasswordUrl: buildUrl(config.apiConfig.coreUrl, config.apiConfig.endpoints.auth.changePassword),
|
||||||
loginValidateUrl: buildUrl(config.apiConfig.coreUrl, config.apiConfig.endpoints.auth.loginValidate),
|
loginValidateUrl: buildUrl(config.apiConfig.coreUrl, config.apiConfig.endpoints.auth.loginValidate),
|
||||||
};
|
};
|
||||||
@@ -87,13 +87,13 @@ const PerfilContent = ({ config }) => {
|
|||||||
const { data, dataLoading, dataError, postData, postDataValidated } = useDataContext();
|
const { data, dataLoading, dataError, postData, postDataValidated } = useDataContext();
|
||||||
const { logout } = useAuth();
|
const { logout } = useAuth();
|
||||||
|
|
||||||
const usuario = data?.member;
|
const identity = JSON.parse(localStorage.getItem("identity"));
|
||||||
const myRequests = data?.requests ?? [];
|
const myRequests = data?.requests ?? [];
|
||||||
const incomes = data?.payments ?? [];
|
const incomes = data?.payments ?? [];
|
||||||
const hasCollaborator = data?.hasCollaborator ?? false;
|
const hasCollaborator = data?.hasCollaborator ?? false;
|
||||||
const hasCollaboratorRequest = data?.hasCollaboratorRequest ?? false;
|
const hasCollaboratorRequest = data?.hasCollaboratorRequest ?? false;
|
||||||
const hasGreenHouse = data?.hasGreenHouse ?? false;
|
const hasGreenHouse = data?.hasGreenhouse ?? false;
|
||||||
const hasGreenHouseRequest = data?.hasGreenHouseRequest ?? false;
|
const hasGreenHouseRequest = data?.hasGreenhouseRequest ?? false;
|
||||||
|
|
||||||
const [showAddCollaboratorModal, setShowAddCollaboratorModal] = useState(false);
|
const [showAddCollaboratorModal, setShowAddCollaboratorModal] = useState(false);
|
||||||
const [showRemoveCollaboratorModal, setShowRemoveCollaboratorModal] = useState(false);
|
const [showRemoveCollaboratorModal, setShowRemoveCollaboratorModal] = useState(false);
|
||||||
@@ -117,7 +117,7 @@ const PerfilContent = ({ config }) => {
|
|||||||
await postData(config.requestUrl, {
|
await postData(config.requestUrl, {
|
||||||
type: CONSTANTS.REQUEST_TYPE_UNREGISTER,
|
type: CONSTANTS.REQUEST_TYPE_UNREGISTER,
|
||||||
status: CONSTANTS.REQUEST_PENDING,
|
status: CONSTANTS.REQUEST_PENDING,
|
||||||
requested_by: usuario.user_id
|
requestedBy: identity.user.userId
|
||||||
});
|
});
|
||||||
setFeedbackModal({
|
setFeedbackModal({
|
||||||
title: 'Solicitud enviada',
|
title: 'Solicitud enviada',
|
||||||
@@ -140,7 +140,7 @@ const PerfilContent = ({ config }) => {
|
|||||||
await postData(config.requestUrl, {
|
await postData(config.requestUrl, {
|
||||||
type: CONSTANTS.REQUEST_TYPE_ADD_GREENHOUSE,
|
type: CONSTANTS.REQUEST_TYPE_ADD_GREENHOUSE,
|
||||||
status: CONSTANTS.REQUEST_PENDING,
|
status: CONSTANTS.REQUEST_PENDING,
|
||||||
requested_by: usuario.user_id
|
requestedBy: identity.user.userId
|
||||||
});
|
});
|
||||||
setFeedbackModal({
|
setFeedbackModal({
|
||||||
title: 'Solicitud enviada',
|
title: 'Solicitud enviada',
|
||||||
@@ -163,7 +163,7 @@ const PerfilContent = ({ config }) => {
|
|||||||
await postData(config.requestUrl, {
|
await postData(config.requestUrl, {
|
||||||
type: CONSTANTS.REQUEST_TYPE_REMOVE_GREENHOUSE,
|
type: CONSTANTS.REQUEST_TYPE_REMOVE_GREENHOUSE,
|
||||||
status: CONSTANTS.REQUEST_PENDING,
|
status: CONSTANTS.REQUEST_PENDING,
|
||||||
requested_by: usuario.user_id
|
requestedBy: identity.user.userId
|
||||||
});
|
});
|
||||||
setFeedbackModal({
|
setFeedbackModal({
|
||||||
title: 'Solicitud enviada',
|
title: 'Solicitud enviada',
|
||||||
@@ -191,7 +191,7 @@ const PerfilContent = ({ config }) => {
|
|||||||
const handleChangePassword = async () => {
|
const handleChangePassword = async () => {
|
||||||
try {
|
try {
|
||||||
const validOldPassword = await postData(config.loginValidateUrl, {
|
const validOldPassword = await postData(config.loginValidateUrl, {
|
||||||
userId: usuario.user_id,
|
userId: identity.user.userId,
|
||||||
password: newPasswordData.currentPassword
|
password: newPasswordData.currentPassword
|
||||||
});
|
});
|
||||||
if (!validOldPassword.valid) throw new Error("La contraseña actual es incorrecta.");
|
if (!validOldPassword.valid) throw new Error("La contraseña actual es incorrecta.");
|
||||||
@@ -199,7 +199,7 @@ const PerfilContent = ({ config }) => {
|
|||||||
if (newPasswordData.newPassword.length < 8) throw new Error("La nueva contraseña debe tener al menos 8 caracteres.");
|
if (newPasswordData.newPassword.length < 8) throw new Error("La nueva contraseña debe tener al menos 8 caracteres.");
|
||||||
|
|
||||||
const response = await postData(config.changePasswordUrl, {
|
const response = await postData(config.changePasswordUrl, {
|
||||||
userId: usuario.user_id,
|
userId: identity.user.userId,
|
||||||
newPassword: newPasswordData.newPassword
|
newPassword: newPasswordData.newPassword
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -231,9 +231,9 @@ const PerfilContent = ({ config }) => {
|
|||||||
|
|
||||||
const mappedRequests = myRequests.map(r => ({
|
const mappedRequests = myRequests.map(r => ({
|
||||||
...r,
|
...r,
|
||||||
request_type: r.request_type ?? r.type,
|
type: r.type ?? r.type,
|
||||||
request_status: r.request_status ?? r.status,
|
status: r.status ?? r.status,
|
||||||
request_created_at: r.request_created_at ?? r.created_at
|
request_createdAt: r.request_createdAt ?? r.createdAt
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if (dataLoading) return <p className="text-center my-5"><LoadingIcon /></p>;
|
if (dataLoading) return <p className="text-center my-5"><LoadingIcon /></p>;
|
||||||
@@ -247,10 +247,10 @@ const PerfilContent = ({ config }) => {
|
|||||||
<Card className="shadow-sm rounded-4 perfil-card">
|
<Card className="shadow-sm rounded-4 perfil-card">
|
||||||
<Card.Header className="bg-secondary text-white rounded-top-4 d-flex align-items-center justify-content-between">
|
<Card.Header className="bg-secondary text-white rounded-top-4 d-flex align-items-center justify-content-between">
|
||||||
<div className="d-flex align-items-center">
|
<div className="d-flex align-items-center">
|
||||||
<img src={getPFP(usuario.type)} alt="PFP" width={36} className="me-3" />
|
<img src={getPFP(identity.metadata.type)} alt="PFP" width={36} className="me-3" />
|
||||||
<div className="m-0 p-0">
|
<div className="m-0 p-0">
|
||||||
<Card.Title className="mb-0">{`@${usuario.user_name}`}</Card.Title>
|
<Card.Title className="mb-0">{`@${identity.account.username}`}</Card.Title>
|
||||||
<small>Te uniste el {parseDate(usuario.created_at)}</small>
|
<small>Te uniste el {parseDate(identity.metadata.createdAt)}</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -293,21 +293,21 @@ const PerfilContent = ({ config }) => {
|
|||||||
|
|
||||||
<Card.Body>
|
<Card.Body>
|
||||||
<ListGroup variant="flush" className="border rounded-3">
|
<ListGroup variant="flush" className="border rounded-3">
|
||||||
<ListGroup.Item><FontAwesomeIcon icon={faUser} className="me-2" />Nombre: <strong>{usuario.display_name}</strong></ListGroup.Item>
|
<ListGroup.Item><FontAwesomeIcon icon={faUser} className="me-2" />Nombre: <strong>{identity.user.displayName}</strong></ListGroup.Item>
|
||||||
<ListGroup.Item><FontAwesomeIcon icon={faIdCard} className="me-2" />DNI: <strong>{usuario.dni}</strong></ListGroup.Item>
|
<ListGroup.Item><FontAwesomeIcon icon={faIdCard} className="me-2" />DNI: <strong>{identity.metadata.dni}</strong></ListGroup.Item>
|
||||||
<ListGroup.Item><FontAwesomeIcon icon={faEnvelope} className="me-2" />Email: <strong>{usuario.email}</strong></ListGroup.Item>
|
<ListGroup.Item><FontAwesomeIcon icon={faEnvelope} className="me-2" />Email: <strong>{identity.account.email}</strong></ListGroup.Item>
|
||||||
<ListGroup.Item><FontAwesomeIcon icon={faPhone} className="me-2" />Teléfono: <strong>{usuario.phone}</strong></ListGroup.Item>
|
<ListGroup.Item><FontAwesomeIcon icon={faPhone} className="me-2" />Teléfono: <strong>{identity.metadata.phone}</strong></ListGroup.Item>
|
||||||
<ListGroup.Item>
|
<ListGroup.Item>
|
||||||
<FontAwesomeIcon icon={faHashtag} className="me-2" />Socio Nº: <strong>{usuario.member_number}</strong> | Huerto Nº: <strong>{usuario.plot_number}</strong>
|
<FontAwesomeIcon icon={faHashtag} className="me-2" />Socio Nº: <strong>{identity.metadata.memberNumber}</strong> | Huerto Nº: <strong>{identity.metadata.plotNumber}</strong>
|
||||||
</ListGroup.Item>
|
</ListGroup.Item>
|
||||||
<ListGroup.Item>
|
<ListGroup.Item>
|
||||||
<FontAwesomeIcon icon={faSeedling} className="me-2" />Tipo de socio: <strong>{['LISTA DE ESPERA', 'HORTELANO', 'HORTELANO + INVERNADERO', 'COLABORADOR', 'SUBVENCION', 'DESARROLLADOR'][usuario.type]}</strong>
|
<FontAwesomeIcon icon={faSeedling} className="me-2" />Tipo de socio: <strong>{['LISTA DE ESPERA', 'HORTELANO', 'HORTELANO + INVERNADERO', 'COLABORADOR', 'SUBVENCION', 'DESARROLLADOR'][identity.metadata.type]}</strong>
|
||||||
</ListGroup.Item>
|
</ListGroup.Item>
|
||||||
<ListGroup.Item>
|
<ListGroup.Item>
|
||||||
<FontAwesomeIcon icon={faUserShield} className="me-2" />Rol en huertos: <strong>{['USUARIO', 'ADMIN', 'DESARROLLADOR'][usuario.role]}</strong>
|
<FontAwesomeIcon icon={faUserShield} className="me-2" />Rol en huertos: <strong>{['USUARIO', 'ADMIN', 'DESARROLLADOR'][identity.metadata.role]}</strong>
|
||||||
</ListGroup.Item>
|
</ListGroup.Item>
|
||||||
<ListGroup.Item>
|
<ListGroup.Item>
|
||||||
<FontAwesomeIcon icon={faCalendar} className="me-2" />Estado: <strong>{usuario.status === 1 ? 'ACTIVO' : 'INACTIVO'}</strong>
|
<FontAwesomeIcon icon={faCalendar} className="me-2" />Estado: <strong>{identity.account.status === 1 ? 'ACTIVO' : 'INACTIVO'}</strong>
|
||||||
</ListGroup.Item>
|
</ListGroup.Item>
|
||||||
</ListGroup>
|
</ListGroup>
|
||||||
</Card.Body>
|
</Card.Body>
|
||||||
@@ -321,7 +321,7 @@ const PerfilContent = ({ config }) => {
|
|||||||
{incomes.length === 0 && <p className="text-center">No hay pagos registrados.</p>}
|
{incomes.length === 0 && <p className="text-center">No hay pagos registrados.</p>}
|
||||||
<div className="d-flex flex-wrap gap-3 mb-4">
|
<div className="d-flex flex-wrap gap-3 mb-4">
|
||||||
{incomes.map(income => (
|
{incomes.map(income => (
|
||||||
<IngresoCard key={income.income_id} income={income} editable={false} />
|
<IngresoCard key={income.incomeId} income={income} editable={false} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -331,7 +331,7 @@ const PerfilContent = ({ config }) => {
|
|||||||
|
|
||||||
<div className="d-flex flex-wrap gap-3 mb-4">
|
<div className="d-flex flex-wrap gap-3 mb-4">
|
||||||
{mappedRequests.map(request => (
|
{mappedRequests.map(request => (
|
||||||
<SolicitudCard key={request.request_id} data={request} editable={false} onProfile={true} />
|
<SolicitudCard key={request.requestId} data={request} editable={false} onProfile={true} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -432,7 +432,7 @@ const PerfilContent = ({ config }) => {
|
|||||||
>
|
>
|
||||||
<PreUserForm
|
<PreUserForm
|
||||||
userType={3}
|
userType={3}
|
||||||
plotNumber={usuario.plot_number}
|
plotNumber={identity.metadata.plotNumber}
|
||||||
errors={validationErrors}
|
errors={validationErrors}
|
||||||
onSubmit={async (formData) => {
|
onSubmit={async (formData) => {
|
||||||
setValidationErrors({});
|
setValidationErrors({});
|
||||||
@@ -447,15 +447,15 @@ const PerfilContent = ({ config }) => {
|
|||||||
const request = await postData(config.requestUrl, {
|
const request = await postData(config.requestUrl, {
|
||||||
type: CONSTANTS.REQUEST_TYPE_ADD_COLLABORATOR,
|
type: CONSTANTS.REQUEST_TYPE_ADD_COLLABORATOR,
|
||||||
status: CONSTANTS.REQUEST_PENDING,
|
status: CONSTANTS.REQUEST_PENDING,
|
||||||
requested_by: usuario.user_id
|
requestedBy: identity.user.userId
|
||||||
});
|
});
|
||||||
|
|
||||||
const requestId = request?.request_id;
|
const requestId = request?.requestId;
|
||||||
if (!requestId) throw new Error("No se pudo crear la solicitud.");
|
if (!requestId) throw new Error("No se pudo crear la solicitud.");
|
||||||
|
|
||||||
await postData(config.preUsersUrl, {
|
await postData(config.preUsersUrl, {
|
||||||
...formData,
|
...formData,
|
||||||
request_id: requestId
|
requestId: requestId
|
||||||
});
|
});
|
||||||
|
|
||||||
setValidationErrors({});
|
setValidationErrors({});
|
||||||
@@ -495,7 +495,7 @@ const PerfilContent = ({ config }) => {
|
|||||||
await postData(config.requestUrl, {
|
await postData(config.requestUrl, {
|
||||||
type: CONSTANTS.REQUEST_TYPE_REMOVE_COLLABORATOR,
|
type: CONSTANTS.REQUEST_TYPE_REMOVE_COLLABORATOR,
|
||||||
status: CONSTANTS.REQUEST_PENDING,
|
status: CONSTANTS.REQUEST_PENDING,
|
||||||
requested_by: usuario.user_id
|
requestedBy: identity.user.userId
|
||||||
});
|
});
|
||||||
|
|
||||||
setFeedbackModal({
|
setFeedbackModal({
|
||||||
|
|||||||
@@ -28,11 +28,11 @@ const Socios = () => {
|
|||||||
if (configLoading || !config) return <p className="text-center my-5"><LoadingIcon /></p>;
|
if (configLoading || !config) return <p className="text-center my-5"><LoadingIcon /></p>;
|
||||||
|
|
||||||
const reqConfig = {
|
const reqConfig = {
|
||||||
baseUrl: `${config.apiConfig.baseUrl}${config.apiConfig.endpoints.members.all}`,
|
baseUrl: `${config.apiConfig.baseUrl}${config.apiConfig.endpoints.users.all}`,
|
||||||
incomesUrl: `${config.apiConfig.baseUrl}${config.apiConfig.endpoints.members.payments}`,
|
incomesUrl: `${config.apiConfig.baseUrl}${config.apiConfig.endpoints.users.payments}`,
|
||||||
rawIncomesUrl: `${config.apiConfig.baseUrl}${config.apiConfig.endpoints.incomes.all}`,
|
rawIncomesUrl: `${config.apiConfig.baseUrl}${config.apiConfig.endpoints.incomes.all}`,
|
||||||
params: {
|
params: {
|
||||||
_sort: "member_number",
|
_sort: "memberNumber",
|
||||||
_order: "asc"
|
_order: "asc"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -67,24 +67,24 @@ const SociosContent = ({ reqConfig }) => {
|
|||||||
} = usePaginatedList({
|
} = usePaginatedList({
|
||||||
data,
|
data,
|
||||||
pageSize: PAGE_SIZE,
|
pageSize: PAGE_SIZE,
|
||||||
filterFn: (socio, filters) => {
|
filterFn: (identity, filters) => {
|
||||||
if (filters.todos) return true;
|
if (filters.todos) return true;
|
||||||
if (!filters.inactivos && socio.status === 0) return false;
|
if (!filters.inactivos && identity.account.status === 0) return false;
|
||||||
return (
|
return (
|
||||||
(filters.listaEspera && socio.type === 0) ||
|
(filters.listaEspera && identity.metadata.type === 0) ||
|
||||||
(filters.hortelanos && socio.type === 1) ||
|
(filters.hortelanos && identity.metadata.type === 1) ||
|
||||||
(filters.invernadero && socio.type === 2) ||
|
(filters.invernadero && identity.metadata.type === 2) ||
|
||||||
(filters.colaboradores && socio.type === 3) ||
|
(filters.colaboradores && identity.metadata.type === 3) ||
|
||||||
(filters.inactivos && socio.status === 0)
|
(filters.inactivos && identity.account.status === 0)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
searchFn: (socio, term) => {
|
searchFn: (identity, term) => {
|
||||||
const normalized = term.toLowerCase();
|
const normalized = term.toLowerCase();
|
||||||
return (
|
return (
|
||||||
socio.display_name?.toLowerCase().includes(normalized) ||
|
identity.user.displayName?.toLowerCase().includes(normalized) ||
|
||||||
socio.dni?.toLowerCase().includes(normalized) ||
|
identity.metadata.dni?.toLowerCase().includes(normalized) ||
|
||||||
String(socio.member_number).includes(normalized) ||
|
String(identity.metadata.memberNumber).includes(normalized) ||
|
||||||
String(socio.plot_number).includes(normalized)
|
String(identity.metadata.plotNumber).includes(normalized)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
initialFilters: {
|
initialFilters: {
|
||||||
@@ -98,20 +98,20 @@ const SociosContent = ({ reqConfig }) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const listaEsperaOrdenada = data ? data
|
const listaEsperaOrdenada = data ? data
|
||||||
.filter(s => s.type === 0 && s.status !== 0)
|
.filter(identity => identity.metadata.type === 0 && identity.account.status !== 0)
|
||||||
.sort((a, b) => new Date(a.created_at) - new Date(b.created_at)) : [];
|
.sort((a, b) => new Date(a.metadata.createdAt) - new Date(b.metadata.createdAt)) : [];
|
||||||
|
|
||||||
const handleCreate = () => {
|
const handleCreate = () => {
|
||||||
setCreatingSocio(true);
|
setCreatingSocio(true);
|
||||||
const socio = {
|
const socio = {
|
||||||
user_id: null,
|
userId: null,
|
||||||
user_name: "nuevo" + Date.now(),
|
userName: "nuevo" + Date.now(),
|
||||||
email: "",
|
email: "",
|
||||||
display_name: "Nuevo Socio",
|
displayName: "Nuevo Socio",
|
||||||
role: 0,
|
role: 0,
|
||||||
global_status: 1,
|
globalStatus: 1,
|
||||||
member_number: "",
|
memberNumber: "",
|
||||||
plot_number: "",
|
plotNumber: "",
|
||||||
dni: "",
|
dni: "",
|
||||||
phone: "",
|
phone: "",
|
||||||
notes: "",
|
notes: "",
|
||||||
@@ -130,7 +130,7 @@ const SociosContent = ({ reqConfig }) => {
|
|||||||
|
|
||||||
const handleCreateSubmit = async (newSocio) => {
|
const handleCreateSubmit = async (newSocio) => {
|
||||||
try {
|
try {
|
||||||
newSocio.user_name = newSocio.display_name.split(" ")[0].toLowerCase() + newSocio.member_number;
|
newSocio.userName = newSocio.displayName.split(" ")[0].toLowerCase() + newSocio.memberNumber;
|
||||||
await postData(reqConfig.baseUrl, newSocio);
|
await postData(reqConfig.baseUrl, newSocio);
|
||||||
setError(null);
|
setError(null);
|
||||||
setCreatingSocio(false);
|
setCreatingSocio(false);
|
||||||
@@ -162,7 +162,7 @@ const SociosContent = ({ reqConfig }) => {
|
|||||||
setIncomesError(null);
|
setIncomesError(null);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const url = reqConfig.incomesUrl.replace(":member_number", memberNumber);
|
const url = reqConfig.incomesUrl.replace(":memberNumber", memberNumber);
|
||||||
const res = await getData(url);
|
const res = await getData(url);
|
||||||
setIncomes(res.data);
|
setIncomes(res.data);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -174,7 +174,7 @@ const SociosContent = ({ reqConfig }) => {
|
|||||||
|
|
||||||
const handleIncomeUpdate = async (editado) => {
|
const handleIncomeUpdate = async (editado) => {
|
||||||
try {
|
try {
|
||||||
await putData(`${reqConfig.rawIncomesUrl}/${editado.income_id}`, editado);
|
await putData(`${reqConfig.rawIncomesUrl}/${editado.incomeId}`, editado);
|
||||||
await handleViewIncomes(selectedMemberNumber);
|
await handleViewIncomes(selectedMemberNumber);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Error actualizando ingreso:", err);
|
console.error("Error actualizando ingreso:", err);
|
||||||
@@ -219,17 +219,17 @@ const SociosContent = ({ reqConfig }) => {
|
|||||||
)}
|
)}
|
||||||
renderCard={(socio) => {
|
renderCard={(socio) => {
|
||||||
const position = socio.type === 0
|
const position = socio.type === 0
|
||||||
? listaEsperaOrdenada.findIndex(s => s.user_id === socio.user_id) + 1
|
? listaEsperaOrdenada.findIndex(s => s.userId === socio.userId) + 1
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SocioCard
|
<SocioCard
|
||||||
key={socio.user_id}
|
key={socio.userId}
|
||||||
socio={socio}
|
socio={socio}
|
||||||
onUpdate={handleEditSubmit}
|
onUpdate={handleEditSubmit}
|
||||||
onDelete={handleDelete}
|
onDelete={handleDelete}
|
||||||
onCancel={handleCancelCreate}
|
onCancel={handleCancelCreate}
|
||||||
onViewIncomes={() => handleViewIncomes(socio.member_number)}
|
onViewIncomes={() => handleViewIncomes(socio.memberNumber)}
|
||||||
error={error}
|
error={error}
|
||||||
onClearError={() => setError(null)}
|
onClearError={() => setError(null)}
|
||||||
positionIfWaitlist={position}
|
positionIfWaitlist={position}
|
||||||
@@ -256,7 +256,7 @@ const SociosContent = ({ reqConfig }) => {
|
|||||||
)}
|
)}
|
||||||
<div className="d-flex flex-wrap gap-3 p-3 justify-content-start">
|
<div className="d-flex flex-wrap gap-3 p-3 justify-content-start">
|
||||||
{incomes.map((income) => (
|
{incomes.map((income) => (
|
||||||
<IngresoCard key={income.income_id} income={income}
|
<IngresoCard key={income.incomeId} income={income}
|
||||||
onUpdate={handleIncomeUpdate} className='from-members' />
|
onUpdate={handleIncomeUpdate} className='from-members' />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -49,30 +49,28 @@ const SolicitudesContent = ({ reqConfig }) => {
|
|||||||
searchFn: (entry, term) => {
|
searchFn: (entry, term) => {
|
||||||
const normalized = term.toLowerCase();
|
const normalized = term.toLowerCase();
|
||||||
return (
|
return (
|
||||||
entry.pre_display_name?.toLowerCase().includes(normalized) ||
|
entry.preDisplayName?.toLowerCase().includes(normalized) ||
|
||||||
entry.pre_dni?.toLowerCase().includes(normalized) ||
|
entry.preDni?.toLowerCase().includes(normalized) ||
|
||||||
entry.pre_email?.toLowerCase().includes(normalized) ||
|
entry.preEmail?.toLowerCase().includes(normalized) ||
|
||||||
String(entry.pre_phone).includes(normalized)
|
String(entry.prePhone).includes(normalized)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
sortFn: (a, b) => a.request_status - b.request_status
|
sortFn: (a, b) => a.status - b.status
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleAccept = async (entry) => {
|
const handleAccept = async (entry) => {
|
||||||
const url = reqConfig.acceptUrl.replace(":request_id", entry.request_id);
|
const url = reqConfig.acceptUrl.replace(":requestId", entry.requestId);
|
||||||
try {
|
try {
|
||||||
await putData(url, {});
|
await putData(url, {});
|
||||||
console.log("✅ Solicitud aceptada:", entry.request_id);
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("❌ Error al aceptar solicitud:", err.message);
|
console.error("❌ Error al aceptar solicitud:", err.message);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleReject = async (entry) => {
|
const handleReject = async (entry) => {
|
||||||
const url = reqConfig.rejectUrl.replace(":request_id", entry.request_id);
|
const url = reqConfig.rejectUrl.replace(":requestId", entry.requestId);
|
||||||
try {
|
try {
|
||||||
await putData(url, {});
|
await putData(url, {});
|
||||||
console.log("🛑 Solicitud rechazada:", entry.request_id);
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("❌ Error al rechazar solicitud:", err.message);
|
console.error("❌ Error al rechazar solicitud:", err.message);
|
||||||
}
|
}
|
||||||
@@ -107,7 +105,7 @@ const SolicitudesContent = ({ reqConfig }) => {
|
|||||||
items={filtered}
|
items={filtered}
|
||||||
renderCard={(entry) => (
|
renderCard={(entry) => (
|
||||||
<SolicitudCard
|
<SolicitudCard
|
||||||
key={entry.request_id}
|
key={entry.requestId}
|
||||||
data={entry}
|
data={entry}
|
||||||
onAccept={() => handleAccept(entry)}
|
onAccept={() => handleAccept(entry)}
|
||||||
onReject={() => handleReject(entry)}
|
onReject={() => handleReject(entry)}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const CONSTANTS = {
|
const CONSTANTS = {
|
||||||
|
// Service
|
||||||
|
SERVICE_ID: 1,
|
||||||
|
|
||||||
// Roles
|
// Roles
|
||||||
ROLE_USER: 0,
|
ROLE_USER: 0,
|
||||||
ROLE_ADMIN: 1,
|
ROLE_ADMIN: 1,
|
||||||
|
|||||||
Reference in New Issue
Block a user