@7365admin1/layer-common 3.2.2-staging.83 → 3.2.2-staging.84

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -105,42 +105,90 @@
105
105
  />
106
106
  </v-dialog>
107
107
 
108
- <ConfirmDialog
109
- v-model="confirmDialog"
110
- :loading="deleteLoading"
111
- @submit="handleDeleteRole"
112
- >
113
- <template #title>
114
- <span class="font-weight-medium text-h5">Delete Role</span>
115
- </template>
116
-
117
- <template #description>
118
- <p class="text-subtitle-2">
119
- Are you sure you want to delete this role? This action cannot be
120
- undone.
121
- </p>
122
- </template>
123
-
124
- <template #footer>
125
- <div class="d-flex justify-center ga-3 w-100">
126
- <v-btn
127
- variant="text"
128
- @click="confirmDialog = false"
129
- :disabled="deleteLoading"
130
- >
131
- Close
132
- </v-btn>
133
- <v-btn
134
- color="primary"
135
- variant="flat"
136
- @click="handleDeleteRole"
137
- :loading="deleteLoading"
138
- >
139
- Delete Role
140
- </v-btn>
141
- </div>
142
- </template>
143
- </ConfirmDialog>
108
+ <v-dialog v-model="confirmDialog" max-width="450">
109
+ <v-card>
110
+ <v-toolbar>
111
+ <v-row no-gutters class="fill-height px-6" align="center">
112
+ <span class="font-weight-bold text-h6 text-capitalize">
113
+ Delete Role
114
+ </span>
115
+ </v-row>
116
+ </v-toolbar>
117
+
118
+ <v-card-text>
119
+ <span v-if="!hasAssignedMembers" class="text-subtitle-2">
120
+ Are you sure you want to delete this role? This action cannot be
121
+ undone.
122
+ </span>
123
+ <template v-else>
124
+ <p class="text-subtitle-2 mb-4">
125
+ There are currently
126
+ <span class="text-error font-weight-bold">
127
+ {{ deletionPreview.members.length }}
128
+ {{ deletionPreview.members.length === 1 ? "user" : "users" }}
129
+ </span>
130
+ assigned to this role. Reassign each user before deleting it so
131
+ they do not lose access.
132
+ </p>
133
+
134
+ <v-row
135
+ v-for="member in deletionPreview.members"
136
+ :key="member._id"
137
+ no-gutters
138
+ class="mb-3 pa-3 border rounded-lg"
139
+ align="center"
140
+ >
141
+ <v-col cols="12" sm="5" class="text-body-2 mb-2 mb-sm-0">
142
+ {{ member.name || member.user }}
143
+ </v-col>
144
+ <v-col cols="12" sm="7">
145
+ <v-select
146
+ v-model="memberReassignments[member._id]"
147
+ :items="deletionPreview.replacementRoles"
148
+ item-title="name"
149
+ item-value="_id"
150
+ label="Reassign role"
151
+ density="comfortable"
152
+ hide-details
153
+ />
154
+ </v-col>
155
+ </v-row>
156
+ </template>
157
+ </v-card-text>
158
+
159
+ <v-toolbar class="pa-0" density="compact">
160
+ <v-row no-gutters>
161
+ <v-col cols="6" class="pa-0">
162
+ <v-btn
163
+ block
164
+ variant="text"
165
+ class="text-none"
166
+ size="large"
167
+ height="48"
168
+ @click="closeDeleteDialog"
169
+ :disabled="deleteLoading"
170
+ >
171
+ Cancel
172
+ </v-btn>
173
+ </v-col>
174
+ <v-col cols="6" class="pa-0">
175
+ <v-btn
176
+ block
177
+ variant="flat"
178
+ color="black"
179
+ class="text-none font-weight-bold rounded-0"
180
+ height="48"
181
+ @click="handleDeleteRole"
182
+ :loading="deleteLoading"
183
+ :disabled="hasAssignedMembers && !canConfirmDeletion"
184
+ >
185
+ {{ hasAssignedMembers ? "Confirm" : "Delete" }}
186
+ </v-btn>
187
+ </v-col>
188
+ </v-row>
189
+ </v-toolbar>
190
+ </v-card>
191
+ </v-dialog>
144
192
 
145
193
  <Snackbar v-model="messageSnackbar" :text="message" :color="messageColor" />
146
194
  </v-row>
