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'; import { getToken } from '~/lib/auth'; 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%)'; const API = '/api/gateway'; function StatusBadge(props: { status: 'ACTIVE' | 'INACTIVE' }) { const active = () => props.status === 'ACTIVE'; return ( {active() ? 'Active' : 'Inactive'} ); } 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; }; 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 = { 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 = { 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 10–14 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.5–3 hours for full bridal. Party makeup takes around 45–60 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 3–5 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 2–3 days. Full event films take 10–15 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 3–5 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 4–6 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 3–4 weeks for events under 200 guests; 6–8 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 = { 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([]); const [draggingDashboardWidget, setDraggingDashboardWidget] = createSignal(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('TCK-1042'); const [openFaqIndex, setOpenFaqIndex] = createSignal(0); const [ticketMessage, setTicketMessage] = createSignal(''); const [createTicketFiles, setCreateTicketFiles] = createSignal([]); const [viewTicketFiles, setViewTicketFiles] = createSignal([]); const [profileFormData, setProfileFormData] = createSignal>({}); 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([]); const [portfolioLanguages, setPortfolioLanguages] = createSignal([]); const [portfolioServiceAreas, setPortfolioServiceAreas] = createSignal([]); const [portfolioSpecialtyInput, setPortfolioSpecialtyInput] = createSignal(''); const [portfolioLanguageInput, setPortfolioLanguageInput] = createSignal(''); const [portfolioAreaInput, setPortfolioAreaInput] = createSignal(''); const [profileDocumentType, setProfileDocumentType] = createSignal('Aadhar Card'); const [portfolioFormValues, setPortfolioFormValues] = createSignal>({}); const [portfolioFormErrors, setPortfolioFormErrors] = createSignal>({}); const [userRoles, setUserRoles] = createSignal([]); const [portfolioValidationNotice, setPortfolioValidationNotice] = createSignal(''); const [portfolioServices, setPortfolioServices] = createSignal>([]); const [portfolioServiceDraft, setPortfolioServiceDraft] = createSignal<{ name: string; model: string; price: string; details: string }>({ name: '', model: 'Flat', price: '', details: '' }); const [portfolioExperiences, setPortfolioExperiences] = createSignal>([]); const [portfolioExperienceDraft, setPortfolioExperienceDraft] = createSignal<{ year: string; title: string; details: string }>({ year: '', title: '', details: '' }); const [portfolioDesignTools, setPortfolioDesignTools] = createSignal([]); const [portfolioToolInput, setPortfolioToolInput] = createSignal(''); const [portfolioPhotos, setPortfolioPhotos] = createSignal([]); const [requirementsView, setRequirementsView] = createSignal<'list' | 'new' | 'detail'>('list'); const [requirementsStep, setRequirementsStep] = createSignal(1); const [requirementRows, setRequirementRows] = createSignal(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(JOB_SEEKER_OPEN_JOBS); const [companyJobSubmissions, setCompanyJobSubmissions] = createSignal([]); const [companyJobDraft] = createSignal(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(null); const [paymentStep, setPaymentStep] = createSignal<'idle' | 'processing' | 'verifying' | 'success' | 'error'>('idle'); const [paymentRef, setPaymentRef] = createSignal(null); const [paymentResult, setPaymentResult] = createSignal(null); // Coupon state const [couponCode, setCouponCode] = createSignal(''); const [appliedCoupon, setAppliedCoupon] = createSignal<{code: string; discount_type: string; discount_value: number; final_price_inr: number} | null>(null); const [couponError, setCouponError] = createSignal(''); const [couponLoading, setCouponLoading] = createSignal(false); const [creditManageView, setCreditManageView] = createSignal(false); const [txRows, setTxRows] = createSignal>([ ['#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>({ 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 = {}; 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 applyCoupon = async () => { const code = couponCode().trim(); if (!code) { setCouponError('Enter a coupon code'); return; } setCouponLoading(true); setCouponError(''); try { const token = getToken(); const headers: HeadersInit = { 'Content-Type': 'application/json', ...(token ? { 'Authorization': `Bearer ${token}` } : {}) }; const res = await fetch(`${API}/coupons/validate`, { method: 'POST', headers, credentials: 'include', body: JSON.stringify({ coupon_code: code, role_key: normalizeRoleKey(props.roleKey || ''), package_price_inr: Number(checkoutPackage()?.price_paise || 0) }) }); const data = await res.json(); if (res.ok && data.valid) { setAppliedCoupon({ code, discount_type: data.discount_type, discount_value: data.discount_value, final_price_inr: data.final_price_inr }); } else { setCouponError(data.message || 'Invalid coupon'); setAppliedCoupon(null); } } catch (e) { setCouponError('Network error'); setAppliedCoupon(null); } finally { setCouponLoading(false); } }; const startPayment = async (pkg: any) => { setPaymentStep('processing'); try { const token = getToken(); const headers: HeadersInit = { 'Content-Type': 'application/json', ...(token ? { 'Authorization': `Bearer ${token}` } : {}) }; const ac = appliedCoupon(); const body: any = { package_id: pkg.id, amount: ac ? ac.final_price_inr : pkg.price_paise, }; if (ac) body.coupon_code = ac.code; const res = await fetch(`${API}/payments/create-order`, { method: 'POST', headers, credentials: 'include', body: JSON.stringify(body), }); const data = await res.json().catch(() => ({})); if (!res.ok) { setPaymentStep('error'); setCouponError('Payment initiation failed'); return; } setPaymentRef(data.order_id || `ORD-${Date.now()}`); setTimeout(() => verifyPayment(pkg), 1200); } catch (e) { setPaymentRef(`ORD-MOCK-${Date.now()}`); setTimeout(() => verifyPayment(pkg), 1200); } }; const verifyPayment = async (pkg: any) => { setPaymentStep('verifying'); try { const token = getToken(); const headers: HeadersInit = { 'Content-Type': 'application/json', ...(token ? { 'Authorization': `Bearer ${token}` } : {}) }; const res = await fetch(`${API}/payments/verify`, { method: 'POST', headers, credentials: 'include', body: JSON.stringify({ order_id: paymentRef(), payment_id: `PAY-${Date.now()}` }), }); if (res.ok) { setPaymentStep('success'); const creditsToAdd = Number(pkg.credits) + Number(pkg.bonus_credits || 0); setLeadCredits((prev) => prev + creditsToAdd); const ac = appliedCoupon(); const amountPaid = ac ? ac.final_price_inr : pkg.price_paise; const newRow: [string, string, string, string, string, string] = [ paymentRef() || `#INV-${Date.now()}`, pkg.display_name || pkg.name, Number(creditsToAdd).toLocaleString(), `₹${(amountPaid / 100).toLocaleString('en-IN')}`, 'Completed', new Date().toLocaleDateString('en-US', { month: 'short', day: '2-digit', year: 'numeric' }), ]; setTxRows((prev) => [newRow, ...prev]); setAppliedCoupon(null); setCouponCode(''); } else { setPaymentStep('error'); } } 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 = { 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 = { 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 = {}; 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 = { 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 (

{field}

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`} />
} > {(faq, i) => (

{faq.a}

)}

Final review mode: check all tabs, then submit for approval.}> Step {activePortfolioStepIndex + 1} of {portfolioStepKeys.length}

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 } >
); }; const renderCustomerContent = () => { const tab = resolvedTabKey(); if (customerKey() === 'my dashboard') { if (tab === 'recent requirements') { return (

Recent Requirements

{(row) => { const chip = statusChip(row.status); return (
{row.title} {row.amount} {row.status} {row.responses} responses
); }}
); } if (tab === 'quick actions') { return (

Quick Actions

{['Post New Requirement', 'View Responses', 'Buy Credits', 'Explore Professionals'].map((a, i) => ( ))}

Recent Activity

{['Requirement posted', 'New response received', 'Credit purchase completed'].map((a) =>
{a}
)}
); } return (

Complete Verification

To start receiving opportunities, submit your profile and portfolio for admin approval.

Step 1

Profile: {approvalTone(profileApprovalState()).label}

Step 2

Portfolio: {approvalTone(portfolioApprovalState()).label}

Widget Customization

Drag and drop cards below to reorder your dashboard widgets.

Welcome back, {props.liveData?.userName ?? 'Alex'}

To start receiving opportunities, complete My Profile and My Portfolio, then submit both for approval.

Profile Status

85%

Credits Balance

{leadCredits().toLocaleString('en-IN')}

{(w) => (
{ 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`} >

{titleCase(w)}

42

)}
); } 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 (

{labelText} *

!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" />
); }; 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 (

Settings

{(item) => ( )}

Current Password*

New Password*

Confirm Password*

{[ ['email_updates', 'Email Updates'], ['in_app_alerts', 'In-app Alerts'], ['verification_reminders', 'Verification Reminders'], ].map(([key, title]) => (

{title}

))}
{[ ['profile_visibility', 'Profile Visibility'], ['data_sharing_consent', 'Data Sharing Consent'], ].map(([key, title]) => (

{title}

))}

Delete Account

Permanently remove your account and data.

!

Delete account?

This will permanently remove your account. This action cannot be undone.

); } return (

{isPreferencesTab ? 'Preference Details' : titleCase(selectedTab)}

{fieldsForTab.length} fields
{(field) => renderField(field)}
} >
{(field) => renderField(field)}
} >

