nxtgauge-frontend-solid/src/components/admin/DashboardDesignPreview.tsx

6671 lines
454 KiB
TypeScript
Raw Normal View History

import { For, Show, createEffect, createMemo, createResource, createSignal, onMount } from 'solid-js';
import {
Plus, Search, ArrowRight, Clock, User, BookOpen, AlertCircle, Save, X,
LayoutGrid, List, CheckCircle, Edit2, Trash2, Globe, Lock,
Rocket, TrendingUp, ShieldCheck, Mail, Phone, MapPin,
ChevronRight, ChevronLeft, ChevronDown, ChevronUp,
Download, Filter, MoreVertical, Star, HelpCircle,
Award, Bell, BadgeCheck, Bookmark, BriefcaseBusiness, Calendar,
Camera, CheckCircle2, Clapperboard, Compass, Coins, Code2,
Dumbbell, Eye, FileText, GraduationCap, HandHelping,
HeadphonesIcon, Image, LogOut, Megaphone, PenTool,
RefreshCw, Scissors, Settings, Settings2, UtensilsCrossed,
UserCircle2, Users,
} from 'lucide-solid';
import { RuntimeKBConfig, RuntimeKBArticle } from '../../lib/runtime/types';
function titleCase(value: string) {
return String(value || '')
.replace(/_/g, ' ')
.replace(/\b\w/g, (c) => c.toUpperCase());
}
const ORANGE_ICON_FILTER = 'invert(51%) sepia(86%) saturate(2445%) hue-rotate(353deg) brightness(101%) contrast(103%)';
const BLUE_ICON_FILTER = 'invert(11%) sepia(85%) saturate(2462%) hue-rotate(233deg) brightness(91%) contrast(101%)';
function StatusBadge(props: { status: 'ACTIVE' | 'INACTIVE' }) {
const active = () => props.status === 'ACTIVE';
return (
<span style={`display:inline-flex;align-items:center;border-radius:9999px;border:1px solid ${active() ? '#FFD8C2' : '#D1D5DB'};background:${active() ? '#FFF1EB' : '#F3F4F6'};color:${active() ? '#FF5E13' : '#4B5563'};padding:2px 10px;font-size:12px;font-weight:500`}>
{active() ? 'Active' : 'Inactive'}
</span>
);
}
function sidebarIcon(label: string) {
const key = String(label || '').toLowerCase().trim();
if (key.includes('dashboard')) return LayoutGrid;
if (key.includes('portfolio')) return Image;
if (key.includes('profile')) return UserCircle2;
if (key.includes('lead')) return HandHelping;
if (key.includes('response')) return FileText;
if (key.includes('credit')) return Coins;
if (key.includes('explore')) return Compass;
if (key.includes('verification')) return BadgeCheck;
if (key.includes('support') || key.includes('help center')) return HeadphonesIcon;
if (key === 'settings') return Settings2;
if (key.includes('switch role') || key.includes('switch services') || key.includes('switch service')) return RefreshCw;
if (key.includes('logout')) return LogOut;
if (key.includes('job')) return BriefcaseBusiness;
if (key.includes('application')) return FileText;
if (key.includes('shortlisted')) return Users;
if (key.includes('saved')) return Bookmark;
if (key.includes('requirement')) return FileText;
return LayoutGrid;
}
type CustomerView = {
title: string;
subtitle: string;
tabs: string[];
cta?: string;
};
type ProfileSpec = {
title: string;
subtitle: string;
tabs: string[];
tabFields: Record<string, string[]>;
};
function normalizeRoleKey(roleKey: string): string {
const key = String(roleKey || '').toUpperCase();
if (key.includes('COMPANY')) return 'COMPANY';
if (key.includes('CUSTOMER')) return 'CUSTOMER';
if (key.includes('SERVICE_SEEKER')) return 'CUSTOMER';
if (key.includes('JOB_SEEKER') || key.includes('JOBSEEKER')) return 'JOB_SEEKER';
if (key.includes('PHOTOGRAPHER')) return 'PHOTOGRAPHER';
if (key.includes('MAKEUP')) return 'MAKEUP_ARTIST';
if (key.includes('DEVELOPER')) return 'DEVELOPER';
if (key.includes('VIDEO')) return 'VIDEO_EDITOR';
if (key.includes('UGC') || (key.includes('CONTENT') && key.includes('CREATOR'))) return 'UGC_CONTENT_CREATOR';
if (key.includes('GRAPHIC')) return 'GRAPHIC_DESIGNER';
if (key.includes('SOCIAL')) return 'SOCIAL_MEDIA_MANAGER';
if (key.includes('FITNESS')) return 'FITNESS_TRAINER';
if (key.includes('TUTOR')) return 'TUTOR';
if (key.includes('CATER')) return 'CATERING_SERVICES';
return 'PROFESSIONAL';
}
const PROFILE_SPECS: Record<string, ProfileSpec> = {
CUSTOMER: {
title: 'Service Seeker Profile',
subtitle: 'Manage your personal details, service preferences, documents, and account settings.',
tabs: ['basic information', 'documents', 'settings'],
tabFields: {
'basic information': ['First Name', 'Last Name', 'Email Address', 'Mobile Number', 'Area', 'Place', 'PIN Code', 'Service Category'],
documents: ['Identity Proof', 'Address Proof'],
settings: ['Password & Login', 'Notification Preferences', 'Privacy Controls'],
},
},
COMPANY: {
title: 'Company Profile',
subtitle: 'Configure organization details, hiring preferences, compliance documents, and settings.',
tabs: ['basic information', 'documents', 'settings'],
tabFields: {
'basic information': ['Company Name', 'Company Email', 'Company Phone', 'City', 'Area', 'Place', 'PIN Code', 'Website URL'],
documents: ['GST Certificate', 'PAN Card', 'Incorporation Certificate'],
settings: ['Account Security', 'Team Access', 'Notification Preferences'],
},
},
JOB_SEEKER: {
title: 'Job Seeker Profile',
subtitle: 'Maintain your career profile, resume, preferences, and verification docs.',
tabs: ['basic information', 'documents', 'settings'],
tabFields: {
'basic information': ['First Name', 'Last Name', 'Email Address', 'Mobile Number', 'Current Role', 'Total Experience', 'City', 'Area', 'Place'],
documents: ['Identity Proof', 'Address Proof', 'Education Proof'],
settings: ['Password & Login', 'Notification Preferences', 'Privacy Controls'],
},
},
PHOTOGRAPHER: {
title: 'Photographer Profile',
subtitle: 'Manage your photography details, pricing, portfolio, and documents.',
tabs: ['basic information', 'documents', 'settings'],
tabFields: {
'basic information': ['First Name', 'Last Name', 'Email Address', 'Mobile Number', 'Gender', 'Address Line 1', 'Address Line 2 (Optional)', 'City', 'Area', 'State', 'PIN Code'],
documents: ['Identity Proof', 'Address Proof', 'Portfolio Ownership Proof'],
settings: ['Password & Login', 'Notification Preferences', 'Privacy Controls'],
},
},
MAKEUP_ARTIST: {
title: 'Makeup Artist Profile',
subtitle: 'Manage makeup specialization, services, portfolio, and compliance documents.',
tabs: ['basic information', 'documents', 'settings'],
tabFields: {
'basic information': ['First Name', 'Last Name', 'Email Address', 'Mobile Number', 'Gender', 'Address Line 1', 'Address Line 2 (Optional)', 'City', 'Area', 'State', 'PIN Code'],
documents: ['Identity Proof', 'Address Proof', 'Professional Certifications'],
settings: ['Password & Login', 'Notification Preferences', 'Privacy Controls'],
},
},
DEVELOPER: {
title: 'Developer Profile',
subtitle: 'Showcase technical profile, pricing models, portfolio projects, and documents.',
tabs: ['basic information', 'documents', 'settings'],
tabFields: {
'basic information': ['First Name', 'Last Name', 'Email Address', 'Mobile Number', 'Gender', 'Address Line 1', 'Address Line 2 (Optional)', 'City', 'Area', 'State', 'PIN Code'],
documents: ['Identity Proof', 'Address Proof', 'Tax Document'],
settings: ['Password & Login', 'Notification Preferences', 'Privacy Controls'],
},
},
VIDEO_EDITOR: {
title: 'Video Editor Profile',
subtitle: 'Manage editing profile, services, portfolio, and verification documents.',
tabs: ['basic information', 'documents', 'settings'],
tabFields: {
'basic information': ['First Name', 'Last Name', 'Email Address', 'Mobile Number', 'Gender', 'Address Line 1', 'Address Line 2 (Optional)', 'City', 'Area', 'State', 'PIN Code'],
documents: ['Identity Proof', 'Address Proof', 'Tax Document'],
settings: ['Password & Login', 'Notification Preferences', 'Privacy Controls'],
},
},
UGC_CONTENT_CREATOR: {
title: 'UGC Content Creator Profile',
subtitle: 'Manage your creator profile, content style, pricing, and portfolio deliverables.',
tabs: ['basic information', 'documents', 'settings'],
tabFields: {
'basic information': ['First Name', 'Last Name', 'Email Address', 'Mobile Number', 'Gender', 'Address Line 1', 'Address Line 2 (Optional)', 'City', 'Area', 'State', 'PIN Code'],
documents: ['Identity Proof', 'Address Proof', 'Tax Document'],
settings: ['Password & Login', 'Notification Preferences', 'Privacy Controls'],
},
},
GRAPHIC_DESIGNER: {
title: 'Graphic Designer Profile',
subtitle: 'Manage design profile, service pricing, portfolio assets, and documents.',
tabs: ['basic information', 'documents', 'settings'],
tabFields: {
'basic information': ['First Name', 'Last Name', 'Email Address', 'Mobile Number', 'Gender', 'Address Line 1', 'Address Line 2 (Optional)', 'City', 'Area', 'State', 'PIN Code'],
documents: ['Identity Proof', 'Address Proof', 'Tax Document'],
settings: ['Password & Login', 'Notification Preferences', 'Privacy Controls'],
},
},
SOCIAL_MEDIA_MANAGER: {
title: 'Social Media Manager Profile',
subtitle: 'Manage social profile details, service plans, case studies, and documents.',
tabs: ['basic information', 'documents', 'settings'],
tabFields: {
'basic information': ['First Name', 'Last Name', 'Email Address', 'Mobile Number', 'Gender', 'Address Line 1', 'Address Line 2 (Optional)', 'City', 'Area', 'State', 'PIN Code'],
documents: ['Identity Proof', 'Address Proof', 'Tax Document'],
settings: ['Password & Login', 'Notification Preferences', 'Privacy Controls'],
},
},
FITNESS_TRAINER: {
title: 'Fitness Trainer Profile',
subtitle: 'Manage training details, plans, certifications, and profile settings.',
tabs: ['basic information', 'documents', 'settings'],
tabFields: {
'basic information': ['First Name', 'Last Name', 'Email Address', 'Mobile Number', 'Gender', 'Address Line 1', 'Address Line 2 (Optional)', 'City', 'Area', 'State', 'PIN Code'],
documents: ['Identity Proof', 'Address Proof', 'Certification Proof'],
settings: ['Password & Login', 'Notification Preferences', 'Privacy Controls'],
},
},
TUTOR: {
title: 'Tutor Profile',
subtitle: 'Manage teaching details, subjects, pricing, documents, and settings.',
tabs: ['basic information', 'documents', 'settings'],
tabFields: {
'basic information': ['First Name', 'Last Name', 'Email Address', 'Mobile Number', 'Gender', 'Address Line 1', 'Address Line 2 (Optional)', 'City', 'Area', 'State', 'PIN Code'],
documents: ['Identity Proof', 'Address Proof', 'Educational Proof'],
settings: ['Password & Login', 'Notification Preferences', 'Privacy Controls'],
},
},
CATERING_SERVICES: {
title: 'Catering Services Profile',
subtitle: 'Manage business details, menu packages, gallery, and compliance docs.',
tabs: ['basic information', 'documents', 'settings'],
tabFields: {
'basic information': ['Business Name', 'Contact Person Name', 'Email Address', 'Mobile Number', 'Gender', 'Address Line 1', 'Address Line 2 (Optional)', 'City', 'Area', 'State', 'PIN Code'],
documents: ['Identity Proof', 'Address Proof', 'Food License'],
settings: ['Password & Login', 'Notification Preferences', 'Privacy Controls'],
},
},
PROFESSIONAL: {
title: 'Professional Profile',
subtitle: 'Manage professional details, pricing, portfolio, and account settings.',
tabs: ['basic information', 'documents', 'settings'],
tabFields: {
'basic information': ['Full Name', 'Email Address', 'Mobile Number', 'Gender', 'Address Line 1', 'Address Line 2 (Optional)', 'City', 'Area', 'State', 'PIN Code'],
documents: ['Identity Proof', 'Address Proof', 'Tax Document'],
settings: ['Password & Login', 'Notification Preferences', 'Privacy Controls'],
},
},
};
function profileSpecForRole(roleKey: string): ProfileSpec {
const normalized = normalizeRoleKey(roleKey);
const base = PROFILE_SPECS[normalized] || PROFILE_SPECS.PROFESSIONAL;
const existingDocuments = Array.isArray(base.tabFields?.documents) ? base.tabFields.documents : [];
const documents = Array.from(new Set(['Address', 'Address Proof', ...existingDocuments]));
return {
...base,
tabFields: {
...base.tabFields,
documents,
},
};
}
type PortfolioSpec = {
roleLabel: string;
tabs: string[];
specialties: string[];
statsLabels: string[];
equipmentLabel: string;
galleryTabLabel: string;
experienceTabLabel: string;
serviceTabLabel: string;
faqItems: Array<{ q: string; a: string }>;
packages: Array<{ name: string; price: string; items: string[] }>;
};
const PORTFOLIO_SPECS: Record<string, PortfolioSpec> = {
PHOTOGRAPHER: {
roleLabel: 'Photographer',
tabs: ['about', 'services & pricing', 'portfolio gallery', 'experience & equipment', 'testimonials', 'faqs'],
specialties: ['Wedding', 'Pre-Wedding', 'Candid', 'Event', 'Portrait', 'Lifestyle'],
statsLabels: ['Shoots Done', 'Years Exp', 'Verified Pro', 'Last Delivery', 'Will Travel'],
equipmentLabel: 'Camera & Equipment',
galleryTabLabel: 'portfolio gallery',
experienceTabLabel: 'experience & equipment',
serviceTabLabel: 'services & pricing',
faqItems: [
{ q: 'Do you travel for shoots?', a: 'Yes, I cover Pan-India and select international locations. Travel charges apply beyond 50km.' },
{ q: 'How long before I receive the final photos?', a: 'Edited photos are delivered within 1014 working days after the shoot.' },
{ q: 'What equipment do you use?', a: 'I shoot with Canon EOS R6 and Sony A7IV, with a full range of prime and zoom lenses.' },
{ q: 'Do you provide raw files?', a: 'Raw files are not included by default. They can be added as an optional upgrade.' },
],
packages: [
{ name: 'Essential', price: '₹15,000', items: ['4-hour shoot', '100 edited photos', 'Online gallery', '1 location'] },
{ name: 'Premium', price: '₹28,000', items: ['8-hour shoot', '250 edited photos', 'Online gallery', '2 locations', 'Drone shots'] },
{ name: 'Signature', price: '₹50,000', items: ['Full-day shoot', '500 edited photos', 'USB delivery', '3 locations', 'Drone + Reel'] },
],
},
MAKEUP_ARTIST: {
roleLabel: 'Makeup Artist',
tabs: ['about', 'services & pricing', 'gallery', 'experience & certifications', 'testimonials', 'faqs'],
specialties: ['Bridal', 'Party', 'Editorial', 'SFX', 'Airbrush', 'Natural'],
statsLabels: ['Sessions Done', 'Years Exp', 'Verified Pro', 'Last Booking', 'Will Travel'],
equipmentLabel: 'Kit & Products',
galleryTabLabel: 'gallery',
experienceTabLabel: 'experience & certifications',
serviceTabLabel: 'services & pricing',
faqItems: [
{ q: 'Do you do trials before the wedding?', a: 'Yes, a bridal trial is mandatory. It helps finalise the look and ensures comfort on the big day.' },
{ q: 'Which brands do you use?', a: 'I work with MAC, Huda Beauty, Fenty, and NARS for face. Products are selected based on skin type.' },
{ q: 'Do you travel for events?', a: 'Yes. Travel is available with prior notice. Charges apply for locations beyond 30km.' },
{ q: 'How long does bridal makeup take?', a: 'Typically 2.53 hours for full bridal. Party makeup takes around 4560 minutes.' },
],
packages: [
{ name: 'Party', price: '₹3,500', items: ['Full face makeup', 'Hair styling', '45-min session', 'Touch-up kit'] },
{ name: 'Bridal', price: '₹18,000', items: ['Trial session', 'Full bridal look', 'HD & airbrush', 'Touch-up on-site'] },
{ name: 'Bridal Party', price: '₹35,000', items: ['Bride + 4 family', 'Full day', 'Airbrush finish', 'On-site artist'] },
],
},
TUTOR: {
roleLabel: 'Tutor',
tabs: ['about', 'subjects & pricing', 'student work', 'qualifications', 'testimonials', 'faqs'],
specialties: ['Mathematics', 'Physics', 'Chemistry', 'Biology', 'English', 'Programming'],
statsLabels: ['Students Taught', 'Years Exp', 'Verified Pro', 'Next Slot', 'Online OK'],
equipmentLabel: 'Teaching Tools',
galleryTabLabel: 'student work',
experienceTabLabel: 'qualifications',
serviceTabLabel: 'subjects & pricing',
faqItems: [
{ q: 'Do you teach online or in-person?', a: 'Both modes available. Online via Zoom or Google Meet. In-person in Chennai and surrounding areas.' },
{ q: 'What boards do you cover?', a: 'CBSE, ICSE, State Board, IB, and A-Levels. I also prepare students for JEE and NEET.' },
{ q: 'How many students per batch?', a: 'Group batches have max 5 students. Individual sessions are 1-on-1 for focused learning.' },
{ q: 'Do you provide study material?', a: 'Yes. Custom notes, practice sheets, and mock tests are included in all plans.' },
],
packages: [
{ name: 'Crash Course', price: '₹5,000/mo', items: ['10 sessions/month', '1 subject', 'Practice tests', 'Online only'] },
{ name: 'Core Plan', price: '₹8,500/mo', items: ['16 sessions/month', '2 subjects', 'Study materials', 'Doubt clearing'] },
{ name: 'Intensive', price: '₹14,000/mo', items: ['24 sessions/month', '3 subjects', 'Mock exams', 'Progress reports'] },
],
},
DEVELOPER: {
roleLabel: 'Developer',
tabs: ['about', 'services & pricing', 'projects', 'tech stack & experience', 'testimonials', 'faqs'],
specialties: ['Web Development', 'Mobile Apps', 'API / Backend', 'UI/UX', 'DevOps', 'Consulting'],
statsLabels: ['Projects Done', 'Years Exp', 'Verified Pro', 'Last Delivery', 'Remote OK'],
equipmentLabel: 'Tech Stack',
galleryTabLabel: 'projects',
experienceTabLabel: 'tech stack & experience',
serviceTabLabel: 'services & pricing',
faqItems: [
{ q: 'Do you work on fixed price or hourly?', a: 'Both models available. Small projects are fixed-price; larger engagements use hourly or milestone billing.' },
{ q: 'Do you sign NDAs?', a: 'Yes. NDAs are standard for all client projects involving proprietary data or unreleased products.' },
{ q: 'Can you handle full-stack?', a: 'Yes. I cover React/SolidJS frontend, Rust/Node backend, PostgreSQL databases, and cloud deployment.' },
{ q: 'What is your typical delivery time?', a: 'Landing pages in 35 days. Full apps depend on scope. Detailed estimate provided after briefing.' },
],
packages: [
{ name: 'Starter', price: '₹20,000', items: ['Landing page / MVP', '5-day delivery', '2 revisions', 'Basic SEO'] },
{ name: 'Business', price: '₹65,000', items: ['Full web app', '3-week delivery', 'API integration', 'Admin panel', 'Deployment'] },
{ name: 'Enterprise', price: 'Custom', items: ['Complex systems', 'Dedicated sprint', 'Team collaboration', 'SLA included'] },
],
},
VIDEO_EDITOR: {
roleLabel: 'Video Editor',
tabs: ['about', 'services & pricing', 'showreel', 'experience & tools', 'testimonials', 'faqs'],
specialties: ['Wedding Films', 'Corporate', 'Music Videos', 'Reels', 'Documentary', 'Product'],
statsLabels: ['Videos Done', 'Years Exp', 'Verified Pro', 'Last Delivery', 'Remote OK'],
equipmentLabel: 'Editing Suite',
galleryTabLabel: 'showreel',
experienceTabLabel: 'experience & tools',
serviceTabLabel: 'services & pricing',
faqItems: [
{ q: 'Which editing software do you use?', a: 'Adobe Premiere Pro, DaVinci Resolve, and After Effects for motion graphics and colour grading.' },
{ q: 'What is your turnaround time?', a: 'Short reels in 23 days. Full event films take 1015 working days depending on footage length.' },
{ q: 'Do you accept raw footage from other cameras?', a: 'Yes. Any format is accepted — I handle transcoding as part of the workflow.' },
{ q: 'How many revisions are included?', a: '2 revisions are included in all packages. Additional revisions are charged at ₹500 per round.' },
],
packages: [
{ name: 'Reel Edit', price: '₹3,000', items: ['Up to 60s reel', 'Music sync', '2 revisions', '48hr delivery'] },
{ name: 'Event Film', price: '₹12,000', items: ['5-min highlight', 'Colour grade', 'Titles + music', '10-day delivery'] },
{ name: 'Feature Film', price: '₹28,000', items: ['Full-length film', 'Cinematic grade', 'Motion graphics', 'Multi-format export'] },
],
},
UGC_CONTENT_CREATOR: {
roleLabel: 'UGC Content Creator',
tabs: ['about', 'services & pricing', 'content portfolio', 'experience & tools', 'testimonials', 'faqs'],
specialties: ['UGC Ads', 'Product Demos', 'Lifestyle UGC', 'Voiceover', 'Scripted Reels', 'Performance Creatives'],
statsLabels: ['Campaigns Done', 'Years Exp', 'Verified Pro', 'Last Delivery', 'Remote OK'],
equipmentLabel: 'Creator Setup',
galleryTabLabel: 'content portfolio',
experienceTabLabel: 'experience & tools',
serviceTabLabel: 'services & pricing',
faqItems: [
{ q: 'Do you create scripts for UGC ads?', a: 'Yes. Script ideation and hooks are included in campaign packages based on your brand goals.' },
{ q: 'Can you deliver platform-specific formats?', a: 'Yes. I deliver optimized cuts for Instagram, YouTube Shorts, and TikTok formats.' },
{ q: 'Are raw files included?', a: 'Raw files are optional and available as an add-on depending on package scope.' },
{ q: 'What is your turnaround time?', a: 'Most UGC deliverables are completed in 35 business days after brief and product receipt.' },
],
packages: [
{ name: 'Starter UGC', price: '₹7,500', items: ['1 video creative', 'Script + hook', 'Vertical format', '2 revisions'] },
{ name: 'Growth UGC', price: '₹18,000', items: ['3 video creatives', 'Platform variations', 'Usage rights', '4 revisions'] },
{ name: 'Scale UGC', price: '₹35,000', items: ['6 video creatives', 'A/B hook variants', 'Ad-ready exports', 'Priority delivery'] },
],
},
GRAPHIC_DESIGNER: {
roleLabel: 'Graphic Designer',
tabs: ['about', 'services & pricing', 'portfolio', 'experience & tools', 'testimonials', 'faqs'],
specialties: ['Brand Identity', 'UI/UX Design', 'Print', 'Social Media', 'Motion', 'Packaging'],
statsLabels: ['Projects Done', 'Years Exp', 'Verified Pro', 'Last Delivery', 'Remote OK'],
equipmentLabel: 'Design Tools',
galleryTabLabel: 'portfolio',
experienceTabLabel: 'experience & tools',
serviceTabLabel: 'services & pricing',
faqItems: [
{ q: 'What file formats do you deliver?', a: 'Final files in AI, PDF, PNG, SVG, and any format required. Print-ready and web-optimised variants included.' },
{ q: 'Do you create brand guidelines?', a: 'Yes. Brand identity packages include a full style guide covering colour, typography, and usage rules.' },
{ q: 'How many concepts do you provide initially?', a: '3 initial concepts are presented for branding. UI/UX starts with wireframes before visual designs.' },
{ q: 'Do you handle printing coordination?', a: 'Yes. I work with trusted print vendors and can manage end-to-end print production.' },
],
packages: [
{ name: 'Logo Pack', price: '₹8,000', items: ['3 logo concepts', '2 revisions', 'All file formats', 'Usage rights'] },
{ name: 'Brand Kit', price: '₹22,000', items: ['Logo + palette', 'Typography', 'Brand guidelines', 'Social templates'] },
{ name: 'Full Identity', price: '₹45,000', items: ['Complete brand', 'UI kit', 'Print collateral', 'Motion logo'] },
],
},
SOCIAL_MEDIA_MANAGER: {
roleLabel: 'Social Media Manager',
tabs: ['about', 'services & pricing', 'case studies', 'experience & tools', 'testimonials', 'faqs'],
specialties: ['Instagram', 'YouTube', 'LinkedIn', 'Twitter/X', 'Facebook', 'Content Strategy'],
statsLabels: ['Brands Managed', 'Years Exp', 'Verified Pro', 'Last Campaign', 'Remote OK'],
equipmentLabel: 'Platforms & Tools',
galleryTabLabel: 'case studies',
experienceTabLabel: 'experience & tools',
serviceTabLabel: 'services & pricing',
faqItems: [
{ q: 'Do you create the content too?', a: 'Yes. Content creation — including copy, graphics, and reels — is included in all monthly retainer plans.' },
{ q: 'How do you measure results?', a: 'Monthly reports covering reach, engagement rate, follower growth, and link clicks are shared via dashboard.' },
{ q: 'Do you handle paid ads?', a: 'Yes. Meta and Google ad campaigns are available as add-ons with dedicated reporting.' },
{ q: 'What industries do you specialise in?', a: 'Fashion, F&B, real estate, personal brands, and D2C e-commerce. Industry-specific content strategy provided.' },
],
packages: [
{ name: 'Starter', price: '₹12,000/mo', items: ['2 platforms', '12 posts/month', 'Captions + hashtags', 'Monthly report'] },
{ name: 'Growth', price: '₹22,000/mo', items: ['3 platforms', '24 posts/month', 'Reels + Stories', 'Ad management'] },
{ name: 'Premium', price: '₹40,000/mo', items: ['5 platforms', 'Daily posting', 'Full content calendar', 'Influencer outreach'] },
],
},
FITNESS_TRAINER: {
roleLabel: 'Fitness Trainer',
tabs: ['about', 'training plans', 'client results', 'certifications', 'testimonials', 'faqs'],
specialties: ['Weight Loss', 'Strength', 'Yoga', 'HIIT', 'Nutrition', 'Rehabilitation'],
statsLabels: ['Clients Trained', 'Years Exp', 'Certified Pro', 'Next Slot', 'Online OK'],
equipmentLabel: 'Certifications & Tools',
galleryTabLabel: 'client results',
experienceTabLabel: 'certifications',
serviceTabLabel: 'training plans',
faqItems: [
{ q: 'Do you offer online training?', a: 'Yes. Online sessions via Zoom with personalised programs tracked through fitness apps.' },
{ q: 'Is nutrition guidance included?', a: 'Basic nutrition guidance is included. A detailed meal plan is available as an add-on.' },
{ q: 'How long until I see results?', a: 'Visible progress typically begins in 46 weeks with consistent training and diet adherence.' },
{ q: 'Do you design custom workout plans?', a: 'Yes. Every client gets a custom plan based on fitness level, goals, and equipment access.' },
],
packages: [
{ name: 'Starter', price: '₹4,000/mo', items: ['8 sessions/month', 'Workout plan', 'WhatsApp check-ins', 'Progress tracking'] },
{ name: 'Transform', price: '₹8,000/mo', items: ['16 sessions/month', 'Custom diet plan', 'Weekly reviews', 'App access'] },
{ name: 'Elite', price: '₹15,000/mo', items: ['Daily check-in', 'Full nutrition plan', 'Body composition tracking', 'Priority access'] },
],
},
CATERING_SERVICES: {
roleLabel: 'Catering Services',
tabs: ['about', 'packages & pricing', 'gallery', 'experience & certifications', 'testimonials', 'faqs'],
specialties: ['Weddings', 'Corporate Events', 'Private Parties', 'Buffet', 'Live Counters', 'Theme Catering'],
statsLabels: ['Events Done', 'Years Active', 'Certified', 'Last Event', 'Pan-India'],
equipmentLabel: 'Equipment & Certifications',
galleryTabLabel: 'gallery',
experienceTabLabel: 'experience & certifications',
serviceTabLabel: 'packages & pricing',
faqItems: [
{ q: 'What is your minimum guest count?', a: 'Minimum 50 guests for standard bookings. Intimate private dining available for 20+ guests.' },
{ q: 'Do you handle equipment setup?', a: 'Yes. Full setup including chafing dishes, serving counters, and staff is included in all packages.' },
{ q: 'Are custom menus available?', a: 'Absolutely. Menus are fully customisable — dietary restrictions, regional cuisines, and themed menus accommodated.' },
{ q: 'How far in advance should I book?', a: 'At least 34 weeks for events under 200 guests; 68 weeks for large-scale events.' },
],
packages: [
{ name: 'Essential', price: '₹350/plate', items: ['3-course menu', 'Serving staff', 'Basic setup', 'Buffet style'] },
{ name: 'Premium', price: '₹650/plate', items: ['5-course menu', 'Live counters', 'Themed decor', 'Dedicated manager'] },
{ name: 'Royal', price: '₹1,200/plate', items: ['Custom menu', 'Chef station', 'Premium décor', 'Full-day service'] },
],
},
PROFESSIONAL: {
roleLabel: 'Professional',
tabs: ['about', 'services & pricing', 'portfolio', 'experience', 'testimonials', 'faqs'],
specialties: ['Primary Service', 'Secondary Service', 'Consulting', 'Training', 'Events', 'Custom'],
statsLabels: ['Projects Done', 'Years Exp', 'Verified Pro', 'Last Delivery', 'Remote OK'],
equipmentLabel: 'Tools & Equipment',
galleryTabLabel: 'portfolio',
experienceTabLabel: 'experience',
serviceTabLabel: 'services & pricing',
faqItems: [
{ q: 'How do I get started?', a: 'Send a requirement, review the professional\'s profile, and accept the request to receive their contact details.' },
{ q: 'What is your availability?', a: 'Availability is updated regularly on the profile. Contact for specific date confirmation.' },
{ q: 'Do you provide a contract?', a: 'Yes. A service agreement is shared before any project begins for mutual clarity.' },
{ q: 'What is your revision policy?', a: 'Revisions are included as per the selected package. Additional revisions are billed separately.' },
],
packages: [
{ name: 'Basic', price: 'From ₹5,000', items: ['Core deliverables', 'Standard timeline', '1 revision', 'Email support'] },
{ name: 'Standard', price: 'From ₹15,000', items: ['Full scope', 'Priority delivery', '3 revisions', 'Call support'] },
{ name: 'Premium', price: 'Custom', items: ['Custom scope', 'Dedicated support', 'Unlimited revisions', 'SLA'] },
],
},
};
function portfolioSpecForRole(roleKey: string): PortfolioSpec {
const normalized = normalizeRoleKey(roleKey);
return PORTFOLIO_SPECS[normalized] || PORTFOLIO_SPECS.PROFESSIONAL;
}
function portfolioMediaConfig(roleKey: string): {
mode: 'visual' | 'non_visual';
ctaLabel: string;
items: string[];
} {
const normalized = normalizeRoleKey(roleKey);
if (
normalized === 'PHOTOGRAPHER'
|| normalized === 'MAKEUP_ARTIST'
|| normalized === 'VIDEO_EDITOR'
|| normalized === 'UGC_CONTENT_CREATOR'
|| normalized === 'GRAPHIC_DESIGNER'
|| normalized === 'SOCIAL_MEDIA_MANAGER'
|| normalized === 'CATERING_SERVICES'
|| normalized === 'DEVELOPER'
|| normalized === 'FITNESS_TRAINER'
) {
return {
mode: 'visual',
ctaLabel: 'Upload Images',
items: ['Campaign Shot', 'Result Highlight', 'Before/After', 'Client Output', 'Style Board', 'Final Delivery', 'Portfolio Select', 'Recent Work'],
};
}
return {
mode: 'non_visual',
ctaLabel: 'Add Work Entry',
items: ['Case Study Summary', 'Outcome & Metrics', 'Client Feedback Snippet', 'Delivery Timeline', 'Method & Process', 'Proof of Work'],
};
}
const PORTFOLIO_TESTIMONIALS = [
{ name: 'Priya S.', rating: 5, text: 'Absolutely brilliant work. The results exceeded every expectation. Highly recommended.', category: 'Verified Booking' },
{ name: 'Rohan M.', rating: 5, text: 'Professional, punctual, and highly creative. Loved the final deliverables.', category: 'Verified Booking' },
{ name: 'Ananya K.', rating: 4, text: 'Great communication throughout the project. Delivered on time with excellent quality.', category: 'Verified Booking' },
{ name: 'Kiran T.', rating: 5, text: 'An absolute pleasure to work with. Will definitely hire again for our next project.', category: 'Verified Booking' },
];
function customerViewFor(sidebar: string, roleKey: string): CustomerView {
const key = String(sidebar || '').toLowerCase().trim();
const role = normalizeRoleKey(roleKey);
const isProfessionalRole = role !== 'COMPANY' && role !== 'JOB_SEEKER' && role !== 'CUSTOMER';
if (key === 'my dashboard') return { title: 'Service Seeker Dashboard Overview', subtitle: 'Manage your requirements and track professional responses in real-time.', tabs: ['overview', 'recent requirements', 'quick actions'], cta: 'Post New Requirement' };
if (key === 'leads') return { title: 'Leads', subtitle: 'Browse marketplace requirements and request contact access for current opportunities.', tabs: [], cta: 'Buy Credits' };
if (key === 'jobs') {
if (role === 'JOB_SEEKER') return { title: 'Jobs', subtitle: 'Scroll through approved jobs, filter opportunities, and apply with your job seeker profile.', tabs: ['all jobs', 'recommended', 'saved', 'applied', 'expiring soon'], cta: 'Post A Resume' };
return { title: 'Post Job', subtitle: 'Create a job, submit it for approval, and publish it to attract the right candidates.', tabs: [], cta: 'Post New Job' };
}
if (key === 'my requirements') return { title: 'My Requirements Management', subtitle: 'Manage and track active service requests, drafts, and closed items.', tabs: ['all requirements', 'open', 'closed', 'drafts'], cta: 'Post New Requirement' };
if (key === 'received responses' || key === 'my responses') {
if (role !== 'CUSTOMER') return { title: 'My Responses', subtitle: 'Track requested and pending leads with current request status.', tabs: ['requested leads', 'pending leads'] };
return { title: 'Received Professional Responses', subtitle: 'Review and manage professional applications for active requirements.', tabs: ['all responses', 'new', 'shortlisted', 'rejected'] };
}
if (key === 'shortlisted responses') return { title: 'Shortlisted Responses', subtitle: 'Focus on high-intent responses and convert them to confirmed engagements.', tabs: ['all shortlisted', 'interview scheduled', 'finalized'] };
if (key === 'applications') return { title: 'Applications', subtitle: 'Review all candidate applications received for your active job postings.', tabs: ['all applications', 'shortlisted', 'under review', 'rejected'], cta: 'View Job Postings' };
if (key === 'shortlisted candidates') return { title: 'Shortlisted Candidates', subtitle: 'Manage candidates you have shortlisted across all job postings.', tabs: ['shortlisted', 'interview scheduled', 'offer extended'] };
if (key === 'my applications') return { title: 'My Applications', subtitle: 'Track the status of all jobs you have applied to.', tabs: ['all', 'under review', 'shortlisted', 'rejected'], cta: 'Browse Jobs' };
if (key === 'saved jobs') return { title: 'Saved Jobs', subtitle: 'Jobs you have bookmarked. Apply before they expire.', tabs: ['saved', 'expiring soon'], cta: 'Browse Jobs' };
if (key.includes('profile')) {
const spec = profileSpecForRole(roleKey);
return { title: spec.title, subtitle: spec.subtitle, tabs: spec.tabs, cta: 'Save Changes' };
}
if (key === 'my portfolio') {
if (!isProfessionalRole) {
return { title: 'Portfolio Unavailable', subtitle: 'My Portfolio is available only for professional roles.', tabs: [] };
}
const spec = portfolioSpecForRole(roleKey);
return { title: `${spec.roleLabel} Portfolio`, subtitle: 'Manage your public portfolio, showcase your work, and control what service seekers see before they accept your contact request.', tabs: spec.tabs, cta: 'Edit Portfolio' };
}
if (key === 'credits') return { title: 'Credits & Billing', subtitle: 'View credit balance, top-up packages, and transaction history.', tabs: ['overview', 'buy credits', 'transactions', 'usage history'], cta: 'Buy Credits' };
if (key === 'explore nxtgauge') return { title: 'Explore Marketplace', subtitle: 'Discover top-tier professionals and specialized services.', tabs: [] };
if (key === 'verification') return { title: 'Verification Portal', subtitle: 'Track verification progress, documents, and updates.', tabs: ['approval status', 'documents', 'activity'] };
if (key === 'help center' || key === 'support') return { title: 'Help Center', subtitle: 'Get help, manage tickets, and contact support.', tabs: [] };
if (key === 'settings') return { title: 'Account & Privacy Settings', subtitle: 'Configure account security and privacy preferences.', tabs: ['account', 'privacy', 'notifications'] };
if (key === 'switch role' || key === 'switch services' || key === 'switch service') return { title: 'Service Switcher Portal', subtitle: 'Switch to approved services without logging out.', tabs: ['available services', 'pending approvals', 'onboarding'] };
if (key === 'logout') return { title: 'Logout Confirmation', subtitle: 'Confirm before ending your current session.', tabs: ['confirm logout', 'cancel'] };
return { title: 'Service Seeker Dashboard', subtitle: 'Preview service seeker dashboard flow.', tabs: ['overview'] };
}
const REQUIREMENT_ROWS = [
{
id: '#REQ-9012',
title: 'Wedding Shoot in Goa',
summary: 'Traditional & drone coverage',
category: 'PHOTOGRAPHER',
amount: '₹50,000',
budget: '₹50,000 - ₹80,000',
location: 'Goa (On-site)',
submission: 'Oct 24, 2023',
status: 'approved',
responses: 5,
responseTag: 'Active (5 Responses)',
},
{
id: '#REQ-8945',
title: 'E-commerce Portal Redesign',
summary: 'Next.js + Tailwind CSS specialist',
category: 'DEVELOPER',
amount: '₹1,20,000',
budget: '₹1,20,000 - ₹2,00,000',
location: 'Remote',
submission: 'Nov 02, 2023',
status: 'under review',
responses: 0,
responseTag: 'In Review',
},
{
id: '#REQ-8832',
title: 'Corporate Brand Identity',
summary: 'Logo, stationery & guidelines',
category: 'UI DESIGNER',
amount: '₹35,000',
budget: '₹35,000 Flat',
location: 'Mumbai (Hybrid)',
submission: 'Oct 15, 2023',
status: 'rejected',
responses: 0,
responseTag: 'Closed',
},
{
id: '#REQ-9108',
title: 'Home Fitness Program',
summary: '12-week transformation plan',
category: 'FITNESS TRAINER',
amount: '₹18,000',
budget: '₹18,000 - ₹28,000',
location: 'Chennai (Online + Offline)',
submission: 'Nov 08, 2023',
status: 'active',
responses: 3,
responseTag: 'New (3 Responses)',
},
{
id: '#REQ-9121',
title: 'Product Launch Promo Video',
summary: 'Scripted edit + motion graphics',
category: 'VIDEO EDITOR',
amount: '₹40,000',
budget: '₹40,000 - ₹70,000',
location: 'Remote',
submission: 'Nov 10, 2023',
status: 'draft',
responses: 0,
responseTag: 'Draft',
},
{
id: '#REQ-8660',
title: 'Weekly Maths Coaching',
summary: 'Class 10 board-focused tutoring',
category: 'TUTOR',
amount: '₹8,000',
budget: '₹8,000 - ₹14,000',
location: 'Pune (Online)',
submission: 'Sep 28, 2023',
status: 'closed',
responses: 12,
responseTag: 'Completed',
},
];
const REQUIREMENT_ROLE_OPTIONS = [
{ key: 'PHOTOGRAPHER', title: 'Photographer', desc: 'Capture moments with professional event, portrait, or commercial photography.', icon: '/sidebar-icons/photographer.svg' },
{ key: 'MAKEUP_ARTIST', title: 'Makeup Artist', desc: 'Professional styling for weddings, film, or editorial shoots.', icon: '/sidebar-icons/makeup-artist.svg' },
{ key: 'TUTOR', title: 'Tutor', desc: 'Expert guidance for academic subjects, languages, or specialized skills.', icon: '/sidebar-icons/tutor.svg' },
{ key: 'DEVELOPER', title: 'Developer', desc: 'Build websites, mobile apps, or enterprise software solutions.', icon: '/sidebar-icons/developers.svg' },
{ key: 'VIDEO_EDITOR', title: 'Video Editor', desc: 'Professional post-production for YouTube, film, or social media content.', icon: '/sidebar-icons/report.svg' },
{ key: 'UGC_CONTENT_CREATOR', title: 'UGC Content Creator', desc: 'Create user-generated content for ads, social campaigns, and product promotions.', icon: '/sidebar-icons/report.svg' },
{ key: 'FITNESS_TRAINER', title: 'Fitness Trainer', desc: 'Personalized workout plans and health coaching for your goals.', icon: '/sidebar-icons/users.svg' },
{ key: 'CATERING_SERVICES', title: 'Catering Services', desc: 'High-quality food services for events, corporate parties, and weddings.', icon: '/sidebar-icons/order.svg' },
{ key: 'GRAPHIC_DESIGNER', title: 'Graphic Designer', desc: 'Creative branding, logo design, and visual marketing assets.', icon: '/sidebar-icons/designation.svg' },
{ key: 'SOCIAL_MEDIA_MANAGER', title: 'Social Media Manager', desc: 'Strategic growth and content management for your online presence.', icon: '/sidebar-icons/leads.svg' },
];
const REQUIREMENT_ROLE_DETAILS: Record<string, { title: string; subtitle: string; fields: string[]; toggles: string[]; styles: string[] }> = {
PHOTOGRAPHER: {
title: 'Photography Details',
subtitle: 'Tell us more about the shoot to get accurate quotes.',
fields: ['Event Type', 'Shoot Type', 'Event Date & Time', 'Event Duration (Hours)', 'Venue / Location', 'Number of People', 'Delivery Deadline'],
toggles: ['Outdoor Shoot', 'Drone Required', 'Physical Album'],
styles: ['Black & White', 'Vintage', 'Cinematic', 'Fine Art'],
},
MAKEUP_ARTIST: {
title: 'Makeup Service Details',
subtitle: 'Share look preferences and event details for precise proposals.',
fields: ['Event Type', 'Makeup Category', 'Event Date & Time', 'Artists Required', 'Venue / Location', 'Skin Tone Preference', 'Ready By Time'],
toggles: ['Trial Session Required', 'Hair Styling Included', 'Travel Included'],
styles: ['Natural', 'Glam', 'HD', 'Airbrush'],
},
TUTOR: {
title: 'Tutoring Requirement Details',
subtitle: 'Specify class details so tutors can send the right plan.',
fields: ['Subject', 'Class / Grade', 'Mode (Online / Offline)', 'Sessions Per Week', 'Preferred Start Date', 'Student Location', 'Exam Goal'],
toggles: ['1-on-1 Sessions', 'Homework Support', 'Weekly Progress Reports'],
styles: ['Concept Focused', 'Exam Focused', 'Crash Course', 'Practice Heavy'],
},
DEVELOPER: {
title: 'Development Requirement Details',
subtitle: 'Add technical scope details for better estimates.',
fields: ['Project Type', 'Platform', 'Preferred Stack', 'Project Duration', 'Launch Deadline', 'Team Size Needed', 'Support Duration'],
toggles: ['UI/UX Included', 'API Development', 'Post-launch Maintenance'],
styles: ['MVP', 'Scale-ready', 'Enterprise', 'Performance-first'],
},
VIDEO_EDITOR: {
title: 'Video Editing Details',
subtitle: 'Tell us the output style and timeline for quick delivery.',
fields: ['Video Category', 'Final Duration', 'Footage Volume', 'Delivery Date', 'Editing Style', 'Platform', 'Revision Rounds'],
toggles: ['Color Grading', 'Subtitles', 'Motion Graphics'],
styles: ['Cinematic', 'Social Reels', 'Corporate', 'Documentary'],
},
UGC_CONTENT_CREATOR: {
title: 'UGC Campaign Details',
subtitle: 'Share campaign objective and deliverables for accurate creator proposals.',
fields: ['Campaign Goal', 'Platform', 'Deliverables Needed', 'Brand Category', 'Delivery Deadline', 'Target Audience', 'Usage Rights Duration'],
toggles: ['Script Support', 'Voiceover Needed', 'Product Shipping Required'],
styles: ['Product Demo', 'Lifestyle UGC', 'Hook-first Ads', 'Testimonial Style'],
},
FITNESS_TRAINER: {
title: 'Fitness Coaching Details',
subtitle: 'Share your goals and routine to match with the right coach.',
fields: ['Primary Goal', 'Current Activity Level', 'Preferred Mode', 'Training Days Per Week', 'Preferred Timings', 'Health Conditions', 'Goal Timeline'],
toggles: ['Nutrition Plan', 'Home Equipment Plan', 'Weekly Tracking'],
styles: ['Weight Loss', 'Strength', 'Mobility', 'Athletic'],
},
CATERING_SERVICES: {
title: 'Catering Requirement Details',
subtitle: 'Provide event and menu details to receive accurate quotes.',
fields: ['Event Type', 'Cuisine Preference', 'Guest Count', 'Service Date', 'Venue / Location', 'Meal Slot', 'Serving Style'],
toggles: ['Live Counters', 'Dessert Station', 'Serving Staff Included'],
styles: ['South Indian', 'North Indian', 'Continental', 'Fusion'],
},
GRAPHIC_DESIGNER: {
title: 'Design Requirement Details',
subtitle: 'Define your creative brief for better design proposals.',
fields: ['Project Type', 'Brand Industry', 'Deliverables Needed', 'Deadline', 'Target Audience', 'Reference Links', 'Output Formats'],
toggles: ['Brand Guidelines', 'Source Files', 'Print-ready Assets'],
styles: ['Minimal', 'Bold', 'Luxury', 'Playful'],
},
SOCIAL_MEDIA_MANAGER: {
title: 'Social Media Requirement Details',
subtitle: 'Tell us campaign goals and channels for the best fit.',
fields: ['Primary Goal', 'Platforms', 'Posting Frequency', 'Campaign Duration', 'Start Date', 'Brand Category', 'Monthly Budget'],
toggles: ['Reels Production', 'Ad Management', 'Community Management'],
styles: ['Growth Focused', 'Brand Awareness', 'Lead Generation', 'Content-first'],
},
};
const RESPONSE_ROWS = [
{ name: 'Julianne Vance', status: 'new', quote: '₹12,86,500' },
{ name: 'Marcus Holloway', status: 'shortlisted', quote: '₹6,80,600' },
{ name: 'Sarah Jenkins', status: 'rejected', quote: '₹4,15,000' },
{ name: 'David Wu', status: 'new', quote: '₹8,30,000' },
];
const COMPANY_JOB_STEPS = ['Job Basics', 'Role & Requirements', 'Compensation & Location', 'Screening', 'Review & Checkout'];
const COMPANY_JOB_SKILLS = ['Cloud Architecture', 'Kubernetes', 'Go/Rust', 'PostgreSQL', 'CI/CD', 'System Design'];
const LEAD_MARKETPLACE_TABS = ['All Leads', 'Recommended'];
type LeadCardStatus = 'open' | 'requested' | 'unlocked' | 'closed';
const INITIAL_PRO_LEAD_CARDS = [
{
id: 'LD-29831',
title: 'Luxury Wedding Coverage - ECR',
category: 'Wedding Photography',
location: 'Chennai, India',
area: 'ECR',
dateRequired: 'Apr 14, 2026',
urgency: 'High / Immediate',
budget: '₹2,40,000',
budgetValue: 240000,
priceRange: '₹2,00,000 - ₹2,60,000',
cost: 25,
status: 'open' as LeadCardStatus,
match: '98% match',
contactCount: 7,
maxContacts: 10,
},
{
id: 'LD-29745',
title: 'Editorial Fashion Shoot - Studio Series',
category: 'Fashion / Editorial',
location: 'Chennai, India',
area: 'Nungambakkam',
dateRequired: 'Apr 22, 2026',
urgency: 'Medium',
budget: '₹1,10,000',
budgetValue: 110000,
priceRange: '₹90,000 - ₹1,30,000',
cost: 25,
status: 'requested' as LeadCardStatus,
match: '92% match',
contactCount: 9,
maxContacts: 10,
},
{
id: 'LD-29612',
title: 'Corporate Branding Shoot - OMR Campus',
category: 'Commercial Architecture',
location: 'Chennai, India',
area: 'Sholinganallur',
dateRequired: 'May 05, 2026',
urgency: 'Low / Flexible',
budget: '₹1,85,000',
budgetValue: 185000,
priceRange: '₹1,50,000 - ₹2,10,000',
cost: 25,
status: 'unlocked' as LeadCardStatus,
match: '85% match',
contactCount: 10,
maxContacts: 10,
},
{
id: 'LD-29588',
title: 'Temple Wedding Documentary',
category: 'Traditional Wedding',
location: 'Chennai, India',
area: 'Mylapore',
dateRequired: 'Apr 30, 2026',
urgency: 'High / Immediate',
budget: '₹95,000',
budgetValue: 95000,
priceRange: '₹70,000 - ₹1,10,000',
cost: 25,
status: 'open' as LeadCardStatus,
match: '90% match',
contactCount: 4,
maxContacts: 10,
},
{
id: 'LD-29477',
title: 'Product Photography - Electronics',
category: 'E-commerce',
location: 'Chennai, India',
area: 'T Nagar',
dateRequired: 'May 12, 2026',
urgency: 'Medium',
budget: '₹75,000',
budgetValue: 75000,
priceRange: '₹50,000 - ₹90,000',
cost: 25,
status: 'open' as LeadCardStatus,
match: '88% match',
contactCount: 6,
maxContacts: 10,
},
{
id: 'LD-29340',
title: 'Corporate Leadership Portraits',
category: 'Corporate Portrait',
location: 'Chennai, India',
area: 'Guindy',
dateRequired: 'May 22, 2026',
urgency: 'Low / Flexible',
budget: '₹1,35,000',
budgetValue: 135000,
priceRange: '₹1,00,000 - ₹1,50,000',
cost: 25,
status: 'closed' as LeadCardStatus,
match: '84% match',
contactCount: 10,
maxContacts: 10,
},
];
const JOB_SEEKER_OPEN_JOBS = [
{ id: 'JOB-1001', title: 'Senior UX/UI Architect', company: 'Design System Global', location: 'San Francisco, CA (Remote)', salary: '$160k - $210k', exp: '5-7 Years Exp.', type: 'Full-time', tags: ['FIGMA', 'REACT', 'TOKEN STUDIO'], match: '98% Match', posted: 'Posted 2 hours ago' },
{ id: 'JOB-1002', title: 'Engineering Manager (Cloud Infrastructure)', company: 'FinStream Tech', location: 'London, UK (Hybrid)', salary: '£120k - £150k', exp: '8+ Years Exp.', type: 'Hybrid', tags: ['AWS', 'KUBERNETES', 'TERRAFORM'], match: '92% Match', posted: 'Posted 5 hours ago' },
{ id: 'JOB-1003', title: 'Head of Talent Acquisition', company: 'GreenGrowth HR', location: 'Remote (North America)', salary: '$130k - $180k', exp: '10+ Years Exp.', type: 'Worldwide', tags: ['RECRUITING', 'STRATEGIC HR'], match: '85% Match', posted: 'Posted 1 day ago' },
{ id: 'JOB-1004', title: 'Senior Data Scientist (LLM Focus)', company: 'Aether Intelligence', location: 'New York, NY', salary: '$200k - $250k', exp: '4+ Years Exp.', type: 'Fast Hire', tags: ['PYTHON', 'PYTORCH', 'TRANSFORMERS'], match: '95% Match', posted: 'Posted 3 hours ago' },
];
type JobBoardCard = (typeof JOB_SEEKER_OPEN_JOBS)[number];
type CompanyJobSubmissionStatus = 'VERIFICATION_PENDING' | 'VERIFIED' | 'APPROVAL_PENDING' | 'APPROVED_LIVE';
type CompanyJobSubmission = {
id: string;
job: JobBoardCard;
status: CompanyJobSubmissionStatus;
};
type CompanyJobDraft = {
title: string;
company: string;
location: string;
salary: string;
exp: string;
type: string;
tags: string[];
match: string;
posted: string;
department: string;
openings: string;
};
type RequirementRow = (typeof REQUIREMENT_ROWS)[number];
const DEFAULT_COMPANY_JOB_DRAFT: CompanyJobDraft = {
title: 'Senior Technical Architect',
company: 'Your Company',
location: 'Remote',
salary: '$80,000 - $120,000',
exp: '8+ Years Exp.',
type: 'Full-time, Permanent',
tags: COMPANY_JOB_SKILLS.slice(0, 3),
match: 'New',
posted: 'Posted just now',
department: 'Engineering & Infrastructure',
openings: '1',
};
const JOB_SEEKER_APPLIED_ROWS = [
{ id: 'APP-NX-8293', title: 'Senior Product Designer', company: 'Stripe', location: 'Remote, USA', status: 'Shortlisted', note: 'Recruiter viewed 2h ago' },
{ id: 'APP-NX-7741', title: 'Staff UX Engineer', company: 'Airbnb', location: 'San Francisco, CA', status: 'Under Review', note: 'In initial screening' },
{ id: 'APP-NX-9011', title: 'Product Marketing Lead', company: 'Notion', location: 'New York, NY', status: 'Applied', note: 'Successfully submitted' },
{ id: 'APP-NX-5529', title: 'Growth Specialist', company: 'Meta', location: 'Remote', status: 'Not Selected', note: 'Closed on Oct 10' },
];
const HELP_CENTER_CATEGORIES = [
{ title: 'Account & Login', description: 'Trouble logging in? Manage your password and account access.', articles: 24, icon: '/sidebar-icons/users.svg' },
{ title: 'Profile & Verification', description: 'How to get verified and complete your profile faster.', articles: 18, icon: '/sidebar-icons/approval.svg' },
{ title: 'Jobs & Applications', description: 'Find work and manage your active project applications.', articles: 32, icon: '/sidebar-icons/jobs.svg' },
{ title: 'Leads & Responses', description: 'Learn how to respond to incoming business leads.', articles: 15, icon: '/sidebar-icons/leads.svg' },
{ title: 'Credits & Payments', description: 'Invoices, purchasing credits, and billing history.', articles: 21, icon: '/sidebar-icons/credits.svg' },
{ title: 'Settings & Security', description: 'Manage data, sessions, and notification preferences.', articles: 12, icon: '/sidebar-icons/role.svg' },
{ title: 'Service Switching', description: 'How to switch between approved service profiles.', articles: 9, icon: '/sidebar-icons/role.svg' },
{ title: 'Support & Tickets', description: 'Track your support history and ticket updates.', articles: 14, icon: '/sidebar-icons/support.svg' },
];
const HELP_CENTER_ARTICLES = [
'How to verify your business account',
'Setting up two-factor authentication',
'Understanding lead credit balances',
'Troubleshooting mobile notifications',
'Connecting your bank account',
];
const HELP_CENTER_FAQS = [
{
q: 'What are lead credits?',
a: 'Lead credits are the internal currency on Nxtgauge. You use them to respond to new inquiries and business opportunities.',
},
{
q: 'How long does verification take?',
a: 'Most verifications complete within 24 to 72 hours, depending on document quality and review queue.',
},
{
q: 'Can I change my account service?',
a: 'Yes. Use Switch Services once your additional service registration is approved.',
},
{
q: 'What is the refund policy for credits?',
a: 'Credits follow platform policy and may be eligible for adjustment when billing issues are validated.',
},
];
const HELP_TICKET_ROWS = [
{ id: 'TCK-1042', title: 'Verification clarification required', status: 'Open', updated: '2h ago', priority: 'High', lastMessage: 'Please share GST certificate copy.' },
{ id: 'TCK-1031', title: 'Unable to see credit invoice', status: 'In Progress', updated: 'Yesterday', priority: 'Medium', lastMessage: 'Invoice regenerated and shared via email.' },
{ id: 'TCK-1007', title: 'Need onboarding status update', status: 'Resolved', updated: '3 days ago', priority: 'Low', lastMessage: 'Profile approved successfully.' },
] as const;
const HELP_TICKET_DETAILS: Record<
string,
{
userMessage: string;
adminMessage: string;
requestedDocuments: string[];
receivedFiles: Array<{ file: string; state: 'Received' | 'Pending Upload' }>;
}
> = {
'TCK-1042': {
userMessage: 'Can you confirm if any additional document is required from my side?',
adminMessage: 'Your verification is active. Please upload the pending documents listed below to avoid delays.',
requestedDocuments: ['GST Certificate', 'Authorization Letter', 'Business PAN Copy'],
receivedFiles: [
{ file: 'gst_certificate.pdf', state: 'Received' },
{ file: 'authorization_letter.jpg', state: 'Received' },
{ file: 'business_pan.pdf', state: 'Pending Upload' },
],
},
'TCK-1031': {
userMessage: 'I cannot find my latest credit invoice in billing history.',
adminMessage: 'Invoice has been regenerated. Please verify if the attached copy is visible on your billing page now.',
requestedDocuments: ['Invoice Month Confirmation'],
receivedFiles: [{ file: 'invoice_month_confirmation.txt', state: 'Received' }],
},
'TCK-1007': {
userMessage: 'Can I get an update on my onboarding review status?',
adminMessage: 'Your onboarding has been approved. No further action is pending from your side.',
requestedDocuments: [],
receivedFiles: [],
},
};
function roleIcon(roleKey: string) {
const key = String(roleKey || '').toLowerCase();
if (key.includes('photo')) return Camera;
if (key.includes('makeup')) return Scissors;
if (key.includes('tutor')) return GraduationCap;
if (key.includes('developer')) return Code2;
if (key.includes('video')) return Clapperboard;
if (key.includes('ugc') || (key.includes('content') && key.includes('creator'))) return Clapperboard;
if (key.includes('graphic')) return PenTool;
if (key.includes('social')) return Megaphone;
if (key.includes('cater')) return UtensilsCrossed;
if (key.includes('fitness')) return Dumbbell;
return BriefcaseBusiness;
}
function roleIconAsset(roleKey: string) {
const key = String(roleKey || '').toLowerCase();
if (key.includes('photo')) return '/sidebar-icons/photographer.svg';
if (key.includes('makeup')) return '/sidebar-icons/makeup-artist.svg';
if (key.includes('tutor')) return '/sidebar-icons/tutor.svg';
if (key.includes('developer')) return '/sidebar-icons/developers.svg';
if (key.includes('video')) return '';
if (key.includes('ugc') || (key.includes('content') && key.includes('creator'))) return '/sidebar-icons/report.svg';
if (key.includes('graphic')) return '/sidebar-icons/designation.svg';
if (key.includes('social')) return '/sidebar-icons/leads.svg';
if (key.includes('cater')) return '';
if (key.includes('fitness')) return '/sidebar-icons/users.svg';
if (key.includes('company')) return '/sidebar-icons/company.svg';
return '/sidebar-icons/role.svg';
}
export default function DashboardDesignPreview(props: {
status: 'ACTIVE' | 'INACTIVE';
sidebarItems: string[];
activeSidebar: string;
onSidebarSelect: (item: string) => void;
tabs: string[];
activeTab: string;
onTabSelect: (item: string) => void;
widgets: string[];
fields: string[];
mode?: 'default' | 'customer_external';
roleKey?: string;
exploreRoles?: Array<{ key: string; name: string }>;
onOpenFullscreen?: () => void;
hidePreviewHeader?: boolean;
liveData?: { userName: string; userId: string; rolePrefix: string };
}) {
const [isVerified, setIsVerified] = createSignal(false);
const [verificationPending, setVerificationPending] = createSignal(false);
const isProfessionalRoleKey = (roleKey: string) => {
const role = normalizeRoleKey(roleKey);
return role !== 'COMPANY' && role !== 'JOB_SEEKER' && role !== 'CUSTOMER';
};
const normalizeTabKey = (value: string) => String(value || '').trim().toLowerCase();
const isCustomerExternalMode = createMemo(() => props.mode === 'customer_external');
const previewSidebarItems = createMemo(() => (props.sidebarItems.length ? props.sidebarItems : ['My Dashboard', 'My Profile', 'Switch Services', 'Logout']));
const customerView = createMemo(() => customerViewFor(props.activeSidebar || previewSidebarItems()[0] || 'My Dashboard', props.roleKey || ''));
const currentProfileSpec = createMemo(() => profileSpecForRole(props.roleKey || ''));
const isJobSeekerRole = createMemo(() => normalizeRoleKey(props.roleKey || '') === 'JOB_SEEKER');
const activeTabKey = createMemo(() => normalizeTabKey(props.activeTab));
const previewTabs = createMemo(() => {
if (isCustomerExternalMode()) return customerView().tabs;
return props.tabs.length ? props.tabs : ['overview'];
});
const resolvedTabKey = createMemo(() => {
const tabs = previewTabs();
const key = activeTabKey();
return tabs.some((item) => normalizeTabKey(item) === key) ? key : normalizeTabKey(tabs[0] || '');
});
const previewWidgets = createMemo(() => (props.widgets.length ? props.widgets : ['total_requirements', 'open', 'closed', 'responses', 'saved_pros']));
const previewFields = createMemo(() => (props.fields.length ? props.fields : ['full_name', 'email', 'verification_status', 'approval_status']));
const customerKey = createMemo(() => String(props.activeSidebar || '').toLowerCase().trim());
const portfolioJobsCompletedPreview = 1;
const portfolioFeedbackCountPreview = 0;
const portfolioTestimonialsUnlocked = createMemo(() => portfolioJobsCompletedPreview >= 3 && portfolioFeedbackCountPreview >= 2);
const exploreRoleCards = createMemo(() => {
const roles = Array.isArray(props.exploreRoles) ? props.exploreRoles : [];
const activeRoles = userRoles();
const professionalOnly = roles
.filter((r) => String(r?.key || '').trim())
.filter((r) => {
const roleKey = String(r?.key || '').toLowerCase();
return !roleKey.includes('company')
&& !roleKey.includes('job_seeker')
&& !roleKey.includes('jobseeker')
&& !roleKey.includes('customer')
&& !roleKey.includes('service_seeker');
})
.map((role) => {
const roleKey = String(role.key || '').trim();
const title = String(role.name || '').trim() || titleCase(roleKey.replace(/_/g, ' ').toLowerCase());
const isRegistered = activeRoles.some((ar) => normalizeRoleKey(ar.role_key || ar.key) === normalizeRoleKey(roleKey));
const isCurrent = normalizeRoleKey(props.roleKey || '') === normalizeRoleKey(roleKey);
return {
key: roleKey,
title,
subtitle: `Apply and onboard for ${title} to unlock more opportunities on Nxtgauge.`,
status: isCurrent ? 'Active' : isRegistered ? 'Registered' : 'Available',
action: isCurrent ? 'Active' : isRegistered ? 'Switch' : 'Register',
iconAsset: roleIconAsset(roleKey),
Icon: roleIcon(roleKey),
};
});
const defaults = [
{ key: 'PHOTOGRAPHER', title: 'Photographer', subtitle: 'Capture professional moments and monetize your creative vision.', iconAsset: '/sidebar-icons/photographer.svg', Icon: Camera },
{ key: 'MAKEUP_ARTIST', title: 'Makeup Artist', subtitle: 'Offer beauty services for events and premium clientele.', iconAsset: '/sidebar-icons/makeup-artist.svg', Icon: Scissors },
{ key: 'TUTOR', title: 'Tutor', subtitle: 'Share expertise through remote and flexible teaching.', iconAsset: '/sidebar-icons/tutor.svg', Icon: GraduationCap },
{ key: 'DEVELOPER', title: 'Developer', subtitle: 'Build scalable products for high-growth businesses.', iconAsset: '/sidebar-icons/developers.svg', Icon: Code2 },
{ key: 'VIDEO_EDITOR', title: 'Video Editor', subtitle: 'Craft compelling stories with world-class editing.', iconAsset: '/sidebar-icons/report.svg', Icon: Clapperboard },
{ key: 'UGC_CONTENT_CREATOR', title: 'UGC Content Creator', subtitle: 'Create ad-ready user-generated content for brand campaigns.', iconAsset: '/sidebar-icons/report.svg', Icon: Clapperboard },
{ key: 'GRAPHIC_DESIGNER', title: 'Graphic Designer', subtitle: 'Design visual systems that brands remember.', iconAsset: '/sidebar-icons/designation.svg', Icon: PenTool },
{ key: 'SOCIAL_MEDIA_MANAGER', title: 'Social Media Manager', subtitle: 'Manage digital presence and audience growth.', iconAsset: '/sidebar-icons/leads.svg', Icon: Megaphone },
{ key: 'FITNESS_TRAINER', title: 'Fitness Trainer', subtitle: 'Coach clients on health and performance goals.', iconAsset: '/sidebar-icons/users.svg', Icon: Dumbbell },
{ key: 'CATERING_SERVICES', title: 'Catering Services', subtitle: 'Deliver high-quality catering for events and celebrations.', iconAsset: '/sidebar-icons/order.svg', Icon: UtensilsCrossed },
];
const merged = [...professionalOnly];
defaults.forEach((item) => {
if (!merged.some((row) => normalizeRoleKey(row.key) === normalizeRoleKey(item.key))) {
const isRegistered = activeRoles.some((ar) => normalizeRoleKey(ar.role_key || ar.key) === normalizeRoleKey(item.key));
const isCurrent = normalizeRoleKey(props.roleKey || '') === normalizeRoleKey(item.key);
merged.push({
...item,
status: isCurrent ? 'Active' : isRegistered ? 'Registered' : 'Available',
action: isCurrent ? 'Active' : isRegistered ? 'Switch' : 'Register'
});
}
});
return merged.slice(0, 10);
});
const [dashboardWidgetOrder, setDashboardWidgetOrder] = createSignal<string[]>([]);
const [draggingDashboardWidget, setDraggingDashboardWidget] = createSignal<string | null>(null);
const [helpCenterTab, setHelpCenterTab] = createSignal<'help_center' | 'my_tickets' | 'create_ticket'>('help_center');
const [myTicketsTab, setMyTicketsTab] = createSignal<'all_tickets' | 'view_ticket'>('all_tickets');
const [activeTicketId, setActiveTicketId] = createSignal<string>('TCK-1042');
const [openFaqIndex, setOpenFaqIndex] = createSignal<number | null>(0);
const [ticketMessage, setTicketMessage] = createSignal('');
const [createTicketFiles, setCreateTicketFiles] = createSignal<string[]>([]);
const [viewTicketFiles, setViewTicketFiles] = createSignal<string[]>([]);
const [profileFormData, setProfileFormData] = createSignal<Record<string, string>>({});
const [profileSaving, setProfileSaving] = createSignal(false);
const [profileSaveStatus, setProfileSaveStatus] = createSignal<'idle' | 'saved' | 'error'>('idle');
const [profileSettingsTab, setProfileSettingsTab] = createSignal<'change_password' | 'notifications' | 'privacy'>('change_password');
const [showDeleteAccountModal, setShowDeleteAccountModal] = createSignal(false);
const [portfolioEditMode, setPortfolioEditMode] = createSignal(false);
const [portfolioTopTab, setPortfolioTopTab] = createSignal<'my_portfolio' | 'preview'>('my_portfolio');
const [profileApprovalState, setProfileApprovalState] = createSignal<'DRAFT' | 'SUBMITTED' | 'IN_REVIEW' | 'DOCUMENTS_REQUESTED' | 'APPROVED' | 'REJECTED'>('DRAFT');
const [portfolioApprovalState, setPortfolioApprovalState] = createSignal<'DRAFT' | 'SUBMITTED' | 'IN_REVIEW' | 'DOCUMENTS_REQUESTED' | 'APPROVED' | 'REJECTED'>('DRAFT');
const [portfolioSpecialties, setPortfolioSpecialties] = createSignal<string[]>([]);
const [portfolioLanguages, setPortfolioLanguages] = createSignal<string[]>([]);
const [portfolioServiceAreas, setPortfolioServiceAreas] = createSignal<string[]>([]);
const [portfolioSpecialtyInput, setPortfolioSpecialtyInput] = createSignal('');
const [portfolioLanguageInput, setPortfolioLanguageInput] = createSignal('');
const [portfolioAreaInput, setPortfolioAreaInput] = createSignal('');
const [profileDocumentType, setProfileDocumentType] = createSignal('Aadhar Card');
const [portfolioFormValues, setPortfolioFormValues] = createSignal<Record<string, string>>({});
const [portfolioFormErrors, setPortfolioFormErrors] = createSignal<Record<string, string>>({});
const [userRoles, setUserRoles] = createSignal<any[]>([]);
const [portfolioValidationNotice, setPortfolioValidationNotice] = createSignal('');
const [portfolioServices, setPortfolioServices] = createSignal<Array<{ name: string; model: string; price: string; details: string }>>([]);
const [portfolioServiceDraft, setPortfolioServiceDraft] = createSignal<{ name: string; model: string; price: string; details: string }>({ name: '', model: 'Flat', price: '', details: '' });
const [portfolioExperiences, setPortfolioExperiences] = createSignal<Array<{ year: string; title: string; details: string }>>([]);
const [portfolioExperienceDraft, setPortfolioExperienceDraft] = createSignal<{ year: string; title: string; details: string }>({ year: '', title: '', details: '' });
const [portfolioDesignTools, setPortfolioDesignTools] = createSignal<string[]>([]);
const [portfolioToolInput, setPortfolioToolInput] = createSignal('');
const [portfolioPhotos, setPortfolioPhotos] = createSignal<string[]>([]);
const [requirementsView, setRequirementsView] = createSignal<'list' | 'new' | 'detail'>('list');
const [requirementsStep, setRequirementsStep] = createSignal(1);
const [requirementRows, setRequirementRows] = createSignal<RequirementRow[]>(REQUIREMENT_ROWS);
const [selectedRequirementRole, setSelectedRequirementRole] = createSignal('PHOTOGRAPHER');
const [selectedRequirementId, setSelectedRequirementId] = createSignal('#REQ-9012');
const [jobPostView, setJobPostView] = createSignal<'form' | 'review' | 'success'>('form');
const [jobPostStep, setJobPostStep] = createSignal(1);
const [jobBoardJobs, setJobBoardJobs] = createSignal<JobBoardCard[]>(JOB_SEEKER_OPEN_JOBS);
const [companyJobSubmissions, setCompanyJobSubmissions] = createSignal<CompanyJobSubmission[]>([]);
const [companyJobDraft] = createSignal<CompanyJobDraft>(DEFAULT_COMPANY_JOB_DRAFT);
const [jobSeekerScreen, setJobSeekerScreen] = createSignal<'list' | 'detail' | 'apply'>('list');
const [jobSeekerSelectedId, setJobSeekerSelectedId] = createSignal(JOB_SEEKER_OPEN_JOBS[0]?.id || '');
const [jobSeekerApplyStep, setJobSeekerApplyStep] = createSignal(2);
const [lastJobSeekerTabKey, setLastJobSeekerTabKey] = createSignal('');
const [leadCards, setLeadCards] = createSignal(INITIAL_PRO_LEAD_CARDS);
const [leadMarketplaceTab, setLeadMarketplaceTab] = createSignal('All Leads');
const [leadSearch, setLeadSearch] = createSignal('');
const [leadAreaFilter, setLeadAreaFilter] = createSignal('All Areas');
const [leadBudgetFilter, setLeadBudgetFilter] = createSignal('All Budgets');
const [leadDateFilter, setLeadDateFilter] = createSignal('Any Date');
const [leadSortFilter, setLeadSortFilter] = createSignal('Newest First');
const [leadFiltersOpen, setLeadFiltersOpen] = createSignal(false);
const [leadSortOpen, setLeadSortOpen] = createSignal(false);
const [leadPage, setLeadPage] = createSignal(1);
const [activeLeadDetailId, setActiveLeadDetailId] = createSignal('');
const [leadContactConfirmId, setLeadContactConfirmId] = createSignal('');
const [activeResponseLeadId, setActiveResponseLeadId] = createSignal('');
const [responsesDetailMode, setResponsesDetailMode] = createSignal(false);
const [requestedSearch, setRequestedSearch] = createSignal('');
const [requestedStatusFilter, setRequestedStatusFilter] = createSignal('All Status');
const [requestedSortFilter, setRequestedSortFilter] = createSignal('Newest First');
const [requestedSortOpen, setRequestedSortOpen] = createSignal(false);
const [requestedFilterOpen, setRequestedFilterOpen] = createSignal(false);
const [requestedPage, setRequestedPage] = createSignal(1);
const [leadCredits, setLeadCredits] = createSignal(250);
const [checkoutPackage, setCheckoutPackage] = createSignal<any | null>(null);
const [paymentStep, setPaymentStep] = createSignal<'idle' | 'processing' | 'verifying' | 'success' | 'error'>('idle');
const [paymentRef, setPaymentRef] = createSignal<string | null>(null);
const [paymentResult, setPaymentResult] = createSignal<any>(null);
const [creditManageView, setCreditManageView] = createSignal(false);
const [txRows, setTxRows] = createSignal<Array<[string, string, string, string, string, string]>>([
['#INV-2023-089', 'Enterprise Growth', '5,000', '₹1,20,000', 'Completed', 'Oct 24, 2023'],
['#INV-2023-074', 'Starter Kick', '500', '₹15,000', 'Pending', 'Oct 23, 2023'],
['#INV-2023-052', 'Pro Pack', '2,500', '₹65,000', 'Completed', 'Oct 21, 2023'],
['#INV-2023-031', 'Top-up', '1,000', '₹30,000', 'Failed', 'Oct 20, 2023'],
]);
const [leadRequestRows, setLeadRequestRows] = createSignal([
{ id: 'LD-29745', title: 'Editorial Fashion Shoot - Studio Series', city: 'Nungambakkam, Chennai', requestDate: 'Apr 02, 2026', status: 'request_sent', decisionDate: '--' },
{ id: 'LD-29612', title: 'Corporate Branding Shoot - OMR Campus', city: 'Sholinganallur, Chennai', requestDate: 'Apr 01, 2026', status: 'contact_unlocked', decisionDate: 'Apr 01, 2026' },
{ id: 'LD-29588', title: 'Temple Wedding Documentary', city: 'Mylapore, Chennai', requestDate: 'Mar 30, 2026', status: 'rejected', decisionDate: 'Mar 30, 2026' },
] as Array<{ id: string; title: string; city: string; requestDate: string; status: 'request_sent' | 'approved' | 'contact_unlocked' | 'rejected' | 'expired_refunded' | 'cancelled_by_professional'; decisionDate: string }>);
const [lastSidebarKey, setLastSidebarKey] = createSignal('');
const [profileSettingToggles, setProfileSettingToggles] = createSignal<Record<string, boolean>>({
email_updates: true,
in_app_alerts: true,
verification_reminders: true,
profile_visibility: true,
data_sharing_consent: false,
});
const toggleProfileSetting = (key: string) => {
setProfileSettingToggles((prev) => ({ ...prev, [key]: !prev[key] }));
};
const submitCompanyJobForReview = () => {
const draft = companyJobDraft();
const id = `JOB-COMP-${Date.now()}`;
const submittedJob: JobBoardCard = {
id,
title: draft.title,
company: draft.company,
location: draft.location,
salary: draft.salary,
exp: draft.exp,
type: draft.type,
tags: draft.tags,
match: draft.match,
posted: draft.posted,
};
setCompanyJobSubmissions((prev) => [{ id, job: submittedJob, status: 'VERIFICATION_PENDING' }, ...prev]);
setTimeout(() => {
setCompanyJobSubmissions((prev) => prev.map((row) => (row.id === id ? { ...row, status: 'VERIFIED' } : row)));
setTimeout(() => {
setCompanyJobSubmissions((prev) => prev.map((row) => (row.id === id ? { ...row, status: 'APPROVAL_PENDING' } : row)));
setTimeout(() => {
setCompanyJobSubmissions((prev) => prev.map((row) => (row.id === id ? { ...row, status: 'APPROVED_LIVE' } : row)));
setJobBoardJobs((prev) => [submittedJob, ...prev.filter((job) => job.id !== id)]);
setJobSeekerSelectedId(id);
}, 650);
}, 650);
}, 650);
};
const submitRequirementForReview = () => {
const roleKey = selectedRequirementRole();
const roleLabel = titleCase(roleKey.replace(/_/g, ' ').toLowerCase());
if (hasLive()) {
apiPost('/api/customers/requirements', {
profession_key: roleKey,
title: `${roleLabel} Requirement`,
description: 'Submitted via dashboard',
location: 'Chennai',
budget_min: 10000000,
budget_max: 20000000,
}).then((res: any) => res?.json?.().then((r: any) => {
// After creating, submit for approval
if (r?.id) apiPost(`/api/customers/requirements/${r.id}/submit`, {});
})).then(() => refetchRequirementsLive());
}
const id = `#REQ-${Math.floor(9200 + Math.random() * 899)}`;
const submission = new Date().toLocaleDateString('en-US', { month: 'short', day: '2-digit', year: 'numeric' });
const newRequirement: RequirementRow = {
id,
title: `${roleLabel} Requirement`,
summary: 'Submitted from customer requirement form',
category: roleKey,
amount: '₹1,50,000',
budget: '₹1,50,000 - ₹2,00,000',
location: 'Chennai (On-site)',
submission,
status: 'under review',
responses: 0,
responseTag: 'Verification Pending',
};
setRequirementRows((prev) => [newRequirement, ...prev]);
setSelectedRequirementId(id);
setRequirementsView('list');
setRequirementsStep(1);
setTimeout(() => {
setRequirementRows((prev) => prev.map((row) => (row.id === id ? { ...row, status: 'approved', responses: 0, responseTag: 'Approval Pending' } : row)));
setTimeout(() => {
setRequirementRows((prev) => prev.map((row) => (row.id === id ? { ...row, status: 'active', responses: 0, responseTag: 'Active (0 Responses)' } : row)));
setLeadCards((prev) => {
const leadId = id.replace('#REQ', 'LD');
if (prev.some((card) => card.id === leadId)) return prev;
return [
{
id: leadId,
title: newRequirement.title,
category: roleLabel,
location: 'Chennai, India',
area: 'Chennai',
dateRequired: 'May 30, 2026',
urgency: 'Medium',
budget: '₹1,50,000',
budgetValue: 150000,
priceRange: newRequirement.budget,
cost: 25,
status: 'open',
match: '90% match',
contactCount: 0,
maxContacts: 10,
},
...prev,
];
});
}, 650);
}, 650);
};
const isProfessionalRole = createMemo(() => isProfessionalRoleKey(props.roleKey || ''));
const bothApprovalsApproved = createMemo(() => {
if (!isProfessionalRole()) return profileApprovalState() === 'APPROVED';
return profileApprovalState() === 'APPROVED' && portfolioApprovalState() === 'APPROVED';
});
const approvalTone = (state: string) => {
if (state === 'APPROVED') return { border: '#E5E7EB', bg: '#F9FAFB', text: '#374151', label: 'Approved' };
if (state === 'IN_REVIEW' || state === 'SUBMITTED') return { border: '#E5E7EB', bg: '#F9FAFB', text: '#374151', label: 'In Review' };
if (state === 'DOCUMENTS_REQUESTED') return { border: '#E5E7EB', bg: '#F9FAFB', text: '#374151', label: 'Documents Requested' };
if (state === 'REJECTED') return { border: '#E5E7EB', bg: '#F9FAFB', text: '#374151', label: 'Rejected' };
return { border: '#E5E7EB', bg: '#F9FAFB', text: '#374151', label: 'Draft' };
};
// ─── Live API integration (customer_external mode with liveData) ──────────
const hasLive = () => isCustomerExternalMode() && !!props.liveData;
const livePrefix = () => props.liveData?.rolePrefix ?? '';
const GW = '/api/gateway';
const apiFetch = (path: string) =>
fetch(`${GW}${path}`, { credentials: 'include' })
.then((r) => (r.ok ? r.json() : null))
.catch(() => null);
const apiPost = (path: string, body: unknown) =>
fetch(`${GW}${path}`, {
method: 'POST',
credentials: 'include',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
}).catch(() => null);
const apiDelete = (path: string) =>
fetch(`${GW}${path}`, { method: 'DELETE', credentials: 'include' }).catch(() => null);
// Credits balance
const [creditsResource] = createResource(
() => (hasLive() ? livePrefix() : null),
(prefix) => apiFetch(`/api/${prefix}/wallet/balance`),
);
// Marketplace requirements (professionals)
const [marketplaceResource] = createResource(
() => (hasLive() && isProfessionalRole() ? livePrefix() : null),
(prefix) => apiFetch(`/api/${prefix}/marketplace?limit=50`),
);
// My lead requests (professionals)
const [leadRequestsResource, { refetch: refetchLeadRequestsLive }] = createResource(
() => (hasLive() && isProfessionalRole() ? livePrefix() : null),
(prefix) => apiFetch(`/api/${prefix}/leads/requests/me?limit=50`),
);
// Customer requirements
const [requirementsResource, { refetch: refetchRequirementsLive }] = createResource(
() => (hasLive() && normalizeRoleKey(props.roleKey ?? '') === 'CUSTOMER' ? 'yes' : null),
() => apiFetch('/api/customers/requirements?limit=50'),
);
// Jobs board
const [jobsResource] = createResource(
() => {
const r = normalizeRoleKey(props.roleKey ?? '');
return hasLive() && (r === 'JOB_SEEKER' || r === 'COMPANY') ? r : null;
},
() => apiFetch('/api/jobs?limit=50'),
);
// User profile (all roles)
const [profileResource] = createResource(
() => (hasLive() ? livePrefix() : null),
(prefix) => apiFetch(`/api/${prefix}/profile/me`),
);
// Professional services (Packages)
const [servicesResource, { refetch: refetchServicesLive }] = createResource(
() => (hasLive() && isProfessionalRole() ? livePrefix() : null),
(prefix) => apiFetch(`/api/${prefix}/services/me`),
);
// Professional portfolio
const [portfolioResource, { refetch: refetchPortfolioLive }] = createResource(
() => (hasLive() && isProfessionalRole() ? livePrefix() : null),
(prefix) => apiFetch(`/api/${prefix}/portfolio/me`),
);
// Current user roles (for switching and exploration status)
const [userRolesResource, { refetch: refetchUserRolesLive }] = createResource(
() => (hasLive() ? 'yes' : null),
() => apiFetch('/api/users/roles'),
);
// Tracecoin pricing packages
const [pricingPackagesResource] = createResource(
() => (hasLive() ? 'yes' : null),
() => apiFetch('/api/packages'),
);
// Dynamic Knowledge Base Resource
const [kbResource] = createResource(
() => (hasLive() ? 'yes' : null),
async () => {
const res = await apiFetch('/api/runtime-config/knowledge_base/GLOBAL_KB');
const data = (res?.payload as RuntimeKBConfig) || { articles: [] };
return data;
}
);
const [kbSearch, setKbSearch] = createSignal('');
const [kbCategory, setKbCategory] = createSignal('All');
const filteredKbArticles = createMemo(() => {
const data = kbResource()?.articles || [];
return data.filter(a => {
if (!a.isPublished) return false;
const matchesSearch = a.title.toLowerCase().includes(kbSearch().toLowerCase()) ||
a.content.toLowerCase().includes(kbSearch().toLowerCase());
const matchesCategory = kbCategory() === 'All' || a.category === kbCategory();
return matchesSearch && matchesCategory;
});
});
const kbCategoriesWithCounts = createMemo(() => {
const articles = kbResource()?.articles || [];
const counts: Record<string, number> = {};
articles.forEach(a => {
if (!a.isPublished) return;
counts[a.category] = (counts[a.category] || 0) + 1;
});
return Object.entries(counts).map(([title, articles]) => ({
title,
articles,
icon: '/icons/help-book.png', // Placeholder icon
description: `Guides and documentation for ${title}.`
}));
});
const BEEP = 'https://nxtgauge.free.beeceptor.com';
const startPayment = async (pkg: any) => {
setPaymentStep('processing');
try {
const res = await fetch(`${BEEP}/payments/create-order`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ package_id: pkg.id, amount: pkg.price_paise }),
});
const data = await (res.ok ? res.json() : { order_id: `ORD-${Date.now()}` });
setPaymentRef(data.order_id || `ORD-${Date.now()}`);
// Simulate network latency for UX
setTimeout(() => verifyPayment(pkg), 1200);
} catch (e) {
// Fallback for mock environment
setPaymentRef(`ORD-MOCK-${Date.now()}`);
setTimeout(() => verifyPayment(pkg), 1200);
}
};
const verifyPayment = async (pkg: any) => {
setPaymentStep('verifying');
try {
const res = await fetch(`${BEEP}/payments/verify`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ order_id: paymentRef(), status: 'success' }),
});
if (res.ok || true) { // Always succeed in mock mode if user requested
setPaymentStep('success');
const creditsToAdd = Number(pkg.credits) + Number(pkg.bonus_credits || 0);
setLeadCredits((prev) => prev + creditsToAdd);
const newRow: [string, string, string, string, string, string] = [
paymentRef() || `#INV-${Date.now()}`,
pkg.display_name || pkg.name,
Number(creditsToAdd).toLocaleString(),
`${(pkg.price_paise / 100).toLocaleString('en-IN')}`,
'Completed',
new Date().toLocaleDateString('en-US', { month: 'short', day: '2-digit', year: 'numeric' }),
];
setTxRows((prev) => [newRow, ...prev]);
}
} catch (e) {
setPaymentStep('error');
}
};
const adjustCreditsManually = (amount: number, reason: string) => {
setLeadCredits((prev) => prev + amount);
const newRow: [string, string, string, string, string, string] = [
`#ADJ-${Date.now().toString().slice(-6)}`,
`Adjustment: ${reason}`,
amount > 0 ? `+${amount.toLocaleString()}` : amount.toLocaleString(),
'₹0',
'Completed',
new Date().toLocaleDateString('en-US', { month: 'short', day: '2-digit', year: 'numeric' }),
];
setTxRows((prev) => [newRow, ...prev]);
};
// Sync resources → local signals
createEffect(() => {
const d = creditsResource();
if (d != null && typeof d.balance === 'number') setLeadCredits(d.balance);
});
createEffect(() => {
const d = marketplaceResource();
if (!d) return;
const items: any[] = Array.isArray(d.items) ? d.items : Array.isArray(d) ? d : [];
if (!items.length) return;
setLeadCards(items.map((item: any) => ({
id: String(item.id ?? item.requirement_id ?? ''),
title: String(item.title ?? item.description ?? 'Requirement'),
category: String(item.category ?? item.profession_key ?? props.roleKey ?? ''),
location: String(item.location ?? item.city ?? 'India'),
area: String(item.area ?? item.locality ?? ''),
dateRequired: item.required_by
? new Date(item.required_by).toLocaleDateString('en-US', { month: 'short', day: '2-digit', year: 'numeric' })
: 'TBD',
urgency: item.urgency === 'HIGH' ? 'High' : item.urgency === 'MEDIUM' ? 'Medium' : 'Low',
budget: item.budget_min != null
? `${Math.round(item.budget_min / 100).toLocaleString('en-IN')} - ₹${Math.round((item.budget_max ?? item.budget_min) / 100).toLocaleString('en-IN')}`
: '₹0',
budgetValue: Number(item.budget_max ?? item.budget_min ?? 0) / 100,
priceRange: item.budget_min != null
? `${Math.round(item.budget_min / 100).toLocaleString('en-IN')} - ₹${Math.round((item.budget_max ?? item.budget_min) / 100).toLocaleString('en-IN')}`
: '₹0',
cost: 25,
status: 'open' as const,
match: '80% match',
contactCount: Number(item.contact_count ?? 0),
maxContacts: Number(item.max_contacts ?? 10),
})));
});
createEffect(() => {
const d = leadRequestsResource();
if (!d) return;
const items: any[] = Array.isArray(d.items) ? d.items : Array.isArray(d) ? d : [];
if (!items.length) return;
const statusMap: Record<string, any> = {
PENDING: 'request_sent', CONTACT_UNLOCKED: 'contact_unlocked',
REJECTED: 'rejected', CANCELLED: 'cancelled_by_professional', EXPIRED: 'expired_refunded',
};
setLeadRequestRows(items.map((item: any) => ({
id: String(item.id ?? ''),
title: String(item.title ?? item.requirement_title ?? 'Lead Request'),
city: String(item.location ?? item.city ?? 'India'),
requestDate: item.created_at
? new Date(item.created_at).toLocaleDateString('en-US', { month: 'short', day: '2-digit', year: 'numeric' })
: '--',
status: statusMap[String(item.status ?? '')] ?? 'request_sent',
decisionDate: item.decision_date
? new Date(item.decision_date).toLocaleDateString('en-US', { month: 'short', day: '2-digit', year: 'numeric' })
: '--',
})));
});
createEffect(() => {
const d = requirementsResource();
if (!d) return;
const items: any[] = Array.isArray(d.items) ? d.items : Array.isArray(d) ? d : [];
if (!items.length) return;
const statusMap: Record<string, string> = {
PENDING: 'under review', APPROVED: 'approved', ACTIVE: 'active',
REJECTED: 'closed', CLOSED: 'closed',
};
setRequirementRows(items.map((item: any) => ({
id: String(item.id ?? ''),
title: String(item.title ?? item.description ?? 'Requirement'),
summary: String(item.description ?? ''),
category: String(item.category ?? item.profession_key ?? ''),
amount: item.budget_min != null
? `${Math.round(item.budget_min / 100).toLocaleString('en-IN')}`
: '₹0',
budget: item.budget_min != null
? `${Math.round(item.budget_min / 100).toLocaleString('en-IN')} - ₹${Math.round((item.budget_max ?? item.budget_min) / 100).toLocaleString('en-IN')}`
: '₹0',
location: String(item.location ?? 'India'),
submission: item.created_at
? new Date(item.created_at).toLocaleDateString('en-US', { month: 'short', day: '2-digit', year: 'numeric' })
: '--',
status: statusMap[String(item.status ?? '')] ?? 'under review',
responses: Number(item.response_count ?? 0),
responseTag: `Active (${Number(item.response_count ?? 0)} Responses)`,
})));
});
createEffect(() => {
const d = jobsResource();
if (!d) return;
const items: any[] = Array.isArray(d.items) ? d.items : Array.isArray(d) ? d : [];
if (!items.length) return;
setJobBoardJobs(items.map((item: any) => ({
id: String(item.id ?? ''),
title: String(item.title ?? 'Position'),
company: String(item.company_name ?? item.company ?? 'Company'),
location: String(item.location ?? 'India'),
salary: item.salary_min != null
? `${Math.round(item.salary_min / 100).toLocaleString('en-IN')}+`
: 'Negotiable',
exp: String(item.experience_required ?? item.experience ?? '0-2 yrs'),
type: String(item.employment_type ?? item.type ?? 'Full-Time'),
tags: Array.isArray(item.tags) ? item.tags : [],
match: '',
posted: item.created_at
? new Date(item.created_at).toLocaleDateString('en-US', { month: 'short', day: 'numeric' })
: '--',
})));
});
createEffect(() => {
const d = profileResource();
if (!d) return;
const parts = String(d.display_name || d.full_name || d.business_name || '').split(' ');
const map: Record<string, string> = {};
map['First Name'] = d.first_name || parts[0] || '';
map['Last Name'] = d.last_name || parts.slice(1).join(' ') || '';
map['Business Name'] = d.business_name || d.display_name || '';
map['Contact Person Name'] = d.contact_person || d.display_name || '';
map['Company Name'] = d.company_name || d.display_name || '';
map['Email Address'] = d.email || '';
map['Mobile Number'] = d.phone || d.mobile || '';
if (d.location) map['City'] = d.location;
if (d.area) map['Area'] = d.area;
if (d.state) map['State'] = d.state;
if (d.pin_code) map['PIN Code'] = d.pin_code;
if (d.bio) map['Bio'] = d.bio;
if (d.status) setProfileApprovalState(
d.status === 'APPROVED' ? 'APPROVED'
: d.status === 'REJECTED' ? 'REJECTED'
: d.status === 'PENDING' ? 'IN_REVIEW'
: 'DRAFT',
);
setProfileFormData((prev) => ({ ...prev, ...map }));
});
createEffect(() => {
const d = userRolesResource();
if (Array.isArray(d)) setUserRoles(d);
else if (d && Array.isArray(d.data)) setUserRoles(d.data);
});
createEffect(() => {
const d = servicesResource();
if (!d) return;
const items = Array.isArray(d.items) ? d.items : Array.isArray(d) ? d : [];
if (items.length > 0) {
setPortfolioServices(items.map((it: any) => ({
id: it.id,
name: it.name || '',
model: it.model || 'Flat',
price: it.price || '',
details: it.details || ''
})));
}
});
createEffect(() => {
const d = portfolioResource();
if (!d) return;
if (Array.isArray(d.photos)) setPortfolioPhotos(d.photos);
if (Array.isArray(d.experience)) setPortfolioExperiences(d.experience);
if (Array.isArray(d.specialties)) setPortfolioSpecialties(d.specialties);
if (Array.isArray(d.languages)) setPortfolioLanguages(d.languages);
if (Array.isArray(d.service_areas)) setPortfolioServiceAreas(d.service_areas);
});
// ─── End live API integration ─────────────────────────────────────────────
const registerRole = async (roleKey: string) => {
const res = await apiPost('/api/users/roles/register', { role_key: roleKey.toUpperCase() });
if (res && (res.ok || res.status === 200)) {
window.location.reload();
} else {
alert(`Failed to register as ${roleKey}. Please check if you are already registered.`);
}
};
const switchRole = async (roleKey: string) => {
const res = await apiPost('/api/users/roles/switch', { role: roleKey.toUpperCase() });
if (res && (res.ok || res.status === 200)) {
window.location.reload();
} else {
alert(`Failed to switch to ${roleKey}.`);
}
};
const submitProfileForApproval = async () => {
if (!hasLive() || !livePrefix()) return;
try {
const res = await fetch(`${GW}/api/${livePrefix()}/profile/submit`, {
method: 'POST',
credentials: 'include',
headers: { 'Content-Type': 'application/json' },
});
if (res.ok) {
setProfileApprovalState('SUBMITTED');
setTimeout(() => setProfileApprovalState('IN_REVIEW'), 250);
}
} catch {
setProfileApprovalState('SUBMITTED');
}
};
const submitPortfolioForApproval = () => {
setPortfolioApprovalState('SUBMITTED');
setTimeout(() => setPortfolioApprovalState('IN_REVIEW'), 250);
};
createEffect(() => {
const roleKey = normalizeRoleKey(props.roleKey || '');
const spec = portfolioSpecForRole(roleKey);
setPortfolioSpecialties(spec.specialties.slice(0, 6));
setPortfolioLanguages(['English', 'Hindi', 'Tamil']);
setPortfolioServiceAreas(['T. Nagar', 'Adyar', 'Velachery', 'Anna Nagar']);
setPortfolioSpecialtyInput('');
setPortfolioLanguageInput('');
setPortfolioAreaInput('');
setPortfolioFormValues({});
setPortfolioFormErrors({});
setPortfolioValidationNotice('');
setPortfolioServices([{ name: 'Core Service', model: 'Flat', price: '₹15,000', details: 'Includes planning and delivery' }]);
setPortfolioServiceDraft({ name: '', model: 'Flat', price: '', details: '' });
setPortfolioExperiences([{ year: '2022', title: 'Started professional practice', details: 'Handled 40+ projects successfully' }]);
setPortfolioExperienceDraft({ year: '', title: '', details: '' });
setPortfolioToolInput('');
setPortfolioDesignTools(['Figma', 'Adobe Photoshop', 'Illustrator']);
setPortfolioPhotos(['sample-1.jpg', 'sample-2.jpg']);
});
const addPortfolioTag = (
value: string,
setter: (next: (prev: string[]) => string[]) => void,
max = 6,
) => {
const normalized = String(value || '').trim();
if (!normalized) return false;
let added = false;
setter((prev) => {
if (prev.some((item) => item.toLowerCase() === normalized.toLowerCase()) || prev.length >= max) return prev;
added = true;
return [...prev, normalized];
});
return added;
};
const removePortfolioTag = (
value: string,
setter: (next: (prev: string[]) => string[]) => void,
) => setter((prev) => prev.filter((item) => item !== value));
const selectedTicket = createMemo(() => HELP_TICKET_ROWS.find((row) => row.id === activeTicketId()) || HELP_TICKET_ROWS[0]);
const selectedTicketDetails = createMemo(() => HELP_TICKET_DETAILS[selectedTicket().id] || HELP_TICKET_DETAILS['TCK-1042']);
const leadCostPerContact = 25;
const leadsPerPage = 3;
const requestedPerPage = 5;
const lockedLeadCredits = createMemo(() => leadCards().filter((card) => card.status === 'requested').length * leadCostPerContact);
const usableLeadCredits = createMemo(() => Math.max(0, leadCredits() - lockedLeadCredits()));
const filteredLeadCards = createMemo(() => {
const query = leadSearch().trim().toLowerCase();
const area = leadAreaFilter();
const budget = leadBudgetFilter();
const date = leadDateFilter();
const list = leadCards().filter((lead) => {
if (lead.status !== 'open') return false;
const matchesQuery = !query
|| lead.title.toLowerCase().includes(query)
|| lead.category.toLowerCase().includes(query)
|| lead.location.toLowerCase().includes(query)
|| String(lead.area || '').toLowerCase().includes(query);
if (!matchesQuery) return false;
if (area !== 'All Areas' && String(lead.area || '') !== area) return false;
if (date === 'Within 7 Days') {
const diff = (Date.parse(lead.dateRequired) - Date.now()) / (1000 * 60 * 60 * 24);
if (!(diff >= 0 && diff <= 7)) return false;
}
if (date === 'This Month') {
const value = new Date(lead.dateRequired);
const now = new Date();
if (!(value.getMonth() === now.getMonth() && value.getFullYear() === now.getFullYear())) return false;
}
if (budget === 'Under ₹1L' && lead.budgetValue >= 100000) return false;
if (budget === '₹1L - ₹2L' && !(lead.budgetValue >= 100000 && lead.budgetValue <= 200000)) return false;
if (budget === 'Above ₹2L' && lead.budgetValue <= 200000) return false;
return true;
});
const sorted = [...list];
if (leadSortFilter() === 'Budget High-Low') sorted.sort((a, b) => b.budgetValue - a.budgetValue);
if (leadSortFilter() === 'Budget Low-High') sorted.sort((a, b) => a.budgetValue - b.budgetValue);
if (leadSortFilter() === 'Newest First') sorted.sort((a, b) => Date.parse(b.dateRequired) - Date.parse(a.dateRequired));
return sorted;
});
const totalLeadPages = createMemo(() => Math.max(1, Math.ceil(filteredLeadCards().length / leadsPerPage)));
const pagedLeadCards = createMemo(() => {
const start = (leadPage() - 1) * leadsPerPage;
return filteredLeadCards().slice(start, start + leadsPerPage);
});
const filteredRequestedRows = createMemo(() => {
const query = requestedSearch().trim().toLowerCase();
const status = requestedStatusFilter();
const sorted = leadRequestRows().filter((row) => {
if (status !== 'All Status' && status !== titleCase(row.status.replace(/_/g, ' '))) return false;
if (!query) return true;
return row.id.toLowerCase().includes(query) || row.title.toLowerCase().includes(query) || row.city.toLowerCase().includes(query);
});
if (requestedSortFilter() === 'Oldest First') {
sorted.sort((a, b) => Date.parse(a.requestDate) - Date.parse(b.requestDate));
} else {
sorted.sort((a, b) => Date.parse(b.requestDate) - Date.parse(a.requestDate));
}
return sorted;
});
const totalRequestedPages = createMemo(() => Math.max(1, Math.ceil(filteredRequestedRows().length / requestedPerPage)));
const pagedRequestedRows = createMemo(() => {
const start = (requestedPage() - 1) * requestedPerPage;
return filteredRequestedRows().slice(start, start + requestedPerPage);
});
const ticketSummary = createMemo(() => {
const openCount = HELP_TICKET_ROWS.filter((row) => row.status !== 'Resolved').length;
const resolvedCount = HELP_TICKET_ROWS.length - openCount;
return { openCount, resolvedCount, total: HELP_TICKET_ROWS.length };
});
const openTicketDetails = (ticketId: string) => {
setHelpCenterTab('my_tickets');
setActiveTicketId(ticketId);
setMyTicketsTab('view_ticket');
setTicketMessage('');
setViewTicketFiles([]);
};
createEffect(() => {
const key = customerKey();
if (key !== lastSidebarKey()) {
setLastSidebarKey(key);
if (key === 'credits') props.onTabSelect('overview');
}
});
createEffect(() => {
setDashboardWidgetOrder(previewWidgets());
});
createEffect(() => {
if (customerKey() !== 'help center' && customerKey() !== 'support') setHelpCenterTab('help_center');
});
createEffect(() => {
if (customerKey() !== 'my requirements') {
setRequirementsView('list');
setRequirementsStep(1);
}
});
createEffect(() => {
if (customerKey() !== 'leads') {
setLeadMarketplaceTab('All Leads');
setLeadSearch('');
setLeadAreaFilter('All Areas');
setLeadBudgetFilter('All Budgets');
setLeadDateFilter('Any Date');
setLeadSortFilter('Newest First');
setLeadFiltersOpen(false);
setLeadSortOpen(false);
setLeadPage(1);
setActiveLeadDetailId('');
setLeadContactConfirmId('');
setActiveResponseLeadId('');
setResponsesDetailMode(false);
setRequestedSearch('');
setRequestedStatusFilter('All Status');
setRequestedSortFilter('Newest First');
setRequestedSortOpen(false);
setRequestedFilterOpen(false);
setRequestedPage(1);
}
});
createEffect(() => {
void leadSearch();
void leadAreaFilter();
void leadBudgetFilter();
void leadDateFilter();
void leadSortFilter();
setLeadPage(1);
});
createEffect(() => {
if (leadPage() > totalLeadPages()) setLeadPage(totalLeadPages());
});
createEffect(() => {
void requestedSearch();
void requestedStatusFilter();
void requestedSortFilter();
setRequestedPage(1);
});
createEffect(() => {
if (requestedPage() > totalRequestedPages()) setRequestedPage(totalRequestedPages());
});
createEffect(() => {
if (customerKey() !== 'jobs') {
setJobPostView('form');
setJobPostStep(1);
setJobSeekerScreen('list');
setJobSeekerSelectedId(jobBoardJobs()[0]?.id || '');
setJobSeekerApplyStep(2);
setLastJobSeekerTabKey('');
}
});
createEffect(() => {
if (customerKey() !== 'my portfolio') setPortfolioEditMode(false);
if (customerKey() !== 'my portfolio') setPortfolioTopTab('my_portfolio');
});
const openPortfolioPreviewInline = () => {
setPortfolioTopTab('preview');
props.onSidebarSelect('My Portfolio');
props.onTabSelect('about');
};
createEffect(() => {
if (customerKey() !== 'jobs' || !isJobSeekerRole()) return;
const tabKey = normalizeTabKey(resolvedTabKey());
if (tabKey === lastJobSeekerTabKey()) return;
setLastJobSeekerTabKey(tabKey);
setJobSeekerScreen('list');
setJobSeekerSelectedId(jobBoardJobs()[0]?.id || '');
});
createEffect(() => {
const rows = jobBoardJobs();
const active = jobSeekerSelectedId();
if (!rows.length) return;
if (!rows.some((job) => job.id === active)) {
setJobSeekerSelectedId(rows[0].id);
}
});
createEffect(() => {
if (helpCenterTab() !== 'my_tickets') {
setMyTicketsTab('all_tickets');
setActiveTicketId('TCK-1042');
setViewTicketFiles([]);
}
});
createEffect(() => {
if (helpCenterTab() !== 'create_ticket') setCreateTicketFiles([]);
});
const moveDashboardWidget = (movingKey: string, targetKey: string) => {
if (!movingKey || !targetKey || movingKey === targetKey) return;
setDashboardWidgetOrder((prev) => {
const from = prev.indexOf(movingKey);
const to = prev.indexOf(targetKey);
if (from === -1 || to === -1) return prev;
const next = [...prev];
next.splice(from, 1);
next.splice(to, 0, movingKey);
return next;
});
};
const statusChip = (value: string) => {
const key = value.toLowerCase();
if (key === 'active' || key === 'new') return { bg: '#FFF1EB', c: '#FF5E13' };
if (key === 'closed' || key === 'contacted') return { bg: '#ECFDF3', c: '#059669' };
if (key === 'shortlisted') return { bg: '#EEF2FF', c: '#4338CA' };
if (key === 'draft') return { bg: '#FEF3C7', c: '#B45309' };
return { bg: '#F3F4F6', c: '#6B7280' };
};
const requestLeadContact = (leadId: string) => {
if (usableLeadCredits() < leadCostPerContact) return;
if (hasLive()) {
apiPost(`/api/${livePrefix()}/leads/request`, { requirement_id: leadId })
.then(() => refetchLeadRequestsLive());
}
let changed = false;
setLeadCards((prev) => prev.map((card) => {
if (card.id !== leadId || card.status !== 'open' || card.contactCount >= card.maxContacts) return card;
changed = true;
const nextCount = Math.min(card.maxContacts, card.contactCount + 1);
return {
...card,
contactCount: nextCount,
status: (nextCount >= card.maxContacts ? 'closed' : 'requested') as LeadCardStatus,
};
}));
if (!changed) return;
setLeadRequestRows((prev) => {
const idx = prev.findIndex((row) => row.id === leadId);
if (idx >= 0) {
const next = [...prev];
next[idx] = { ...next[idx], status: 'request_sent', decisionDate: '--' };
return next;
}
const selected = leadCards().find((card) => card.id === leadId);
return [
{
id: leadId,
title: selected?.title || 'Lead Request',
city: selected ? `${selected.area || 'Central'}, ${selected.location}` : 'Chennai, India',
requestDate: 'Apr 02, 2026',
status: 'request_sent' as const,
decisionDate: '--',
},
...prev,
];
});
};
const leadDetailsSpec = (lead: { category: string }) => {
const c = lead.category.toLowerCase();
if (c.includes('photography') || c.includes('fashion')) {
return { timeframe: '3-5 shoot days + 7 days edit', scope: 'Pre-shoot planning, full day coverage, edited album delivery', highlights: ['Shot list alignment with customer brief', 'Venue and lighting plan finalization', 'Edited photos + social cuts'] };
}
if (c.includes('design') || c.includes('branding')) {
return { timeframe: '7-14 working days', scope: 'Brand exploration, visual concepts, revision rounds, handoff', highlights: ['Moodboard and style direction', 'Logo/system deliverables', 'Source files + usage formats'] };
}
if (c.includes('video')) {
return { timeframe: '5-10 working days', scope: 'Editing, color correction, sound polish, export variants', highlights: ['Storyboard-based edits', 'Platform-specific outputs', 'Two revision rounds'] };
}
return { timeframe: '5-10 working days', scope: 'Requirement discovery, execution plan, and final delivery', highlights: ['Clear milestone tracking', 'Weekly progress updates', 'Final quality checklist'] };
};
const openLeadDetailsInNewTab = (leadId: string) => {
setActiveLeadDetailId(leadId);
setLeadMarketplaceTab('View Details');
};
const openResponseLeadDetails = (leadId: string) => {
setActiveResponseLeadId(leadId);
setResponsesDetailMode(true);
};
const openLeadContactConfirm = (leadId: string) => setLeadContactConfirmId(leadId);
const confirmLeadContactRequest = () => {
const leadId = leadContactConfirmId();
if (!leadId) return;
requestLeadContact(leadId);
setLeadContactConfirmId('');
};
const approveLeadContact = (leadId: string) => {
setLeadCards((prev) => prev.map((card) => card.id === leadId && card.status === 'requested'
? { ...card, status: 'unlocked' as const }
: card));
setLeadCredits((prev) => Math.max(0, prev - leadCostPerContact));
setLeadRequestRows((prev) => prev.map((row) => row.id === leadId
? { ...row, status: 'contact_unlocked' as const, decisionDate: 'Apr 03, 2026' }
: row));
};
const cancelLeadRequest = (leadId: string) => {
if (hasLive()) {
apiDelete(`/api/${livePrefix()}/leads/requests/${leadId}`)
.then(() => refetchLeadRequestsLive());
}
setLeadCards((prev) => prev.map((card) => {
if (card.id !== leadId) return card;
if (card.status !== 'requested' && card.status !== 'closed') return card;
return { ...card, contactCount: Math.max(0, card.contactCount - 1), status: 'open' as LeadCardStatus };
}));
setLeadCredits((prev) => Math.max(0, prev - leadCostPerContact));
setLeadRequestRows((prev) => prev.map((row) => row.id === leadId
? { ...row, status: 'cancelled_by_professional' as const, decisionDate: 'Apr 03, 2026' }
: row));
};
const refundPendingLead = (leadId: string) => {
setLeadCards((prev) => prev.map((card) => {
if (card.id !== leadId) return card;
if (card.status !== 'requested' && card.status !== 'closed') return card;
return { ...card, contactCount: Math.max(0, card.contactCount - 1), status: 'open' as LeadCardStatus };
}));
setLeadRequestRows((prev) => prev.map((row) => row.id === leadId
? { ...row, status: 'expired_refunded' as const, decisionDate: 'Auto-refunded' }
: row));
};
const leadMatchPercent = (lead: { match: string }) => {
const value = Number.parseInt(String(lead.match || '').replace(/[^0-9]/g, ''), 10);
return Number.isFinite(value) ? value : 70;
};
const leadProbability = (lead: { match: string; urgency: string; contactCount: number; maxContacts: number }) => {
const urgencyBoost = lead.urgency.includes('High') ? 8 : lead.urgency.includes('Medium') ? 4 : 0;
const slotFactor = ((lead.maxContacts - lead.contactCount) / Math.max(1, lead.maxContacts)) * 40;
const score = Math.round(0.5 * leadMatchPercent(lead) + slotFactor + urgencyBoost);
return Math.min(95, Math.max(5, score));
};
const leadProbabilityColor = (score: number) => {
if (score >= 75) return '#16A34A';
if (score >= 50) return '#F59E0B';
return '#DC2626';
};
const leadProbabilityLabel = (score: number) => {
if (score >= 75) return 'High';
if (score >= 50) return 'Medium';
return 'Low';
};
const leadGaugeNeedlePoint = (score: number) => {
const clamped = Math.max(0, Math.min(100, score));
const angleDeg = 180 - (clamped * 180) / 100;
const angleRad = (angleDeg * Math.PI) / 180;
const radius = 34;
return {
x: 60 + Math.cos(angleRad) * radius,
y: 60 - Math.sin(angleRad) * radius,
};
};
const leadGaugeDash = (score: number) => {
const clamped = Math.max(0, Math.min(100, score));
const arcLength = Math.PI * 50;
return `${((clamped / 100) * arcLength).toFixed(1)} ${arcLength.toFixed(1)}`;
};
const renderPortfolioContent = () => {
const spec = portfolioSpecForRole(props.roleKey || '');
const mediaConfig = portfolioMediaConfig(props.roleKey || '');
const submissionTabs = spec.tabs.filter((item) => normalizeTabKey(item) !== normalizeTabKey('testimonials'));
const selectedPortfolioTab = submissionTabs.find((item) => normalizeTabKey(item) === normalizeTabKey(resolvedTabKey())) || submissionTabs[0] || 'about';
const selectedPortfolioTabKey = normalizeTabKey(selectedPortfolioTab);
const serviceTabKey = normalizeTabKey(spec.serviceTabLabel);
const galleryTabKey = normalizeTabKey(spec.galleryTabLabel);
const experienceTabKey = normalizeTabKey(spec.experienceTabLabel);
const testimonialsTabKey = normalizeTabKey('testimonials');
const faqsTabKey = normalizeTabKey('faqs');
const portfolioJobsCompleted = portfolioJobsCompletedPreview;
const portfolioFeedbackCount = portfolioFeedbackCountPreview;
const testimonialsUnlocked = portfolioTestimonialsUnlocked();
const isPreviewMode = portfolioTopTab() === 'preview';
const canEdit = !isPreviewMode;
const portfolioStepKeys = submissionTabs.map((item) => normalizeTabKey(item));
const activePortfolioStepIndex = Math.max(0, portfolioStepKeys.findIndex((key) => key === selectedPortfolioTabKey));
const goToPortfolioStep = (index: number) => {
const bounded = Math.max(0, Math.min(portfolioStepKeys.length - 1, index));
props.onTabSelect(submissionTabs[bounded] || submissionTabs[0] || 'about');
};
const portfolioTools = (() => {
const role = normalizeRoleKey(props.roleKey || '');
if (role === 'GRAPHIC_DESIGNER') return ['Figma', 'Adobe Photoshop', 'Illustrator', 'InDesign', 'After Effects'];
if (role === 'SOCIAL_MEDIA_MANAGER') return ['Meta Business Suite', 'Canva', 'Buffer', 'Hootsuite', 'Google Analytics'];
if (role === 'DEVELOPER') return ['React', 'TypeScript', 'Node.js', 'PostgreSQL', 'Docker'];
if (role === 'VIDEO_EDITOR') return ['Premiere Pro', 'After Effects', 'DaVinci Resolve', 'CapCut', 'Audition'];
if (role === 'PHOTOGRAPHER') return ['Lightroom', 'Photoshop', 'Capture One', 'Bridge', 'Snapseed'];
return ['Domain Tool 1', 'Domain Tool 2', 'Domain Tool 3'];
})();
const portfolioFormFieldsByTab: Record<string, string[]> = {
about: ['Professional Headline', 'About You', 'Area', 'Place', 'Travel Preference', 'Response Time'],
[serviceTabKey]: ['Primary Service', 'Pricing Model', 'Starting Price', 'Delivery Timeline', 'Includes', 'Additional Notes'],
[galleryTabKey]: ['Portfolio Item Title', 'Portfolio Link', 'Category', 'Project Summary', 'Outcome', 'Asset Upload'],
[experienceTabKey]: ['Years of Experience', 'Top Tools', 'Milestone 1', 'Milestone 2', 'Certifications', 'Working Style'],
[testimonialsTabKey]: ['Client Name', 'Client Feedback', 'Rating', 'Project Type', 'Client Location', 'Consent'],
[faqsTabKey]: ['Question 1', 'Answer 1', 'Question 2', 'Answer 2', 'Question 3', 'Answer 3'],
};
const selectedPortfolioFormFields = portfolioFormFieldsByTab[selectedPortfolioTabKey] || portfolioFormFieldsByTab.about;
const setPortfolioFieldValue = (field: string, value: string) => {
const fieldKey = `${selectedPortfolioTabKey}::${field}`;
setPortfolioFormValues((prev) => ({ ...prev, [fieldKey]: value }));
setPortfolioFormErrors((prev) => ({ ...prev, [fieldKey]: '' }));
setPortfolioValidationNotice('');
};
const renderPortfolioFormField = (field: string) => {
const key = String(field || '').toLowerCase();
const isSelect = /model|category|style|rating|consent|response time|travel|type|timeline/i.test(key);
const isLong = /about|summary|notes|answer|feedback|includes/i.test(key);
const fieldKey = `${selectedPortfolioTabKey}::${field}`;
const fieldValue = portfolioFormValues()[fieldKey] || '';
const fieldError = portfolioFormErrors()[fieldKey] || '';
const placeholder = (() => {
if (key.includes('area')) return 'Enter area in Chennai';
if (key.includes('place')) return 'Enter place in Chennai';
if (key.includes('price')) return 'Enter amount';
if (key.includes('link')) return 'Paste URL';
if (key.includes('upload')) return 'Upload file (PDF/JPG/PNG)';
return `${isSelect ? 'Select' : 'Enter'} ${field.toLowerCase()}`;
})();
return (
<div style="display:flex;flex-direction:column;gap:6px">
<p style="margin:0;font-size:11px;font-weight:700;color:#6B7280;letter-spacing:0.01em;text-transform:none">{field}</p>
<Show
when={isLong}
fallback={
<div style="position:relative">
<input type="text" value={fieldValue} onInput={(e) => setPortfolioFieldValue(field, e.currentTarget.value)} placeholder={placeholder} style={`width:100%;height:36px;border:1px solid ${fieldError ? '#FFD8C2' : '#E5E7EB'};border-radius:8px;background:white;padding:0 30px 0 10px;font-size:12px;color:#111827;outline:none`} />
<Show when={isSelect}>
<span style="position:absolute;right:10px;top:50%;transform:translateY(-50%);color:#9CA3AF;font-size:12px"></span>
</Show>
</div>
}
>
<textarea value={fieldValue} onInput={(e) => setPortfolioFieldValue(field, e.currentTarget.value)} placeholder={placeholder} style={`width:100%;min-height:74px;border:1px solid ${fieldError ? '#FFD8C2' : '#E5E7EB'};border-radius:8px;background:white;padding:8px 10px;font-size:12px;color:#111827;outline:none;resize:vertical`} />
</Show>
<Show when={!!fieldError}>
<p style="margin:0;font-size:11px;color:#C2410C">{fieldError}</p>
</Show>
</div>
);
};
const validatePortfolioStep = (stepKey: string) => {
const nextErrors: Record<string, string> = {};
const stepFields = portfolioFormFieldsByTab[stepKey] || [];
stepFields.forEach((field) => {
const fKey = `${stepKey}::${field}`;
const value = (portfolioFormValues()[fKey] || '').trim();
const optional = /optional/i.test(field);
const isUpload = /asset upload/i.test(field);
if (!optional && !isUpload && !value) nextErrors[fKey] = 'This field is required';
});
if (stepKey === serviceTabKey && portfolioServices().length < 1) {
setPortfolioValidationNotice('Add at least one service with pricing.');
} else if (stepKey === galleryTabKey && (portfolioPhotos().length < 1 || portfolioPhotos().length > 6)) {
setPortfolioValidationNotice('Add 1 to 6 portfolio photos.');
} else if (stepKey === experienceTabKey && portfolioExperiences().length < 1) {
setPortfolioValidationNotice('Add at least one experience entry.');
} else if (Object.keys(nextErrors).length) {
setPortfolioValidationNotice('Please fill all required fields in this tab.');
} else {
setPortfolioValidationNotice('');
}
setPortfolioFormErrors((prev) => ({ ...prev, ...nextErrors }));
return Object.keys(nextErrors).length === 0
&& !(stepKey === serviceTabKey && portfolioServices().length < 1)
&& !(stepKey === galleryTabKey && (portfolioPhotos().length < 1 || portfolioPhotos().length > 6))
&& !(stepKey === experienceTabKey && portfolioExperiences().length < 1);
};
const addServiceDraft = async () => {
const draft = portfolioServiceDraft();
if (!draft.name.trim() || !draft.price.trim()) {
setPortfolioValidationNotice('Add service name and price to continue.');
return;
}
if (hasLive()) {
try {
const res = await apiPost(`/api/${livePrefix()}/services`, {
name: draft.name.trim(),
model: draft.model.trim() || 'Flat',
price: draft.price.trim(),
details: draft.details.trim(),
});
if (res && (res.ok || res.status === 200)) {
refetchServicesLive();
setPortfolioServiceDraft({ name: '', model: 'Flat', price: '', details: '' });
setPortfolioValidationNotice('');
} else {
setPortfolioValidationNotice('Failed to save service to backend.');
}
} catch (err) {
console.error(err);
setPortfolioValidationNotice('Network error while saving service.');
}
} else {
setPortfolioServices((prev) => [...prev, {
name: draft.name.trim(),
model: draft.model.trim() || 'Flat',
price: draft.price.trim(),
details: draft.details.trim(),
}]);
setPortfolioServiceDraft({ name: '', model: 'Flat', price: '', details: '' });
setPortfolioValidationNotice('');
}
};
const removeServiceItem = async (index: number) => {
const target = portfolioServices()[index];
if (hasLive() && target && (target as any).id) {
try {
const res = await apiDelete(`/api/${livePrefix()}/services/${(target as any).id}`);
if (res && (res.ok || res.status === 200)) {
refetchServicesLive();
}
} catch (err) {
console.error('Failed to delete service:', err);
}
} else {
setPortfolioServices((prev) => prev.filter((_, i) => i !== index));
}
};
const addExperienceDraft = async () => {
const draft = portfolioExperienceDraft();
if (!draft.year.trim() || !draft.title.trim()) {
setPortfolioValidationNotice('Add year and title for each experience entry.');
return;
}
const nextExp = [...portfolioExperiences(), {
year: draft.year.trim(),
title: draft.title.trim(),
details: draft.details.trim(),
}];
if (hasLive()) {
try {
const res = await apiPost(`/api/${livePrefix()}/portfolio/experience`, nextExp);
if (res && (res.ok || res.status === 200)) {
refetchPortfolioLive();
setPortfolioExperienceDraft({ year: '', title: '', details: '' });
setPortfolioValidationNotice('');
}
} catch (err) {
console.error(err);
}
} else {
setPortfolioExperiences(nextExp);
setPortfolioExperienceDraft({ year: '', title: '', details: '' });
setPortfolioValidationNotice('');
}
};
const removeExperienceItem = async (index: number) => {
const nextExp = portfolioExperiences().filter((_, i) => i !== index);
if (hasLive()) {
try {
const res = await apiPost(`/api/${livePrefix()}/portfolio/experience`, nextExp);
if (res && (res.ok || res.status === 200)) refetchPortfolioLive();
} catch (err) {
console.error(err);
}
} else {
setPortfolioExperiences(nextExp);
}
};
const addPhotoItem = async () => {
const current = portfolioPhotos();
if (current.length >= 6) {
setPortfolioValidationNotice('Portfolio is limited to 6 photos.');
return;
}
const nextLabel = `portfolio-${current.length + 1}.jpg`;
const nextPhotos = [...current, nextLabel];
if (hasLive()) {
try {
const res = await apiPost(`/api/${livePrefix()}/portfolio/photos`, nextPhotos);
if (res && (res.ok || res.status === 200)) refetchPortfolioLive();
} catch (err) {
console.error(err);
}
} else {
setPortfolioPhotos(nextPhotos);
}
setPortfolioValidationNotice('');
};
const removePhotoItem = async (index: number) => {
const nextPhotos = portfolioPhotos().filter((_, i) => i !== index);
if (hasLive()) {
try {
const res = await apiPost(`/api/${livePrefix()}/portfolio/photos`, nextPhotos);
if (res && (res.ok || res.status === 200)) refetchPortfolioLive();
} catch (err) {
console.error(err);
}
} else {
setPortfolioPhotos(nextPhotos);
}
};
const showSection = (tabKey: string) => (isPreviewMode ? portfolioStepKeys.includes(tabKey) : selectedPortfolioTabKey === tabKey);
return (
<div style="display:flex;flex-direction:column;gap:14px">
<div style="border-radius:12px;border:1px solid #E5E7EB;background:white;padding:0 12px;box-shadow:0 1px 3px rgba(0,0,0,0.04)">
<div style="display:flex;align-items:center;gap:20px;border-bottom:1px solid #E5E7EB;padding-top:10px">
<button
type="button"
onClick={() => setPortfolioTopTab('my_portfolio')}
style={`padding:0 0 10px;font-size:13px;font-weight:500;background:none;border:none;white-space:nowrap;cursor:pointer;color:${portfolioTopTab() === 'my_portfolio' ? '#FF5E13' : '#6B7280'};border-bottom:${portfolioTopTab() === 'my_portfolio' ? '2px solid #FF5E13' : '2px solid transparent'};margin-bottom:-1px`}
>
My Portfolio
</button>
<button
type="button"
onClick={() => setPortfolioTopTab('preview')}
style={`padding:0 0 10px;font-size:13px;font-weight:500;background:none;border:none;white-space:nowrap;cursor:pointer;color:${portfolioTopTab() === 'preview' ? '#FF5E13' : '#6B7280'};border-bottom:${portfolioTopTab() === 'preview' ? '2px solid #FF5E13' : '2px solid transparent'};margin-bottom:-1px`}
>
Preview
</button>
</div>
</div>
{/* Profile Header */}
<div style="border-radius:14px;border:1px solid #E5E7EB;background:white;box-shadow:0 1px 3px rgba(0,0,0,0.06);overflow:hidden">
<div style="height:3px;background:linear-gradient(90deg,#FF5E13 0%,#FF8A4C 55%,#FFD0B5 100%)" />
<Show when={isPreviewMode}>
<div style="padding:16px 20px;border-bottom:1px solid #E5E7EB;display:flex;align-items:flex-start;justify-content:space-between;gap:12px">
<div style="display:grid;gap:8px">
<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap">
<p style="margin:0;font-size:18px;font-weight:800;color:#111827">Alex Morgan</p>
<span style="font-size:11px;font-weight:700;color:#374151;background:#F3F4F6;border:1px solid #E5E7EB;border-radius:999px;padding:2px 9px">Verified</span>
<span style="font-size:11px;font-weight:700;color:#C2410C;background:#FFF1EB;border:1px solid #FFD8C2;border-radius:999px;padding:2px 9px">Top Response Rate</span>
</div>
<p style="margin:0;font-size:13px;color:#4B5563">{spec.roleLabel}</p>
<div style="display:flex;align-items:center;gap:6px;flex-wrap:wrap">
<span style="height:24px;padding:0 10px;border-radius:999px;background:#FFF1EB;color:#C2410C;font-size:11px;font-weight:700;display:inline-flex;align-items:center">Area: South Chennai</span>
<span style="height:24px;padding:0 10px;border-radius:999px;background:#FFF1EB;color:#C2410C;font-size:11px;font-weight:700;display:inline-flex;align-items:center">Place: T. Nagar, Chennai</span>
<span style="height:24px;padding:0 10px;border-radius:999px;border:1px solid #E5E7EB;background:#F9FAFB;color:#374151;font-size:11px;font-weight:700;display:inline-flex;align-items:center">Travel: T. Nagar, Adyar, Velachery, Anna Nagar</span>
</div>
</div>
<div style="display:flex;gap:8px;flex-shrink:0;align-self:center" />
</div>
</Show>
<div style="padding:0 20px;border-bottom:1px solid #E5E7EB;background:#FFFFFF">
<div style="display:flex;align-items:center;gap:20px;overflow-x:auto;padding-top:10px">
<For each={[...submissionTabs, 'preview']}>
{(item) => {
const itemKey = normalizeTabKey(item);
const isPreviewStep = itemKey === 'preview';
const isLockedTestimonialsTab = itemKey === 'testimonials' && !testimonialsUnlocked;
const isActive = isPreviewStep ? isPreviewMode : (!isPreviewMode && selectedPortfolioTabKey === itemKey);
return (
<button
type="button"
disabled={isLockedTestimonialsTab}
onClick={() => {
if (isLockedTestimonialsTab) return;
if (isPreviewStep) {
setPortfolioTopTab('preview');
return;
}
setPortfolioTopTab('my_portfolio');
props.onTabSelect(item);
}}
title={isLockedTestimonialsTab ? 'Unlock after 3 completed jobs and 2 customer feedback entries' : (isPreviewStep ? 'Final preview before submit' : '')}
style={`padding:0 0 10px;font-size:13px;font-weight:500;background:none;border:none;white-space:nowrap;cursor:${isLockedTestimonialsTab ? 'not-allowed' : 'pointer'};opacity:${isLockedTestimonialsTab ? 0.5 : 1};color:${isActive ? '#FF5E13' : '#6B7280'};border-bottom:${isActive ? '2px solid #FF5E13' : '2px solid transparent'};margin-bottom:-1px;flex-shrink:0`}
>
{titleCase(item)}{isLockedTestimonialsTab ? ' • Locked' : ''}
</button>
);
}}
</For>
</div>
</div>
<Show when={isPreviewMode}>
<div style="padding:14px 16px;display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px">
{spec.statsLabels.slice(0, 4).map((label, i) => (
<div style="border:1px solid #E5E7EB;border-radius:12px;background:#FAFBFD;padding:12px 12px">
<p style="margin:0;font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:0.05em;color:#9CA3AF">{label}</p>
<p style="margin:5px 0 0;font-size:14px;font-weight:800;color:#111827">{i===0?'248':i===1?'7+':i===2?'Verified':i===3?'2 days':'Yes'}</p>
</div>
))}
</div>
</Show>
</div>
<Show when={!isPreviewMode}>
<div style="display:grid;grid-template-columns:2fr 1fr;gap:10px">
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<div style="display:flex;justify-content:space-between;align-items:center;gap:10px">
<p style="margin:0;font-size:13px;font-weight:700;color:#111827">{titleCase(selectedPortfolioTab)}</p>
<span style="height:22px;padding:0 8px;border-radius:999px;border:1px solid #DDEBFF;background:#EEF4FF;display:inline-flex;align-items:center;font-size:10px;font-weight:700;color:#03004E">
{selectedPortfolioFormFields.length} fields
</span>
</div>
<Show when={!!portfolioValidationNotice()}>
<div style="margin-top:10px;border:1px solid #E5E7EB;background:#F9FAFB;border-radius:8px;padding:8px 10px;font-size:12px;color:#374151">
{portfolioValidationNotice()}
</div>
</Show>
<Show when={selectedPortfolioTabKey === serviceTabKey}>
<div style="display:grid;gap:10px;margin-top:10px">
<div style="display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px">
<input type="text" value={portfolioServiceDraft().name} onInput={(e) => setPortfolioServiceDraft((prev) => ({ ...prev, name: e.currentTarget.value }))} placeholder="Service name" style="height:36px;border:1px solid #E5E7EB;border-radius:8px;background:white;padding:0 10px;font-size:12px;color:#111827;outline:none" />
<input type="text" value={portfolioServiceDraft().price} onInput={(e) => setPortfolioServiceDraft((prev) => ({ ...prev, price: e.currentTarget.value }))} placeholder="Starting price" style="height:36px;border:1px solid #E5E7EB;border-radius:8px;background:white;padding:0 10px;font-size:12px;color:#111827;outline:none" />
<input type="text" value={portfolioServiceDraft().model} onInput={(e) => setPortfolioServiceDraft((prev) => ({ ...prev, model: e.currentTarget.value }))} placeholder="Pricing model (Flat/Hourly)" style="height:36px;border:1px solid #E5E7EB;border-radius:8px;background:white;padding:0 10px;font-size:12px;color:#111827;outline:none" />
<input type="text" value={portfolioServiceDraft().details} onInput={(e) => setPortfolioServiceDraft((prev) => ({ ...prev, details: e.currentTarget.value }))} placeholder="Delivery timeline or details" style="height:36px;border:1px solid #E5E7EB;border-radius:8px;background:white;padding:0 10px;font-size:12px;color:#111827;outline:none" />
</div>
<div style="display:flex;justify-content:flex-start">
<button type="button" onClick={addServiceDraft} style="height:32px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 12px;font-size:12px;font-weight:700;color:#374151;cursor:pointer">Add Service</button>
</div>
<div style="display:grid;gap:8px">
<For each={portfolioServices()}>{(service, idx) => (
<div style="border:1px solid #E5E7EB;border-radius:10px;background:#FAFBFD;padding:10px;display:grid;grid-template-columns:1fr auto;gap:8px;align-items:start">
<div style="display:grid;gap:4px">
<p style="margin:0;font-size:12px;font-weight:700;color:#111827">{service.name}</p>
<p style="margin:0;font-size:11px;color:#6B7280">{service.model} {service.price}</p>
<p style="margin:0;font-size:11px;color:#374151">{service.details || 'No additional notes'}</p>
</div>
<button type="button" onClick={() => removeServiceItem(idx())} style="height:28px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 10px;font-size:11px;font-weight:700;color:#374151;cursor:pointer">Remove</button>
</div>
)}</For>
</div>
</div>
</Show>
<Show when={selectedPortfolioTabKey === galleryTabKey}>
<div style="display:grid;gap:10px;margin-top:10px">
<div style="display:flex;align-items:center;justify-content:space-between;gap:8px">
<p style="margin:0;font-size:12px;color:#374151">Portfolio photos ({portfolioPhotos().length}/6)</p>
<button type="button" onClick={addPhotoItem} disabled={portfolioPhotos().length >= 6} style={`height:32px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 12px;font-size:12px;font-weight:700;color:#374151;cursor:${portfolioPhotos().length >= 6 ? 'not-allowed' : 'pointer'};opacity:${portfolioPhotos().length >= 6 ? 0.6 : 1}`}>Add Photo</button>
</div>
<div style="display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px">
<For each={portfolioPhotos()}>{(photo, idx) => (
<div style="border:1px solid #E5E7EB;border-radius:10px;background:#FAFBFD;padding:10px;display:flex;align-items:center;justify-content:space-between;gap:8px">
<span style="font-size:12px;font-weight:600;color:#374151">{photo}</span>
<button type="button" onClick={() => removePhotoItem(idx())} style="height:26px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 8px;font-size:11px;font-weight:700;color:#374151;cursor:pointer">Remove</button>
</div>
)}</For>
</div>
</div>
</Show>
<Show when={selectedPortfolioTabKey === experienceTabKey}>
<div style="display:grid;gap:10px;margin-top:10px">
<div style="display:grid;grid-template-columns:110px 1fr;gap:10px">
<input type="text" value={portfolioExperienceDraft().year} onInput={(e) => setPortfolioExperienceDraft((prev) => ({ ...prev, year: e.currentTarget.value }))} placeholder="Year" style="height:36px;border:1px solid #E5E7EB;border-radius:8px;background:white;padding:0 10px;font-size:12px;color:#111827;outline:none" />
<input type="text" value={portfolioExperienceDraft().title} onInput={(e) => setPortfolioExperienceDraft((prev) => ({ ...prev, title: e.currentTarget.value }))} placeholder="Role or milestone title" style="height:36px;border:1px solid #E5E7EB;border-radius:8px;background:white;padding:0 10px;font-size:12px;color:#111827;outline:none" />
</div>
<textarea value={portfolioExperienceDraft().details} onInput={(e) => setPortfolioExperienceDraft((prev) => ({ ...prev, details: e.currentTarget.value }))} placeholder="Brief details" style="min-height:72px;border:1px solid #E5E7EB;border-radius:8px;background:white;padding:8px 10px;font-size:12px;color:#111827;outline:none;resize:vertical" />
<div style="display:flex;justify-content:flex-start">
<button type="button" onClick={addExperienceDraft} style="height:32px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 12px;font-size:12px;font-weight:700;color:#374151;cursor:pointer">Add Experience</button>
</div>
<div style="border:1px solid #E5E7EB;border-radius:10px;background:#FAFBFD;padding:10px;display:grid;gap:8px">
<p style="margin:0;font-size:11px;font-weight:700;color:#6B7280;letter-spacing:0.01em;text-transform:none">Design Tools</p>
<div style="display:flex;flex-wrap:wrap;gap:6px">
<For each={portfolioDesignTools()}>
{(tool) => (
<span style="height:24px;padding:0 8px;border-radius:6px;border:1px solid #E5E7EB;background:white;font-size:11px;font-weight:600;color:#374151;display:inline-flex;align-items:center;gap:6px">
{tool}
<button type="button" onClick={() => removePortfolioTag(tool, setPortfolioDesignTools)} style="border:none;background:none;color:#6B7280;cursor:pointer;padding:0;font-size:11px;line-height:1">x</button>
</span>
)}
</For>
</div>
<div style="display:grid;grid-template-columns:1fr auto;gap:8px;align-items:center">
<input type="text" value={portfolioToolInput()} onInput={(e) => setPortfolioToolInput(e.currentTarget.value)} placeholder="Add tools (e.g. Figma, Photoshop, Illustrator)" style="height:34px;border:1px solid #E5E7EB;border-radius:8px;background:white;padding:0 10px;font-size:12px;color:#374151;outline:none" />
<button
type="button"
onClick={() => {
const added = addPortfolioTag(portfolioToolInput(), setPortfolioDesignTools, 10);
if (added) setPortfolioToolInput('');
}}
style="height:32px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 12px;font-size:12px;font-weight:700;color:#374151;cursor:pointer"
>
Add Tool
</button>
</div>
</div>
<div style="display:grid;gap:8px">
<For each={portfolioExperiences()}>{(entry, idx) => (
<div style="border:1px solid #E5E7EB;border-radius:10px;background:#FAFBFD;padding:10px;display:grid;grid-template-columns:1fr auto;gap:8px;align-items:start">
<div style="display:grid;gap:4px">
<p style="margin:0;font-size:12px;font-weight:700;color:#111827">{entry.year} - {entry.title}</p>
<p style="margin:0;font-size:11px;color:#374151">{entry.details || 'No additional notes'}</p>
</div>
<button type="button" onClick={() => removeExperienceItem(idx())} style="height:28px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 10px;font-size:11px;font-weight:700;color:#374151;cursor:pointer">Remove</button>
</div>
)}</For>
</div>
</div>
</Show>
<Show when={selectedPortfolioTabKey !== serviceTabKey && selectedPortfolioTabKey !== galleryTabKey && selectedPortfolioTabKey !== experienceTabKey}>
<div style="display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin-top:10px">
<For each={selectedPortfolioFormFields}>{(field) => renderPortfolioFormField(field)}</For>
</div>
</Show>
</div>
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<p style="margin:0;font-size:11px;letter-spacing:0.04em;text-transform:uppercase;color:#6B7280">Portfolio Form</p>
<p style="margin:8px 0 0;font-size:18px;font-weight:800;color:#111827">Simple step-by-step input</p>
<p style="margin:8px 0 0;font-size:12px;color:#6B7280;line-height:1.5">Fill one tab at a time. Use Next to move through sections, then check final Preview before submitting.</p>
<Show when={!!portfolioValidationNotice()}>
<div style="margin-top:10px;border:1px solid #E5E7EB;background:#F9FAFB;border-radius:8px;padding:8px 10px;font-size:12px;color:#374151">
{portfolioValidationNotice()}
</div>
</Show>
<div style="display:grid;gap:6px;margin-top:10px">
<For each={submissionTabs}>{(tabName, idx) => (
<div style={`height:28px;border-radius:8px;border:1px solid #E5E7EB;background:${idx() === activePortfolioStepIndex ? '#FFF8F4' : '#F9FAFB'};padding:0 10px;display:flex;align-items:center;font-size:11px;font-weight:700;color:${idx() === activePortfolioStepIndex ? '#C2410C' : '#374151'}`}>
{idx() + 1}. {titleCase(tabName)}
</div>
)}</For>
</div>
</div>
</div>
</Show>
<Show when={isPreviewMode}>
<Show when={showSection(normalizeTabKey('about'))}>
{/* About + Specialties */}
<div style="display:grid;grid-template-columns:2fr 1fr;gap:10px">
<div style="border-radius:14px;border:1px solid #E5E7EB;background:white;box-shadow:0 1px 3px rgba(0,0,0,0.05);overflow:hidden">
<div style="padding:12px 16px;border-bottom:1px solid #E5E7EB">
<p style="margin:0;font-size:13px;font-weight:700;color:#111827;display:flex;align-items:center;gap:6px"><UserCircle2 size={14} style="color:#FF5E13" /> About</p>
</div>
<div style="padding:14px 16px">
<Show
when={canEdit}
fallback={<p style="margin:0;font-size:13px;color:#374151;line-height:1.6">Professional {spec.roleLabel.toLowerCase()} with 7+ years of experience delivering high-quality work across India. Committed to excellence, creativity, and client satisfaction on every project.</p>}
>
<textarea
value={`Professional ${spec.roleLabel.toLowerCase()} with 7+ years of experience delivering high-quality work across India. Committed to excellence, creativity, and client satisfaction on every project.`}
style="width:100%;min-height:84px;border:1px solid #FFD8C2;border-radius:10px;background:#FFFCFA;padding:10px;font-size:13px;color:#374151;line-height:1.6;resize:vertical"
/>
</Show>
<div style="margin-top:10px;display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px">
{['Fast response within 2 hours', 'Clear scope & milestone planning', 'Delivery-first execution'].map((line) => (
<div style="border:1px solid #F3F4F6;border-radius:8px;background:#FAFAFA;padding:8px;font-size:11px;font-weight:600;color:#374151">{line}</div>
))}
</div>
</div>
<div style="display:flex;border-top:1px solid #F3F4F6">
{[['7+','Years Exp'],['248','Projects'],['4.9','Rating'],['128','Reviews']].map(([val,lbl], i) => (
<div style={`flex:1;padding:12px 16px;${i<3?'border-right:1px solid #F3F4F6':''}`}>
<p style="margin:0;font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:0.05em;color:#9CA3AF">{lbl}</p>
<p style="margin:4px 0 0;font-size:14px;font-weight:700;color:#111827">{val}</p>
</div>
))}
</div>
</div>
<div style="border-radius:14px;border:1px solid #E5E7EB;background:white;box-shadow:0 1px 3px rgba(0,0,0,0.05);overflow:hidden">
<div style="padding:12px 16px;border-bottom:1px solid #E5E7EB">
<p style="margin:0;font-size:13px;font-weight:700;color:#111827;display:flex;align-items:center;gap:6px"><Rocket size={14} style="color:#FF5E13" /> Specialties</p>
</div>
<div style="padding:14px 16px;display:flex;flex-wrap:wrap;gap:6px">
<For each={portfolioSpecialties()}>
{(s) => (
<span style="height:24px;padding:0 8px;border-radius:6px;border:1px solid #E5E7EB;background:#F9FAFB;font-size:11px;font-weight:600;color:#374151;display:inline-flex;align-items:center;gap:6px">
{s}
<Show when={canEdit}>
<button
type="button"
onClick={() => removePortfolioTag(s, setPortfolioSpecialties)}
style="border:none;background:none;color:#6B7280;cursor:pointer;padding:0;font-size:11px;line-height:1"
aria-label={`Remove ${s}`}
>
x
</button>
</Show>
</span>
)}
</For>
</div>
<Show when={canEdit}>
<div style="padding:0 16px 12px;display:flex;gap:8px;align-items:center">
<input
type="text"
value={portfolioSpecialtyInput()}
onInput={(e) => setPortfolioSpecialtyInput(e.currentTarget.value)}
placeholder="Add specialty"
style="flex:1;height:32px;border:1px solid #E5E7EB;border-radius:8px;background:white;padding:0 10px;font-size:12px;color:#374151;outline:none"
/>
<button
type="button"
onClick={() => {
const added = addPortfolioTag(portfolioSpecialtyInput(), setPortfolioSpecialties, 6);
if (added) setPortfolioSpecialtyInput('');
}}
style="height:32px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 10px;font-size:11px;font-weight:700;color:#374151;cursor:pointer"
>
Add
</button>
</div>
</Show>
<div style="padding:0 16px 14px;border-top:1px solid #F3F4F6;margin-top:4px">
<p style="margin:10px 0 6px;font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:0.05em;color:#9CA3AF">Languages</p>
<div style="display:flex;gap:5px;flex-wrap:wrap">
<For each={portfolioLanguages()}>
{(l) => (
<span style="height:22px;padding:0 8px;border-radius:6px;border:1px solid #E5E7EB;background:#F9FAFB;font-size:11px;font-weight:600;color:#374151;display:inline-flex;align-items:center;gap:6px">
{l}
<Show when={canEdit}>
<button
type="button"
onClick={() => removePortfolioTag(l, setPortfolioLanguages)}
style="border:none;background:none;color:#6B7280;cursor:pointer;padding:0;font-size:11px;line-height:1"
aria-label={`Remove ${l}`}
>
x
</button>
</Show>
</span>
)}
</For>
</div>
<Show when={canEdit}>
<div style="margin-top:6px;display:flex;gap:8px;align-items:center">
<input
type="text"
value={portfolioLanguageInput()}
onInput={(e) => setPortfolioLanguageInput(e.currentTarget.value)}
placeholder="Add language"
style="flex:1;height:30px;border:1px solid #E5E7EB;border-radius:8px;background:white;padding:0 10px;font-size:12px;color:#374151;outline:none"
/>
<button
type="button"
onClick={() => {
const added = addPortfolioTag(portfolioLanguageInput(), setPortfolioLanguages, 6);
if (added) setPortfolioLanguageInput('');
}}
style="height:30px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 10px;font-size:11px;font-weight:700;color:#374151;cursor:pointer"
>
Add
</button>
</div>
</Show>
<p style="margin:10px 0 6px;font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:0.05em;color:#9CA3AF">Service Areas</p>
<div style="display:flex;flex-wrap:wrap;gap:5px">
<For each={portfolioServiceAreas()}>
{(c) => (
<span style="height:22px;padding:0 8px;border-radius:6px;border:1px solid #E5E7EB;background:#F9FAFB;font-size:11px;font-weight:600;color:#374151;display:inline-flex;align-items:center;gap:6px">
{c}
<Show when={canEdit}>
<button
type="button"
onClick={() => removePortfolioTag(c, setPortfolioServiceAreas)}
style="border:none;background:none;color:#6B7280;cursor:pointer;padding:0;font-size:11px;line-height:1"
aria-label={`Remove ${c}`}
>
x
</button>
</Show>
</span>
)}
</For>
</div>
<Show when={canEdit}>
<div style="margin-top:6px;display:flex;gap:8px;align-items:center">
<input
type="text"
value={portfolioAreaInput()}
onInput={(e) => setPortfolioAreaInput(e.currentTarget.value)}
placeholder="Add service area in Chennai"
style="flex:1;height:30px;border:1px solid #E5E7EB;border-radius:8px;background:white;padding:0 10px;font-size:12px;color:#374151;outline:none"
/>
<button
type="button"
onClick={() => {
const added = addPortfolioTag(portfolioAreaInput(), setPortfolioServiceAreas, 8);
if (added) setPortfolioAreaInput('');
}}
style="height:30px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 10px;font-size:11px;font-weight:700;color:#374151;cursor:pointer"
>
Add
</button>
</div>
</Show>
</div>
</div>
</div>
</Show>
<Show when={showSection(serviceTabKey)}>
{/* Packages */}
<div style="border-radius:12px;border:1px solid #E5E7EB;background:linear-gradient(180deg,#FFFFFF 0%,#FCFCFD 100%);box-shadow:0 1px 3px rgba(0,0,0,0.06);overflow:hidden">
<div style="padding:12px 16px;border-bottom:1px solid #E5E7EB;display:flex;justify-content:space-between;align-items:center">
<p style="margin:0;font-size:13px;font-weight:700;color:#111827;display:flex;align-items:center;gap:6px"><Coins size={14} style="color:#FF5E13" /> {titleCase(spec.serviceTabLabel)}</p>
<span style="height:22px;padding:0 8px;border-radius:999px;background:#FFF1EB;border:1px solid #FFD8C2;color:#C2410C;font-size:10px;font-weight:800;display:inline-flex;align-items:center">Transparent Pricing</span>
</div>
<Show when={canEdit}>
<div style="padding:10px 12px;border-bottom:1px solid #E5E7EB;background:#FFFFFF;display:grid;gap:8px">
<div style="display:grid;grid-template-columns:1.2fr 0.9fr 1fr 1.3fr auto;gap:8px;padding:8px;border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB">
<p style="margin:0;font-size:11px;font-weight:700;color:#6B7280;text-transform:uppercase">Service</p>
<p style="margin:0;font-size:11px;font-weight:700;color:#6B7280;text-transform:uppercase">Pricing Type</p>
<p style="margin:0;font-size:11px;font-weight:700;color:#6B7280;text-transform:uppercase">Amount</p>
<p style="margin:0;font-size:11px;font-weight:700;color:#6B7280;text-transform:uppercase">Details</p>
<p style="margin:0;font-size:11px;font-weight:700;color:#6B7280;text-transform:uppercase;text-align:center">Action</p>
</div>
{[1, 2].map((row) => (
<div style="display:grid;grid-template-columns:1.2fr 0.9fr 1fr 1.3fr auto;gap:8px;align-items:center;padding:8px;border:1px solid #E5E7EB;border-radius:10px;background:white">
<input type="text" value={row === 1 ? 'Wedding Coverage' : 'Pre-wedding Shoot'} style="height:34px;border:1px solid #E5E7EB;border-radius:8px;background:white;padding:0 10px;font-size:12px;color:#374151" />
<select style="height:34px;border:1px solid #E5E7EB;border-radius:8px;background:white;padding:0 10px;font-size:12px;color:#374151">
<option>Flat</option>
<option>Hourly</option>
<option>Per Day</option>
</select>
<input type="text" value={row === 1 ? '₹45,000' : '₹18,000'} style="height:34px;border:1px solid #E5E7EB;border-radius:8px;background:white;padding:0 10px;font-size:12px;color:#374151" />
<input type="text" value={row === 1 ? '8 hours, 300 photos' : '4 hours, 120 photos'} style="height:34px;border:1px solid #E5E7EB;border-radius:8px;background:white;padding:0 10px;font-size:12px;color:#374151" />
<button type="button" style="height:32px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 10px;font-size:11px;font-weight:700;color:#374151">Remove</button>
</div>
))}
<div style="display:flex;justify-content:flex-start">
<button type="button" style="height:32px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 12px;font-size:12px;font-weight:700;color:#374151">+ Add Service</button>
</div>
</div>
</Show>
<div style="display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px;padding:12px">
{spec.packages.map((pkg, i) => (
<div style={`border:1px solid ${i === 1 ? '#FFD8C2' : '#E5E7EB'};background:${i === 1 ? '#FFF8F4' : '#FFFFFF'};border-radius:10px;padding:12px`}>
<Show when={i === 1}>
<span style="height:20px;padding:0 8px;border-radius:999px;background:#FF5E13;color:white;font-size:10px;font-weight:800;display:inline-flex;align-items:center">Most Chosen</span>
</Show>
<p style="margin:0;font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:0.05em;color:#9CA3AF">{pkg.name}</p>
<p style="margin:4px 0 0;font-size:16px;font-weight:700;color:#111827">{pkg.price}</p>
<div style="margin-top:8px;display:grid;gap:4px">
{pkg.items.map((item) => (
<div style="display:flex;align-items:center;gap:6px;font-size:12px;color:#374151">
<CheckCircle2 size={11} style="color:#9CA3AF;flex-shrink:0" /> {item}
</div>
))}
</div>
</div>
))}
</div>
</div>
</Show>
<Show when={showSection(galleryTabKey)}>
{/* Work Gallery */}
<div style="border-radius:12px;border:1px solid #E5E7EB;background:linear-gradient(180deg,#FFFFFF 0%,#FCFCFD 100%);box-shadow:0 1px 3px rgba(0,0,0,0.06);overflow:hidden">
<div style="padding:12px 16px;border-bottom:1px solid #E5E7EB;display:flex;align-items:center;justify-content:space-between">
<p style="margin:0;font-size:13px;font-weight:700;color:#111827;display:flex;align-items:center;gap:6px"><Image size={14} style="color:#FF5E13" /> {titleCase(spec.galleryTabLabel)}</p>
<button type="button" disabled={!canEdit} style={`height:30px;border-radius:8px;border:none;background:#0D0D2A;color:white;padding:0 12px;font-size:11px;font-weight:600;cursor:${canEdit ? 'pointer' : 'not-allowed'};opacity:${canEdit ? 1 : 0.6}`}>{mediaConfig.ctaLabel}</button>
</div>
<Show when={canEdit}>
<div style="padding:10px 12px;border-bottom:1px solid #E5E7EB;background:#FFF8F4">
<div style="height:34px;border:1px dashed #FFD8C2;border-radius:8px;background:#FFFCFA;display:flex;align-items:center;justify-content:center;font-size:12px;color:#9A3412;font-weight:600">
Drag files here or click upload to add portfolio samples (max 6 photos)
</div>
</div>
</Show>
<Show
when={mediaConfig.mode === 'visual'}
fallback={
<div style="padding:14px 16px;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px">
<For each={mediaConfig.items}>
{(item, idx) => (
<div style="min-height:84px;border-radius:10px;border:1px solid #E5E7EB;background:#F9FAFB;padding:10px;display:flex;gap:8px;align-items:flex-start">
<FileText size={16} style="color:#9CA3AF;flex-shrink:0;margin-top:2px" />
<div>
<p style="margin:0;font-size:12px;font-weight:700;color:#111827">{item}</p>
<p style="margin:4px 0 0;font-size:11px;color:#6B7280">Entry #{idx() + 1} Structured proof without mandatory photos</p>
</div>
</div>
)}
</For>
</div>
}
>
<div style="padding:14px 16px;display:grid;grid-template-columns:repeat(3,1fr);gap:8px">
{[0,1,2,3,4,5].map((i) => (
<div style="height:110px;border-radius:10px;border:1px solid #E5E7EB;background:linear-gradient(180deg,#FFFFFF 0%,#F8FAFC 100%);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:6px">
<Image size={20} style="color:#C5CCD5" />
<span style="font-size:10px;color:#9CA3AF;text-align:center;padding:0 6px;line-height:1.35">{mediaConfig.items[i % mediaConfig.items.length]}</span>
</div>
))}
</div>
</Show>
</div>
</Show>
<Show when={showSection(experienceTabKey)}>
{/* Experience */}
<div style="border-radius:12px;border:1px solid #E5E7EB;background:linear-gradient(180deg,#FFFFFF 0%,#FCFCFD 100%);box-shadow:0 1px 3px rgba(0,0,0,0.06);overflow:hidden">
<div style="padding:12px 16px;border-bottom:1px solid #E5E7EB">
<p style="margin:0;font-size:13px;font-weight:700;color:#111827;display:flex;align-items:center;gap:6px"><BriefcaseBusiness size={14} style="color:#FF5E13" /> {titleCase(spec.experienceTabLabel)}</p>
</div>
<Show when={canEdit}>
<div style="padding:10px 12px;border-bottom:1px solid #E5E7EB;background:#FFF8F4;display:grid;grid-template-columns:120px 1fr;gap:8px">
<input type="text" value="Year" style="height:34px;border:1px solid #FFD8C2;border-radius:8px;background:#FFFCFA;padding:0 10px;font-size:12px;color:#374151" />
<input type="text" value="Milestone description" style="height:34px;border:1px solid #FFD8C2;border-radius:8px;background:#FFFCFA;padding:0 10px;font-size:12px;color:#374151" />
</div>
</Show>
<div style="padding:14px 16px">
<p style="margin:0 0 8px;font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:0.05em;color:#9CA3AF">{spec.equipmentLabel}</p>
<div style="display:flex;flex-wrap:wrap;gap:6px">
{spec.specialties.map((item) => (
<span style="height:24px;padding:0 8px;border-radius:6px;border:1px solid #E5E7EB;background:#F9FAFB;font-size:11px;font-weight:600;color:#374151;display:inline-flex;align-items:center">{item}</span>
))}
</div>
<div style="margin-top:12px">
<p style="margin:0 0 8px;font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:0.05em;color:#9CA3AF">Design Tools</p>
<Show
when={canEdit}
fallback={
<div style="display:flex;flex-wrap:wrap;gap:6px">
{(portfolioDesignTools().length ? portfolioDesignTools() : portfolioTools).map((tool) => (
<span style="height:24px;padding:0 8px;border-radius:6px;border:1px solid #E5E7EB;background:#F9FAFB;font-size:11px;font-weight:600;color:#374151;display:inline-flex;align-items:center">{tool}</span>
))}
</div>
}
>
<div style="display:grid;grid-template-columns:1fr auto;gap:8px;align-items:center">
<input type="text" placeholder="Add tools (e.g. Figma, Photoshop, Illustrator)" style="height:34px;border:1px solid #E5E7EB;border-radius:8px;background:white;padding:0 10px;font-size:12px;color:#374151" />
<button type="button" style="height:32px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 12px;font-size:12px;font-weight:700;color:#374151">+ Add Tool</button>
</div>
<div style="display:flex;flex-wrap:wrap;gap:6px;margin-top:8px">
{(portfolioDesignTools().length ? portfolioDesignTools() : portfolioTools).map((tool) => (
<span style="height:24px;padding:0 8px;border-radius:6px;border:1px solid #E5E7EB;background:#F9FAFB;font-size:11px;font-weight:600;color:#374151;display:inline-flex;align-items:center;gap:6px">
{tool}
<button type="button" style="border:none;background:none;color:#9CA3AF;cursor:pointer;font-size:11px;line-height:1"></button>
</span>
))}
</div>
</Show>
</div>
</div>
<div style="border-top:1px solid #F3F4F6">
{[['2018','Started professional career as '+spec.roleLabel],['2020','Completed 100+ successful projects'],['2022','Won regional industry recognition'],['2024','Joined Nxtgauge marketplace']].map(([yr, desc], i, arr) => (
<div style={`display:flex;gap:12px;align-items:flex-start;padding:10px 16px;${i<arr.length-1?'border-bottom:1px solid #F3F4F6':''}`}>
<span style="margin-top:2px;width:8px;height:8px;border-radius:999px;background:#FF5E13;flex-shrink:0" />
<p style="margin:0;font-size:11px;font-weight:700;color:#9CA3AF;min-width:32px">{yr}</p>
<p style="margin:0;font-size:13px;color:#374151;line-height:1.5">{desc}</p>
</div>
))}
</div>
</div>
</Show>
<Show when={showSection(testimonialsTabKey)}>
{/* Testimonials */}
<div style="border-radius:12px;border:1px solid #E5E7EB;background:linear-gradient(180deg,#FFFFFF 0%,#FCFCFD 100%);box-shadow:0 1px 3px rgba(0,0,0,0.06);overflow:hidden">
<div style="padding:12px 16px;border-bottom:1px solid #E5E7EB;display:flex;align-items:center;justify-content:space-between;gap:10px">
<p style="margin:0;font-size:13px;font-weight:700;color:#111827;display:flex;align-items:center;gap:6px"><Star size={14} style="color:#FF5E13" /> Testimonials</p>
<Show
when={testimonialsUnlocked}
fallback={<span style="font-size:11px;font-weight:700;color:#C2410C;background:#FFF1EB;border:1px solid #FFD8C2;border-radius:6px;padding:1px 7px">Locked For New Profiles</span>}
>
<span style="font-size:11px;font-weight:600;color:#374151;background:#F3F4F6;border:1px solid #E5E7EB;border-radius:6px;padding:1px 7px">4.9 · 128 reviews</span>
</Show>
</div>
<Show
when={testimonialsUnlocked}
fallback={
<div style="padding:16px">
<div style="border:1px dashed #FFD8C2;background:#FFF8F4;border-radius:10px;padding:14px">
<p style="margin:0;font-size:13px;font-weight:700;color:#111827">Testimonials will be activated automatically.</p>
<p style="margin:6px 0 0;font-size:12px;line-height:1.5;color:#6B7280">
New professionals unlock testimonials after completing at least <strong>3 jobs</strong> and receiving at least <strong>2 customer feedback entries</strong>.
</p>
<p style="margin:8px 0 0;font-size:11px;color:#9CA3AF">Current progress: {portfolioJobsCompleted} jobs completed {portfolioFeedbackCount} feedback received</p>
</div>
</div>
}
>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;padding:10px">
{PORTFOLIO_TESTIMONIALS.map((t, i) => (
<div style="padding:14px 16px;border:1px solid #E5E7EB;border-radius:10px;background:#FFFFFF">
<div style="display:flex;justify-content:space-between;align-items:center">
<p style="margin:0;font-size:13px;font-weight:700;color:#111827">{t.name}</p>
<div style="display:flex;gap:1px">
{Array.from({length: t.rating}).map(() => <Star size={11} style="color:#F59E0B" fill="#F59E0B" />)}
</div>
</div>
<p style="margin:2px 0 0;font-size:11px;color:#9CA3AF">{t.category}</p>
<p style="margin:8px 0 0;font-size:12px;color:#374151;line-height:1.5">{t.text}</p>
</div>
))}
</div>
</Show>
</div>
</Show>
<Show when={showSection(faqsTabKey)}>
{/* FAQs */}
<div style="border-radius:12px;border:1px solid #E5E7EB;background:linear-gradient(180deg,#FFFFFF 0%,#FCFCFD 100%);box-shadow:0 1px 3px rgba(0,0,0,0.06);overflow:hidden">
<div style="padding:12px 16px;border-bottom:1px solid #E5E7EB">
<p style="margin:0;font-size:13px;font-weight:700;color:#111827;display:flex;align-items:center;gap:6px"><HelpCircle size={14} style="color:#FF5E13" /> Frequently Asked Questions</p>
</div>
<Show when={canEdit}>
<div style="padding:10px 12px;border-bottom:1px solid #E5E7EB;background:#FFF8F4;display:grid;gap:8px">
<input type="text" value="Add question" style="height:34px;border:1px solid #FFD8C2;border-radius:8px;background:#FFFCFA;padding:0 10px;font-size:12px;color:#374151" />
<textarea style="min-height:66px;border:1px solid #FFD8C2;border-radius:8px;background:#FFFCFA;padding:8px 10px;font-size:12px;color:#374151;resize:vertical">Add answer</textarea>
</div>
</Show>
<For each={spec.faqItems}>{(faq, i) => (
<div style={`border-bottom:${i() < spec.faqItems.length - 1 ? '1px solid #F3F4F6' : 'none'}`}>
<button
type="button"
onClick={() => setOpenFaqIndex(openFaqIndex()===i() ? null : i())}
style={`width:100%;display:flex;justify-content:space-between;align-items:center;padding:12px 16px;background:${openFaqIndex()===i() ? '#FFF8F4' : 'none'};border:none;cursor:pointer;text-align:left`}
>
<span style="font-size:13px;font-weight:700;color:#111827">{faq.q}</span>
{openFaqIndex()===i() ? <ChevronUp size={15} style="color:#374151;flex-shrink:0" /> : <ChevronDown size={15} style="color:#9CA3AF;flex-shrink:0" />}
</button>
<Show when={openFaqIndex()===i()}>
<div style="padding:0 16px 12px">
<p style="margin:0;font-size:13px;color:#374151;line-height:1.6">{faq.a}</p>
</div>
</Show>
</div>
)}</For>
</div>
</Show>
</Show>
<div style="border-radius:12px;border:1px solid #E5E7EB;background:white;padding:10px 12px;display:flex;align-items:center;justify-content:space-between;gap:10px">
<p style="margin:0;font-size:12px;color:#6B7280">
<Show when={!isPreviewMode} fallback={<span>Final review mode: check all tabs, then submit for approval.</span>}>
<span>Step {activePortfolioStepIndex + 1} of {portfolioStepKeys.length}</span>
</Show>
</p>
<div style="display:flex;align-items:center;gap:8px">
<button
type="button"
onClick={() => {
if (isPreviewMode) {
setPortfolioTopTab('my_portfolio');
goToPortfolioStep(portfolioStepKeys.length - 1);
return;
}
goToPortfolioStep(activePortfolioStepIndex - 1);
}}
disabled={!isPreviewMode && activePortfolioStepIndex === 0}
style={`height:32px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 12px;font-size:12px;font-weight:700;color:#374151;cursor:${(!isPreviewMode && activePortfolioStepIndex === 0) ? 'not-allowed' : 'pointer'};opacity:${(!isPreviewMode && activePortfolioStepIndex === 0) ? 0.5 : 1}`}
>
Previous
</button>
<Show
when={!isPreviewMode}
fallback={
<button type="button" onClick={() => setPortfolioTopTab('my_portfolio')} style="height:32px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 12px;font-size:12px;font-weight:700;color:#374151">
Back To Edit
</button>
}
>
<button
type="button"
onClick={() => {
const currentStepKey = portfolioStepKeys[activePortfolioStepIndex];
if (!validatePortfolioStep(currentStepKey)) return;
if (activePortfolioStepIndex >= portfolioStepKeys.length - 1) {
setPortfolioTopTab('preview');
return;
}
goToPortfolioStep(activePortfolioStepIndex + 1);
}}
style="height:32px;border-radius:8px;border:none;background:#03004E;color:white;padding:0 12px;font-size:12px;font-weight:700"
>
{activePortfolioStepIndex >= portfolioStepKeys.length - 1 ? 'Final Preview' : 'Next'}
</button>
</Show>
</div>
</div>
</div>
);
};
const renderCustomerContent = () => {
const tab = resolvedTabKey();
if (customerKey() === 'my dashboard') {
if (tab === 'recent requirements') {
return (
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<p style="margin:0;font-size:14px;font-weight:700;color:#111827">Recent Requirements</p>
<div style="margin-top:10px;display:grid;gap:8px">
<For each={requirementRows()}>{(row) => {
const chip = statusChip(row.status);
return (
<div style="display:grid;grid-template-columns:2fr 1fr 1fr 1fr;gap:8px;padding:8px;border:1px solid #E5E7EB;border-radius:8px;background:#F9FAFB">
<span style="font-size:12px;font-weight:700;color:#111827">{row.title}</span>
<span style="font-size:12px;color:#6B7280">{row.amount}</span>
<span style={`display:inline-flex;align-items:center;justify-content:center;height:22px;border-radius:999px;background:${chip.bg};color:${chip.c};font-size:11px;font-weight:700;text-transform:uppercase`}>{row.status}</span>
<span style="font-size:12px;color:#374151">{row.responses} responses</span>
</div>
);
}}</For>
</div>
</div>
);
}
if (tab === 'quick actions') {
return (
<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px">
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<p style="margin:0;font-size:14px;font-weight:700;color:#111827">Quick Actions</p>
<div style="display:grid;gap:8px;margin-top:8px">
{['Post New Requirement', 'View Responses', 'Buy Credits', 'Explore Professionals'].map((a, i) => (
<button type="button" style={`height:34px;border-radius:8px;border:${i===0?'none':'1px solid #E5E7EB'};background:${i===0?'#FF5E13':'white'};color:${i===0?'white':'#374151'};font-size:12px;font-weight:700;cursor:pointer;text-align:left;padding:0 10px`}>
{a}
</button>
))}
</div>
</div>
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<p style="margin:0;font-size:14px;font-weight:700;color:#111827">Recent Activity</p>
<div style="margin-top:8px;display:grid;gap:8px">
{['Requirement posted', 'New response received', 'Credit purchase completed'].map((a) => <div style="padding:8px;border:1px solid #E5E7EB;border-radius:8px;background:#F9FAFB;font-size:12px;color:#374151">{a}</div>)}
</div>
</div>
</div>
);
}
return (
<div style="display:flex;flex-direction:column;gap:10px">
<Show when={!bothApprovalsApproved()}>
<div style="border:1px solid #E5E7EB;background:white;border-radius:12px;padding:12px;box-shadow:0 1px 4px rgba(0,0,0,0.04)">
<p style="margin:0;font-size:14px;font-weight:800;color:#111827">Complete Verification</p>
<p style="margin:6px 0 0;font-size:12px;color:#6B7280;line-height:1.5">
To start receiving opportunities, submit your profile and portfolio for admin approval.
</p>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:10px">
<div style="border:1px solid #E5E7EB;border-radius:8px;background:#F9FAFB;padding:8px">
<p style="margin:0;font-size:11px;color:#6B7280">Step 1</p>
<p style="margin:4px 0 0;font-size:12px;font-weight:800;color:#111827">Profile: {approvalTone(profileApprovalState()).label}</p>
</div>
<div style="border:1px solid #E5E7EB;border-radius:8px;background:#F9FAFB;padding:8px">
<p style="margin:0;font-size:11px;color:#6B7280">Step 2</p>
<p style="margin:4px 0 0;font-size:12px;font-weight:800;color:#111827">Portfolio: {approvalTone(portfolioApprovalState()).label}</p>
</div>
</div>
<div style="display:flex;gap:8px;flex-wrap:wrap;margin-top:10px">
<button type="button" onClick={() => { props.onSidebarSelect('My Profile'); props.onTabSelect('basic information'); }} style="height:32px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 12px;font-size:12px;font-weight:700;color:#374151">Open My Profile</button>
<Show when={isProfessionalRole()}>
<button type="button" onClick={() => { props.onSidebarSelect('My Portfolio'); props.onTabSelect('about'); }} style="height:32px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 12px;font-size:12px;font-weight:700;color:#374151">Open My Portfolio</button>
</Show>
<button type="button" onClick={() => props.onSidebarSelect('Verification')} style="height:32px;border-radius:8px;border:none;background:#03004E;color:white;padding:0 12px;font-size:12px;font-weight:700">Open Verification</button>
</div>
</div>
</Show>
<div style="border:1px solid #E5E7EB;background:white;border-radius:12px;padding:10px 12px;box-shadow:0 1px 4px rgba(0,0,0,0.04)">
<p style="margin:0;font-size:11px;letter-spacing:0.04em;text-transform:uppercase;color:#6B7280">Widget Customization</p>
<p style="margin:4px 0 0;font-size:12px;color:#374151">Drag and drop cards below to reorder your dashboard widgets.</p>
</div>
<div style="display:grid;grid-template-columns:2fr 1fr 1fr;gap:10px">
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<p style="margin:0;font-size:32px;font-weight:800;color:#111827;line-height:1.1">Welcome back, {props.liveData?.userName ?? 'Alex'}</p>
<p style="margin:6px 0 0;font-size:13px;color:#6B7280">To start receiving opportunities, complete My Profile and My Portfolio, then submit both for approval.</p>
<div style="display:flex;gap:8px;flex-wrap:wrap;margin-top:10px">
<button type="button" onClick={() => { props.onSidebarSelect('My Profile'); props.onTabSelect('basic information'); }} style="height:30px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 10px;font-size:11px;font-weight:700;color:#374151">Fill My Profile</button>
<Show when={isProfessionalRole()}>
<button type="button" onClick={() => { props.onSidebarSelect('My Portfolio'); props.onTabSelect('about'); }} style="height:30px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 10px;font-size:11px;font-weight:700;color:#374151">Fill My Portfolio</button>
</Show>
<button type="button" onClick={() => props.onSidebarSelect('Verification')} style="height:30px;border-radius:8px;border:none;background:#03004E;color:white;padding:0 10px;font-size:11px;font-weight:700">Submit For Approval</button>
</div>
</div>
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<p style="margin:0;font-size:11px;letter-spacing:0.04em;color:#6B7280;text-transform:uppercase">Profile Status</p>
<p style="margin:8px 0 0;font-size:34px;font-weight:800;color:#111827">85%</p>
</div>
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<p style="margin:0;font-size:11px;letter-spacing:0.04em;text-transform:uppercase;color:#6B7280">Credits Balance</p>
<p style="margin:8px 0 0;font-size:34px;font-weight:800;line-height:1;color:#111827">{leadCredits().toLocaleString('en-IN')}</p>
</div>
</div>
<div style="display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:10px">
<For each={dashboardWidgetOrder().slice(0, 5)}>
{(w) => (
<div
draggable
onDragStart={(e) => {
setDraggingDashboardWidget(w);
e.dataTransfer?.setData('text/plain', w);
}}
onDragOver={(e) => e.preventDefault()}
onDrop={(e) => {
e.preventDefault();
moveDashboardWidget(draggingDashboardWidget() || '', w);
setDraggingDashboardWidget(null);
}}
style={`border:1px solid #E5E7EB;background:${draggingDashboardWidget() === w ? '#FFF8F4' : 'white'};border-radius:12px;padding:10px;min-height:92px;box-shadow:0 1px 3px rgba(0,0,0,0.05);cursor:grab`}
>
<p style="margin:0;font-size:11px;letter-spacing:0.04em;text-transform:uppercase;color:#6B7280">{titleCase(w)}</p>
<p style="margin:10px 0 0;font-size:22px;font-weight:800;color:#111827">42</p>
</div>
)}
</For>
</div>
</div>
);
}
if (customerKey().includes('profile')) {
const spec = currentProfileSpec();
const selectedTab = spec.tabs.find((item) => normalizeTabKey(item) === normalizeTabKey(tab)) || spec.tabs[0] || 'basic info';
const selectedTabKey = normalizeTabKey(selectedTab);
const defaultFields = ['First Name', 'Last Name', 'Email Address', 'Mobile Number', 'City'];
const fieldsForTab = spec.tabFields[selectedTab] || spec.tabFields[spec.tabs[0] || ''] || defaultFields;
const isPreferencesTab = normalizeTabKey(selectedTab) === 'preferences';
const isDocumentsTab = selectedTabKey === 'documents';
const isRequiredField = (field: string) => !/\(optional\)|optional/i.test(field);
const requiredCount = fieldsForTab.filter((f) => isRequiredField(f)).length;
const profileState = () => approvalTone(profileApprovalState());
const renderField = (field: string) => {
const required = isRequiredField(field);
const isSelect = /country|mode|type|category|level|gender|industry|subjects|platforms|budget|response time/i.test(field);
const isSpecialitiesField = /specialit|specializ|skills/i.test(field);
const cleanLabel = String(field || '').replace(/\(optional\)/ig, '').trim();
const safeLabel = cleanLabel || 'value';
const key = safeLabel.toLowerCase();
const labelText = (() => {
if (key.includes('specialt') || key.includes('specialit') || key.includes('specializ')) return 'Specialities';
return safeLabel;
})();
const isCityField = key === 'city';
const placeholderText = (() => {
if (key.includes('gender')) return 'Select gender';
if (key.includes('address line 1')) return 'Enter address line 1';
if (key.includes('address line 2')) return 'Enter address line 2';
if (key === 'city') return 'Chennai';
if (key === 'state') return 'Enter state';
if (key === 'address') return 'Enter full address in Chennai';
if (key.includes('address proof')) return 'Upload address proof (PDF/JPG/PNG)';
if (key.includes('proof') || key.includes('certificate') || key.includes('document')) return `Upload ${labelText} (PDF/JPG/PNG)`;
if (key.includes('pin code') || key.includes('pincode')) return 'Enter 6-digit pincode';
if (key.includes('area')) return 'Enter area in Chennai';
if (key.includes('place')) return 'Enter place in Chennai';
if (isSpecialitiesField) return 'e.g. Wedding, Product, Portrait';
return `${isSelect ? 'Select' : 'Enter'} ${labelText.toLowerCase()}`;
})();
return (
<div style="display:flex;flex-direction:column;gap:6px">
<p style="margin:0;font-size:11px;font-weight:700;color:#6B7280;letter-spacing:0.01em;text-transform:none">
{labelText}
<Show when={required}>
<span style="color:#FF5E13;margin-left:4px">*</span>
</Show>
</p>
<div style="position:relative">
<input
type="text"
value={profileFormData()[field] ?? (isCityField ? 'Chennai' : '')}
readOnly={isCityField}
onInput={(e) => !isCityField && setProfileFormData((prev) => ({ ...prev, [field]: e.currentTarget.value }))}
placeholder={placeholderText}
style="width:100%;height:36px;border:1px solid #E5E7EB;border-radius:8px;background:white;padding:0 30px 0 10px;font-size:12px;color:#111827;outline:none"
/>
<Show when={isSelect}>
<span style="position:absolute;right:10px;top:50%;transform:translateY(-50%);color:#9CA3AF;font-size:12px"></span>
</Show>
</div>
</div>
);
};
if (selectedTab === 'settings') {
const settingsTabs: Array<{ key: 'change_password' | 'notifications' | 'privacy'; label: string }> = [
{ key: 'change_password', label: 'Change Password' },
{ key: 'notifications', label: 'Notifications' },
{ key: 'privacy', label: 'Privacy' },
];
const activeSettingsTab = profileSettingsTab();
return (
<div style="display:grid;grid-template-columns:1fr;gap:10px">
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<p style="margin:0;font-size:13px;font-weight:700;color:#111827">Settings</p>
<div style="display:flex;align-items:center;gap:20px;margin-top:10px;border-bottom:1px solid #E5E7EB">
<For each={settingsTabs}>
{(item) => (
<button
type="button"
onClick={() => setProfileSettingsTab(item.key)}
style={`padding:0 0 10px;font-size:13px;font-weight:500;background:none;border:none;cursor:pointer;${activeSettingsTab === item.key ? 'color:#FF5E13;border-bottom:2px solid #FF5E13;margin-bottom:-1px' : 'color:#6B7280'}`}
>
{item.label}
</button>
)}
</For>
</div>
<Show when={activeSettingsTab === 'change_password'}>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:10px">
<div style="display:flex;flex-direction:column;gap:6px">
<p style="margin:0;font-size:11px;font-weight:700;color:#6B7280;letter-spacing:0.04em;text-transform:uppercase">Current Password<span style="color:#FF5E13;margin-left:4px">*</span></p>
<input type="password" placeholder="Enter current password" style="height:36px;border:1px solid #E5E7EB;border-radius:8px;background:white;padding:0 10px;font-size:12px;color:#111827;outline:none" />
</div>
<div style="display:flex;flex-direction:column;gap:6px">
<p style="margin:0;font-size:11px;font-weight:700;color:#6B7280;letter-spacing:0.04em;text-transform:uppercase">New Password<span style="color:#FF5E13;margin-left:4px">*</span></p>
<input type="password" placeholder="Enter new password" style="height:36px;border:1px solid #E5E7EB;border-radius:8px;background:white;padding:0 10px;font-size:12px;color:#111827;outline:none" />
</div>
</div>
<div style="display:flex;flex-direction:column;gap:6px;margin-top:10px">
<p style="margin:0;font-size:11px;font-weight:700;color:#6B7280;letter-spacing:0.04em;text-transform:uppercase">Confirm Password<span style="color:#FF5E13;margin-left:4px">*</span></p>
<input type="password" placeholder="Confirm new password" style="height:36px;border:1px solid #E5E7EB;border-radius:8px;background:white;padding:0 10px;font-size:12px;color:#111827;outline:none" />
</div>
</Show>
<Show when={activeSettingsTab === 'notifications'}>
<div style="display:grid;gap:8px;margin-top:10px">
{[
['email_updates', 'Email Updates'],
['in_app_alerts', 'In-app Alerts'],
['verification_reminders', 'Verification Reminders'],
].map(([key, title]) => (
<div style="display:flex;justify-content:space-between;align-items:center;gap:10px;padding:10px;border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB">
<p style="margin:0;font-size:12px;font-weight:700;color:#111827">{title}</p>
<button
type="button"
onClick={() => toggleProfileSetting(String(key))}
style={`height:30px;border-radius:999px;padding:0 12px;font-size:11px;font-weight:700;cursor:pointer;border:1px solid ${profileSettingToggles()[String(key)] ? '#C7D2FE' : '#D1D5DB'};background:${profileSettingToggles()[String(key)] ? '#EEF2FF' : 'white'};color:${profileSettingToggles()[String(key)] ? '#03004E' : '#374151'}`}
>
{profileSettingToggles()[String(key)] ? 'On' : 'Off'}
</button>
</div>
))}
</div>
</Show>
<Show when={activeSettingsTab === 'privacy'}>
<div style="display:grid;gap:8px;margin-top:10px">
{[
['profile_visibility', 'Profile Visibility'],
['data_sharing_consent', 'Data Sharing Consent'],
].map(([key, title]) => (
<div style="display:flex;justify-content:space-between;align-items:center;gap:10px;padding:10px;border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB">
<p style="margin:0;font-size:12px;font-weight:700;color:#111827">{title}</p>
<button
type="button"
onClick={() => toggleProfileSetting(String(key))}
style={`height:30px;border-radius:999px;padding:0 12px;font-size:11px;font-weight:700;cursor:pointer;border:1px solid ${profileSettingToggles()[String(key)] ? '#C7D2FE' : '#D1D5DB'};background:${profileSettingToggles()[String(key)] ? '#EEF2FF' : 'white'};color:${profileSettingToggles()[String(key)] ? '#03004E' : '#374151'}`}
>
{profileSettingToggles()[String(key)] ? 'On' : 'Off'}
</button>
</div>
))}
<div style="display:flex;justify-content:space-between;align-items:center;gap:10px;padding:10px;border:1px solid #FFE2D3;border-radius:10px;background:#FFF8F4">
<div>
<p style="margin:0;font-size:12px;font-weight:700;color:#111827">Delete Account</p>
<p style="margin:2px 0 0;font-size:11px;color:#6B7280">Permanently remove your account and data.</p>
</div>
<button
type="button"
onClick={() => setShowDeleteAccountModal(true)}
style="height:30px;border-radius:8px;padding:0 12px;font-size:11px;font-weight:700;cursor:pointer;border:1px solid #FFD0BA;background:white;color:#FF5E13"
>
Delete
</button>
</div>
</div>
</Show>
<div style="display:flex;justify-content:flex-end;gap:8px;margin-top:12px;padding-top:12px;border-top:1px solid #E5E7EB">
<button type="button" style="height:34px;border-radius:8px;border:1px solid #D1D5DB;background:white;color:#374151;padding:0 14px;font-size:12px;font-weight:700">Cancel</button>
<button type="button" style="height:34px;border-radius:8px;border:none;background:#03004E;color:white;padding:0 14px;font-size:12px;font-weight:700">
{activeSettingsTab === 'change_password' ? 'Update Password' : 'Save Settings'}
</button>
</div>
</div>
<Show when={showDeleteAccountModal()}>
<div style="position:fixed;inset:0;background:rgba(15,23,42,0.4);display:flex;align-items:center;justify-content:center;z-index:50;padding:16px">
<div style="width:min(460px,100%);border:1px solid #E5E7EB;background:white;border-radius:14px;box-shadow:0 10px 30px rgba(0,0,0,0.18);padding:16px">
<div style="display:flex;align-items:center;gap:8px">
<span style="width:22px;height:22px;border-radius:999px;background:#FFF1EB;color:#FF5E13;display:inline-flex;align-items:center;justify-content:center;font-size:13px;font-weight:800">!</span>
<p style="margin:0;font-size:15px;font-weight:800;color:#111827">Delete account?</p>
</div>
<p style="margin:10px 0 0;font-size:13px;color:#374151;line-height:1.5">
This will permanently remove your account. This action cannot be undone.
</p>
<div style="display:flex;justify-content:flex-end;gap:8px;margin-top:14px">
<button
type="button"
onClick={() => setShowDeleteAccountModal(false)}
style="height:34px;border-radius:8px;border:1px solid #D1D5DB;background:white;color:#374151;padding:0 14px;font-size:12px;font-weight:700"
>
Cancel
</button>
<button
type="button"
onClick={() => setShowDeleteAccountModal(false)}
style="height:34px;border-radius:8px;border:none;background:#03004E;color:white;padding:0 14px;font-size:12px;font-weight:700"
>
Yes, Delete Account
</button>
</div>
</div>
</div>
</Show>
</div>
);
}
return (
<div style="display:grid;grid-template-columns:2fr 1fr;gap:10px">
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<div style="display:flex;justify-content:space-between;align-items:center;gap:10px">
<p style="margin:0;font-size:13px;font-weight:700;color:#111827">{isPreferencesTab ? 'Preference Details' : titleCase(selectedTab)}</p>
<span style="height:22px;padding:0 8px;border-radius:999px;border:1px solid #DDEBFF;background:#EEF4FF;display:inline-flex;align-items:center;font-size:10px;font-weight:700;color:#03004E">
{fieldsForTab.length} fields
</span>
</div>
<Show
when={isDocumentsTab}
fallback={
<Show
when={isPreferencesTab}
fallback={
<div style="display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin-top:10px">
<For each={fieldsForTab}>{(field) => renderField(field)}</For>
</div>
}
>
<div style="display:grid;grid-template-columns:1fr;gap:8px;margin-top:10px;max-width:560px">
<For each={fieldsForTab}>{(field) => renderField(field)}</For>
</div>
</Show>
}
>
<div style="display:grid;grid-template-columns:1fr;gap:10px;margin-top:10px;max-width:560px">
<div style="display:flex;flex-direction:column;gap:6px">
<p style="margin:0;font-size:11px;font-weight:700;color:#6B7280;letter-spacing:0.01em;text-transform:none">
Document type<span style="color:#FF5E13;margin-left:4px">*</span>
</p>
<select
value={profileDocumentType()}
onChange={(e) => setProfileDocumentType(e.currentTarget.value)}
style="width:100%;height:36px;border:1px solid #E5E7EB;border-radius:8px;background:white;padding:0 10px;font-size:12px;color:#111827;outline:none"
>
<option>Aadhar Card</option>
<option>PAN Card</option>
<option>Passport</option>
<option>Driving License</option>
</select>
</div>
<div style="display:flex;flex-direction:column;gap:6px">
<p style="margin:0;font-size:11px;font-weight:700;color:#6B7280;letter-spacing:0.01em;text-transform:none">
Upload document<span style="color:#FF5E13;margin-left:4px">*</span>
</p>
<input
type="text"
value=""
placeholder={`Upload ${profileDocumentType().toLowerCase()} (PDF/JPG/PNG)`}
style="width:100%;height:36px;border:1px solid #E5E7EB;border-radius:8px;background:white;padding:0 10px;font-size:12px;color:#111827;outline:none"
/>
</div>
</div>
</Show>
<div style="display:flex;justify-content:flex-end;gap:8px;margin-top:12px;padding-top:12px;border-top:1px solid #E5E7EB">
<button type="button" onClick={() => setProfileFormData({})} style="height:34px;border-radius:8px;border:1px solid #D1D5DB;background:white;color:#374151;padding:0 14px;font-size:12px;font-weight:700">Cancel</button>
<button
type="button"
onClick={() => {
if (!hasLive()) return;
const data = profileFormData();
setProfileSaving(true);
const fn = data['First Name'] || '';
const ln = data['Last Name'] || '';
const display = data['Business Name'] || data['Company Name'] || data['Contact Person Name'] || [fn, ln].filter(Boolean).join(' ');
fetch(`${GW}/api/${livePrefix()}/profile/me`, {
method: 'PATCH',
credentials: 'include',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
display_name: display || undefined,
full_name: display || undefined,
first_name: fn || undefined,
last_name: ln || undefined,
business_name: data['Business Name'] || undefined,
company_name: data['Company Name'] || undefined,
contact_person: data['Contact Person Name'] || undefined,
bio: data['Bio'] || undefined,
location: data['City'] || undefined,
area: data['Area'] || undefined,
state: data['State'] || undefined,
pin_code: data['PIN Code'] || undefined,
phone: data['Mobile Number'] || undefined,
email: data['Email Address'] || undefined,
}),
}).then((r) => {
setProfileSaving(false);
setProfileSaveStatus(r.ok ? 'saved' : 'error');
setTimeout(() => setProfileSaveStatus('idle'), 2500);
}).catch(() => { setProfileSaving(false); setProfileSaveStatus('error'); });
}}
style={`height:34px;border-radius:8px;border:none;background:${profileSaveStatus() === 'error' ? '#DC2626' : profileSaveStatus() === 'saved' ? '#16A34A' : '#03004E'};color:white;padding:0 14px;font-size:12px;font-weight:700`}
>
{profileSaving() ? 'Saving…' : profileSaveStatus() === 'saved' ? 'Saved ✓' : profileSaveStatus() === 'error' ? 'Error — Retry' : 'Save Changes'}
</button>
</div>
</div>
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<p style="margin:0;font-size:11px;letter-spacing:0.04em;text-transform:uppercase;color:#6B7280">What To Do Next</p>
<p style="margin:8px 0 0;font-size:18px;font-weight:800;color:#111827;line-height:1.3">Complete profile and portfolio to unlock leads</p>
<p style="margin:8px 0 0;font-size:12px;color:#6B7280;line-height:1.5">Finish My Profile and My Portfolio, then submit both for admin approval. Leads will unlock only after approval.</p>
<div style="display:grid;gap:8px;margin-top:10px">
<div style="display:flex;align-items:center;justify-content:space-between;gap:8px;padding:8px;border:1px solid #E5E7EB;border-radius:8px;background:#F9FAFB">
<span style="font-size:11px;font-weight:700;color:#374151">My Profile</span>
<span style="font-size:11px;font-weight:800;color:#111827">{approvalTone(profileApprovalState()).label}</span>
</div>
<Show when={isProfessionalRole()}>
<div style="display:flex;align-items:center;justify-content:space-between;gap:8px;padding:8px;border:1px solid #E5E7EB;border-radius:8px;background:#F9FAFB">
<span style="font-size:11px;font-weight:700;color:#374151">My Portfolio</span>
<span style="font-size:11px;font-weight:800;color:#111827">{approvalTone(portfolioApprovalState()).label}</span>
</div>
</Show>
</div>
<div style="display:grid;gap:8px;margin-top:10px">
<button type="button" onClick={() => { props.onSidebarSelect('My Profile'); props.onTabSelect('basic information'); }} style="height:32px;border:1px solid #D1D5DB;border-radius:8px;background:white;color:#374151;padding:0 12px;font-size:12px;font-weight:700">Fill My Profile</button>
<Show when={isProfessionalRole()}>
<button type="button" onClick={() => { props.onSidebarSelect('My Portfolio'); props.onTabSelect('about'); }} style="height:32px;border:1px solid #D1D5DB;border-radius:8px;background:white;color:#374151;padding:0 12px;font-size:12px;font-weight:700">Fill My Portfolio</button>
</Show>
<button type="button" onClick={() => props.onSidebarSelect('Verification')} style="height:32px;border:none;border-radius:8px;background:#03004E;color:white;padding:0 12px;font-size:12px;font-weight:700">Submit For Approval</button>
</div>
</div>
</div>
);
}
if (customerKey() === 'leads') {
if (!bothApprovalsApproved()) {
return (
<div style="display:grid;gap:12px">
<div style="border:1px solid #E5E7EB;background:white;border-radius:14px;padding:14px">
<p style="margin:0;font-size:22px;font-weight:800;color:#111827">Leads Locked</p>
<p style="margin:8px 0 0;font-size:13px;color:#6B7280;line-height:1.55">
Complete verification before accessing leads. You must submit profile and portfolio, then get admin approval.
</p>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:10px">
<div style="border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB;padding:10px">
<p style="margin:0;font-size:11px;color:#6B7280;text-transform:uppercase;letter-spacing:0.05em">Profile Verification</p>
<p style="margin:6px 0 0;font-size:13px;font-weight:800;color:#111827">{approvalTone(profileApprovalState()).label}</p>
</div>
<div style="border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB;padding:10px">
<p style="margin:0;font-size:11px;color:#6B7280;text-transform:uppercase;letter-spacing:0.05em">Portfolio Verification</p>
<p style="margin:6px 0 0;font-size:13px;font-weight:800;color:#111827">{approvalTone(portfolioApprovalState()).label}</p>
</div>
</div>
<div style="display:flex;gap:8px;flex-wrap:wrap;margin-top:10px">
<button type="button" onClick={() => props.onSidebarSelect('Verification')} style="height:32px;border-radius:8px;border:none;background:#03004E;color:white;padding:0 12px;font-size:12px;font-weight:700">Open Verification</button>
<button type="button" onClick={() => { props.onSidebarSelect('My Profile'); props.onTabSelect('basic information'); }} style="height:32px;border-radius:8px;border:1px solid #E5E7EB;background:white;color:#374151;padding:0 12px;font-size:12px;font-weight:700">Complete Profile</button>
<button type="button" onClick={() => { props.onSidebarSelect('My Portfolio'); props.onTabSelect('about'); }} style="height:32px;border-radius:8px;border:1px solid #E5E7EB;background:white;color:#374151;padding:0 12px;font-size:12px;font-weight:700">Complete Portfolio</button>
</div>
</div>
</div>
);
}
const requestStatusPill = (status: string) => {
if (status === 'request_sent') return { bg: '#DBEAFE', c: '#1D4ED8', text: 'Request Sent' };
if (status === 'approved') return { bg: '#DCFCE7', c: '#15803D', text: 'Approved' };
if (status === 'contact_unlocked') return { bg: '#ECFDF3', c: '#047857', text: 'Contact Unlocked' };
if (status === 'rejected') return { bg: '#FEE2E2', c: '#B91C1C', text: 'Rejected' };
if (status === 'expired_refunded') return { bg: '#E0E7FF', c: '#4338CA', text: 'Expired · Refunded' };
if (status === 'cancelled_by_professional') return { bg: '#FFF1EB', c: '#C2410C', text: 'Cancelled by Professional' };
return { bg: '#F3F4F6', c: '#6B7280', text: titleCase(status) };
};
const leadTabs = () => (activeLeadDetailId() ? [...LEAD_MARKETPLACE_TABS, 'View Details'] : LEAD_MARKETPLACE_TABS);
const selectedLead = () => leadCards().find((item) => item.id === activeLeadDetailId()) || null;
if (resolvedTabKey() === 'requested contacts') {
return (
<div style="display:flex;flex-direction:column;gap:10px">
<div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:10px">
<div style="border:1px solid #E5E7EB;background:white;border-radius:14px;padding:12px">
<p style="margin:0;font-size:11px;letter-spacing:0.06em;text-transform:uppercase;color:#9CA3AF">Total Spent</p>
<p style="margin:8px 0 0;font-size:30px;line-height:1;font-weight:800;color:#111827">{250 - leadCredits()}</p>
<p style="margin:6px 0 0;font-size:12px;color:#6B7280">Tracecoins used this month</p>
</div>
<div style="border:1px solid #D7DBFF;background:#03004E;border-radius:14px;padding:12px;color:white">
<p style="margin:0;font-size:11px;letter-spacing:0.06em;text-transform:uppercase;color:#D7DBFF">Active Requests</p>
<p style="margin:8px 0 0;font-size:30px;line-height:1;font-weight:800">{leadCards().filter((card) => card.status === 'requested').length}</p>
<div style="height:4px;border-radius:999px;background:rgba(255,255,255,0.2);overflow:hidden;margin-top:8px">
<div style={`height:100%;width:${Math.min(100, leadCards().filter((card) => card.status === 'requested').length * 10)}%;background:#FF5E13`} />
</div>
</div>
<div style="border:1px solid #E5E7EB;background:white;border-radius:14px;padding:12px">
<p style="margin:0;font-size:11px;letter-spacing:0.06em;text-transform:uppercase;color:#9CA3AF">Locked Credits</p>
<p style="margin:8px 0 0;font-size:30px;line-height:1;font-weight:800;color:#111827">{lockedLeadCredits()}</p>
<p style="margin:6px 0 0;font-size:12px;color:#6B7280">Held until service seeker decision (auto-refund in 1 day)</p>
</div>
</div>
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;overflow:hidden;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<div style="padding:10px 12px;border-bottom:1px solid #E5E7EB;display:flex;justify-content:space-between;align-items:center">
<p style="margin:0;font-size:18px;font-weight:800;color:#111827">Requested Contacts</p>
<div style="display:flex;gap:8px">
<div style="position:relative">
<button type="button" onClick={() => { setRequestedSortOpen((prev) => !prev); setRequestedFilterOpen(false); }} style="display:inline-flex;height:32px;align-items:center;gap:6px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 10px;font-size:12px;color:#374151;font-weight:600">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#FF5E13" stroke-width="2"><path d="M7 4v13"/><path d="m3 13 4 4 4-4"/><path d="M17 20V7"/><path d="m21 11-4-4-4 4"/></svg>
Sort
</button>
<Show when={requestedSortOpen()}>
<div style="position:absolute;right:0;top:36px;z-index:20;min-width:170px;border:1px solid #E5E7EB;border-radius:10px;background:white;padding:6px;box-shadow:0 8px 24px rgba(0,0,0,0.12)">
{['Newest First', 'Oldest First'].map((item) => (
<button type="button" onClick={() => { setRequestedSortFilter(item); setRequestedSortOpen(false); }} style={`display:block;width:100%;text-align:left;border:none;background:${requestedSortFilter() === item ? '#FFF1EB' : 'transparent'};color:${requestedSortFilter() === item ? '#FF5E13' : '#374151'};padding:8px 10px;border-radius:8px;font-size:12px;font-weight:600;cursor:pointer`}>
{item}
</button>
))}
</div>
</Show>
</div>
<div style="position:relative">
<button type="button" onClick={() => { setRequestedFilterOpen((prev) => !prev); setRequestedSortOpen(false); }} style="display:inline-flex;height:32px;align-items:center;gap:6px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 10px;font-size:12px;color:#374151;font-weight:600">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#FF5E13" stroke-width="2"><path d="M3 5h18M6 12h12M10 19h4"/></svg>
Filter
</button>
<Show when={requestedFilterOpen()}>
<div style="position:absolute;right:0;top:36px;z-index:20;min-width:220px;border:1px solid #E5E7EB;border-radius:10px;background:white;padding:6px;box-shadow:0 8px 24px rgba(0,0,0,0.12)">
{['All Status', 'Request Sent', 'Contact Unlocked', 'Rejected', 'Expired Refunded', 'Cancelled By Professional'].map((item) => (
<button type="button" onClick={() => { setRequestedStatusFilter(item); setRequestedFilterOpen(false); }} style={`display:block;width:100%;text-align:left;border:none;background:${requestedStatusFilter() === item ? '#FFF1EB' : 'transparent'};color:${requestedStatusFilter() === item ? '#FF5E13' : '#374151'};padding:8px 10px;border-radius:8px;font-size:12px;font-weight:600;cursor:pointer`}>
{item}
</button>
))}
</div>
</Show>
</div>
<button type="button" style="height:32px;border-radius:8px;border:none;background:#03004E;padding:0 10px;font-size:12px;font-weight:700;color:white">Export</button>
</div>
</div>
<div style="padding:10px 12px;border-bottom:1px solid #E5E7EB;display:flex;align-items:center;gap:8px;flex-wrap:wrap">
<div style="height:32px;min-width:220px;flex:1;border:1px solid #E5E7EB;border-radius:8px;background:#F9FAFB;padding:0 10px;display:flex;align-items:center;gap:8px;font-size:12px;color:#9CA3AF">
<Search size={14} />
<input value={requestedSearch()} onInput={(e) => setRequestedSearch(e.currentTarget.value)} placeholder="Search by lead ID / title / area..." style="border:none;background:transparent;outline:none;width:100%;font-size:12px;color:#111827" />
</div>
<span style="height:24px;padding:0 10px;border-radius:999px;border:1px solid #E5E7EB;background:#F9FAFB;display:inline-flex;align-items:center;font-size:11px;font-weight:700;color:#6B7280">Sort: {requestedSortFilter()}</span>
<span style="height:24px;padding:0 10px;border-radius:999px;border:1px solid #E5E7EB;background:#F9FAFB;display:inline-flex;align-items:center;font-size:11px;font-weight:700;color:#6B7280">Status: {requestedStatusFilter()}</span>
</div>
<div style="max-height:360px;overflow:auto">
<table style="width:100%;border-collapse:collapse">
<thead style="background:#03004E;color:white">
<tr>
{['Lead ID', 'Lead Title', 'Request Date', 'Request Status', 'Cost', 'Decision Date', 'Action'].map((h) => (
<th style="padding:10px;text-align:left;font-size:10px;letter-spacing:0.06em;text-transform:uppercase">{h}</th>
))}
</tr>
</thead>
<tbody>
<For each={pagedRequestedRows()}>
{(row) => {
const badge = requestStatusPill(row.status);
return (
<tr style="border-top:1px solid #F3F4F6">
<td style="padding:10px;font-size:12px;color:#4B5563;font-weight:700">#{row.id}</td>
<td style="padding:10px">
<p style="margin:0;font-size:14px;font-weight:700;color:#111827">{row.title}</p>
<p style="margin:2px 0 0;font-size:12px;color:#9CA3AF">{row.city}</p>
</td>
<td style="padding:10px;font-size:12px;color:#374151">{row.requestDate}</td>
<td style="padding:10px"><span style={`height:22px;padding:0 10px;border-radius:999px;display:inline-flex;align-items:center;font-size:11px;font-weight:700;background:${badge.bg};color:${badge.c}`}>{badge.text}</span></td>
<td style="padding:10px;font-size:14px;font-weight:700;color:#111827">{leadCostPerContact}</td>
<td style="padding:10px;font-size:12px;color:#6B7280">{row.decisionDate}</td>
<td style="padding:10px">
<div style="display:flex;gap:6px;flex-wrap:wrap">
<Show when={row.status === 'request_sent'}>
<button type="button" onClick={() => approveLeadContact(row.id)} style="height:28px;border-radius:8px;border:none;background:#03004E;padding:0 10px;font-size:11px;font-weight:700;color:white">Approve (Demo)</button>
<button type="button" onClick={() => cancelLeadRequest(row.id)} style="height:28px;border-radius:8px;border:1px solid #FECACA;background:#FEF2F2;padding:0 10px;font-size:11px;font-weight:700;color:#B91C1C">Cancel Request</button>
<button type="button" onClick={() => refundPendingLead(row.id)} style="height:28px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 10px;font-size:11px;font-weight:700;color:#374151">Refund After 1 Day</button>
</Show>
<Show when={row.status === 'contact_unlocked'}>
<button type="button" style="height:28px;border-radius:8px;border:none;background:#FF5E13;padding:0 10px;font-size:11px;font-weight:700;color:white">View Data</button>
</Show>
</div>
</td>
</tr>
);
}}
</For>
</tbody>
</table>
</div>
<div style="padding:10px 12px;border-top:1px solid #E5E7EB;display:flex;justify-content:space-between;align-items:center">
<p style="margin:0;font-size:12px;color:#6B7280">
Showing {pagedRequestedRows().length ? (requestedPage() - 1) * requestedPerPage + 1 : 0} to {(requestedPage() - 1) * requestedPerPage + pagedRequestedRows().length} of {filteredRequestedRows().length} requests
</p>
<div style="display:flex;gap:6px">
<For each={Array.from({ length: totalRequestedPages() }, (_, i) => i + 1)}>
{(pageNo) => (
<button
type="button"
onClick={() => setRequestedPage(pageNo)}
style={`width:30px;height:30px;border-radius:8px;border:1px solid #E5E7EB;background:${requestedPage() === pageNo ? '#FF5E13' : 'white'};color:${requestedPage() === pageNo ? 'white' : '#6B7280'};font-size:12px;font-weight:700`}
>
{pageNo}
</button>
)}
</For>
</div>
</div>
</div>
</div>
);
}
if (leadMarketplaceTab() === 'View Details' && selectedLead()) {
const lead = selectedLead()!;
const spec = leadDetailsSpec(lead);
return (
<div style="display:flex;flex-direction:column;gap:10px">
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<div style="border:1px solid #E5E7EB;border-radius:12px;background:linear-gradient(135deg,#FFF8F4 0%, #FFFFFF 70%);padding:14px">
<div style="display:flex;align-items:flex-start;justify-content:space-between;gap:10px;flex-wrap:wrap">
<div>
<p style="margin:0;font-size:11px;letter-spacing:0.06em;text-transform:uppercase;color:#6B7280">View Details</p>
<p style="margin:4px 0 0;font-size:26px;font-weight:800;color:#111827;line-height:1.2">{lead.title}</p>
<p style="margin:6px 0 0;font-size:12px;color:#6B7280">{lead.category} {lead.location} {lead.area}</p>
</div>
<span style="height:24px;padding:0 10px;border-radius:999px;background:#FFF1EB;color:#C2410C;display:inline-flex;align-items:center;font-size:11px;font-weight:700">{lead.match}</span>
</div>
<div style="margin-top:10px;display:flex;align-items:center;gap:8px;flex-wrap:wrap">
<span style="height:24px;padding:0 8px;border-radius:999px;border:1px solid #E5E7EB;background:white;font-size:11px;color:#374151;display:inline-flex;align-items:center;gap:4px"><Calendar size={11} style="color:#6B7280" /><strong style="font-weight:700;color:#6B7280">Time Frame:</strong>{spec.timeframe}</span>
<span style="height:24px;padding:0 8px;border-radius:999px;border:1px solid #E5E7EB;background:white;font-size:11px;color:#374151;display:inline-flex;align-items:center;gap:4px"><Calendar size={11} style="color:#6B7280" /><strong style="font-weight:700;color:#6B7280">Date:</strong>{lead.dateRequired}</span>
<span style="height:24px;padding:0 8px;border-radius:999px;border:1px solid #E5E7EB;background:white;font-size:11px;color:#374151;display:inline-flex;align-items:center;gap:4px"><Coins size={11} style="color:#6B7280" /><strong style="font-weight:700;color:#6B7280">Budget:</strong>{lead.budget}</span>
<span style="height:24px;padding:0 8px;border-radius:999px;border:1px solid #E5E7EB;background:white;font-size:11px;color:#374151;display:inline-flex;align-items:center;gap:4px"><MapPin size={11} style="color:#6B7280" /><strong style="font-weight:700;color:#6B7280">Area:</strong>{String(lead.area || 'Chennai')}</span>
</div>
</div>
<div style="margin-top:10px;display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:8px">
<div style="border:1px solid #E5E7EB;border-radius:10px;background:white;padding:10px;display:flex;align-items:flex-start;gap:8px">
<span style="width:24px;height:24px;border-radius:999px;background:#FFF1EB;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0"><Calendar size={13} style="color:#FF5E13" /></span>
<div><p style="margin:0;font-size:11px;color:#6B7280;font-weight:700">Schedule</p><p style="margin:3px 0 0;font-size:13px;font-weight:800;color:#111827;line-height:1.35">{spec.timeframe}</p></div>
</div>
<div style="border:1px solid #E5E7EB;border-radius:10px;background:white;padding:10px;display:flex;align-items:flex-start;gap:8px">
<span style="width:24px;height:24px;border-radius:999px;background:#FFF1EB;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0"><Calendar size={13} style="color:#FF5E13" /></span>
<div><p style="margin:0;font-size:11px;color:#6B7280;font-weight:700">Date Required</p><p style="margin:3px 0 0;font-size:13px;font-weight:800;color:#111827">{lead.dateRequired}</p></div>
</div>
<div style="border:1px solid #E5E7EB;border-radius:10px;background:white;padding:10px;display:flex;align-items:flex-start;gap:8px">
<span style="width:24px;height:24px;border-radius:999px;background:#FFF1EB;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0"><MapPin size={13} style="color:#FF5E13" /></span>
<div><p style="margin:0;font-size:11px;color:#6B7280;font-weight:700">Area</p><p style="margin:3px 0 0;font-size:13px;font-weight:800;color:#111827">{String(lead.area || 'Chennai')}</p></div>
</div>
<div style="border:1px solid #E5E7EB;border-radius:10px;background:white;padding:10px;display:flex;align-items:flex-start;gap:8px">
<span style="width:24px;height:24px;border-radius:999px;background:#FFF1EB;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0"><TrendingUp size={13} style="color:#FF5E13" /></span>
<div style="min-width:0;flex:1">
<p style="margin:0;font-size:11px;color:#6B7280;font-weight:700">Win Probability</p>
<p style={`margin:3px 0 0;font-size:13px;font-weight:800;color:${leadProbabilityColor(leadProbability(lead))}`}>{leadProbability(lead)}%</p>
<div style="margin-top:5px;height:5px;border-radius:999px;background:#E5E7EB;overflow:hidden">
<div style={`height:100%;width:${leadProbability(lead)}%;background:${leadProbabilityColor(leadProbability(lead))}`} />
</div>
</div>
</div>
</div>
<div style="margin-top:10px;display:grid;grid-template-columns:2fr 1fr;gap:10px">
<div style="display:grid;gap:10px">
<div style="border:1px solid #E5E7EB;border-radius:12px;background:white;padding:12px">
<p style="margin:0;font-size:11px;letter-spacing:0.05em;text-transform:uppercase;color:#6B7280;font-weight:700">Work Scope</p>
<p style="margin:8px 0 0;font-size:14px;color:#1F2937;line-height:1.65">{spec.scope}</p>
</div>
<div style="border:1px solid #E5E7EB;border-radius:12px;background:#F9FAFB;padding:12px">
<p style="margin:0 0 8px;font-size:11px;letter-spacing:0.05em;text-transform:uppercase;color:#6B7280;font-weight:700">Lead Specific Highlights</p>
<div style="display:grid;gap:6px">
<For each={spec.highlights}>{(item) => <div style="display:flex;align-items:flex-start;gap:6px"><span style="margin-top:3px;width:6px;height:6px;border-radius:999px;background:#FF5E13;flex-shrink:0" /><span style="font-size:14px;color:#1F2937;line-height:1.55">{item}</span></div>}</For>
</div>
</div>
</div>
<div style="border:1px solid #E5E7EB;border-radius:12px;background:white;padding:12px;display:grid;gap:8px;align-content:start">
<div style="display:flex;justify-content:space-between;gap:8px;padding-bottom:6px;border-bottom:1px solid #F3F4F6"><span style="font-size:12px;color:#6B7280">Lead ID</span><span style="font-size:12px;color:#111827;font-weight:700">{lead.id}</span></div>
<div style="display:flex;justify-content:space-between;gap:8px;padding-bottom:6px;border-bottom:1px solid #F3F4F6">
<span style="font-size:12px;color:#6B7280">Unlock Cost</span>
<span style="height:22px;padding:0 8px;border-radius:999px;border:1px solid #FFD8C2;background:#FFF1EB;display:inline-flex;align-items:center;gap:6px"><span style="width:14px;height:14px;border-radius:999px;background:#FF5E13;color:white;display:inline-flex;align-items:center;justify-content:center;font-size:9px;font-weight:800;line-height:1">NG</span><span style="font-size:12px;color:#C2410C;font-weight:800">{lead.cost} Tracecoin</span></span>
</div>
<div style="display:flex;justify-content:space-between;gap:8px;padding-bottom:6px;border-bottom:1px solid #F3F4F6"><span style="font-size:12px;color:#6B7280">Contacted</span><span style="font-size:12px;color:#111827;font-weight:700">{lead.contactCount}/{lead.maxContacts}</span></div>
<div style="display:flex;gap:8px;margin-top:6px;flex-wrap:wrap">
<button type="button" onClick={() => { setLeadMarketplaceTab('All Leads'); setActiveLeadDetailId(''); }} style="height:32px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 12px;font-size:12px;font-weight:700;color:#374151">Back to Leads</button>
<button type="button" onClick={() => openLeadContactConfirm(lead.id)} disabled={usableLeadCredits() < leadCostPerContact || lead.contactCount >= lead.maxContacts} style={`height:32px;border-radius:8px;border:none;padding:0 12px;font-size:12px;font-weight:700;color:white;background:${usableLeadCredits() < leadCostPerContact || lead.contactCount >= lead.maxContacts ? '#9CA3AF' : '#03004E'}`}>Request Contact</button>
</div>
</div>
</div>
</div>
</div>
);
}
return (
<div style="display:flex;flex-direction:column;gap:10px">
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;overflow:hidden;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<div style="padding:10px 12px;border-bottom:1px solid #E5E7EB;display:flex;align-items:center;gap:8px;flex-wrap:wrap">
<For each={leadTabs()}>
{(item) => (
<button
type="button"
onClick={() => { setLeadMarketplaceTab(item); if (item !== 'View Details') setActiveLeadDetailId(''); }}
style={`height:30px;padding:0 8px;border:none;border-bottom:${leadMarketplaceTab() === item ? '2px solid #FF5E13' : '2px solid transparent'};background:none;font-size:12px;font-weight:700;color:${leadMarketplaceTab() === item ? '#FF5E13' : '#6B7280'}`}
>
{item}
</button>
)}
</For>
</div>
<div style="padding:10px 12px;border-bottom:1px solid #E5E7EB;display:flex;align-items:center;gap:8px;flex-wrap:wrap">
<div style="height:34px;min-width:220px;flex:1;border:1px solid #E5E7EB;border-radius:8px;background:#F9FAFB;padding:0 10px;display:flex;align-items:center;gap:8px;font-size:12px;color:#9CA3AF">
<Search size={14} />
<input value={leadSearch()} onInput={(e) => setLeadSearch(e.currentTarget.value)} placeholder="Search by role, area, keyword..." style="border:none;background:transparent;outline:none;width:100%;font-size:12px;color:#111827" />
</div>
<div style="position:relative">
<button
type="button"
onClick={() => { setLeadFiltersOpen((prev) => !prev); setLeadSortOpen(false); }}
style="display:inline-flex;height:34px;align-items:center;gap:6px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 12px;font-size:12px;color:#374151;font-weight:600"
>
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#FF5E13" stroke-width="2"><path d="M3 5h18M6 12h12M10 19h4"/></svg>
Filters
</button>
<Show when={leadFiltersOpen()}>
<div style="position:absolute;right:0;top:38px;z-index:20;min-width:280px;border:1px solid #E5E7EB;border-radius:12px;background:white;box-shadow:0 8px 24px rgba(0,0,0,0.12);padding:10px;display:grid;gap:8px">
<div>
<p style="margin:0 0 4px;font-size:10px;letter-spacing:0.05em;text-transform:uppercase;color:#9CA3AF;font-weight:700">Area</p>
<select value={leadAreaFilter()} onChange={(e) => setLeadAreaFilter(e.currentTarget.value)} style="height:34px;width:100%;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 10px;font-size:12px;color:#374151">
<option>All Areas</option>
<option>ECR</option>
<option>Nungambakkam</option>
<option>Sholinganallur</option>
<option>Mylapore</option>
<option>T Nagar</option>
<option>Guindy</option>
</select>
</div>
<div>
<p style="margin:0 0 4px;font-size:10px;letter-spacing:0.05em;text-transform:uppercase;color:#9CA3AF;font-weight:700">Budget</p>
<select value={leadBudgetFilter()} onChange={(e) => setLeadBudgetFilter(e.currentTarget.value)} style="height:34px;width:100%;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 10px;font-size:12px;color:#374151">
<option>All Budgets</option>
<option>Under 1L</option>
<option>1L - 2L</option>
<option>Above 2L</option>
</select>
</div>
<div>
<p style="margin:0 0 4px;font-size:10px;letter-spacing:0.05em;text-transform:uppercase;color:#9CA3AF;font-weight:700">Date</p>
<select value={leadDateFilter()} onChange={(e) => setLeadDateFilter(e.currentTarget.value)} style="height:34px;width:100%;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 10px;font-size:12px;color:#374151">
<option>Any Date</option>
<option>Within 7 Days</option>
<option>This Month</option>
</select>
</div>
<div style="display:flex;justify-content:flex-end;gap:8px;padding-top:4px">
<button type="button" onClick={() => { setLeadAreaFilter('All Areas'); setLeadBudgetFilter('All Budgets'); setLeadDateFilter('Any Date'); }} style="height:30px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 10px;font-size:11px;color:#374151;font-weight:700">Reset</button>
<button type="button" onClick={() => setLeadFiltersOpen(false)} style="height:30px;border-radius:8px;border:none;background:#03004E;color:white;padding:0 10px;font-size:11px;font-weight:700">Apply</button>
</div>
</div>
</Show>
</div>
<div style="position:relative">
<button
type="button"
onClick={() => { setLeadSortOpen((prev) => !prev); setLeadFiltersOpen(false); }}
style="display:inline-flex;height:34px;align-items:center;gap:6px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 12px;font-size:12px;color:#374151;font-weight:600"
>
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#FF5E13" stroke-width="2"><path d="M7 4v13"/><path d="m3 13 4 4 4-4"/><path d="M17 20V7"/><path d="m21 11-4-4-4 4"/></svg>
Sort
</button>
<Show when={leadSortOpen()}>
<div style="position:absolute;right:0;top:38px;z-index:20;min-width:190px;border:1px solid #E5E7EB;border-radius:10px;background:white;padding:6px;box-shadow:0 8px 24px rgba(0,0,0,0.12)">
{['Newest First', 'Budget High-Low', 'Budget Low-High'].map((item) => (
<button type="button" onClick={() => { setLeadSortFilter(item); setLeadSortOpen(false); }} style={`display:block;width:100%;text-align:left;border:none;background:${leadSortFilter() === item ? '#FFF1EB' : 'transparent'};color:${leadSortFilter() === item ? '#FF5E13' : '#374151'};padding:8px 10px;border-radius:8px;font-size:12px;font-weight:600;cursor:pointer`}>
{item}
</button>
))}
</div>
</Show>
</div>
<span style="height:24px;padding:0 10px;border-radius:999px;border:1px solid #E5E7EB;background:#F9FAFB;display:inline-flex;align-items:center;font-size:11px;font-weight:700;color:#6B7280">Sort: {leadSortFilter()}</span>
</div>
<div style="padding:12px;display:grid;gap:10px;background:#FAFBFF;max-height:520px;overflow:auto">
<For each={pagedLeadCards()}>
{(lead) => (
<div style={`border:1px solid ${lead.status === 'requested' ? '#FFE2D3' : lead.status === 'unlocked' ? '#CFF5E9' : lead.status === 'closed' ? '#F3F4F6' : '#E5E7EB'};border-radius:14px;background:white;padding:14px 16px`}>
<div style="display:grid;grid-template-columns:minmax(0,1fr) auto;gap:12px;align-items:start">
<div style="min-width:0">
<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap">
<span style={`height:20px;padding:0 8px;border-radius:999px;font-size:10px;font-weight:700;display:inline-flex;align-items:center;background:${lead.status === 'unlocked' ? '#ECFDF3' : lead.status === 'requested' ? '#FFF1EB' : lead.status === 'closed' ? '#F3F4F6' : '#EEF2FF'};color:${lead.status === 'unlocked' ? '#047857' : lead.status === 'requested' ? '#C2410C' : lead.status === 'closed' ? '#6B7280' : '#3730A3'}`}>
{lead.status === 'unlocked' ? 'Contact Unlocked' : lead.status === 'requested' ? 'Request Sent' : lead.status === 'closed' ? 'Lead Closed' : 'Open Lead'}
</span>
<span style="font-size:12px;color:#6B7280">{lead.category} {lead.location}</span>
</div>
<p style="margin:6px 0 0;font-size:20px;line-height:1.3;font-weight:800;color:#111827">{lead.title}</p>
<div style="margin-top:10px;display:flex;align-items:center;gap:12px;white-space:nowrap;overflow-x:auto;padding-bottom:2px">
<span style="font-size:12px;color:#111827;font-weight:700">Area: {lead.area}</span>
<span style="font-size:12px;color:#D1D5DB">|</span>
<span style="font-size:12px;color:#111827;font-weight:700">Date: {lead.dateRequired}</span>
<span style="font-size:12px;color:#D1D5DB">|</span>
<span style="height:24px;display:inline-flex;align-items:center;gap:6px;padding:0 8px;border:1px solid #FFE2D3;border-radius:999px;background:#FFF7F2">
<span style="width:14px;height:14px;border-radius:999px;background:#FF5E13;color:white;display:inline-flex;align-items:center;justify-content:center;font-size:10px;font-weight:800;line-height:1">T</span>
<span style="font-size:12px;color:#C2410C;font-weight:800">{lead.cost}</span>
</span>
<span style="font-size:12px;color:#D1D5DB">|</span>
<span style="display:inline-flex;align-items:center;gap:6px">
<svg width="62" height="34" viewBox="0 0 120 70" aria-label="Lead probability gauge">
<path d="M 10 60 A 50 50 0 0 1 110 60" fill="none" stroke="#E5E7EB" stroke-width="8" stroke-linecap="round" />
<path d="M 10 60 A 50 50 0 0 1 110 60" fill="none" stroke={leadProbabilityColor(leadProbability(lead))} stroke-width="8" stroke-linecap="round" stroke-dasharray={leadGaugeDash(leadProbability(lead))} />
<line x1="60" y1="60" x2={leadGaugeNeedlePoint(leadProbability(lead)).x} y2={leadGaugeNeedlePoint(leadProbability(lead)).y} stroke="#111827" stroke-width="3" stroke-linecap="round" />
<circle cx="60" cy="60" r="4.5" fill="#111827" />
</svg>
<span style={`font-size:12px;font-weight:800;color:${leadProbabilityColor(leadProbability(lead))}`}>{leadProbability(lead)}%</span>
</span>
<span style="font-size:12px;color:#D1D5DB">|</span>
<span style="height:24px;display:inline-flex;align-items:center;gap:6px;padding:0 8px;border:1px solid #E5E7EB;border-radius:999px;background:#F9FAFB">
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="#6B7280" stroke-width="2"><path d="M16 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="8.5" cy="7" r="4"/><path d="M20 8v6"/><path d="M23 11h-6"/></svg>
<span style="font-size:11px;color:#111827;font-weight:700">{lead.contactCount}/{lead.maxContacts}</span>
<span style="font-size:10px;color:#6B7280">contacted</span>
</span>
<span style="font-size:12px;color:#6B7280;font-weight:700">{Math.max(0, lead.maxContacts - lead.contactCount)} slots left</span>
</div>
</div>
<div style="display:flex;flex-direction:column;align-items:flex-end;gap:8px">
<p style="margin:0;font-size:11px;letter-spacing:0.06em;text-transform:uppercase;color:#FF5E13;font-weight:700">{lead.match}</p>
<p style="margin:0;font-size:24px;line-height:1;font-weight:800;color:#111827">{lead.budget}</p>
<p style="margin:0;font-size:11px;color:#9CA3AF">Est. Budget</p>
<div style="display:flex;gap:6px;flex-wrap:wrap;justify-content:flex-end;padding-top:2px">
<button type="button" onClick={() => openLeadDetailsInNewTab(lead.id)} style="height:30px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 10px;font-size:12px;font-weight:700;color:#374151">View Details</button>
<Show when={lead.status === 'open'}>
<button
type="button"
onClick={() => openLeadContactConfirm(lead.id)}
disabled={usableLeadCredits() < leadCostPerContact || lead.contactCount >= lead.maxContacts}
style={`height:30px;border-radius:8px;border:none;padding:0 10px;font-size:12px;font-weight:700;color:white;background:${usableLeadCredits() < leadCostPerContact || lead.contactCount >= lead.maxContacts ? '#9CA3AF' : '#03004E'};cursor:${usableLeadCredits() < leadCostPerContact || lead.contactCount >= lead.maxContacts ? 'not-allowed' : 'pointer'}`}
>
Request Contact
</button>
</Show>
<Show when={lead.status === 'requested'}>
<button type="button" onClick={() => cancelLeadRequest(lead.id)} style="height:30px;border-radius:8px;border:1px solid #FECACA;background:#FEF2F2;padding:0 10px;font-size:12px;font-weight:700;color:#B91C1C">Cancel Request</button>
</Show>
</div>
</div>
</div>
</div>
)}
</For>
</div>
<div style="padding:10px 12px;border-top:1px solid #E5E7EB;display:flex;justify-content:space-between;align-items:center">
<p style="margin:0;font-size:12px;color:#6B7280">
Showing {pagedLeadCards().length ? (leadPage() - 1) * leadsPerPage + 1 : 0} to {(leadPage() - 1) * leadsPerPage + pagedLeadCards().length} of {filteredLeadCards().length} leads
</p>
<div style="display:flex;gap:6px">
<For each={Array.from({ length: totalLeadPages() }, (_, i) => i + 1)}>
{(pageNo) => (
<button
type="button"
onClick={() => setLeadPage(pageNo)}
style={`width:30px;height:30px;border-radius:8px;border:1px solid #E5E7EB;background:${leadPage() === pageNo ? '#FF5E13' : 'white'};color:${leadPage() === pageNo ? 'white' : '#6B7280'};font-size:12px;font-weight:700`}
>
{pageNo}
</button>
)}
</For>
</div>
</div>
</div>
<Show when={leadContactConfirmId()}>
<div style="position:fixed;inset:0;background:rgba(15,23,42,0.45);display:flex;align-items:center;justify-content:center;z-index:60;padding:16px">
<div style="width:min(460px,100%);border:1px solid #E5E7EB;background:white;border-radius:14px;box-shadow:0 10px 30px rgba(0,0,0,0.18);padding:16px">
<div style="display:flex;align-items:center;gap:8px">
<span style="width:22px;height:22px;border-radius:999px;background:#FFF1EB;color:#FF5E13;display:inline-flex;align-items:center;justify-content:center;font-size:13px;font-weight:800">T</span>
<p style="margin:0;font-size:16px;font-weight:800;color:#111827">Confirm Contact Unlock</p>
</div>
<p style="margin:10px 0 0;font-size:13px;color:#374151;line-height:1.5">You are about to spend <strong>25 Tracecoins</strong> to request and view this service seeker contact when approved. Do you want to continue?</p>
<div style="display:flex;justify-content:flex-end;gap:8px;margin-top:14px">
<button type="button" onClick={() => setLeadContactConfirmId('')} style="height:34px;border-radius:8px;border:1px solid #D1D5DB;background:white;color:#374151;padding:0 14px;font-size:12px;font-weight:700">Cancel</button>
<button type="button" onClick={confirmLeadContactRequest} style="height:34px;border-radius:8px;border:none;background:#03004E;color:white;padding:0 14px;font-size:12px;font-weight:700">Yes, Request Contact</button>
</div>
</div>
</div>
</Show>
</div>
);
}
if (customerKey() === 'jobs') {
if (isJobSeekerRole()) {
const selectedJob = () => jobBoardJobs().find((job) => job.id === jobSeekerSelectedId()) || jobBoardJobs()[0];
const selectedAppliedTab = normalizeTabKey(tab) === 'applied';
const selectedOpenJobCards = () => {
const tabKey = normalizeTabKey(tab);
const rows = jobBoardJobs();
if (tabKey === 'recommended') return rows.slice(0, 3);
if (tabKey === 'saved') return rows.slice(1);
if (tabKey === 'expiring soon') return rows.filter((_, idx) => idx % 2 === 0);
return rows;
};
const stepWidth = () => `${Math.round((jobSeekerApplyStep() / 4) * 100)}%`;
if (selectedAppliedTab) {
return (
<div style="display:flex;flex-direction:column;gap:10px">
<div style="display:flex;justify-content:space-between;align-items:center">
<div style="display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:8px;flex:1">
{[
{ label: 'Total Applications', value: '24', tone: 'dark' },
{ label: 'Under Review', value: '08', tone: 'blue' },
{ label: 'Shortlisted', value: '03', tone: 'orange' },
{ label: 'Interviews', value: '02', tone: 'green' },
].map((card) => (
<div style={`border:1px solid #E5E7EB;border-radius:12px;padding:10px;background:${card.tone === 'dark' ? '#03004E' : 'white'};color:${card.tone === 'dark' ? 'white' : '#111827'};box-shadow:0 1px 3px rgba(0,0,0,0.05)`}>
<p style={`margin:0;font-size:11px;letter-spacing:0.05em;text-transform:uppercase;color:${card.tone === 'dark' ? '#D7DBFF' : '#9CA3AF'}`}>{card.label}</p>
<p style={`margin:4px 0 0;font-size:32px;line-height:1;font-weight:800;color:${card.tone === 'orange' ? '#C2410C' : card.tone === 'green' ? '#16A34A' : card.tone === 'blue' ? '#2563EB' : card.tone === 'dark' ? 'white' : '#111827'}`}>{card.value}</p>
</div>
))}
</div>
<div style="display:flex;gap:8px;margin-left:10px">
<button type="button" style="height:34px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 10px;font-size:12px;font-weight:700;color:#374151">Filters</button>
<button type="button" style="height:34px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 10px;font-size:12px;font-weight:700;color:#374151">Most Recent</button>
</div>
</div>
<div style="border:1px solid #E5E7EB;border-radius:14px;background:white;overflow:hidden;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<div style="padding:10px 12px;border-bottom:1px solid #E5E7EB;display:flex;justify-content:space-between;align-items:center">
<p style="margin:0;font-size:14px;font-weight:800;color:#111827;letter-spacing:0.05em;text-transform:uppercase">Latest Updates</p>
<span style="font-size:11px;color:#9CA3AF">Track your application status and recruiter responses</span>
</div>
<div style="display:grid;gap:8px;padding:10px">
<For each={JOB_SEEKER_APPLIED_ROWS}>
{(row) => {
const tone = row.status === 'Shortlisted'
? { bg: '#FFF1EB', c: '#C2410C' }
: row.status === 'Under Review'
? { bg: '#E8F0FF', c: '#2563EB' }
: row.status === 'Not Selected'
? { bg: '#FEE2E2', c: '#B91C1C' }
: { bg: '#F3F4F6', c: '#374151' };
return (
<div style={`border:1px solid #E5E7EB;border-left:4px solid ${tone.c};border-radius:10px;background:#FCFCFD;padding:10px;display:grid;grid-template-columns:1fr auto auto;gap:10px;align-items:center`}>
<div>
<p style="margin:0;font-size:10px;letter-spacing:0.05em;text-transform:uppercase;color:#6B7280">{row.id} Applied On Oct 12, 2023</p>
<p style="margin:4px 0 0;font-size:28px;line-height:1.2;font-weight:800;color:#111827">{row.title}</p>
<p style="margin:4px 0 0;font-size:13px;color:#4B5563">{row.company} {row.location}</p>
</div>
<div style="text-align:right">
<span style={`height:24px;padding:0 10px;border-radius:999px;background:${tone.bg};color:${tone.c};font-size:11px;font-weight:700;display:inline-flex;align-items:center`}>{row.status}</span>
<p style="margin:6px 0 0;font-size:12px;color:#6B7280">{row.note}</p>
</div>
<button type="button" style="height:32px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 10px;font-size:12px;font-weight:700;color:#374151">View Details</button>
</div>
);
}}
</For>
</div>
</div>
<div style="border:1px solid #FFD8C2;border-radius:14px;background:#FFF8F4;padding:14px;display:flex;justify-content:space-between;align-items:center;gap:10px">
<div>
<p style="margin:0;font-size:30px;line-height:1.2;font-weight:800;color:#111827">Boost your response rate</p>
<p style="margin:6px 0 0;font-size:13px;color:#6B7280">Recruiters are more likely to respond to profiles with updated resume and portfolio links.</p>
</div>
<button type="button" onClick={() => setJobSeekerScreen('apply')} style="height:34px;border:none;border-radius:9px;background:#03004E;color:white;padding:0 12px;font-size:12px;font-weight:700;white-space:nowrap">Optimize Profile</button>
</div>
</div>
);
}
if (jobSeekerScreen() === 'apply') {
return (
<div style="border:1px solid #E5E7EB;border-radius:16px;background:white;box-shadow:0 1px 4px rgba(0,0,0,0.06);overflow:hidden">
<div style="display:grid;grid-template-columns:280px 1fr;min-height:520px">
<aside style="background:#03004E;color:white;padding:14px;display:flex;flex-direction:column;justify-content:space-between">
<div>
<p style="margin:0;font-size:36px;line-height:1.1;font-weight:800">Nxtgauge</p>
<p style="margin:12px 0 0;font-size:10px;letter-spacing:0.08em;text-transform:uppercase;color:#A7B2FF">Applying For</p>
<p style="margin:4px 0 0;font-size:42px;line-height:1.1;font-weight:800">{selectedJob().title}</p>
<p style="margin:8px 0 0;font-size:13px;color:#D7DBFF">Full-time Remote {selectedJob().salary}</p>
<div style="margin-top:14px;border:1px solid rgba(255,255,255,0.18);border-radius:10px;padding:10px;background:rgba(255,255,255,0.04)">
<p style="margin:0;font-size:12px;font-weight:700">{selectedJob().company}</p>
<p style="margin:3px 0 0;font-size:11px;color:#D7DBFF">{selectedJob().location}</p>
</div>
</div>
<div>
<p style="margin:0;font-size:12px;color:#D7DBFF">Step {jobSeekerApplyStep()} of 4</p>
<div style="height:4px;border-radius:999px;background:rgba(255,255,255,0.2);margin-top:6px;overflow:hidden"><div style={`height:100%;background:#FF5E13;width:${stepWidth()}`} /></div>
</div>
</aside>
<div style="padding:14px;display:flex;flex-direction:column;gap:12px">
<div style="display:flex;align-items:center;gap:8px;border-bottom:1px solid #E5E7EB;padding-bottom:10px">
{[
{ key: 1, label: 'Profile' },
{ key: 2, label: 'Materials' },
{ key: 3, label: 'Details' },
{ key: 4, label: 'Review' },
].map((step, idx, arr) => (
<>
<button
type="button"
onClick={() => setJobSeekerApplyStep(step.key)}
style={`height:28px;padding:0 10px;border-radius:999px;border:1px solid ${jobSeekerApplyStep() === step.key ? '#FF5E13' : '#E5E7EB'};background:${jobSeekerApplyStep() === step.key ? '#FFF1EB' : '#F9FAFB'};font-size:11px;font-weight:700;color:${jobSeekerApplyStep() === step.key ? '#C2410C' : '#6B7280'}`}
>
{step.key}. {step.label}
</button>
<Show when={idx < arr.length - 1}><span style="color:#D1D5DB"></span></Show>
</>
))}
</div>
<p style="margin:0;font-size:38px;line-height:1.1;font-weight:800;color:#111827">Resume & Portfolio</p>
<p style="margin:0;font-size:14px;color:#6B7280">Showcase your best work and professional journey to the hiring team.</p>
<div>
<p style="margin:0 0 6px;font-size:11px;letter-spacing:0.06em;text-transform:uppercase;color:#6B7280">Resume (PDF)</p>
<div style="min-height:120px;border:1px dashed #F4B6A0;border-radius:12px;background:#FFFCFB;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px">
<FileText size={24} style="color:#C2410C" />
<p style="margin:0;font-size:14px;color:#111827">Drop your resume here or <span style="color:#C2410C;font-weight:700">browse</span></p>
<p style="margin:0;font-size:12px;color:#6B7280">Maximum file size: 5MB</p>
</div>
</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px">
<div style="grid-column:1 / -1">
<p style="margin:0 0 6px;font-size:11px;letter-spacing:0.06em;text-transform:uppercase;color:#6B7280">Portfolio Link</p>
<div style="height:40px;border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB;padding:0 10px;display:flex;align-items:center;font-size:13px;color:#6B7280">https://yourportfolio.com</div>
</div>
<div style="height:54px;border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB;padding:0 10px;display:flex;align-items:center;justify-content:space-between">
<div><p style="margin:0;font-size:12px;font-weight:700;color:#111827">Cover Letter</p><p style="margin:2px 0 0;font-size:11px;color:#6B7280">Optional doc</p></div>
<button type="button" style="width:20px;height:20px;border-radius:999px;border:none;background:#FFF1EB;color:#C2410C;font-size:14px;font-weight:700;line-height:1">+</button>
</div>
<div style="height:54px;border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB;padding:0 10px;display:flex;align-items:center;justify-content:space-between">
<div><p style="margin:0;font-size:12px;font-weight:700;color:#111827">GitHub Profile</p><p style="margin:2px 0 0;font-size:11px;color:#6B7280">Optional link</p></div>
<button type="button" style="width:20px;height:20px;border-radius:999px;border:none;background:#FFF1EB;color:#C2410C;font-size:14px;font-weight:700;line-height:1">+</button>
</div>
</div>
<div style="display:flex;align-items:center;justify-content:space-between;border-top:1px solid #E5E7EB;padding-top:10px">
<button type="button" onClick={() => setJobSeekerScreen('detail')} style="height:34px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 12px;font-size:12px;font-weight:700;color:#374151">Back</button>
<div style="display:flex;gap:8px">
<button type="button" style="height:34px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 12px;font-size:12px;font-weight:700;color:#374151">Save Draft</button>
<button type="button" onClick={() => setJobSeekerApplyStep((prev) => Math.min(4, prev + 1))} style="height:34px;border-radius:8px;border:none;background:#C2410C;padding:0 14px;font-size:12px;font-weight:700;color:white">Continue</button>
</div>
</div>
</div>
</div>
</div>
);
}
if (jobSeekerScreen() === 'detail') {
return (
<div style="display:grid;grid-template-columns:1.1fr 1fr;gap:10px;align-items:start">
<div style="border:1px solid #E5E7EB;border-radius:14px;background:white;padding:12px;display:flex;flex-direction:column;gap:8px;box-shadow:0 1px 4px rgba(0,0,0,0.06);max-height:78vh;overflow:auto">
<p style="margin:0;font-size:24px;line-height:1.15;font-weight:800;color:#111827">Available Positions</p>
<p style="margin:0;font-size:13px;color:#6B7280">Found 128 high-match opportunities for your profile.</p>
<For each={selectedOpenJobCards()}>
{(job) => (
<button
type="button"
onClick={() => setJobSeekerSelectedId(job.id)}
style={`text-align:left;border:1px solid ${job.id === selectedJob().id ? '#FF5E13' : '#E5E7EB'};border-radius:12px;background:${job.id === selectedJob().id ? '#FFFCFA' : '#FCFCFD'};padding:10px;display:grid;gap:6px`}
>
<div style="display:flex;justify-content:space-between;align-items:center">
<p style="margin:0;font-size:18px;line-height:1.25;font-weight:800;color:#111827">{job.title}</p>
<span style="height:20px;padding:0 8px;border-radius:999px;background:#FFF1EB;color:#C2410C;font-size:10px;font-weight:700;display:inline-flex;align-items:center">Top Match</span>
</div>
<p style="margin:0;font-size:13px;color:#4B5563">{job.company} {job.location}</p>
<p style="margin:0;font-size:13px;color:#6B7280;line-height:1.45">We are looking for a visionary professional to lead core product experiences and collaborate across teams.</p>
<div style="display:flex;justify-content:space-between;align-items:center;gap:8px">
<div style="display:flex;flex-wrap:wrap;gap:6px">
<For each={job.tags.slice(0, 3)}>
{(tag) => <span style="height:22px;padding:0 8px;border-radius:7px;border:1px solid #E5E7EB;background:#F3F4F6;font-size:10px;font-weight:700;color:#4B5563;display:inline-flex;align-items:center">{tag}</span>}
</For>
</div>
<p style="margin:0;font-size:20px;line-height:1.1;font-weight:800;color:#111827">{job.salary}</p>
</div>
</button>
)}
</For>
</div>
<div style="border:1px solid #E5E7EB;border-radius:14px;background:white;box-shadow:0 1px 4px rgba(0,0,0,0.06);overflow:hidden;max-height:78vh;display:flex;flex-direction:column">
<div style="height:140px;background:linear-gradient(180deg,#d8e3eb 0%,#f8fafc 100%);position:relative">
<button type="button" onClick={() => setJobSeekerScreen('list')} style="position:absolute;right:10px;top:10px;width:28px;height:28px;border-radius:999px;border:1px solid rgba(255,255,255,0.7);background:rgba(17,24,39,0.35);color:white;display:flex;align-items:center;justify-content:center">×</button>
</div>
<div style="padding:12px;display:grid;gap:10px;overflow:auto">
<div>
<p style="margin:0;font-size:26px;line-height:1.2;font-weight:800;color:#111827">{selectedJob().title}</p>
<p style="margin:6px 0 0;font-size:13px;font-weight:700;color:#C2410C">{selectedJob().company} {selectedJob().location}</p>
</div>
<div style="display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px">
{[
['Location', selectedJob().location],
['Experience', selectedJob().exp],
['Employment', selectedJob().type],
['Compensation', selectedJob().salary],
['Match', selectedJob().match],
['Posted', selectedJob().posted],
].map(([label, val]) => (
<div style="border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB;padding:10px">
<p style="margin:0;font-size:10px;letter-spacing:0.06em;text-transform:uppercase;color:#9CA3AF">{label}</p>
<p style="margin:5px 0 0;font-size:13px;font-weight:700;color:#111827">{val}</p>
</div>
))}
</div>
<div>
<p style="margin:0;font-size:11px;letter-spacing:0.09em;text-transform:uppercase;color:#6B7280">Skills</p>
<div style="display:flex;flex-wrap:wrap;gap:6px;margin-top:7px">
<For each={selectedJob().tags}>
{(tag) => <span style="height:24px;padding:0 9px;border-radius:8px;border:1px solid #E5E7EB;background:#F3F4F6;font-size:10px;font-weight:700;color:#374151;display:inline-flex;align-items:center">{tag}</span>}
</For>
</div>
</div>
<div>
<p style="margin:0;font-size:11px;letter-spacing:0.09em;text-transform:uppercase;color:#6B7280">The Opportunity</p>
<p style="margin:6px 0 0;font-size:14px;line-height:1.6;color:#374151">As a senior role at Nxtgauge, you will shape product experiences used by thousands of professionals and build systems that scale with ambition.</p>
</div>
<div>
<p style="margin:0;font-size:11px;letter-spacing:0.09em;text-transform:uppercase;color:#6B7280">Core Requirements</p>
<div style="display:grid;gap:6px;margin-top:6px">
{[
'Mastery of product and design system governance.',
'Strong track record of shipping complex B2B products.',
'Deep understanding of accessibility and UX research.',
].map((item) => <p style="margin:0;font-size:13px;color:#374151;line-height:1.45"> {item}</p>)}
</div>
</div>
<div style="border:1px solid #191970;border-radius:12px;background:#03004E;color:white;padding:12px">
<p style="margin:0;font-size:10px;letter-spacing:0.08em;text-transform:uppercase;color:#CDD4FF">Total Compensation</p>
<p style="margin:6px 0 0;font-size:24px;line-height:1.2;font-weight:800">{selectedJob().salary} <span style="font-size:12px;font-weight:600">/ year</span></p>
<div style="display:flex;gap:8px;margin-top:10px">
<button type="button" onClick={() => { setJobSeekerApplyStep(2); setJobSeekerScreen('apply'); }} style="height:36px;flex:1;border:none;border-radius:9px;background:#FF5E13;color:white;padding:0 12px;font-size:12px;font-weight:700">Apply Now</button>
<button type="button" style="width:36px;height:36px;border-radius:9px;border:1px solid rgba(255,255,255,0.3);background:transparent;color:white;display:flex;align-items:center;justify-content:center"><Bookmark size={14} /></button>
</div>
<p style="margin:8px 0 0;font-size:10px;letter-spacing:0.08em;text-transform:uppercase;color:#AAB4FF;text-align:center">Application update: {selectedJob().posted}</p>
</div>
</div>
</div>
</div>
);
}
return (
<div style="display:flex;flex-direction:column;gap:10px">
<div style="display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:8px">
{[
{ label: 'Matching Jobs', value: '124', accent: '#B91C1C', hint: '' },
{ label: 'Saved Jobs', value: '12', accent: '#4338CA', hint: '' },
{ label: 'Applied', value: '48', accent: '#6B7280', hint: '' },
{ label: 'Shortlisted', value: '06', accent: '#0EA5E9', hint: '' },
{ label: 'New Today', value: '18', accent: 'white', hint: 'dark' },
].map((card) => (
<div style={`border:1px solid #E5E7EB;border-radius:12px;padding:10px;background:${card.hint === 'dark' ? '#03004E' : 'white'};box-shadow:0 1px 3px rgba(0,0,0,0.05)`}>
<p style={`margin:0;font-size:10px;letter-spacing:0.06em;text-transform:uppercase;color:${card.hint === 'dark' ? '#D7DBFF' : '#6B7280'}`}>{card.label}</p>
<p style={`margin:5px 0 0;font-size:34px;line-height:1;font-weight:800;color:${card.hint === 'dark' ? 'white' : card.accent}`}>{card.value}</p>
</div>
))}
</div>
<div style="border:1px solid #E5E7EB;border-radius:12px;background:white;padding:10px;display:flex;align-items:center;gap:8px;flex-wrap:wrap;box-shadow:0 1px 3px rgba(0,0,0,0.05)">
<button type="button" style="height:32px;border-radius:8px;border:1px solid #E5E7EB;background:#F9FAFB;padding:0 10px;font-size:12px;font-weight:700;color:#374151">Filters</button>
{['Role: All Roles', 'Industry: Tech', 'Location: Remote', 'Salary: $100k+', 'Experience: Senior'].map((item) => (
<button type="button" style="height:32px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 10px;font-size:12px;color:#374151">{item}</button>
))}
<button type="button" style="height:32px;border-radius:8px;border:none;background:#EEF2FF;padding:0 10px;font-size:12px;font-weight:700;color:#3730A3">Reset</button>
</div>
<div style="display:grid;gap:8px">
<For each={selectedOpenJobCards()}>
{(job) => (
<div style="border:1px solid #E5E7EB;border-radius:12px;background:white;padding:10px;display:grid;grid-template-columns:1fr auto;gap:10px;box-shadow:0 1px 3px rgba(0,0,0,0.05)">
<div>
<p style="margin:0;font-size:20px;line-height:1.25;font-weight:800;color:#111827">{job.title}</p>
<p style="margin:5px 0 0;font-size:13px;color:#4B5563">{job.company} {job.location}</p>
<div style="display:flex;flex-wrap:wrap;gap:6px;margin-top:8px">
{[job.salary, job.exp, job.type].map((pill, idx) => (
<span style={`height:22px;padding:0 8px;border-radius:8px;border:1px solid #E5E7EB;background:${idx === 2 ? '#FFF8F4' : '#F9FAFB'};font-size:10px;font-weight:700;color:${idx === 2 ? '#C2410C' : '#374151'};display:inline-flex;align-items:center`}>{pill}</span>
))}
</div>
<div style="display:flex;flex-wrap:wrap;gap:6px;margin-top:8px">
<For each={job.tags}>{(tag) => <span style="height:22px;padding:0 8px;border-radius:7px;border:1px solid #E5E7EB;background:#F3F4F6;font-size:10px;font-weight:700;color:#4B5563;display:inline-flex;align-items:center">{tag}</span>}</For>
</div>
</div>
<div style="display:flex;flex-direction:column;align-items:flex-end;justify-content:space-between;gap:8px;min-width:200px">
<div style="text-align:right">
<span style="height:20px;padding:0 8px;border-radius:999px;background:#FFF1EB;color:#C2410C;font-size:10px;font-weight:700;display:inline-flex;align-items:center">{job.match}</span>
<p style="margin:8px 0 0;font-size:12px;color:#9CA3AF">{job.posted}</p>
</div>
<div style="display:flex;align-items:center;gap:6px">
<button
type="button"
onClick={() => {
setJobSeekerSelectedId(job.id);
setJobSeekerScreen('detail');
}}
style="height:32px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 10px;font-size:12px;font-weight:700;color:#374151"
>
View Details
</button>
<button
type="button"
onClick={() => {
setJobSeekerSelectedId(job.id);
setJobSeekerApplyStep(2);
setJobSeekerScreen('apply');
}}
style="height:32px;border-radius:8px;border:none;background:#03004E;padding:0 12px;font-size:12px;font-weight:700;color:white"
>
Apply Now
</button>
</div>
</div>
</div>
)}
</For>
</div>
<div style="display:flex;justify-content:center">
<button type="button" style="height:34px;border-radius:10px;border:1px solid #FFD8C2;background:#FFFCFA;padding:0 16px;font-size:12px;font-weight:700;color:#C2410C">Show More Opportunities</button>
</div>
</div>
);
}
const progressWidth = () => `${Math.round((jobPostStep() / COMPANY_JOB_STEPS.length) * 100)}%`;
const latestSubmission = () => companyJobSubmissions()[0] || null;
const latestStatusLabel = () => {
const status = latestSubmission()?.status;
if (status === 'VERIFICATION_PENDING') return 'In Verification Management';
if (status === 'VERIFIED' || status === 'APPROVAL_PENDING') return 'In Approval Management';
if (status === 'APPROVED_LIVE') return 'Approved and Live';
return 'Submitted';
};
const goNextJobStep = () => {
if (jobPostStep() >= COMPANY_JOB_STEPS.length) {
setJobPostView('review');
return;
}
setJobPostStep((prev) => Math.min(COMPANY_JOB_STEPS.length, prev + 1));
};
const goPrevJobStep = () => setJobPostStep((prev) => Math.max(1, prev - 1));
if (jobPostView() === 'success') {
return (
<div style="display:grid;grid-template-columns:2fr 1fr;gap:10px">
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:20px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<div style="display:flex;flex-direction:column;align-items:center;text-align:center;padding:16px 0 8px">
<div style="width:150px;height:150px;border-radius:999px;border:1px solid #F3E2DA;background:#FFF9F5;display:flex;align-items:center;justify-content:center">
<div style="width:56px;height:56px;border-radius:999px;background:#C2410C;color:white;display:flex;align-items:center;justify-content:center;font-size:28px;font-weight:800"></div>
</div>
<p style="margin:14px 0 0;font-size:52px;line-height:1.05;font-weight:800;color:#0D0D2A">Job Submitted Successfully!</p>
<p style="margin:10px 0 0;font-size:14px;color:#4B5563;max-width:640px;line-height:1.5">Your listing for <strong>{companyJobDraft().title}</strong> has been sent to Verification Management first, then Approval Management. Job seekers can see it only after final approval.</p>
<div style="margin-top:24px;padding-top:20px;border-top:1px solid #E5E7EB;display:flex;justify-content:flex-end;gap:12px">
<button type="button" style="height:40px;padding:0 20px;border-radius:10px;border:1px solid #E5E7EB;background:white;font-size:13px;font-weight:600;color:#374151;cursor:pointer">Discard Changes</button>
<Show
when={!verificationPending()}
fallback={
<button type="button" disabled style="height:40px;padding:0 24px;border-radius:10px;background:#F3F4F6;color:#9CA3AF;border:none;font-size:13px;font-weight:600;cursor:not-allowed">Application Submitted</button>
}
>
<button
type="button"
onClick={() => setVerificationPending(true)}
style="height:40px;padding:0 24px;border-radius:10px;background:#FF5E13;color:white;border:none;font-size:13px;font-weight:600;cursor:pointer;box-shadow:0 2px 4px rgba(255,94,19,0.2)"
>
Submit for Verification
</button>
</Show>
</div>
<p style="margin:8px 0 0;font-size:12px;font-weight:700;color:#C2410C">{latestStatusLabel()}</p>
<div style="display:flex;gap:8px;margin-top:14px">
<button type="button" style="height:36px;border-radius:10px;border:1px solid #E5E7EB;background:white;padding:0 14px;font-size:12px;font-weight:700;color:#374151">View Job Details</button>
<button type="button" onClick={() => { setJobPostView('form'); setJobPostStep(1); }} style="height:36px;border-radius:10px;border:none;background:#C2410C;padding:0 14px;font-size:12px;font-weight:700;color:white">Post Another Job</button>
</div>
</div>
<div style="margin-top:14px;border:1px solid #E5E7EB;border-radius:14px;background:#FCFCFD;padding:14px">
<div style="display:flex;justify-content:space-between;align-items:center">
<p style="margin:0;font-size:30px;font-weight:800;color:#111827">Approval Tracking</p>
<span style="height:24px;padding:0 10px;border-radius:999px;background:#FFF1EB;color:#C2410C;font-size:11px;font-weight:700;display:inline-flex;align-items:center">REF: #JX-9902</span>
</div>
<div style="display:grid;gap:10px;margin-top:12px">
{[
{ title: 'Job Submitted', desc: 'Form submitted by company.', done: true },
{ title: 'Verification Management', desc: 'Job content and policy checks run here first.', done: !!latestSubmission() && latestSubmission()!.status !== 'VERIFICATION_PENDING' },
{ title: 'Approval Management', desc: 'Post-verification approval gate for publishing.', done: !!latestSubmission() && latestSubmission()!.status === 'APPROVED_LIVE' },
{ title: 'Published To Job Seekers', desc: 'Visible in Jobs list and View Details only after approval.', done: !!latestSubmission() && latestSubmission()!.status === 'APPROVED_LIVE' },
].map((row, idx) => (
<div style="display:flex;align-items:flex-start;gap:10px">
<span style={`width:18px;height:18px;border-radius:999px;display:inline-flex;align-items:center;justify-content:center;font-size:10px;font-weight:800;flex-shrink:0;background:${row.done ? '#FFF1EB' : '#F3F4F6'};color:${row.done ? '#C2410C' : '#9CA3AF'}`}>{row.done ? '✓' : idx + 1}</span>
<div>
<p style={`margin:0;font-size:14px;font-weight:700;color:${row.done ? '#111827' : '#94A3B8'}`}>{row.title}</p>
<p style={`margin:2px 0 0;font-size:12px;line-height:1.45;color:${row.done ? '#6B7280' : '#B8C1D1'}`}>{row.desc}</p>
</div>
</div>
))}
</div>
</div>
</div>
<div style="display:flex;flex-direction:column;gap:10px">
<div style="border:1px solid #E5E7EB;background:#03004E;border-radius:16px;padding:14px;color:white;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<p style="margin:0;font-size:30px;line-height:1.15;font-weight:800">Did you know?</p>
<p style="margin:8px 0 0;font-size:13px;line-height:1.55;color:#D5D8FF">Jobs with high-quality company descriptions receive <strong>40% more applications</strong>. Take a moment to update your profile.</p>
<button type="button" style="margin-top:10px;height:30px;border:none;border-radius:8px;background:#C2410C;padding:0 10px;font-size:12px;font-weight:700;color:white">Enhance Profile</button>
</div>
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<p style="margin:0;font-size:18px;font-weight:800;color:#111827">Back to Dashboard</p>
<p style="margin:6px 0 0;font-size:12px;color:#6B7280">Monitor all your active listings and candidate inflow.</p>
<button type="button" style="margin-top:10px;height:34px;width:100%;border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB;padding:0 12px;font-size:12px;font-weight:700;color:#374151">Go to Dashboard</button>
</div>
<div style="border:1px solid #E5E7EB;background:white;border-radius:12px;padding:10px;display:flex;align-items:center;justify-content:space-between">
<div>
<p style="margin:0;font-size:13px;font-weight:700;color:#111827">Need help?</p>
<p style="margin:2px 0 0;font-size:11px;color:#6B7280">Chat with a hiring specialist</p>
</div>
<button type="button" style="height:28px;border:none;border-radius:8px;background:#FFF1EB;color:#C2410C;padding:0 10px;font-size:11px;font-weight:700">Connect</button>
</div>
</div>
</div>
);
}
if (jobPostView() === 'review') {
return (
<div style="display:grid;grid-template-columns:2fr 1fr;gap:10px">
<div style="display:flex;flex-direction:column;gap:10px">
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<p style="margin:0;font-size:11px;letter-spacing:0.05em;text-transform:uppercase;color:#9CA3AF">Jobs &gt; Review & Checkout</p>
<p style="margin:6px 0 0;font-size:50px;line-height:1.05;font-weight:800;color:#0D0D2A">Review & Checkout</p>
<p style="margin:8px 0 0;font-size:14px;color:#6B7280">Step 5 of 5: Finalize your job posting details and approve payment.</p>
</div>
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<div style="display:flex;justify-content:space-between;align-items:center">
<p style="margin:0;font-size:35px;font-weight:800;color:#111827">Job Basics</p>
<button type="button" style="height:28px;border:none;border-radius:8px;background:#FFF1EB;color:#C2410C;padding:0 10px;font-size:11px;font-weight:700">Edit</button>
</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:10px">
{[
['Job Title', companyJobDraft().title],
['Employment Type', companyJobDraft().type],
['Company Department', companyJobDraft().department],
['Openings', companyJobDraft().openings],
].map(([label, value]) => (
<div style="border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB;padding:10px">
<p style="margin:0;font-size:10px;letter-spacing:0.06em;text-transform:uppercase;color:#9CA3AF">{label}</p>
<p style="margin:6px 0 0;font-size:20px;font-weight:800;color:#111827;line-height:1.2">{value}</p>
</div>
))}
</div>
</div>
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<div style="display:flex;justify-content:space-between;align-items:center">
<p style="margin:0;font-size:35px;font-weight:800;color:#111827">Role & Requirements</p>
<button type="button" style="height:28px;border:none;border-radius:8px;background:#FFF1EB;color:#C2410C;padding:0 10px;font-size:11px;font-weight:700">Edit</button>
</div>
<p style="margin:10px 0 0;font-size:11px;letter-spacing:0.05em;text-transform:uppercase;color:#9CA3AF">Technical Skills</p>
<div style="display:flex;flex-wrap:wrap;gap:6px;margin-top:6px">
<For each={companyJobDraft().tags}>
{(skill) => <span style="height:24px;padding:0 8px;border-radius:8px;border:1px solid #E5E7EB;background:#F3F4F6;font-size:11px;font-weight:700;color:#374151;display:inline-flex;align-items:center">{skill}</span>}
</For>
</div>
<p style="margin:10px 0 0;font-size:11px;letter-spacing:0.05em;text-transform:uppercase;color:#9CA3AF">Required Experience</p>
<p style="margin:4px 0 0;font-size:16px;font-weight:700;color:#111827">{companyJobDraft().exp}</p>
</div>
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<div style="display:flex;justify-content:space-between;align-items:center">
<p style="margin:0;font-size:35px;font-weight:800;color:#111827">Compensation & Location</p>
<button type="button" style="height:28px;border:none;border-radius:8px;background:#FFF1EB;color:#C2410C;padding:0 10px;font-size:11px;font-weight:700">Edit</button>
</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:10px">
<div style="border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB;padding:10px">
<p style="margin:0;font-size:10px;letter-spacing:0.06em;text-transform:uppercase;color:#9CA3AF">Salary Range</p>
<p style="margin:6px 0 0;font-size:20px;font-weight:800;color:#111827">{companyJobDraft().salary} / year</p>
</div>
<div style="border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB;padding:10px">
<p style="margin:0;font-size:10px;letter-spacing:0.06em;text-transform:uppercase;color:#9CA3AF">Location</p>
<p style="margin:6px 0 0;font-size:20px;font-weight:800;color:#111827">{companyJobDraft().location}</p>
</div>
</div>
</div>
</div>
<div style="display:flex;flex-direction:column;gap:10px">
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;overflow:hidden;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<div style="background:#03004E;padding:12px;color:white">
<p style="margin:0;font-size:30px;font-weight:800;line-height:1.1">Pricing & Approval</p>
<p style="margin:6px 0 0;font-size:13px;color:#D7DBFF">Review costs and confirm submission</p>
</div>
<div style="padding:12px">
<div style="border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB;padding:10px;display:flex;justify-content:space-between;align-items:center">
<span style="font-size:14px;color:#374151">Post Status</span>
<span style="font-size:14px;font-weight:700;color:#C2410C">This is a Paid Job Post</span>
</div>
<div style="display:grid;gap:8px;margin-top:10px">
<div style="display:flex;justify-content:space-between;font-size:14px;color:#374151"><span>Credits Required</span><strong style="color:#111827">500 Tracecoins</strong></div>
<div style="display:flex;justify-content:space-between;font-size:14px;color:#374151"><span>Current Balance</span><strong style="color:#111827">1200 Tracecoins</strong></div>
<div style="height:1px;background:#E5E7EB" />
<div style="display:flex;justify-content:space-between;font-size:16px;color:#111827;font-weight:800"><span>Remaining Balance</span><span style="color:#16A34A">700 Tracecoins</span></div>
</div>
<div style="margin-top:10px;border:1px solid #FFD8C2;border-radius:10px;background:#FFF8F4;padding:10px">
<p style="margin:0;font-size:13px;font-weight:700;color:#111827">Approval Required: Yes</p>
<p style="margin:4px 0 0;font-size:12px;color:#6B7280;line-height:1.45">Your post will be reviewed by our moderation team within 24 hours.</p>
</div>
<button type="button" onClick={() => { submitCompanyJobForReview(); setJobPostView('success'); }} style="margin-top:10px;height:38px;width:100%;border:none;border-radius:10px;background:#03004E;color:white;font-size:12px;font-weight:700">Pay 500 Tracecoins & Submit</button>
</div>
</div>
<div style="border:1px solid #FFD8C2;background:linear-gradient(135deg,#3A1E00 0%,#C2410C 90%);border-radius:16px;padding:14px;color:white;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<p style="margin:0;font-size:11px;letter-spacing:0.06em;text-transform:uppercase;color:#FFE7DA">Pro Tip</p>
<p style="margin:8px 0 0;font-size:16px;line-height:1.4;font-weight:700">Boost your visibility by 40% with Sponsored Highlights.</p>
<button type="button" style="margin-top:10px;height:30px;border:1px solid rgba(255,255,255,0.35);border-radius:8px;background:transparent;color:white;padding:0 10px;font-size:12px;font-weight:700">Learn More</button>
</div>
<div style="display:flex;justify-content:space-between;gap:8px">
<button type="button" onClick={() => { setJobPostView('form'); setJobPostStep(4); }} style="height:34px;flex:1;border-radius:8px;border:1px solid #E5E7EB;background:white;color:#374151;padding:0 12px;font-size:12px;font-weight:700">Back</button>
<button type="button" onClick={() => { submitCompanyJobForReview(); setJobPostView('success'); }} style="height:34px;flex:1;border-radius:8px;border:none;background:#C2410C;color:white;padding:0 12px;font-size:12px;font-weight:700">Confirm & Submit</button>
</div>
</div>
</div>
);
}
return (
<div style="display:flex;flex-direction:column;gap:10px">
<div style="display:grid;grid-template-columns:2fr 3fr;gap:10px">
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<p style="margin:0;font-size:11px;letter-spacing:0.06em;text-transform:uppercase;color:#9CA3AF">Billing Policy</p>
<p style="margin:6px 0 0;font-size:34px;line-height:1.1;font-weight:800;color:#111827">Job Posting Rule</p>
<span style="margin-top:8px;height:22px;padding:0 8px;border-radius:999px;background:#ECFDF3;color:#15803D;font-size:11px;font-weight:700;display:inline-flex;align-items:center">Free First Job</span>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:10px">
<div style="border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB;padding:10px"><p style="margin:0;font-size:11px;color:#6B7280">Cost Required</p><p style="margin:6px 0 0;font-size:20px;font-weight:800;color:#111827">0 Tracecoins</p></div>
<div style="border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB;padding:10px"><p style="margin:0;font-size:11px;color:#6B7280">Usage Count</p><p style="margin:6px 0 0;font-size:20px;font-weight:800;color:#111827">1 Job Posted</p></div>
</div>
</div>
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<p style="margin:0;font-size:11px;letter-spacing:0.06em;text-transform:uppercase;color:#9CA3AF">Lifecycle</p>
<p style="margin:6px 0 0;font-size:34px;line-height:1.1;font-weight:800;color:#111827">Approval Flow Status</p>
<div style="display:flex;align-items:center;gap:6px;margin-top:12px">
<For each={['Draft', 'Submitted', 'Under Review', 'Approved', 'Live']}>
{(step, idx) => (
<>
<span style={`width:26px;height:26px;border-radius:999px;display:inline-flex;align-items:center;justify-content:center;font-size:11px;font-weight:800;background:${idx() + 1 <= jobPostStep() ? '#C2410C' : '#E5E7EB'};color:${idx() + 1 <= jobPostStep() ? 'white' : '#9CA3AF'}`}>{idx() + 1}</span>
<Show when={idx() < 4}>
<span style={`height:2px;flex:1;min-width:18px;background:${idx() + 1 < jobPostStep() ? '#C2410C' : '#E5E7EB'}`} />
</Show>
</>
)}
</For>
</div>
</div>
</div>
<div style="display:grid;grid-template-columns:2fr 1fr;gap:10px">
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<p style="margin:0;font-size:36px;font-weight:800;color:#111827">Step {jobPostStep()}: {COMPANY_JOB_STEPS[jobPostStep() - 1]}</p>
<div style="height:6px;border-radius:999px;background:#E5E7EB;overflow:hidden;margin-top:10px"><div style={`height:100%;background:#C2410C;width:${progressWidth()}`} /></div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:12px">
<div style="grid-column:1 / -1;display:flex;flex-direction:column;gap:6px"><p style="margin:0;font-size:11px;letter-spacing:0.05em;text-transform:uppercase;color:#6B7280">Job Title</p><div style="height:38px;border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB;padding:0 10px;display:flex;align-items:center;font-size:12px;color:#374151">{companyJobDraft().title}</div></div>
<div style="display:flex;flex-direction:column;gap:6px"><p style="margin:0;font-size:11px;letter-spacing:0.05em;text-transform:uppercase;color:#6B7280">Department</p><div style="height:38px;border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB;padding:0 10px;display:flex;align-items:center;justify-content:space-between;font-size:12px;color:#374151"><span>{companyJobDraft().department}</span><span></span></div></div>
<div style="display:flex;flex-direction:column;gap:6px"><p style="margin:0;font-size:11px;letter-spacing:0.05em;text-transform:uppercase;color:#6B7280">Job Category</p><div style="height:38px;border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB;padding:0 10px;display:flex;align-items:center;justify-content:space-between;font-size:12px;color:#374151"><span>Select Category</span><span></span></div></div>
<div style="grid-column:1 / -1;display:flex;flex-direction:column;gap:6px"><p style="margin:0;font-size:11px;letter-spacing:0.05em;text-transform:uppercase;color:#6B7280">Employment Type</p><div style="display:flex;gap:6px"><span style="height:28px;padding:0 10px;border-radius:999px;border:1px solid #E5E7EB;background:#FFF1EB;color:#C2410C;display:inline-flex;align-items:center;font-size:11px;font-weight:700">{companyJobDraft().type}</span></div></div>
<div style="display:flex;flex-direction:column;gap:6px"><p style="margin:0;font-size:11px;letter-spacing:0.05em;text-transform:uppercase;color:#6B7280">Seniority</p><div style="height:38px;border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB;padding:0 10px;display:flex;align-items:center;justify-content:space-between;font-size:12px;color:#374151"><span>Entry Level</span><span></span></div></div>
<div style="display:flex;flex-direction:column;gap:6px"><p style="margin:0;font-size:11px;letter-spacing:0.05em;text-transform:uppercase;color:#6B7280">Openings</p><div style="height:38px;border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB;padding:0 10px;display:flex;align-items:center;font-size:12px;color:#374151">{companyJobDraft().openings}</div></div>
<div style="grid-column:1 / -1;display:flex;flex-direction:column;gap:6px"><p style="margin:0;font-size:11px;letter-spacing:0.05em;text-transform:uppercase;color:#6B7280">Description</p><div style="min-height:120px;border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB;padding:10px;font-size:12px;color:#9CA3AF">Detailed job responsibilities, skills, and expectations...</div></div>
</div>
<div style="display:flex;justify-content:space-between;align-items:center;gap:8px;margin-top:12px;border-top:1px solid #E5E7EB;padding-top:10px">
<button type="button" onClick={goPrevJobStep} disabled={jobPostStep() === 1} style={`height:34px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 12px;font-size:12px;font-weight:700;color:${jobPostStep() === 1 ? '#9CA3AF' : '#374151'};cursor:${jobPostStep() === 1 ? 'not-allowed' : 'pointer'}`}>Back</button>
<div style="display:flex;gap:8px">
<button type="button" style="height:34px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 12px;font-size:12px;font-weight:700;color:#374151">Save as Draft</button>
<button type="button" onClick={jobPostStep() === COMPANY_JOB_STEPS.length ? () => setJobPostView('review') : goNextJobStep} style="height:34px;border-radius:8px;border:none;background:#03004E;padding:0 12px;font-size:12px;font-weight:700;color:white">
{jobPostStep() === COMPANY_JOB_STEPS.length ? 'Go To Review' : 'Next: Role & Requirements'}
</button>
</div>
</div>
</div>
<div style="display:flex;flex-direction:column;gap:10px">
<div style="border:1px solid #D9D8F9;background:#4F4B8A;border-radius:16px;padding:14px;color:white;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<div style="display:flex;justify-content:space-between;align-items:center">
<p style="margin:0;font-size:11px;letter-spacing:0.06em;text-transform:uppercase;color:#DADAFB">Live Preview</p>
<span style="height:20px;padding:0 8px;border-radius:999px;border:1px solid rgba(255,255,255,0.3);font-size:10px;font-weight:700;display:inline-flex;align-items:center">FREE POST</span>
</div>
<p style="margin:10px 0 0;font-size:10px;color:#DADAFB;letter-spacing:0.06em;text-transform:uppercase">Position</p>
<p style="margin:4px 0 0;font-size:26px;line-height:1.15;font-weight:800;color:white">Product Design Manager</p>
<div style="display:grid;gap:8px;margin-top:12px">
{[
['Location', 'Remote / San Francisco'],
['Type', 'Full-Time Role'],
['Posting Fee', '$0.00 (Tracecoins: 0)'],
].map(([label, val]) => (
<div style="display:flex;justify-content:space-between;align-items:center;gap:8px">
<span style="font-size:11px;color:#D7DBFF">{label}</span>
<span style="font-size:12px;font-weight:700;color:white;text-align:right">{val}</span>
</div>
))}
</div>
</div>
<div style="border:1px solid #E5E7EB;background:#FFF8F4;border-radius:14px;padding:12px;box-shadow:0 1px 3px rgba(0,0,0,0.05)">
<p style="margin:0;font-size:12px;font-weight:700;color:#111827">Need help writing?</p>
<p style="margin:6px 0 0;font-size:12px;color:#6B7280;line-height:1.45">Try our AI Generator to create a compelling description in seconds.</p>
<button type="button" style="margin-top:8px;height:30px;border:none;border-radius:8px;background:#FFF1EB;color:#C2410C;padding:0 10px;font-size:11px;font-weight:700">Launch AI Assistant</button>
</div>
</div>
</div>
</div>
);
}
if (customerKey() === 'my requirements') {
const statusMeta = (value: string) => {
const key = String(value || '').toLowerCase();
if (key === 'approved') return { bg: '#DCFCE7', c: '#15803D', label: 'Approved' };
if (key === 'active') return { bg: '#DBEAFE', c: '#1D4ED8', label: 'Active' };
if (key === 'under review') return { bg: '#FFEDD5', c: '#C2410C', label: 'Under Review' };
if (key === 'draft') return { bg: '#F3F4F6', c: '#4B5563', label: 'Draft' };
if (key === 'closed') return { bg: '#E5E7EB', c: '#4B5563', label: 'Closed' };
if (key === 'rejected') return { bg: '#FEE2E2', c: '#B91C1C', label: 'Rejected' };
return { bg: '#F3F4F6', c: '#6B7280', label: titleCase(value) };
};
const filteredRows = requirementRows().filter((row) => {
if (tab === 'open') return row.status === 'active' || row.status === 'under review';
if (tab === 'closed') return row.status === 'closed';
if (tab === 'drafts') return row.status === 'draft';
return true;
});
const selectedRoleDetails = () => REQUIREMENT_ROLE_DETAILS[selectedRequirementRole()] || REQUIREMENT_ROLE_DETAILS.PHOTOGRAPHER;
const steps = ['Choose Type', 'Basic Details', 'Role-Specific', 'Budget & Location', 'Attachments', 'Review'];
const canGoBack = () => requirementsStep() > 1;
const nextLabel = () => (requirementsStep() === steps.length ? 'Submit For Approval' : 'Next');
const goNextStep = () => {
if (requirementsStep() >= steps.length) {
submitRequirementForReview();
return;
}
setRequirementsStep((prev) => Math.min(steps.length, prev + 1));
};
const goBackStep = () => setRequirementsStep((prev) => Math.max(1, prev - 1));
if (requirementsView() === 'new') {
return (
<div style="display:flex;flex-direction:column;gap:12px">
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:16px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<div style="display:flex;align-items:center;justify-content:space-between">
<p style="margin:0;font-size:20px;font-weight:800;color:#111827">Post New Requirement</p>
<button
type="button"
onClick={() => { setRequirementsView('list'); setRequirementsStep(1); }}
style="height:30px;border-radius:8px;border:1px solid #E5E7EB;background:white;color:#374151;padding:0 10px;font-size:12px;font-weight:700"
>
Back To List
</button>
</div>
<div style="display:flex;align-items:flex-start;justify-content:space-between;gap:8px;margin-top:12px">
<For each={steps}>
{(step, idx) => (
<div style="flex:1;display:flex;align-items:center;gap:8px">
<div style="display:flex;flex-direction:column;align-items:center;gap:6px;min-width:58px">
<span style={`width:32px;height:32px;border-radius:999px;display:inline-flex;align-items:center;justify-content:center;font-size:12px;font-weight:800;border:1px solid ${requirementsStep() > idx() + 1 ? '#FF5E13' : '#D1D5DB'};background:${requirementsStep() === idx() + 1 ? '#FF5E13' : requirementsStep() > idx() + 1 ? '#FFF1EB' : '#F9FAFB'};color:${requirementsStep() === idx() + 1 ? 'white' : requirementsStep() > idx() + 1 ? '#FF5E13' : '#6B7280'}`}>{idx() + 1}</span>
<p style={`margin:0;font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:0.04em;color:${requirementsStep() === idx() + 1 ? '#111827' : '#9CA3AF'}`}>{step}</p>
</div>
<Show when={idx() < steps.length - 1}>
<div style={`height:2px;flex:1;background:${requirementsStep() > idx() + 1 ? '#FF5E13' : '#E5E7EB'};margin-top:16px`} />
</Show>
</div>
)}
</For>
</div>
</div>
<Show when={requirementsStep() === 1}>
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:16px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<p style="margin:0;font-size:30px;font-weight:800;color:#111827;text-align:center">What kind of professional are you looking for?</p>
<p style="margin:8px 0 0;font-size:14px;color:#6B7280;text-align:center">Select a category to start your requirement. This helps us match you with the right experts.</p>
<div style="display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px;margin-top:14px">
<For each={REQUIREMENT_ROLE_OPTIONS}>
{(role) => {
const active = selectedRequirementRole() === role.key;
return (
<button
type="button"
onClick={() => setSelectedRequirementRole(role.key)}
style={`text-align:left;border:1px solid ${active ? '#FF5E13' : '#E5E7EB'};border-radius:12px;background:white;padding:12px;min-height:154px;display:flex;flex-direction:column;gap:10px`}
>
<div style="display:flex;align-items:center;justify-content:space-between">
<span style="width:40px;height:40px;border-radius:10px;background:#F3F4F6;border:1px solid #E5E7EB;display:flex;align-items:center;justify-content:center">
<img src={role.icon} alt="" style={`width:18px;height:18px;object-fit:contain;filter:${ORANGE_ICON_FILTER}`} />
</span>
<Show when={active}>
<span style="display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:999px;background:#FFF1EB;border:1px solid #FFD8C2;color:#FF5E13;font-size:12px;font-weight:800"></span>
</Show>
</div>
<p style="margin:0;font-size:16px;font-weight:800;color:#111827">{role.title}</p>
<p style="margin:0;font-size:12px;line-height:1.5;color:#6B7280">{role.desc}</p>
<span style={`margin-top:auto;height:30px;border-radius:8px;display:inline-flex;align-items:center;justify-content:center;font-size:12px;font-weight:700;${active ? 'background:#FF5E13;color:white' : 'border:1px solid #E5E7EB;color:#FF5E13'}`}>{active ? 'Continue' : 'Select'}</span>
</button>
);
}}
</For>
</div>
</div>
</Show>
<Show when={requirementsStep() === 2}>
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:16px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<p style="margin:0;font-size:30px;font-weight:800;color:#111827">Basic Requirement Details</p>
<p style="margin:8px 0 0;font-size:13px;color:#6B7280">Add core details before role-specific inputs.</p>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:12px">
{['Requirement Title', 'Priority', 'Requirement Description', 'Expected Start Date', 'Service City', 'Contact Number'].map((field) => (
<div style="display:flex;flex-direction:column;gap:6px">
<p style="margin:0;font-size:11px;font-weight:700;letter-spacing:0.05em;text-transform:uppercase;color:#6B7280">{field}</p>
<div style="height:38px;border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB;padding:0 10px;display:flex;align-items:center;font-size:12px;color:#9CA3AF">
Enter {field.toLowerCase()}
</div>
</div>
))}
</div>
</div>
</Show>
<Show when={requirementsStep() === 3}>
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:16px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<p style="margin:0;font-size:30px;font-weight:800;color:#111827">{selectedRoleDetails().title}</p>
<p style="margin:8px 0 0;font-size:13px;color:#6B7280">{selectedRoleDetails().subtitle}</p>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:12px">
<For each={selectedRoleDetails().fields}>
{(field, idx) => (
<div style={`display:flex;flex-direction:column;gap:6px;${field.includes('Venue') ? 'grid-column:1 / -1' : ''}`}>
<p style="margin:0;font-size:11px;font-weight:700;letter-spacing:0.05em;text-transform:uppercase;color:#6B7280">{field}</p>
<div style="height:38px;border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB;padding:0 10px;display:flex;align-items:center;justify-content:space-between;font-size:12px;color:#9CA3AF">
<span>{idx() % 2 === 0 ? 'Select' : 'Enter'} {field.toLowerCase()}</span>
<Show when={idx() % 2 === 0}><span></span></Show>
</div>
</div>
)}
</For>
</div>
<div style="display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px;margin-top:12px">
<For each={selectedRoleDetails().toggles}>
{(toggleLabel) => (
<div style="display:flex;align-items:center;gap:10px;padding:10px;border:1px solid #E5E7EB;border-radius:10px;background:#FBFBFB">
<span style="width:32px;height:18px;border-radius:999px;background:#E5E7EB;position:relative;display:inline-flex;align-items:center;padding:2px">
<span style="width:14px;height:14px;border-radius:999px;background:white" />
</span>
<span style="font-size:12px;font-weight:700;color:#374151">{toggleLabel}</span>
</div>
)}
</For>
</div>
<div style="margin-top:12px">
<p style="margin:0;font-size:11px;font-weight:700;letter-spacing:0.05em;text-transform:uppercase;color:#6B7280">Style Needed</p>
<div style="display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:8px;margin-top:8px">
<For each={selectedRoleDetails().styles}>
{(styleLabel) => (
<div style="height:34px;border:1px solid #E5E7EB;border-radius:8px;background:#F9FAFB;padding:0 10px;display:flex;align-items:center;gap:8px;font-size:12px;color:#374151">
<span style="width:14px;height:14px;border-radius:4px;border:1px solid #F5B197;background:white" />
{styleLabel}
</div>
)}
</For>
</div>
</div>
</div>
</Show>
<Show when={requirementsStep() === 4}>
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:16px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<p style="margin:0;font-size:30px;font-weight:800;color:#111827">Budget & Location</p>
<p style="margin:8px 0 0;font-size:13px;color:#6B7280">Set your target budget and service location to get relevant quotes.</p>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:12px">
{['Budget Range', 'Urgency Level', 'Service Location', 'Mode (Remote / On-site)', 'Preferred Start Date', 'Flexible Budget'].map((field, idx) => (
<div style="display:flex;flex-direction:column;gap:6px">
<p style="margin:0;font-size:11px;font-weight:700;letter-spacing:0.05em;text-transform:uppercase;color:#6B7280">{field}</p>
<div style="height:38px;border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB;padding:0 10px;display:flex;align-items:center;justify-content:space-between;font-size:12px;color:#9CA3AF">
<span>{idx % 2 === 0 ? 'Enter' : 'Select'} {field.toLowerCase()}</span>
<Show when={idx % 2 === 1}><span></span></Show>
</div>
</div>
))}
</div>
</div>
</Show>
<Show when={requirementsStep() === 5}>
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:16px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<p style="margin:0;font-size:30px;font-weight:800;color:#111827">Attachments</p>
<p style="margin:8px 0 0;font-size:13px;color:#6B7280">Upload reference files to help professionals understand your requirement better.</p>
<div style="display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px;margin-top:12px">
{[1, 2, 3, 4].map((slot) => (
<div style="height:110px;border:1px dashed #F5B197;border-radius:12px;background:#FFF9F6;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:6px">
<span style="width:26px;height:26px;border-radius:999px;background:white;border:1px solid #FFD8C2;display:flex;align-items:center;justify-content:center;color:#FF5E13;font-weight:800">+</span>
<p style="margin:0;font-size:11px;color:#6B7280">Attachment {slot}</p>
</div>
))}
</div>
</div>
</Show>
<Show when={requirementsStep() === 6}>
<div style="display:grid;grid-template-columns:2fr 1fr;gap:10px">
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:16px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<p style="margin:0;font-size:30px;font-weight:800;color:#111827">Review & Submit</p>
<p style="margin:8px 0 0;font-size:13px;color:#6B7280">Final check before submitting for approval.</p>
<div style="margin-top:12px;display:grid;gap:8px">
{[
['Category', titleCase(selectedRequirementRole().replace(/_/g, ' ').toLowerCase())],
['Requirement Title', 'Luxury Wedding Shoot'],
['Budget Range', '₹1,50,000 - ₹2,00,000'],
['Service Location', 'Chennai, TN'],
['Expected Start Date', 'Nov 12, 2023'],
].map(([label, value]) => (
<div style="display:flex;justify-content:space-between;align-items:center;padding:10px;border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB">
<span style="font-size:12px;color:#6B7280">{label}</span>
<span style="font-size:12px;font-weight:700;color:#111827">{value}</span>
</div>
))}
</div>
</div>
<div style="border:1px solid #E5E7EB;background:linear-gradient(180deg,#FFFFFF 0%,#FFF6F0 100%);border-radius:16px;padding:16px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<p style="margin:0;font-size:11px;letter-spacing:0.06em;text-transform:uppercase;color:#6B7280">Approval Flow</p>
<p style="margin:8px 0 0;font-size:20px;font-weight:800;color:#111827">Submit For Approval</p>
<p style="margin:8px 0 0;font-size:12px;color:#6B7280;line-height:1.5">Once submitted, your requirement goes to Verification Management first, then Approval Management. Only after both stages it goes live in professional leads.</p>
<div style="display:grid;gap:8px;margin-top:12px">
{['Draft Created', 'Verification Management', 'Approval Management', 'Live In Leads'].map((state, idx) => (
<div style="display:flex;align-items:center;gap:8px">
<span style={`width:18px;height:18px;border-radius:999px;display:inline-flex;align-items:center;justify-content:center;font-size:10px;font-weight:800;background:${idx < 2 ? '#ECFDF3' : '#F3F4F6'};color:${idx < 2 ? '#059669' : '#9CA3AF'}`}>{idx < 2 ? '✓' : idx + 1}</span>
<span style={`font-size:12px;color:${idx < 2 ? '#111827' : '#6B7280'}`}>{state}</span>
</div>
))}
</div>
</div>
</div>
</Show>
<div style="display:flex;align-items:center;justify-content:space-between;border-top:1px solid #E5E7EB;padding-top:12px">
<button
type="button"
onClick={goBackStep}
disabled={!canGoBack()}
style={`height:34px;border-radius:8px;padding:0 12px;font-size:12px;font-weight:700;border:1px solid #E5E7EB;background:white;color:${canGoBack() ? '#374151' : '#9CA3AF'};cursor:${canGoBack() ? 'pointer' : 'not-allowed'}`}
>
Back
</button>
<div style="display:flex;gap:8px">
<button type="button" style="height:34px;border-radius:8px;border:1px solid #E5E7EB;background:white;color:#374151;padding:0 12px;font-size:12px;font-weight:700">Save As Draft</button>
<button type="button" onClick={goNextStep} style="height:34px;border-radius:8px;border:none;background:#03004E;color:white;padding:0 12px;font-size:12px;font-weight:700">{nextLabel()}</button>
</div>
</div>
</div>
);
}
if (requirementsView() === 'detail') {
const selectedRow = requirementRows().find((row) => row.id === selectedRequirementId()) || requirementRows()[0];
const status = statusMeta(selectedRow.status);
return (
<div style="display:grid;grid-template-columns:2fr 1fr;gap:10px">
<div style="display:flex;flex-direction:column;gap:10px">
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<div style="display:flex;align-items:center;justify-content:space-between;gap:8px">
<div>
<p style="margin:0;font-size:11px;letter-spacing:0.05em;text-transform:uppercase;color:#9CA3AF">Requirements &gt; Details</p>
<p style="margin:6px 0 0;font-size:38px;line-height:1.05;font-weight:800;color:#111827">{selectedRow.title}</p>
<div style="display:flex;align-items:center;gap:8px;margin-top:8px">
<span style={`height:22px;padding:0 10px;border-radius:999px;display:inline-flex;align-items:center;font-size:11px;font-weight:700;background:${status.bg};color:${status.c}`}>{status.label}</span>
<span style="height:22px;padding:0 10px;border-radius:999px;display:inline-flex;align-items:center;font-size:11px;font-weight:700;background:#DBEAFE;color:#1D4ED8">Active</span>
<span style="font-size:12px;color:#6B7280">Created on {selectedRow.submission}</span>
</div>
</div>
<div style="display:flex;gap:8px">
<button type="button" style="height:32px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 12px;font-size:12px;font-weight:700;color:#374151">Duplicate</button>
<button type="button" style="height:32px;border-radius:8px;border:none;background:#FF5E13;padding:0 12px;font-size:12px;font-weight:700;color:white">Boost Requirement</button>
</div>
</div>
<div style="display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;margin-top:10px">
{[
['Proposed Budget', selectedRow.budget],
['Location & Urgency', selectedRow.location],
['Project Scope', '3 Day Event'],
].map(([label, val]) => (
<div style="border:1px solid #E5E7EB;border-radius:12px;background:#F9FAFB;padding:10px">
<p style="margin:0;font-size:11px;letter-spacing:0.05em;text-transform:uppercase;color:#9CA3AF">{label}</p>
<p style="margin:7px 0 0;font-size:16px;font-weight:800;color:#111827">{val}</p>
</div>
))}
</div>
</div>
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<p style="margin:0;font-size:34px;font-weight:800;color:#111827">Requirement Overview</p>
<p style="margin:10px 0 0;font-size:13px;line-height:1.7;color:#374151">We are looking for a premium {selectedRow.category.toLowerCase().replace(/_/g, ' ')} team for a high-end project with a focus on quality, timeline ownership, and clear communication throughout execution.</p>
<div style="margin-top:10px;padding:10px;border:1px solid #FEC7AA;border-radius:10px;background:#FFF9F5">
<p style="margin:0;font-size:11px;letter-spacing:0.05em;text-transform:uppercase;color:#C2410C;font-weight:700">Special Instructions</p>
<ul style="margin:8px 0 0;padding-left:18px;color:#374151;font-size:13px;line-height:1.6">
<li>Mandatory experience in similar premium projects.</li>
<li>Must be available for milestone reviews every 72 hours.</li>
<li>NDA required before onboarding and deliverable sharing.</li>
</ul>
</div>
</div>
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<p style="margin:0;font-size:30px;font-weight:800;color:#111827">Reference Material</p>
<div style="display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:8px;margin-top:10px">
{[1, 2, 3, 4].map((slot) => (
<div style="height:84px;border:1px dashed #F5B197;border-radius:10px;background:#FFF9F6;display:flex;align-items:center;justify-content:center;color:#9CA3AF;font-size:12px;font-weight:700">
{slot === 4 ? 'Add More' : `Asset ${slot}`}
</div>
))}
</div>
</div>
</div>
<div style="display:flex;flex-direction:column;gap:10px">
<div style="border:1px solid #D9D8F9;background:#4F4B8A;border-radius:16px;padding:14px;color:white;box-shadow:0 1px 4px rgba(0,0,0,0.08)">
<p style="margin:0;font-size:11px;letter-spacing:0.06em;text-transform:uppercase;color:#DADAFB">Response Metrics</p>
<p style="margin:8px 0 0;font-size:54px;line-height:1;font-weight:800">08</p>
<p style="margin:4px 0 0;font-size:12px;color:#E5E7FF">Total Responses</p>
<div style="height:1px;background:rgba(255,255,255,0.2);margin:10px 0" />
<div style="display:flex;justify-content:space-between;font-size:12px">
<span>03 Shortlisted</span>
<span>03 Rejected</span>
</div>
</div>
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<p style="margin:0;font-size:11px;letter-spacing:0.06em;text-transform:uppercase;color:#9CA3AF">Approval History</p>
<div style="display:grid;gap:10px;margin-top:10px">
{['Requirement Approved', 'Under Review', 'Submitted', 'Draft Created'].map((step) => (
<div style="display:flex;align-items:center;gap:8px">
<span style="width:18px;height:18px;border-radius:999px;background:#ECFDF3;color:#059669;display:inline-flex;align-items:center;justify-content:center;font-size:10px;font-weight:800"></span>
<div>
<p style="margin:0;font-size:12px;font-weight:700;color:#111827">{step}</p>
<p style="margin:1px 0 0;font-size:11px;color:#9CA3AF">Oct 24, 2023</p>
</div>
</div>
))}
</div>
</div>
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:12px;display:grid;gap:8px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
{['Extend Expiry', 'Edit Details', 'Close Requirement'].map((action, idx) => (
<button type="button" style={`height:36px;border-radius:8px;border:1px solid ${idx === 2 ? '#FECACA' : '#E5E7EB'};background:${idx === 2 ? '#FEF2F2' : '#F9FAFB'};color:${idx === 2 ? '#B91C1C' : '#374151'};font-size:12px;font-weight:700`}>{action}</button>
))}
</div>
</div>
</div>
);
}
const totalCount = requirementRows().length;
const draftCount = requirementRows().filter((item) => item.status === 'draft').length;
const submittedCount = requirementRows().filter((item) => item.status === 'under review').length;
const approvedCount = requirementRows().filter((item) => item.status === 'approved').length;
const activeCount = requirementRows().filter((item) => item.status === 'active').length;
const rejectedCount = requirementRows().filter((item) => item.status === 'rejected').length;
return (
<div style="display:flex;flex-direction:column;gap:10px">
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<div style="display:flex;align-items:center;justify-content:space-between;gap:10px">
<div>
<p style="margin:0;font-size:47px;line-height:1.05;font-weight:800;color:#111827">My Requirements</p>
<p style="margin:6px 0 0;font-size:14px;color:#6B7280">Create, submit for approval, and manage your requirements with precision and clarity.</p>
</div>
<button
type="button"
onClick={() => { setRequirementsView('new'); setRequirementsStep(1); }}
style="height:38px;border-radius:10px;border:none;background:#03004E;color:white;padding:0 14px;font-size:12px;font-weight:700"
>
+ Post New Requirement
</button>
</div>
<div style="display:grid;grid-template-columns:2fr repeat(5,minmax(0,1fr));gap:8px;margin-top:10px">
{[
['Total Requirements', String(totalCount)],
['Drafts', String(draftCount)],
['Submitted', String(submittedCount)],
['Approved', String(approvedCount)],
['Active', String(activeCount)],
['Rejected', String(rejectedCount)],
].map(([label, value], idx) => (
<div style={`border:1px solid #E5E7EB;border-radius:10px;background:${idx === 0 ? '#FFF8F4' : '#F9FAFB'};padding:10px;${idx === 0 ? 'border-left:3px solid #FF5E13' : ''}`}>
<p style="margin:0;font-size:10px;letter-spacing:0.06em;text-transform:uppercase;color:#9CA3AF;font-weight:700">{label}</p>
<p style={`margin:6px 0 0;font-size:${idx === 0 ? '42px' : '36px'};line-height:1;font-weight:800;color:#111827`}>{value}</p>
</div>
))}
</div>
</div>
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;overflow:hidden;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<div style="padding:10px 12px;border-bottom:1px solid #E5E7EB;display:flex;align-items:center;gap:8px">
{['All Requirements', 'Drafts', 'Submitted', 'Approved', 'Active', 'Rejected', 'Closed', 'Expired'].map((label, idx) => (
<button type="button" style={`height:30px;padding:0 8px;border:none;border-bottom:${idx === 0 ? '2px solid #FF5E13' : '2px solid transparent'};background:none;font-size:12px;font-weight:700;color:${idx === 0 ? '#FF5E13' : '#6B7280'}`}>{label}</button>
))}
</div>
<div style="padding:10px 12px;border-bottom:1px solid #E5E7EB;display:flex;align-items:center;gap:8px">
<div style="height:34px;flex:1;border:1px solid #E5E7EB;border-radius:8px;background:#F9FAFB;padding:0 10px;display:flex;align-items:center;gap:8px;font-size:12px;color:#9CA3AF"><Search size={14} /> Search ID or Title...</div>
{['Sort By: Newest', 'Category: All', 'Status: All'].map((item) => (
<button type="button" style="height:34px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 10px;font-size:12px;color:#374151">{item}</button>
))}
<button type="button" style="height:34px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 10px;font-size:12px;color:#374151">Export</button>
</div>
<div style="overflow-x:auto">
<table style="width:100%;border-collapse:collapse;min-width:920px">
<thead style="background:#F9FAFB">
<tr>
{['ID', 'Requirement Details', 'Category', 'Budget & Location', 'Submission', 'Status', 'Actions'].map((head) => (
<th style="padding:10px;text-align:left;font-size:10px;letter-spacing:0.06em;text-transform:uppercase;color:#9CA3AF">{head}</th>
))}
</tr>
</thead>
<tbody>
<For each={filteredRows}>
{(row) => {
const status = statusMeta(row.status);
return (
<tr style="border-top:1px solid #F3F4F6">
<td style="padding:10px;font-size:12px;color:#9CA3AF;font-weight:700">{row.id}</td>
<td style="padding:10px">
<p style="margin:0;font-size:14px;font-weight:700;color:#111827">{row.title}</p>
<p style="margin:3px 0 0;font-size:12px;color:#6B7280">{row.summary}</p>
</td>
<td style="padding:10px"><span style="height:20px;padding:0 8px;border-radius:999px;border:1px solid #E5E7EB;background:#F3F4F6;display:inline-flex;align-items:center;font-size:10px;font-weight:700;color:#4B5563">{row.category}</span></td>
<td style="padding:10px">
<p style="margin:0;font-size:13px;font-weight:700;color:#111827">{row.budget}</p>
<p style="margin:2px 0 0;font-size:11px;color:#9CA3AF">{row.location}</p>
</td>
<td style="padding:10px;font-size:12px;color:#6B7280">{row.submission}</td>
<td style="padding:10px">
<span style={`height:22px;padding:0 10px;border-radius:999px;display:inline-flex;align-items:center;font-size:11px;font-weight:700;background:${status.bg};color:${status.c}`}>{status.label}</span>
<p style="margin:6px 0 0;font-size:11px;color:#1D4ED8;font-weight:700">{row.responseTag}</p>
</td>
<td style="padding:10px">
<div style="display:flex;gap:6px">
<button
type="button"
onClick={() => { setSelectedRequirementId(row.id); setRequirementsView('detail'); }}
style="height:28px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 10px;font-size:11px;font-weight:700;color:#374151"
>
View
</button>
<button type="button" style="height:28px;border-radius:8px;border:none;background:#03004E;padding:0 10px;font-size:11px;font-weight:700;color:white">Edit</button>
</div>
</td>
</tr>
);
}}
</For>
</tbody>
</table>
</div>
<div style="padding:10px 12px;border-top:1px solid #E5E7EB;display:flex;justify-content:space-between;align-items:center">
<p style="margin:0;font-size:12px;color:#9CA3AF">Showing 1 to {Math.min(filteredRows.length, 6)} of {filteredRows.length} requirements</p>
<div style="display:flex;gap:6px">
{[1, 2, 3].map((p) => <button type="button" style={`width:28px;height:28px;border-radius:8px;border:1px solid #E5E7EB;background:${p === 1 ? '#FF5E13' : 'white'};color:${p === 1 ? 'white' : '#6B7280'};font-size:12px;font-weight:700`}>{p}</button>)}
</div>
</div>
</div>
</div>
);
}
if (customerKey() === 'received responses' || customerKey() === 'my responses') {
if (normalizeRoleKey(props.roleKey || '') !== 'CUSTOMER') {
const leadStatusPill = (status: string) => {
if (status === 'request_sent') return { c: '#374151', text: 'Request Sent' };
if (status === 'contact_unlocked') return { c: '#374151', text: 'Contact Unlocked' };
if (status === 'approved') return { c: '#374151', text: 'Approved' };
if (status === 'rejected') return { c: '#374151', text: 'Rejected' };
if (status === 'expired_refunded') return { c: '#374151', text: 'Expired · Refunded' };
if (status === 'cancelled_by_professional') return { c: '#374151', text: 'Cancelled' };
return { c: '#374151', text: titleCase(status) };
};
const responseSelectedLead = () => leadCards().find((item) => item.id === activeResponseLeadId()) || null;
const list = filteredRequestedRows().filter((row) => {
if (resolvedTabKey() === 'pending leads') return row.status === 'request_sent';
return true;
});
const totalPages = Math.max(1, Math.ceil(list.length / requestedPerPage));
const currentPage = Math.min(requestedPage(), totalPages);
const pagedList = list.slice((currentPage - 1) * requestedPerPage, (currentPage - 1) * requestedPerPage + requestedPerPage);
if (responsesDetailMode() && responseSelectedLead()) {
const lead = responseSelectedLead()!;
const spec = leadDetailsSpec(lead);
return (
<div style="display:flex;flex-direction:column;gap:10px">
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<div style="border:1px solid #E5E7EB;border-radius:12px;background:#FFFFFF;padding:14px">
<div style="display:flex;align-items:flex-start;justify-content:space-between;gap:10px;flex-wrap:wrap">
<div>
<p style="margin:0;font-size:11px;letter-spacing:0.06em;text-transform:uppercase;color:#6B7280">My Responses View Details</p>
<p style="margin:4px 0 0;font-size:24px;font-weight:800;color:#111827">{lead.title}</p>
<p style="margin:4px 0 0;font-size:12px;color:#6B7280">{lead.category} {lead.location} {lead.area}</p>
</div>
<button type="button" onClick={() => { setResponsesDetailMode(false); setActiveResponseLeadId(''); }} style="height:32px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 12px;font-size:12px;font-weight:700;color:#374151">Back to My Responses</button>
</div>
<div style="margin-top:10px;display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:8px">
<div style="border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB;padding:10px;display:flex;gap:8px">
<span style="width:24px;height:24px;border-radius:999px;background:#FFF1EB;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0"><Calendar size={13} style="color:#FF5E13" /></span>
<div><p style="margin:0;font-size:11px;color:#6B7280;font-weight:700">Schedule</p><p style="margin:3px 0 0;font-size:13px;font-weight:800;color:#111827">{spec.timeframe}</p></div>
</div>
<div style="border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB;padding:10px;display:flex;gap:8px">
<span style="width:24px;height:24px;border-radius:999px;background:#FFF1EB;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0"><Calendar size={13} style="color:#FF5E13" /></span>
<div><p style="margin:0;font-size:11px;color:#6B7280;font-weight:700">Date Required</p><p style="margin:3px 0 0;font-size:13px;font-weight:800;color:#111827">{lead.dateRequired}</p></div>
</div>
<div style="border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB;padding:10px;display:flex;gap:8px">
<span style="width:24px;height:24px;border-radius:999px;background:#FFF1EB;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0"><MapPin size={13} style="color:#FF5E13" /></span>
<div><p style="margin:0;font-size:11px;color:#6B7280;font-weight:700">Area</p><p style="margin:3px 0 0;font-size:13px;font-weight:800;color:#111827">{String(lead.area || 'Chennai')}</p></div>
</div>
<div style="border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB;padding:10px;display:flex;gap:8px">
<span style="width:24px;height:24px;border-radius:999px;background:#FFF1EB;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0"><Coins size={13} style="color:#FF5E13" /></span>
<div><p style="margin:0;font-size:11px;color:#6B7280;font-weight:700">Unlock Cost</p><p style="margin:3px 0 0;font-size:13px;font-weight:800;color:#C2410C">{lead.cost} Tracecoin</p></div>
</div>
</div>
</div>
<div style="margin-top:10px;display:grid;grid-template-columns:2fr 1fr;gap:10px">
<div style="display:grid;gap:10px">
<div style="border:1px solid #E5E7EB;border-radius:12px;background:white;padding:12px">
<p style="margin:0;font-size:11px;letter-spacing:0.05em;text-transform:uppercase;color:#6B7280;font-weight:700">Work Scope</p>
<p style="margin:8px 0 0;font-size:14px;color:#1F2937;line-height:1.65">{spec.scope}</p>
</div>
<div style="border:1px solid #E5E7EB;border-radius:12px;background:#F9FAFB;padding:12px">
<p style="margin:0 0 8px;font-size:11px;letter-spacing:0.05em;text-transform:uppercase;color:#6B7280;font-weight:700">Lead Specific Highlights</p>
<div style="display:grid;gap:6px"><For each={spec.highlights}>{(item) => <div style="display:flex;align-items:flex-start;gap:6px"><span style="margin-top:3px;width:6px;height:6px;border-radius:999px;background:#FF5E13;flex-shrink:0" /><span style="font-size:14px;color:#1F2937;line-height:1.55">{item}</span></div>}</For></div>
</div>
</div>
<div style="border:1px solid #E5E7EB;border-radius:12px;background:white;padding:12px;display:grid;gap:8px;align-content:start">
<div style="display:flex;justify-content:space-between;gap:8px;padding-bottom:6px;border-bottom:1px solid #F3F4F6"><span style="font-size:12px;color:#6B7280">Lead ID</span><span style="font-size:12px;color:#111827;font-weight:700">{lead.id}</span></div>
<div style="display:flex;justify-content:space-between;gap:8px;padding-bottom:6px;border-bottom:1px solid #F3F4F6"><span style="font-size:12px;color:#6B7280">Category</span><span style="font-size:12px;color:#111827;font-weight:700">{lead.category}</span></div>
<div style="display:flex;justify-content:space-between;gap:8px;padding-bottom:6px;border-bottom:1px solid #F3F4F6"><span style="font-size:12px;color:#6B7280">Location</span><span style="font-size:12px;color:#111827;font-weight:700">{lead.location}</span></div>
<div style="display:flex;justify-content:space-between;gap:8px;padding-bottom:6px;border-bottom:1px solid #F3F4F6"><span style="font-size:12px;color:#6B7280">Status</span><span style="font-size:12px;color:#111827;font-weight:700">From My Responses</span></div>
</div>
</div>
</div>
</div>
);
}
return (
<div style="display:flex;flex-direction:column;gap:10px">
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;overflow:hidden;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<div style="padding:10px 12px;border-bottom:1px solid #E5E7EB;display:flex;justify-content:space-between;align-items:center;gap:10px">
<p style="margin:0;font-size:18px;font-weight:800;color:#111827">My Responses</p>
<div style="display:flex;gap:8px">
<div style="position:relative">
<button type="button" onClick={() => { setRequestedSortOpen((prev) => !prev); setRequestedFilterOpen(false); }} style="display:inline-flex;height:32px;align-items:center;gap:6px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 10px;font-size:12px;color:#374151;font-weight:600">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#FF5E13" stroke-width="2"><path d="M7 4v13"/><path d="m3 13 4 4 4-4"/><path d="M17 20V7"/><path d="m21 11-4-4-4 4"/></svg>
Sort
</button>
<Show when={requestedSortOpen()}>
<div style="position:absolute;right:0;top:36px;z-index:20;min-width:170px;border:1px solid #E5E7EB;border-radius:10px;background:white;padding:6px;box-shadow:0 8px 24px rgba(0,0,0,0.12)">
{['Newest First', 'Oldest First'].map((item) => (
<button type="button" onClick={() => { setRequestedSortFilter(item); setRequestedSortOpen(false); }} style={`display:block;width:100%;text-align:left;border:none;background:${requestedSortFilter() === item ? '#FFF1EB' : 'transparent'};color:${requestedSortFilter() === item ? '#FF5E13' : '#374151'};padding:8px 10px;border-radius:8px;font-size:12px;font-weight:600;cursor:pointer`}>
{item}
</button>
))}
</div>
</Show>
</div>
<div style="position:relative">
<button type="button" onClick={() => { setRequestedFilterOpen((prev) => !prev); setRequestedSortOpen(false); }} style="display:inline-flex;height:32px;align-items:center;gap:6px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 10px;font-size:12px;color:#374151;font-weight:600">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#FF5E13" stroke-width="2"><path d="M3 5h18M6 12h12M10 19h4"/></svg>
Filter
</button>
<Show when={requestedFilterOpen()}>
<div style="position:absolute;right:0;top:36px;z-index:20;min-width:220px;border:1px solid #E5E7EB;border-radius:10px;background:white;padding:6px;box-shadow:0 8px 24px rgba(0,0,0,0.12)">
{['All Status', 'Request Sent', 'Contact Unlocked', 'Rejected', 'Expired Refunded', 'Cancelled By Professional'].map((item) => (
<button type="button" onClick={() => { setRequestedStatusFilter(item); setRequestedFilterOpen(false); }} style={`display:block;width:100%;text-align:left;border:none;background:${requestedStatusFilter() === item ? '#FFF1EB' : 'transparent'};color:${requestedStatusFilter() === item ? '#FF5E13' : '#374151'};padding:8px 10px;border-radius:8px;font-size:12px;font-weight:600;cursor:pointer`}>
{item}
</button>
))}
</div>
</Show>
</div>
<button type="button" style="display:inline-flex;height:32px;align-items:center;gap:6px;border-radius:8px;border:none;background:#03004E;padding:0 10px;font-size:12px;font-weight:700;color:white"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>Export</button>
</div>
</div>
<div style="padding:10px 12px;border-bottom:1px solid #E5E7EB;display:flex;align-items:center;gap:8px;flex-wrap:wrap">
<div style="height:32px;min-width:220px;flex:1;border:1px solid #E5E7EB;border-radius:8px;background:#F9FAFB;padding:0 10px;display:flex;align-items:center;gap:8px;font-size:12px;color:#9CA3AF">
<Search size={14} />
<input value={requestedSearch()} onInput={(e) => setRequestedSearch(e.currentTarget.value)} placeholder="Search by lead ID / title / area..." style="border:none;background:transparent;outline:none;width:100%;font-size:12px;color:#111827" />
</div>
<span style="height:24px;padding:0 10px;border-radius:999px;border:1px solid #E5E7EB;background:#F9FAFB;display:inline-flex;align-items:center;font-size:11px;font-weight:700;color:#6B7280">Sort: {requestedSortFilter()}</span>
<span style="height:24px;padding:0 10px;border-radius:999px;border:1px solid #E5E7EB;background:#F9FAFB;display:inline-flex;align-items:center;font-size:11px;font-weight:700;color:#6B7280">Status: {requestedStatusFilter()}</span>
</div>
<div style="max-height:420px;overflow:auto">
<table style="width:100%;border-collapse:collapse">
<thead style="background:#03004E;color:white">
<tr>
{['Lead ID', 'Lead Title', 'Request Date', 'Status', 'Cost', 'Decision Date', 'Action'].map((h) => (
<th style="padding:10px;text-align:left;font-size:10px;letter-spacing:0.06em;text-transform:uppercase">{h}</th>
))}
</tr>
</thead>
<tbody>
<For each={pagedList}>
{(row) => {
const badge = leadStatusPill(row.status);
return (
<tr style="border-top:1px solid #F3F4F6">
<td style="padding:10px;font-size:12px;color:#4B5563;font-weight:700">#{row.id}</td>
<td style="padding:10px">
<p style="margin:0;font-size:14px;font-weight:700;color:#111827">{row.title}</p>
<p style="margin:2px 0 0;font-size:12px;color:#9CA3AF">{row.city}</p>
</td>
<td style="padding:10px;font-size:12px;color:#374151">{row.requestDate}</td>
<td style="padding:10px">
<span style={`display:inline-flex;align-items:center;font-size:12px;font-weight:600;color:${badge.c}`}>{badge.text}</span>
</td>
<td style="padding:10px;font-size:14px;font-weight:700;color:#111827">{leadCostPerContact}</td>
<td style="padding:10px;font-size:12px;color:#6B7280">{row.decisionDate}</td>
<td style="padding:10px">
<div style="display:flex;gap:6px;flex-wrap:wrap">
<button
type="button"
title="View Details"
aria-label="View Details"
onClick={() => openResponseLeadDetails(row.id)}
style="width:30px;height:30px;border-radius:8px;border:1px solid #E5E7EB;background:white;display:inline-flex;align-items:center;justify-content:center;color:#374151"
>
<Eye size={14} />
</button>
<Show when={row.status === 'request_sent'}>
<button
type="button"
title="Cancel Request"
aria-label="Cancel Request"
onClick={() => cancelLeadRequest(row.id)}
style="width:30px;height:30px;border-radius:8px;border:1px solid #E5E7EB;background:white;display:inline-flex;align-items:center;justify-content:center;color:#374151"
>
<X size={14} />
</button>
</Show>
</div>
</td>
</tr>
);
}}
</For>
</tbody>
</table>
</div>
<div style="padding:10px 12px;border-top:1px solid #E5E7EB;display:flex;justify-content:space-between;align-items:center">
<p style="margin:0;font-size:12px;color:#6B7280">
Showing {pagedList.length ? (currentPage - 1) * requestedPerPage + 1 : 0} to {(currentPage - 1) * requestedPerPage + pagedList.length} of {list.length} responses
</p>
<div style="display:flex;gap:6px">
<For each={Array.from({ length: totalPages }, (_, i) => i + 1)}>
{(pageNo) => (
<button
type="button"
onClick={() => setRequestedPage(pageNo)}
style={`width:30px;height:30px;border-radius:8px;border:1px solid #E5E7EB;background:${currentPage === pageNo ? '#FF5E13' : 'white'};color:${currentPage === pageNo ? 'white' : '#6B7280'};font-size:12px;font-weight:700`}
>
{pageNo}
</button>
)}
</For>
</div>
</div>
</div>
</div>
);
}
const list = RESPONSE_ROWS.filter((r) => {
if (tab === 'new') return r.status === 'new';
if (tab === 'shortlisted') return r.status === 'shortlisted';
if (tab === 'rejected') return r.status === 'rejected';
return true;
});
return (
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;box-shadow:0 1px 4px rgba(0,0,0,0.06);display:grid;gap:8px">
<div style="display:flex;align-items:center;justify-content:space-between;gap:8px;padding:10px;border:1px solid #FFE2D3;border-radius:10px;background:#FFF8F4">
<p style="margin:0;font-size:12px;color:#9A3412;line-height:1.4">Before accepting contact request, review portfolio, experience, and quoted charges.</p>
<button
type="button"
onClick={openPortfolioPreviewInline}
style="height:30px;border-radius:8px;border:none;background:#03004E;color:white;padding:0 10px;font-size:12px;font-weight:700;white-space:nowrap"
>
Preview Portfolio
</button>
</div>
<For each={list}>{(row) => {
const chip = statusChip(row.status);
return (
<div style="display:grid;grid-template-columns:2fr 1fr 1fr;gap:8px;padding:10px;border:1px solid #E5E7EB;border-radius:8px;background:#fff">
<div>
<p style="margin:0;font-size:13px;font-weight:700;color:#111827">{row.name}</p>
<p style="margin:2px 0 0;font-size:12px;color:#6B7280">Applied for active requirement</p>
<p style="margin:6px 0 0;font-size:11px;font-weight:700;color:#FF5E13">Experience: 7+ years</p>
</div>
<div style="font-size:18px;font-weight:800;color:#111827">{row.quote}</div>
<div style="display:flex;align-items:center;justify-content:flex-end;gap:8px;flex-wrap:wrap">
<span style={`display:inline-flex;align-items:center;justify-content:center;height:22px;border-radius:999px;padding:0 8px;background:${chip.bg};color:${chip.c};font-size:11px;font-weight:700;text-transform:uppercase`}>{row.status}</span>
<button
type="button"
onClick={openPortfolioPreviewInline}
style="height:30px;border-radius:8px;border:1px solid #E5E7EB;background:white;color:#374151;padding:0 10px;font-size:12px;font-weight:700"
>
View Portfolio
</button>
<button type="button" style="height:30px;border-radius:8px;border:none;background:#0D0D2A;color:white;padding:0 10px;font-size:12px;font-weight:700">View Profile</button>
<button type="button" style="height:30px;border-radius:8px;border:none;background:#FF5E13;color:white;padding:0 10px;font-size:12px;font-weight:700">Accept Contact</button>
</div>
</div>
);
}}</For>
</div>
);
}
if (customerKey() === 'shortlisted responses') {
const list = RESPONSE_ROWS.filter((r) => {
if (tab === 'interview scheduled') return r.status === 'shortlisted';
if (tab === 'finalized') return r.status === 'shortlisted';
return r.status === 'shortlisted';
});
return (
<div style="display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px">
<For each={list}>{(p) => (
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:12px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<p style="margin:0;font-size:13px;font-weight:700;color:#111827">{p.name}</p>
<p style="margin:4px 0 0;font-size:12px;color:#6B7280">High-potential response for active requirement</p>
<p style="margin:8px 0 0;font-size:12px;font-weight:700;color:#FF5E13">Quoted {p.quote}</p>
<div style="display:flex;gap:8px;margin-top:10px">
<button type="button" style="height:30px;border-radius:8px;border:1px solid #E5E7EB;background:#F9FAFB;color:#374151;padding:0 10px;font-size:12px;font-weight:700">View Details</button>
<button type="button" style="height:30px;border-radius:8px;border:none;background:#FF5E13;color:white;padding:0 10px;font-size:12px;font-weight:700">Finalize</button>
</div>
</div>
)}</For>
</div>
);
}
if (customerKey() === 'credits') {
const invoiceRows = [
['#INV-2023-089', 'Oct 14, 2023', 'Enterprise Pack', '₹499.00', 'Paid'],
['#INV-2023-074', 'Sep 14, 2023', 'Enterprise Pack', '₹499.00', 'Paid'],
['#INV-2023-052', 'Aug 14, 2023', 'Growth Starter', '₹135.00', 'Paid'],
['#INV-2023-031', 'Jul 14, 2023', 'Growth Starter', '₹135.00', 'Failed'],
] as const;
const renderCheckout = () => {
const pkg = checkoutPackage();
if (!pkg) return null;
const step = paymentStep();
return (
<div style="display:flex;flex-direction:column;gap:14px">
<div style="display:flex;align-items:center;gap:10px">
<button
type="button"
onClick={() => { setCheckoutPackage(null); setPaymentStep('idle'); }}
style="height:32px;border:1px solid #E5E7EB;background:white;border-radius:8px;padding:0 12px;font-size:12px;font-weight:700;color:#374151;cursor:pointer"
>
Back to Packages
</button>
<h3 style="margin:0;font-size:18px;font-weight:800;color:#111827">Finalize Purchase</h3>
</div>
<div style="display:grid;grid-template-columns:1fr 1.2fr;gap:14px">
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:16px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<p style="margin:0;font-size:11px;text-transform:uppercase;letter-spacing:0.05em;color:#6B7280;font-weight:700">Selected Package</p>
<h2 style="margin:8px 0;font-size:24px;font-weight:800;color:#111827">{pkg.display_name || pkg.name}</h2>
<div style="display:flex;align-items:center;gap:10px;margin-top:12px">
<div style="width:40px;height:40px;border-radius:12px;background:#FFF1EB;border:1px solid #FFD8C2;display:flex;align-items:center;justify-content:center">
<img src="/sidebar-icons/credits.svg" alt="" style={`width:20px;height:20px;object-fit:contain;filter:${ORANGE_ICON_FILTER}`} />
</div>
<div>
<p style="margin:0;font-size:18px;font-weight:800;color:#111827">{(Number(pkg.credits) + Number(pkg.bonus_credits || 0)).toLocaleString()} TC</p>
<p style="margin:0;font-size:12px;color:#6B7280">Total Tracecoins</p>
</div>
</div>
<div style="margin-top:16px;padding-top:16px;border-top:1px solid #F3F4F6">
<div style="display:flex;justify-content:space-between;margin-bottom:8px">
<span style="font-size:13px;color:#6B7280">Base Credits</span>
<span style="font-size:13px;font-weight:700;color:#111827">{Number(pkg.credits).toLocaleString()}</span>
</div>
<Show when={pkg.bonus_credits > 0}>
<div style="display:flex;justify-content:space-between;margin-bottom:8px">
<span style="font-size:13px;color:#6B7280">Bonus Credits</span>
<span style="font-size:13px;font-weight:700;color:#FF5E13">+{Number(pkg.bonus_credits).toLocaleString()}</span>
</div>
</Show>
<div style="display:flex;justify-content:space-between;margin-top:12px;padding-top:12px;border-top:2px solid #F3F4F6">
<span style="font-size:15px;font-weight:800;color:#111827">Total Amount</span>
<span style="font-size:18px;font-weight:800;color:#FF5E13">{(Number(pkg.price_paise) / 100).toLocaleString('en-IN')}</span>
</div>
</div>
</div>
<div style="border:1px solid #D9D8F9;background:#F5F5FF;border-radius:16px;padding:20px;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<Show when={step === 'idle'}>
<div style="width:56px;height:56px;border-radius:999px;background:white;display:flex;align-items:center;justify-content:center;margin-bottom:14px;box-shadow:0 2px 8px rgba(3,0,78,0.1)">
<img src="/sidebar-icons/security.svg" alt="" style={`width:28px;height:28px;object-fit:contain;filter:${BLUE_ICON_FILTER}`} />
</div>
<h3 style="margin:0;font-size:18px;font-weight:800;color:#03004E">Secure Gateway</h3>
<p style="margin:8px 0 20px;font-size:13px;color:#4F4B8A;max-width:240px">Continue to our secure partner gateway to complete the transaction.</p>
<button
type="button"
onClick={() => startPayment(pkg)}
style="height:44px;width:100%;max-width:220px;border:none;border-radius:10px;background:#03004E;color:white;font-size:14px;font-weight:700;cursor:pointer;box-shadow:0 4px 12px rgba(3,0,78,0.2)"
>
Confirm & Pay Now
</button>
</Show>
<Show when={step === 'processing' || step === 'verifying'}>
<div style="width:48px;height:48px;border:4px solid #E5E7EB;border-top-color:#FF5E13;border-radius:50%;animation:spin 1s linear infinite;margin-bottom:16px" />
<style>{`@keyframes spin { to { transform: rotate(360deg); } }`}</style>
<h3 style="margin:0;font-size:18px;font-weight:800;color:#111827">{step === 'processing' ? 'Creating Order...' : 'Verifying Payment...'}</h3>
<p style="margin:6px 0 0;font-size:13px;color:#6B7280">Please do not refresh or close the page.</p>
</Show>
<Show when={step === 'success'}>
<div style="width:64px;height:64px;border-radius:999px;background:#DCFCE7;display:flex;align-items:center;justify-content:center;margin-bottom:16px;border:2px solid #22C55E">
<span style="font-size:32px;color:#15803D"></span>
</div>
<h3 style="margin:0;font-size:22px;font-weight:800;color:#15803D">Payment Successful!</h3>
<p style="margin:8px 0 20px;font-size:13px;color:#15803D;max-width:280px">Your account has been credited with {(Number(pkg.credits) + Number(pkg.bonus_credits || 0)).toLocaleString()} Tracecoins.</p>
<div style="background:white;border:1px solid #DCFCE7;border-radius:12px;padding:12px;width:100%;max-width:260px;margin-bottom:20px">
<p style="margin:0;font-size:11px;color:#6B7280;text-transform:uppercase">New Balance</p>
<p style="margin:4px 0 0;font-size:20px;font-weight:800;color:#111827">{leadCredits().toLocaleString()} TC</p>
</div>
<button
type="button"
onClick={() => { setCheckoutPackage(null); setPaymentStep('idle'); }}
style="height:40px;width:100%;max-width:220px;border:none;border-radius:10px;background:#03004E;color:white;font-size:13px;font-weight:700;cursor:pointer"
>
Back to Dashboard
</button>
</Show>
<Show when={step === 'error'}>
<div style="width:64px;height:64px;border-radius:999px;background:#FEE2E2;display:flex;align-items:center;justify-content:center;margin-bottom:16px;border:2px solid #EF4444">
<span style="font-size:32px;color:#B91C1C"></span>
</div>
<h3 style="margin:0;font-size:20px;font-weight:800;color:#B91C1C">Payment Failed</h3>
<p style="margin:8px 0 20px;font-size:13px;color:#6B7280;max-width:240px">Something went wrong with the mock gateway. Please try again.</p>
<button
type="button"
onClick={() => setPaymentStep('idle')}
style="height:40px;width:100%;max-width:220px;border:none;border-radius:10px;background:#B91C1C;color:white;font-size:13px;font-weight:700;cursor:pointer"
>
Try Again
</button>
</Show>
</div>
</div>
</div>
);
};
const renderCreditManagement = () => {
let amtInput: HTMLInputElement | undefined;
let rsnInput: HTMLInputElement | undefined;
return (
<div style="display:flex;flex-direction:column;gap:14px">
<div style="display:flex;align-items:center;gap:10px">
<button
type="button"
onClick={() => setCreditManageView(false)}
style="height:32px;border:1px solid #E5E7EB;background:white;border-radius:8px;padding:0 12px;font-size:12px;font-weight:700;color:#374151;cursor:pointer"
>
Back
</button>
<h3 style="margin:0;font-size:18px;font-weight:800;color:#111827">Credit Management Console</h3>
</div>
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:20px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<div style="display:flex;align-items:center;gap:12px;margin-bottom:20px;padding-bottom:16px;border-bottom:1px solid #F3F4F6">
<div style="width:48px;height:48px;border-radius:999px;background:#FFF1EB;display:flex;align-items:center;justify-content:center">
<img src="/sidebar-icons/credits.svg" alt="" style={`width:24px;height:24px;object-fit:contain;filter:${ORANGE_ICON_FILTER}`} />
</div>
<div>
<p style="margin:0;font-size:12px;color:#6B7280;text-transform:uppercase;font-weight:700">Current User Balance</p>
<p style="margin:2px 0 0;font-size:24px;font-weight:800;color:#111827">{leadCredits().toLocaleString()} TC</p>
</div>
</div>
<div style="display:grid;grid-template-columns:1fr 2fr 1fr;gap:12px;align-items:flex-end">
<div>
<label style="display:block;font-size:11px;font-weight:700;color:#6B7280;margin-bottom:6px;text-transform:uppercase">Amount (coins)</label>
<input
ref={amtInput}
type="number"
placeholder="e.g. 500 or -200"
style="width:100%;height:38px;border-radius:8px;border:1px solid #E5E7EB;padding:0 12px;font-size:13px;outline:none"
/>
</div>
<div>
<label style="display:block;font-size:11px;font-weight:700;color:#6B7280;margin-bottom:6px;text-transform:uppercase">Reason for adjustment</label>
<input
ref={rsnInput}
type="text"
placeholder="e.g. Compensation for downtime, Referral bonus..."
style="width:100%;height:38px;border-radius:8px;border:1px solid #E5E7EB;padding:0 12px;font-size:13px;outline:none"
/>
</div>
<button
type="button"
onClick={() => {
const amount = Number(amtInput?.value || 0);
const reason = rsnInput?.value || 'Administrative Adjustment';
if (amount === 0) return;
adjustCreditsManually(amount, reason);
if (amtInput) amtInput.value = '';
if (rsnInput) rsnInput.value = '';
}}
style="height:38px;border:none;border-radius:8px;background:#03004E;color:white;font-size:13px;font-weight:700;cursor:pointer"
>
Apply Adjustment
</button>
</div>
<p style="margin:10px 0 0;font-size:11px;color:#6B7280">Note: Adjustments are final and logged in transaction history for auditing.</p>
</div>
</div>
);
};
if (checkoutPackage()) return renderCheckout();
if (creditManageView()) return renderCreditManagement();
if (tab === 'buy credits') {
return (
<div style="display:flex;flex-direction:column;gap:10px">
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;box-shadow:0 1px 4px rgba(0,0,0,0.06);display:flex;align-items:center;justify-content:space-between;gap:12px">
<div>
<p style="margin:0;font-size:11px;text-transform:uppercase;letter-spacing:0.06em;color:#6B7280">Current Balance</p>
<p style="margin:6px 0 0;font-size:22px;font-weight:800;color:#111827;line-height:1">{leadCredits().toLocaleString()} <span style="font-size:14px;color:#64748B;font-weight:700">Tracecoins</span></p>
<p style="margin:6px 0 0;font-size:12px;color:#FF5E13;font-weight:700">+12% from last month</p>
</div>
<div style="display:flex;gap:10px">
<button
type="button"
onClick={() => setCreditManageView(true)}
style="height:36px;border:1px solid #E5E7EB;background:white;border-radius:8px;color:#374151;padding:0 14px;font-size:12px;font-weight:700;white-space:nowrap"
>
Manage Credits
</button>
<button type="button" style="height:36px;border:none;border-radius:8px;background:#03004E;color:white;padding:0 14px;font-size:12px;font-weight:700;white-space:nowrap">Buy Credits</button>
</div>
</div>
<div style="display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px">
<For each={pricingPackagesResource() || []}>
{(pkg) => (
<div style={`border:${pkg.is_popular ? '2px solid #FF5E13' : '1px solid #E5E7EB'};background:white;border-radius:12px;padding:14px;box-shadow:0 1px 3px rgba(0,0,0,0.05);position:relative`}>
<Show when={pkg.is_popular}>
<span style="position:absolute;top:-10px;right:10px;height:20px;padding:0 10px;border-radius:999px;background:#FF5E13;color:white;font-size:10px;font-weight:700;display:inline-flex;align-items:center">MOST POPULAR</span>
</Show>
<div style="width:28px;height:28px;border-radius:999px;background:#FFF1EB;border:1px solid #FFD8C2;display:flex;align-items:center;justify-content:center">
<img src="/sidebar-icons/credits.svg" alt="" style={`width:14px;height:14px;object-fit:contain;filter:${ORANGE_ICON_FILTER}`} />
</div>
<p style="margin:0;font-size:10px;letter-spacing:0.06em;text-transform:uppercase;font-weight:700;color:#9CA3AF">{pkg.name}</p>
<p style="margin:3px 0 0;font-size:20px;font-weight:800;color:#111827;line-height:1.1">{pkg.display_name || pkg.name}</p>
<p style="margin:8px 0 0;font-size:20px;font-weight:800;color:#111827;line-height:1">{Number(pkg.credits).toLocaleString()}</p>
<p style="margin:0;font-size:12px;color:#6B7280">Credits</p>
<Show when={pkg.bonus_credits > 0}>
<p style="margin:8px 0 0;font-size:10px;font-weight:700;color:#FF5E13;background:#FFF1EB;border:1px solid #FFD8C2;height:20px;padding:0 8px;border-radius:999px;display:inline-flex;align-items:center">+{pkg.bonus_credits} bonus</p>
</Show>
<p style="margin:10px 0 0;font-size:20px;font-weight:800;color:#111827;line-height:1">{(Number(pkg.price_paise) / 100).toLocaleString('en-IN')}</p>
<button
type="button"
onClick={() => setCheckoutPackage(pkg)}
style={`margin-top:10px;height:32px;width:100%;border:none;border-radius:8px;background:${pkg.is_popular ? '#FF5E13' : '#03004E'};color:white;font-size:12px;font-weight:700;cursor:pointer`}
>
Buy Package
</button>
</div>
)}
</For>
</div>
<div style="display:grid;grid-template-columns:2fr 1fr;gap:10px">
<div style="border:1px solid #E5E7EB;background:white;border-radius:12px;padding:12px;box-shadow:0 1px 3px rgba(0,0,0,0.05)">
<p style="margin:0;font-size:13px;font-weight:700;color:#111827">Why buy larger packs?</p>
<div style="display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;margin-top:8px">
<div style="border:1px solid #E5E7EB;border-radius:10px;padding:10px;background:#F9FAFB">
<p style="margin:0;font-size:12px;font-weight:700;color:#111827">More savings</p>
<p style="margin:4px 0 0;font-size:11px;color:#6B7280">Higher packs include bonus credits.</p>
</div>
<div style="border:1px solid #E5E7EB;border-radius:10px;padding:10px;background:#F9FAFB">
<p style="margin:0;font-size:12px;font-weight:700;color:#111827">No expiry</p>
<p style="margin:4px 0 0;font-size:11px;color:#6B7280">Credits stay active with your account.</p>
</div>
<div style="border:1px solid #E5E7EB;border-radius:10px;padding:10px;background:#F9FAFB">
<p style="margin:0;font-size:12px;font-weight:700;color:#111827">Instant activation</p>
<p style="margin:4px 0 0;font-size:11px;color:#6B7280">Credits reflect right after purchase.</p>
</div>
</div>
</div>
<div style="border:1px solid #E5E7EB;background:#03004E;border-radius:12px;padding:12px;color:white;box-shadow:0 1px 3px rgba(0,0,0,0.05)">
<p style="margin:0;font-size:11px;letter-spacing:0.06em;text-transform:uppercase;color:#C7D2FE">Recommended</p>
<p style="margin:6px 0 0;font-size:20px;font-weight:800;line-height:1.2">Start with Standard</p>
<p style="margin:6px 0 0;font-size:12px;color:#D7DBFF;line-height:1.45">Best value for active buying and response unlocks.</p>
<button type="button" style="margin-top:10px;height:32px;border:none;border-radius:8px;background:#FF5E13;color:white;padding:0 12px;font-size:12px;font-weight:700;width:100%">Buy Standard</button>
</div>
</div>
</div>
);
}
if (tab === 'transactions') {
return (
<div style="display:flex;flex-direction:column;gap:10px">
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;box-shadow:0 1px 4px rgba(0,0,0,0.06);overflow:hidden">
<div style="padding:12px;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid #E5E7EB;background:#F9FAFB">
<div style="display:flex;align-items:center;gap:8px;flex:1">
<input value="" readOnly placeholder="Search transactions..." style="height:34px;min-width:220px;flex:1;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 12px;font-size:12px;color:#6B7280;outline:none" />
<button type="button" style="display:inline-flex;height:34px;align-items:center;gap:6px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 12px;font-size:12px;font-weight:500;color:#374151">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#FF5E13" stroke-width="2"><path d="M7 4v13"/><path d="m3 13 4 4 4-4"/><path d="M17 20V7"/><path d="m21 11-4-4-4 4"/></svg>
Sort
</button>
<button type="button" style="display:inline-flex;height:34px;align-items:center;gap:6px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 12px;font-size:12px;font-weight:500;color:#374151">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#FF5E13" stroke-width="2"><path d="M3 5h18M6 12h12M10 19h4"/></svg>
Filters
</button>
</div>
<button type="button" style="display:inline-flex;align-items:center;gap:6px;height:34px;border:none;border-radius:8px;background:#0D0D2A;color:white;padding:0 12px;font-size:12px;font-weight:600">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#FF5E13" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
Export
</button>
</div>
<table style="width:100%;border-collapse:collapse">
<thead style="background:#03004E;color:white">
<tr>
{['Invoice No', 'Package', 'Credits', 'Amount Paid', 'Status', 'Date', 'Actions'].map((h) => (
<th style="padding:10px;font-size:11px;text-align:left;letter-spacing:0.04em;text-transform:uppercase">{h}</th>
))}
</tr>
</thead>
<tbody>
{txRows().map((row) => (
<tr style="border-bottom:1px solid #E5E7EB">
<td style="padding:10px;font-size:12px;font-weight:700;color:#374151">{row[0]}</td>
<td style="padding:10px;font-size:12px;color:#111827">{row[1]}</td>
<td style="padding:10px;font-size:12px;color:#111827">{row[2]}</td>
<td style="padding:10px;font-size:12px;font-weight:700;color:#111827">{row[3]}</td>
<td style="padding:10px;font-size:12px">
<span style={`display:inline-flex;height:22px;padding:0 10px;border-radius:999px;font-size:11px;font-weight:700;align-items:center;background:${row[4] === 'Completed' ? '#FFF3EE' : row[4] === 'Pending' ? '#EEF2FF' : '#F3F4F6'};color:${row[4] === 'Completed' ? '#FF5E13' : row[4] === 'Pending' ? '#03004E' : '#6B7280'}`}>{row[4]}</span>
</td>
<td style="padding:10px;font-size:12px;color:#64748B">{row[5]}</td>
<td style="padding:10px">
<button type="button" style="display:inline-flex;align-items:center;gap:6px;height:28px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 10px;font-size:11px;font-weight:700;color:#374151">
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="#FF5E13" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
Download
</button>
</td>
</tr>
))}
</tbody>
</table>
<div style="padding:10px;display:flex;align-items:center;justify-content:space-between">
<p style="margin:0;font-size:12px;color:#64748B">Showing 1 to 4 of 42 transactions</p>
<div style="display:flex;gap:6px">
{[1, 2, 3].map((p) => (
<button type="button" style={`width:30px;height:30px;border-radius:8px;border:1px solid #E5E7EB;background:${p === 1 ? '#FF5E13' : '#fff'};color:${p === 1 ? 'white' : '#6B7280'};font-size:12px;font-weight:700`}>{p}</button>
))}
</div>
</div>
</div>
</div>
);
}
if (tab === 'usage history') {
return (
<div style="display:flex;flex-direction:column;gap:10px">
<div style="display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px">
<div style="border:1px solid #E5E7EB;background:white;border-radius:12px;padding:12px;box-shadow:0 1px 3px rgba(0,0,0,0.05)"><div style="display:flex;align-items:center;gap:6px"><img src="/sidebar-icons/report.svg" alt="" style={`width:14px;height:14px;object-fit:contain;filter:${ORANGE_ICON_FILTER}`} /><p style="margin:0;font-size:11px;color:#6B7280;text-transform:uppercase">Total Used (30d)</p></div><p style="margin:8px 0 0;font-size:20px;font-weight:800;color:#111827">12,480</p></div>
<div style="border:1px solid #E5E7EB;background:white;border-radius:12px;padding:12px;box-shadow:0 1px 3px rgba(0,0,0,0.05)"><div style="display:flex;align-items:center;gap:6px"><img src="/sidebar-icons/leads.svg" alt="" style={`width:14px;height:14px;object-fit:contain;filter:${ORANGE_ICON_FILTER}`} /><p style="margin:0;font-size:11px;color:#6B7280;text-transform:uppercase">Most Used Action</p></div><p style="margin:8px 0 0;font-size:18px;font-weight:800;color:#111827">Boost Profile</p></div>
<div style="border:1px solid #E5E7EB;background:white;border-radius:12px;padding:12px;box-shadow:0 1px 3px rgba(0,0,0,0.05)"><div style="display:flex;align-items:center;gap:6px"><img src="/sidebar-icons/credits.svg" alt="" style={`width:14px;height:14px;object-fit:contain;filter:${ORANGE_ICON_FILTER}`} /><p style="margin:0;font-size:11px;color:#6B7280;text-transform:uppercase">Current Balance</p></div><p style="margin:8px 0 0;font-size:20px;font-weight:800;color:#111827">12,450 TC</p></div>
</div>
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;box-shadow:0 1px 4px rgba(0,0,0,0.06);overflow:hidden">
<div style="padding:12px;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid #E5E7EB;background:#F9FAFB">
<div style="display:flex;align-items:center;gap:8px;flex:1">
<input value="" readOnly placeholder="Search usage history..." style="height:34px;min-width:220px;flex:1;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 12px;font-size:12px;color:#6B7280;outline:none" />
<button type="button" style="display:inline-flex;height:34px;align-items:center;gap:6px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 12px;font-size:12px;font-weight:500;color:#374151">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#FF5E13" stroke-width="2"><path d="M7 4v13"/><path d="m3 13 4 4 4-4"/><path d="M17 20V7"/><path d="m21 11-4-4-4 4"/></svg>
Sort
</button>
<button type="button" style="display:inline-flex;height:34px;align-items:center;gap:6px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 12px;font-size:12px;font-weight:500;color:#374151">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#FF5E13" stroke-width="2"><path d="M3 5h18M6 12h12M10 19h4"/></svg>
Filters
</button>
</div>
<button type="button" style="display:inline-flex;align-items:center;gap:6px;height:34px;border:none;border-radius:8px;background:#0D0D2A;color:white;padding:0 12px;font-size:12px;font-weight:600">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#FF5E13" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
Export
</button>
</div>
<table style="width:100%;border-collapse:collapse">
<thead style="background:#03004E;color:white">
<tr>
{['Usage ID', 'Action Type', 'Credits Used', 'Related ID', 'Date', 'Remarks'].map((h) => (
<th style="padding:10px;font-size:11px;text-align:left;letter-spacing:0.04em;text-transform:uppercase">{h}</th>
))}
</tr>
</thead>
<tbody>
{[
['#US-99421', 'Unlock Contact', '-5.00', 'CONT-2034', 'Oct 24, 2023', 'Direct profile unlock for enterprise tier'],
['#US-99418', 'Boost Profile', '-25.00', 'PROF-8812', 'Oct 23, 2023', 'Featured placement (7 days)'],
['#US-99405', 'Batch Export', '-150.00', 'EXP-0044', 'Oct 22, 2023', 'Export of 300 leads'],
['#US-99388', 'Unlock Contact', '-5.00', 'CONT-1992', 'Oct 21, 2023', 'Individual unlock action'],
].map((row) => (
<tr style="border-bottom:1px solid #E5E7EB">
<td style="padding:10px;font-size:12px;font-weight:700;color:#64748B">{row[0]}</td>
<td style="padding:10px;font-size:12px;color:#111827">{row[1]}</td>
<td style="padding:10px;font-size:12px;font-weight:700;color:#03004E">{row[2]}</td>
<td style="padding:10px;font-size:12px;color:#64748B">{row[3]}</td>
<td style="padding:10px;font-size:12px;color:#64748B">{row[4]}</td>
<td style="padding:10px;font-size:12px;color:#64748B">{row[5]}</td>
</tr>
))}
</tbody>
</table>
<div style="padding:10px;display:flex;justify-content:space-between;align-items:center;border-top:1px solid #E5E7EB">
<p style="margin:0;font-size:12px;color:#64748B">Showing 1 to 4 of 142 results</p>
<div style="display:flex;gap:6px">
{[1, 2, 3].map((p) => (
<button type="button" style={`width:30px;height:30px;border-radius:8px;border:1px solid #E5E7EB;background:${p === 1 ? '#03004E' : '#fff'};color:${p === 1 ? 'white' : '#6B7280'};font-size:12px;font-weight:700`}>{p}</button>
))}
</div>
</div>
</div>
</div>
);
}
if (tab === 'invoices') {
return (
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;box-shadow:0 1px 4px rgba(0,0,0,0.06);overflow:hidden">
<div style="padding:12px;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid #E5E7EB;background:#F9FAFB">
<div style="display:flex;align-items:center;gap:8px;flex:1">
<input value="" readOnly placeholder="Search invoices..." style="height:34px;min-width:220px;flex:1;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 12px;font-size:12px;color:#6B7280;outline:none" />
<button type="button" style="display:inline-flex;height:34px;align-items:center;gap:6px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 12px;font-size:12px;font-weight:500;color:#374151">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#FF5E13" stroke-width="2"><path d="M7 4v13"/><path d="m3 13 4 4 4-4"/><path d="M17 20V7"/><path d="m21 11-4-4-4 4"/></svg>
Sort
</button>
<button type="button" style="display:inline-flex;height:34px;align-items:center;gap:6px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 12px;font-size:12px;font-weight:500;color:#374151">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#FF5E13" stroke-width="2"><path d="M3 5h18M6 12h12M10 19h4"/></svg>
Filters
</button>
</div>
<button type="button" style="display:inline-flex;align-items:center;gap:6px;height:34px;border:none;border-radius:8px;background:#0D0D2A;color:white;padding:0 12px;font-size:12px;font-weight:600">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#FF5E13" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
Export
</button>
</div>
<table style="width:100%;border-collapse:collapse">
<thead style="background:#03004E;color:white">
<tr>
{['Invoice Number', 'Billing Date', 'Package', 'Total', 'Status'].map((h) => (
<th style="padding:10px;font-size:11px;text-align:left;letter-spacing:0.04em;text-transform:uppercase">{h}</th>
))}
</tr>
</thead>
<tbody>
{invoiceRows.map((row) => (
<tr style="border-bottom:1px solid #E5E7EB">
<td style="padding:10px;font-size:12px;font-weight:700;color:#111827">{row[0]}</td>
<td style="padding:10px;font-size:12px;color:#6B7280">{row[1]}</td>
<td style="padding:10px;font-size:12px;color:#111827">{row[2]}</td>
<td style="padding:10px;font-size:12px;font-weight:700;color:#111827">{row[3]}</td>
<td style="padding:10px;font-size:12px">
<span style={`display:inline-flex;height:22px;padding:0 10px;border-radius:999px;font-size:11px;font-weight:700;align-items:center;background:${row[4] === 'Paid' ? '#FFF3EE' : '#F3F4F6'};color:${row[4] === 'Paid' ? '#FF5E13' : '#6B7280'}`}>{row[4]}</span>
</td>
</tr>
))}
</tbody>
</table>
<div style="padding:10px;display:flex;justify-content:space-between;align-items:center;border-top:1px solid #E5E7EB">
<p style="margin:0;font-size:12px;color:#64748B">Showing 1 to 4 of 24 invoices</p>
<div style="display:flex;gap:6px">
{[1, 2, 3].map((p) => (
<button type="button" style={`width:30px;height:30px;border-radius:8px;border:1px solid #E5E7EB;background:${p === 1 ? '#03004E' : '#fff'};color:${p === 1 ? 'white' : '#6B7280'};font-size:12px;font-weight:700`}>{p}</button>
))}
</div>
</div>
</div>
);
}
return (
<div style="display:flex;flex-direction:column;gap:10px">
<div style="display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px">
<div style="border:1px solid #E5E7EB;background:white;border-radius:12px;padding:12px;box-shadow:0 1px 3px rgba(0,0,0,0.05)">
<div style="display:flex;align-items:center;gap:6px">
<img src="/sidebar-icons/credits.svg" alt="" style={`width:14px;height:14px;object-fit:contain;filter:${ORANGE_ICON_FILTER}`} />
<p style="margin:0;font-size:11px;color:#6B7280;text-transform:uppercase">Current Balance</p>
</div>
<p style="margin:8px 0 0;font-size:26px;font-weight:800;color:#111827">12,450 TC</p>
<p style="margin:4px 0 0;font-size:12px;color:#FF5E13;font-weight:700">+12% from last month</p>
</div>
<div style="border:1px solid #E5E7EB;background:white;border-radius:12px;padding:12px;box-shadow:0 1px 3px rgba(0,0,0,0.05)">
<div style="display:flex;align-items:center;gap:6px">
<img src="/sidebar-icons/report.svg" alt="" style={`width:14px;height:14px;object-fit:contain;filter:${ORANGE_ICON_FILTER}`} />
<p style="margin:0;font-size:11px;color:#6B7280;text-transform:uppercase">Monthly Usage</p>
</div>
<p style="margin:8px 0 0;font-size:26px;font-weight:800;color:#111827">1,248</p>
<p style="margin:4px 0 0;font-size:12px;color:#6B7280">Avg 42/day</p>
</div>
<div style="border:1px solid #E5E7EB;background:white;border-radius:12px;padding:12px;box-shadow:0 1px 3px rgba(0,0,0,0.05)">
<div style="display:flex;align-items:center;gap:6px">
<img src="/sidebar-icons/approval.svg" alt="" style={`width:14px;height:14px;object-fit:contain;filter:${ORANGE_ICON_FILTER}`} />
<p style="margin:0;font-size:11px;color:#6B7280;text-transform:uppercase">Pending Invoices</p>
</div>
<p style="margin:8px 0 0;font-size:26px;font-weight:800;color:#111827">1</p>
<button type="button" style="margin-top:8px;height:30px;border:none;border-radius:8px;background:#03004E;color:white;padding:0 10px;font-size:12px;font-weight:700">Buy Credits</button>
</div>
</div>
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;box-shadow:0 1px 4px rgba(0,0,0,0.06);overflow:hidden">
<div style="padding:10px 12px;background:#F9FAFB;border-bottom:1px solid #E5E7EB;display:flex;justify-content:space-between;align-items:center">
<p style="margin:0;font-size:14px;font-weight:700;color:#111827">Recent Transactions</p>
<button type="button" style="height:30px;border:none;border-radius:8px;background:#03004E;color:white;padding:0 10px;font-size:12px;font-weight:700">Buy Credits</button>
</div>
<div style="padding:12px;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid #E5E7EB;background:#F9FAFB">
<div style="display:flex;align-items:center;gap:8px;flex:1">
<input value="" readOnly placeholder="Search transactions..." style="height:34px;min-width:220px;flex:1;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 12px;font-size:12px;color:#6B7280;outline:none" />
<button type="button" style="display:inline-flex;height:34px;align-items:center;gap:6px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 12px;font-size:12px;font-weight:500;color:#374151">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#FF5E13" stroke-width="2"><path d="M7 4v13"/><path d="m3 13 4 4 4-4"/><path d="M17 20V7"/><path d="m21 11-4-4-4 4"/></svg>
Sort
</button>
<button type="button" style="display:inline-flex;height:34px;align-items:center;gap:6px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 12px;font-size:12px;font-weight:500;color:#374151">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#FF5E13" stroke-width="2"><path d="M3 5h18M6 12h12M10 19h4"/></svg>
Filters
</button>
</div>
<button type="button" style="display:inline-flex;align-items:center;gap:6px;height:34px;border:none;border-radius:8px;background:#0D0D2A;color:white;padding:0 12px;font-size:12px;font-weight:600">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#FF5E13" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
Export
</button>
</div>
<table style="width:100%;border-collapse:collapse">
<thead style="background:#03004E;color:white">
<tr>
{['Transaction ID', 'Package', 'Credits', 'Amount Paid', 'Status', 'Date'].map((h) => (
<th style="padding:10px;font-size:11px;text-align:left;letter-spacing:0.04em;text-transform:uppercase">{h}</th>
))}
</tr>
</thead>
<tbody>
{txRows().slice(0, 3).map((row: any) => (
<tr style="border-bottom:1px solid #E5E7EB">
<td style="padding:10px;font-size:12px;font-weight:700;color:#374151">{row[0]}</td>
<td style="padding:10px;font-size:12px;color:#111827">{row[1]}</td>
<td style="padding:10px;font-size:12px;color:#111827">{row[2]}</td>
<td style="padding:10px;font-size:12px;font-weight:700;color:#111827">{row[3]}</td>
<td style="padding:10px;font-size:12px">
<span style={`display:inline-flex;height:22px;padding:0 10px;border-radius:999px;font-size:11px;font-weight:700;align-items:center;background:${row[4] === 'Completed' ? '#FFF3EE' : row[4] === 'Pending' ? '#EEF2FF' : '#F3F4F6'};color:${row[4] === 'Completed' ? '#FF5E13' : row[4] === 'Pending' ? '#03004E' : '#6B7280'}`}>{row[4]}</span>
</td>
<td style="padding:10px;font-size:12px;color:#64748B">{row[5]}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
);
}
if (customerKey() === 'explore nxtgauge') {
return (
<div style="display:flex;flex-direction:column;gap:12px">
<div style="border:1px solid #E5E7EB;border-radius:16px;background:white;box-shadow:0 1px 4px rgba(0,0,0,0.06);padding:20px">
<p style="margin:0;font-size:34px;line-height:1.12;font-weight:800;color:#111827;max-width:760px">Explore opportunities on Nxtgauge</p>
<p style="margin:10px 0 0;font-size:14px;line-height:1.5;max-width:760px;color:#6B7280">Discover services, connect with verified users, and expand into additional roles using the same dashboard workflow.</p>
</div>
<div style="display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px">
{[
{ key: 'COMPANY', title: 'Company', icon: '/sidebar-icons/users.svg', subtitle: 'Hire talent, post jobs, and manage applications in one path.' },
{ key: 'JOB_SEEKER', title: 'Job Seeker', icon: '/sidebar-icons/company.svg', subtitle: 'Explore opportunities and apply to roles with your profile.' },
{ key: 'SERVICE_SEEKER', title: 'Service Seeker', icon: '/sidebar-icons/candidate.svg', subtitle: 'Post requirements and connect with verified professionals.' },
].map((roleCard) => {
const activeRoles = userRoles();
const isRegistered = activeRoles.some((ar) => normalizeRoleKey(ar.role_key || ar.key) === normalizeRoleKey(roleCard.key));
const isCurrentRole = normalizeRoleKey(props.roleKey || '') === normalizeRoleKey(roleCard.key);
return (
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;box-shadow:0 1px 4px rgba(0,0,0,0.06);display:flex;flex-direction:column;gap:8px">
<img src={roleCard.icon} alt="" style={`width:20px;height:20px;object-fit:contain;filter:${ORANGE_ICON_FILTER}`} />
<p style="margin:0;font-size:18px;font-weight:800;color:#111827">{roleCard.title}</p>
<p style="margin:0;font-size:12px;line-height:1.5;color:#6B7280">{roleCard.subtitle}</p>
<button
type="button"
onClick={() => isCurrentRole ? null : isRegistered ? switchRole(roleCard.key) : registerRole(roleCard.key)}
style={`margin-top:auto;height:32px;border-radius:8px;border:none;background:${isCurrentRole ? '#E5E7EB' : '#03004E'};color:${isCurrentRole ? '#4B5563' : 'white'};padding:0 10px;font-size:12px;font-weight:700`}
>
{isCurrentRole ? 'Current Role' : isRegistered ? 'Switch' : `Register as ${roleCard.title}`}
</button>
</div>
);
})}
</div>
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<p style="margin:0;font-size:30px;font-weight:800;color:#111827">Professional Services</p>
<p style="margin:6px 0 0;font-size:13px;color:#6B7280">Choose from 10 professional roles, including UGC Content Creator.</p>
<div style="display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:10px;margin-top:12px">
<For each={exploreRoleCards()}>
{(role) => (
<div style="border:1px solid #E5E7EB;border-radius:12px;background:white;padding:12px;display:flex;flex-direction:column;min-height:174px">
<div style="display:flex;align-items:center;justify-content:space-between">
<Show
when={role.iconAsset}
fallback={<role.Icon size={18} color="#FF5E13" strokeWidth={2.2} />}
>
<img src={role.iconAsset} alt="" style={`width:18px;height:18px;object-fit:contain;filter:${ORANGE_ICON_FILTER}`} />
</Show>
<span style={`display:inline-flex;align-items:center;height:20px;padding:0 8px;border-radius:999px;font-size:10px;font-weight:700;border:1px solid ${role.status === 'Registered' ? '#D1D5DB' : '#FFD8C2'};background:${role.status === 'Registered' ? '#F3F4F6' : '#FFF1EB'};color:${role.status === 'Registered' ? '#4B5563' : '#FF5E13'}`}>{role.status}</span>
</div>
<p style="margin:10px 0 0;font-size:18px;font-weight:800;color:#111827;line-height:1.2">{role.title}</p>
<p style="margin:6px 0 0;font-size:12px;line-height:1.45;color:#6B7280">{role.subtitle}</p>
<button
type="button"
onClick={() => role.action === 'Active' ? null : role.action === 'Switch' ? switchRole(role.key) : registerRole(role.key)}
style={`margin-top:auto;height:32px;border-radius:8px;border:none;background:${role.action === 'Register' ? '#03004E' : '#E5E7EB'};color:${role.action === 'Register' ? 'white' : '#4B5563'};padding:0 10px;font-size:12px;font-weight:700`}
>
{role.action}
</button>
</div>
)}
</For>
</div>
</div>
<div style="border:1px solid #E5E7EB;background:linear-gradient(180deg,#FFFFFF 0%,#FFFAF7 100%);border-radius:20px;padding:18px;box-shadow:0 8px 20px rgba(15,23,42,0.06)">
<p style="margin:0;font-size:12px;letter-spacing:0.08em;text-transform:uppercase;font-weight:700;color:#FF5E13;text-align:center">Growth Advantage</p>
<p style="margin:4px 0 0;font-size:32px;font-weight:800;color:#111827;text-align:center;line-height:1.1">Why Add More Services?</p>
<p style="margin:8px auto 0;font-size:13px;line-height:1.5;color:#6B7280;text-align:center;max-width:760px">A multi-service profile helps you acquire more opportunities, improve trust, and scale consistently on a single platform.</p>
<div style="margin-top:14px;display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px">
<div style="border:1px solid #E5E7EB;background:white;border-radius:14px;padding:14px;box-shadow:0 2px 6px rgba(0,0,0,0.05)">
<div style="width:34px;height:34px;border-radius:999px;background:#FFF3EE;display:flex;align-items:center;justify-content:center"><img src="/sidebar-icons/leads.svg" alt="" style={`width:16px;height:16px;object-fit:contain;filter:${ORANGE_ICON_FILTER}`} /></div>
<p style="margin:10px 0 0;font-size:15px;font-weight:800;color:#111827">Reach More Buyers</p>
<p style="margin:6px 0 0;font-size:12px;color:#6B7280;line-height:1.45">Get discovered by customers across multiple demand categories.</p>
</div>
<div style="border:1px solid #E5E7EB;background:white;border-radius:14px;padding:14px;box-shadow:0 2px 6px rgba(0,0,0,0.05)">
<div style="width:34px;height:34px;border-radius:999px;background:#FFF3EE;display:flex;align-items:center;justify-content:center"><img src="/sidebar-icons/pricing.svg" alt="" style={`width:16px;height:16px;object-fit:contain;filter:${ORANGE_ICON_FILTER}`} /></div>
<p style="margin:10px 0 0;font-size:15px;font-weight:800;color:#111827">Increase Revenue Paths</p>
<p style="margin:6px 0 0;font-size:12px;color:#6B7280;line-height:1.45">Offer additional services and create new income streams.</p>
</div>
<div style="border:1px solid #E5E7EB;background:white;border-radius:14px;padding:14px;box-shadow:0 2px 6px rgba(0,0,0,0.05)">
<div style="width:34px;height:34px;border-radius:999px;background:#FFF3EE;display:flex;align-items:center;justify-content:center"><img src="/sidebar-icons/approval.svg" alt="" style={`width:16px;height:16px;object-fit:contain;filter:${ORANGE_ICON_FILTER}`} /></div>
<p style="margin:10px 0 0;font-size:15px;font-weight:800;color:#111827">Strengthen Credibility</p>
<p style="margin:6px 0 0;font-size:12px;color:#6B7280;line-height:1.45">Verified multi-service profiles build confidence and improve conversion.</p>
</div>
<div style="border:1px solid #E5E7EB;background:white;border-radius:14px;padding:14px;box-shadow:0 2px 6px rgba(0,0,0,0.05)">
<div style="width:34px;height:34px;border-radius:999px;background:#FFF3EE;display:flex;align-items:center;justify-content:center"><img src="/sidebar-icons/report.svg" alt="" style={`width:16px;height:16px;object-fit:contain;filter:${ORANGE_ICON_FILTER}`} /></div>
<p style="margin:10px 0 0;font-size:15px;font-weight:800;color:#111827">Scale Faster</p>
<p style="margin:6px 0 0;font-size:12px;color:#6B7280;line-height:1.45">Grow your business from one unified account and workflow.</p>
</div>
</div>
</div>
</div>
);
}
if (customerKey() === 'verification') {
if (tab === 'approval status') {
return (
<div style="display:flex;flex-direction:column;gap:12px">
<div style="border:1px solid #E5E7EB;background:white;border-radius:14px;padding:14px">
<p style="margin:0;font-size:22px;font-weight:800;color:#111827">Verification Center</p>
<p style="margin:6px 0 0;font-size:13px;color:#6B7280;line-height:1.5">Complete just 2 steps. Submit profile and portfolio. We review and unlock access.</p>
<div style="display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;margin-top:10px">
<div style="border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB;padding:10px">
<p style="margin:0;font-size:10px;letter-spacing:0.06em;text-transform:uppercase;color:#9CA3AF">Step 1</p>
<p style="margin:8px 0 0;font-size:13px;font-weight:800;color:#111827">Profile: {approvalTone(profileApprovalState()).label}</p>
</div>
<div style="border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB;padding:10px">
<p style="margin:0;font-size:10px;letter-spacing:0.06em;text-transform:uppercase;color:#9CA3AF">Step 2</p>
<p style="margin:8px 0 0;font-size:13px;font-weight:800;color:#111827">Portfolio: {approvalTone(portfolioApprovalState()).label}</p>
</div>
<div style="border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB;padding:10px">
<p style="margin:0;font-size:10px;letter-spacing:0.06em;text-transform:uppercase;color:#9CA3AF">Final Access</p>
<p style="margin:8px 0 0;font-size:13px;font-weight:800;color:#111827">{bothApprovalsApproved() ? 'Unlocked' : 'Blocked'}</p>
</div>
</div>
</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px">
<div style="border:1px solid #E5E7EB;background:white;border-radius:14px;padding:14px">
<p style="margin:0;font-size:18px;font-weight:800;color:#111827">Profile Verification</p>
<p style="margin:6px 0 0;font-size:12px;color:#6B7280">Finish your basic information and required documents, then submit.</p>
<div style="display:flex;gap:8px;justify-content:flex-end;margin-top:10px">
<button type="button" onClick={() => { props.onSidebarSelect('My Profile'); props.onTabSelect('basic information'); }} style="height:32px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 12px;font-size:12px;font-weight:700;color:#374151">Open My Profile</button>
<button type="button" onClick={submitProfileForApproval} disabled={profileApprovalState() === 'IN_REVIEW'} style={`height:32px;border-radius:8px;border:none;background:${profileApprovalState() === 'IN_REVIEW' ? '#9CA3AF' : '#03004E'};color:white;padding:0 12px;font-size:12px;font-weight:700`}>Submit Profile</button>
</div>
</div>
<div style="border:1px solid #E5E7EB;background:white;border-radius:14px;padding:14px">
<p style="margin:0;font-size:18px;font-weight:800;color:#111827">Portfolio Verification</p>
<p style="margin:6px 0 0;font-size:12px;color:#6B7280">Add portfolio details and submit separately for review.</p>
<div style="display:flex;gap:8px;justify-content:flex-end;margin-top:10px">
<button type="button" onClick={() => { props.onSidebarSelect('My Portfolio'); props.onTabSelect('about'); }} style="height:32px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 12px;font-size:12px;font-weight:700;color:#374151">Open My Portfolio</button>
<button type="button" onClick={submitPortfolioForApproval} disabled={portfolioApprovalState() === 'IN_REVIEW'} style={`height:32px;border-radius:8px;border:none;background:${portfolioApprovalState() === 'IN_REVIEW' ? '#9CA3AF' : '#03004E'};color:white;padding:0 12px;font-size:12px;font-weight:700`}>Submit Portfolio</button>
</div>
</div>
</div>
<div style="border:1px solid #E5E7EB;background:#F9FAFB;border-radius:12px;padding:12px">
<p style="margin:0;font-size:12px;color:#374151;line-height:1.5"><strong>Admin Flow:</strong> once submitted, both items appear in Verification Management. Admin can request documents or approve. Leads remain blocked until both are approved.</p>
</div>
</div>
);
}
if (tab === 'submitted details') {
return (
<div style="display:grid;grid-template-columns:1fr 1.5fr;gap:12px">
<div style="border:1px solid #E5E7EB;background:white;border-radius:14px;padding:14px">
<p style="margin:0;font-size:20px;font-weight:800;color:#111827">Application Snapshot</p>
<div style="display:grid;gap:8px;margin-top:10px">
{[
['Service', 'Social Media Manager'],
['Submission ID', 'VRF-2023-1042'],
['Submitted On', 'Oct 22, 2023'],
['Status', 'Under Review'],
].map(([k, v]) => (
<div style="padding:10px;border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB;font-size:12px;color:#374151"><strong>{k}:</strong> {v}</div>
))}
</div>
</div>
<div style="border:1px solid #E5E7EB;background:white;border-radius:14px;padding:14px">
<p style="margin:0;font-size:20px;font-weight:800;color:#111827">Submitted Details</p>
<div style="margin-top:10px;padding:10px;border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB;font-size:12px;line-height:1.6;color:#374151">
Strategic Social Media Manager with 6+ years of experience in content strategy, campaign planning, and audience growth for D2C brands.
</div>
<div style="display:flex;gap:6px;flex-wrap:wrap;margin-top:10px">
{['Sprout Social', 'Figma', 'Google Analytics'].map((tool) => <span style="height:24px;padding:0 10px;border-radius:999px;border:1px solid #E5E7EB;background:white;display:inline-flex;align-items:center;font-size:11px;color:#374151">{tool}</span>)}
</div>
</div>
</div>
);
}
if (tab === 'documents') {
return (
<div style="display:grid;gap:12px">
<div style="display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px">
<div style="border:1px solid #E5E7EB;background:white;border-radius:12px;padding:12px">
<p style="margin:0;font-size:10px;letter-spacing:0.06em;text-transform:uppercase;color:#9CA3AF">Total Documents</p>
<p style="margin:6px 0 0;font-size:22px;font-weight:800;color:#111827">3</p>
</div>
<div style="border:1px solid #E5E7EB;background:white;border-radius:12px;padding:12px">
<p style="margin:0;font-size:10px;letter-spacing:0.06em;text-transform:uppercase;color:#9CA3AF">Approved</p>
<p style="margin:6px 0 0;font-size:22px;font-weight:800;color:#03004E">2</p>
</div>
<div style="border:1px solid #FFE2D3;background:#FFF8F4;border-radius:12px;padding:12px">
<p style="margin:0;font-size:10px;letter-spacing:0.06em;text-transform:uppercase;color:#9CA3AF">Needs Action</p>
<p style="margin:6px 0 0;font-size:22px;font-weight:800;color:#FF5E13">1</p>
</div>
</div>
<div style="border:1px solid #FFE2D3;border-radius:12px;background:#FFF8F4;padding:12px;display:flex;align-items:center;justify-content:space-between;gap:10px">
<div>
<p style="margin:0;font-size:12px;font-weight:800;color:#111827">Admin requested missing documents</p>
<p style="margin:4px 0 0;font-size:12px;color:#374151">Required Missing Documents: Address Proof (clear PDF/JPG/PNG).</p>
</div>
<button type="button" style="height:32px;border:none;border-radius:8px;background:#03004E;color:white;padding:0 12px;font-size:12px;font-weight:700;white-space:nowrap">Upload Missing</button>
</div>
<div style="border:1px solid #E5E7EB;background:white;border-radius:14px;overflow:hidden">
<div style="padding:12px;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid #E5E7EB">
<p style="margin:0;font-size:18px;font-weight:800;color:#111827">Documents</p>
<button type="button" style="height:32px;border:none;border-radius:8px;background:#03004E;color:white;padding:0 12px;font-size:12px;font-weight:700">Upload New</button>
</div>
<table style="width:100%;border-collapse:collapse">
<thead>
<tr style="border-bottom:1px solid #E5E7EB;background:#F9FAFB">
<th style="text-align:left;padding:10px;font-size:11px;color:#6B7280">Document</th>
<th style="text-align:left;padding:10px;font-size:11px;color:#6B7280">File</th>
<th style="text-align:left;padding:10px;font-size:11px;color:#6B7280">Status</th>
<th style="text-align:right;padding:10px;font-size:11px;color:#6B7280">Action</th>
</tr>
</thead>
<tbody>
{[
['Identity Proof', 'id_scan_v2.pdf', 'Approved'],
['Address Proof', 'electricity_bill.jpg', 'Rejected'],
['Tax Document', 'itr_form16_2023.pdf', 'Approved'],
].map(([doc, file, state]) => (
<tr style="border-top:1px solid #F3F4F6">
<td style="padding:10px;font-size:12px;color:#111827;font-weight:600">{doc}</td>
<td style="padding:10px;font-size:12px;color:#374151">{file}</td>
<td style="padding:10px">
<span style={`height:22px;padding:0 8px;border-radius:999px;border:1px solid ${state === 'Rejected' ? '#FFD8C2' : '#DDEBFF'};background:${state === 'Rejected' ? '#FFF1EB' : '#EEF4FF'};display:inline-flex;align-items:center;font-size:10px;font-weight:700;color:${state === 'Rejected' ? '#FF5E13' : '#03004E'}`}>{state}</span>
</td>
<td style="padding:10px;text-align:right">
<Show
when={state === 'Rejected'}
fallback={<span style="font-size:11px;color:#9CA3AF">No action</span>}
>
<button type="button" style="height:28px;border:1px solid #D1D5DB;border-radius:8px;background:white;color:#374151;padding:0 10px;font-size:11px;font-weight:700">Re-upload</button>
</Show>
</td>
</tr>
))}
</tbody>
</table>
</div>
<div style="border:1px solid #FFE2D3;border-radius:12px;background:#FFF8F4;padding:10px;font-size:12px;color:#374151">
Address Proof needs re-upload to continue verification.
</div>
</div>
);
}
if (tab === 're-upload') {
return (
<div style="display:grid;grid-template-columns:1fr 1.5fr;gap:12px">
<div style="border:1px solid #FFE2D3;background:#FFF8F4;border-radius:14px;padding:12px">
<p style="margin:0;font-size:12px;color:#FF5E13;font-weight:700">1 item needs correction</p>
<p style="margin:8px 0 0;font-size:12px;color:#374151">Identity proof is unclear. Please upload a clear copy.</p>
</div>
<div style="border:1px solid #E5E7EB;background:white;border-radius:14px;padding:12px">
<p style="margin:0;font-size:20px;font-weight:800;color:#111827">Upload Correction</p>
<input type="file" style="margin-top:10px;font-size:12px;color:#374151" />
<div style="display:flex;justify-content:flex-end;gap:8px;margin-top:10px">
<button type="button" style="height:32px;border-radius:8px;border:1px solid #D1D5DB;background:white;color:#374151;padding:0 12px;font-size:12px;font-weight:700">Cancel</button>
<button type="button" style="height:32px;border-radius:8px;border:none;background:#03004E;color:white;padding:0 12px;font-size:12px;font-weight:700">Submit</button>
</div>
</div>
</div>
);
}
if (tab === 'activity') {
return (
<div style="border:1px solid #E5E7EB;background:white;border-radius:14px;overflow:hidden">
<div style="padding:12px;border-bottom:1px solid #E5E7EB">
<p style="margin:0;font-size:20px;font-weight:800;color:#111827">Verification Updates</p>
</div>
<div style="padding:12px;display:grid;gap:8px">
{[
['Today, 11:30 AM', 'Correction submitted', 'Completed'],
['Today, 10:45 AM', 'Re-upload requested', 'Action Needed'],
['Yesterday, 04:20 PM', 'Reviewer note added', 'Updated'],
['Yesterday, 11:10 AM', 'Verification started', 'Started'],
].map(([time, title, state]) => (
<div style="display:flex;align-items:center;justify-content:space-between;gap:10px;padding:10px;border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB">
<div>
<p style="margin:0;font-size:12px;font-weight:700;color:#111827">{title}</p>
<p style="margin:2px 0 0;font-size:11px;color:#6B7280">{time}</p>
</div>
<span style={`height:22px;padding:0 8px;border-radius:999px;border:1px solid ${state === 'Action Needed' ? '#FFD8C2' : '#DDEBFF'};background:${state === 'Action Needed' ? '#FFF1EB' : '#EEF4FF'};display:inline-flex;align-items:center;font-size:10px;font-weight:700;color:${state === 'Action Needed' ? '#FF5E13' : '#03004E'}`}>{state}</span>
</div>
))}
</div>
</div>
);
}
return (
<div style="border:1px solid #E5E7EB;background:white;border-radius:14px;padding:14px">
<p style="margin:0;font-size:14px;font-weight:700;color:#111827">Details will appear here</p>
<p style="margin:6px 0 0;font-size:12px;color:#6B7280">This section is being prepared. Please use the available tabs above.</p>
</div>
);
}
if (customerKey() === 'help center' || customerKey() === 'support') {
const active = helpCenterTab();
return (
<div style="display:flex;flex-direction:column;gap:12px">
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<p style="margin:0;font-size:28px;line-height:1.1;font-weight:800;color:#111827">Help Center</p>
<p style="margin:8px 0 0;font-size:14px;color:#6B7280">Get help, manage tickets, and contact support.</p>
<div style="display:flex;align-items:center;gap:24px;margin-top:12px;border-bottom:1px solid #E5E7EB;padding-bottom:8px">
<button type="button" onClick={() => setHelpCenterTab('help_center')} style={`border:none;background:none;padding:0 0 8px;font-size:13px;font-weight:${active === 'help_center' ? 700 : 500};color:${active === 'help_center' ? '#FF5E13' : '#6B7280'};border-bottom:${active === 'help_center' ? '2px solid #FF5E13' : '2px solid transparent'};cursor:pointer`}>Help Center</button>
<button type="button" onClick={() => setHelpCenterTab('my_tickets')} style={`border:none;background:none;padding:0 0 8px;font-size:13px;font-weight:${active === 'my_tickets' ? 700 : 500};color:${active === 'my_tickets' ? '#FF5E13' : '#6B7280'};border-bottom:${active === 'my_tickets' ? '2px solid #FF5E13' : '2px solid transparent'};cursor:pointer`}>My Tickets</button>
<button type="button" onClick={() => setHelpCenterTab('create_ticket')} style={`border:none;background:none;padding:0 0 8px;font-size:13px;font-weight:${active === 'create_ticket' ? 700 : 500};color:${active === 'create_ticket' ? '#FF5E13' : '#6B7280'};border-bottom:${active === 'create_ticket' ? '2px solid #FF5E13' : '2px solid transparent'};cursor:pointer`}>Create Ticket</button>
</div>
</div>
<Show when={active === 'help_center'}>
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<p style="margin:0;font-size:11px;letter-spacing:0.08em;text-transform:uppercase;font-weight:700;color:#FF5E13">Knowledge Base</p>
<div style="display:grid;grid-template-columns:1fr 1.8fr auto;gap:8px;margin-top:10px">
<select
value={kbCategory()}
onChange={(e) => setKbCategory(e.currentTarget.value)}
style="height:36px;border:1px solid #D1D5DB;border-radius:10px;background:white;padding:0 12px;display:flex;align-items:center;font-size:12px;color:#111827;outline:none"
>
<option value="All">All Categories</option>
<For each={kbCategoriesWithCounts()}>{cat => <option value={cat.title}>{cat.title}</option>}</For>
</select>
<div style="position:relative">
<input
type="text"
placeholder="Search help articles, tickets, and guides"
value={kbSearch()}
onInput={(e) => setKbSearch(e.currentTarget.value)}
style="width:100%;height:36px;border:1px solid #D1D5DB;border-radius:10px;background:white;padding:0 12px;font-size:12px;color:#111827;outline:none"
/>
</div>
<button type="button" style="height:36px;width:44px;border:none;border-radius:10px;background:#0D0D2A;color:white;font-size:16px;font-weight:700"></button>
</div>
<div style="display:flex;align-items:center;gap:8px;margin-top:10px">
<span style="font-size:11px;color:#6B7280">Popular:</span>
{['Verification', 'Credits', 'Lead Response'].map((tag) => <button onClick={() => setKbSearch(tag)} style="height:22px;padding:0 10px;border-radius:999px;border:1px solid #E5E7EB;background:#F9FAFB;color:#374151;display:inline-flex;align-items:center;font-size:11px;cursor:pointer">{tag}</button>)}
</div>
</div>
<div style="display:flex;justify-content:space-between;align-items:center">
<p style="margin:0;font-size:24px;font-weight:800;color:#111827;line-height:1.1">Browse by Category</p>
</div>
<div style="display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px">
<For each={kbCategoriesWithCounts()}>{(cat) => (
<button
onClick={() => setKbCategory(cat.title)}
style="text-align:left;border:1px solid #E5E7EB;background:white;border-radius:14px;padding:12px;box-shadow:0 1px 4px rgba(0,0,0,0.05);cursor:pointer;transition:all 0.2s"
onMouseEnter={(e) => e.currentTarget.style.borderColor = '#FF5E13'}
onMouseLeave={(e) => e.currentTarget.style.borderColor = '#E5E7EB'}
>
<div style={`width:32px;height:32px;border-radius:8px;background:#FFF3EE;display:flex;align-items:center;justify-content:center;margin-bottom:10px`}>
<BookOpen size={16} color="#FF5E13" />
</div>
<p style="margin:0;font-size:14px;font-weight:800;color:#111827">{cat.title}</p>
<p style="margin:6px 0 0;font-size:11px;line-height:1.45;color:#6B7280">{cat.description}</p>
<div style="display:flex;justify-content:space-between;align-items:center;margin-top:10px">
<span style="font-size:10px;font-weight:700;color:#9CA3AF;text-transform:uppercase">{cat.articles} Articles</span>
</div>
</button>
)}</For>
</div>
<div style="display:grid;grid-template-columns:100%;gap:12px">
<div>
<div style="display:flex;justify-content:space-between;align-items:end;margin-bottom:10px">
<p style="margin:0;font-size:24px;font-weight:800;color:#111827;line-height:1.1">
{kbSearch() || kbCategory() !== 'All' ? 'Search Results' : 'Important Articles'}
</p>
<Show when={kbSearch() || kbCategory() !== 'All'}>
<button onClick={() => { setKbSearch(''); setKbCategory('All'); }} style="font-size:11px;color:#FF5E13;font-weight:700;background:none;border:none;cursor:pointer">Clear Filters</button>
</Show>
</div>
<div style="display:grid;grid-template-columns:repeat(2, 1fr);gap:8px">
<For each={filteredKbArticles()}>{(a) => (
<button type="button" style="height:auto;min-height:44px;border:1px solid #E5E7EB;background:white;border-radius:10px;padding:12px;display:flex;justify-content:space-between;align-items:center;cursor:pointer;transition:all 0.15s">
<div style="display:flex;flex-direction:column;gap:2px;text-align:left">
<span style="font-[10px];font-weight:700;color:#FF5E13;text-transform:uppercase;letter-spacing:0.02em">{a.category}</span>
<span style="font-size:13px;font-weight:700;color:#111827">{a.title}</span>
<span style="font-size:11px;color:#6B7280;line-clamp:1;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:1;-webkit-box-orient:vertical">{a.content}</span>
</div>
<span style="font-size:14px;color:#9CA3AF"></span>
</button>
)}</For>
<Show when={filteredKbArticles().length === 0}>
<div style="grid-column:1/-1;padding:40px;text-align:center;background:#F9FAFB;border-radius:12px;border:1px dashed #D1D5DB">
<AlertCircle size={24} color="#9CA3AF" style="margin-bottom:8px" />
<p style="margin:0;font-size:13px;color:#6B7280">No articles found matching your criteria.</p>
</div>
</Show>
</div>
</div>
</div>
<div>
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:10px">
<p style="margin:0;font-size:24px;font-weight:800;color:#111827;line-height:1.1">Quick Guides</p>
<span style="font-size:11px;color:#9CA3AF">Actionable tutorials to master Nxtgauge</span>
</div>
<div style="display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px">
{[
{ title: 'The First 24 Hours: Setup', text: 'Complete your core profile requirements and find your first lead fast.', read: '8 min read', level: 'Beginner', Icon: Rocket },
{ title: 'Maximizing Lead Conversions', text: 'Use response quality and timing strategies to improve closure rate.', read: '15 min read', level: 'Growth', Icon: TrendingUp },
{ title: 'Data Privacy & Security', text: 'Understand how we protect your business and financial information.', read: '5 min read', level: 'Essential', Icon: ShieldCheck },
].map((g) => (
<div style="border:1px solid #E5E7EB;background:white;border-radius:12px;overflow:hidden;box-shadow:0 1px 4px rgba(0,0,0,0.05)">
<div style="padding:10px;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid #F3F4F6;background:#FAFAFA">
<span style="height:22px;padding:0 8px;border-radius:999px;background:#FFF1EB;color:#FF5E13;font-size:10px;font-weight:700;display:inline-flex;align-items:center;border:1px solid #FFD8C2">{g.level}</span>
<span style="width:24px;height:24px;border-radius:999px;background:#FFF1EB;display:inline-flex;align-items:center;justify-content:center;color:#FF5E13;border:1px solid #FFD8C2">
<g.Icon size={13} />
</span>
</div>
<div style="padding:12px">
<p style="margin:0;font-size:14px;font-weight:800;color:#111827">{g.title}</p>
<p style="margin:6px 0 0;font-size:12px;line-height:1.45;color:#6B7280">{g.text}</p>
<div style="margin-top:10px;display:flex;align-items:center;justify-content:space-between">
<p style="margin:0;font-size:11px;color:#9CA3AF;text-transform:uppercase">{g.read}</p>
<button type="button" style="height:26px;border-radius:7px;border:1px solid #D1D5DB;background:white;color:#374151;padding:0 9px;font-size:11px;font-weight:700">Read</button>
</div>
</div>
</div>
))}
</div>
</div>
</Show>
<Show when={active === 'my_tickets'}>
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:16px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<div style="display:flex;justify-content:space-between;align-items:center;gap:10px">
<p style="margin:0;font-size:24px;line-height:1.1;font-weight:800;color:#111827">My Tickets</p>
<div style="display:flex;gap:8px">
<span style="height:26px;padding:0 10px;border-radius:999px;border:1px solid #E5E7EB;background:#F9FAFB;display:inline-flex;align-items:center;font-size:11px;color:#374151;font-weight:600">Open: {ticketSummary().openCount}</span>
<span style="height:26px;padding:0 10px;border-radius:999px;border:1px solid #E5E7EB;background:#F9FAFB;display:inline-flex;align-items:center;font-size:11px;color:#374151;font-weight:600">Resolved: {ticketSummary().resolvedCount}</span>
</div>
</div>
<div style="margin-top:10px;border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB;padding:10px 12px">
<p style="margin:0;font-size:12px;color:#6B7280">You have {ticketSummary().total} tickets. {ticketSummary().openCount} still need action and {ticketSummary().resolvedCount} are resolved.</p>
</div>
<div style="margin-top:14px;display:flex;align-items:center;gap:18px;border-bottom:1px solid #E5E7EB;padding-bottom:8px">
<button type="button" onClick={() => setMyTicketsTab('all_tickets')} style={`border:none;background:none;padding:0 0 8px;font-size:13px;font-weight:${myTicketsTab() === 'all_tickets' ? 700 : 500};color:${myTicketsTab() === 'all_tickets' ? '#FF5E13' : '#6B7280'};border-bottom:${myTicketsTab() === 'all_tickets' ? '2px solid #FF5E13' : '2px solid transparent'};cursor:pointer`}>All Tickets</button>
<button type="button" onClick={() => setMyTicketsTab('view_ticket')} style={`border:none;background:none;padding:0 0 8px;font-size:13px;font-weight:${myTicketsTab() === 'view_ticket' ? 700 : 500};color:${myTicketsTab() === 'view_ticket' ? '#FF5E13' : '#6B7280'};border-bottom:${myTicketsTab() === 'view_ticket' ? '2px solid #FF5E13' : '2px solid transparent'};cursor:pointer`}>View Ticket</button>
</div>
<Show when={myTicketsTab() === 'all_tickets'}>
<div style="margin-top:12px;border:1px solid #E5E7EB;border-radius:12px;overflow:hidden;background:white">
<table style="width:100%;border-collapse:collapse">
<thead>
<tr style="background:#F9FAFB;border-bottom:1px solid #E5E7EB">
<th style="text-align:left;padding:10px;font-size:11px;color:#6B7280;text-transform:uppercase;letter-spacing:0.04em">Ticket ID</th>
<th style="text-align:left;padding:10px;font-size:11px;color:#6B7280;text-transform:uppercase;letter-spacing:0.04em">Request</th>
<th style="text-align:left;padding:10px;font-size:11px;color:#6B7280;text-transform:uppercase;letter-spacing:0.04em">State</th>
<th style="text-align:left;padding:10px;font-size:11px;color:#6B7280;text-transform:uppercase;letter-spacing:0.04em">Priority</th>
<th style="text-align:left;padding:10px;font-size:11px;color:#6B7280;text-transform:uppercase;letter-spacing:0.04em">Last Message</th>
<th style="text-align:left;padding:10px;font-size:11px;color:#6B7280;text-transform:uppercase;letter-spacing:0.04em">Updated</th>
<th style="text-align:left;padding:10px;font-size:11px;color:#6B7280;text-transform:uppercase;letter-spacing:0.04em">Action</th>
</tr>
</thead>
<tbody>
{HELP_TICKET_ROWS.map((t) => (
<tr onClick={() => openTicketDetails(t.id)} style={`border-top:1px solid #F3F4F6;background:${activeTicketId() === t.id ? '#F5F7FF' : 'white'};cursor:pointer`}>
<td style="padding:10px;font-size:12px;font-weight:700;color:#374151">{t.id}</td>
<td style="padding:10px;font-size:12px;color:#111827;font-weight:600">{t.title}</td>
<td style="padding:10px">
<span style={`height:22px;padding:0 8px;border-radius:999px;border:1px solid ${t.status === 'Resolved' ? '#D1FAE5' : '#E5E7EB'};background:${t.status === 'Resolved' ? '#ECFDF3' : '#F9FAFB'};display:inline-flex;align-items:center;font-size:10px;font-weight:700;color:${t.status === 'Resolved' ? '#059669' : '#374151'}`}>{t.status}</span>
</td>
<td style="padding:10px;font-size:12px;color:#6B7280">{t.priority}</td>
<td style="padding:10px;font-size:12px;color:#6B7280">{t.lastMessage}</td>
<td style="padding:10px;font-size:12px;color:#6B7280">{t.updated}</td>
<td style="padding:10px">
<button
type="button"
onClick={() => {
openTicketDetails(t.id);
}}
style="height:28px;border-radius:8px;border:none;background:#0D0D2A;color:white;font-size:11px;font-weight:700;padding:0 10px;cursor:pointer"
>
Open
</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
</Show>
<Show when={myTicketsTab() === 'view_ticket'}>
<div style="margin-top:12px;border:1px solid #E5E7EB;border-radius:12px;background:white;padding:14px">
<div style="display:flex;justify-content:space-between;align-items:center;gap:8px">
<div>
<p style="margin:0;font-size:16px;font-weight:800;color:#111827">Ticket Communication</p>
<p style="margin:3px 0 0;font-size:12px;color:#6B7280">{activeTicketId()} Share updates and attachments with support team.</p>
</div>
<span style="height:24px;padding:0 10px;border-radius:999px;border:1px solid #E5E7EB;background:#F9FAFB;display:inline-flex;align-items:center;font-size:11px;color:#374151">Message Support</span>
</div>
<div style="margin-top:12px;display:grid;grid-template-columns:1.4fr 1fr;gap:10px">
<div style="display:grid;gap:8px">
<div style="border:1px solid #E5E7EB;border-radius:8px;background:#F9FAFB;padding:10px">
<p style="margin:0;font-size:11px;color:#6B7280">User message</p>
<p style="margin:4px 0 0;font-size:12px;color:#111827">{selectedTicketDetails().userMessage}</p>
</div>
<div style="border:1px solid #E5E7EB;border-radius:8px;background:#F9FAFB;padding:10px">
<p style="margin:0;font-size:11px;color:#6B7280">Admin reply</p>
<p style="margin:4px 0 0;font-size:12px;color:#111827">{selectedTicketDetails().adminMessage}</p>
</div>
<div style="margin-top:2px;border:1px solid #E5E7EB;border-radius:10px;background:white;padding:10px">
<p style="margin:0 0 8px;font-size:12px;font-weight:700;color:#111827">Reply to Support</p>
<textarea
value={ticketMessage()}
onInput={(event) => setTicketMessage(event.currentTarget.value)}
placeholder="Write your message to support team..."
style="min-height:82px;width:100%;border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB;padding:10px;font-size:12px;color:#111827;resize:vertical"
/>
<div style="display:flex;justify-content:flex-end;margin-top:8px">
<button type="button" style="height:36px;border-radius:10px;border:none;background:#0D0D2A;color:white;padding:0 14px;font-size:12px;font-weight:700">Send Message</button>
</div>
</div>
</div>
<div style="display:grid;gap:8px">
<div style="border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB;padding:10px">
<p style="margin:0;font-size:11px;font-weight:700;color:#6B7280;text-transform:uppercase">Requested Documents</p>
<div style="display:grid;gap:6px;margin-top:8px">
<For each={selectedTicketDetails().requestedDocuments.length ? selectedTicketDetails().requestedDocuments : ['No documents requested']}>{(d) => (
<div style="display:flex;justify-content:space-between;align-items:center;background:white;border:1px solid #E5E7EB;border-radius:8px;padding:6px 8px">
<span style="font-size:12px;color:#111827">{d}</span>
<span style="font-size:10px;font-weight:700;color:#6B7280">{selectedTicketDetails().requestedDocuments.length ? 'Pending' : 'NA'}</span>
</div>
)}</For>
</div>
</div>
<div style="border:1px solid #E5E7EB;border-radius:10px;background:#F9FAFB;padding:10px">
<p style="margin:0;font-size:11px;font-weight:700;color:#6B7280;text-transform:uppercase">Received From User</p>
<div style="display:grid;gap:6px;margin-top:8px">
<For each={selectedTicketDetails().receivedFiles.length ? selectedTicketDetails().receivedFiles : [{ file: 'No files received yet', state: 'Pending Upload' as const }]}>{(f) => (
<div style="display:flex;justify-content:space-between;align-items:center;background:white;border:1px solid #E5E7EB;border-radius:8px;padding:6px 8px">
<span style="font-size:12px;color:#111827">{f.file}</span>
<span style={`font-size:10px;font-weight:700;color:${f.state === 'Received' ? '#059669' : '#6B7280'}`}>{f.state}</span>
</div>
)}</For>
</div>
</div>
<div style="border:1px dashed #D1D5DB;border-radius:10px;background:#F9FAFB;padding:10px">
<p style="margin:0 0 8px;font-size:11px;font-weight:700;color:#6B7280;text-transform:uppercase">Upload Requested Files</p>
<input
type="file"
multiple
onChange={(event) => {
const files = event.currentTarget.files;
setViewTicketFiles(files ? Array.from(files).map((file) => file.name) : []);
}}
style="width:100%;font-size:12px;color:#374151"
/>
<Show when={viewTicketFiles().length}>
<div style="display:flex;flex-wrap:wrap;gap:6px;margin-top:8px">
<For each={viewTicketFiles()}>{(name) => <span style="height:24px;padding:0 8px;border-radius:999px;background:white;border:1px solid #E5E7EB;display:inline-flex;align-items:center;font-size:11px;color:#374151">{name}</span>}</For>
</div>
</Show>
</div>
</div>
</div>
</div>
</Show>
</div>
</Show>
<Show when={active === 'create_ticket'}>
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:16px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<p style="margin:0;font-size:24px;line-height:1.1;font-weight:800;color:#111827">Create Ticket</p>
<p style="margin:6px 0 0;font-size:13px;color:#6B7280">Create a support request with complete details for faster resolution.</p>
<div style="margin-top:12px;display:grid;grid-template-columns:1fr 1fr;gap:12px">
<div><p style="margin:0 0 6px;font-size:11px;font-weight:700;color:#6B7280;text-transform:uppercase">Subject</p><input type="text" placeholder="Enter ticket subject" style="height:38px;width:100%;border:1px solid #D1D5DB;border-radius:10px;background:white;padding:0 10px;font-size:12px;color:#111827" /></div>
<div><p style="margin:0 0 6px;font-size:11px;font-weight:700;color:#6B7280;text-transform:uppercase">Category</p><select style="height:38px;width:100%;border:1px solid #D1D5DB;border-radius:10px;background:white;padding:0 10px;font-size:12px;color:#111827"><option>Profile & Verification</option><option>Billing & Credits</option><option>Requirements</option><option>Other</option></select></div>
<div><p style="margin:0 0 6px;font-size:11px;font-weight:700;color:#6B7280;text-transform:uppercase">Priority</p><select style="height:38px;width:100%;border:1px solid #D1D5DB;border-radius:10px;background:white;padding:0 10px;font-size:12px;color:#111827"><option>Medium</option><option>High</option><option>Low</option></select></div>
<div><p style="margin:0 0 6px;font-size:11px;font-weight:700;color:#6B7280;text-transform:uppercase">Order / Requirement ID</p><input type="text" placeholder="Optional reference" style="height:38px;width:100%;border:1px solid #D1D5DB;border-radius:10px;background:white;padding:0 10px;font-size:12px;color:#111827" /></div>
<div style="grid-column:1 / -1"><p style="margin:0 0 6px;font-size:11px;font-weight:700;color:#6B7280;text-transform:uppercase">Description</p><textarea placeholder="Describe the issue in detail..." style="min-height:120px;width:100%;border:1px solid #D1D5DB;border-radius:10px;background:white;padding:10px;font-size:12px;color:#111827;resize:vertical" /></div>
<div style="grid-column:1 / -1">
<p style="margin:0 0 6px;font-size:11px;font-weight:700;color:#6B7280;text-transform:uppercase">Attachment</p>
<div style="border:1px dashed #D1D5DB;border-radius:10px;background:#F9FAFB;padding:12px">
<input
type="file"
multiple
onChange={(event) => {
const files = event.currentTarget.files;
setCreateTicketFiles(files ? Array.from(files).map((file) => file.name) : []);
}}
style="width:100%;font-size:12px;color:#374151"
/>
<Show when={createTicketFiles().length}>
<div style="display:flex;flex-wrap:wrap;gap:6px;margin-top:8px">
<For each={createTicketFiles()}>{(name) => <span style="height:24px;padding:0 8px;border-radius:999px;background:white;border:1px solid #E5E7EB;display:inline-flex;align-items:center;font-size:11px;color:#374151">{name}</span>}</For>
</div>
</Show>
</div>
</div>
</div>
<div style="display:flex;justify-content:flex-end;gap:8px;margin-top:12px">
<button type="button" style="height:36px;border-radius:8px;border:1px solid #D1D5DB;background:white;color:#374151;padding:0 12px;font-size:12px;font-weight:700">Cancel</button>
<button type="button" style="height:36px;border-radius:8px;border:none;background:#0D0D2A;color:white;padding:0 14px;font-size:12px;font-weight:700">Submit Ticket</button>
</div>
</div>
</Show>
</div>
);
}
if (customerKey() === 'settings') {
if (tab === 'privacy') {
return <div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">{['Profile visibility', 'Data sharing consent', 'Session management'].map((s) => <div style="display:flex;justify-content:space-between;align-items:center;padding:8px;border:1px solid #E5E7EB;border-radius:8px;background:#F9FAFB;margin-top:8px"><span style="font-size:12px;color:#374151">{s}</span><span style="font-size:12px;color:#6B7280">Enabled</span></div>)}</div>;
}
if (tab === 'notifications') {
return <div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">{['Response alerts', 'Billing alerts', 'Security alerts'].map((s) => <div style="display:flex;justify-content:space-between;align-items:center;padding:8px;border:1px solid #E5E7EB;border-radius:8px;background:#F9FAFB;margin-top:8px"><span style="font-size:12px;color:#374151">{s}</span><span style="font-size:12px;color:#6B7280">On</span></div>)}</div>;
}
return <div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">{['Change Password', 'Two-factor authentication', 'Login activity'].map((s) => <div style="padding:8px;border:1px solid #E5E7EB;border-radius:8px;background:#F9FAFB;font-size:12px;color:#374151;margin-top:8px">{s}</div>)}</div>;
}
if (customerKey() === 'switch role' || customerKey() === 'switch services' || customerKey() === 'switch service') {
const activeRoles = userRoles();
return (
<div style="display:flex;flex-direction:column;gap:12px">
<div style="border:1px solid #E5E7EB;border-radius:16px;background:white;box-shadow:0 1px 4px rgba(0,0,0,0.06);padding:20px">
<p style="margin:0;font-size:30px;line-height:1.1;font-weight:800;color:#111827">Switch Services</p>
<p style="margin:6px 0 0;font-size:14px;color:#6B7280">Switch between your active roles to manage different business operations.</p>
</div>
<div style="display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px">
<For each={activeRoles}>
{(role) => {
const roleKey = String(role.role_key || role.key).toUpperCase();
const isCurrent = normalizeRoleKey(props.roleKey || '') === normalizeRoleKey(roleKey);
return (
<div style={`border:1px solid ${isCurrent ? '#FFD8C2' : '#E5E7EB'};background:${isCurrent ? '#FFF9F7' : 'white'};border-radius:16px;padding:16px;box-shadow:0 1px 4px rgba(0,0,0,0.06);display:flex;flex-direction:column;gap:8px`}>
<div style="display:flex;align-items:center;justify-content:space-between">
<div style="width:32px;height:32px;border-radius:8px;background:#FFF3EE;display:flex;align-items:center;justify-content:center">
{(() => {
const Icon = roleIcon(roleKey);
return <Icon size={16} color="#FF5E13" />;
})()}
</div>
<span style={`height:20px;padding:0 8px;border-radius:999px;font-size:10px;font-weight:700;background:${role.status === 'APPROVED' ? '#ECFDF5' : '#FEF3C7'};color:${role.status === 'APPROVED' ? '#059669' : '#D97706'}`}>{role.status}</span>
</div>
<p style="margin:4px 0 0;font-size:16px;font-weight:800;color:#111827">{titleCase(roleKey.replace(/_/g, ' '))}</p>
<button
type="button"
disabled={isCurrent}
onClick={() => switchRole(roleKey)}
style={`margin-top:auto;height:32px;border-radius:8px;border:none;background:${isCurrent ? '#E5E7EB' : '#03004E'};color:${isCurrent ? '#4B5563' : 'white'};padding:0 10px;font-size:12px;font-weight:700;cursor:${isCurrent ? 'default' : 'pointer'}`}
>
{isCurrent ? 'Active' : 'Switch Role'}
</button>
</div>
);
}}
</For>
<Show when={activeRoles.length === 0}>
<div style="grid-column:1 / -1;padding:20px;text-align:center;color:#6B7280;background:#F9FAFB;border-radius:12px;border:1px dashed #D1D5DB">
No other active roles found. Explore Nxtgauge to add more.
</div>
</Show>
</div>
</div>
);
}
if (customerKey() === 'logout') {
if (tab === 'cancel') {
return <div style="max-width:420px;margin:0 auto;border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;text-align:center;box-shadow:0 1px 4px rgba(0,0,0,0.06)"><p style="margin:0;font-size:18px;font-weight:800;color:#111827">Logout Cancelled</p><p style="margin:6px 0 0;font-size:13px;color:#6B7280">Your session is still active.</p></div>;
}
return (
<div style="max-width:420px;margin:0 auto;border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;text-align:center;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<p style="margin:0;font-size:18px;font-weight:800;color:#111827">Confirm Logout</p>
<p style="margin:6px 0 0;font-size:13px;color:#6B7280">Are you sure you want to logout from the service seeker portal?</p>
<div style="display:flex;justify-content:center;gap:8px;margin-top:12px"><button type="button" style="height:32px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 12px;font-size:12px;font-weight:700;color:#374151">Cancel</button><button type="button" style="height:32px;border-radius:8px;border:none;background:#FF5E13;color:white;padding:0 12px;font-size:12px;font-weight:700">Logout</button></div>
</div>
);
}
if (customerKey() === 'my portfolio') {
if (!isProfessionalRoleKey(props.roleKey || '')) {
return (
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:16px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<p style="margin:0;font-size:16px;font-weight:800;color:#111827">My Portfolio is only for professionals</p>
<p style="margin:6px 0 0;font-size:13px;color:#6B7280">Switch to a professional role to manage and preview portfolio content.</p>
</div>
);
}
return renderPortfolioContent();
}
return (
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<p style="margin:0;font-size:13px;font-weight:700;color:#111827">Screen Preview</p>
<p style="margin:6px 0 0;font-size:13px;color:#6B7280">Service seeker screen is selected and interactive.</p>
</div>
);
};
const portfolioTabIcon = (tabLabel: string) => {
const key = normalizeTabKey(tabLabel);
if (key === 'overview') return LayoutGrid;
if (key === 'about') return UserCircle2;
if (key.includes('services')) return Coins;
if (key.includes('portfolio')) return Image;
if (key.includes('experience')) return BriefcaseBusiness;
if (key === 'testimonials') return Star;
if (key === 'faqs') return HelpCircle;
return FileText;
};
return (
<div style="border:1px solid #E5E7EB;border-radius:12px;overflow:hidden;background:#fff">
<Show when={!props.hidePreviewHeader}>
<div style="padding:10px 14px;border-bottom:1px solid #E5E7EB;background:#F9FAFB;display:flex;justify-content:space-between;align-items:center">
<p style="margin:0;font-size:12px;font-weight:700;color:#374151">Actual End-User Dashboard UI Preview</p>
<div style="display:flex;align-items:center;gap:8px">
<Show when={props.onOpenFullscreen}>
<button
type="button"
onClick={() => props.onOpenFullscreen?.()}
title="Open Full Screen Preview"
aria-label="Open Full Screen Preview"
style="height:28px;width:28px;border-radius:7px;border:1px solid #E5E7EB;background:white;display:inline-flex;align-items:center;justify-content:center;cursor:pointer;color:#374151"
>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polyline points="15 3 21 3 21 9"></polyline>
<polyline points="9 21 3 21 3 15"></polyline>
<line x1="21" y1="3" x2="14" y2="10"></line>
<line x1="3" y1="21" x2="10" y2="14"></line>
</svg>
</button>
</Show>
<StatusBadge status={props.status} />
</div>
</div>
</Show>
<div style="display:grid;grid-template-columns:220px 1fr;min-height:680px;background:#F3F4F6">
<aside style="display:flex;flex-direction:column;border-right:1px solid #E5E7EB;background:#fff">
<div style="height:64px;display:flex;align-items:center;border-bottom:1px solid #E5E7EB;padding:0 14px">
<img src="/nxtgauge-logo.png" alt="Nxtgauge" style="height:40px;object-fit:contain;max-width:170px" />
</div>
<div style="padding:10px 8px;display:flex;flex-direction:column;gap:4px;overflow:auto">
<For each={previewSidebarItems()}>
{(item) => (
<button
type="button"
onClick={() => props.onSidebarSelect(item)}
style={`display:flex;align-items:center;gap:9px;text-align:left;height:34px;border-radius:8px;padding:0 10px;border:none;cursor:pointer;font-size:12px;font-weight:600;background:${props.activeSidebar === item ? '#FFF3EE' : 'transparent'};color:${props.activeSidebar === item ? '#FF5E13' : '#6B7280'}`}
>
{(() => {
const Icon = sidebarIcon(item);
return <Icon size={14} style={`color:${props.activeSidebar === item ? '#FF5E13' : '#9CA3AF'};flex-shrink:0`} strokeWidth={props.activeSidebar === item ? 2.5 : 2} />;
})()}
{titleCase(item)}
</button>
)}
</For>
</div>
</aside>
<main style="display:flex;flex-direction:column">
<header style="height:64px;background:#fff;border-bottom:1px solid #E5E7EB;display:flex;align-items:center;justify-content:space-between;padding:0 16px">
<div style="display:flex;align-items:center;gap:10px">
<div style="position:relative">
<Search size={16} style="position:absolute;left:10px;top:50%;transform:translateY(-50%);color:#9CA3AF" />
<input value="" readOnly placeholder="Search resources..." style="height:36px;width:280px;border-radius:10px;border:1px solid #E5E7EB;background:#F9FAFB;padding:0 12px 0 32px;font-size:12px;color:#6B7280" />
</div>
</div>
<div style="display:flex;align-items:center;gap:8px">
<button type="button" style="width:34px;height:34px;border-radius:8px;border:1px solid #E5E7EB;background:white;display:flex;align-items:center;justify-content:center;cursor:pointer;color:#6B7280"><Bell size={16} /></button>
<button type="button" style="width:34px;height:34px;border-radius:8px;border:1px solid #E5E7EB;background:white;display:flex;align-items:center;justify-content:center;cursor:pointer;color:#6B7280"><Settings size={16} /></button>
<button type="button" style="width:34px;height:34px;border-radius:8px;border:1px solid #E5E7EB;background:white;display:flex;align-items:center;justify-content:center;cursor:pointer;color:#6B7280"><User size={16} /></button>
</div>
</header>
<Show when={!isVerified()}>
<div style="margin:14px 14px 0;background:#FFF7ED;border:1px solid #FFEDD5;border-radius:12px;padding:12px 16px;display:flex;align-items:center;justify-content:space-between;gap:12px;box-shadow:0 1px 2px rgba(0,0,0,0.05)">
<div style="display:flex;align-items:center;gap:12px">
<div style="width:36px;height:36px;border-radius:10px;background:#FFEDD5;display:flex;align-items:center;justify-content:center;color:#EA580C">
<AlertCircle size={20} />
</div>
<div>
<p style="margin:0;font-size:14px;font-weight:700;color:#9A3412">Account Verification Required</p>
<p style="margin:2px 0 0;font-size:12px;color:#C2410C">{verificationPending() ? 'Your profile is currently under review by our team. This usually takes 24-48 hours.' : 'Complete your profile details to unlock all platform features and start receiving leads.'}</p>
</div>
</div>
<button
type="button"
onClick={() => props.onSidebarSelect('My Profile')}
style="height:32px;padding:0 14px;border-radius:8px;background:#EA580C;color:white;border:none;font-size:12px;font-weight:600;cursor:pointer;display:flex;align-items:center;white-space:nowrap"
>
{verificationPending() ? 'View Verification Status' : 'Complete Profile'}
</button>
</div>
</Show>
<div style="padding:14px">
<Show when={!(isCustomerExternalMode() && (customerKey() === 'help center' || customerKey() === 'support'))}>
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<p style="margin:0;font-size:12px;color:#6B7280">Current View</p>
<p style="margin:4px 0 0;font-size:24px;font-weight:800;color:#111827">{isCustomerExternalMode() ? customerView().title : titleCase(props.activeSidebar)}</p>
<p style="margin:4px 0 0;font-size:13px;color:#6B7280">{isCustomerExternalMode() ? customerView().subtitle : 'Interactive preview for configured dashboard.'}</p>
<Show when={previewTabs().length > 0 && customerKey() !== 'my portfolio'}>
<Show
when={customerKey() === 'my portfolio'}
fallback={
<div style="margin-top:12px;display:flex;align-items:center;gap:20px;border-bottom:1px solid #E5E7EB">
<For each={previewTabs()}>
{(item) => (
(() => {
const itemKey = normalizeTabKey(item);
const isLockedTestimonialsTab = customerKey() === 'my portfolio' && itemKey === 'testimonials' && !portfolioTestimonialsUnlocked();
return (
<button
type="button"
disabled={isLockedTestimonialsTab}
onClick={() => {
if (isLockedTestimonialsTab) return;
props.onTabSelect(item);
}}
title={isLockedTestimonialsTab ? 'Unlock after 3 completed jobs and 2 customer feedback entries' : ''}
style={`padding-bottom:10px;font-size:13px;font-weight:500;background:none;border:none;cursor:${isLockedTestimonialsTab ? 'not-allowed' : 'pointer'};opacity:${isLockedTestimonialsTab ? 0.5 : 1};${resolvedTabKey() === itemKey ? 'color:#FF5E13;border-bottom:2px solid #FF5E13;margin-bottom:-1px' : 'color:#6B7280'}`}
>
{titleCase(item)} {isLockedTestimonialsTab ? '• Locked' : ''}
</button>
);
})()
)}
</For>
</div>
}
>
<div style="margin-top:12px;display:flex;align-items:center;gap:8px;overflow-x:auto;padding-bottom:2px">
<For each={previewTabs()}>
{(item) => {
const itemKey = normalizeTabKey(item);
const isLockedTestimonialsTab = itemKey === 'testimonials' && !portfolioTestimonialsUnlocked();
const isActive = resolvedTabKey() === itemKey;
const Icon = portfolioTabIcon(item);
return (
<button
type="button"
disabled={isLockedTestimonialsTab}
onClick={() => {
if (isLockedTestimonialsTab) return;
props.onTabSelect(item);
}}
title={isLockedTestimonialsTab ? 'Unlock after 3 completed jobs and 2 customer feedback entries' : ''}
style={`min-width:148px;height:40px;border-radius:10px;border:1px solid ${isActive ? '#FFD8C2' : '#E5E7EB'};background:${isActive ? '#FFF8F4' : 'white'};padding:0 10px;display:flex;align-items:center;gap:8px;cursor:${isLockedTestimonialsTab ? 'not-allowed' : 'pointer'};opacity:${isLockedTestimonialsTab ? 0.5 : 1};flex-shrink:0`}
>
<span style={`width:22px;height:22px;border-radius:7px;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;border:1px solid ${isActive ? '#FFD8C2' : '#E5E7EB'};background:${isActive ? '#FFF1EB' : '#F9FAFB'}`}>
<Icon size={12} style={`color:${isActive ? '#C2410C' : '#6B7280'}`} />
</span>
<span style={`font-size:12px;font-weight:700;line-height:1.2;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:${isActive ? '#111827' : '#374151'}`}>
{titleCase(item)}{isLockedTestimonialsTab ? ' · Locked' : ''}
</span>
</button>
);
}}
</For>
</div>
</Show>
</Show>
</div>
</Show>
<Show when={isCustomerExternalMode()} fallback={<div style="margin-top:10px;border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;box-shadow:0 1px 4px rgba(0,0,0,0.06)"><p style="margin:0;font-size:13px;color:#374151">Default preview mode.</p></div>}>
<div style="margin-top:10px">{renderCustomerContent()}</div>
</Show>
<Show when={!isCustomerExternalMode()}>
<div style="border:1px solid #E5E7EB;background:white;border-radius:16px;padding:14px;margin-top:10px;box-shadow:0 1px 4px rgba(0,0,0,0.06)">
<p style="margin:0;font-size:11px;letter-spacing:0.05em;text-transform:uppercase;color:#6B7280">Fields View</p>
<div style="display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;margin-top:8px">
<For each={previewFields()}>
{(f) => <div style="padding:8px;border:1px solid #E5E7EB;border-radius:8px;background:#F9FAFB;font-size:12px;color:#374151">{titleCase(f)}</div>}
</For>
</div>
</div>
</Show>
</div>
</main>
</div>
</div>
);
}