Files
lms/frontend/src/pages/AssignmentSubmissionList.vue
2025-07-03 13:02:57 +05:30

227 lines
4.7 KiB
Vue

<template>
<header
class="sticky top-0 z-10 flex items-center justify-between border-b bg-surface-white px-3 py-2.5 sm:px-5"
>
<Breadcrumbs :items="breadcrumbs" />
</header>
<div class="md:w-3/4 md:mx-auto py-5 mx-5">
<div class="grid grid-cols-3 gap-5 mb-5">
<Link
doctype="LMS Assignment"
v-model="assignmentID"
:placeholder="__('Assignment')"
/>
<Link doctype="User" v-model="member" :placeholder="__('Member')" />
<FormControl
v-model="status"
type="select"
:options="statusOptions"
:placeholder="__('Status')"
/>
</div>
<ListView
v-if="submissions.loading || submissions.data?.length"
:columns="submissionColumns"
:rows="submissions.data"
rowKey="name"
>
<ListHeader
class="mb-2 grid items-center space-x-4 rounded bg-surface-gray-2 p-2"
>
<ListHeaderItem :item="item" v-for="item in submissionColumns" />
</ListHeader>
<ListRows>
<router-link
v-for="row in submissions.data"
:to="{
name: 'AssignmentSubmission',
params: {
assignmentID: row.assignment,
submissionName: row.name,
},
}"
>
<ListRow :row="row">
<template #default="{ column, item }">
<ListRowItem :item="row[column.key]" :align="column.align">
<div v-if="column.key == 'status'">
<Badge :theme="getStatusTheme(row[column.key])">
{{ row[column.key] }}
</Badge>
</div>
<div v-else>
{{ row[column.key] }}
</div>
</ListRowItem>
</template>
</ListRow>
</router-link>
</ListRows>
</ListView>
<div
v-else
class="text-center p-5 text-ink-gray-5 mt-52 w-3/4 md:w-1/2 mx-auto space-y-2"
>
<Pencil class="size-8 mx-auto stroke-1 text-ink-gray-4" />
<div class="text-xl font-medium">
{{ __('No submissions') }}
</div>
<div class="leading-5">
{{ __('There are no submissions for this assignment.') }}
</div>
</div>
</div>
</template>
<script setup>
import {
Badge,
Breadcrumbs,
createListResource,
FormControl,
ListView,
ListHeader,
ListHeaderItem,
ListRows,
ListRow,
ListRowItem,
usePageMeta,
} from 'frappe-ui'
import { computed, inject, onMounted, ref, watch } from 'vue'
import { useRouter } from 'vue-router'
import { Pencil } from 'lucide-vue-next'
import { sessionStore } from '../stores/session'
import Link from '@/components/Controls/Link.vue'
const user = inject('$user')
const dayjs = inject('$dayjs')
const { brand } = sessionStore()
const router = useRouter()
const assignmentID = ref('')
const member = ref('')
const status = ref('')
onMounted(() => {
if (!user.data?.is_instructor && !user.data?.is_moderator) {
router.push({ name: 'Courses' })
}
assignmentID.value = router.currentRoute.value.query.assignmentID
member.value = router.currentRoute.value.query.member
status.value = router.currentRoute.value.query.status
reloadSubmissions()
})
const getAssignmentFilters = () => {
let filters = {}
if (assignmentID.value) {
filters.assignment = assignmentID.value
}
if (member.value) {
filters.member = member.value
}
if (status.value) {
filters.status = status.value
}
return filters
}
const submissions = createListResource({
doctype: 'LMS Assignment Submission',
fields: [
'name',
'assignment',
'assignment_title',
'member_name',
'creation',
'status',
],
orderBy: 'creation desc',
transform(data) {
return data.map((row) => {
return {
...row,
creation: dayjs(row.creation).fromNow(),
}
})
},
})
watch([assignmentID, member, status], () => {
router.push({
query: {
assignmentID: assignmentID.value,
member: member.value,
status: status.value,
},
})
reloadSubmissions()
})
const reloadSubmissions = () => {
submissions.update({
filters: getAssignmentFilters(),
})
submissions.reload()
}
const submissionColumns = computed(() => {
return [
{
label: 'Member',
key: 'member_name',
width: 1,
},
{
label: 'Assignment',
key: 'assignment_title',
width: 2,
},
{
label: 'Submitted',
key: 'creation',
width: 1,
align: 'left',
},
{
label: 'Status',
key: 'status',
width: 1,
align: 'center',
},
]
})
const statusOptions = computed(() => {
return [
{ label: '', value: '' },
{ label: 'Pass', value: 'Pass' },
{ label: 'Fail', value: 'Fail' },
{ label: 'Not Graded', value: 'Not Graded' },
]
})
const getStatusTheme = (status) => {
if (status === 'Pass') {
return 'green'
} else if (status === 'Not Graded') {
return 'blue'
} else {
return 'red'
}
}
const breadcrumbs = computed(() => {
return [
{
label: 'Assignment Submissions',
},
]
})
usePageMeta(() => {
return {
title: __('Assignment Submissions'),
icon: brand.favicon,
}
})
</script>