Document type*

Upload document*

What To Do Next

Complete profile and portfolio to unlock leads

Finish My Profile and My Portfolio, then submit both for admin approval. Leads will unlock only after approval.

My Profile {approvalTone(profileApprovalState()).label}
My Portfolio {approvalTone(portfolioApprovalState()).label}
); } if (customerKey() === 'leads') { if (!bothApprovalsApproved()) { return (

Leads Locked

Complete verification before accessing leads. You must submit profile and portfolio, then get admin approval.

Profile Verification

{approvalTone(profileApprovalState()).label}

Portfolio Verification

{approvalTone(portfolioApprovalState()).label}

); } 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 (

Total Spent

{250 - leadCredits()}

Tracecoins used this month

Active Requests

{leadCards().filter((card) => card.status === 'requested').length}

card.status === 'requested').length * 10)}%;background:#FF5E13`} />

Locked Credits

{lockedLeadCredits()}

Held until service seeker decision (auto-refund in 1 day)

Requested Contacts

{['Newest First', 'Oldest First'].map((item) => ( ))}
{['All Status', 'Request Sent', 'Contact Unlocked', 'Rejected', 'Expired Refunded', 'Cancelled By Professional'].map((item) => ( ))}
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" />
Sort: {requestedSortFilter()} Status: {requestedStatusFilter()}
{['Lead ID', 'Lead Title', 'Request Date', 'Request Status', 'Cost', 'Decision Date', 'Action'].map((h) => ( ))} {(row) => { const badge = requestStatusPill(row.status); return ( ); }}
{h}
#{row.id}

