Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions assets/vue/components/attendance/AttendanceForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,14 @@ import LayoutFormButtons from "../../components/layout/LayoutFormButtons.vue"
import BaseButton from "../../components/basecomponents/BaseButton.vue"
import BaseAdvancedSettingsButton from "../../components/basecomponents/BaseAdvancedSettingsButton.vue"
import BaseInputText from "../basecomponents/BaseInputText.vue"
import { useRoute } from "vue-router"
import { useRoute, useRouter } from "vue-router"
import { RESOURCE_LINK_PUBLISHED } from "../../constants/entity/resourcelink"
import { useCidReq } from "../../composables/cidReq"
import gradebookService from "../../services/gradebookService"

const { t } = useI18n()
const route = useRoute()
const router = useRouter()
const { sid, cid } = useCidReq()
const emit = defineEmits(["backPressed"])
const props = defineProps({
Expand Down Expand Up @@ -194,10 +195,22 @@ const submitForm = async () => {
try {
if (props.initialData?.id) {
await attendanceService.updateAttendance(props.initialData.id, postData)
emit("backPressed", route.query)
} else {
await attendanceService.createAttendance(postData)
const created = await attendanceService.createAttendance(postData)
router.push({
name: "AddCalendarEvent",
params: {
node: parentResourceNodeId.value,
id: created.id,
},
query: {
cid: route.query.cid,
sid: route.query.sid,
gid: route.query.gid,
},
})
}
emit("backPressed", route.query)
} catch (error) {
console.error("Error submitting attendance:", error)
}
Expand Down
9 changes: 6 additions & 3 deletions assets/vue/components/attendance/AttendanceTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,20 @@

<!-- Column for # attended -->
<Column
field="results.length"
field="doneCalendars"
header="# attended"
sortable
>
<template #body="slotProps">
<center>{{ slotProps.data.results ? slotProps.data.results.length : 0 }}</center>
<center>{{ slotProps.data.doneCalendars ?? 0 }}</center>
</template>
</Column>

<!-- Column for Detail -->
<Column header="Detail">
<Column
v-if="isAdminOrTeacher"
header="Detail"
>
<template #body="slotProps">
<div class="flex gap-2 justify-center">
<Button
Expand Down
3 changes: 3 additions & 0 deletions assets/vue/components/basecomponents/ChamiloIcons.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export const chamiloIconToClass = {
"file-text": "mdi mdi-file-document",
"file-upload": "mdi mdi-file-upload",
"file-video": "mdi mdi-file-video",
"file-excel": "mdi mdi-file-excel-box",
"filter": "mdi mdi-filter",
"file-replace": "mdi mdi-file-replace",
"fit-to-screen": "",
Expand Down Expand Up @@ -140,4 +141,6 @@ export const chamiloIconToClass = {
"account-cancel": "mdi mdi-account-cancel",
"zip-pack": "mdi mdi-archive",
"zip-unpack": "mdi mdi-archive-arrow-down",
"clear-all": "mdi mdi-broom",
"qrcode": "mdi mdi-qrcode",
}
69 changes: 44 additions & 25 deletions assets/vue/services/attendanceService.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,14 +164,9 @@ export default {
}
},

/**
* Fetches users related to attendance based on course, session, or group.
* @param {Object} params - Object with courseId, sessionId, and/or groupId.
* @returns {Promise<Array>} - List of users.
*/
getAttendanceSheetUsers: async (params) => {
getAttendanceSheetUsers: async (attendanceId, params) => {
try {
const response = await axios.get(`/attendance/users/context`, { params })
const response = await axios.get(`/attendance/${attendanceId}/users/context`, { params })
return response.data
} catch (error) {
console.error("Error fetching attendance sheet users:", error)
Expand Down Expand Up @@ -215,27 +210,36 @@ export default {
return response.data
},

/**
* Exports an attendance list to PDF format.
* @param {Number|String} attendanceId - ID of the attendance list.
* @returns {Promise<Blob>} - PDF file of the attendance list.
*/
exportAttendanceToPdf: async (attendanceId) => {
const response = await axios.get(`${ENTRYPOINT}attendances/${attendanceId}/export/pdf`, {
responseType: "blob",
})
exportAttendanceToPdf: async (attendanceId, { cid, sid, gid }) => {
const response = await axios.get(
`/attendance/${attendanceId}/export/pdf`,
{
params: { cid, sid, gid },
responseType: "blob",
}
)
return response.data
},

/**
* Exports an attendance list to XLS format.
* @param {Number|String} attendanceId - ID of the attendance list.
* @returns {Promise<Blob>} - XLS file of the attendance list.
*/
exportAttendanceToXls: async (attendanceId) => {
const response = await axios.get(`${ENTRYPOINT}attendances/${attendanceId}/export/xls`, {
responseType: "blob",
})
exportAttendanceToXls: async (attendanceId, { cid, sid, gid }) => {
const response = await axios.get(
`/attendance/${attendanceId}/export/xls`,
{
params: { cid, sid, gid },
responseType: "blob",
}
)
return response.data
},

generateQrCode: async (attendanceId, { cid, sid, gid }) => {
const response = await axios.get(
`/attendance/${attendanceId}/qrcode`,
{
params: { cid, sid, gid },
responseType: "blob",
}
)
return response.data
},

Expand All @@ -250,4 +254,19 @@ export default {
throw error
}
},

getAttendancesWithDoneCount: async (params) => {
const response = await axios.get(`/attendance/list_with_done_count`, { params });
return response.data;
},

getStudentAttendanceData: async (attendanceId) => {
try {
const response = await axios.get(`/attendance/${attendanceId}/student-dates`)
return response.data
} catch (error) {
console.error("Error fetching student attendance data:", error)
throw error
}
},
}
27 changes: 27 additions & 0 deletions assets/vue/views/attendance/AttendanceCalendarAdd.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
<template>
<LayoutFormGeneric>
<div class="bg-blue-100 text-blue-800 p-4 rounded border border-blue-300">
<strong>{{ t("Information") }}:</strong>
<span v-if="attendanceTitle">
{{ t("You are adding calendar events for attendance") }}: <strong>{{ attendanceTitle }}</strong
>.
</span>
<span>
{{
t(
"The attendance calendar allows you to register attendance lists (one per real session the students need to attend). Add new attendance lists here.",
)
}}
</span>
</div>

<template #header>
<BaseIcon icon="calendar-plus" />
{{ t("Add Attendance Calendar") }}
Expand All @@ -15,10 +30,22 @@ import { useI18n } from "vue-i18n"
import LayoutFormGeneric from "../../components/layout/LayoutFormGeneric.vue"
import BaseIcon from "../../components/basecomponents/BaseIcon.vue"
import AttendanceCalendarForm from "../../components/attendance/AttendanceCalendarForm.vue"
import attendanceService from "../../services/attendanceService"
import { onMounted, ref } from "vue"

const { t } = useI18n()
const router = useRouter()
const route = useRoute()
const attendanceTitle = ref("")

onMounted(async () => {
try {
const attendance = await attendanceService.getAttendance(route.params.id)
attendanceTitle.value = attendance.title
} catch (error) {
console.error("Error fetching attendance:", error)
}
})

const goBack = () => {
router.push({
Expand Down
42 changes: 23 additions & 19 deletions assets/vue/views/attendance/AttendanceCalendarList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,29 @@
<div class="p-4">
<!-- Toolbar -->
<BaseToolbar>
<BaseButton
:label="t('Back to Attendance Sheet')"
icon="back"
type="info"
@click="redirectToAttendanceSheet"
/>
<BaseButton
:label="t('Add Calendar Event')"
icon="plus"
type="success"
@click="redirectToAddCalendarEvent"
/>

<BaseButton
:label="t('Clear All')"
icon="delete"
type="error"
@click="clearAllEvents"
/>
<template #start>
<BaseButton
icon="back"
size="normal"
type="black"
@click="redirectToAttendanceSheet"
:title="t('Back to Attendance Sheet')"
/>
<BaseButton
icon="plus"
size="normal"
type="black"
@click="redirectToAddCalendarEvent"
:title="t('Add Calendar Event')"
/>
<BaseButton
icon="clear-all"
size="normal"
type="black"
@click="clearAllEvents"
:title="t('Clear All')"
/>
</template>
</BaseToolbar>

<!-- Informative Message -->
Expand Down
18 changes: 11 additions & 7 deletions assets/vue/views/attendance/AttendanceList.vue
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
<template>
<div>
<BaseToolbar>
<BaseButton
:label="t('Add Attendance')"
icon="plus"
type="black"
@click="redirectToCreateAttendance"
/>
<template #start>
<BaseButton
v-if="!isStudent"
icon="file-add"
size="normal"
type="black"
:title="t('Add Attendance')"
@click="redirectToCreateAttendance"
/>
</template>
</BaseToolbar>

<AttendanceTable
:attendances="attendances"
:loading="isLoading"
Expand Down Expand Up @@ -113,6 +116,7 @@ const fetchAttendances = async ({ page = 1, rows = 10 } = {}) => {
resourceLinkListFromEntity: item.resourceLinkListFromEntity,
attendanceQualifyTitle: item.attendanceQualifyTitle,
attendanceWeight: item.attendanceWeight,
doneCalendars: item.doneCalendars,
}))

if (isStudent.value) {
Expand Down
Loading
Loading