fix: user changes

This commit is contained in:
sajjadtalkhabi
2026-05-28 13:34:30 +03:30
parent cb86920015
commit 7ed6ec9ae1
46 changed files with 328 additions and 1114 deletions
@@ -67,7 +67,7 @@ const emit = defineEmits(['delete'])
const teacherName = computed(() => {
const t = props.course.teacher
if (!t) return '—'
return `${t.firstName || ''} ${t.lastName || ''}`.trim() || t.fullName || '—'
return t.name
})
const isActive = computed(() => props.course.isActive ?? false)
@@ -1,9 +1,14 @@
<template>
<BasicModal width="95%" max-width="42rem" min-width="auto" :show-close-button="true">
<BasicModal
title="افزودن دانشجو"
title-en="Add Student"
width="95%"
max-width="42rem"
min-width="auto"
:show-close-button="true"
>
<template #default="{ close }">
<div class="add-term-student">
<LineTitleBlock title="افزودن دانشجو" title-en="Add Student" />
<div class="add-term-student__search">
<SvgIcon name="user" :size="18" color="var(--color-thd-gray)" />
<input
@@ -37,20 +42,6 @@
</div>
<CircleButton
v-if="isAttached(user.id)"
tooltip="حذف از ترم"
bg-color="rgba(104, 104, 104, 0.05)"
size="2.25rem"
type="button"
:loading="pendingId === user.id"
@click="onDetach(user)"
>
<template #icon>
<SvgIcon name="trash" :size="16" color="var(--color-error)" />
</template>
</CircleButton>
<CircleButton
v-else
tooltip="افزودن به ترم"
bg-color="rgba(104, 104, 104, 0.05)"
size="2.25rem"
@@ -91,15 +82,9 @@ import BaseButton from '@/components/BaseButton.vue'
import SvgIcon from '@/components/icons/SvgIcon.vue'
import NoItems from '@/components/blocks/NoItems.vue'
import CircleButton from '@/components/CircleButton.vue'
import LineTitleBlock from '@/components/LineTitleBlock.vue'
import { useAdminUsersListQuery } from '@/services/query/admin-users'
import SkeletonLoaderBlock from '@/components/blocks/SkeletonLoaderBlock.vue'
import {
adminTermsKeys,
useAddAdminTermStudentsMutation,
useAdminTermStudentsQuery,
useRemoveAdminTermStudentMutation,
} from '@/services/query/admin-terms'
import { adminTermsKeys, useAddAdminTermStudentsMutation } from '@/services/query/admin-terms'
defineOptions({ name: 'AddTermStudentModal' })
@@ -111,29 +96,13 @@ const termId = computed(() => modalData.value.termId ?? null)
const searchInput = ref('')
const searchQuery = ref('')
const userFilters = computed(() => ({ name: searchQuery.value }))
const userPagination = ref({ page: 1, perPage: 20 })
const userFilters = computed(() => ({ search: searchQuery.value }))
const userPagination = ref({ page: 1, perPage: 10 })
const { data: usersResponse, isLoading } = useAdminUsersListQuery(userFilters, userPagination)
const users = computed(() => usersResponse.value?.data ?? [])
const attachedFilters = computed(() => ({}))
const attachedPagination = ref({ page: 1, perPage: 200 })
const { data: attachedResponse } = useAdminTermStudentsQuery(
termId,
attachedFilters,
attachedPagination,
{ enabled: () => !!termId.value }
)
const attachedIds = computed(() => new Set((attachedResponse.value?.data ?? []).map((u) => u.id)))
const isAttached = (id) => attachedIds.value.has(id)
const userLabel = (user) =>
`${user.firstName || ''} ${user.lastName || ''}`.trim() ||
user.fullName ||
user.phoneNumber ||
'—'
const userLabel = (user) => user.name.trim() || '—'
const onSearchInput = useDebounce(() => {
searchQuery.value = searchInput.value || ''
@@ -143,7 +112,6 @@ const onSearchInput = useDebounce(() => {
const pendingId = ref(null)
const addMutation = useAddAdminTermStudentsMutation()
const removeMutation = useRemoveAdminTermStudentMutation()
const invalidate = () => queryClient.invalidateQueries({ queryKey: adminTermsKeys.all })
@@ -153,7 +121,7 @@ const onAttach = async (user) => {
try {
await addMutation.mutateAsync({
termId: termId.value,
payload: { userIds: [user.id] },
payload: { userId: user.id },
})
invalidate()
} finally {
@@ -161,17 +129,6 @@ const onAttach = async (user) => {
}
}
const onDetach = async (user) => {
if (!termId.value) return
pendingId.value = user.id
try {
await removeMutation.mutateAsync({ termId: termId.value, userId: user.id })
invalidate()
} finally {
pendingId.value = null
}
}
watch(termId, () => {
searchInput.value = ''
searchQuery.value = ''
@@ -293,7 +250,7 @@ watch(termId, () => {
&__footer {
display: flex;
justify-content: flex-start;
justify-content: flex-end;
}
&__close-btn {
@@ -1,15 +1,21 @@
<template>
<BasicModal width="95%" max-width="80rem" min-width="auto" :show-close-button="true">
<template #default="{ data, close }">
<BasicModal
title="جزئیات ترم"
title-en="Term Details"
width="95%"
max-width="80rem"
min-width="auto"
:show-close-button="true"
>
<template #default="{ close }">
<div v-if="!term" class="term-details">
<p class="term-details__loading">در حال بارگذاری</p>
</div>
<div v-else class="term-details">
<section class="term-details__section">
<LineTitleBlock title="جزئیات ترم" title-en="Term Details" />
<div class="term-details__overview">
<div class="term-details__image">
<img v-if="term.image" :src="term.image" :alt="term.title" />
<img v-if="term.coverUrl" :src="term.coverUrl" :alt="term.title" />
<SvgIcon v-else name="book" :size="32" color="#bcbcbc" />
</div>
<div class="term-details__overview-grid">
@@ -51,19 +57,19 @@
<div v-else-if="students.length > 0">
<div v-for="student in students" :key="student.id" class="term-details__student-row">
<div class="term-details__student-main">
<div v-if="studentAvatar(student)" class="term-details__avatar">
<img :src="studentAvatar(student)" :alt="student.name" />
<div v-if="studentAvatar(student?.user)" class="term-details__avatar">
<img :src="studentAvatar(student?.user)" :alt="student.name" />
</div>
<div v-else class="term-details__avatar term-details__avatar--placeholder">
<SvgIcon name="user" :size="20" color="#bcbcbc" />
</div>
<div>
<p class="term-details__student-name">{{ student.name || '—' }}</p>
<p class="term-details__student-name">{{ student?.user?.name || '—' }}</p>
<p class="term-details__student-meta">
<span dir="ltr">{{ student.phone || '—' }}</span>
<template v-if="student.email">
<span dir="ltr">{{ student?.user.phone || '—' }}</span>
<template v-if="student?.user.email">
<span class="term-details__sep">،</span>
<span dir="ltr">{{ student.email }}</span>
<span dir="ltr">{{ student?.user.email }}</span>
</template>
</p>
</div>
@@ -114,7 +120,6 @@
</BaseButton>
</div>
</div>
<span class="term-details__data-tap" v-if="false">{{ data }}</span>
</template>
</BasicModal>
</template>
@@ -135,12 +140,12 @@ import LineTitleBlock from '@/components/LineTitleBlock.vue'
import LineInfoBlock from '@/components/blocks/LineInfoBlock.vue'
import PaginationBlock from '@/components/blocks/PaginationBlock.vue'
import SkeletonLoaderBlock from '@/components/blocks/SkeletonLoaderBlock.vue'
import { useAdminTermEnrolleesQuery, useAdminTermQuery } from '@/services/query/admin-terms'
import {
adminCoursesKeys,
useAdminCoursesListQuery,
useUpdateAdminCourseMutation,
} from '@/services/query/admin-courses'
import { useAdminTermQuery, useTermAttendeesQuery } from '@/services/query/admin-terms'
defineOptions({ name: 'TermDetailsModal' })
@@ -167,7 +172,7 @@ const {
reset: resetStudentPagination,
} = usePagination({ page: 1, perPage: 10 })
const { data: studentsData, isLoading: studentsPending } = useTermAttendeesQuery(
const { data: studentsData, isLoading: studentsPending } = useAdminTermEnrolleesQuery(
termId,
studentFilters,
studentPagination,