feat: split assigment submit

This commit is contained in:
Reto Aebersold 2023-12-14 09:21:17 +01:00
parent acd9c3959b
commit 1979dcd428
4 changed files with 327 additions and 120 deletions

View File

@ -0,0 +1,124 @@
<script setup lang="ts">
import ItCheckbox from "@/components/ui/ItCheckbox.vue";
import { computed, reactive } from "vue";
import type { CourseSessionUserObjectsType } from "@/gql/graphql";
import dayjs from "dayjs";
import DateEmbedding from "@/components/dueDates/DateEmbedding.vue";
import ItButton from "@/components/ui/ItButton.vue";
import { useMutation } from "@urql/vue";
import { UPSERT_ASSIGNMENT_COMPLETION_MUTATION } from "@/graphql/mutations";
import { useUserStore } from "@/stores/user";
import { bustItGetCache } from "@/fetchHelpers";
import eventBus from "@/utils/eventBus";
import log from "loglevel";
import type { Assignment } from "@/types";
const props = defineProps<{
evaluationDocumentUrl: string;
submissionDeadlineStart?: string | null;
circleExpert?: CourseSessionUserObjectsType;
courseSessionId: string;
assignment: Assignment;
learningContentId: string;
}>();
const state = reactive({
confirmInput: false,
confirmPerson: false,
});
const circleExpertName = computed(() => {
return `${props.circleExpert?.first_name} ${props.circleExpert?.last_name}`;
});
const cannotSubmit = computed(() => {
return !state.confirmInput || !state.confirmPerson;
});
const upsertAssignmentCompletionMutation = useMutation(
UPSERT_ASSIGNMENT_COMPLETION_MUTATION
);
const onSubmit = async () => {
try {
await upsertAssignmentCompletionMutation.executeMutation({
assignmentId: props.assignment.id,
courseSessionId: props.courseSessionId,
learningContentId: props.learningContentId,
completionDataString: JSON.stringify({}),
completionStatus: "SUBMITTED",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
id: props.assignmentCompletion?.id,
});
bustItGetCache(
`/api/course/completion/${props.courseSessionId}/${useUserStore().id}/`
);
// if solution sample is available, do not close the assigment automatically
if (!props.assignment.solution_sample) {
eventBus.emit("finishedLearningContent", true);
}
} catch (error) {
log.error("Could not submit assignment", error);
}
};
</script>
<template>
<div>
<ItCheckbox
class="w-full border-b border-gray-400 py-10 sm:py-6"
:checkbox-item="{
label: $t('assignment.confirmSubmitResults'),
value: 'value',
checked: state.confirmInput,
}"
data-cy="confirm-submit-results"
@toggle="state.confirmInput = !state.confirmInput"
></ItCheckbox>
<div class="w-full border-b border-gray-400">
<ItCheckbox
class="py-6"
:checkbox-item="{
label: $t('assignment.confirmSubmitPerson'),
value: 'value',
checked: state.confirmPerson,
}"
data-cy="confirm-submit-person"
@toggle="state.confirmPerson = !state.confirmPerson"
></ItCheckbox>
<div v-if="circleExpert" class="flex flex-row items-center pb-6 pl-[49px]">
<img
alt="Notification icon"
class="mr-2 h-[45px] min-w-[45px] rounded-full"
:src="circleExpert.avatar_url"
/>
<p class="text-base font-bold">
{{ circleExpertName }}
</p>
</div>
</div>
<div class="flex flex-col space-x-2 pt-6 text-base sm:flex-row">
<p>{{ $t("assignment.assessmentDocumentDisclaimer") }}</p>
<a :href="evaluationDocumentUrl" class="underline">
{{ $t("assignment.showAssessmentDocument") }}
</a>
</div>
<p v-if="submissionDeadlineStart" class="pt-6">
{{ $t("assignment.dueDateSubmission") }}
<DateEmbedding
:single-date="dayjs(props.submissionDeadlineStart)"
></DateEmbedding>
</p>
<ItButton
class="mt-6"
variant="blue"
size="large"
:disabled="cannotSubmit"
data-cy="submit-assignment"
@click="onSubmit"
>
<p>{{ $t("assignment.submitAssignment") }}</p>
</ItButton>
</div>
</template>

View File

