feat(account-setup): enhance localization and UI for account setup process
- Added new language support and improved translations for account setup steps across multiple languages. - Updated the organization step to streamline user input and enhance suggestions for organization names. - Refactored task management components to improve user experience when adding and managing tasks. - Removed outdated CSS for admin center components to simplify styling and improve maintainability. - Introduced new UI elements and transitions for a more engaging account setup experience. - Enhanced Redux state management to accommodate new features and localization updates.
This commit is contained in:
@@ -22,29 +22,19 @@ interface MembersStepProps {
|
||||
token?: any;
|
||||
}
|
||||
|
||||
// Common email suggestions based on organization
|
||||
const getEmailSuggestions = (orgName?: string) => {
|
||||
if (!orgName) return [];
|
||||
|
||||
const cleanOrgName = orgName.toLowerCase().replace(/[^a-z0-9]/g, '');
|
||||
const suggestions = [
|
||||
`info@${cleanOrgName}.com`,
|
||||
`team@${cleanOrgName}.com`,
|
||||
`hello@${cleanOrgName}.com`,
|
||||
`contact@${cleanOrgName}.com`
|
||||
];
|
||||
|
||||
return suggestions;
|
||||
return [`info@${cleanOrgName}.com`, `team@${cleanOrgName}.com`, `hello@${cleanOrgName}.com`, `contact@${cleanOrgName}.com`];
|
||||
};
|
||||
|
||||
// Role suggestions for team members
|
||||
const roleSuggestions = [
|
||||
{ role: 'Designer', icon: '🎨', description: 'UI/UX, Graphics, Creative' },
|
||||
{ role: 'Developer', icon: '💻', description: 'Frontend, Backend, Full-stack' },
|
||||
{ role: 'Project Manager', icon: '📊', description: 'Planning, Coordination' },
|
||||
{ role: 'Marketing', icon: '📢', description: 'Content, Social Media, Growth' },
|
||||
{ role: 'Sales', icon: '💼', description: 'Business Development, Client Relations' },
|
||||
{ role: 'Operations', icon: '⚙️', description: 'Admin, HR, Finance' }
|
||||
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<MembersStepProps> = ({ isDarkMode, styles, token }) => {
|
||||
@@ -63,30 +53,18 @@ const MembersStep: React.FC<MembersStepProps> = ({ isDarkMode, styles, token })
|
||||
|
||||
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(() => {
|
||||
const newIndex = teamMembers.length;
|
||||
inputRefs.current[newIndex]?.focus();
|
||||
}, 100);
|
||||
setTimeout(() => inputRefs.current[teamMembers.length]?.focus(), 100);
|
||||
};
|
||||
|
||||
const removeEmail = (id: number) => {
|
||||
if (teamMembers.length > 1) {
|
||||
dispatch(setTeamMembers(teamMembers.filter(teamMember => teamMember.id !== id)));
|
||||
}
|
||||
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
|
||||
)
|
||||
)
|
||||
);
|
||||
dispatch(setTeamMembers(teamMembers.map(teamMember => teamMember.id === id ? { ...teamMember, value: sanitizedValue } : teamMember)));
|
||||
};
|
||||
|
||||
const handleKeyPress = (e: React.KeyboardEvent<HTMLInputElement>, index: number) => {
|
||||
@@ -94,11 +72,8 @@ const MembersStep: React.FC<MembersStepProps> = ({ isDarkMode, styles, token })
|
||||
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();
|
||||
}
|
||||
if (index === teamMembers.length - 1 && teamMembers.length < 5) addEmail();
|
||||
else if (index < teamMembers.length - 1) inputRefs.current[index + 1]?.focus();
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -115,32 +90,27 @@ const MembersStep: React.FC<MembersStepProps> = ({ isDarkMode, styles, token })
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setTimeout(() => {
|
||||
inputRefs.current[0]?.focus();
|
||||
}, 200);
|
||||
setTimeout(() => inputRefs.current[0]?.focus(), 200);
|
||||
}, []);
|
||||
|
||||
const getEmailStatus = (email: string, memberId: number) => {
|
||||
if (!email.trim()) return 'empty';
|
||||
if (!validatedEmails.has(memberId)) return 'empty';
|
||||
if (validateEmail(email)) return 'valid';
|
||||
return 'invalid';
|
||||
return validateEmail(email) ? 'valid' : 'invalid';
|
||||
};
|
||||
|
||||
const handleBlur = (memberId: number, email: string) => {
|
||||
setFocusedIndex(null);
|
||||
if (email.trim()) {
|
||||
setValidatedEmails(prev => new Set(prev).add(memberId));
|
||||
}
|
||||
if (email.trim()) setValidatedEmails(prev => new Set(prev).add(memberId));
|
||||
};
|
||||
|
||||
const languages = [
|
||||
{ key: 'en', label: 'English', flag: '🇺🇸' },
|
||||
{ key: 'es', label: 'Español', flag: '🇪🇸' },
|
||||
{ key: 'pt', label: 'Português', flag: '🇵🇹' },
|
||||
{ key: 'de', label: 'Deutsch', flag: '🇩🇪' },
|
||||
{ key: 'alb', label: 'Shqip', flag: '🇦🇱' },
|
||||
{ key: 'zh', label: '简体中文', flag: '🇨🇳' }
|
||||
{ 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) => {
|
||||
@@ -148,18 +118,8 @@ const MembersStep: React.FC<MembersStepProps> = ({ isDarkMode, styles, token })
|
||||
i18n.changeLanguage(languageKey);
|
||||
};
|
||||
|
||||
const languageMenuItems: MenuProps['items'] = languages.map(lang => ({
|
||||
key: lang.key,
|
||||
label: (
|
||||
<div className="flex items-center space-x-2">
|
||||
<span>{lang.flag}</span>
|
||||
<span>{lang.label}</span>
|
||||
</div>
|
||||
),
|
||||
onClick: () => handleLanguageChange(lang.key)
|
||||
}));
|
||||
|
||||
const currentLanguage = languages.find(lang => lang.key === language) || languages[0];
|
||||
const languageMenuItems: MenuProps['items'] = languages.map(lang => ({ key: lang.key, label: <div className="flex items-center space-x-2"><span>{lang.flag}</span><span>{lang.label}</span></div>, onClick: () => handleLanguageChange(lang.key) }));
|
||||
|
||||
return (
|
||||
<div className="w-full members-step">
|
||||
@@ -284,26 +244,6 @@ const MembersStep: React.FC<MembersStepProps> = ({ isDarkMode, styles, token })
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Language Switcher */}
|
||||
<div className="flex justify-center mt-8">
|
||||
<Dropdown
|
||||
menu={{ items: languageMenuItems }}
|
||||
placement="topCenter"
|
||||
trigger={['click']}
|
||||
>
|
||||
<Button
|
||||
type="text"
|
||||
size="small"
|
||||
icon={<GlobalOutlined />}
|
||||
className="flex items-center space-x-2"
|
||||
style={{ color: token?.colorTextTertiary }}
|
||||
>
|
||||
<span>{currentLanguage.flag}</span>
|
||||
<span>{currentLanguage.label}</span>
|
||||
</Button>
|
||||
</Dropdown>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user