feat: comentario al completar turno, Google Sheets corregido, scheduling 8:30-17 5 slots, mejoras responsive
Deploy / deploy (push) Failing after 12m35s
Deploy / deploy (push) Failing after 12m35s
- Agrega campo comentario opcional al marcar turno COMPLETADO (textarea en UI, guardado en DB, escrito en col N del sheet) - Corrige mapeo Google Sheets: email→I, telefono→J, vacíos en K-M, comentario→N - Actualiza scheduling: inicio 8:30, fin 17:00, máx 5 turnos simultáneos - entrypoint.sh: migrate deploy → db push para aplicar cambios de schema automáticamente - Historial cliente: tarjetas visuales con header, fecha y observaciones destacadas - Dashboard/turnos cliente: mejoras responsive mobile - Fix display duración: 0.5 hs → "30 min" Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+27
-20
@@ -1,21 +1,30 @@
|
||||
import { prisma } from "./prisma";
|
||||
|
||||
const SLOTS_PARALELOS = 4; // 2 jefes × 2 autos c/u
|
||||
const HORA_INICIO = 8;
|
||||
const HORA_FIN = 18;
|
||||
const SLOTS_PARALELOS = 5;
|
||||
const INICIO_H = 8;
|
||||
const INICIO_M = 30;
|
||||
const FIN_H = 17;
|
||||
const FIN_M = 0;
|
||||
const INICIO_MINUTOS = INICIO_H * 60 + INICIO_M; // 510
|
||||
const FIN_MINUTOS = FIN_H * 60 + FIN_M; // 1020
|
||||
|
||||
function esDiaHabil(fecha: Date): boolean {
|
||||
const dia = fecha.getDay(); // 0=Dom, 6=Sab
|
||||
const dia = fecha.getDay();
|
||||
return dia >= 1 && dia <= 5;
|
||||
}
|
||||
|
||||
function horasDentroDeJornada(inicio: Date, fin: Date): boolean {
|
||||
const h1 = inicio.getHours() + inicio.getMinutes() / 60;
|
||||
const h2 = fin.getHours() + fin.getMinutes() / 60;
|
||||
return h1 >= HORA_INICIO && h2 <= HORA_FIN;
|
||||
function minutosDelDia(fecha: Date): number {
|
||||
return fecha.getHours() * 60 + fecha.getMinutes();
|
||||
}
|
||||
|
||||
function horasDentroDeJornada(inicio: Date, fin: Date): boolean {
|
||||
return (
|
||||
minutosDelDia(inicio) >= INICIO_MINUTOS &&
|
||||
minutosDelDia(fin) <= FIN_MINUTOS &&
|
||||
inicio.toDateString() === fin.toDateString()
|
||||
);
|
||||
}
|
||||
|
||||
// Devuelve cuántos turnos activos se superponen con el rango dado
|
||||
async function turnosSolapados(inicio: Date, fin: Date): Promise<number> {
|
||||
const count = await prisma.turno.count({
|
||||
where: {
|
||||
@@ -34,7 +43,6 @@ export interface SlotDisponible {
|
||||
fechaFin: Date;
|
||||
}
|
||||
|
||||
// Busca los próximos N slots disponibles para una duración dada (en horas)
|
||||
export async function obtenerSlotsDisponibles(
|
||||
duracionHoras: number,
|
||||
diasAdelante = 14
|
||||
@@ -47,29 +55,29 @@ export async function obtenerSlotsDisponibles(
|
||||
fechaLimite.setDate(fechaLimite.getDate() + diasAdelante);
|
||||
|
||||
let cursor = new Date(ahora);
|
||||
// Empezar desde el siguiente slot redondo (media hora)
|
||||
// Avanzar al siguiente slot de :00 o :30
|
||||
cursor.setMinutes(cursor.getMinutes() >= 30 ? 60 : 30, 0, 0);
|
||||
|
||||
while (cursor < fechaLimite && slots.length < 20) {
|
||||
if (!esDiaHabil(cursor)) {
|
||||
cursor.setDate(cursor.getDate() + 1);
|
||||
cursor.setHours(HORA_INICIO, 0, 0, 0);
|
||||
cursor.setHours(INICIO_H, INICIO_M, 0, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
const hInicio = cursor.getHours() + cursor.getMinutes() / 60;
|
||||
if (hInicio < HORA_INICIO) {
|
||||
cursor.setHours(HORA_INICIO, 0, 0, 0);
|
||||
if (minutosDelDia(cursor) < INICIO_MINUTOS) {
|
||||
cursor.setHours(INICIO_H, INICIO_M, 0, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
const fin = new Date(cursor.getTime() + duracionMs);
|
||||
const hFin = fin.getHours() + fin.getMinutes() / 60;
|
||||
|
||||
if (hFin > HORA_FIN) {
|
||||
// Pasar al día siguiente
|
||||
if (
|
||||
fin.toDateString() !== cursor.toDateString() ||
|
||||
minutosDelDia(fin) > FIN_MINUTOS
|
||||
) {
|
||||
cursor.setDate(cursor.getDate() + 1);
|
||||
cursor.setHours(HORA_INICIO, 0, 0, 0);
|
||||
cursor.setHours(INICIO_H, INICIO_M, 0, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -78,7 +86,6 @@ export async function obtenerSlotsDisponibles(
|
||||
slots.push({ fechaInicio: new Date(cursor), fechaFin: new Date(fin) });
|
||||
}
|
||||
|
||||
// Avanzar 30 minutos
|
||||
cursor = new Date(cursor.getTime() + 30 * 60 * 1000);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user