{row.title}

{row.city}

{row.requestDate} {badge.text} {leadCostPerContact} {row.decisionDate}

Showing {pagedRequestedRows().length ? (requestedPage() - 1) * requestedPerPage + 1 : 0} to {(requestedPage() - 1) * requestedPerPage + pagedRequestedRows().length} of {filteredRequestedRows().length} requests

i + 1)}> {(pageNo) => ( )}
); } if (leadMarketplaceTab() === 'View Details' && selectedLead()) { const lead = selectedLead()!; const spec = leadDetailsSpec(lead); return (

View Details

{lead.title}

{lead.category} • {lead.location} • {lead.area}

{lead.match}
Time Frame:{spec.timeframe} Date:{lead.dateRequired} Budget:{lead.budget} Area:{String(lead.area || 'Chennai')}

Schedule

{spec.timeframe}

Date Required

{lead.dateRequired}

Area

{String(lead.area || 'Chennai')}

Win Probability

{leadProbability(lead)}%

Work Scope

{spec.scope}

Lead Specific Highlights

{(item) =>
{item}
}
Lead ID{lead.id}
Unlock Cost NG{lead.cost} Tracecoin
Contacted{lead.contactCount}/{lead.maxContacts}
); } return (
{(item) => ( )}
setLeadSearch(e.currentTarget.value)} placeholder="Search by role, area, keyword..." style="border:none;background:transparent;outline:none;width:100%;font-size:12px;color:#111827" />

Area

Budget

Date

