estimate module setup and wizard ui

This commit is contained in:
Mayur Shinde
2026-06-09 14:47:25 +05:30
parent 944a745892
commit 716d096fc8
14 changed files with 1013 additions and 3 deletions
@@ -0,0 +1,106 @@
/**
* StartStep — Screen 1 "Simple Start" (spec §4 / §5).
* Captures name, property address, mobile, email, contact method + consent.
* Consent is required before proceeding (spec §15 Privacy / §3 compliance).
*/
import React from 'react';
import { User, MapPin, Phone, Mail } from 'lucide-react';
import { useEstimateWizard } from '../../EstimateWizardContext';
const Field = ({ icon: Icon, label, children }) => (
<label className="block">
<span className="text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1.5 flex items-center gap-1.5">
{Icon && <Icon size={15} className="text-amber-500" />} {label}
</span>
{children}
</label>
);
const inputCls =
'w-full rounded-xl border border-zinc-200 dark:border-white/10 bg-white dark:bg-zinc-900 px-3.5 py-2.5 ' +
'text-zinc-900 dark:text-white placeholder-zinc-400 focus:outline-none focus:ring-2 focus:ring-amber-500';
const StartStep = () => {
const { inputs, setInput } = useEstimateWizard();
return (
<div className="space-y-4">
<Field icon={User} label="Name">
<input
className={inputCls}
placeholder="First and last name"
value={inputs.name}
onChange={(e) => setInput('name', e.target.value)}
autoComplete="name"
/>
</Field>
<Field icon={MapPin} label="Property address">
<input
className={inputCls}
placeholder="Street, city, state, ZIP"
value={inputs.address}
onChange={(e) => setInput('address', e.target.value)}
autoComplete="street-address"
/>
</Field>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<Field icon={Phone} label="Mobile number">
<input
className={inputCls}
placeholder="(555) 123-4567"
value={inputs.phone}
onChange={(e) => setInput('phone', e.target.value)}
autoComplete="tel"
inputMode="tel"
/>
</Field>
<Field icon={Mail} label="Email">
<input
className={inputCls}
placeholder="you@email.com"
value={inputs.email}
onChange={(e) => setInput('email', e.target.value)}
autoComplete="email"
inputMode="email"
/>
</Field>
</div>
<div>
<span className="text-sm font-medium text-zinc-700 dark:text-zinc-300 mb-1.5 block">Best contact method?</span>
<div className="flex gap-2">
{['text', 'email', 'phone'].map((m) => (
<button
key={m}
type="button"
onClick={() => setInput('contactMethod', m)}
className={`flex-1 rounded-xl border px-3 py-2 text-sm font-medium capitalize transition-all
${inputs.contactMethod === m
? 'border-amber-500 bg-amber-50 dark:bg-amber-500/10 text-amber-700 dark:text-amber-300'
: 'border-zinc-200 dark:border-white/10 text-zinc-600 dark:text-zinc-300 hover:border-amber-400'}`}
>
{m}
</button>
))}
</div>
</div>
<label className="flex items-start gap-2.5 rounded-xl bg-zinc-50 dark:bg-white/5 p-3.5 cursor-pointer">
<input
type="checkbox"
className="mt-0.5 h-4 w-4 accent-amber-500"
checked={inputs.consent}
onChange={(e) => setInput('consent', e.target.checked)}
/>
<span className="text-xs text-zinc-600 dark:text-zinc-400 leading-relaxed">
I agree to be contacted about my roof estimate and understand my address and any insurance
details I provide are used to generate this educational report. This is not a binding quote.
</span>
</label>
</div>
);
};
export default StartStep;