diff --git a/CHANGELOG.md b/CHANGELOG.md
index ce688142..c1311ce7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,7 @@ and this project adheres to
## Fixed
- 🐛(y-webrtc) fix prob connection #147
+- ⚡️(frontend) improve select share stability #159
## Changed
diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-member-create.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-member-create.spec.ts
index be8c8253..fbb0db78 100644
--- a/src/frontend/apps/e2e/__tests__/app-impress/doc-member-create.spec.ts
+++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-member-create.spec.ts
@@ -170,7 +170,7 @@ test.describe('Document create member', () => {
const inputSearch = page.getByLabel(/Find a member to add to the document/);
- const email = randomName('test@test.fr', browserName, 1)[0];
+ const [email] = randomName('test@test.fr', browserName, 1);
await inputSearch.fill(email);
await page.getByRole('option', { name: email }).click();
@@ -191,7 +191,22 @@ test.describe('Document create member', () => {
expect(responseCreateInvitation.ok()).toBeTruthy();
await inputSearch.fill(email);
- await expect(page.getByText('Loading...')).toBeHidden();
- await expect(page.getByRole('option', { name: email })).toBeHidden();
+ await page.getByRole('option', { name: email }).click();
+ // Choose a role
+ await page.getByRole('combobox', { name: /Choose a role/ }).click();
+ await page.getByRole('option', { name: 'Owner' }).click();
+
+ const responsePromiseCreateInvitationFail = page.waitForResponse(
+ (response) =>
+ response.url().includes('/invitations/') && response.status() === 400,
+ );
+
+ await page.getByRole('button', { name: 'Validate' }).click();
+ await expect(
+ page.getByText(`"${email}" is already invited to the document.`),
+ ).toBeVisible();
+ const responseCreateInvitationFail =
+ await responsePromiseCreateInvitationFail;
+ expect(responseCreateInvitationFail.ok()).toBeFalsy();
});
});
diff --git a/src/frontend/apps/impress/src/features/docs/members/members-add/components/AddMembers.tsx b/src/frontend/apps/impress/src/features/docs/members/members-add/components/AddMembers.tsx
index 2dd6448d..d33a5082 100644
--- a/src/frontend/apps/impress/src/features/docs/members/members-add/components/AddMembers.tsx
+++ b/src/frontend/apps/impress/src/features/docs/members/members-add/components/AddMembers.tsx
@@ -70,14 +70,23 @@ export const AddMembers = ({ currentRole, doc }: ModalAddMembersProps) => {
duration: 4000,
};
- const onError = (dataError: APIErrorUser['data']) => {
- const messageError =
- dataError?.type === OptionType.INVITATION
+ const onError = (dataError: APIErrorUser) => {
+ let messageError =
+ dataError['data']?.type === OptionType.INVITATION
? t(`Failed to create the invitation for {{email}}.`, {
- email: dataError?.value,
+ email: dataError['data']?.value,
})
: t(`Failed to add the member in the document.`);
+ if (
+ dataError.cause?.[0] ===
+ 'Document invitation with this Email address and Document already exists.'
+ ) {
+ messageError = t('"{{email}}" is already invited to the document.', {
+ email: dataError['data']?.value,
+ });
+ }
+
toast(messageError, VariantType.ERROR, toastOptions);
};
@@ -106,11 +115,12 @@ export const AddMembers = ({ currentRole, doc }: ModalAddMembersProps) => {
setIsPending(false);
setResetKey(resetKey + 1);
+ setSelectedUsers([]);
settledPromises.forEach((settledPromise) => {
switch (settledPromise.status) {
case 'rejected':
- onError((settledPromise.reason as APIErrorUser).data);
+ onError(settledPromise.reason as APIErrorUser);
break;
case 'fulfilled':
@@ -132,7 +142,7 @@ export const AddMembers = ({ currentRole, doc }: ModalAddMembersProps) => {
-
+
{
+ const optionsSelect = useMemo(() => {
if (!resolveOptionsRef.current || !options) {
return;
}
@@ -81,6 +81,8 @@ export const SearchUsers = ({
resolveOptionsRef.current(users);
resolveOptionsRef.current = null;
+
+ return users;
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [options, selectedUsers]);
@@ -91,16 +93,26 @@ export const SearchUsers = ({
};
const timeout = useRef(null);
- const onInputChangeHandle = useCallback((newValue: string) => {
- setInput(newValue);
- if (timeout.current) {
- clearTimeout(timeout.current);
- }
+ const onInputChangeHandle = useCallback(
+ (newValue: string, actionMeta: InputActionMeta) => {
+ if (
+ actionMeta.action === 'input-blur' ||
+ actionMeta.action === 'menu-close'
+ ) {
+ return;
+ }
- timeout.current = setTimeout(() => {
- setUserQuery(newValue);
- }, 1000);
- }, []);
+ setInput(newValue);
+ if (timeout.current) {
+ clearTimeout(timeout.current);
+ }
+
+ timeout.current = setTimeout(() => {
+ setUserQuery(newValue);
+ }, 1000);
+ },
+ [],
+ );
return (
input
? t("We didn't find a mail matching, try to be more accurate")