import React, { useEffect, useRef, useState } from 'react'; import { Form, Input, Button, Typography, Card, Avatar, Tag, Alert, Space, Dropdown, MenuProps } from '@/shared/antd-imports'; import { CloseCircleOutlined, MailOutlined, PlusOutlined, UserOutlined, CheckCircleOutlined, ExclamationCircleOutlined, GlobalOutlined } from '@/shared/antd-imports'; import { useTranslation } from 'react-i18next'; import { setTeamMembers } from '@/features/account-setup/account-setup.slice'; import { useDispatch, useSelector } from 'react-redux'; import { RootState } from '@/app/store'; import { validateEmail } from '@/utils/validateEmail'; import { sanitizeInput } from '@/utils/sanitizeInput'; import { setLanguage } from '@/features/i18n/localesSlice'; const { Title, Paragraph, Text } = Typography; interface Email { id: number; value: string; } interface MembersStepProps { isDarkMode: boolean; styles: any; token?: any; } const getEmailSuggestions = (orgName?: string) => { if (!orgName) return []; const cleanOrgName = orgName.toLowerCase().replace(/[^a-z0-9]/g, ''); return [`info@${cleanOrgName}.com`, `team@${cleanOrgName}.com`, `hello@${cleanOrgName}.com`, `contact@${cleanOrgName}.com`]; }; const getRoleSuggestions = (t: any) => [ { role: 'Designer', icon: '🎨', description: t('roleSuggestions.designer') }, { role: 'Developer', icon: 'πŸ’»', description: t('roleSuggestions.developer') }, { role: 'Project Manager', icon: 'πŸ“Š', description: t('roleSuggestions.projectManager') }, { role: 'Marketing', icon: 'πŸ“’', description: t('roleSuggestions.marketing') }, { role: 'Sales', icon: 'πŸ’Ό', description: t('roleSuggestions.sales') }, { role: 'Operations', icon: 'βš™οΈ', description: t('roleSuggestions.operations') } ]; const MembersStep: React.FC = ({ isDarkMode, styles, token }) => { const { t, i18n } = useTranslation('account-setup'); const { teamMembers, organizationName } = useSelector( (state: RootState) => state.accountSetupReducer ); const { language } = useSelector((state: RootState) => state.localesReducer); const inputRefs = useRef<(HTMLInputElement | null)[]>([]); const dispatch = useDispatch(); const [focusedIndex, setFocusedIndex] = useState(null); const [showSuggestions, setShowSuggestions] = useState(false); const [validatedEmails, setValidatedEmails] = useState>(new Set()); const emailSuggestions = getEmailSuggestions(organizationName); const addEmail = () => { if (teamMembers.length >= 5) return; const newId = teamMembers.length > 0 ? Math.max(...teamMembers.map(t => t.id)) + 1 : 0; dispatch(setTeamMembers([...teamMembers, { id: newId, value: '' }])); setTimeout(() => inputRefs.current[teamMembers.length]?.focus(), 100); }; const removeEmail = (id: number) => { if (teamMembers.length > 1) dispatch(setTeamMembers(teamMembers.filter(teamMember => teamMember.id !== id))); }; const updateEmail = (id: number, value: string) => { const sanitizedValue = sanitizeInput(value); dispatch(setTeamMembers(teamMembers.map(teamMember => teamMember.id === id ? { ...teamMember, value: sanitizedValue } : teamMember))); }; const handleKeyPress = (e: React.KeyboardEvent, index: number) => { if (e.key === 'Enter') { const input = e.currentTarget as HTMLInputElement; if (input.value.trim() && validateEmail(input.value.trim())) { e.preventDefault(); if (index === teamMembers.length - 1 && teamMembers.length < 5) addEmail(); else if (index < teamMembers.length - 1) inputRefs.current[index + 1]?.focus(); } } }; const handleSuggestionClick = (suggestion: string) => { const emptyEmailIndex = teamMembers.findIndex(member => !member.value.trim()); if (emptyEmailIndex !== -1) { updateEmail(teamMembers[emptyEmailIndex].id, suggestion); } else if (teamMembers.length < 5) { const newId = teamMembers.length > 0 ? Math.max(...teamMembers.map(t => t.id)) + 1 : 0; dispatch(setTeamMembers([...teamMembers, { id: newId, value: suggestion }])); } setShowSuggestions(false); }; useEffect(() => { setTimeout(() => inputRefs.current[0]?.focus(), 200); }, []); const getEmailStatus = (email: string, memberId: number) => { if (!email.trim()) return 'empty'; if (!validatedEmails.has(memberId)) return 'empty'; return validateEmail(email) ? 'valid' : 'invalid'; }; const handleBlur = (memberId: number, email: string) => { setFocusedIndex(null); if (email.trim()) setValidatedEmails(prev => new Set(prev).add(memberId)); }; const languages = [ { key: 'en', label: t('languages.en'), flag: 'πŸ‡ΊπŸ‡Έ' }, { key: 'es', label: t('languages.es'), flag: 'πŸ‡ͺπŸ‡Έ' }, { key: 'pt', label: t('languages.pt'), flag: 'πŸ‡΅πŸ‡Ή' }, { key: 'de', label: t('languages.de'), flag: 'πŸ‡©πŸ‡ͺ' }, { key: 'alb', label: t('languages.alb'), flag: 'πŸ‡¦πŸ‡±' }, { key: 'zh', label: t('languages.zh'), flag: 'πŸ‡¨πŸ‡³' } ]; const handleLanguageChange = (languageKey: string) => { dispatch(setLanguage(languageKey)); i18n.changeLanguage(languageKey); }; const currentLanguage = languages.find(lang => lang.key === language) || languages[0]; const languageMenuItems: MenuProps['items'] = languages.map(lang => ({ key: lang.key, label:
{lang.flag}{lang.label}
, onClick: () => handleLanguageChange(lang.key) })); return (
{/* Header */}
{t('membersStepTitle')} {t('membersStepDescription', { organizationName })}
{/* Team Members List */}
{teamMembers.map((teamMember, index) => { const emailStatus = getEmailStatus(teamMember.value, teamMember.id); return (
: emailStatus === 'invalid' ? : } />
updateEmail(teamMember.id, e.target.value)} onKeyPress={e => handleKeyPress(e, index)} onFocus={() => setFocusedIndex(index)} onBlur={() => handleBlur(teamMember.id, teamMember.value)} ref={el => inputRefs.current[index] = el} className="border-0 shadow-none" style={{ backgroundColor: 'transparent', color: token?.colorText }} prefix={} status={emailStatus === 'invalid' ? 'error' : undefined} suffix={ emailStatus === 'valid' ? ( ) : emailStatus === 'invalid' ? ( ) : null } /> {emailStatus === 'invalid' && ( {t('invalidEmail')} )} {emailStatus === 'valid' && ( {t('validEmailAddress')} )}
{teamMembers.length > 1 && (
); })}
{/* Add Member Button */} {teamMembers.length < 5 && ( )}
{/* Skip Option */}
); }; export default MembersStep;