diff --git a/src/api/groups.ts b/src/api/groups.ts index 8ec82d2..a122f39 100644 --- a/src/api/groups.ts +++ b/src/api/groups.ts @@ -69,4 +69,16 @@ export default { return [undefined, e?.response?.data?.error ?? e.message]; } }, + deleteMany: async (IDs: number[]): Promise<[AxiosResponse?, string?]> => { + try { + const data = await $axios.delete(`v1/groups`, { + data: { + array: IDs, + }, + }); + return [data, undefined]; + } catch (e: any) { + return [undefined, e?.response?.data?.error ?? e.message]; + } + }, }; diff --git a/src/api/users.ts b/src/api/users.ts index ca127d8..b5b4e88 100644 --- a/src/api/users.ts +++ b/src/api/users.ts @@ -71,4 +71,36 @@ export default { return [undefined, e?.response?.data?.error ?? e.message]; } }, + deleteMany: async (IDs: number[]): Promise<[AxiosResponse?, string?]> => { + try { + const data = await $axios.delete(`v1/users`, { + data: { + array: IDs, + }, + }); + return [data, undefined]; + } catch (e: any) { + return [undefined, e?.response?.data?.error ?? e.message]; + } + }, + blockMany: async (IDs: number[]): Promise<[AxiosResponse?, string?]> => { + try { + const data = await $axios.patch(`v1/users/block`, { + array: IDs, + }); + return [data, undefined]; + } catch (e: any) { + return [undefined, e?.response?.data?.error ?? e.message]; + } + }, + unblockMany: async (IDs: number[]): Promise<[AxiosResponse?, string?]> => { + try { + const data = await $axios.patch(`v1/users/unblock`, { + array: IDs, + }); + return [data, undefined]; + } catch (e: any) { + return [undefined, e?.response?.data?.error ?? e.message]; + } + }, }; diff --git a/src/components.d.ts b/src/components.d.ts index dd81cd0..62bd02a 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -9,8 +9,10 @@ declare module 'vue' { export interface GlobalComponents { AppFooter: typeof import('./components/AppFooter.vue')['default'] ConfirmModal: typeof import('./components/ConfirmModal.vue')['default'] + copy: typeof import('./components/ConfirmModal copy.vue')['default'] ErrorPlate: typeof import('./components/ErrorPlate.vue')['default'] HelloWorld: typeof import('./components/HelloWorld.vue')['default'] + InfoModal: typeof import('./components/InfoModal.vue')['default'] LanguageSwitcher: typeof import('./components/LanguageSwitcher.vue')['default'] LogoComponent: typeof import('./components/Icons/LogoComponent.vue')['default'] NavigationDrawer: typeof import('./components/NavigationDrawer.vue')['default'] diff --git a/src/components/InfoModal.vue b/src/components/InfoModal.vue new file mode 100644 index 0000000..0935692 --- /dev/null +++ b/src/components/InfoModal.vue @@ -0,0 +1,42 @@ + + + diff --git a/src/locales/en/actions.json b/src/locales/en/actions.json index 0288fde..e61d40d 100644 --- a/src/locales/en/actions.json +++ b/src/locales/en/actions.json @@ -4,6 +4,7 @@ "create-group": "Create group", "create-user": "Create user", "reset-password": "Reset password", + "delete": "Delete", "edit": "Edit", "block": "Block", "unblock": "Unblock", diff --git a/src/locales/en/groups.json b/src/locales/en/groups.json index 93d46f5..36d696e 100644 --- a/src/locales/en/groups.json +++ b/src/locales/en/groups.json @@ -26,6 +26,10 @@ "delete-one": { "title": "Delete group", "message": "Are you sure you want to delete group with ID {0}? This action cannot be undone" + }, + "delete-many": { + "title": "Delete groups", + "message": "Are you sure you want to delete {0} groups? This action cannot be undone" } } } diff --git a/src/locales/en/users.json b/src/locales/en/users.json index 4053cdb..25b6640 100644 --- a/src/locales/en/users.json +++ b/src/locales/en/users.json @@ -40,6 +40,10 @@ "delete-one": { "title": "Delete user", "message": "Are you sure you want to delete user with ID {0}? This action cannot be undone" + }, + "delete-many": { + "title": "Delete users", + "message": "Are you sure you want to delete {0} users? This action cannot be undone" } } } diff --git a/src/locales/ru/actions.json b/src/locales/ru/actions.json index 26df083..8438ef6 100644 --- a/src/locales/ru/actions.json +++ b/src/locales/ru/actions.json @@ -4,6 +4,7 @@ "create-group": "Создать группу", "create-user": "Создать пользователя", "reset-password": "Сбросить пароль", + "delete": "Удалить", "edit": "Редактировать", "block": "Заблокировать", "unblock": "Разблокировать", diff --git a/src/locales/ru/groups.json b/src/locales/ru/groups.json index 4ae0092..f6fa6b9 100644 --- a/src/locales/ru/groups.json +++ b/src/locales/ru/groups.json @@ -26,6 +26,10 @@ "delete-one": { "title": "Удаление группы", "message": "Вы уверены, что хотите удалить группу с ID {0}? Данное действие нельзя будет отменить" + }, + "delete-many": { + "title": "Удаление групп", + "message": "Вы уверены, что хотите удалить {0} групп? Данное действие нельзя будет отменить" } } } diff --git a/src/locales/ru/users.json b/src/locales/ru/users.json index 284546f..dbb432d 100644 --- a/src/locales/ru/users.json +++ b/src/locales/ru/users.json @@ -40,6 +40,10 @@ "delete-one": { "title": "Удаление пользователя", "message": "Вы уверены, что хотите удалить пользователя с ID {0}? Данное действие нельзя будет отменить" + }, + "delete-many": { + "title": "Удаление пользователей", + "message": "Вы уверены, что хотите удалить {0} пользователей? Данное действие нельзя будет отменить" } } } diff --git a/src/pages/users/components/GroupsTab.vue b/src/pages/users/components/GroupsTab.vue index 1f3dae7..ce9c3ca 100644 --- a/src/pages/users/components/GroupsTab.vue +++ b/src/pages/users/components/GroupsTab.vue @@ -151,6 +151,7 @@ watch( density="comfortable" class="mr-1" :disabled="isDeleted(item.deletedAt)" + :loading="$groups.loadingActionsID.includes(item.ID)" @click="editGroup(item)" > edit @@ -162,7 +163,7 @@ watch( variant="text" density="comfortable" :disabled="isDeleted(item.deletedAt)" - :loading="$groups.loadingDeleteID === item.ID" + :loading="$groups.loadingActionsID.includes(item.ID)" @click="deleteGroup(item)" > close diff --git a/src/pages/users/components/UsersTab.vue b/src/pages/users/components/UsersTab.vue index dadfba6..23d503c 100644 --- a/src/pages/users/components/UsersTab.vue +++ b/src/pages/users/components/UsersTab.vue @@ -204,6 +204,7 @@ watch( density="comfortable" class="mr-1" :disabled="isDeleted(item.deletedAt)" + :loading="$users.loadingActionsID.includes(item.ID)" > more_vert @@ -233,7 +234,7 @@ watch( variant="text" density="comfortable" :disabled="isDeleted(item.deletedAt)" - :loading="$users.loadingDeleteID === item.ID" + :loading="$users.loadingActionsID.includes(item.ID)" @click="deleteUser(item)" > close diff --git a/src/pages/users/index.vue b/src/pages/users/index.vue index c446745..69d77a1 100644 --- a/src/pages/users/index.vue +++ b/src/pages/users/index.vue @@ -3,6 +3,7 @@ import { useLocale } from 'vuetify'; import { UsersPageTabs } from '@/enums/user-tab.enum'; import { useUsersStore } from '@/stores/users'; import { useGroupsStore } from '@/stores/groups'; +import { useConfirmationStore } from '@/stores/confirmation'; import ErrorPlate from '@/components/ErrorPlate.vue'; import AddUser from './components/AddUser.vue'; import AddGroup from './components/AddGroup.vue'; @@ -16,6 +17,7 @@ const { t } = useLocale(); const $users = useUsersStore(); const $groups = useGroupsStore(); +const $confirmation = useConfirmationStore(); const tableHeight: Ref = ref(500); setInterval(() => { @@ -28,7 +30,7 @@ setInterval(() => { }, 100); // -// MARK: Tabs +// Tabs // const tab: Ref = ref(UsersPageTabs.USERS); const parseURLSearch = () => { @@ -87,14 +89,14 @@ watch(tab, () => { }); // -// MARK: Creation +// Creation // const openCreationModal = () => { tab.value === UsersPageTabs.USERS ? $users.openModal() : $groups.openModal(); }; // -// MARK: Search model +// Search model // const $search: WritableComputedRef = computed({ get() { @@ -107,14 +109,14 @@ const $search: WritableComputedRef = computed({ }, }); // -// MARK: Error +// Error // const $error: ComputedRef = computed(() => tab.value === UsersPageTabs.USERS ? $users.error : $groups.error, ); // -// MARK: Common functions +// Common functions // const getAll = () => { tab.value === UsersPageTabs.USERS ? $users.getAll() : $groups.getAll(); @@ -129,6 +131,43 @@ const resetActions = () => { $users.resetSelected(); $groups.resetSelected(); }; +const deleteMany = () => { + const len = + tab.value === UsersPageTabs.USERS + ? $users.selected.length + : $groups.selected.length; + $confirmation.openModal(); + $confirmation.setTitle( + t( + `$vuetify.${tab.value === UsersPageTabs.USERS ? 'users' : 'groups'}.delete.delete-many.title`, + ), + ); + $confirmation.setMessage( + t( + `$vuetify.${tab.value === UsersPageTabs.USERS ? 'users' : 'groups'}.delete.delete-many.message`, + [len], + ), + ); + $confirmation.setOnConfirm( + tab.value === UsersPageTabs.USERS + ? () => { + $users.deleteMany($users.selected); + $users.resetSelected(); + } + : () => { + $groups.deleteMany($groups.selected); + $groups.resetSelected(); + }, + ); +}; +const blockMany = () => { + $users.blockMany($users.selected); + $users.resetSelected(); +}; +const unblockMany = () => { + $users.unblockMany($users.selected); + $users.resetSelected(); +};