feat: moved invite members form to antd form (#2745)

* feat: moved invite members form to antd form

Signed-off-by: GermaVinsmoke <vaibhav1180@gmail.com>

* chore: center align add more btn

Signed-off-by: GermaVinsmoke <vaibhav1180@gmail.com>

* chore: name optional, space proper alignment

Signed-off-by: GermaVinsmoke <vaibhav1180@gmail.com>

* chore: used lib fn for require message

Signed-off-by: GermaVinsmoke <vaibhav1180@gmail.com>

---------

Signed-off-by: GermaVinsmoke <vaibhav1180@gmail.com>
Co-authored-by: Palash Gupta <palashgdev@gmail.com>
This commit is contained in:
GermaVinsmoke 2023-05-24 11:47:21 +05:30 committed by GitHub
parent fda0441686
commit 234a69de8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 113 additions and 132 deletions

View File

@ -1,54 +1,24 @@
import { PlusOutlined } from '@ant-design/icons'; import { PlusOutlined } from '@ant-design/icons';
import { Button, Form, Input, Select, Space, Typography } from 'antd'; import {
import { Dispatch, SetStateAction, useCallback, useEffect } from 'react'; Button,
Form,
FormInstance,
Input,
Select,
Space,
Typography,
} from 'antd';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { requireErrorMessage } from 'utils/form/requireErrorMessage';
import { InviteTeamMembersProps } from '../PendingInvitesContainer/index'; import { InviteMemberFormValues } from '../PendingInvitesContainer/index';
import { SelectDrawer, TitleWrapper } from './styles'; import { SelectDrawer, SpaceContainer, TitleWrapper } from './styles';
const { Option } = Select; const { Option } = Select;
function InviteTeamMembers({ allMembers, setAllMembers }: Props): JSX.Element { function InviteTeamMembers({ form, onFinish }: Props): JSX.Element {
const { t } = useTranslation('organizationsettings'); const { t } = useTranslation('organizationsettings');
useEffect(
() => (): void => {
setAllMembers([
{
email: '',
name: '',
role: 'VIEWER',
},
]);
},
[setAllMembers],
);
const onAddHandler = (): void => {
setAllMembers((state) => [
...state,
{
email: '',
name: '',
role: 'VIEWER',
},
]);
};
const onChangeHandler = useCallback(
(value: string, index: number, type: string): void => {
setAllMembers((prev) => [
...prev.slice(0, index),
{
...prev[index],
[type]: value,
},
...prev.slice(index, prev.length - 1),
]);
},
[setAllMembers],
);
return ( return (
<> <>
<TitleWrapper> <TitleWrapper>
@ -56,52 +26,50 @@ function InviteTeamMembers({ allMembers, setAllMembers }: Props): JSX.Element {
<Typography>{t('name_optional')}</Typography> <Typography>{t('name_optional')}</Typography>
<Typography>{t('role')}</Typography> <Typography>{t('role')}</Typography>
</TitleWrapper> </TitleWrapper>
<Form> <Form
<Space direction="vertical" align="center" size="middle"> form={form}
{allMembers.map((e, index) => ( onFinish={onFinish}
<Space key={Number(index)} direction="horizontal"> initialValues={{ members: [{ email: '', name: '', role: 'VIEWER' }] }}
<Input
placeholder={t('email_placeholder')}
value={e.email}
onChange={(event): void => {
onChangeHandler(event.target.value, index, 'email');
}}
required
/>
<Input
placeholder={t('name_placeholder')}
value={e.name}
onChange={(event): void => {
onChangeHandler(event.target.value, index, 'name');
}}
required
/>
<SelectDrawer
value={e.role}
onSelect={(value: unknown): void => {
if (typeof value === 'string') {
onChangeHandler(value, index, 'role');
}
}}
> >
<Form.List name="members">
{(fields, { add }): JSX.Element => (
<SpaceContainer direction="vertical" align="center" size="middle">
{fields.map(({ key, name }) => (
<Space key={key} direction="horizontal" align="start">
<Form.Item
name={[name, 'email']}
rules={[{ required: true, message: requireErrorMessage('Email') }]}
>
<Input placeholder={t('email_placeholder')} />
</Form.Item>
<Form.Item name={[name, 'name']}>
<Input placeholder={t('name_placeholder')} />
</Form.Item>
<Form.Item name={[name, 'role']} initialValue="VIEWER">
<SelectDrawer>
<Option value="ADMIN">ADMIN</Option> <Option value="ADMIN">ADMIN</Option>
<Option value="VIEWER">VIEWER</Option> <Option value="VIEWER">VIEWER</Option>
<Option value="EDITOR">EDITOR</Option> <Option value="EDITOR">EDITOR</Option>
</SelectDrawer> </SelectDrawer>
</Form.Item>
</Space> </Space>
))} ))}
<Button onClick={onAddHandler} icon={<PlusOutlined />} type="default"> <Form.Item>
<Button onClick={add} icon={<PlusOutlined />} type="default">
{t('add_another_team_member')} {t('add_another_team_member')}
</Button> </Button>
</Space> </Form.Item>
</SpaceContainer>
)}
</Form.List>
</Form> </Form>
</> </>
); );
} }
interface Props { interface Props {
allMembers: InviteTeamMembersProps[]; form: FormInstance<InviteMemberFormValues>;
setAllMembers: Dispatch<SetStateAction<InviteTeamMembersProps[]>>; onFinish: (values: InviteMemberFormValues) => Promise<void>;
} }
export default InviteTeamMembers; export default InviteTeamMembers;

View File

@ -1,4 +1,4 @@
import { Select } from 'antd'; import { Select, Space } from 'antd';
import styled from 'styled-components'; import styled from 'styled-components';
export const SelectDrawer = styled(Select)` export const SelectDrawer = styled(Select)`
@ -13,3 +13,9 @@ export const TitleWrapper = styled.div`
min-width: 11rem; min-width: 11rem;
} }
`; `;
export const SpaceContainer = styled(Space)`
& .ant-form-item {
margin-bottom: 0px;
}
`;

View File

@ -1,5 +1,5 @@
import { PlusOutlined } from '@ant-design/icons'; import { PlusOutlined } from '@ant-design/icons';
import { Button, Modal, Space, Typography } from 'antd'; import { Button, Form, Modal, Space, Typography } from 'antd';
import { ColumnsType } from 'antd/lib/table'; import { ColumnsType } from 'antd/lib/table';
import deleteInvite from 'api/user/deleteInvite'; import deleteInvite from 'api/user/deleteInvite';
import getPendingInvites from 'api/user/getPendingInvites'; import getPendingInvites from 'api/user/getPendingInvites';
@ -27,6 +27,7 @@ function PendingInvitesContainer(): JSX.Element {
isInviteTeamMemberModalOpen, isInviteTeamMemberModalOpen,
setIsInviteTeamMemberModalOpen, setIsInviteTeamMemberModalOpen,
] = useState<boolean>(false); ] = useState<boolean>(false);
const [form] = Form.useForm<InviteMemberFormValues>();
const [isInvitingMembers, setIsInvitingMembers] = useState<boolean>(false); const [isInvitingMembers, setIsInvitingMembers] = useState<boolean>(false);
const { t } = useTranslation(['organizationsettings', 'common']); const { t } = useTranslation(['organizationsettings', 'common']);
const [state, setText] = useCopyToClipboard(); const [state, setText] = useCopyToClipboard();
@ -58,14 +59,6 @@ function PendingInvitesContainer(): JSX.Element {
setIsInviteTeamMemberModalOpen(value); setIsInviteTeamMemberModalOpen(value);
}; };
const [allMembers, setAllMembers] = useState<InviteTeamMembersProps[]>([
{
email: '',
name: '',
role: 'VIEWER',
},
]);
const [dataSource, setDataSource] = useState<DataProps[]>([]); const [dataSource, setDataSource] = useState<DataProps[]>([]);
const { hash } = useLocation(); const { hash } = useLocation();
@ -192,15 +185,16 @@ function PendingInvitesContainer(): JSX.Element {
}, },
]; ];
const onInviteClickHandler = async (): Promise<void> => { const onInviteClickHandler = useCallback(
async (values: InviteMemberFormValues): Promise<void> => {
try { try {
setIsInvitingMembers(true); setIsInvitingMembers(true);
allMembers.forEach( values.members.forEach(
async (members): Promise<void> => { async (member): Promise<void> => {
const { error, statusCode } = await sendInvite({ const { error, statusCode } = await sendInvite({
email: members.email, email: member.email,
name: members.name, name: member.name,
role: members.role, role: member.role,
}); });
if (statusCode !== 200) { if (statusCode !== 200) {
@ -230,7 +224,9 @@ function PendingInvitesContainer(): JSX.Element {
}), }),
}); });
} }
}; },
[getParsedInviteData, getPendingInvitesResponse, notifications, t],
);
return ( return (
<div> <div>
@ -248,7 +244,7 @@ function PendingInvitesContainer(): JSX.Element {
</Button>, </Button>,
<Button <Button
key={t('invite_team_members').toString()} key={t('invite_team_members').toString()}
onClick={onInviteClickHandler} onClick={form.submit}
type="primary" type="primary"
disabled={isInvitingMembers} disabled={isInvitingMembers}
loading={isInvitingMembers} loading={isInvitingMembers}
@ -257,7 +253,7 @@ function PendingInvitesContainer(): JSX.Element {
</Button>, </Button>,
]} ]}
> >
<InviteTeamMembers allMembers={allMembers} setAllMembers={setAllMembers} /> <InviteTeamMembers form={form} onFinish={onInviteClickHandler} />
</Modal> </Modal>
<Space direction="vertical" size="middle"> <Space direction="vertical" size="middle">
@ -298,4 +294,15 @@ interface DataProps {
accessLevel: ROLES; accessLevel: ROLES;
inviteLink: string; inviteLink: string;
} }
type Role = 'ADMIN' | 'VIEWER' | 'EDITOR';
export interface InviteMemberFormValues {
members: {
email: string;
name: string;
role: Role;
}[];
}
export default PendingInvitesContainer; export default PendingInvitesContainer;