@ -0,0 +1,101 @@
<script setup lang="ts">
import ItButton from "@/components/ui/ItButton.vue";
import ItCheckbox from "@/components/ui/ItCheckbox.vue";
import { computed, ref } from "vue";
import { bustItGetCache, useCSRFFetch } from "@/fetchHelpers";
import { useUserStore } from "@/stores/user";
import eventBus from "@/utils/eventBus";
import log from "loglevel";
import dayjs from "dayjs";
import { useMutation } from "@urql/vue";
import { UPSERT_ASSIGNMENT_COMPLETION_MUTATION } from "@/graphql/mutations";
import type { CourseSessionUserObjectsType } from "@/gql/graphql";
import type { Assignment } from "@/types";
const props = defineProps<{
submissionDeadlineStart?: string | null;
circleExpert?: CourseSessionUserObjectsType;
courseSessionId: string;
assignment: Assignment;
learningContentId: string;
}>();
const confirmPerson = ref(false);
const upsertAssignmentCompletionMutation = useMutation(
UPSERT_ASSIGNMENT_COMPLETION_MUTATION
);
const circleExpertName = computed(() => {
return `${props.circleExpert?.first_name} ${props.circleExpert?.last_name}`;
});
const { data: learningMentors } = useCSRFFetch(
`/api/mentor/${props.courseSessionId}/mentors`
).json();
const onSubmit = async () => {
try {
await upsertAssignmentCompletionMutation.executeMutation({
assignmentId: props.assignment.id,
courseSessionId: props.courseSessionId,
learningContentId: props.learningContentId,
completionDataString: JSON.stringify({}),
completionStatus: "SUBMITTED",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
id: props.assignmentCompletion?.id,
});
bustItGetCache(
`/api/course/completion/${props.courseSessionId}/${useUserStore().id}/`
);
// if solution sample is available, do not close the assigment automatically
if (!props.assignment.solution_sample) {
eventBus.emit("finishedLearningContent", true);
}
} catch (error) {
log.error("Could not submit assignment", error);
}
};
</script>
<template>
<div class="w-full border-b border-gray-400">
<ItCheckbox
class="py-6"
:checkbox-item="{
label: $t('a.confirmSubmitPersonPraxisAssignment'),
value: 'value',
checked: confirmPerson,
}"
data-cy="confirm-submit-person"
@toggle="confirmPerson = !confirmPerson"
></ItCheckbox>
<div v-if="circleExpert" class="flex flex-row items-center pb-6 pl-[49px]">
<img
alt="Notification icon"
class="mr-2 h-[45px] min-w-[45px] rounded-full"
:src="circleExpert.avatar_url"
/>
<p class="text-base font-bold">
{{ circleExpertName }}
</p>
</div>
{{ learningMentors }}
</div>
<p v-if="props.submissionDeadlineStart" class="pt-6">
{{ $t("assignment.dueDateSubmission") }}
<DateEmbedding :single-date="dayjs(props.submissionDeadlineStart)"></DateEmbedding>
</p>
<ItButton
class="mt-6"
variant="blue"
size="large"
:disabled="!confirmPerson"
data-cy="submit-assignment"
@click="onSubmit"
>
<p>{{ $t("assignment.submitAssignment") }}</p>
</ItButton>
</template>

View File

@ -0,0 +1,71 @@
<script setup lang="ts">
import ItButton from "@/components/ui/ItButton.vue";
import ItCheckbox from "@/components/ui/ItCheckbox.vue";
import { ref } from "vue";
import { bustItGetCache } from "@/fetchHelpers";
import { useUserStore } from "@/stores/user";
import eventBus from "@/utils/eventBus";
import log from "loglevel";
import { useMutation } from "@urql/vue";
import { UPSERT_ASSIGNMENT_COMPLETION_MUTATION } from "@/graphql/mutations";
import type { Assignment } from "@/types";
const props = defineProps<{
courseSessionId: string;
assignment: Assignment;
learningContentId: string;
}>();
const upsertAssignmentCompletionMutation = useMutation(
UPSERT_ASSIGNMENT_COMPLETION_MUTATION
);
const confirmInput = ref(false);
const onSubmit = async () => {
try {
await upsertAssignmentCompletionMutation.executeMutation({
assignmentId: props.assignment.id,
courseSessionId: props.courseSessionId,
learningContentId: props.learningContentId,
completionDataString: JSON.stringify({}),
completionStatus: "SUBMITTED",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
id: props.assignmentCompletion?.id,
});
bustItGetCache(
`/api/course/completion/${props.courseSessionId}/${useUserStore().id}/`
);
// if solution sample is available, do not close the assigment automatically
if (!props.assignment.solution_sample) {
eventBus.emit("finishedLearningContent", true);
}
} catch (error) {
log.error("Could not submit assignment", error);
}
};
</script>
<template>
<ItCheckbox
class="w-full border-b border-gray-400 py-10 sm:py-6"
:checkbox-item="{
label: $t('assignment.confirmSubmitResults'),
value: 'value',
checked: confirmInput,
}"
data-cy="confirm-submit-results"
@toggle="confirmInput = !confirmInput"
></ItCheckbox>
<ItButton
class="mt-6"
variant="blue"
size="large"
:disabled="!confirmInput"
data-cy="submit-assignment"
@click="onSubmit"
>
<p>{{ $t("assignment.submitAssignment") }}</p>
</ItButton>
</template>

