feat: add delete class action and confirm dialog in class list and detail views
This commit is contained in:
@@ -8,6 +8,7 @@ export const classApi = {
|
||||
create: (data) => axiosInstance.post('/classes/admin/create', data),
|
||||
update: (id, data) => axiosInstance.put(`/classes/admin/update/${id}`, data),
|
||||
delete: (id) => axiosInstance.delete(`/classes/admin/delete/${id}`),
|
||||
restore: (id) => axiosInstance.post(`/classes/admin/restore/${id}`),
|
||||
registerUsers: (classId, userIds, notify) =>
|
||||
axiosInstance.post(`/classes/admin/${classId}/register-users`, { userIds, notify }),
|
||||
removeUser: (classId, userId) =>
|
||||
|
||||
@@ -11,6 +11,16 @@
|
||||
@click="$router.push(`/financial-reports?classId=${classId}`)"
|
||||
/>
|
||||
</PermissionGate>
|
||||
<PermissionGate permission="classes:delete">
|
||||
<Button
|
||||
label="حذف کلاس"
|
||||
icon="pi pi-trash"
|
||||
severity="danger"
|
||||
text
|
||||
class="ml-2"
|
||||
@click="confirmDeleteClass"
|
||||
/>
|
||||
</PermissionGate>
|
||||
<Button label="ویرایش" icon="pi pi-pencil" class="ml-2" @click="$router.push(`/classes/edit/${classId}`)" />
|
||||
<Button label="بازگشت" icon="pi pi-arrow-left" text severity="secondary" @click="$router.push('/classes')" />
|
||||
</PageHeader>
|
||||
@@ -135,12 +145,20 @@
|
||||
:loading="!!removingUserId"
|
||||
@confirm="handleRemoveStudent"
|
||||
/>
|
||||
|
||||
<ConfirmDeleteDialog
|
||||
v-model="deleteClassDialogVisible"
|
||||
title="حذف کلاس"
|
||||
:message="deleteClassDialogMessage"
|
||||
:loading="isDeletingClass"
|
||||
@confirm="handleDeleteClass"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { classApi } from '@/api/classApi';
|
||||
import { formatClassDays, formatClassTime } from '@/utils/classSchedule';
|
||||
import { sessionApi } from '@/api/sessionApi';
|
||||
@@ -157,6 +175,7 @@ import DataTable from 'primevue/datatable';
|
||||
import Column from 'primevue/column';
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const classId = route.params.id;
|
||||
const { toPersianDigits, formatJalali } = usePersianDate();
|
||||
const { showError, showSuccess } = useToast();
|
||||
@@ -170,6 +189,34 @@ const removeDialogVisible = ref(false);
|
||||
const removingUserId = ref('');
|
||||
const studentToRemove = ref(null);
|
||||
|
||||
const deleteClassDialogVisible = ref(false);
|
||||
const isDeletingClass = ref(false);
|
||||
|
||||
const deleteClassDialogMessage = computed(() => {
|
||||
const name = classData.value?.name;
|
||||
return name
|
||||
? `آیا از حذف کلاس «${name}» اطمینان دارید؟ تمام جلسات و پیوندهای مرتبط با این کلاس نیز به سطل زباله منتقل میشوند.`
|
||||
: 'آیا از حذف این کلاس اطمینان دارید؟ تمام جلسات و پیوندهای مرتبط با این کلاس نیز به سطل زباله منتقل میشوند.';
|
||||
});
|
||||
|
||||
const confirmDeleteClass = () => {
|
||||
deleteClassDialogVisible.value = true;
|
||||
};
|
||||
|
||||
const handleDeleteClass = async () => {
|
||||
isDeletingClass.value = true;
|
||||
try {
|
||||
await classApi.delete(classId);
|
||||
showSuccess('کلاس و جلسات مرتبط با موفقیت حذف شدند');
|
||||
deleteClassDialogVisible.value = false;
|
||||
router.push('/classes');
|
||||
} catch (err) {
|
||||
showError(err);
|
||||
} finally {
|
||||
isDeletingClass.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const removeDialogMessage = computed(() => {
|
||||
const name = studentToRemove.value?.name;
|
||||
return name
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
</template>
|
||||
</Column>
|
||||
|
||||
<Column header="عملیات" style="width: 120px">
|
||||
<Column header="عملیات" style="width: 140px">
|
||||
<template #body="{ data }">
|
||||
<div class="flex align-items-center gap-1">
|
||||
<Button
|
||||
@@ -50,6 +50,7 @@
|
||||
rounded
|
||||
size="small"
|
||||
severity="info"
|
||||
v-tooltip.top="'مشاهده'"
|
||||
@click="$router.push(`/classes/view/${data._id || data.id}`)"
|
||||
/>
|
||||
<PermissionGate permission="classes:update">
|
||||
@@ -59,29 +60,52 @@
|
||||
rounded
|
||||
size="small"
|
||||
severity="warning"
|
||||
v-tooltip.top="'ویرایش'"
|
||||
@click="$router.push(`/classes/edit/${data._id || data.id}`)"
|
||||
/>
|
||||
</PermissionGate>
|
||||
<PermissionGate permission="classes:delete">
|
||||
<Button
|
||||
icon="pi pi-trash"
|
||||
text
|
||||
rounded
|
||||
size="small"
|
||||
severity="danger"
|
||||
v-tooltip.top="'حذف'"
|
||||
@click="confirmDelete(data)"
|
||||
/>
|
||||
</PermissionGate>
|
||||
</div>
|
||||
</template>
|
||||
</Column>
|
||||
</DataTableWrapper>
|
||||
|
||||
<ConfirmDeleteDialog
|
||||
v-model="deleteDialogVisible"
|
||||
title="حذف کلاس"
|
||||
:message="deleteMessage"
|
||||
:loading="isDeleting"
|
||||
@confirm="handleDelete"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted } from 'vue';
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
import { useDataTable } from '@/composables/useDataTable';
|
||||
import { usePersianDate } from '@/composables/usePersianDate';
|
||||
import { useToast } from '@/composables/useToast';
|
||||
import { classApi } from '@/api/classApi';
|
||||
import { formatClassSchedule } from '@/utils/classSchedule';
|
||||
import PageHeader from '@/components/common/PageHeader.vue';
|
||||
import DataTableWrapper from '@/components/common/DataTableWrapper.vue';
|
||||
import ConfirmDeleteDialog from '@/components/common/ConfirmDeleteDialog.vue';
|
||||
import PermissionGate from '@/components/common/PermissionGate.vue';
|
||||
import Button from 'primevue/button';
|
||||
import Column from 'primevue/column';
|
||||
|
||||
const { toPersianDigits } = usePersianDate();
|
||||
const { showSuccess, showError } = useToast();
|
||||
|
||||
const {
|
||||
items,
|
||||
@@ -94,6 +118,38 @@ const {
|
||||
onSearch
|
||||
} = useDataTable(classApi.getAll);
|
||||
|
||||
const deleteDialogVisible = ref(false);
|
||||
const selectedClass = ref(null);
|
||||
const isDeleting = ref(false);
|
||||
|
||||
const deleteMessage = computed(() => {
|
||||
const name = selectedClass.value?.name;
|
||||
return name
|
||||
? `آیا از حذف کلاس «${name}» اطمینان دارید؟ تمام جلسات و پیوندهای مرتبط با این کلاس نیز به سطل زباله منتقل میشوند.`
|
||||
: 'آیا از حذف این کلاس اطمینان دارید؟ تمام جلسات و پیوندهای مرتبط با این کلاس نیز به سطل زباله منتقل میشوند.';
|
||||
});
|
||||
|
||||
const confirmDelete = (classItem) => {
|
||||
selectedClass.value = classItem;
|
||||
deleteDialogVisible.value = true;
|
||||
};
|
||||
|
||||
const handleDelete = async () => {
|
||||
if (!selectedClass.value) return;
|
||||
isDeleting.value = true;
|
||||
try {
|
||||
await classApi.delete(selectedClass.value._id || selectedClass.value.id);
|
||||
showSuccess('کلاس و جلسات مرتبط با موفقیت حذف شدند');
|
||||
deleteDialogVisible.value = false;
|
||||
selectedClass.value = null;
|
||||
loadData();
|
||||
} catch (err) {
|
||||
showError(err);
|
||||
} finally {
|
||||
isDeleting.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
loadData();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user