{['Newest First', 'Budget High-Low', 'Budget Low-High'].map((item) => ( ))}
Sort: {leadSortFilter()}
{(lead) => (
{lead.status === 'unlocked' ? 'Contact Unlocked' : lead.status === 'requested' ? 'Request Sent' : lead.status === 'closed' ? 'Lead Closed' : 'Open Lead'} {lead.category} • {lead.location}

{lead.title}

Area: {lead.area} | Date: {lead.dateRequired} | T {lead.cost} | {leadProbability(lead)}% | {lead.contactCount}/{lead.maxContacts} contacted {Math.max(0, lead.maxContacts - lead.contactCount)} slots left

{lead.match}

{lead.budget}

Est. Budget

)}

Showing {pagedLeadCards().length ? (leadPage() - 1) * leadsPerPage + 1 : 0} to {(leadPage() - 1) * leadsPerPage + pagedLeadCards().length} of {filteredLeadCards().length} leads

i + 1)}> {(pageNo) => ( )}
T

Confirm Contact Unlock

You are about to spend 25 Tracecoins to request and view this service seeker contact when approved. Do you want to continue?

); } 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 (
{[ { 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) => (

{card.label}

{card.value}

))}

Latest Updates

Track your application status and recruiter responses
{(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 (

{row.id} • Applied On Oct 12, 2023

{row.title}

{row.company} • {row.location}

{row.status}

{row.note}

); }}

Boost your response rate

Recruiters are more likely to respond to profiles with updated resume and portfolio links.

); } if (jobSeekerScreen() === 'apply') { return (
{[ { key: 1, label: 'Profile' }, { key: 2, label: 'Materials' }, { key: 3, label: 'Details' }, { key: 4, label: 'Review' }, ].map((step, idx, arr) => ( <> ))}

Resume & Portfolio

Showcase your best work and professional journey to the hiring team.

Resume (PDF)

Drop your resume here or browse

Maximum file size: 5MB

Portfolio Link

https://yourportfolio.com

Cover Letter

Optional doc

GitHub Profile

Optional link

); } if (jobSeekerScreen() === 'detail') { return (

Available Positions

Found 128 high-match opportunities for your profile.

{(job) => ( )}

{selectedJob().title}

{selectedJob().company} • {selectedJob().location}

{[ ['Location', selectedJob().location], ['Experience', selectedJob().exp], ['Employment', selectedJob().type], ['Compensation', selectedJob().salary], ['Match', selectedJob().match], ['Posted', selectedJob().posted], ].map(([label, val]) => (

{label}

{val}

))}

Skills

{(tag) => {tag}}

The Opportunity

As a senior role at Nxtgauge, you will shape product experiences used by thousands of professionals and build systems that scale with ambition.

Core Requirements

{[ 'Mastery of product and design system governance.', 'Strong track record of shipping complex B2B products.', 'Deep understanding of accessibility and UX research.', ].map((item) =>

• {item}

)}

Total Compensation

{selectedJob().salary} / year

Application update: {selectedJob().posted}

); } return (
{[ { 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) => (

{card.label}

{card.value}

))}
{['Role: All Roles', 'Industry: Tech', 'Location: Remote', 'Salary: $100k+', 'Experience: Senior'].map((item) => ( ))}
{(job) => (

{job.title}

{job.company} • {job.location}

{[job.salary, job.exp, job.type].map((pill, idx) => ( {pill} ))}
{(tag) => {tag}}
{job.match}

{job.posted}

)}
); } 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 (

Job Submitted Successfully!

Your listing for {companyJobDraft().title} has been sent to Verification Management first, then Approval Management. Job seekers can see it only after final approval.

Application Submitted } >

{latestStatusLabel()}

Approval Tracking

REF: #JX-9902
{[ { 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) => (
{row.done ? '✓' : idx + 1}

{row.title}

{row.desc}

))}

Did you know?

Jobs with high-quality company descriptions receive 40% more applications. Take a moment to update your profile.

Back to Dashboard

Monitor all your active listings and candidate inflow.

Need help?

