5623 add an inviteteam onboarding step (#5769)

## Changes
- add a new invite Team onboarding step
- update currentUser.state to currentUser.onboardingStep

## Edge cases
We will never display invite team onboarding step 
- if number of workspaceMember > 1
- if a workspaceMember as been deleted

## Important changes
Update typeorm package version to 0.3.20 because we needed a fix on
`indexPredicates` pushed in 0.3.20 version
(https://github.com/typeorm/typeorm/issues/10191)

## Result
<img width="844" alt="image"
src="https://github.com/twentyhq/twenty/assets/29927851/0dab54cf-7c66-4c64-b0c9-b0973889a148">



https://github.com/twentyhq/twenty/assets/29927851/13268d0a-cfa7-42a4-84c6-9e1fbbe48912
This commit is contained in:
martmull
2024-06-12 21:13:18 +02:00
committed by GitHub
parent 2fdd2f4949
commit 3986824017
60 changed files with 1009 additions and 372 deletions

View File

@ -1,17 +1,16 @@
import { useEffect } from 'react';
import { Controller, useForm } from 'react-hook-form';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { zodResolver } from '@hookform/resolvers/zod';
import { Key } from 'ts-key-enum';
import { IconCopy, IconMail, IconSend } from 'twenty-ui';
import { IconMail, IconSend } from 'twenty-ui';
import { z } from 'zod';
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { Button } from '@/ui/input/button/components/Button';
import { TextInput } from '@/ui/input/components/TextInput';
import { extractEmailsList } from '@/workspace/utils/extractEmailList';
import { sanitizeEmailList } from '@/workspace/utils/sanitizeEmailList';
import { useSendInviteLinkMutation } from '~/generated/graphql';
import { isDefined } from '~/utils/isDefined';
@ -35,7 +34,7 @@ const validationSchema = () =>
if (!value.length) {
return;
}
const emails = extractEmailsList(value);
const emails = sanitizeEmailList(value.split(','));
if (emails.length === 0) {
ctx.addIssue({
code: z.ZodIssueCode.invalid_string,
@ -69,7 +68,6 @@ type FormInput = {
};
export const WorkspaceInviteTeam = () => {
const theme = useTheme();
const { enqueueSnackBar } = useSnackBar();
const [sendInviteLink] = useSendInviteLinkMutation();
@ -82,14 +80,13 @@ export const WorkspaceInviteTeam = () => {
});
const submit = handleSubmit(async (data) => {
const emailsList = extractEmailsList(data.emails);
const emailsList = sanitizeEmailList(data.emails.split(','));
const result = await sendInviteLink({ variables: { emails: emailsList } });
if (isDefined(result.errors)) {
throw result.errors;
}
enqueueSnackBar('Invite link sent to email addresses', {
variant: SnackBarVariant.Success,
icon: <IconCopy size={theme.icon.size.md} />,
duration: 2000,
});
});

View File

@ -1,28 +0,0 @@
import { extractEmailsList } from '@/workspace/utils/extractEmailList';
describe('extractEmailList', () => {
it('should extract email list', () => {
expect(extractEmailsList('toto@toto.com')).toEqual(['toto@toto.com']);
});
it('should extract email list with multiple emails', () => {
expect(extractEmailsList('toto@toto.com,toto2@toto.com')).toEqual([
'toto@toto.com',
'toto2@toto.com',
]);
});
it('should extract email list with multiple emails and wrong emails', () => {
expect(extractEmailsList('toto@toto.com,toto2@toto.com,toto')).toEqual([
'toto@toto.com',
'toto2@toto.com',
'toto',
]);
});
it('should remove duplicates', () => {
expect(extractEmailsList('toto@toto.com,toto@toto.com')).toEqual([
'toto@toto.com',
]);
});
it('should remove empty emails', () => {
expect(extractEmailsList('toto@toto.com,')).toEqual(['toto@toto.com']);
});
});

View File

@ -0,0 +1,24 @@
import { sanitizeEmailList } from '@/workspace/utils/sanitizeEmailList';
describe('sanitizeEmailList', () => {
it('should do nothing if sanitized email list', () => {
expect(sanitizeEmailList(['toto@toto.com', 'toto2@toto.com'])).toEqual([
'toto@toto.com',
'toto2@toto.com',
]);
});
it('should trim spaces', () => {
expect(sanitizeEmailList([' toto@toto.com ', ' toto2@toto.com'])).toEqual([
'toto@toto.com',
'toto2@toto.com',
]);
});
it('should filter empty emails', () => {
expect(sanitizeEmailList(['toto@toto.com', ''])).toEqual(['toto@toto.com']);
});
it('should remove duplicates', () => {
expect(sanitizeEmailList(['toto@toto.com', 'toto@toto.com'])).toEqual([
'toto@toto.com',
]);
});
});

View File

@ -1,8 +1,7 @@
export const extractEmailsList = (emails: string) => {
export const sanitizeEmailList = (emailList: string[]): string[] => {
return Array.from(
new Set(
emails
.split(',')
emailList
.map((email) => email.trim())
.filter((email) => email.length > 0),
),