Skip to content

Commit

Permalink
Merge pull request #112 from avantifellows/quiz_engine_ui_changes
Browse files Browse the repository at this point in the history
Changes made to the User Interface of Quiz Engine
  • Loading branch information
suryabulusu committed Jun 15, 2023
2 parents 852bc50 + 7a5f408 commit 832ff0c
Show file tree
Hide file tree
Showing 17 changed files with 251 additions and 68 deletions.
33 changes: 21 additions & 12 deletions src/components/Omr/OmrModal.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
<template>
<div class="flex flex-col bg-white w-full justify-between">
<div class="flex flex-col bg-white w-full justify-between">
<Header
class="fixed top-0"
v-if="isQuizAssessment"
:hasQuizEnded="hasQuizEnded"
:hasTimeLimit="quizTimeLimit != null"
:title="title"
:userId="userId"
:isOmrMode="isOmrMode"
v-model:isPaletteVisible="isPaletteVisible"
:timeRemaining="timeRemaining"
Expand All @@ -14,16 +16,14 @@
@end-test-by-time="endTestByTime"
data-test="omr-header"
></Header>

<div
class="flex flex-col grow space-y-10"
>
<div class="mt-20 mb-20">
<!-- to ensure that questions don't appear behind footer -->
<div
v-for="(questionSetState, index) in questionSetStates" :key="index" class="space-y-2">
<p :class="titleTextClass" :data-test="`questionSetTitle-${index}`">{{ questionSetState.title }}</p>
<p :class="instructionTextClass" :data-test="`questionSetInstruction-${index}`" v-html="questionSetState.instructionText"></p>
v-for="(questionSetState, index) in questionSetStates" :key="index" class="space-y-2 mt-[66px]">
<div class="bg-gray-300"><p :class="titleTextClass" :data-test="`questionSetTitle-${index}`">{{ questionSetState.title }}</p></div>
<p :class="instructionTextClass" v-html="questionSetState.instructionText" :data-test="`questionSetInstruction-${index}`"></p>
<div class="mt-4 space-y-4">
<OmrItem
v-for="(questionState, qindex) in questionSetState.paletteItems"
Expand Down Expand Up @@ -55,12 +55,12 @@
class="flex w-full lg:p-6 justify-between z-50 place-self-end fixed bottom-0"
:class="{
'bg-white p-4': !isQuizAssessment,
'bg-gray-200 py-4 px-2': isQuizAssessment,
'bg-gray-200 py-2 px-2': isQuizAssessment,
}"
></div>
</div>
</div>
</template>
</div>
</template>