Chat with a hiring specialist

); } if (jobPostView() === 'review') { return (

Jobs > Review & Checkout

Review & Checkout

Step 5 of 5: Finalize your job posting details and approve payment.

Job Basics

{[ ['Job Title', companyJobDraft().title], ['Employment Type', companyJobDraft().type], ['Company Department', companyJobDraft().department], ['Openings', companyJobDraft().openings], ].map(([label, value]) => (

{label}

{value}

))}

Role & Requirements

Technical Skills

{(skill) => {skill}}

Required Experience

{companyJobDraft().exp}

Compensation & Location

Salary Range

{companyJobDraft().salary} / year

Location

{companyJobDraft().location}

Pricing & Approval

Review costs and confirm submission

Post Status This is a Paid Job Post
Credits Required500 Tracecoins
Current Balance1200 Tracecoins
Remaining Balance700 Tracecoins

Approval Required: Yes

Your post will be reviewed by our moderation team within 24 hours.

Pro Tip

Boost your visibility by 40% with Sponsored Highlights.

); } return (

Billing Policy

Job Posting Rule

Free First Job

Cost Required

0 Tracecoins

Usage Count

1 Job Posted

Lifecycle

Approval Flow Status

{(step, idx) => ( <> {idx() + 1} )}

Step {jobPostStep()}: {COMPANY_JOB_STEPS[jobPostStep() - 1]}

Job Title

{companyJobDraft().title}

Department

{companyJobDraft().department}

Job Category

Select Category

Employment Type

{companyJobDraft().type}

Seniority

Entry Level

Openings

{companyJobDraft().openings}

Description

Detailed job responsibilities, skills, and expectations...

Live Preview

FREE POST

Position

Product Design Manager

{[ ['Location', 'Remote / San Francisco'], ['Type', 'Full-Time Role'], ['Posting Fee', '$0.00 (Tracecoins: 0)'], ].map(([label, val]) => (
{label} {val}
))}

Need help writing?

Try our AI Generator to create a compelling description in seconds.

); } 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 (

Post New Requirement

{(step, idx) => (
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}

{step}

idx() + 1 ? '#FF5E13' : '#E5E7EB'};margin-top:16px`} />
)}

What kind of professional are you looking for?

Select a category to start your requirement. This helps us match you with the right experts.

{(role) => { const active = selectedRequirementRole() === role.key; return ( ); }}

Basic Requirement Details

Add core details before role-specific inputs.

{['Requirement Title', 'Priority', 'Requirement Description', 'Expected Start Date', 'Service City', 'Contact Number'].map((field) => (

{field}

Enter {field.toLowerCase()}
))}

{selectedRoleDetails().title}

{selectedRoleDetails().subtitle}

{(field, idx) => (

{field}

{idx() % 2 === 0 ? 'Select' : 'Enter'} {field.toLowerCase()}
)}
{(toggleLabel) => (
{toggleLabel}
)}

Style Needed

{(styleLabel) => (
{styleLabel}
)}

Budget & Location

Set your target budget and service location to get relevant quotes.

{['Budget Range', 'Urgency Level', 'Service Location', 'Mode (Remote / On-site)', 'Preferred Start Date', 'Flexible Budget'].map((field, idx) => (

{field}

{idx % 2 === 0 ? 'Enter' : 'Select'} {field.toLowerCase()}
))}

Attachments

Upload reference files to help professionals understand your requirement better.

{[1, 2, 3, 4].map((slot) => (
+

Attachment {slot}

))}

Review & Submit

Final check before submitting for approval.

{[ ['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]) => (
{label} {value}
))}

Approval Flow

Submit For Approval

Once submitted, your requirement goes to Verification Management first, then Approval Management. Only after both stages it goes live in professional leads.

{['Draft Created', 'Verification Management', 'Approval Management', 'Live In Leads'].map((state, idx) => (
{idx < 2 ? '✓' : idx + 1} {state}
))}
); } if (requirementsView() === 'detail') { const selectedRow = requirementRows().find((row) => row.id === selectedRequirementId()) || requirementRows()[0]; const status = statusMeta(selectedRow.status); return (

Requirements > Details

{selectedRow.title}

{status.label} Active Created on {selectedRow.submission}
{[ ['Proposed Budget', selectedRow.budget], ['Location & Urgency', selectedRow.location], ['Project Scope', '3 Day Event'], ].map(([label, val]) => (

{label}

{val}

))}

Requirement Overview

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.

Special Instructions

  • Mandatory experience in similar premium projects.
  • Must be available for milestone reviews every 72 hours.
  • NDA required before onboarding and deliverable sharing.

Reference Material

{[1, 2, 3, 4].map((slot) => (
{slot === 4 ? 'Add More' : `Asset ${slot}`}
))}

Response Metrics

08

Total Responses

03 Shortlisted 03 Rejected

Approval History

{['Requirement Approved', 'Under Review', 'Submitted', 'Draft Created'].map((step) => (

{step}

Oct 24, 2023

))}
{['Extend Expiry', 'Edit Details', 'Close Requirement'].map((action, idx) => ( ))}
); } 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 (

My Requirements

Create, submit for approval, and manage your requirements with precision and clarity.

{[ ['Total Requirements', String(totalCount)], ['Drafts', String(draftCount)], ['Submitted', String(submittedCount)], ['Approved', String(approvedCount)], ['Active', String(activeCount)], ['Rejected', String(rejectedCount)], ].map(([label, value], idx) => (

{label}

{value}

))}
{['All Requirements', 'Drafts', 'Submitted', 'Approved', 'Active', 'Rejected', 'Closed', 'Expired'].map((label, idx) => ( ))}
Search ID or Title...
{['Sort By: Newest', 'Category: All', 'Status: All'].map((item) => ( ))}
{['ID', 'Requirement Details', 'Category', 'Budget & Location', 'Submission', 'Status', 'Actions'].map((head) => ( ))} {(row) => { const status = statusMeta(row.status); return ( ); }}
{head}
{row.id}

{row.title}

{row.summary}

{row.category}

{row.budget}

{row.location}

{row.submission} {status.label}

{row.responseTag}

Showing 1 to {Math.min(filteredRows.length, 6)} of {filteredRows.length} requirements

{[1, 2, 3].map((p) => )}
); } 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 (

My Responses • View Details

{lead.title}

{lead.category} • {lead.location} • {lead.area}

Schedule

{spec.timeframe}

Date Required

{lead.dateRequired}

Area

{String(lead.area || 'Chennai')}

Unlock Cost

{lead.cost} Tracecoin

Work Scope

{spec.scope}

Lead Specific Highlights

{(item) =>
{item}
}
Lead ID{lead.id}
Category{lead.category}
Location{lead.location}
StatusFrom My Responses
); } return (

My Responses

{['Newest First', 'Oldest First'].map((item) => ( ))}
{['All Status', 'Request Sent', 'Contact Unlocked', 'Rejected', 'Expired Refunded', 'Cancelled By Professional'].map((item) => ( ))}
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" />
Sort: {requestedSortFilter()} Status: {requestedStatusFilter()}
{['Lead ID', 'Lead Title', 'Request Date', 'Status', 'Cost', 'Decision Date', 'Action'].map((h) => ( ))} {(row) => { const badge = leadStatusPill(row.status); return ( ); }}
{h}
#{row.id}

{row.title}

{row.city}

{row.requestDate} {badge.text} {leadCostPerContact} {row.decisionDate}

Showing {pagedList.length ? (currentPage - 1) * requestedPerPage + 1 : 0} to {(currentPage - 1) * requestedPerPage + pagedList.length} of {list.length} responses

i + 1)}> {(pageNo) => ( )}
); } 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 (

Before accepting contact request, review portfolio, experience, and quoted charges.

{(row) => { const chip = statusChip(row.status); return (

{row.name}

Applied for active requirement

Experience: 7+ years

{row.quote}
{row.status}
); }}
); } 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 (
{(p) => (

{p.name}

High-potential response for active requirement

Quoted {p.quote}

)}
); } 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 (

Finalize Purchase

Selected Package

{pkg.display_name || pkg.name}

{(Number(pkg.credits) + Number(pkg.bonus_credits || 0)).toLocaleString()} TC

Total Tracecoins

Base Credits {Number(pkg.credits).toLocaleString()}
0}>
Bonus Credits +{Number(pkg.bonus_credits).toLocaleString()}
{/* Coupon section */}

Coupon Code

setCouponCode(e.currentTarget.value)} style="flex:1;height:32px;border:1px solid #E5E7EB;border-radius:6px;padding:0 8px;font-size:12px" disabled={couponLoading()} />

{couponError()}

Coupon ({appliedCoupon()!.code}) -{appliedCoupon()!.discount_type === 'PERCENT' ? `${appliedCoupon()!.discount_value}%` : `₹${appliedCoupon()!.discount_value}`}
Total Amount ₹{((appliedCoupon() ? appliedCoupon().final_price_inr : Number(pkg.price_paise)) / 100).toLocaleString('en-IN')}

Secure Gateway

Continue to our secure partner gateway to complete the transaction.

{step === 'processing' ? 'Creating Order...' : 'Verifying Payment...'}

Please do not refresh or close the page.

Payment Successful!

Your account has been credited with {(Number(pkg.credits) + Number(pkg.bonus_credits || 0)).toLocaleString()} Tracecoins.

New Balance

{leadCredits().toLocaleString()} TC

Payment Failed

Something went wrong with the mock gateway. Please try again.

); }; const renderCreditManagement = () => { let amtInput: HTMLInputElement | undefined; let rsnInput: HTMLInputElement | undefined; return (

Credit Management Console

Current User Balance

{leadCredits().toLocaleString()} TC

Note: Adjustments are final and logged in transaction history for auditing.

); }; if (checkoutPackage()) return renderCheckout(); if (creditManageView()) return renderCreditManagement(); if (tab === 'buy credits') { return (

Current Balance

{leadCredits().toLocaleString()} Tracecoins

+12% from last month

{(pkg) => (
MOST POPULAR

{pkg.name}

{pkg.display_name || pkg.name}

{Number(pkg.credits).toLocaleString()}

Credits

0}>

+{pkg.bonus_credits} bonus

₹{(Number(pkg.price_paise) / 100).toLocaleString('en-IN')}

)}

Why buy larger packs?

More savings

Higher packs include bonus credits.

No expiry

Credits stay active with your account.

Instant activation

Credits reflect right after purchase.

Recommended

Start with Standard

Best value for active buying and response unlocks.

); } if (tab === 'transactions') { return (
{['Invoice No', 'Package', 'Credits', 'Amount Paid', 'Status', 'Date', 'Actions'].map((h) => ( ))} {txRows().map((row) => ( ))}
{h}
{row[0]} {row[1]} {row[2]} {row[3]} {row[4]} {row[5]}

Showing 1 to 4 of 42 transactions

{[1, 2, 3].map((p) => ( ))}
); } if (tab === 'usage history') { return (

Total Used (30d)

12,480

Most Used Action

Boost Profile

Current Balance

12,450 TC

{['Usage ID', 'Action Type', 'Credits Used', 'Related ID', 'Date', 'Remarks'].map((h) => ( ))} {[ ['#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) => ( ))}
{h}
{row[0]} {row[1]} {row[2]} {row[3]} {row[4]} {row[5]}

Showing 1 to 4 of 142 results

{[1, 2, 3].map((p) => ( ))}
); } if (tab === 'invoices') { return (
{['Invoice Number', 'Billing Date', 'Package', 'Total', 'Status'].map((h) => ( ))} {invoiceRows.map((row) => ( ))}
{h}
{row[0]} {row[1]} {row[2]} {row[3]} {row[4]}

Showing 1 to 4 of 24 invoices

{[1, 2, 3].map((p) => ( ))}
); } return (

Current Balance

12,450 TC

+12% from last month

Monthly Usage

1,248

Avg 42/day

Pending Invoices

1

Recent Transactions

{['Transaction ID', 'Package', 'Credits', 'Amount Paid', 'Status', 'Date'].map((h) => ( ))} {txRows().slice(0, 3).map((row: any) => ( ))}
{h}
{row[0]} {row[1]} {row[2]} {row[3]} {row[4]} {row[5]}
); } if (customerKey() === 'explore nxtgauge') { return (

Explore opportunities on Nxtgauge

Discover services, connect with verified users, and expand into additional roles using the same dashboard workflow.

{[ { 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 (

{roleCard.title}

{roleCard.subtitle}

); })}

Professional Services

Choose from 10 professional roles, including UGC Content Creator.

{(role) => (
} > {role.status}

{role.title}

{role.subtitle}

)}

Growth Advantage

Why Add More Services?

A multi-service profile helps you acquire more opportunities, improve trust, and scale consistently on a single platform.

Reach More Buyers

Get discovered by customers across multiple demand categories.

Increase Revenue Paths

Offer additional services and create new income streams.

Strengthen Credibility

Verified multi-service profiles build confidence and improve conversion.

Scale Faster

Grow your business from one unified account and workflow.

); } if (customerKey() === 'verification') { if (tab === 'approval status') { return (

Verification Center

Complete just 2 steps. Submit profile and portfolio. We review and unlock access.

Step 1

Profile: {approvalTone(profileApprovalState()).label}

Step 2

Portfolio: {approvalTone(portfolioApprovalState()).label}

Final Access

{bothApprovalsApproved() ? 'Unlocked' : 'Blocked'}

Profile Verification

Finish your basic information and required documents, then submit.

Portfolio Verification

Add portfolio details and submit separately for review.

Admin Flow: once submitted, both items appear in Verification Management. Admin can request documents or approve. Leads remain blocked until both are approved.

); } if (tab === 'submitted details') { return (

Application Snapshot

{[ ['Service', 'Social Media Manager'], ['Submission ID', 'VRF-2023-1042'], ['Submitted On', 'Oct 22, 2023'], ['Status', 'Under Review'], ].map(([k, v]) => (
{k}: {v}
))}

Submitted Details

Strategic Social Media Manager with 6+ years of experience in content strategy, campaign planning, and audience growth for D2C brands.
{['Sprout Social', 'Figma', 'Google Analytics'].map((tool) => {tool})}
); } if (tab === 'documents') { return (

Total Documents

3

Approved

2

Needs Action

1

Admin requested missing documents

Required Missing Documents: Address Proof (clear PDF/JPG/PNG).

Documents

{[ ['Identity Proof', 'id_scan_v2.pdf', 'Approved'], ['Address Proof', 'electricity_bill.jpg', 'Rejected'], ['Tax Document', 'itr_form16_2023.pdf', 'Approved'], ].map(([doc, file, state]) => ( ))}
Document File Status Action
{doc} {file} {state} No action} >
Address Proof needs re-upload to continue verification.
); } if (tab === 're-upload') { return (

1 item needs correction

Identity proof is unclear. Please upload a clear copy.

Upload Correction

); } if (tab === 'activity') { return (

Verification Updates

{[ ['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]) => (

{title}

{time}

{state}
))}
); } return (

Details will appear here

This section is being prepared. Please use the available tabs above.

); } if (customerKey() === 'help center' || customerKey() === 'support') { const active = helpCenterTab(); return (

Help Center

Get help, manage tickets, and contact support.

Knowledge Base

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" />
Popular: {['Verification', 'Credits', 'Lead Response'].map((tag) => )}

Browse by Category

{(cat) => ( )}

{kbSearch() || kbCategory() !== 'All' ? 'Search Results' : 'Important Articles'}

{(a) => ( )}

No articles found matching your criteria.

Quick Guides

Actionable tutorials to master Nxtgauge
{[ { 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) => (
{g.level}

{g.title}

{g.text}

{g.read}

))}

My Tickets

Open: {ticketSummary().openCount} Resolved: {ticketSummary().resolvedCount}

You have {ticketSummary().total} tickets. {ticketSummary().openCount} still need action and {ticketSummary().resolvedCount} are resolved.

{HELP_TICKET_ROWS.map((t) => ( openTicketDetails(t.id)} style={`border-top:1px solid #F3F4F6;background:${activeTicketId() === t.id ? '#F5F7FF' : 'white'};cursor:pointer`}> ))}
Ticket ID Request State Priority Last Message Updated Action
{t.id} {t.title} {t.status} {t.priority} {t.lastMessage} {t.updated}

Ticket Communication

{activeTicketId()} • Share updates and attachments with support team.

Message Support

User message

{selectedTicketDetails().userMessage}

Admin reply

{selectedTicketDetails().adminMessage}

Reply to Support