Files
worklenz/worklenz-frontend/src/components/account-setup/members-step.tsx
chamikaJ a6863d8280 refactor: update code to use centralized Ant Design imports
- Replaced direct import of '@ant-design/icons' with centralized import from '@/shared/antd-imports'
2025-07-23 12:07:48 +05:30

183 lines
5.5 KiB
TypeScript

import React, { useEffect, useRef } from 'react';
import { Form, Input, Button, List, Alert, message, InputRef } from '@/shared/antd-imports';
import { CloseCircleOutlined, MailOutlined, PlusOutlined } from '@/shared/antd-imports';
import { useTranslation } from 'react-i18next';
import { Typography } from '@/shared/antd-imports';
import { setTeamMembers, setTasks } 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 { Rule } from 'antd/es/form';
const { Title } = Typography;
interface Email {
id: number;
value: string;
}
interface MembersStepProps {
isDarkMode: boolean;
styles: any;
}
const MembersStep: React.FC<MembersStepProps> = ({ isDarkMode, styles }) => {
const { t } = useTranslation('account-setup');
const { teamMembers, organizationName } = useSelector(
(state: RootState) => state.accountSetupReducer
);
const inputRefs = useRef<(InputRef | null)[]>([]);
const dispatch = useDispatch();
const [form] = Form.useForm();
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[newId]?.focus();
}, 0);
};
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<HTMLInputElement>) => {
const input = e.currentTarget as HTMLInputElement;
if (!input.value.trim()) return;
e.preventDefault();
addEmail();
};
// Function to set ref that doesn't return anything (void)
const setInputRef = (index: number) => (el: InputRef | null) => {
inputRefs.current[index] = el;
};
useEffect(() => {
setTimeout(() => {
inputRefs.current[teamMembers.length - 1]?.focus();
// Set initial form values
const initialValues: Record<string, string> = {};
teamMembers.forEach(teamMember => {
initialValues[`email-${teamMember.id}`] = teamMember.value;
});
form.setFieldsValue(initialValues);
}, 200);
}, []);
const formRules = {
email: [
{
validator: async (_: any, value: string) => {
if (!value) return;
if (!validateEmail(value)) {
throw new Error(t('invalidEmail'));
}
},
},
],
};
return (
<Form
form={form}
className="invite-members-form"
style={{
minHeight: '300px',
width: '600px',
paddingBottom: '1rem',
marginBottom: '3rem',
marginTop: '3rem',
display: 'flex',
flexDirection: 'column',
}}
>
<Form.Item>
<Title level={2} style={{ marginBottom: '1rem' }}>
{t('step3Title')} "<mark>{organizationName}</mark>".
</Title>
</Form.Item>
<Form.Item
layout="vertical"
rules={[{ required: true }]}
label={
<span className="font-medium">
{t('step3InputLabel')}&nbsp; <MailOutlined /> {t('maxMembers')}
</span>
}
>
<List
dataSource={teamMembers}
bordered={false}
itemLayout="vertical"
renderItem={(teamMember, index) => (
<List.Item key={teamMember.id}>
<div className="invite-members-form" style={{ display: 'flex', width: '600px' }}>
<Form.Item
rules={formRules.email as Rule[]}
className="w-full"
validateTrigger={['onChange', 'onBlur']}
name={`email-${teamMember.id}`}
>
<Input
placeholder={t('emailPlaceholder')}
value={teamMember.value}
onChange={e => updateEmail(teamMember.id, e.target.value)}
onPressEnter={handleKeyPress}
ref={setInputRef(index)}
status={teamMember.value && !validateEmail(teamMember.value) ? 'error' : ''}
id={`member-${index}`}
/>
</Form.Item>
<Button
className="custom-close-button"
style={{ marginLeft: '48px' }}
type="text"
icon={<CloseCircleOutlined />}
disabled={teamMembers.length === 1}
onClick={() => removeEmail(teamMember.id)}
/>
</div>
</List.Item>
)}
/>
<Button
type="dashed"
icon={<PlusOutlined />}
onClick={addEmail}
style={{ marginTop: '16px' }}
disabled={teamMembers.length == 5}
>
{t('tasksStepAddAnother')}
</Button>
<div
style={{
marginTop: '24px',
display: 'flex',
justifyContent: 'space-between',
}}
></div>
</Form.Item>
</Form>
);
};
export default MembersStep;