<script lang="ts">
import Header from "../Questions/Header.vue"
Expand All @@ -84,7 +84,8 @@ import {
quizType,
QuestionSetIndexLimits,
questionSetPalette,
TimeLimit
TimeLimit,
quizTitleType
} from "../../types"
import { useToast, POSITION } from "vue-toastification"
Expand Down Expand Up @@ -152,6 +153,14 @@ export default defineComponent({
isOmrMode: {
type: Boolean,
default: false,
},
userId: {
type: String,
default: ""
},
title: {
required: true,
type: [null, String] as PropType<quizTitleType>,
}
},
setup(props, context) {
Expand All @@ -166,9 +175,9 @@ export default defineComponent({
reRenderKey: false, // a key to re-render a component
hasEndTestBeenClickedOnce: true,
instructionTextClass:
"text-lg md:text-xl lg:text-2xl mx-4 m-2 leading-tight whitespace-pre-wrap text-slate-500",
"text-lg sm:text-xl text-base mx-4 m-2 leading-tight whitespace-pre-wrap text-slate-500",
titleTextClass:
"text-lg md:text-xl lg:text-2xl mx-4 mt-10 m-2 font-bold leading-tight whitespace-pre-wrap",
"text-lg sm:text-xl text-base mx-4 py-2 font-medium leading-tight whitespace-pre-wrap bg-gray-300",
})
// display warning when time remaining goes below this threshold (in minutes)
Expand Down
29 changes: 21 additions & 8 deletions src/components/Questions/Body.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@
</QuestionPalette>

<div class="overflow-y-auto flex flex-col w-full">
<!-- question number and type information-->
<div class="bg-gray-300">
<p :class="questionHeaderTextClass" data-test="question-header-text" v-html="questionHeaderText"></p>
<!-- questionHeaderPrefix shows the question index no. and the type of question -->
<p :class="questionHeaderPrefixClass" data-test="question-index-type" v-html="questionHeaderPrefix"></p>
<!-- questionHeaderSuffix shows the subject and section no. of question -->
<p :class="questionHeaderSuffixClass" data-test="question-subject-section" v-html="questionHeaderSuffix"></p>
</div>
<!-- question text -->
<div class="mx-6 md:mx-10">
Expand Down Expand Up @@ -267,10 +269,16 @@ export default defineComponent({
wrongOptionClass: "text-white bg-red-500",
questionHeaderTextClass:
"text-lg md:text-xl lg:text-2xl mx-4 m-2 text-center leading-tight whitespace-pre-wrap",
// <!-- questionHeaderPrefix shows the question index no. and the type of question -->
questionHeaderPrefixClass:
"float-left text-lg sm:text-xl mx-4 m-2 text-left leading-tight whitespace-pre-wrap text-base",
// <!-- questionHeaderSuffix shows the subject and section no. of question -->
questionHeaderSuffixClass:
"float-right text-lg sm:text-xl mx-4 m-2 text-right leading-tight whitespace-pre-wrap text-base",
questionTextClass:
"text-lg md:text-xl lg:text-2xl mx-4 mt-6 m-2 font-bold leading-tight whitespace-pre-wrap",
"text-lg base:text-lg lg:text-xl mx-4 mt-6 m-2 font-bold leading-tight whitespace-pre-wrap",
optionTextClass:
"p-2 text-lg md:text-xl lg:text-2xl border rounded-md mx-2 whitespace-pre-wrap",
"p-2 text-base base:text-lg lg:text-xl border rounded-md mx-2 whitespace-pre-wrap",
subjectiveAnswer: null as string | null, // holds the answer to the subjective question
numericalAnswer: null as number | null // holds the answer to the numerical question
})
Expand Down Expand Up @@ -397,9 +405,13 @@ export default defineComponent({
context.emit("navigate", questionIndex)
}
const questionHeaderText = computed(() => {
return `${props.questionSetTitle} / Q.${props.currentQuestionIndex + 1} ${questionTypeHeaderMapping.get(props.questionType)}`
})
const questionHeaderPrefix = computed(() => {
return `Q.${props.currentQuestionIndex + 1} | ${questionTypeHeaderMapping.get(props.questionType)}`;
});
const questionHeaderSuffix = computed(() => {
return props.questionSetTitle;
});
// styling class for the question image and loading spinner containers
const questionImageAreaClass = computed(() => ({
Expand Down Expand Up @@ -626,7 +638,8 @@ export default defineComponent({
return {
...toRefs(state),
questionHeaderText,
questionHeaderPrefix,
questionHeaderSuffix,
stopImageLoading,
optionBackgroundClass,
isOptionMarked,
Expand Down
76 changes: 50 additions & 26 deletions src/components/Questions/Header.vue
Original file line number Diff line number Diff line change
@@ -1,40 +1,64 @@
<template>
<div class="flex w-full justify-between bg-gray-100 p-4">
<!-- hamburger for question palette -->
<icon-button
:class="{invisible: isOmrMode}"
:iconConfig="togglePaletteButtonIconConfig"
:buttonClass="togglePaletteButtonClass"
@click="togglePalette"
data-test="togglePaletteButton"
></icon-button>
<div class="flex space-x-3">
<!-- countdown timer / can't click -->
<icon-button
v-if="!hasQuizEnded && hasTimeLimit"
:titleConfig="countdownTimerTitleConfig"
:buttonClass="countdownTimerClass"
data-test="countdownTimer"
></icon-button>

<!-- end-test button -->
<icon-button
:titleConfig="endTestButtonTitleConfig"
:buttonClass="endTestButtonClass"
@click="endTest"
data-test="endTestButton"
></icon-button>
<div>
<div class="fixed top-0 left-0 w-full ">
<div class="flex w-full justify-between bg-gray-200 p-4">
<!-- hamburger for question palette -->
<icon-button
:class="{invisible: isOmrMode}"
:iconConfig="togglePaletteButtonIconConfig"
:buttonClass="togglePaletteButtonClass"
@click="togglePalette"
data-test="togglePaletteButton"
></icon-button>
<div class="flex space-x-3">
<!-- countdown timer / can't click -->
<icon-button
v-if="!hasQuizEnded && hasTimeLimit"
:titleConfig="countdownTimerTitleConfig"
:buttonClass="countdownTimerClass"
data-test="countdownTimer"
></icon-button>

<!-- end-test button -->
<icon-button
:titleConfig="endTestButtonTitleConfig"
:buttonClass="endTestButtonClass"
@click="endTest"
data-test="endTestButton"
></icon-button>
</div>
</div>
<div
class="bg-white-400 w-full justify between">
<div class="py-4 h-12 bg-white px-4">
<div class="float-left text-lg sm:text-xl text-base truncate" data-test="test-name">
{{ $props.title }}
</div>
<div class="float-right text-lg sm:text-xl text-base mx-1 px-1" data-test="user-id">
Id: {{ $props.userId }}
</div>
</div>
</div>
</div>
</div>
</template>

<script lang="ts">
import IconButton from "../UI/Buttons/IconButton.vue";
import { defineComponent, reactive, toRefs, computed, watch, onMounted } from "vue";
import { defineComponent, reactive, toRefs, computed, watch, onMounted, PropType } from "vue";
import { quizTitleType } from "../../types";
export default defineComponent({
name: "Header",
props: {
title: {
type: [null, String] as PropType<quizTitleType>,
required: true,
},
userId: {
type: String,
default: ""
},
hasQuizEnded: {
type: Boolean,
default: false,
Expand Down
8 changes: 4 additions & 4 deletions src/components/Questions/Palette/QuestionPalette.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<div class="bg-white p-4 sm:p-6 lg:p-8 overflow-auto">
<div class="bg-white p-4 sm:p-6 lg:p-8 overflow-auto sm:w-1/3 lg:w-1/3 xl:w-1/3">
<div
class="bg-gray-200 border-gray-500 border-1 rounded-md p-4 grid grid-rows-2 space-y-2"
class="bg-gray-200 rounded-md p-4 grid grid-rows-2 space-y-2"
>
<div class="grid grid-cols-2">
<Success
Expand Down Expand Up @@ -95,9 +95,9 @@ export default defineComponent({
const state = {
instructionTextClass:
"text-lg md:text-xl lg:text-2xl mx-4 m-2 leading-tight whitespace-pre-wrap text-slate-500",
"text-lg md:text-xl lg:text-2xl mx-4 mt-2 leading-none text-slate-500",
titleTextClass:
"text-lg md:text-xl lg:text-2xl mx-4 mt-10 m-2 font-bold leading-tight whitespace-pre-wrap",
"text-lg md:text-xl lg:text-2xl mx-4 mt-10 font-bold leading-tight whitespace-pre-wrap",
}
return {
Expand Down
45 changes: 43 additions & 2 deletions src/components/Questions/QuestionModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,32 @@
v-model:isPaletteVisible="isPaletteVisible"
:timeRemaining="timeRemaining"
:warningTimeLimit="timeLimitWarningThreshold"
:title="title"
:userId="userId"
@time-limit-warning="displayTimeLimitWarning"
@end-test="endTest"
@end-test-by-time="endTestByTime"
data-test="header"
></Header>
<div v-if="!isQuizAssessment">
<div
class="bg-white-400 w-full justify between">
<div class="p-4 h-14 bg-white">
<div class="float-left text-lg sm:text-xl truncate" data-test="test-name">
{{ $props.title }}
</div>
<div class="float-right text-lg sm:text-xl mx-1 px-1 " data-test="user-id">
Id: {{ $props.userId }}
</div>
</div>
</div>
</div>
<div
class="flex flex-col grow bg-white w-full justify-between overflow-hidden"
class="scroll-container flex flex-col grow bg-white w-full justify-between overflow-hidden"
>
<Body
:text="currentQuestion.text"
:class="bodyContainerClass"
:options="currentQuestion.options"
:correctAnswer="questionCorrectAnswer"
:questionType="questionType"
Expand Down Expand Up @@ -83,7 +99,8 @@ import {
quizType,
QuestionSetIndexLimits,
questionSetPalette,
TimeLimit
TimeLimit,
quizTitleType
} from "../../types"
import { useToast, POSITION } from "vue-toastification"
const clonedeep = require("lodash.clonedeep");
Expand Down Expand Up @@ -143,6 +160,14 @@ export default defineComponent({
timeRemaining: {
type: Number,
default: 0
},
userId: {
type: String,
default: ""
},
title: {
required: true,
type: [null, String] as PropType<quizTitleType>,
}
},
setup(props, context) {
Expand Down Expand Up @@ -352,6 +377,10 @@ To attempt this question, unselect an answer to another question in this section
window.removeEventListener("resize", checkScreenOrientation)
})

const bodyContainerClass = computed(() => ({
"mt-36": isQuizAssessment.value
}))

const currentQuestion = computed(
() => props.questions[props.currentQuestionIndex]
)
Expand Down Expand Up @@ -467,6 +496,7 @@ To attempt this question, unselect an answer to another question in this section
endTestByTime,
navigateToQuestion,
currentQuestion,
bodyContainerClass,
questionType,
questionCorrectAnswer,
isGradedQuestion,
Expand All @@ -491,3 +521,14 @@ To attempt this question, unselect an answer to another question in this section
],
});
</script>

<style>
.truncate {
@apply whitespace-nowrap overflow-hidden overflow-ellipsis;
max-width: 10em; /*(10em) Adjust this value to determine the maximum width in characters */
}
.scroll-container {
height: 100vh; /* Adjust the height as per your needs */
overflow: auto;
}
</style>
16 changes: 13 additions & 3 deletions src/components/Scorecard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,16 @@

<!-- name of the quiz -->
<div
class="text-center text-sm md:text-lg lg:text-xl font-medium truncate"
class="text-center text-lg md:text-lg lg:text-xl font-semibold"
>
{{ title }}
</div>
<!-- student's userId -->
<div
class="text-center text-lg md:text-lg lg:text-xl pt-5 leading-tight" data-test="user-id"
>
Id: {{ userId }}
</div>

<!-- canvas element for drawing the confetti -->
<canvas id="confetticanvas" class="fixed z-50"></canvas>
Expand Down Expand Up @@ -182,6 +188,10 @@ export default defineComponent({
required: true,
type: [null, String] as PropType<quizTitleType>,
},
userId: {
type: String,
default: ""
},
result: {
type: Object as PropType<CircularProgressResult>,
default: () => {},
Expand All @@ -199,9 +209,9 @@ export default defineComponent({
reRenderKey: false, // a key to re-render a component
// classes for watch again button
backButtonClass:
"bg-[#F78000] hover:bg-primary-hover bp-500:w-40 px-6 py-3 bp-500:p-4 bp-500:px-10 sm:p-6 rounded-2xl md:rounded-xl shadow-xl disabled:opacity-50 disabled:pointer-events-none invisible",
"bg-back-color hover:bg-primary-hover bp-500:w-40 px-6 py-3 bp-500:p-4 bp-500:px-10 sm:p-6 rounded-2xl md:rounded-xl shadow-xl disabled:opacity-50 disabled:pointer-events-none invisible",
shareButtonClass:
"bg-[#10B981] hover:bg-green-600 bp-500:w-40 px-6 py-3 bp-500:p-4 bp-500:px-10 sm:p-6 rounded-2xl md:rounded-xl shadow-xl disabled:opacity-50 disabled:pointer-events-none",
"flex justify-center bg-share-color hover:bg-green-600 bp-500:w-40 px-6 py-3 bp-500:p-4 bp-500:px-10 sm:p-6 rounded-2xl md:rounded-xl shadow-xl disabled:opacity-50 disabled:pointer-events-none",
isPortrait: true,
isMobileLandscape: false, // whether the screen corresponds to a mobile screen in landscape mode
confettiHandler,
Expand Down
Loading

0 comments on commit 832ff0c

Please sign in to comment.