From 7c8ecb7563b534dc693bcc519c78700fd7a30514 Mon Sep 17 00:00:00 2001
From: 230417 <230417@epvc.pt>
Date: Thu, 12 Mar 2026 17:23:09 +0000
Subject: [PATCH] =?UTF-8?q?corre=C3=A7=C3=A3o?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
web/src/pages/Booking.tsx | 357 +++++++++++++++++++++++---------------
1 file changed, 213 insertions(+), 144 deletions(-)
diff --git a/web/src/pages/Booking.tsx b/web/src/pages/Booking.tsx
index bda3253..1afcefe 100644
--- a/web/src/pages/Booking.tsx
+++ b/web/src/pages/Booking.tsx
@@ -29,16 +29,24 @@ export default function Booking() {
const [barberId, setBarber] = useState('');
const [date, setDate] = useState('');
const [slot, setSlot] = useState('');
+ const [step, setStep] = useState(searchParams.get('service') ? 2 : 1);
// Sincroniza o serviceId se o parâmetro mudar (ex: navegação interna)
useEffect(() => {
const s = searchParams.get('service');
- if (s) setService(s);
+ if (s) {
+ setService(s);
+ setStep(2);
+ }
}, [searchParams]);
const selectedService = shop?.services.find((s) => s.id === serviceId);
const selectedBarber = shop?.barbers.find((b) => b.id === barberId);
+ // Avanço automático por efeito colateral (opcional, mas vamos fazer por clique para ser mais explícito)
+ const nextStep = () => setStep((s) => Math.min(s + 1, 4));
+ const prevStep = () => setStep((s) => Math.max(s - 1, 1));
+
/**
* Função para gerar horários padrão se não houver horários específicos predefinidos
* pelo barbeiro na Base de Dados.
@@ -111,173 +119,234 @@ export default function Booking() {
};
const steps = [
- { id: 1, label: 'Serviço', icon: Scissors, completed: !!serviceId },
- { id: 2, label: 'Barbeiro', icon: User, completed: !!barberId },
- { id: 3, label: 'Data', icon: Calendar, completed: !!date },
- { id: 4, label: 'Horário', icon: Clock, completed: !!slot },
+ { id: 1, label: 'Serviço', icon: Scissors, completed: !!serviceId, active: step === 1 },
+ { id: 2, label: 'Barbeiro', icon: User, completed: !!barberId, active: step === 2 },
+ { id: 3, label: 'Data', icon: Calendar, completed: !!date, active: step === 3 },
+ { id: 4, label: 'Horário', icon: Clock, completed: !!slot, active: step === 4 },
];
return (
-
-
Agendar em {shop.name}
-
{shop.address}
+
+
+
Agendar em {shop.name}
+
{shop.address}
+
+ {step > 1 && (
+
+ )}
{/* Progress Steps */}
-
- {steps.map((step, idx) => (
-
+
+ {steps.map((s, idx) => (
+
-
{
+ if (s.completed || s.id < step) setStep(s.id);
+ }}
+ disabled={!s.completed && s.id > step}
+ className={`w-10 h-10 rounded-full flex items-center justify-center border-2 transition-all ${s.active
+ ? 'bg-amber-600 border-amber-600 text-white shadow-lg ring-4 ring-amber-100'
+ : s.completed
+ ? 'bg-amber-500 border-amber-500 text-white'
+ : 'bg-white border-slate-200 text-slate-400'
}`}
>
- {step.completed ? : }
-
-
- {step.label}
+ {s.completed && !s.active ? : }
+
+
+ {s.label}
{idx < steps.length - 1 && (
-
+
)}
))}
-
- {/* Step 1: Service */}
-
-
-
-
1. Escolha o serviço
-
-
- {shop.services.map((s) => (
-
- ))}
-
-
-
- {/* Step 2: Barber */}
-
-
-
-
2. Escolha o barbeiro
-
-
- {shop.barbers.map((b) => (
-
- ))}
-
-
-
- {/* Step 3 & 4: Date & Time */}
-
-
-
-
-
3. Escolha a data
+
+ {/* Step Info Summary (Show what was already selected) */}
+ {step > 1 && selectedService && (
+
+
+
+
+
+
+
Serviço Selecionado
+
{selectedService.name}
+
-
setDate(e.target.value)}
- min={new Date().toISOString().split('T')[0]}
- />
-
-
-
-
-
4. Escolha o horário
-
-
- {!barberId || !date ? (
-
Escolha primeiro o barbeiro e a data.
- ) : availableSlots.length > 0 ? (
- availableSlots.map((h) => (
-
- ))
- ) : (
-
Nenhum horário disponível para esta data.
- )}
-
-
-
-
- {/* Summary */}
- {canSubmit && selectedService && (
-
-
Resumo do agendamento
-
-
- Serviço:
- {selectedService.name}
-
-
- Barbeiro:
- {selectedBarber?.name}
-
-
- Data e hora:
-
- {new Date(date).toLocaleDateString('pt-BR')} às {slot}
-
-
-
- Total:
- {currency(selectedService.price)}
-
+
+
{currency(selectedService.price)}
)}
-
+ {step > 2 && selectedBarber && (
+
+
+
+
+
+
Barbeiro
+
{selectedBarber.name}
+
+
+ )}
+
+ {/* Dynamic Step Content */}
+
+ {step === 1 && (
+
+
+
1
+
Escolha o serviço
+
+
+ {shop.services.map((s) => (
+
+ ))}
+
+
+ )}
+
+ {step === 2 && (
+
+
+
2
+
Escolha o barbeiro
+
+
+ {shop.barbers.map((b) => (
+
+ ))}
+
+
+ )}
+
+ {step === 3 && (
+
+
+
+ {
+ setDate(e.target.value);
+ if (e.target.value) setStep(4);
+ }}
+ min={new Date().toISOString().split('T')[0]}
+ className="text-lg py-6"
+ />
+
+
+ )}
+
+ {step === 4 && (
+
+
+
4
+
Escolha o horário
+
+
+
+
+
+ {new Date(date).toLocaleDateString('pt-PT', { day: 'numeric', month: 'long', year: 'numeric' })}
+
+
+
+
+
+ {availableSlots.length > 0 ? (
+ availableSlots.map((h) => (
+
+ ))
+ ) : (
+
+
Infelizmente não há horários livres para este dia.
+
+ )}
+
+
+ {/* Final Summary & Confirmation */}
+ {canSubmit && (
+
+
+
+
Total a pagar
+
{currency(selectedService?.price || 0)}
+
+
+
+
+ )}
+
+ )}
+
);
}
-
-
-
-
-