From 2e22c112d3c96294de15223c05db13be03829df8 Mon Sep 17 00:00:00 2001 From: Sidney Date: Sun, 19 Jul 2026 22:06:33 -0300 Subject: [PATCH] =?UTF-8?q?feat:=20for=C3=A7ar=20configura=C3=A7=C3=B5es?= =?UTF-8?q?=20de=20agendamento=20na=20pagina=20publica=20(limites=20de=20a?= =?UTF-8?q?nteced=C3=AAncia=20e=20bloqueio=20online)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/[slug]/agendar/page.tsx | 34 ++++++++++++++++++++++++++--- src/app/api/tenant/profile/route.ts | 2 ++ 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/app/[slug]/agendar/page.tsx b/src/app/[slug]/agendar/page.tsx index afefce2..2024a1c 100644 --- a/src/app/[slug]/agendar/page.tsx +++ b/src/app/[slug]/agendar/page.tsx @@ -26,6 +26,7 @@ export default function PublicBookingPage({ params }: { params: Promise<{ slug: const [establishment, setEstablishment] = useState({ name: '', type: 'barbearia', description: '', phone: '', address: '', rating: 5.0, reviews: 0, + allowOnlineBooking: true, bookingAdvanceMin: 60, bookingAdvanceMaxDays: 30 }); // Algoritmo dinâmico de fatiamento de grade @@ -68,6 +69,9 @@ export default function PublicBookingPage({ params }: { params: Promise<{ slug: address: fullAddress || '', rating: 5.0, reviews: 0, + allowOnlineBooking: profile.allowOnlineBooking !== false, + bookingAdvanceMin: profile.bookingAdvanceMin || 60, + bookingAdvanceMaxDays: profile.bookingAdvanceMaxDays || 30, }); // Gerar slots com horários do tenant @@ -105,7 +109,8 @@ export default function PublicBookingPage({ params }: { params: Promise<{ slug: }, [slug]); const today = new Date(); - const dates = Array.from({ length: 14 }, (_, i) => { + const maxDays = establishment.bookingAdvanceMaxDays || 30; + const dates = Array.from({ length: maxDays }, (_, i) => { const d = new Date(today); d.setDate(d.getDate() + i); return d; @@ -195,6 +200,20 @@ export default function PublicBookingPage({ params }: { params: Promise<{ slug: ); } + if (!establishment.allowOnlineBooking && !booked) { + return ( +
+
+
+ +
+

Agendamento Indisponível

+

O agendamento online está temporariamente desativado para este estabelecimento. Por favor, entre em contato diretamente pelo WhatsApp ou telefone.

+
+
+ ); + } + return (
{/* HEADER */} @@ -334,7 +353,16 @@ export default function PublicBookingPage({ params }: { params: Promise<{ slug: Horários disponíveis
- {(slots.length > 0 ? slots : ['09:00', '09:30', '10:00', '10:30', '11:00', '11:30', '14:00', '14:30', '15:00', '15:30', '16:00', '16:30', '17:00', '17:30', '18:00']).map(slot => ( + {(slots.length > 0 ? slots : ['09:00', '09:30', '10:00', '10:30', '11:00', '11:30', '14:00', '14:30', '15:00', '15:30', '16:00', '16:30', '17:00', '17:30', '18:00']).map(slot => { + const isToday = selectedDate === today.toISOString().split('T')[0]; + const [sh, sm] = slot.split(':').map(Number); + const slotMinutes = sh * 60 + sm; + const currentMinutes = today.getHours() * 60 + today.getMinutes(); + const isPastOrTooSoon = isToday && (slotMinutes < currentMinutes + (establishment.bookingAdvanceMin || 60)); + + if (isPastOrTooSoon) return null; + + return (
setSelectedTime(slot)} style={{ padding: '12px', borderRadius: 'var(--radius-sm)', cursor: 'pointer', textAlign: 'center', fontWeight: 600, fontSize: '14px', transition: 'all 0.2s', @@ -344,7 +372,7 @@ export default function PublicBookingPage({ params }: { params: Promise<{ slug: }}> {slot}
- ))} + )})}
)} diff --git a/src/app/api/tenant/profile/route.ts b/src/app/api/tenant/profile/route.ts index a5d6fc1..76b7bc6 100644 --- a/src/app/api/tenant/profile/route.ts +++ b/src/app/api/tenant/profile/route.ts @@ -45,6 +45,8 @@ export async function GET(req: NextRequest) { interval: settings.interval || 30, workingDays: settings.working_days || [1, 2, 3, 4, 5, 6], allowOnlineBooking: settings.allow_online_booking !== false, + bookingAdvanceMin: settings.booking_advance_min || 60, + bookingAdvanceMaxDays: settings.booking_advance_max_days || 30, }); } catch (error: any) { console.error('GET Profile error:', error);