first commit

This commit is contained in:
2026-07-16 20:48:43 -03:00
commit 5696cee264
1111 changed files with 322270 additions and 0 deletions
@@ -0,0 +1,136 @@
import React, { useEffect, useState } from "react";
import { PendingRepeatView } from "@core/Models/Repeats.model";
import { getPendingRepeatsCurrentWeek } from "../../admin/(client-profile)/org/[oid]/client/[clientId]/Client.Service";
import { createAppointment } from "../../admin/(organization-profile)/org/profile/[id]/appointments/[appdate]/Appointment.Service";
import { useSessionStore } from "@core/Store/Sesion.Store";
import { useAlert } from "@core/Store/Alert.Store";
import { EVENT_TYPES, useEventHandlerStore } from "@core/Store/EventHandler.Store";
import dayjs from "dayjs";
import Button from "../Button/Button";
import { ThemeProvider } from "@emotion/react";
import turnosXpressTheme from "@core/app/theme/turnosXpress";
import style from "./style.module.css";
import { Box, Typography, Card, CardContent, Checkbox } from "@mui/material";
interface PendingRepeatsCardProps {
companyId?: string;
employeeId?: string; // Optional filter
allowEmployeeFilter?: boolean;
}
const PendingRepeatsCard: React.FC<PendingRepeatsCardProps> = ({ companyId, employeeId, allowEmployeeFilter }) => {
const SessionInfo = useSessionStore();
const alert = useAlert();
const eventHandler = useEventHandlerStore();
const [pendingRepeats, setPendingRepeats] = useState<PendingRepeatView[]>([]);
const [filterByMe, setFilterByMe] = useState<boolean>(false);
const loadRepeats = () => {
if (!SessionInfo.userId) return;
const isGlobalView = !companyId;
const isFilterByMeActive = isGlobalView || (allowEmployeeFilter && filterByMe);
eventHandler.setEventType(EVENT_TYPES.LOADING);
getPendingRepeatsCurrentWeek({
companyId,
employeeId,
sessionUser: SessionInfo.userId,
filterBySessionUser: isFilterByMeActive
}).then(res => {
setPendingRepeats(res);
}).catch(err => {
alert.showError(err.message || "Error al cargar repeticiones pendientes");
}).finally(() => {
eventHandler.setEventType(EVENT_TYPES.SLEEP);
});
};
useEffect(() => {
loadRepeats();
}, [companyId, employeeId, SessionInfo.userId, filterByMe, allowEmployeeFilter]);
const handleCreateAppointment = (repeat: PendingRepeatView) => {
eventHandler.setEventType(EVENT_TYPES.LOADING);
createAppointment({
companyId: String(repeat.companyId),
serviceId: String(repeat.serviceId),
employeeId: String(repeat.employeeId),
clientId: String(repeat.clientId),
repeatId: repeat.id,
start: dayjs(repeat.pendingDate).toISOString(),
notification: false,
validation: false,
sessionUser: SessionInfo.userId,
}).then(() => {
alert.showSuccess("Turno creado con éxito");
loadRepeats(); // Refresh the list
}).catch(err => {
alert.showError(err.format ? err.format() : err.message);
}).finally(() => {
eventHandler.setEventType(EVENT_TYPES.SLEEP);
});
};
if (pendingRepeats.length === 0 && !filterByMe) {
return null;
}
return (
<ThemeProvider theme={turnosXpressTheme}>
<Box className={style.container}>
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 2 }}>
<Typography variant="h6" className={style.title} sx={{ mb: 0 }}>
Turnos recurrentes pendientes de creación (Semana Actual)
</Typography>
{(allowEmployeeFilter && companyId) && (
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
<Typography variant="body2" sx={{ color: 'text.secondary' }}>
Solo mis turnos
</Typography>
<Checkbox
checked={filterByMe}
onChange={(e) => setFilterByMe(e.target.checked)}
color="primary"
size="small"
sx={{ padding: 0 }}
/>
</Box>
)}
</Box>
{pendingRepeats.length === 0 ? (
<Typography variant="body2" sx={{ color: 'text.secondary', p: 2 }}>
No hay turnos recurrentes pendientes.
</Typography>
) : (
<div className={style.grid}>
{pendingRepeats.map(repeat => (
<Card key={repeat.id} className={style.card}>
<CardContent>
<Typography variant="subtitle1" fontWeight="bold">
{repeat.clientName}
</Typography>
<Typography variant="body2" color="text.secondary">
{repeat.serviceName} con {repeat.employeeName}
</Typography>
<Typography variant="body2" sx={{ mt: 1, color: "var(--wine-red)", fontWeight: "bold" }}>
{dayjs(repeat.pendingDate).format("dddd DD/MM HH:mm")} hs.
</Typography>
<Box sx={{ mt: 2, display: "flex", justifyContent: "flex-end" }}>
<Button
text="Crear Turno"
color="primary"
onClick={() => handleCreateAppointment(repeat)}
/>
</Box>
</CardContent>
</Card>
))}
</div>
)}
</Box>
</ThemeProvider>
);
};
export default PendingRepeatsCard;
@@ -0,0 +1,26 @@
.container {
width: 100%;
margin-bottom: 24px;
padding: 16px;
background-color: #fff9fa;
border: 1px solid var(--wine-red);
border-radius: 8px;
}
.title {
color: var(--wine-red);
margin-bottom: 16px !important;
font-weight: 600 !important;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 16px;
}
.card {
border-radius: 8px !important;
box-shadow: 0 2px 8px rgba(0,0,0,0.05) !important;
border: 1px solid #eaeaea;
}