View File

@ -1,25 +1,19 @@
<script setup lang="ts">
import DateEmbedding from "@/components/dueDates/DateEmbedding.vue";
import ItButton from "@/components/ui/ItButton.vue";
import ItCheckbox from "@/components/ui/ItCheckbox.vue";
import ItSuccessAlert from "@/components/ui/ItSuccessAlert.vue";
import {
useCourseData,
useCourseSessionDetailQuery,
useCurrentCourseSession,
} from "@/composables";
import { bustItGetCache, useCSRFFetch } from "@/fetchHelpers";
import { UPSERT_ASSIGNMENT_COMPLETION_MUTATION } from "@/graphql/mutations";
import AssignmentSubmissionResponses from "@/pages/learningPath/learningContentPage/assignment/AssignmentSubmissionResponses.vue";
import { useUserStore } from "@/stores/user";
import type { Assignment, AssignmentCompletion, AssignmentTask } from "@/types";
import { useMutation } from "@urql/vue";
import log from "loglevel";
import { computed, reactive } from "vue";
import { computed } from "vue";
import { useTranslation } from "i18next-vue";
import eventBus from "@/utils/eventBus";
import dayjs from "dayjs";
import type { AssignmentAssignmentAssignmentTypeChoices } from "@/gql/graphql";
import CaseWorkSubmit from "@/components/learningPath/assignment/CaseWorkSubmit.vue";
import SimpleSubmit from "@/components/learningPath/assignment/SimpleSubmit.vue";
import PraxisAssignmentSubmit from "@/components/learningPath/assignment/PraxisAssignmentSubmit.vue";
const props = defineProps<{
assignment: Assignment;
@ -39,11 +33,6 @@ const courseData = useCourseData(courseSession.value.course.slug);
const { t } = useTranslation();
const state = reactive({
confirmInput: false,
confirmPerson: false,
});
const learningContent = computed(() => {
return courseData.findLearningContent(props.learningContentId);
});
@ -61,10 +50,6 @@ const circleExpert = computed(() => {
return circleExperts.value[0];
});
const { data: learningMentors } = useCSRFFetch(
`/api/mentor/${courseSession.value.id}/mentors`
).json();
const circleExpertName = computed(() => {
return `${circleExpert.value?.first_name} ${circleExpert.value?.last_name}`;
});
@ -81,13 +66,6 @@ const completionTaskData = computed(() => {
return props.assignmentCompletion?.task_completion_data ?? {};
});
const cannotSubmit = computed(() => {
return (
(!state.confirmInput && !isPraxisAssignment.value) ||
(props.assignment.assignment_type === "CASEWORK" && !state.confirmPerson)
);
});
function checkAssignmentType(
assignmentType: AssignmentAssignmentAssignmentTypeChoices[]
) {
@ -95,15 +73,8 @@ function checkAssignmentType(
}
const isCasework = computed(() => checkAssignmentType(["CASEWORK"]));
const mayBeEvaluated = computed(() =>
checkAssignmentType(["CASEWORK", "PRAXIS_ASSIGNMENT"])
);
const isPraxisAssignment = computed(() => checkAssignmentType(["PRAXIS_ASSIGNMENT"]));
const upsertAssignmentCompletionMutation = useMutation(
UPSERT_ASSIGNMENT_COMPLETION_MUTATION
);
const onEditTask = (task: AssignmentTask) => {
emit("editTask", task);
};
@ -115,30 +86,6 @@ const openSolutionSample = () => {
window.open(url, "_blank");
}
};
const onSubmit = async () => {
try {
await upsertAssignmentCompletionMutation.executeMutation({
assignmentId: props.assignment.id,
courseSessionId: courseSession.value.id,
learningContentId: props.learningContentId,
completionDataString: JSON.stringify({}),
completionStatus: "SUBMITTED",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
id: props.assignmentCompletion?.id,
});
bustItGetCache(
`/api/course/completion/${courseSession.value.id}/${useUserStore().id}/`
);
// if solution sample is available, do not close the assigment automatically
if (!props.assignment.solution_sample) {
eventBus.emit("finishedLearningContent", true);
}
} catch (error) {
log.error("Could not submit assignment", error);
}
};
</script>
<template>
<div class="w-full border border-gray-400 p-8" data-cy="confirm-container">
@ -147,67 +94,31 @@ const onSubmit = async () => {
</h3>
<div v-if="completionStatus === 'IN_PROGRESS'">
<ItCheckbox
v-if="!isPraxisAssignment"
class="w-full border-b border-gray-400 py-10 sm:py-6"
:checkbox-item="{
label: $t('assignment.confirmSubmitResults'),
value: 'value',
checked: state.confirmInput,
}"
data-cy="confirm-submit-results"
@toggle="state.confirmInput = !state.confirmInput"
></ItCheckbox>
<div v-if="mayBeEvaluated" class="w-full border-b border-gray-400">
<ItCheckbox
class="py-6"
:checkbox-item="{
label: isPraxisAssignment
? $t('a.confirmSubmitPersonPraxisAssignment')
: $t('assignment.confirmSubmitPerson'),
value: 'value',
checked: state.confirmPerson,
}"
data-cy="confirm-submit-person"
@toggle="state.confirmPerson = !state.confirmPerson"
></ItCheckbox>
<div v-if="circleExpert" class="flex flex-row items-center pb-6 pl-[49px]">
<img
alt="Notification icon"
class="mr-2 h-[45px] min-w-[45px] rounded-full"
:src="circleExpert.avatar_url"
/>
<p class="text-base font-bold">
{{ circleExpertName }}
</p>
</div>
<div>
{{ learningMentors }}
</div>
<!-- TODO: find way to find user that will do the corrections -->
</div>
<div v-if="isCasework" class="flex flex-col space-x-2 pt-6 text-base sm:flex-row">
<p>{{ $t("assignment.assessmentDocumentDisclaimer") }}</p>
<a :href="props.assignment.evaluation_document_url" class="underline">
{{ $t("assignment.showAssessmentDocument") }}
</a>
</div>
<p v-if="mayBeEvaluated && props.submissionDeadlineStart" class="pt-6">
{{ $t("assignment.dueDateSubmission") }}
<DateEmbedding
:single-date="dayjs(props.submissionDeadlineStart)"
></DateEmbedding>
</p>
<ItButton
class="mt-6"
variant="blue"
size="large"
:disabled="cannotSubmit"
data-cy="submit-assignment"
@click="onSubmit"
>
<p>{{ $t("assignment.submitAssignment") }}</p>
</ItButton>
<CaseWorkSubmit
v-if="isCasework"
:course-session-id="courseSessionId"
:assignment="assignment"
:learning-content-id="learningContentId"
:circle-expert="circleExpert"
:evaluation-document-url="assignment.evaluation_document_url"
:submission-deadline-start="submissionDeadlineStart"
/>
<PraxisAssignmentSubmit
v-else-if="isPraxisAssignment"
:course-session-id="courseSessionId"
:assignment="assignment"
:learning-content-id="learningContentId"
:circle-expert="circleExpert"
:submission-deadline-start="submissionDeadlineStart"
/>
<SimpleSubmit
v-else
:course-session-id="courseSessionId"
:assignment="assignment"
:learning-content-id="learningContentId"
/>
</div>
<div v-else class="pt-6">
<ItSuccessAlert
@ -220,7 +131,7 @@ const onSubmit = async () => {
}}
</p>
<div
v-if="props.assignment.solution_sample"
v-if="assignment.solution_sample"
class="pt-2"
data-cy="show-sample-solution"
>
@ -242,7 +153,7 @@ const onSubmit = async () => {
</div>
</div>
<AssignmentSubmissionResponses
:assignment="props.assignment"
:assignment="assignment"
:assignment-completion-data="completionData"
:assignment-task-completion-data="completionTaskData"
:allow-edit="completionStatus === 'IN_PROGRESS'"