Skip to content

Commit

Permalink
feat: evaluation feedback record
Browse files Browse the repository at this point in the history
  • Loading branch information
pateljannat committed Sep 9, 2024
1 parent bd94890 commit 60f2e86
Show file tree
Hide file tree
Showing 12 changed files with 4,798 additions and 1,070 deletions.
2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"chart.js": "^4.4.1",
"dayjs": "^1.11.6",
"feather-icons": "^4.28.0",
"frappe-ui": "^0.1.56",
"frappe-ui": "^0.1.67",
"lucide-vue-next": "^0.383.0",
"markdown-it": "^14.0.0",
"pinia": "^2.0.33",
Expand Down
26 changes: 18 additions & 8 deletions frontend/src/components/Controls/Rating.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
<template>
<div class="flex text-center">
<div v-for="index in 5">
<Star
:class="index <= rating ? 'fill-orange-500' : ''"
class="h-6 w-6 fill-gray-400 text-gray-50 mr-1 cursor-pointer"
@click="markRating(index)"
/>
<div class="space-y-1">
<label class="block text-xs text-gray-600" v-if="props.label">
{{ props.label }}
</label>
<div class="flex text-center">
<div v-for="index in 5">
{{ rating }}
<Star
:class="index <= rating ? 'fill-orange-500' : ''"
class="h-6 w-6 fill-gray-400 text-gray-50 mr-1 cursor-pointer"
@click="markRating(index)"
/>
</div>
</div>
</div>
</template>
Expand All @@ -23,11 +29,15 @@ const props = defineProps({
type: Number,
default: 0,
},
label: {
type: String,
default: '',
},
})
const emit = defineEmits(['update:modelValue'])
let rating = ref(props.modelValue)
console.log(props.modelValue)
let emitChange = (value) => {
emit('update:modelValue', value)
}
Expand Down
156 changes: 156 additions & 0 deletions frontend/src/components/Modals/Event.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
<template>
<Dialog
v-model="show"
:options="{
size: '2xl',
}">
<template #body>
<div class="flex text-base">
<div class="flex flex-col w-1/2 p-5">
<div class="text-lg font-semibold mb-4">
{{ event.title }}
</div>

