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 { Button, Form, Input, Select, Space, Typography } from 'antd';
import { Dispatch, SetStateAction, useCallback, useEffect } from 'react';
import {
Button,
Form,
FormInstance,
Input,
Select,
Space,
Typography,
} from 'antd';
import { useTranslation } from 'react-i18next';
import { requireErrorMessage } from 'utils/form/requireErrorMessage';
import { InviteTeamMembersProps } from '../PendingInvitesContainer/index';
import { SelectDrawer, TitleWrapper } from './styles';
import { InviteMemberFormValues } from '../PendingInvitesContainer/index';
import { SelectDrawer, SpaceContainer, TitleWrapper } from './styles';
const { Option } = Select;
function InviteTeamMembers({ allMembers, setAllMembers }: Props): JSX.Element {
function InviteTeamMembers({ form, onFinish }: Props): JSX.Element {
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 (
<>
<TitleWrapper>
@ -56,52 +26,50 @@ function InviteTeamMembers({ allMembers, setAllMembers }: Props): JSX.Element {
<Typography>{t('name_optional')}</Typography>
<Typography>{t('role')}</Typography>
</TitleWrapper>
<Form>
<Space direction="vertical" align="center" size="middle">
{allMembers.map((e, index) => (
<Space key={Number(index)} direction="horizontal">
<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');
}
}}
>
<Option value="ADMIN">ADMIN</Option>
<Option value="VIEWER">VIEWER</Option>
<Option value="EDITOR">EDITOR</Option>
</SelectDrawer>
</Space>
))}
<Button onClick={onAddHandler} icon={<PlusOutlined />} type="default">
{t('add_another_team_member')}
</Button>
</Space>
<Form
form={form}
onFinish={onFinish}
initialValues={{ members: [{ email: '', name: '', role: 'VIEWER' }] }}
>
<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="VIEWER">VIEWER</Option>
<Option value="EDITOR">EDITOR</Option>
</SelectDrawer>
</Form.Item>
</Space>
))}
<Form.Item>
<Button onClick={add} icon={<PlusOutlined />} type="default">
{t('add_another_team_member')}
</Button>
</Form.Item>
</SpaceContainer>
)}
</Form.List>
</Form>
</>
);
}
interface Props {
allMembers: InviteTeamMembersProps[];
setAllMembers: Dispatch<SetStateAction<InviteTeamMembersProps[]>>;
form: FormInstance<InviteMemberFormValues>;
onFinish: (values: InviteMemberFormValues) => Promise<void>;
}
export default InviteTeamMembers;

View File

@ -1,4 +1,4 @@
import { Select } from 'antd';
import { Select, Space } from 'antd';
import styled from 'styled-components';
export const SelectDrawer = styled(Select)`
@ -13,3 +13,9 @@ export const TitleWrapper = styled.div`
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 { Button, Modal, Space, Typography } from 'antd';
import { Button, Form, Modal, Space, Typography } from 'antd';
import { ColumnsType } from 'antd/lib/table';
import deleteInvite from 'api/user/deleteInvite';
import getPendingInvites from 'api/user/getPendingInvites';
@ -27,6 +27,7 @@ function PendingInvitesContainer(): JSX.Element {
isInviteTeamMemberModalOpen,
setIsInviteTeamMemberModalOpen,
] = useState<boolean>(false);
const [form] = Form.useForm<InviteMemberFormValues>();
const [isInvitingMembers, setIsInvitingMembers] = useState<boolean>(false);
const { t } = useTranslation(['organizationsettings', 'common']);
const [state, setText] = useCopyToClipboard();
@ -58,14 +59,6 @@ function PendingInvitesContainer(): JSX.Element {
setIsInviteTeamMemberModalOpen(value);
};
const [allMembers, setAllMembers] = useState<InviteTeamMembersProps[]>([
{
email: '',
name: '',
role: 'VIEWER',
},
]);
const [dataSource, setDataSource] = useState<DataProps[]>([]);
const { hash } = useLocation();
@ -192,45 +185,48 @@ function PendingInvitesContainer(): JSX.Element {
},
];
const onInviteClickHandler = async (): Promise<void> => {
try {
setIsInvitingMembers(true);
allMembers.forEach(
async (members): Promise<void> => {
const { error, statusCode } = await sendInvite({
email: members.email,
name: members.name,
role: members.role,
});
if (statusCode !== 200) {
notifications.error({
message:
error ||
t('something_went_wrong', {
ns: 'common',
}),
const onInviteClickHandler = useCallback(
async (values: InviteMemberFormValues): Promise<void> => {
try {
setIsInvitingMembers(true);
values.members.forEach(
async (member): Promise<void> => {
const { error, statusCode } = await sendInvite({
email: member.email,
name: member.name,
role: member.role,
});
}
},
);
setTimeout(async () => {
const { data, status } = await getPendingInvitesResponse.refetch();
if (status === 'success' && data.payload) {
setDataSource(getParsedInviteData(data?.payload || []));
}
setIsInvitingMembers(false);
toggleModal(false);
}, 2000);
} catch (error) {
notifications.error({
message: t('something_went_wrong', {
ns: 'common',
}),
});
}
};
if (statusCode !== 200) {
notifications.error({
message:
error ||
t('something_went_wrong', {
ns: 'common',
}),
});
}
},
);
setTimeout(async () => {
const { data, status } = await getPendingInvitesResponse.refetch();
if (status === 'success' && data.payload) {
setDataSource(getParsedInviteData(data?.payload || []));
}
setIsInvitingMembers(false);
toggleModal(false);
}, 2000);
} catch (error) {
notifications.error({
message: t('something_went_wrong', {
ns: 'common',
}),
});
}
},
[getParsedInviteData, getPendingInvitesResponse, notifications, t],
);
return (
<div>
@ -248,7 +244,7 @@ function PendingInvitesContainer(): JSX.Element {
</Button>,
<Button
key={t('invite_team_members').toString()}
onClick={onInviteClickHandler}
onClick={form.submit}
type="primary"
disabled={isInvitingMembers}
loading={isInvitingMembers}
@ -257,7 +253,7 @@ function PendingInvitesContainer(): JSX.Element {
</Button>,
]}
>
<InviteTeamMembers allMembers={allMembers} setAllMembers={setAllMembers} />
<InviteTeamMembers form={form} onFinish={onInviteClickHandler} />
</Modal>
<Space direction="vertical" size="middle">
@ -298,4 +294,15 @@ interface DataProps {
accessLevel: ROLES;
inviteLink: string;
}
type Role = 'ADMIN' | 'VIEWER' | 'EDITOR';
export interface InviteMemberFormValues {
members: {
email: string;
name: string;
role: Role;
}[];
}
export default PendingInvitesContainer;