feat(leads): Lead Creation Phase 1 — page shell, section framework, mock data

- CreateLeadPage.jsx: full page shell with Quick Capture / Full Form toggle, Barlow Condensed header, breadcrumb nav, GSAP progress bar stub, mobile sticky save footer
- LeadSectionWrapper.jsx: collapsible section component with Framer Motion height animation, spring chevron rotation, completion dot, dual light/dark header design matching GlassPanel language
- 5 sections wired up: Contact (blue), Property (emerald), Job Details (amber), Insurance (violet), Assignment (cyan) — Quick Capture shows first 3, Full Form shows all 5
- Section indicator pills in header dim gracefully when hidden in Quick Capture mode
- LEAD_FORM_OPTIONS added to mockStore: lead types, sources, work types, trade types, urgency/priority levels, insurance companies, claim statuses, phone/email types, US states
- Route /emp/fa/leads/new added (FIELD_AGENT, ADMIN, OWNER)
- New Lead nav item added to sidebar for all 3 roles
This commit is contained in:
Satyam
2026-03-13 16:07:29 +05:30
parent dc117e8180
commit 8bb321e1f7
5 changed files with 523 additions and 2 deletions
+5 -2
View File
@@ -5,7 +5,7 @@ import { useTheme } from '../context/ThemeContext';
import {
LayoutDashboard, Map, Calendar, LogOut, User, Home, MessageSquare,
ChevronLeft, ChevronRight, Sun, Moon, Trophy, Users, Briefcase,
FileText, Menu, X, Calculator
FileText, Menu, X, Calculator, PlusCircle
} from 'lucide-react';
import PageTransition from './PageTransition';
@@ -137,10 +137,11 @@ const Layout = () => {
{ to: "/owner/snapshot", icon: LayoutDashboard, label: "Owners Box" },
{ to: "/admin/dashboard", icon: LayoutDashboard, label: "Dashboard" },
{ to: "/owner/projects", icon: Briefcase, label: "Projects" },
{ to: "/emp/fa/leads/new", icon: PlusCircle, label: "New Lead" },
{ to: "/owner/maps", icon: Map, label: "Territory Map" },
{
to: "/owner/pro-canvas",
icon: LayoutDashboard, // Placeholder icon, maybe change later
icon: LayoutDashboard,
label: <span><span className="text-[#fda913]">Pro</span>Canvas</span>
},
{ to: "/owner/estimate", icon: Calculator, label: "Estimate Builder" },
@@ -153,6 +154,7 @@ const Layout = () => {
{ to: "/admin/dashboard", icon: LayoutDashboard, label: "Dashboard" },
{ to: "/admin/schedule", icon: Calendar, label: "Schedule" },
{ to: "/admin/leaderboard", icon: Trophy, label: "Leaderboard" },
{ to: "/emp/fa/leads/new", icon: PlusCircle, label: "New Lead" },
{ to: "/admin/maps", icon: Map, label: "Territory Map" },
{
to: "/admin/pro-canvas",
@@ -179,6 +181,7 @@ const Layout = () => {
return [
{ to: "/emp/fa/dashboard", icon: LayoutDashboard, label: "Dashboard" },
{ to: "/emp/fa/maps", icon: Map, label: "My Map" },
{ to: "/emp/fa/leads/new", icon: PlusCircle, label: "New Lead" },
{
to: "/emp/fa/pro-canvas",
icon: LayoutDashboard,
+101
View File
@@ -0,0 +1,101 @@
import React from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { ChevronDown, CheckCircle2 } from 'lucide-react';
import { useTheme } from '../../context/ThemeContext';
export default function LeadSectionWrapper({
title,
icon: Icon,
accentColor,
isOpen,
onToggle,
children,
isComplete = false,
}) {
const { theme } = useTheme();
const isDark = theme === 'dark';
return (
<div className={`rounded-2xl overflow-hidden border transition-shadow duration-200
${isDark
? 'bg-zinc-900/70 backdrop-blur-xl border-white/[0.08] shadow-[0_8px_32px_rgba(0,0,0,0.3)]'
: 'bg-white border-zinc-200/60 shadow-md hover:shadow-lg'
}`}
>
{/* --- Header Button --- */}
<button
type="button"
onClick={onToggle}
className={`w-full flex items-center justify-between px-5 py-3.5 transition-opacity duration-150 hover:opacity-90 active:opacity-75
${isDark ? 'border-b border-white/[0.08]' : 'rounded-t-2xl'}
`}
style={isDark ? { backgroundColor: 'rgba(39,39,42,0.8)' } : { backgroundColor: accentColor }}
aria-expanded={isOpen}
>
{/* Left: icon + title */}
<div className="flex items-center gap-3">
{Icon && (
<Icon
size={17}
className={isDark ? '' : 'text-white'}
style={isDark ? { color: accentColor } : { opacity: 0.92 }}
/>
)}
<h3 className={`font-['Barlow_Condensed'] font-black uppercase tracking-widest text-sm
${isDark ? 'text-[#E4E4E5]' : 'text-white'}
`}>
{title}
</h3>
</div>
{/* Right: completion indicator + chevron */}
<div className="flex items-center gap-2">
<AnimatePresence>
{isComplete && (
<motion.div
initial={{ scale: 0, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
exit={{ scale: 0, opacity: 0 }}
transition={{ type: 'spring', stiffness: 400, damping: 25 }}
>
<CheckCircle2
size={15}
className={isDark ? '' : 'text-white/90'}
style={isDark ? { color: accentColor } : {}}
/>
</motion.div>
)}
</AnimatePresence>
<motion.div
animate={{ rotate: isOpen ? 180 : 0 }}
transition={{ type: 'spring', stiffness: 300, damping: 28 }}
>
<ChevronDown
size={16}
className={isDark ? 'text-zinc-400' : 'text-white/80'}
/>
</motion.div>
</div>
</button>
{/* --- Collapsible Content --- */}
<AnimatePresence initial={false}>
{isOpen && (
<motion.div
key="content"
initial={{ height: 0, opacity: 0 }}
animate={{ height: 'auto', opacity: 1 }}
exit={{ height: 0, opacity: 0 }}
transition={{ type: 'spring', stiffness: 300, damping: 32, opacity: { duration: 0.15 } }}
className="overflow-hidden"
>
<div className="p-5 pt-4">
{children}
</div>
</motion.div>
)}
</AnimatePresence>
</div>
);
}