@@ -367,10 +415,49 @@ async function refreshRolesAfterUpdate(savedPermissions: string[]) {
367
415
  const confirmDialog = ref(false);
368
416
  const selectedRoleId = ref<string | null>(null);
369
417
  const deleteLoading = ref(false);
418
+ const deletionPreview = ref({
419
+ members: [] as Array<Record<string, any>>,
420
+ replacementRoles: [] as Array<Record<string, any>>,
421
+ });
422
+ const memberReassignments = ref<Record<string, string>>({});
423
+
424
+ const hasAssignedMembers = computed(
425
+ () => deletionPreview.value.members.length > 0
426
+ );
427
+
428
+ const canConfirmDeletion = computed(() =>
429
+ deletionPreview.value.members.every(
430
+ (member) => Boolean(memberReassignments.value[member._id])
431
+ )
432
+ );
370
433
 
371
- function openDeleteDialog(id: string) {
434
+ const { getDeletionPreview, deleteWithReassignments } = useRole();
435
+
436
+ async function openDeleteDialog(id: string) {
372
437
  selectedRoleId.value = id;
373
- confirmDialog.value = true;
438
+ deletionPreview.value = { members: [], replacementRoles: [] };
439
+ memberReassignments.value = {};
440
+ deleteLoading.value = true;
441
+
442
+ try {
443
+ const res = await getDeletionPreview(id);
444
+ deletionPreview.value = res.data;
445
+ confirmDialog.value = true;
446
+ } catch (error: any) {
447
+ const errorMessage =
448
+ error?.response?._data?.message || "Failed to load role assignments.";
449
+ showMessage(errorMessage, "error");
450
+ selectedRoleId.value = null;
451
+ } finally {
452
+ deleteLoading.value = false;
453
+ }
454
+ }
455
+
456
+ function closeDeleteDialog() {
457
+ confirmDialog.value = false;
458
+ selectedRoleId.value = null;
459
+ deletionPreview.value = { members: [], replacementRoles: [] };
460
+ memberReassignments.value = {};
374
461
  }
375
462
 
376
463
  function showMessage(msg: string, color: string) {
@@ -383,17 +470,23 @@ async function handleDeleteRole() {
383
470
  if (!selectedRoleId.value) return;
384
471
  deleteLoading.value = true;
385
472
  try {
386
- const res = await deleteRole(selectedRoleId.value);
387
-
388
- confirmDialog.value = false;
473
+ const reassignments = deletionPreview.value.members.map((member) => ({
474
+ memberId: member._id,
475
+ roleId: memberReassignments.value[member._id],
476
+ }));
477
+ const res = hasAssignedMembers.value
478
+ ? await deleteWithReassignments(selectedRoleId.value, reassignments)
479
+ : await deleteRole(selectedRoleId.value);
480
+
481
+ closeDeleteDialog();
389
482
  showMessage(res.message, "success");
390
483
  getRoles();
391
484
  } catch (error: any) {
392
- const errorMessage = error?.response?._data?.message;
485
+ const errorMessage =
486
+ error?.response?._data?.message || "Failed to delete role.";
393
487
  showMessage(errorMessage, "error");
394
488
  } finally {
395
489
  deleteLoading.value = false;
396
- selectedRoleId.value = null;
397
490
  }
398
491
  }
399
492
  </script>
@@ -68,6 +68,26 @@ export default function useRole() {
68
68
  });
69
69
  }
70
70
 
71
+ function getDeletionPreview(_id: string) {
72
+ return useNuxtApp().$api<Record<string, any>>(
73
+ `/api/roles/${_id}/deletion-preview`,
74
+ { method: "GET" }
75
+ );
76
+ }
77
+
78
+ function deleteWithReassignments(
79
+ _id: string,
80
+ reassignments: Array<{ memberId: string; roleId: string }>
81
+ ) {
82
+ return useNuxtApp().$api<Record<string, any>>(
83
+ `/api/roles/${_id}/delete-with-reassignments`,
84
+ {
85
+ method: "PUT",
86
+ body: { reassignments },
87
+ }
88
+ );
89
+ }
90
+
71
91
  const role = useState<TRole>("userRole", () => {
72
92
  return {
73
93
  _id: "",
@@ -103,6 +123,8 @@ export default function useRole() {
103
123
  updateRoleById,
104
124
  updateRoleFieldById,
105
125
  deleteRole,
126
+ getDeletionPreview,
127
+ deleteWithReassignments,
106
128
  updatePermissionById,
107
129
  getRoleByUserId,
108
130
  };
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@7365admin1/layer-common",
3
3
  "license": "MIT",
4
4
  "type": "module",
5
- "version": "3.2.2-staging.83",
5
+ "version": "3.2.2-staging.84",
6
6
  "author": "7365admin1",
7
7
  "main": "./nuxt.config.ts",
8
8
  "publishConfig": {