Files
banu-front/src/features/admin/assignments/components/modals/AssignmentSubmissionsModal.vue
T
sajjadtalkhabi 3f3c66a02d fix: test
2026-05-28 15:40:22 +03:30

242 lines
6.7 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<BasicModal
title="تکالیف فرستادگان"
title-en="Delegates Submissions"
width="95%"
max-width="60rem"
min-width="auto"
:show-close-button="true"
>
<template #default="{ close }">
<div class="assignment-submissions">
<SkeletonLoaderBlock v-if="isLoading" :rows="4" :cols-per-row="1" />
<div v-else-if="submissions.length > 0" class="assignment-submissions__list">
<div
v-for="submission in submissions"
:key="submission.id"
class="assignment-submissions__row"
>
<div class="assignment-submissions__user">
<div v-if="submission.user?.avatarUrl" class="assignment-submissions__avatar">
<img :src="submission.user.avatarUrl" :alt="userName(submission.user)" />
</div>
<div
v-else
class="assignment-submissions__avatar assignment-submissions__avatar--placeholder"
>
<SvgIcon name="user" :size="20" color="#bcbcbc" />
</div>
<div>
<p class="assignment-submissions__name">{{ userName(submission.user) }}</p>
<p class="assignment-submissions__location">
{{ locationFromAddress(submission.user) || '—' }}
</p>
</div>
</div>
<div class="assignment-submissions__pill">
<span class="assignment-submissions__pill-label">تاریخ ارسال:</span>
<span class="assignment-submissions__pill-value">{{ submittedAt(submission) }}</span>
</div>
<BaseButton
text="جزئیات"
custom-class="assignment-submissions__details-btn"
@click="onShowDetails(submission)"
>
<template #appendIcon>
<SvgIcon name="caret-left" :size="14" color="#fff" />
</template>
</BaseButton>
</div>
</div>
<NoItems v-else title="موردی یافت نشد" desc="تکلیفی ارسال نشده است." />
<PaginationBlock :pagination="paginationMeta" @update:page="setPage" />
<div class="assignment-submissions__divider" />
<div class="assignment-submissions__footer">
<BaseButton text="بستن" custom-class="assignment-submissions__close-btn" @click="close">
<template #appendIcon>
<SvgIcon name="arrow-left" :size="18" color="#fff" />
</template>
</BaseButton>
</div>
</div>
</template>
</BasicModal>
</template>
<script setup>
import { computed, ref } from 'vue'
import useModal from '@/composables/useModal'
import BasicModal from '@/components/BasicModal.vue'
import BaseButton from '@/components/BaseButton.vue'
import SvgIcon from '@/components/icons/SvgIcon.vue'
import NoItems from '@/components/blocks/NoItems.vue'
import { formatJalaaliDate } from '@/utils/date-utils'
import { usePagination } from '@/composables/usePagination'
import LineTitleBlock from '@/components/LineTitleBlock.vue'
import PaginationBlock from '@/components/blocks/PaginationBlock.vue'
import SkeletonLoaderBlock from '@/components/blocks/SkeletonLoaderBlock.vue'
import { useAdminAssignmentSubmissionsQuery } from '@/services/query/admin-assignments'
defineOptions({ name: 'AssignmentSubmissionsModal' })
const { getModal, openModal } = useModal()
const modalData = computed(() => getModal('AssignmentSubmissionsModal')?.data ?? {})
const assignmentId = computed(() => modalData.value.id ?? null)
const filters = ref({})
const { pagination, setPage } = usePagination({ page: 1, perPage: 10 })
const { data, isLoading } = useAdminAssignmentSubmissionsQuery(assignmentId, filters, pagination, {
enabled: () => !!assignmentId.value,
keepPreviousData: true,
})
const submissions = computed(() => data.value?.data ?? [])
const paginationMeta = computed(() => ({
page: pagination.value.page,
perPage: pagination.value.perPage,
...data.value?.meta,
}))
const userName = (user) =>
user?.name || `${user?.firstName || ''} ${user?.lastName || ''}`.trim() || user?.fullName || '—'
const locationFromAddress = (user) => {
const province = user?.province?.name || user?.address?.province?.name || ''
const city = user?.city?.name || user?.address?.city?.name || ''
return [province, city].filter(Boolean).join('، ')
}
const submittedAt = (sub) =>
sub.faSubmittedAt || formatJalaaliDate(sub.submittedAt || sub.createdAt || sub.reviewedAt) || '—'
const onShowDetails = (submission) => {
openModal('AssignmentSubmissionDetailsModal', {
assignmentId: assignmentId.value,
submissionId: submission.id,
submission,
})
}
</script>
<style lang="scss" scoped>
.assignment-submissions {
width: 100%;
text-align: start;
&__assignment {
font-family: var(--font-family-fa);
font-size: 0.85rem;
color: var(--color-prim-gray);
margin: 0 0 0.75rem;
}
&__list {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
&__row {
display: flex;
align-items: center;
gap: 0.625rem;
padding: 0.625rem 0.875rem;
background: rgba(255, 255, 255, 60%);
border-radius: 0.875rem;
box-shadow: 0 4px 10px -6px rgba(241, 241, 241, 70%);
flex-wrap: wrap;
}
&__user {
flex: 1 1 40%;
display: flex;
align-items: center;
gap: 0.625rem;
min-width: 0;
}
&__avatar {
width: 2.75rem;
height: 2.75rem;
border-radius: 9999px;
overflow: hidden;
background: #f5f5f5;
flex-shrink: 0;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
&--placeholder {
display: flex;
align-items: center;
justify-content: center;
}
}
&__name {
font-family: var(--font-family-fa);
font-size: 0.95rem;
color: #4b4b4b;
margin: 0 0 0.25rem;
}
&__location {
font-family: var(--font-family-fa);
font-size: 0.7rem;
color: #989898;
margin: 0;
}
&__pill {
background: rgba(107, 107, 107, 5%);
border-radius: 0.875rem;
padding: 0.375rem 1rem;
text-align: center;
min-width: 9rem;
white-space: nowrap;
}
&__pill-label {
font-family: var(--font-family-fa);
font-size: 0.7rem;
color: #535353;
margin-inline-end: 0.25rem;
}
&__pill-value {
font-family: var(--font-family-en);
font-size: 0.7rem;
color: #535353;
}
&__details-btn {
min-width: 5rem;
padding: 0 1rem;
}
&__divider {
border-block-end: 1px solid var(--color-thd-gray);
margin-block: 1.25rem;
}
&__footer {
display: flex;
justify-content: flex-end;
}
&__close-btn {
min-width: 12rem;
}
}
</style>