From 7ff9cb524851e26d58275815b6d62a84aea9b487 Mon Sep 17 00:00:00 2001 From: 7eliassen Date: Thu, 5 Feb 2026 23:50:48 +0300 Subject: [PATCH 1/6] feat: add ability to remove team member --- src/application/i18n/messages/en.json | 5 + src/application/services/useNoteSettings.ts | 17 +++ .../noteSettings.repository.interface.ts | 7 ++ src/domain/noteSettings.service.ts | 9 ++ src/infrastructure/noteSettings.repository.ts | 10 ++ .../components/team/MoreActions.vue | 102 ++++++++++++++++++ src/presentation/components/team/Team.vue | 15 +++ src/presentation/pages/NoteSettings.vue | 8 ++ 8 files changed, 173 insertions(+) create mode 100644 src/presentation/components/team/MoreActions.vue diff --git a/src/application/i18n/messages/en.json b/src/application/i18n/messages/en.json index aed70cd6..78538e17 100644 --- a/src/application/i18n/messages/en.json +++ b/src/application/i18n/messages/en.json @@ -67,6 +67,11 @@ "roles": { "Read": "Reader", "Write": "Writer" + }, + "removeMemberConfirmationTitle": "Remove member", + "removeMemberConfirmationBody": "Are you sure you want to remove user from the team?", + "ContextMenu": { + "remove": "Remove" } } }, diff --git a/src/application/services/useNoteSettings.ts b/src/application/services/useNoteSettings.ts index 7e2d38a3..1c7c9187 100644 --- a/src/application/services/useNoteSettings.ts +++ b/src/application/services/useNoteSettings.ts @@ -66,6 +66,13 @@ interface UseNoteSettingsComposableState { * @param newParentURL - New parent note URL */ setParent: (id: NoteId, newParentURL: string) => Promise; + + /** + * Delete team member by user id + * @param id - Note id + * @param userId - User id + */ + removeMemberByUserId: (id: NoteId, userId: UserId) => Promise; } /** @@ -188,6 +195,15 @@ export default function (): UseNoteSettingsComposableState { } }; + /** + * Delete team member by user id + * @param id - Note id + * @param userId - User id + */ + const removeMemberByUserId = async (id: NoteId, userId: UserId) => { + await noteSettingsService.removeMemberByUserId(id, userId); + } + return { updateCover, setParent, @@ -198,5 +214,6 @@ export default function (): UseNoteSettingsComposableState { revokeHash, changeRole, deleteNoteById, + removeMemberByUserId, }; } diff --git a/src/domain/noteSettings.repository.interface.ts b/src/domain/noteSettings.repository.interface.ts index ce2d8a1e..856bd512 100644 --- a/src/domain/noteSettings.repository.interface.ts +++ b/src/domain/noteSettings.repository.interface.ts @@ -43,4 +43,11 @@ export default interface NoteSettingsRepositoryInterface { * @param id - Note id */ deleteNote(id: NoteId): Promise; + + /** + * Delete team member by user id + * @param id - Note id + * @param userId - User id + */ + removeMemberByUserId(id: NoteId, userId: UserId): Promise; } diff --git a/src/domain/noteSettings.service.ts b/src/domain/noteSettings.service.ts index 26ca425d..28d39032 100644 --- a/src/domain/noteSettings.service.ts +++ b/src/domain/noteSettings.service.ts @@ -118,4 +118,13 @@ export default class NoteSettingsService { public async deleteNote(id: NoteId): Promise { return await this.noteSettingsRepository.deleteNote(id); } + + /** + * Delete team member by user id + * @param id - Note id + * @param userId - User id + */ + public async removeMemberByUserId(id: NoteId, userId: UserId): Promise { + return await this.noteSettingsRepository.removeMemberByUserId(id, userId); + } } diff --git a/src/infrastructure/noteSettings.repository.ts b/src/infrastructure/noteSettings.repository.ts index 90efebe2..6e0003c5 100644 --- a/src/infrastructure/noteSettings.repository.ts +++ b/src/infrastructure/noteSettings.repository.ts @@ -69,4 +69,14 @@ export default class NoteSettingsRepository implements NoteSettingsRepositoryInt public async deleteNote(id: NoteId): Promise { await this.transport.delete(`/note/` + id); } + + /** + * Delete team member by user id + * @param id - Note id + * @param userId - User id + */ + public async removeMemberByUserId(id: NoteId, userId: UserId): Promise { + const data = { userId }; + await this.transport.delete(`/note-settings/${id}/team`, data); + } } diff --git a/src/presentation/components/team/MoreActions.vue b/src/presentation/components/team/MoreActions.vue new file mode 100644 index 00000000..fc77f98b --- /dev/null +++ b/src/presentation/components/team/MoreActions.vue @@ -0,0 +1,102 @@ + + + + + + diff --git a/src/presentation/components/team/Team.vue b/src/presentation/components/team/Team.vue index b02e5817..e5efa3d1 100644 --- a/src/presentation/components/team/Team.vue +++ b/src/presentation/components/team/Team.vue @@ -15,6 +15,11 @@ :note-id="noteId" :team-member="member" /> + diff --git a/src/presentation/pages/NoteSettings.vue b/src/presentation/pages/NoteSettings.vue index 0c86bcb5..cbe31641 100644 --- a/src/presentation/pages/NoteSettings.vue +++ b/src/presentation/pages/NoteSettings.vue @@ -73,7 +73,7 @@ Date: Mon, 9 Feb 2026 22:30:26 +0300 Subject: [PATCH 3/6] chore: small fixes --- src/application/i18n/messages/en.json | 5 +++-- src/presentation/components/team/MoreActions.vue | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/application/i18n/messages/en.json b/src/application/i18n/messages/en.json index 78538e17..eed27673 100644 --- a/src/application/i18n/messages/en.json +++ b/src/application/i18n/messages/en.json @@ -69,8 +69,9 @@ "Write": "Writer" }, "removeMemberConfirmationTitle": "Remove member", - "removeMemberConfirmationBody": "Are you sure you want to remove user from the team?", - "ContextMenu": { + "removeMemberConfirmationBody": "Are you sure you want to remove the user from the team?", + "contextMenu": { + "title": "More actions", "remove": "Remove" } } diff --git a/src/presentation/components/team/MoreActions.vue b/src/presentation/components/team/MoreActions.vue index 74d4669d..42b31a08 100644 --- a/src/presentation/components/team/MoreActions.vue +++ b/src/presentation/components/team/MoreActions.vue @@ -3,6 +3,7 @@ ref="triggerButton" class="more-actions-button" @click="handleButtonClick" + :title="t('noteSettings.team.contextMenu.title')" > (); const menuItems: ContextMenuItem[] = [ { - title: t('noteSettings.team.ContextMenu.remove'), + title: t('noteSettings.team.contextMenu.remove'), onActivate: () => { handleRemove(props.teamMember); hide(); From 98111c00ee1577e697f40e85e7c3dd5fd6bb7531 Mon Sep 17 00:00:00 2001 From: 7eliassen Date: Mon, 9 Feb 2026 22:39:15 +0300 Subject: [PATCH 4/6] chore: add error handle --- src/presentation/components/team/MoreActions.vue | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/presentation/components/team/MoreActions.vue b/src/presentation/components/team/MoreActions.vue index 42b31a08..0265f3b2 100644 --- a/src/presentation/components/team/MoreActions.vue +++ b/src/presentation/components/team/MoreActions.vue @@ -41,9 +41,13 @@ const triggerButton = ref(); const menuItems: ContextMenuItem[] = [ { title: t('noteSettings.team.contextMenu.remove'), - onActivate: () => { - handleRemove(props.teamMember); + onActivate: async () => { hide(); + try { + await handleRemove(props.teamMember); + } catch (error) { + console.error('Failed to remove team member', error); + } }, }, ]; From 879ff7c7ba3768947f00346e7699a3d2a4529167 Mon Sep 17 00:00:00 2001 From: 7eliassen Date: Thu, 12 Feb 2026 23:45:25 +0300 Subject: [PATCH 5/6] refactor: removeTeamMember optimization --- src/application/services/useNoteSettings.ts | 8 +++++--- src/domain/noteSettings.repository.interface.ts | 3 ++- src/domain/noteSettings.service.ts | 3 ++- src/infrastructure/noteSettings.repository.ts | 6 ++++-- .../components/team/MoreActions.vue | 17 ++++++++--------- src/presentation/components/team/Team.vue | 8 ++++---- src/presentation/pages/NoteSettings.vue | 15 +++++++++++---- 7 files changed, 36 insertions(+), 24 deletions(-) diff --git a/src/application/services/useNoteSettings.ts b/src/application/services/useNoteSettings.ts index 9613b0dd..bd488b3a 100644 --- a/src/application/services/useNoteSettings.ts +++ b/src/application/services/useNoteSettings.ts @@ -71,8 +71,9 @@ interface UseNoteSettingsComposableState { * Delete team member by user id * @param id - Note id * @param userId - User id + * @returns true if user was removed */ - removeMemberByUserId: (id: NoteId, userId: UserId) => Promise; + removeMemberByUserId: (id: NoteId, userId: UserId) => Promise; } /** @@ -199,9 +200,10 @@ export default function (): UseNoteSettingsComposableState { * Delete team member by user id * @param id - Note id * @param userId - User id + * @returns true if user was removed */ - const removeMemberByUserId = async (id: NoteId, userId: UserId): Promise => { - await noteSettingsService.removeMemberByUserId(id, userId); + const removeMemberByUserId = async (id: NoteId, userId: UserId): Promise => { + return await noteSettingsService.removeMemberByUserId(id, userId); }; return { diff --git a/src/domain/noteSettings.repository.interface.ts b/src/domain/noteSettings.repository.interface.ts index 856bd512..4ac752d1 100644 --- a/src/domain/noteSettings.repository.interface.ts +++ b/src/domain/noteSettings.repository.interface.ts @@ -48,6 +48,7 @@ export default interface NoteSettingsRepositoryInterface { * Delete team member by user id * @param id - Note id * @param userId - User id + * @returns true if user was removed */ - removeMemberByUserId(id: NoteId, userId: UserId): Promise; + removeMemberByUserId(id: NoteId, userId: UserId): Promise; } diff --git a/src/domain/noteSettings.service.ts b/src/domain/noteSettings.service.ts index 1037a7d1..bede251f 100644 --- a/src/domain/noteSettings.service.ts +++ b/src/domain/noteSettings.service.ts @@ -123,8 +123,9 @@ export default class NoteSettingsService { * Delete team member by user id * @param id - Note id * @param userId - User id + * @returns true if user was removed */ - public async removeMemberByUserId(id: NoteId, userId: UserId): Promise { + public async removeMemberByUserId(id: NoteId, userId: UserId): Promise { return await this.noteSettingsRepository.removeMemberByUserId(id, userId); } } diff --git a/src/infrastructure/noteSettings.repository.ts b/src/infrastructure/noteSettings.repository.ts index 3112f28f..72d9f245 100644 --- a/src/infrastructure/noteSettings.repository.ts +++ b/src/infrastructure/noteSettings.repository.ts @@ -74,10 +74,12 @@ export default class NoteSettingsRepository implements NoteSettingsRepositoryInt * Delete team member by user id * @param id - Note id * @param userId - User id + * @returns true if user was removed */ - public async removeMemberByUserId(id: NoteId, userId: UserId): Promise { + public async removeMemberByUserId(id: NoteId, userId: UserId): Promise { const data = { userId }; + const response = await this.transport.delete(`/note-settings/${id}/team`, data); - await this.transport.delete(`/note-settings/${id}/team`, data); + return response === userId; } } diff --git a/src/presentation/components/team/MoreActions.vue b/src/presentation/components/team/MoreActions.vue index 0265f3b2..a794598c 100644 --- a/src/presentation/components/team/MoreActions.vue +++ b/src/presentation/components/team/MoreActions.vue @@ -1,9 +1,9 @@