feat(09-03): create multistep quote form components (3 steps)
- QuoteMultistep.tsx (110 lines): Parent component managing step state and navigation with visual indicator - QuoteStep1Overview.tsx: Read-only overview with offer name, total price, and phase list - QuoteStep2Selection.tsx: Phase/service listing (read-only MVP) with calculated total - QuoteStep3Summary.tsx: Summary card with optional email and notes capture, Accept/Reject buttons All components use shadcn/ui with Tailwind styling and follow accessibility patterns. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import type { PublicQuoteView } from "@/lib/quote-service";
|
||||
import { QuoteStep1Overview } from "./QuoteStep1Overview";
|
||||
import { QuoteStep2Selection } from "./QuoteStep2Selection";
|
||||
import { QuoteStep3Summary } from "./QuoteStep3Summary";
|
||||
|
||||
interface QuoteMultistepProps {
|
||||
quote: PublicQuoteView;
|
||||
}
|
||||
|
||||
export function QuoteMultistep({ quote }: QuoteMultistepProps) {
|
||||
const [currentStep, setCurrentStep] = useState(1);
|
||||
|
||||
const handleNextStep = () => {
|
||||
if (currentStep < 3) {
|
||||
setCurrentStep(currentStep + 1);
|
||||
}
|
||||
};
|
||||
|
||||
const handlePrevStep = () => {
|
||||
if (currentStep > 1) {
|
||||
setCurrentStep(currentStep - 1);
|
||||
}
|
||||
};
|
||||
|
||||
// Step progress indicator
|
||||
const stepIndicator = (
|
||||
<div className="flex items-center justify-center gap-2 mb-6">
|
||||
{[1, 2, 3].map((step) => (
|
||||
<div key={step} className="flex items-center">
|
||||
<div
|
||||
className={`w-8 h-8 rounded-full flex items-center justify-center font-semibold text-sm ${
|
||||
step <= currentStep
|
||||
? "bg-blue-600 text-white"
|
||||
: "bg-slate-200 text-slate-600"
|
||||
}`}
|
||||
>
|
||||
{step}
|
||||
</div>
|
||||
{step < 3 && (
|
||||
<div
|
||||
className={`w-8 h-0.5 ${
|
||||
step < currentStep ? "bg-blue-600" : "bg-slate-200"
|
||||
}`}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{stepIndicator}
|
||||
|
||||
{currentStep === 1 && (
|
||||
<QuoteStep1Overview
|
||||
quote={quote}
|
||||
onNext={handleNextStep}
|
||||
/>
|
||||
)}
|
||||
|
||||
{currentStep === 2 && (
|
||||
<QuoteStep2Selection
|
||||
quote={quote}
|
||||
onNext={handleNextStep}
|
||||
onPrev={handlePrevStep}
|
||||
/>
|
||||
)}
|
||||
|
||||
{currentStep === 3 && (
|
||||
<QuoteStep3Summary
|
||||
quote={quote}
|
||||
onPrev={handlePrevStep}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user