import React, { useState, useEffect, useRef } from 'react'; import { Link, useNavigate } from 'react-router-dom'; import { useAppDispatch } from '../store/hooks'; import { registerUser } from '../store/slices/authThunks'; import toast from 'react-hot-toast'; import { validatePhoneNumber, validateEmail, validatePassword, validateName } from '../utils/validation'; import { Eye, EyeOff, Mail, Lock, User, Building, Phone, Sun, Moon, ArrowRight, ArrowLeft, AlertCircle, Cloud, Zap, MapPin, Globe, FileText, Briefcase, Users, TrendingUp, Calendar, Hash, CheckCircle, Circle } from 'lucide-react'; import { useAppSelector } from '../store/hooks'; import { RootState } from '../store'; import { toggleTheme } from '../store/slices/themeSlice'; import { cn } from '../utils/cn'; interface FormData { firstName: string; lastName: string; email: string; password: string; confirmPassword: string; phone: string; company: string; companyType: 'corporation' | 'llc' | 'partnership' | 'sole_proprietorship' | 'other' | ''; registrationNumber: string; gstNumber: string; panNumber: string; address: string; website: string; businessLicense: string; taxId: string; industry: string; yearsInBusiness: string; annualRevenue: string; employeeCount: string; } const Signup: React.FC = () => { const [currentStep, setCurrentStep] = useState(1); const [formData, setFormData] = useState({ firstName: '', lastName: '', email: '', password: '', confirmPassword: '', phone: '', company: '', companyType: '', registrationNumber: '', gstNumber: '', panNumber: '', address: '', website: '', businessLicense: '', taxId: '', industry: '', yearsInBusiness: '', annualRevenue: '', employeeCount: '' }); const [showPassword, setShowPassword] = useState(false); const [showConfirmPassword, setShowConfirmPassword] = useState(false); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(''); const [agreedToTerms, setAgreedToTerms] = useState(false); const [showCompanyTypeDropdown, setShowCompanyTypeDropdown] = useState(false); const [showIndustryDropdown, setShowIndustryDropdown] = useState(false); const navigate = useNavigate(); const dispatch = useAppDispatch(); const { theme } = useAppSelector((state: RootState) => state.theme); const totalSteps = 4; const companyTypes = [ { value: 'corporation', label: 'Corporation' }, { value: 'llc', label: 'LLC' }, { value: 'partnership', label: 'Partnership' }, { value: 'sole_proprietorship', label: 'Sole Proprietorship' }, { value: 'other', label: 'Other' } ]; const industries = [ 'Technology Services', 'IT Consulting', 'Cloud Services', 'Software Development', 'Digital Marketing', 'E-commerce', 'Healthcare IT', 'Financial Services', 'Education Technology', 'Manufacturing', 'Retail', 'Telecommunications', 'Energy', 'Transportation', 'Real Estate', 'Media & Entertainment', 'Professional Services', 'Other' ]; // Close dropdowns when clicking outside useEffect(() => { const handleClickOutside = (event: MouseEvent) => { const target = event.target as Element; if (!target.closest('.dropdown-container')) { setShowCompanyTypeDropdown(false); setShowIndustryDropdown(false); } }; document.addEventListener('mousedown', handleClickOutside); return () => { document.removeEventListener('mousedown', handleClickOutside); }; }, []); const handleInputChange = (field: string, value: string) => { setFormData(prev => ({ ...prev, [field]: value })); setError(''); // Clear error when user starts typing }; const validateStep = (step: number): boolean => { setError(''); switch (step) { case 1: if (!validateName(formData.firstName)) { setError('First name must be between 2 and 50 characters'); return false; } if (!validateName(formData.lastName)) { setError('Last name must be between 2 and 50 characters'); return false; } if (!validateEmail(formData.email)) { setError('Please enter a valid email address'); return false; } if (!validatePhoneNumber(formData.phone)) { setError('Please enter a valid phone number'); return false; } break; case 2: if (!validatePassword(formData.password)) { setError('Password must be at least 8 characters with uppercase, lowercase, number, and special character'); return false; } if (formData.password !== formData.confirmPassword) { setError('Passwords do not match'); return false; } if (!formData.company || formData.company.trim().length === 0) { setError('Company name is required'); return false; } break; case 3: if (!formData.companyType) { setError('Company type is required'); return false; } if (!formData.registrationNumber || formData.registrationNumber.trim().length === 0) { setError('Registration number is required'); return false; } if (!formData.address || formData.address.trim().length === 0) { setError('Business address is mandatory for vendor registration'); return false; } if (formData.address.trim().length < 10) { setError(`Business address must be at least 10 characters long. Current length: ${formData.address.trim().length} characters`); return false; } break; case 4: if (!formData.industry || formData.industry.trim().length === 0) { setError('Industry is required'); return false; } if (!formData.yearsInBusiness || formData.yearsInBusiness.trim().length === 0) { setError('Years in business is required'); return false; } if (!formData.employeeCount || formData.employeeCount.trim().length === 0) { setError('Number of employees is required'); return false; } if (isNaN(Number(formData.yearsInBusiness)) || Number(formData.yearsInBusiness) < 0) { setError('Years in business must be a valid number'); return false; } if (isNaN(Number(formData.employeeCount)) || Number(formData.employeeCount) < 1) { setError('Number of employees must be at least 1'); return false; } if (formData.annualRevenue && (isNaN(Number(formData.annualRevenue)) || Number(formData.annualRevenue) < 0)) { setError('Annual revenue must be a valid number'); return false; } if (!agreedToTerms) { setError('Please agree to the terms and conditions'); return false; } break; } return true; }; const nextStep = () => { if (validateStep(currentStep)) { setCurrentStep(prev => Math.min(prev + 1, totalSteps)); } }; const prevStep = () => { setCurrentStep(prev => Math.max(prev - 1, 1)); setError(''); }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!validateStep(currentStep)) { return; } setIsLoading(true); try { // Prepare the registration data, only including fields with actual values const registrationData: any = { firstName: formData.firstName, lastName: formData.lastName, email: formData.email, password: formData.password, phone: formData.phone, company: formData.company, // Vendor-specific fields companyType: formData.companyType || undefined, registrationNumber: formData.registrationNumber, address: formData.address, industry: formData.industry, yearsInBusiness: formData.yearsInBusiness, employeeCount: formData.employeeCount, role: 'channel_partner_admin', userType: 'channel_partner' }; // Only add optional fields if they have values if (formData.gstNumber && formData.gstNumber.trim()) { registrationData.gstNumber = formData.gstNumber; } if (formData.panNumber && formData.panNumber.trim()) { registrationData.panNumber = formData.panNumber; } if (formData.website && formData.website.trim()) { registrationData.website = formData.website; } if (formData.businessLicense && formData.businessLicense.trim()) { registrationData.businessLicense = formData.businessLicense; } if (formData.taxId && formData.taxId.trim()) { registrationData.taxId = formData.taxId; } if (formData.annualRevenue && formData.annualRevenue.trim()) { registrationData.annualRevenue = formData.annualRevenue; } await dispatch(registerUser(registrationData)).unwrap(); navigate('/login', { state: { message: 'Registration successful! You can now login.' } }); } catch (err: any) { const errorMessage = err.message || 'An error occurred during signup. Please try again.'; setError(errorMessage); toast.error(errorMessage); } finally { setIsLoading(false); } }; const handleThemeToggle = () => { dispatch(toggleTheme()); }; const renderStepIndicator = () => { return (
{Array.from({ length: totalSteps }, (_, index) => (
index + 1 ? "bg-green-500 border-green-500 text-white" : currentStep === index + 1 ? "bg-blue-500 border-blue-500 text-white" : "bg-white dark:bg-slate-700 border-slate-300 dark:border-slate-600 text-slate-500" )}> {currentStep > index + 1 ? ( ) : ( {index + 1} )}
{index < totalSteps - 1 && (
index + 1 ? "bg-green-500" : "bg-slate-300 dark:bg-slate-600" )} /> )}
))}
); }; const renderStepContent = () => { switch (currentStep) { case 1: return (

Personal Information

Let's start with your basic information

handleInputChange('firstName', e.target.value)} className="block w-full pl-10 pr-3 py-3 border border-slate-300 dark:border-slate-600 rounded-xl bg-white dark:bg-slate-700 text-slate-900 placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200" placeholder="Enter first name" required />
handleInputChange('lastName', e.target.value)} className="block w-full pl-10 pr-3 py-3 border border-slate-300 dark:border-slate-600 rounded-xl bg-white dark:bg-slate-700 text-slate-900 placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200" placeholder="Enter last name" required />
handleInputChange('email', e.target.value)} className="block w-full pl-10 pr-3 py-3 border border-slate-300 dark:border-slate-600 rounded-xl bg-white dark:bg-slate-700 text-slate-900 placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200" placeholder="Enter email address" required />
handleInputChange('phone', e.target.value)} className="block w-full pl-10 pr-3 py-3 border border-slate-300 dark:border-slate-600 rounded-xl bg-white dark:bg-slate-700 text-slate-900 placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200" placeholder="Enter phone number" required />
); case 2: return (

Account Security

Create a secure password and provide company information

handleInputChange('password', e.target.value)} className="block w-full pl-10 pr-12 py-3 border border-slate-300 dark:border-slate-600 rounded-xl bg-white dark:bg-slate-700 text-slate-900 placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200" placeholder="Create password" required />
handleInputChange('confirmPassword', e.target.value)} className="block w-full pl-10 pr-12 py-3 border border-slate-300 dark:border-slate-600 rounded-xl bg-white dark:bg-slate-700 text-slate-900 placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200" placeholder="Confirm password" required />
handleInputChange('company', e.target.value)} className="block w-full pl-10 pr-3 py-3 border border-slate-300 dark:border-slate-600 rounded-xl bg-white dark:bg-slate-700 text-slate-900 placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200" placeholder="Enter company name" required />
); case 3: return (

Business Details

Provide your business registration and contact information

{showCompanyTypeDropdown && (
{companyTypes.map((type) => ( ))}
)}
handleInputChange('registrationNumber', e.target.value)} className="block w-full pl-10 pr-3 py-3 border border-slate-300 dark:border-slate-600 rounded-xl bg-white dark:bg-slate-700 text-slate-900 placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200" placeholder="e.g., 1234567890" required />
handleInputChange('gstNumber', e.target.value)} className="block w-full pl-10 pr-3 py-3 border border-slate-300 dark:border-slate-600 rounded-xl bg-white dark:bg-slate-700 text-slate-900 placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200" placeholder="e.g., 24ABCDE1234F1Z9" />
handleInputChange('panNumber', e.target.value)} className="block w-full pl-10 pr-3 py-3 border border-slate-300 dark:border-slate-600 rounded-xl bg-white dark:bg-slate-700 text-slate-900 placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200" placeholder="e.g., ABCDE1234F" />
handleInputChange('address', e.target.value)} className="block w-full pl-10 pr-3 py-3 border border-slate-300 dark:border-slate-600 rounded-xl bg-white dark:bg-slate-700 text-slate-900 placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200" placeholder="Enter complete business address (min. 10 characters)" required />
Minimum 10 characters required = 10 ? "text-green-500" : "text-slate-500 dark:text-slate-400" )}> {formData.address.length}/10
handleInputChange('website', e.target.value)} className="block w-full pl-10 pr-3 py-3 border border-slate-300 dark:border-slate-600 rounded-xl bg-white dark:bg-slate-700 text-slate-900 placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200" placeholder="https://example.com" />
); case 4: return (

Business Profile

Complete your business profile and agree to terms

{showIndustryDropdown && (
{industries.map((industry) => ( ))}
)}
handleInputChange('yearsInBusiness', e.target.value)} className="block w-full pl-10 pr-3 py-3 border border-slate-300 dark:border-slate-600 rounded-xl bg-white dark:bg-slate-700 text-slate-900 placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200" placeholder="e.g., 5" required />
handleInputChange('annualRevenue', e.target.value)} className="block w-full pl-10 pr-3 py-3 border border-slate-300 dark:border-slate-600 rounded-xl bg-white dark:bg-slate-700 text-slate-900 placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200" placeholder="e.g., 1000000" />
handleInputChange('employeeCount', e.target.value)} className="block w-full pl-10 pr-3 py-3 border border-slate-300 dark:border-slate-600 rounded-xl bg-white dark:bg-slate-700 text-slate-900 placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all duration-200" placeholder="e.g., 50" required />
{/* Terms and Conditions */}
setAgreedToTerms(e.target.checked)} className="h-4 w-4 text-blue-600 focus:ring-blue-500 border-slate-300 dark:border-slate-600 rounded mt-1" />
); default: return null; } }; return (
{/* Theme Toggle */}
{/* Logo and Header */}

Join Cloudtopiaa Connect

Partner with us to offer next-gen cloud services.

{/* Step Indicator */} {renderStepIndicator()} {/* Signup Form */}
{renderStepContent()} {/* Error Message */} {error && (
{error}
)} {/* Navigation Buttons */}
{currentStep < totalSteps ? ( ) : ( )}
{/* Sign In Link */}

Already have an account?{' '} Sign in here

{/* Switch to Reseller */}

Are you a Reseller?{' '} Sign up here

{/* Footer */}

© 2025 Cloudtopiaa. All rights reserved.

); }; export default Signup;