import React, { useEffect } from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom'; import { Space, Steps, Button, Typography } from 'antd/es'; import logger from '@/utils/errorLogger'; import { setCurrentStep } 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'; import MembersStep from '@/components/account-setup/members-step'; import { evt_account_setup_complete, evt_account_setup_skip_invite, evt_account_setup_visit, } from '@/shared/worklenz-analytics-events'; import { useMixpanelTracking } from '@/hooks/useMixpanelTracking'; import { verifyAuthentication } from '@/features/auth/authSlice'; import { setUser } from '@/features/user/userSlice'; import { IAuthorizeResponse } from '@/types/auth/login.types'; import { RootState } from '@/app/store'; import { useDocumentTitle } from '@/hooks/useDoumentTItle'; import { getUserSession, setSession } from '@/utils/session-helper'; import { validateEmail } from '@/utils/validateEmail'; import { sanitizeInput } from '@/utils/sanitizeInput'; import logo from '@/assets/images/worklenz-light-mode.png'; import logoDark from '@/assets/images/worklenz-dark-mode.png'; import './account-setup.css'; import { IAccountSetupRequest } from '@/types/project-templates/project-templates.types'; import { profileSettingsApiService } from '@/api/settings/profile/profile-settings.api.service'; const { Title } = Typography; const AccountSetup: React.FC = () => { const dispatch = useDispatch(); const { t } = useTranslation('account-setup'); useDocumentTitle(t('setupYourAccount', 'Account Setup')); const navigate = useNavigate(); const { trackMixpanelEvent } = useMixpanelTracking(); const { currentStep, organizationName, projectName, templateId, tasks, teamMembers } = useSelector((state: RootState) => state.accountSetupReducer); const userDetails = getUserSession(); const themeMode = useSelector((state: RootState) => state.themeReducer.mode); const isDarkMode = themeMode === 'dark'; const organizationNamePlaceholder = userDetails?.name ? `e.g. ${userDetails?.name}'s Team` : ''; useEffect(() => { trackMixpanelEvent(evt_account_setup_visit); const verifyAuthStatus = async () => { try { const response = await dispatch(verifyAuthentication()).unwrap() as IAuthorizeResponse; if (response?.authenticated) { setSession(response.user); dispatch(setUser(response.user)); // Prevent invited users from accessing account setup if (response.user.invitation_accepted) { navigate('/worklenz/home'); return; } if (response?.user?.setup_completed) { navigate('/worklenz/home'); } } } catch (error) { logger.error('Failed to verify authentication status', error); } }; void verifyAuthStatus(); }, [dispatch, navigate, trackMixpanelEvent]); const calculateHeight = () => { if (currentStep === 2) { return tasks.length * 105; } if (currentStep === 3) { return teamMembers.length * 105; } return 'min-content'; }; const styles = { form: { width: '600px', paddingBottom: '1rem', marginTop: '3rem', height: '100%', overflow: 'hidden', }, label: { color: isDarkMode ? '' : '#00000073', fontWeight: 500, }, buttonContainer: { display: 'flex', justifyContent: 'center', alignItems: 'center', marginTop: '1rem', }, drawerFooter: { display: 'flex', justifyContent: 'right', padding: '10px 16px', }, container: { height: '100vh', width: '100vw', display: 'flex', flexDirection: 'column' as const, alignItems: 'center', padding: '3rem 0', backgroundColor: isDarkMode ? 'black' : '#FAFAFA', }, contentContainer: { backgroundColor: isDarkMode ? '#141414' : 'white', marginTop: '1.5rem', paddingTop: '3rem', margin: '1.5rem auto 0', width: '100%', maxWidth: '66.66667%', minHeight: 'fit-content', display: 'flex', flexDirection: 'column' as const, }, space: { display: 'flex', flexDirection: 'column' as const, alignItems: 'center', gap: '0', flexGrow: 1, width: '100%', minHeight: 'fit-content', }, steps: { margin: '1rem 0', width: '600px', }, stepContent: { flexGrow: 1, width: '600px', minHeight: calculateHeight(), overflow: 'visible', }, actionButtons: { flexGrow: 1, width: '600px', marginBottom: '1rem', }, }; const completeAccountSetup = async (skip = false) => { try { const model: IAccountSetupRequest = { team_name: sanitizeInput(organizationName), project_name: sanitizeInput(projectName), tasks: tasks.map(task => sanitizeInput(task.value.trim())).filter(task => task !== ''), team_members: skip ? [] : teamMembers .map(teamMember => sanitizeInput(teamMember.value.trim())) .filter(email => validateEmail(email)), }; const res = await profileSettingsApiService.setupAccount(model); if (res.done && res.body.id) { trackMixpanelEvent(skip ? evt_account_setup_skip_invite : evt_account_setup_complete); navigate(`/worklenz/projects/${res.body.id}?tab=tasks-list&pinned_tab=tasks-list`); } } catch (error) { logger.error('completeAccountSetup', error); } }; const steps = [ { title: '', content: ( dispatch(setCurrentStep(currentStep + 1))} styles={styles} organizationNamePlaceholder={organizationNamePlaceholder} /> ), }, { title: '', content: ( dispatch(setCurrentStep(currentStep + 1))} styles={styles} isDarkMode={isDarkMode} /> ), }, { title: '', content: ( dispatch(setCurrentStep(currentStep + 1))} styles={styles} isDarkMode={isDarkMode} /> ), }, { title: '', content: , }, ]; const isContinueDisabled = () => { switch (currentStep) { case 0: return !organizationName?.trim(); case 1: return !projectName?.trim() && !templateId; case 2: return tasks.length === 0 || tasks.every(task => !task.value?.trim()); case 3: return ( teamMembers.length > 0 && !teamMembers.some(member => validateEmail(member.value?.trim())) ); default: return true; } }; const nextStep = () => { if (currentStep === 3) { completeAccountSetup(); } else { dispatch(setCurrentStep(currentStep + 1)); } }; return (
Logo
{t('setupYourAccount')}
{steps[currentStep].content}
{currentStep !== 0 && (
{currentStep === 3 && ( )}
)}
); }; export default AccountSetup;