<div class="flex flex-col space-y-3">
<div class="flex items-center space-x-1">
<BookOpen class="h-4 w-4 stroke-1.5" />
<span>
{{ event.course_title }}
</span>
</div>
<div class="flex items-center space-x-1">
<Calendar class="h-4 w-4 stroke-1.5" />
<span>
{{ dayjs(event.date).format("DD MMM YYYY") }}
</span>
</div>
<div class="flex items-center space-x-1">
<Clock class="h-4 w-4 stroke-1.5" />
<span>
{{ formatTime(event.start_time) }} - {{ formatTime(event.end_time) }}
</span>
</div>
<div class="flex items-center space-x-1">
<User class="h-4 w-4 stroke-1.5" />
<span>
{{ event.member }}
</span>
</div>
</div>
<Button @click="openCallLink(event.venue)" class="mt-auto">
<template #prefix>
<Video class="h-4 w-4 stroke-1.5" />
</template>
<span>
{{ __("Join Meeting") }}
</span>
</Button>
</div>
<div class="flex flex-col space-y-4 border-l w-1/2 p-5">
{{ evaluation.rating }}
<Rating v-model="evaluation.rating" :label="__('Rating')"/>
<FormControl type="select" :options='[{
value: "Pending",
label: __("Pending")
}, {
value: "In Progress",
label: __("In Progress")
}, {
value: "Pass",
label: __("Pass")
}, {
value: "Fail",
label: __("Fail")
}]'
v-model="evaluation.status" :label="__('Status')" />
<FormControl type="textarea" v-model="evaluation.summary" :label="__('Summary')" />
<Button variant="solid" @click="saveEvaluation()">
{{ __("Save") }}
</Button>
</div>
</div>
</template>
</Dialog>
</template>
<script setup>
import { Dialog, Button, FormControl, createResource } from 'frappe-ui';
import { User, Calendar, Clock, Video, BookOpen } from "lucide-vue-next"
import { inject, reactive, watch } from "vue"
import { formatTime, showToast } from "@/utils"
import Rating from "@/components/Controls/Rating.vue"
const show = defineModel()
const dayjs = inject("$dayjs")
const props = defineProps({
event: {
type: [Object, null],
required: true,
},
});
const evaluation = reactive({
rating: 0,
status: "Pending",
summary: "",
})
const openCallLink = (link) => {
window.open(link, "_blank")
}
const evaluationResource = createResource({
url: "lms.lms.api.save_evaluation_details",
makeParams(values) {
return {
member: props.event.member,
course: props.event.course,
date: props.event.date,
start_time: props.event.start_time,
end_time: props.event.end_time,
status: evaluation.status,
rating: evaluation.rating,
summary: evaluation.summary,
}
},
auto: false
})
const evaluationDetails = createResource({
url: "frappe.client.get",
makeParams(values) {
return {
doctype: "LMS Certificate Evaluation",
filters: {
member: props.event.member,
course: props.event.course,
}
}
},
onSuccess(data) {
for (const key in data) {
if (key in evaluation)
evaluation[key] = data[key]
}
},
auto: false
})
const saveEvaluation = () => {
evaluationResource.submit({}, {
onSuccess: () => {
show.value = false
showToast( __("Success"), __("Evaluation saved successfully"), "check")
}
})
}
watch(show, () => {
if (show.value) {
evaluation.rating = 0
evaluation.status = "Pending"
evaluation.summary = ""
evaluationDetails.reload()
}
})
</script>
2 changes: 1 addition & 1 deletion frontend/src/components/NoPermission.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<div>
{{ __('Please login to access this page.') }}
</div>
<Button variant="solid" @click="redirectToLogin()" class="mt-2">
<Button @click="redirectToLogin()" class="mt-4">
{{ __('Login') }}
</Button>
</div>
Expand Down
17 changes: 10 additions & 7 deletions frontend/src/pages/Profile.vue
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ const coverImage = createResource({
const setActiveTab = () => {
let fragments = route.path.split('/')
let sections = ['certificates', 'roles', 'evaluations']
let sections = ['certificates', 'roles', 'slots', 'schedule']
sections.forEach((section) => {
if (fragments.includes(section)) {
activeTab.value = convertToTitleCase(section)
Expand All @@ -158,10 +158,11 @@ const setActiveTab = () => {
watchEffect(() => {
if (activeTab.value) {
let route = {
About: { name: 'ProfileAbout' },
Certificates: { name: 'ProfileCertificates' },
Roles: { name: 'ProfileRoles' },
Evaluations: { name: 'ProfileEvaluator' },
"About": { name: 'ProfileAbout' },
"Certificates": { name: 'ProfileCertificates' },
"Roles": { name: 'ProfileRoles' },
"Slots": { name: 'ProfileEvaluator' },
"Schedule": { name: 'ProfileEvaluationSchedule' },
}[activeTab.value]
router.push(route)
}
Expand All @@ -185,8 +186,10 @@ const isSessionUser = () => {
const getTabButtons = () => {
let buttons = [{ label: 'About' }, { label: 'Certificates' }]
if ($user.data?.is_moderator) buttons.push({ label: 'Roles' })
if (isSessionUser() && $user.data?.is_evaluator)
buttons.push({ label: 'Evaluations' })
if (isSessionUser() && ($user.data?.is_evaluator || $user.data?.is_moderator)) {
buttons.push({ label: 'Slots' })
buttons.push({ label: 'Schedule' })
}
return buttons
}
Expand Down
92 changes: 92 additions & 0 deletions frontend/src/pages/ProfileEvaluationSchedule.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<template>
<div class="mt-7 mb-20">
<div class="flex h-screen flex-col overflow-hidden">
<Calendar
v-if="evaluations.data?.length"
:config="{
defaultMode: 'Month',
disableModes: ['Day', 'Week'],
redundantCellHeight: 100,
enableShortcuts: true,
}"
:events="evaluations.data"
@click="(event) => openEvent(event)"
>
<template #header="{currentMonthYear,
decrement,
increment,
}">
<div class="mb-2 flex justify-between">
<span class="text-lg font-semibold">
{{ currentMonthYear }}
</span>
<div class="flex gap-x-1">
<Button
@click="decrement()"
variant="ghost"
class="h-4 w-4"
icon="chevron-left"
/>
<Button
@click="increment()"
variant="ghost"
class="h-4 w-4"
icon="chevron-right"
/>
</div>
</div>
</template>
</Calendar>
</div>
</div>
<Event v-model="showEvent" :event="currentEvent"/>
</template>
<script setup>
import { Calendar, createListResource, Button } from "frappe-ui"
import { inject, ref } from "vue"
import Event from "@/components/Modals/Event.vue"
const user = inject("$user")
const currentEvent = ref(null)
const showEvent = ref(false)
const props = defineProps({
profile: {
type: Object,
required: true,
},
})
const evaluations = createListResource({
doctype: "LMS Certificate Request",
filters: {
"evaluator": user.data?.name
},
fields: ["name", "member_name", "member", "course", "course_title", "date", "start_time", "end_time", "google_meet_link"],
auto: true,
cache: ["schedule", user.data?.name],
transform(data) {
return data.map((d) => {
return {
title: `${d.member_name}'s Evaluation`,
participant: d.member_name,
id: d.name,
venue: d.google_meet_link,
fromDate: `${d.date} ${d.start_time}`,
toDate: `${d.date} ${d.end_time}`,
color: "green",
start_time: d.start_time,
end_time: d.end_time,
course: d.course,
course_title: d.course_title,
member: d.member,
}
})
},
})
const openEvent = (event) => {
currentEvent.value = event.calendarEvent
showEvent.value = true
}
</script>
7 changes: 6 additions & 1 deletion frontend/src/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,14 @@ const routes = [
},
{
name: 'ProfileEvaluator',
path: 'evaluations',
path: 'slots',
component: () => import('@/pages/ProfileEvaluator.vue'),
},
{
name: 'ProfileEvaluationSchedule',
path: 'schedule',
component: () => import('@/pages/ProfileEvaluationSchedule.vue'),
}
],
},
{
Expand Down
Loading

0 comments on commit 60f2e86

Please sign in to comment.