feat(account-setup): enhance account setup process with new survey and task management features
- Expanded localization files to include additional text for account setup steps in multiple languages. - Introduced new components for the survey step, allowing users to provide feedback on their needs and preferences. - Implemented task management features, enabling users to add and manage tasks during the account setup process. - Enhanced the organization step with suggestions for organization names based on industry categories. - Improved UI/UX with new design elements and transitions for a smoother user experience. - Updated Redux state management to handle new survey and task data effectively. - Added language switcher functionality to support multilingual users during the setup process.
This commit is contained in:
@@ -219,4 +219,205 @@
|
||||
/* Smooth transitions for theme switching */
|
||||
* {
|
||||
transition: background-color 0.3s ease, color 0.3s ease, border-color 0.3s ease;
|
||||
}
|
||||
|
||||
/* Survey step transitions */
|
||||
.survey-page-transition {
|
||||
animation: fadeInUp 0.4s ease-out;
|
||||
}
|
||||
|
||||
@keyframes fadeInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Survey option hover effects */
|
||||
.survey-option-card {
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.survey-option-card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* Progress bar animation */
|
||||
.ant-progress-line {
|
||||
transition: all 0.5s ease-out;
|
||||
}
|
||||
|
||||
/* Survey button animations */
|
||||
.survey-nav-button {
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.survey-nav-button:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
/* Project step enhancements */
|
||||
.project-suggestion-button {
|
||||
transition: all 0.2s ease;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.project-suggestion-button:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.project-suggestion-button:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.template-preview-card {
|
||||
transition: all 0.3s ease;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.template-preview-card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.template-preview-card.selected {
|
||||
box-shadow: 0 4px 20px rgba(24, 144, 255, 0.2);
|
||||
}
|
||||
|
||||
/* Enhanced form styling for project step */
|
||||
.project-step .ant-input-affix-wrapper {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.project-step .ant-input-affix-wrapper:focus-within {
|
||||
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.1);
|
||||
}
|
||||
|
||||
.project-step .ant-card {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.project-step .ant-card:hover {
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
/* Organization step enhancements */
|
||||
.organization-step .ant-input-affix-wrapper {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.organization-step .ant-input-affix-wrapper:focus-within {
|
||||
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.1);
|
||||
border-color: #1890ff;
|
||||
}
|
||||
|
||||
.organization-step .ant-card {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.organization-step .ant-card:hover {
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.organization-suggestion-button {
|
||||
transition: all 0.2s ease;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.organization-suggestion-button:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.organization-suggestion-button:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
/* Character counter styling */
|
||||
.organization-step .character-counter {
|
||||
font-size: 12px;
|
||||
opacity: 0.7;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.organization-step .character-counter.active {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Naming tips hover effect */
|
||||
.organization-step .naming-tip {
|
||||
transition: all 0.2s ease;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.organization-step .naming-tip:hover {
|
||||
background-color: rgba(24, 144, 255, 0.05);
|
||||
}
|
||||
|
||||
/* Tasks step enhancements */
|
||||
.tasks-step .task-item-card {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.tasks-step .task-item-card:hover {
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.tasks-step .task-input {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.tasks-step .task-input:focus {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.task-suggestion-button {
|
||||
transition: all 0.2s ease;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.task-suggestion-button:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.task-suggestion-button:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
/* Members step enhancements */
|
||||
.members-step .member-item-card {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.members-step .member-item-card:hover {
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.members-step .member-input {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.members-step .member-input:focus {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.email-suggestion-button {
|
||||
transition: all 0.2s ease;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.email-suggestion-button:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.email-suggestion-button:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
@@ -2,10 +2,11 @@ import React, { useEffect } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { Space, Steps, Button, Typography, theme } from '@/shared/antd-imports';
|
||||
import { Space, Steps, Button, Typography, theme, Dropdown, MenuProps } from '@/shared/antd-imports';
|
||||
import { GlobalOutlined } from '@/shared/antd-imports';
|
||||
|
||||
import logger from '@/utils/errorLogger';
|
||||
import { setCurrentStep } from '@/features/account-setup/account-setup.slice';
|
||||
import { setCurrentStep, setSurveySubStep } from '@/features/account-setup/account-setup.slice';
|
||||
import { OrganizationStep } from '@/components/account-setup/organization-step';
|
||||
import { ProjectStep } from '@/components/account-setup/project-step';
|
||||
import { TasksStep } from '@/components/account-setup/tasks-step';
|
||||
@@ -34,6 +35,7 @@ import { IAccountSetupRequest } from '@/types/project-templates/project-template
|
||||
import { profileSettingsApiService } from '@/api/settings/profile/profile-settings.api.service';
|
||||
import { surveyApiService } from '@/api/survey/survey.api.service';
|
||||
import { ISurveySubmissionRequest, ISurveyAnswer } from '@/types/account-setup/survey.types';
|
||||
import { setLanguage } from '@/features/i18n/localesSlice';
|
||||
|
||||
const { Title } = Typography;
|
||||
|
||||
@@ -62,14 +64,15 @@ const getAccountSetupStyles = (token: any) => ({
|
||||
|
||||
const AccountSetup: React.FC = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation('account-setup');
|
||||
const { t, i18n } = useTranslation('account-setup');
|
||||
useDocumentTitle(t('setupYourAccount', 'Account Setup'));
|
||||
const navigate = useNavigate();
|
||||
const { trackMixpanelEvent } = useMixpanelTracking();
|
||||
const { token } = theme.useToken();
|
||||
|
||||
const { currentStep, organizationName, projectName, templateId, tasks, teamMembers, surveyData } =
|
||||
const { currentStep, organizationName, projectName, templateId, tasks, teamMembers, surveyData, surveySubStep } =
|
||||
useSelector((state: RootState) => state.accountSetupReducer);
|
||||
const { language } = useSelector((state: RootState) => state.localesReducer);
|
||||
const userDetails = getUserSession();
|
||||
const themeMode = useSelector((state: RootState) => state.themeReducer.mode);
|
||||
|
||||
@@ -266,9 +269,17 @@ const AccountSetup: React.FC = () => {
|
||||
case 0:
|
||||
return !organizationName?.trim();
|
||||
case 1:
|
||||
// Survey step - no required fields, can always continue
|
||||
// Survey step - check current sub-step requirements
|
||||
if (surveySubStep === 0) {
|
||||
return !(surveyData.organization_type && surveyData.user_role);
|
||||
} else if (surveySubStep === 1) {
|
||||
return !(surveyData.main_use_cases && surveyData.main_use_cases.length > 0);
|
||||
} else if (surveySubStep === 2) {
|
||||
return !surveyData.how_heard_about;
|
||||
}
|
||||
return false;
|
||||
case 2:
|
||||
// Project step - either project name OR template must be provided
|
||||
return !projectName?.trim() && !templateId;
|
||||
case 3:
|
||||
return tasks.length === 0 || tasks.every(task => !task.value?.trim());
|
||||
@@ -368,11 +379,17 @@ const AccountSetup: React.FC = () => {
|
||||
|
||||
const nextStep = async () => {
|
||||
if (currentStep === 1) {
|
||||
// Save survey data when moving from survey step
|
||||
await saveSurveyData();
|
||||
}
|
||||
|
||||
if (currentStep === 4) {
|
||||
// Handle survey sub-step navigation
|
||||
if (surveySubStep < 2) {
|
||||
// Move to next survey sub-step
|
||||
dispatch(setSurveySubStep(surveySubStep + 1));
|
||||
} else {
|
||||
// Survey completed, save data and move to next main step
|
||||
await saveSurveyData();
|
||||
dispatch(setCurrentStep(currentStep + 1));
|
||||
dispatch(setSurveySubStep(0)); // Reset for next time
|
||||
}
|
||||
} else if (currentStep === 4) {
|
||||
// Complete setup after members step
|
||||
completeAccountSetup();
|
||||
} else {
|
||||
@@ -380,11 +397,59 @@ const AccountSetup: React.FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
// Language switcher functionality
|
||||
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: '🇨🇳' }
|
||||
];
|
||||
|
||||
const handleLanguageChange = (languageKey: string) => {
|
||||
dispatch(setLanguage(languageKey));
|
||||
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];
|
||||
|
||||
return (
|
||||
<div
|
||||
className="min-h-screen w-full flex flex-col items-center py-8 px-4"
|
||||
className="min-h-screen w-full flex flex-col items-center py-8 px-4 relative"
|
||||
style={{ backgroundColor: token.colorBgLayout }}
|
||||
>
|
||||
{/* Language Switcher - Top Right */}
|
||||
<div className="absolute top-6 right-6">
|
||||
<Dropdown
|
||||
menu={{ items: languageMenuItems }}
|
||||
placement="bottomRight"
|
||||
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>
|
||||
|
||||
{/* Logo */}
|
||||
<div className="mb-4">
|
||||
<img src={isDarkMode ? logoDark : logo} alt="Logo" width={235} height={50} />
|
||||
@@ -437,7 +502,19 @@ const AccountSetup: React.FC = () => {
|
||||
type="link"
|
||||
className="p-0 font-medium"
|
||||
style={{ color: token.colorTextSecondary }}
|
||||
onClick={() => dispatch(setCurrentStep(currentStep - 1))}
|
||||
onClick={() => {
|
||||
if (currentStep === 1 && surveySubStep > 0) {
|
||||
// Go back within survey sub-steps
|
||||
dispatch(setSurveySubStep(surveySubStep - 1));
|
||||
} else {
|
||||
// Go back to previous main step
|
||||
dispatch(setCurrentStep(currentStep - 1));
|
||||
if (currentStep === 2) {
|
||||
// When going back to survey from next step, go to last sub-step
|
||||
dispatch(setSurveySubStep(2));
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
{t('goBack')}
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user