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